Androidのメモとか

ポキオの日記です。今日も遅延してない。

IBM CloudのWatson IoT Platformを使ってNode-REDとESP8266でPub/Subしてみた

PubったりSubったり。

いままでの話

relativelayout.hatenablog.com

relativelayout.hatenablog.com

今回はMQTT

IBM Cloud上のNode-REDとESP8266をMQTTで双方向通信をしてみようと思います。

www.ibm.com

所謂HTTPな通信に比べて軽量なデータなのでIoTに向いていると言われています。ただ、実際は送受信をする際に、データを送る側(Publisher)と受ける側(Subscriber)の間に仲介をする役目(Broker)が必要になってくるわけですが、このBrokerの機能を無料で提供しているサービスがあまり少なく、ウィークエンドプログラマーには厳しいものがあります。

mosquitto.org

Mosquittoという痒くなりそうな名前のオープンソースなBrokerもあって、これをローカルのマシンに入れれば、同じネットワーク内ではMQTT通信が可能ですが・・・やっぱり、サクッとNATを超えていい感じに通信したい。そこで、IBM CloudのWatson IoT Platformなわけです。

internetofthings.ibmcloud.com

これ、IBM Cloudのライト・アカウントでも無料で使えるんですね・・・(多分200MB/月まで)。IBMは本当に神ですね・・・。ドキュメントも充実しているところも、流石IBMという感じ。IBM様ですね。

developer.ibm.com

ちょうどいい記事があったので、これを参考に実装してみようと思います。

Watson IoT Platformを使ってみる

前置きが長くなりましたが。

IBM Cloud Node-RED MQTT ESP8266

IBM CloudでInternet of Things Platformを有効にします。

IBM Cloud Node-RED MQTT ESP8266

Watson IoT Platformのダッシュボードのメニュー>Devicesから、デバイスの登録をしていきます。最初にDevice Typeを新規登録します。ここでは一旦、MQTTDeviceとしました。

IBM Cloud Node-RED MQTT ESP8266

次にDeviceの新規登録。先程作ったMQTTDeviceDevice Typeとして、新規登録します。Device IDは多分ユニークな値なら良いはず・・・(震え声)テキトーに設定していきます。

セキュリティの設定は甘くしておきます・・・

IBM Cloud Node-RED MQTT ESP8266

Watson IoT Platformのダッシュボードのメニュー>SECURITY>Connection Securityで、接続時に必要とされるセキュアさが設定できるのですが、TLS Optionalにしておきます。これは後々使うESP8266のライブラリのためです・・・。

次にNode−REDをいじります

IBM Cloud Node-RED MQTT ESP8266

今回は、とりあえず動かしてみるくらいのモチベーションなので「ESP8266からMQTTを受け取ったらLog出力」「Node-REDからESP8266にMQTT送信」の2つのフローを作ってみました。Watson IoTのノードはそれぞれこんな感じに設定しました。

IBM Cloud Node-RED MQTT ESP8266

まず、MQTTを受け取る側は、Watson IoT Platformで受け取ったすべてのDevice Eventを受けるようにしておきます。なので、すべてのAllにチェックを入れておきます。

IBM Cloud Node-RED MQTT ESP8266

一方、MQTTを送信する側はこんな感じで設定します。先程設定したDevice IDやらDevice Typeなどを設定していきます。

最後にESP8266の実装

今回は、このライブラリを使ってMQTTしていきます。

github.com

大まかに言うと、以下のことを実装します。

  • Wi-Fi接続
  • Brokerに接続
  • Brokerに対してSubscribe登録
  • MQTT受信した時の挙動を指定
  • Brokerに対してPublishする実装

実際のコードはこんな感じです。

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

#define SSID "xxxxx" // アクセスポイントのSSID
#define PASSWORD "xxxxx" // アクセスポイントのパスワード

#define ORG "xxxxx" // Watson IoT Platformで割り振られているID(My Organization)
#define DEVICE_TYPE "MQTTDevice" // Device Type
#define DEVICE_ID "xxxxx" // Device ID
#define TOKEN "xxxxx" // Deviceを登録した時に発行されるトークン

char server[] = ORG ".messaging.internetofthings.ibmcloud.com"; // Brokerのサーバーはこんな感じに決まる
char subTopic[] = "iot-2/cmd/notify/fmt/json"; // Subscribeするトピックの設定(Node-REDのノードで設定したコマンド名)
char pubTopic[] = "iot-2/evt/request/fmt/json"; // Publishするトピックの設定(Node-REDのノードで設定したイベント名)
char authMethod[] = "use-token-auth"; // トークンを使って認証をしていくというお気持ち表明
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;

WiFiClient wifiClient;
PubSubClient client(wifiClient);

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

  // 最初にWi-Fi接続
  connectWifi();

  // MQTTクライアントの初期化
  client.setServer(server, 1883);
  client.setCallback(callback);
}

void loop() {
  // MQTTクライアントが未接続だったら・・・
  if (!client.connected()) {
    // 接続して、Subscribe登録して、一発Publishする
    connectMqtt();
    subscribeMqtt();
    publishMqtt();
  }

  client.loop();
}

// Subscribeしてるトピックに対して、なにかMQTTを受け取ったときの挙動を記述(ただLog表示するだけ)
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

// Wi-Fi接続
void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(SSID, PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
    //    Blink.softly(&pixels, NUMLED, 255, 255, 255);
  }

  Serial.println("connected!");
}

// Brokerに接続
void connectMqtt() {
  if (!!!client.connected()) {
    Serial.print("Reconnecting client to ");
    Serial.println(server);
    while (!!!client.connect(clientId, authMethod, token)) {
      Serial.print(".");
      delay(500);
    }
    Serial.println();
  }
}

// Brokerに対してSubscribe
void subscribeMqtt() {
  Serial.print("subscribe to "); Serial.print(subTopic);
  if (client.subscribe(subTopic)) {
    Serial.println(" OK");
  } else {
    Serial.println(" FAILED");
  }
}

// Brokerに対してPublish
void publishMqtt() {
  Serial.print("publish to "); Serial.print(pubTopic);
  if (client.publish(pubTopic, "{\"d\":\"request\"}")) {
    Serial.println(" OK");
  } else {
    Serial.println(" FAILED");
  }
}

ここで、Watson IoT Platformのセキュリティ設定を変更したのは、このPubSubClientでAPI Keyを使った認証がうまくいかなかったので、トークンだけで認証ができるようにしたかったからです。(ちょっとセキュリティがアレかもしれないですが・・・)

動作させてみます!

ESP8266が起動すると、スグにPublishしてきますが・・・

IBM Cloud Node-RED MQTT ESP8266

Node-RED上のLog出力にもちゃんと表示されていますね。

IBM Cloud Node-RED MQTT ESP8266

また、Node-REDからPublishしてやると、ESP8266のログ出力にも表示されてます。いい感じに双方向通信できてますねー。

いやー、IBMはドキュメントが豊富で助かりますね。というわけで、MQTTをESP8266で触ってみた話でした!

「Androidのメモとか」は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。

このブログは個人的なメモ書きであったり、考えを書く場所であります。執筆者の所属する団体や企業のコメントや意向とは無関係であります。また、このブログは必ずしも正しいことが書かれているとは限らず、誤字脱字や意図せず誤った情報を載せる場合がありえます。それが原因で読者が不利益を被ったとしても、執筆者はいかなる責任も負いません。ありがとうございます。