From ce99e70bf9be6152daa2b9b454ab9543f61808a7 Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Thu, 4 Jun 2020 19:25:13 -0400 Subject: [PATCH 1/7] tweak package; my wxgov.js --- modules/default/weather/providers/weathergov.js | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index c24e4de1..a86c3bea 100755 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherObject, SunCalc */ +/* global WeatherProvider, WeatherObject */ /* Magic Mirror * Module: Weather @@ -11,6 +11,7 @@ * Note that this is only for US locations (lat and lon) and does not require an API key * Since it is free, there are some items missing - like sunrise, sunset, humidity, etc. */ + WeatherProvider.register("weathergov", { // Set the name of the provider. // This isn't strictly necessary, since it will fallback to the provider identifier diff --git a/package.json b/package.json index f568d73c..8d93e7b6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "The open source modular smart mirror platform.", "main": "js/electron.js", "scripts": { - "start": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js", + "start": "./node_modules/.bin/electron js/electron.js", "server": "node ./serveronly", "install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error", "install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error", From a4aabfcdae7edc2223ab3722754bb48be4695a42 Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Thu, 4 Jun 2020 19:26:09 -0400 Subject: [PATCH 2/7] add the lock file --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 428fd1fe..20930a94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4634,9 +4634,9 @@ "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" }, "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", + "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" }, "mri": { "version": "1.1.5", From df3aa22c59a57b02d01d3c5febe6d8aebe23873f Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Thu, 4 Jun 2020 23:35:32 -0400 Subject: [PATCH 3/7] current appears to be working --- .../default/weather/providers/weathergov.js | 77 ++++++++++++++++++- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index a86c3bea..e56c13a6 100755 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -18,9 +18,37 @@ WeatherProvider.register("weathergov", { // But for debugging (and future alerts) it would be nice to have the real name. providerName: "Weather.gov", + // need setConfig URLs status + configURLs: false, + + //multiple urls involved + forecastURL: "tbd", + forecastHourlyURL: "tbd", + forecastGridDataURL: "tbd", + observationStationsURL: "tbd", + stationObsURL: "tbd", + + // Called to set the config, this config is the same as the weather module's config. + setConfig: function (config) { + this.config = config; + Log.info(`Weather provider: ${this.providerName} config set.`, this.config); + // URLs needed from weather.gov + this.fetchWxGovURLs(this.config); + }, + + // Called when the weather provider is about to start. + start: function () { + Log.info(`Weather provider: ${this.providerName} started.`); + }, + // Overwrite the fetchCurrentWeather method. fetchCurrentWeather() { - this.fetchData(this.getUrl()) + if (!this.configURLs) { + Log.info("fetch wx waiting on config URLs"); + return; + } + // this.fetchData(this.getUrl()) + this.fetchData(this.forecastURL) .then((data) => { if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) { // Did not receive usable new data. @@ -37,9 +65,14 @@ WeatherProvider.register("weathergov", { .finally(() => this.updateAvailable()); }, - // Overwrite the fetchCurrentWeather method. + // Overwrite the fetchWeatherForecast method. fetchWeatherForecast() { - this.fetchData(this.getUrl()) + if (!this.configURLs) { + Log.info("fetch wx waiting on config URLs"); + return; + } + //this.fetchData(this.getUrl()) + this.fetchData(this.forecastHourlyURL) .then((data) => { if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) { // Did not receive usable new data. @@ -57,6 +90,44 @@ WeatherProvider.register("weathergov", { }, /** Weather.gov Specific Methods - These are not part of the default provider methods */ + + /* + * Get specific URLs + */ + fetchWxGovURLs(config) { + // wxCtl.initialLoadDelay here ? + this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`) + .then((data) => { + if (!data || !data.properties) { + // points URL did not respond with usable data. + return; + } + this.forecastURL = data.properties.forecast; + Log.log(this.forecastURL); + this.forecastHourlyURL = data.properties.forecastHourly; + this.forecastGridDataURL = data.properties.forecastGridData; + this.observationStationsURL = data.properties.observationStations; + // with this URL, we chain another promise for the station obs URL + return this.fetchData(data.properties.observationStations); + //const wxStations = await this.fetchData(wxPoints.properties.observationStationsURL); + }) + .then((obsData) => { + if (!obsData || !obsData.features) { + // obs station URL did not respond with usable data. + return; + } + this.stationObsURL = obsData.features[0].id + "/observations/latest"; + Log.log(this.stationObsURL); + }) + .catch((err) => { + Log.error(err); + }) + .finally(() => { + this.configURLs = true; + this.fetchCurrentWeather(); + }); + }, + /* * Gets the complete url for the request */ From 9d2d170c2d4014f0ba5e11cfaf52410e1d35adb0 Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Sat, 13 Jun 2020 11:58:06 -0400 Subject: [PATCH 4/7] add additional URLs per API --- .../default/weather/providers/weathergov.js | 103 ++++++++++++------ 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index e56c13a6..c41742fa 100755 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -3,13 +3,14 @@ /* Magic Mirror * Module: Weather * Provider: weather.gov + * https://weather-gov.github.io/api/general-faqs * - * By Vince Peri + * Original by Vince Peri * MIT Licensed. * * This class is a provider for weather.gov. * Note that this is only for US locations (lat and lon) and does not require an API key - * Since it is free, there are some items missing - like sunrise, sunset, humidity, etc. + * Since it is free, there are some items missing - like sunrise, sunset */ WeatherProvider.register("weathergov", { @@ -18,10 +19,10 @@ WeatherProvider.register("weathergov", { // But for debugging (and future alerts) it would be nice to have the real name. providerName: "Weather.gov", - // need setConfig URLs status + // Flag all needed URLs availability configURLs: false, - //multiple urls involved + //This API has multiple urls involved forecastURL: "tbd", forecastHourlyURL: "tbd", forecastGridDataURL: "tbd", @@ -31,9 +32,7 @@ WeatherProvider.register("weathergov", { // Called to set the config, this config is the same as the weather module's config. setConfig: function (config) { this.config = config; - Log.info(`Weather provider: ${this.providerName} config set.`, this.config); - // URLs needed from weather.gov - this.fetchWxGovURLs(this.config); + (this.config.apiBase = "https://api.weather.gov"), this.fetchWxGovURLs(this.config); }, // Called when the weather provider is about to start. @@ -41,26 +40,28 @@ WeatherProvider.register("weathergov", { Log.info(`Weather provider: ${this.providerName} started.`); }, + // This returns the name of the fetched location or an empty string. + fetchedLocation: function () { + return this.fetchedLocationName || ""; + }, + // Overwrite the fetchCurrentWeather method. fetchCurrentWeather() { if (!this.configURLs) { Log.info("fetch wx waiting on config URLs"); return; } - // this.fetchData(this.getUrl()) - this.fetchData(this.forecastURL) + this.fetchData(this.stationObsURL) .then((data) => { - if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) { + if (!data || !data.properties) { // Did not receive usable new data. - // Maybe this needs a better check? return; } - - const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties.periods[0]); + const currentWeather = this.generateWeatherObjectFromCurrentWeather(data.properties); this.setCurrentWeather(currentWeather); }) .catch(function (request) { - Log.error("Could not load data ... ", request); + Log.error("Could not load station obs data ... ", request); }) .finally(() => this.updateAvailable()); }, @@ -71,20 +72,17 @@ WeatherProvider.register("weathergov", { Log.info("fetch wx waiting on config URLs"); return; } - //this.fetchData(this.getUrl()) - this.fetchData(this.forecastHourlyURL) + this.fetchData(this.forecastURL) .then((data) => { if (!data || !data.properties || !data.properties.periods || !data.properties.periods.length) { // Did not receive usable new data. - // Maybe this needs a better check? return; } - const forecast = this.generateWeatherObjectsFromForecast(data.properties.periods); this.setWeatherForecast(forecast); }) .catch(function (request) { - Log.error("Could not load data ... ", request); + Log.error("Could not load forecast hourly data ... ", request); }) .finally(() => this.updateAvailable()); }, @@ -95,21 +93,20 @@ WeatherProvider.register("weathergov", { * Get specific URLs */ fetchWxGovURLs(config) { - // wxCtl.initialLoadDelay here ? this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`) .then((data) => { if (!data || !data.properties) { // points URL did not respond with usable data. return; } + this.fetchedLocationName = data.properties.relativeLocation.properties.city + ", " + data.properties.relativeLocation.properties.state; + Log.log("Forecast location is " + this.fetchedLocationName); this.forecastURL = data.properties.forecast; - Log.log(this.forecastURL); this.forecastHourlyURL = data.properties.forecastHourly; this.forecastGridDataURL = data.properties.forecastGridData; this.observationStationsURL = data.properties.observationStations; // with this URL, we chain another promise for the station obs URL return this.fetchData(data.properties.observationStations); - //const wxStations = await this.fetchData(wxPoints.properties.observationStationsURL); }) .then((obsData) => { if (!obsData || !obsData.features) { @@ -117,34 +114,44 @@ WeatherProvider.register("weathergov", { return; } this.stationObsURL = obsData.features[0].id + "/observations/latest"; - Log.log(this.stationObsURL); }) .catch((err) => { Log.error(err); }) .finally(() => { + // excellent, let's fetch some actual wx data this.configURLs = true; this.fetchCurrentWeather(); }); }, - /* - * Gets the complete url for the request - */ - getUrl() { - return this.config.apiBase + this.config.lat + "," + this.config.lon + this.config.weatherEndpoint; - }, - /* * Generate a WeatherObject based on currentWeatherInformation + * Weather.gov API uses specific units; API does not include choice of units + * ... object needs data in units based on config! */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); - currentWeather.temperature = currentWeatherData.temperature; - currentWeather.windSpeed = currentWeatherData.windSpeed.split(" ", 1); - currentWeather.windDirection = this.convertWindDirection(currentWeatherData.windDirection); - currentWeather.weatherType = this.convertWeatherType(currentWeatherData.shortForecast, currentWeatherData.isDaytime); + currentWeather.date = moment(currentWeatherData.timestamp); + currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value); + currentWeather.windSpeed = this.covertSpeed(currentWeatherData.windSpeed.value); + currentWeather.windDirection = currentWeatherData.windDirection.value; + currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value); + currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value); + currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value); + currentWeather.rain = null; + currentWeather.snow = null; + 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); @@ -220,6 +227,34 @@ WeatherProvider.register("weathergov", { return days.slice(1); }, + /* + * Unit conversions + */ + // conversion to fahrenheit + convertTemp(temp) { + if (this.config.tempUnits === "imperial") { + return (9 / 5) * temp + 32; + } else { + return temp; + } + }, + // conversion to mph + covertSpeed(metSec) { + if (this.config.windUnits === "imperial") { + return metSec * 2.23694; + } else { + return metSec; + } + }, + // conversion to inches + convertLength(meters) { + if (this.config.units === "imperial") { + return meters * 39.3701; + } else { + return meters; + } + }, + /* * Calculate the astronomical data */ From 12441212162b62a6f247f7a1f2185f426bb188cb Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Sat, 11 Jul 2020 15:01:16 -0400 Subject: [PATCH 5/7] change weathergov.js for multi-URL api --- modules/default/weather/providers/weathergov.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index c41742fa..1b28bba1 100755 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -1,4 +1,4 @@ -/* global WeatherProvider, WeatherObject */ +/* global WeatherProvider, WeatherObject, SunCalc */ /* Magic Mirror * Module: Weather @@ -203,7 +203,7 @@ WeatherProvider.register("weathergov", { // specify date weather.date = moment(forecast.startTime); - // If the first value of today is later than 17:00, we have an icon at least! + // use the forecast isDayTime attribute to help build the weatherType label weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime); } From c1e38b917e384470ee5c565f39457f170aef083d Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Sat, 11 Jul 2020 15:06:24 -0400 Subject: [PATCH 6/7] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5bc9b4..ad6a5f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ _This release is scheduled to be released on 2020-10-01._ - Fix calendar display. Account for current timezone. [#2068](https://github.com/MichMich/MagicMirror/issues/2068) - Fix logLevel being set before loading config. - Fix incorrect namespace links in svg clockfaces. [#2072](https://github.com/MichMich/MagicMirror/issues/2072) +- Fix weather/providers/weathergov for API guidelines [#2045] ## [2.12.0] - 2020-07-01 From e949af6fd55f47996c21e4d6a4306a5cb404a014 Mon Sep 17 00:00:00 2001 From: easyas314 <30437725+easyas314@users.noreply.github.com> Date: Sat, 11 Jul 2020 16:13:31 -0400 Subject: [PATCH 7/7] revert package.json --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 70658c2c..e421d505 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4749,9 +4749,9 @@ "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" }, "moment": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", - "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "mri": { "version": "1.1.5", diff --git a/package.json b/package.json index 4b8bf9e8..63d9fcdd 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "The open source modular smart mirror platform.", "main": "js/electron.js", "scripts": { - "start": "./node_modules/.bin/electron js/electron.js", + "start": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js", "server": "node ./serveronly", "install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error", "install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error",