From 713111254b3241b63b1178872dc670611a068c7c Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Fri, 22 Sep 2017 12:26:47 +0200 Subject: [PATCH] First implementation of the currentWeatherView --- .../weather/providers/openweathermap.js | 24 ++-- modules/default/weather/weather.css | 46 ++++++++ modules/default/weather/weather.js | 103 ++++++++++++++++-- modules/default/weather/weatherday.js | 24 ---- modules/default/weather/weatherobject.js | 60 ++++++++++ modules/default/weather/weatherprovider.js | 8 +- 6 files changed, 213 insertions(+), 52 deletions(-) create mode 100644 modules/default/weather/weather.css delete mode 100644 modules/default/weather/weatherday.js create mode 100644 modules/default/weather/weatherobject.js diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index 4f3651a6..edc27657 100644 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherDay */ +/* global WeatherProvider, WeatherObject */ /* Magic Mirror * Module: Weather @@ -34,7 +34,7 @@ WeatherProvider.register("openweathermap", { return; } - var currentWeather = this.generateWeatherDayFromCurrentWeather(data) + var currentWeather = this.generateWeatherObjectFromCurrentWeather(data) this.setCurrentWeather(currentWeather) }) .catch(function(request) { @@ -47,18 +47,18 @@ WeatherProvider.register("openweathermap", { /* - * Generate a WeatherDay based on currentWeatherInformation + * Generate a WeatherObject based on currentWeatherInformation */ - generateWeatherDayFromCurrentWeather: function(currentWeatherData) { - var currentWeather = new WeatherDay() + generateWeatherObjectFromCurrentWeather: function(currentWeatherData) { + var currentWeather = new WeatherObject() - 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) + currentWeather.humidity = currentWeatherData.main.humidity ? parseFloat(currentWeatherData.main.humidity) : null + currentWeather.temperature = currentWeatherData.main.temp ? parseFloat(currentWeatherData.main.temp) : null + currentWeather.windSpeed = currentWeatherData.wind.speed ? parseFloat(currentWeatherData.wind.speed) : null + currentWeather.windDirection = currentWeatherData.wind.deg ? currentWeatherData.wind.deg : null + currentWeather.weatherType = currentWeatherData.weather[0].icon ? this.convertWeatherType(currentWeatherData.weather[0].icon) : null + currentWeather.sunrise = currentWeatherData.sys.sunrise ? new Date(currentWeatherData.sys.sunrise * 1000) : null + currentWeather.sunset = currentWeatherData.sys.sunset ? new Date(currentWeatherData.sys.sunset * 1000) : null return currentWeather }, diff --git a/modules/default/weather/weather.css b/modules/default/weather/weather.css new file mode 100644 index 00000000..febc777c --- /dev/null +++ b/modules/default/weather/weather.css @@ -0,0 +1,46 @@ +.weather .weathericon, +.weather .fa-home { + font-size: 75%; + line-height: 65px; + display: inline-block; + -ms-transform: translate(0, -3px); /* IE 9 */ + -webkit-transform: translate(0, -3px); /* Safari */ + transform: translate(0, -3px); +} + +.weather .humidityIcon { + padding-right: 4px; +} + +.weather .humidity-padding { + padding-bottom: 6px; +} + + +.weather .day { + padding-left: 0; + padding-right: 25px; +} + +.weather .weather-icon { + padding-right: 30px; + text-align: center; +} + +.weather .min-temp { + padding-left: 20px; + padding-right: 0; +} + +.weather .rain { + padding-left: 20px; + padding-right: 0; +} + +.weather tr.colored .min-temp { + color: #BCDDFF; +} + +.weather tr.colored .max-temp { + color: #FF8E99; +} diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index 2be3ff0b..a5c410b2 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -11,18 +11,25 @@ Module.register("weather",{ // Default module config. defaults: { - foo: "bar", - weatherProvider: "openweathermap" + updateInterval: 10 * 60 * 1000, + weatherProvider: "openweathermap", + units: config.units, + roundTemp: false }, // Module properties. weatherProvider: null, + // Define required scripts. + getStyles: function() { + return ["weather-icons.css", "weather.css"]; + }, + // Return the scripts that are nessecery for the weather module. getScripts: function () { var scripts = [ "weatherprovider.js", - "weatherday.js" + "weatherobject.js" ]; // Add the provider file to the required scripts. @@ -39,24 +46,96 @@ Module.register("weather",{ // 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() + // Schedule the first update. + this.scheduleUpdate(0) }, // Generate the dom. This is now pretty simple for debugging. getDom: function() { - var wrapper = document.createElement("div") - - wrapper.innerHTML += "Name: " + this.weatherProvider.providerName + "
" - wrapper.innerHTML += JSON.stringify(this.weatherProvider.currentWeather()) - - return wrapper + return this.currentWeatherView(this.weatherProvider.currentWeather()) }, // 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); + this.updateDom(0) + this.scheduleUpdate() + }, + + scheduleUpdate: function(delay = null) { + var nextLoad = this.config.updateInterval; + if (delay !== null && delay >= 0) { + nextLoad = delay; + } + + setTimeout(() => { + // Currently we are fetching the currentWeather. + // In the future, it depends what we want to show. + // So there needs to be some logic here... + // if config.weatherType == 'current', do this... + // if config.weatherType === 'forecast, do that ... + this.weatherProvider.fetchCurrentWeather() + }, nextLoad); + }, + + /* Views */ + + // Generate the current weather view + currentWeatherView: function (currentWeather) { + var wrapper = document.createElement("div") + + if (currentWeather === null) { + return wrapper + } + + // Detail bar. + + var detailBar = document.createElement("div") + + this.addValueToWrapper(detailBar, null, "wi wi-strong-wind dimmed", "span", true) // Wind Icon + this.addValueToWrapper(detailBar, currentWeather.windSpeed ? Math.round(currentWeather.windSpeed) : null) // WindSpeed + this.addValueToWrapper(detailBar, currentWeather.windDirection ? this.translate(currentWeather.cardinalWindDirection()) + "  " : null, "", "sup") // WindDirection + + var now = new Date(); + var sunriseSunsetTime = (currentWeather.sunrise < now && currentWeather.sunset > now) ? currentWeather.sunset : currentWeather.sunrise + var sunriseSunsetIcon = (currentWeather.sunrise < now && currentWeather.sunset > now) ? "wi-sunset" : "wi-sunrise" + this.addValueToWrapper(detailBar, null, "wi dimmed " + sunriseSunsetIcon, "span", true) // Sunrise / Sunset Icon + this.addValueToWrapper(detailBar, moment(sunriseSunsetTime).format("HH:mm")) // Sunrise / Sunset Time + + detailBar.className = "normal medium" + wrapper.appendChild(detailBar) + + // Main info + + var mainInfo = document.createElement("div") + + this.addValueToWrapper(mainInfo, null, "weathericon wi wi-" + currentWeather.weatherType, "span", true) // Wind Icon + this.addValueToWrapper(mainInfo, parseFloat(currentWeather.temperature).toFixed(this.config.roundTemp ? 0 : 1) + "°", "bright" ) // WindSpeed + + mainInfo.className = "large light" + wrapper.appendChild(mainInfo) + + return wrapper + }, + + // A convenience function to add an element to a wrapper with a specific value and class. + addValueToWrapper: function(wrapper, value, classNames, element = "span", forceAdd = false, addSpacer = true) { + if (value === null && !forceAdd) { + return + } + + var valueWrapper = document.createElement(element) + valueWrapper.className = classNames + if (addSpacer) { + valueWrapper.innerHTML = " " + } + + if (value !== null) { + valueWrapper.innerHTML += value + } + + wrapper.appendChild(valueWrapper) } + }); diff --git a/modules/default/weather/weatherday.js b/modules/default/weather/weatherday.js deleted file mode 100644 index c8f63057..00000000 --- a/modules/default/weather/weatherday.js +++ /dev/null @@ -1,24 +0,0 @@ -/* 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 - } -}; \ No newline at end of file diff --git a/modules/default/weather/weatherobject.js b/modules/default/weather/weatherobject.js new file mode 100644 index 00000000..2525eb6e --- /dev/null +++ b/modules/default/weather/weatherobject.js @@ -0,0 +1,60 @@ +/* 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 WeatherObject { + constructor() { + this.windSpeed = null + this.windDirection = null + this.sunrise = null + this.sunset = null + this.temperature = null + this.weatherType = null + } + + cardinalWindDirection () { + if (this.windDirection>11.25 && this.windDirection<=33.75){ + return "NNE"; + } else if (this.windDirection > 33.75 && this.windDirection <= 56.25) { + return "NE"; + } else if (this.windDirection > 56.25 && this.windDirection <= 78.75) { + return "ENE"; + } else if (this.windDirection > 78.75 && this.windDirection <= 101.25) { + return "E"; + } else if (this.windDirection > 101.25 && this.windDirection <= 123.75) { + return "ESE"; + } else if (this.windDirection > 123.75 && this.windDirection <= 146.25) { + return "SE"; + } else if (this.windDirection > 146.25 && this.windDirection <= 168.75) { + return "SSE"; + } else if (this.windDirection > 168.75 && this.windDirection <= 191.25) { + return "S"; + } else if (this.windDirection > 191.25 && this.windDirection <= 213.75) { + return "SSW"; + } else if (this.windDirection > 213.75 && this.windDirection <= 236.25) { + return "SW"; + } else if (this.windDirection > 236.25 && this.windDirection <= 258.75) { + return "WSW"; + } else if (this.windDirection > 258.75 && this.windDirection <= 281.25) { + return "W"; + } else if (this.windDirection > 281.25 && this.windDirection <= 303.75) { + return "WNW"; + } else if (this.windDirection > 303.75 && this.windDirection <= 326.25) { + return "NW"; + } else if (this.windDirection > 326.25 && this.windDirection <= 348.75) { + return "NNW"; + } else { + return "N"; + } + } +}; \ No newline at end of file diff --git a/modules/default/weather/weatherprovider.js b/modules/default/weather/weatherprovider.js index 08489aeb..a7ca4cba 100644 --- a/modules/default/weather/weatherprovider.js +++ b/modules/default/weather/weatherprovider.js @@ -19,7 +19,7 @@ var WeatherProvider = Class.extend({ // The following properties have accestor methods. // Try to not access them directly. - currentWeatherDay: null, + currentWeatherObject: null, weatherForecastArray: null, // The following properties will be set automaticly. @@ -63,7 +63,7 @@ var WeatherProvider = Class.extend({ // This returns a WeatherDay object for the current weather. currentWeather: function() { - return this.currentWeatherDay + return this.currentWeatherObject }, // This returns an array of WeatherDay objects for the weather forecast. @@ -72,9 +72,9 @@ var WeatherProvider = Class.extend({ }, // Set the currentWeather and notify the delegate that new information is availabe. - setCurrentWeather: function(currentWeatherDay) { + setCurrentWeather: function(currentWeatherObject) { // We should check here if we are passing a WeatherDay - this.currentWeatherDay = currentWeatherDay + this.currentWeatherObject = currentWeatherObject this.updateAvailable() },