2016-03-29 13:28:15 +02:00
|
|
|
/* global Module */
|
|
|
|
|
|
|
|
/* Magic Mirror
|
|
|
|
* Module: CurrentWeather
|
|
|
|
*
|
|
|
|
* By Michael Teeuw http://michaelteeuw.nl
|
|
|
|
* MIT Licensed.
|
|
|
|
*/
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
Module.register("currentweather",{
|
2016-03-29 13:28:15 +02:00
|
|
|
|
|
|
|
// Default module config.
|
|
|
|
defaults: {
|
2016-04-05 14:35:11 -04:00
|
|
|
location: "",
|
|
|
|
appid: "",
|
2016-04-24 15:25:35 -05:00
|
|
|
units: config.units,
|
2016-04-05 14:35:11 -04:00
|
|
|
updateInterval: 10 * 60 * 1000, // every 10 minutes
|
|
|
|
animationSpeed: 1000,
|
|
|
|
timeFormat: config.timeFormat,
|
2016-04-18 19:53:34 -04:00
|
|
|
showPeriod: true,
|
|
|
|
showPeriodUpper: false,
|
2016-04-24 17:40:18 -05:00
|
|
|
showDirection: true,
|
2016-03-29 13:28:15 +02:00
|
|
|
lang: config.language,
|
|
|
|
|
|
|
|
initialLoadDelay: 0, // 0 seconds delay
|
|
|
|
retryDelay: 2500,
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
apiVersion: "2.5",
|
|
|
|
apiBase: "http://api.openweathermap.org/data/",
|
|
|
|
weatherEndpoint: "weather",
|
2016-03-29 13:28:15 +02:00
|
|
|
|
|
|
|
iconTable: {
|
2016-04-05 14:35:11 -04:00
|
|
|
"01d": "wi-day-sunny",
|
|
|
|
"02d": "wi-day-cloudy",
|
|
|
|
"03d": "wi-cloudy",
|
|
|
|
"04d": "wi-cloudy-windy",
|
|
|
|
"09d": "wi-showers",
|
|
|
|
"10d": "wi-rain",
|
|
|
|
"11d": "wi-thunderstorm",
|
|
|
|
"13d": "wi-snow",
|
|
|
|
"50d": "wi-fog",
|
|
|
|
"01n": "wi-night-clear",
|
|
|
|
"02n": "wi-night-cloudy",
|
|
|
|
"03n": "wi-night-cloudy",
|
|
|
|
"04n": "wi-night-cloudy",
|
|
|
|
"09n": "wi-night-showers",
|
|
|
|
"10n": "wi-night-rain",
|
|
|
|
"11n": "wi-night-thunderstorm",
|
|
|
|
"13n": "wi-night-snow",
|
|
|
|
"50n": "wi-night-alt-cloudy-windy"
|
2016-03-29 13:28:15 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Define required scripts.
|
|
|
|
getScripts: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
return ["moment.js"];
|
2016-03-29 13:28:15 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Define required scripts.
|
|
|
|
getStyles: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
return ["weather-icons.css", "currentweather.css"];
|
2016-03-29 13:28:15 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Define start sequence.
|
|
|
|
start: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
Log.info("Starting module: " + this.name);
|
2016-03-29 13:28:15 +02:00
|
|
|
|
|
|
|
// Set locale.
|
|
|
|
moment.locale(config.language);
|
2016-04-03 19:52:13 +02:00
|
|
|
|
2016-03-29 13:28:15 +02:00
|
|
|
this.windSpeed = null;
|
2016-04-24 16:15:05 -05:00
|
|
|
this.windDirection = null;
|
2016-03-29 13:28:15 +02:00
|
|
|
this.sunriseSunsetTime = null;
|
|
|
|
this.sunriseSunsetIcon = null;
|
|
|
|
this.temperature = null;
|
|
|
|
this.weatherType = null;
|
|
|
|
|
|
|
|
this.loaded = false;
|
|
|
|
this.scheduleUpdate(this.config.initialLoadDelay);
|
|
|
|
|
|
|
|
this.updateTimer = null;
|
2016-04-03 19:52:13 +02:00
|
|
|
|
2016-03-29 13:28:15 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Override dom generator.
|
|
|
|
getDom: function() {
|
|
|
|
var wrapper = document.createElement("div");
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
if (this.config.appid === "") {
|
2016-03-29 13:28:15 +02:00
|
|
|
wrapper.innerHTML = "Please set the correct openweather <i>appid</i> in the config for module: " + this.name + ".";
|
|
|
|
wrapper.className = "dimmed light small";
|
|
|
|
return wrapper;
|
|
|
|
}
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
if (this.config.location === "") {
|
2016-03-29 13:28:15 +02:00
|
|
|
wrapper.innerHTML = "Please set the openweather <i>location</i> in the config for module: " + this.name + ".";
|
|
|
|
wrapper.className = "dimmed light small";
|
|
|
|
return wrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.loaded) {
|
|
|
|
wrapper.innerHTML = "Loading weather ...";
|
|
|
|
wrapper.className = "dimmed light small";
|
|
|
|
return wrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
var small = document.createElement("div");
|
|
|
|
small.className = "normal medium";
|
|
|
|
|
|
|
|
var windIcon = document.createElement("span");
|
|
|
|
windIcon.className = "wi wi-strong-wind dimmed";
|
|
|
|
small.appendChild(windIcon);
|
2016-04-24 17:40:18 -05:00
|
|
|
|
2016-03-29 13:28:15 +02:00
|
|
|
var windSpeed = document.createElement("span");
|
2016-04-03 19:52:13 +02:00
|
|
|
windSpeed.innerHTML = " " + this.windSpeed;
|
2016-03-29 13:28:15 +02:00
|
|
|
small.appendChild(windSpeed);
|
2016-04-24 16:15:05 -05:00
|
|
|
|
2016-04-24 17:40:18 -05:00
|
|
|
if (this.showDirection) {
|
|
|
|
var windDirection = document.createElement("span");
|
|
|
|
windDirection.innerHTML = " " + this.windDirection;
|
|
|
|
small.appendChild(windDirection);
|
|
|
|
}
|
|
|
|
|
2016-03-29 13:28:15 +02:00
|
|
|
var spacer = document.createElement("span");
|
|
|
|
spacer.innerHTML = " ";
|
|
|
|
small.appendChild(spacer);
|
|
|
|
|
|
|
|
var sunriseSunsetIcon = document.createElement("span");
|
|
|
|
sunriseSunsetIcon.className = "wi dimmed " + this.sunriseSunsetIcon;
|
|
|
|
small.appendChild(sunriseSunsetIcon);
|
|
|
|
|
|
|
|
var sunriseSunsetTime = document.createElement("span");
|
2016-04-03 19:52:13 +02:00
|
|
|
sunriseSunsetTime.innerHTML = " " + this.sunriseSunsetTime;
|
2016-03-29 13:28:15 +02:00
|
|
|
small.appendChild(sunriseSunsetTime);
|
|
|
|
|
|
|
|
var large = document.createElement("div");
|
|
|
|
large.className = "large light";
|
|
|
|
|
|
|
|
var weatherIcon = document.createElement("span");
|
|
|
|
weatherIcon.className = "wi weathericon " + this.weatherType;
|
|
|
|
large.appendChild(weatherIcon);
|
|
|
|
|
|
|
|
var temperature = document.createElement("span");
|
|
|
|
temperature.className = "bright";
|
2016-04-05 14:35:11 -04:00
|
|
|
temperature.innerHTML = " " + this.temperature + "°";
|
2016-03-29 13:28:15 +02:00
|
|
|
large.appendChild(temperature);
|
|
|
|
|
|
|
|
wrapper.appendChild(small);
|
|
|
|
wrapper.appendChild(large);
|
|
|
|
return wrapper;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* updateWeather(compliments)
|
|
|
|
* Requests new data from openweather.org.
|
|
|
|
* Calls processWeather on succesfull response.
|
|
|
|
*/
|
|
|
|
updateWeather: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
var url = this.config.apiBase + this.config.apiVersion + "/" + this.config.weatherEndpoint + this.getParams();
|
2016-03-29 13:28:15 +02:00
|
|
|
var self = this;
|
|
|
|
var retry = true;
|
|
|
|
|
|
|
|
var weatherRequest = new XMLHttpRequest();
|
|
|
|
weatherRequest.open("GET", url, true);
|
|
|
|
weatherRequest.onreadystatechange = function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
if (this.readyState === 4) {
|
|
|
|
if (this.status === 200) {
|
|
|
|
self.processWeather(JSON.parse(this.response));
|
|
|
|
} else if (this.status === 401) {
|
|
|
|
self.config.appid = "";
|
|
|
|
self.updateDom(self.config.animationSpeed);
|
|
|
|
|
|
|
|
Log.error(self.name + ": Incorrect APPID.");
|
|
|
|
retry = false;
|
|
|
|
} else {
|
|
|
|
Log.error(self.name + ": Could not load weather.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retry) {
|
|
|
|
self.scheduleUpdate((self.loaded) ? -1 : self.config.retryDelay);
|
|
|
|
}
|
2016-03-29 13:28:15 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
weatherRequest.send();
|
|
|
|
},
|
|
|
|
|
|
|
|
/* getParams(compliments)
|
|
|
|
* Generates an url with api parameters based on the config.
|
|
|
|
*
|
|
|
|
* return String - URL params.
|
|
|
|
*/
|
|
|
|
getParams: function() {
|
|
|
|
var params = "?";
|
2016-04-05 14:35:11 -04:00
|
|
|
params += "q=" + this.config.location;
|
|
|
|
params += "&units=" + this.config.units;
|
|
|
|
params += "&lang=" + this.config.lang;
|
|
|
|
params += "&APPID=" + this.config.appid;
|
2016-03-29 13:28:15 +02:00
|
|
|
|
|
|
|
return params;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* processWeather(data)
|
|
|
|
* Uses the received data to set the various values.
|
|
|
|
*
|
|
|
|
* argument data object - Weather information received form openweather.org.
|
|
|
|
*/
|
|
|
|
processWeather: function(data) {
|
|
|
|
this.temperature = this.roundValue(data.main.temp);
|
|
|
|
this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed));
|
2016-04-24 16:15:05 -05:00
|
|
|
if (this.showDirection) {
|
|
|
|
this.windDirection = this.deg2Cardinal(data.wind.deg);
|
|
|
|
} else {}
|
2016-03-29 13:28:15 +02:00
|
|
|
this.weatherType = this.config.iconTable[data.weather[0].icon];
|
|
|
|
|
2016-04-18 19:12:24 +02:00
|
|
|
var now = new Date();
|
|
|
|
var sunrise = new Date(data.sys.sunrise * 1000);
|
|
|
|
var sunset = new Date(data.sys.sunset * 1000);
|
|
|
|
|
|
|
|
// The moment().format('h') method has a bug on the Raspberry Pi.
|
|
|
|
// So we need to generate the timestring manually.
|
|
|
|
// See issue: https://github.com/MichMich/MagicMirror/issues/181
|
|
|
|
var sunriseSunsetDateObject = (sunrise < now && sunset > now) ? sunset : sunrise;
|
|
|
|
var timeString = moment(sunriseSunsetDateObject).format('HH:mm');
|
|
|
|
if (this.config.timeFormat !== 24) {
|
|
|
|
var hours = sunriseSunsetDateObject.getHours() % 12 || 12;
|
2016-04-18 19:53:34 -04:00
|
|
|
if (this.config.showPeriod) {
|
|
|
|
if (this.config.showPeriodUpper) {
|
|
|
|
timeString = hours + moment(sunriseSunsetDateObject).format(':mm A');
|
|
|
|
} else {
|
|
|
|
timeString = hours + moment(sunriseSunsetDateObject).format(':mm a');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
timeString = hours + moment(sunriseSunsetDateObject).format(':mm');
|
|
|
|
}
|
2016-03-29 13:28:15 +02:00
|
|
|
}
|
|
|
|
|
2016-04-18 19:12:24 +02:00
|
|
|
this.sunriseSunsetTime = timeString;
|
|
|
|
this.sunriseSunsetIcon = (sunrise < now && sunset > now) ? "wi-sunset" : "wi-sunrise";
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-03-29 13:28:15 +02:00
|
|
|
this.loaded = true;
|
|
|
|
this.updateDom(this.config.animationSpeed);
|
|
|
|
},
|
|
|
|
|
|
|
|
/* scheduleUpdate()
|
|
|
|
* Schedule next update.
|
|
|
|
*
|
|
|
|
* argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
|
|
|
|
*/
|
|
|
|
scheduleUpdate: function(delay) {
|
|
|
|
var nextLoad = this.config.updateInterval;
|
2016-04-05 14:35:11 -04:00
|
|
|
if (typeof delay !== "undefined" && delay >= 0) {
|
2016-03-29 13:28:15 +02:00
|
|
|
nextLoad = delay;
|
2016-04-03 19:52:13 +02:00
|
|
|
}
|
2016-03-29 13:28:15 +02:00
|
|
|
|
|
|
|
var self = this;
|
|
|
|
setTimeout(function() {
|
|
|
|
self.updateWeather();
|
|
|
|
}, nextLoad);
|
|
|
|
},
|
|
|
|
|
|
|
|
/* ms2Beaufort(ms)
|
|
|
|
* Converts m2 to beaufort (windspeed).
|
|
|
|
*
|
|
|
|
* argument ms number - Windspeed in m/s.
|
|
|
|
*
|
|
|
|
* return number - Windspeed in beaufort.
|
|
|
|
*/
|
|
|
|
ms2Beaufort: function(ms) {
|
|
|
|
var kmh = ms * 60 * 60 / 1000;
|
|
|
|
var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
|
|
|
|
for (var beaufort in speeds) {
|
|
|
|
var speed = speeds[beaufort];
|
|
|
|
if (speed > kmh) {
|
|
|
|
return beaufort;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 12;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* function(temperature)
|
|
|
|
* Rounds a temperature to 1 decimal.
|
|
|
|
*
|
|
|
|
* argument temperature number - Temperature.
|
|
|
|
*
|
|
|
|
* return number - Rounded Temperature.
|
|
|
|
*/
|
2016-04-24 16:15:05 -05:00
|
|
|
|
2016-04-24 16:55:39 -05:00
|
|
|
deg2Cardinal: function(deg) {
|
2016-04-24 16:15:05 -05:00
|
|
|
if (deg>11.25 && deg<33.75){
|
|
|
|
return "NNE";
|
|
|
|
}else if (deg>33.75 && deg<56.25){
|
|
|
|
return "ENE";
|
|
|
|
}else if (deg>56.25 && deg<78.75){
|
|
|
|
return "E";
|
|
|
|
}else if (deg>78.75 && deg<101.25){
|
|
|
|
return "ESE";
|
|
|
|
}else if (deg>101.25 && deg<123.75){
|
|
|
|
return "ESE";
|
|
|
|
}else if (deg>123.75 && deg<146.25){
|
|
|
|
return "SE";
|
|
|
|
}else if (deg>146.25 && deg<168.75){
|
|
|
|
return "SSE";
|
|
|
|
}else if (deg>168.75 && deg<191.25){
|
|
|
|
return "S";
|
|
|
|
}else if (deg>191.25 && deg<213.75){
|
|
|
|
return "SSW";
|
|
|
|
}else if (deg>213.75 && deg<236.25){
|
|
|
|
return "SW";
|
|
|
|
}else if (deg>236.25 && deg<258.75){
|
|
|
|
return "WSW";
|
|
|
|
}else if (deg>258.75 && deg<281.25){
|
|
|
|
return "W";
|
|
|
|
}else if (deg>281.25 && deg<303.75){
|
|
|
|
return "WNW";
|
|
|
|
}else if (deg>303.75 && deg<326.25){
|
|
|
|
return "NW";
|
|
|
|
}else if (deg>326.25 && deg<348.75){
|
|
|
|
return "NNW";
|
|
|
|
}else{
|
|
|
|
return "N";
|
|
|
|
}
|
2016-04-24 17:40:18 -05:00
|
|
|
},
|
2016-04-24 16:15:05 -05:00
|
|
|
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
roundValue: function(temperature) {
|
2016-03-29 13:28:15 +02:00
|
|
|
return parseFloat(temperature).toFixed(1);
|
|
|
|
}
|
|
|
|
});
|