ESP32でMatterデバイスを作成してHomeKitから操作

Category: 電子工作
thumbnail

Matterとは

  • スマートホームの標準規格
  • 2022年に1.0がリリースされたばかりの新しい規格
  • Connectivity Standards Alliance (CSA)が策定
  • CSAは元々Zigbee Allianceという名前で、その名の通りZigbee規格を策定している団体

Matterが生まれるまでの流れ

  1. ビックテック各社がお得意の囲い込みでスマートホーム業界を独占しようと独自規格を策定
  2. 独自規格が乱立した結果、互換性の無いデバイスが溢れ、スマートどころかカオスとなる
  3. 元凶たちが集まり、ロイヤリティーフリーな共通規格としてMatterが作られる

という経緯があるため、Matterでは相互接続性が重視されており、

  • Amazon Alexa
  • Apple HomeKit
  • Google Home

などの各社スマートホームシステムに接続することができます。

Matterデバイスを作ってみる

今回は、ESP32 + Arduino IDEで開発します。ボードマネジャーをインストールしておいてください。
https://github.com/espressif/arduino-esp32

Important

arduino-esp32 v3.3.7, v3.3.8にはバグがあり、Matterが動作しません。
https://github.com/espressif/arduino-esp32/issues/12403

ハードウェア

ESP32-C3を使いました。
このサンプルはESP32-C6やESP32-S3でも動きますが、ESP32, ESP32-S2ではSSIDとパスワードでWiFiに接続する必要があります。

Note

MatterはWi-Fi, Ethernet, Threadに対応しています。BLEは接続時のCommissioningに使われます。

  • ESP32-H2,C5はThreadで接続されます
  • ESP32-C3,C6,S3はWiFi接続ですが、BLE-Commissioningで認証情報を渡すためパスワードは不要です
  • ESP32, ESP32-S2はBLE-Commissioningに対応していないのでSSIDとパスワードを設定してWiFiに接続する必要があります

アプリ

林檎畑の住人なのでiPhoneに標準でインストールされているホームappを使いました。
先述の通り、Matterはスマートホームの標準規格なので他のアプリからも操作できます。(持ってないので未検証)

iOS18以降のiPhoneであればMatterハブ(HomePodとか)が無くても接続できますが、使おうとしたときに接続中と表示され待たされたり、あまり実用的と言えるものではありませんでした。
https://support.apple.com/ja-jp/102135

サンプルコード

0番ピンに接続したLEDをMatterでオンオフする最小限のコードです。

書き込む前にArduinoのツールから以下のように設定します。
USB CDC On BootEnable
Partition SchemeHuge APP (3MB No OTA/1MB SPIFFS)(フラッシュを2MBくらい使います)
Erase All Flash Before Sketch UploadEnable

#include <Matter.h>

#define LED_PIN 0

MatterOnOffLight OnOffLight;

bool led_toggle(bool state) {
  digitalWrite(LED_PIN, state);
  return true;
}

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);

  OnOffLight.begin();
  OnOffLight.onChange(led_toggle);

  Matter.begin();

  if (!Matter.isDeviceCommissioned()) {
    Serial.printf("Pairing code: %s\n", Matter.getManualPairingCode().c_str());
    Serial.printf("QR code URL: %s\n", Matter.getOnboardingQRCodeUrl().c_str());
  }
}

void loop() {}

接続

シリアルモニターに出力されるURLにアクセスするとQRコードが表示されます。
これをホームappの右上の+ボタン→"アクセサリを追加"から読み取ります。
途中、"認定されていないアクセサリ"と表示されますが、当然なので気にせず続けます。

接続されるとホームappの他にも、ウィジェットやコントロールセンターに追加して操作することができるようになります。

HomeKitではデバイスがiCloud同期されるので、iPhoneで追加すればmacやApple Watchなどからも操作できます。
また、自宅にホームハブに対応したAppleデバイス(HomePodかApple TV)を設置していれば、設定をせずとも外出先から操作できるようになります。

その他サンプル

Dimmable Light

調光可能なライト

コード
#include <Matter.h>

#define LED_PIN 0

MatterDimmableLight DimmableLight;

bool set_light(bool state, uint8_t brightness) {
  Serial.printf("Status: %s, Brightness: %d\n", state?"ON":"OFF", brightness);
  if (state) {
    analogWrite(LED_PIN, brightness);
  } else {
    digitalWrite(LED_PIN, LOW);
  }
  return true;
}

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);

  DimmableLight.begin();
  DimmableLight.onChange(set_light);

  Matter.begin();

  if (!Matter.isDeviceCommissioned()) {
    Serial.printf("Pairing code: %s\n", Matter.getManualPairingCode().c_str());
    Serial.printf("QR code URL: %s\n", Matter.getOnboardingQRCodeUrl().c_str());
  }
}

void loop() {}

Color Light

WS2812 (NeoPixel)

コード 0番ピンにNeoPixelのDataピンを接続
#include <Matter.h>

#define LED_PIN 0

MatterColorLight ColorLight;


bool setRGBLight(bool state, espHsvColor_t colorHSV) {
  if (state) {
    espRgbColor_t rgbColor = espHsvColorToRgbColor(colorHSV);
    rgbLedWrite(LED_PIN, rgbColor.r, rgbColor.g, rgbColor.b);
  } else {
    digitalWrite(LED_PIN, LOW);
  }
  return true;
}

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);

  ColorLight.begin();
  ColorLight.onChange(setRGBLight);

  Matter.begin();

  if (!Matter.isDeviceCommissioned()) {
    Serial.printf("Pairing code: %s\n", Matter.getManualPairingCode().c_str());
    Serial.printf("QR code URL: %s\n", Matter.getOnboardingQRCodeUrl().c_str());
  }
}

void loop() {}

温度センサー

ESP32内蔵の温度センサーの測定値を表示します。
ESP32自体の発熱があるので気温より高い温度が表示されます。

コード 内蔵のセンサーを使うので配線は不要です
#include <Matter.h>

MatterTemperatureSensor TempSensor;

void setup() {
  Serial.begin(9600);

  TempSensor.begin();
  Matter.begin();

  if (!Matter.isDeviceCommissioned()) {
    Serial.printf("Pairing code: %s\n", Matter.getManualPairingCode().c_str());
    Serial.printf("QR code URL: %s\n", Matter.getOnboardingQRCodeUrl().c_str());
  }
}

void loop() {
  TempSensor.setTemperature(temperatureRead());
  Serial.printf("Temp: %.02fC\n", TempSensor.getTemperature());

  delay(5000);
}

おわりに

arduino-esp32のexampleには、これ以外にも様々なサンプルがあるので、参考にしてみてください。
https://github.com/espressif/arduino-esp32/tree/master/libraries/Matter/examples