346 lines
9.9 KiB
JavaScript
Raw Normal View History

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,
showPeriod: true,
showPeriodUpper: false,
2016-05-11 09:25:16 +02:00
showWindDirection: true,
2016-05-03 19:14:27 -05:00
useBeaufort: 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
},
2016-05-11 12:38:41 +02:00
// Define required translations.
getTranslations: function() {
// The translations for the defaut modules are defined in the core translation files.
// Therefor we can just return false. Otherwise we should have returned a dictionairy.
// If you're trying to build yiur own module including translations, check out the documentation.
return false;
},
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-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-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) {
2016-05-11 12:38:41 +02:00
wrapper.innerHTML = this.translate('LOADING');
2016-03-29 13:28:15 +02:00
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-05-11 12:38:41 +02:00
2016-03-29 13:28:15 +02:00
var windSpeed = document.createElement("span");
windSpeed.innerHTML = " " + this.windSpeed;
2016-03-29 13:28:15 +02:00
small.appendChild(windSpeed);
2016-05-11 12:38:41 +02:00
2016-04-24 18:34:39 -05:00
if (this.config.showWindDirection) {
2016-04-24 17:40:18 -05:00
var windDirection = document.createElement("span");
2016-05-11 12:38:41 +02:00
windDirection.innerHTML = " " + this.translate(this.windDirection);
2016-04-24 17:40:18 -05:00
small.appendChild(windDirection);
}
2016-03-29 13:28:15 +02:00
var spacer = document.createElement("span");
spacer.innerHTML = "&nbsp;";
small.appendChild(spacer);
var sunriseSunsetIcon = document.createElement("span");
sunriseSunsetIcon.className = "wi dimmed " + this.sunriseSunsetIcon;
small.appendChild(sunriseSunsetIcon);
var sunriseSunsetTime = document.createElement("span");
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 + "&deg;";
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);
2016-05-11 12:38:41 +02:00
2016-05-03 19:14:27 -05:00
if (this.config.useBeaufort){
this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed));
}else {
this.windSpeed = parseFloat(data.wind.speed).toFixed(0);
}
2016-05-11 12:38:41 +02:00
2016-05-03 19:14:27 -05:00
this.windDirection = this.deg2Cardinal(data.wind.deg);
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);
2016-05-11 12:38:41 +02:00
// The moment().format('h') method has a bug on the Raspberry Pi.
2016-04-18 19:12:24 +02:00
// 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) {
2016-05-10 16:18:35 +02:00
//var hours = sunriseSunsetDateObject.getHours() % 12 || 12;
if (this.config.showPeriod) {
if (this.config.showPeriodUpper) {
2016-05-10 16:18:35 +02:00
//timeString = hours + moment(sunriseSunsetDateObject).format(':mm A');
timeString = moment(sunriseSunsetDateObject).format('h:mm A');
} else {
2016-05-10 16:18:35 +02:00
//timeString = hours + moment(sunriseSunsetDateObject).format(':mm a');
timeString = moment(sunriseSunsetDateObject).format('h:mm a');
}
} else {
2016-05-10 16:18:35 +02:00
//timeString = hours + moment(sunriseSunsetDateObject).format(':mm');
timeString = moment(sunriseSunsetDateObject).format('h: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-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-05-11 12:38:41 +02:00
2016-04-24 16:55:39 -05:00
deg2Cardinal: function(deg) {
2016-05-11 09:25:16 +02:00
if (deg>11.25 && deg<=33.75){
2016-04-24 16:15:05 -05:00
return "NNE";
2016-05-11 09:25:16 +02:00
} else if (deg > 33.75 && deg <= 56.25) {
2016-04-24 16:15:05 -05:00
return "ENE";
2016-05-11 09:25:16 +02:00
} else if (deg > 56.25 && deg <= 78.75) {
2016-04-24 16:15:05 -05:00
return "E";
2016-05-11 09:25:16 +02:00
} else if (deg > 78.75 && deg <= 101.25) {
2016-04-24 16:15:05 -05:00
return "ESE";
2016-05-11 09:25:16 +02:00
} else if (deg > 101.25 && deg <= 123.75) {
2016-04-24 16:15:05 -05:00
return "ESE";
2016-05-11 09:25:16 +02:00
} else if (deg > 123.75 && deg <= 146.25) {
2016-04-24 16:15:05 -05:00
return "SE";
2016-05-11 09:25:16 +02:00
} else if (deg > 146.25 && deg <= 168.75) {
2016-04-24 16:15:05 -05:00
return "SSE";
2016-05-11 09:25:16 +02:00
} else if (deg > 168.75 && deg <= 191.25) {
2016-04-24 16:15:05 -05:00
return "S";
2016-05-11 09:25:16 +02:00
} else if (deg > 191.25 && deg <= 213.75) {
2016-04-24 16:15:05 -05:00
return "SSW";
2016-05-11 09:25:16 +02:00
} else if (deg > 213.75 && deg <= 236.25) {
2016-04-24 16:15:05 -05:00
return "SW";
2016-05-11 09:25:16 +02:00
} else if (deg > 236.25 && deg <= 258.75) {
2016-04-24 16:15:05 -05:00
return "WSW";
2016-05-11 09:25:16 +02:00
} else if (deg > 258.75 && deg <= 281.25) {
2016-04-24 16:15:05 -05:00
return "W";
2016-05-11 09:25:16 +02:00
} else if (deg > 281.25 && deg <= 303.75) {
2016-04-24 16:15:05 -05:00
return "WNW";
2016-05-11 09:25:16 +02:00
} else if (deg > 303.75 && deg <= 326.25) {
2016-04-24 16:15:05 -05:00
return "NW";
2016-05-11 09:25:16 +02:00
} else if (deg > 326.25 && deg <= 348.75) {
2016-04-24 16:15:05 -05:00
return "NNW";
2016-05-11 09:25:16 +02:00
} else {
2016-04-24 16:15:05 -05:00
return "N";
}
2016-04-24 17:40:18 -05:00
},
2016-04-24 16:15:05 -05:00
2016-05-11 12:38:41 +02: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);
}
});