Skip to content

ESP8266との接続

本記事では、ESP8266プロジェクトでのPubSubClientの使用方法について紹介します。クライアントとMQTTブローカー間の接続、サブスクライブ、メッセージングなどの機能の実装方法を解説します。

ESP8266は、高度に統合されたWi-Fi SoCソリューションを提供します。低消費電力、小型設計、高い安定性によりユーザーの要件を満たします。ESP8266は完全かつ独立したWi-Fiネットワーク機能を備えており、単独での利用や他のホストMCUのスレーブとして動作可能です。

本記事では、ESP8266クライアントをTCPポートおよびTLS/SSLポート経由でMQTTブローカーに接続する方法を示します。Serverlessデプロイメントの場合はTLS/SSLポート接続のデモをご参照ください。TCPポート接続とTLS/SSLポート接続では設定が異なりますが、パブリッシュおよびサブスクライブ機能のコードは同じです。

前提条件

接続前に、ブローカーとクライアントの準備が必要です。

MQTTブローカーの準備

EMQXが提供する無料のパブリックMQTTブローカーを利用できます。このサービスはEMQXプラットフォームを基に構築されています。ブローカーアクセス情報は以下の通りです:

  • ブローカー:broker.emqx.io
  • TCPポート:1883
  • SSL/TLSポート:8883

また、デプロイメントを作成することも可能です。デプロイメントの概要で接続情報を確認してください。デプロイメントが稼働中であることを確認し、TCPポートまたはTLS/SSLポートでMQTTサーバーへの接続をテストしてください。

独自のデプロイメントを作成する場合は、アクセス制御 -> 認証を確認し、認証用のユーザー名とパスワードを設定してください。

Arduino IDE

本記事ではコードエディター兼アップローダーとしてArduino IDEを使用します。オープンソースのArduinoソフトウェア(IDE)はコードの作成とボードへのアップロードを容易にします。任意のArduinoボードで使用可能です。

依存関係のインストール

Arduino IDEで以下のインストールを完了してください:

  1. ESP8266開発ボードのインストール
    ツール -> 開発ボード -> 開発ボードマネージャーをクリックし、ESP8266を検索してインストールをクリックします。
  2. PubSubClientのインストール
    スケッチ -> ライブラリをインクルード -> **ライブラリマネージャー...**をクリックし、PubSubClientを検索してNick O’LearyによるPubSubClientをインストールします。

TCPポートでの接続

このセクションでは、Arduino IDEでESP8266クライアントをTCPポート経由でMQTTブローカーに接続する方法を説明します。

  1. ライブラリESP8266WiFiとPubSubClientをインポートします。
c
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
  1. Wi-Fi名とパスワード、接続先アドレスとポートを設定します。

サンプルコードはパブリックMQTTサーバーに接続するため、ユーザー名とパスワードは不要です。デプロイメントを作成した場合は、クライアント認証を参照してユーザー名とパスワードを設定してください。

c
// WiFi設定
const char *ssid = "WIFI_SSID";             // ご自身のWiFi名に置き換えてください
const char *password = "WIFI_PASSWORD";   // ご自身のWiFiパスワードに置き換えてください

// MQTTブローカー設定
const char *mqtt_broker = "broker.emqx.io";  // EMQXブローカーのエンドポイント
const char *mqtt_topic = "emqx/esp8266";     // MQTTトピック
const char *mqtt_username = "emqx";  // 認証用MQTTユーザー名
const char *mqtt_password = "public";  // 認証用MQTTパスワード
const int mqtt_port = 1883;  // MQTTポート(TCP)
  1. シリアル接続を開き、プログラムの結果を出力し、Wi-Fiネットワークに接続します。
c
void setup() {
    Serial.begin(115200);
    connectToWiFi();
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectToMQTTBroker();
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nConnected to the WiFi network");
}
  1. MQTTブローカーを設定し、コールバック関数を記述し、シリアルモニターに接続情報を出力します。
c
void connectToMQTTBroker() {
    while (!mqtt_client.connected()) {
        String client_id = "esp8266-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Connected to MQTT broker");
            mqtt_client.subscribe(mqtt_topic);
            // 接続成功時にメッセージをパブリッシュ
            mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
        } else {
            Serial.print("Failed to connect to MQTT broker, rc=");
            Serial.print(mqtt_client.state());
            Serial.println(" try again in 5 seconds");
            delay(5000);
        }
    }
}
  1. MQTTブローカーへの接続に成功すると、ESP8266はトピックesp8266/testにメッセージをパブリッシュし、同トピックのメッセージをサブスクライブします。
c
mqtt_client.subscribe(mqtt_topic);
// 接続成功時にメッセージをパブリッシュ
mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
  1. 受信したメッセージのトピック名をシリアルポートに出力し、メッセージの各バイトを順に表示します。
c
void mqttCallback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message received on topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (unsigned int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}

以下に完全なコードを示します。

c
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// WiFi設定
const char *ssid = "WIFI_SSID";             // ご自身のWiFi名に置き換えてください
const char *password = "WIFI_PASSWORD";   // ご自身のWiFiパスワードに置き換えてください

// MQTTブローカー設定
const char *mqtt_broker = "broker.emqx.io";  // EMQXブローカーのエンドポイント
const char *mqtt_topic = "emqx/esp8266";     // MQTTトピック
const char *mqtt_username = "emqx";  // 認証用MQTTユーザー名
const char *mqtt_password = "public";  // 認証用MQTTパスワード
const int mqtt_port = 1883;  // MQTTポート(TCP)

WiFiClient espClient;
PubSubClient mqtt_client(espClient);

void connectToWiFi();

void connectToMQTTBroker();

void mqttCallback(char *topic, byte *payload, unsigned int length);

void setup() {
    Serial.begin(115200);
    connectToWiFi();
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectToMQTTBroker();
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nConnected to the WiFi network");
}

void connectToMQTTBroker() {
    while (!mqtt_client.connected()) {
        String client_id = "esp8266-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Connected to MQTT broker");
            mqtt_client.subscribe(mqtt_topic);
            // 接続成功時にメッセージをパブリッシュ
            mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
        } else {
            Serial.print("Failed to connect to MQTT broker, rc=");
            Serial.print(mqtt_client.state());
            Serial.println(" try again in 5 seconds");
            delay(5000);
        }
    }
}

void mqttCallback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message received on topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (unsigned int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}

void loop() {
    if (!mqtt_client.connected()) {
        connectToMQTTBroker();
    }
    mqtt_client.loop();
}

TLS/SSLポートでの接続

このセクションでは、Arduino IDEでESP8266クライアントをTLS/SSLポート経由でMQTTブローカーに接続する方法を説明します。TLS/SSLポート接続の設定はTCPポート接続と異なりますが、パブリッシュおよびサブスクライブ機能のコードは同じです。

  1. ライブラリESP8266WiFi、PubSubClient、timeをインポートします。
c
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <time.h>
  1. Wi-Fi名とパスワード、接続先アドレスとポートを設定します。

サンプルコードはパブリックMQTTサーバーに接続するため、ユーザー名とパスワードは不要です。デプロイメントを作成した場合は、クライアント認証を参照してユーザー名とパスワードを設定してください。

c
// WiFi認証情報
const char *ssid = "WIFI_SSID";             // ご自身のWiFi名に置き換えてください
const char *password = "WIFI_PASSWORD";   // ご自身のWiFiパスワードに置き換えてください

// MQTTブローカー設定
const int mqtt_port = 8883;  // MQTTポート(TLS)
const char *mqtt_broker = "broker.emqx.io";  // EMQXブローカーのエンドポイント
const char *mqtt_topic = "emqx/esp8266";     // MQTTトピック
const char *mqtt_username = "emqx";  // 認証用MQTTユーザー名
const char *mqtt_password = "public";  // 認証用MQTTパスワード
  1. サーバーとSSL証明書を設定します。
c
// NTPサーバー設定
const char *ntp_server = "pool.ntp.org";     // デフォルトNTPサーバー
// const char* ntp_server = "cn.pool.ntp.org"; // 中国ユーザー向け推奨NTPサーバー
const long gmt_offset_sec = 0;            // GMTオフセット(秒単位、タイムゾーンに応じて調整)
const int daylight_offset_sec = 0;        // サマータイムオフセット(秒単位)

// WiFiおよびMQTTクライアント初期化
BearSSL::WiFiClientSecure espClient;
PubSubClient mqtt_client(espClient);

// MQTTブローカー用SSL証明書
// EMQXパブリックブローカー broker.emqx.ioで使用されるDigiCert Global Root G2をロード
static const char ca_cert[]
PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----
)EOF";

// EMQX Serverless Deploymentで使用されるDigiCert Global Root CA ca_certのロード例
/*
static const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)EOF";
*/
  1. シリアル接続を開き、プログラムの結果を出力し、Wi-Fiネットワークに接続します。
c
void setup() {
    Serial.begin(115200);
    connectToWiFi();
    syncTime();  // X.509検証には時刻同期が必要
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectToMQTT();
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
}
  1. フィンガープリントとMQTTブローカーを設定し、コールバック関数を記述し、シリアルモニターに接続情報を出力します。
c
void connectToMQTT() {
    BearSSL::X509List serverTrustedCA(ca_cert);
    espClient.setTrustAnchors(&serverTrustedCA);
    while (!mqtt_client.connected()) {
        String client_id = "esp8266-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Connected to MQTT broker");
            mqtt_client.subscribe(mqtt_topic);
            // 接続成功時にメッセージをパブリッシュ
            mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
        } else {
            char err_buf[128];
            espClient.getLastSSLError(err_buf, sizeof(err_buf));
            Serial.print("Failed to connect to MQTT broker, rc=");
            Serial.println(mqtt_client.state());
            Serial.print("SSL error: ");
            Serial.println(err_buf);
            delay(5000);
        }
    }
}
  1. MQTTブローカーへの接続に成功すると、ESP8266はメッセージをパブリッシュし、MQTTブローカーをサブスクライブします。
c
mqtt_client.subscribe(mqtt_topic);
// 接続成功時にメッセージをパブリッシュ
mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
  1. 受信したメッセージのトピック名をシリアルポートに出力し、メッセージの各バイトを順に表示します。
c
void mqttCallback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message received on topic: ");
    Serial.print(topic);
    Serial.print("]: ");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
}

以下に完全なコードを示します。

c
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <time.h>

// WiFi認証情報
const char *ssid = "WIFI_SSID";             // ご自身のWiFi名に置き換えてください
const char *password = "WIFI_PASSWORD";   // ご自身のWiFiパスワードに置き換えてください

// MQTTブローカー設定
const int mqtt_port = 8883;  // MQTTポート(TLS)
const char *mqtt_broker = "broker.emqx.io";  // EMQXブローカーのエンドポイント
const char *mqtt_topic = "emqx/esp8266";     // MQTTトピック
const char *mqtt_username = "emqx";  // 認証用MQTTユーザー名
const char *mqtt_password = "public";  // 認証用MQTTパスワード

// NTPサーバー設定
const char *ntp_server = "pool.ntp.org";     // デフォルトNTPサーバー
// const char* ntp_server = "cn.pool.ntp.org"; // 中国ユーザー向け推奨NTPサーバー
const long gmt_offset_sec = 0;            // GMTオフセット(秒単位、タイムゾーンに応じて調整)
const int daylight_offset_sec = 0;        // サマータイムオフセット(秒単位)

// WiFiおよびMQTTクライアント初期化
BearSSL::WiFiClientSecure espClient;
PubSubClient mqtt_client(espClient);

// MQTTブローカー用SSL証明書
// EMQXパブリックブローカー broker.emqx.ioで使用されるDigiCert Global Root G2をロード
static const char ca_cert[]
PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----
)EOF";

// EMQX Serverless Deploymentで使用されるDigiCert Global Root CA ca_certのロード例
/*
static const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)EOF";
*/


// 関数宣言
void connectToWiFi();

void connectToMQTT();

void syncTime();

void mqttCallback(char *topic, byte *payload, unsigned int length);


void setup() {
    Serial.begin(115200);
    connectToWiFi();
    syncTime();  // X.509検証には時刻同期が必要
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectToMQTT();
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
}

void syncTime() {
    configTime(gmt_offset_sec, daylight_offset_sec, ntp_server);
    Serial.print("Waiting for NTP time sync: ");
    while (time(nullptr) < 8 * 3600 * 2) {
        delay(1000);
        Serial.print(".");
    }
    Serial.println("Time synchronized");
    struct tm timeinfo;
    if (getLocalTime(&timeinfo)) {
        Serial.print("Current time: ");
        Serial.println(asctime(&timeinfo));
    } else {
        Serial.println("Failed to obtain local time");
    }
}

void connectToMQTT() {
    BearSSL::X509List serverTrustedCA(ca_cert);
    espClient.setTrustAnchors(&serverTrustedCA);
    while (!mqtt_client.connected()) {
        String client_id = "esp8266-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Connected to MQTT broker");
            mqtt_client.subscribe(mqtt_topic);
            // 接続成功時にメッセージをパブリッシュ
            mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
        } else {
            char err_buf[128];
            espClient.getLastSSLError(err_buf, sizeof(err_buf));
            Serial.print("Failed to connect to MQTT broker, rc=");
            Serial.println(mqtt_client.state());
            Serial.print("SSL error: ");
            Serial.println(err_buf);
            delay(5000);
        }
    }
}

void mqttCallback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message received on topic: ");
    Serial.print(topic);
    Serial.print("]: ");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
}

void loop() {
    if (!mqtt_client.connected()) {
        connectToMQTT();
    }
    mqtt_client.loop();
}

接続のテスト

ESP8266クライアントがMQTTブローカーに正常に接続された後、Arduino IDEとMQTTXを使って接続をテストできます。

  1. Arduino IDEで完全なコードをESP8266にアップロードし、シリアルモニターを開きます。
    esp8266_connection
  2. MQTTXクライアントとMQTTブローカー間の接続を確立し、ESP8266にメッセージを送信します。
    esp8266_mqttx
  3. シリアルモニターでESP8266が受信したメッセージを確認します。
    esp8266_receive

まとめ

以上で、ESP8266プロジェクトにおけるMQTT接続の作成、クライアントとMQTTブローカー間の接続、サブスクライブ、メッセージ送受信のシミュレーションを実装しました。サンプルコードはこちらからダウンロード可能です。また、他言語のデモ例もGitHubでご覧いただけます。