スイッチやセンサの状態や、リレーやサーボモータの制御コマンドを送受信する目的で、MQTT (Message Queueing Telemetry Transport)というプロトコルが使われます。MQTTは、Home AssistantやHomebridgeでもサポートされていますし、Arduinoでも使えるので、スマートホーム自作に活用できます。通常は家の中にMQTTサーバー(MQTTの用語ではブローカーと呼ぶので以下ではブローカー)を用意して使用しますが、インターネット上にも試作・実験で誰でも使える公開ブローカーが用意されてます。
今回は、そんな公衆MQTTブローカーを使って、ESP 32に接続したLEDをHomeKitから点滅(Lチカ)させます。以下の経路で接続します:
- LEDを接続したESP 32
- ESP 32をMQTTに接続するライブラリ: EspMQTTClient
- Eclipse Projectの公衆MQTTブローカー
- Homebridge + MQTTプラグイン
- iPhoneやMacのホーム.app
MQTTの使われ方
例えば、ArduinoやESP 32で無線スイッチを作って、人がon/offしたことをLAN経由で他のコンピュータに伝える仕組みを考えてみます。ソケット通信のライブラリを使って他のコンピュータにスイッチの状態を伝えるのが簡単で効率が良いのですが、プログラムを起動する手順が面倒です。Arduinoに簡単なWebサーバーのような応答をさせて、スイッチ状態をHTTPで送る方法もあります。下の写真はHTTP経由でLEDを点灯するLチカの例です。
( こちらから転載 )
この場合、コントロールするために普通のWebサーバやcurlコマンドも使えて便利です。でもHTTPは送りたいデータ以外にお約束のテキストを色々転送する必要があるので、せいぜい数バイトしか送る必要がないIoT的な用途には無駄(オーバーヘッド)が多いです。もともと制御用のプロトコルじゃないので、on/offの表現方法も自由過ぎて標準化が必要です。
そこでMQTTが使われます。短いメッセージを効率よく伝える用作られたIoT向きのプロトコルです。MQTTを使う場合、MQTTブローカーというサーバを別途用意して、それにデータ送信側と受信側がクライアントとして接続します。
手順には、雑誌や新聞の出版と購読をメタファーにした名前がついていて、サーバコンピュータは書籍取次業者(ブローカー)として機能します。データを送信したい側は、雑誌名・新聞名に相当するトピック (topic) に適当な名前をつけて、送りたいデータをメッセージ (message) として「出版 (publish) 」します。データを受信したい側は、雑誌名・新聞名であるtopicを指定して、「購読 (subscribe)」しておくと、送信側からデータがpublishされたときに、これをmessageとして受け取れます。
例えば、上の図のように、on/offスイッチ側がswitchというトピックを指定してoffという文字列をパブリッシュすると、switchをサブスクライブしている他のコンピュータにそれが伝わります。そのコンピュータでHomebridgeとMQTTプラグインが動いていれば、このon/offスイッチをHomeKitのアクセサリとして扱えます。
MQTTをインストールする
MQTTのソフトウェアを提供するオープンソースプロジェクトにはいろいろあるようですが、Mosquittoが定番の一つのようです。なのでこれを使います。Mosquitto一式をRaspberry Pi OSやUbuntuなどにインストールするには、
sudo apt install mosquitto mosquitto-clients
とします。MQTTクライアントのみで、ブローカを動かさないなら、mosquitto-clientsだけで良いです。Windows用もあります。個人的にはDOS窓はあまり好きではないので、WSLでUbuntuを使うのが良いのではと思います。その場合、Ubuntuのシェルウィンドウからaptコマンドで取り寄せます。
macOSの場合は、homebrewを使って以下のようにインストールします。
brew install mosquitto
これでMQTTブローカーにアクセスする2つのコマンド、mosquitto_subとmosquitto_pubコマンドが使えるようになります。
公衆MQTTブローカーを使ってみる
スマートホームで使うMQTTブローカーは、自宅で稼働させて、自家用に使うのが一般的だと思います。ただ、自前でサーバを建てたりメンテするのが煩わしいという人のために、インターネット上でMQTTブローカーを提供するサービスもあります。Mosquittoを作っているEclipse Fundationというところは、mqtt.eclipseprojects.ioというIPアドレスで、無料MQTTブローカーを提供してます。誰でもすぐに使えます。
(修正:今試したら、eclipseprojectsのブローカーが止まってました。broker.hivemq.com というところは動いていたので、こちらも試してください。)
例えば、
mosquitto_sub -h mqtt.eclipseprojects.io -t #
とするとものすごい量のデータが流れてきます。コントロールCで止めてください。(修正:改めて試したら-t #の指定ができませんでした。仕様が変わったのかもしれません。)
-hがアドレス、-tがトピック名を表します。トピックの設定で#を使うと、全部の文字に合致する意味になるので、このブローカーに流れている全てのメッセージが表示されます。世界中の人たちがこのブローカーを使ってテストしている様子がわかります。
それっぽい名前のトピック、例えばtestとかsensorで始まるトピックに限定してみると、この記事を書いた時点では次のような情報が現れました(testの場合)。
mosquitto_sub -h mqtt.eclipseprojects.io -t test/# -v test/dht11/temp_c 24.50 test/dht11/temp_f 76.10 test/dht11/humidity 53.00
トピックは任意の文字列なのですが、慣例としてスラッシュで区切って階層的に使います。-tで指定したtest/#というパラメータの意味は、test/で始まる全てのトピックという意味です。また-vオプションは、メッセージだけでなく、それのトピック名も表示するという意味です。その結果、誰かがtest/dht11/の名前で温度と湿度のデータを流しているようです。
ではこのMQTTブローカーに、何かデータを流してみましょう。他の人と被らないように、diysmarthomeというトピックをつけて流してみます。まずは、
mosquitto_sub -h mqtt.eclipseprojects.io -t diysmarthome/# -v
でサブスクライブしておきます。別のシェルウィンドウから、
mosquitto_pub -h mqtt.eclipseprojects.io -t diysmarthome -m hello mosquitto_pub -h mqtt.eclipseprojects.io -t diysmarthome/sw -m on mosquitto_pub -h mqtt.eclipseprojects.io -t diysmarthome/sw -m off
とパブリッシュすると(-mオプションがメッセージを表します)、サブスクライブ側には、
mosquitto_sub -h mqtt.eclipseprojects.io -t diysmarthome/# -v diysmarthome hello diysmarthome/sw on diysmarthome/sw off
と表示されます。この公衆MQTTブローカーに流れる情報は、誰でも見ることができますし、トピックがバッティングする可能性もありますので、実際のスマートホームの制御には適してません。でも、動作チェックの目的なら十分に使えます。以下で試してみます。
HomebridgeでMQTTを使う
MQTTをHomeKitから使うために、HomebridgeにMQTTプラグインを追加します。HomegridgeにはMQTTを使うプラグインが多数あります。プラグインのページでmqttを検索すると30個見つかりました。
ここではHomebridge Mqttthingというプラグインを使ってみます。このプラグインで、HomeKitで定義されるほとんどのデバイスを作ることができ、その動作をMQTTトピック・メッセージに紐付け設定できます。このプラグインをインストールし、設定画面を開きます。アクセサリを追加するボタンを選び、Light bulb – on/offというアクセサリを作ってみます。名前はMQTT Lightにします。
URLには公衆MQTTブローカーのアドレスを入れておきます。ユーザ名やパスワードは不要なので空白にしておきます。
トピック名も決めておきます。タグで指定された名前そのままの、わかりやすい名前にしておきました。
この結果、configファイルには以下のような記述が書き込まれました。
{
"type": "lightbulb-OnOff",
"name": "MQTT Light",
"url": "mqtt://mqtt.eclipseprojects.io",
"topics": {
"getOnline": "diysmarthome/getonline",
"getOn": "diysmarthome/geton",
"setOn": "diysmarthome/seton"
},
"accessory": "mqttthing"
}
Homebridgeを再起動すると、iPhoneやMacのホーム.appにこのアクセサリが現れます。
このアクセサリを操作する前に、Ubuntu, Windows, Macなどのシェルウィンドウで以下のコマンドを動かしておきます。
mosquitto_sub -h mqtt.eclipseprojects.io -t diysmarthome/# -v
ここで、ホーム.appからこのアクセサリをタップまたはクリックすると、表示はオン・オフするのですが、
—>
同時に、実行中のmosquitto_subのコマンドの応答として、以下のような結果が表示されて、
diysmarthome/seton true diysmarthome/seton false
MQTTブローカーにデータが流れていることがわかります。このプラグインでは、デフォルトではtrue、falseという文字列が流されます(設定で変更可能です)。ホーム.appの操作で、このアクセサリがオンになるとsetonトピックにtrueと言うメッセージが、オフになるとfaseが流れてきます。
では、先ほど設定したgetonの方も試してみます。別のシェルウィンドウから、
mosquitto_pub -h mqtt.eclipseprojects.io -t diysmarthome/geton -m true
とタイプしてみます。ホーム.appの表示がオンになります。また-mとしてfalseを送ると表示がオフになります。
—>
ここで実行したmosquitto_sub, mosquitto_pubコマンドに相当するプログラムをArduinoやESP 32の上に書けば、on/off型の電球の動きをするアクセサリが作れるわけです。
MQTTでLチカする
ここで作ったMQTT Lightに応答するアクセサリを、ESP 32を使って作ります。そのために、Arduino IDEにMQTTを扱うためのライブラリを導入します。Arduino IDEの「ツール」「ライブラリを管理…」からライブラリマネージャを開き、ここでespmqttで検索すると、ライブラリが見つかります。このEspMQTTClientライブラリを使います。
ライブラリのサイトで配布されているサンプルをもとに、以下のように、LEDを点滅させるプログラムを作りました。
#include "EspMQTTClient.h"
EspMQTTClient *client;
const int LED=13; //pin for LED
const char SSID[] = "XXXXXXXX"; //WiFi SSID
const char PASS[] = "xxxxxxxx"; //WiFi password
char CLIENTID[] = "diysmarthome_cv3a2JTs";//unique ID
const char MQTTADD[] = "mqtt.eclipseprojects.io"; //Broker addr
const short MQTTPORT = 1883; //Broker port
const char MQTTUSER[] = "";//Can be omitted if not needed
const char MQTTPASS[] = "";//Can be omitted if not needed
const char SUBTOPIC[] = "diysmarthome/seton"; //sub topic
const char PUBTOPIC[] = "diysmarthome/geton"; //pub topic
const char DBGTOPIC[] = "diysmarthome/debug"; //debug topic
void setup() {
pinMode(LED, OUTPUT);
client = new EspMQTTClient(SSID,PASS,MQTTADD,MQTTUSER,MQTTPASS,CLIENTID,MQTTPORT);
}
void onMessageReceived(const String& msg) {
client->publish(DBGTOPIC, "Message received.");
if(msg.compareTo("true")==0) {
digitalWrite(LED, HIGH);
client->publish(PUBTOPIC,"true");
}
else if(msg.compareTo("false")==0) {
client->publish(PUBTOPIC,"false");
digitalWrite(LED, LOW);
}
}
void onConnectionEstablished() {
client->subscribe(SUBTOPIC, onMessageReceived); //set callback
client->publish(DBGTOPIC, "Connection established.");
}
void loop() {
client->loop();
delay(100);//動作安定のため?効果は不明
}
CLIENTIDは、デバイス固有のIDにしておくべきらしいです。MACアドレスを使うことが多いらしいですが、ここではランダムな文字列を含ませておきました。
onConnectionEstablishedは、MQTTへのコネクションが成立したときに呼ばれる関数のようです。ここで、サブスクライブしたトピックにメッセージが到着したときに呼ばれる関数を、コールバック関数として登録します。
onMessageReceivedは、そのコールバック関数です。サブスクライブしたトピックにメッセージが流されると呼ばれます。メッセージの内容を判断してLEDを点滅してます。
メインloopの100ms遅延は、動作安定のために入れました。これを入れないでフルスピードでclient->loop()を呼び出すと、onConnectionEstablishedが何度も呼ばれてしまいました。インターネットの遅延に対して、接続できなかったと勘違いして再接続している様子でした。それで100ms遅延を入れました。
このプログラムをESP 32にダウンロードして動かすと、iPhoneやMacのホームのボタン操作で、
—> —>
LEDが点滅します(写真は使い回しです)。
mosquitto_subの命令を稼働させておけば、対応するトピックの情報が見られます。
mosquitto_sub -h mqtt.eclipseprojects.io -t diysmarthome/# -v diysmarthome/debug Connection established. diysmarthome/seton true diysmarthome/debug Message received. diysmarthome/geton true diysmarthome/seton false diysmarthome/debug Message received. diysmarthome/geton false
デバッグのために、/degugと言うトピックを使いました。デバッグメッセージはシリアルポートに流すことが多いですが、こうすると、MQTTで動作状態を確認することができます。
このESP 32のLEDは、mosquitto_pubコマンドからもon/offできます。
% mosquitto_pub -h mqtt.eclipseprojects.io -t diysmarthome/seton -m true % mosquitto_pub -h mqtt.eclipseprojects.io -t diysmarthome/seton -m false
LEDが点滅するだけでなく、ホーム.appの表示も同期します。
—>
まとめ
MQTTブローカーを開発しているEclipse Projectの公衆MQTTブローカーを使って、HomeKitの電球アクセサリを作りました。MQTTはいろいろなIoT機器や関連するサーバーが採用しています。データをモニターするのも楽なので、デバッグも捗ります。
今回は公衆のブローカーを使いましたが、通常はLAN内に設置します。次回は、スマートホームサーバを動かしているRaspberry PiやUbuntuサーバにMQTTブローカーを設置します。
コメント