Merge branch 'develop' into deprecate-old-weather

This commit is contained in:
buxxi 2021-01-24 10:22:39 +01:00
commit 6cbd267384
14 changed files with 131 additions and 52 deletions

View File

@ -26,6 +26,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

View File

@ -1,7 +1,4 @@
{% if current or weatherData %}
{% if weatherData %}
{% set current = weatherData.current %}
{% endif %}
{% if current %}
{% if not config.onlyTemp %}
<div class="normal medium">
<span class="wi wi-strong-wind dimmed"></span>

View File

@ -1,10 +1,5 @@
{% if forecast or weatherData %}
{% if weatherData %}
{% set forecast = weatherData.days %}
{% set numSteps = forecast | calcNumEntries %}
{% else %}
{% if forecast %}
{% set numSteps = forecast | calcNumSteps %}
{% endif %}
{% set currentStep = 0 %}
<table class="{{ config.tableClass }}">
{% set forecast = forecast.slice(0, numSteps) %}

View File

@ -1,7 +1,4 @@
{% if hourly or weatherData %}
{% if weatherData %}
{% set hourly = weatherData.hours %}
{% endif %}
{% if hourly %}
{% set numSteps = hourly | calcNumEntries %}
{% set currentStep = 0 %}
<table class="{{ config.tableClass }}">
@ -29,4 +26,4 @@
{% endif %}
<!-- Uncomment the line below to see the contents of the `hourly` object. -->
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{weatherData | dump}}</div> -->
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{hourly | dump}}</div> -->

View File

@ -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.

View File

@ -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"

View File

@ -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())
@ -56,8 +68,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 +81,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);
@ -77,6 +89,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

View File

@ -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;
}
},

View File

@ -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"

View File

@ -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 = "?";

View File

@ -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"

View File

@ -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,

View File

@ -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",
@ -130,8 +120,9 @@ Module.register("weather", {
case "daily":
case "forecast":
return `forecast.njk`;
//Make the invalid values use the "Loading..." from forecast
default:
return `${this.config.type.toLowerCase()}.njk`;
return `forecast.njk`;
}
},
@ -141,7 +132,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
@ -167,12 +158,19 @@ Module.register("weather", {
}
setTimeout(() => {
if (this.config.weatherEndpoint === "/onecall") {
this.weatherProvider.fetchWeatherData();
} else if (this.config.type === "forecast") {
this.weatherProvider.fetchWeatherForecast();
} else {
switch (this.config.type.toLowerCase()) {
case "current":
this.weatherProvider.fetchCurrentWeather();
break;
case "hourly":
this.weatherProvider.fetchWeatherHourly();
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);
},

View File

@ -11,12 +11,13 @@
var WeatherProvider = Class.extend({
// Weather Provider Properties
providerName: null,
defaults: {},
// The following properties have accessor methods.
// 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 +58,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 +75,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 +96,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.
setWeatherHourly: function (weatherHourlyArray) {
this.weatherHourlyArray = weatherHourlyArray;
},
// Set the fetched location name.
@ -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) {