前回の記事で、ESP32のオンボードボタンとLEDを、MQTTを介してHomeKitに接続しました。その結果、iPhoneやMacのホーム.appには、このESP32が照明器具として表示されて、LEDのOn/Offが可能になりました。
今回は、これをArduino OTAに対応させて、WiFi経由でプログラムをアップデートできるようにします。追加するのは5行です。
HomeKitアクセサリのDIY
先の記事で紹介したように、MQTTとHomebridge経由でESP32/ESP8266をHomeKitに接続することで、簡単なプログラムにより、HomeKitで定義済みの多くのアクセサリを作ることができます。mqttthingプラグインが、HomeKitアクセサリの動作を、MQTTメッセージに割り当ててくれるからです。
例えば、照明器具、スマートプラグ、スイッチ、温度計、湿度計、光センサ、人感センサ、振動センサ、開閉センサ、炭酸ガスセンサ、煙センサ、漏水センサ、ドアベル、冷暖房機器、扇風機、電動カーテン、電動ブラインド、自動ドア、ガレージドア、電気錠、電動バルブ、テレビ、アンプ、防犯システムなどを作ることができます。
前回作ったシンプルなESP32プログラムも、LEDのピンにリレーを接続すれば、照明器具、スマートプラグ、電気錠、電動バルブなどになります。タクトスイッチのピンにしっかりとしたスイッチを接続すれば、無線スイッチ、ドアベルになり、センサを接続すれば、人感センサ、開閉センサ、漏水センサなどが作れます。ただ、カーテン、ブラインド、自動ドア、ガレージドアなどは、開閉の進捗状況を反映させるため、もう少し追加の工作が必要です。
Arduino OTAに対応させる
スマートホームアクセサリを自作して、次に欲しくなる機能は無線経由でのプログラム更新機能(OTA: Over The Air)ではないでしょうか。壁スイッチやシーリングライトに組み込んだESP32のプログラムを修正しようとする場合、分解してUSBケーブルを接続するのは大変です。Arduino IDEには、Arduino OTAという便利な機能があるので、今回はそれを組み込みます。
Arduino OTAを使うためには、前回のプログラムに以下の行を追加します。追加する行は、//for OTAというコメントを書いた5行です。
#include "EspMQTTClient.h"
#include "ArduinoOTA.h" //for OTA
const int LEDpin = 2; //ESP32 onboard blue LED
const int BTNpin = 0; //ESP32 onboard BOOT button
const char SUBTOPIC[] = "mqttthing/LEDLight/set"; //mqtt topic to subscribe
const char PUBTOPIC[] = "mqttthing/LEDLight/get"; //mqtt topic to publish
EspMQTTClient client(
"WifiSSID",
"WifiPassword",
"192.168.xxx.xxx",// MQTT Broker server ip (RPi)
"MQTTUsername", // Can be omitted if not needed
"MQTTPassword", // Can be omitted if not needed
"TestClient" // Client name that uniquely identify your device
);
void setup() {
pinMode(LEDpin,OUTPUT);
pinMode(BTNpin,INPUT);
}
void onConnectionEstablished() {
ArduinoOTA.setHostname("LEDLight"); //for OTA
ArduinoOTA.setPassword("OTAPassword"); //for OTA
ArduinoOTA.begin(); //for OTA
client.subscribe(SUBTOPIC, onMessageReceived); //set callback
}
void onMessageReceived(const String& msg) {
if(msg.compareTo("true")==0) digitalWrite(LEDpin,HIGH);
else if(msg.compareTo("false")==0) digitalWrite(LEDpin,LOW);
}
int previousBTN = HIGH;
void loop() {
int currentBTN = digitalRead(BTNpin);
if(previousBTN != currentBTN) { //toggle LED when BTN HIGH-to-LOW
if(currentBTN == LOW) {
bool targetLED = !digitalRead(LEDpin);
digitalWrite(LEDpin, targetLED);
client.publish(PUBTOPIC,(targetLED ? "true" : "false"));
}
previousBTN = currentBTN;
}
client.loop();
ArduinoOTA.handle(); //for OTA
}
簡単に説明すると、
- プログラムの最初で、ArduinoOTA.hをインクルードする
- WiFiが確立された段階(onConnectionEstablished()の中)で、OTAの名前をsetHostname()で決めて、パスワードをsetPassword()で設定して、begin()で開始する
- loop()でOTAのハンドラーhandle()を定期的に呼び出す
という行を追加しました。自己流なので、もっと正しいやり方があれば、ぜひコメントで教えてください。例えば、setHostname(), setPassword()は、setup()の中でやっても良いかもしれません。
setPasswordの代わりに、setPasswordHash()を使えば、md5のハッシュ値で設定できます。今回は、WiFiのパスワードを平文で書いているので、こちらも平文にしました。
Arduino OTAを使う
このプログラムをUSBシリアル経由で書き込めば、Arduino OTAが使えるようになります。Arduino IDEのTools/Portメニューの中に、setHostname()で指定した名前が見えているはずです。これを選択します。
プログラムをアップロードしようとすると、パスワードを聞かれます。設定したパスワードを入力すれば、アップロードされます。
これで、何かに組み込まれてしまってアクセス困難なESP32であっても、プログラム修正が容易です。
まとめ
前回作ったESP32用HomeKitアクセサリプログラムに、Arduino OTA機能を追加しました。5行追加するだけです。これでArduino IDEからWiFi経由でプログラムアップロード可能になりました。ESP8266でも、全く同じ方法でOTA機能を実現的ます。
実際に使ってみると、Arduino IDEのPortメニューから、ESP32が消えて見えなくなる場合があります。原因を知らないのですが、mDNSの不調かと推測してます。その場合は、ESP32を再起動すると大抵復活します。機器に組み込んでしまってリセットボタンが押せない場合は、電源のOff/Onでも復活します。
