A small temperature alarm in Toit 2.0
A temperature alarm needs a little memory. Switch it on at 30°C, keep it on while the reading drifts down, and switch it off at 27°C. That gap stops a sequence like 30, 29, 30, 29 from repeatedly changing the alarm state.
I used that small task to try Toit 2.0. The release is a useful excuse to look beyond blinking an LED: the same language also runs host scripts, so the decision logic can be exercised before connecting a sensor. [1][2]
Start with the state you want
There are two states, on and off. A reading at or above 30 sets the state to on. A reading at or below 27 sets it to off. Everything between those limits leaves it alone. This is hysteresis: the current reading does not completely determine the output; the previous state matters too.
The initial state is part of the design. In this example it is off, so starting at 29°C leaves the alarm off. Arriving at the same temperature after a 30°C reading leaves it on. Neither case is an accident.
!Synthetic temperature trace with an alarm turning on at 30 degrees, holding through 29, and turning off at 27.
Original plot from the executed synthetic sequence. Sample positions are ordered readings, not elapsed seconds.
Run the whole program
Get the archive that matches your platform from the official v2.0.0 release, extract it, and put its bin directory on your PATH. Check the selected runtime:
toit --version
Mine returned v2.0.0. Save this as sensor.toit:
main:
readings := [28, 30, 29, 30, 29, 27, 29, 31]
alarm := false
readings.do: |temperature|
if temperature >= 30:
alarm = true
else if temperature <= 27:
alarm = false
print "$temperature C: $alarm"
Then analyze and execute it:
toit analyze sensor.toit
toit run sensor.toit
The analyzer completed successfully. The program printed:
28 C: false
30 C: true
29 C: true
30 C: true
29 C: true
27 C: false
29 C: false
31 C: true
The syntax takes a moment to read if you normally use Python. := introduces a local variable; = changes it. readings.do: calls a block for each value, and |temperature| names the block's parameter. The string interpolates both variables. [3]
The missing assignment does the work
There is deliberately no final else. At 28 or 29, the program does not assign to alarm, which preserves the previous state. Replacing that block with alarm = temperature >= 30 would throw the memory away.
For this exact sequence, including the initial off state, the single-threshold rule changes state five times. The hysteresis rule changes it three times. Those are properties of this synthetic input, not measurements of a physical sensor or proof that these thresholds suit a device.
I also ran separate inputs for an empty list, each exact threshold, a starting value inside the gap, a descending sequence, and repeated boundary readings. They behaved as specified. A real device still needs decisions about missing readings, units, startup behavior and what should happen if its process restarts.
Toit 2.0's announcement includes a peripheral API change that accepts pin numbers directly. That is relevant when taking the next step onto supported hardware, but this program uses no GPIO, board or sensor. [1] It is a small, completed host-side example you can change without wiring anything first.
References
1. Florian Loitsch, Toit v2.0.0 and the official release.
2. Toit contributors, Learn Toit.
3. Toit contributors, language source and standard library.
Asset credits
Original chart made from the synthetic program output; no third-party image assets.
AI disclosure
AI was used to draft the article.
Mentions
A small temperature alarm in Toit 2.0 A temperature alarm needs a little memory. Switch it on at 30°C, keep it on while the reading drifts down, and switch it off at 27°C. That gap stops a sequence like 30, 29, 30, 29 from repeatedly changing the alarm state. I used that small task to try Toit 2.0. The release is a useful excuse to look beyond blinking an LED: the same language also runs host scripts, so the decision logic can be exercised before connecting a sensor. [1][2] Start with the state you want There are two states, on and off. A reading at or above 30 sets the state to on. A reading at or below 27 sets it to off. Everything between those limits leaves it alone. This is hysteresis: the current reading does not completely determine the output; the previous state matters too. The initial state is part of the design. In this example it is off, so starting at 29°C leaves the alarm off. Arriving at the same temperature after a 30°C reading leaves it on. Neither case is an accident. !Synthetic temperature trace with an alarm turning on at 30 degrees, holding through 29, and turning off at 27. Original plot from the executed synthetic sequence. Sample positions are ordered readings, not elapsed seconds. Run the whole program Get the archive that matches your platform from the official v2.0.0 release, extract it, and put its bin directory on your PATH. Check the selected runtime: toit --version Mine returned v2.0.0. Save this as sensor.toit: main: readings := [28, 30, 29, 30, 29, 27, 29, 31] alarm := false readings.do: |temperature| if temperature >= 30: alarm = true else if temperature <= 27: alarm = false print "$temperature C: $alarm" Then analyze and execute it: toit analyze sensor.toit toit run sensor.toit The analyzer completed successfully. The program printed: 28 C: false 30 C: true 29 C: true 30 C: true 29 C: true 27 C: false 29 C: false 31 C: true The syntax takes a moment to read if you normally use Python. := introduces a local variable; = changes it. readings.do: calls a block for each value, and |temperature| names the block's parameter. The string interpolates both variables. [3] The missing assignment does the work There is deliberately no final else. At 28 or 29, the program does not assign to alarm, which preserves the previous state. Replacing that block with alarm = temperature >= 30 would throw the memory away. For this exact sequence, including the initial off state, the single-threshold rule changes state five times. The hysteresis rule changes it three times. Those are properties of this synthetic input, not measurements of a physical sensor or proof that these thresholds suit a device. I also ran separate inputs for an empty list, each exact threshold, a starting value inside the gap, a descending sequence, and repeated boundary readings. They behaved as specified. A real device still needs decisions about missing readings, units, startup behavior and what should happen if its process restarts. Toit 2.0's announcement includes a peripheral API change that accepts pin numbers directly. That is relevant when taking the next step onto supported hardware, but this program uses no GPIO, board or sensor. [1] It is a small, completed host-side example you can change without wiring anything first. References 1. Florian Loitsch, Toit v2.0.0 and the official release. 2. Toit contributors, Learn Toit. 3. Toit contributors, language source and standard library. Asset credits Original chart made from the synthetic program output; no third-party image assets. AI disclosure AI was used to draft the article.
Less time waiting for firmware builds. More time experimenting with hardware. GitHub: toitlang/toit