Repository navigation
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@GreenGrassBlueOcean all the PR's where tripple checked with oracle, test plant - tested with fable and co-verified with kimi3-pro. If anything, let me know |
|
Thanks @gdluck ,can you please split out the trace pr so that we can add the actual physical trace to the myhome repo? Like we did with all traces before? |
|
Done: the physical capture is split out as OpenWebNet-HA/MyHOME#799 ( |
…penWebNet-HA#136-OpenWebNet-HA#142 and MyHOME OpenWebNet-HA#791-OpenWebNet-HA#798 The maintainer asked on OpenWebNet-HA/OWNd#137 (comment 6384484511) for the physical trace behind the 2026-10-24 pull requests to be added to this repo like every capture before. Same plant and format as f461_live_2026-10-15 and f461_live_2026-10-18: a BTicino F461 2.0.11 (WHO 13 device type 200, WHO 1013 134.15.5.0) with BT-F411/4 lights at 06 / 07, an F422 light at 09 whose actuator lacked configurator 2 at capture time, a BT-F411/2 5 s shutter at 05 and a KW4691 standalone thermostat at zone 2 with a BT-F430/2 valve and a BT-F430/4 fan coil; no central unit. tests/fixtures/traces/f461_live_2026-10-23/: the derived trace archive (299 event-session frames, 939 tx / rx / result rows in ten runs: the oracle replay of 165 read-only requests, reviewer reads, setpoint restore, final state, report-form writes, the event session during a local Home Assistant run, the bus monitor of an earlier run, two flicker re-tries) and its README with the plant, the runs, what the plant established and which pull request each frame backs. MAC / IP are synthetic in both their text and WHO 13 byte forms. tests/test_f461_live_2026_10_23_trace.py pins the facts the pull requests rely on: the *michnovka#4*2## reply order with dimension 12 before and different from 14, *michnovka#4*2*20## followed by two actuator frames and *michnovka#4*#0*20## answering both, *#1*0007## NACK vs *#1*07## ACK vs *#1*7## empty, *OpenWebNet-HA#13**0## echoed on the event session, every WHO 16 request refused in under 10 ms, the dimension 27 model name frame, *michnovka#4*#2*14## and the other central-unit forms refused, one *2*0*0##, the shutter's own stop 5.1-5.9 s after each run; plus entity replays through handle_event that pass on the base branch with the pinned OWNd. tests/test_trace_oracle_validation.py: tier 4 tolerates the authentic *OpenWebNet-HA#13**27*70#52#54#49## reply until the pinned OWNd carries the dimension 27 decoder (OWNd#139); it parses to None without raising. The *4*311*2## NACK / *4*311*#2## ACK pair cited by OWNd#137 is already in f461_live_2026-10-15 and is referenced, not duplicated. scripts/update_trace_matrix.py leaves the matrix unchanged (the F461 row already covers WHO 1, 2, 4, 13, 1013). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Central-unit WHATs (311, 1, 303, ...) address the central unit by API contract (OWNd#77 fix 3): `where` must be `#0`, `#0#N` or `#Z`; `#Z#N` and plain zones are refused with ValueError. The plain zone form `*4*311*Z##` is nack/silent on all 12 emulated gateways (own-firmware- oracle thermo-zone-mode, ownd-pr82-heating) and a live F461 2.0.11 NACKs `*4*311*2##` while it ACKs `*4*311*michnovka#2##`. The default `#0` is unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
844f4fb to
a6c4cdc
Compare
Requested by A
Summary
OWNHeatingCommand.set_central_mode("1", CLIMATE_MODE_AUTO)built*4*311*1##: the builder accepted anywhere. The central-unit WHATs (311 automatic, 1 heating, 303 off, ...) address the central unit by API contract: #77 fix 3 ("*4*311*1##produces no bus frame;*4*311*#1##does") and the WHO 4 specification, where the central-unit commands take#0(99-zone central unit),#0#N(zone N of a 4-zone central unit) or#Z(a zone addressed through the central unit). The zone-level builder for a plain zone isset_mode(where, ...).The guard therefore applies to every WHAT this builder produces, by contract. The oracle evidence per WHAT is uneven and is listed honestly below: the plain form of 311 is
nack/silenton all 12 emulated gateways and NACKed by a live F461 2.0.11, while the plain forms of 1 and 303 are forwarded to the bus by some gateways (as a frame addressed to zone 1, which is not what the central-unit builder is for).Refs #77. The
central_statusdeprecation-text correction that this PR carried at first is now its own PR (see Companion).Changes
OWNd/message/heating.py:_WHO4_CENTRAL_WHERE_REGEX = #(?:0#[0-9]+|[0-9]+);set_central_moderequiresstr(where)tofullmatchit (#0,#0#N,#Z; ASCII digits, so#0\nand#١are refused).#Z#Nis not a central-unit form and is refused too (the first version of this PR accepted it). Anything else raisesValueError("Central unit mode needs a central unit address such as '#0': ..."). The default#0is unchanged. Callers checked: MyHOMEclimate.pypassesself._where, which is#0or#0#1when_central; the golden corpus uses#0and#0#1.CHANGELOG.md: entry under[Unreleased]/Fixed.State Diagram
stateDiagram-v2 direction TB state "1. OWNHeatingCommand.set_central_mode(where, mode)" as Builder { [*] --> Validate Validate --> Built : where fullmatch #0 | #0#N | #Z\n*4*311*#0##, *4*1*#0#1##, *4*303*#23## Validate --> Refused : plain zone 1 / 2 / 0, 23#1, #1#2, #, ##0, #0*22, #a, #0\n, #١\nValueError , before - *4*311*1## was built and sent } state "2. What the gateways do with the two forms of 311 (oracle thermo-zone-mode, ownd-pr82-heating; live F461 2.0.11)" as Gateway { [*] --> Plain Plain --> NackSilent : *4*311*1## nack/silent on 12 of 12\nlive *4*311*2## NACK [*] --> Central Central --> Forwarded : *4*311*#1## ack/out on 9, nack/out on F460 / F461 / MyHomeServer1\nlive *4*311*#2## ACK , no central unit - changes nothing }Where are the traces
#Zformtests/fixtures/traces/f461_live_2026-10-15(merged), runsrun3_climateandprobe_followup*4*311*2##NACKed;*4*311*#2##,*4*303*#2##,*4*302*#2##,*4*102*#2##,*4*202*#2##ACKed (they change nothing on a plant without a central unit)OpenWebNet-HA/MyHOME#799(open),f461_live_2026-10-23run 1 (run1_oracle_replay_readonly) andmyhomeserver1_live_2026-10-24run 2 (run2_reads_thermo_sound_alarm_lights)*#13**16*3*87*13##)*#4*#2##,*#4*#2*14##,*#4*#0##,*#4*#0*14##NACK after the bus timeout. MyHomeServer1:*#4*#0##and*#4*#0*14##NACK after ~4.2 s. No*4*311*...##was sent on the MyHomeServer1 (a real home).What does the Oracle say
Suites
thermo-zone-modeandownd-pr82-heating(results/<P>/<V>/oracle/full/<suite>.tsv; the rows are identical in both where both carry the frame). Twelve gateways: F450020010, F453010100, F453AV030014, F454020051, F459020105, F460020012, F461020011, H4684020054, MH200020102, MH200N010108, MH202010024, MyHomeServer1028206.ack/outnack/out(forwarded, no central unit on the emulated bus)nack/silent*4*311*1##(plain, this builder before the fix)*4*311*#1##(central form, this builder)*4*1*1##(plain heating)*4*0*1##(plain conditioning)*4*303*1##(plain off)So "every gateway refuses the plain form" holds for 311 only. For 1, 0 and 303 the plain form is a zone command that some gateways forward; this builder refuses it anyway because it is the central-unit builder (contract above), and
set_mode(where, ...)remains the zone-level builder. No published row exists for the plain forms of 302, 102 and 202 (the live F461 ACKs their#2forms, table above).Testing
tests/test_who4_central_mode_address.py(new, 21 cases):test_set_central_mode_requires_a_central_address(14:1,2,0,23#1, empty,#,##0,#0*22,#a,#0\n, an Arabic-Indic digit,#1#2,#00#1,#0#),test_set_central_mode_refuses_a_plain_zone_for_every_mode(3: 311, 1, 303 onwhere="1"),test_set_central_mode_keeps_central_addresses(#0,#0#1,#23),test_set_central_mode_default_is_the_central_unit.master17 fail, 4 pass (set_central_mode('1', 'auto')returns*4*311*1##,#1#2is accepted); on this branch all 21 pass.1928 passed, 1 skipped(master:1907 passed, 1 skipped); 100 % statement coverage (scripts/verify_coverage.py),mypy OWNd tests/typingclean,ruff checkclean,scripts/sync_documentation.py --checkandscripts/verify_library_standards.pypass.Live retest (2026-10-24)
Not exercised live: neither plant has a central unit and
*4*311*...##was not sent (the plant's zone 2 is standalone;set_central_mode('2', 'auto')now raises without a gateway).Companion
MyHOME: none needed (MyHOME already passes a central-unit address). Related OWNd PR:
docs(heating): central_status deprecation text names the real reason(split out of this PR): #143.🤖 Generated with Claude Code