スマートホームデバイスは、Apple のホームアプリで使える HomeKit や Matter に対応したものは、しばしば高価で、メーカー独自のサーバーを経由して通信するため、セキュリティ上の懸念がつきものです。 そんな理由から、多くのユーザーが自分でスマートホームデバイスを作ろうと試みています。たとえば、有名な Homebridge もその一例ですが、Raspberry Pi などのコンソールが必要で、コマンドラインとの対決も避けられません。 かつて私も Homebridge での構築を試みましたが、頻繁な接続の切断に悩まされ、結局使用しなくなりました。
さらに、ESP32-Arduino 用の Matter ライブラリや MQTT を使用してブリッジを介して通信する方法も存在しますが、これらはプロトコル的に一工程を必要とし、安定性の確保が難しかったです。というかほぼ使い物になりません。
そこで、今回はあまり知られていないかもしれませんが、 すぐに構築でき、(現時点では)安定性が確保されている HAA+ESP32 を使用したスマートホームデバイスの作成方法をご紹介します。
HAA – Home Accessory Architect
RavenSystemさんのオープンソースプロジェクトで、ESP チップにファームウェアを書き込み、HomeKit デバイスを作ることができます。HomeKit へのサポートはネイティヴ(!)であり、ブリッジを必要としません。 センサーやスイッチなどを繋げることができたり、UART や HTTP リクエストを送ることもできます。そしてそれらの設定はMEPLHAA スクリプトと呼ばれる JSON な独自構文をデバイスにアップすることで完了します。
MEPLHAA スクリプトを使い、HomeKitアクセサリを構築し、それをサービスとして使います。
今回は、基本的な HAA のセットアップを行い、 次に湿度・温度センサー(DHT22)とリレーを接続し、温度や湿度をモニターしファンを回す簡単なスマートデバイスを作ろうと思います。
ESP32 や ESP8266 に対応していますので、余っているやつでトライしてみてください。
ESP32 が乗った DevKitやNodeMCU は Amazon などでかなり安い価格で販売されています。メジャーなやつを買いましょう。
また、小型化を目指すなら Seeed Studio XIAO ESP32-C3 もいいかもしれません。
注意なんですが、HAA はカメラやディスプレイには対応しないと明言されています。 つまり、Seeed XIAO ESP32-S3 をドアカメラにしたり、M5Stack をモニター端末として使うことができません。
センサーはメジャーなDHT22を使います。
リレーは、3.3Vで動くやつを使います。古典的なやつです。ACも使えるので照明の操作とかもできます。
ソリッドステートリレーの名で、フォトカプラが安価で売ってますが電流値が低く照明や動力にはほぼ使えません。古典的なやつを買いましょう。
[Release ページ][https://github.com/RavenSystem/haa/releases] から自分のボードにあった bin ファイルをダウンロードします。 自分の持っているボードに乗っているチップがわからない場合は、以下を参考にして下さい。 メジャーなものを取り上げました。
ボード | bin ファイル |
---|---|
ESP32-WROOM-32, NodeMCU-32, ESP32 DEVKIT V1 | fullhaaboot_esp32.bin |
ESP-WROOM-02,Wemos D1, D1 mini | fullhaaboot.bin |
Seeed XIAO ESP32C3 | fullhaaboot_esp32c3.bin |
ESP32-C6-WROOM-1,ESP32-C6-DevKitC | fullhaaboot_esp32c6.bin |
Seeed XIAO ESP32S3 | fullhaaboot_esp32s3.bin |
ダウンロードしたら、わかりやすいところに置いておきます。
この記事をここまで読める人には関係ないと思いますが、ESP ファミリーにファームウェアを書き込むためにesptool.py
を使います。 つまり、Python も必要です。 Python 2.7 か 3.4 以上をインストールし、esptool.py
をインストールしましょう。 (Python3 推奨です)
$ pip install esptool
esptool.py
を使いフラッシュを消去します。繋がっているボードを勝手に認識するので、書き込むボードのみを PC に接続して下さい。python3 -m esptool erase_flash
python3 -m esptool -b 460800 --before=default_reset --after=hard_reset write_flash -fs 2MB -fm dio 0x0 <さっきのbinファイル>
python3 -m esptool -b 115200 --before=default_reset --after=hard_reset write_flash -fs 1MB -fm dout 0x0 <さっきのbinファイル>
Mac なら、
<さっきのbinファイル>
以前までをコピペして、bin ファイルをターミナルにドラッグ&ドロップすれば、bin ファイルの場所が入ります。
HAA-xxxxxx
という WiFi を探します。 (例えば以下のように WiFi 一覧に現れます)この WiFi に接続します。
次に、Web ブラウザ(Safari など)を開き、設定用の URL にアクセスします。
http://192.168.4.1:4567
MEPLHAA スクリプトが準備できているなら、この画面で入れることができます。あとで説明します。
Search WiFi
」ボタンを押して、家の中の WiFi を探し選びます。Password
」 というところにパスワードを入れて、上にある緑の「Save
」ボタンを押します。ちなみに、”HAA BOOT”モードというのは、さっきのオレンジの画面のことを指します。
これは別にいつのタイミングでも良いんですが、iPhone のホームアプリからデバイスをホームに追加します。 ここから QR コードを見つけ出して、ホームのアクセス追加から読み取ります。
なお、HAA の HomeKit コードを手動で入力することもできます。
0218-2017
我が家にはたくさんの HAA デバイスがありますが、1 回登録すればデバイスが変わろうともペアリングの必要はありません。
これが結構難儀です。 HAA と化した ESP32/8266 ボードの IP アドレスを探して、アクセスしないといけません。 以下のような方法があります。
これがちょっと一手間なんですが、一番早く確認できる方法でやってみましょう。
Arduino IDE や PlatformIO を持っている人は、ESP32/8266 ボードのポートを選択して、シリアルモニターを開きます。
Arduino IDE を持っていないという素人か玄人は、screen
で/dev/tty.usbxxxx
をモニターします。
ボーレートを合わせて(普通は 115200 です)、ボードをリセットします。 すると、ゴチャゴチャと色々帰ってきますが、その中で以下の様な部分を見つけます。
Connected (繋がっているWiFiの名前) DHCP start IP:192.168.11.37/255.255.255.0 GW:192.168.11.1
この中の、IP:192.168.11.37
というのが今回作ったデバイスの IP アドレスになります。
Mac や PC の Web ブラウザから、
http://192.168.11.37:4567
にアクセスします。さっきのオレンジの画面みたいな白い画面が出ます。 ちなみに、”HAA MAIN”モードというのは、この白いの画面のことを指します。
いよいよここに、MEPLHAA スクリプトというものを書き込んで、HomeKit アクセサリ化します。
MEPLHAA スクリプトは形は JSON なのですが、アクセサリの指定や設定等、非常に単純化されており、シンプルに書くことができます。でもリファレンスがないとサッパリです。
以下に、今回構築するスクリプトを置いておきます。 1つのセンサーと 2 つの GPIO 出力を備えたデバイス
{
"c": {
"n": "HAA-XXX1",
"sn": "XXXXXX-AAA",
"tz": "JST-9",
"o": 1,
"r": [
{
"n": 0,
"s": 115200,
"p": 0,
"b": 0,
"g": [1]
}
],
"io": [[[12], 2], [4]],
"l": 13,
"b": [[0, 5]],
"f": 1
},
"a": [
{
"t": 24,
"n": 2,
"g": 4,
"k": 10,
"j": 30
},
{
"0": {
"r": [[12, 0]]
},
"1": {
"r": [[12, 1]]
},
"t": 1,
"d": 3600,
"s": 5,
"b": [[0]]
}
]
}
簡単に説明します。
"c"
は Config、つまり設定ブロックを表します。この中には、
コマンド | 意味 | 例 |
---|---|---|
"n" |
デバイスの名前 | "HAA-XXXXXX" |
"sn" |
シリアルナンバー | "XXXXXX-<Acc#>" |
"tz" |
タイムゾーン | "JST-9" |
というかんじにデバイス固有のものを記載しますが、正直なくても動作します。
"io"
には、使用するボードの GPIO ナンバーを入れて宣言します。 これがなければ、一切の GPIO 操作ができません。 僕は一回ここで詰みました。必ず入れる様にしましょう。
[[GPIOナンバー] , 引数]
のように指定している部分がありますが、以下の様になってます。
モード | 説明 |
---|---|
0 | 無効 (デフォルト) |
1 | 入力のみ |
2 | 出力のみ |
3 | オープンドレイン付きの出力のみ |
4 | * 出力および入力、オープンドレイン付き |
5 | * 出力および入力 |
6 | 入力のみ、バイナリ入力(ボタン/スイッチ)サポート付き |
7 | ソフトウェア PWM、出力のみ |
8 | ソフトウェア PWM、オープンドレイン付きの出力のみ |
9 | * ハードウェア PWM、出力のみ |
10 | * ADC 入力 |
ちなみに、なくても Arduino でいうpinMode()
が無い状態なので別に動きます。
GPIO の設定はここに詳しく書いてあります。
他の部分もさらっと説明します。
"o"
は、ログの残し方。
"r"
は、UART の設定。使わなければ必要ありません。
"l"
には、ステータス LEDの設定。
"b"
には、セットアップモードに入るためのボタン GPIO 設定。
"f"
には、ボタン入力のデバウンス設定
この辺は、僕もよくわからず入れております。このほかにも使えるコマンドがあり、かなり高機能です。 General Configurationを参考にしてみて下さい。
"a"
には、アクセサリの設定が入り、{ }
で区切られます。 HomeKitで対応されているアクセサリなら、ある程度再現できる様です。 Service Typesを参考にして下さい。
ここでは、今回使うアクセサリ設定を書きます。
{
"t": 24,
"n": 2,
"g": 4,
"k": 10,
"j": 30
}
セクション | キー | 説明 |
---|---|---|
Actions | “t” | アクセサリの種類 |
Sensor GPIO | “g” | 接続されているGPIOラインのセンサー |
Sensor Type | “n” | センサータイプ |
Sensor Polling Time | “j” | センサーの読み取り頻度(秒) |
Humidity Offset | “k” | 適用する補正オフセット(湿度) |
Temperature Offset | “z” | 適用する補正オフセット(温度) |
Sensor Index | “u” | 同じGPIOに複数のセンサーが接続されている場合に使用するセンサー。DS18B20のみ |
アクセサリの種類には、
タイプ | アクセサリの種類 |
---|---|
22 | 温度センサー |
23 | 湿度センサー |
24 | 温度および湿度センサー |
センサータイプ には、
タイプ | アクセサリの種類 | 説明 |
---|---|---|
1 | 22, 23 & 24 | DHT11 温度および湿度センサー |
2 | 22, 23 & 24 | DHT22 Type 1 (デフォルト) 温度および湿度センサー |
3 | 22 | DS18B20 温度センサー |
4 | 22, 23 & 24 | Si7021 1-Wire バージョン 温度および湿度センサー |
5 | 22 | ADC NTC サーミスタ |
6 | 22 | ADC PTC サーミスタ |
7 | 22 | Raw ADC NTC サーミスタ |
8 | 22 | Raw ADC PTC サーミスタ |
9 | 23 | Raw ADC 湿度センサー |
10 | 23 | Raw ADC 湿度センサー (反転ロジック) |
100 | 22 | ビルトインチップ温度センサー (ESP32-C および ESP32-Sのみ) |
とあります。 今回はDHT22を使いますので、"2"
を選んでいます。
また、DHT22は温度が10℃ほど低く出る様でしたので、"k"
温度オフセットを使っています。
{
"0": {
"r": [[12, 0]]
},
"1": {
"r": [[12, 1]]
},
"t": 1,
"d": 3600,
"s": 5,
"b": [[0]]
}
"0"
でオフの状態のGPIOのステートを、 "1"
でオンの状態のGPIOのステートを設定します。
セクション | キー | 説明 |
---|---|---|
Actions | “0”, “1” など | サービスが実行するアクション |
Binary Inputs | “b” | 特定のアクションを呼び出すGPIO |
Inching Time | “i” | サービスをオフ状態に戻すまでの時間 |
State & Status Inputs | “f[n]” & “g[n]” | サービスの状態を管理する入力 |
ICMP Ping Inputs | “q[n]” & “p[n]” | サービスの状態を管理するPing入力 |
Service Notifications | “m” | 他のサービスから送信される通知 |
Initial Lock State | “ks” | 起動時のロック状態 |
Initial State | “s” | 起動時にサービスが入る状態 |
Maximum Use Time | “d” | サービスがオンになれる最大時間 |
Actions on Boot | “xa” | 起動時のサービスアクションの実行を有効/無効にする |
スイッチサービスについては、Switchesに詳しくあります。 |
というふうに項目がありすぎて書くのがめんどくさいんですが、MEPLHAA スクリプトを使って任意のアクセサリを作ることができます。
この時点でホームアプリにはHomeKitアクセサリとして表示されると思いますが、虚無を操作することしかできないので、センサーとリレーを接続します。 さっきのMEPLHAA スクリプトを使って、DHT22から温度と湿度を取得し、ホームアプリのオートメーションからファンを回せる様にします。
ESP32 DevKitV1を使ってます。GPIO番号などは使っているボードやセンサーなどによって都度読み替えて下さい。 さっきのスクリプトの通りに行くならこれで動きます。 MEPLHAA スクリプトを書く前にArduinoでテストコードを書いて、ハードウェアでチェックしても良いかもしれませんね。
ちなみに、ホームアプリからはこんな感じに見ることができます。
熱帯ドロセラ(食虫植物)を栽培している温室水槽に丸ごと入れてます。 また、オートメーションを使って、温度や時間によってファンを回す様にしています。
くぅ~疲れましたw これにて完結です!
実は、GitHubでたまたまプロジェクトを見つけたのが始まりでした
本当はブログに書こうとは思わなかったのですが←
やってみたらクッソ意味わからず、他に挑もうとする日本人のガイドになろうと思った所存ですw