ESP32でMatter対応のLightデバイスを試作しました。On/Off機能があり、それに伴ってESP32のLEDが点灯・消灯し、押しボタンスイッチでトグルします。Arduinoから簡単に使えるライブラリesp32-arduino-matterを使用しました。
HomeKitアクセサリをDIYする
HomeKit対応電子回路をDIYする場合、ESP32が一番手頃だと思います。Arduino IDEで簡単にプログラムできますし、
技適対応のWiFi/Bluetoothを搭載してますし、何よりも価格が安い(送料込み600円程度)です。今まで、ESP32にHomeSpanライブラリを使ってHomeKit Accessory Protocol (HAP)を実装する方法
と、MQTTブローカーとHomebridge経由でHomeKitアクセサリを作る方法を試してきました。
HomeSpanは、手元の環境では「応答なし」状態に陥りやすい
ので、主にMQTTベースでDIYしてきました。今回はこれらの方法に加えて、MatterデバイスとしてHomeKitに接続することを目指します。
本格Matterで挫折
Arduino IDEにESP32用ボードマネージャをインストールして使う方法は楽です。このほか、ESP32プログラム開発には、Espressif IoT Development Framework (IDF) を使うこともできます。どちらかというとIDFの方が純正で正当な開発環境で、ESP32用ボードマネージャは、IDFを元にEspressif社が配布している派生版です。
EspressifはIDF用のMatterの開発ツールも配布しています。なのでこれを使えば、Matterデバイスを開発することができます。IDFでMatter開発する手順を紹介したYouTube動画もありました。
ただインストールがめんどくさくて、ビルドの途中で挫折していました。
Arduinoでお手軽Matter
Arduinoでお手軽に開発できるようになると良いなと思っていたところ、年末くらい(2022年) にArduino向けのMatterライブラリを作ってくださった方がいました。こちらです。
Espressifのライブラリをプリコンパイルして、Arduinoから簡単に使えるようにしてくれてます。このサンプルプログラムをコンパイルして、Lightデバイスを作ってみました。LightといってもESP32基板上のLEDが点灯するだけです。また押しボタンスイッチでのトグル入力もできました。これに明るいLEDや本格的なスイッチを外付けすれば、ちゃんとした照明器具になると思います。
Matterライブラリの準備
ライブラリを準備する手順は、上記のgithubページに書かれてます。
- まずは、ESP32 ボードバージョンを最新版にします。ライブラリのページには2.0.11にせよと書いてありましたが、最新版の2.0.14でもokでした。メニューのツール〜ボード〜ボードマネージャからESP32対応を最新に更新します。
- ArduinoのC++17サポートを有効にします。Macの場合、~/Library/Arduino15/packages/esp32/hardware/esp32/2.0.7/platform.txtの中に書かれている-std=gnu++11という文字を-std=gnu++17に書き換えます。4箇所ありました。ここでArduino IDEを再起動します。
- こちらからzipファイルになったライブラリ一式 (esp32-arduino-matter.zip) をダウンロードします。
- メニューのスケッチ〜ライブラリをインクルード〜.zip形式のライブラリをインストール…を選んで、ダウンロードしたライブラリのzipもしくはフォルダを選択します。
- メニューのツール〜Partition SchemeをMinimal SPIFFSに設定します。(保存領域をたくさん確保するため)
- 古いデータに起因する問題を回避するために、メニューのツール〜Erase Flash Before Sketch UploadをEnabledにします。(念のためにだそうです)
- メニューのファイル〜スケッチ例〜カスタムライブラリのスケッチ例から、Esp32 Arduino Matterを選んで、スケッチ例を開きコンパイルしてESP32にダウンロードします。
という手順です。特に問題なくすんなり準備できました。
Lightスケッチ例を試す
次に、ライブラリに含まれているLightデバイスのスケッチ例
を試しました。このスケッチ例では、GPIOピンの2番のLEDをMatterのライトとして使い、ピン0番をトグルスイッチに使ってます。トグルスイッチを押すとLEDが点灯・消灯します。
今まで知らなかったのですが、2番ピンにはESP32開発ボードの青色LEDが接続されていて、ピン0番はBOOTボタンに接続されているんですね。下は、ピン0番が押されるとピン2番がHIGHになるスケッチを動かしたところです。BOOTボタンを押すと青色LEDが光ります。
コンパイルとダウンロードが終わると、Matterデバイスとして動作開始します。シリアルモニターを開いておくとメッセージが流れますが、その中で11桁のペアリングコードが表示されます。これはしっかりメモしておきます。(下の例では数字を書き換えてあります)
I (1724) chip[SVR]: Manual pairing code: [12345678901]
ちなみにこの数字は、いつも同じでした。このライブラリで決められた数値なのかもしれません。
Matterデバイスを登録する
今回初めてMatter対応デバイスを使いました。なので、色々と不慣れなことが多かったです。まずは、いつものHomeKitアクセサリと同様に、ホームの右上の+ボタンからアクセサリの追加を試みました。
QRコードは用意してありませんので、「その他のオプション…」を選択します。
すると「近くにあるアクセサリ」にESP32が現れます。この段階ではESP32とiPhoneがBLEで接続して通信していると思われます。ここでMatter Accessoryを選ぶと設定コード入力画面になります。
ここもQRコードは無いので、Arduinoのシリアルモニターに流れていた11桁のペアリングコードを手作業で入力します。認定されていないアクセサリなので、警告が出ますが「このまま追加」を選びます。
この後、登録に成功すれば、場所や名前を聞かれますので、適当に設定します。
登録できない場合の対応
このようにすんなりと登録できれば良いのですが、初めてのMatterデバイスだったので色々と躓きました。
WiFiを2.4GHzにする
まず、ペアリングの段階では、iPhoneを2.4GHzのWiFiに接続しておく必要があります。ESP32には2.4GHzのWiFiしか搭載されていないからです。5GHzのWiFiに接続してペアリング作業を進めると、シリアルモニターにネットワーク関係のエラーが表示されます。
ホームを最新版にする
登録に苦労していたときに、こんな画面が現れたことがありました。
ホームの右上のメニューから、「ホームを設定」を選ぶと、アップデートが選択できます。ホームハブだけのアップデートなのか、iPhoneホームアプリのアップデートなのか不明ですが、いろいろな要素をMatter対応にアップデートする必要があるようです。iPhone、HomePod、MacのOSとファームウェアアップデートは済ませてあるのですが、それだけでは足りないようです。アップデートを進めようとすると、
というようなメッセージが現れます。ホームをアップデートすると、他のデバイスや、家族のデバイスなどもアップデートする必要があるようです。互換性を確保するために、自動ではアップデートされない仕組みのようでした。ここは構わずアップデートします。これでなんとかMatterデバイスを登録できました。
Matterデバイスを使う
登録ができたら、いよいよ使ってみます。iPhoneやMacのホームには、ESP32が以下のように照明デバイスとして表示されます。タップやクリックするとon/offします。
それと同期して、ESP32の青色ダイオードも点灯・消灯します。またESP32のBOOTボタンを押すと、この電球デバイスの状態がon/offと切り替わります。動画を以下に掲載します。
プログラムを確認する
サンプルプログラムの内容を確認しておきます。全体は前述のようにこちらにあります。
これのコメントを日本語にしました。割と簡単な構造です。
#include "Matter.h"
#include <app/server/OnboardingCodesUtil.h>
using namespace chip;
using namespace chip::app::Clusters;
using namespace esp_matter;
using namespace esp_matter::endpoint;
// LEDと押しボタンスイッチのピン番号
const int LED_PIN = 2;
const int TOGGLE_BUTTON_PIN = 0;
// トグルボタンのチャッタリング防止時間と状態を覚えておくための変数
const int DEBOUNCE_DELAY = 500;
int last_toggle;
// MatterのClusterとアトリビュートのID。OnOffクラスタでOnOffを提供する
const uint32_t CLUSTER_ID = OnOff::Id;
const uint32_t ATTRIBUTE_ID = OnOff::Attributes::OnOff::Id;
// Endpoint and attribute ref that will be assigned to Matter device
uint16_t light_endpoint_id = 0;
attribute_t *attribute_ref;
// いろいろなデバイスのイベントを聴取する可能性があるけど、ここでは使わないので空欄にしておく
static void on_device_event(const ChipDeviceEvent *event, intptr_t arg) {}
static esp_err_t on_identification
(identification::callback_type_t type, uint16_t endpoint_id,uint8_t effect_id, void *priv_data)
{
return ESP_OK;
}
// アトリビュートが更新される時に呼び出されるリスナー関数
// 更新が来たら、パス (endpointとclusterとattribute)をチェックして、一致したらLEDを更新する
static esp_err_t on_attribute_update(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) {
if (type == attribute::PRE_UPDATE && endpoint_id == light_endpoint_id &&
cluster_id == CLUSTER_ID && attribute_id == ATTRIBUTE_ID) {
// light on/off attributeがアップデートされたので、
boolean new_state = val->val.b;
digitalWrite(LED_PIN, new_state); //LEDを点灯消灯する
}
return ESP_OK;
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
pinMode(TOGGLE_BUTTON_PIN, INPUT);
// デバッグ用の設定。ESP_LOG_ERRORなどに変更するとメッセージが減る
esp_log_level_set("*", ESP_LOG_DEBUG);
// Matterノートの設定
node::config_t node_config;
node_t *node = node::create(&node_config, on_attribute_update, on_identification);
// Light endpoint / cluster / attributes をデフォルト値に設定
on_off_light::config_t light_config;
light_config.on_off.on_off = false;
light_config.on_off.lighting.start_up_on_off = false;
endpoint_t *endpoint = on_off_light::create(node, &light_config, ENDPOINT_FLAG_NONE, NULL);
// on/off attributeへの参照を保存. 後の処理でattribute値を読むために使われる.
attribute_ref = attribute::get(cluster::get(endpoint, CLUSTER_ID), ATTRIBUTE_ID);
// 生成したendpoint idも保存しておく
light_endpoint_id = endpoint::get_id(endpoint);
// Matter deviceを動かす
esp_matter::start(on_device_event);
// Matterデバイス設定に必要なコードを表示(ペアリングコードなど)
PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE));
}
// 現在のMatterデバイスのlight on/off attribute 値を読み取る
esp_matter_attr_val_t get_onoff_attribute_value() {
esp_matter_attr_val_t onoff_value = esp_matter_invalid(NULL);
attribute::get_val(attribute_ref, &onoff_value);
return onoff_value;
}
// light on/off attribute 値を設定する
void set_onoff_attribute_value(esp_matter_attr_val_t* onoff_value) {
attribute::update(light_endpoint_id, CLUSTER_ID, ATTRIBUTE_ID, onoff_value);
}
// チャッタリング防止のために500ms毎に押しボタンスイッチ状態を調べて押されていたらLEDを反転
void loop() {
if ((millis() - last_toggle) > DEBOUNCE_DELAY) {
if (!digitalRead(TOGGLE_BUTTON_PIN)) {
last_toggle = millis();
// 実際のon/off値を調べて、それを反転する
esp_matter_attr_val_t onoff_value = get_onoff_attribute_value();
onoff_value.val.b = !onoff_value.val.b;
set_onoff_attribute_value(&onoff_value);
}
}
}
このサンプルは、LEDを点灯消灯する機能と、ボタンを押すとLEDが反転する機能があります。電球のように点灯消灯するだけの機能や、押しボタンだけのデバイスならば、さらに簡単にプログラムが書けます。
スマートプラグを作る
ライブラリには、スマートプラグのサンプルも載ってます。2連の🔌プラグに対応してます。これもコンパイルしてすぐに動きました。2連を1連に変更するのも難しくはありません。
ただ、今のところ作れるのは、ライトとスマートプラグだけのようです。他に、Espressifのライブラリを見ながら、スイッチを作ろうと試しました。でも、コンパイルもダウンロードも出来て、HomeKitとペアリングも出来るのですが、ホームアプリ上では「非対応」状態になってしまいました。
Espressifの本家のgitでも、スイッチが作れないという話題が上がってました。ライブラリの不具合なのか、Matterの仕様なのか、Appleホームが未対応なのか不明ですが、Matterは始まったばかりなので、これから動くようになるのかもしれません。
まとめ
ESP32でMatterデバイスを作りました。LEDと押しボタンスイッチでon/offするデバイスです。Espressifのオリジナルなライブラリを使うより、簡単にプログラムできると思います。ライブラリ作者の方によると、コンパイルしたコードのサイズが大きくなってしまうので、構成の方法を検討したいとのことです。なので、今後ライブラリが大きく変更される可能性はあります。でも今のままでも、DIY用途で十分に実用的なものが作れると思います。
これでESP32を使ってHomeKitアクセサリをDIYする方法が3通り可能になりました。
- HomeSpanでHAPを使う
- MQTTを使う
- Matterを使う(今回)
です。最初に述べたようにHomeSpanは手元の環境で応答無しの状態に陥ることが多いです。一方で今回のMatterのライブラリは安定していて、応答も速いです。ただし、照明とプラグしか作成できませんでした。2番目のMQTTを使う方法を、これからもしばらくは使うことになりそうです。
コメント
はじめまして、こちら参考にさせていただきまして取り組んでいるのですが
6の
古いデータに起因する問題を回避するために、メニューのツール〜Erase Flash Before Sketch UploadをEnabledにします。
こちらのツールの追加方法が分からず
進行できなくなってしまい
誠にお手数ではありますがご教授して頂きたいです。
よろしくお願い致します。
Arduinoのツールメニューから選択します。ただ、念のためという手順でしたので、無視しても大丈夫かと思います。
前回のお返事ありがとうございました。
加えてまた質問なのですが答えていただけましたら幸いです。
手順2の
ArduinoのC++17サポートを有効にします。Macの場合、~/Library/Arduino15/packages/esp32/hardware/esp32/2.0.7/platform.txの中に書かれている-std=gnu++11という文字を-std=gnu++17に書き換えます。1箇所だけです。ここでArduino IDEを再起動します。
この部分なのですがファイルが見つからず、素人で大変申し訳なくMACのどこからどう書き換えるのか分かりやすく記載していただけますと幸いです。ターミナルからであればコマンド等分かりやすくご教授頂けると助かります。
よろしくおねがいします。
すみません、脱字がありました。正しくは、
~/Library/Arduino15/packages/esp32/hardware/esp32/2.0.7/platform.txt
です。本文も訂正しました。ご指摘ありがとうございました。