mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 19:53:36 +00:00
Merge pull request #2648 from rejas/weather_cleanup
Add common methods to weatherobject
This commit is contained in:
commit
06389e35f9
@ -23,7 +23,9 @@
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"eqeqeq": "error",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-unused-vars": "off"
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-return": "error"
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ _This release is scheduled to be released on 2021-10-01._
|
||||
- Refactor test configs, use default test config for all tests.
|
||||
- Updated github templates.
|
||||
- Actually test all js and css files when lint script is run.
|
||||
- Update jsdocs and print warnings during testing too
|
||||
- Update jsdocs and print warnings during testing too.
|
||||
- Update weathergov provider to try fetching not just current, but also foreacst, when API URLs available.
|
||||
- Refactored clock layout
|
||||
- Refactored clock layout.
|
||||
- Refactored methods from weatherproviders into weatherobject (isDaytime, updateSunTime).
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -164,9 +164,7 @@ WeatherProvider.register("envcanada", {
|
||||
// CORS errors when accessing EC
|
||||
//
|
||||
getUrl() {
|
||||
const path = "https://thingproxy.freeboard.io/fetch/https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml";
|
||||
|
||||
return path;
|
||||
return "https://thingproxy.freeboard.io/fetch/https://dd.weather.gc.ca/citypage_weather/xml/" + this.config.provCode + "/" + this.config.siteCode + "_e.xml";
|
||||
},
|
||||
|
||||
//
|
||||
@ -513,8 +511,6 @@ WeatherProvider.register("envcanada", {
|
||||
weather.maxTemperature = this.convertTemp(nextTemp);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
//
|
||||
@ -560,8 +556,6 @@ WeatherProvider.register("envcanada", {
|
||||
weather.precipitation = foreGroup[today].querySelector("abbreviatedForecast pop").textContent;
|
||||
weather.precipitationUnits = foreGroup[today].querySelector("abbreviatedForecast pop").getAttribute("units");
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
//
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* global WeatherProvider, WeatherObject, SunCalc */
|
||||
/* global WeatherProvider, WeatherObject */
|
||||
|
||||
/* Magic Mirror
|
||||
* Module: Weather
|
||||
@ -105,19 +105,20 @@ WeatherProvider.register("smhi", {
|
||||
* @returns {WeatherObject} The converted weatherdata at the specified location
|
||||
*/
|
||||
convertWeatherDataToObject(weatherData, coordinates) {
|
||||
let currentWeather = new WeatherObject("metric", "metric", "metric"); //Weather data is only for Sweden and nobody in Sweden would use imperial
|
||||
// Weather data is only for Sweden and nobody in Sweden would use imperial
|
||||
let currentWeather = new WeatherObject("metric", "metric", "metric");
|
||||
|
||||
currentWeather.date = moment(weatherData.validTime);
|
||||
let times = SunCalc.getTimes(currentWeather.date.toDate(), coordinates.lat, coordinates.lon);
|
||||
currentWeather.sunrise = moment(times.sunrise, "X");
|
||||
currentWeather.sunset = moment(times.sunset, "X");
|
||||
currentWeather.updateSunTime(coordinates.lat, coordinates.lon);
|
||||
currentWeather.humidity = this.paramValue(weatherData, "r");
|
||||
currentWeather.temperature = this.paramValue(weatherData, "t");
|
||||
currentWeather.windSpeed = this.paramValue(weatherData, "ws");
|
||||
currentWeather.windDirection = this.paramValue(weatherData, "wd");
|
||||
currentWeather.weatherType = this.convertWeatherType(this.paramValue(weatherData, "Wsymb2"), this.isDayTime(currentWeather));
|
||||
currentWeather.weatherType = this.convertWeatherType(this.paramValue(weatherData, "Wsymb2"), currentWeather.isDayTime());
|
||||
|
||||
//Determine the precipitation amount and category and update the weatherObject with it, the valuetype to use can be configured or uses median as default.
|
||||
// Determine the precipitation amount and category and update the
|
||||
// weatherObject with it, the valuetype to use can be configured or uses
|
||||
// median as default.
|
||||
let precipitationValue = this.paramValue(weatherData, this.config.precipitationValue);
|
||||
switch (this.paramValue(weatherData, "pcat")) {
|
||||
// 0 = No precipitation
|
||||
@ -171,7 +172,7 @@ WeatherProvider.register("smhi", {
|
||||
}
|
||||
|
||||
//Keep track of what icons has been used for each hour of daytime and use the middle one for the forecast
|
||||
if (this.isDayTime(weatherObject)) {
|
||||
if (weatherObject.isDayTime()) {
|
||||
dayWeatherTypes.push(weatherObject.weatherType);
|
||||
}
|
||||
if (dayWeatherTypes.length > 0) {
|
||||
@ -201,16 +202,6 @@ WeatherProvider.register("smhi", {
|
||||
return { lat: data.geometry.coordinates[0][1], lon: data.geometry.coordinates[0][0] };
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the weatherObject is at dayTime.
|
||||
*
|
||||
* @param {WeatherObject} weatherObject The weatherObject to look at
|
||||
* @returns {boolean} true if it is at dayTime
|
||||
*/
|
||||
isDayTime(weatherObject) {
|
||||
return weatherObject.date.isBetween(weatherObject.sunrise, weatherObject.sunset, undefined, "[]");
|
||||
},
|
||||
|
||||
/**
|
||||
* The distance between the data points is increasing in the data the more distant the prediction is.
|
||||
* Find these gaps and fill them with the previous hours data to make the data returned a complete set.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* global WeatherProvider, WeatherObject, SunCalc */
|
||||
/* global WeatherProvider, WeatherObject */
|
||||
|
||||
/* Magic Mirror
|
||||
* Module: Weather
|
||||
@ -116,9 +116,7 @@ WeatherProvider.register("ukmetoffice", {
|
||||
}
|
||||
|
||||
// determine the sunrise/sunset times - not supplied in UK Met Office data
|
||||
let times = this.calcAstroData(location);
|
||||
currentWeather.sunrise = times[0];
|
||||
currentWeather.sunset = times[1];
|
||||
currentWeather.updateSunTime(location.lat, location.lon);
|
||||
|
||||
return currentWeather;
|
||||
},
|
||||
@ -154,20 +152,6 @@ WeatherProvider.register("ukmetoffice", {
|
||||
return days;
|
||||
},
|
||||
|
||||
/*
|
||||
* calculate the astronomical data
|
||||
*/
|
||||
calcAstroData(location) {
|
||||
const sunTimes = [];
|
||||
|
||||
// determine the sunrise/sunset times
|
||||
let times = SunCalc.getTimes(new Date(), location.lat, location.lon);
|
||||
sunTimes.push(moment(times.sunrise, "X"));
|
||||
sunTimes.push(moment(times.sunset, "X"));
|
||||
|
||||
return sunTimes;
|
||||
},
|
||||
|
||||
/*
|
||||
* Convert the Met Office icons to a more usable name.
|
||||
*/
|
||||
@ -248,16 +232,16 @@ WeatherProvider.register("ukmetoffice", {
|
||||
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
||||
},
|
||||
|
||||
/*
|
||||
/**
|
||||
* Generates an url with api parameters based on the config.
|
||||
*
|
||||
* return String - URL params.
|
||||
* @param {string} forecastType daily or 3hourly forecast
|
||||
* @returns {string} url
|
||||
*/
|
||||
getParams(forecastType) {
|
||||
let params = "?";
|
||||
params += "res=" + forecastType;
|
||||
params += "&key=" + this.config.apiKey;
|
||||
|
||||
return params;
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* global WeatherProvider, WeatherObject, SunCalc */
|
||||
/* global WeatherProvider, WeatherObject */
|
||||
|
||||
/* Magic Mirror
|
||||
* Module: Weather
|
||||
@ -71,13 +71,11 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
// For DataHub requests, the API key/secret are sent in the headers rather than as query strings.
|
||||
// Headers defined according to Data Hub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
|
||||
getHeaders() {
|
||||
let headers = {
|
||||
return {
|
||||
accept: "application/json",
|
||||
"x-ibm-client-id": this.config.apiKey,
|
||||
"x-ibm-client-secret": this.config.apiSecret
|
||||
};
|
||||
|
||||
return headers;
|
||||
},
|
||||
|
||||
// Fetch data using supplied URL and request headers
|
||||
@ -150,11 +148,9 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
}
|
||||
|
||||
// Determine the sunrise/sunset times - (still) not supplied in UK Met Office data
|
||||
// Passes {longitude, latitude, height} to calcAstroData
|
||||
// Could just pass lat/long from this.config, but returned data from MO also contains elevation
|
||||
let times = this.calcAstroData(currentWeatherData.features[0].geometry.coordinates);
|
||||
currentWeather.sunrise = times[0];
|
||||
currentWeather.sunset = times[1];
|
||||
// Passes {longitude, latitude} to SunCalc, could pass height to, but
|
||||
// SunCalc.getTimes doesnt take that into account
|
||||
currentWeather.updateSunTime(this.config.lat, this.config.lon);
|
||||
|
||||
return currentWeather;
|
||||
},
|
||||
@ -223,7 +219,6 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
|
||||
// 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)
|
||||
|
||||
forecastWeather.rawData = forecastDataDays[day];
|
||||
|
||||
dailyForecasts.push(forecastWeather);
|
||||
@ -238,18 +233,6 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
this.fetchedLocationName = name;
|
||||
},
|
||||
|
||||
// Calculate sunrise/sunset times
|
||||
calcAstroData(location) {
|
||||
const sunTimes = [];
|
||||
|
||||
// Careful to pass values to SunCalc in correct order (latitude, longitude, elevation)
|
||||
let times = SunCalc.getTimes(new Date(), location[1], location[0], location[2]);
|
||||
sunTimes.push(moment(times.sunrise, "X"));
|
||||
sunTimes.push(moment(times.sunset, "X"));
|
||||
|
||||
return sunTimes;
|
||||
},
|
||||
|
||||
// Convert temperatures to Fahrenheit (from degrees C), if required
|
||||
convertTemp(tempInC) {
|
||||
return this.config.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC;
|
||||
|
@ -89,7 +89,6 @@ WeatherProvider.register("weatherbit", {
|
||||
currentWeather.windSpeed = parseFloat(currentWeatherData.data[0].wind_spd);
|
||||
currentWeather.windDirection = currentWeatherData.data[0].wind_dir;
|
||||
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.data[0].weather.icon);
|
||||
Log.log("Wx Icon: " + currentWeatherData.data[0].weather.icon);
|
||||
currentWeather.sunrise = moment(currentWeatherData.data[0].sunrise, "HH:mm").add(tzOffset, "m");
|
||||
currentWeather.sunset = moment(currentWeatherData.data[0].sunset, "HH:mm").add(tzOffset, "m");
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* global WeatherProvider, WeatherObject, SunCalc */
|
||||
/* global WeatherProvider, WeatherObject */
|
||||
|
||||
/* Magic Mirror
|
||||
* Module: Weather
|
||||
@ -130,7 +130,7 @@ WeatherProvider.register("weathergov", {
|
||||
// excellent, let's fetch some actual wx data
|
||||
this.configURLs = true;
|
||||
// handle 'forecast' config, fall back to 'current'
|
||||
if (config.type == "forecast") {
|
||||
if (config.type === "forecast") {
|
||||
this.fetchWeatherForecast();
|
||||
} else {
|
||||
this.fetchCurrentWeather();
|
||||
@ -158,18 +158,11 @@ WeatherProvider.register("weathergov", {
|
||||
currentWeather.precipitation = this.convertLength(currentWeatherData.precipitationLastHour.value);
|
||||
currentWeather.feelsLikeTemp = this.convertTemp(currentWeatherData.heatIndex.value);
|
||||
|
||||
let isDaytime = true;
|
||||
if (currentWeatherData.icon.includes("day")) {
|
||||
isDaytime = true;
|
||||
} else {
|
||||
isDaytime = false;
|
||||
}
|
||||
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.textDescription, isDaytime);
|
||||
|
||||
// determine the sunrise/sunset times - not supplied in weather.gov data
|
||||
let times = this.calcAstroData(this.config.lat, this.config.lon);
|
||||
currentWeather.sunrise = times[0];
|
||||
currentWeather.sunset = times[1];
|
||||
currentWeather.updateSunTime(this.config.lat, this.config.lon);
|
||||
|
||||
// update weatherType
|
||||
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.textDescription, currentWeather.isDayTime());
|
||||
|
||||
return currentWeather;
|
||||
},
|
||||
@ -272,20 +265,6 @@ WeatherProvider.register("weathergov", {
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Calculate the astronomical data
|
||||
*/
|
||||
calcAstroData(lat, lon) {
|
||||
const sunTimes = [];
|
||||
|
||||
// determine the sunrise/sunset times
|
||||
let times = SunCalc.getTimes(new Date(), lat, lon);
|
||||
sunTimes.push(moment(times.sunrise, "X"));
|
||||
sunTimes.push(moment(times.sunset, "X"));
|
||||
|
||||
return sunTimes;
|
||||
},
|
||||
|
||||
/*
|
||||
* Convert the icons to a more usable name.
|
||||
*/
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* global SunCalc */
|
||||
|
||||
/* Magic Mirror
|
||||
* Module: Weather
|
||||
*
|
||||
@ -10,6 +12,14 @@
|
||||
* As soon as we start implementing the forecast, mode properties will be added.
|
||||
*/
|
||||
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;
|
||||
@ -80,8 +90,7 @@ class WeatherObject {
|
||||
}
|
||||
|
||||
kmhWindSpeed() {
|
||||
const windInKmh = this.windUnits === "imperial" ? this.windSpeed * 1.609344 : (this.windSpeed * 60 * 60) / 1000;
|
||||
return windInKmh;
|
||||
return this.windUnits === "imperial" ? this.windSpeed * 1.609344 : (this.windSpeed * 60 * 60) / 1000;
|
||||
}
|
||||
|
||||
nextSunAction() {
|
||||
@ -113,4 +122,31 @@ class WeatherObject {
|
||||
|
||||
return this.tempUnits === "imperial" ? feelsLike : ((feelsLike - 32) * 5) / 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the weatherObject is at dayTime.
|
||||
*
|
||||
* @returns {boolean} true if it is at dayTime
|
||||
*/
|
||||
isDayTime() {
|
||||
return this.date.isBetween(this.sunrise, this.sunset, undefined, "[]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the sunrise / sunset time depending on the location
|
||||
*
|
||||
* @param {number} lat latitude
|
||||
* @param {number} lon longitude
|
||||
*/
|
||||
updateSunTime(lat, lon) {
|
||||
let now = !this.date ? new Date() : this.date.toDate();
|
||||
let times = SunCalc.getTimes(now, lat, lon);
|
||||
this.sunrise = moment(times.sunrise, "X");
|
||||
this.sunset = moment(times.sunset, "X");
|
||||
}
|
||||
}
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = WeatherObject;
|
||||
}
|
||||
|
15
package-lock.json
generated
15
package-lock.json
generated
@ -44,7 +44,8 @@
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-prettier": "^1.2.0"
|
||||
"stylelint-prettier": "^1.2.0",
|
||||
"suncalc": "^1.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@ -9373,6 +9374,12 @@
|
||||
"node": ">= 8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/suncalc": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.8.0.tgz",
|
||||
"integrity": "sha1-HZiYEJVjB4dQ9JlKlZ5lTYdqy/U=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@ -17712,6 +17719,12 @@
|
||||
"debug": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"suncalc": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.8.0.tgz",
|
||||
"integrity": "sha1-HZiYEJVjB4dQ9JlKlZ5lTYdqy/U=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
|
@ -62,7 +62,8 @@
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-prettier": "^1.2.0"
|
||||
"stylelint-prettier": "^1.2.0",
|
||||
"suncalc": "^1.8.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron": "^13.2.3"
|
||||
|
24
tests/unit/functions/weather_object_spec.js
Normal file
24
tests/unit/functions/weather_object_spec.js
Normal file
@ -0,0 +1,24 @@
|
||||
const WeatherObject = require("../../../modules/default/weather/weatherobject.js");
|
||||
|
||||
global.moment = require("moment");
|
||||
global.SunCalc = require("suncalc");
|
||||
|
||||
describe("WeatherObject", function () {
|
||||
let weatherobject;
|
||||
|
||||
beforeAll(function () {
|
||||
weatherobject = new WeatherObject("metric", "metric", "metric", true);
|
||||
});
|
||||
|
||||
it("should return true for daytime at noon", function () {
|
||||
weatherobject.date = moment(12, "HH");
|
||||
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
|
||||
expect(weatherobject.isDayTime()).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for daytime at midnight", function () {
|
||||
weatherobject.date = moment(0, "HH");
|
||||
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
|
||||
expect(weatherobject.isDayTime()).toBe(false);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user