Repository navigation
Managing Guests and Rentals Recipes
Part of Managing guests and rentals, which explains the patterns these recipes build on: a permanent user on a recurring schedule, rotating a standing user, or adding and removing one per guest.
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.
Keep the remove automation: it's what revokes the code. Don't replace it with
condition: calendar.bookings on the guest. That calendar is on during every
booking, so a guest kept around with it as their condition would get their code
back during every later booking.
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.
Getting Started
- Upgrading to 7.0
- 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