A first setup of the new Weather Module

This commit is contained in:
Michael Teeuw 2017-09-21 16:38:18 +02:00
parent 8a101f9e9a
commit ef172592b8
5 changed files with 343 additions and 1 deletions

View File

@ -16,7 +16,8 @@ var defaultModules = [
"helloworld",
"newsfeed",
"weatherforecast",
"updatenotification"
"updatenotification",
"weather"
];
/*************** DO NOT EDIT THE LINE BELOW ***************/

View File

@ -0,0 +1,120 @@
/* global WeatherProvider, WeatherDay */
/* Magic Mirror
* Module: Weather
*
* By Michael Teeuw http://michaelteeuw.nl
* MIT Licensed.
*
* This class is the blueprint for a weather provider.
*/
WeatherProvider.register("openweathermap", {
// Set the name of the provider.
// This isn't strictly nessecery, since it will fallback to the provider identifier
// But for debugging (and future alerts) it would be nice to have the real name.
providerName: "OpenWeatherMap",
// Overwrite the fetchCurrentWeather method.
fetchCurrentWeather: function() {
var apiVersion = "2.5"
var apiBase = "http://api.openweathermap.org/data/"
var weatherEndpoint = "weather"
var url = apiBase + apiVersion + "/" + weatherEndpoint + this.getParams()
this.fetchData(url)
.then(data => {
Log.log(data)
if (!data || !data.main || typeof data.main.temp === "undefined") {
// Did not receive usable new data.
// Maybe this needs a better check?
return;
}
var currentWeather = this.generateWeatherDayFromCurrentWeather(data)
this.setCurrentWeather(currentWeather)
})
.catch(function(request) {
Log.error("Could not load data ... ", request)
})
},
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */
/*
* Generate a WeatherDay based on currentWeatherInformation
*/
generateWeatherDayFromCurrentWeather: function(currentWeatherData) {
var currentWeather = new WeatherDay()
currentWeather.humidity = parseFloat(currentWeatherData.main.humidity)
currentWeather.temperature = parseFloat(currentWeatherData.main.temp)
currentWeather.windSpeed = parseFloat(currentWeatherData.wind.speed)
currentWeather.windDirection = currentWeatherData.wind.deg
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.weather[0].icon)
currentWeather.sunrise = new Date(currentWeatherData.sys.sunrise * 1000)
currentWeather.sunset = new Date(currentWeatherData.sys.sunset * 1000)
return currentWeather
},
/*
* Convert the OpenWeatherMap icons to a more usable name.
*/
convertWeatherType: function(weatherType) {
var weatherTypes = {
"01d": "day-sunny",
"02d": "day-cloudy",
"03d": "cloudy",
"04d": "cloudy-windy",
"09d": "showers",
"10d": "rain",
"11d": "thunderstorm",
"13d": "snow",
"50d": "fog",
"01n": "night-clear",
"02n": "night-cloudy",
"03n": "night-cloudy",
"04n": "night-cloudy",
"09n": "night-showers",
"10n": "night-rain",
"11n": "night-thunderstorm",
"13n": "night-snow",
"50n": "night-alt-cloudy-windy"
}
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null
},
/* getParams(compliments)
* Generates an url with api parameters based on the config.
*
* return String - URL params.
*/
getParams: function() {
var params = "?";
if(this.config.locationID) {
params += "id=" + this.config.locationID;
} else if(this.config.location) {
params += "q=" + this.config.location;
} else if (this.firstEvent && this.firstEvent.geo) {
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon
} else if (this.firstEvent && this.firstEvent.location) {
params += "q=" + this.firstEvent.location;
} else {
this.hide(this.config.animationSpeed, {lockString:this.identifier});
return;
}
params += "&units=" + this.config.units;
params += "&lang=" + this.config.lang;
params += "&APPID=" + this.config.apiKey;
return params;
},
});

View File

@ -0,0 +1,62 @@
/* global Module, WeatherProvider */
/* Magic Mirror
* Module: Weather
*
* By Michael Teeuw http://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("weather",{
// Default module config.
defaults: {
foo: "bar",
weatherProvider: "openweathermap"
},
// Module properties.
weatherProvider: null,
// Return the scripts that are nessecery for the weather module.
getScripts: function () {
var scripts = [
"weatherprovider.js",
"weatherday.js"
];
// Add the provider file to the required scripts.
scripts.push(this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js"))
return scripts
},
// Start the weather module.
start: function () {
// Initialize the weather provider.
this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this)
// Let the weather provider know we are starting.
this.weatherProvider.start()
// Fetch the current weather. This is something we need to schedule.
this.weatherProvider.fetchCurrentWeather()
},
// Generate the dom. This is now pretty simple for debugging.
getDom: function() {
var wrapper = document.createElement("div")
wrapper.innerHTML += "Name: " + this.weatherProvider.providerName + "<br>"
wrapper.innerHTML += JSON.stringify(this.weatherProvider.currentWeather())
return wrapper
},
// What to do when the weather provider has new information available?
updateAvailable: function() {
Log.log("New weather information available.")
console.info(this.weatherProvider.currentWeather())
this.updateDom(0);
}
});

View File

@ -0,0 +1,24 @@
/* global Class */
/* Magic Mirror
* Module: Weather
*
* By Michael Teeuw http://michaelteeuw.nl
* MIT Licensed.
*
* This class is the blueprint for a day which includes weather information.
*/
// Currently this is focused on the information which is nessecery for the current weather.
// As soon as we start implementing the forecast, mode properties will be added.
class WeatherDay {
constructor() {
this.windSpeed = null
this.windDirection = null
this.sunrise = null
this.sunset = null
this.temperature = null
this.weatherType = null
}
};

View File

@ -0,0 +1,135 @@
/* global Class */
/* Magic Mirror
* Module: Weather
*
* By Michael Teeuw http://michaelteeuw.nl
* MIT Licensed.
*
* This class is the blueprint for a weather provider.
*/
/**
* Base BluePrint for the WeatherProvider
*/
var WeatherProvider = Class.extend({
// Weather Provider Properties
providerName: null,
// The following properties have accestor methods.
// Try to not access them directly.
currentWeatherDay: null,
weatherForecastArray: null,
// The following properties will be set automaticly.
// You do not need to overwrite these properties.
config: null,
delegate: null,
providerIdentifier: null,
// Weather Provider Methods
// All the following methods can be overwrited, although most are good as they are.
// Called when a weather provider is initialized.
init: function(config) {
this.config = config;
Log.info("Weather provider: " + this.providerName + " initialized.")
},
// Called to set the config, this config is the same as the weather module's config.
setConfig: function(config) {
this.config = config
Log.info("Weather provider: " + this.providerName + " config set.", this.config)
},
// Called when the weather provider is about to start.
start: function(config) {
Log.info("Weather provider: " + this.providerName + " started.")
},
// This method should start the API request to fetch the current weather.
// This method should definetly be overwritten in the provider.
fetchCurrentWeather: function() {
Log.warn("Weather provider: " + this.providerName + " does not subclass the fetchCurrentWeather method.")
},
// This method should start the API request to fetch the weather forecast.
// This method should definetly be overwritten in the provider.
fetchWeatherForeCast: function() {
Log.warn("Weather provider: " + this.providerName + " does not subclass the fetchWeatherForeCast method.")
},
// This returns a WeatherDay object for the current weather.
currentWeather: function() {
return this.currentWeatherDay
},
// This returns an array of WeatherDay objects for the weather forecast.
weatherForecast: function() {
return this.weatherForecastArray
},
// Set the currentWeather and notify the delegate that new information is availabe.
setCurrentWeather: function(currentWeatherDay) {
// We should check here if we are passing a WeatherDay
this.currentWeatherDay = currentWeatherDay
this.updateAvailable()
},
// Notify the delegate that new weather is available.
updateAvailable: function() {
this.delegate.updateAvailable(this)
},
// A convinience function to make requests. It returns a promise.
fetchData: function(url, method = "GET", data = null) {
return new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();
request.open(method, url, true);
request.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
resolve(JSON.parse(this.response));
} else {
reject(request)
}
}
};
request.send();
})
}
});
/**
* Collection of registered weather providers.
*/
WeatherProvider.providers = []
/**
* Static method to register a new weather provider.
*/
WeatherProvider.register = function(providerIdentifier, providerDetails) {
WeatherProvider.providers[providerIdentifier.toLowerCase()] = WeatherProvider.extend(providerDetails)
}
/**
* Static method to initialize a new weather provider.
*/
WeatherProvider.initialize = function(providerIdentifier, delegate) {
providerIdentifier = providerIdentifier.toLowerCase()
var provider = new WeatherProvider.providers[providerIdentifier]()
provider.delegate = delegate
provider.setConfig(delegate.config)
provider.providerIdentifier = providerIdentifier;
if (!provider.providerName) {
provider.providerName = providerIdentifier
}
return provider;
}