From 4915ad8fc778c220df5edbc9598a83b63dd40729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Sun, 28 Aug 2022 20:21:49 +0200 Subject: [PATCH 1/6] feat(weather/smhi): support hourly forecasts --- modules/default/weather/providers/smhi.js | 29 +++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index dea1f1b22d..4bced3e0c9 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -21,7 +21,7 @@ WeatherProvider.register("smhi", { }, /** - * Implements method in interface for fetching current weather + * Implements method in interface for fetching current weather. */ fetchCurrentWeather() { this.fetchData(this.getURL()) @@ -37,14 +37,13 @@ WeatherProvider.register("smhi", { }, /** - * Implements method in interface for fetching a forecast. - * Handling hourly forecast would be easy as not grouping by day but it seems really specific for one weather provider for now. + * Implements method in interface for fetching a multi-day forecast. */ fetchWeatherForecast() { this.fetchData(this.getURL()) .then((data) => { let coordinates = this.resolveCoordinates(data); - let weatherObjects = this.convertWeatherDataGroupedByDay(data.timeSeries, coordinates); + const weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates); this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`); this.setWeatherForecast(weatherObjects); }) @@ -52,6 +51,21 @@ WeatherProvider.register("smhi", { .finally(() => this.updateAvailable()); }, + /** + * Implements method in interface for fetching hourly forecasts. + */ + fetchWeatherHourly() { + this.fetchData(this.getURL()) + .then((data) => { + let coordinates = this.resolveCoordinates(data); + let weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates, "hour"); + this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`); + this.setWeatherHourly(weatherObjects); + }) + .catch((error) => Log.error("Could not load data: " + error.message)) + .finally(() => this.updateAvailable()); + }, + /** * Overrides method for setting config with checks for the precipitationValue being unset or invalid * @@ -149,7 +163,7 @@ WeatherProvider.register("smhi", { * @param {object} coordinates Coordinates of the locations of the weather * @returns {WeatherObject[]} Array of weatherobjects */ - convertWeatherDataGroupedByDay(allWeatherData, coordinates) { + convertWeatherDataGroupedBy(allWeatherData, coordinates, groupBy = "day") { let currentWeather; let result = []; @@ -157,10 +171,11 @@ WeatherProvider.register("smhi", { let dayWeatherTypes = []; for (const weatherObject of allWeatherObjects) { - //If its the first object or if a day change we need to reset the summary object - if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, "day")) { + //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); dayWeatherTypes = []; + currentWeather.temperature = weatherObject.temperature; currentWeather.date = weatherObject.date; currentWeather.minTemperature = Infinity; currentWeather.maxTemperature = -Infinity; From 48756e877403d914c64c8da06a4f7e5bfbace07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Sun, 28 Aug 2022 20:23:01 +0200 Subject: [PATCH 2/6] feat(weather/smhi): calculate apparent temperature --- modules/default/weather/providers/smhi.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index 4bced3e0c9..25a266085c 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -108,6 +108,16 @@ WeatherProvider.register("smhi", { return `https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/${lon}/lat/${lat}/data.json`; }, + /** Calculates the apparent temperature based on known atmospheric data. */ + calculateApparentTemperature(weatherData) { + const Ta = this.paramValue(weatherData, "t"); + const rh = this.paramValue(weatherData, "r"); + const ws = this.paramValue(weatherData, "ws"); + const p = (rh / 100) * 6.105 * Math.E * ((17.27 * Ta) / (237.7 + Ta)) + + return Ta + 0.33 * p - 0.7 * ws - 4 + }, + /** * Converts the returned data into a WeatherObject with required properties set for both current weather and forecast. * The returned units is always in metric system. @@ -128,6 +138,7 @@ WeatherProvider.register("smhi", { currentWeather.windSpeed = this.paramValue(weatherData, "ws"); currentWeather.windDirection = this.paramValue(weatherData, "wd"); currentWeather.weatherType = this.convertWeatherType(this.paramValue(weatherData, "Wsymb2"), currentWeather.isDayTime()); + currentWeather.feelsLikeTemp = this.calculateAT(weatherData); // Determine the precipitation amount and category and update the // weatherObject with it, the valuetype to use can be configured or uses From 0a1067ec7d72271a6296ca4b8a0ad392e1ce90fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Sun, 28 Aug 2022 20:23:43 +0200 Subject: [PATCH 3/6] feat(weather/smhi): support custom location names --- modules/default/weather/providers/smhi.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index 25a266085c..ce5ac772c4 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -17,7 +17,8 @@ WeatherProvider.register("smhi", { defaults: { lat: 0, lon: 0, - precipitationValue: "pmedian" + precipitationValue: "pmedian", + location: false, }, /** @@ -29,7 +30,7 @@ WeatherProvider.register("smhi", { let closest = this.getClosestToCurrentTime(data.timeSeries); let coordinates = this.resolveCoordinates(data); let weatherObject = this.convertWeatherDataToObject(closest, coordinates); - this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`); + this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`); this.setCurrentWeather(weatherObject); }) .catch((error) => Log.error("Could not load data: " + error.message)) @@ -43,8 +44,8 @@ WeatherProvider.register("smhi", { this.fetchData(this.getURL()) .then((data) => { let coordinates = this.resolveCoordinates(data); - const weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates); - this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`); + let weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates); + this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`); this.setWeatherForecast(weatherObjects); }) .catch((error) => Log.error("Could not load data: " + error.message)) @@ -59,7 +60,7 @@ WeatherProvider.register("smhi", { .then((data) => { let coordinates = this.resolveCoordinates(data); let weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates, "hour"); - this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`); + this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`); this.setWeatherHourly(weatherObjects); }) .catch((error) => Log.error("Could not load data: " + error.message)) From 6f273d76b3c3eda8580df4646bdd83a6facb0989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Sun, 28 Aug 2022 20:36:52 +0200 Subject: [PATCH 4/6] chore: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50562df169..0cd76213ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ _This release is scheduled to be released on 2022-10-01._ - Possibility to fetch calendars through socket notifications. - New scripts `install-mm` (and `install-mm:dev`) for simplifying mm installation (now: `npm run install-mm`) and adding params `--no-audit --no-fund --no-update-notifier` for less noise. - New `showTimeToday` option in calendar module shows time for current-day events even if `timeFormat` is `"relative"` +- Add hourly forecasts, apparent temperature & custom location name to SMHI weather provider ## Updated From 02cf9b37e23eee624b5b39383195d26c7aa6c9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Mon, 29 Aug 2022 20:08:27 +0200 Subject: [PATCH 5/6] refactor: use `const` instead of `let` --- modules/default/weather/providers/smhi.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index ce5ac772c4..faa5d19620 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -27,9 +27,9 @@ WeatherProvider.register("smhi", { fetchCurrentWeather() { this.fetchData(this.getURL()) .then((data) => { - let closest = this.getClosestToCurrentTime(data.timeSeries); - let coordinates = this.resolveCoordinates(data); - let weatherObject = this.convertWeatherDataToObject(closest, coordinates); + const closest = this.getClosestToCurrentTime(data.timeSeries); + const coordinates = this.resolveCoordinates(data); + const weatherObject = this.convertWeatherDataToObject(closest, coordinates); this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`); this.setCurrentWeather(weatherObject); }) @@ -43,8 +43,8 @@ WeatherProvider.register("smhi", { fetchWeatherForecast() { this.fetchData(this.getURL()) .then((data) => { - let coordinates = this.resolveCoordinates(data); - let weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates); + const coordinates = this.resolveCoordinates(data); + const weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates); this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`); this.setWeatherForecast(weatherObjects); }) @@ -58,8 +58,8 @@ WeatherProvider.register("smhi", { fetchWeatherHourly() { this.fetchData(this.getURL()) .then((data) => { - let coordinates = this.resolveCoordinates(data); - let weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates, "hour"); + const coordinates = this.resolveCoordinates(data); + const weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates, "hour"); this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`); this.setWeatherHourly(weatherObjects); }) From 50f72f09ac0921e9f12008ff5b1010d9cc13aee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Tue, 30 Aug 2022 10:06:34 +0200 Subject: [PATCH 6/6] refactor: fix linting & code style issues --- modules/default/weather/providers/smhi.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index faa5d19620..5e1ef4a3db 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -18,7 +18,7 @@ WeatherProvider.register("smhi", { lat: 0, lon: 0, precipitationValue: "pmedian", - location: false, + location: false }, /** @@ -109,14 +109,19 @@ WeatherProvider.register("smhi", { return `https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/${lon}/lat/${lat}/data.json`; }, - /** Calculates the apparent temperature based on known atmospheric data. */ + /** + * Calculates the apparent temperature based on known atmospheric data. + * + * @param {object} weatherData Weatherdata to use for the calculation + * @returns {number} The apparent temperature + */ calculateApparentTemperature(weatherData) { const Ta = this.paramValue(weatherData, "t"); const rh = this.paramValue(weatherData, "r"); const ws = this.paramValue(weatherData, "ws"); - const p = (rh / 100) * 6.105 * Math.E * ((17.27 * Ta) / (237.7 + Ta)) + const p = (rh / 100) * 6.105 * Math.E * ((17.27 * Ta) / (237.7 + Ta)); - return Ta + 0.33 * p - 0.7 * ws - 4 + return Ta + 0.33 * p - 0.7 * ws - 4; }, /** @@ -173,6 +178,7 @@ WeatherProvider.register("smhi", { * * @param {object[]} allWeatherData Array of weatherdata * @param {object} coordinates Coordinates of the locations of the weather + * @param {string} groupBy The interval to use for grouping the data (day, hour) * @returns {WeatherObject[]} Array of weatherobjects */ convertWeatherDataGroupedBy(allWeatherData, coordinates, groupBy = "day") {