Repository navigation
Conversation
`*#1001*WHERE*11*<mask>##` is the actuator autodiagnostic frame a gateway pushes with `*1*19*WHERE##` when a status request reaches a faulty actuator: own-firmware-oracle what19 (input `*michnovka#1*74##`) shows it on F453, F453AV, F459, F460, F461, MH200N, MyHomeServer1 (after `*1*19*74##`) and MH202 (alone), and a physical MH200 capture agrees (findings/MH200N/what19.md, EVID-MH200-WHAT19-FAULT). OWNd returned a generic OWNEvent with who == 1001 and exposed nothing. OWNLightingDiagnosticEvent (registered for WHO 1001, exported) exposes diagnostic_mask as sent and cleared_bits (1-based from the left). The bit meanings are Open in the oracle, so nothing is interpreted. Only the single-value bit-string shape is decoded; `*#1001*74*11*101*5##` fails closed. README WHO catalog lists WHO 1001 (sync_documentation --update). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
… class `OWNLightingDiagnosticEvent` took any non-empty 0/1 string as the autodiagnostic mask although every capture (oracle `what19` on eight gateways, physical MH200) carries exactly 24 bits and the docstring said so: `*#1001*74*11*1##` reported "mask is 1 (cleared bits: none)". The mask now requires a single 24-character 0/1 value; other DIMENSION 11 value frames keep `diagnostic_mask` None. The log line computes the cleared bits directly (the `or ()` fallback could never trigger). Tests: the negative-shape test returned before asserting on three of its five frames and skipped the mask assertions for the request shape; it now asserts the exact parsed class per frame (eight frames incl. 1, 23 and 26 bit strings and a 24-character non-bit string), the two malformed frames are pinned as not parsing at all, and the status-request test asserts it is an `OWNCommand`, not a diagnostic event. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Self-correction in c42dc2f (no review asked for it). @GreenGrassBlueOcean could you confirm the reading, or say if you see it differently? Context. How it was found. Reading the decoder against the base-class contract instead of its own tests: the mask check was Live check (F461 2.0.11, 2026-10-26 16:45 UTC). A dimension 11 read on a healthy light, What changed. The mask requires a single 24-character 0/1 value (other DIMENSION 11 value frames keep |
Requested by A
Summary
*#1001*74*11*111110111111111111110111##is the actuator autodiagnostic frame the oracle gateways push together with*1*19*74##when a status request (*#1*74##) reaches the emulated faulty actuator (and the physical MH200 capture behind that finding); the same dimension is also answered on request (*#1001*WHERE*11##) by the lights read on the live F461 and MyHomeServer1 (see Hardware Verification). OWNd returned a genericOWNEventwithwho == 1001, so nothing exposed the mask. The bit meanings are marked Open in the oracle, so this PR exposes the mask as sent and interprets nothing. Split out of #139.Changes
OWNd/message/lighting.py:OWNLightingDiagnosticEvent(anOWNEventsubclass, registered for WHO 1001, exported fromOWNd.message) exposesdiagnostic_maskas sent andcleared_bits(1-based from the left;(6, 21)for the oracle mask,()when every bit is set). Only the single-value bit-string shape is decoded:*#1001*74*11*101*5##(a trailing value) fails closed withdiagnostic_mask is None(the first version of this PR would have reported "101"). Other WHO 1001 shapes (*#1001*74##, dimension 12) havediagnostic_mask is None. MyHOME'sdevice_health.pyreadswho/dimension/dimension_valueon the event and is unaffected.scripts/sync_documentation.py+README.md: the WHO catalog row for Lighting now reads**1** / **1001**with the diagnostic class listed (python scripts/sync_documentation.py --update).CHANGELOG.md: entry under[Unreleased]/Added.State Diagram
stateDiagram-v2 direction TB state "1. Gateway on *#1*74## to a faulty actuator (oracle what19; physical MH200 capture)" as Bus { [*] --> Request Request --> Fault : *1*19*74## then *#1001*74*11*<24-bit mask>##\nF453, F453AV, F459, F460, F461, MH200N, MyHomeServer1 Request --> MaskOnly : *#1001*74*11*<mask>## only , MH202 Request --> What19Only : *1*19*74## only , F454, H4684, MH200 Request --> Refused : nack / silent , F450 } state "2. OWNMessage.parse of the WHO 1001 frame" as Parse { [*] --> Who1001 Who1001 --> Diagnostic : *#1001*74*11*<bits>## , one value, all 0/1\nOWNLightingDiagnosticEvent, diagnostic_mask as sent, cleared_bits , 6, 21\n, before - generic OWNEvent, nothing exposed Who1001 --> NoMask : *#1001*74*11*101*5##, *#1001*74*12*5##\nOWNLightingDiagnosticEvent, diagnostic_mask None , fail closed }Where are the traces
findings/MH200N/what19.md, physical captureEVID-MH200-WHAT19-FAULT(agreewith the emulated output; bits 6 and 21 left Open)*1*19*WHERE##+*#1001*WHERE*11*<mask>##OpenWebNet-HA/MyHOME#799(merged),f461_live_2026-10-23run 1*#1001*74##NACK (no WHO 1001 device on this plant)*#1001*06*11##->*#1001*06*11*111111111111111101101111##(ACK 120 ms), same for 07; group*#1001*0*11##NACK after 3.0 s but*#1001*05*11*…##,06,07,09and*#1013*257*11*111111111111111111111111##arrive on the event session*#1001*0014*11##and*#1001*0010*11##-> same mask111111111111111101101111(ACK 139 / 157 ms); group*#1001*0*11##ACK after 3.7 s with*#1001*0*11*111111111111111101101111##on the command session, about 80 per-device masks and*#1013*256*11*…##on the event sessionWhat does the Oracle say
Suite
what19,results/<P>/<V>/oracle/full/what19.tsv, input*#1*74##:010100, F453AV030014, F459020105, F460020012, F461020011, MH200N010108, MyHomeServer1028206ack/out*1*19*74##then*#1001*74*11*111110111111111111110111##010024ack/out*#1001*74*11*111110111111111111110111##only020051, H4684020054, MH200020102ack/out*1*19*74##only020010nack/silentfindings/MH200N/what19.mdstates that the gateway "only translates the bitmask verbatim" and leaves the meaning of bits 6 and 21 Open; this PR exposes the mask and interprets nothing. (The findings page's fleet list omits F453 and MH202; the TSV rows above include them.)Testing
tests/test_who1001_diagnostic_event.py(new, 13 cases): the oracle mask parses asOWNLightingDiagnosticEvent/OWNEventwithwhere == "74",dimension == 11, the mask kept,cleared_bits == (6, 21)and the log line; an all-ones mask gives(); eight other shapes assert the exact parsed class and no mask (trailing value, dimension 12, 1-, 23- and 26-bit strings, 24 characters with a non-bit, the bare dimension 11 request and*#1001*74##as plainOWNCommand); two malformed frames (#inside the value, non-digits) do not parse at all;*#1001*74##is asserted not to be a diagnostic event. (Revision c42dc2f: the mask must be exactly 24 bits, as every capture is and the docstring said; the first revision took any non-empty 0/1 string, and the negative-shape test returned before asserting on three of its frames.)masterthe module fails at collection (OWNLightingDiagnosticEventdoes not exist; with that import removed the WHO 1001 frame is a plainOWNEvent); on this branch all 8 pass.1920 passed, 1 skipped; 100 % statement coverage,mypyclean,ruffclean,scripts/sync_documentation.py --check(README regenerated in this PR) andscripts/verify_library_standards.pypass.Live retest (2026-10-24)
Exercised live on 2026-10-24 (table above): dimension 11 is also a readable per-device dimension: the two lights read on each plant answered on request, and the group request made every light that answered (05 / 06 / 07 / 09 on the F461, about 80 WHEREs on the MyHomeServer1) report the same mask
111111111111111101101111(bits 17 and 20 cleared, counted from the left); this head parses every one of those captured frames asOWNLightingDiagnosticEventwithcleared_bits == (17, 20), while*#1013*25x*11*…##staysOWNGatewayDiagnosticEvent. Inference, unverified: that mask is the healthy pattern of these firmware generations and the oracle's111110111111111111110111(bits 6 and 21) the fault pattern; the bit meanings stay open and the decoder interprets nothing. No faulty actuator was available, so the push path (*1*19*WHERE##followed by the mask) rests on the oracle rows only. The MyHomeServer1 group reply withwhere == "0"is worth a test case; I will add it if you want it in this PR.Companion
None. Split from #139 (WHO 13 dimension 27 model name).
🤖 Generated with Claude Code