🚀

ESP32からMQTT BrokerにSSL/TLSでデータをpublishする

2025/02/14に公開

Overview

IoT Data PlatformであるThingsBoard関連の記事を書いていますが、DeviceからThingsBoardにデータを投げるためにはどのようにFirmwareを実装すればよいのか本記事で書きます。ここで実装するFirmwareは、ThingsBoardに限らず、MQTT Broker一般に使えるはずです。

前提

以下を使って実装します。

  • Arduino
  • PlatformIO
  • ESP32

thingsboard-client-sdkなるものをThingsBoardが提供していますが、データをpublishする程度であればこれを使う必要性もないですし、汎用的に使える記事にするためにもこれは使いません。

触れないこと

Arduino FrameworkとPlatformIOそのものについては本記事では深く触れません。

平文でMQTT Brokerにpublishする

まずは基本の形から。SSL/TLSは使わずThingsBoardにデータをpublishするFirmwareを実装します。10秒に1回、適当なダミーデータを作ってMQTT Brokerにデータをpublishしているだけです。
https://github.com/kazrin/thingsboard-firmwares/blob/5a1508671266aca911218f3f256cd4eb7919de30/src/publishTelemetry/publishPlain.cpp#L1-L64

MQTT Brokerに関わる部分だけピックアップしてみます。

MQTT Clientの初期化

以下の3行でMQTT Clientを初期化します。
Clientには pubsubclientを使っています(2025年2月現在最新のversionはv2.8ですが、2020年5月のもの。これ以外にpopularなClientはあるのでしょうか)。

#include <PubSubClient.h>
WiFiClient wifiClient;
PubSubClient pubsubClient(wifiClient);

MQTT Brokerの設定

以下でMQTT Brokerの設定をしています。ThingsBoardの場合、 MQTTBrokerConfig::server = mqtt.thingsboard.cloud, MQTTBrokerConfig::port = 1883 です。

pubsubClient.setServer(MQTTBrokerConfig::server, MQTTBrokerConfig::port);

MQTT BrokerとConnectionを張る

実際に接続している部分です。ThingsBoardの場合、BasicMQTTclient_id, user_name, password に設定する値は2パターンあります。

pubsubClient.connect(
            BasicMQTT::client_id,
            BasicMQTT::user_name,
            BasicMQTT::password);

1. Access Tokenを使う場合

1パターン目はAccess Tokenを使う場合です。Access Tokenはここから取得できます。

上のプログラムの例では config.cpp でCredentialを設定するようにしているのですが、Access Tokenを使う場合は以下のように設定します。

namespace BasicMQTT
{
    const char *client_id = "aaaaa"; // 任意の文字列
    const char *user_name = "xxxxxxxx"; // Access Tokenを入力
    const char *password = nullptr;
}

client_idは任意の文字列でかまいません。

2. Basic MQTT Credentialを使う場合

ThingsBoardの以下の箇所でBasic MQTT Credentialを確認できます。

config.cppには該当する値を各変数に割り当てます。

補足になりますが、ThingsBoardではAccess Tokenを使うか、Basic MQTT Credentialを使うかいずれか一方しか選べません。一方が設定されていたら、他方では接続できません。

データをpublishする

以下でpublishします。上の例では、publishするデータ telemetry をJSONにして、これを文字列に変換した上でpublishしています。 ThingsBoardの場合、MQTTBrokerConfig::topic = v1/devices/me/telemetry です。

pubsubClient.publish(MQTTBrokerConfig::topic, telemetry.c_str());

補足

先述したようにconfig.cppでのBasicMQTTの設定に加え、同じファイル内のWiFiConfigでESP32に接続させるWiFiのSSID/Passwordを設定した上でFirmwareを書き込めば動作します。ESP32は2.4GHz帯のWiFiでないとうまく動作しないと思います。

うまく動作していればSerial Monitorに以下のような文字列が10秒ごとのpublishの都度出力されます。

Published with following payload:
{"temperature":23,"humidity":55,"pressure":1006}

ThingsBoard上でもデータが送信されていることを確認できます。

SSL/TLSで安全にデータをpublishする

上の例は平文でのデータ送信でした。PrivateなNetworkでない限り盗聴されたり改竄されたりする恐れがあるので、SSL/TLSでデータを送りたい場合があります。その場合の実装例が以下になります。

https://github.com/kazrin/thingsboard-firmwares/blob/5a1508671266aca911218f3f256cd4eb7919de30/src/publishTelemetry/publishSSL.cpp#L1-L68

平文のものとの差分を見てみます。

$ diff src/publishTelemetry/publishPlain.cpp src/publishTelemetry/publishSSL.cpp 
2a3
> #include <WiFiClientSecure.h>
9c10
< WiFiClient wifiClient;
---
> WiFiClientSecure wifiClient;
44a46,48
>     // Set up SSL client
>     wifiClient.setCACert(MQTTBrokerConfig::root_ca);
> 
46c50
<     pubsubClient.setServer(MQTTBrokerConfig::server, MQTTBrokerConfig::port);
---
>     pubsubClient.setServer(MQTTBrokerConfig::server, MQTTBrokerConfig::secure_port);

差分1: WiFiClient -> WiFiClientSecureへの変更

PubSubClientの初期化にはWiFiクライアントを与える必要があるのですが、このWiFiクライアントが WiFiClient から WiFiClientSecure に変更されています。 #include <WiFiClientSecure.h> はこれを使うための宣言です。SSL/TLSを扱うのに WiFiClient では機能が足りないので WiFiClientSecure を使うようにしています。

wifiClient.setCACert(MQTTBrokerConfig::root_ca); でルート証明書をWiFiClientSecureに与えています。この証明書もconfig.cppで設定するようにしています。
ThingsBoardの場合このlinkでルート証明書を取得し、これを設定することでSSL/TLSで接続できますようになります。

差分2: Portを1883 -> 8883に変更

MQTTでSSL/TLSを使う場合、ThingsBoardでは8883ポートを利用しますので、 MQTTBrokerConfig::port から MQTTBrokerConfig::secure_port に変更しています。

SSL/TLSによって通信が暗号化されるだけなのでSerial Monitorの出力内容やThingsBoard上での見え方に差異はありません。

まとめ

MQTT Brokerとの通信というIoTの第一歩の内容でもWeb上にあまりないので書いてみました。いつか誰かの役に立てばと思います。

Discussion