Welcome to telecotele.com » 丁寧な暮らし

入門スマートホーム

これじゃ本当に丁寧な暮らしだよ

tags: house

入門スマートホームのカバー画像

リンクプラスをBLEから操作するとか赤外線リモコンの信号を見るを行いました。 次はどうする?こうして調べた情報をもとに、壁スイッチとかエアコンをスマホから操作したいですね。

自前でアプリを作って操作するのも手ではありますが、いまさらイチから作るのは大変。 できれば既存の仕組みに乗っかりたい。 普段手元にあるのはiPhoneとApple Watchなので、基本「ホーム」アプリを使うことになるでしょう。

このアプリを使うためには、HomeKit1に対応したデバイスが必要です。 対応デバイスとして赤外線送信機能を持つ製品も市販されていますが、このくらい自分で作れるのでは? また、リンクプラスの操作を考えて任意のBLEパケットを読み書きするような製品を探しましたが見当たらず、やっぱり心の中の🤖が「自分で作れば良いのに…」と語りかけてきます。

ということで対応デバイスを作って、最終的にはこんな感じの画面から操作できるようにしました。

ホームアプリ画面 ホームアプリ画面

以下で詳細を述べていきます。

HomeKitデバイスを作る

まず対応デバイスを作りましょう。 方法としては

  • 方法1: デバイスに直で実装する
  • 方法2: ブリッジ経由で対応させる
    • ブリッジがHAPを実装している
    • ホームアプリとブリッジ間はHAPで通信、ブリッジとデバイス間の通信は何でも良い
    • 例: https://homebridge.io/ など

があるようです。 ここでは方法2「ブリッジ経由で対応させる」を選びました。 理由として何かこだわりがあるわけではなく、単に参考にしたページがその方法を採用していたからです。 その参考にしたページは下記のとおり。

エアコンリモコンのHomeKitアクセサリをDIYする (前編:赤外線送出) | DIY Smart Matter
https://diysmartmatter.com/archives/293

エアコンリモコンのHomeKitアクセサリをDIYする (中編:MQTT対応) | DIY Smart Matter
https://diysmartmatter.com/archives/290

エアコンリモコンのHomeKitアクセサリをDIYする (後編:温度センサ他) | DIY Smart Matter
https://diysmartmatter.com/archives/289

このページの構成をほぼそのまま、ブリッジにはHomebridgeを用い、デバイスとブリッジ間の通信はMQTT(とhomebridge-mqttthing plugin)を使うという構成にしています。

Homebridge本体とMQTTブローカーはNAS上のコンテナで動かしました。 HAPではmDNSが使われるらしく、これをコンテナで扱うのはハマりそうで心配……ですが、このためだけに別途Raspberry Piなどを用意するというのも無駄に思えて、こうしています。

Homebridgeとデバイス間は必ずしもMQTTである必要はありません。 別にHTTPで通信しても良いでしょう。 ただ、MQTTにはRetainの機能がありこれは便利でした。 Retainはトピックにメッセージを保持する機能です。 パブリッシャーがRetainフラグを付けてメッセージを流すと、ブローカーはそのメッセージをサブスクライバーにすぐ配信するとともに、メッセージを保持しておき今後新たなサブスクライバーが接続すると同時にそこに向けてもメッセージを再送します。

これで何が嬉しいかですが、デバイスが再起動し状態を復元するのに便利です。 例として照明などのアクセサリを操作する場合のHomebridgeとデバイスにおけるやり取りの流れは、

  1. HomebridgeがsetOnトピックで操作データを流すことで、デバイスに指示する
  2. デバイスはgetOnトピックで現在の状態(操作結果など)を流すことで、Homebridgeに報告

となっています。 ここで、2.のデバイス側ではRetainフラグを付けてメッセージを流しておき、さらに自分自身でサブスクライブ(とそれをもとに現在の状態を把握)もしておきます。 すると、何らかの原因でデバイスが再起動した場合でもgetOnをサブスクライブした瞬間に以前自分が送ったメッセージからアクセサリの状態を復元できます。 もし初期値を「OFF」など固定値にしておくと実際の状態とはズレる可能性があり、また不揮発性の領域は追加で部品が必要だったり書き換え回数の制約があったりするのでこれは避けたいです。 HomebridgeのHTTP APIを叩くことでもアクセサリの状態は取得できますが、これはlogin用エンドポイントにアクセスしてJWTを取得して……という手間がかかる一方、MQTTならRetainとサブスクライブだけで済みます。

なお、Retainによって保持されるメッセージは各トピックにつき最新1件のみです。 何かRetainフラグ付きのメッセージが(他のパブリッシャーからであっても)送られれば上書きされ、また(他のパブリッシャーでも)削除することもできます。 そのため、ブローカーに不特定多数がアクセスする状況だと難があると思いますが、ここではブローカーは自分専用、自分が管理するデバイスしかアクセスしないという前提です。

作ったもの

以上を踏まえて作ったデバイスについて紹介します。

まずは、赤外線リモコン信号の送信器についてです。 当初、赤外線リモコンの信号を見るで述べた「三菱 エアコン」「Panasonic 壁スイッチ」「日立 照明」、ほかは余裕があれば操作するくらいの気でいました。 しかし、なかなか機器が反応しない! はじめは赤外線LEDに40mAほど流してみて、受光部に向ければ5メートルほど離れても反応したので意外と届くもんなんだなと思っていたところ……100mAほど流しても受光部に向けないと反応しない! どうやら壁や天井などによる反射を期待するならもっと電流を流さないといけないようです。 設置位置を考えると、すべての機器に向けてLEDを配置することはできません。 でもあまり電流を流すのもなぁ……まぁ最悪、エアコンが操作できれば満足なのでは?外出時にOFFにして、帰宅前にONにしたりさ……。

ということで、エアコンの操作だけを目的とし受光部めがけて赤外線LEDを配置した送信器を作りました(次図)。

赤外線リモコン送信器 赤外線リモコン送信器

ケースも設計し3Dプリンタで出力、基板はJLCPCBに注文しました。 JLCPCBに注文するのは2年ぶりでしたがなんか “OCS NEP” という安価な発送方法が増えており、かかった費用は基板5枚と送料含めて$3程度(!)です。 しかも、タイミングが良かったのか配送がめちゃめちゃ早く進んで注文から6日で受け取れました。

MCUはESP-WROOM-02を使っています。 理由は余っていたからです。 新規でやるならESP32系のほうがBLEも使えて便利……だと思いますが、このESP-WROOM-02はたいぶ前に購入して持て余していたところ活用できて良かった。 ESP-WROOM-02でもファームウェアの書き換えはOTAで行える2ので便利です。

プログラムでは、MQTTメッセージに対するデバウンスを工夫しました。 エアコンの操作に関するMQTTのメッセージは、setActiveトピック(ON/OFF)やsetTargetHeaterCoolerStateトピック(冷房/暖房の切り替え)、setCoolingThresholdTemperatureトピック(冷房時の設定温度)など複数のトピックに分かれて届きます。 特にオフ状態から冷房/暖房を開始するタイミングでは各トピックに対してバースト的にデータが送られており、何かデータが届くたびに赤外線リモコン信号を送信していては無駄が多く、エアコン側でも受理してくれないかも知れません。 そこで、「あるトピックでデータを受信したら100ms待って、他のトピックにデータが来ていなかったら赤外線リモコン信号を送信。もしデータが来ていたら再びそこから100ms待って他のトピックに……」という処理を実装しています。 JavaScriptでいうところのsetTimeout()とキャンセルの組み合わせのようなもの、具体的なESP-WROOM-02における実装ではTicker.hdetach()once_ms()を組み合わせました。 なお、homebridge-mqttthingには “Receive Debounce” という設定を通じてメッセージのデバウンスを行ってくれる機能もあります。 ただ、これは単一のあるトピック内でのデバウンスの話っぽく今回のようにトピックまたぎでデバウンスしたい場合には適しません。

赤外線リモコン送信器の話は以上。 次は(リンクプラス操作用に)BLEパケットを読み書きするデバイスです。 これには次図のM5Stackを使いました。

M5Stack M5Stack

せっかく画面があるので、簡易サイネージとして「日付」「外気温・湿度」「締切までの残り時間」「Yahoo!デベロッパーネットワークの気象情報APIから取得した降水強度」も表示3しています。 いずれの情報も外部のプログラムからMQTT経由で配信される構成です。 「締切までの残り時間」の話は、後でもちょっと述べます。

ホームハブ

はい、HomeKit対応のデバイスを作りました。 これでホームアプリから操作できるといえばできるのですが……次の問題があります。

  • 外出先からの操作はできない
  • 「オートメーション」が使えない
  • Apple Watchからの操作が不安定

HAPではホームアプリとHomeKitデバイスの間でmDNSが使われる、ということで外出先からは使えません。 ではmDNS Repeaterを使ったり、L2VPN4を使えばいける?かも知れませんが未検証です。 (なお、今回のデバイスはMQTTのメッセージにより動いているため、ホームアプリが使えなくて良いなら外出先からでもVPNを張ったりして直接MQTTメッセージを送りつければ一応の操作はできます。)

また、現状ではホームアプリから「オートメーション」の機能が使えません。 オートメーションは時間や状態に応じてデバイスを自動的に操作してくれる機能で、これを使うためには後述の「ホームハブ」が必要です。 (ここでも、今回に関してはホームアプリに頼らずデバイスに直接MQTTメッセージを投げることで似たようなことは実現できるとは思います。)

さらに、いまの状態だとApple WatchからHomeKitデバイスを操作する場合、直接デバイスにアクセスするようです。 iPhoneとペアリングしていてBluetooth経由で繋がっていたとしてもその経路は使われず、別途Wi-Fi経由でデバイスに繋ぐ必要があります。 それで良いなら良いのですが、自分の環境ではApple WatchのWi-Fiは不安定なようでたまにホームアプリ上のデバイスが「応答なし」になっていました。 似た話でiPhoneのロック画面にホームアプリのウィジェット(現在の室温)を表示していたところ、たまにスリープから復帰する際に「応答なし」5になっていたりこの辺も不安定です。

これらの問題は「ホームハブ」の導入で解決します。 ホームハブはHomeKitデバイスとホームアプリを繋ぐもので、iCloudを経由することで外出先からでもデバイスの操作を可能にし、オートメーションの実行も担当します。 また、ホームハブを導入するとApple Watch上のホームアプリは直接デバイスに繋ぎに行かなくなるのか(実際のところは未確認)、なぜかApple WatchのWi-Fiをオフにしても操作できるようになります。 この操作は試した限りでは安定しており、“似た話”で述べたiPhoneのロック画面でもホームハブ導入後は「応答なし」になることもなく満足です。

ホームハブは独立した製品ではなく、HomePodやApple TVなどの製品に付随する機能として提供されています。 ここでは、HomePod miniの中古品を購入しホームハブとしました。 自分が購入した際の相場としてはだいたい8,000円ちょっとくらい。 直近の相場についてはなんか安くなっていたら嫌なので調べていません。 死んだ子の年を数えるな。

なお、HomePod miniに話しかけるとSiriを介したHomeKitデバイスの操作も可能です。 ただ、このSiriの音量はうるさいですね……と思うこともあるかも知れません。 これはHomePod miniの「アクセシビリティ」から「Siriの音量を自動的に調整」をオフにし、さらに音楽再生の音量を調整することで小さくできます。

サイネージ

以上でHomeKitの話は終わり。 ついでにGrafanaで作ったサイネージも修正したので自慢します。 現状はこうだ!!!

Grafanaの画面 Grafanaの画面

これをサブモニターの一部に表示している。 温度とか湿度とかの気象データに関しては丁寧なす暮らしで述べたnetatmo由来の値、消費電力に関してはCube J1のAPI調査で得られた値を使っています。

そして、“7d 16h 35m”とあるのはM5Stackのところで述べた何らかの「締切までの残り時間」です。 この残り時間は、特定のiCloudカレンダーに登録された予定から拾っています。 直近の予定を返すAPIのようなものは無いようでしたが、下記のページを参考に、

iCloudの任意のカレンダーのCalDAVのURLを得る方法(2016年版)
https://unoun.github.io/2016/06/how-to-get-icloud-any-caldav-url/

CalDAVのURL(自分の環境ではpXX-caldav.icloud.comというホスト名だった)を見つけて、iCloudの「アプリ用パスワード (app-specific password)」を発行して、CalDAV経由でアクセスして予定を拾っています。

以上です。おわり。 丁寧な暮らしなのに書きすぎた。

Footnotes

  1. HomePodなどのホームハブがあればMatterに対応したデバイスでも使えるようですが、この辺は調べていないので割愛します。

  2. 事前にOTAによる書き換えを想定したファームウェアを書いておく必要はある。

  3. ※画面上のデータは開発中のものであり、一部ダミーデータが含まれます。

  4. IOS、ではなくiOSから使えるかは分かりません。

  5. Wi-Fiがスリープしていたのか、またはロック画面を表示した瞬間にmDNSのリクエスト/レスポンスを処理する構成でその処理に時間がかかっていたとか?と思いますが……