If you have ever created an application for a microcontroller such as the ESP32, you might have noticed that it’s quite different to most of the software development we as IT consultants are doing most of the time. Using C/C++ and ancient tooling for flashing and debugging always takes some time getting used to for me. The developers of Toit (see website) try to change this by introducing a programming language and associated tooling that support memory safety, over-the-air updates and fleet management for ESP32 devices.
Why does it feel like it’s 1990 when developing software for embedded systems?
As a software engineer, I am used to having a lot of tooling, quick development cycles and easy continuous deployment when working on projects. In the world of IoT and embedded computing, this doesn’t apply anymore in many cases. I have done a couple of small projects using ESP32 microcontrollers, which was nice, but I immediately noticed a couple of drawbacks that working with limited hardware has.
Most people try to squeeze the best possible performance out of the limited hardware. That is probably why the gold standard programming language that is used in these systems is C/C++, which can be a bit hard for beginners. Having a lot of control over the hardware also comes with a lot of control over stuff that can go wrong. I spent multiple days of searching for a bug once, which in the end just overwrote some memory because I hadn’t allocated enough of it.
Flashing controllers like this can also be annoying because it’s typically done via a serial connection over USB. Over-the-air (OTA) updating is also possible, but it creates a whole new set of challenges, like for example a faulty OTA updater that overwrites memory of the main application. There also isn’t that much tooling for OTA updates and if you want to update over the internet you will probably have a bad time. If you want to have a fleet management solution like balena, you are pretty much out of luck.
In theory, there are other languages than C/C++, like MicroPython, that can be used for easier development. Python, however, isn’t specifically designed for IoT usage, which means that it carries some baggage that hits its performance. MicroPython is a step in the right direction, but it doesn’t solve all the aforementioned problems.
What is Toit and why do I like it so much?
Toit (pronounced just like Jake Peralta would do) is a project by some former Google engineers that aims to improve the development experience when creating applications for microcontrollers. Currently, the project is under heavy development, which means that it’s not production-ready yet, and it only supports ESP32 chips right now. However, it’s worth taking a look at the components that Toit has to offer.
The Toit programming language is easy to learn and specifically designed to be used on embedded systems. It provides just the right features to be able to write IoT applications efficiently. The syntax takes a little time to get used to, but all in all, it’s pretty simple.
The bytecode that Toit compiles into is run on a virtual machine that is installed on the ESP32. This VM is able to schedule application executions, which for example allows an application to read data from a sensor every minute and stay in deep sleep the rest of the time. It will also ensure that different apps are isolated from each other and can’t read or write each other’s memory.
Because one of their main goals was improving the developers’ experience, the Toit developers offer a live reload server called Jaguar. This is a small Toit application that runs on the controller and checks periodically if it received any updates for the Toit apps over the local network. This means that the developer’s computer doesn’t have to be connected to the ESP32 via cable anymore during development or to update the running applications to a new version.
There is also a cloud service that allows for further fleet management. On startup, devices will register at the service, which allows for checking the health of all active devices and services and also makes OTA updates over the internet possible. If you have ever used balena before, you might recognize this feature. However, the cloud service is currently deprecated because it’s based on an older version of Toit. The developers are working on a replacement, which will be open source, so you don’t have to rely on their proprietary service anymore.
Great! What does all of this look like?
To try this out, you can follow this tutorial, which guides you through downloading the Jaguar toolkit and installing the Toit VM on your ESP32. I have created a small sample application that reads some values from an SCD30 sensor that is attached to the ESP32 via I²C. This code could be easily extended with functionality that publishes the sensor data via MQTT (see this example on GitHub).
// The / symbol separates variable name and data type
// The construcor of scd30.Measurements is called with three arguments without parenthesis
measurements/scd30.Measurements := scd30.Measurements 0.0 0.0 0.0
// main: defines the entrypoint of the application
bus := i2c.Bus
--sda=gpio.Pin 21 // Named parameter definitions are marked with --
device := bus.device scd30.Scd30.I2C_ADDRESS
scd30 := scd30.Scd30 device
measurements = scd30.read
print "co2: $measurements.co2, temperature: $measurements.temperature, humidity: $measurements.humidity"
This example basically just opens an I²C connection to the SCD30 sensor and prints the read values to the serial output. As I said, the syntax can be a little confusing because method parameters are just listed after the method name separated by spaces without parenthesis. Also, named parameters that are beginning with
-- can be written on a separate line. After understanding the basics, however, it’s a simple language where you don’t have to worry too much about deep control of your hardware.
After saving the code as
scd30.toit, deploying the application over the local network onto your freshly flashed ESP32 is easy enough with the
jag run scd30.toit command. If you want, you can also use
jag watch scd30.toit, which will watch the local codebase and will automatically redeploy if any changes are detected. If you use the Toit cloud service, the serial output of the ESP32 will be displayed in your dashboard. Otherwise you would have to read it directly from the controller via USB and the
jag monitor command.
So, is Toit the next big thing for IoT?
The ease of use and the fact that there is already a lot of great tooling in the Toit ecosystem makes it a great candidate for a language that is widely adopted in the IoT industry. The performance might not be as good as C/C++ code, but for most IoT applications this is not required, and development velocity has much higher value. However, Toit is still at its very beginning with a lot of construction going on, so I wouldn’t recommend it for production use just yet. I also had some issues finding specific things in the documentation because it’s not totally complete and sometimes contains deprecated information. I will definitely come back to Toit next year to see what has changed and I hope the language continues to grow and mature. If you like to play with microcontrollers and hardware, I highly recommend giving Toit a spin and taking part in the development process of the language through their Discord server.