Added Override Notification Option to Weather Module (#3178)

Fixes #3126 

Added the option `allowOverrideNotification` to `weather.js`. This
allows the module to receive the `CURRENT_WEATHER_OVERRIDE`
notification. The expected payload for this notification is a
full/partial `weatherObject` that is used to supplement/replace the
existing `weatherObject` returned by whichever weather provider is in
use.

No visual changes.

First time contributing - let me know if I've missed something
🙂

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
This commit is contained in:
NolanKingdon 2023-09-08 01:41:20 -04:00 committed by GitHub
parent 9d49196e69
commit 5cbdd28db3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 2 deletions

View File

@ -13,6 +13,7 @@ _This release is scheduled to be released on 2023-10-01._
- Added UV Index support to OpenWeatherMap - Added UV Index support to OpenWeatherMap
- Added 'hideDuplicates' flag to the calendar module - Added 'hideDuplicates' flag to the calendar module
- Added `allowOverrideNotification` to weather module to enable sending current weather objects with the `CURRENT_WEATHER_OVERRIDE` notification to supplement/replace the current weather displayed
### Removed ### Removed

View File

@ -0,0 +1,112 @@
/* global Class, WeatherObject */
/*
* Wrapper class to enable overrides of currentOverrideWeatherObject.
*
* Sits between the weather.js module and the provider implementations to allow us to
* combine the incoming data from the CURRENT_WEATHER_OVERRIDE notification with the
* existing data received from the current api provider. If no notifications have
* been received then the api provider's data is used.
*
* The intent is to allow partial WeatherObjects from local sensors to augment or
* replace the WeatherObjects from the api providers.
*
* This class shares the signature of WeatherProvider, and passes any methods not
* concerning the current weather directly to the api provider implementation that
* is currently in use.
*/
const OverrideWrapper = Class.extend({
baseProvider: null,
providerName: "localWrapper",
notificationWeatherObject: null,
currentOverrideWeatherObject: null,
init(baseProvider) {
this.baseProvider = baseProvider;
// Binding the scope of current weather functions so any fetchData calls with
// setCurrentWeather nested in them call this classes implementation instead
// of the provider's default
this.baseProvider.setCurrentWeather = this.setCurrentWeather.bind(this);
this.baseProvider.currentWeather = this.currentWeather.bind(this);
},
/* Unchanged Api Provider Methods */
setConfig(config) {
this.baseProvider.setConfig(config);
},
start() {
this.baseProvider.start();
},
fetchCurrentWeather() {
this.baseProvider.fetchCurrentWeather();
},
fetchWeatherForecast() {
this.baseProvider.fetchWeatherForecast();
},
fetchWeatherHourly() {
this.baseProvider.fetchEatherHourly();
},
weatherForecast() {
this.baseProvider.weatherForecast();
},
weatherHourly() {
this.baseProvider.weatherHourly();
},
fetchedLocation() {
this.baseProvider.fetchedLocation();
},
setWeatherForecast(weatherForecastArray) {
this.baseProvider.setWeatherForecast(weatherForecastArray);
},
setWeatherHourly(weatherHourlyArray) {
this.baseProvider.setWeatherHourly(weatherHourlyArray);
},
setFetchedLocation(name) {
this.baseProvider.setFetchedLocation(name);
},
updateAvailable() {
this.baseProvider.updateAvailable();
},
async fetchData(url, type = "json", requestHeaders = undefined, expectedResponseHeaders = undefined) {
this.baseProvider.fetchData(url, type, requestHeaders, expectedResponseHeaders);
},
/* Override Methods */
/**
* Override to return this scope's
* @returns {WeatherObject} The current weather object. May or may not contain overridden data.
*/
currentWeather() {
return this.currentOverrideWeatherObject;
},
/**
* Override to combine the overrideWeatherObejct provided in the
* notificationReceived method with the currentOverrideWeatherObject provided by the
* api provider fetchData implementation.
* @param {WeatherObject} currentWeatherObject - the api provider weather object
*/
setCurrentWeather(currentWeatherObject) {
this.currentOverrideWeatherObject = Object.assign(currentWeatherObject, this.notificationWeatherObject);
},
/**
* Updates the overrideWeatherObject, calls setCurrentWeather to combine it with
* the existing current weather object provided by the base provider, and signals
* that an update is ready.
* @param {WeatherObject} payload - the weather object received from the CURRENT_WEATHER_OVERRIDE
* notification. Represents information to augment the
* existing currentOverrideWeatherObject with.
*/
notificationReceived(payload) {
this.notificationWeatherObject = payload;
// setCurrentWeather combines the newly received notification weather with
// the existing weather object we return for current weather
this.setCurrentWeather(this.currentOverrideWeatherObject);
this.updateAvailable();
}
});

View File

@ -23,6 +23,7 @@ Module.register("weather", {
showHumidity: false, showHumidity: false,
showIndoorHumidity: false, showIndoorHumidity: false,
showIndoorTemperature: false, showIndoorTemperature: false,
allowOverrideNotification: false,
showPeriod: true, showPeriod: true,
showPeriodUpper: false, showPeriodUpper: false,
showPrecipitationAmount: false, showPrecipitationAmount: false,
@ -61,7 +62,7 @@ Module.register("weather", {
// Return the scripts that are necessary for the weather module. // Return the scripts that are necessary for the weather module.
getScripts: function () { getScripts: function () {
return ["moment.js", this.file("../utils.js"), "weatherutils.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file(`providers/${this.config.weatherProvider.toLowerCase()}.js`)]; return ["moment.js", this.file("../utils.js"), "weatherutils.js", "weatherobject.js", this.file("providers/overrideWrapper.js"), "weatherprovider.js", "suncalc.js", this.file(`providers/${this.config.weatherProvider.toLowerCase()}.js`)];
}, },
// Override getHeader method. // Override getHeader method.
@ -119,6 +120,8 @@ Module.register("weather", {
} else if (notification === "INDOOR_HUMIDITY") { } else if (notification === "INDOOR_HUMIDITY") {
this.indoorHumidity = this.roundValue(payload); this.indoorHumidity = this.roundValue(payload);
this.updateDom(300); this.updateDom(300);
} else if (notification === "CURRENT_WEATHER_OVERRIDE" && this.config.allowOverrideNotification) {
this.weatherProvider.notificationReceived(payload);
} }
}, },

View File

@ -1,4 +1,4 @@
/* global Class, performWebRequest */ /* global Class, performWebRequest, OverrideWrapper */
/* MagicMirror² /* MagicMirror²
* Module: Weather * Module: Weather
@ -164,5 +164,9 @@ WeatherProvider.initialize = function (providerIdentifier, delegate) {
provider.providerName = pi; provider.providerName = pi;
} }
if (config.allowOverrideNotification) {
return new OverrideWrapper(provider);
}
return provider; return provider;
}; };