33This document describes the way to develop your own MagicMirror² weather
44provider for the weather module.
55
6- ## The weather provider file: yourprovider.js
6+ ::: warning BREAKING CHANGE in v2.35.0
77
8- This is the script in which the weather provider will be defined. In its most
9- simple form, the weather provider must implement the following:
8+ Weather providers now run ** server-side** as Node.js classes. The old
9+ client-side ` WeatherProvider.register("name", { ... }) ` API was removed. Custom
10+ providers from earlier versions must be updated for the new structure.
11+
12+ :::
13+
14+ ## The weather provider file: ` yourprovider.js `
15+
16+ This is the script in which the weather provider will be defined. The file must
17+ be placed in MagicMirror's built-in weather provider directory:
18+
19+ ``` bash
20+ ~ /MagicMirror/defaultmodules/weather/providers/yourprovider.js
21+ ```
22+
23+ The filename (lowercased) must match the ` weatherProvider ` value in ` config.js ` .
1024
1125``` js
12- WeatherProvider .register (" yourprovider" , {
13- providerName: " YourProvider" ,
26+ {
27+ module: " weather" ,
28+ config: {
29+ weatherProvider: " yourprovider" ,
30+ type: " current" // or "forecast" / "hourly"
31+ }
32+ }
33+ ```
1434
15- fetchCurrentWeather () {},
35+ This directory is part of the MagicMirror git repository. A custom file placed
36+ here may conflict with future updates, so keep a copy outside the repository
37+ before running ` git pull ` . You can also tell git not to track local changes to
38+ that file:
1639
17- fetchWeatherForecast () {},
18- });
40+ ``` bash
41+ git -C ~ /MagicMirror update-index --assume-unchanged \
42+ defaultmodules/weather/providers/yourprovider.js
43+ ```
44+
45+ In its most simple form, the weather provider must implement the following:
46+
47+ ``` js
48+ const HTTPFetcher = require (" #http_fetcher" );
49+
50+ class YourProvider {
51+ constructor (config ) {
52+ this .config = config;
53+ this .locationName = null ;
54+ this .fetcher = null ;
55+ this .onDataCallback = null ;
56+ this .onErrorCallback = null ;
57+ }
58+
59+ setCallbacks (onData , onError ) {
60+ this .onDataCallback = onData;
61+ this .onErrorCallback = onError;
62+ }
63+
64+ initialize () {
65+ this .fetcher = new HTTPFetcher (" https://your.api/endpoint" , {
66+ reloadInterval: this .config .updateInterval ,
67+ logContext: " weatherprovider.yourprovider" ,
68+ });
69+
70+ this .fetcher .on (" response" , async (response ) => {
71+ const data = await response .json ();
72+ this .onDataCallback (this .parseWeather (data));
73+ });
74+
75+ this .fetcher .on (" error" , (errorInfo ) => this .onErrorCallback (errorInfo));
76+ }
77+
78+ start () {
79+ this .fetcher ? .startPeriodicFetch ();
80+ }
81+
82+ stop () {
83+ this .fetcher ? .clearTimer ();
84+ }
85+
86+ parseWeather (data ) {
87+ return { temperature: data .temp };
88+ }
89+ }
90+
91+ module .exports = YourProvider;
1992` ` `
2093
2194## Weather provider methods to implement
@@ -29,121 +102,114 @@ The weather module expects the weather data to be in metric units:
29102
30103Some weather APIs already deliver their data in those units.
31104
32- If that is not the case you can use helper methods from the ` weatherutils.js `
33- class to convert the data .
105+ If that is not the case, convert the values before sending them to the weather
106+ module .
34107
35108:::
36109
37- ### ` fetchCurrentWeather() `
38-
39- This method is called when the weather module tries to fetch the current weather
40- of your provider. The implementation of this method is required for current
41- weather support. The implementation can make use of the already implemented
42- function ` this.fetchData(url, method, data); ` , which is returning a promise.
43- After the response is processed, the current weather information (as a
44- [ WeatherObject] ( #weatherobject ) ) needs to be set with
45- ` this.setCurrentWeather(currentWeather); ` . It will then automatically refresh
46- the module DOM with the new data.
47-
48- ### ` fetchWeatherForecast() `
49-
50- This method is called when the weather module tries to fetch the weather of your
51- provider. The implementation of this method is required for forecast support.
52- The implementation can make use of the already implemented function
53- ` this.fetchData(url, method, data); ` , which is returning a promise. After the
54- response is processed, the weather forecast information (as an array of
55- [ WeatherObject] ( #weatherobject ) s) needs to be set with
56- ` this.setWeatherForecast(forecast); ` . It will then automatically refresh the
57- module DOM with the new data.
58-
59- ### ` fetchWeatherHourly() `
60-
61- This method is called when the weather module tries to fetch the weather of your
62- provider. The implementation of this method is required for hourly support. The
63- implementation can make use of the already implemented function
64- ` this.fetchData(url, method, data); ` , which is returning a promise. After the
65- response is processed, the hourly weather forecast information (as an array of
66- [ WeatherObject] ( #weatherobject ) s) needs to be set with
67- ` this.setWeatherHourly(forecast); ` . It will then automatically refresh the
68- module DOM with the new data.
110+ ### ` constructor (config )`
69111
70- ## Weather Provider instance methods
112+ This method receives the full weather module config. Store it as `this.config`
113+ and initialize the provider state here. The optional `locationName` property is
114+ shown in the module header.
71115
72- ### ` init( )`
116+ ### `setCallbacks(onData, onError )`
73117
74- Called when a weather provider is initialized.
118+ This method is called by the `node_helper` before `initialize()`. Store both
119+ callbacks and call `onData(weatherData)` whenever new weather data is available.
120+ Call `onError({ message, translationKey })` when something goes wrong.
75121
76- ### ` setConfig(config )`
122+ ### ` initialize ( )`
77123
78- Called to set the config, this config is the same as the weather module's
79- config.
124+ This method is called once when the provider is loaded. It may be ` async ` .
80125
81- ### ` start() `
126+ Validate required options such as API keys, coordinates, or provider-specific
127+ location IDs here. If required configuration is missing, call ` onErrorCallback`
128+ with a useful message and return early — without creating the fetcher.
82129
83- Called when the weather provider is about to start.
130+ If validation passes, delegate the fetcher setup to a private helper (e.g.
131+ ` #initializeFetcher ()` ). Keeping these two concerns separate makes the code
132+ easier to follow. You can also resolve ` this .locationName ` here if your provider
133+ needs an extra lookup before starting to fetch.
84134
85- #### ` currentWeather() `
135+ If ` initialize ()` throws, provider startup fails and the module reports an
136+ error. For API errors, call ` onErrorCallback` with a useful message instead of
137+ throwing from setup code.
86138
87- This returns a WeatherDay object for the current weather.
88-
89- ### ` weatherForecast() `
90-
91- This returns an array of WeatherDay objects for the weather forecast.
92-
93- ### ` weatherHourly() `
94-
95- This returns an array of WeatherDay objects for the hourly weather forecast.
96-
97- ### ` fetchedLocation() `
139+ ### ` start ()`
98140
99- This returns the name of the fetched location or an empty string.
141+ This method is called when the weather provider is about to start. Usually this
142+ starts periodic fetching:
100143
101- ### ` setCurrentWeather(currentWeatherObject) `
144+ ` ` ` js
145+ start () {
146+ this .fetcher ? .startPeriodicFetch ();
147+ }
148+ ` ` `
102149
103- Set the currentWeather and notify the delegate that new information is
104- available.
150+ ### ` stop ()`
105151
106- ### ` setWeatherForecast(weatherForecastArray) `
152+ This method is called when the weather provider is stopped. Cancel timers or
153+ other open resources here:
107154
108- Set the weatherForecastArray and notify the delegate that new information is
109- available.
155+ ` ` ` js
156+ stop () {
157+ this .fetcher ? .clearTimer ();
158+ }
159+ ` ` `
110160
111- ### ` setWeatherHourly(weatherHourlyArray) `
161+ ### Parsing weather data
112162
113- Set the weatherHourlyArray and notify the delegate that new information is
114- available.
163+ Process the API response in your ` HTTPFetcher` response handler and pass the
164+ result to ` onDataCallback` . Return a plain JavaScript object for
165+ ` type: " current" ` , or an array of objects for ` type: " forecast" ` and
166+ ` type: " hourly" ` .
115167
116- ### ` setFetchedLocation(name) `
168+ Wrap ` response .json ()` and your parsing logic in ` try ` /` catch ` so invalid JSON
169+ or unexpected API response shapes can be reported through ` onErrorCallback`
170+ instead of failing silently.
117171
118- Set the fetched location name.
172+ ` HTTPFetcher` (` require (" #http_fetcher" )` ) handles periodic fetching with retry
173+ and backoff. See
174+ [` js/ http_fetcher .js ` ](https://github.com/MagicMirrorOrg/MagicMirror/blob/master/js/http_fetcher.js)
175+ for all options. Common ` translationKey` values: ` MODULE_ERROR_UNAUTHORIZED ` ,
176+ ` MODULE_ERROR_RATE_LIMITED ` , ` MODULE_ERROR_SERVER_ERROR ` ,
177+ ` MODULE_ERROR_NO_CONNECTION ` , ` MODULE_ERROR_UNSPECIFIED ` .
119178
120- ### ` updateAvailable() `
179+ ## Weather Provider instance methods
121180
122- Notify the delegate that new weather is available.
181+ The ` node_helper ` controls the provider lifecycle in this order:
123182
124- ### ` fetchData(url, method, data) `
183+ 1. ` setCallbacks (onData, onError)`
184+ 2. ` initialize ()`
185+ 3. ` start ()`
186+ 4. ` stop ()` when the module is stopped
125187
126- A convenience function to make requests. It returns a promise.
188+ These replace the old client-side provider methods such as
189+ ` fetchCurrentWeather ()` , ` fetchWeatherForecast ()` , ` setCurrentWeather ()` , and
190+ ` updateAvailable ()` .
127191
128192## WeatherObject
129193
130- This object holds all data from your provider for usage in the template.
131-
132- | Property | Type | Value/Unit |
133- | -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
134- | date | ` object ` | [ Moment.js] ( https://momentjs.com/ ) object of the time/date. |
135- | windSpeed | ` number ` | Speed of the wind in metric: ` meter/second ` |
136- | windDirection | ` number ` | Direction of the wind in degrees. |
137- | sunrise | ` object ` | [ Moment.js] ( https://momentjs.com/ ) object of sunrise. |
138- | sunset | ` object ` | [ Moment.js] ( https://momentjs.com/ ) object of sunset. |
139- | temperature | ` number ` | Current temperature in metric ` celsius degree ` . |
140- | minTemperature | ` number ` | Lowest temperature of the day in metric ` celsius degree ` . |
141- | maxTemperature | ` number ` | Highest temperature of the day in metric ` celsius degree ` . |
142- | weatherType | ` string ` | Icon name of the weather type. <br > Possible values: [ WeatherIcons] ( https://www.npmjs.com/package/weathericons ) |
143- | humidity | ` number ` | Percentage of humidity |
144- | rain | ` number ` | Metric: ` millimeters ` <br > Imperial: ` inches ` |
145- | snow | ` number ` | Metric: ` millimeters ` <br > Imperial: ` inches ` |
146- | precipitation | ` number ` | Metric: ` millimeters ` <br > Imperial: ` inches ` <br > UK Met Office provider: ` percent ` |
194+ This object holds all data from your provider for usage in the template. A
195+ server-side provider returns plain objects; the weather module converts them to
196+ ` WeatherObject` instances on the client.
197+
198+ | Property | Type | Value/Unit |
199+ | ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------- |
200+ | date | ` Date ` | JavaScript ` Date ` object of the time/date. |
201+ | windSpeed | ` number` | Speed of the wind in metric: ` meter/ second` |
202+ | windFromDirection | ` number` | Direction of the wind in degrees. |
203+ | sunrise | ` Date ` | JavaScript ` Date ` object of sunrise. |
204+ | sunset | ` Date ` | JavaScript ` Date ` object of sunset. |
205+ | temperature | ` number` | Current temperature in metric ` celsius degree` . |
206+ | minTemperature | ` number` | Lowest temperature of the day in metric ` celsius degree` . |
207+ | maxTemperature | ` number` | Highest temperature of the day in metric ` celsius degree` . |
208+ | weatherType | ` string` | Icon name of the weather type. <br> Possible values: [WeatherIcons](https://www.npmjs.com/package/weathericons) |
209+ | humidity | ` number` | Percentage of humidity |
210+ | precipitationAmount | ` number` | Metric: ` millimeters` |
211+ | precipitationUnits | ` string` | Optional precipitation unit override |
212+ | precipitationProbability | ` number` | Precipitation probability as percentage |
147213
148214### Current weather
149215
@@ -154,7 +220,7 @@ For the current weather object the following properties are required:
154220- sunset
155221- temperature
156222- weatherType
157- - windDirection
223+ - windFromDirection
158224- windSpeed
159225
160226### Weather forecast
@@ -164,5 +230,12 @@ For the forecast weather object the following properties are required:
164230- date
165231- maxTemperature
166232- minTemperature
167- - rain
233+ - precipitationAmount
168234- weatherType
235+
236+ If your API does not provide one of these values, use a sensible fallback where
237+ possible. The important part is that the weather module receives the fields it
238+ expects for the selected ` type` .
239+
240+ For real examples, look at the built-in providers in
241+ [` defaultmodules/ weather/ providers/ ` ](https://github.com/MagicMirrorOrg/MagicMirror/tree/master/defaultmodules/weather/providers).
0 commit comments