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
ちょうどいい記事があったので、これを参考に実装してみようと思います。
前置きが長くなりましたが。
IBM CloudでInternet of Things Platform
を有効にします。
Watson IoT Platformのダッシュボードのメニュー>Devicesから、デバイスの登録をしていきます。最初にDevice Type
を新規登録します。ここでは一旦、MQTTDevice
としました。
次にDeviceの新規登録。先程作ったMQTTDevice
をDevice Type
として、新規登録します。Device ID
は多分ユニークな値なら良いはず・・・(震え声)テキトーに設定していきます。
セキュリティの設定は甘くしておきます・・・
Watson IoT Platformのダッシュボードのメニュー>SECURITY>Connection Securityで、接続時に必要とされるセキュアさが設定できるのですが、TLS Optional
にしておきます。これは後々使うESP8266のライブラリのためです・・・。
次にNode−REDをいじります
今回は、とりあえず動かしてみるくらいのモチベーションなので「ESP8266からMQTTを受け取ったらLog出力」「Node-REDからESP8266にMQTT送信」の2つのフローを作ってみました。Watson IoTのノードはそれぞれこんな感じに設定しました。
まず、MQTTを受け取る側は、Watson IoT Platformで受け取ったすべてのDevice Eventを受けるようにしておきます。なので、すべてのAll
にチェックを入れておきます。
一方、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"
#define PASSWORD "xxxxx"
#define ORG "xxxxx"
#define DEVICE_TYPE "MQTTDevice"
#define DEVICE_ID "xxxxx"
#define TOKEN "xxxxx"
char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
char subTopic[] = "iot-2/cmd/notify/fmt/json";
char pubTopic[] = "iot-2/evt/request/fmt/json";
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("");
connectWifi();
client.setServer(server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
connectMqtt();
subscribeMqtt();
publishMqtt();
}
client.loop();
}
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();
}
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.println("connected!");
}
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();
}
}
void subscribeMqtt() {
Serial.print("subscribe to "); Serial.print(subTopic);
if (client.subscribe(subTopic)) {
Serial.println(" OK");
} else {
Serial.println(" FAILED");
}
}
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してきますが・・・
Node-RED上のLog出力にもちゃんと表示されていますね。
また、Node-REDからPublishしてやると、ESP8266のログ出力にも表示されてます。いい感じに双方向通信できてますねー。
いやー、IBMはドキュメントが豊富で助かりますね。というわけで、MQTTをESP8266で触ってみた話でした!