Repository navigation
fix(climate): poll *#4*Z## on F454 & MH202 and harvest partial NACK responses (#866) - #867
Merged
GreenGrassBlueOcean merged 3 commits intoNov 8, 2026
Conversation
…OpenWebNet-HA#866) Promote F454 (003598) to supports_zone_status=True with profile flag delegation (OWNd#164), remove F454 from ZONE_TEMPERATURE_POLL so standalone thermostats hydrate hvac_mode and target_temperature on cold start, harvest partial OWNNackError.responses in CommandWorkerPool, and commit live F454 FW 2.0 129-frame trace replay suite.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…enWebNet-HA#866) Enable *#4*Z## zone status polls on BTicino MH202 (FW 1.0) alongside F454. Live hardware traces verified that MH202 answers zone status in 160-250 ms across standalone thermostats, while the firmware oracle confirms MH202 translates *#4*1## to SCS and replies. Document compatibility and calibrate test matrix.
3 tasks done
|
I'm not at pc, but I think is a duplicate of my finding with f455: #873 . If so, I think we must merge logic. |
4 tasks done
GreenGrassBlueOcean
merged commit Nov 8, 2026
2c8be56
into
OpenWebNet-HA:v2-phase1-architecture
16 checks passed
gdluck
pushed a commit
to gdluck/HomeAssistant-MyHOME
that referenced
this pull request
Nov 8, 2026
…p sweep (OpenWebNet-HA#466) A physical F455 1.0.76 answers the single-dimension reads *michnovka#4*Z*0##, *michnovka#4*Z*14## and *michnovka#4*Z*12## in ~0.1 s and the actuator form *michnovka#4*Z#1*20## in 0.09 s, but ACKs *michnovka#4*Z## only after ~9 s (the issue_674 timeouts) and returns nothing for *michnovka#4*0## (tests/fixtures/traces/issue_466/F455_direct_requests_2026-11-06.jsonl); its standalone zone 2 reported nothing on its own in four minutes of debug log. The F455 was on neither the zone status poll nor the temperature poll, so a quiet zone had no temperature, setpoint or mode after a restart. Nothing the issue_674 fixes decided is undone: F455 zones still ask nothing on add, stay off the *michnovka#4*Z## and *michnovka#4*Z*0## polls, and the startup sweep is unchanged. Added: - SILENT_ZONE_POLL = {"F455"} and SILENT_ZONE_GRACE = 120 s (gateway.py, with silent_zone_poll_needed). - MyHOMEClimate._poll_if_silent: 120 s after the startup sweep, a zone still without a temperature (a restored one does not count) or a setpoint of its own asks *michnovka#4*Z*0##, then *michnovka#4*Z*14##, *michnovka#4*Z*12## (its reply is followed by the zone's mode frame) and *michnovka#4*Z#1*20##, each only once the previous read was answered; a refused or unanswered read ends it, so a zone without a probe costs one request. The actuator is asked last because hvac_action is derived when an actuator report finds the mode known. tests/test_f455_zone_polling.py ties the unchanged gates, the capture behind each read and the poll itself together. Squash of the three development commits of OpenWebNet-HA#873 (the first two added F455 to the poll tables and a ZONE_SETPOINT_POLL, the third reverted that in favour of this mechanism), rebased on OpenWebNet-HA#867 and its ZONE_TEMPERATURE_POLL table. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the problem
On BTicino F454 (
003598) and MH202 (03535/003535) plants with standalone room thermostats (no#099-zone central unit), climate entities initializecurrent_temperatureandactuatorstatus after a Home Assistant startup, whilehvac_mode(state) andtarget_temperatureremainedunknown/Noneon cold start until a thermostat spontaneously transmitted a mode or setpoint change:F454andMH202firmware silently drop the general heating status sweep*#4*0##(general_zone_request_refused = True, verified inown-firmware-oracleonF454 020051andMH202 010024, and confirmed on live hardware).#674(F45510 s command-session socket hangs on unpopulated actuator-only channels),F454andMH202were conservatively placed insupports_zone_status = FalseandZONE_TEMPERATURE_POLL, causing startup to request only Dimension 0 (*#4*Z*0##) and Dimension 20 (*#4*Z*20##) instead of the per-zone status request*#4*Z##.*#4*Z##into the four SCS bus queries ($0499ZZ3000/12/0E/0D) and answer all five OpenWebNet frames (*#4*Z*0*TTTT##,*#4*Z*12*TTTT*3##,*4*WHAT*Z##,*#4*Z*14*TTTT*3##,*#4*Z*13*OO##):F454(up to 4 command sessions) answers in ~1.31–1.33 s on both 99-zone#0central-unit plants (#629, FW1.0.34) and standalone thermostat plants (#866, FW2.0, 13 standalone zones).MH202answers in ~160–250 ms across all zones (#866, FW1.0, 5 standalone zones).*#*0##(NACK),OWNdreturnsNonefromOWNCommandSession.send(..., is_status_request=True)while preserving the partial frames inOWNNackError.responses(_command_session.last_error.responses), whichCommandWorkerPool.sending_looppreviously discarded whencollected is None.Fixes #866
Companion
OWNdPR: OpenWebNet-HA/OWNd#164Companion trace PR (MH202): #869
What is the solution
supports_zone_statustoGatewayProfile.supports_heating_zone_statusand promoteF454andMH202:MyHOMEGatewayHandler.supports_zone_status(custom_components/myhome/gateway.py) checksprofile.supports_heating_zone_statusfirst (boolwins when present, aligning withOpenWebNet-HA/OWNd#164) and removes"F454"and"MH202"from the fallback exclusion list so behavior is identical on bothOWNd==2.0.0b13andOWNd >= 2.0.0b14."F454"and"MH202"fromZONE_TEMPERATURE_POLL(gateway.py); single-session (MH200,MH201,H4684,F450) and uncaptured (F459) SCS-only models retain the fast ~120 ms*#4*Z*0##poll, andF455remainssupports_zone_status = False(#674).OWNNackError.responseson NACKed status requests:CommandWorkerPool.sending_loop(custom_components/myhome/gateway_sessions.py), whencollected is Noneandtask["is_status_request"]isTrue, partial replies recorded in_command_session.last_error.responses(OWNNackError.responses) are deduplicated againstbus_monitor.has_frame_since(...), recorded, dispatched viamyhome_message_<mac>, and bridged to any offline primary while keeping_cancel_written(task)NACK semantics intact. Becausedispatcher_sendruns synchronously before thewrittencancellation callback tick,MyHOMEClimate._poll_answeredseesself._poll_health.frames != frames_beforeand never falsely flags a partially-answering standalone thermostat as unresponsive.scripts/update_gateway_profiles.py,docs/configuration/climate.md,docs/configuration/runtime_behaviour.md, and regenerateddocs/getting-started/hardware-compatibility.mdviascripts/sync_documentation.py --update.tests/fixtures/traces/issue_866/myhome_trace_F454_all_2026-11-04T19-00-04.json(129 frames: 86 RX, 43 TX) andtests/test_issue_866_f454_zone_status_trace.py.State Diagram
flowchart TD Start["Startup Sweep Completes on F454 (003598) / MH202 (03535)"] --> SweepSkip["*#4*0## Omitted (general_zone_request_refused = True)"] SweepSkip --> ZoneAdd["MyHOMEClimate Zone Added (_poll_on_add = True)"] ZoneAdd --> SendPoll["Send *#4*Z## via CommandWorkerPool"] SendPoll --> BusExpand["Gateway Expands to 4 SCS Queries ($0499ZZ3000 / 12 / 0E / 0D)"] BusExpand -->|"All 4 Answered (F454: ~1.3 s; MH202: ~200 ms)"| Ack["collected = 5 Frames + *#*1## ACK"] BusExpand -->|"Subset Answered + *#*0##"| PartialNack["collected = None; OWNNackError.responses Harvested"] BusExpand -->|"Unpopulated Zone (e.g. Z=14)"| EmptyNack["collected = None; responses = []"] Ack --> Hydrate["Hydrate Temp (Dim 0), Effective Setpoint (Dim 12 > Dim 14), Mode (*4*1*Z##), Offset (Dim 13)"] PartialNack --> Hydrate EmptyNack --> Backoff["PollHealth Counts Unanswered Poll -> Backoff After 2 Misses"]Hardware Verification
@xduss's physical BTicino F454 (FW 2.0, Home Assistant2026.10.4, MyHOME2.0.0b17,OWNd 2.0.0b13) with 13 standalone thermostats (WHERE = 1..13, zero#0central unit) in [Bug]: F454 – Thermostat states and target temperatures not initialized after startup #866:*#4*0##sweeps at18:51:53and18:52:42produced zero replies on the bus.*#4*2##,*#4*1##,*#4*3##, and*#4*4##queries each returned all 5 frames (Dim 0,Dim 12,*4*1*Z##,Dim 14,Dim 13) within1.312–1.332 s, confirming full standalone zone hydration without a central unit.@xduss's physical BTicino MH202 (FW 1.0, Home Assistant2026.10.4, MyHOME2.0.0b17,OWNd 2.0.0b13) with 5 standalone thermostats (WHERE = 1..5) in [Bug]: F454 – Thermostat states and target temperatures not initialized after startup #866:*#4*1##through*#4*5##queries each returned all 5 frames within160–250 ms.#629(F454FW 1.0.34+#0central unit, where*#4*1##..*#4*15##likewise completed in~1.3 seach with all 5 frames).How is it tested
tests/test_issue_866_f454_zone_status_trace.py:test_issue_866_trace_archive_metadata_and_who4_invariants: verifies trace metadata, absence of#0, silence after both*#4*0##sweeps, and1.31–1.34 s5-frame completion for*#4*1##..*#4*4##.test_f454_and_003598_enable_zone_status_and_skip_general_and_temp_polls: verifiesF454,BTicino F454, and003598setsupports_zone_status = True,zone_temperature_poll_needed = False, omit*#4*0##, and send*#4*1##onasync_update().test_issue_866_cold_start_replay_hydrates_standalone_zones_and_preserves_dim12_setpoint: replays all 86 RX frames from a cold start (noRestoreEntity, no#0), verifyingHVACMode.HEAT, ambient temperatures, Dimension 12 effective setpoints (22.0 / 23.0 / 22.0 / 21.5 °C) preserved over trailing Dimension 14 (20.0 °C), active actuator state on zone6, dual actuators on zone8, dynamic discovery + immediate*#4*13##poll on zone13, andNonestate on unpopulated zone14.test_partial_nack_status_request_harvests_ownd_responses_and_counts_zone_answered: verifiesCommandWorkerPool.sending_loopharvestsOWNNackError.responseson NACKed status requests, skips frames already recorded onbus_monitor, hydrateszone5, and incrementsPollHealth.frames.tests/test_issue_866_mh202_zone_status_trace.py) in companion PR test(climate): commit live MH202 FW 1.0 zone status trace and replay test (#866) #869.tests/test_startup_requests_per_firmware.py(verifyingMH202andF454both skip*#4*0##and temperature polls in favor of*#4*Z##),tests/test_issue_674_f455_climate_trace.py,tests/test_climate_humidity_poll_gate.py, and profile resolution tests.tests/test_issue_466_hl4684_trace.py(calibrating003535/03535catalogue codes to verifysupports_zone_status is True).OWNd==2.0.0b13andOpenWebNet-HA/OWNd#164):pytest: 100.0% statement coverage acrosscustom_components/myhome(18,695 / 18,695statements,0missed).ruff check custom_components tests scripts:All checks passed!scripts/verify_ha_standards.py:SUCCESS: All Home Assistant architectural standards passed!(54/54Platinum rules).scripts/sync_documentation.py --check:SUCCESS: All documentation is calibrated and in sync with the codebase!Where are the traces
tests/fixtures/traces/issue_866/myhome_trace_F454_all_2026-11-04T19-00-04.json— 129 frames (86RX,43TX) captured on a physicalBTicino F454(FW 2.0) with 13 standalone heating zones (1..13) and unpopulated zone14, scrubbed of all network identifiers.tests/fixtures/traces/issue_866/myhome_trace_MH202_all_2026-11-04T20-39-35.json— 71 frames captured on a physicalBTicino MH202(FW 1.0) with 5 standalone heating zones (1..5), scrubbed of all network identifiers (committed in test(climate): commit live MH202 FW 1.0 zone status trace and replay test (#866) #869).What does the Firmware Oracle / Encyclopedia say
WHO = 4, Machine KBownkb-build-0.9.0):ownkb:claim:c000439/c000449(specified):*#WHO*WHERE##requests current zone status;*#*0##(NACK) is a negative result or failed-sequence terminator.ownkb:claim:c003242/c003244(specified):DIMENSION 12(*#4*WHERE*12##) returns the complete probe status combining effective target temperature with operating context, whereasDIMENSION 14reports the base manual setpoint.own-firmware-oracle,mcp_index.jsonSHA-256 verified):*#4*0##onF454(020051) andMH202(010024):NACK (*#*0##)/SILENT (Drop)— zero SCS bus telegrams emitted.*#4*1##onF454(020051):OUT (Bus)—bt_H4690emits the 4 SCS queries24 30 34 39 39 30 31 33 30 30 30 0d(Dim 0),...31 32 0d(Dim 12+ mode),...30 45 0d(Dim 14), and...30 44 0d(Dim 13).*#4*1##onMH202(010024, targetd62d664c1b50):ACK (*#*1##)+OUT (Bus)—cosoemits the 4 SCS queries$0499013000(Dim 0),$0499013012(Dim 12),$049901300E(Dim 14), and$049901300D(Dim 13).Checklist
What is the problem,What is the solution,State Diagram,How is it tested,Where are the traces,What does the Firmware Oracle / Encyclopedia say).handle_event()and do not manually subscribe viaasync_dispatcher_connect.pytest,ruff, andscripts/verify_ha_standards.pypass.