Repository navigation
feat(door_entry): support WHO 6 door entry and WHO 8 lock/intercom commands and events - #100
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ercom dialects - Register WHO 8 event and command parsers (OWNLockEvent / OWNLockCommand) - Expose public is_camera_on and is_camera_off properties on OWNDoorEntryEvent - Expand WHO 8 support with full TS10/oracle and trace dialects from draft PR OpenWebNet-HA#85 (calls, session actions, cameras, PTZ, amplifier mute, teleloops, and command builders) - Add OWNIntercomEvent and OWNIntercomCommand aliases and export constants in OWNd.message - Clean up stale WHO 6 from OWNCommand.parse fallback dispatch - Add WHO_DOOR_ENTRY and WHO_LOCK to MH200 and MH200N supported profiles - Add comprehensive test coverage asserting WHO 8 registry parsing and 100% statement/branch coverage
🔍 Protocol, Grammar & Architecture Review: Recommendations & Required FixesThank you for adding typed message parsing and builders for WHO 6 and WHO 8! The unit test coverage and parsing abstractions are thorough. Before merging and tagging the release for downstream integrations (like 1.
|
fedem95
left a comment
There was a problem hiding this comment.
Checked on 5013ae4. Three of the points in your own review are still open in the code:
_DOOR_ENTRY_SHORT(^\*6\*(?P<what>\d+)\*?##$) accepts any WHAT:*6*3##and*6*42##parse as validOWNDoorEntryEvents.- WHO 6 and 8 are in
DEFAULT_SUPPORTED_WHO, so every profile now advertises them (MH201, F452, F454, MyHomeServer1, Generic), while the description mentions adding them to MH200/MH200N. In MyHOME this doesn't change the discovery sweep (1, 2, 4, 16), but it does feed standby routing, shared-bus delegation and diagnostics. OWNLockEvent.is_incoming_callis True for any WHAT 1, including the internal call*8*1#6#2#11*16##and the pager*8*1#14#2#11*4##. MyHOME#667 firesmyhome_doorbell_eventwheneveris_callis True.
On the evidence:
- The #667 trace README says all WHERE values were "deterministically mapped to fictitious mock addresses", so the frames aren't verbatim. Its only door-entry frames are
*8*1#1#4*74##,*8*9#1#4*73##and*6*9##; there is no WHO 6 call/lock/staircase/camera-on frame and no WHO 8 lock/staircase/PTZ/mute frame. - The 59 WHO 8 inputs in
firmware_oracle.jsonare alldownrows of theintercom-ts10suite; no WHO 8 frame was emitted by any firmware. "59 authentic on-wire frames" doesn't describe them. WHO_6.pdf/WHO_8.pdfreturn 404 on developer.legrand.com and aren't in sxpert/myhomepylgg-docs. Which documents are cited?- libqtdevices
videodoorentry_devicedoes back the WHO 8 codes (1, 2, 3, 4, 6, 9, 19–22, 37, 40, 59–64, 76–79). It names 9CALLER_ADDRESS; the description's sequence calls*8*9#1#4*73##"Handset answers". libqtdevices has no WHO 6 device.
Tests: the branch is 4 commits behind master. As is, MyHOME v2-phase1-architecture (0433228) gets 12 sound-source failures (no OWNSoundCommand.select_track from #95). Merged locally with master: OWNd 1302 passed (test_metadata excluded for my env), MyHOME 3497 passed, 1 skipped.
…, call kinds, naming) - Restrict the WHO 6 short form to WHAT 9 (*6*9## and *6*9*##); *6*3## and *6*42## no longer parse as door entry events. - Remove WHO 6/8 from DEFAULT_SUPPORTED_WHO. Only the MH200 has a capture (MyHOME#667), so MH200 and MH200N list them and the docstrings say why. - WHO 8 WHAT 1: is_incoming_call is true only for entrance panel kinds 1..4; add is_internal_call (kind 6). Pager and internal calls are no longer reported as doorbell rings. is_call still means any call session. - Drop lock_status (*OpenWebNet-HA#8*WHERE*19##): no documented dimension 19 for WHO 8 and no firmware verdict. - Make OWNIntercomEvent/OWNIntercomCommand the primary classes, keep OWNLockEvent/OWNLockCommand as aliases. - Note WHAT 20 (chime) is not in the published WHO 6 table and has no capture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @fedem95, this was worth doing, and my own follow-up was sloppy: I flagged the right problems but didn't re-check them against the code or the evidence before you did. Fixes are in 5532cf5 (master merged in, so Code
Profiles
So the MH200 lists them (captured), the MH200N by family, both with the evidence in the docstring. If someone with another gateway and a door entry system can capture it, we update that profile. As a general rule for OWNd, I'd suggest Description corrected
Happy to split the PR if you'd rather merge only the trace-backed part now. |
fedem95
left a comment
There was a problem hiding this comment.
Thanks for addressing the earlier findings. The parser changes and call classification look good, and CI is green. Approved.
Note: MH200NProfile advertises WHO 6/8 based on the MH200 family, while the docstring correctly notes that this has not been captured on an MH200N. This is transparent and non-blocking here, but should be treated as an inference until verified on MH200N hardware.
WHO 6 (Door Entry) & WHO 8 (Video Door Entry & Intercom) command builders and event decoders
Adds parser registrations, typed command builders and event decoders for WHO 6 (Basic Video Door Entry) and WHO 8 (Video Door Entry & Intercom, including lock actuators).
Companion Home Assistant integration PR: OpenWebNet-HA/MyHOME#667.
1. What is the problem?
OWNMessage.parse/OWNEvent.parsereturned a genericOWNEventfor door entry and intercom frames, andOWNCommand.parsereturnedNonefor WHO 8. Consumers had no typed classes, readable logs or state properties.*6*9##was rejected. The L4686SDK form has noWHEREfield, and the base regexes required one.OWNCommand.parsehad a legacyif _who in (6, 7, 9):branch; 6 now has a registered parser.2. How is it solved?
Short-form frame in
OWNd/message/base.py_DOOR_ENTRY_SHORTaccepts only WHAT 9 withoutWHERE(*6*9##, and the field variant*6*9*##).*6*9**##keepswhere="*"via the normal status regex. Any other short WHO 6 frame (*6*3##,*6*42##) is not valid.(6, 7, 9)fallback is now(7, 9).OWNDoorEntryEvent/OWNDoorEntryCommand(WHO 6)is_incoming_call(WHAT 6),is_broadcast_call(WHAT 6, WHERE 4100),is_chime(WHAT 20, unverified: not in the L4686SDK table, no capture),is_call(incoming or chime),is_lock_open(WHAT 10, or 22 in conversation),is_staircase_on/is_staircase_off(12 / 11),is_camera_on/is_camera_off(0 / 9).open_lock(where)(riser4001#2supported),staircase_light_on/off(where),camera_on(where),camera_off().OWNIntercomEvent/OWNIntercomCommand(WHO 8), withOWNLockEvent/OWNLockCommandkept as aliasesis_callis true for any call session.is_incoming_callis true only for entrance panel call kinds 1–4.is_internal_callfor kind 6,is_pagerfor kind 14 (or callee 4). Pluscall_kind,multimedia_type,caller,callee.CALLER_ADDRESS), VCT init (37), rearm (40).status(where)→*#8*WHERE##.Profiles & registry
register_event_parser/register_command_parserfor 6 and 8; constantsWHO_DOOR_ENTRY = 6,WHO_LOCK = WHO_INTERCOM = 8; exports inOWNd/message/__init__.py.DEFAULT_SUPPORTED_WHO. Whether a gateway reports them depends on the plant having a door entry system and on the gateway firmware relaying it. Only the MH200 has a capture, soMH200Profilelists them (captured) andMH200NProfileby family; the docstrings say so. Other profiles are unchanged until someone captures them.Frame mapping
Source: C = captured (MyHOME#667, MH200), S = L4686SDK table, L = libqtdevices, U = unverified.
*6*6*1##is_incoming_call,is_call*6*6*4100##is_broadcast_call,is_call*6*20*1##is_chime,is_call*6*10*4001##is_lock_open/open_lock(4001)*6*22*4001##is_lock_open*6*12*1##/*6*11*1##is_staircase_on/off/staircase_light_on/off(1)*6*0*4001##is_camera_on/camera_on(4001)*6*9##is_camera_off/camera_off()*8*1#1#4*74##is_call,is_incoming_call,call_kind=1,multimedia_type=4*8*1#6#2#11*16##is_call,is_internal_call,caller="11",callee="16"*8*1#14#2#11*4##is_call,is_pager*8*2#6#2*11##session_action="answer"/answer_call(...)*8*3#6#2*411##/*8*3#1#3*11##session_action="end"/"stop_video"*8*9#1#4*73##session_action="caller_notification",caller="73"*8*4#11*20##/*8*6#11*20##switch_camera/cycle_camera*8*19*20##/*8*20*20##is_unlocked/is_locked/unlock,lock*8*21*11##/*8*22*0##is_staircase_on/off*8*59#1*20##ptz_direction="up",ptz_action="press"*8*63*11##/*8*64*11##is_muted/mute_amplifier,unmute_amplifier*#8*11##status("11")3. How is it tested?
tests/test_door_entry.py: every WHO 6 and WHO 8 decoder and builder, the three camera-off spellings, rejection of other short WHO 6 frames, call classification (entrance panel vs internal vs pager), theOWNLock*aliases, and registry dispatch throughOWNMessage.parse/OWNCommand.parse.tests/test_profiles.py: MH200/MH200N list WHO 6/8;DEFAULT_SUPPORTED_WHO, MH201, F452, F454 and MyHomeServer1 do not.tests/test_firmware_oracle_conformance.py: all oracle input frames parse into specialised classes. This shows the parser accepts them, not that hardware sends them.ruff,mypyandscripts/verify_library_standards.pyclean.4. Where are the real traces?
MyHOME#667,
tests/fixtures/traces/issue_667/myhome_trace_MH200_intercom_bell_gate_2026-10-09.json: MH200, firmware 2.1.0, simple BTicino door entry setup. Addresses are remapped for privacy, so the frames are not verbatim. Door entry frames, in order:*8*1#1#4*74##: entrance panel 1 calls handset 74.*8*9#1#4*73##: caller address 73 (sent after the call; that it marks the answer is not shown).*6*9##: camera off, short form, when the call ends.There is no WHO 6 call/lock/staircase/camera-on frame and no WHO 8 lock/staircase/PTZ/mute frame in it.
Firmware oracle (
tests/golden/firmware_oracle.json): the WHO 8 rows are inputs of theintercom-ts10suite sent down to emulated gateways; no firmware emitted a WHO 8 frame. They are parse coverage, not captures. The emulated firmwares NACK WHO 8 commands, but the MH200N target does not run the image'sbt_vcttranslator, so those NACKs are not evidence about the real gateway.Reference sources
videodoorentry_device(WHAT 1, 2, 3, 4, 6, 9, 19–22, 37, 40, 59–64, 76–79). There is no complete public WHO 8 specification.Captures wanted: anyone with a door entry system on another gateway (MH201, F452, F454, MyHomeServer1, …), or a richer setup than mine (locks, staircase light, internal calls, pager), please attach a bus trace so the profiles and the unverified rows can be confirmed.
🤖 Generated with Claude Code