Arduino IDEとESP32でMatterデバイスを作る

DIYする

以前、有志の方が作った、Arduino IDEで使えるMatterライブラリesp32-arduino-matterを使用して、ESP32でMatter対応プログラムを作りました。

ESP32でMatterデバイスをDIYする
この記事の情報は古いです。最新版をご覧ください。(2025年12月3日)ESP32でMatter対応のLightデバイスを試作しました。On/Off機能があり、それに伴ってESP32のLEDが点灯・消灯し、押しボタンスイッチでトグルします。...

今は、本家のespressif社が提供しているarduino-esp32で、Matter機能が提供されているようです。そこで、arduino-esp32を使って、Matter対応プログラムを作ってみました。

Espressifのライブラリ

以前の記事で使ったesp32-arduino-matterのページには、

このリポジトリはアーカイブされており、今後はメンテナンスされません! 現在はarduino-esp32がMatterをサポートしているので、そちらを使用してください。

と書かれていました。リンク先は、本家Espressif社の、Arduino IDEボードマネージャのリポジトリでした。

GitHub - espressif/arduino-esp32: Arduino core for the ESP32
Arduino core for the ESP32. Contribute to espressif/arduino-esp32 development by creating an account on GitHub.

ということで、現在のArduinoのESP32ボードマネージャでは、Matter関係のサポートがされているようです。ボードマネージャの最新バージョンは3.3.3です。

ちなみにボードマネージャのインストール方法はこちらをご覧ください。

Installing - - — Arduino ESP32 latest documentation

いつものように、ボートはESP32 Dev Moduleに設定してます。

サンプルをコンパイルする

このリポジトリの、libraries/Matter/examplesには、いろいろなMatterデバイスのサンプルがあります。現バージョンのESP32用ボードマネージャを使えば、これらが全て使えます。

この中から、一番簡単そうなOnOffライトを選んで試してみます。Arduinoのスケッチは、MatterOnOffLight.inoというファイルです。何も考えず、これをArduino IDEにコピペし、コンパイルを試みました。すると、ストレージ容量が足りないという意味のエラーが出ました。出来上がったプログラムが、現在使えるストレージ容量の131%になったようです。

試しに、Arduino IDEのメニューのTools -> Partition Schemeから、8Mにしてみました。

そうしたらコンパイルが通りました。とりあえず幸先良いです。

実は、市場にあるESP32ボードのほとんどのフラッシュメモリは4MBです。手元のESP32も4MBです。なのでこの設定では、ほぼ使えません。あとで調整します。

プログラムを解読する

このプログラムは、On/Offするだけの単純な照明器具のプログラムです。調光や調色機能はありません。その機能を確認するために、ESP32の青色LEDをライトに割り当ててます。また、人がライトをOn/Offする物理スイッチも用意されています。これをESP32のBOOT押しボタンに割り当ててます。動作すれば、HomeKitなどからのOn/Off操作により、青色LEDがOn/Offします。また、BOOTボタンを押すと、青色LEDがOn/Offすると同時に、HomeKit側のスイッチも状態変化します。

プログラムを読んで理解したこと(間違っているかもしれませんが)を、日本語でコメント書き足してみます。ちなみに、青色LEDは2番ピンに、BOOTボタンは0番ピンに割り当てられてます。

#include <Matter.h>
#if !CONFIG_ENABLE_CHIPOBLE
//もしBLEでコミッションするならフラッシュメモリの無駄を防ぐためWiFiはインクルードしない
#include <WiFi.h>
#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);
#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
  }
}

プログラムのポイントをまとめると以下のようです。

  • コミッション(最初にHomeKitに登録する作業)する時に、WiFiまたはBLEを使う
  • BLE使う時はそこでWiFiの設定ができるけど、WiFi使う場合は、プログラムの中でSSID/Passwordを手動で設定しておく
    • 今回使うESP32無印はBLEコミッションできないのでWiFi設定が必須
  • Matter環境からOnOff指示が来る時のコールバック関数をonChange()メソッドで設定しておく
  • そのコールバック関数でライトをOnOffする
  • 物理ボタンの操作でもライトをOnOffする
    • その場合は、toggle()メソッドでMatter環境に伝える
  • 最初のloop()に入った時にコミッションできてなければ、できるまで永遠に待つ
  • 動作していても物理ボタン5秒長押しされたらコミッションをやり直す

コミッションは、プログラムしなくてもやってくれるみたいですし、コールバックなどもわかりやすいと思いました。

メモリ不足を工夫で乗り切る

使ったボードは、技適マークが刻印されているESP32無印です。フラッシュメモリ容量は4MBです。先の手順で、8MBのパーティションスキームでコンパイルしたあと、ダウンロードしてみましたが、当然ですが動作しませんでした。

現在流通しているESP32は、ほとんどが4MBで、この上の8MB, 16MBの製品は見当たりませんでした。そこで、パーティションスキームで工夫することにします。ESP32のパーティションスキームについて、以下のサイトがとても参考になりました。

ESP32のパーティション設定
概要arduino-esp32のv3.0系調査でパーティションまわりを調べてみました。パーティションとは?ESP32シリーズは2MBから32MBまでのフラッシュメモリを搭載しており、アプリやファイル保存領域として利用することができます。上記...

以下はこのページから引用させていただいた表です。4MBのESP32を、それぞれのパーティションスキームが、どのように分割するかが書かれてます。デフォルトでは、OTAでの使用を考慮して1,280kB x 2に分割し、他をファイル領域 (spiffs) にしているようです。

filename total ota_0 ota_1 spiffs 備考
default.csv 4MB 1,280KB 1,280KB 1,408KB 標準。BLEだと容量が足りない
huge_app.csv 4MB 3,072KB 0KB 896KB OTAをなくしてspiffsを減らす
min_spiffs.csv 4MB 1,920KB 1,920KB 128KB spiffsを減らす
no_fs.csv 4MB 1,984KB 1,984KB 0KB spiffsを無くした
no_ota.csv 4MB 2,048KB 0KB 1,920KB OTAをなくしてspiffsを増やす

今回の利用では、ファイル領域は少なくても良いと思います。一方で、できればOTAは使いたいところです。ということで、spiffsを減らすmin_spiffsスキームを使うことにしました。プログラムを保存する領域は1,920KBです。デフォルトから50%増えるので、31%超過している現状を打破できるかと思いました。ということで、Arduino IDEのToolsメニューから、そのように設定しました。Flash Sizeは4MBで、Minimum SPIFFSを選んでます。

コミッションする

パーティションを調整したことで、プログラムが動作するようになりました。シリアルモニターには、以下のように、

  1. WiFiに接続できたこと、IPアドレスを得たこと
  2. まだコミッションされていないこと
  3. コミッションに必要なcode(数値)とQRコード(URL)
  4. コミッションできるまで待っていること

が表示されます。loop()の冒頭に書かれた数行を実施し、そのあとのループで止まっている状態です。

Connecting to your_ssid
...
WiFi connected
IP address: 
192.168.0.146
E (4604) chip[DMG]: Endpoint 0, Cluster 0x0000_0031 not found in IncreaseClusterDataVersion!

Matter Node is not commissioned yet.
Initiate the device discovery in your Matter environment.
Commission it to your Matter hub with the manual pairing code or QR code
Manual pairing code: 34970112332
QR code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=MT:Y.K9042C00KA0648G00
Matter Node not commissioned yet. Waiting for commissioning.
Matter Node not commissioned yet. Waiting for commissioning.
Matter Node not commissioned yet. Waiting for commissioning.

このcodeの11桁の数字、もしくはURL先にあるQRコード、のいずれかを使ってHomeKitに追加します。下の写真は、

  1. iPhoneのホームから、画面右上の+ボタンを押し、
  2. 「アクセサリを追加」メニューを選んで、
  3. 上のメッセージにあるURL先の、QRコードを読み込ませている

ところです。

実はHomeKitの状態が良くないのか何度か挑戦して、ようやく追加できました。iPhoneを再起動したら、追加できました。

動作確認

iPhoneやMacのホームには、ESP32が以下のように照明デバイスとして表示されます。タップやクリックするとon/offします。

それと同期して、ESP32の青色ダイオードも点灯・消灯します。またESP32のBOOTボタンを押すと、この電球デバイスの状態がon/offと切り替わります。

操作している様子の動画を以下に示します。画面ボタンを操作した後、最初に物理ボタンを使った時に、画面ボタンへの反映に6秒程度の時間がかかってます。他のMatterデバイス(以前紹介したOnvisのプラグ)でも同程度の遅延が発生しているので、HomeKit環境側の問題かと思われます。それ以外の操作では、問題なく動作してます。

ESP32のMatter対応状況

githubのページに、ESP32モデルに対して、ライブラリが提供している機能が掲載されています。ESP32がハードウェアを搭載していても、非サポートの機能があります。

今回使用した無印とS2は、BLEを搭載してはいますが、BLEコミッションをサポートしていません。なので、先のサンプルプログラムのように、WiFiのSSID/パスワードをプログラムのコード内で設定して、そのあとWiFiを使ってコミッションする必要があります。

C5, C6も同様に、Threadを搭載してはいますが、Matter over Threadは、サポートしていません。ESP-IDFを使って頑張れば、C5, C6でもMatter over Threadが可能だそうです。

今後は、BLEコミッションと、Threadをぜひ試してみたいです。

まとめ

Espressif社のArduino IDE用ESP32ボードマネージャーが、Matter対応していました。おかげで、Arduino IDEを使ってMatterプログラムを作ることができました。ライブラリはわかりやすくて、シンプルです。使いやすいArduino IDEでプログラムできるので、素人DIYでもMatterデバイスが作れると思います。

一方で、HomeKit側の不調が原因と思われますが、コミッションに手間取りました。また、4MBモデルではメモリー容量が厳しいので、複雑なプログラムを作れるのか、さらにはOTAができるのかなど、今後確かめたいです。

コメント

タイトルとURLをコピーしました