Summary of PRs concerning me in progress

Hi @pierre-gilles,

Thanks for merging #3270: CI will no longer break on daylight saving time change days :folded_hands:

Here’s the status of my 10 other open PRs on Gladys. They are all mergeable, with no conflicts with master. Cursor has approved the latest versions of 9 of them. #3200 is still awaiting review after the rebase.

The only red in their CI is the sun curve test, the one fixed by #3270: their branches don’t yet contain the fix. It will disappear at the next rebase.

:warning: Another test will soon break, unrelated to time: the energy calendars test (calendar.test.js) publishes a hardcoded date from 2022. It will fail starting on 01/01/2027, when this date falls outside the 5-year window.

:thermometer: Thermostat: Fixes (feedback from @mutmut)

  • #3268 – fix: end of derogation at the right time despite time change
    A derogation “until the next slot” ended one hour too early or too late when the time changed in between. The banners also display the day of the slot when it’s not today. This day is calculated by the server in Gladys’ timezone, not in the phone’s timezone.
    :white_check_mark: Approved by Cursor. CodeRabbit’s comments have been addressed or answered.
  • #3269 – fix: derogation follows schedule changes
    If the schedule is modified during a derogation “until the next slot,” its end is recalculated on the new next slot. An already expired derogation is not restarted. An empty schedule receives the default duration.
    :white_check_mark: Approved by Cursor, CodeRabbit’s feedback addressed.

:thermometer: Thermostat: Features

To be merged in this order, as they stack: #3200 → #3201 → #3218. Then #3219, #3225, and #3258, in any order.

  • #3200 – air conditioning, multiple probes, filter by room
    Control of air conditioners (air-conditioning, mode and on/off), average of multiple temperature probes, selectors filtered by room. Also adds the “active preset” feature, with its migration, to trigger scenes when the schedule changes preset. Finally, an air conditioner turned on by remote during an “Off” slot creates a derogation until the next slot.
    :yellow_circle: Rebased, awaiting a new review from Cursor.
  • #3201 – radiators with pilot wire
    :white_check_mark: Approved by Cursor.
  • #3218 – delay before turning off heating when a window opens
    :white_check_mark: Approved by Cursor, CodeRabbit’s feedback addressed. Your decision: the default delay, set to 60 s for now.
  • #3219 – change thermostat schedule from a scene
    :white_check_mark: Approved by Cursor.
  • #3225 – animation of the gauge towards the new setpoint
    :white_check_mark: Approved by Cursor.
  • #3258 – “All day” option in schedule ranges
    :white_check_mark: Approved by Cursor.

:spiral_calendar: Scenes

  • #3015 – “time ranges” trigger
    A complete weekly schedule fits in a single scene. It launches at the start and end of each range (including those that cross midnight), with a scene.in-time-range condition.
    :white_check_mark: Rebased (conflicts resolved with scene updates), Spanish translation added, approved by Cursor.

:ocean: Dashboard

  • #3028 – tide widget
    Tide clock, next high and low tides, current water height, day curve, and tabs for 7 days. The coefficient is displayed on French coasts. The calculation is done locally once the station data is downloaded.
    I’ve left this PR open for now because, despite the graphical integration I’ve done, I still can’t do what I want with external integrations.

Thanks!

:alarm_clock: Appendix: A test that will break on 31/12/2026

In short: from 31/12/2026 at midnight (Paris time), the “Server test” job will be red on all PRs and on master, due to a single test. The code is correct; it’s the test that depends on the current date. This is the same type of issue as the sun test fixed by #3270.

The affected test
server/test/lib/energy-contract/manager/calendar.test.js (around line 292), added with energy contracts (#3130). It checks that the initial filling of a tariff calendar only recalculates costs from the start of the first contract (01/01/2025). To do this, it publishes a Tempo color with a hardcoded date:

await energyContract.publishCalendarEntries('tempo', [{ date: '2022-01-01', value: 'blue' }], ...);

Why it will break
calendar.publish.js refuses dates older than 5 years (PAST_WINDOW_MS = 5 * 365 days), which is intentional. But the window advances each day while the test date is fixed:

  • On 01/01/2022 in Paris, it starts at 2021-12-31T23:00Z.
  • The window counts 1,825 days, without leap years.
  • Between 01/01/2022 and 01/01/2027, there are 1,826 days, because 2024 is a leap year.

The date thus falls outside the window on 30/12/2026 at 23:00 UTC. The publication is then refused with starts_at must be between 5 years ago and 7 days ahead.

Verified by running this test on master with the clock offset:

Clock Result
30/12/2026 22:58 UTC :white_check_mark: 10 tests pass
30/12/2026 23:01 UTC :cross_mark: 1 failure

Possible fixes

  1. Bring the date closer (e.g., 2024-06-01): one line to change, but the problem returns mid-2029.
  2. Freeze the clock during this test with sinon’s fake timers (shouldAdvanceTime, because the test also relies on a real delay): the test no longer depends on the day it runs.

I propose option 2, in a small separate PR. I can take care of it if you want.

Hi @Will_71,

Thanks for all your hard work, and for the very clear summary!

I’ve reviewed your 10 PRs: code review, plus a test of the interface on each branch, with simulated devices (MQTT for windows and the pilot wire). Everything is posted as a comment on each GitHub PR. Overall, it works really well. Here are the main points:

  • #3268 / #3269 : OK. There’s just one point to fix on each: the label “tomorrow” remains displayed after midnight, and a 30-minute exception can be extended until the next point in the schedule.
  • #3200 : the air conditioning, the average of the sensors, and the filter by room work well. However, an air conditioning stop misinterpreted (timeout, power cut, remote control during an Off slot) can stop the thermostat permanently. Small point: a Comfort setting at 21°C by default in air conditioning mode is cold.
  • #3201 : great in the interface. Just one real issue: once the radiator is stopped from the module, you can’t restart it from the module.
  • #3218 : OK. You just need to limit the delay, as a huge value overflows the timer.
  • #3219 : OK. The “service stopped” test doesn’t work, and the summary of the card displays the raw ID of the schedule.
  • #3225 : OK, just a bit of finishing.
  • #3258 : “Copy to” a day in “All day” cuts off the heating for the rest of the day. This needs to be fixed before merging, as it’s the typical use case for holidays.
  • #3015 : issue with the time change for slots that start or end between 2 a.m. and 3 a.m., and a bug in the editor (the lines reorder while you’re typing).
  • #3028 : as you said, it’s better to go through an external integration. I noted in the review what will need to be revisited during the porting.

Two general remarks:

  • Each PR passes alone on master, but #3200, #3201 and #3218 conflict with each other. During the rebase, some lines won’t be flagged by git but will break; I listed them in the reviews.
  • The “Server test” red on all PRs comes from the solar curve test during the time change, fixed by #3270. A merge of master is sufficient.

Thanks again, it’s a great contribution to the thermostat! :folded_hands:

Thanks for your feedback. I’ll take care of it as soon as possible.

For PRs that will be in conflict, yes, it was planned, but I didn’t want to mix them, knowing that the requests and bugs came in as testing progressed, so each PR didn’t open at the same time.

I’ll keep you informed as soon as I make progress.

For the PR on tides, the external integration has been published for several days now, but I left the PR open for the moment regarding certain graphical points that I can’t reproduce.