Skip to content

ODevice Recipes

Copy-paste patterns for common tasks.

Recipe 1: Basic read-only sensor

python
from odevice import App, Device, Number

app = App("Sensors")
sensor = Device(id="s1", name="Temp", properties={"temp": Number(unit="°C")})
app.add(sensor)
sensor.update(temp=22.5)
app.run()

Recipe 2: Writable switch with backend

python
from odevice import App, Device, Boolean

app = App("Controls")
relay = Device(id="r1", name="Relay", properties={"on": Boolean(writable=True)})
app.add(relay)

@relay.on_write("on")
async def set_relay(value):
    await your_backend.set_relay(value)
    return value

app.run()

Recipe 3: Gauge with deadband

python
pressure = Number(unit="bar", min=0, max=10, view="gauge", deadband=0.1, max_rate=2)

Recipe 4: Enum mode selector

python
mode = Enum(options=["auto", "manual", "off"], writable=True)

Recipe 5: Poll a REST backend

python
async def poll():
    while True:
        data = await httpx.get("http://api/status").json()
        device.update(rpm=data["rpm"])
        await asyncio.sleep(1)

Recipe 6: MQTT bridge

python
def on_message(client, userdata, msg):
    sensor.update(temperature=json.loads(msg.payload)["temperature"])

Recipe 7: Multiple devices

python
for i in range(3):
    app.add(Device(id=f"pump-{i}", name=f"Pump {i}", properties={...}))

Recipe 8: Embed in existing FastAPI app

python
runtime = App("Embedded")
runtime.add(device)
fastapi_app = await runtime.run_async()  # returns FastAPI app

Recipe 9: Custom view override

python
Number(unit="kW", view="trend")  # force trend chart

Recipe 10: Viewer-only demo user

python
runtime = App("Demo")
# bootstrap creates 'admin'. Add a viewer:
runtime.auth.create_user("viewer", "password123", "viewer")
runtime.run()

Recipe 11: Stateless action button

python
pump.action("reset", label="Reset Pump", severity="danger", confirm="Sure?")

@pump.on_action("reset")
async def do_reset():
    await backend.reset()

Recipe 12: Warning threshold

python
# property must allow it
pressure = Number(unit="bar", min=0, max=10, configurable={"warning": True})

app.add_warning("pump-01", "pressure", ">", 8.0, duration=5, severity="warning")

Recipe 13: Automation (condition -> command)

python
power = Boolean(writable=True, automation={"allow_set": True})

app.add_automation("High Pressure Stop",
    when={"entity": "pump-01", "property": "pressure", "operator": ">", "value": 9, "duration": 3},
    then={"entity": "pump-01", "property": "power", "operation": "set", "value": False},
    cooldown=30)

Recipe 14: Daily schedule

python
app.add_schedule("Morning Start", "Asia/Bangkok",
    schedule={"type": "daily", "time": "08:00"},
    action={"entity": "pump-01", "property": "power", "operation": "set", "value": True})

Recipe 15: Backend-declared page with grid

python
app.add_page(Page(id="reports", title="Reports", icon="chart",
                  columns=2, density="compact",
                  sections=[Section(title="Pump", entities=["pump-01"])]))

Recipe 16: Map / location widget

python
from odevice import Location
tracker = Device(id="t1", name="Tracker",
                 properties={"pos": Location(lat=13.7, lng=100.5)})

Built for self-hosted IoT runtimes.