Skip to content

Add preset temperatures and weekly schedules for Adam zones - #937

Closed
MartvanMale wants to merge 7 commits into
plugwise:mainfrom
MartvanMale:zone-preset-and-schedule
Closed

MartvanMale wants to merge 7 commits into
plugwise:mainfrom
MartvanMale:zone-preset-and-schedule

Conversation

@MartvanMale

@MartvanMale MartvanMale commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Draft: I'm still doing a final review of my own before this is ready.

Summary

This adds two things Home Assistant users of an Adam (and a non-legacy Anna) cannot do today: change the temperatures behind the presets of a zone, and read and change the weekly schedules on the gateway. It picks up the request from #57 and the work in #59 and plugwise-beta#148, which were closed in 2021 without being merged.

Two existing bugs are fixed along the way.

The diff looks large, but most of it is test data: 57 files in fixtures/ and tests/data/ hold about 16,800 of the 17,400 added lines. The code changes are about 650 lines in plugwise/ and tests/*.py.

Changes

  1. Each zone now reads its own preset rule (bug fix). _presets() read every preset rule on the gateway and the last one won, so every zone showed the same preset setpoints. It now reads the rule attached to the zone, and falls back to the old behaviour when a zone has no single rule of its own.
  2. Each zone with its own preset rule gets preset temperatures: home_preset_temperature, asleep_preset_temperature, away_preset_temperature, vacation_preset_temperature and no_frost_preset_temperature, each an actuator with bounds 4-30 and resolution 0.5. set_number() writes them through set_preset_temperature().
  3. The gateway entity gets schedules: per rule id the name, the active flag, the zones it is attached to, and its time slots ({"start": "mo 07:15", "end": "mo 16:30", "preset": "home"}). Start and end keep the gateway's own notation.
  4. set_schedule() changes a schedule's slots and, optionally, its name. create_schedule() and delete_schedule() add and remove schedules.
  5. Switching a schedule on now activates it (bug fix). set_schedule_state() only attached the zone. On my Adam a schedule does not run unless its rule is active, so choosing an inactive schedule did nothing, while the zone was still reported as following it. Switching on now also sends <active>true</active>. This includes a schedule that is already attached but inactive.
  6. Writes are validated. Schedule slots are checked for day and time notation, numeric setpoints in range and valid keys, and names cannot contain ]]>. Preset writes keep every attribute and escape the values. Legacy gateways raise PlugwiseError for schedule writes.

Gateway behaviour

Measured on my Adam, firmware 3.12.6, with test rules attached to no zone or to a zone at 5-6 °C (below room temperature):

  • A PUT to /core/rules;id=… that carries <directives> replaces the whole directive set, for preset rules and schedules alike. A PUT without <directives> keeps them. Both writers therefore send the complete set.
  • Writing a preset rule re-applies the zone's active preset, so a manual setpoint on that zone is reset. I documented this rather than restore the setpoint afterwards.
  • Schedules accept gaps and overlapping slots. With overlapping slots, the slot that starts latest wins. Four schedules in the fixtures that were made in the app only make sense under this reading. A malformed time gets HTTP 400 and changes nothing.
  • POST /core/rules creates a schedule, inactive and attached to no zone. DELETE /core/rules;id=… removes one.
  • Switching a running schedule off, or deleting it, leaves the zone at its last setpoint.

Tests

  • New tests for every part, run against the existing fixtures; coverage stays at 100%.
  • tests/data/*/*.json and fixtures/*/data.json are updated for the new keys and the per-zone preset order. The expected schedules were computed from each fixture's XML by a separate parser, and both parsers agree on all 38 setups in userdata/.
  • mypy, ruff, pylint and the other pre-commit hooks pass.

Open questions

  • The preset temperatures cover heating only; the cooling setpoints are kept as they are. Is that acceptable as a first step?
  • I can split this into smaller PRs if you prefer. Each commit comes with its own tests, and the commits follow the order of the list above, except that the last one adds both a switching fix and the validation.

Running in Home Assistant

A test Home Assistant (2026.10.2) runs my plugwise-beta branch on top of this library branch, connected to my Adam. Each zone shows the five preset temperature numbers in its Configuration section, and each schedule on my gateway shows up as a read-only calendar. The plugwise-beta branch adds actions to get, set, create and delete schedules, and I have run them against my gateway.

A zone with its preset temperatures The Set schedule action
Garage zone with its preset temperature numbers Set schedule action form

Once these changes are in a release, I will open the plugwise-beta PR with the number entities, the calendars and the actions.

Summary by CodeRabbit

  • New Features
    • View schedules, including their active status, time slots, and zone assignments.
    • Create, edit, activate, and delete schedules on supported gateways.
    • View and adjust heating setpoints for individual zones’ home, asleep, away, vacation, and no-frost presets.
  • Limitations
    • Schedule changes are not supported on legacy gateways.

_presets() now reads only the preset rule attached to the zone, so each
zone on an Adam with several zones gets its own preset setpoints. When no
rule or several rules are attached to a zone, it reads all preset rules,
so gateways without per-zone rules keep their preset list.
set_number() sends all five presets on every write and changes only the
target heating setpoint. The gateway replaces a rule's whole directive
set on each write.
Schedules are keyed by rule id. Slot start and end times keep the
gateway's notation, such as "mo 07:15".
Slots are checked for valid day and time notation and a setpoint
between 4 and 30 before anything is sent to the gateway.
set_schedule_state() sends active=true with the contexts when a schedule
is switched on. Switching off leaves the flag as it is.
- set_schedule_state() switches on a schedule that is attached but
  inactive, instead of treating it as already on.
- set_schedule() no longer fails on a rule without directives or a name,
  and set_preset_temperature() refuses a preset rule whose switch point
  lacks its settings.
- Switching an attached schedule on again no longer adds its zone a
  second time.
- A schedule renamed through set_schedule() can be switched by its new
  name.
- Schedule writes check every setpoint value and slot key, and refuse
  a name containing "]]>".
- Preset writes keep every attribute of the rule and escape the values.
- Legacy gateways refuse schedule writes instead of ignoring them.
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f260494f-1fa9-4115-a643-3f51b2ffd370
Commits

Reviewing files that changed from the base of the PR and between a9c1c2f and fa2ffc5.

Files selected for processing: 68
  • CHANGELOG.md
  • fixtures/adam_bad_thermostat/data.json
  • fixtures/adam_heatpump_cooling/data.json
  • fixtures/adam_jip/data.json
  • fixtures/adam_multiple_devices_per_zone/data.json
  • fixtures/adam_onoff_cooling_fake_firmware/data.json
  • fixtures/adam_plus_anna/data.json
  • fixtures/adam_plus_anna_new/data.json
  • fixtures/adam_plus_anna_new_regulation_off/data.json
  • fixtures/adam_zone_per_device/data.json
  • fixtures/anna_elga_2/data.json
  • fixtures/anna_elga_2_cooling/data.json
  • fixtures/anna_elga_2_schedule_off/data.json
  • fixtures/anna_elga_no_cooling/data.json
  • fixtures/anna_heatpump_cooling/data.json
  • fixtures/anna_heatpump_cooling_fake_firmware/data.json
  • fixtures/anna_heatpump_heating/data.json
  • fixtures/anna_loria_cooling_active/data.json
  • fixtures/anna_loria_driessens/data.json
  • fixtures/anna_loria_heating_idle/data.json
  • fixtures/anna_p1/data.json
  • fixtures/anna_v4/data.json
  • fixtures/anna_v4_dhw/data.json
  • fixtures/anna_v4_no_modules/data.json
  • fixtures/anna_v4_no_tag/data.json
  • fixtures/anna_without_boiler_fw441/data.json
  • fixtures/m_adam_cooling/data.json
  • fixtures/m_adam_heating/data.json
  • fixtures/m_adam_heating_off_schedule/data.json
  • fixtures/m_adam_jip/data.json
  • fixtures/m_adam_multiple_devices_per_zone/data.json
  • fixtures/m_anna_heatpump_cooling/data.json
  • fixtures/m_anna_heatpump_idle/data.json
  • plugwise/__init__.py
  • plugwise/constants.py
  • plugwise/data.py
  • plugwise/helper.py
  • plugwise/legacy/smile.py
  • plugwise/smile.py
  • tests/data/adam/adam_bad_thermostat.json
  • tests/data/adam/adam_heatpump_cooling.json
  • tests/data/adam/adam_jip.json
  • tests/data/adam/adam_multiple_devices_per_zone.json
  • tests/data/adam/adam_onoff_cooling_fake_firmware.json
  • tests/data/adam/adam_plus_anna.json
  • tests/data/adam/adam_plus_anna_new.json
  • tests/data/adam/adam_plus_anna_new_regulation_off.json
  • tests/data/adam/adam_zone_per_device.json
  • tests/data/anna/anna_elga_2.json
  • tests/data/anna/anna_elga_2_cooling.json
  • tests/data/anna/anna_elga_2_schedule_off.json
  • tests/data/anna/anna_elga_no_cooling.json
  • tests/data/anna/anna_heatpump_cooling.json
  • tests/data/anna/anna_heatpump_cooling_fake_firmware.json
  • tests/data/anna/anna_heatpump_heating.json
  • tests/data/anna/anna_loria_cooling_active.json
  • tests/data/anna/anna_loria_driessens.json
  • tests/data/anna/anna_loria_heating_idle.json
  • tests/data/anna/anna_p1.json
  • tests/data/anna/anna_v4.json
  • tests/data/anna/anna_v4_dhw.json
  • tests/data/anna/anna_v4_no_modules.json
  • tests/data/anna/anna_v4_no_tag.json
  • tests/data/anna/anna_without_boiler_fw441.json
  • tests/test_adam.py
  • tests/test_anna.py
  • tests/test_init.py
  • tests/test_legacy_anna.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

This change adds parsing and exposure of weekly gateway schedules and per-zone preset temperatures. It adds API operations to update presets and create, edit, and delete schedules, and changes schedule activation handling. Fixtures and tests cover Adam and Anna devices.

Changes: Schedules and preset temperature support

Layer / File(s) Summary
Gateway data and entity parsing
plugwise/constants.py, plugwise/helper.py, plugwise/data.py, fixtures/*/data.json, tests/data/*
The gateway data model now includes schedule details and five preset-temperature actuators. Parsing collects schedule names, activation state, zone associations, time slots, and preset-rule data. Device fixtures add schedule and preset-temperature examples.
Preset and schedule write behavior
plugwise/smile.py, tests/test_adam.py, tests/test_init.py
The API validates and serializes preset and schedule writes. It updates cached rule data after successful requests. Schedule activation requests now set the active marker and avoid duplicate zone-context changes.
Public API and legacy behavior
plugwise/__init__.py, plugwise/legacy/smile.py, tests/test_legacy_anna.py, CHANGELOG.md
The public API exposes schedule set, create, and delete methods. The legacy API rejects these operations. The changelog records the schedule and preset-temperature changes.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant SmileAPI
  participant Gateway
  Client->>SmileAPI: Request schedule update
  SmileAPI->>Gateway: Send validated schedule data
  Gateway-->>SmileAPI: Return response
  SmileAPI->>SmileAPI: Update cached schedule state
Loading

Possibly related PRs

  • plugwise/python-plugwise#934: Both changes cover selection and activation of schedules linked to a location, including schedules that are inactive.
  • plugwise/python-plugwise#936: This change adds schedule and preset write requests that use the request retry path addressed by PR #936.

Suggested reviewers: compatech, bouwew

Merge Risk: Minimal · up to fa2ff

This change adds per-zone preset temperatures and schedule editing for Adam and Anna gateways. No concrete merge-blocking defect was found in the supplied context. The open question about preset heating values above the cooling value rests on gateway behavior that has not been confirmed.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the main changes: preset temperatures and weekly schedules. It is concise and directly related to the changeset, although it does not mention the additional Anna support.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 69 functions across 10 files. (58 skipped:…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 69 functions across 10 files. (58 skipped: 58 unsupported.)

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai
coderabbitai Bot requested review from CoMPaTech and bouwew October 25, 2026 20:24
@bouwew

bouwew commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

@MartvanMale nice work!!

And yes, please split this PR in two parts, one covering the presets and one covering the schedules.

Also, I would want to test the integration-updates in Plugwise-beta before rolling them out to HA Plugwise (I just had a look in your github, you are already testing in pw-beta👍)).

@MartvanMale

Copy link
Copy Markdown
Contributor Author

Thanks, I will split this PR into two and create one into plugwise-beta.
The plugwise-beta side is running on my test instance. I will give it a final check and then open the PR.

@bouwew bouwew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split this PR into two separate PR's, thanks!

@bouwew

bouwew commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

@MartvanMale please rebase onto the updated plugwise main branch (= v1.16.0) and create a new PR for the weekly schedule functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants