Repository navigation
V2 phase1 architecture - #232
Open
GreenGrassBlueOcean wants to merge 1542 commits into
Open
GreenGrassBlueOcean wants to merge 1542 commits into
GreenGrassBlueOcean wants to merge 1542 commits into
Conversation
This was referenced Sep 8, 2026
Closed
Options flow crash on HA 2025.12+ + aggressive WHO=18 (energy) polling causing gateway overload
#221
Closed
Closed
Closed
Closed
Closed
Closed
Closed
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 ☂️ |
GreenGrassBlueOcean
added a commit
that referenced
this pull request
Sep 8, 2026
Member
|
Finally had time to spin up that VM. What does not work is:
With all that's been discussed today, I'm not sure what was supposed to make the cut at this stage though 😅 |
chore(release): 2.0.0b16 version bump, release notes, and README/roadmap refresh
…sistant-custom-component
…11+ and clean container smoke logs
fix(compat): bridge HA 2026.11+ logger export removal and EntityRegistry._async_update_entity(compat_name)
…tener for HA 2026.11+
…r-compat-name fix(compat): restore legacy compat_name in _register_availability_listener for HA 2026.11+
…oom amplifier volume
…group join/handover
fix(media_player): decouple fixed high line-level decoder feed from room amplifier volume
…tion end_stop check
…oexistence docs(cen): document native scenario coexistence and CEN/actuator address separation
…-trace test(traces): ingest Issue #767 MH200N pre-09W29 F414 dimmer 61 capture
Advanced covers widened every level change below 2 % to 2 % (#466, #702) through the module constant MIN_POSITION_DELTA, which no user could change: resolve_cover_strategy never passed a value to NativePositionStrategy. On long-travel shutters a 1 % run is long enough to move the motor (3.75 m F401 shutters behind an F454, discussion #770), so the floor is now a per-cover YAML option. - min_position_delta: whole percent 1-10, default 2 (unchanged). - Rejected on a cover that is not advanced (timed covers use min_motor_pulse). - Passed to NativePositionStrategy on both the advanced and the strategy: native route; shown as a state attribute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s and replay tests
…401-slat-traces test(cover): add #770 F454 + F401 shutter and slat-tilt trace fixtures and replay tests
…s requests myhome.send_message passed every frame to handler.send(), so a status or dimension request such as *#1*52*5## went out as a command. When the gateway NACKed it (an F454 with a Legrand 067226 at 52 answers with WHERE 0 replies and a NACK, #777), OWNd logged "Could not send message ... Retrying (1)", sent the request a second time and then logged "No more retries" at ERROR. These are the ERRORs in the #777 reporter's first trace; the integration's own startup queries were already sent as status requests and only log the NACK at DEBUG. Status and dimension requests now go through send_status_request(): same queue, status tier, a NACK is final and logged at DEBUG. Commands and dimension writes are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…401-slat-traces test(trace): ingest #770 F454 + F401 1% position step verification trace and tests
…quests fix(services): send status and dimension requests from send_message as requests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
test: collect #746 bus events on the event loop to keep their order
… trace fixture
…-trace test(trace): ingest #777 F454 + Legrand 067226 + F411 shared WHERE 52 trace fixture
feat(cover): per-cover min_position_delta for advanced covers
This branch has not been deployed
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.
Summary of Changes in v2 Phase 1 Architecture
This pull request delivers the complete Phase 1 & Phase 2 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.0b11 client library integration, zero strict typing errors under
mypy --strict, and 100.0% statement test coverage (15,911/15,911 statements) across 4,393 passing automated tests (plus Syrupy snapshot test suites) spanning 1,519 commits and 297 merged sub-pull requests.The current pre-release is
2.0.0b16(#703). Everything below is whatv2-phase1-architecturecontains; the sections right after this one list what is new in2.0.0b16(since2.0.0b15),2.0.0b15(since2.0.0b14), and2.0.0b14(since2.0.0b13).🆕 What's new since
2.0.0b15(2.0.0b16)2.0.0b16merges 86 pull requests since2.0.0b15on OWNd 2.0.0b11 (including the post-tag HA 2026.11 compatibility and group resync fixes #769, #771, #772). The headlines:exposeengine projecting Home Assistant entities and the clock onto free SCS addresses: virtual WHO 1 / WHO 2 actuators that physical wall controls can drive (mirroring HA state back to wall LEDs), WHO 4 virtual temperature probes, WHO 18 virtual energy meters, and the WHO 13 bus clock. Custom actions run as Home Assistant scripts.min_motor_pulse, default0.4 s,0disables) for timed covers and ≥2% minimum step when stationary for advanced covers; plainUP/DOWN(*2*1*WHERE##/*2*2*WHERE##) full runs at0%and100%; timed endpoint runs settle attravel_time + 2 s; timed runs end at the actuator's stop status (*2*0*WHERE##) and full-travel keypad runs report the endpoint; Venetian blind slat tilt (slat_tilt,slat_time); impulse garage/gate covers on WHO 1 relays with optional safety approval, nativelockplatform for WHO 6 door-entry strikes, and doorbell events; cover stop frames overtake queued commands; pluggableCoverKinematicsStrategyhierarchy; warning whenadvanced: trueis set on standard F411 shutters.AUTOon standalone zones, fan coils per season, season persisted across restarts;hvac_actionderived from season when actuator omits heating flag; standalone default follows the plant; F455 10 s command timeouts eliminated; migrated tonative_*temperature API.01–09; ON dimmers on a fresh install probed on Dimension 1 for brightness support; timed turn-on migrated to OWNd builders; lights already reported by the startup sweep are not polled again; area and group re-syncs only skip/cancel once every registered member has echoed in the commanded polarity, and group members inherit the group's bus interface (#4#02).myhome_scene_event).FrameSchedulerwith per-target ordering and user commands prioritized ahead of status polls; H4684 / LGRH4684 and MH201 WHO 1013 identification; kernel and distribution queries in the diagnostic sweep; HA websession injected into OWNd discovery;myhome.sync_timerejects half-hour time zones with a translated error instead of truncating the offset.myhome.yamlcopied into the config entry so they survive if the file is removed; blank-start discovery suppresses phantom entities;ignored_addressescan be cleared in the UI; restored sensors keep native ID regeneration; legacy entityfriendly_namepreserved ascompat_nameacross HA 2026.11+ registry migration and availability updates; local brand assets bundled incustom_components/myhome/brand.config_flow,gateway, anddecoder_poolsplit into focused subpackages; private OWNd access and runtime shims removed;mypy --strictverified against pinned OWNd 2.0.0b11; 4-tier trace-vs-firmware-oracle conformance gate and empty-bus NACK verification; HA deprecation guard in pytest and container smoke tests.📦 Previous Beta Summaries (
2.0.0b15&2.0.0b14)What shipped in
2.0.0b15(since2.0.0b14— 41 PRs on OWNd 2.0.0b10)actuator_fault) and withdraw on recovery;ignored_addressesin the Options Flow silences faulty or unwanted devices and their repair issues.WHAT 19) handled gracefully without dropping light entities; brightness 0% routes toswitch_offto avoid gateway firmware NACKs; dimension and motion frames no longer trigger broadcast resync sweeps; blank-start lighting discovery withoutmyhome.yaml.libqtdevices; 99-zone central unit polled with plain status request and exempt from Dimension 14 polling /PollHealth; invalid fan speeds outside 0–3 caught as friendly service errors; exact0.0 °CWHO 4 readings preserved.WHEREsystem frames routed to the central alarm panel; read-only auxiliary panel mode with AUX arm/disarm guidance; MH202 and H4890 alarm profile and golden trace support.WHERE 0frames ignored by illuminance discovery; dusk curfew blueprint and hardware-coupled sensor guide.CalibrateAllCoversButtonEntity.What shipped in
2.0.0b14(since2.0.0b13— 105 PRs on OWNd 2.0.0b9)0#N) or a temperature probe (PZZ,WHERE ≥ 100) is no longer a zone; a running zone's dimension 12 write is its new setpoint; zones that never answer are no longer polled at startup; one WHO 4WHEREgrammar plus a CI guard against rawWHEREreads.*1*0*0##; event session closed on cancel; command workers capped at the profile's session limit; F461, H4890, MyHomeServer1 traces close the WHO 13 / 1013 gaps;myhome.sync_timealso writes DIMENSION 0 for MH200N.long_pressonce per hold withlong_press_repeat, CEN+ wire-WHEREaddresses (Living Now KW8011); centralized shutter buttons as device triggers; F520 energy meter sweep and discovery; one unique ID per temperature probe.OptionsFlowWithReload, no entry update listener (fixes the options-flow reload race), and averify_ha_standards.pyrule that keeps it that way.__init__,cover,gatewayandlight(#467, #468, #472, #475, #485); OWNd timezone monkeypatch removed (#482); anti-drift sentinels, per-beta documentation snapshots with Delta Explorer, hardware trace matrix synced to #466 by CI, Crowdin translation pipeline.🏆 Integration Quality Scale & Architectural Modernization
Home Assistant Core ≥ 2026.3 & Platinum Tier Quality Scale:
OptionsFlowWithReload, the config entry update listener is gone, legacy entity names survive the 2026.11compat_nameregistry migration, and Home Assistant deprecation warnings fail CI in both pytest and container smoke tests.brandsapproved inhome-assistant/brands#2052and bundled locally incustom_components/myhome/brand(feat(brands): bundle local brand assets in custom_components/myhome/brand for HA 2026.3+ and HACS #741), strict unique IDs, config entry uniqueness, removal instructions, setup tests, runtime-data mapping.PARALLEL_UPDATES = 0across all 10 platform files), config entry unloading, reconnect grace period logging, reauth flow, 100% test coverage.async-dependency), HA websession injection for UPnP discovery (inject-websession, fix(config_flow): inject the HA websession into OWNd discovery and correct the OWNd licence #757), and zero strict typing errors across all modules (strict-typing, verified against pinnedOWNd==2.0.0b11, fix(typing): check mypy --strict against the pinned OWNd 2.0.0b11 types #765).mypy --strictwith zero errors across all 73 integration modules (chore: strict-typing ratchet, CI dry-run fixes; cover travel time copied_from #326, chore(typing): strict-typing ratchet phases 1-3 (507 -> 269 errors) #375, fix(typing): Resolve 64 new strict typing errors from OWNd 2.0.0b7 #393, fix(typing): make the strict-typing gate fail, and clear the 11 errors behind it #560, fix(typing): clear the two strict-typing errors on the v2 base #570, fix(typing): check mypy --strict against the pinned OWNd 2.0.0b11 types #765), backed by OWNd's PEP 561py.typedmarker.entry.runtime_dataMigration: Gateway state, frame routing, and platforms live entirely within typedMyHOMERuntimeData, completely retiring legacyhass.data[DOMAIN]storage (feat: quality-scale Bronze + Gold (runtime_data, exception translations, stale devices, entity audit, docs); min core 2026.3 #321).has_entity_name = True): Fully adopts Home Assistant standard naming conventions with translation keys instrings.json/translations/en.json, automatic entity ID generation (feat: Home Assistant device/entity naming (quality-scale has-entity-name, entity-translations) #325), opt-in entity ID updates when renaming devices (feat: opt-in entity ID updates when renaming MyHOME devices #672), and legacycompat_namepreservation (fix(migrate): preserve legacy entity friendly_name as compat_name on HA 2026.11+ #727, fix(compat): bridge HA 2026.11+ logger export removal and EntityRegistry._async_update_entity(compat_name) #769, fix(compat): restore legacy compat_name in _register_availability_listener for HA 2026.11+ #772).HomeAssistantError,ServiceValidationError) are mapped to translation keys underexceptionsinstrings.jsonandtranslations/en.json(feat: quality-scale Bronze + Gold (runtime_data, exception translations, stale devices, entity audit, docs); min core 2026.3 #321, fix(services): reject half-hour time zones in sync_time with a translated error #764).async_remove_config_entry_device(feat: quality-scale Bronze + Gold (runtime_data, exception translations, stale devices, entity audit, docs); min core 2026.3 #321), and allows silencing faulty or unwanted addresses viaignored_addresses(feat(options): silence faulty or unwanted devices via ignored_addresses option #611, fix(options): allow clearing ignored_addresses when omitted or empty in UI (#612) #666).Deep Modularization & Package Decomposition:
legacy_yaml.py,migrate.py, refactor(init): decompose __init__.py into legacy_yaml and migrate sibling modules (Milestone 1) #467, feat(discovery): reusable sweep poll gate, dimmer capability probe, and legacy YAML migration (#733) #742): Decomposed__init__.pyboot pipeline into dedicated legacy YAML parser and schema migration engine, migratingmyhome.yamldevice settings into the config entry so they survive if the file is removed.cover_calibration.py,cover_motion.py,cover_scope.py,cover_kinematics.py, refactor(cover): encapsulate calibration hub, motion math, and isolate multi-gateway state (Milestone 2) #468, feat(cover,light): pluggable CoverKinematicsStrategy hierarchy and low-priority fade step routing (#730) #739): Decomposedcover.py, isolating multi-gateway state, extracting the pluggableCoverKinematicsStrategyhierarchy, and establishing the central calibration hub.gateway/,gateway_sessions.py,gateway_events.py,gateway_resync.py,frame_scheduler.py, refactor: decompose init, cover, and gateway session/event runners (Milestones 1–3) #472, feat(scheduler): standalone FrameScheduler and per-target worker serialization (#731) #738, refactor(arch): modularize config_flow, gateway identity, and decoder pool (#732) #744): Decomposedgateway.pyinto focused package mixins, dedicated session runners, standalone per-targetFrameScheduler, event listener & watchdog supervisor, and debounced reactive resync coordinator.light_fade.py,light_dali.py,light_group.py, refactor(light): extract SoftwareFadeEngine and DaliFeatureLock subsystems (Milestone 4) #475, refactor(light): extract SoftwareFadeEngine and DaliFeatureLock subsystems (Milestone 4) #485): Decomposedlight.py, extracting theSoftwareFadeEngine,DaliFeatureLock, and light group management into dedicated, self-contained subsystems.config_flow/,decoder_pool/,media_player_*.py, refactor(media_player): split the audio zone entity into layered modules #559, arch(modularize): split monolithic config_flow.py, gateway.py, and platform modules into focused packages #732, refactor(arch): modularize config_flow, gateway identity, and decoder pool (#732) #744): Split monolithicconfig_flow.py,decoder_pool.py, andmedia_player.pyinto layered, single-responsibility modules.Unified Platform Skeleton (
discovery.py), Frame Router (router.py) & Declarative Expose Engine (expose.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, refactor: one WHO 4 WHERE grammar and a CI guard against raw WHERE reads #556, feat(discovery): resolve blank start lighting discovery and suppress polling avalanche (#578) #580, fix(discovery): improve blank-start discovery quality and suppress phantom entities (#681) #686, feat(discovery): reusable sweep poll gate, dimmer capability probe, and legacy YAML migration (#733) #742, feat(expose): add declarative HA-to-SCS bus expose engine and virtual actuator LED sync #750):discovery.py): Unified lifecycle engine across all 10 entity platforms (light,switch,cover,lock,climate,alarm_control_panel,sensor,binary_sensor,media_player,button). Standardizes restore, configure, discover, and route phases with a reusable sweep poll gate that prevents polling avalanches during paced startup sweeps (feat(discovery): resolve blank start lighting discovery and suppress polling avalanche (#578) #580, fix(discovery): improve blank-start discovery quality and suppress phantom entities (#681) #686, feat(discovery): reusable sweep poll gate, dimmer capability probe, and legacy YAML migration (#733) #742).router.py): Dedicated per-gatewayFrameRouterdelivering frames directly to subscribing entities by address without string-interpolated dispatcher overhead.WHEREgrammar (where_grammar.py, refactor: one WHO 4 WHERE grammar and a CI guard against raw WHERE reads #556, test(climate): teach the routing grammar the 4-zone central address #0#N (#717) #719): Canonical parser for heating zones, 99-zone (#0) and 4-zone (#0#N) central units, pumps (0#N), and probes (PZZ), guarded in CI bytests/test_where_usage_guard.py.expose.py, feat(expose): add declarative HA-to-SCS bus expose engine and virtual actuator LED sync #750): Projects Home Assistant entities and the clock onto free SCS addresses — virtual WHO 1 / WHO 2 actuators that physical wall controls can drive (synchronizing HA state back to wall LEDs), WHO 4 virtual temperature probes, WHO 18 virtual energy meters, WHO 13 bus clock broadcasts, and custom Home AssistantScriptactions.🚀 Key Subsystems & Feature Capabilities
Transports, Gateway Profiles, Scheduling & 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, fix(services): send DIMENSION 0 alongside DIMENSION 22 during sync_time (#520) #522, refactor(repairs): track device faults per gateway and raise them as self-clearing repair issues #593, feat(config-flow): start new gateways at the profile's default command sessions #606, fix(gateway): support firmware-discriminated gateway profiles (OWNd#80) #623, fix(gateway): disable passive event inactivity timeout on quiet plants (#637) #640, feat(gateway): add H4684 and LGRH4684 models to WHO 1013 identification #652, feat(gateway_sessions): prioritize user commands over status polls in command queue (#680) #685, feat(gateway): include kernel and distribution queries in diagnostic sweep (#466, #709) #711, fix(gateway): identify MH201 via empty-WHERE WHO 1013 and include in device type 200 #722, refactor(protocol): eliminate private OWNd access and runtime shims (#736) #737, feat(scheduler): standalone FrameScheduler and per-target worker serialization (#731) #738, fix(config_flow): inject the HA websession into OWNd discovery and correct the OWNd licence #757, fix(services): reject half-hour time zones in sync_time with a translated error #764):
F453AV,OWNd#80), WHO 22 tuner & sound source builders, WHO 25 Scenario Plus, WHO 4 season/holiday/humidity support, and zero private symbol access (refactor(protocol): eliminate private OWNd access and runtime shims (#736) #737, fix(typing): check mypy --strict against the pinned OWNd 2.0.0b11 types #765).F452 / F453AV,F455(docs(gateway): reclassify F455 as single-bus Basic Gateway (#466) #471, Community Call for Real-World Gateway Traces: Help Us Eliminate Hardware Blind Spots! 📡 #466, test(trace): add authentic Legrand F455 Basic Gateway trace and plant fixtures (#466) #596),Legrand 3578(USB/Serial, [Feature Request]: Support USB-based OpenZigBee gateway (Legrand 3578 / Serial Transport) #233).F454,F461,MH200,MH200N,MH202,MH201,MyHomeServer1,HL4684 / H4684 / LGRH4684(feat(gateway): add H4684 and LGRH4684 models to WHO 1013 identification #652), and the4890family (AM4890,H4890,LN4890,LN4890A, Community Call for Real-World Gateway Traces: Help Us Eliminate Hardware Blind Spots! 📡 #466, 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).actuator_fault, refactor(repairs): track device faults per gateway and raise them as self-clearing repair issues #593), gateway identity mismatches/corrections, and unconfigured timezone (999, feat(gateway): generate repair issue for unconfigured timezone (999) #387, feat(repairs): add repair issue for unknown gateway models #388).frame_scheduler.py, feat(gateway_sessions): prioritize user commands over status polls in command queue (#680) #685, feat(gateway_sessions): let a cover stop overtake unrelated queued frames (#645) #694, feat(scheduler): standalone FrameScheduler and per-target worker serialization (#731) #738):poll_health.py, perf(climate): stop polling heating zones that never answer #555, fix(climate): exempt central units from Dimension 14 status queries and PollHealth (#582) #590) skipping silent heating zones at startup while exempting central units.myhome.sync_timewrites both DIMENSION 22 and DIMENSION 0 (for MH200N), and rejects half-hour time zones with a translated error instead of silently truncating the offset (fix(services): reject half-hour time zones in sync_time with a translated error #764).Multiple Gateways, Shared Buses & Warm Standby (Two gateways in one installation? Help us support shared buses (MH200N + MH201, MHS1 + LN4890, …) #453, feat(gateway): multiple gateway and shared bus support (#453) #459, Adding a second gateway discovers the bus before its shared-bus role can be set, leaving cover devices with only unavailable buttons #524, fix(topology): ask for bus topology when adding a gateway, prune whole duplicate devices (#524) #525, fix(tests): eliminate dispatcher/event-bus race in CEN failover tests #529, fix(gateway): align shared-bus evidence window docs with the 10-minute constant #531):
{mac}-{who}-{where}) or Shared (several gateways on one physical bus) with an explicit role per gateway: Primary, Secondary (delegated WHOs), or Warm standby (automatic failover when primary drops > 60 s).bus_topologystep runs before entry creation, recommending roles and delegated WHOs from the gateway models and pruning duplicate devices cleanly.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, fix(light): prevent dimension and motion frames from triggering broadcast resync sweeps (#612) #614, fix(light): handle dimmer no-load state WHAT 19 and promote to dimmable (#619) #622, fix(light): guard brightness 0 against firmware NACK and clamp 1% brightness #635, feat(lighting): migrate timed turn-on commands to OWNd b11 builders #659, fix(light): skip post-discovery poll for lights the startup sweep already reported (#612) #701, feat(light): support 2-digit Area 0 point-to-point addressing (01-09) (#684) #713, feat(resync,light_group): scope group echo cancellation and multi-entity area sweeps (#734) #740, feat(discovery): reusable sweep poll gate, dimmer capability probe, and legacy YAML migration (#733) #742, fix(resync): require all registered area entities to echo before skipping or cancelling area sweep (#746) #749, fix(resync,light_group): inherit group bus interface for members and seed leading group echoes (#734, #740) #771):
01–09) and automatic Dimension 1 capability probing when an unknown light is discovered ON during a fresh install.WHAT 19) & Brightness 0 Guard (fix(light): handle dimmer no-load state WHAT 19 and promote to dimmable (#619) #622, fix(light): guard brightness 0 against firmware NACK and clamp 1% brightness #635): Handles F414 dimmer no-load frames without dropping entities and routes brightness 0% toswitch_offto prevent firmware NACKs.light_fade.py,light_dali.py, [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, [RFC] Support & Compatibility for Adaptive Lighting (Circadian Lighting) with MyHOME Fixtures #461, feat(light): adaptive lighting compatibility and bus traffic optimization (#461) #462, refactor(light): extract SoftwareFadeEngine and DaliFeatureLock subsystems (Milestone 4) #475, refactor(light): extract SoftwareFadeEngine and DaliFeatureLock subsystems (Milestone 4) #485): Low-priority software-stepped fade curves andlock_features: truepreventing DALI gateways (F429 / F461) from polluting relays or dimmers with remembered Dimension 12 (HSV) or Dimension 14 (tunable white) values.light_group.py,gateway_resync.py, 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, fix(light): prevent dimension and motion frames from triggering broadcast resync sweeps (#612) #614, fix(light): skip post-discovery poll for lights the startup sweep already reported (#612) #701, feat(resync,light_group): scope group echo cancellation and multi-entity area sweeps (#734) #740, fix(resync): require all registered area entities to echo before skipping or cancelling area sweep (#746) #749, fix(resync,light_group): inherit group bus interface for members and seed leading group echoes (#734, #740) #771): Area and group sweeps only skip or cancel once every registered member has echoed in the commanded polarity; group members inherit the group's bus interface (#4#02); dimension and motion frames never trigger false broadcast resyncs; startup sweep replies suppress duplicate post-discovery polls.Cover Subsystem (WHO=2 & WHO=1), Venetian Slat Tilt & Video Door Entry Locks (WHO=6) (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, feat(device_trigger): add centralized shutter controls to gateway device triggers (#445, #466) #503, feat(cover): implement venetian blind slat tilt inching and clarify dimension 11 shutter level (#492) #508, feat(cover,lock): impulse garage/gate control, multi-factor safety approval, and intercom events #667, feat(cover): enable native broadcast for general covers behind an interface and pace fan-out #679, feat(gateway_sessions): let a cover stop overtake unrelated queued frames (#645) #694, feat(cover): motor start-up floor and full runs at 0/100% (#466) #702, fix(cover): end timed runs on stop status instead of stop write (#705) #707, feat(cover): per-cover motor start-up floor instead of single constant (#704) #708, feat(cover,light): pluggable CoverKinematicsStrategy hierarchy and low-priority fade step routing (#730) #739, fix(cover): confirm end_stop on full-travel bus runs and scope run timeouts #760, fix(cover,docs): warn and guide when F411 standard shutters set advanced: true (#761) #762):
cover_kinematics.py, feat(cover): motor start-up floor and full runs at 0/100% (#466) #702, fix(cover): end timed runs on stop status instead of stop write (#705) #707, feat(cover): per-cover motor start-up floor instead of single constant (#704) #708, feat(cover,light): pluggable CoverKinematicsStrategy hierarchy and low-priority fade step routing (#730) #739, fix(cover): confirm end_stop on full-travel bus runs and scope run timeouts #760):min_motor_pulsefloor (default0.4 s,0disables) and book the stretched run; stationary advanced covers widen sub-2% moves.UP/DOWN(*2*1*WHERE##/*2*2*WHERE##) full runs at0%and100%; timed endpoint runs settle on atravel_time + 2 stimer without sending a stop frame; mid-run timed stops book position from the actuator's*2*0*WHERE##stop status (fix(cover): end timed runs on stop status instead of stop write (#705) #707), and full-travel keypad runs confirm the endpoint (fix(cover): confirm end_stop on full-travel bus runs and scope run timeouts #760).advanced: trueis configured on standard F411 shutters that do not report Dimension 10 position (fix(cover,docs): warn and guide when F411 standard shutters set advanced: true (#761) #762).slat_tilt,slat_time, feat(cover): implement venetian blind slat tilt inching and clarify dimension 11 shutter level (#492) #508): Timed slat pulse positioning alongside shutter travel.WHAT 18or timed ON) with contact sensor feedback and optional multi-factor approval; nativelockplatform for WHO 6 door-entry strikes with constant-time PIN verification, auto-relock, and doorbell call events (*6*9**##, test(traces): ingest Issue #669 MH202 visitor doorbell call and wall control traces #751, **No Home Assistant event generated for received doorbell telegram (*6*9**##)** #759).*2*1*0#4#02##), and exposecentralized_shutter_open/_close/_stopdevice triggers.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, climate: trailing '3' on WHO 4 dimension 12 is read as protection/off, so _target_temperature goes stale #454, feat(climate): follow WHO 4 dimension 7 zone state on Home+Control plants (#429) #457, Climate: a temperature probe (WHERE >= 100) is routed to zone WHERE-100 and can discover a phantom zone #549, fix(climate): a temperature probe is not zone WHERE-100 #550, fix(climate): a dimension 12 mode 3 of a running zone is its new setpoint (#454) #552, perf(climate): stop polling heating zones that never answer #555, refactor: one WHO 4 WHERE grammar and a CI guard against raw WHERE reads #556, fix(heating): exactly-zero WHO 4 readings are 0.0, freezing/probe/zero tests (#566) #569, fix(climate): exempt central units from Dimension 14 status queries and PollHealth (#582) #590, fix(climate): align central unit mode commands and fan mode with OWNd canonical protocol (OWNd#77) #630, fix(climate): poll 99-zone central unit with plain status request (#629) #636, fix(climate): turn OWNd's fan-speed ValueError into a service error (OWNd#77) #641, feat(climate): support WHO 4 season frames and generic setpoint mode (#649) #657, fix(climate): migrate to the native_* temperature API #665, fix(climate): eliminate 10s command session timeouts on F455 and add authentic trace fixture (#674) #675, feat(climate): support WHO 4 holiday plan and vacation program attributes #689, fix(climate): zones follow the plant for the standalone default (#697) #698, feat(climate): remember zone humidity support and query dimension 60 on startup (#710) #712, fix(climate,services): poll F461 zones, AUTO on standalone zones, fan coil per season, refuse WHO 4 dimension 22 (live F461 capture) #714, fix(climate): restore season and fan_coil_sides across restarts and bridge dim 19 is_active (#714) #715, fix(climate): determine hvac_action from season when active actuator carries no heating flag #721, feat(climate): keep the season of a central unit's mode frames (#699) #725):
102/202), holiday/vacation program attributes, and Dimension 60 zone humidity (queried at startup when supported). Persists season and fan-coil sides across restarts and deriveshvac_actionfrom the active season when the actuator carries no heating flag.#0& 4695#0#1), Probes & Pumps: Master central unit mode commands aligned withlibqtdevices(fix(climate): align central unit mode commands and fan mode with OWNd canonical protocol (OWNd#77) #630), polled via plain status requests (fix(climate): poll 99-zone central unit with plain status request (#629) #636), and exempt from Dimension 14 polling (fix(climate): exempt central units from Dimension 14 status queries and PollHealth (#582) #590); subordinates defaultstandalonefrom the plant (fix(climate): zones follow the plant for the standalone default (#697) #698); pumps (0#N) and probes (WHERE ≥ 100) strictly separated from zones (fix(climate): a pump status (WHERE 0#N) is not zone N (#431) #432, fix(climate): a temperature probe is not zone WHERE-100 #550).AUTOsupport.Audio & Multi-Room Sound System 2.0 (WHO=16 & WHO=22) (fix(media_player): make F441M source selection work — routing address used the wrong digits #422, feat(media_player): tuner entity for WHO=16 sound sources (F500) #427, 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, feat(media_player): automatic companion decoder discovery & transparent DLNA streaming bridge #487, fix(media_player): parse real OWNSoundEvent dimensions and handle malformed RDS frames #497, feat(media_player): add cast platform and host/name companion resolution #519, feat(media_player): add group handover, 100% pre-gain, and F441 multiroom trace #521, fix(media_player): grace period before a member's group-leave OFF #528, fix(media_player): async_join_players is additive, not a snapshot #530, fix(media_player): switch off rooms that hear a decoder they do not own when it stops #532, fix(audio): keep the decoder books across restarts and close the #532 audit leftovers #535, fix(audio): keep the group when the anti-hiss timer switches its rooms off (live-tested) #538, perf(media_player): wake a parked group faster #544, fix(media_player): turning off a group's leading room no longer silences the whole group #554, feat(audio): never guess a streaming companion, guard decoders at runtime, pin the Music Assistant contract #568, feat(audio): auto-join active streaming group and sync wall button source selection (#579) #581, feat(sound): modernize sound source commands and intercept physical wall transport steps (blocked on OWNd 2.0.0b11) #651, fix(media_player): do not wake amplifiers on Dimension 1 volume status reports (#669) #670, fix(media_player): centralise power-state decision engine, document sound system state machine, and add intercom ducking trace replay (#682) #683, feat(sound): read tuner frequency, preset and RDS from WHO 22, with optional per-frequency pictures #695, fix(media_player): allow claiming idle decoder from parked group and reconcile displaced rooms #723):
async_join_players, leader handover on OFF, persistent.storagegroup/decoder books across restarts, anti-hiss group parking, automatic group join when a room is switched on at its physical wall button (feat(audio): auto-join active streaming group and sync wall button source selection (#579) #581), and claiming idle decoders from parked groups (fix(media_player): allow claiming idle decoder from parked group and reconcile displaced rooms #723).decoder_companion.py, feat(media_player): automatic companion decoder discovery & transparent DLNA streaming bridge #487, feat(media_player): add cast platform and host/name companion resolution #519, feat(audio): never guess a streaming companion, guard decoders at runtime, pin the Music Assistant contract #568): Explicit companion matching (dlna_dmr,upnp,cast) without guessing, forwardingplay_mediawhile keeping hardware volume, pre-gain, and F441M routing on the matrix slot.Scenario Controls (WHO=15 CEN, WHO=25 CEN+ / Scenario Plus & WHO=17 Scenes) (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, #439, #515, #548, #597, #603, #639, #656, #671):
long_pressdeduplication withlong_press_repeat, and forwarded event context for trigger IDs.myhome_scene_event).Sensors, Binary Sensors & Energy Counters (WHO=1, 4, 9, 18, 25) (#244, #245, #247, #308, #441, #452, #494, #506, #607, #633, #661, #678):
51–59and71–79.0.0 °Chandling (#569); WHO 1 PIR (WHAT = 34) and illuminance (DIMENSION = 6) discovery with broadcastWHERE 0phantom filtering (#607); WHO 25 dry contacts (3477/F482) with dusk curfew blueprint (#633).Burglar Alarm Platform (WHO=5) (#311, #470, #490, #576, #608, #609, #618, #620):
3485/3486) and partition state tracking with empty-WHEREsystem frame routing (#618), zone 0 broadcast synchronization, AUX arm/disarm support (#609), MH202/H4890 profile support (#576), and MH200/MH200N phantom zone suppression (#490).Lovelace Bus Monitor Card v2 (
<myhome-bus-card>) (#275, #276, #277, #278, #279, #305, #343, #449, #470, #747):RECtrace freeze, Sweep Bus workflow (#470), strict WebSocket frame validation (#747), andnode:testfrontend suite.Internationalization & Documentation (#415, #463, #464, #483, #495, #507, #511, #513, #577, #687, #768):
PLATFORMS,SUPPORTED_GATEWAY_MODELS,manifest.jsonSSDP, OWNd profiles, options-flow fields, device triggers, translations, and the firmware oracle (#743).docs/configuration/and per-beta Delta Explorer (docs/roadmap/beta-differences.md) updated throughv2.0.0b16(#703, #768).Golden Corpus, Firmware Oracle & CI Verification:
tests/golden/corpus.json) and 4-tier Firmware Oracle Conformance Gate (tests/test_firmware_oracle_conformance.py, #642, #720, #743, #745, #766) validating gateway profiles and real plant traces against empirical firmware verdicts.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 #421
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 #453
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
Closes #492
Closes #493
Closes #494
Closes #498
Closes #501
Closes #510
Closes #520
Closes #523
Closes #524
Closes #537
Closes #540
Closes #541
Closes #549
Closes #553
Closes #563
Closes #564
Closes #565
Closes #566
Closes #578
Closes #579
Closes #582
Closes #600
Closes #601
Closes #604
Closes #612
Closes #615
Closes #616
Closes #619
Closes #624
Closes #629
Closes #631
Closes #637
Closes #645
Closes #654
Closes #658
Closes #669
Closes #674
Closes #676
Closes #677
Closes #680
Closes #681
Closes #682
Closes #684
Closes #690
Closes #697
Closes #699
Closes #704
Closes #705
Closes #706
Closes #709
Closes #710
Closes #730
Closes #731
Closes #732
Closes #733
Closes #734
Closes #735
Closes #736
Closes #746
Closes #759
Closes #761
Addresses #445
Addresses #466
👥 Credits & Attribution
This integration is developed and maintained by the OpenWebNet-HA community.
Special thanks to:
OWN DOC.zip), the officialWHO_24.pdfLighting Management specification, and CEN+ community automation references.