Skip to content
raman325 edited this page Oct 17, 2026 · 1 revision

Upgrading to 7.0

Lock Code Manager 7.0 replaces the engine that keeps your locks in sync. What you configure is unchanged — the same users, PINs, conditions, entities, actions and dashboards — but how LCM talks to each lock is new, and a few behaviours you can see have changed. The biggest ones:

  • LCM never touches a code it didn't create. A lock that already holds codes in an entry's slots is refused rather than overwritten.
  • A restart no longer rewrites PINs on locks that hide their codes.
  • Locks that can't report their codes are recognised, and you are told which slots LCM will use on them.
  • When LCM stops trying a slot, it stays stopped until you click Submit on the repair, change the user, or a fresh read shows the lock already matches. A slot the lock keeps changing back, or a PIN the lock refuses, waits for you.

Before you upgrade

There is nothing to migrate and nothing to search your automations for:

  • Config entries stay at version 5. No migration runs, and nothing is renamed or renumbered.
  • No actions, entities or events are removed. hard_refresh_usercodes gains an optional forget_reporting field.
  • Requirements are unchanged: Home Assistant 2026.9.0 or newer, and for Z-Wave JS locks a driver (zwave-js) of 15.24.3 or newer.

7.0 adds one storage file, .storage/lock_code_manager.core. To roll back to 6.0.x, restore the older version and delete that file. Taking a Home Assistant backup before upgrading is still a good idea.


One worker per lock

Each lock now has a single worker that handles every read, write, retry and pause for that lock, shared by every config entry that uses it. Things you may notice:

  • Every write is checked. After setting or clearing a code, LCM reads that slot back. A slot only shows as in sync once the lock confirms it.
  • Turning a user off and on quickly shows the slot as pending until the lock confirms it, instead of showing an unknown code for a while.
  • Z-Wave JS writes are faster. The extra read the integration did after each write is gone; LCM's own read-back confirms it.
  • An entry's entities no longer wait for its slowest lock to finish setting up.
  • Debug logs show every exchange with a lock, with how long it took. See Troubleshooting: Debug Logs.

The sync_status attribute of the in sync sensors now takes only in_sync, out_of_sync, syncing and suspended (and is absent while the slot hasn't been read yet). pending_confirmation and loading are no longer reported; a write waiting for the lock's confirmation reads syncing. If an automation or template checks for either old value, update it.


Restarts don't rewrite PINs

Many locks (Matter, many Z-Wave locks) never show the PIN in a slot, only that there is one. Before 7.0, after a restart LCM couldn't tell whether those codes were its own, and wrote them again.

LCM now remembers what it wrote to each slot — as a salted fingerprint, never the PIN itself — in .storage/lock_code_manager.core. After a restart, a hidden code that matches is treated as in sync and left alone.


LCM never touches a code it didn't create

  • Adding a lock that already holds codes in the entry's slots is refused, naming the slots: "Clear those slots on the lock, then add it again." Before, those codes were overwritten. A lock that can't be read is refused too, rather than added unchecked. This applies to the options flow and to reauth. See Adding and Removing Locks.
  • New users go only in free slots. Allocation skips any slot that holds a code, on every provider.
  • Turning a slot off or removing a user never touches a lock user without LCM's tag, on locks that have users (Z-Wave User Credential, Matter): only users carrying LCM's tag are cleared or deleted. One exception is kept for upgrades from before LCM tagged its users: when LCM writes a slot your configuration already uses, an untagged user already sitting in that slot is taken over and tagged rather than duplicated.
  • Akuvox and Schlage no longer pull existing codes into LCM. Before, at setup and at a hard refresh, they tagged codes added outside LCM into LCM slots. Now such codes are left alone, like on every other provider. Codes LCM already tagged are not affected. To bring one of those people under LCM, add them as a user in LCM (LCM writes its own code), then delete their old code on the lock.

Removing a user on a lock with users

On Z-Wave User Credential and Matter locks, removing an LCM user now removes only the PIN LCM wrote:

  • The lock user is deleted only if nothing else is left on it. If the person also has, say, a fingerprint added at the lock, the user is kept and loses LCM's tag.
  • On Matter, only PINs created by Home Assistant's own fabric count as LCM's. A PIN added from another Matter controller is never removed.
  • A user named just a number (or lcm3) in the vendor's app is never mistaken for LCM's. LCM writes those short names only where its full tag can't be used: on Z-Wave, a short name counts as LCM's only on a lock whose name limit is too short for lcm:<slot>:; on Matter, only on a user Home Assistant's own fabric created.

Locks that can't report their codes

Some locks never say what a slot holds — a Zigbee2MQTT lock answering not_supported_255, or a ZHA lock answering status 0xFF. LCM now recognises them:

  • The setup, options, add-user and reauth flows tell you when a lock can't report its codes, which slots LCM will use, and that any keypad code in those slots will be replaced. Saving goes ahead.
  • The lock codes card shows such slots as Not reported.
  • LCM remembers, across restarts, whether a lock has ever reported a code. On a lock that has, a slot it can't describe counts as taken. If a lock was wrongly taken for one that can report, use hard_refresh_usercodes with forget_reporting: true on it — see Services and Actions.

Repairs

See Repair Issues for every repair.

  • Sync suspended and Code not removed: LCM stops trying the slot, and Submit now means "try again". Changing the user (new PIN, turning them off or on) also starts the slot over. LCM keeps checking the slot without writing to it, and clears the repair itself once a fresh read shows the lock already matches — for example after the radio link recovers, or after you delete a code at the keypad. On Z-Wave JS locks, which LCM doesn't poll, that check happens when you run hard_refresh_usercodes. A push from the lock never clears it, since it may come from a cache.
  • A slot the lock keeps changing back (for example a keypad taking the code back) stays stopped until you click Submit or change the user, even if the lock later agrees.
  • A suspended slot's repair names the cause when the lock or integration gave one.
  • Re-paired locks. When a lock is re-paired under the same entity ID (for example a Zigbee2MQTT lock re-joined under the same name), LCM moves to the new device on its own. Two new repairs cover the edge cases: Check slots on re-paired lock names slots whose clear was dropped, and Reload Lock Code Manager to use re-paired lock asks for a reload. See Adding and Removing Locks.
  • Unmanaged code → Clear on a lock that isn't answering now waits for the lock and clears the code when it is back.

The lock codes card shows what the lock said

The lock codes card never presents a configured PIN as if the lock had reported it. New states: Checking… (waiting for the lock to confirm the slot), Disabled on lock, Not reported, and hollow dots for a code whose value is unknown (hidden, or the lock didn't answer). A managed slot that is in sync on a lock that hides its codes shows LCM's PIN in italics, as configured rather than read.

The user card's per-lock status no longer shows Confirming; a write waiting for confirmation shows as Syncing.


Provider fixes

  • Z-Wave JS UI: a lock refusing a duplicate code is now recognised. Before, a lock that hides its codes could show in sync with a PIN it had refused; now the user is turned off with a Slot disabled repair.
  • ZHA: a passing failure answer on a write is treated as no answer and retried, not as a refused PIN.
  • Schlage and Akuvox: a validation error on a write is treated as a refused PIN (Slot disabled repair).
  • Schlage: a new PIN is written only after the old code is deleted, so the old PIN can't stay working beside it. Availability comes from the lock entity instead of a full cloud read every 30 seconds.
  • Zigbee2MQTT: a cached state republished by Zigbee2MQTT can no longer be mistaken for the lock's answer after a write.
  • Matter: user names are capped at 9 bytes, so names with non-ASCII characters are shortened correctly.

If something goes wrong

  • Check Settings → System → Repairs first. See Repair Issues.
  • Debug logs and diagnostics: Lock Code Manager's diagnostics include each lock's state as the new engine sees it — whether the lock is answering, and each slot's status, hold and tries.
  • To roll back, install 6.0.x and delete .storage/lock_code_manager.core.

Clone this wiki locally