28

ESP32 MQTT Publish with Rust

 9 months ago
source link: https://medium.com/iotics/esp32-mqtt-publish-with-rust-678d1068ee2
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ESP32 MQTT Publish with Rust

Here at IOTICS, we are in the habit of concocting various fun, weird and sometimes practical use-cases with microcontrollers and seeing how they integrate with our technology. Recently we’ve been combining this with our love of Rust, and because the ecosystem is in its early days, we thought it might prove helpful to its growth to share parts of our journey.

While the folks at https://github.com/esp-rs/esp-idf-svc are working hard on wrapping ESP-IDF’s MQTT Client, here’s a way to publish to MQTT today, using existing libraries.

Prerequisites

Follow Ivan Markov’s brilliant guide on installing the required toolchain and all the other prerequisites for your board. It worked well for me, and I’m sure it will work great for you too!

Project Setup

Note: I’ll only consider ESP32 in this guide to keep this section short. For ESP32-S2 or ESP32-S3, please browse Ivan Markov’s guide. You would have to change the target in .cargo/config.toml, tweak build.rs, and possibly leverage some of the flags used in the defaults files.

I would like to draw your attention to the following from Cargo.toml :

  • opt-level = “s” is required for the compiled code to fit an ESP32. It instruct the rustc compiled to optimize for size. s is small enough, while z is supposed to produce the smallest output.
  • the native feature of esp-idf-sys makes it utilize the esp-idf tooling over Platform IO. It is experimental, but it has worked nicely for me so far.

While esp_idf_svc does include a logger instance, currently, there is no API to allow us to change the logging level to info . For this reason, we have to create our static logger instance.

Running the code

Install espflash and espmonnitor if you haven’t done it already.

cargo install cargo-espflash
cargo install cargo-espmonitor

You can find out which serial port is your ESP32 connected to by running:

espflash board-info

With all the pieces in place, let’s compile the code and flash it onto the ESP32.

cargo build
espflash <SERIAL-PORT> target/xtensa-esp32-espidf/debug/esp32_mqtt_publish
espmonitor <SERIAL-PORT>

Hopefully, everything goes fine, and the Hello World! I’m a Rustacean! message will greet you, alongside plenty of debugging information.

If you’re missing something which sounds related to the toolchain, you should double-check that you haven’t missed something from Ivan Markov’s guide.

Before we can even think of publishing messages to MQTT, we need to connect to the Wifi.

All that’s left now is to flash the updated code and see if you’ve managed to remember your Wifi password :)

cargo build
espflash <SERIAL-PORT> target/xtensa-esp32-espidf/debug/esp32_mqtt_publish
espmonitor <SERIAL-PORT>

If you remembered your Wifi credentials correctly, there would be two things that might surprise you further.

Firstly, the logging output will increase considerably. It might take a few seconds to locate the Wifi connected message.

Secondly, you might also notice that the Wifi gets stopped right after it connects. Don’t rush to restart your router; everything is fine! This happens because the _wifi variable gets dropped by Rust at the end of the function. On drop, everything required to establish the Wifi connection is cleaned up.

This is why the setup_wifi function returns the wifi instance. As long as we want to use the Wifi connection, we’ll have to keep this instance in scope. netif_stack, sys_loop_stack and default_nvs will also need to be kept around, but this is a given because the lifetime of _wifi depends on theirs.

MQTT

We’re finally ready to publish a message to MQTT.

mqtt-protocol is the first MQTT client that I’ve found to work decently on an ESP32, but there could be others.

We also bring in embedded-hal and esp-idf-hal so that we can use a delay provider.

It quickly becomes evident that mqtt-protocol is a pretty low-level library, and a lot is left up to the user. This suits us very well, though, as it runs just fine on an ESP32 even if it wasn’t built for it.

Here we have a connect function that takes an unused reference to an EspWifi just to make sure that the caller doesn’t try to call it without being connected to the Wifi. We could even go the extra mile and double-check that the Wifi is still connected, but I will leave this optimization up to you.

A TcpStream is created and connected to the given address before the ConnectPacket is sent. If everything goes well and a ConnackPacket comes back through the stream saying that the connection was accepted, we return the TcpStream to the caller.

The mqtt_publish function does what you’d expect it to. It takes an unused reference to an EspWifi and a mutable reference to a TcpStream through which to publish the message.

The most interesting part here is TopicName::new_unchecked. If you would try the safe version, TopicName::new, you will discover that your ESP32 will run out of memory. This is caused by TopicName::new using regex behind the scenes, which is a bit too heavy for an ESP32.

All that’s left to do now is to go ahead and publish something.

After the Wifi connection is established, we call mqtt_connect to perform the MQTT handshake, and if all goes fine, it will give us back a TcpStream.

We then re-use the TcpStream to publish MQTT messages every 10 seconds.

A quick re-flash with the new code and messages should start appearing on the other side.

cargo build
espflash <SERIAL-PORT> target/xtensa-esp32-espidf/debug/esp32_mqtt_publish
espmonitor <SERIAL-PORT>

The code is on GitHub

All the code shown in this article is also available in GitHub: https://github.com/mihai-dinculescu/esp32-mqtt-publish.

Conclusion

This is the minimal code you need to write to publish messages to MQTT in Rust on an ESP32 microcontroller. It’s possible, and it works pretty well!

In a real-life use case, you would probably want to create yourself an MQTT Client wrapper, which you’ll then hopefully publish to crates.io so that we can all benefit ❤


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK