ESP32からMQTT BrokerにSSL/TLSでデータをpublishする
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しているだけです。
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の場合、BasicMQTT
のclient_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でデータを送りたい場合があります。その場合の実装例が以下になります。
平文のものとの差分を見てみます。
$ 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