Repository navigation
test(trace): ingest the F461 2.0.11 heating comfort / eco preset capture (dimension 12 split from 14) - #812
Conversation
…ure (dimension 12 split from 14) Follow-up asked for in the review of OpenWebNet-HA#810: from a 23.5 baseline on the physical F461 2.0.11 + Living Now KW4691 (zone 2, heating season), the dimension 7 templates *michnovka#4*2*michnovka#7*1*3## (heating comfort) and *michnovka#4*2*michnovka#7*1*4## (heating eco), each followed at once by reads of dimension 12 and 14, a *michnovka#4*2## poll and reads 48 s into eco, then Home Assistant's climate.set_temperature 23.5 while the two dimensions differed (2026-10-24 20:08-20:12 UTC; results posted on OpenWebNet-HA#791). What the plant said: a heating preset moves dimension 12 (21.0, then 18.0) and leaves dimension 14 at the last commanded value (23.5) for as long as it was observed (48 s); the mode frame *4*108*2## / *4*107*2## takes the season frame's place in the dimension 12 and *michnovka#4*2## replies; the write is echoed as *4*1*2##, *michnovka#4*2*12*0235*3##, *4*1*2##, *michnovka#4*2*0*0238## and the poll 7.4 s later reads 12 = 14 = 23.5. On the base branch the climate entity shows 23.5 -> 21.0 -> 18.0 in heat and 23.5 after the write. Archive tests/fixtures/traces/f461_presets_live_2026-10-24/ in the format of f461_live_2026-10-24 (47 event-session frames, 122 rows, two runs, one listener, probe rows aligned to the listener clock, t_estimated on the command-session replies, events_after bounded by the ACK, synthetic MAC / IP), its README, tests/test_f461_presets_live_2026_10_24_trace.py (9 tests) and *michnovka#4*2*michnovka#7*1*4## in PHYSICAL_ONLY_TX_FRAMES (no oracle stimulus; tier 1 failed on it before). *4*107*2## / *4*108*2## parse with mode = None (OpenWebNet-HA/OWNd#146). Refs OpenWebNet-HA#791 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
GreenGrassBlueOcean
left a comment
There was a problem hiding this comment.
Thanks for the clean follow-up capture on the physical F461 2.0.11 + KW4691 plant — this closes item 1 from #810 review 5639746797 cleanly. Archive schema, monotonic t / t_estimated / events_after invariants, UTC math, privacy checks (0 findings), PHYSICAL_ONLY_TX_FRAMES coverage, and the 8-section PR #778 template all check out.
Requesting one small test adjustment before merge so we don't create a cross-repo CI deadlock when OpenWebNet-HA/OWNd#146 lands:
Blocking: make WHAT 107 / 108 / 208 assertions forward-compatible with OpenWebNet-HA/OWNd#146
OpenWebNet-HA/OWNd's .github/workflows/myhome-conformance.yml (MyHOME test suite job) is a required CI check on every OWNd PR: it checks out OpenWebNet-HA/MyHOME (v2-phase1-architecture), installs the OWNd PR checkout in place of the pinned release, and runs pytest tests.
Right now, two trace tests hard-pin mode is None and human_readable_log == "Zone 2's mode is unknown.":
tests/test_f461_presets_live_2026_10_24_trace.pylines 297–301 (this PR) for*4*107*2##/*4*108*2##.tests/test_f461_live_2026_10_24_trace.pylines 292–296 (merged in #810) for*4*108*2##/*4*208*2##.
As soon as an OWNd PR implements OpenWebNet-HA/OWNd#146 (decoding 107 / 108 as heating eco / comfort with mode == "heat", season == "heating" and 207 / 208 as cooling eco / comfort with mode == "cool", season == "conditioning"), OWNd's required MyHOME test suite gate will fail on both assertions before MyHOME can bump its OWNd== pin.
Please relax both locations to accept both pre-OWNd#146 (None) and post-OWNd#146 ("heat" / "cool" with matching season), following the dual-OWNd pattern in tests/test_message_edges.py:194,201 (see inline suggestion on tests/test_f461_presets_live_2026_10_24_trace.py, and apply the analogous (None, "heat") / (None, "cool") update to tests/test_f461_live_2026_10_24_trace.py:292-296).
(Note: I verified test_replay_presets_show_dimension_12_and_keep_heating at lines 445–472 against climate.py — MESSAGE_TYPE_MODE sets HVACMode.HEAT on CLIMATE_MODE_HEAT and only calls _show_nominal() when prev_mode == HVACMode.OFF, so the entity replay already stays green after OWNd#146; only the docstring note (mode = None) at line 449 would become historical.)
Minor / non-blocking
- Rounding nit (
+15.5 svs+16 s): the*#4*2##zone poll inheating_eco(t = 53.394vst = 37.864,+15.53 s) is written as+15.5 sinREADME.md(lines 67, 82) and Hardware Verification, and rounded to+16 sin the Mermaid sequence diagram,capture.runs[0].purpose(JSON line 21), andtests/test_f461_presets_live_2026_10_24_trace.pydocstring (line 24). Optional to align while touching the test file. - Once updated, please mark the PR Ready for review and we can merge right away.
| # the mode frames 107 / 108 parse but carry no mode the pinned OWNd knows (OpenWebNet-HA/OWNd#146) | ||
| for raw in (MODE_ECO, MODE_COMFORT): | ||
| msg = OWNMessage.parse(raw) | ||
| assert msg is not None and msg.zone == 2 and getattr(msg, "mode", None) is None | ||
| assert msg.human_readable_log == "Zone 2's mode is unknown." |
There was a problem hiding this comment.
Accept both pinned OWNd <= 2.0.0b11 (mode is None) and OpenWebNet-HA/OWNd#146 (mode == "heat", season == "heating") so OWNd's myhome-conformance.yml gate stays green when OWNd#146 opens (please apply the matching (None, "heat") / (None, "cool") relaxation to tests/test_f461_live_2026_10_24_trace.py:292-296 in this PR as well):
| # the mode frames 107 / 108 parse but carry no mode the pinned OWNd knows (OpenWebNet-HA/OWNd#146) | |
| for raw in (MODE_ECO, MODE_COMFORT): | |
| msg = OWNMessage.parse(raw) | |
| assert msg is not None and msg.zone == 2 and getattr(msg, "mode", None) is None | |
| assert msg.human_readable_log == "Zone 2's mode is unknown." | |
| # WHAT 107 / 108: pinned OWNd <= 2.0.0b11 leaves mode = None; OpenWebNet-HA/OWNd#146 decodes them as heating eco / comfort. | |
| for raw in (MODE_ECO, MODE_COMFORT): | |
| msg = OWNMessage.parse(raw) | |
| assert msg is not None and msg.zone == 2 | |
| assert getattr(msg, "mode", None) in (None, "heat") | |
| assert getattr(msg, "season", None) in (None, "heating") | |
| assert (getattr(msg, "mode", None) is None) == ( | |
| msg.human_readable_log == "Zone 2's mode is unknown." | |
| ) |
…ide the pinned None Review of OpenWebNet-HA#812 (5642383839): OWNd's required MyHOME conformance job runs this suite against every OWNd PR, so the two trace tests that pinned `mode is None` for *4*107*2##, *4*108*2## and *4*208*2## would fail the moment OpenWebNet-HA/OWNd#146 decodes them (heating eco / comfort, cooling comfort). Both locations (this PR's presets test and the merged f461_live_2026-10-24 test) now accept None or the decoded mode / season, with the "mode is unknown" log tied to the None case, as tests/test_message_edges.py does for the two OWNd generations. Rounding nit: the *michnovka#4*2## poll 15.53 s into eco is written +15.5 s everywhere (test docstring, archive purpose), as in the README. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Done in 5ff109d and marked ready for review.
|
GreenGrassBlueOcean
left a comment
There was a problem hiding this comment.
LGTM — thanks for the quick turnaround! Both trace tests (test_f461_presets_live_2026_10_24_trace.py and test_f461_live_2026_10_24_trace.py) now keep OWNd's myhome-conformance.yml gate green across both pinned OWNd and OpenWebNet-HA/OWNd#146, and the +15.5 s rounding is aligned throughout.
089fef5
into
OpenWebNet-HA:v2-phase1-architecture
…ixtures hold (#799, #810, #815 follow-up) Read against the fixture rows rather than the PR texts: - f461_live_2026-10-23 README: run 1 is 165 read-only requests in total (134 mirrored from the oracle suites plus 31 plant reads), not 165 plus 31; the setpoint write `*#4*2*#14*0235*3##` is followed by dimension 12 at once and no dimension 14 is pushed: the "dimension 14 catches up 0.3 s later" was the 12 -> 14 gap inside the reply to the probe's own `*#4*2##` 2.8 s later. test_setpoint_write_mode_3_restores_the_setpoint_in_force asserted only evt.index(12) < evt.index(14), which the poll reply order satisfies by itself; it now asserts that no dimension 14 follows the write before the next request, and its docstring matches. - test_replay_run4b_zone_2_through_the_climate_entity said "valve off" for a run without any dimension 19 / 20 frame and never asserted the commanded setpoint: the docstring drops the valve, the body asserts _target_temperature == 23.5. - myhomeserver1_live_2026-10-24 README: 33 zones report a temperature (zone 43 has an actuator but no dimension 0), 34 answer the actuator request; the all-zone actuator test's docstring counts the 43 frames its body asserts (44 only with the earlier zone 35 reply). - test_trace_oracle_validation note for `*#4*0*60##`: the MyHomeServer1 ACK came at 0.50 s with 8 replies; the 17th zone answered by 0.97 s. - test_replay_knob_turn_shows_dimension_12 (#810) claimed "dimension 14 changes nothing" on a run whose every dimension 14 frame carries the dimension 12 value, 18.0; the values cannot tell the two apart, so the test asserts the dimension 12 hold flag, which only a dimension 12 report sets, and says where the discriminating replay is (#812). - test_replay_action_sequence_matches_the_recorded_entity_states (#815) compared the replay and the record with two separate literals; it now compares the recorded actions with the replay's first changes and says the trailing idle was read back, not recorded. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Record note from the WHO 4 PDF audit of 2026-10-26 (no change requested): the dimension 7 preset templates ( |
Requested by A
Refs #791
What is the problem
The review of #810 (review 5639746797, "Follow-up PRs / issues", item 1) asked for a small follow-up trace: in
f461_live_2026-10-24run 4 the heating comfort template*#4*2*#7*1*3##had been sent from a 21.0 baseline that already matched the KW4691's comfort preset, the "eco" request there was*#4*2*#7*2*3##(context 2 / state 3, cooling comfort, not heating eco*#4*2*#7*1*4##), and no dimension 14 read was sent while the preset was active. The capture was run the same evening and its results were posted on #791 (comment 6388993746); this PR puts the frames in the repository, astests/fixtures/traces/f461_live_2026-10-24/did for the first capture.What is the solution
A new derived trace archive,
tests/fixtures/traces/f461_presets_live_2026-10-24/(named afterf461_who14_live_2026-10-18: gateway, topic,live, date), in the exact format off461_live_2026-10-24(command-session replies at their request'stwitht_estimated,events_afterbounded by the ACK, one monotonictaxis with per-runt_offset,probe_segmentswithlistener_offset_s, synthetic MAC00:03:50:00:10:23/ IP192.0.2.92, genericclimate.climate_zone_2), plustests/test_f461_presets_live_2026_10_24_trace.py(9 tests) and one entry inPHYSICAL_ONLY_TX_FRAMES.climate.set_temperature.capture.runs[].probe_segments[].listener_offset_s; the probe's own event log matched the listener's frames exactly over every request window before it was dropped). Home Assistant's only request in the window, the*#4*2*#14*0235*3##write at 20:11:20 UTC, is listed incapture.home_assistant_requestsfrom its debug log (not included); its echo is in the frames and it has notx/resultrow. Home Assistant sent no poll between the listener start and the write (its debug log shows only frames received).capture.runs):run1_heating_comfort_then_heating_eco103 rows / 36 frames (20:08:49-20:10:22 UTC),run2_home_assistant_write_realigns19 / 11 (20:11:20-20:12:04 UTC); 47 event-session frames and 122 rows in all. The listener's frames after 20:12:04 UTC (clock, humidity, temperature) are not included.gatewayblock only (no WHO 13 identity frame was exchanged); no password, no local paths, no logs or diagnostics, no room-named entity id.python scripts/anonymize_plant_fixture.py --checkon the three new files: 0 with personal data;tests/test_fixture_privacy.pypasses.tests/test_trace_oracle_validation.py:*#4*2*#7*1*4##joinsPHYSICAL_ONLY_TX_FRAMES(no oracle stimulus for the dimension 7 templates; tier 1 failed on exactly that frame before the entry); the*#4*2*#7*1*3##entry's note now also records this capture's reply (from 23.5). Tier 4: every rx frame parses in the pinned OWNd;*4*107*2##/*4*108*2##parse withmode = Noneon the pinned OWNd (heating: WHAT 107 / 108 / 208 (zone eco / comfort mode echoes of a KW4691 behind an F461) are not decoded OWNd#146), so nopending_decoder_rxentry is needed; the test accepts the decoded heating eco / comfort as well, so OWNd's conformance job stays green when "Failed to set up" issue #146 lands.python scripts/update_trace_matrix.pywas run: the F461 row already covers WHO 4 and 13,README.md/docs/trace-availability.mdare unchanged.*#4*2*#7*1*4##is context 1 (heating), state 4 (eco), heating eco;*#4*2*#7*1*3##is heating comfort. The archive's steps arebaseline_poll,heating_comfort,heating_eco,poll_after_ha_write; the test locals use the same names.State Diagram
sequenceDiagram participant Z as F461 zone 2 KW4691 participant P as probe participant H as Home Assistant Note over Z,H: run 1, baseline 12 = 14 = 23.5 P->>Z: *#4*2## Z-->>P: 0, *#4*2*12*0235*3##, *4*1*2##, *#4*2*14*0235*3##, 13 Note over Z,H: heating comfort template P->>Z: *#4*2*#7*1*3## Z-->>P: *#4*2*7*1*3##, *#4*2*12*0210*3##, *4*108*2## P->>Z: *#4*2*12## and *#4*2*14## at +1 s and +13 s Z-->>P: 12 = 21.0 with *4*108*2##, 14 = 23.5 Note over Z,H: heating eco template P->>Z: *#4*2*#7*1*4## Z-->>P: *#4*2*7*1*4##, *#4*2*12*0180*3##, *4*107*2## P->>Z: *#4*2*12## and *#4*2*14## at +1 s, +13 s and +48 s Z-->>P: 12 = 18.0 with *4*107*2##, 14 = 23.5 P->>Z: *#4*2## at +15.5 s Z-->>P: 0, *#4*2*12*0180*3##, *4*107*2##, *#4*2*14*0235*3##, 13 Note over Z,H: run 2, the write realigns both H->>Z: *#4*2*#14*0235*3## Z-->>H: *4*1*2##, *#4*2*12*0235*3##, *4*1*2##, *#4*2*0*0238## P->>Z: *#4*2## 7.4 s later Z-->>P: 0, *#4*2*12*0235*3##, *4*1*2##, *#4*2*14*0235*3##, 13Review follow-up (review 5642383839)
mode is None, a cross-repo deadlock once heating: WHAT 107 / 108 / 208 (zone eco / comfort mode echoes of a KW4691 behind an F461) are not decoded OWNd#146 lands → 5ff109d: both locations relaxed as suggested,tests/test_f461_presets_live_2026_10_24_trace.py(107 / 108:mode in (None, "heat"),season in (None, "heating")) and the mergedtests/test_f461_live_2026_10_24_trace.py(108 →heat/heating, 208 →cool/conditioning), with the "mode is unknown" log asserted only for theNonecase (a second-opinion review pointed out that a decoder might keep that log string). The replay test needs no change (noted in its docstring thatmode = Noneis the pinned behaviour).+15.5 sin the test docstring, the archivepurposeand the sequence diagram, as in the README.Hardware Verification
F461 2.0.11, KW4691 zone 2, 2026-10-24 20:08-20:12 UTC; every frame is in the archive.
*#4*2*#7*1*3##from 12 = 14 = 23.5 (ACK 68 ms) was echoed as*#4*2*7*1*3##,*#4*2*12*0210*3##,*4*108*2##,*#4*2*0*0238##;*#4*2*12##answered*#4*2*12*0210*3##,*4*108*2##and*#4*2*14##answered*#4*2*14*0235*3##at +1 s and at +13 s.*#4*2*#7*1*4##15.5 s later (ACK 89 ms) was echoed as*#4*2*7*1*4##,*#4*2*12*0180*3##,*4*107*2##,*#4*2*0*0238##; dimension 12 read 18.0 (with*4*107*2##) and dimension 14 read 23.5 at +1 s, +13 s and +48 s. Every 12 / 14 pair read after the comfort echo differed (21.0 / 23.5 twice, 18.0 / 23.5 three times); nothing realigned them while a preset was active. The split was observed for 48 s into eco; how long it lasts beyond that was not measured.*#4*2*12##returns*4*108*2##/*4*107*2##where the heating season returns*4*1*2##, and the*#4*2##poll 15.5 s into eco answered*#4*2*0*0238##,*#4*2*12*0180*3##,*4*107*2##,*#4*2*14*0235*3##,*#4*2*13*00##, as*4*102*2##does in antifreeze (f461_live_2026-10-24run 3). The season frame appears once in run 1 (the baseline poll).climate.set_temperature23.5 at 20:11:20 UTC, 2 min into eco:*4*1*2##,*#4*2*12*0235*3##,*4*1*2##,*#4*2*0*0238##(no dimension 14 frame, as for every dimension 14 write off461_live_2026-10-24); the*#4*2##sent 7.4 s after the echo (result at 8.8 s, ACK 1.44 s) read0,12= 23.5,*4*1*2##,14= 23.5,13. 43 s after the write the valve reported itself off (*#4*2#1*#20*0##,*#4*2#1*20*0##); no actuator frame accompanied the preset changes.*#4*2##polls in 1.30-1.44 s, the two template writes in 68 / 89 ms; a template's echo reached the event session 35-50 ms after its ACK. No dimension 14 frame other than a read reply and no dimension 7 frame other than the two template echoes is in the capture; the*#4*2*60*40##at 20:10:22 UTC arrived with no request in either log.hvac_mode: heatthroughout (the dimension 14 read replies do not move the shown setpoint, the mode frames 107 / 108 leave the mode alone, the dimension 7 heating context keepsheat); run 2's echo moves it to 23.5 at once. This is the behaviour fix(climate): show the setpoint in force (dimension 12), keep dimension 14 as the commanded value #791 merged, now pinned on the preset path.How is it tested
pytest tests/test_f461_presets_live_2026_10_24_trace.py: 9 passed. Schema and synthetic identity, every frame parses in the pinned OWNd (with the zone stateeco/comfortin theheatingcontext andmode = Nonefor 107 / 108), result rows consistent with theirtx/rxrows (a template write has no reply and its echo arrived after the ACK), the comfort and eco facts above with their offsets (+1.1 / +13.3 / +47.8 s for dimension 12, +2.2 / +14.4 / +49.0 s for dimension 14), the "no realignment while a preset is active" statement over every pair read, the write echo and the poll of run 2, and two replays of the event frames through the climate entity as it is on the base branch (23.5 -> 21.0 -> 18.0 inheat; 18.0 -> 23.5 on the write echo).pytest tests/test_trace_oracle_validation.py tests/test_device_health_corpus.py tests/test_fixture_privacy.py: 254 passed (tier 1 failed on*#4*2*#7*1*4##before thePHYSICAL_ONLY_TX_FRAMESentry: 1 failed, 253 passed).master, f04d8aa, no fix PR applied):pytest tests/ -n 4 --cov=custom_components.myhome: 4533 passed, 1 skipped, 100 % statement coverage (16,080 / 16,080).ruff check .,scripts/typing_ratchet.py(0 strict errors),scripts/verify_ha_standards.py,scripts/sync_documentation.py --check,scripts/update_trace_matrix.py(no change),scripts/anonymize_plant_fixture.py --check(3 files, 0 with personal data): all pass.Where are the traces
tests/fixtures/traces/f461_presets_live_2026-10-24/myhome_trace_F461_presets_live_2026-10-24.json,run1_heating_comfort_then_heating_eco, stepheating_comfort*#4*2*#7*1*3##->*#4*2*7*1*3##,*#4*2*12*0210*3##,*4*108*2##;*#4*2*12##->*#4*2*12*0210*3##,*4*108*2##;*#4*2*14##->*#4*2*14*0235*3##(+1 s, +13 s)heating_eco*#4*2*#7*1*4##->*#4*2*7*1*4##,*#4*2*12*0180*3##,*4*107*2##;*#4*2*12##->*#4*2*12*0180*3##,*4*107*2##;*#4*2*14##->*#4*2*14*0235*3##(+1 s, +13 s, +48 s);*#4*2##->0, 12 = 0180, *4*107*2##, 14 = 0235, 13run2_home_assistant_write_realigns*#4*2*#14*0235*3##(Home Assistant) ->*4*1*2##,*#4*2*12*0235*3##,*4*1*2##,*#4*2*0*0238##;*#4*2##->0, 12 = 0235, *4*1*2##, 14 = 0235, 13;*#4*2#1*#20*0##,*#4*2#1*20*0##tests/fixtures/traces/f461_live_2026-10-24/,run4_preset_templates(#810)*#4*2*#7*1*3##->*#4*2*12*0210*3##(unchanged);*#4*2*#7*2*3##->*#4*2*7*2*3##,*#4*2*12*0250*3##,*4*208*2##What does the Firmware Oracle / Encyclopedia say
*#4*2##,*#4*2*12##and*#4*2*14##canonicalise to existing verdicts (tier 1 passes), while*#4*2*#7*1*4##has no stimulus and joins*#4*2*#7*1*3##/*#4*2*#7*2*3##inPHYSICAL_ONLY_TX_FRAMESwith its live reply. The ACK timings (reads 95-149 ms, template writes 68-89 ms,*#4*2##1.30-1.44 s) match the F461 rows off461_live_2026-10-23andf461_live_2026-10-24.*#4*where*#7*[CONTEXT]*[STATE]##with context 1 heating / 2 cooling and state 3 comfort / 4 eco, so*#4*2*#7*1*3##is heating comfort and*#4*2*#7*1*4##heating eco; dimension 12 is the complete probe status with the setpoint in force, dimension 14 the commanded setpoint. The mode frames*4*107*2##/*4*108*2##that the KW4691 returns in the season frame's place while a preset is active are decoded by neither (heating: WHAT 107 / 108 / 208 (zone eco / comfort mode echoes of a KW4691 behind an F461) are not decoded OWNd#146 tracks them, now backed by eight occurrences in run 1 next to the*4*108*2##/*4*208*2##off461_live_2026-10-24run 4).Checklist
What is the problem,What is the solution,State Diagram,Hardware Verification,How is it tested,Where are the traces,What does the Firmware Oracle / Encyclopedia say,Checklist).handle_event()).pytest,ruff, andscripts/verify_ha_standards.pypass.🤖 Generated with Claude Code