Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor common weather methods into utils class #2958

Merged
merged 2 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
});
});