FutureTense / keymaster

Home Assistant integration for managing Z-Wave enabled locks
MIT License
239 stars 44 forks source link

[Feature Request] ZHA Support #163

Open firstof9 opened 3 years ago

firstof9 commented 3 years ago

Is your feature request related to a problem? Please describe. Add ZHA user code management support.

Describe the solution you'd like Add ZHA user code management support.

Describe alternatives you've considered n/a

Additional context Reference: https://www.home-assistant.io/integrations/zha/#service-zhaclear_lock_user_code

flyize commented 3 years ago

This would be so awesome.

firstof9 commented 3 years ago

Not 100% sure we can pull the codes from the locks tho.

flyize commented 3 years ago

I've no real idea exactly what this means, but apparently 'we' can.

https://community.home-assistant.io/t/zha-user-code-management-on-zigbee-door-locks/225594/19

firstof9 commented 3 years ago

Yes I dug into the code and it's possible to get codes as well as set them. Hopefully Jesse will drop a PR for it soon 👍

willheineman commented 3 years ago

So excited to see this happen. I've been using the developer setting / services to set and enable ZHA codes since the feature was added.

arsenicks commented 3 years ago

Need any help for testing or other info on this ?

firstof9 commented 3 years ago

I think RL caught up with Jesse, stay tuned.

unnamedjk commented 3 years ago

Is there anything i can get started on for this? Could really use it for my project at the house.

firstof9 commented 3 years ago

Feel free to clone the repo and submit a PR. I don't have any zigbee infrastructure/devices.

unnamedjk commented 3 years ago

Feel free to clone the repo and submit a PR. I don't have any zigbee infrastructure/devices.

I will take a look and see what i can do, thanks!

Stupco commented 3 years ago

Keeping an eye on this, as current ZHA lock management is pretty rudimentary.

adamkoch commented 2 years ago

Feel free to clone the repo and submit a PR. I don't have any zigbee infrastructure/devices.

@firstof9 Would asking the community to donate $$ to get you a zigbee lock help?

Alternatively would it be possible for you to give a bit of detail on where to start in terms of looking to add ZHA support in the code? (which files, how it would integrate with what already exists for z-wave).

Thanks!

firstof9 commented 2 years ago

If I can grab the _doorlock_channel from the ZhaDoorLock class for the device, we can get this done rather easy.

@raman325 if you have an idea how we could pull that off for the coordinator, we'd just need away to detect if the lock entity that's passed in is part of the zha integration, thoughts?

thinking something like:

@callback
def async_using_zha(
    lock: KeymasterLock = None, entity_id: str = None, ent_reg: EntityRegistry = None
) -> bool:
    """Returns whether the zha integration is configured."""
    return zha_supported and _async_using(
        ZHA_DOMAIN, lock, entity_id, ent_reg
    )
firstof9 commented 2 years ago

@adamkoch I have a branch setup if you'd like to give some really alpha code a shot... https://github.com/firstof9/keymaster/tree/zha-support

flyize commented 2 years ago

I'd love to help test as well, but have no idea how to install this branch, which I suppose means I wouldn't be much help.

firstof9 commented 2 years ago

Same as any manual download of a custom component 😉

flyize commented 2 years ago

Oh! Of course. Duh

adamkoch commented 2 years ago

Amazing, thanks @firstof9 🙇 I am yet to add my zigbee lock to HA but am planning to do it soon and will give the alpha a go then.

evanmoses-okta commented 2 years ago

I gave it a shot. Home Assistant 2021.11.3 The lock is a Yale Assure lock with the Zigbee module. Works fine to lock/unlock it.

So far: I tried to read lock codes and set a code. Not working. The code slots entities all show "unavailable". Here's what I see in the logs:

home-assistant   | 2021-12-10 15:49:45 ERROR (MainThread) [homeassistant.components.binary_sensor] Error while setting up keymaster platform for binary_sensor
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 249, in _async_setup_platform
home-assistant   |     await asyncio.shield(task)
home-assistant   |   File "/config/custom_components/keymaster/binary_sensor.py", line 89, in async_setup_entry
home-assistant   |     elif async_using_zha(lock=primary_lock):
home-assistant   |   File "/config/custom_components/keymaster/helpers.py", line 158, in async_using_zha
home-assistant   |     return zha_supported and _async_using(ZHA_DOMAIN, lock, entity_id, ent_reg)
home-assistant   | NameError: name 'zha_supported' is not defined
home-assistant   | 2021-12-10 15:49:45 ERROR (MainThread) [custom_components.keymaster] Error fetching keymaster data:
home-assistant   | 2021-12-10 15:49:46 WARNING (MainThread) [homeassistant.helpers.service] Unable to find referenced entities timer.keymaster_ground_floor_autolock

And when I tried to set a code, I saw

home-assistant   | 2021-12-10 15:58:51 ERROR (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Error executing script. Unexpected error for call_service at pos 1: name 'zha_supported' is not defined
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 371, in _async_step
home-assistant   |     await getattr(self, handler)()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 571, in _async_call_service_step
home-assistant   |     await service_task
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1495, in async_call
home-assistant   |     task.result()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1530, in _execute_service
home-assistant   |     await handler.job.target(service_call)
home-assistant   |   File "/config/custom_components/keymaster/__init__.py", line 232, in _add_code
home-assistant   |     await add_code(hass, entity_id, code_slot, usercode)
home-assistant   |   File "/config/custom_components/keymaster/services.py", line 170, in add_code
home-assistant   |     elif async_using_zha(entity_id=entity_id, ent_reg=async_get_entity_registry(hass)):
home-assistant   |   File "/config/custom_components/keymaster/helpers.py", line 158, in async_using_zha
home-assistant   |     return zha_supported and _async_using(ZHA_DOMAIN, lock, entity_id, ent_reg)
home-assistant   | NameError: name 'zha_supported' is not defined
home-assistant   | 2021-12-10 15:58:51 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [2769624032] Error handling message: Unknown error
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 26, in _handle_async_response
home-assistant   |     await func(hass, connection, msg)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 523, in handle_execute_script
home-assistant   |     await script_obj.async_run(msg.get("variables"), context=context)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1243, in async_run
home-assistant   |     await asyncio.shield(run.async_run())
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 353, in async_run
home-assistant   |     await self._async_step(log_exceptions=False)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 371, in _async_step
home-assistant   |     await getattr(self, handler)()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 571, in _async_call_service_step
home-assistant   |     await service_task
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1495, in async_call
home-assistant   |     task.result()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1530, in _execute_service
home-assistant   |     await handler.job.target(service_call)
home-assistant   |   File "/config/custom_components/keymaster/__init__.py", line 232, in _add_code
home-assistant   |     await add_code(hass, entity_id, code_slot, usercode)
home-assistant   |   File "/config/custom_components/keymaster/services.py", line 170, in add_code
home-assistant   |     elif async_using_zha(entity_id=entity_id, ent_reg=async_get_entity_registry(hass)):
home-assistant   |   File "/config/custom_components/keymaster/helpers.py", line 158, in async_using_zha
home-assistant   |     return zha_supported and _async_using(ZHA_DOMAIN, lock, entity_id, ent_reg)
home-assistant   | NameError: name 'zha_supported' is not defined
emoses commented 2 years ago

Sorry, I had my work clothes on, please reply to this user rather than evanmoses-okta, above. And to clarify this is testing @firstof9 's zha-support branch.

emoses commented 2 years ago

Update, I fixed that error by adding zha_supported = True further up in helpers.py. Now I get

Logger: homeassistant.components.binary_sensor
Source: custom_components/keymaster/binary_sensor.py:179
Integration: Binary sensor (documentation, issues)
First occurred: 4:14:13 PM (1 occurrences)
Last logged: 4:14:13 PM

keymaster: Error on device update!
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 431, in _async_add_entity
    await entity.async_device_update(warning=False)
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 651, in async_device_update
    await task
  File "/config/custom_components/keymaster/binary_sensor.py", line 179, in async_update
    network_ready = self.primary_lock.lock_entity_id.available
AttributeError: 'str' object has no attribute 'available'

And if I try to call the refresh_codes service:

home-assistant   | 2021-12-10 16:16:23 ERROR (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Error executing script. Unexpected error for call_service at pos 1: name 'SERVICE_SET_LOCK_USER_CODE' is not defined
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 371, in _async_step
home-assistant   |     await getattr(self, handler)()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 571, in _async_call_service_step
home-assistant   |     await service_task
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1495, in async_call
home-assistant   |     task.result()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1530, in _execute_service
home-assistant   |     await handler.job.target(service_call)
home-assistant   |   File "/config/custom_components/keymaster/__init__.py", line 232, in _add_code
home-assistant   |     await add_code(hass, entity_id, code_slot, usercode)
home-assistant   |   File "/config/custom_components/keymaster/services.py", line 172, in add_code
home-assistant   |     await call_service(hass, ZHA_DOMAIN, SERVICE_SET_LOCK_USER_CODE, servicedata)
home-assistant   | NameError: name 'SERVICE_SET_LOCK_USER_CODE' is not defined
home-assistant   | 2021-12-10 16:16:23 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [2881742880] Error handling message: Unknown error
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 26, in _handle_async_response
home-assistant   |     await func(hass, connection, msg)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 523, in handle_execute_script
home-assistant   |     await script_obj.async_run(msg.get("variables"), context=context)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1243, in async_run
home-assistant   |     await asyncio.shield(run.async_run())
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 353, in async_run
home-assistant   |     await self._async_step(log_exceptions=False)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 371, in _async_step
home-assistant   |     await getattr(self, handler)()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 571, in _async_call_service_step
home-assistant   |     await service_task
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1495, in async_call
home-assistant   |     task.result()
home-assistant   |   File "/usr/src/homeassistant/homeassistant/core.py", line 1530, in _execute_service
home-assistant   |     await handler.job.target(service_call)
home-assistant   |   File "/config/custom_components/keymaster/__init__.py", line 232, in _add_code
home-assistant   |     await add_code(hass, entity_id, code_slot, usercode)
home-assistant   |   File "/config/custom_components/keymaster/services.py", line 172, in add_code
home-assistant   |     await call_service(hass, ZHA_DOMAIN, SERVICE_SET_LOCK_USER_CODE, servicedata)
home-assistant   | NameError: name 'SERVICE_SET_LOCK_USER_CODE' is not defined
home-assistant   | 2021-12-10 16:14:13 ERROR (MainThread) [homeassistant.components.binary_sensor] keymaster: Error on device update!
home-assistant   | Traceback (most recent call last):
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 431, in _async_add_entity
home-assistant   |     await entity.async_device_update(warning=False)
home-assistant   |   File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 651, in async_device_update
home-assistant   |     await task
home-assistant   |   File "/config/custom_components/keymaster/binary_sensor.py", line 179, in async_update
home-assistant   |     network_ready = self.primary_lock.lock_entity_id.available
home-assistant   | AttributeError: 'str' object has no attribute 'available'
home-assistant   | 2021-12-10 16:14:13 ERROR (MainThread) [custom_components.keymaster] Error fetching keymaster data:
firstof9 commented 2 years ago

I've made some changes based on your error messages, please try the updated files, I've also set the ZHA network sensor to always be on, for testing purposes.

emoses commented 2 years ago

Some progress. Now there's a periodic error (every 5s):

This error originated from a custom integration.

Logger: custom_components.keymaster
Source: custom_components/keymaster/__init__.py:665
Integration: keymaster (documentation, issues)
First occurred: 7:51:04 PM (48 occurrences)
Last logged: 7:55:05 PM

Unexpected error fetching keymaster data: 'KeymasterLock' object has no attribute 'cluster_channels'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/config/custom_components/keymaster/__init__.py", line 610, in async_update_usercodes
    return await self._async_update()
  File "/config/custom_components/keymaster/__init__.py", line 665, in _async_update
    doorlock_channel = self._primary_lock.cluster_channels.get(CHANNEL_DOORLOCK)
AttributeError: 'KeymasterLock' object has no attribute 'cluster_channels'

When I tried to set a user code I saw

Logger: homeassistant.components.websocket_api.http.connection
Source: components/websocket_api/connection.py:134
Integration: Home Assistant WebSocket API (documentation, issues)
First occurred: 7:54:40 PM (1 occurrences)
Last logged: 7:54:40 PM

[2871094792] Error handling message: extra keys not allowed @ data['usercode']. Got None required key not provided @ data['user_code']. Got None

The code slots still show unavailable, although calling refresh_codes appears to complete successfully.

flyize commented 2 years ago

FWIW, my Kwikset 913 doesn't show up as a possible lock when I try to add the integration.

firstof9 commented 2 years ago

That sounds like the ZHA integration isn't placing your lock in the lock domain

flyize commented 2 years ago

Where would I find that? This is what the device looks like in ZHA.

image

firstof9 commented 2 years ago

Click on the lock there, it's entity_id should be something like lock.front_door_lock

flyize commented 2 years ago

Yep. It shows lock.

image

firstof9 commented 2 years ago

It should be showing up, the lock domain is part of core and not dependent on a specific integration.

flyize commented 2 years ago

So, as you alluded to, that was user error. I was able to get everything added but adding/deleting PINs isn't working. I followed the instructions to enable debug logging, but this is the only error I see.

Logger: frontend.js.latest.202112120
Source: components/system_log/__init__.py:189
First occurred: 9:36:16 AM (1 occurrences)
Last logged: 9:36:16 AM

http://homeassistant.local:8123/lovelace-room/keypad-front_door:0:0 Uncaught

edit: I lied, this one popped up too

This error originated from a custom integration.

Logger: custom_components.keymaster.binary_sensor
Source: custom_components/keymaster/binary_sensor.py:88
Integration: keymaster (documentation, issues)
First occurred: 9:36:30 AM (6 occurrences)
Last logged: 9:48:30 AM

Z-Wave integration not found
firstof9 commented 2 years ago

Double check to make sure you grabbed the zha-support branch.

firstof9 commented 2 years ago

I don't expect it to work out of the box, and very unlikely to manage your codes just yet.

flyize commented 2 years ago

I'm so sorry. I hope we can soon get past this period of user errors. I understand that it might not work, but I'm super excited that it eventually will. New error:

This error originated from a custom integration.

Logger: custom_components.keymaster
Source: custom_components/keymaster/__init__.py:665
Integration: keymaster (documentation, issues)
First occurred: 10:18:13 AM (2 occurrences)
Last logged: 10:18:18 AM

Unexpected error fetching keymaster data: 'KeymasterLock' object has no attribute 'cluster_channels'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/config/custom_components/keymaster/__init__.py", line 610, in async_update_usercodes
    return await self._async_update()
  File "/config/custom_components/keymaster/__init__.py", line 665, in _async_update
    doorlock_channel = self._primary_lock.cluster_channels.get(CHANNEL_DOORLOCK)
AttributeError: 'KeymasterLock' object has no attribute 'cluster_channels'
firstof9 commented 2 years ago

Yup that's the error I'm stuck at right now, once we can get past that, we should be golden.

arsenicks commented 2 years ago

I know this isn't even finished yet but do you think it would take a good amount of effort making it work for zigbee2mqtt after zha support is functionnal ?

firstof9 commented 2 years ago

It depends, mqtt doesn't have any service calls we can utilize as easily as zwavejs and zha.

arsenicks commented 2 years ago

Can't argue with that I'm no so knowledgable on the fact but I had the impression the only thing required would be to publish on the specific topic. Ex. Can be set by publishing to zigbee2mqtt/FRIENDLY_NAME/set with payload {"pin_code": {"user": VALUE, "user_type": VALUE, "user_enabled": VALUE, "pin_code": VALUE}}

src: https://www.zigbee2mqtt.io/devices/BE468.html

I don't want to hiijack the thread, might come back with a new feature req once zha is done :)

flyize commented 2 years ago

What's the easiest way to remove this test integration? I know I can delete the folder, but specifically the automations?

firstof9 commented 2 years ago

1) Remove the integration from Configuration -> Integrations 2) Verify the directory was cleaned up in packages (it should auto delete all the generated YAML when you remove the integration)

flyize commented 2 years ago

Strange. That's what I did, but I still have a ton of (orphaned) automations. No worries, I'll just remove em all one by one.

firstof9 commented 2 years ago

Once the files are removed from packages you should be able to reload the automation and the orphans disappear

flyize commented 2 years ago

Packages was empty, and I restarted HA, but they were still there. I just manually deleted them. ;)

firstof9 commented 2 years ago

@flyize I just pushed an update to the zha-support branch, it no longer appears to be getting an error, can you confirm this for me?

Thanks.

flyize commented 2 years ago

Now I have this:

This error originated from a custom integration.

Logger: custom_components.keymaster
Source: custom_components/keymaster/__init__.py:672
Integration: keymaster (documentation, issues)
First occurred: 1:28:17 PM (6 occurrences)
Last logged: 1:28:42 PM

Unexpected error fetching keymaster data: 'str' object has no attribute 'cluster_channels'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/config/custom_components/keymaster/__init__.py", line 616, in async_update_usercodes
    return await self._async_update()
  File "/config/custom_components/keymaster/__init__.py", line 672, in _async_update
    doorlock_channel = lock_entity.cluster_channels.get(CHANNEL_DOORLOCK)
AttributeError: 'str' object has no attribute 'cluster_channels'
firstof9 commented 2 years ago

Thanks for checking.

firstof9 commented 2 years ago

I've made another push, if anyone's game. Please enable debug logging as I did add an extra message specifically for ZHA.

flyize commented 2 years ago

To update do I just overwrite the custom component and restart?

firstof9 commented 2 years ago

Correct.

flyize commented 2 years ago

I updated this, but the error seems the same?

This error originated from a custom integration.

Logger: custom_components.keymaster
Source: custom_components/keymaster/__init__.py:672
Integration: keymaster (documentation, issues)
First occurred: 4:09:12 PM (16 occurrences)
Last logged: 4:10:27 PM

Unexpected error fetching keymaster data: 'str' object has no attribute 'cluster_channels'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 187, in _async_refresh
    self.data = await self._async_update_data()
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 147, in _async_update_data
    return await self.update_method()
  File "/config/custom_components/keymaster/__init__.py", line 616, in async_update_usercodes
    return await self._async_update()
  File "/config/custom_components/keymaster/__init__.py", line 672, in _async_update
    doorlock_channel = lock_entity.cluster_channels.get(CHANNEL_DOORLOCK)
AttributeError: 'str' object has no attribute 'cluster_channels'
firstof9 commented 2 years ago

Could you enable debugging for the integration, you should get an output stating something like ZHA Devices: <data>?