Skip to content

Release 2.36.0#4127

Merged
khassel merged 427 commits intomasterfrom
develop
Apr 30, 2026
Merged

Release 2.36.0#4127
khassel merged 427 commits intomasterfrom
develop

Conversation

@khassel
Copy link
Copy Markdown
Collaborator

@khassel khassel commented Apr 30, 2026

Release Notes

Thanks to: @cgillinger, @khassel, @KristjanESPERANTO, @sonnyb9

⚠️ This release needs nodejs version >=22.21.1 <23 || >=24 (no change to previous release)

Compare to previous Release v2.35.0

This release falls outside the quarterly schedule. We opted for an early release due to:

  • Security fix for the internal cors proxy
  • API change of the weather provider smi
  • Several bug fixes

Breaking Changes

The cors proxy is now disabled by default. If required, it must be explicitly enabled in the config.js file. See the documentation.

⚠️ Security

You can find several publicly accessible MagicMirror² instances.

This should never be done. Doing so makes your entire configuration, including secrets and API keys, publicly visible. Furthermore, it allows attackers to target the host; this is only prevented beginning with this release.

Public MagicMirror² instances should always run behind a reverse proxy with authentication.

[core]

[dependencies]

[modules/newsfeed]

[modules/updatenotification]

[modules/weather]

[testing]

khassel and others added 30 commits January 3, 2025 21:52
clientonly:
- did work only with xserver and `DISPLAY` env var
- now checks for `WAYLAND_DISPLAY` or `DISPLAY` env var before running
- if `WAYLAND_DISPLAY` is set now starts with wayland parameters

electron tests see #3676
fixes #3267 AGAIN, correctly, add testcase
add testcase for #3679 , broadcast clipping incorrectly

I added a test module (tests/testNotification) to catch the notification
and check the count. (one way to configure)
i put this module in the tests folder, and added /tests to the server
paths.
(can't have a module in a nested folder, like tests/modules/xxx)

but I have a problem. i can run the test config (MM_CONFIG_FILE), and
the two modules work correctly,
but in the spec runner, the calendar module times out on the broadcast
test.. there is only local ics file access, no outside hosts

I forced my system date to 1/1/24 (same as runner) and again the manual
testcase works fine

I added two test config.js,(configs/calendar) one works great (symbols)
, one fails (broadcast test)
I added additional delay in the calendarspec runner to try to debug the
module, but it still not long enough.. no messages of trouble when I get
into the browser.. BUT, this may be because of the log being turned
off... (just thought of this)

I created a special ICS (in mocks) that has 12 events, 1 for each
month.. (so I can check clipping and broadcast) the US holidays one is
sensitive to the current date, and I couldn't get it to work on
1/1/2024..

also, in general, is there a mechanism to run test:just_one_runner?
waiting thru the electron test to get to one testcase.. ugh..
I also added a few new words to the cspell dictionary that were added in
the changelog.

I have not made an extra entry in the changelog for these tiny things.
- fix setup to run with xserver and labwc
- remove electronParams from calendar_spec.js (forgotten in
#3680)

fixes [running tests locally without labwc
installed](#3681 (comment))

follow up to #3680
Since we don't use the `raspberry` information, calling it in `si.get`
is useless.

I also made the string construction in the code a bit more readable. The
output remains the same.
Due to a typo the icon displayed in the openmeteo provider was "N/A" for
a certain weather condition

<img width="284" alt="Bildschirmfoto 2025-01-13 um 16 35 40"
src="https://github.com/user-attachments/assets/e64bf0f8-32d9-44a5-a2b0-42d4f2d6b6df"
/>

---------

Co-authored-by: veeck <gitkraken@veeck.de>
after updating deps 2 files needed formatting updates
This PR will introduce different issue templates for bug reports,
feature requests and so on on GitHub. There is still room for
fine-tuning, but it's reached a state to show it to you and get
feedback.

I think that this can lead to better bug reports.

You can see the result in my repo:
https://github.com/KristjanESPERANTO/MagicMirror/issues/new/choose

Feel free to create new issues for testing.

What do you think? Do we want to pursue this further?
This doesn't actually change anything functionally, but with this we use
the same schema as for `start:wayland:dev` and `start:windows:dev`.
fixes #3701 

offset calculation wrong when user looking back at east coast event

added testcase
Fixes #3296 

The problem was that the fetch-methods threw errors when something went
wrong instead of calling `updateAvailable()`. `updateAvailable()` must
be called in order to schedule the next update.

I added some filtering for the hourly forecast that removes hours in the
past. If the API call fails we use the cached data, but we should only
display hours in the future.
to call `sudo apt-get update` before `sudo apt-get install`

I had problems running the tests on my fork, while running the `apt-get
install` command in automated tests workflow I got

```bash
E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/m/mesa/libegl-mesa0_24.0.9-0ubuntu0.3_amd64.deb  404  Not Found [IP: 52.147.219.192 80]
```

Found a similar
[Issue](actions/runner-images#10785 (comment))
with a solution which is to run `sudo apt-get update` before.
Therefor -> Therefore

refs: #3690
nothing to see here really

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
Hello and thank you for wanting to contribute to the MagicMirror²
project!

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.
> 2. Include these infos in the description:
>
> - Does the pull request solve a **related** issue?
> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
> - What does the pull request accomplish? Use a list if needed.
> - If it includes major visual changes please add screenshots.
>
> 3. Please run `npm run lint:prettier` before submitting so that
>    style issues are fixed.
> 4. Don't forget to add an entry about your changes to
>    the CHANGELOG.md file.

**Note**: Sometimes the development moves very fast. It is highly
recommended that you update your branch of `develop` before creating a
pull request to send us your changes. This makes everyone's lives
easier (including yours) and helps us out on the development team.

Thanks again and have a nice day!
This does not change the rules of ESLint. It's just a little cosmetic
fine-tuning.
Fixes #3727

---------

Co-authored-by: veeck <gitkraken@veeck.de>
I have updated weatherflow.js to implement the following changes (as
described in #3728)

- Fixed: Weather icons now show up properly
- Added: Location Name support
- Added: Hourly weather forecast support
- Added to current conditions:
  - "Feels like" temp
- Fixed icon for current conditions to be sourced from current
conditions (rather than daily forecast)
  - UV index
- Added to daily forecast
  - Precipitation amount and UV index (via hourly forecast data)

Before:

![image](https://github.com/user-attachments/assets/cfef043c-75ef-4571-8bdc-462e75d3ed81)

After:

![image](https://github.com/user-attachments/assets/e36118bb-a508-4ab1-a7ad-a775bd7a9bb3)
I've had this on my agenda for a long time 🙂
Hello,

we have updated the core Greek translation and added Greek translation
to Alerts module.

Thank you!

---------

Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr>
Co-authored-by: Konstantinos <geraki@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
see
https://forum.magicmirror.builders/topic/19440/digital-clock-minutes-darker

changelog added

question.. 

we have a config parm for seconds color, but not hour/minute
I have used css here.. is that too inconsistent?

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Veeck <github@veeck.de>
fixes #3360 

superseeds #3429

had to open a new PR because getting `permission denied` when trying to
push to the old one.
see discussion in
#3746

As [electron v35 requires node js
v22.14.0](https://www.electronjs.org/blog/electron-35-0) we should
update this here too.
exclude issues with label `ready (coming with next release)` from stale
job
The command wasn't correct.
…V Index, add config option to hide precipitation entries that are zero [Rebased Version of PR #3526] (#3748)

Fixed Version of PR #3526 since that was against the wrong branch and
had issues.

Original PR Text: 
Basically the title. Just some existing weather data included into
hourly, some config option ("hideZeroes") to hide precipitation when it
is zero (this actually shrinks the entire table, removing columns that
are completely empty), and add a spacing column to fix the UV Index
column.

---------

Co-authored-by: Veeck <github@veeck.de>
cgillinger and others added 25 commits April 3, 2026 11:04
## Summary
This PR migrates the SMHI weather provider from the deprecated PMP3gv2
API to the new SNOW1gv1 API.

The old API (pmp3g/version/2) started returning HTTP 404 on 2026-03-31.

## Changes
- Updated API endpoint:
  - `pmp3g/version/2` → `snow1g/version/1`
- Updated response parsing:
  - `validTime` → `time`
  - `parameters[]` → `data` (flat structure)
- Updated parameter names:
  - `t` → `air_temperature`
  - `ws` → `wind_speed`
  - etc.
- Updated precipitation handling to match new
`predominant_precipitation_type_at_surface`
- Updated coordinate parsing (flat `[lon, lat]`)
- Added missing value handling (`9999 → null`)

## Notes
- Maintains backward compatibility for `precipitationValue` config
- No UI changes
- Symbol mapping unchanged (same codes 1–27)

## Testing
- Verified against live SMHI SNOW1gv1 API responses
- Confirmed old API returns HTTP 404

## Impact
Fixes broken SMHI provider due to API deprecation.
…line (#4083)

In PR #4072 GitHub Bot complained that `newsfeedfetcher.js` used the old
`.pipe()` method to connect streams (HTTP body → iconv decoding → RSS
parser). `.pipe()` has a weakness: errors in one stream are **not**
automatically forwarded to downstream streams. An I/O or decoding error
would silently disappear.

## Solution

Replaced `.pipe()` with `await stream.promises.pipeline()`. The
`pipeline()` API is designed to propagate errors correctly through the
entire chain and to clean up all streams on failure. Errors now reliably
land in the `catch` block and call `fetchFailedCallback` exactly once.
The redundant `parser.on("error")` handler was removed, as it would have
caught the same error again and called the callback a second time.

## Why not the bot's suggested fix?

The GitHub Bot suggested the older callback-based
`stream.pipeline(callback)` variant:

```js
stream.pipeline(nodeStream, iconv.decodeStream(...), parser, (error) => {
    if (!error) return;
    // error handling...
});
```

This has two drawbacks compared to my approach:

1. It uses the older callback style — `stream.promises.pipeline()` with
`async/await` is the modern, more readable API.
2. The bot's suggestion kept both the `parser.on("error")` handler
**and** the `catch` block, which would not have fixed the
double-callback problem.

----

Related to #4073
…4085)

In PR #4072 the GitHub bot complained about a missing variable
declaration for `config` in `app.js` and suggested adding `let config`.
Applying that suggestion broke the app because `server_functions.js` was
accessing `config` as an implicit global variable - the `let`
declaration made it unreachable from there.

So instead of the `let` declaration, I replaced all bare `config`
references with explicit `global.config`. This makes the dependency on
the global variable visible without changing runtime behavior,
consistent with how other globals like `global.root_path` and
`global.version` are already handled throughout the codebase.

Related to #4073
…#4084)

Resolve target hostname before proxying and reject any address that is
not globally routable (loopback, RFC 1918, link-local, etc.) using
ipaddr.js and dns.lookup().
`node-ical` has released a new version that fixes an issue reported by
one of our users (jens-maus/node-ical#495).
I'd like to have that in the develop branch. Instead of just updating
that, I think it would make sense to include the others as well.

`undici` had a major release but according to the release notes we are
not affected.
Previously only master was scanned via the default CodeQL setup. Since
development happens on develop, this PR replaces the default setup with
a custom workflow that covers both branches. This gives an overview of
the security status across the current release (master) and the
development branch (develop).

As a result we should also see issues in the develop branch here:
https://github.com/MagicMirrorOrg/MagicMirror/security/code-scanning
PR #4084 blocked SSRF by checking the IP before `fetch()` — but
`fetch()` resolves DNS again on its own. With DNS rebinding (TTL=0,
alternating IPs) an attacker can slip a private IP through between check
and connection.

Fix: resolve DNS once, validate, pin the validated IP for the
connection.

No second DNS query → no rebinding window. `isPrivateTarget()` is gone,
code is shorter than before.

Not a likely attack for a typical MagicMirror setup, but it doesn't add
complexity so there's no reason not to close the gap.
)

During the server-side migration (PR #4032), the `instanceId` was built
with `Date.now()`, making it unique per client reload. This approach was
fine in the old browser-based architecture where reloads cleaned up
everything automatically. But now the node_helper persists across
reloads, so each reconnect created a new `HTTPFetcher` while the old one
kept polling - silently multiplying API calls over time.

The fix is simple: use `this.identifier` as the `instanceId`, which is
already stable and unique per module slot. This is the same approach the
Calendar module uses.

On the node_helper side, when a provider already exists for the same
`instanceId`, we now skip re-creation and just resend
`WEATHER_INITIALIZED` so the client picks up where it left off.

Fixes https://forum.magicmirror.builders/topic/20199
I provide docker images with alpine linux and tested the new cors
approach.

It didn't work because after calling

```js
  const dispatcher = new Agent({ connect: { lookup: (_h, _o, cb) => cb(null, address, family) } });
```

the dispatcher variable was undefined.

This PR solves this and I tested this under debian too.

The mix of internal fetch and newer undici did not work and alpine needs
additionally the `process.nextTick`.

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
If a module uses this.io.of() to register a custom socket.io namespace,
connections on that namespace trigger the onAny handler in setSocketIO
before config is set, causing a TypeError.

Fixes #4089
### What's the problem?

The `selfSignedCert` option passes an undici `Agent` as `dispatcher` to
`fetch()`. But Node's built-in `fetch()` and undici@8's `Agent` use
different internal handler APIs - passing them together throws:

```
invalid onRequestStart method
```

### What's the fix?

When `selfSignedCert` is enabled (i.e. a `dispatcher` is set), use
undici's own `fetch()` instead of the global one. For all other
requests, keep using `globalThis.fetch`.

```js
const fetchFn = requestOptions.dispatcher ? undiciFetch : globalThis.fetch;
```

### Why not just always use undici's fetch?

That would fix the crash - but it would break some tests. MSW (Mock
Service Worker), which is used in our test suite to intercept HTTP
requests, only hooks into `globalThis.fetch`. Undici's fetch bypasses
those interceptors entirely, so tests would start making real network
requests instead of getting the mocked responses. We could rewrite all
tests to use undici-compatible mocking instead - but that would be a
massive change for no real benefit.

----

Fixes #4093
After the big weather refactor (#4032), OpenWeatherMap was effectively
hard-wired to One Call v3. One Call 2.5 is deprecated and no longer
available, so it looked like v2.5 support was effectively over — but the
classic `/weather` and `/forecast` endpoints were never actually
dropped. This restores support for those.

Fixes #4100.

## What this PR does
- handles OpenWeatherMap responses by endpoint again (`/onecall`,
`/weather`, `/forecast`)
- restores v2.5 current and forecast support (including hourly via
3-hour forecast slots)
- filters outdated hourly entries centrally while keeping the current
hour visible (if available)

## Screenshot
<img width="768" height="481" alt="bildo"
src="https://github.com/user-attachments/assets/9bce3531-3731-4fd7-b41e-e20603afa725"
/>
Disable secret substitution only for cors=allowAll, the last attempt in
#4102 was to restrictive.

Secret substitution should also work if cors=disabled.

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Fixes #4105

```bash
In JavaScript, standard JSON does not support functions.
If you use JSON.stringify() on an object containing functions,
those functions will be omitted (if they are object properties)
or changed to null (if they are in an array).
```

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
While looking at the WeatherFlow provider (to evaluate #4107), I noticed
a few things that weren't quite right.

1. **UV index was broken for most providers in forecast/hourly views.**
The templates read `uv_index`, but only the WeatherAPI provider actually
wrote that key. All other providers (OpenWeatherMap, WeatherFlow,
PirateWeather, etc.) use `uvIndex` - so UV was silently never displayed
for them. This went unnoticed because `showUVIndex` defaults to `false`
and there were no test assertions for it. Standardized everything on
`uvIndex` and added test coverage.

2. **WeatherFlow didn't map precipitation for current weather.** The API
provides `precip_accum_local_day` and `precip_probability`, but they
weren't passed through. While adding them I also noticed the template
used truthiness checks, which hid valid zero values. Fixed both.

3. **`||` vs `??` in WeatherFlow provider.** Several numeric fields used
`|| null`, replacing valid `0` with `null`. Switched to `??` for
correctness.
Add minimal GITHUB_TOKEN permissions to electron-rebuild workflow to
enforce least privilege and satisfy CodeQL alert
[#14](https://github.com/MagicMirrorOrg/MagicMirror/security/code-scanning/14).
#4113)

As reported in #4109, the weather module retries much more frequently
than expected after network errors. #4092 already fixed the main cause
(duplicate fetchers), but the backoff logic in `HTTPFetcher` still has a
gap: once retries are exhausted, `calculateBackoffDelay` keeps returning
a short fixed delay (60s) instead of falling back to `reloadInterval`.
The same problem existed for 5xx errors, where the delay grew to 8× the
configured interval.

Inspired by #4110 (thanks @CodeLine9), this PR makes both error paths
fall back to `reloadInterval` after retries are exhausted. I also
simplified the catch block, extracted a `#shortenUrl()` helper for log
messages, and added tests for the backoff progression.
…kUpdates (#4115)

This fixes CodeQL alert
[#16](https://github.com/MagicMirrorOrg/MagicMirror/security/code-scanning/16)
by replacing shell-built git commands with `execFile` + `cwd` in
updatenotification’s `git_helper`.

It also includes a small cleanup in `checkUpdates()` (remove unnecessary
async/Promise wrapper) and updates the related unit tests.
## Summary

This updates `js/http_fetcher.js` so HTTP `304 Not Modified` responses
are emitted through the normal `response` event instead of being treated
as errors.

That aligns the core fetcher with the built-in `yr` weather provider in
`v2.35.0`, which already includes explicit logic to handle `304` and
reuse cached data.

Closes #4119.

## Root cause

`HTTPFetcher` currently treats all non-OK responses as errors. Since
`304` is not an OK response, it never reaches providers listening on the
`response` event.

At the same time, `defaultmodules/weather/providers/yr.js` expects to
receive `304` and handle it by reusing cached data.

## What changed

- special-case HTTP `304` in `HTTPFetcher`
- emit `304` through the normal `response` event
- preserve the existing error path for other non-OK statuses

## Validation

- confirmed `defaultmodules/weather/providers/yr.js` already expects
`response.status === 304`
- compared the unpatched `v2.35.0` `HTTPFetcher` behavior to the
provider logic
- ran `node --check js/http_fetcher.js`

Co-authored-by: sonnyb9 <sonnyb9@users.noreply.github.com>
When a client reconnects while the backend is still in its rate-limit
protection phase, the weather module has no data to show and stays on
`Loading...` until the next scheduled API call. This mainly affects
server mode setups, where the server keeps running while a remote client
temporarily loses its connection and reloads. It was [raised in the
forum](https://forum.magicmirror.builders/topic/20218/request-loop-loading...-in-standard-weather-module-open-meteo-after-update/11?_=1777106416020)
and is worthy of a fix to improve the user experience.

With this PR the node helper caches the last successful `WEATHER_DATA`
payload per instance and replays it immediately on reconnect. The client
gets its last known state right away instead of waiting for the next
fetch. The cache is cleaned up when the provider stops.

Tests are included to cover reconnect with and without cached data, and
the cleanup path.
Open-Meteo updates `current_weather` every 15 minutes, but the hourly
array only has entries at full hours. The old code did an exact
timestamp match - so at 14:15, 14:30 or 14:45 it never found a match and
silently fell back to index 0, showing midnight values for humidity,
feels-like temp, precipitation, etc.

Fix: `findLastIndex((hour) => hour.time <= currentMs)` - the last hourly
entry at or before the current time.

While fixing the bug I found several dead branches left over from the
#4032 refactor: a path for pre-transposed hourly data that
`#parseWeatherApiResponse` makes unreachable, an `Array.isArray` guard
that's always true, and a `Log.debug` inside the dead branch. Removing
those accounts for most of the ~40 deleted lines - the actual fix is one
line.

Fixes #4122.
Comment thread clientonly/index.js Dismissed
Comment thread tests/configs/config_variables.js Dismissed
@khassel khassel merged commit fb41d24 into master Apr 30, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.