MQTT Exercise: Sending Messages

Setup

✅ You can find a prepared project skeleton in intro/mqtt/exercise.

✅ In intro/mqtt/host_client you can find a host run program that mimics the behavior of a second client. Run it in a separate terminal using the cargo run command. Find more information about the host client below.

The client also generates random RGB colors and publishes them in a topic. This is only relevant for the second part of this exercise.

❗️ Similar to the http exercises you need to configure your connection credentials in cfg.toml for both programs. Besides WiFi credentials you'll also need to add MQTT server details. Check each cfg.toml.example for required settings. Remember the name between brackets in the the cfg.toml file is the name of the package in Cargo.toml.

The structure of the exercises is as below. In this part, we will focus on the Temperature topic.

example_client_broker_board

Tasks

✅ Create an EspMqttClient with a default configuration and an empty handler closure.

✅ Send an empty message under the hello_topic to the broker. Use the hello_topic(uuid) utility function to generate a properly scoped topic.

✅ Verify a successful publish by having a client connected that logs these messages. The host_client implements this behavior. You should run it in another terminal.

✅ In the loop at the end of your main function, publish the board temperature on temperature_data_topic(uuid) every second. Verify this, too.

Establishing a connection

Connections are managed by an instance of esp_idf_svc::mqtt::client::EspMqttClient. It is constructed using

  • a broker URL which in turn contains credentials, if necessary
  • a configuration of the type esp_idf_svc::mqtt::client::MqttClientConfiguration
  • a handler closure similar to the http server exercise

#![allow(unused)]

fn main() {
let mut client = EspMqttClient::new(broker_url, 
    &mqtt_config, 
    move |message_event| {
        // ... your handler code here - leave this empty for now
        // we'll add functionality later in this chapter
    })?;

}

Support tools & crates

To log the sensor values sent by the board, a helper client is provided under intro/mqtt/host_client. It subscribes to the temperature topic.

The mqtt_messages crate (located in common/lib) supports handling messages, subscriptions and topics:

Functions to generate topic strings

  • color_topic(uuid) - creates a topic to send colors that will be published to the board.
  • hello_topic(uuid) - test topic for initially verifying a successful connection
  • temperature_data_topic(uuid) - creates a whole "temperature" topic string

Encoding and decoding message payloads

The board temperature f32 float is converted to four "big endian" bytes using temp.to_be_bytes().


#![allow(unused)]
fn main() {
// temperature
let temperature_data = &temp.to_be_bytes() as &[u8]; // board
let decoded_temperature = f32::from_be_bytes(temperature_data); // workstation
}

Publish & Subscribe

EspMqttClient is also responsible for publishing messages under a given topic. The publish function includes a retain parameter indicating whether this message should also be delivered to clients that connect after it has been published.


#![allow(unused)]
fn main() {
let publish_topic = /* ... */;
let payload: &[u8] = /* ... */ ;
client.publish(publish_topic, QoS::AtLeastOnce, false, payload)?;
}

Troubleshooting

  • error: expected expression, found . when building example client: update your stable Rust installation to 1.58 or newer
  • MQTT messages not showing up? make sure all clients (board and workstation) use the same UUID (you can see it in the log output)
  • Make sure the cfg.toml file is configured properly. The example-client has a dbg!() output at the start of the program, that shows mqtt configuration. It should output the content of your cfg.toml file.
  • error: expected expression, found . while running the host-client can be solved with rustup update