From d48113f2d9bdc02067f46d34f51c61ab061070df Mon Sep 17 00:00:00 2001 From: buxxi Date: Sat, 23 Jan 2021 10:13:41 +0100 Subject: [PATCH 1/5] Moving openweathermap specific check for hourly into its provider and make invalid types fail nicer --- .../weather/providers/openweathermap.js | 12 ++++++++++ modules/default/weather/weather.js | 23 ++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index 2fde7139..ba8a22a3 100755 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -77,6 +77,18 @@ WeatherProvider.register("openweathermap", { .finally(() => this.updateAvailable()); }, + /** + * Overrides method for setting config to check if endpoint is correct for hourly + * + * @param config + */ + setConfig(config) { + this.config = config; + if (this.config.type === "hourly") { + this.config.weatherEndpoint = "/onecall"; + } + }, + /** OpenWeatherMap Specific Methods - These are not part of the default provider methods */ /* * Gets the complete url for the request diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index defe0ae5..b2214105 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -129,9 +129,9 @@ Module.register("weather", { return `hourly.njk`; case "daily": case "forecast": - return `forecast.njk`; default: - return `${this.config.type.toLowerCase()}.njk`; + //Make the invalid values use the "Loading..." from forecast + return `forecast.njk`; } }, @@ -167,12 +167,19 @@ Module.register("weather", { } setTimeout(() => { - if (this.config.weatherEndpoint === "/onecall") { - this.weatherProvider.fetchWeatherData(); - } else if (this.config.type === "forecast") { - this.weatherProvider.fetchWeatherForecast(); - } else { - this.weatherProvider.fetchCurrentWeather(); + switch (this.config.type.toLowerCase()) { + case "current": + this.weatherProvider.fetchCurrentWeather(); + break; + case "hourly": + this.weatherProvider.fetchWeatherData(); + break; + case "daily": + case "forecast": + this.weatherProvider.fetchWeatherForecast(); + break; + default: + Log.error(`Invalid type ${this.config.type} configured (must be one of 'current', 'hourly', 'daily' or 'forecast')`); } }, nextLoad); }, From e2cfa24686edabf811559b3ebc51d055fd34e7e5 Mon Sep 17 00:00:00 2001 From: buxxi Date: Sat, 23 Jan 2021 10:45:55 +0100 Subject: [PATCH 2/5] make weatherprovider have a method for hourly fetching instead of a generic weatherData --- modules/default/weather/current.njk | 5 +---- modules/default/weather/forecast.njk | 9 ++------- modules/default/weather/hourly.njk | 7 ++----- .../weather/providers/openweathermap.js | 6 +++--- modules/default/weather/weather.js | 4 ++-- modules/default/weather/weatherprovider.js | 18 +++++++++--------- 6 files changed, 19 insertions(+), 30 deletions(-) diff --git a/modules/default/weather/current.njk b/modules/default/weather/current.njk index e863eec4..ef09eb9c 100755 --- a/modules/default/weather/current.njk +++ b/modules/default/weather/current.njk @@ -1,7 +1,4 @@ -{% if current or weatherData %} - {% if weatherData %} - {% set current = weatherData.current %} - {% endif %} +{% if current %} {% if not config.onlyTemp %}
diff --git a/modules/default/weather/forecast.njk b/modules/default/weather/forecast.njk index a031d858..8fa04298 100644 --- a/modules/default/weather/forecast.njk +++ b/modules/default/weather/forecast.njk @@ -1,10 +1,5 @@ -{% if forecast or weatherData %} - {% if weatherData %} - {% set forecast = weatherData.days %} - {% set numSteps = forecast | calcNumEntries %} - {% else %} - {% set numSteps = forecast | calcNumSteps %} - {% endif %} +{% if forecast %} + {% set numSteps = forecast | calcNumSteps %} {% set currentStep = 0 %} {% set forecast = forecast.slice(0, numSteps) %} diff --git a/modules/default/weather/hourly.njk b/modules/default/weather/hourly.njk index 6fe17f6e..3950ece2 100644 --- a/modules/default/weather/hourly.njk +++ b/modules/default/weather/hourly.njk @@ -1,7 +1,4 @@ -{% if hourly or weatherData %} - {% if weatherData %} - {% set hourly = weatherData.hours %} - {% endif %} +{% if hourly %} {% set numSteps = hourly | calcNumEntries %} {% set currentStep = 0 %}
@@ -29,4 +26,4 @@ {% endif %} - + diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index ba8a22a3..fd9b3244 100755 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -56,8 +56,8 @@ WeatherProvider.register("openweathermap", { .finally(() => this.updateAvailable()); }, - // Overwrite the fetchWeatherData method. - fetchWeatherData() { + // Overwrite the fetchWeatherHourly method. + fetchWeatherHourly() { this.fetchData(this.getUrl()) .then((data) => { if (!data) { @@ -69,7 +69,7 @@ WeatherProvider.register("openweathermap", { this.setFetchedLocation(`(${data.lat},${data.lon})`); const weatherData = this.generateWeatherObjectsFromOnecall(data); - this.setWeatherData(weatherData); + this.setWeatherHourly(weatherData.hours); }) .catch(function (request) { Log.error("Could not load data ... ", request); diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index b2214105..d6678134 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -141,7 +141,7 @@ Module.register("weather", { config: this.config, current: this.weatherProvider.currentWeather(), forecast: this.weatherProvider.weatherForecast(), - weatherData: this.weatherProvider.weatherData(), + hourly: this.weatherProvider.weatherHourly(), indoor: { humidity: this.indoorHumidity, temperature: this.indoorTemperature @@ -172,7 +172,7 @@ Module.register("weather", { this.weatherProvider.fetchCurrentWeather(); break; case "hourly": - this.weatherProvider.fetchWeatherData(); + this.weatherProvider.fetchWeatherHourly(); break; case "daily": case "forecast": diff --git a/modules/default/weather/weatherprovider.js b/modules/default/weather/weatherprovider.js index 8642e9a4..2d031b2e 100644 --- a/modules/default/weather/weatherprovider.js +++ b/modules/default/weather/weatherprovider.js @@ -16,7 +16,7 @@ var WeatherProvider = Class.extend({ // Try to not access them directly. currentWeatherObject: null, weatherForecastArray: null, - weatherDataObject: null, + weatherHourlyArray: null, fetchedLocationName: null, // The following properties will be set automatically. @@ -57,10 +57,10 @@ var WeatherProvider = Class.extend({ Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherForecast method.`); }, - // This method should start the API request to fetch the weather forecast. + // This method should start the API request to fetch the weather hourly. // This method should definitely be overwritten in the provider. - fetchWeatherData: function () { - Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherData method.`); + fetchWeatherHourly: function () { + Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherHourly method.`); }, // This returns a WeatherDay object for the current weather. @@ -74,8 +74,8 @@ var WeatherProvider = Class.extend({ }, // This returns an object containing WeatherDay object(s) depending on the type of call. - weatherData: function () { - return this.weatherDataObject; + weatherHourly: function () { + return this.weatherHourlyArray; }, // This returns the name of the fetched location or an empty string. @@ -95,9 +95,9 @@ var WeatherProvider = Class.extend({ this.weatherForecastArray = weatherForecastArray; }, - // Set the weatherDataObject and notify the delegate that new information is available. - setWeatherData: function (weatherDataObject) { - this.weatherDataObject = weatherDataObject; + // Set the weatherHourlyArray and notify the delegate that new information is available. + setWeatherHourlyData: function (weatherHourlyArray) { + this.weatherHourlyArray = weatherHourlyArray; }, // Set the fetched location name. From 41508931bec38038bb56d309ca93a24aa428a64e Mon Sep 17 00:00:00 2001 From: buxxi Date: Sat, 23 Jan 2021 11:21:56 +0100 Subject: [PATCH 3/5] Moving default values regarding specific providers into the providers themselves --- modules/default/weather/providers/darksky.js | 9 +++++++++ modules/default/weather/providers/openweathermap.js | 12 ++++++++++++ modules/default/weather/providers/smhi.js | 9 ++++++++- modules/default/weather/providers/ukmetoffice.js | 7 +++++++ .../default/weather/providers/ukmetofficedatahub.js | 10 ++++++++++ modules/default/weather/providers/weatherbit.js | 9 +++++++++ modules/default/weather/providers/weathergov.js | 8 ++++++++ modules/default/weather/weather.js | 12 +----------- modules/default/weather/weatherprovider.js | 6 ++++-- 9 files changed, 68 insertions(+), 14 deletions(-) diff --git a/modules/default/weather/providers/darksky.js b/modules/default/weather/providers/darksky.js index b2bf4e78..ea073887 100755 --- a/modules/default/weather/providers/darksky.js +++ b/modules/default/weather/providers/darksky.js @@ -15,6 +15,15 @@ WeatherProvider.register("darksky", { // Not strictly required, but helps for debugging. providerName: "Dark Sky", + // Set the default config properties that is specific to this provider + defaults: { + apiBase: "https://cors-anywhere.herokuapp.com/https://api.darksky.net", + weatherEndpoint: "/forecast", + apiKey: "", + lat: 0, + lon: 0 + }, + units: { imperial: "us", metric: "si" diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index fd9b3244..66f31703 100755 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -14,6 +14,18 @@ WeatherProvider.register("openweathermap", { // But for debugging (and future alerts) it would be nice to have the real name. providerName: "OpenWeatherMap", + // Set the default config properties that is specific to this provider + defaults: { + apiVersion: "2.5", + apiBase: "https://api.openweathermap.org/data/", + weatherEndpoint: "/weather", + locationID: false, + location: false, + lat: 0, + lon: 0, + apiKey: "" + }, + // Overwrite the fetchCurrentWeather method. fetchCurrentWeather() { this.fetchData(this.getUrl()) diff --git a/modules/default/weather/providers/smhi.js b/modules/default/weather/providers/smhi.js index cdbaf013..a27b1300 100644 --- a/modules/default/weather/providers/smhi.js +++ b/modules/default/weather/providers/smhi.js @@ -14,6 +14,13 @@ WeatherProvider.register("smhi", { providerName: "SMHI", + // Set the default config properties that is specific to this provider + defaults: { + lat: 0, + lon: 0, + precipitationValue: "pmedian" + }, + /** * Implements method in interface for fetching current weather */ @@ -55,7 +62,7 @@ WeatherProvider.register("smhi", { this.config = config; if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) == -1) { console.log("invalid or not set: " + config.precipitationValue); - config.precipitationValue = "pmedian"; + config.precipitationValue = this.defaults.precipitationValue; } }, diff --git a/modules/default/weather/providers/ukmetoffice.js b/modules/default/weather/providers/ukmetoffice.js index b71ced88..11cee48f 100755 --- a/modules/default/weather/providers/ukmetoffice.js +++ b/modules/default/weather/providers/ukmetoffice.js @@ -14,6 +14,13 @@ WeatherProvider.register("ukmetoffice", { // But for debugging (and future alerts) it would be nice to have the real name. providerName: "UK Met Office", + // Set the default config properties that is specific to this provider + defaults: { + apiBase: "http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/", + locationID: false, + apiKey: "" + }, + units: { imperial: "us", metric: "si" diff --git a/modules/default/weather/providers/ukmetofficedatahub.js b/modules/default/weather/providers/ukmetofficedatahub.js index af2e09c6..03e5fa5a 100644 --- a/modules/default/weather/providers/ukmetofficedatahub.js +++ b/modules/default/weather/providers/ukmetofficedatahub.js @@ -44,6 +44,16 @@ WeatherProvider.register("ukmetofficedatahub", { // Set the name of the provider. providerName: "UK Met Office (DataHub)", + // Set the default config properties that is specific to this provider + defaults: { + apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/", + apiKey: "", + apiSecret: "", + lat: 0, + lon: 0, + windUnits: "mph" + }, + // Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api) getUrl(forecastType) { let queryStrings = "?"; diff --git a/modules/default/weather/providers/weatherbit.js b/modules/default/weather/providers/weatherbit.js index 6bd3508e..afca0c83 100644 --- a/modules/default/weather/providers/weatherbit.js +++ b/modules/default/weather/providers/weatherbit.js @@ -14,6 +14,15 @@ WeatherProvider.register("weatherbit", { // Not strictly required, but helps for debugging. providerName: "Weatherbit", + // Set the default config properties that is specific to this provider + defaults: { + apiBase: "https://api.weatherbit.io/v2.0", + weatherEndpoint: "/current", + apiKey: "", + lat: 0, + lon: 0 + }, + units: { imperial: "I", metric: "M" diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index 86837763..ee418edc 100755 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -19,6 +19,14 @@ WeatherProvider.register("weathergov", { // But for debugging (and future alerts) it would be nice to have the real name. providerName: "Weather.gov", + // Set the default config properties that is specific to this provider + defaults: { + apiBase: "https://api.weatherbit.io/v2.0", + weatherEndpoint: "/forecast", + lat: 0, + lon: 0 + }, + // Flag all needed URLs availability configURLs: false, diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index d6678134..4006313a 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -12,10 +12,6 @@ Module.register("weather", { weatherProvider: "openweathermap", roundTemp: false, type: "current", // current, forecast, daily (equivalent to forecast), hourly (only with OpenWeatherMap /onecall endpoint) - lat: 0, - lon: 0, - location: false, - locationID: false, units: config.units, useKmh: false, tempUnits: config.units, @@ -40,12 +36,6 @@ Module.register("weather", { fade: true, fadePoint: 0.25, // Start on 1/4th of the list. initialLoadDelay: 0, // 0 seconds delay - retryDelay: 2500, - apiKey: "", - apiSecret: "", - apiVersion: "2.5", - apiBase: "https://api.openweathermap.org/data/", // TODO: this should not be part of the weather.js file, but should be contained in the openweatherprovider - weatherEndpoint: "/weather", appendLocationNameToHeader: true, calendarClass: "calendar", tableClass: "small", @@ -129,8 +119,8 @@ Module.register("weather", { return `hourly.njk`; case "daily": case "forecast": + //Make the invalid values use the "Loading..." from forecast default: - //Make the invalid values use the "Loading..." from forecast return `forecast.njk`; } }, diff --git a/modules/default/weather/weatherprovider.js b/modules/default/weather/weatherprovider.js index 2d031b2e..29e0aee5 100644 --- a/modules/default/weather/weatherprovider.js +++ b/modules/default/weather/weatherprovider.js @@ -11,6 +11,7 @@ var WeatherProvider = Class.extend({ // Weather Provider Properties providerName: null, + defaults: {}, // The following properties have accessor methods. // Try to not access them directly. @@ -154,10 +155,11 @@ WeatherProvider.register = function (providerIdentifier, providerDetails) { WeatherProvider.initialize = function (providerIdentifier, delegate) { providerIdentifier = providerIdentifier.toLowerCase(); - var provider = new WeatherProvider.providers[providerIdentifier](); + const provider = new WeatherProvider.providers[providerIdentifier](); + const config = Object.assign({}, provider.defaults, delegate.config); provider.delegate = delegate; - provider.setConfig(delegate.config); + provider.setConfig(config); provider.providerIdentifier = providerIdentifier; if (!provider.providerName) { From 5a421220c953c8287de4c0f40ce85d27359bc00e Mon Sep 17 00:00:00 2001 From: buxxi Date: Sat, 23 Jan 2021 11:40:02 +0100 Subject: [PATCH 4/5] Updating readme and changelog and fixing typo in method --- CHANGELOG.md | 1 + modules/default/weather/providers/README.md | 21 ++++++++++++++++++--- modules/default/weather/weatherprovider.js | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f2ad6f3..1dcbd667 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ _This release is scheduled to be released on 2021-04-01._ - Code cleanup for FEELS like and added {DEGREE} placeholder for FEELSLIKE for each language - Converted newsfeed module to use templates. - Update documentation and help screen about invalid config files. +- Moving weather provider specific code and configuration into each provider and making hourly part of the interface. ### Removed diff --git a/modules/default/weather/providers/README.md b/modules/default/weather/providers/README.md index 02cef8dd..f6e5d732 100755 --- a/modules/default/weather/providers/README.md +++ b/modules/default/weather/providers/README.md @@ -29,16 +29,23 @@ WeatherProvider.register("yourprovider", { #### `fetchCurrentWeather()` -This method is called when the weather module tries to fetch the current weather of your provider. The implementation of this method is required. +This method is called when the weather module tries to fetch the current weather of your provider. The implementation of this method is required for current weather support. The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise. After the response is processed, the current weather information (as a [WeatherObject](#weatherobject)) needs to be set with `this.setCurrentWeather(currentWeather);`. It will then automatically refresh the module DOM with the new data. #### `fetchWeatherForecast()` -This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required. +This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required for forecast support. The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise. -After the response is processed, the weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setCurrentWeather(forecast);`. +After the response is processed, the weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setWeatherForecast(forecast);`. +It will then automatically refresh the module DOM with the new data. + +#### `fetchWeatherHourly()` + +This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required for hourly support. +The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise. +After the response is processed, the hourly weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setWeatherHourly(forecast);`. It will then automatically refresh the module DOM with the new data. ### Weather Provider instance methods @@ -63,6 +70,10 @@ This returns a WeatherDay object for the current weather. This returns an array of WeatherDay objects for the weather forecast. +#### `weatherHourly()` + +This returns an array of WeatherDay objects for the hourly weather forecast. + #### `fetchedLocation()` This returns the name of the fetched location or an empty string. @@ -75,6 +86,10 @@ Set the currentWeather and notify the delegate that new information is available Set the weatherForecastArray and notify the delegate that new information is available. +#### `setWeatherHourly(weatherHourlyArray)` + +Set the weatherHourlyArray and notify the delegate that new information is available. + #### `setFetchedLocation(name)` Set the fetched location name. diff --git a/modules/default/weather/weatherprovider.js b/modules/default/weather/weatherprovider.js index 29e0aee5..87667fd9 100644 --- a/modules/default/weather/weatherprovider.js +++ b/modules/default/weather/weatherprovider.js @@ -97,7 +97,7 @@ var WeatherProvider = Class.extend({ }, // Set the weatherHourlyArray and notify the delegate that new information is available. - setWeatherHourlyData: function (weatherHourlyArray) { + setWeatherHourly: function (weatherHourlyArray) { this.weatherHourlyArray = weatherHourlyArray; }, From 3c4d7a33e086b92994a7530e85e4c130497244fb Mon Sep 17 00:00:00 2001 From: buxxi Date: Sat, 23 Jan 2021 12:07:10 +0100 Subject: [PATCH 5/5] Fixing code style issue with no return before default --- modules/default/weather/weather.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index 4006313a..50c73031 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -119,6 +119,7 @@ Module.register("weather", { return `hourly.njk`; case "daily": case "forecast": + return `forecast.njk`; //Make the invalid values use the "Loading..." from forecast default: return `forecast.njk`;