Skip to content

V2 phase1 architecture - #232

Open
GreenGrassBlueOcean wants to merge 923 commits into
masterfrom
v2-phase1-architecture
Open

GreenGrassBlueOcean wants to merge 923 commits into
masterfrom
v2-phase1-architecture

Conversation

@GreenGrassBlueOcean

@GreenGrassBlueOcean GreenGrassBlueOcean commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary of Changes in v2 Phase 1 Architecture

This pull request delivers the complete Phase 1 Architecture Modernization for the OpenWebNet MyHOME integration. It establishes a modern, asynchronous foundation for Legrand & BTicino MyHOME SCS bus systems, achieving full Home Assistant Core ≥ 2026.3 compliance (Python 3.14), Integration Quality Scale 🏆 Platinum tier standards (54/54 rules satisfied/exempt), official OWNd 2.0.0b8 client library integration, zero strict typing errors under mypy --strict, and 100.0% statement test coverage (7,952/7,952 statements) across 2,336 passing automated tests (plus 5 snapshot test suites) spanning 812 commits and 103 merged sub-pull requests.


🏆 Integration Quality Scale & Architectural Modernization

  1. Home Assistant Core ≥ 2026.3 & Platinum Tier Quality Scale:

  2. Four-Milestone Modular Refactoring (Phase 1 Deep Modularization):

  3. Unified Platform Skeleton (discovery.py) & Per-Gateway Frame Router (router.py) (refactor: one platform skeleton (restore / configure / discover / route) - all nine platforms #329, feat: quality-scale chain (#349, #321, #325, #326, #329) rebuilt on v2-phase1-architecture #363, fix(light): complete FrameRouter migration for MyHOMELightGroup #391):

    • Platform Skeleton (discovery.py): Implemented a unified lifecycle engine across all 9 entity platforms (light, switch, cover, climate, alarm_control_panel, sensor, binary_sensor, media_player, button). Standardizes the four lifecycle phases: restore (pre-loading saved entities from registry), configure (applying myhome.yaml), discover (instantaneous creation on first bus frame), and route (dispatching subsequent frames). Eliminates startup race conditions and frame loss during initial gateway status sweeps.
    • Central Frame Router (router.py): Replaced legacy myhome_update_{mac}_{who}_{where} dispatcher signals (60+ string-interpolated signals) with a dedicated per-gateway FrameRouter delivering frames directly to subscribing entities by address.
    • FrameRouter Interface Contract: Enforces strict handle_event typing contract on MyHOMEEntity and establishes an architectural checklist in the pull request template to prevent legacy dispatcher regressions (fix(light): complete FrameRouter migration for MyHOMELightGroup #391).

🚀 Key Subsystems & Feature Capabilities

  1. Transports, Gateway Profiles, Identity Resolution & Connection Resilience (Call to Action :: Gateway Traces :: #291 #292, Trace Builders with the 2.0.0b12 version #297, MH201: unexpected error logs with unclear reason #304, [v2-architecture] [F454 Gateway] No heartbeat received in 120 seconds #315, fix(gateway): identify gateways by precedence; gate startup discovery on the profile #345, [BUG] False gateway identity mismatch: confirmed F454 reports WHO=13 device type 200 #370, fix(gateway): treat WHO=13 device type 200 as ambiguous between F454 and MyHomeServer1 #373, Regression of #254: the first command after ~30 s of silence is silently lost (MyHomeServer1) #378, fix(gateway): close idle command sessions before the gateway drops them #381, feat(gateway): generate repair issue for unconfigured timezone (999) #387, feat(repairs): add repair issue for unknown gateway models #388, chore: bump OWNd to 2.0.0b7 for HMAC refactor #394, Spurious ERROR logged on startup discovery when subsystems are not present (*#4*0##, *#16*0##) #406, test(config_flow): prevent unmocked socket connects on reauth and options flow reload #413, fix(yaml): normalize single-digit MAC octets and harden secondary bus key indexing (#408) #414, Fix false gateway identity mismatch (#370) by using WHO=1013 diagnostics #420, Show the gateway's own model data in HA (device page, diagnostics) #423, fix(gateway): close the event session when the listener is cancelled #444, fix(identity): a same-family model with a code of its own is a contradiction #446, fix(gateway): cap command workers at the gateway profile's session limit #450, test(ownd): accept one or two sends for a NACKed status request #451, fix(gateway): a general "all lights off" (*1*0*0##) killed the event listener — entities unavailable until reload #455, Community Call for Real-World Gateway Traces: Help Us Eliminate Hardware Blind Spots! 📡 #466, docs(gateway): reclassify F455 as single-bus Basic Gateway (#466) #471, refactor(gateway): remove obsolete OWNd timezone monkeypatch #482, feat(gateway): reinstate 4890 family with authentic H4890 traces (#466) #484, feat(ci): auto-sync hardware trace matrix to issue #466 and normalize 4890 family naming #486):

  2. Lighting Subsystem (WHO=1) & Adaptive Lighting Compatibility ([FEATURE] DALI RGB / RGBW Color Support & Physical Bus Validation #288, DALI DT8 Light Temperature and RGB Support #307, feat(light): per-light feature lock for DALI DT8 fixtures (#288) — on v2-phase1 #364, P7: lighting groups & general sync — declared groups + reactive re-sync for group/general frames #368, feat: implement declared groups as assumed state lights with member inference (#368) #376, feat: debounced resync for group area general frames (#368 PR A) #377, Who= '1' Where ='10' Not available in the latest v2-phase1-architecture #402, fix(light): allow point-to-point WHERE '10' and correct Area 10 to '100' (#402) #403, fix(light): keep the last state when a light reports an unknown WHAT #456, fix(light): an unknown WHAT does not keep a state restored at startup #458, [RFC] Support & Compatibility for Adaptive Lighting (Circadian Lighting) with MyHOME Fixtures #461, feat(light): adaptive lighting compatibility and bus traffic optimization (#461) #462, fix(gateway): skip lighting scope events when is_on is None #465, refactor(light): extract SoftwareFadeEngine and DaliFeatureLock subsystems (Milestone 4) #475, refactor(light): extract SoftwareFadeEngine and DaliFeatureLock subsystems (Milestone 4) #485):

  3. Cover Subsystem (WHO=2) & Virtual Positioning Calibration (RFC: timed covers, what I measured on a MyHOMEServer1 (latencies, frame order, non-linear position) #302, feat(frontend): bus-monitor trace/sweep workflow, self-describing exports, node test suite #319, feat(cover): travel-time calibration on the bus - calibrate_cover service, buttons, bus-measured runs (backend; card UI in #355) #349, A full open or close writes a stop at the end of the estimated time instead of letting the cover reach its end stop #379, A cover's position advances even when its direction frame never reached the bus #380, fix(cover): avoid artificial stop frames on full runs (#379) #384, fix(cover): abort motion and prevent position advance on undelivered frames (#380) #385, docs(covers): clarify automated travel time calibration sequence #411, docs(covers): the remaining points from the b13 field test #417, fix: cover level 255, per-family CEN triggers, corrected CEN golden frames #430, Mh201 and General cover button behaviour #433, fix(cover): a general / area / group cover follows its shutters (#433) #436, refactor(cover): encapsulate calibration hub, motion math, and isolate multi-gateway state (Milestone 2) #468):

  4. Climate & Thermoregulation Subsystem (WHO=4) ([BUG] Standalone Climate Zones not exposing FAN #303, Climate entity for Zone 1 incorrectly changes to heating when another zone is heating #333, fix(climate): an actuator status is not a second zone (#333) #336, fix(climate): enable fan mode dynamically for climate zones with fancoils (#303) #352, [BUG} Climate entities show 17 °C instead of the active 7 °C antifreeze target #383, fix(climate): preserve active antifreeze target temperature across status sweeps (#383) #386, [BUG] Standalone Climate Zones are not updating hvac_action. #404, fix(climate): resolve hvac_action idle and preserve auto fan mode (#404, #303) #405, [BUG] Climat Zones do not support Fan OFF #410, fix(climate): omit unsupported 'off' from fancoil fan modes (#410) #412, Climate: bus traces wanted to fix how manual, programmed, holiday and vacation modes are shown #429, Pump actuator incorrectly interpreted as zone actuator #431, fix(climate): a pump status (WHERE 0#N) is not zone N (#431) #432, feat(climate): follow WHO 4 dimension 7 zone state on Home+Control plants (#429) #457):

  5. Audio & Multi-Room Sound System 2.0 (WHO=16) (fix(media_player): make F441M source selection work — routing address used the wrong digits #422, test(sound): expect environment-addressed matrix routing #428, test(sound): expect the dimension-5 WHO 16 status request #435, fix(media_player): read sound addresses from where, not zone #437, fix(gateway): discover WHO 16 with the dimension-5 status request *#16*0*5## #438, feat(media_player): multi-room audio grouping and Music Assistant integration #460):

  6. Scenario Controls (WHO=15 CEN & WHO=25 CEN+) (Deprecated via_device argument in gateway.py will stop working in Home Assistant 2027.8 #310, fix: cover level 255, per-family CEN triggers, corrected CEN golden frames #430, fix(cen+): long_press once per hold, repeats as long_press_repeat #439):

  7. Sensors, Binary Sensors & Energy Counters ([Feature / Bug]: Dynamic discovery for WHO 1 light/motion sensors (Legrand 048834) & ghost light prevention #244, fix(sensor): dynamic discovery for WHO 1 light/motion sensors and ghost light prevention (#244) #245, fix: Resolve dry contact ghost devices and zero-padded WHERE sensor updates (WHO 1/25) #247, [Bug] F454 + 3455/L4577: recurring NACKs from temperature polling; readings continue when the request is disabled #308, Discovered temperature probe 105 is recreated and polled with *#4*105*15##, causing retry warnings #441, fix(sensor): one unique id per temperature probe, however it was created (#441) #452):

  8. Burglar Alarm Platform (WHO=5) (Need help configuring Alarm feature (F454) #311, feat(sweep): add WHO 5 alarm and WHO 16 sound to bus sweep with MH200 golden samples #470):

  9. Lovelace Bus Monitor Card v2 (<myhome-bus-card>) (The Custom card does not have the Who=5 filter applicable #275, fix(frontend): add WHO=5 filter and generalize card field filtering (#275) #276, [Bug]: Custom element does not exist (myhome-openwebnet-bus-monitor / myhome-bus-card) and duplicate card registration in v2.0.0b5 #277, fix(frontend): deduplicate bus card in picker and eliminate event loop warnings (#277) #278, fix(frontend): resolve static path import coverage and restore 100% test coverage #279, timezone issue #305, fix(frontend): render bus-monitor timestamps in the browser's local time (#305) #343, fix(bus-monitor): backfill the card's whole buffer and export the full ring #449, feat(sweep): add WHO 5 alarm and WHO 16 sound to bus sweep with MH200 golden samples #470):

  10. Internationalization & Documentation (docs(mkdocs): render GitHub-style callouts as admonitions #415, chore(translations): set up Crowdin localization pipeline and anti-drift tooling #463, docs: add dynamic hardware trace availability matrix #464, feat(ci): dynamically calibrate supported entity domains table in README #483):

  11. Golden Corpus Conformance & CI Verification:


Resolved Issues & Merged Pull Requests

Closes #6
Closes #30
Closes #69
Closes #80
Closes #92
Closes #103
Closes #105
Closes #110
Closes #115
Closes #116
Closes #117
Closes #118
Closes #121
Closes #123
Closes #127
Closes #132
Closes #134
Closes #136
Closes #139
Closes #143
Closes #146
Closes #147
Closes #150
Closes #151
Closes #152
Closes #156
Closes #157
Closes #159
Closes #161
Closes #162
Closes #165
Closes #166
Closes #168
Closes #170
Closes #172
Closes #174
Closes #176
Closes #177
Closes #178
Closes #179
Closes #181
Closes #185
Closes #188
Closes #190
Closes #191
Closes #194
Closes #200
Closes #203
Closes #205
Closes #212
Closes #213
Closes #215
Closes #219
Closes #220
Closes #230
Closes #231
Closes #233
Closes #234
Closes #237
Closes #240
Closes #241
Closes #242
Closes #243
Closes #244
Closes #245
Closes #246
Closes #247
Closes #249
Closes #250
Closes #251
Closes #252
Closes #253
Closes #254
Closes #255
Closes #256
Closes #257
Closes #258
Closes #259
Closes #262
Closes #263
Closes #264
Closes #265
Closes #266
Closes #268
Closes #269
Closes #270
Closes #271
Closes #272
Closes #273
Closes #275
Closes #276
Closes #277
Closes #278
Closes #279
Closes #280
Closes #281
Closes #282
Closes #283
Closes #284
Closes #285
Closes #286
Closes #287
Closes #288
Closes #289
Closes #290
Closes #292
Closes #293
Closes #295
Closes #296
Closes #297
Closes #301
Closes #302
Closes #303
Closes #304
Closes #305
Closes #307
Closes #308
Closes #309
Closes #310
Closes #311
Closes #313
Closes #315
Closes #316
Closes #319
Closes #321
Closes #325
Closes #326
Closes #329
Closes #333
Closes #334
Closes #336
Closes #345
Closes #347
Closes #348
Closes #349
Closes #350
Closes #352
Closes #353
Closes #356
Closes #361
Closes #363
Closes #364
Closes #365
Closes #368
Closes #369
Closes #370
Closes #371
Closes #372
Closes #373
Closes #375
Closes #376
Closes #377
Closes #378
Closes #379
Closes #380
Closes #381
Closes #382
Closes #383
Closes #384
Closes #385
Closes #386
Closes #387
Closes #388
Closes #390
Closes #391
Closes #393
Closes #394
Closes #395
Closes #396
Closes #401
Closes #402
Closes #403
Closes #404
Closes #405
Closes #406
Closes #407
Closes #408
Closes #410
Closes #411
Closes #412
Closes #413
Closes #414
Closes #415
Closes #417
Closes #420
Closes #422
Closes #423
Closes #425
Closes #428
Closes #429
Closes #430
Closes #431
Closes #432
Closes #433
Closes #434
Closes #435
Closes #436
Closes #437
Closes #438
Closes #439
Closes #440
Closes #441
Closes #443
Closes #444
Closes #446
Closes #449
Closes #450
Closes #451
Closes #452
Closes #454
Closes #455
Closes #456
Closes #457
Closes #458
Closes #460
Closes #461
Closes #462
Closes #463
Closes #464
Closes #465
Closes #467
Closes #468
Closes #469
Closes #470
Closes #471
Closes #472
Closes #473
Closes #475
Closes #477
Closes #478
Closes #481
Closes #482
Closes #483
Closes #484
Closes #485
Closes #486
Addresses #466

This was referenced Sep 8, 2026
@codecov-commenter

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

@anotherjulien

Copy link
Copy Markdown
Member

Finally had time to spin up that VM.
First impression is that what works works 😄
The transition covered everything, also all device names reverted to <device type> <APL>.

What does not work is:

  • Advanced covers seem to be discovered as regular covers, even after seeing position aware OWN frames (I have Legrand 67557 everywhere)
  • Dry contacts (I have a Legrand 3477 coupled with a mechanical lever to monitor if my garage door is open/closed)
  • Lux Meters (I have a Legrand 048834 for motion/light sensing outdoors)
  • The mechanism to lock/unlock APL endpoints (relies with WHO 14, I've used it occasionally but I'm not sure many people do)

With all that's been discussed today, I'm not sure what was supposed to make the cut at this stage though 😅

GreenGrassBlueOcean and others added 30 commits September 27, 2026 23:08
…nnotations-syntax-standards

test(standards): enforce valid Python syntax and strict __future__ positioning
…dress-tolerance

feat(cenplus): support wire WHERE address resolution and KW8011 lifecycle (#466)
…nion-cast-and-host-matching

feat(media_player): add cast platform and host/name companion resolution
…room trace

- Implement leader handover in async_unjoin_player via DecoderPool.transfer_leadership
- Expand DecoderPool idle states to include paused and standby
- Allow self-healing decoder claiming from inactive owners
- Expand CONF_DECODER_PRE_GAIN up to 100% for line-level gain staging to eliminate F441 hiss
- Forward volume and mute directly to streaming companion entities
- Add anonymized authentic MH200 + F441M multiroom sound trace
- Update unit tests, privacy tests, and sync trace availability documentation
…me (#520)

MH200N gateways accept DIMENSION 22 for date and timezone updates but ignore or fail to advance the clock time unless DIMENSION 0 (*#13**#0*H*M*S*T##) is explicitly sent. Sending set_time_to_now right after set_datetime_to_now ensures all gateways maintain accurate real-time clocks.
…-sync-time

fix(services): send DIMENSION 0 alongside DIMENSION 22 during sync_time (#520)
…layer

- Add tests for decoder pool leadership transfer to last remaining member
- Add test for leadership transfer when leader lacks active decoder
- Add test for claiming idle decoder from powered-off owner zone
- Streamline decoder volume synchronization to companion target
- Guard async_unjoin_player turn-off command with _turning_off to dampen bus-OFF echoes
…e duplicate devices (#524)

A gateway added next to a configured one was set up as a standalone
primary: its startup sweep discovered every device the other gateway
already had. Once it was made a follower, only the duplicate actuators
were pruned, leaving their lock / unlock / calibrate buttons unavailable
on devices without an actuator.

- Config flow: when another IP gateway is configured, a bus_topology step
  asks standalone or shared before the entry exists. Shared creates the
  entry as secondary / standby of the chosen gateway (role and delegated
  WHOs suggested from both models) and promotes a standalone primary to
  shared primary.
- Pruning a follower's duplicate now also removes its companion buttons
  and the device once empty; button setup cleans up orphans left by
  earlier versions (only when the primary has the actuator).
- topology: split the follower delegation out of
  infer_shared_bus_topology; recommend_follower keeps the configured
  gateway as primary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iss auto-off

A zone that was just dropped from a group can now reclaim its former
decoder from the leader within a 30s handover window, turning the
displaced leader off instead of leaving it silently holding the
decoder. Decoders auto power off their zone shortly after the
underlying stream goes idle, pauses, or stops, avoiding audible hiss.

Also fixes a missing patch/AsyncMock import in test_decoder_pool.py
and restores 100% test coverage on decoder_pool.py and media_player.py.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tics gap

Ingests the physical F461 bus sweep contributed by @lyubomirtraykov in
issue #466 (comment 5870342995): 200 authentic on-wire frames covering
WHO 1 (lights), WHO 2 (automation), WHO 4 (climate, 7 zones), WHO 5
(alarm), WHO 13 (gateway diagnostics), WHO 16 (audio), WHO 18 (energy),
and WHO 1013 (gateway object model).

Adds a dedicated replay test plus targeted assertions for the WHO 13/
WHO 1013 gateway diagnostics, which the F461 had never answered in our
corpus before, and regenerates the Hardware Trace Availability Matrix
in README.md and docs/trace-availability.md via scripts/update_trace_matrix.py.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…oup-handover-and-gain-staging

feat(media_player): add group handover, 100% pre-gain, and F441 multiroom trace
…traces

test(466): add BTicino F461 gateway trace closing WHO 13/1013 diagnostics gap
…gateway

anotherjulien found it on #525: after a follower's duplicate covers are
pruned in favour of the primary, its device-level "Calibrate all covers"
button stayed present and looked available even though this gateway has
nothing left to calibrate. `available` now also requires at least one
cover entity of this config entry, matching what `async_press` already
checks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The F461 physical bus sweep contributed by @lyubomirtraykov in issue #466
(comment 5870342995) answers the WHO=13 device type query with the shared
code 200 and the WHO=1013 OBJECT_MODEL query with 134 - trailing metadata
*15*5*0 (N_CONF/BRAND/LINE), identical to the three gateways already
confirmed in PR #420 (F454, MH202, MyHomeServer1).

Adds a golden plant fixture (tests/fixtures/plants/issue_466_f461/) with
the real identity-exchange frames and parametrizes
test_golden_who1013_exchange / test_real_who1013_reply_is_object_model_n_conf_brand_line
to replay it, and updates the const.py commentary that previously listed
F461 as "reported in issue #370, no diagnostics yet" for WHO=13 code 200
and left WHO=1013 code 134 untraced.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixes a real audible-interruption bug reported against multi-room grouping:
a member zone dropped from its group (own unjoin, or left out of a join
snapshot) was switched off immediately, even when the same room was about
to be reassigned elsewhere (e.g. reused as a new leader) a couple of seconds
later. Captured trace, single-decoder install:

  Transferring leadership of badkamer to audio_zone_23 (1 remaining member(s))
  Calling set_members on native player badkamer with add=[], remove=['audio_zone_23']
  Clearing active output protocol on badkamer
  Setting active output protocol on Eetkamer to Native      (+2.0s)
  Start Queue Flow stream for Queue Eetkamer                (+1.3s)

Note: deselecting the leader itself is already handled atomically by
DecoderPool.transfer_leadership (async_unjoin_player's leader branch,
merged separately) and needs no grace period — this change does not touch
that path. What was still missing is protection for a plain member being
dropped from its group without becoming a leader in the same call: its own
unjoin, or a join-snapshot drop.

A dropped member now keeps playing through a 5-second grace period instead
of being switched off immediately:

- Group bookkeeping (group_members) still updates at once.
- Only the physical OFF frame is delayed, cancelled by anything that puts
  the zone back to work within the window: play_media, turn_on, or being
  joined into a different group (_async_wake_zone, the leader-join path,
  and a genuine bus ON report all cancel it).
- Since the amplifier was never turned off, a follow-up play_media skips
  its own wake step — zero audible gap.
- Nothing reclaiming the zone in time still switches it off, just delayed.

Tests: a member surviving its own wake-sequence echo through a full
departure-and-reclaim cycle, the grace-period fallback, a join-snapshot
drop, and a departing member immediately joined into a different group.
Updated test_unjoin_player_member, which pinned the old immediate-off
behaviour.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ndover-grace

fix(media_player): grace period before a member's group-leave OFF
…who1013-golden

test(466): confirm F461 WHO1013 identity 134 on physical hardware
…rding

fix(topology): ask for bus topology when adding a gateway, prune whole duplicate devices (#524)
async_dispatcher_connect and hass.bus.async_listen classify a plain
lambda as an Executor-type HassJob (not a synchronous @callback), so
homeassistant schedules the listener onto a background job instead of
invoking it inline. The two CEN/CEN+ failover-bridging tests asserted
on listener state immediately after await gw_sb._process_message(msg)
without awaiting hass.async_block_till_done(), racing the scheduled
job. This passed reliably under the pinned local test environment but
flaked in the "Run Pytest Suite & Coverage" CI job, which installs an
unpinned/newer homeassistant release:
https://github.com/OpenWebNet-HA/MyHOME/actions/runs/36442320774/job/108995686149

Decorate the listeners with @callback, matching the convention already
used elsewhere in this file, so delivery is synchronous and deterministic.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…n-dispatcher-test-race

fix(tests): eliminate dispatcher/event-bus race in CEN failover tests
…ice triggers (#445, #466)

Adds native Home Assistant Device Trigger support for centralized shutter commands broadcast on WHO=2 General address 0 (*2*11#..., *2*12#..., *2*10#...).

- Enriches myhome_general_automation_event, myhome_area_automation_event, and myhome_group_automation_event with where, gateway_mac, and entry_id payloads.
- Dispatches gateway-scoped events via async_dispatcher_send for multi-gateway plant isolation.
- Exposes centralized_shutter_open, centralized_shutter_close, and centralized_shutter_stop device triggers on MyHOME Gateway device entries.
- Adds device_automation translation strings to strings.json and translations/en.json.
- Adds comprehensive unit tests in test_device_trigger.py and updates assertions in test_gateway.py and test_issue_445_myhomeserver1_covers.py.
…rdware

Incorporates two follow-up bus traces from @f18m answering the open
questions in #445 (comment 5854237269) that had put this PR in draft
(#445 comment 5868017035):

- Trace 1 (stationary STOP/PRESET press): the LN-4660M2's STOP button
  sends the byte-identical *2*10#001#1*0## frame whether shutters are
  moving or already stationary - no separate preset-recall command or
  Dimension 11 write was observed.
- Trace 2 (local room keypad): a LOCAL keypad on the same hardware
  family uses the plain *2*WHAT*WHERE## syntax at its own point address,
  never the centralized multi-parameter form on General address 0, and
  captures the first real on-wire Dimension 10 "closing" transitional
  state (*#2*02*10*12*100*001*0##).

Adds both as golden corpus fixtures (tests/golden/frames/who02_automation.yaml)
and as two new regression tests in test_issue_445_myhomeserver1_covers.py
asserting exactly one myhome_general_automation_event fires for the
stationary STOP and none fires for the local keypad frames.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ions

Explains how to set decoder_1_pre_gain against the BTicino hardware's own
feedback (Ingresso RCA / Controllo Stereo signal LED) instead of guessing a
percentage, and warns against wiring a decoder's headphone/AUX output
instead of its fixed line-out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d-control-triggers

feat(device_trigger): add centralized shutter controls to gateway device triggers (#445, #466)
…e constant (#523)

SHARED_BUS_EVIDENCE_WINDOW_S is 600.0 (10 minutes), matching the #459
audit's intent, but the gateway.py comment and gateways.md both said
5 minutes / 300.0. Align both to the actual 10-minute window and drop
the unused SHARED_BUS_RX_WINDOW_S leftover from the old RX/RX
correlation logic.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nce-window-523

fix(gateway): align shared-bus evidence window docs with the 10-minute constant

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

5 participants