diff --git a/CHANGELOG.md b/CHANGELOG.md index 92864bc48b..a1f013121b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Special thanks to: @rejas, @sdetweil - Updated da translation - Rework weather module - Use fetch instead of XMLHttpRequest in weatherprovider + - Reworked how weatherproviders handle units - Use unix() method for parsing times, fix suntimes on the way ### Fixed diff --git a/modules/default/weather/current.njk b/modules/default/weather/current.njk index bfeb0b8f13..ae542caa9a 100644 --- a/modules/default/weather/current.njk +++ b/modules/default/weather/current.njk @@ -3,15 +3,7 @@
- {% if config.useBeaufort %} - {{ current.beaufortWindSpeed() | round }} - {% else %} - {% if config.useKmh %} - {{ current.kmhWindSpeed() | round }} - {% else %} - {{ current.windSpeed | round }} - {% endif %} - {% endif %} + {{ current.windSpeed | unit("wind") | round }} {% if config.showWindDirection %} {% if config.showWindDirectionAsArrow %} diff --git a/modules/default/weather/providers/darksky.js b/modules/default/weather/providers/darksky.js index b5bf20e3b2..aa48a12bd8 100644 --- a/modules/default/weather/providers/darksky.js +++ b/modules/default/weather/providers/darksky.js @@ -26,11 +26,6 @@ WeatherProvider.register("darksky", { lon: 0 }, - units: { - imperial: "us", - metric: "si" - }, - fetchCurrentWeather() { this.fetchData(this.getUrl()) .then((data) => { @@ -67,13 +62,12 @@ WeatherProvider.register("darksky", { // Create a URL from the config and base URL. getUrl() { - const units = this.units[this.config.units] || "auto"; - return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=${units}&lang=${this.config.lang}`; + return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=si&lang=${this.config.lang}`; }, // Implement WeatherDay generator. generateWeatherDayFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const currentWeather = new WeatherObject(); currentWeather.date = moment(); currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity); @@ -91,7 +85,7 @@ WeatherProvider.register("darksky", { const days = []; for (const forecast of forecasts) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const weather = new WeatherObject(); weather.date = moment.unix(forecast.time); weather.minTemperature = forecast.temperatureMin; diff --git a/modules/default/weather/providers/envcanada.js b/modules/default/weather/providers/envcanada.js index 0d3e34ae95..fdea195bf0 100644 --- a/modules/default/weather/providers/envcanada.js +++ b/modules/default/weather/providers/envcanada.js @@ -11,13 +11,13 @@ * https://dd.weather.gc.ca/citypage_weather/schema/ * https://eccc-msc.github.io/open-data/msc-datamart/readme_en/ * - * This module supports Canadian locations only and requires 2 additional config parms: + * This module supports Canadian locations only and requires 2 additional config parameters: * * siteCode - the city/town unique identifier for which weather is to be displayed. Format is 's0000000'. * * provCode - the 2-character province code for the selected city/town. * - * Example: for Toronto, Ontario, the following parms would be used + * Example: for Toronto, Ontario, the following parameters would be used * * siteCode: 's0000458', * provCode: 'ON' @@ -64,10 +64,6 @@ WeatherProvider.register("envcanada", { start: function () { Log.info(`Weather provider: ${this.providerName} started.`); this.setFetchedLocation(this.config.location); - - // Ensure kmH are ignored since these are custom-handled by this Provider - - this.config.useKmh = false; }, // @@ -150,7 +146,7 @@ WeatherProvider.register("envcanada", { // generateWeatherObjectFromCurrentWeather(ECdoc) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(); // There are instances where EC will update weather data and current temperature will not be // provided. While this is a defect in the EC systems, we need to accommodate to avoid a current temp @@ -161,13 +157,13 @@ WeatherProvider.register("envcanada", { // EC finds no current temp. In this scenario, MM will end up displaying a current temp of null; if (ECdoc.querySelector("siteData currentConditions temperature").textContent) { - currentWeather.temperature = this.convertTemp(ECdoc.querySelector("siteData currentConditions temperature").textContent); + currentWeather.temperature = ECdoc.querySelector("siteData currentConditions temperature").textContent; this.cacheCurrentTemp = currentWeather.temperature; } else { currentWeather.temperature = this.cacheCurrentTemp; } - currentWeather.windSpeed = this.convertWind(ECdoc.querySelector("siteData currentConditions wind speed").textContent); + currentWeather.windSpeed = currentWeather.convertWindToMs(ECdoc.querySelector("siteData currentConditions wind speed").textContent); currentWeather.windDirection = ECdoc.querySelector("siteData currentConditions wind bearing").textContent; @@ -190,11 +186,11 @@ WeatherProvider.register("envcanada", { currentWeather.feelsLikeTemp = currentWeather.temperature; if (ECdoc.querySelector("siteData currentConditions windChill")) { - currentWeather.feelsLikeTemp = this.convertTemp(ECdoc.querySelector("siteData currentConditions windChill").textContent); + currentWeather.feelsLikeTemp = ECdoc.querySelector("siteData currentConditions windChill").textContent; } if (ECdoc.querySelector("siteData currentConditions humidex")) { - currentWeather.feelsLikeTemp = this.convertTemp(ECdoc.querySelector("siteData currentConditions humidex").textContent); + currentWeather.feelsLikeTemp = ECdoc.querySelector("siteData currentConditions humidex").textContent; } } @@ -225,7 +221,7 @@ WeatherProvider.register("envcanada", { const days = []; - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const weather = new WeatherObject(); const foreBaseDates = ECdoc.querySelectorAll("siteData forecastGroup dateTime"); const baseDate = foreBaseDates[1].querySelector("timeStamp").textContent; @@ -326,7 +322,7 @@ WeatherProvider.register("envcanada", { days.push(weather); // - // Now do the the rest of the forecast starting at nextDay. We will process each day using 2 EC + // Now do the rest of the forecast starting at nextDay. We will process each day using 2 EC // forecast Elements. This will address the fact that the EC forecast always includes Today and // Tonight for each day. This is why we iterate through the forecast by a a count of 2, with each // iteration looking at the current Element and the next Element. @@ -335,7 +331,7 @@ WeatherProvider.register("envcanada", { let lastDate = moment(baseDate, "YYYYMMDDhhmmss"); for (let stepDay = nextDay; stepDay < lastDay; stepDay += 2) { - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + let weather = new WeatherObject(); // Add 1 to the date to reflect the current forecast day we are building @@ -389,7 +385,7 @@ WeatherProvider.register("envcanada", { const hourGroup = ECdoc.querySelectorAll("siteData hourlyForecastGroup hourlyForecast"); for (let stepHour = 0; stepHour < 24; stepHour += 1) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const weather = new WeatherObject(); // Determine local time by applying UTC offset to the forecast timestamp @@ -399,7 +395,7 @@ WeatherProvider.register("envcanada", { // Capture the temperature - weather.temperature = this.convertTemp(hourGroup[stepHour].querySelector("temperature").textContent); + weather.temperature = hourGroup[stepHour].querySelector("temperature").textContent; // Capture Likelihood of Precipitation (LOP) and unit-of-measure values @@ -450,7 +446,7 @@ WeatherProvider.register("envcanada", { weather.minTemperature = this.todayTempCacheMin; weather.maxTemperature = this.todayTempCacheMax; } else { - weather.minTemperature = this.convertTemp(currentTemp); + weather.minTemperature = currentTemp; weather.maxTemperature = weather.minTemperature; } } @@ -463,14 +459,14 @@ WeatherProvider.register("envcanada", { // if (todayClass === "low") { - weather.minTemperature = this.convertTemp(todayTemp); + weather.minTemperature = todayTemp; if (today === 0 && fullDay === true) { this.todayTempCacheMin = weather.minTemperature; } } if (todayClass === "high") { - weather.maxTemperature = this.convertTemp(todayTemp); + weather.maxTemperature = todayTemp; if (today === 0 && fullDay === true) { this.todayTempCacheMax = weather.maxTemperature; } @@ -482,11 +478,11 @@ WeatherProvider.register("envcanada", { if (fullDay === true) { if (nextClass === "low") { - weather.minTemperature = this.convertTemp(nextTemp); + weather.minTemperature = nextTemp; } if (nextClass === "high") { - weather.maxTemperature = this.convertTemp(nextTemp); + weather.maxTemperature = nextTemp; } } }, @@ -536,31 +532,6 @@ WeatherProvider.register("envcanada", { } }, - // - // Unit conversions - // - // - // Convert C to F temps - // - convertTemp(temp) { - if (this.config.tempUnits === "imperial") { - return 1.8 * temp + 32; - } else { - return temp; - } - }, - - // - // Convert km/h to mph - // - convertWind(kilo) { - if (this.config.windUnits === "imperial") { - return kilo / 1.609344; - } else { - return kilo; - } - }, - // // Convert the icons to a more usable name. // diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index 5f4cfa8385..f5f786fa01 100644 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -30,14 +30,14 @@ WeatherProvider.register("openweathermap", { fetchCurrentWeather() { this.fetchData(this.getUrl()) .then((data) => { + let currentWeather; if (this.config.weatherEndpoint === "/onecall") { - const weatherData = this.generateWeatherObjectsFromOnecall(data); - this.setCurrentWeather(weatherData.current); + currentWeather = this.generateWeatherObjectsFromOnecall(data).current; this.setFetchedLocation(`${data.timezone}`); } else { - const currentWeather = this.generateWeatherObjectFromCurrentWeather(data); - this.setCurrentWeather(currentWeather); + currentWeather = this.generateWeatherObjectFromCurrentWeather(data); } + this.setCurrentWeather(currentWeather); }) .catch(function (request) { Log.error("Could not load data ... ", request); @@ -49,15 +49,17 @@ WeatherProvider.register("openweathermap", { fetchWeatherForecast() { this.fetchData(this.getUrl()) .then((data) => { + let forecast; + let location; if (this.config.weatherEndpoint === "/onecall") { - const weatherData = this.generateWeatherObjectsFromOnecall(data); - this.setWeatherForecast(weatherData.days); - this.setFetchedLocation(`${data.timezone}`); + forecast = this.generateWeatherObjectsFromOnecall(data).days; + location = `${data.timezone}`; } else { - const forecast = this.generateWeatherObjectsFromForecast(data.list); - this.setWeatherForecast(forecast); - this.setFetchedLocation(`${data.city.name}, ${data.city.country}`); + forecast = this.generateWeatherObjectsFromForecast(data.list); + location = `${data.city.name}, ${data.city.country}`; } + this.setWeatherForecast(forecast); + this.setFetchedLocation(location); }) .catch(function (request) { Log.error("Could not load data ... ", request); @@ -123,8 +125,9 @@ WeatherProvider.register("openweathermap", { * Generate a WeatherObject based on currentWeatherInformation */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const currentWeather = new WeatherObject(); + currentWeather.date = moment.unix(currentWeatherData.dt); currentWeather.humidity = currentWeatherData.main.humidity; currentWeather.temperature = currentWeatherData.main.temp; currentWeather.feelsLikeTemp = currentWeatherData.main.feels_like; @@ -147,7 +150,7 @@ WeatherProvider.register("openweathermap", { return this.fetchForecastDaily(forecasts); } // if weatherEndpoint does not match forecast or forecast/daily, what should be returned? - return [new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh)]; + return [new WeatherObject()]; }, /* @@ -158,7 +161,7 @@ WeatherProvider.register("openweathermap", { return this.fetchOnecall(data); } // if weatherEndpoint does not match onecall, what should be returned? - return { current: new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh), hours: [], days: [] }; + return { current: new WeatherObject(), hours: [], days: [] }; }, /* @@ -174,7 +177,7 @@ WeatherProvider.register("openweathermap", { let snow = 0; // variable for date let date = ""; - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + let weather = new WeatherObject(); for (const forecast of forecasts) { if (date !== moment.unix(forecast.dt).format("YYYY-MM-DD")) { @@ -187,7 +190,7 @@ WeatherProvider.register("openweathermap", { // push weather information to days array days.push(weather); // create new weather-object - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + weather = new WeatherObject(); minTemp = []; maxTemp = []; @@ -250,7 +253,7 @@ WeatherProvider.register("openweathermap", { const days = []; for (const forecast of forecasts) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const weather = new WeatherObject(); weather.date = moment.unix(forecast.dt); weather.minTemperature = forecast.temp.min; @@ -296,7 +299,7 @@ WeatherProvider.register("openweathermap", { let precip = false; // get current weather, if requested - const current = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const current = new WeatherObject(); if (data.hasOwnProperty("current")) { current.date = moment.unix(data.current.dt).utcOffset(data.timezone_offset / 60); current.windSpeed = data.current.wind_speed; @@ -328,7 +331,7 @@ WeatherProvider.register("openweathermap", { current.feelsLikeTemp = data.current.feels_like; } - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + let weather = new WeatherObject(); // get hourly weather, if requested const hours = []; @@ -363,7 +366,7 @@ WeatherProvider.register("openweathermap", { } hours.push(weather); - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + weather = new WeatherObject(); } } @@ -402,7 +405,7 @@ WeatherProvider.register("openweathermap", { } days.push(weather); - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + weather = new WeatherObject(); } } @@ -471,7 +474,7 @@ WeatherProvider.register("openweathermap", { return; } - params += "&units=" + this.config.units; + params += "&units=metric"; // WeatherProviders should use metric internally and use the units only for when displaying data params += "&lang=" + this.config.lang; params += "&APPID=" + this.config.apiKey; diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index d3ff79ac72..bb0d2cb2e7 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -75,7 +75,7 @@ WeatherProvider.register("smhi", { setConfig(config) { this.config = config; if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) === -1) { - console.log("invalid or not set: " + config.precipitationValue); + Log.log("invalid or not set: " + config.precipitationValue); config.precipitationValue = this.defaults.precipitationValue; } }, @@ -134,8 +134,7 @@ WeatherProvider.register("smhi", { * @returns {WeatherObject} The converted weatherdata at the specified location */ convertWeatherDataToObject(weatherData, coordinates) { - // Weather data is only for Sweden and nobody in Sweden would use imperial - let currentWeather = new WeatherObject("metric", "metric", "metric"); + let currentWeather = new WeatherObject(); currentWeather.date = moment(weatherData.validTime); currentWeather.updateSunTime(coordinates.lat, coordinates.lon); @@ -191,7 +190,7 @@ WeatherProvider.register("smhi", { for (const weatherObject of allWeatherObjects) { //If its the first object or if a day/hour change we need to reset the summary object if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, groupBy)) { - currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + currentWeather = new WeatherObject(); dayWeatherTypes = []; currentWeather.temperature = weatherObject.temperature; currentWeather.date = weatherObject.date; diff --git a/modules/default/weather/providers/ukmetoffice.js b/modules/default/weather/providers/ukmetoffice.js index 23ec29bfdb..773d0b37ee 100644 --- a/modules/default/weather/providers/ukmetoffice.js +++ b/modules/default/weather/providers/ukmetoffice.js @@ -21,11 +21,6 @@ WeatherProvider.register("ukmetoffice", { apiKey: "" }, - units: { - imperial: "us", - metric: "si" - }, - // Overwrite the fetchCurrentWeather method. fetchCurrentWeather() { this.fetchData(this.getUrl("3hourly")) @@ -80,7 +75,7 @@ WeatherProvider.register("ukmetoffice", { * Generate a WeatherObject based on currentWeatherInformation */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const currentWeather = new WeatherObject(); const location = currentWeatherData.SiteRep.DV.Location; // data times are always UTC @@ -103,11 +98,11 @@ WeatherProvider.register("ukmetoffice", { if (timeInMins >= p && timeInMins - 180 < p) { // finally got the one we want, so populate weather object currentWeather.humidity = rep.H; - currentWeather.temperature = this.convertTemp(rep.T); - currentWeather.feelsLikeTemp = this.convertTemp(rep.F); + currentWeather.temperature = rep.T; + currentWeather.feelsLikeTemp = rep.F; currentWeather.precipitation = parseInt(rep.Pp); - currentWeather.windSpeed = this.convertWindSpeed(rep.S); - currentWeather.windDirection = this.convertWindDirection(rep.D); + currentWeather.windSpeed = currentWeather.convertWindToMetric(rep.S); + currentWeather.windDirection = currentWeather.valueWindDirection(rep.D); currentWeather.weatherType = this.convertWeatherType(rep.W); } } @@ -130,7 +125,7 @@ WeatherProvider.register("ukmetoffice", { // loop round the (5) periods getting the data // for each period array, Day is [0], Night is [1] for (const period of forecasts.SiteRep.DV.Location.Period) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const weather = new WeatherObject(); // data times are always UTC const dateStr = period.value; @@ -140,8 +135,8 @@ WeatherProvider.register("ukmetoffice", { if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) { // populate the weather object weather.date = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD"); - weather.minTemperature = this.convertTemp(period.Rep[1].Nm); - weather.maxTemperature = this.convertTemp(period.Rep[0].Dm); + weather.minTemperature = period.Rep[1].Nm; + weather.maxTemperature = period.Rep[0].Dm; weather.weatherType = this.convertWeatherType(period.Rep[0].W); weather.precipitation = parseInt(period.Rep[0].PPd); @@ -192,46 +187,6 @@ WeatherProvider.register("ukmetoffice", { return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; }, - /* - * Convert temp (from degrees C) if required - */ - convertTemp(tempInC) { - return this.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC; - }, - - /* - * Convert wind speed (from mph to m/s or km/h) if required - */ - convertWindSpeed(windInMph) { - return this.windUnits === "metric" ? (this.useKmh ? windInMph * 1.60934 : windInMph / 2.23694) : windInMph; - }, - - /* - * Convert the wind direction cardinal to value - */ - convertWindDirection(windDirection) { - const windCardinals = { - N: 0, - NNE: 22, - NE: 45, - ENE: 67, - E: 90, - ESE: 112, - SE: 135, - SSE: 157, - S: 180, - SSW: 202, - SW: 225, - WSW: 247, - W: 270, - WNW: 292, - NW: 315, - NNW: 337 - }; - - return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null; - }, - /** * Generates an url with api parameters based on the config. * diff --git a/modules/default/weather/providers/ukmetofficedatahub.js b/modules/default/weather/providers/ukmetofficedatahub.js index 508d700d8c..049f9c4da3 100644 --- a/modules/default/weather/providers/ukmetofficedatahub.js +++ b/modules/default/weather/providers/ukmetofficedatahub.js @@ -20,11 +20,9 @@ * weatherProvider: "ukmetofficedatahub", * apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/", * apiKey: "[YOUR API KEY]", - * apiSecret: "[YOUR API SECRET]]", + * apiSecret: "[YOUR API SECRET]", * lat: [LATITUDE (DECIMAL)], - * lon: [LONGITUDE (DECIMAL)], - * windUnits: "mps" | "kph" | "mph" (default) - * tempUnits: "imperial" | "metric" (default) + * lon: [LONGITUDE (DECIMAL)] * * At time of writing, free accounts are limited to 360 requests a day per service (hourly, 3hourly, daily); take this in mind when * setting your update intervals. For reference, 360 requests per day is once every 4 minutes. @@ -51,8 +49,7 @@ WeatherProvider.register("ukmetofficedatahub", { apiKey: "", apiSecret: "", lat: 0, - lon: 0, - windUnits: "mph" + lon: 0 }, // Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api) @@ -115,7 +112,7 @@ WeatherProvider.register("ukmetofficedatahub", { // Create a WeatherObject using current weather data (data for the current hour) generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const currentWeather = new WeatherObject(); // Extract the actual forecasts let forecastDataHours = currentWeatherData.features[0].properties.timeSeries; @@ -128,17 +125,17 @@ WeatherProvider.register("ukmetofficedatahub", { let forecastTime = moment.utc(forecastDataHours[hour].time); if (nowUtc.isSameOrAfter(forecastTime) && nowUtc.isBefore(moment(forecastTime.add(1, "h")))) { currentWeather.date = forecastTime; - currentWeather.windSpeed = this.convertWindSpeed(forecastDataHours[hour].windSpeed10m); + currentWeather.windSpeed = forecastDataHours[hour].windSpeed10m; currentWeather.windDirection = forecastDataHours[hour].windDirectionFrom10m; - currentWeather.temperature = this.convertTemp(forecastDataHours[hour].screenTemperature); - currentWeather.minTemperature = this.convertTemp(forecastDataHours[hour].minScreenAirTemp); - currentWeather.maxTemperature = this.convertTemp(forecastDataHours[hour].maxScreenAirTemp); + currentWeather.temperature = forecastDataHours[hour].screenTemperature; + currentWeather.minTemperature = forecastDataHours[hour].minScreenAirTemp; + currentWeather.maxTemperature = forecastDataHours[hour].maxScreenAirTemp; currentWeather.weatherType = this.convertWeatherType(forecastDataHours[hour].significantWeatherCode); currentWeather.humidity = forecastDataHours[hour].screenRelativeHumidity; currentWeather.rain = forecastDataHours[hour].totalPrecipAmount; currentWeather.snow = forecastDataHours[hour].totalSnowAmount; currentWeather.precipitation = forecastDataHours[hour].probOfPrecipitation; - currentWeather.feelsLikeTemp = this.convertTemp(forecastDataHours[hour].feelsLikeTemperature); + currentWeather.feelsLikeTemp = forecastDataHours[hour].feelsLikeTemperature; // Pass on full details, so they can be used in custom templates // Note the units of the supplied data when using this (see top of file) @@ -194,7 +191,7 @@ WeatherProvider.register("ukmetofficedatahub", { // Go through each day in the forecasts for (let day in forecastDataDays) { - const forecastWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const forecastWeather = new WeatherObject(); // Get date of forecast let forecastDate = moment.utc(forecastDataDays[day].time); @@ -202,11 +199,11 @@ WeatherProvider.register("ukmetofficedatahub", { // Check if forecast is for today or in the future (i.e., ignore yesterday's forecast) if (forecastDate.isSameOrAfter(today)) { forecastWeather.date = forecastDate; - forecastWeather.minTemperature = this.convertTemp(forecastDataDays[day].nightMinScreenTemperature); - forecastWeather.maxTemperature = this.convertTemp(forecastDataDays[day].dayMaxScreenTemperature); + forecastWeather.minTemperature = forecastDataDays[day].nightMinScreenTemperature; + forecastWeather.maxTemperature = forecastDataDays[day].dayMaxScreenTemperature; // Using daytime forecast values - forecastWeather.windSpeed = this.convertWindSpeed(forecastDataDays[day].midday10MWindSpeed); + forecastWeather.windSpeed = forecastDataDays[day].midday10MWindSpeed; forecastWeather.windDirection = forecastDataDays[day].midday10MWindDirection; forecastWeather.weatherType = this.convertWeatherType(forecastDataDays[day].daySignificantWeatherCode); forecastWeather.precipitation = forecastDataDays[day].dayProbabilityOfPrecipitation; @@ -214,7 +211,7 @@ WeatherProvider.register("ukmetofficedatahub", { forecastWeather.humidity = forecastDataDays[day].middayRelativeHumidity; forecastWeather.rain = forecastDataDays[day].dayProbabilityOfRain; forecastWeather.snow = forecastDataDays[day].dayProbabilityOfSnow; - forecastWeather.feelsLikeTemp = this.convertTemp(forecastDataDays[day].dayMaxFeelsLikeTemp); + forecastWeather.feelsLikeTemp = forecastDataDays[day].dayMaxFeelsLikeTemp; // Pass on full details, so they can be used in custom templates // Note the units of the supplied data when using this (see top of file) @@ -232,27 +229,6 @@ WeatherProvider.register("ukmetofficedatahub", { this.fetchedLocationName = name; }, - // Convert temperatures to Fahrenheit (from degrees C), if required - convertTemp(tempInC) { - return this.config.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC; - }, - - // Convert wind speed from metres per second - // To keep the supplied metres per second units, use "mps" - // To use kilometres per hour, use "kph" - // Else assumed imperial and the value is returned in miles per hour (a Met Office user is likely to be UK-based) - convertWindSpeed(windInMpS) { - if (this.config.windUnits === "mps") { - return windInMpS; - } - - if (this.config.windUnits === "kph" || this.config.windUnits === "metric" || this.config.useKmh) { - return windInMpS * 3.6; - } - - return windInMpS * 2.23694; - }, - // Match the Met Office "significant weather code" to a weathericons.css icon // Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264 // and: https://erikflowers.github.io/weather-icons/ diff --git a/modules/default/weather/providers/weatherbit.js b/modules/default/weather/providers/weatherbit.js index 7c8010a837..75f49a6984 100644 --- a/modules/default/weather/providers/weatherbit.js +++ b/modules/default/weather/providers/weatherbit.js @@ -23,11 +23,6 @@ WeatherProvider.register("weatherbit", { lon: 0 }, - units: { - imperial: "I", - metric: "M" - }, - fetchedLocation: function () { return this.fetchedLocationName || ""; }, @@ -95,8 +90,7 @@ WeatherProvider.register("weatherbit", { // Create a URL from the config and base URL. getUrl() { - const units = this.units[this.config.units] || "auto"; - return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=${units}&key=${this.config.apiKey}`; + return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=M&key=${this.config.apiKey}`; }, // Implement WeatherDay generator. @@ -106,7 +100,7 @@ WeatherProvider.register("weatherbit", { let tzOffset = d.getTimezoneOffset(); tzOffset = tzOffset * -1; - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(); currentWeather.date = moment.unix(currentWeatherData.data[0].ts); currentWeather.humidity = parseFloat(currentWeatherData.data[0].rh); @@ -126,7 +120,7 @@ WeatherProvider.register("weatherbit", { const days = []; for (const forecast of forecasts) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const weather = new WeatherObject(); weather.date = moment(forecast.datetime, "YYYY-MM-DD"); weather.minTemperature = forecast.min_temp; diff --git a/modules/default/weather/providers/weatherflow.js b/modules/default/weather/providers/weatherflow.js index a847fabd06..06ab8f71d5 100644 --- a/modules/default/weather/providers/weatherflow.js +++ b/modules/default/weather/providers/weatherflow.js @@ -23,32 +23,15 @@ WeatherProvider.register("weatherflow", { stationid: "" }, - units: { - imperial: { - temp: "f", - wind: "mph", - pressure: "hpa", - precip: "in", - distance: "mi" - }, - metric: { - temp: "c", - wind: "kph", - pressure: "mb", - precip: "mm", - distance: "km" - } - }, - fetchCurrentWeather() { this.fetchData(this.getUrl()) .then((data) => { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const currentWeather = new WeatherObject(); currentWeather.date = moment(); currentWeather.humidity = data.current_conditions.relative_humidity; currentWeather.temperature = data.current_conditions.air_temperature; - currentWeather.windSpeed = data.current_conditions.wind_avg; + currentWeather.windSpeed = currentWeather.convertWindToMs(data.current_conditions.wind_avg); currentWeather.windDirection = data.current_conditions.wind_direction; currentWeather.weatherType = data.forecast.daily[0].icon; currentWeather.sunrise = moment.unix(data.forecast.daily[0].sunrise); @@ -67,7 +50,7 @@ WeatherProvider.register("weatherflow", { const days = []; for (const forecast of data.forecast.daily) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const weather = new WeatherObject(); weather.date = moment.unix(forecast.day_start_local); weather.minTemperature = forecast.air_temp_low; @@ -88,22 +71,6 @@ WeatherProvider.register("weatherflow", { // Create a URL from the config and base URL. getUrl() { - return ( - this.config.apiBase + - "better_forecast?station_id=" + - this.config.stationid + - "&units_temp=" + - this.units[this.config.units].temp + - "&units_wind=" + - this.units[this.config.units].wind + - "&units_pressure=" + - this.units[this.config.units].pressure + - "&units_precip=" + - this.units[this.config.units].precip + - "&units_distance=" + - this.units[this.config.units].distance + - "&token=" + - this.config.token - ); + return `${this.config.apiBase}better_forecast?station_id=${this.config.stationid}&units_temp=c&units_wind=kph&units_pressure=mb&units_precip=mm&units_distance=km&token=${this.config.token}`; } }); diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index eb2c42798c..7e39335ab7 100644 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -131,8 +131,8 @@ WeatherProvider.register("weathergov", { } this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state; Log.log("Forecast location is " + this.fetchedLocationName); - this.forecastURL = data.properties.forecast; - this.forecastHourlyURL = data.properties.forecastHourly; + this.forecastURL = data.properties.forecast + "?units=si"; + this.forecastHourlyURL = data.properties.forecastHourly + "?units=si"; this.forecastGridDataURL = data.properties.forecastGridData; this.observationStationsURL = data.properties.observationStations; // with this URL, we chain another promise for the station obs URL @@ -171,7 +171,7 @@ WeatherProvider.register("weathergov", { const days = []; // variable for date - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + let weather = new WeatherObject(); for (const forecast of forecasts) { weather.date = moment(forecast.startTime.slice(0, 19)); if (forecast.windSpeed.search(" ") < 0) { @@ -187,7 +187,7 @@ WeatherProvider.register("weathergov", { days.push(weather); - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + weather = new WeatherObject(); } // push weather information to days array @@ -201,24 +201,24 @@ WeatherProvider.register("weathergov", { * ... object needs data in units based on config! */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + const currentWeather = new WeatherObject(); currentWeather.date = moment(currentWeatherData.timestamp); - currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value); - currentWeather.windSpeed = this.convertSpeed(currentWeatherData.windSpeed.value); + currentWeather.temperature = currentWeatherData.temperature.value; + currentWeather.windSpeed = currentWeather.convertWindToMs(currentWeatherData.windSpeed.value); currentWeather.windDirection = currentWeatherData.windDirection.value; - currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value); - currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value); + currentWeather.minTemperature = currentWeatherData.minTemperatureLast24Hours.value; + currentWeather.maxTemperature = currentWeatherData.maxTemperatureLast24Hours.value; currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value); currentWeather.rain = null; currentWeather.snow = null; currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value); if (currentWeatherData.heatIndex.value !== null) { - currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value); + currentWeather.feelsLikeTemp = currentWeatherData.heatIndex.value; } else if (currentWeatherData.windChill.value !== null) { - currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.windChill.value); + currentWeather.feelsLikeTemp = currentWeatherData.windChill.value; } else { - currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.temperature.value); + currentWeather.feelsLikeTemp = currentWeatherData.temperature.value; } // determine the sunrise/sunset times - not supplied in weather.gov data currentWeather.updateSunTime(this.config.lat, this.config.lon); @@ -247,7 +247,7 @@ WeatherProvider.register("weathergov", { let maxTemp = []; // variable for date let date = ""; - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + let weather = new WeatherObject(); weather.precipitation = 0; for (const forecast of forecasts) { @@ -259,7 +259,7 @@ WeatherProvider.register("weathergov", { // push weather information to days array days.push(weather); // create new weather-object - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); + weather = new WeatherObject(); minTemp = []; maxTemp = []; @@ -298,26 +298,6 @@ WeatherProvider.register("weathergov", { /* * Unit conversions */ - // conversion to fahrenheit - convertTemp(temp) { - if (this.config.tempUnits === "imperial") { - return (9 / 5) * temp + 32; - } else { - return temp; - } - }, - // conversion to mph or kmh - convertSpeed(metSec) { - if (this.config.windUnits === "imperial") { - return metSec * 2.23694; - } else { - if (this.config.useKmh) { - return metSec * 3.6; - } else { - return metSec; - } - } - }, // conversion to inches convertLength(meters) { if (this.config.units === "imperial") { @@ -395,31 +375,5 @@ WeatherProvider.register("weathergov", { } return null; - }, - - /* - Convert the direction into Degrees - */ - convertWindDirection(windDirection) { - const windCardinals = { - N: 0, - NNE: 22, - NE: 45, - ENE: 67, - E: 90, - ESE: 112, - SE: 135, - SSE: 157, - S: 180, - SSW: 202, - SW: 225, - WSW: 247, - W: 270, - WNW: 292, - NW: 315, - NNW: 337 - }; - - return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null; } }); diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index 6a02d182f9..58780b32c9 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -13,7 +13,6 @@ Module.register("weather", { roundTemp: false, type: "current", // current, forecast, daily (equivalent to forecast), hourly (only with OpenWeatherMap /onecall endpoint) units: config.units, - useKmh: false, tempUnits: config.units, windUnits: config.units, updateInterval: 10 * 60 * 1000, // every 10 minutes @@ -23,7 +22,6 @@ Module.register("weather", { showPeriodUpper: false, showWindDirection: true, showWindDirectionAsArrow: false, - useBeaufort: true, lang: config.language, showHumidity: false, showSun: true, @@ -77,6 +75,14 @@ Module.register("weather", { start: function () { moment.locale(this.config.lang); + if (this.config.useKmh) { + Log.warn("Your are using the deprecated config values 'useKmh'. Please switch to windUnits!"); + this.windUnits = "kmh"; + } else if (this.config.useBeaufort) { + Log.warn("Your are using the deprecated config values 'useBeaufort'. Please switch to windUnits!"); + this.windUnits = "beaufort"; + } + // Initialize the weather provider. this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this); @@ -195,6 +201,59 @@ Module.register("weather", { return roundValue === "-0" ? 0 : roundValue; }, + /** + * Convert temp (from degrees C) into imperial or metric unit depending on + * your config + * + * @param {number} tempInC the temperature you want to convert in celsius + * @returns {number} the temperature converted to what is defined in the config + */ + convertTemp(tempInC) { + return this.config.tempUnits === "imperial" ? this.roundValue(tempInC * 1.8 + 32) : tempInC; + }, + + /** + * + * Convert wind speed (from meters per second) into whatever is defined in + * your config. Can be 'beaufort', 'kmh', 'knots, 'imperial' (mph) or + * 'metric' (mps) + * + * @param {number} windInMS the windspeed you want to convert + * @returns {number} the windspeed converted to what is defined in the config + */ + convertWind(windInMS) { + switch (this.config.windUnits) { + case "beaufort": + return this.beaufortWindSpeed(windInMS); + case "kmh": + return (windInMS * 3600) / 1000; + case "knots": + return windInMS * 1.943844; + case "imperial": + return windInMS * 2.2369362920544; + case "metric": + default: + return windInMS; + } + }, + + /** + * Convert wind (from m/s) to beaufort scale + * + * @param {number} speedInMS the windspeed you want to convert + * @returns {number} the speed in beaufort + */ + beaufortWindSpeed(speedInMS) { + const windInKmh = (speedInMS * 3600) / 1000; + const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; + for (const [index, speed] of speeds.entries()) { + if (speed > windInKmh) { + return index; + } + } + return 12; + }, + addFilters() { this.nunjucksEnvironment().addFilter( "formatTime", @@ -221,9 +280,7 @@ Module.register("weather", { "unit", function (value, type) { if (type === "temperature") { - if (this.config.tempUnits === "metric" || this.config.tempUnits === "imperial") { - value += "°"; - } + value = this.convertTemp(value) + "°"; if (this.config.degreeLabel) { if (this.config.tempUnits === "metric") { value += "C"; @@ -245,8 +302,9 @@ Module.register("weather", { } } else if (type === "humidity") { value += "%"; + } else if (type === "wind") { + value = this.convertWind(value); } - return value; }.bind(this) ); diff --git a/modules/default/weather/weatherobject.js b/modules/default/weather/weatherobject.js index 8df71721b4..eb90db1aa9 100644 --- a/modules/default/weather/weatherobject.js +++ b/modules/default/weather/weatherobject.js @@ -14,17 +14,8 @@ class WeatherObject { /** * Constructor for a WeatherObject - * - * @param {string} units what units to use, "imperial" or "metric" - * @param {string} tempUnits what tempunits to use - * @param {string} windUnits what windunits to use - * @param {boolean} useKmh use kmh if true, mps if false */ - constructor(units, tempUnits, windUnits, useKmh) { - this.units = units; - this.tempUnits = tempUnits; - this.windUnits = windUnits; - this.useKmh = useKmh; + constructor() { this.date = null; this.windSpeed = null; this.windDirection = null; @@ -78,19 +69,38 @@ class WeatherObject { } } - beaufortWindSpeed() { - const windInKmh = this.windUnits === "imperial" ? this.windSpeed * 1.609344 : this.useKmh ? this.windSpeed : (this.windSpeed * 60 * 60) / 1000; - const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; - for (const [index, speed] of speeds.entries()) { - if (speed > windInKmh) { - return index; - } - } - return 12; + /* + * Convert the wind direction cardinal to value + */ + valueWindDirection(windDirection) { + const windCardinals = { + N: 0, + NNE: 22, + NE: 45, + ENE: 67, + E: 90, + ESE: 112, + SE: 135, + SSE: 157, + S: 180, + SSW: 202, + SW: 225, + WSW: 247, + W: 270, + WNW: 292, + NW: 315, + NNW: 337 + }; + + return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null; + } + + convertWindToMetric(mph) { + return mph / 2.2369362920544; } - kmhWindSpeed() { - return this.windUnits === "imperial" ? this.windSpeed * 1.609344 : (this.windSpeed * 60 * 60) / 1000; + convertWindToMs(kmh) { + return kmh * 0.27777777777778; } nextSunAction() { @@ -101,8 +111,8 @@ class WeatherObject { if (this.feelsLikeTemp) { return this.feelsLikeTemp; } - const windInMph = this.windUnits === "imperial" ? this.windSpeed : this.windSpeed * 2.23694; - const tempInF = this.tempUnits === "imperial" ? this.temperature : (this.temperature * 9) / 5 + 32; + const windInMph = this.windSpeed * 2.2369362920544; + const tempInF = (this.temperature * 9) / 5 + 32; let feelsLike = tempInF; if (windInMph > 3 && tempInF < 50) { @@ -120,7 +130,7 @@ class WeatherObject { 1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity; } - return this.tempUnits === "imperial" ? feelsLike : ((feelsLike - 32) * 5) / 9; + return ((feelsLike - 32) * 5) / 9; } /** diff --git a/tests/configs/modules/weather/currentweather_options.js b/tests/configs/modules/weather/currentweather_options.js index bd433f6435..2dd9216327 100644 --- a/tests/configs/modules/weather/currentweather_options.js +++ b/tests/configs/modules/weather/currentweather_options.js @@ -11,7 +11,7 @@ let config = { config: { location: "Munich", mockData: '"#####WEATHERDATA#####"', - useBeaufort: false, + windUnits: "beaufort", showWindDirectionAsArrow: true, showSun: false, showHumidity: true, diff --git a/tests/e2e/modules/weather_current_spec.js b/tests/e2e/modules/weather_current_spec.js index 694782b160..97ae3eec85 100644 --- a/tests/e2e/modules/weather_current_spec.js +++ b/tests/e2e/modules/weather_current_spec.js @@ -1,4 +1,3 @@ -const moment = require("moment"); const helpers = require("../helpers/global-setup"); const weatherFunc = require("../helpers/weather-functions"); @@ -14,39 +13,15 @@ describe("Weather module", () => { }); it("should render wind speed and wind direction", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6 WSW"); // now "12" + await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "12 WSW"); }); it("should render temperature with icon", async () => { - await weatherFunc.getText(".weather .large.light span.bright", "1.5°"); // now "1°C" + await weatherFunc.getText(".weather .large.light span.bright", "1.5°"); }); it("should render feels like temperature", async () => { - await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°"); // now "Feels like -6°C" - }); - }); - - describe("Default configuration with sunrise", () => { - beforeAll(async () => { - const sunrise = moment().startOf("day").unix(); - const sunset = moment().startOf("day").unix(); - await weatherFunc.startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } }); - }); - - it("should render sunrise", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(4)", "12:00 am"); - }); - }); - - describe("Default configuration with sunset", () => { - beforeAll(async () => { - const sunrise = moment().startOf("day").unix(); - const sunset = moment().endOf("day").unix(); - await weatherFunc.startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } }); - }); - - it("should render sunset", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(4)", "11:59 pm"); + await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°"); }); }); }); @@ -66,65 +41,44 @@ describe("Weather module", () => { await weatherFunc.startApp("tests/configs/modules/weather/currentweather_options.js", {}); }); - it("should render useBeaufort = false", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "12"); + it("should render windUnits in beaufort", async () => { + await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6"); }); - it("should render showWindDirectionAsArrow = true", async () => { + it("should render windDirection with an arrow", async () => { const elem = await helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-up"); expect(elem).not.toBe(null); expect(elem.outerHTML).toContain("transform:rotate(250deg);"); }); - it("should render showHumidity = true", async () => { + it("should render humidity", async () => { await weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93.7"); }); - it("should render degreeLabel = true for temp", async () => { + it("should render degreeLabel for temp", async () => { await weatherFunc.getText(".weather .large.light span.bright", "1°C"); }); - it("should render degreeLabel = true for feels like", async () => { + it("should render degreeLabel for feels like", async () => { await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C"); }); }); - describe("Current weather units", () => { + describe("Current weather with imperial units", () => { beforeAll(async () => { - await weatherFunc.startApp("tests/configs/modules/weather/currentweather_units.js", { - main: { - temp: (1.49 * 9) / 5 + 32, - temp_min: (1 * 9) / 5 + 32, - temp_max: (2 * 9) / 5 + 32 - }, - wind: { - speed: 11.8 * 2.23694 - } - }); - }); - - it("should render imperial units for wind", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "6 WSW"); - }); - - it("should render imperial units for temp", async () => { - await weatherFunc.getText(".weather .large.light span.bright", "34,7°"); - }); - - it("should render imperial units for feels like", async () => { - await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°"); + await weatherFunc.startApp("tests/configs/modules/weather/currentweather_units.js", {}); }); - it("should render custom decimalSymbol = ',' for humidity", async () => { - await weatherFunc.getText(".weather .normal.medium span:nth-child(3)", "93,7"); + it("should render wind in imperial units", async () => { + await weatherFunc.getText(".weather .normal.medium span:nth-child(2)", "26 WSW"); }); - it("should render custom decimalSymbol = ',' for temp", async () => { + it("should render temperatures in fahrenheit", async () => { await weatherFunc.getText(".weather .large.light span.bright", "34,7°"); }); - it("should render custom decimalSymbol = ',' for feels like", async () => { - await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°"); + it("should render 'feels like' in fahrenheit", async () => { + await weatherFunc.getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 21,9°"); }); }); }); diff --git a/tests/e2e/modules/weather_forecast_spec.js b/tests/e2e/modules/weather_forecast_spec.js index 9268c6d157..cd03691609 100644 --- a/tests/e2e/modules/weather_forecast_spec.js +++ b/tests/e2e/modules/weather_forecast_spec.js @@ -86,7 +86,7 @@ describe("Weather module: Weather Forecast", () => { await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_units.js", {}); }); - const temperatures = ["24_4°", "21_0°", "22_9°", "23_4°", "20_6°"]; + const temperatures = ["75_9°", "69_8°", "73_2°", "74_1°", "69_1°"]; for (const [index, temp] of temperatures.entries()) { it("should render custom decimalSymbol = '_' for temp " + temp, async () => { await weatherFunc.getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp); diff --git a/tests/electron/helpers/weather-setup.js b/tests/electron/helpers/weather-setup.js new file mode 100644 index 0000000000..2c9b9ad1f5 --- /dev/null +++ b/tests/electron/helpers/weather-setup.js @@ -0,0 +1,29 @@ +const helpers = require("./global-setup"); +const path = require("path"); +const fs = require("fs"); +const { generateWeather, generateWeatherForecast } = require("../../mocks/weather_test"); + +exports.getText = async (element, result) => { + const elem = await helpers.getElement(element); + await expect(elem).not.toBe(null); + const text = await elem.textContent(); + await expect( + text + .trim() + .replace(/(\r\n|\n|\r)/gm, "") + .replace(/[ ]+/g, " ") + ).toBe(result); +}; + +exports.startApp = async (configFile, systemDate) => { + let mockWeather; + if (configFile.includes("forecast")) { + mockWeather = generateWeatherForecast(); + } else { + mockWeather = generateWeather(); + } + let content = fs.readFileSync(path.resolve(__dirname + "../../../../" + configFile)).toString(); + content = content.replace("#####WEATHERDATA#####", mockWeather); + fs.writeFileSync(path.resolve(__dirname + "../../../../config/config.js"), content); + await helpers.startApplication("", systemDate); +}; diff --git a/tests/electron/modules/weather_spec.js b/tests/electron/modules/weather_spec.js new file mode 100644 index 0000000000..fe77743110 --- /dev/null +++ b/tests/electron/modules/weather_spec.js @@ -0,0 +1,28 @@ +const helpers = require("../helpers/global-setup"); +const weatherHelper = require("../helpers/weather-setup"); + +describe("Weather module", () => { + afterEach(async () => { + await helpers.stopApplication(); + }); + + describe("Current weather with sunrise", () => { + beforeAll(async () => { + await weatherHelper.startApp("tests/configs/modules/weather/currentweather_default.js", "13 Jan 2019 00:30:00 GMT"); + }); + + it("should render sunrise", async () => { + await weatherHelper.getText(".weather .normal.medium span:nth-child(4)", "7:00 am"); + }); + }); + + describe("Current weather with sunset", () => { + beforeAll(async () => { + await weatherHelper.startApp("tests/configs/modules/weather/currentweather_default.js", "13 Jan 2019 12:30:00 GMT"); + }); + + it("should render sunset", async () => { + await weatherHelper.getText(".weather .normal.medium span:nth-child(4)", "3:45 pm"); + }); + }); +}); diff --git a/tests/unit/functions/weather_object_spec.js b/tests/unit/functions/weather_object_spec.js index 4eb6a61517..57535e70e8 100644 --- a/tests/unit/functions/weather_object_spec.js +++ b/tests/unit/functions/weather_object_spec.js @@ -10,7 +10,7 @@ describe("WeatherObject", () => { beforeAll(() => { originalTimeZone = moment.tz.guess(); moment.tz.setDefault("Africa/Dar_es_Salaam"); - weatherobject = new WeatherObject("metric", "metric", "metric", true); + weatherobject = new WeatherObject(); }); it("should return true for daytime at noon", () => { @@ -25,6 +25,14 @@ describe("WeatherObject", () => { expect(weatherobject.isDayTime()).toBe(false); }); + it("should convert windspeed correctly from mph to mps", () => { + expect(Math.round(weatherobject.convertWindToMetric(93.951324266285))).toBe(42); + }); + + it("should convert wind direction correctly from cardinal to value", () => { + expect(weatherobject.valueWindDirection("SSE")).toBe(157); + }); + afterAll(() => { moment.tz.setDefault(originalTimeZone); });