From c191ff003255c1b81853b713ad2f673b37d584f1 Mon Sep 17 00:00:00 2001 From: Veeck Date: Fri, 28 Oct 2022 19:56:55 +0200 Subject: [PATCH] Refactor common weather methods into utils class (#2958) Co-authored-by: veeck --- CHANGELOG.md | 7 +- .../default/weather/providers/envcanada.js | 4 +- .../default/weather/providers/ukmetoffice.js | 6 +- .../default/weather/providers/weatherflow.js | 4 +- .../default/weather/providers/weathergov.js | 4 +- modules/default/weather/weather.js | 61 +----------- modules/default/weather/weatherobject.js | 40 +------- modules/default/weather/weatherutils.js | 98 +++++++++++++++++++ tests/unit/functions/weather_object_spec.js | 23 +++-- 9 files changed, 133 insertions(+), 114 deletions(-) create mode 100644 modules/default/weather/weatherutils.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f16669a..9dddd6f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,9 +28,10 @@ Special thanks to: @rejas, @sdetweil - Updated da translation - Rework weather module - Make sure smhi provider api only gets a maximum of 6 digits coordinates (#2955) - - Use fetch instead of XMLHttpRequest in weatherprovider - - Reworked how weatherproviders handle units - - Use unix() method for parsing times, fix suntimes on the way + - Use fetch instead of XMLHttpRequest in weatherprovider (#2935) + - Reworked how weatherproviders handle units (#2849) + - Use unix() method for parsing times, fix suntimes on the way (#2950) + - Refactor conversion functions into utils class (#2958) ### Fixed diff --git a/modules/default/weather/providers/envcanada.js b/modules/default/weather/providers/envcanada.js index fdea195b..4842446b 100644 --- a/modules/default/weather/providers/envcanada.js +++ b/modules/default/weather/providers/envcanada.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherObject */ +/* global WeatherProvider, WeatherObject, WeatherUtils */ /* MagicMirror² * Module: Weather @@ -163,7 +163,7 @@ WeatherProvider.register("envcanada", { currentWeather.temperature = this.cacheCurrentTemp; } - currentWeather.windSpeed = currentWeather.convertWindToMs(ECdoc.querySelector("siteData currentConditions wind speed").textContent); + currentWeather.windSpeed = WeatherUtils.convertWindToMs(ECdoc.querySelector("siteData currentConditions wind speed").textContent); currentWeather.windDirection = ECdoc.querySelector("siteData currentConditions wind bearing").textContent; diff --git a/modules/default/weather/providers/ukmetoffice.js b/modules/default/weather/providers/ukmetoffice.js index 773d0b37..d572e53e 100644 --- a/modules/default/weather/providers/ukmetoffice.js +++ b/modules/default/weather/providers/ukmetoffice.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherObject */ +/* global WeatherProvider, WeatherObject, WeatherUtils */ /* MagicMirror² * Module: Weather @@ -101,8 +101,8 @@ WeatherProvider.register("ukmetoffice", { currentWeather.temperature = rep.T; currentWeather.feelsLikeTemp = rep.F; currentWeather.precipitation = parseInt(rep.Pp); - currentWeather.windSpeed = currentWeather.convertWindToMetric(rep.S); - currentWeather.windDirection = currentWeather.valueWindDirection(rep.D); + currentWeather.windSpeed = WeatherUtils.convertWindToMetric(rep.S); + currentWeather.windDirection = WeatherUtils.convertWindDirection(rep.D); currentWeather.weatherType = this.convertWeatherType(rep.W); } } diff --git a/modules/default/weather/providers/weatherflow.js b/modules/default/weather/providers/weatherflow.js index 06ab8f71..d15023b5 100644 --- a/modules/default/weather/providers/weatherflow.js +++ b/modules/default/weather/providers/weatherflow.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherObject */ +/* global WeatherProvider, WeatherObject, WeatherUtils */ /* MagicMirror² * Module: Weather @@ -31,7 +31,7 @@ WeatherProvider.register("weatherflow", { currentWeather.humidity = data.current_conditions.relative_humidity; currentWeather.temperature = data.current_conditions.air_temperature; - currentWeather.windSpeed = currentWeather.convertWindToMs(data.current_conditions.wind_avg); + currentWeather.windSpeed = WeatherUtils.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); diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index 7e39335a..19ce22e3 100644 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherObject */ +/* global WeatherProvider, WeatherObject, WeatherUtils */ /* MagicMirror² * Module: Weather @@ -205,7 +205,7 @@ WeatherProvider.register("weathergov", { currentWeather.date = moment(currentWeatherData.timestamp); currentWeather.temperature = currentWeatherData.temperature.value; - currentWeather.windSpeed = currentWeather.convertWindToMs(currentWeatherData.windSpeed.value); + currentWeather.windSpeed = WeatherUtils.convertWindToMs(currentWeatherData.windSpeed.value); currentWeather.windDirection = currentWeatherData.windDirection.value; currentWeather.minTemperature = currentWeatherData.minTemperatureLast24Hours.value; currentWeather.maxTemperature = currentWeatherData.maxTemperatureLast24Hours.value; diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index 58780b32..009b4fb8 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -1,4 +1,4 @@ -/* global WeatherProvider */ +/* global WeatherProvider, WeatherUtils */ /* MagicMirror² * Module: Weather @@ -58,7 +58,7 @@ Module.register("weather", { // Return the scripts that are necessary for the weather module. getScripts: function () { - return ["moment.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js")]; + return ["moment.js", "weatherutils.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js")]; }, // Override getHeader method. @@ -201,59 +201,6 @@ 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", @@ -280,7 +227,7 @@ Module.register("weather", { "unit", function (value, type) { if (type === "temperature") { - value = this.convertTemp(value) + "°"; + value = this.roundValue(WeatherUtils.convertTemp(value, this.config.tempUnits)) + "°"; if (this.config.degreeLabel) { if (this.config.tempUnits === "metric") { value += "C"; @@ -303,7 +250,7 @@ Module.register("weather", { } else if (type === "humidity") { value += "%"; } else if (type === "wind") { - value = this.convertWind(value); + value = WeatherUtils.convertWind(value, this.config.windUnits); } return value; }.bind(this) diff --git a/modules/default/weather/weatherobject.js b/modules/default/weather/weatherobject.js index eb90db1a..0e28b4f2 100644 --- a/modules/default/weather/weatherobject.js +++ b/modules/default/weather/weatherobject.js @@ -1,4 +1,4 @@ -/* global SunCalc */ +/* global SunCalc, WeatherUtils */ /* MagicMirror² * Module: Weather @@ -69,40 +69,6 @@ class WeatherObject { } } - /* - * 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; - } - - convertWindToMs(kmh) { - return kmh * 0.27777777777778; - } - nextSunAction() { return moment().isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise"; } @@ -111,8 +77,8 @@ class WeatherObject { if (this.feelsLikeTemp) { return this.feelsLikeTemp; } - const windInMph = this.windSpeed * 2.2369362920544; - const tempInF = (this.temperature * 9) / 5 + 32; + const windInMph = WeatherUtils.convertWind(this.windSpeed, "imperial"); + const tempInF = WeatherUtils.convertTemp(this.temperature, "imperial"); let feelsLike = tempInF; if (windInMph > 3 && tempInF < 50) { diff --git a/modules/default/weather/weatherutils.js b/modules/default/weather/weatherutils.js new file mode 100644 index 00000000..c0af86af --- /dev/null +++ b/modules/default/weather/weatherutils.js @@ -0,0 +1,98 @@ +/* MagicMirror² + * Weather Util Methods + * + * By Rejas + * MIT Licensed. + */ +const WeatherUtils = { + /** + * 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; + }, + + /** + * Convert temp (from degrees C) into imperial or metric unit depending on + * your config + * + * @param {number} tempInC the temperature in celsius you want to convert + * @param {string} unit can be 'imperial' or 'metric' + * @returns {number} the converted temperature + */ + convertTemp(tempInC, unit) { + return unit === "imperial" ? tempInC * 1.8 + 32 : tempInC; + }, + + /** + * Convert wind speed into another unit. + * + * @param {number} windInMS the windspeed in meter/sec you want to convert + * @param {string} unit can be 'beaufort', 'kmh', 'knots, 'imperial' (mph) + * or 'metric' (mps) + * @returns {number} the converted windspeed + */ + convertWind(windInMS, unit) { + switch (unit) { + 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 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; + }, + + convertWindToMetric(mph) { + return mph / 2.2369362920544; + }, + + convertWindToMs(kmh) { + return kmh * 0.27777777777778; + } +}; + +if (typeof module !== "undefined") { + module.exports = WeatherUtils; +} diff --git a/tests/unit/functions/weather_object_spec.js b/tests/unit/functions/weather_object_spec.js index 57535e70..188f07e0 100644 --- a/tests/unit/functions/weather_object_spec.js +++ b/tests/unit/functions/weather_object_spec.js @@ -1,4 +1,5 @@ const WeatherObject = require("../../../modules/default/weather/weatherobject.js"); +const WeatherUtils = require("../../../modules/default/weather/weatherutils.js"); global.moment = require("moment-timezone"); global.SunCalc = require("suncalc"); @@ -25,15 +26,21 @@ 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); }); }); + +describe("WeatherObject", () => { + it("should convert windspeed correctly from mph to mps", () => { + expect(Math.round(WeatherUtils.convertWindToMetric(93.951324266285))).toBe(42); + }); + + it("should convert windspeed correctly from kmh to mps", () => { + expect(Math.round(WeatherUtils.convertWindToMs(151.2))).toBe(42); + }); + + it("should convert wind direction correctly from cardinal to value", () => { + expect(WeatherUtils.convertWindDirection("SSE")).toBe(157); + }); +});