Skip to content

fix(lighting): WHAT 39 is the end of movement of a WHO 1 motion detector - #135

Merged
GreenGrassBlueOcean merged 5 commits into
masterfrom
fix/lighting-what-39-motion-end
Oct 23, 2026
Merged

GreenGrassBlueOcean merged 5 commits into
masterfrom
fix/lighting-what-39-motion-end

Conversation

@GreenGrassBlueOcean

@GreenGrassBlueOcean GreenGrassBlueOcean commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What is the problem

In OpenWebNet-HA/MyHOME#777, @eC0y0te reported a Legrand 067226 Céliane BUS motion/luminosity detector (no relay) configured at A=5, PL=2 (WHERE=52) to drive a BTicino F411 channel at the same address, behind a BTicino F454 gateway (firmware 2.0.51).

  1. The detector reports two presence states on its address:
    • *1*34*52##: movement detected. OWNd already parses this as MESSAGE_TYPE_MOTION, motion = True.
    • *1*39*52##: end of movement, sent when the detector's occupancy timer runs out. OWNd did not know WHAT 39. It became unknown_state = 39, with is_on = None and is_sensor = False.
  2. Consequences downstream (MyHOME):
    • A light sharing the detector's address logged light 52 reports unknown lighting WHAT 39; keeping its last state on every occupancy cycle.
    • The motion binary_sensor could not clear on WHAT 39. It waited for its 315 s software timeout instead of the detector's own 45 s.

How is it solved

  1. WHAT 39 is parsed as end of movement (OWNd/message/lighting.py) (@gdluck's patch, authorship kept):
    • *1*39*WHERE## sets:
      • message_type = MESSAGE_TYPE_MOTION
      • motion = False
      • new motion_end = True
      • is_sensor = True
      • is_on = None
      • unknown_state = None
    • Added the OWNLightingEvent.motion_end property.
    • is_on returns None for motion_end, just as it does for motion and is_anomaly.
  2. Backward-compatible shape:
    • WHAT 39 stays MESSAGE_TYPE_MOTION, with motion = False.
    • MyHOME up to v2 b16, and 0.9.x, only act on message_type == motion_detected and message.motion. For them WHAT 39 stays the no-op it was as unknown_state 39.
    • The docstrings of motion, motion_end and is_on say how to tell the cases apart.
  3. Evidence ranked by strength, not asserted:
    • The original patch cited a firmware corpus file that is not in OpenWebNet-HA/own-firmware-oracle.
    • The decode is now reproduced on our emulated gateway firmware (see the oracle section below), and the comments cite that.
  4. CHANGELOG.md: entry under [Unreleased].

How is it tested

  • tests/test_who1_what39_motion_end.py (new):
    • WHAT 39 gives MESSAGE_TYPE_MOTION, motion False, motion_end True, is_sensor True, is_on None, unknown_state None.
    • WHAT 34 is unchanged.
    • The factory parses *1*39*52#4#01## with a bus interface.
    • Plain light frames (*1*0*52##, *1*1*52##, *1*19*52##) are not motion_end.
    • The reporter's cycle *1*39*52## → *1*1000#0*52## → *1*0*52## gives one motion end, then a non-sensor command translation, then the F411 OFF state.
    • Backward-compatible shape: not (message_type == motion_detected and motion).
  • tests/test_message_protocol.py: WHAT 39 is no longer in the unknown-WHAT parametrization (38 replaces it).
  • Full suite:
    • 1907 passed, 1 skipped; mypy OWNd is clean, with 0 issues.
    • ruff check is clean.
  • Companion MyHOME PR (OpenWebNet-HA/MyHOME#781): its #777, light and binary_sensor tests pass against both this branch and the released 2.0.0b11.

State Diagram

stateDiagram-v2
    direction TB

    state "1. OWNLightingEvent parse of *1*WHAT*WHERE##" as Parse {
        [*] --> CheckWhat
        CheckWhat --> LightState : WHAT 0..18, 20..31 (table)\nis_on True/False, is_sensor False
        CheckWhat --> Anomaly : WHAT 19\nis_anomaly True, unknown_state 19, is_on None
        CheckWhat --> Motion : WHAT 34\nmessage_type motion_detected\nmotion True, is_sensor True, is_on None
        CheckWhat --> MotionEnd : WHAT 39 (new)\nmessage_type motion_detected\nmotion False, motion_end True\nis_sensor True, is_on None
        CheckWhat --> Unknown : any other WHAT\nunknown_state WHAT, is_on None
    }

    state "2. Detector occupancy cycle on the bus (F454 + 067226 + F411 at 52)" as Cycle {
        [*] --> Idle
        Idle --> Occupied : *1*34*52##\nthen detector *1*1000#1*52##\nthen F411 *1*1*52##
        Occupied --> Occupied : *1*34*52## repeated while people move
        Occupied --> Idle : ~45 s (DIM 7) after last WHAT 34\n*1*39*52##\nthen *1*1000#0*52##\nthen F411 *1*0*52##
    }

    state "3. Consumer view (MyHOME)" as Consumer {
        [*] --> SensorOff
        SensorOff --> SensorOn : motion True (WHAT 34)
        SensorOn --> SensorOff : motion_end True (WHAT 39)\nor software timeout
        SensorOn --> SensorOn : older consumers ignore WHAT 39\n(motion False) and wait for the timeout
    }
Loading

Where are the traces

Subsystem Real Community Capture Files Contributor & Hardware Plant Captured Wire Frames Verified by This PR
WHO=1 motion detector sharing an actuator address Raw trace in MyHOME#777 (comment), replayed in MyHOME/tests/test_issue_777_light_motion_same_address.py (OpenWebNet-HA/MyHOME#781) @eC0y0te: BTicino F454 (FW 2.0.51), Legrand 067226 detector + BTicino F411 at WHERE 52 Occupancy, 5 cycles: *1*34*52## → *1*1000#1*52## → *1*1*52##; *1*39*52## → *1*1000#0*52## → *1*0*52## (~45 s after the last WHAT 34, within ~90 ms). Detector timeout: *#1*0*7*0*0*45##.
Retest of the MyHOME fix on b16 + OWNd 2.0.0b11 MyHOME#777 (comment) @eC0y0te: same plant WHAT 39 clears the motion sensor immediately, and the F411 *1*0*52## follows ~90 ms later.

What does the Oracle / Encyclopedia say

  1. OpenWebNet Encyclopedia (functional/who-1-lighting/zigbee-variant.md):

    • Status specified: the ZigBee OpenWebNet WHO 1 table defines WHAT 34 "Movement detected" and WHAT 39 "End of movement detected" (ownkb:claim:c001481, c001463, c001464).
    • The SCS-oriented WHO 1 table does not list them, and the KB marks them as ZigBee-specific. This PR adds SCS firmware evidence for both.
    • The same ZigBee use case shows WHAT 32 Toggle at half the detector's time while people are still present. That has not been seen on SCS and is left as is.
  2. Firmware oracle (OpenWebNet-HA/own-firmware-oracle#56 (merged), suite who1-motion-detector (findings), suites run 39967360131):

    • Emulated gateway firmware, harness=full, on all 12 targets, including the reporter's exact gateway and version (F454 2.0.51).
    • Every target ran twice and the two runs were byte-identical, which the workflow requires before it accepts a result.

    Presence decode, up (inbound SCS):

    SCS frame Output Gateways
    B8 52 1D 00 *1*34*52## F453, F453AV, F454, F459, F460, F461, MH200N, MH202, MyHomeServer1
    B8 52 1D 01 *1*39*52## F454, F459, F460, F461, MH200N, MH202, MyHomeServer1
    B8 52 1D 01 no output F453, F453AV, MH200, F450, H4684

    So WHAT 39 reaches a client on the seven current gateways. On F453 / F453AV only WHAT 34 does, and this PR changes nothing for them. MH200 020102 gives *1*32*52## for presence 00; that is recorded in the findings but not interpreted.

    Dimension replies, up (inbound SCS): these are the replies to the detector's own requests. They give context for MyHOME; this PR does not parse them differently.

    SCS frame Output Reporter saw Gateways
    D5 00 21 44 15 00 00 02 *#1*0*5*2## same F454, F459, F460, F461, MH200N, MH202, MyHomeServer1
    D5 00 21 44 10 00 00 00 *#1*0*6*0## same same seven
    D5 00 21 44 16 00 00 2D *#1*0*7*0*0*45## same same seven
    D1 52 01 44 {15,10,16} … *#1*52*{5,6,7}*…## the seven + F453, F453AV

    Only frames whose address byte is 00 give the reporter's *#1*0*…##; the same replies carrying 52 come out with 52. So the WHERE 0 is on the bus, not added by the gateway.

    Requests, down: *#1*52*7## goes on the bus as D1 52 01 43 16 00 00 00, and *#1*52*5## / *#1*52*6## the same way with 15 / 10 in place of 16.


🤖 Generated with Claude Code

gdluck and others added 2 commits October 23, 2026 15:00
A WHO 1 motion detector (Legrand 067226, BTicino 048834) reports *1*34*WHERE##
when it detects movement and *1*39*WHERE## when its occupancy timer runs out.
The F461 bt_luci translator decodes the SCS presence status frame (class 0x1D)
value 00 as WHAT 34 and value 01 as WHAT 39 (oracle2/hex2own_corpus.tsv rows
B8311D00 / B8311D01). OWNd only knew WHAT 34, so WHAT 39 was an unknown
lighting WHAT and a light sharing the sensor's address logged a warning on
every end of movement (OpenWebNet-HA/MyHOME#777).

WHAT 39 now sets message_type motion_detected with motion False, a new
motion_end property, is_sensor True and is_on None.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Audit follow-up to the WHAT 39 commit:
- Evidence is now stated by strength: specified in the ZigBee OpenWebNet
  WHO 1 table, observed on SCS in the MyHOME#777 F454 + Legrand 067226
  trace, and the 0x1D translator reading marked as reported (it is not in
  the OpenWebNet-HA firmware oracle).
- motion / motion_end / is_on docstrings say how WHAT 39 surfaces, and why
  it stays MESSAGE_TYPE_MOTION with motion False (consumers that act on
  motion is True keep ignoring it).
- Tests for the reporter's 39 / 1000#0 / 0 sequence and for that
  backward-compatible shape; CHANGELOG entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

The SCS presence status decode is now reproduced on emulated F454 2.0.51
and F461 2.0.11 firmware (own-firmware-oracle suite who1-motion-detector):
B8 52 1D 00 -> *1*34*52##, B8 52 1D 01 -> *1*39*52##. The test docstring
and the parser comment no longer call it "reported, not reproduced".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
own-firmware-oracle#56 (suites run 39967360131) replayed the presence
status frames on all 12 emulated gateways: B8 52 1D 00 / 01 give
*1*34*52## / *1*39*52## on F454, F459, F460, F461, MH200N, MH202 and
MyHomeServer1; F453 / F453AV give WHAT 34 only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@fedem95 fedem95 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WHAT 39 motion-end handling is clearly distinguished from motion detection and lighting states, with focused regression coverage and supporting trace evidence. All checks are passing. Approved.

@GreenGrassBlueOcean
GreenGrassBlueOcean merged commit f04d8aa into master Oct 23, 2026
16 checks passed
@GreenGrassBlueOcean
GreenGrassBlueOcean deleted the fix/lighting-what-39-motion-end branch October 23, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants