Skip to content

Event-driven programming

An event-driven program waits for things to happen, and runs a piece of code for each one. A button press, a timer tick and an incoming network message are all events. The code that handles one is often called a handler.

The loop you may know

Most microcontroller programs start as a loop:

while True:
    if button.value() == 0:
        led.on()
    temperature = sensor.read()
    time.sleep(0.1)

Every job lives inside the loop, and each one waits for the others. A slow sensor read delays the button check. A sleep long enough to pace one job stalls all of them. Adding a job means reworking the timing of the rest.

The same program, as events

Written as events, each job stands on its own:

  • when the button pin falls, turn the LED on
  • every 10 seconds, read the sensor

Nothing is checked in a loop. The board sleeps until an event arrives, runs its handler, and waits again. Jobs with different timing don't get in each other's way.

How Thingstudio does it

Thingstudio is built on asyncio, MicroPython's built-in module for event-driven programming. It provides an event loop: one scheduler that runs many tasks, switching between them whenever one is waiting.

In Thingstudio, each chain of nodes that starts at a source (a timer, an interrupt, an mqtt subscribe) is one handler. When you deploy, the flow is turned into MicroPython code in which each source becomes an asyncio task. While one task waits, for a timer or the network, the others run.

The one rule: don't block

Everything shares one event loop. A handler that stops and waits without handing control back stops every other handler too. In a function node, that means no time.sleep() and no long loops.

To wait, use a node built for it: delay waits, timer repeats. They hand control back while they wait. Inside a function node, await asyncio.sleep(1) does the same:

await asyncio.sleep(1)
return msg

More

Further reading: