Faking presence with one Advanced Flow

Faking presence with one Advanced Flow (17 lanes)

Spent some time rebuilding my Travel Mode automation. It used to be 13 separate Standard Flows, each with its own trigger and presence check. Toggling them as a group was painful, and the logic was fragmented across so many places I couldn’t reason about it as a whole. Consolidated into one Advanced Flow with 17 lanes. Built most of it with Claude through the Homey MCP — wouldn’t have had the patience to click through 136 cards by hand.

Sharing the patterns in case they’re useful.

One flow, no boolean toggle

Every lane gates on presence:noone_athome. No “Travel Mode is ON” variable to flip. Walk in the door and first_user_enter resumes the ecobee program. Walk out and the AND of last_user_left + zone Home inactive kicks Travel ON.

The lanes are color-coded with sticky notes on the left of each one:

  • blue = presence transitions

  • yellow = scheduled routines

  • red = security and intrusion

  • green = climate

Ends up at around 136 cards. The Homey UI gets noticeably sluggish above 150, so design for that ceiling if you’re consolidating something this big.

Better Lights dimZone instead of per-light enumeration

If you’re not using Better Lights (nl.lrvdlinden.better-lights), it’s worth a look. The dimZone action hits every dimmable in a zone in one card, including devices added to that zone later. My Lights Out lane went from 30+ cards to 8.

Action: Better Lights → dimZone

Args: { zone: "Library", brightness: 0 }

Added two bathroom lights to a previously-empty Guest Bathroom zone last week. They got picked up by the relevant lanes the next time they fired. Zero flow edits.

Cascading random delay

A trigger at 22:00 with delay 0–30 min random still grid-aligns to 22:xx every night. To get a real one-hour fire window:

Trigger: cron 21:30

→ Random condition (chance: 33)

True → Delay 0 sec

False → Random condition (chance: 50)

True → Delay 30 min

False → Delay 60 min

→ ANY join (whichever delay fires first wins)

→ noone_home gate

→ action chain

That gives roughly 33/33/33 across (21:30, 22:00, 22:30), and each run picks a different bucket independently.

For the Evening Presence Loop I used cron:every_nth with n=17. Prime number, doesn’t grid-align to anything. Pair it with a 60% random skip and a weighted room-pick (Library 20%, Kitchen 25%, Office 33%, Entertainment 50%, Hallway as fallback) and the loop fires 0–1 times per evening at an unpredictable time in an unpredictable room for 22 minutes.

AND / ANY gates for multi-trigger lanes

AND on Lane 0 means I don’t think we’re traveling just because someone’s outside watering the garden — both last_user_left AND zone Home inactive have to be true:

[last_user_left] ─┐

├─[ALL/AND]─→ ecobee + lock front door

[Home inactive] ──┘

ANY on the intrusion lanes catches OR-of-triggers (door contact OR camera person detection → same response):

[contact:open]   ─┐

├─[ANY]─→ noone_home → panic lights + push image

[motion:human] ──┘

The push_image gotcha that cost me a session

Camera snapshots on push notifications work via a droptoken field on the action card. Format:

"droptoken": "homey:device:<camera-uuid>|image-camera-main"

Pipe separator, not colon. You bind it in the UI by dragging the snapshot token from the camera trigger onto the push card.

The Homey REST API does not let you set this field. The Advanced Flow update schema rejects droptoken (additionalProperties: false). And if you update the flow without including the droptoken on those cards, the existing binding gets stripped silently — every push_image card has to be re-bound in the UI. Burned a Claude session trying six formats before figuring out it’s the schema rejecting the field, not a syntax problem.

What this means in practice: once you’ve manually bound push_image snapshots, treat the flow as read-only via the API. Need to extend it later? Build a companion flow.

That’s exactly what I did for the Guest Bathroom additions — instead of editing the main 136-card flow and risking the snapshot bindings, I made a 10-card companion (cron + random delay + presence gate + one dimZone Guest Bathroom @0). Independent random offset is actually more realistic than synchronized shutdown.

If anyone from Athom is reading: please make droptoken settable via the API.

The lanes

# Color What it does
0 blue Travel ON: last_user_left AND Home zone inactive → ecobee 80°F + lock front door
1 blue Travel OFF: first_user_enter → ecobee resume_program
2 yellow Sunset → Porch ON @100% + Library @50%
3 yellow Bedtime randomized 21:30–22:30 → kitchen/library/office/ent OFF + hallway @20%
4 yellow Lights Out randomized 23:00–00:00 → all interior zones OFF (porch stays for lane 5)
5 yellow Sunrise → Porch OFF
6 yellow Doorbell ding → Hallway @80% + Library @100% → 45s → both OFF
7 red Front entry intrusion (contact OR motion) → panic lights + push image
8 red Garage entry intrusion → same pattern
9 red Utility room motion → same pattern
10 red Lock tampered → push + Hallway ON (no siren, on purpose)
11 red Interior motion (highest severity) → all zones @100% + all camera sirens + critical push
12 yellow Sound layer 18:00–21:00, 50% skip → Office Sonos: TPR 7m → BR24 7m → pause
13 yellow Floodlight pulse 20:00–22:00, 50% skip → Pool + Front floodlights 4m
14 green Humidity > 65% sustained 15min → ecobee cool, target 78°F
15 green Humidity < 58% sustained 10min → ecobee back to 80°F (hysteresis)
16 yellow Evening Presence Loop every 17min after sunset, 60% skip → weight-pick one room

Apps in use

  • Better Lights (nl.lrvdlinden.better-lights) — zone-level dim commands

  • HomeyScript — for anything Better Lights can’t do

  • Better Logic — variables and richer conditions

One question

Anyone found a way to bind camera snapshots to push notifications purely via the API? I tried six droptoken formats before confirming it’s UI-only. If there’s a workaround, I’m curious.