Skip to content

Commit

Permalink
Added Override Notification Option to Weather Module (#3178)
Browse files Browse the repository at this point in the history
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
:slightly_smiling_face:

---------

Co-authored-by: veeck <[email protected]>
  • Loading branch information
NolanKingdon and rejas authored Sep 8, 2023
1 parent 9d49196 commit 5cbdd28
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ _This release is scheduled to be released on 2023-10-01._

- Added UV Index support to OpenWeatherMap
- 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

Expand Down
112 changes: 112 additions & 0 deletions modules/default/weather/providers/overrideWrapper.js
Original file line number Diff line number Diff line change
@@ -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();
}
});
5 changes: 4 additions & 1 deletion modules/default/weather/weather.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Module.register("weather", {
showHumidity: false,
showIndoorHumidity: false,
showIndoorTemperature: false,
allowOverrideNotification: false,
showPeriod: true,
showPeriodUpper: false,
showPrecipitationAmount: false,
Expand Down Expand Up @@ -61,7 +62,7 @@ Module.register("weather", {

// Return the scripts that are necessary for the weather module.
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.
Expand Down Expand Up @@ -119,6 +120,8 @@ Module.register("weather", {
} else if (notification === "INDOOR_HUMIDITY") {
this.indoorHumidity = this.roundValue(payload);
this.updateDom(300);
} else if (notification === "CURRENT_WEATHER_OVERRIDE" && this.config.allowOverrideNotification) {
this.weatherProvider.notificationReceived(payload);
}
},

Expand Down
6 changes: 5 additions & 1 deletion modules/default/weather/weatherprovider.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global Class, performWebRequest */
/* global Class, performWebRequest, OverrideWrapper */

/* MagicMirror²
* Module: Weather
Expand Down Expand Up @@ -164,5 +164,9 @@ WeatherProvider.initialize = function (providerIdentifier, delegate) {
provider.providerName = pi;
}

if (config.allowOverrideNotification) {
return new OverrideWrapper(provider);
}

return provider;
};

0 comments on commit 5cbdd28

Please sign in to comment.