arduino-esp32を使って作ったMatter対応ESP32プログラムを、Arduino OTAに対応させました。Arduino IDEからWiFi経由 (Over The Air) でプログラムをアップデートできます。プログラムに5行足すだけで、簡単です。
ESP32で作ったMatterデバイス
前回の記事では、Arduino IDEとarduino-esp32ライブラリを使ったMatterデバイスを作りました。

iPhone, Macのホームに、Matterデバイスとして登録し、ホーム画面の操作や、

ESP32の物理ボタン操作でオンボードLEDがOn/Offします。
。 
Matterプログラムは、サイズが大きく、フラッシュメモリが4MBのESP32の場合、デフォルトのパーティショニングでは、メモリ超過します。不揮発メモリ用の領域を削減することで、パーティションに収まりました。それでもフラッシュメモリの割り当てパーティションの87%を占めています。この残り容量で、OTA対応できるのかどうか、確認したいと思いました。
MatterデバイスのOTA(使いません)
MatterにはOTAの機能が備わっているようです。仕組みを詳しく調べることはしてませんが、特定のサーバでファームウェアアップデートが準備された場合に、自動的にアップデートされるようです。ただ、正式に認証されているMatterデバイスじゃないと対応しないような説明もありました。さらに、実際にはMatterのOTAを使わずに、従来通りメーカー提供のアプリの中でファームウェアアップデートする方式のデバイスも多いようです。ということで、難しそうですし、可能かどうかも不明なので、MatterのOTAは諦めます。
Arduino IDEのOTAを使う
Arduino IDEが提供しているOTAの機能です。下の記事で説明しました。詳しくはこちらをご覧ください。

シリアルポートのメニューに、WiFiの選択肢が現れるので、それを選択して、プログラムをESPにアップロードします。Arduino IDEでDIYしたデバイスをOTAする時は、Arduino IDEを使っている状態なので、これを使うのが理にかなってます。
プログラムをOTA対応
前回のプログラムをOTA対応させました。追加したプログラムは、//———-OTA————-でコメントした5行です。手動でWiFi設定する場合と、BLEでコミッションする場合で、WiFi確立のタイミングが異なるので、手動WiFi設定の場合のみOTA対応させました。BLEコミッションの場合もOTA可能だと思いますので、後日挑戦したいと思います。
#include <Matter.h>
#if !CONFIG_ENABLE_CHIPOBLE
//もしBLEでコミッションするならフラッシュメモリの無駄を防ぐためWiFiはインクルードしない
#include <WiFi.h>
#include <ArduinoOTA.h> //-----------OTA-----------
#endif
#include <Preferences.h>
// BLEでコミッションするならCONFIG_ENABLE_CHIPOBLEを定義しておく
#if !CONFIG_ENABLE_CHIPOBLE
// BLEでコミッションしない場合は、手動でWiFi指定してWiFiでコミッションする
const char *ssid = "your-ssid"; // Change this to your WiFi SSID
const char *password = "your-password"; // Change this to your WiFi password
#endif
// このNodeのEndpointsのリスト ここではOn/Off Light Endpoint
MatterOnOffLight OnOffLight;
// 最後のOnOff状態をPreferencesを使って記憶
Preferences matterPref;
const char *onOffPrefKey = "OnOff";
// オンボードのLEDのピン番号。
const uint8_t ledPin = 2; // ESP32では2番が青色LEDなのでそれを書いておく
// bootボタンを入力に使う場合0
const uint8_t buttonPin = 0;
// Button control
uint32_t button_time_stamp = 0; // チャッタリング制御用
bool button_state = false; // ボタン状態 false = released | true = pressed
const uint32_t debouceTime = 250; // チャッタリング防止時間 (ms)
const uint32_t decommissioningTimeout = 5000; // 5秒長押しで設定モードへ
// ライトをOnOffする命令が来ると、このcallback関数が呼ばれる
bool setLightOnOff(bool state) {
Serial.printf("User Callback :: New Light State = %s\r\n", state ? "ON" : "OFF");
if (state) {
digitalWrite(ledPin, HIGH); //OnならLEDを点灯して
} else {
digitalWrite(ledPin, LOW); //OffならLEDを消灯
}
// store last OnOff state for when the Light is restarted / power goes off
matterPref.putBool(onOffPrefKey, state); //電源落とされても復帰するようバックアップ
// This callback must return the success state to Matter core
return true; //必ずtrueを返す
}
void setup() {
// ボタンとLEDを初期化
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
// CONFIG_ENABLE_CHIPOBLE is enabled when BLE is used to commission the Matter Network
// BLEでコミッションしないなら、手動でWiFi起動
#if !CONFIG_ENABLE_CHIPOBLE
// We start by connecting to a WiFi network
Serial.print("Connecting to ");
Serial.println(ssid);
// Manually connect to WiFi
WiFi.begin(ssid, password);
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\r\nWiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(500);
//OTA setup
ArduinoOTA.setHostname("matterLight"); //-----------OTA-----------
ArduinoOTA.setPasswordHash("12345678901234567890123456789012"); //-----------OTA-----
ArduinoOTA.begin(); //-----------OTA-----------
#endif
// Matter EndPointを初期化。不揮発メモリ(?)から過去の状態を読んで設定
matterPref.begin("MatterPrefs", false);
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
OnOffLight.begin(lastOnOffState);
OnOffLight.onChange(setLightOnOff);//変化した場合のcallback関数を設定
// Matter beginning - 全てのEndPointsが初期化できたら開始
Matter.begin();
// すでにコミッション済みのアクセサリの再起動かもしれない、その場合
if (Matter.isDeviceCommissioned()) {
Serial.println("Matter Node is commissioned and connected to the network. Ready for use.");
Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF");
OnOffLight.updateAccessory(); // configure the Light based on initial state
}
}
void loop() {
// コミッション済みかどうかをチェック(loop中にコミッション状態変化することもある)
if (!Matter.isDeviceCommissioned()) { // コミッション終わってなかったら
Serial.println(""); // ペアリング情報を流す
Serial.println("Matter Node is not commissioned yet.");
Serial.println("Initiate the device discovery in your Matter environment.");
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code");
Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
// waits for Matter Light Commissioning.
uint32_t timeCount = 0;
while (!Matter.isDeviceCommissioned()) { //コミッション終わるまで待ち、5秒ごとにメッセージ出す
delay(100);
if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec
Serial.println("Matter Node not commissioned yet. Waiting for commissioning.");
}
}
Serial.printf("Initial state: %s\r\n", OnOffLight.getOnOff() ? "ON" : "OFF");
OnOffLight.updateAccessory(); // configure the Light based on initial state
Serial.println("Matter Node is commissioned and connected to the network. Ready for use.");
}
// ボタンはライトの制御にも使う。ボタンが押されたかどうかチェック
if (digitalRead(buttonPin) == LOW && !button_state) { //前回HIGH今回LOWなら
// チャッタリング防止
button_time_stamp = millis(); // ボタン押下時刻を記録
button_state = true; // pressed.
}
// ボタン短押しでライトをOnOff(チャッタリング期間を過ぎて、ボタンHIGHなら、短押し)
uint32_t time_diff = millis() - button_time_stamp;
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) {
button_state = false; // released
// Toggle button is released - toggle the light
Serial.println("User button released. Toggling Light!");
OnOffLight.toggle(); // Matter Controller also can see the change
}
// ボタンを5秒長押しなら、ライトを消して、つぎのloopでコミッションやり直しへ
if (button_state && time_diff > decommissioningTimeout) {
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
OnOffLight.setOnOff(false); // turn the light off
Matter.decommission();
button_time_stamp = millis(); // avoid running decommissining again, reboot takes a second or so
}
#if !CONFIG_ENABLE_CHIPOBLE
ArduinoOTA.handle(); //-----------OTA-----------
#endif
}
動作確認
OTAの動作確認をしました。このプログラムを、まずは有線でアップロードして動作させます。するとArduino IDEのポートのメニューに、WiFi接続先が現れます。下図では、プログラム内で指定したmatterLightという名前で表れています。

これを選択して、プログラムをアップロードすると、パスワード入力ダイアログが現れます。

プログラムの中で指定したハッシュに対応するパスワードを入力すると、無事にアップロードされました。
OTA化によるサイズ変化
OTA改造前後のプログラムサイズを比較します。改造前後のIDEウィンドウのスクリーンショットを、アニメーションGIFにしたのが、下図です。Outputの部分を見ると、増加は35kB程度でした。保存領域の87%を占めていたプログラムが、89%に増加する程度です。

空き容量が少ないことには変わりありませんが、OTAに改造しても大差ないようです。
まとめ
Arduino IDEで作ったESP32用のMatterプログラムを、OTA対応に改造しました。プログラムサイズの増加は2%程度でした。改造は5行追加するだけですし、Arduino IDEの機能で簡単にOTAアップデートできますので、DIYプログラマーに最適ではないかと思います。




コメント
なんと、IKEAの新製品の発売が始まっています、早いですねー。価格も安いです。さっそく注文しなくちゃ。あとは、アップルのスマートディスプレイ待ちです。
センサ類が発売されているようですね。Matter over Threadでしょうか