Skip to content

fix(gateway,climate): ingest H/L4684 FW 6.0.11 trace and fix H/L4684 & WHO 4 bugs (#466) - #818

Merged
GreenGrassBlueOcean merged 1 commit into
v2-phase1-architecturefrom
fix/issue-466-hl4684-trace-and-bugs
Oct 26, 2026
Merged

GreenGrassBlueOcean merged 1 commit into
v2-phase1-architecturefrom
fix/issue-466-hl4684-trace-and-bugs

Conversation

@GreenGrassBlueOcean

@GreenGrassBlueOcean GreenGrassBlueOcean commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What is the problem

A physical BTicino H/L4684 Colour Touch Screen (FW 6.0.11, kernel 2.6.2, distro 6.0.0, WHO 13 device type 23) diagnostics capture contributed by @andrea-mag in #466 (comment 6398442412) uncovered six integration & trace-matrix bugs across WHO 3, WHO 4, WHO 13, WHO 16/22, WHO 1013, SSDP discovery, and diagnostics redaction:

  1. SSDP modelName = "H/L4684" missed manifest.json & fell back to GenericGatewayProfile:
    • Physical H/L4684 (urn:schemas-bticino-it:device:touchscreen:1) announces "H/L4684" (with a slash), whereas manifest.json only matched "HL4684".
    • Under OWNd==2.0.0b11, "H/L4684" fell back to GenericGatewayProfile (command_session_limit() returned None instead of 1, and WHO 5 / WHO 25 remained enabled), while supports_zone_status checked "HL4684" in "H/L4684" (False) and "H4684" in "H/L4684" (False), leaving supports_zone_status == True on "H/L4684".
    • On FW >= 6.0.0 (6.0.11), H/L4684 runs both bt_difson (WHO 16) and bt_multi (WHO 22), which was not advertised by profile_supports_who(22) or gateway_supported_whos("H/L4684", "6.0.11"), and WHO 13 Dimension 16 auto-detection did not refresh self.gateway.profile.
  2. Gateway Identity (WHO 13 device type 23 & "/" normalization):
    • H/L4684 (FW 6.0.11) reports *#13**15*23## on the wire (WHO 13 device type 23), which was listed only in the unverified third-party Nmap table rather than field-confirmed BTicino hardware, and "/" was not stripped in gateway_model_family() / _normalized().
  3. Pure-valve heating zones could not retract tentative ClimateEntityFeature.FAN_MODE:
    • All 8 heating zones in @andrea-mag's capture (11, 22, 33, 44, 55, 66, 77, 88, where Zone 33 has fan: true and the other 7 have fan: false) emit *#4*Z#N*20*5## on Dimension 20.
    • In climate.py, receiving 20*5 tentatively enables ClimateEntityFeature.FAN_MODE (auto/low/medium/high) and queries Dimension 19 via _ask_fan_coil_sides() (*#4*Z*19##), which on pure-valve zones answers *#4*Z*19*0*0## (VALVE_STATUS: neither heating nor cooling uses a fan coil, as captured in myhomeserver1_live_2026-10-25 zones 35..70 and issue_674 F455). Previously, climate.py never retracted tentative FAN_MODE once Dimension 19 proved neither side of an unconfigured zone is a fan coil.
  4. Diagnostics leaked options["config_file_path"]:
    • diagnostics.py redacted legacy "file_path" (CONF_LEGACY_FILE_PATH) but omitted "config_file_path" (CONF_FILE_PATH).
  5. myhome.sweep_bus omitted *#1013*0*1## (OBJECT_MODEL):
    • sweep_bus queried WHO 13 (0, 15, 16, 23, 24) but never queried *#1013*0*1##, leaving who1013_code: null in user-submitted sweep/diagnostics captures unless WHO 13 returned shared code 200.
  6. Hardware Trace Matrix lacked WHO 3 (Load) and H/L4684 canonicalization:
    • scripts/update_trace_matrix.py omitted WHO 3 and keyed "H/L4684" separately from "H4684".

Relates to #466
Companion OWNd PR: OpenWebNet-HA/OWNd#147

Note

Merge Order (MyHOME#818 first): Merge this PR before OpenWebNet-HA/OWNd#147. MyHOME#818 passes against both pinned OWNd==2.0.0b11 and OWNd#147, and updates the 4 MyHOME tests that OWNd's myhome-conformance.yml CI workflow runs against v2-phase1-architecture.


What is the solution

  1. SSDP matcher, H4684Profile binding, and FW >= 6.0.0 WHO 22 gating (manifest.json, gateway.py, identity.py, topology.py, scripts/update_gateway_profiles.py):
    • Added the traced "H/L4684" SSDP matcher to custom_components/myhome/manifest.json (alongside pre-existing "HL4684").
    • Added _profile_for_model() and _firmware_at_least() (with TODO(OWNd>2.0.0b11) markers for the temporary shims) so "H/L4684", "HL4684", and "HC4684" resolve to H4684Profile under both OWNd==2.0.0b11 and OWNd#147, refresh self.gateway.profile when *#13**16*V*R*B## updates gateway.firmware, advertise WHO 22 when FW >= (6, 0, 0), and evaluate supports_zone_status == False across all H/L4684 spellings and MyHOME_Suite catalogue codes.
  2. Gateway identity corroboration for WHO 13 code 23 & "/" normalization (const.py, identity.py):
    • Promoted "23": ("H4684", "H/L4684", "L4684") to WHO13_OBSERVED_DEVICE_TYPES (while keeping WHO1013_OBJECT_MODELS["19"] = ("H4684", "L4684") faithful to MHCatalogue.db, with _same_product_names() linking "H/L4684" / "HL4684" across both WHO 13 and WHO 1013), added "H4684" to SUPPORTED_GATEWAY_MODELS, and stripped "/" in gateway_model_family() and identity._normalized().
  3. Retract tentative FAN_MODE on pure-valve zones proven non-fan-coil by Dimension 19 (climate.py):
    • Added self._fan_configured = bool(fan and not self._central), _has_no_fan_coil_sides(), and _disable_fan_mode().
    • When Dimension 19 (*#4*Z*19*CV*HV##) reports fan_coil_heating is False and fan_coil_cooling is False on a zone not explicitly configured with fan=True, tentative ClimateEntityFeature.FAN_MODE, fan_modes, and fan_mode are retracted and prevented from re-activating on subsequent 20*5 frames or stale state restore, while preserving explicit fan=True zones (Zone 33) and genuine fan-coil zones (19*5*0).
  4. Redact CONF_FILE_PATH in diagnostics & include *#1013*0*1## in myhome.sweep_bus (diagnostics.py, services.py):
    • Added CONF_FILE_PATH ("config_file_path") to TO_REDACT.
    • Added "*#1013*0*1##" to gateway_queries in handle_sweep_bus.
  5. Ingest sanitized H/L4684 (FW 6.0.11) trace & update Hardware Trace Availability Matrix:
    • Added tests/fixtures/traces/issue_466/config_entry-myhome_HL4684_fw6_0_11.json + README.md, added WHO 3 (Load) and H/L4684 canonicalization to scripts/update_trace_matrix.py, and synchronized README.md + docs/ via scripts/sync_documentation.py --update.

State Diagram

stateDiagram-v2
    [*] --> PureOrUnknownZone: MyHOMEClimate(fan=False)
    [*] --> ExplicitFanZone: MyHOMEClimate(fan=True)

    PureOrUnknownZone --> TentativeFanZone: Rx *#4*Z#N*20*{5..8}##\n(_ask_fan_coil_sides -> *#4*Z*19##)
    PureOrUnknownZone --> ConfirmedPureValve: Rx *#4*Z*19*0*0##\n(CV not in 5..8 & HV not in 5..8)
    PureOrUnknownZone --> ConfirmedFanCoil: Rx *#4*Z*19*{5..8}*0## or *0*{5..8}##

    TentativeFanZone --> ConfirmedPureValve: Rx *#4*Z*19*0*0##\n_disable_fan_mode() retracts FAN_MODE
    TentativeFanZone --> ConfirmedFanCoil: Rx *#4*Z*19*{5..8}*...##\nFAN_MODE retained

    ConfirmedPureValve --> ConfirmedPureValve: Rx *#4*Z#N*20*5## or *20*1##\nTracks actuator state & hvac_action\n(FAN_MODE stays disabled)
    ExplicitFanZone --> ExplicitFanZone: Rx *#4*Z*19*0*0##\n_fan_configured=True preserves FAN_MODE
Loading

Hardware Verification

  • Backed by physical BTicino H/L4684 (FW 6.0.11, kernel 2.6.2, distro 6.0.0, WHO 13 device type 23) capture from @andrea-mag's multi-subsystem SCS plant (68 lights, 8 switches, 8 heating zones 11..88 + #0 central unit, 8 WHO 3 load-priority channels #1..#8, 12 dual-dialect WHO 16 + WHO 22 amplifier zones + 2 active stereo sources).
  • Detailed hardware breakdown and follow-up questions posted in #466 (comment 6402416947).

How is it tested

  • tests/test_issue_466_hl4684_trace.py:
    • test_hl4684_trace_fixture_integrity_and_parser_coverage: parses all 257 frames (212 rx, 45 tx) across WHO 1, 2, 3, 4, 13, 16, 22, verifies 29 OWNLoadEvent frames across #1..#8, and asserts config_file_path redaction.
    • test_scs_gateway_aliases_disable_point_to_point_zone_status: verifies supports_zone_status is False across "H/L4684", "HL4684", "HC4684", "H4684", "L4684", "BTicino H/L4684", and MyHOME_Suite catalogue codes (003598, 003594, 003565, 003535, 573992).
    • test_hl4684_ssdp_profile_identity_and_fw6_who22: replays *#13**15*23##, *#13**16*6*0*11##, *#13**23*2*6*2##, *#13**24*6*0*0## and *#1013**1*19*15*5*0##, verifying dynamic WHO 22 activation on FW 6.0.11 and conflict-free identity corroboration.
    • test_hl4684_diagnostics_redacts_config_file_path: verifies async_get_config_entry_diagnostics redacts options["config_file_path"].
    • test_hl4684_trace_f430_4_pure_valve_vs_fancoil_zones: replays all 64 WHO 4 frames across zones 11..88, asserts _ask_fan_coil_sides() (*#4*Z*19##) is queued on 20*5, verifies 19*0*0 retracts tentative FAN_MODE on fan=False zones (11, 22, 44, 55, 66, 77, 88) while preserving explicit fan=True (33) and genuine fan-coil (19*5*0) zones, and checks state restoration.
    • test_hl4684_trace_dual_dialect_sound_inventory_deduplication: replays all 28 WHO 16 + WHO 22 rx frames (24 zone + 4 source frames) and verifies clean deduplication into 12 amplifier-zone media_player entities.
  • Updated test_startup_requests_per_firmware.py, test_climate_humidity_poll_gate.py, test_gateway_identification.py, test_gateway_profiles.py, test_diagnostics.py, test_services.py, and test_multi_gateway.py.
  • Full CI-equivalent validation:
    • pytest tests -q --cov=custom_components/myhome (against OWNd#147 on rebased v2-phase1-architecture): 4,980 passed, 100.0% line coverage (16,810 / 16,810, 0 missed lines)
    • pytest against pinned OWNd==2.0.0b11 wheel: All checks passed
    • scripts/typing_ratchet.py (mypy --strict against OWNd==2.0.0b11): 0 errors across all modules
    • ruff check custom_components tests scripts: All checks passed
    • scripts/verify_ha_standards.py: All 54/54 Platinum Home Assistant standards passed
    • scripts/sync_documentation.py --check: All documentation & trace matrices calibrated and in sync

Where are the traces


What does the Firmware Oracle / Encyclopedia say

  1. OpenWebNet Encyclopedia (WHO = 4, WHO = 13, OWN-DEV-0135):
    • WHO = 4 DIMENSION = 19 (VALVE_STATUS, *#4*where*19*CV*HV##): 0 = OFF, 1 = ON, 2 = OPENED, 3 = CLOSED, 4 = STOP, 5 = OFF_FAN_COIL, 6 = ON_SPEED_1, 7 = ON_SPEED_2, 8 = ON_SPEED_3. When neither CV nor HV is in {5, 6, 7, 8} (19*0*0), neither side is a fan coil even if actuator channels (DIMENSION = 20) emit 5 while idle.
    • WHO = 13 DIMENSION = 15: official 2006 spec assigns 13 to H4684, while field firmware 6.0.11 emits 23 (*#13**15*23##).
    • OWN-DEV-0135 (Colour Touch Screen in MHCatalogue.db) maps commercial SKUs H4684 (Axolute) and L4684 (LivingLight).
  2. Firmware Oracle (*#4*0##, *#4*1*19##, *#1013*0*1##):
    • *#4*0## is "silent" on H4684 020054 (trace-corpus.tsv) — corroborated on live H/L4684 6.0.11 (*#4*0## yielded 0 WHO 4 event frames before the next sweep query 1.33 s later).
    • *#4*1*19## is OUT (Bus) across all 12 emulated gateway images (thermo-valve.tsv, dispatching $0499013013\r on H4684 020054).
    • *#1013*0*1## (OBJECT_MODEL) is answered locally by the gateway (ACK *#*1##, returning *#1013**1*19## on H4684 020054) with 0 SCS bus frames across all 12 emulated gateway images (trace-corpus.tsv), making it zero-bus-load to include in myhome.sweep_bus.

Checklist

  • PR Description: Follows the structured sections above (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).
  • Trace-Backed (if protocol/device change): Behavior is verified against real OpenWebNet bus traces or gateway firmware fixtures rather than guessed.
  • V2 Architecture: New or modified entities implement handle_event() and do not manually subscribe via async_dispatcher_connect.
  • Tests & Linters: pytest, ruff, and scripts/verify_ha_standards.py pass.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@GreenGrassBlueOcean
GreenGrassBlueOcean force-pushed the fix/issue-466-hl4684-trace-and-bugs branch from 096b1f3 to 99e3f80 Compare October 25, 2026 22:15
@GreenGrassBlueOcean GreenGrassBlueOcean changed the title fix(gateway,climate): ingest H/L4684 FW 6.0.11 trace and fix H/L4684 & F430/4 bugs (#466) fix(gateway,climate): ingest H/L4684 FW 6.0.11 trace and fix H/L4684 & WHO 4 bugs (#466) Oct 26, 2026
@GreenGrassBlueOcean
GreenGrassBlueOcean merged commit e649bc8 into v2-phase1-architecture Oct 26, 2026
17 checks passed
@GreenGrassBlueOcean
GreenGrassBlueOcean deleted the fix/issue-466-hl4684-trace-and-bugs branch October 26, 2026 08:42
gdluck pushed a commit to gdluck/HomeAssistant-MyHOME that referenced this pull request Oct 26, 2026
…ile_for_model (OpenWebNet-HA#804 follow-up)

_async_apply_gateway_identity called get_gateway_profile(model,
gateway.model_number): OWNd's signature is (model_name, firmware_version),
and model_number is always None on the manual path, so the second argument
was inert and read as if a model number were a firmware. The runtime resolves
the same correction through _profile_for_model (OpenWebNet-HA#818), which also maps the
SSDP spellings; the flow now uses it, without a firmware, which is not known
before the first connection.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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