Skip to content

Add #107: Cycle Time flow setpoint (service flow arg + Cycle Flow entity)#109

Merged
eman merged 1 commit into
mainfrom
feature-issue-107
Jul 20, 2026
Merged

Add #107: Cycle Time flow setpoint (service flow arg + Cycle Flow entity)#109
eman merged 1 commit into
mainfrom
feature-issue-107

Conversation

@eman

@eman eman commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Implements #107: the Obj 91 Sub 421 flow setpoint (the speed the pump targets during cycle-mode ON periods, previously settable only from the GO app) is now exposed through the write interface and, per the review discussion on the issue, as a dashboard entity.

What this does

Service. pump_set_cycle_times gains a flow argument in m³/h (0.1-10.0, matching the constant-flow units convention; the wire float is SI m³/s, 0.227 m³/h = 1.0 gal/min). All three fields now accept 0 = keep-existing: kept fields are resolved from the operation's mandatory fresh Sub 421 read, never from cache, and a kept flow is still echoed to the pump byte-for-byte with no float round trip. Flow-only and single-period writes are therefore safe; a call with all three fields at 0 settles invalid ("nothing to write").

Verification. The confirm readback compares each asserted field (flow epsilon 0.005 m³/h) and distinguishes rejected (every asserted field still at its pre-read value: the pump ignored the write) from clamped (the pump stored something else), mirroring the setpoint semantics. The settle event gains flow (always reported from the readback on confirmed settles, so a keep-everything write doubles as a read) and requested_flow; requested_on_minutes/requested_off_minutes are now emitted independently and omitted for kept fields.

Entity. New "Cycle Flow" number (jfriend00's request on #107): box input, step 0.01, m³/h, reading the cached Sub 421 value and writing flow-only through the same one-write-path. The Cycle Time ON/OFF entities now write only their own period via the keep-existing sentinel instead of reconstructing the other from cache with hard-coded 15/5 fallbacks; an unreadable stored value now settles rejected instead of silently writing a default.

Behavior changes

  • pump_set_cycle_times declares a new field; HA requires all declared fields, so existing callers must add flow: 0 (the bench tool defaults it automatically). The surface is days old.
  • Minute arguments of 0 now mean keep-existing (previously settled invalid).
  • A cycle write the pump wholly ignores now settles rejected (was clamped).

Verification

Host suite: 494 assertions across 8 suites, 42 new for the flow matrix (flow-only preserving periods, combined write, installer-limit clamp, pump-kept rejection, invalid ranges with zero wire traffic, all-kept invalid, kept-periods-unreadable, entity-origin path). ESP32-C3 firmware compiles clean.

Bench-verified end to end on the real pump (every call settling with exactly one event):

Step Result
Keep-flow no-op baseline (on=5 off=15 flow=0) accepted; settled flow: 0.227 (= 1.0 gal/min) proves the verbatim-echo path and reads the current value
Flow-only write flow=0.20 accepted in 1.8 s; settled 0.200, periods untouched at 5/15, kept fields absent from requested_*
Cycle Flow entity readback 0.20 within one 5 s poll
Entity-path write to 0.25 (native-API number command) accepted; event carries origin: entity, op_id: ""
All-keep probe invalid "nothing to write", zero wire writes
flow=0.05 probe invalid range, zero wire writes
Restore flow=0.227 + final no-op accepted; settled 0.227 survives a kept-flow echo

The pump was returned to its pre-bench state (Temperature Control, 5/15 periods, 0.227 m³/h).

Closes #107.

…ity)

The Obj 91 Sub 421 flow setpoint (the speed the pump targets during
cycle-mode ON periods, previously GO-app-only) is now settable:

- pump_set_cycle_times gains a flow argument (m3/h, 0.1-10.0; wire float
  is SI m3/s, encoded via the existing constant-flow conversion)
- all three cycle fields accept 0 = keep-existing, resolved from the
  mandatory fresh Sub 421 read (kept flow stays a verbatim byte echo);
  all-kept settles invalid
- confirm compares per asserted field (flow eps 0.005 m3/h) with the
  pre-read values distinguishing rejected (pump kept) from clamped
- new Cycle Flow number entity (box input, step 0.01); Cycle Time ON/OFF
  entities now write only their own period via the 0-keep sentinel
  instead of reconstructing the other from cache with fallbacks
- settle event gains flow and requested_flow; requested_on/off_minutes
  are emitted independently and omitted for kept fields

Host suite: 494 assertions across 8 suites (42 new for the flow matrix,
incl. clamp, pump-kept rejection, invalid ranges, entity-origin path).
ESP32-C3 firmware compiles clean.

Copilot AI 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.

Pull request overview

This PR implements issue #107 by exposing the Cycle Time (Obj 91 Sub 421) flow setpoint through the existing write-operation interface and surfacing it as a Home Assistant dashboard number entity, while also making cycle-time entity writes safer by relying on the operation layer’s mandatory fresh pre-read rather than cached fallbacks.

Changes:

  • Extend pump_set_cycle_times to include flow (m³/h) with keep-existing sentinels and per-field confirm/readback semantics (accepted/clamped/rejected/invalid).
  • Add a new “Cycle Flow” template number entity and update Cycle Time ON/OFF entities to write only the asserted field (others keep-existing).
  • Update docs and changelog, and expand the host test suite with a flow matrix covering accepted/clamped/rejected/invalid paths and entity-origin behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/test_write_operations.cpp Adds simulator + host tests for cycle-flow setpoint writes and confirm semantics.
packages/alpha_hwr_controls.yaml Updates Cycle Time ON/OFF entities to keep-existing semantics and adds “Cycle Flow” number entity.
docs/programmatic-interface.md Documents the new flow field, keep-existing behavior, and event payload updates.
components/alpha_hwr/write_operation_service.h Extends WriteResult/operation state to include cycle flow + requested_flow, and updates submit signature.
components/alpha_hwr/write_operation_service.cpp Implements keep-existing resolution, flow encoding, and per-field confirm logic for cycle writes.
components/alpha_hwr/control_service.h Adds cached cycle-flow getter; extends write_dhw_config to accept optional setpoint bytes.
components/alpha_hwr/control_service.cpp Implements optional setpoint override for DHW config writes while preserving freshness guard.
components/alpha_hwr/api_bridge.h Updates service handler signature to accept flow.
components/alpha_hwr/api_bridge.cpp Registers flow service field and emits requested_flow + settled flow in events.
components/alpha_hwr/alpha_hwr.h Threads new flow argument through the facade and adds set_cycle_flow() / get_cached_cycle_flow().
CHANGELOG.md Records the feature and the service/entity behavior changes under [Unreleased].

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +924 to +925
float stored = protocol::decode_float_be(h.sim.dhw_setpoint_raw) * 3600.0f;
TEST_ASSERT(std::fabs(stored - 0.5f) < 0.005f, "pump stores the encoded flow (m³/s wire units)");
@eman
eman merged commit 0f0db40 into main Jul 20, 2026
3 checks passed
@eman
eman deleted the feature-issue-107 branch July 20, 2026 05:39
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.

Expose the Cycle Time flow setpoint (Obj 91 Sub 421) through the write interface

2 participants