AI Automation Scripts
Describe an outcome. Get a clean Python script in ~60 seconds. Adjust it when you want in SIMO.io Admin. Fewer surprises, calmer results.
Homes don’t run on rules; they run on rhythm. People wake up early in winter and late in summer. Guests arrive without warning. School bags get dropped by the hallway sensor every afternoon. Most automation systems try to tame that with diagrams, checkboxes, and pages of options. SIMO.io takes a simpler path: you describe the outcome in plain language, we produce a clean Python script you can read, and your SIMO.io hub carries it out. The goal is simple: predictable behavior that feels natural, without a weekend lost to debugging.
If you’ve ever fought a fragile rules engine, you already know the failure modes: one broken link, one renamed scene, one bit of indentation in a YAML file—and the whole routine doesn’t fire. The difference here isn’t just technology. It’s posture. We treat automation as software, not a puzzle. Scripts are standard, inspectable, and easy to adjust. You can tell what they do at a glance, you can explain them to someone else, and you can trust them to behave the same way in August as they do in February.
The promise: clear instructions, clear behavior
Write what you want to happen. SIMO.io turns that into a Python script in about a minute and adds it to your home as a first‑class component. From there it does the boring work the right way: listen for events, check if now is the right time, and act with restraint. One gentle note on the path from request to result: the script is generated in the SIMO.io cloud once, then it runs on your SIMO.io hub from that point onward. That’s it. What matters more is how it feels to live with it.
We aim for three sensations that make a home feel considered rather than automated:
- Steady comfort: temperature and lighting behave like a considerate person is watching, not a timer. A bathroom holds 22 °C (71.6 °F) just before you step in. Corridor lights lift to a quiet 30% for a late glass of water.
- Predictable results: routines do the same thing every day, and they do nothing when they shouldn’t. Motion at noon isn’t treated like motion at 02:00. A guest’s manual change isn’t immediately undone by a background rule.
- Fewer manual tweaks: once a script understands intent and context, you stop babysitting it. If you need to adjust behavior, you change the script in Django Admin like you’d edit a paragraph.
Why scripts beat switchboards and brittle YAML
Automation rules can look friendly at first. Then the edge cases show up. A “simple” adjustment to quiet‑hours ends up touching five places. A renamed room breaks an include you didn’t know was there. A copy‑pasted block keeps an old ID lurking in it. Systems that hide complexity in boxes and lines often make it harder to see what will happen next.
Python scripts are plain language for behavior. You can read a function called on_motion and know what it does. You can keep logic in one place instead of four. You can extract a guard like “is it after dark?” and reuse it across rooms. When something goes wrong, the log points to a specific line, not a silent black hole. And when your projects get serious—multi‑room, multi‑floor, multi‑tenant—the same standard tools work: naming, versioning, code review, shared helpers, tests if you want them. No mysteries. No spelunking.
- Readable by design: event → guard → action is easier to reason about than a tangle of triggers.
- Standard tools: linters, diffs, and editors understand scripts. You can keep a tidy playbook.
- Reusable helpers: quiet hours, presence heuristics, thresholds—refactor once, reuse forever.
- Clear errors: exceptions and prints tell you what happened and why.
- Fewer surprises: indentation in YAML can sink a day; scripts are explicit and testable.
What it’s like to live with
We’ve seen homes with a dozen motion sensors and still‑flickery hallway lights. We’ve seen heating rules that behave like a metronome—on, off, on, off—because the weather wasn’t part of the conversation. The scripts SIMO.io generates favor calm decisions over busy ones. They check the current state, make a change only when it improves things, and never fight a human who just made a choice at the switch.
Here’s the texture of day‑to‑day:
- A presence script sets corridor lights to a soft level in the evening and lets them fade out a few minutes after the last movement.
- A morning script holds a bathroom at 22 °C (71.6 °F) for a short window, then gets out of the way. You don’t wake up to a sauna if you slept in.
- A leak routine shuts the right valve and messages the right person without blasting the whole house awake.
- A guest mode, toggled via a quick double‑click, keeps lights at 60% while the conversation spills past midnight.
The pattern is consistent: scripts listen; they check a guard; they act with restraint. If someone chooses a different level by hand, a good script won’t rush to override it. That’s not a special toggle—it’s a posture.
From request to result in one minute
You write a line or two in the SIMO.io app—“When hallway motion is detected after dark, lift lights to 30% and hold for 2 minutes”—and save. About a minute later, a Script component appears. That’s your Python script. You can run it like any other component, you can see its description, and, if you want to change how it works, you can open it in SIMO.io Admin and edit it directly.
For precision, include IDs in your request when you know them—component IDs, zone IDs, category IDs. Names can change; IDs don’t. But you don’t need to be formal to get started. Natural language is enough for a first pass; you can iterate.
Real‑life example: hallway presence with a guest mode
Let’s walk a hallway most homes recognize. It’s the path between bedrooms and kitchen, the late‑night water run, the route children turn into a track. You want it to be helpful at night and invisible during the day. You want guests to feel welcome without fuss. Here’s the exact request and the script SIMO.io produces.
The request (as written in the app)
“When motion is detected in the Hallway (zone 12) after dark and hallway brightness is below 50 lux, set corridor lights to 30% and keep them on for 2 minutes after the last motion. If someone manually sets a higher level, don’t lower it. Double‑clicking the hallway button (component 455) toggles a 20‑minute guest mode: hold lights at 60% and skip auto‑off. Corridor lights are in category 3. Motion sensor ID is 812. Lux sensor ID is 710.”
Generation takes roughly a minute. SIMO.io returns a Python script plus a short description that appears in the app. You can run it as-is, or open SIMO.io Admin to refine details.
The generated script (open in Django Admin to edit)
from django.db.models import Q
from django.utils import timezone
import time
from simo.core.models import Component
from simo.generic.scripting.helpers import LocalSun
class Automation:
# IDs and thresholds
LIGHTS_CATEGORY = 3 # "Lights" category
HALLWAY_ZONE_ID = 12 # Hallway zone
MOTION_SENSOR_ID = 812 # Motion/presence sensor (binary-sensor)
LUX_SENSOR_ID = 710 # Lux sensor (numeric-sensor)
BUTTON_ID = 455 # Hallway button (button)
TARGET_DIM = 30 # % for normal presence lighting
GUEST_DIM = 60 # % during guest mode
HOLD_SECONDS = 120 # 2 minutes
GUEST_MODE_SECONDS = 20 * 60 # 20 minutes
DARK_LUX = 50 # lux threshold for "dark"
def __init__(self):
self.last_motion_ts = 0
self.guest_mode_until = 0
self.managed = {} # comp_id -> level we set ('on' or int %)
self.light_watch = set()
def now(self):
return timezone.localtime().timestamp()
def in_guest_mode(self):
return self.now() < self.guest_mode_until
def is_dark(self):
lux = Component.objects.filter(id=self.LUX_SENSOR_ID, base_type='numeric-sensor').first()
if lux and lux.value is not None:
try:
return float(lux.value) < self.DARK_LUX
except Exception:
pass
return LocalSun().is_night()
def corridor_lights(self):
return Component.objects.filter(
zone_id=self.HALLWAY_ZONE_ID,
category_id=self.LIGHTS_CATEGORY,
base_type__in=('switch', 'dimmer', 'rgbw-light')
)
def on_light_change(self, comp, actor=None):
prev = self.managed.get(comp.id)
if prev is None:
return
try:
if comp.base_type == 'dimmer':
current = comp.value if isinstance(comp.value, (int, float)) else None
if current is not None and int(current) != int(prev):
self.managed.pop(comp.id, None)
else:
self.managed.pop(comp.id, None)
except Exception:
self.managed.pop(comp.id, None)
def ensure_watch_lights(self):
for comp in self.corridor_lights().exclude(id__in=self.light_watch):
comp.on_change(self.on_light_change)
self.light_watch.add(comp.id)
def set_light_level(self, comp, level):
try:
if comp.base_type == 'dimmer':
current = comp.value if isinstance(comp.value, (int, float)) else 0
# Only raise; do not lower manual overrides
if float(current or 0) + 0.1 < level:
print(f"[Hallway] Set dimmer {comp.id} to {level}%")
comp.send(int(level))
self.managed[comp.id] = int(level)
else:
if not comp.value:
print(f"[Hallway] Turn on light {comp.id}")
comp.turn_on()
self.managed[comp.id] = 'on'
except Exception as e:
print(f"[Hallway] Failed to set light {comp.id}: {e}")
def turn_off_managed(self):
for comp in self.corridor_lights():
if comp.id not in self.managed:
continue
try:
if comp.base_type == 'dimmer':
expected = self.managed.get(comp.id)
current = comp.value if isinstance(comp.value, (int, float)) else None
if current is not None and int(current) == int(expected):
print(f"[Hallway] Auto-off dimmer {comp.id}")
comp.turn_off()
else:
if comp.value:
print(f"[Hallway] Auto-off light {comp.id}")
comp.turn_off()
except Exception as e:
print(f"[Hallway] Failed to turn off {comp.id}: {e}")
self.managed.clear()
def on_motion(self, sensor, actor=None):
if sensor.value:
self.last_motion_ts = self.now()
print("[Hallway] Motion detected")
if self.in_guest_mode():
for comp in self.corridor_lights():
self.set_light_level(comp, self.GUEST_DIM)
return
if self.is_dark():
for comp in self.corridor_lights():
self.set_light_level(comp, self.TARGET_DIM)
else:
print("[Hallway] Motion cleared")
def on_button(self, btn, actor=None):
if btn.value == 'double-click':
if self.in_guest_mode():
self.guest_mode_until = 0
print("[Hallway] Guest mode OFF")
else:
self.guest_mode_until = self.now() + self.GUEST_MODE_SECONDS
print("[Hallway] Guest mode ON (20 min)")
for comp in self.corridor_lights():
self.set_light_level(comp, self.GUEST_DIM)
def run(self, exit):
motion = Component.objects.filter(id=self.MOTION_SENSOR_ID, base_type='binary-sensor').first()
if motion:
motion.on_change(self.on_motion)
btn = Component.objects.filter(id=self.BUTTON_ID, base_type='button').first()
if btn:
btn.on_change(self.on_button)
self.ensure_watch_lights()
while not exit.is_set():
time.sleep(1)
self.ensure_watch_lights()
if not self.in_guest_mode() and self.last_motion_ts:
if self.now() - self.last_motion_ts > self.HOLD_SECONDS:
print("[Hallway] No motion; auto-off lights I set")
self.turn_off_managed()
self.last_motion_ts = 0
The plain‑language description (as shown in the app)
“When the hallway motion sensor (ID 812) detects movement after dark (lux sensor 710 < 50 lx or after sunset), the script raises corridor lights (category 3 in zone 12) to 30% and keeps them on for 2 minutes after the last motion. If someone manually sets a higher level, the script will not lower it. A double‑click on the hallway button (ID 455) toggles Guest Mode for 20 minutes: lights are held at 60% and the auto‑off is skipped. The script listens to sensor and button events and only turns off the lights it turned on.”
Two details worth noting. First, the script never argues with a person—it won’t lower a manual override. Second, the auto‑off only targets lights it turned on, not everything in the zone. That’s the difference between living with automations and living inside them.
How to ask for what you want (and get it right)
Requests don’t need to be formal. Start with normal language and add specifics when you know them. The generator understands zones, categories, and IDs; the more precise you are, the less guessing it has to do. A few patterns help:


- State the trigger and the guard: “When there is motion in the hallway after dark…” reads better than “Turn on hallway lights.”
- Say the action and the limit: “Set corridor lights to 30% and hold for 2 minutes after the last motion.”
- Add IDs where you can: zone 12, category 3, component 812. Labels are for people; IDs are for scripts.
- Include exceptions: “Do not lower a higher manual setting.” These avoid fights at the switch.
- Prefer outcomes over mechanics: tell the script what should be true, not how to press buttons.
If you’re not sure about IDs, ask the app: long‑press a component to see its details, or browse by category. You can always refine the request later—regenerating the script is fast.
A pattern that scales with your home
Every script that behaves well tends to read the same way: an event arrives, a guard decides if it’s the right moment, and an action makes the change. That’s not a style preference; it’s a reliability habit. The shape makes it obvious what happens, when, and why.
- Event: motion, door opened, alarm armed, sunrise, price change.
- Guard: should we act now? Quiet hours? Anyone home? Already at the requested state?
- Action: raise a light, hold a temperature, open a blind, send a message.
It’s a small discipline that pays back on day one and again on day 300—especially when someone else has to read the script after you.
For professionals and tinkerers: edit in Django Admin
The SIMO.io app is the fastest way to describe and deploy. When you want to refine behavior, open SIMO.io Admin. The script is right there, readable, editable, with live logs at your side. You can factor out a shared helper, tidy naming, and keep a consistent style across rooms and floors. The hub executes the script after generation; your edits apply immediately.
- Iterate faster: tweak a threshold, save, watch the log reflect your change in real time.
- Keep symmetry: extract a “quiet hours” guard once and reuse it in similar rooms.
- Stay considerate: design for minimal intrusion—never undo a manual action without a reason.


None of this demands a “developer” title. It rewards anyone who wants a home to behave with precision without turning into a hobby.
Script etiquette: little rules that keep the peace
Homes have people in them. Good scripts respect that. A few guidelines we like and the generator favors:
- Don’t fight the hand: if someone makes a manual change, assume they had a reason. Don’t lower a higher setting without a guard that says you should.
- Be specific, not busy: act only when the guard says it’s time. Idle scripts are quiet scripts.
- Hold, then release: time‑boxed holds (2 min in a corridor, 30 min in a bathroom) feel natural and leave minimal footprints.
- Use IDs for targets: labels are for people; IDs are stable for scripts. It saves future confusion.
- Log clearly, not constantly: a handful of good prints beat a flood of noise.
The result is a home that feels like it understands you rather than second‑guesses you.
Beyond the hallway: a few ideas you’ll recognize
Once you get the taste for scripts you can read, it’s hard to go back to boxes and lines. These are the kinds of everyday wins that show up early:
- Kitchen presence + daylight: keep 300–500 lux on the worktop by blending dimmers with outside light, then step down to 100 lux for late tea.
- Stair treads: low, safe illumination from dusk to dawn, lifted only when movement is detected on the landing.
- Good‑night routine: arm perimeter groups, lock doors, set blinds to closed, drop everything else to off, and leave a path to the bedroom.
- Dawn warm‑up: hold bathrooms at 22 °C (71.6 °F) 30 minutes before the first alarm, then release so the house doesn’t cook empty rooms.
- Leak discipline: shut the right valve, kill a single outlet, and message the owner—not the whole street.
Each of these reads as plain intent. Each becomes a Python script that’s easy to revisit three months later when you decide you prefer 25 minutes to 20.
What makes this sustainable over years
Homes grow, projects evolve, preferences change. The long‑term cost of an automation system isn’t in the first setup; it’s in the fifth change. A Python script that says exactly what it does is future‑proof in a way a chain of rules never quite is. The minute you see the pattern—event, guard, action—you can scan a script and know where to change it. There are fewer places for “that one hidden dependency” to hide.
It’s also easier to scale a way of working. If you’re an integrator, you can keep a small set of helpers—guards for quiet hours, presence heuristics, target curves for dimming—and drop them into new homes with confidence. If you’re a homeowner who likes to tinker, you can keep your own archive of scripts that feel right for your spaces. Either way, tweaks are fast because the shape stays familiar.
The best compliment we hear is simple: “I forgot it was there.” That’s the job. Automations should fade into the background until you need them—and then be obvious enough to change in one pass.
Describe outcomes. Get a Python script. Live in a home that behaves with you, not at you.