Skip to content

Commit

Permalink
Refactor common weather methods into utils class (#2958)
Browse files Browse the repository at this point in the history
Co-authored-by: veeck <[email protected]>
  • Loading branch information
rejas and veeck authored Oct 28, 2022
1 parent dde8860 commit c191ff0
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 111 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions modules/default/weather/providers/envcanada.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeatherProvider, WeatherObject */
/* global WeatherProvider, WeatherObject, WeatherUtils */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions modules/default/weather/providers/ukmetoffice.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeatherProvider, WeatherObject */
/* global WeatherProvider, WeatherObject, WeatherUtils */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions modules/default/weather/providers/weatherflow.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeatherProvider, WeatherObject */
/* global WeatherProvider, WeatherObject, WeatherUtils */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions modules/default/weather/providers/weathergov.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeatherProvider, WeatherObject */
/* global WeatherProvider, WeatherObject, WeatherUtils */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -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;
Expand Down
61 changes: 4 additions & 57 deletions modules/default/weather/weather.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global WeatherProvider */
/* global WeatherProvider, WeatherUtils */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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",
Expand All @@ -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";
Expand All @@ -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)
Expand Down
40 changes: 3 additions & 37 deletions modules/default/weather/weatherobject.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global SunCalc */
/* global SunCalc, WeatherUtils */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -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";
}
Expand All @@ -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) {
Expand Down
98 changes: 98 additions & 0 deletions modules/default/weather/weatherutils.js
Original file line number Diff line number Diff line change
@@ -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;
}
17 changes: 12 additions & 5 deletions tests/unit/functions/weather_object_spec.js
Original file line number Diff line number Diff line change
@@ -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");
Expand All @@ -25,15 +26,21 @@ describe("WeatherObject", () => {
expect(weatherobject.isDayTime()).toBe(false);
});

afterAll(() => {
moment.tz.setDefault(originalTimeZone);
});
});

describe("WeatherObject", () => {
it("should convert windspeed correctly from mph to mps", () => {
expect(Math.round(weatherobject.convertWindToMetric(93.951324266285))).toBe(42);
expect(Math.round(WeatherUtils.convertWindToMetric(93.951324266285))).toBe(42);
});

it("should convert wind direction correctly from cardinal to value", () => {
expect(weatherobject.valueWindDirection("SSE")).toBe(157);
it("should convert windspeed correctly from kmh to mps", () => {
expect(Math.round(WeatherUtils.convertWindToMs(151.2))).toBe(42);
});

afterAll(() => {
moment.tz.setDefault(originalTimeZone);
it("should convert wind direction correctly from cardinal to value", () => {
expect(WeatherUtils.convertWindDirection("SSE")).toBe(157);
});
});

0 comments on commit c191ff0

Please sign in to comment.