Zha lock (I have a Yale)

Anybody can point me to how to get a yale lock up and working in zha? I feel like it needs a lock.py file that looks a lot like this: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/zha/switch.py
Basically I’m not finding much documents to give me a good mental model as to how the zha components work from an architecture point of view.

I just got this working yesterday, but there are still a couple things to sort out.

https://github.com/presslab-us/home-assistant/tree/zha-implement-closure

That code works, but I do see two problems. I’m not sure if they are problems with my implementation or something that needs to be changed in zigpy.

The first is shown below:

2019-05-17 10:06:20 DEBUG (MainThread) [bellows.uart] Data frame: b'2162b157546f15b658954b24ab1593499c69941a4dc49874fadeae83fc7e0fa6f0da7e'
2019-05-17 10:06:20 DEBUG (MainThread) [bellows.uart] Sending: b'83401b7e'
2019-05-17 10:06:20 DEBUG (MainThread) [bellows.ezsp] Application frame 69 (incomingMessageHandler) received
2019-05-17 10:06:20 DEBUG (MainThread) [zigpy.zcl] [0x0aa0:1:0x0101] ZCL request 0x000a: [[<Attribute attrid=0 value=<TypeValue type=enum8, value=1>>]]
2019-05-17 10:06:20 DEBUG (MainThread) [zigpy.zcl] [0x0aa0:1:0x0101] Attribute report received: lock_state=1
2019-05-17 10:06:20 DEBUG (MainThread) [custom_components.zha.core.channels.closures] 0x0aa0:1:0x0101: Attribute report 'Door Lock'[lock_state] = 1
2019-05-17 10:06:22 DEBUG (MainThread) [bellows.ezsp] Send command nop
2019-05-17 10:06:22 DEBUG (MainThread) [bellows.uart] Sending: b'7d33632157542fa0287e'
2019-05-17 10:06:22 DEBUG (MainThread) [bellows.uart] Data frame: b'3263a157542f0db87e'
2019-05-17 10:06:22 DEBUG (MainThread) [bellows.uart] Sending: b'8430fc7e'
2019-05-17 10:06:22 DEBUG (MainThread) [bellows.ezsp] Application frame 5 (nop) received
2019-05-17 10:06:25 DEBUG (MainThread) [bellows.uart] Data frame: b'4263b157546f15b658954b24ab1593499c669e1a4dc49874f0dfada9fe70c058ebee9a1eabfffa097e'
2019-05-17 10:06:25 DEBUG (MainThread) [bellows.uart] Sending: b'8520dd7e'
2019-05-17 10:06:25 DEBUG (MainThread) [bellows.ezsp] Application frame 69 (incomingMessageHandler) received
2019-05-17 10:06:25 WARNING (MainThread) [zigpy.zcl] Data remains after deserializing ZCL frame
2019-05-17 10:06:25 DEBUG (MainThread) [zigpy.zcl] [0x0aa0:1:0x0101] ZCL request 0x0120: []
2019-05-17 10:06:25 DEBUG (MainThread) [zigpy.zcl] [0x0aa0:1:0x0101] No handler for cluster command 32

I’m not sure what causes the “Data remains after deserializing ZCL frame”.

There other is here, seems like the result value from zigpy is not handled right?

2019-05-17 10:13:53 DEBUG (MainThread) [custom_components.zha.core.channels] 0x0aa0:1:0x0101: executed command: lock_door with args: () with kwargs: {} and result: []
2019-05-17 10:13:53 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.140524889446720] list index out of range
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/homeassistant/components/websocket_api/commands.py", line 121, in handle_call_service
connection.context(msg))
  File "/usr/local/lib/python3.7/site-packages/homeassistant/core.py", line 1138, in async_call
self._execute_service(handler, service_call))
  File "/usr/local/lib/python3.7/site-packages/homeassistant/core.py", line 1160, in _execute_service
await handler.func(service_call)
  File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/entity_component.py", line 194, in handle_service
required_features
  File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py", line 316, in entity_service_call
future.result()  # pop exception if have
  File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py", line 337, in _handle_service_platform_call
await getattr(entity, func)(**data)
  File "/root/.homeassistant/custom_components/zha/lock.py", line 96, in async_lock
success = await self._doorlock_channel.lock_door()
  File "/root/.homeassistant/custom_components/zha/core/channels/__init__.py", line 63, in wrapper
return result[1] is Status.SUCCESS
IndexError: list index out of range

Maybe @dmulcahey or @Adminiuga have some thoughts?

I can take a peek when I have some time. Tough w/o a device though.

Thanks, any clues would be appreciated. I’m starting to get more familiar with the code and also have a working thermostat implementation now.

I suspect the IndexError: list index out of range error is something to do with my Yale locks. I have a couple different models but they are all Yale. I see this every time I send a command to the device.

Occasionally I also see EmberStatus.DELIVERY_FAILED but the command actually works. I think the timeout may be just a bit too short. I could see that if the end device only wakes up every 5 seconds (which is reasonable as max is 7 seconds), it could take up to 5 seconds to see the command. Maybe it sends the APS ack on the next wakeup making it 10 seconds, not sure. I will check it out with my packet sniffer.

Tried your code with a Danalock V3 zigbee and I get the same results, lock works perfectly except for the errors. The result from the unlock and lock actions are empty arrays [], but I am having a hard time finding out which code actually returns that result.
Thanks for the great work though, I can finally use my Danalock the way I wanted :slight_smile:

Well to get the result (in result[0]) I needed to change zcl/clusters/closures.py in zigpy like so:

0x0000: ('lock_door_response', (foundation.Status, ), True),
0x0001: ('unlock_door_response', (foundation.Status, ), True),
0x0002: ('toggle_door_response', (foundation.Status, ), True),

But for some reason zha/channels/__init__.py is hardcoded to get the result in result[1]. It’s like it’s hardcoded for a foundation “Default response” or something?

Good to hear, and also not surprising that your other model has this same problem. I sniffed the packets and they look just fine, it is an issue with how the result is parsed.

I guess the result array has result[0] as a return value and result[1] as status
Easy fix to get the status in result[1] is:
0x0000: (‘lock_door_response’, (t.enum8,foundation.Status), True),
0x0001: (‘unlock_door_response’, (t.enum8,foundation.Status), True),
0x0002: (‘toggle_door_response’, (t.enum8,foundation.Status), True),
I took the t.enum8 from the lock_state, although I do not think the result is actually used or filled with something interesting. It is always 0 in my case.

These schema values indicate the positions of the data in the return packet. So they cannot be changed, they must match the Zigbee spec. I think the correct solution is to not parse return[] in the generic ‘decorate_command’, but to let each calling method handle it.

With my latest commit there should be no more errors. You’ll need this too:

You’re gonna open a PR right?

Sure. I’ll need to update the manifest with whatever the new version of zigpy is, once that other pull request is merged.

We’ll handle that part when we bump the libs

Thanks! I shot this message out, went on vacation and forgot about it. I’ll give it a shot.

Thanks to the help of @dmulcahey and @Adminiuga this code has been merged. :+1:

@anderwm / @dmulcahey I have the same lock and have been able to get it working (locking and unlocking) - was curious if you are able to use any of the lock.get/set/clear_usercode services?

It seems like they only work for zwave?

Anyone interested in getting a proper integration for Danalock V3 Zigbee, upvote my feature request here:
https://community.home-assistant.io/t/integration-for-danalock-v3-zigbee/179574