Examples / Bedtime house check
Bedtime house check
At 10:30 every night Murmurator reads every entity in Home Assistant through your tailnet, picks out the lights left on, the doors left unlocked and the windows left open, has your model decide what to switch off and lock, does it, and sends a one-line report to your phone. Home Assistant never has to be reachable from the internet.
Home AssistantTailscaleJavaScriptYour AI models
What you tell the assistant
Why it works
- Home Assistant is reached at http://homeassistant:8123 through a tailscale connection, so nothing in the house is opened to the internet.
- A JavaScript step narrows hundreds of entities to the few that matter before the model sees them, which keeps each night's run cheap.
- The model only chooses from the entities it was shown, and the actions run only when there is something to switch off or lock.
What it builds
Trigger
Schedule
30 22 * * * · America/Toronto
tool
Read the house
home.list_states
javascript
Find loose ends
→ lights_on, unlocked, open
llm
Decide what to do
fast · structured
tool
Turn off lights
home.call_service
if size(decide.output.data.lights_off) > 0
tool
Lock the doors
home.call_service
if size(decide.output.data.lock) > 0
tool
Tell my phone
home.call_service
View the definition
trigger:
kind: schedule
cron: "30 22 * * *"
timezone: America/Toronto
steps:
- key: states
name: Read the house
kind: tool
tool: home.list_states
- key: loose_ends
name: Find loose ends
kind: javascript
inputs: { states: "{{ steps.states.output }}" }
outputs: { lights_on: array, unlocked: array, open: array }
code: |
function main({ states }) {
const pick = (domain, state) => states
.filter(s => s.entity_id.startsWith(domain + ".") && s.state === state)
.map(s => ({ entity_id: s.entity_id, name: s.name }))
return {
lights_on: pick("light", "on"),
unlocked: pick("lock", "unlocked"),
open: pick("binary_sensor", "on").filter(s => /window|door/i.test(s.entity_id))
}
}
- key: decide
name: Decide what to do
kind: llm
model: fast
system: You close up a family home for the night. Choose only from the entities you are given, and keep the phone message to one or two short sentences.
prompt: |
Lights on: {{ steps.loose_ends.output.lights_on }}
Unlocked locks: {{ steps.loose_ends.output.unlocked }}
Open doors and windows: {{ steps.loose_ends.output.open }}
Turn off every light except the porch light. Lock every lock, unless the door it belongs to is open: then leave it and say so.
schema:
type: object
properties:
lights_off: { type: array, items: { type: string } }
lock: { type: array, items: { type: string } }
message: { type: string }
required: [lights_off, lock, message]
- key: lights
name: Turn off lights
kind: tool
if: size(steps.decide.output.data.lights_off) > 0
tool: home.call_service
args:
domain: light
service: turn_off
entity_id: "{{ steps.decide.output.data.lights_off }}"
- key: locks
name: Lock the doors
kind: tool
if: size(steps.decide.output.data.lock) > 0
tool: home.call_service
args:
domain: lock
service: lock
entity_id: "{{ steps.decide.output.data.lock }}"
- key: report
name: Tell my phone
kind: tool
tool: home.call_service
args:
domain: notify
service: mobile_app_pixel
data:
title: House closed up for the night
message: "{{ steps.decide.output.data.message }}"
A sample run
What each step produces
Read the house tool
succeeded
Read the house tool
Calling home.list_states
[
{
"entity_id": "light.kitchen",
"state": "on",
"name": "Kitchen"
},
{
"entity_id": "light.living_room",
"state": "on",
"name": "Living room"
},
{
"entity_id": "light.porch",
"state": "on",
"name": "Porch"
},
{
"entity_id": "light.bedroom",
"state": "off",
"name": "Bedroom"
},
{
"entity_id": "lock.front_door",
"state": "unlocked",
"name": "Front door"
},
{
"entity_id": "lock.back_door",
"state": "locked",
"name": "Back door"
},
{
"entity_id": "binary_sensor.office_window",
"state": "on",
"name": "Office window"
},
{
"entity_id": "binary_sensor.front_door",
"state": "off",
"name": "Front door contact"
},
{
"entity_id": "sensor.outdoor_temperature",
"state": "4.5",
"name": "Outdoor temperature",
"unit": "°C"
}
]
Find loose ends javascript
succeeded
Find loose ends javascript
{
"lights_on": [
{
"entity_id": "light.kitchen",
"name": "Kitchen"
},
{
"entity_id": "light.living_room",
"name": "Living room"
},
{
"entity_id": "light.porch",
"name": "Porch"
}
],
"unlocked": [
{
"entity_id": "lock.front_door",
"name": "Front door"
}
],
"open": [
{
"entity_id": "binary_sensor.office_window",
"name": "Office window"
}
]
}
Decide what to do llm
succeeded
Decide what to do llm
Using model fast (GLM-5.3 Air, Murmurator AI)
{
"text": "",
"data": {
"lights_off": [
"light.kitchen",
"light.living_room"
],
"lock": [
"lock.front_door"
],
"message": "Kitchen and living room lights off, front door locked, porch light left on. The office window is still open."
}
}
Turn off lights tool
succeeded
Turn off lights tool
Calling home.call_service
[
{
"entity_id": "light.kitchen",
"state": "off"
},
{
"entity_id": "light.living_room",
"state": "off"
}
]
Lock the doors tool
succeeded
Lock the doors tool
Calling home.call_service
[
{
"entity_id": "lock.front_door",
"state": "locked"
}
]
Tell my phone tool
succeeded
Tell my phone tool
Calling home.call_service
[]
Trigger payload
{
"scheduled_at": "2026-10-31T02:30:00Z"
}
More examples
Turn one person's AI process into the company's.
Murmurator is invite-only. Already invited? Sign in and build something real.