Claude can explain it best.
Driver for the Zigbee Danalock V3-BTZB / V3-BTZBE, fixing the inverted lock state reported by Hubitat's built-in generic Zigbee lock driver.
Hubitat ships a purpose-built driver for the Z-Wave Danalock V3, but none for the Zigbee model, so a Zigbee Danalock falls back to Generic Zigbee Lock (no keypad) - and that driver decodes the Door Lock cluster's Operating Event Notification backwards. Every manual turn of the thumbturn is reported as its opposite.
Symptoms
- Turning the lock by hand reports the wrong state, consistently and immediately
- Pressing Refresh always reports the correct state
- A rule that refreshes the lock when its state changes appears to work, then silently stops catching turns
That last one is the confusing part, and it is not a rule problem. Refreshing corrects the state, which means the next (inverted) report matches what the hub already believes, so nothing changes, so a change-triggered rule never fires. The workaround can only ever catch every other turn.
Why it happens
Captured on the hub's live log, locking the door by hand:
raw:catchall: ... clusterId:0101, command:20,
data:[02, 01, FF, FF, 00, 13, B5, 13, 32, 00]
-> generic driver: "was unlocked [physical]"
Byte 0 is the Operation Event Source (0x02, Manual) and byte 1 is the Operation Event Code, where ZCL defines 0x01 as Lock and 0x02 as Unlock. The frame says Lock, one millisecond after the bolt was thrown, and it is correct. Only the driver's reading of it is wrong.
The same driver handles the LockState attribute correctly - a Refresh reads attribute 0x0000, sees 0x01, and reports locked - which is why refreshing always told the truth while the automatic reports never did. One driver, two mappings, one of them inverted.
This is also why the bug isn't notorious. Most Zigbee locks report state by sending LockState attribute reports, which the generic driver reads correctly. Only a lock that reports via Operating Event Notifications reaches the broken path. The Danalock does.
It is worth being explicit that this is not a lag or a queueing problem, which is the natural first theory. Alternating tests cannot tell "reports the previous transition" apart from "reports the opposite of this transition", because on a device that only alternates those produce the identical string. The raw frame is the only thing that separates them, and it clears the device entirely - the lock reports instantly and accurately.
Available Here: GitHub - jlslate/Hubitat-Danalock-Zigbee: Hubitat driver for the Zigbee Danalock V3-BTZB/V3-BTZBE, fixing the inverted lock state reported by the built-in generic Zigbee lock driver. · GitHub
Also on HPM.