Repository navigation
Managing Guests and Rentals
A short-term rental, a spare room, a cleaner who comes on Tuesdays: somebody other than the household needs a code, but not all the time.
Start by asking what actually changes — because in the most common case, nothing does, and there is no per-visit work at all.
Complete, paste-able automations are in Recipes below.
| Permanent user, recurring condition | Rotate a standing user | Add and remove | |
|---|---|---|---|
| Use when | The same person, on a repeating schedule | Same number of guests, different people | Ad-hoc, and the count varies |
| Example | The cleaner, every Tuesday morning | A rental unit's guest | A contractor for one week |
| What changes per visit | Nothing | Name and PIN | The user itself |
| Entity IDs | Never change | Never change | Change every time |
| Automations | Keep working | Keep working | Need repointing each time |
Work down that table and stop at the first row that fits. Most recurring access — cleaners, dog walkers, a neighbour who feeds the cat — is the first row, and needs no automation whatsoever.
The cleaner comes every Tuesday. The person is not temporary; only the window is. So this is one permanent user with a schedule attached as their condition — and once it is set up, there is nothing to do per visit, ever.
- Add a user named for the person:
Cleaner, or their actual name. - Create a
schedulehelper covering when they should get in — Tuesday 08:00–12:00. - Attach it as their condition entity.
Their PIN is written to the locks while the schedule is on and removed when it is off. You do not enable and disable anything; the schedule reverses itself. The code is dead for the other six days without you thinking about it.
Use a calendar instead of a schedule when the pattern is irregular — a cleaner who comes fortnightly, or whose day moves — since a calendar can hold arbitrary dates while a schedule repeats weekly. Everything else is the same.
This is also the right shape for a dog walker, a gardener, a carer, or anyone else who comes back on a rhythm. If the person is not changing, do not rotate or re-create them.
Lock Code Manager identifies a user internally by the slot number they hold, not by their name. The name is the label you see; it is not the key.
That means renaming a user changes nothing but the label. Their entity IDs
stay put. Their history stays attached. Every automation, script, dashboard
card and blueprint that references them keeps working. You can rename
Guest 1 to Sarah Chen on Friday and back to Guest 1 on Monday, forever,
and nothing downstream notices.
Adding a user is the opposite. A new user gets new entity IDs, named after
them — text.all_locks_sarah_chen_pin — so anything you want to automate has
to be pointed at the new entities each time. Removing them takes those
entities away again.
Neither is wrong. But if you find yourself re-editing the same automation every booking, you have chosen the wrong pattern.
For when the position is stable but the person is not. Set up once, then change two fields per booking.
- Decide how many guests you can have at once — usually one per rental unit.
- Add that many users, named for the position rather than the person:
Guest 1,Guest 2. Leave them disabled, with no PIN. (Staff who come on a rhythm are not guests — give them their own permanent user per Pattern 0.) - Attach a condition entity to each so the code only works when it should. A calendar is the natural fit for a rental: the PIN is live during the booking and dead outside it, without anything having to remember to turn it off.
Change the name to the guest, set a fresh PIN, and let the calendar handle activation:
action: text.set_value
target:
entity_id: text.all_locks_guest_1_name
data:
value: Sarah Chen
action: text.set_value
target:
entity_id: text.all_locks_guest_1_pin
data:
value: "{{ pin }}"Generate the PIN rather than picking one — generate_pin
draws from a cryptographic source and rejects sequences, repeats and the
common-leak list:
action: lock_code_manager.generate_pin
data:
length: 6
response_variable: generated
action: text.set_value
target:
entity_id: text.all_locks_guest_1_pin
data:
value: "{{ generated.pin }}"Those entity IDs never change, so this automation is written once.
You can also address the person by name with
set_credential, which avoids depending
on entity IDs at all — though for this pattern you would have to rename first
and then set the PIN under the new name, so the entity-driven version above
stays simpler here. Where it earns its keep is rotating a code for somebody
whose name is not changing:
action: lock_code_manager.set_credential
data:
config_entry_title: All Locks
name: Sarah Chen
credential_type: pin
value: "{{ generated.pin }}"
enable_if_disabled: trueenable_if_disabled matters if the code was cleared earlier — clearing disables
the person, so without it the new PIN would be set but inert.
If your booking platform publishes a calendar, the Calendar PIN Setter blueprint does the whole thing: extracts a PIN from the event, sets it when the booking starts, clears it when it ends. Pair it with the Slot Usage Notifier if you want to know when they first arrive.
Better when the count varies — a contractor for one week, a house-sitter once a year — and you would otherwise be maintaining standing users who are empty most of the time. If they are coming back on a schedule, they are Pattern 0, not this.
action: lock_code_manager.generate_pin
data:
length: 6
response_variable: generated
action: lock_code_manager.add_user
data:
config_entry_title: All Locks
name: Sarah Chen
pin: "{{ generated.pin }}"
condition: calendar.bookingsand when they leave:
action: lock_code_manager.delete_user
data:
config_entry_title: All Locks
name: Sarah ChenRemoving a user clears their PIN from every lock in the entry. That is the
point of removing them. If you want the opposite — hand the code over and stop
tracking it here — pass clear_credentials: false, but understand that the
code keeps working and the slot stays occupied.
You do not choose a slot number. Lock Code Manager reads what the locks hold and allocates a free one, so a slot freed by a departing guest is available to the next.
Both actions accept config_entry_title as well as config_entry_id, which
makes hand-written automations readable.
Complete automations, not fragments — paste one in and change the names. Every
one of them generates the PIN rather than choosing it, because
generate_pin draws from a cryptographic
source and rejects sequences, repeats and the common-leak list.
The whole of Pattern 2, driven by the calendar. Two automations: one when a booking starts, one when it ends.
automation:
- alias: "Guests: add on booking start"
triggers:
- trigger: calendar
entity_id: calendar.bookings
event: start
actions:
- action: lock_code_manager.generate_pin
data: {length: 6}
response_variable: generated
- action: lock_code_manager.add_user
data:
config_entry_title: All Locks
name: "{{ trigger.calendar_event.summary }}"
pin: "{{ generated.pin }}"
- action: notify.send_message
target:
entity_id: notify.mobile_app_phone
data:
message: >-
{{ trigger.calendar_event.summary }} arrives today.
Code {{ generated.pin }}.
- alias: "Guests: remove on booking end"
triggers:
- trigger: calendar
entity_id: calendar.bookings
event: end
actions:
- action: lock_code_manager.delete_user
data:
config_entry_title: All Locks
name: "{{ trigger.calendar_event.summary }}"The guest's name comes from the event summary, so the two automations agree about who to remove without storing anything.
The summary has to be a usable name and the same one both times. An event titled
Sarah Chen — 3 nightsadds a user under that whole string, and renaming the event mid-stay means the remove step names somebody who isn't there. If your booking platform writes noisy summaries, either extract the name with a template or use Pattern 1, where the user already exists and only the name and PIN change.
If you would rather the code stop working at checkout without removing the
user, pass condition: calendar.bookings to add_user and drop the second
automation — the condition entity turns the code off when the event ends. The
user stays, holding an inactive code, until you remove them.
For the friend staying this weekend, where there is no calendar. A script with a field, so it takes one tap from a dashboard button.
script:
add_guest:
alias: Add a guest code
fields:
guest_name:
name: Guest name
required: true
selector:
text:
sequence:
- action: lock_code_manager.generate_pin
data: {length: 6}
response_variable: generated
- action: lock_code_manager.add_user
data:
config_entry_title: All Locks
name: "{{ guest_name }}"
pin: "{{ generated.pin }}"
- action: notify.send_message
target:
entity_id: notify.mobile_app_phone
data:
message: "{{ guest_name }}: {{ generated.pin }}"Removing them is lock_code_manager.delete_user with the same name — worth a
second script if you hand out codes often.
A whole party at once.
add_usertakes a list, so a booking with several named guests is one call rather than one per person — and one read of your locks rather than several, which matters on battery locks.delete_usertakes a list of names the same way. The single-person form used throughout this page is shorthand for a list of one and keeps working. See Services and Actions.
add_user allocates the slot and waits for the entry to finish reacting before
it returns, so the next step can address the new user's entities directly rather
than guessing at a delay. (It waits on the entry, not on those specific
entities, so a second write landing at the same instant can release it early —
in practice that means don't fire two of these at once.)
script:
add_one_use_guest:
sequence:
- action: lock_code_manager.generate_pin
data: {length: 6}
response_variable: generated
- action: lock_code_manager.add_user
data:
config_entry_title: All Locks
name: Courier
pin: "{{ generated.pin }}"
# The entities now exist, named after the user.
- action: input_number.set_value
target:
entity_id: input_number.courier_uses
data:
value: 1Then point the Slot Usage Limiter blueprint at
event.all_locks_courier_credential_used, the enabled switch, and that
counter. The code disables itself after one entry.
Entity IDs come from the name. A user called
Couriergetsevent.all_locks_courier_credential_used;Sarah Chengets..._sarah_chen_.... That is fine for a fixed role likeCourier, which is why this recipe uses one — a blueprint automation cannot repoint itself at a new entity ID per guest. For rotating guests, keep the standing user of Pattern 1 and rename it: the entity IDs never move, so the limiter stays pointed at the same ones.
-
enableddefaults to true, and an enabled user must have a PIN. Adding one without apinfails with'Name' cannot be enabled without a PIN. Passenabled: falseto park a user with no code. -
Names are unique by person, not by spelling. Two names that normalize to
the same identity are refused with
A user named 'X' already exists. - You never choose a slot number. Lock Code Manager reads what the locks hold and allocates a free one, so a slot a departing guest freed goes to the next arrival.
-
delete_userclears the PIN from every lock unless you passclear_credentials: false— which leaves the code working on the lock and the slot occupied. -
PIN length must satisfy your strictest lock.
generate_pintakes 4–12 digits; if a lock takes only 4, ask for 4.
You can run two config entries against the same locks — one for permanent codes (you, family, staff) and one for guests — as long as they do not manage the same slot numbers on the same lock.
Worth doing when:
- You want the guest dashboard separate from the household one.
- You want to wipe every guest code at once, by clearing that entry.
- Different people administer them.
Not worth it for two or three codes; one entry is simpler.
Locks have a finite number of slots. Adding users fails once the lock is full. Standing users make the ceiling visible up front rather than at the worst moment.
A code left behind still opens the door. Before 5.0, removing a slot did not clear its PIN. If your locks predate that, the upgrade asks about every code it cannot account for — see [[Upgrading to 5.0#unmanaged-codes|Upgrading-to-5.0#unmanaged-codes]].
Do not reuse a PIN between guests. Generate a new one each time. A returning guest's old code should not still work, and the previous guest should not be able to guess the next one.
A condition entity is not the same as disabling. A disabled user's code is removed from the lock. A user gated by a condition still holds their slot; the code is only written while the condition is on. For a rental you almost always want the condition — it reverses itself.
Check the PIN actually landed. Each user has an in sync sensor per lock. If a lock was asleep or unreachable when you set the code, that sensor tells you before your guest does.
Getting Started
- Upgrading to 6.0
- Upgrading to 5.0
- Configuration Structure
- Adding and Removing Locks
- Migrating from keymaster
UI
Features
- Managing Guests and Rentals
- Services and Actions
- Blueprints
- Tracking lock state change events
- Using Condition Entities
- Unsupported Condition Entities
Advanced
Development
Troubleshooting
FAQ
Supported Integrations