Language: EN

esp32-net6-mqtt

How to connect an ESP32 with NET6 via MQTT

We conclude the series of entries aimed at seeing ways of communication between an ESP32 and a NET6 application written in C#. This time we will communicate through MQTT.

In previous entries in the series, we have seen other forms of communication between the ESP32 and the NET6 application, such as communication through the serial port, through HTTP requests, and through WebSockets.

Before going into details, we remind you that NET6 is compatible with a wide range of platforms, including Windows, Android, Linux, Mac, x86/x64, and ARM7 or higher. Therefore, we can use the same code on different devices, such as desktop computers with Windows or Linux, Android mobiles, or Raspberry Pi.

For those who are not familiar with MQTT, it is a PubSub pattern communication protocol in which clients connect to a server (broker) and send or receive messages through “topics”. MQTT is especially useful in IoT applications for its low power consumption and bandwidth. If you want more information, check this section.

ESP32 Code

Let’s start with the ESP32 part. As always, we organize our code into files, grouping by functionality. Thus, we have the file MqttService.hpp, which contains the logic part of our project related to Mqtt.

class MqttService
{
public:
  void Init()
  {
    mqttClient.setServer(MQTT_BROKER_ADRESS, MQTT_PORT);
    SuscribeMqtt();

    mqttClient.setCallback([this](char* topic, uint8_t* payload, unsigned int length) -> void
    {
      this->OnMqttReceived(topic, payload, length);
    });
  }

  void ConnectMqtt()
  {
    while (!mqttClient.connected())
    {
      Serial.print("Starting MQTT connection...");
      if (mqttClient.connect(MQTT_CLIENT_NAME))
      {
        SuscribeMqtt();
      }
      else
      {
        Serial.print("Failed MQTT connection, rc=");
        Serial.print(mqttClient.state());
        Serial.println(" try again in 5 seconds");

        delay(5000);
      }
    }
  }

  void HandleMqtt()
  {
    if (!mqttClient.connected())
    {
      ConnectMqtt();
    }
    mqttClient.loop();
  }

  void SuscribeMqtt()
  {
    mqttClient.subscribe("hello/world/net");
  }

  String payload;
  void SendB()
  {
    String topic = "hello/world/esp32";
    payload = "A";
    mqttClient.publish(topic.c_str(), payload.c_str());
  }

  void SendA()
  {
    String topic = "hello/world/esp32";
    payload = "B";
    mqttClient.publish(topic.c_str(), payload.c_str());
  }

  String content = "";
  void OnMqttReceived(char* topic, uint8_t* payload, unsigned int length)
  {
    content = "";
    for (size_t i = 0; i < length; i++)
    {
      content.concat((char)payload[i]);
    }

    Serial.println(content);
  }
};

Here we have simply defined the necessary callback functions for the operation. We subscribe to the corresponding topic and, upon receiving a message, we simply print the content by Serial. On the other hand, we have defined two functions to send ‘A’ and ‘B’.

As we have said in previous entries, in a real project you would have to adapt the logic of this file to the needs of your project. For what concerns us in this example, which is communication, it is sufficient.

Now, in our main sketch, we only need to initialize the WiFi and our Mqtt service.

void setup() {
  Serial.begin(115200);

  WIFI_Connect();
  delay(2000);

  mqttService.Init();
}

Finally, in our example, in the main loop, we only send ‘A’ and ‘B’ through Mqtt alternately, when pressing the button.

bool isOn = false;
void Update()
{
  if (M5.BtnA.wasPressed())
  {
    if (isOn == false)
    {
      isOn = true;
      Serial.println("A");
      mqttService.SendA();
    }
    else if (isOn == true)
    {
      isOn = false;
      Serial.println("B");
      mqttService.SendB();
    }
  }
}

void loop()
{
  mqttService.HandleMqtt();

  delay(10);
  Update();
}

NET6 Code

As for the NET6 part, we will use the MQTTnet library that we already saw in this post. Like in the case of the ESP32, and in the previous entries, the first thing we do is create an object to handle the management.

internal class MqttService
{
private IMqttClient mqttClient;

    public async Task Initialize(string brokerIpAddress)
    {
        var factory = new MqttFactory();

        var options = new MqttClientOptionsBuilder()
        .WithClientId("Client1")
        .WithTcpServer(brokerIpAddress, 1883)
        .Build();

        mqttClient = factory.CreateMqttClient();

        mqttClient.ConnectedAsync += (async e =>
        {
            await mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("hello/world/esp32").Build());
        });

        mqttClient.ApplicationMessageReceivedAsync += (async e =>
        {
            Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
        });

        await mqttClient.ConnectAsync(options, CancellationToken.None);
    }

    public async Task SendMqtt(object payload)
    {
        var json = JsonSerializer.Serialize(payload);

        var applicationMessage = new MqttApplicationMessageBuilder()
                                   .WithTopic("hello/world/net")
                                   .WithPayload(json)
                                   .Build();

        await Task.Run(() => mqttClient.PublishAsync(applicationMessage));

    }
}

With this file, the C# part would be as simple as the following.

var brokerIpAddress = "192.168.1.xxx";

Console.Write(" - Initializing MQTT:");
var mqttService = new MqttService();
await mqttService.Initialize(brokerIpAddress);
Console.WriteLine(" OK");

var timer = Observable.Interval(TimeSpan.FromSeconds(2))
.Subscribe(async _ =>
{
    try
    {
        await mqttService.SendMqtt(new { data = System.DateTime.Now });
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{DateTime.Now} Error sending: {ex.Message}");
    }
});

Console.ReadLine();

In the example shown, we have sent the current time through MQTT every 2 seconds. This is just an example and, in a real project, we should integrate this communication into the program’s logic. However, to illustrate how communication through MQTT works, this example is sufficient.

In conclusion, in this series of entries, we have seen how to establish communication between an ESP32 and a NET6 application using different means, such as the serial port, HTTP requests, WebSockets, and finally MQTT. We hope that this series of entries is useful to you as help or inspiration for your projects!

Download the code

All the code from this post is available for download on Github. github-full