Repository navigation
feat(cen): parse and build WHO 25 scenario-plus frames (WHAT 11-15) - #91
Conversation
OWNd returned a bare OWNEvent for *25*11#0*W## .. *25*15*W##. These are the five scenario-plus commands of libqtdevices TS10_1_0_23 (scenario_device.cpp:37-41: "11#0" on, "12" off, "13#0#5" increase, "14#0#5" decrease, "15" stop; sent by ScenarioPlusDevice, :163-186). The gateway firmware (bt_luci on MyHomeServer1, F454, F459) accepts all five with a bus frame (B1 01 93 00 / 94 00 / 95 40 / 96 40 / 97 00) and echoes each on the monitor port; the emitted corpus has *25*12*1xx## and *25*15*1xx## 64 times each. Adds OWNScenarioPlusEvent (action) and OWNScenarioPlusCommand builders, routes WHAT 11-15 to them in the WHO 25 dispatchers, and updates the PR 82 test that expected a bare event for them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018oHp1P4vxxoFnaLUUZpbpZ
f3a0047 to
44b6db6
Compare
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
GreenGrassBlueOcean
left a comment
There was a problem hiding this comment.
Review: WHO 25 Scenario-Plus Frames (WHAT 11–15)
Thanks @gdluck for digging into this! Grounding these frames in the BTicino 10" Touch Screen client (libqtdevices tag TS10_1_0_23, scenario_device.cpp:37-41, Object 406 "Scheduled scenario PLUS") and correlating them with bt_luci's translation to SCS opcodes 93–97 is excellent protocol archeology.
Before merging this into OWNd, there are two structural prerequisites and two code fixes to address:
1. Authentic Bus Trace in MyHOME (PR Required)
We audited the trace corpus in MyHOME/tests/fixtures/traces/ across all gateway captures (MH200N, MH202, MyHomeServer1, F454). All existing authentic on-wire captures under WHO 25 consist exclusively of:
- CEN+ interactions:
*25*21#...through*25*24#... - Dry contacts / IR:
*25*31#1*.../*25*32#1*...
Currently, there are zero authentic customer on-wire traces demonstrating *25*11..15 in the wild. To ground this change in empirical evidence and protect against regressions, we need an authentic bus capture (submitted as a trace fixture PR to MyHOME) showing a real device emitting or receiving these frames.
2. Companion PR in MyHOME
OWNd serves downstream integrations—primarily Home Assistant (MyHOME). To ensure that OWNScenarioPlusCommand and OWNScenarioPlusEvent are not left as dead factory code in OWNd, we need a companion PR in MyHOME demonstrating how these factory builders and parsed events are actually consumed (e.g. platform entities, device triggers, or services) so that we can work with factory functions.
3. Code Fixes in This PR
-
Missing from
__all__inOWNd/message/__init__.py(Must Fix):
OWNScenarioPlusCommandandOWNScenarioPlusEventare imported on line 36 ofOWNd/message/__init__.py, but are missing from__all__(lines 187–192). This causesfrom OWNd.message import *to omit them and triggers typing/linter warnings in downstream consumers:# OWNd/message/__init__.py # CEN & Dry Contact (WHO 15 & 25) "OWNCENEvent", "OWNDryContactEvent", "OWNCENPlusEvent", "OWNCenCommand", "OWNDryContactCommand", "OWNCenPlusCommand", "OWNScenarioPlusEvent", # <-- Add "OWNScenarioPlusCommand", # <-- Add
-
Consistent Human-Readable Logging in
OWNScenarioPlusCommand:
OWNScenarioPlusCommandsets_human_readable_logonly inside its classmethod builders (turn_on,turn_off, etc.), but does not implement an__init__. When an incoming command frame is parsed viaOWNCommand.parse("*25*11#0*11##"), its log message falls back to the genericReceived command *25*11#0*11##.rather thanScenario plus 11: on.. Implementing an__init__(matchingOWNSceneCommand) ensures consistent logging regardless of whether the command was constructed or parsed.
|
Update on this PR:
|
…__all__ (cherry picked from commit 4799743)
|
Cherry-picked your 4799743 onto the branch as feac14e (author kept): |
📡 Physical Plant Trace Captured & Verified — Prerequisite Met! 🎉Following up on our earlier status update: we have officially captured and verified an authentic on-wire trace on physical hardware!
Verified On-Wire Sequence:
With this empirical evidence in-tree and deterministic replay tests passing, the physical trace prerequisite is 100% satisfied. This PR is now unblocked and ready to merge! 🚀 |
…nd replay test (#466) Captured from a physical BTicino MyHomeServer1 gateway (FW 2.87.13) by @TheDarkWizard on 2026-10-09 in response to the community call for real-world WHO 25 scenario plus traces (#466). Validates gateway acceptance, SCS bus relay, and OpenWebNet monitor echo of Scheduled Scenario PLUS frame *25*11#0*11## (~82.8 ms RTT), unblocking OpenWebNet-HA/OWNd#91 and #671. Co-authored-by: TheDarkWizard <9061870+TheDarkWizard@users.noreply.github.com>
GreenGrassBlueOcean
left a comment
There was a problem hiding this comment.
Minor observations (non-blocking)
Event logs include parameters when present; Command logs do not. This matches the tests and is consistent enough.
Builders re-assign _human_readable_log after init already sets it correctly — harmless redundancy.
No explicit validation that parameters match the canonical forms (#0, #0#5). This is the right call given real firmware variance.
No security, correctness, or regression issues stand out. The code is clean, well-documented with source references, and follows project conventions.
fedem95
left a comment
There was a problem hiding this comment.
The five WHO 25 WHAT 11–15 forms are covered by the builders, parser routing, exports, and regression tests. The physical trace and companion integration have been provided, and all checks pass.
Minor note: each builder resets _human_readable_log after init already sets it. This is redundant but harmless.
Summary
Support WHO 25 Scheduled Scenario PLUS (
WHAT 11–15:on,off,increase,decrease,stop), implementingOWNScenarioPlusEventandOWNScenarioPlusCommandwith buildersturn_on,turn_off,increase,decrease,stop.Companion PR to OpenWebNet-HA/MyHOME#671.
1. What is the problem?
In Legrand / BTicino MyHOME installations,
WHO 25carries not only CEN+ pushbuttons (WHAT 21..28) and dry contact / IR events (WHAT 31..32), but is also used by scenario programmers and touch screens (MH200,MH200N,MH202,MyHomeServer1,H4890, TS10libqtdevices) for Scheduled Scenario PLUS control:*25*11#0*WHERE##(turn_on/ start)*25*12*WHERE##(turn_off/ stop)*25*13#0#5*WHERE##(increase)*25*14#0#5*WHERE##(decrease)*25*15*WHERE##(stop)Prior to this PR, frames in the
11–15range parsed as bareOWNEventorOWNCommandwithout type information, action parsing, parameter validation, or builder factories (the PR 82 rule: WHO 25 WHATs other than 21-28 and 31/32 were treated as generic unknown events).2. How is it solved?
OWNd/message/cen.py):OWNScenarioPlusEvent: exposesaction(on,off,increase,decrease,stop),object(scenario WHERE address), andpush_button/ parameters.OWNScenarioPlusCommand: builder methodsturn_on(where),turn_off(where),increase(where),decrease(where),stop(where)._parse_who25_eventand_parse_who25_commandroute WHAT 11–15 toOWNScenarioPlusEventandOWNScenarioPlusCommand.WHAT 21..28) and dry contact (WHAT 31..32) routing remains untouched.11) and gateway-emitted1xxaddresses (*25*12*1xx##).OWNd/message/__init__.py.3. How is it tested?
tests/test_who25_scenario_plus.py):on,off,increase,decrease,stop) for parsing and command builder generation.#0,#0#5), address tolerance (11vs1xx), and fallback to bareOWNEventfor unrecognized WHAT values.tests/test_issue_77_firmware_findings.pyfix 9 to expect the typedOWNScenarioPlusEvent.bt_luci):028206, MH202010024, F454, F459):*25*11#0*11##B1 01 93 00*25*11#0*11##*25*12*11##B1 01 94 00*25*12*11##*25*13#0#5*11##B1 01 95 40*25*13#0#5*11##*25*14#0#5*11##B1 01 96 40*25*14#0#5*11##*25*15*11##B1 01 97 00*25*15*11##libqtdevicestagTS10_1_0_23(scenario_device.cpp:36-41).4. Where are the traces?
Authentic Physical Plant Trace Captured & Verified:
tests/fixtures/traces/issue_466/config_entry-myhome_MyHomeServer1_who25_scenario_plus.json).tests/test_issue_466_myhomeserver1_scenarioplus_trace.py(500 frames replayed through Home Assistant event dispatcher without exceptions).On-Wire Evidence:
[tx] *25*11#0*11##(2026-10-09T17:14:12.215385+00:00): Scenario Plus ON command sent to physical gateway.[rx] *25*11#0*11##(2026-10-09T17:14:12.298174+00:00): Acknowledged and placed on physical SCS bus (translating to bus opcodeB1 01 93 00), echoing back on monitor session 82.8 ms later.[tx] *#25*11##(2026-10-09T17:14:12.300230+00:00).[tx] *25*12#0*11##. Because in OpenWebNet andbt_luciOFF takes no#0parameter (*25*12*WHERE##), the gateway did not echo12#0, confirming the exact grammar distinctions implemented in this PR.