MeranoWhat went wrong?Security and accessGetting started and running it

A guessed wait is not a check

The lock needs 38 seconds; my automation waited 20. The second command hit the motor mid-travel — and took the confirmation down with it.

A white motorised lock sits on the cylinder of a flat door, the handle beside it.
A white motorised lock sits on the cylinder of a flat door, the handle beside it.

The flat door in Merano locks itself when the button is held down on the way out. For that it first had to know whether it is actually shut.

The door contact for that is fitted. And it is not a Zigbee device — it sits in the lock as an accessory and arrives through the lock’s own integration.

I already had the Zigbee pairing window open before the hint came. Reloading the existing integration was enough, and the entity was there.

Before pairing a device, it is worth asking whether it is not already there.

Two small things before it could start

The name. Home Assistant prefixed the area, turning the contact into a name with hallway and corridor in it. Pulled back to something readable — because with a door contact “on” means open, and the name has to read the right way round, or you build the condition backwards.

Measuring before trusting. A contact stuck at “open” would prevent locking permanently and silently. So it was moved before it went into the logic:

15:17:32  shut
15:21:32  open
15:22:02  shut      — 30 seconds open

Both states evidenced, not assumed.

Side finding: both changes land on :32 and :02. The lock is polled about every 30 seconds — so the reading can be half a minute old. Irrelevant for a three-minute delay, but worth knowing.

What the contact achieves

button held → 3 min → door shut?  yes      → lock
                      door open   → wait up to 10 min
                                    shut now?  yes  → lock
                                               no   → WARNING, do not lock

The ten minutes are not a luxury: anyone fetching another bag on the way out holds the door open for more than three minutes. That is the normal case, not a fault — so wait rather than abort.

If it is still open after ten minutes, the bolt does not extend. It would travel into thin air and hit the frame when the door is pulled shut.

The trial run — and the fault in it

15:39:05  button held
15:39:12  away
15:39:34  door open, bathroom heating → 12 °C
15:42:11  door automation fired — and did NOT lock   ← the checkpoint
15:42:14  water off
15:46:33  door shut
15:46:42  locking
15:47:20  locked
15:47:36  button pressed → home, water on, heating 21 °C

The lock held, the logic was right. From outside everything looked correct.

The log nonetheless held an error — and the reason is one number:

The lock needs 38 seconds and stands at “locking” for all of them. My first version waited a stubborn 20 seconds, found “locking” instead of “locked”, took that for a swallowed command and sent a second one — straight into the motor’s travel.

The lock rejected it. Home Assistant counted the rejection as an error, and the automation aborted.

The door shut. The confirmation never came.

That is the same silent failure this whole package is built against — this time in my own code. I only found it because I looked at the log after the trial run.

Twice in one day, two devices

The real finding is not the fault but the pattern:

Device checked after motor needs consequence
water valve 15 s 40 s the fallback fired every time
door lock 20 s 38 s the second attempt took the notification down

Both numbers were guessed. Both were plausible. Both were too short.

A guessed wait is not a check. It is a claim about how long a motor takes — and it holds for exactly one device, namely the one you guessed it on.

The right way is to wait for the result, not for the clock:

- action: lock.lock
  target: { entity_id: lock.<door> }
  continue_on_error: true
- wait_for_trigger:
    - trigger: state
      entity_id: lock.<door>
      to: "locked"
  timeout: "00:01:30"
  continue_on_timeout: true

Three things in there are deliberate:

Waiting for the state instead of a fixed pause. It is done when the device is done, not when the clock has run out.

The timeout with “continue on timeout”. If the confirmation fails to arrive, the notification should still go out — saying that it failed to arrive.

And “continue on error” on the switching command itself, so a rejected command never swallows the notification again.

A fault while switching may do all sorts of things. Just not make sure that nobody hears about it.

What I’d suggest

  1. Ask whether the device is not already there before you open a pairing window. Accessories often arrive through the main device’s integration.
  2. Move a contact before you believe it. A sensor stuck on one state silently blocks everything that depends on it.
  3. Measure how long your device really takes — and then do not use that number, but wait for the result.
  4. Set a timeout and let the notification out anyway. “No confirmation” is information, not a reason to stay quiet.
  5. Do not let a rejected command abort the automation.
  6. Read the log after a trial run, even when everything worked. Here there was nothing to see from outside.

So what?

The door was shut, the heating was down, the water was off. Everything this package is supposed to do, it did.

And it was broken all the same — at the one point you cannot see from outside: it could no longer have told me that it did what it is supposed to do. Next time, when the door genuinely does not shut, the silence would have been identical.

Two guessed numbers in one day, both too short, both plausible. That is not coincidence but a property of guessed numbers: you guess them from what you can picture — and a motor that travels for 38 seconds appears in nobody’s picture.