Events

Run timer, GPIO-edge, and Wi-Fi lifecycle handlers at safe points without blocking the prompt.


Events let the device react later while the prompt stays available. Frothy records a small handler, receives timer or hardware candidates, and runs the handler at a safe statement boundary.

Timers And A Button

Event registration belongs inside a word:

to start-ticks [
  every 1000 [ print: "tick\n" ]
]

to stop-later [
  after 10000 [ led.off: ]
]

to watch-button [
  on $boot_button falling debounce 25 [
    led.toggle:
  ]
]

start-ticks:
stop-later:
watch-button:

every repeats. after removes itself before its body runs. The GPIO handler can use rising, falling, or changes; debounce is optional. The current profile allows one event body per definition, so each source gets one small registration word.

Event Forms

FormIdentityBehavior
every ms [body]kind plus millisecond valueRepeats until cancelled or cleared
after ms [body]kind plus millisecond valueRuns once, then disappears
on pin edge [body]GPIO pinRuns on the selected edge
on pin edge debounce ms [body]GPIO pinDrops candidates inside the debounce window
on wifi.disconnected [body]Wi-Fi stateRuns after a previously working connection drops
on wifi.reconnected [body]Wi-Fi stateRuns when that connection returns
cancel ...matching source identityRemoves one registration

Cancel And Replace

Use the same identity used at registration:

cancel every 1000
cancel after 10000
cancel $boot_button
cancel wifi.disconnected
cancel wifi.reconnected

Timer identity includes both kind and period, so every 1000 and after 1000 are different registrations. GPIO identity is the pin alone: registering a new edge handler for the same pin replaces the old one, and cancel pin removes it regardless of edge or debounce. Each Wi-Fi lifecycle kind has one binding.

The current runtime holds 16 event bindings in total. Re-registering a matching identity replaces it without consuming another slot. mem events shows used and total capacity; events lists the active registrations.

Handler Scope

Event bodies do not capture the parameters or here locals of the word that registered them. Use top-level names or call another top-level word:

presses is 0

to count-press [
  set presses to presses + 1
]

to arm-button [
  on $boot_button falling debounce 25 [ count-press: ]
]

This keeps a handler valid after the registration call has returned.

Dispatch And Output

Candidates arrive asynchronously, but handler code runs in the Frothy runtime at safe points: statement boundaries, loop back-edges, and word returns. A long single expression can delay delivery until the next such point. Handlers do not interrupt one another recursively.

Output produced outside the foreground reply is prefixed with ! on the wire:

! tick

If the platform queue overflows, Frothy reports ! events dropped: N. Keep handlers short and move sustained work into ordinary foreground code when possible.

Wi-Fi Lifecycle

Register Wi-Fi handlers before connecting:

to watch-wifi-down [
  on wifi.disconnected [ print: "wifi down\n" ]
]

to watch-wifi-up [
  on wifi.reconnected [ print: "wifi back\n" ]
]

watch-wifi-down:
watch-wifi-up:
wifi.connect:

The first successful connection is not a wifi.reconnected event. These forms describe a drop and recovery after the device has already obtained an address. See Wi-Fi, HTTP & TCP for connection behavior.

Persistence And Clearing

Event registrations are part of the project overlay. save persists them, restore reinstalls them, and clear or a project wipe removes their live platform registrations. Use events after restore to inspect what is active.

Timers and GPIO handlers are for human-scale asynchronous work. For captured or emitted edges with 100-nanosecond quantization, use Digital signals .