Example Flows

Nine complete automations, block by block: which trigger, how the chain is wired and why. In all of them the trigger does the filtering: its device and room pins narrow the flow, not an if in the chain.

Every flow is built from the Trigger Reference and Action Reference blocks, plus ordinary RUAL blocks. Device references are written as an exact device name (Hallway ceiling); a platform id such as zigbee:0x00158d0007e1a2b3 works identically.

1. Motion lights, but only after dark

What it does. Somebody walks into the hallway. If the hallway is actually dark, the light comes on, warm and dimmed. If it is the middle of the afternoon, nothing happens.

BlockWired
presence detectedroom Hallway, device pin empty
get device statedevice from the trigger's device id, capability illuminance
<the state block's number pin against 30
branchflow from the state block, condition from the comparison
light onon the branch's true pin, device Hallway ceiling, brightness 40, kelvin 2700
  • Device pin empty, room pin set. One block covers every motion sensor in the hallway. Add a second sensor later and it works with no edit.
  • The lux reading comes from the sensor that fired, by feeding the trigger's device id into get device state. Most motion sensors report lux as well as occupancy. Hard-code another sensor's id when the motion sensor has no light meter.
  • Brightness and kelvin ride along on light on. One command means the lamp transitions once instead of visibly jumping to full white first.
  • It fires on the transition, so somebody standing still does not re-run this every thirty seconds and fight anyone who dimmed the lamp by hand.
  • Turning it off is a separate flow: presence cleared, room Hallway, into light off. The delay before it fires is the sensor's own stillness timeout, usually 60 to 120 seconds. If you want longer, put a delay block in front of the light off.

The most common automation there is. presence detected fires on the false to true transition of occupancy in the hallway, so somebody standing still does not re-run it. Its device id feeds get device state, which reads the illuminance the same sensor reports; < compares that against 30 lux and branch only lets light on run when the room is actually dark.

Studio canvas example for the presence detected block: motion, but only after dark.

2. A door opens while nobody is home

What it does. The front door opens. If no motion sensor anywhere in the house currently reads occupied, that is worth a notification.

BlockWired
contact openeddevice Front door
get active sensorssensor type occupancy, room empty
==the query's count against 0
branchtrue pin into the notification of your choice
  • "Nobody home" is derived, not tracked. get active sensors reads the in-memory registry, so asking costs nothing, and asking at the moment the door opened is more accurate than a flag some other flow maintains.
  • Use the trigger's name and at pins in the message. "Front door opened at 14:32" is a useful notification; "a contact sensor changed" is not.
  • A sensor the node has not heard from is excluded rather than counted as inactive. A device that has never reported since it was adopted is invisible to this flow.
  • Occupancy decays. A sensor that read occupied when the node went down is restored as occupied, and stays that way until it reports again.
  • Occupancy is not presence. A motion sensor reads false when a person sits still. A phone or a presence-detection radar such as an FP2 (which reports occupancy continuously rather than on motion) is the better input if false positives are unacceptable.

3. A leak shuts the valve and raises an alarm

What it does. A leak sensor finds water. A smart valve closes, and somebody is told.

BlockWired
water leak detecteddevice and room both empty: any leak sensor anywhere
switch offdevice Water valve
branchcondition from the switch block's ok pin
notificationon both branches, with different text
  • The device pin is empty on purpose. Enumerating sensors means the one you install next year is not covered.
  • The valve comes before the notification. It limits the damage, and should not wait on an email API.
  • The branch on ok is the important part. "Leak detected in the basement, valve closed" and "Leak detected in the basement, VALVE DID NOT RESPOND" call for different human behaviour.
  • Repeated firing is not a problem. A sensor sitting in a puddle and re-reporting does not send thirty notifications. It fires again only if the sensor dries out and gets wet again.
This supplements a plumber and a water alarm It does not replace them. It depends on a mesh, a broker and a node all being up.

4. A double press sets a scene

What it does. One button, three behaviours: single press toggles the lamp, double press sets a warm evening scene across several lamps, hold turns everything off.

BlockWired
button presseddevice Living room button
switchexpression from the trigger's value pin
light toggleon the single case
three light on blockson the double case, each with its own brightness and kelvin
light off blockson the hold case
  • A scene is a few blocks in a row, not a stored object. So it can read the time, check who is home, or vary by season.
  • Find out what your button sends before you write the cases. Aqara buttons send single, double and hold; a Hue dimmer sends initial_press, short_release and long_release; a four-button remote prefixes each with the button number. Press it once with the Zigbee2MQTT frontend open, or read get device and look at state.action.
  • Every press fires, so pressing the same button twice runs the flow twice.

5. A temperature crossing runs the air conditioning

What it does. The office passes 25 °C during the day, so the air conditioner starts cooling to 22 on a quiet fan. When it drops back below 22, the unit goes off.

BlockWired
temperature changedroom Office, above 25
climate setdevice Office AC, mode cool, target 22, fan silent
and a second, separate flow:
temperature changedroom Office, below 22
climate setdevice Office AC, mode off
  • It depends on crossing semantics. A thermometer reporting every minute produces hundreds of readings above 25. Because above fires on the crossing, the unit is told once.
  • The two thresholds are different numbers. Cooling starts at 25 and stops at 22, so the unit does not switch on and off every time the reading wobbles across one value. Picking that gap (hysteresis) is yours to do.
  • Mode, target and fan go in one climate set. A Daikin local API rejects partial updates and resets anything you leave out, so the adapter reads the whole control block, applies your changes and writes it back as one operation. Three blocks would be three cycles, and an occupant can hear the unit stepping through them.
  • A mode other than off implies switching the unit on, so there is no separate power step.
  • The Daikin adapter polls. With the default 30 second interval, the temperature RUAL reacts to can be up to 30 seconds old. A Zigbee or Z-Wave thermostat pushes and has no such delay.

6. Energy over a threshold raises a warning

What it does. A metering plug reports power draw. When something on that circuit pulls more than 2400 W for more than a minute, warn.

BlockWired
device state changeddevice Utility plug
==the trigger's capability pin against power_watts
>the trigger's value pin against 2400
ANDboth conditions
branch, delay, get device state, >, branchwait 60 seconds, re-read power_watts, and only warn if it is still high
  • There is no power changed trigger. Only temperature and humidity have dedicated threshold triggers, so anything else numeric goes through device state changed with a check on the capability pin. The device pin narrows it to that one plug.
  • The delay-then-recheck is the point. A kettle pulls 2400 W for ninety seconds every morning. You want a load that is still drawing when you look again, and the registry already knows the current value, so re-asking is free.
  • Watch the concurrency budget. At most 16 device flows run at once, and a delay holds one of those slots for its whole duration. One minute is fine. If you want ten, move the waiting into the queue or a repeating event.
  • For totals rather than spikes, do not accumulate in a flow. The node can hand you consumption per hour or per day: see Device History and Energy.

7. The house empties, every light goes off

What it does. The last occupancy sensor clears. Every light that is currently on is switched off, without naming any of them.

BlockWired
presence cleareddevice and room empty
get active sensorssensor type occupancy
== and branchcount against 0: nobody anywhere
get lights that are onroom empty
select field valuesthe devices array, field id
mapthat array of ids
execute and light offthe map's function pin drives the execute block, whose value pin is one device id, into the light off device pin
  • The result is derived from live state, not from a list of light names you maintain. Install a lamp next year and it is covered.
  • select field values sits between the query and the map because the query returns device objects and light off wants a device reference.
  • Only lights that are actually on are touched. Lamps whose state the node does not know are excluded rather than assumed off.
  • The re-check matters. presence cleared with an empty device pin fires when any sensor clears. Asking get active sensors whether anything is still occupied turns "a sensor cleared" into "the house is empty".
  • For a per-room version, set the room pin on both the trigger and the query, and drop the whole-house check.

get lights that are on reads the in-memory device registry, so it makes no network call and is cheap enough to run in a loop. It returns only lights whose power state is KNOWN and true: a lamp the node has not heard from since it started is left out rather than assumed off. The count pin feeds > and branch, which is the shape of "if anything is still on, do something about it".

Studio canvas example for the get lights that are on block: asking the registry which lights are on.

8. Auto-adopting a new device into a room

What it does. While you are commissioning a floor, every device that pairs is adopted, named after its model and placed in the room you are working in, without a trip to the API for each one.

BlockWired
device discovereddevice and room empty
get value variablea variable holding the room you are commissioning, for example commissioning_room
device adoptdevice from the trigger's device id, room from that variable, name from the trigger's name pin
branchon the adopt block's newly pin, into a notification or a log document
  • device discovered is the only trigger that fires for unadopted devices. It fires once per device, the first time it is ever seen.
  • device adopt takes name and room pins, so onboarding is one block. If the rename half fails the adoption still stands: ok stays true, and the error pin carries the rename failure.
  • Branch on newly, not on ok. Adoption is idempotent, so notifying on ok would announce devices that were already yours.
  • Prefer this to auto_adopt = true. The config flag adopts everything the radio can hear, forever. This flow is a switch: keep it deactivated, activate it while you are physically commissioning, and deactivate it when you are done. No restart is needed.
  • A safer variant: wire device discovered into a notification carrying name and device id, and adopt from the studio when you recognise it. That is the right default for a mesh that is not brand new.

9. An unknown card at three in the morning

What it does. Somebody is refused at the front door. During the day that is a colleague with an expired badge and not worth a message; at night it is worth waking up for. Meanwhile every successful entry is logged with who and how.

BlockWired
access denieddevice empty: any door
date now, branchoutside working hours
notificationwith the trigger's name, actor and method pins
and a second flow, for the log:
access granteddevice empty
create documenta storage document carrying actor, method, name and at
  • The actor, method and granted pins are on the trigger itself. "Access denied at Front door, unknown card, nfc" is actionable; "a door reported something" is not.
  • Denied and swiped are different triggers. access denied fires on the decision. To react to a specific card regardless of the decision, use NFC card swiped with its card pin.
  • Write the log with a flow, not with history. Access events are recorded in device history, but "who came in last month" is a table you will want to query, filter and export. A storage document per entry gives you that.
Do not wire doorbell rang straight into gate open A doorbell is an unauthenticated button anyone can press. Put a branch in between that checks something: a delivery window, a person at home, a specific NFC token.

Patterns worth reusing

When you wantReach for
One flow covering a whole room or the whole houseLeave the trigger's device pin empty, set the room pin
A condition about the world right nowA query block: they read memory and cost nothing
To know whether a command actually landedBranch on ok, not on the returned device state
To act on a device the trigger identifiedFeed the trigger's device id into the next block's device pin
To act on many devices at onceQuery, select field values for id, map, command
A numeric capability with no dedicated triggerdevice state changed narrowed to one device, then check the capability pin
To avoid reacting to a momentary spikedelay, then re-read with get device state
To answer a question about the pastget device history, not a variable you maintain

Next steps

Device History and Energy Questions about the past: what is recorded, and how to read it back. Troubleshooting When one of these does not fire, this is the checklist. Common Blueprint Patterns The general-purpose shapes these flows are built from.

Frequently asked

How do I turn on a light only when it is dark in RUAL?

Wire presence detected into get device state reading the illuminance capability of the same sensor, compare that number against a lux threshold, and put a branch in front of light on. Most motion sensors report lux as well as occupancy, and the reading from the sensor that fired describes the space it is watching.

How do I turn off every light in RUAL without naming them?

Feed get lights that are on into select field values for the id field, then into map, and drive light off from the execute block inside the map. The query returns only lights whose power state is known and true, so lamps the node has not heard from are left alone rather than blasted with commands.

How do I automatically adopt new smart home devices in RUAL?

Wire the device discovered trigger into the device adopt block, which takes optional name and room pins so onboarding is a single block. Keep that flow deactivated and activate it only while you are physically commissioning hardware, which is safer than the auto_adopt config flag because that adopts everything the radio can hear, forever.