Yes — you don't need to keep the ESP32 stuck in a while True + sleep loop for this. system.schedule() is meant for exactly this kind of periodic work.
For example, to read a sensor every 5 seconds:
import system
def read_sensor():
print("reading sensor")
system.schedule("sensor_reader", 5000, 5000, -1, read_sensor)
This waits 5 seconds, calls read_sensor(), and then keeps calling it every 5 seconds. The -1 means it will continue indefinitely.
The useful part is that your script isn't sitting inside a blocking sleep loop while it waits. The device can continue dealing with things like Wi-Fi, MQTT messages, callbacks, or camera work between runs.
You can also pass arguments directly to your scheduled function:
import system
def read_sensor(sensor_name, pin):
print("reading", sensor_name, "on pin", pin)
system.schedule(
"dht_reader",
5000,
5000,
-1,
read_sensor,
"dht22",
4
)
Every five seconds that effectively calls:
read_sensor("dht22", 4)
The first argument, "dht_reader", is more than just a label. It gives the scheduled task an identity, which means you can stop it later:
system.cancel("dht_reader")
One easy mistake to avoid: pass the function itself, not its name as a string.
# Correct
system.schedule("sensor_reader", 5000, 5000, -1, read_sensor)
# Wrong
system.schedule("sensor_reader", 5000, 5000, -1, "read_sensor")
Studio handles converting the function reference into the callback representation expected by the firmware.
So for periodic sensor reads, telemetry publishing, status checks, and similar background jobs, I'd generally use system.schedule() rather than building the application around a sleeping loop.
For reference, the full signature is:
system.schedule(name, interval_ms, delay_ms, repeats, callback, *callback_args)
Use delay_ms=0 if you want the first run immediately, and use repeats=-1 when the task should keep running until you explicitly cancel it.