Yale Assure lock code management with zigbee2mqtt

I’ve recently installed two Yale Assure locks with Zigbee modules. I was already running zigbee2mqtt and couldn’t find a thorough description of how to use this to set lock codes from the frontend (although there are a few threads on doing the same with ZHA). I’m noting my configuration here in case it helps others, and to invite feedback on any areas where it could be improved.

First to note that several aspects of the lock should appear automatically through zigbee2mqtt once it’s added to the network, including: current state, ability to change state (lock/unlock), the last action, action user, current auto relock time, battery, and sound volume. What is ‘somewhat’ exposed through the zigbee2mqtt interface, but isn’t in the front-end includes setting and enabling user pin codes - it was these aspects that I wanted to pull out and make easy to use from the HA frontend. There is some useful detail on setting and getting these parameters on the zigbee2mqtt page for the lock here.

The first step is to set up mqtt entities in your configuration.yaml file for both the user code (i.e. number) and the code status (i.e. enabled/disabled), for which I use text and switch entities respectively. You can set up as many different users as you like, but I went with the two permanent residents and two extra guest codes (more on those below). I also set them all to be the same device at the automatically set up mqtt device, but unfortunately (although it does group them) it doesn’t appear that you can add them to an existing device.

configuration.yaml additions (duplicate and renumber for more users)
mqtt:  
  text:
    - name: "Lock User 1 Code"
      unique_id: "front_door_lock_user_1_code"
      state_topic: "zigbee2mqtt/Front Door Lock"
      value_template: "{{ value_json['users']['1']['pin_code'] }}"
      mode: 'text'
      min: 4
      max: 8
      pattern: '^[0-9]*$'
      command_topic: "zigbee2mqtt/Front Door Lock/set"
      command_template: '{"pin_code": {"user": "1", "user_type": "unrestricted", "pin_code": "{{ value }}", "user_enabled": {{ "true" if states("switch.front_door_lock_lock_user_1_code_status") == "on" else "false" }} }}' 
      optimistic: false
      qos: 0
      retain: false
      device:
        name: "Front Door Lock"
        identifiers:
          - "lock.front_door_lock"
  switch:
    - name: "Lock User 1 Code Status"
      unique_id: "front_door_lock_user_1_code_status"
      state_topic: "zigbee2mqtt/Front Door Lock"
      value_template: "{{ value_json['users']['1']['status'] }}"
      state_on: "enabled"
      state_off: "disabled"
      command_topic: "zigbee2mqtt/Front Door Lock/set"
      command_template: '{"pin_code": {"user": "1", "user_type": "unrestricted", "pin_code": "{{ states("text.front_door_lock_lock_user_1_code") }}", "user_enabled": {{ value }} }}'
      payload_on: "true"
      payload_off: "false"
      optimistic: false
      qos: 0
      retain: false
      device:
        name: "Front Door Lock"
        identifiers:
          - "lock.front_door_lock"

With this set up, I found that I was able to update the user state of the lock (confirmed via testing the lock, but was not able to see the changed state in HA. In order to read back the state I had to issue a get command on the pin code. To keep things correct in HA I therefore set up an automation to issue the get command every time it sees a pin_code_added message. I also found it was beneficial to add a short delay after the set command was seen to ensure that the lock had updated.

Automation to reread the lock codes after setting
alias: Reread lock codes when set
trigger:
  - platform: mqtt
    topic: zigbee2mqtt/Front Door Lock/action
    payload: pin_code_added
condition: []
action:
  - delay:
      hours: 0
      minutes: 0
      seconds: 15
      milliseconds: 0
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Front Door Lock/get
      payload: "{\"pin_code\": \"\"}"
mode: single

Finally I added the created entities to the frontend using a multiple entity row (added via HACS) within the entities card. This allows changing of the code and enabling/disabling use of the code.

Multiple entity row configuration within frontend
type: entities
entities:
  - entity: switch.front_door_lock_lock_user_1_code_status
    name: User 1 Door Code
    icon: mdi:key-variant
    type: custom:multiple-entity-row
    toggle: true
    state_color: true
    entities:
      - entity: text.front_door_lock_lock_user_1_code
        name: Code

image

Duplication and renumbering of all the above code will allow management of multiple users. A few extensions to these basics that I’ve added include:

Synchronising codes across multiple locks.

We have the same lock on the front and back doors, so it was relatively straightforward to extend the automation to reread the lock codes to also update the back door codes to match the front door. I found it was necessary to introduce a few extra delays into the automation to ensure everything was kept in sync. As previously, duplicate the set command and renumber for however many users you have.

alias: Synchronise locks pin when a message is sent
trigger:
  - platform: mqtt
    topic: zigbee2mqtt/Front Door Lock/action
    payload: pin_code_added
condition: []
action:
  - delay:
      hours: 0
      minutes: 0
      seconds: 15
      milliseconds: 0
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Front Door Lock/get
      payload: "{\"pin_code\": \"\"}"
  - delay:
      hours: 0
      minutes: 0
      seconds: 15
      milliseconds: 0
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Back Door Lock/set
      payload: >-
        {"pin_code": {"user": "1", "user_type": "unrestricted", "pin_code": "{{
        states("text.front_door_lock_lock_user_1_code") }}", "user_enabled": {{
        'true' if states("switch.front_door_lock_lock_user_1_code_status") ==
        "on" else 'false' }} }}
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Back Door Lock/get
      payload: "{\"pin_code\": \"\"}"
mode: single
A single use door code.

I wanted to be able to have codes automatically disable once they’re used. This was pretty straightforward by adding a new automation for this, triggered by use of a specific code on either the front or back doors (in my case I use user 3 for single use codes). I only need to set the front door code as the previous automation syncs the back door.

alias: Clear single-use code when used
trigger:
  - platform: state
    entity_id:
      - sensor.front_door_lock_action_user
    to: "3"
  - platform: state
    entity_id:
      - sensor.back_door_lock_action_user
    to: "3"
condition:
  - condition: or
    conditions:
      - condition: state
        entity_id: sensor.front_door_lock_action_source_name
        state: keypad
      - condition: state
        entity_id: sensor.back_door_lock_action_source_name
        state: keypad
action:
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Front Door Lock/set
      payload: >-
        {"pin_code": {"user": "3", "user_type": "unrestricted", "pin_code": "{{
        states("text.front_door_lock_lock_user_3_code") }}", "user_enabled":
        false }}
mode: single
A 'guest' door code that is only enabled within a time window.

With the switches set up for enable/disable of codes you can set up helper input_datetime entities to enable and disable these via automation as follows. Note that here I’m addressing the entity as a switch, rather than sending the mqtt payload directly as I do for the single use code - both seem to work fine, although this way is probably cleaner.

alias: Disable guest code
trigger:
  - platform: time
    at: input_datetime.guest_code_end
condition: []
action:
  - type: turn_off
    device_id: 5c8e260f49152ae4c4874398e92b2b42
    entity_id: 1789d32c58eea727bfa8096aa358e130
    domain: switch
mode: single
alias: Enable guest code
trigger:
  - platform: time
    at: input_datetime.guest_code_start
condition: []
action:
  - type: turn_on
    device_id: 5c8e260f49152ae4c4874398e92b2b42
    entity_id: 1789d32c58eea727bfa8096aa358e130
    domain: switch
mode: single
The ability to randomly generate codes.

To make life a little easier when updating codes, I added the ability to generate a random number for the single use and guest codes. I did this with the following script - note that I’m not generating numbers below 1000 to ensure that the code has the right quantity of digits, but I suspect that a smarter use of the random code could fix this?

alias: Randomise guest code
sequence:
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Front Door Lock/set
      payload: >-
        {"pin_code": {"user": "4", "user_type": "unrestricted", "pin_code": "{{
        range(1000, 10000) | random }}", "user_enabled": {{ 'true' if
        states("switch.front_door_lock_lock_user_4_code_status") == "on" else
        'false' }} }}

A similar script can be done for other users as necessary, and added to the multiple entity row.

Showing all of the above in an entities card it looks like this:
image

1 Like

Fantastic work @welf !
I managed to set up everything and multiple-etity-row card and will keep tinkering / providing feedback.
So far my comments are:

  • IMPORTANT: automation that fetches the pins back to HA is crucial, as switch relies on it, and without it you wont be able to have user pins in enabled state (setting pin sets it to disabled by default). I have torn my hair for a few hours until I realised that my zigbee2mqtt config for the lock has an Expose PIN setting set to default false - this can be changed in your Zigbee2MQTT dashboard → device page → Settings (specific)
  • waiting for automation(15sec in your script) to fetch the pin back is crucial before switching the toggle, as it will have the stale PIN pushed to the lock
  • may be add a note that onfiguration.yaml is a default global config in root, not zigbee2mqtt/onfiguration.yaml
  • not sure if User 1 will clash with existing users, probably better start with higher number or note it will rewrite these codes? there are total 250 users (0-249 range)
  • configuration.yaml update created another separate “Front Door Lock” entity with User pin/switched. I believe this name is important and the Yale Assure Lock device needs to have the same name “Front Door Lock” . correct me if I am wrong
  • perhaps automation needs to run after HA reboot/config reload too? i.e.:
alias: Reread door lock codes when HA starts
description: ""
triggers:
  - trigger: homeassistant
    event: start
conditions: []
actions:
  - delay:
      hours: 0
      minutes: 0
      seconds: 15
      milliseconds: 0
  - action: mqtt.publish
    metadata: {}
    data:
      topic: zigbee2mqtt/Front Door Lock/get
      payload: "{\"pin_code\": \"\"}"
mode: single
  • curious to get see how do a datepicker in UI.
  • perhaps guest automations only need entity_id:
alias: Disable guest door code
description: ""
triggers:
  - at: input_datetime.guest_code_end
    trigger: time
conditions: []
actions:
  - action: switch.turn_off
    metadata: {}
    data: {}
    target:
      entity_id: switch.front_door_lock_lock_user_4_code_status
mode: single

How do you store the configuration.yaml mqtt section?

I have the section already, but it contains sensor: entries and I tells me that text: is not allowed.

I put these into a package to keep it neat.

In your configuration.yaml make sure there is a line that has

homeassistant:
  packages: !include_dir_named packages

then make sure you hav a folder called packages in your home assistant directory

then you can place all your the code that was above into a sperate yaml file ie lock_codes.yaml

Appreciate the work put in on this! I was able to get it working with my Schlage, however…

Not sure if I’ve missed a step, however toggling the status doesn’t seem to do anything (I only have it setup for user 1, at the moment. Still relying on my Nodered setup to control the rest of the lock). The switch just goes to off, waits a tick, then it’s toggled back at the on position. But there also doesn’t seem to be any coding to tell HA what to do when it’s toggled off.

I am trying to use this for Kwikset 914 with Zigbee but I am confused about the
“configuration.yaml” part. I added the text one but does the switch go under the mqtt part or just in the yaml?

This is nice, but I wonder if it is worth the effort? I have my lock setup with the Bluetooth connected to my AppleTV for HomeKit and Yale App, and Zigbee module to Zigbee2mqtt for Home Assistant. I, for now at least, chose to leave passcode enrollment to the app. It seems a lot easier than dealing with elaborate configuration like this.

Do you find any real advantage to being able to configure passcodes in Home Assistant? I just can imagine when I’d need to do so but not be near the lock itself. And, this would expose configuration of codes to the users of the locks. Seems like it would be bad for least privilege?

I needed to manage my Yale Assure Zigbee locks which are on Zigbee2MQTT and couldn’t find a simple solution that I liked, so I created this custom integration. It provides a visual editor with all the basic functionality I needed. I’m open to extending and improving it if it doesn’t work for you! Try it out.

2 Likes

Nice clean solution Bharat - much prefer this than others I have tried.

I’m running older Yale Assure Keyed Deadbolts which have always had slow response and find I will always get timeouts if using ‘Apply All’, but it seems to work fine when selecting a slot at a time.
Could you add an option in the card config to hide the ‘Apply All’ button as a workaround?

Hey thanks! I’m glad you’re liking it. I just pushed a new version which lets you hide the Apply All (and the Wipe All) buttons. TBH, this is early work and I haven’t yet figured out how to think about that functionality and it’s a little confusing to my wife as well so it’s probably a good idea to let users hide those for now.

That said – I’d love to dig into the timeouts that you’re experiencing. I was experiencing similar timeout issues until I got my Z2M network stabilized. If you’re comfortable with it, can you share your debug logs here? It should *** out your PIN codes so you (hopefully!!) won’t be leaking any sensitive data, and I can try to figure out how to make it more robust. Or if you’re concerned, you can email me at [email protected] and we can work on it together.

Thanks for the quite update to disable the bulk options.

Both locks are fairly close to routers but have always been fairly slow to respond (fast enough for my purposes though). I’ve recently changed from Conbee II to ZBT-2 moved from ZHA to Z2M to see if it helps - no noticable change. I am getting the odd message in Z2M logs indicating an issue with the Front Door lock so that may be affecting things

zh:ember:ezsp: Received network/route error ROUTE_ERROR_INDIRECT_TRANSACTION_EXPIRY for "55456"

Relevant part of logs below (truncated to first 2 attempts for character limit) - I’ve just set up with a few users for testing.

2026-01-26 12:23:29.648 WARNING (MainThread) [custom_components.lockly] MQTT response timeout for slot 2 on Lock - Shed Door (attempts=4)
2026-01-26 12:23:29.659 WARNING (MainThread) [custom_components.lockly] MQTT response timeout for slot 3 on Lock - Shed Door (attempts=4)
2026-01-26 12:27:16.879 DEBUG (MainThread) [custom_components.lockly] Applying slot 1 to locks ['Lock - Front Door', 'Lock - Shed Door'] (enabled=True)
2026-01-26 12:27:16.879 DEBUG (MainThread) [custom_components.lockly] Updated slot 1 (name=Darren, pin=***, enabled=True, busy=True, status=queued)
2026-01-26 12:27:16.882 DEBUG (MainThread) [custom_components.lockly] Manually updated Lockly Configuration data
2026-01-26 12:27:16.883 DEBUG (MainThread) [custom_components.lockly] Persisted slots: [{'slot': 1, 'name': 'Darren', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'queued'}, {'slot': 2, 'name': 'Kerry', 'pin': '***', 'enabled': True, 'busy': False, 'status': 'timeout'}, {'slot': 3, 'name': 'Guest', 'pin': '***', 'enabled': True, 'busy': False, 'status': 'timeout'}]
2026-01-26 12:27:16.883 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 1 on Lock - Front Door
2026-01-26 12:27:16.883 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 1 on Lock - Shed Door
2026-01-26 12:27:16.883 DEBUG (MainThread) [custom_components.lockly] Applying slot 2 to locks ['Lock - Front Door', 'Lock - Shed Door'] (enabled=True)
2026-01-26 12:27:16.883 DEBUG (MainThread) [custom_components.lockly] Updated slot 2 (name=Kerry, pin=***, enabled=True, busy=True, status=queued)
2026-01-26 12:27:16.883 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 1 on Lock - Front Door (attempt=1, timeout=10s)
2026-01-26 12:27:16.884 DEBUG (MainThread) [custom_components.lockly] Updated slot 1 (name=Darren, pin=***, enabled=True, busy=True, status=updating)
2026-01-26 12:27:16.884 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 1 on Lock - Shed Door (attempt=1, timeout=10s)
2026-01-26 12:27:16.884 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Shed Door/set: {'pin_code': {'user': 1, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:16.892 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Shed Door/set
2026-01-26 12:27:16.893 DEBUG (MainThread) [custom_components.lockly] Manually updated Lockly Configuration data
2026-01-26 12:27:16.894 DEBUG (MainThread) [custom_components.lockly] Persisted slots: [{'slot': 1, 'name': 'Darren', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 2, 'name': 'Kerry', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'queued'}, {'slot': 3, 'name': 'Guest', 'pin': '***', 'enabled': True, 'busy': False, 'status': 'timeout'}]
2026-01-26 12:27:16.894 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 2 on Lock - Front Door
2026-01-26 12:27:16.894 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 2 on Lock - Shed Door
2026-01-26 12:27:16.895 DEBUG (MainThread) [custom_components.lockly] Applying slot 3 to locks ['Lock - Front Door', 'Lock - Shed Door'] (enabled=True)
2026-01-26 12:27:16.895 DEBUG (MainThread) [custom_components.lockly] Updated slot 3 (name=Guest, pin=***, enabled=True, busy=True, status=queued)
2026-01-26 12:27:16.895 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 2 on Lock - Shed Door (attempt=1, timeout=10s)
2026-01-26 12:27:16.895 DEBUG (MainThread) [custom_components.lockly] Updated slot 2 (name=Kerry, pin=***, enabled=True, busy=True, status=updating)
2026-01-26 12:27:16.904 DEBUG (MainThread) [custom_components.lockly] Manually updated Lockly Configuration data
2026-01-26 12:27:16.905 DEBUG (MainThread) [custom_components.lockly] Persisted slots: [{'slot': 1, 'name': 'Darren', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 2, 'name': 'Kerry', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 3, 'name': 'Guest', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'queued'}]
2026-01-26 12:27:16.905 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Front Door/set: {'pin_code': {'user': 1, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:16.908 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Front Door/set
2026-01-26 12:27:16.908 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 2 on Lock - Front Door (attempt=1, timeout=10s)
2026-01-26 12:27:16.908 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Front Door/set: {'pin_code': {'user': 2, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:16.916 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Front Door/set
2026-01-26 12:27:16.921 DEBUG (MainThread) [custom_components.lockly] Manually updated Lockly Configuration data
2026-01-26 12:27:16.921 DEBUG (MainThread) [custom_components.lockly] Persisted slots: [{'slot': 1, 'name': 'Darren', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 2, 'name': 'Kerry', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 3, 'name': 'Guest', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'queued'}]
2026-01-26 12:27:16.921 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 3 on Lock - Front Door
2026-01-26 12:27:16.921 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 3 on Lock - Shed Door
2026-01-26 12:27:16.922 DEBUG (MainThread) [custom_components.lockly] Manually updated Lockly Configuration data
2026-01-26 12:27:16.922 DEBUG (MainThread) [custom_components.lockly] Persisted slots: [{'slot': 1, 'name': 'Darren', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 2, 'name': 'Kerry', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 3, 'name': 'Guest', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'queued'}]
2026-01-26 12:27:16.922 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Shed Door/set: {'pin_code': {'user': 2, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:16.925 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 3 on Lock - Front Door (attempt=1, timeout=10s)
2026-01-26 12:27:16.925 DEBUG (MainThread) [custom_components.lockly] Updated slot 3 (name=Guest, pin=***, enabled=True, busy=True, status=updating)
2026-01-26 12:27:16.929 DEBUG (MainThread) [custom_components.lockly] Manually updated Lockly Configuration data
2026-01-26 12:27:16.930 DEBUG (MainThread) [custom_components.lockly] Persisted slots: [{'slot': 1, 'name': 'Darren', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 2, 'name': 'Kerry', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}, {'slot': 3, 'name': 'Guest', 'pin': '***', 'enabled': True, 'busy': True, 'status': 'updating'}]
2026-01-26 12:27:16.930 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Front Door/set: {'pin_code': {'user': 3, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:16.931 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Shed Door/set
2026-01-26 12:27:16.931 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 3 on Lock - Shed Door (attempt=1, timeout=10s)
2026-01-26 12:27:16.931 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Shed Door/set: {'pin_code': {'user': 3, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:16.937 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Front Door/set
2026-01-26 12:27:16.937 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Shed Door/set
2026-01-26 12:27:26.885 DEBUG (MainThread) [custom_components.lockly] Retrying slot 1 on Lock - Front Door (attempt=2/4)
2026-01-26 12:27:26.885 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 1 on Lock - Front Door
2026-01-26 12:27:26.885 DEBUG (MainThread) [custom_components.lockly] Retrying slot 1 on Lock - Shed Door (attempt=2/4)
2026-01-26 12:27:26.885 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 1 on Lock - Shed Door
2026-01-26 12:27:26.885 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 1 on Lock - Front Door (attempt=2, timeout=10s)
2026-01-26 12:27:26.885 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Front Door/set: {'pin_code': {'user': 1, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:26.886 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 1 on Lock - Shed Door (attempt=2, timeout=10s)
2026-01-26 12:27:26.886 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Shed Door/set: {'pin_code': {'user': 1, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:26.891 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Front Door/set
2026-01-26 12:27:26.891 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Shed Door/set
2026-01-26 12:27:26.895 DEBUG (MainThread) [custom_components.lockly] Retrying slot 2 on Lock - Shed Door (attempt=2/4)
2026-01-26 12:27:26.896 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 2 on Lock - Shed Door
2026-01-26 12:27:26.896 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 2 on Lock - Shed Door (attempt=2, timeout=10s)
2026-01-26 12:27:26.896 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Shed Door/set: {'pin_code': {'user': 2, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:26.898 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Shed Door/set
2026-01-26 12:27:26.909 DEBUG (MainThread) [custom_components.lockly] Retrying slot 2 on Lock - Front Door (attempt=2/4)
2026-01-26 12:27:26.909 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 2 on Lock - Front Door
2026-01-26 12:27:26.910 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 2 on Lock - Front Door (attempt=2, timeout=10s)
2026-01-26 12:27:26.910 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Front Door/set: {'pin_code': {'user': 2, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:26.912 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Front Door/set
2026-01-26 12:27:26.927 DEBUG (MainThread) [custom_components.lockly] Retrying slot 3 on Lock - Front Door (attempt=2/4)
2026-01-26 12:27:26.927 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 3 on Lock - Front Door
2026-01-26 12:27:26.927 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 3 on Lock - Front Door (attempt=2, timeout=10s)
2026-01-26 12:27:26.928 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Front Door/set: {'pin_code': {'user': 3, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:26.930 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Front Door/set
2026-01-26 12:27:26.931 DEBUG (MainThread) [custom_components.lockly] Retrying slot 3 on Lock - Shed Door (attempt=2/4)
2026-01-26 12:27:26.932 DEBUG (MainThread) [custom_components.lockly] MQTT publish queued for slot 3 on Lock - Shed Door
2026-01-26 12:27:26.932 DEBUG (MainThread) [custom_components.lockly] Action timer started for slot 3 on Lock - Shed Door (attempt=2, timeout=10s)
2026-01-26 12:27:26.932 DEBUG (MainThread) [custom_components.lockly] MQTT publish to zigbee2mqtt/Lock - Shed Door/set: {'pin_code': {'user': 3, 'user_type': 'unrestricted', 'user_enabled': True, 'pin_code': '***'}}
2026-01-26 12:27:26.935 DEBUG (MainThread) [custom_components.lockly] MQTT publish complete to zigbee2mqtt/Lock - Shed Door/set```

Thanks for sharing your logs! My takeaway is that Apply All is likely hitting the Z2M network a little harder than we want. I’m also sporadically seeing the same failures happen on my production site. I’ve pushed a new fix that serializes ‘Apply All’ so that it removes parallel processing. This is slower, but should be more reliable, and I’m prioritizing reliability for this type of security application. If you try it out, let me know what happens!

I’ve given the update a try and still getting the timeouts, but also not seeing anything in the Z2M logs. HA logs return same as previously posted.
Tested comms are working ok by triggering a lock/unlock and can see them fine in Z2M.

Hm. Can you verify what git commit you’re running at? With the latest code you should see one slot in the Updating mode (in yellow) and the rest in Queued. You shouldn’t see it pushing more than one slot/lock combo at a time. Are you seeing that? Also the Wipe All button should be completely gone (I deleted that feature for now).

Running e464d48 - did a system reboot to see if things changed, but no luck.
Don’t worry about chasing my issues at the moment - I suspect I’ve got network problems since changing to the ZBT-2. I’ll change back to the ConBee II to see if it changes.

One thing I did notice unrelated to the other issues - I separated the cards, so each device was on its own card. When I update one card (one door), the other indicates the same response (e.g. both updating).

1 Like

I’m not sure I fully understand. Did you create a separate Lockly instance for each card? Or did the cards share an instance? In theory (and my testing), I haven’t been able to get slots to cross over between instances. But if you have 2 cards with the same instance, I would expect them to look the same (and act the same, depending on the rest of the card config). If it’s a problem, can you share screenshots?

I think this is a more a misunderstanding on my part due to the lock_entities presence in the card config.
I had two cards same instance but different lock_entities in order to keep slots aligned. I think visually I only expected the one that was updating to indicate.

Ah, I see what you mean. The “Updating” status is tied to the slot, not to the lock. That’s a good point. Let me think on how we’d address that.

1 Like

This is great, thanks for making it. I seem to have a similar issue where the (even just one update) will “Timeout”

  • When setting user codes and clicking “Apply”, the integration sends MQTT commands to zigbee2mqtt/Front Door Lock/set
  • Integration logs show: MQTT response timeout for slot X on Front Door Lock (attempts=4)
  • Card shows “Timeout” status for all slots
  • Lock continues publishing status updates normally to zigbee2mqtt/Front Door Lock

Thanks for trying it out, @Hans_van_der_Drift! Let’s see if we can figure out what’s going on in your setup. I can think of a few reasons why this might be going wrong:

  1. We’re using the wrong protocol to communicate with the locks
  2. We’re using the right protocol, but the Zigbee network is not stable enough for the message to get through (or the LQI is too low on your lock)
  3. There’s something wrong with your lock

To diagnose this, can you try setting a PIN manually via your Z2M web ui? You should be able to click on the device, click on the “Exposes” tab, then fill out the “Pin code” form and submit it. Then look at the logs in Z2M and watch the network traffic and see if it works or not.

If it works reliably from the Z2M dashboard, then it’s an issue in the Lockly code. I’ll need to see your Z2M logs as well as the debug output from your Lockly integration and we’ll be able to figure out what’s wrong and improve Lockly.

If you can’t get it to work reliably from the Z2M dashboard, then the issue lies somewhere in your Zigbee network and/or the device itself. Perhaps the lock’s LQI is too low, or there’s some other challenge.

Let’s start there and see what we can figure out!