Smart HomeをDIYする

Apple HomeKit は対応製品が少なくて高価なのでHomebridgeでがんばります

set, get と target, current の違い

HomeKitの動作説明で、setState, setTargetState, getCurrentStateなどの用語が出てきます。字面から意味をなんとなく想像していたのですが、わりと混乱してました。調べて理解したことをメモしておきます。

setとgetの違い

HomeKitアクセサリには色々はcharacteristicsという変数を持っています。例えば2値のスイッチなら、PowerStateという変数があってオンかオフ(trueかfalse)を表します。mqttthingプラグインでは、この変数を取得して設定するトピックスとして、

  • getOn(on/offの状態をgetするためのトピック)
  • setOn(on/offの状態をsetするためのトピック)

の2種類のトピックスを指定します。例えばsetOnのトピックとして、mqttthing/myswitch/setOnと指定しておけば、このトピックにtrueまたはfalseのメッセージを流すことで、PowerStateをon/offに設定します。一方、getOnは、PowerStateを取得するためのトピックです。

というところまでは、字面からわかるのですが、実はそれほど単純ではありません。

なんとなく混乱する原因は、getとかsetという動詞の主語は誰なのかよくわからない点だと思います。これらの動詞の主語は、HomeKitの中の人、つまり、

  • 別のHomeKitアクセサリ、
  • iPhone, Macで動いているホーム.app、
  • HomePodなどのホームハブ

です。例えば、スイッチの場合、setOnしてスイッチをonにするのはHomeKitの中の人です。その結果、スイッチの状態がonになるので、直後にgetOnトピックにメッセージが流れるとしたらonになっているはずです。

もし、現実世界の人(ユーザ)がこのスイッチアクセサリを手動でonにできるとします。そのことをアクセサリがHomeKitの世界に知らせようとした場合、使うべきトピックはgetOnです。人がセットしたのでsetOnでも良いような気もしますが、setOnはHomeKitの中の人が設定した場合にのみ使います。外界からスイッチが操作された場合はgetです。

まとめると、

  • setはHomeKitの中から状態を変更すること、
  • getは現実世界からの働きかけで更新されたこと

を知らせるトピックスです。

 

targetとcurrentの違い

壁スイッチや電球のようなものは、設定したらすぐにon/offされるのですが、動作に時間がかかるデバイスもあります。例えば、空調をある温度に設定しても、その温度に到達するためには時間がかかります。また、シャッターやカーテンなども、開閉を指示しても、実際に開閉が完了するには20秒くらいかかります。

HomeKitにはガレージドア (Garage Door Opener) というカテゴリのアクセサリがあります。mqttthingでは、車庫のドアを開け閉めするトピックに、

  • setTargetDoorState
  • getCurrentDoorState
  • getTargetDoorState

などが用意されてます。これらの使われ方を以下に説明します。

閉まっているガレージドアのアクセサリは、iPhoneでは以下のように表示されます。こんなガレージ、欲しいですね。

iPhoneでタップしてガレージを開けようとすると、setTargetDoorStateにO (Open の O, 設定で変更可能です)というメッセージが流れます。そしてアイコンは開放中のアニメーションに変わります。

これをサブスクライブしたアクセサリは、ドアを動かすモータの電源をonにして、ドアを開けます。何十秒後かにドアが開いたら、アクセサリは、getCurrentDoorStateにOというメッセージを流します。するとiPhoneのアクセサリは開放済みになります。

閉める時はこの逆です。iPhoneのアイコンを操作すると、setTargetDoorStateにC (CloseのC, これも変更可能です) というメッセージが流れます。アイコンは閉鎖中のアニメーションに変わります。

これをサブスクライブしたアクセサリは、ドアを動かすモータの電源をonにして、ドアを閉めます。何十秒後かにドアが閉まったら、アクセサリは、getCurrentDoorStateにCというメッセージを流します。するとiPhoneのアクセサリは閉鎖済みになります。

一連の流れでメッセージが流されるトピックスは、

  1. setTargetDoorStateトピックにOpenメッセージ
  2. getCurrentDoorStateトピックにOpenメッセージ
  3. setTargetDoorStateトピックにCloseメッセージ
  4. getCurrentDoorStateトピックにCloseメッセージ

という順番になりました。

人が開閉スイッチを押した場合

もしも、人が手動でガレージ開閉スイッチを押した場合は、アクセサリはこのことをどのトピックを使って報告すれば良いのでしょうか。外の世界からの操作なので、もちろんgetです。

 

ガレージドアの例ならば、上で示したトピックスの3番目の項目、getTargetDoorStateを使います。閉鎖されている状態で、getTargetDoorStateにメッセージOを流すと、アイコンは開放中になります。

ガレージドアが開放済みになったら、アクセサリは今度、getCurrentDoorStateにOを流します。するとiPhoneのアクセサリは開放済みになります。

getTargetDoorStateにOを流さないで、いきなりgetCurrentDoorStateにOを流してしまうと、アイコンは、開放中のままで止まってしまいます。順番は逆でも良いので、getTarget...とgetCurrent...の両方をセットで流す必要があります。

セキュリティのためのtarget/current

ここでは、動作に時間がかかるアクセサリの例を示しました。このほかに、電気錠、セキュリティシステムなどの、セキュリティが重要となるアクセサリでもtargetとcurrentが使われます。例えば、電気錠を施錠する場合に、アクセサリにsetLockTargetStateトピックからSecureを送ります。これを受け取ったアクセサリは、確実に施錠をした後、getLockCurrentStateトピックにSecureを流します。それまでの間、アイコンは施錠中・・・の表示になります。アクセサリからの返答を待って、確実に操作されることを確保するための仕組みです。

まとめ

setTargetなんとか、getTargetなんとか、getCurrentなんとか、などの区別がよく分かってなかったので、違いをメモしました。HomeKitに限らず、他のフレームワークでも同じような用語が使われていると思いますので、参考になれば幸いです。

SonoffのZigbee 3.0 USB Dongle Plus

SonoffのZigbee 3.0 USB Dongle PlusというZigbeeドングルを買いました。CC2652が搭載されていると思ったら、Silicon Labs社のEFR32MG21というSoCが搭載されてました。名前は同じですが両方のモデルが存在するようです。EFR32MG21は、Zigbee2MQTTでは実験的にサポートされているチップです。動くという報告もあるのですが、不安定だったので今後に期待してお蔵入りになりました。

今使っているドングル

AliExpressで売っていたドングルを使ってます。CC2652Rが載っていて、Zigbee2MQTTで動くファームウェアが書き込まれているので、挿せばすぐに動きます。Raspberry Piでも、Intel NUCのUbuntuでもZigbee2MQTTで問題なく安定して動いています。(写真をクリックするとAliExpressのページに飛びます)

予備にもう一個欲しいと思いました。同じのを買うのも面白くないので、あちこちで評判の良いSonoffのドングルを買いました。今使っている上記のものより安くて、ケースもかっこいいです。

動かない

Sonoffのドングルが届いたので、今使っているドングルと差し替えて動作確認を試みました。マウントされる場所が、今までは、/dev/ttyUSB0だったものが、/dev/ttyACM0に変わりました。/opt/zigbee2mqtt/data/configuration.yamlの設定を書き換えて、zigbee2mqttを再起動します。これですんなり動くと思いましたが、動きません。

sudo systemctl status zigbee2mqtt

とすると、Zigbeeのコントローラに問題があって停止したというようなメッセージが表示されました。これはファームウェアを更新しないとダメかなと思いました。でもTexas InstrumentsのSmartRF Flash Programmer 2で更新を試みるも、エラーが出て書き込めません。落ち着いて、基板上のチップを見ると違和感があります。どこにもCC2652の文字がありません。メインチップの写真は以下です。

MG21 A02011 B01YMD 2147というように読めます。この番号で検索したところ、Silicon Labsという会社のZigbee用SoCらしいです。SoCなので、ソフトウェア的にZigbeeの機能を実装しているようです。TIのチップでは無いので、TIのファームウェア書き込みツールが動かなくても当然でした。購入したAliExpressのページでは、CC2652P搭載と書かれてましたので、すっかりそのつもりでいました。

アップデートされてた

Sonoffのサイトで探してみたところ、SONOFF Zigbee 3.0 USB Dongle Plusという製品には、ZBDogle-Pというモデルと、ZBDongle-Eという2つのモデルがあるようです。

sonoff.tech

ZBDogle-PはCC2652Pを搭載している一方で、ZBDongle-EはEFR32MG21というチップを搭載しているそうです。ZBDongle-Eが後継機のようで、そちらがメインで紹介されてます。Zigbee2MQTTにも対応してますとも書いてあります。パッケージをよく見ると、箱の右下に、ZBDongle-Eと書いてありました。

さらに検索したら、Zigbee2MQTTでの使い方を説明した動画も見つかりました。最近の製品はEバージョンに置き換わっているけど、設定頑張ればZigbee2MQTTでも使えるとの内容でした。

 

www.youtube.com

それによると、設定ファイル、/opt/zigbee2mqtt/data/configuration.yamlのシリアルの項目に、

serial:
  port: /dev/ttyACM0
  adapter: ezsp

と書いておけば良いらしいです。Zigbee2MQTTのサイトもちゃんと探したら、ezspオプションのことが書いてありました。

www.zigbee2mqtt.io

これが対象とするアダプタは、実験的な段階なので、安定性を求めるなら使うなと書いてありました。

動いたけど不安定

ezspを指定して、Zigbee2MQTTを再起動したところ、systemctl statusコマンドで出ていたエラーは消え、無事動いているようでした。ただし、デバイスをペアリングして操作をしようとすると、動くこともありますが、エラーが出る場合もあります。動く時も、すぐには動作しないで、遅延した後、まとめてon/offを繰り返したりします。壁に埋め込んだスイッチなどは、不適切なコマンドを受け取る影響なのか、マニュアル操作すら動作しなくなってしまいました。壁から取り外して、線を外して接続し直すと復活します。

YouTubeの動画の人は、数日間安定して動作していると言ってましたが、あちらはRaspberry Piらしく、こちらの環境はIntel CPUのUbuntuなので、環境が違うせいかもしれません。とても不安定でした。今現在、安定して動いているドングルを、これに交換する必要性は無いので、SonoffのドングルはZigbee2MQTTが完全対応するまでお蔵入りにすることになりました。

まとめ

SonoffのZigbeeドングルは新モデルに更新されて、TIのチップでは無くなったようです。手元の環境ではZigbee2MQTTで安定して使用できませんでした。旧モデルのZBDongle-Pが入手できれば良いですが、その確証がなければ他を探した方が良いかもしれません。

家庭用エアコンに付いてたJEM-A HA端子をHomeKitから使う

廉価版の家庭用エアコンに、JEM-A HA端子が付いているのを発見しました。仕様を調べて、ESP32に接続し、MQTTとHomebridge経由でHomeKitから使えるようにしました。

参考記事のご紹介

Homebridgeについては以下もご覧ください。

diysmarthome.hatenablog.com

MQTTブローカについてはこちらもご覧ください。

diysmarthome.hatenablog.com

ESP32をMQTT, Homebridgeと連携させる方法はこちらをご覧ください。

diysmarthome.hatenablog.com

謎の多いJEM-A端子

日本電機工業会(JEMA)という業界団体が、標準規格を作っています。その業界規格の一つに、家電製品の自動化のために作られたJEMA標準HA端子-Aという端子があります。HAとは多分ホーム・オートメーションのことですね。この名前のほか、JEM-A端子、JEM-A HA端子、JEMA端子、JEM端子-A、JEM1427端子などと呼ばれているようです。以下ではJEM-A端子と書くことにします。JEM-A端子は、エアコン、給湯機、暖房器具、床暖房、電動で開閉する装置、電気錠、インターフォン(電気錠との連携)、電気温水器、照明器具などのon/off制御と、そのon/off状態のモニタを行う端子です。できることは2値の制御とモニターだけで、温度設定とか明るさ設定などの機能は実現できません。

JEM-A端子は、日本の家電メーカの色々な製品に付いていて、スマートホームDIYに使えそうな面白い規格なのですが、あまり情報がありません。こちらのページくらいが一番詳しいかもしれないです。それによると、端子にはC1, C2, M1, M2の4本のピンがあり、2本が制御、2本がモニタで、それぞれに電圧がかかるかどうかでon/offを表してます。これを制御するためには、フォトカプラなどで絶縁してインタフェースするのが良いようです。

https://mtrx.jp/info/images/JEMA-FIG1.gif

( https://mtrx.jp/info/jema.html から引用 )

C1, C2を250ms程度短絡すると、on/offが反転し、その結果、M1, M2に電圧が出たり消えたりするようです。なので、C1, C2に押しボタンスイッチを接続し、M1, M2にモニタランプ(LED)を接続すれば、ボタンを押すごとにon/offが反転してLEDが点灯・消灯するスイッチボックスが簡単に作れそうです。

ただ、これ以上の細かい規格は分かりません。電圧・電流・タイミングの定格値・許容値も謎です。謎な根本理由が、JEMAが技術情報PDFを1,150円で販売していることだと思います。価格は大したことはないのですが、購入した情報を無許可で「出版」してはいけないことになっています。なので、情報を購入した人はネットで公開できない状況です。色々な家電に付いていて、便利な機能なのに勿体無いです。

www.jema-net.or.jp

もう少し探したところ、こちらにJEM-A端子とフォトカプラでインタフェースする製品の仕様書が見つかりました。JEM-A端子の規格についてあからさまには書かれてませんが、製品仕様からある程度の推測ができます。

https://www2.panasonic.biz/ideacontout/2012/11/14/2012111400020152.PDF

panasonic.bizから引用)

これによると、C1, C2側の耐電圧は30V, 許容電流5mAで、M1, M2側の許容電流は20mAだそうです。M1, M2を2mAで動作させる場合1.6V以下にするようにと書いてあります。回路図も書いてあるので、これを参考に自作すると良いと思いました。フォトカプラに100Ωくらいの抵抗を直列に入れて保護しておけば良いようです。

エアコンのJEM-A端子を発見

JEM-A端子は、意外とあちこちに付いているようです。例えば手近にあるPanasonicのエアコンにもついてました。10年くらい前の、ごく普通の安価な標準モデル家庭用エアコンです。PanasonicのEchonet Light対応機器一覧にも掲載は無く、WiFiも搭載されてません。JEM-A HA端子に関しても、本体にもマニュアルにもどこにも書いてありません。でもなぜか、Panasonicの製品仕様書のページに、JEM-A端子に関する表記がありました。

そこで、エアコンを分解してJEM-A端子を探すことにしました。室内機の右側部分に電子回路がありそうで、薄い鉄板でシールドされてます。下の写真の右端の銀色の部分です。シールドは、噛み合わせの部分にギターピックを挟んで浮かせれば簡単に外れました。

すると、中の基板の手間側に、白いJEM-A端子が見つかりました!下の写真の右下にある4ピンの端子です。上の写真では赤丸のあたりの場所です。

取説にも掲載が無くて、ここに接続できるオプション製品も無いのに、なぜJEM-A端子があるのか謎です。業界団体とのお付き合いの関係で、仕方なく付けているのかもしれません。現場に「なんでこれ必要なのですか?」のような声があったかもしれません。でもDIYする立場としては、とても嬉しいです。無駄と思っても装備せざるを得なかった端子ならば、活かして差し上げたいと思います。

端子ケーブルを作る

接続するためにはコネクタ付きケーブルが必要です。JEM-Aのケーブルは、モノタロウなどで300円くらいで販売されてますが、送料もかかるし、部品から作った方が安いので、自作することにしました。JEM-A端子の形状はどれも同じです。おそらくは規格で決められているのだと思います。この端子に収まるコネクタは、こちらで20個100円で販売されている製品です。自作するには100本で200円のピンも必要です。ピンに配線を接続するためには圧着工具があると良いです。でも半田付けでもokです。こんな感じで完成しました。

圧着工具は無しでもなんとかなりますが、コネクタを外す工具は、絶対に持っていた方が良いです。ペンチやマイナスドライバーで外そうとすると苦労しますし、コネクタやケーブルを損傷させる可能性があります。今回初めてこの手の工具を使いましたが、とても楽でした。

電気特性を調査する

JEM-A端子の、それぞれのピンの電圧を開放状態で測りました。また1kΩの抵抗を取り付けて負荷かけた時の電圧も測定しました。

C1-C2の電圧は、開放時に5.04V、1kΩの抵抗を取り付けた場合に0.45Vでした。ちなみに1kΩを取り付けたら、エアコンが起動しました。一方で、M1-M2のHIGH電圧は、開放時に4.5V、1kΩの抵抗を取り付けた場合に2.3Vでした。M1-M2のLOW電圧は0.2Vでした。これから内部抵抗を計算しました。どうやら内部の回路は5Vで稼働するTTL回路のようです。内部回路の想像図は以下です。

ネットの情報を見ると、端子に現れる電圧が、12Vや15Vの場合もあるらしいですが、扱いやすい5V電圧で良かったです。この回路図を見ると、C1-C2は安心して短絡できそうです。また、M1-M2も十分な保護抵抗が入っている様子なので、LEDを直結しても大丈夫のようです。実際にLEDを接続し、C1-C2を短絡したら、エアコンがon/offし、LEDが控え目に点灯・消灯しました。

エアコンが稼働するとM1の電圧がHIGHになり、停止するとLOWになります。

インタフェース回路を作る

先のPanasonicの仕様書を参考に、回路を考えました。JEM-A端子は、1, 2, 3, 4番がそれぞれ、C1, C2, M1, M2です。Cが制御用、Mがモニター用で、C1, M1が高電圧側、C2, M2がグラウンド側です。回路図のJEM-A端子側に入っっている100Ω抵抗は、気休めです。内部抵抗を調べたところでは、この抵抗は無しでも大丈夫なはずですが、Panasonicの仕様書にも入っていたので取り入れました。GPIO12は内部でプルアップさせるので、直結です。GPIO13に付けた220Ωの抵抗は、フォトカプラに定格の10mAを流すために入れました。

これをユニバーサル基板で半田付けして作ろうと思ってますが、とりあえずはブレッドボードに作って動作確認します。ブレッドボードも段ボールの上にテープで貼り付けた(仮)な状態です。写真のブレッドボード左上にあるコネクタに、JEM-A端子からのケーブルが挿さってます。このコネクタはブレッドボードにも挿さる仕様なので便利でした。

ESP32をプログラムする

MQTTブローカと通信して、メッセージに従ってJEM-A端子のC1ピンをon/offするプログラムを、ESP32に書きました。これと並行して、JEM-A端子のM1ピンをモニターし、その状況をMQTTブローカに報告します。基本の動作は、

  1. MQTTブローカーから、mqttthing/fan/setOnトピックにtrueかfalseが来たら、JEM-AのC1, C2端子を250ms間短絡する。(その結果エアコンがon/offします)
  2. また、JEM-AのM1, M2端子の電圧が変化したら、MQTTのmqttthing/fan/getOnトピックにtrueかfalseを流す。(その結果HomeKitのon/off表示が更新されます)
  3. さらに10分に1回、C1, C2端子の様子をmqttthing/fan/getOnトピックに流す。(HomeKit表示が実態を反映するための念押しです)
  4. 必要に応じて、mqttthing/fan/debugトピックに、デバッグ用のメッセージを流す。

という内容です。プログラムは以下です。C1, C2端子のフォトカプラはGPIO 13番に、M1, M2端子はGPIO 12番に接続してあります。MQTTブローカとの通信には、EspMQTTClientライブラリを使ってます。

//ESP32 fan with EspMQTTClient library. 
//This will simply on/off an air-conditioner through its JEM-A HA port.
// Sep. 8, 2022. (first version)

#include "EspMQTTClient.h"

EspMQTTClient *client;

//input & output pins and values
#define JEMAOUT 13 //GPIO for photo relay to JEM-A control line.
#define JEMA_ON 1  //value for pulse on
#define JEMA_OFF 0 //value for pulse off
#define JEMAIN 12  //GPIO for photo relay driven by JEM-A monitor line. Pull-up.
#define JEMA_false 1  //value when the fan is off (false)
#define JEMA_true 0  //value when the fan is on (true)

int JEMA_last; //previous value read from JEMAIN.

//WiFi
const char SSID[] = "XXXXXXXX"; //WiFi SSID
const char PASS[] = "xxxxxxxx"; //WiFi password
char CLIENTID[] = "ESP32_xx:xx:xx:xx:xx:xx"; //MAC address is set in setup()
//for example, this will be set to "ESP32_12:34:56:78:9A:BC"
const char  MQTTADD[] = "192.168.xxx.xxx"; //Broker IP address
const short MQTTPORT = 1883; //Broker port
const char  MQTTUSER[] = "xxxxx";//Can be omitted if not needed
const char  MQTTPASS[] = "XXXXX";//Can be omitted if not needed
const char  SUBTOPIC[] = "mqttthing/fan/setOn"; //mqtt topic to subscribe
const char  PUBTOPIC[] = "mqttthing/fan/getOn"; //mqtt topic to publish
const char  PUBDEBUG[] = "mqttthing/fan/debug"; //for debug message

void setup() {
  //Digital I/O
  pinMode(JEMAOUT, OUTPUT);//for C1-C2 JEM-A pins
  pinMode(JEMAIN, INPUT_PULLUP);//for M1-M2 JEM-A pins
  JEMA_last=digitalRead(JEMAIN);
  //Serial
  Serial.begin(115200);
  while (!Serial);
  Serial.println("ESP32 fan has started.");
  //MQTT
  String wifiMACString = WiFi.macAddress(); //WiFi MAC address
  wifiMACString.toCharArray(&CLIENTID[6], 18, 0); //"ESP32_xx:xx:xx:xx:xx:xx"
  Serial.print("SSID: ");Serial.println(SSID);
  Serial.print("MQTT broker address: ");Serial.println(MQTTADD);
  Serial.print("MQTT clientID: ");Serial.println(CLIENTID);
  client = new EspMQTTClient(SSID,PASS,MQTTADD,MQTTUSER,MQTTPASS,CLIENTID,MQTTPORT); 
}

void onMessageReceived(const String& msg) { // topic = mqttthing/fan/setOn
  if(msg.compareTo("true")==0) { //requeted to set true (ON)
    client->publish(PUBDEBUG, "received ture on setOn-topic.");
    if(digitalRead(JEMAIN) == JEMA_true) return; //already ON. do nothing.
  }
  else if(msg.compareTo("false")==0) { //requested to set false (OFF)
    client->publish(PUBDEBUG, "received false on setOn-topic.");
    if(digitalRead(JEMAIN) == JEMA_false) return; //already OFF. do nothing.
  }
  //now send a pluse to toggle the fan ON or OFF
  client->publish(PUBDEBUG, "sending a pluse to JEM-A.");
  digitalWrite(JEMAOUT, JEMA_ON); //activate JEM-A C1C2 for 0.25 sec
  delay(250); 
  digitalWrite(JEMAOUT, JEMA_OFF);
}

int counter; //counter for loops 

void onConnectionEstablished() {
  Serial.println("WiFi/MQTT onnection established.");
  client->subscribe(SUBTOPIC, onMessageReceived); //set callback function
  client->publish(PUBDEBUG, "ESP32 fan is ready.");
  counter=999999; //to trigger a publish at the next loop
}

void loop() {
  client->loop();
  int newvalue = digitalRead(JEMAIN);//get current JEMA value
  delay(10); //10 ms delay
  if(newvalue == JEMA_last) {
    if(++counter < 60000) {//check if less than 10 min
      return; //no change and no count-up, do nothing
    }
  }
  //JEMA monitor status has chenged or counter is up
  if(newvalue == JEMA_true){
    client->publish(PUBTOPIC,"true");
  }
  else{ // if new value == JEMA_false
    client->publish(PUBTOPIC,"false");
  }
  JEMA_last = newvalue;
  counter=0;
}

Homebridgeを設定する

Homebridgeにはmqttthingプラグインを入れました。そしてMQTTメッセージに応じて状態が変化するfanアクセサリを作ります。mqttthingの設定は、Homebridge webページのGUIから可能です。その結果、/var/lib/homebridge/config.jsonの設定部分は以下になりました。名前はエアコンにしました。

{
            "type": "fan",
            "name": "エアコン",
            "url": "mqtt://192.168.xxx.xxx:1883",
            "username": "xxxxxxxx",
            "password": "XXXXXXXX",
            "topics": {
                "getOn": "mqttthing/fan/getOn",
                "setOn": "mqttthing/fan/setOn"
            },
            "accessory": "mqttthing"
        }

HomeKitから操作する

この結果、iPhoneMacのホーム.appアプリに、「エアコン」という名前のfanアクセサリボタンが現れました。

クリックするとon/offします。頻繁にon/offするとエアコンに負担がかかるので、動作確認が難しいです。mosquitto_subコマンドで、

mosquitto_sub -h 192.168.xxx.xxx -u xxxxxx -P XXXXXX -t mqttthing/fan/# -v

などとしておけば、以下のようにメッセージが確認できます。

mqttthing/fan/debug ESP32 fan is ready.
mqttthing/fan/getOn true
mqttthing/fan/setOn falsemqttthing/fan/debug received false on setOn-topic.
mqttthing/fan/debug sending a pluse to JEM-A.

これはエアコンがoffの状態でESP32を起動させ、iPhoneからonにしたときの流れです。これでアイコンもオンになります。

onにするとアイコンのファンの羽がゆっくり速度を上げて回転開始し、offすると回転が遅くなり止まります。

(GIFアニメにしたら遅くなりました。実際はもっと速く滑らかに回転します)

まとめ

古めのエアコンにJEM-A端子を見つけたので、HomeKitから使えるようにDIYしました。JEM-A端子ではon/offしかできませんので、温度設定の変更には元々のエアコンのリモコンが必要です。でもシンプルに確実に動作しますし、大体の場面ではこれで十分かと思います。

Athom社のOrange pi zeroを使ったZigbee - Homebridgeサーバ

AthomのZigbee-Homebridgeサーバを使ってみました。Raspberry Pi Zeroに有線LANが付いたような基板にZigbee USBドングルが搭載されて、Homebridge, Zigbee2mqtt, Mosquittoが動きます。コスパは悪いですが、設定不要で動くので、市販のブリッジ製品くらいの気軽さで使えます。

AthomのIoT製品

Tasmota, ESPHome, HomeKitなどに対応したデバイスを作っているAthom Technologyって会社(場所は深圳?)があります。相場に比べて価格が安いわけではないですが、マニア向けなハードウェアを作ってます。そこでZigbee搭載Homebridgeサーバが売られてましたZigbee非搭載のモデルもあります。AliExpressでも売っているので買いやすいと思います。昔はZigbee搭載モデルが7000円くらいでしたが、今は円安・半導体不足のためか1万円超えてます。

Orange Piを使ったサーバ

AliExpressを見ていると、Orange Piっていうコンピュータ基板が見つかります。名前の通り、Raspberry Piのようなコンピュータです。ただし、互換機ではありません。この製品のメイン基板にも、Orange Piシリーズの中のOrange Pi Zeroという基板が使われてます。AliExpressのページなどの情報によると、仕様は以下らしいです。Raspberry Pi Zeroに近いカテゴリの小型基板ですが、ビデオ出力が無く、有線LANが付いている点がサーバ向けの構成になっていて良いです。

今回のHomebridgeサーバ製品、これが、サイズが55 x 50 x 36mmの小いさな白いケースに入っています。Orange Piのロゴが刻印されているので、標準的なケースだと思われます。ケースには、Ethernet, USB 2.0, micro USB (OTG), micro SDカードの端子があります。micro USBは電源用です。

ケースの裏蓋はネジ4本を外すと簡単に開きます。メインのOrange Pi Zero基板に、無線の基板が載ってます。これがZigbee無線のようです。AthomのページによるとCC2530PATR 2.4Z-Mというモジュールらしいです。メインの基板とは4本のヘッダピンで接続されています。ちょっとぐらついてますが箱の中で固定されるので問題ないでしょう。4本のピンは、プリント基板の印字によると、USB 2.0の5V, GNC, D+, D-のピンのようです。Zigbee2MQTTのページによると、CC2530は古いチップで、動くけど推奨しないとのことでした。

付属品

付属品は以下のように完璧ですぐに使用できます。

  • 電源アダプタ(USB電源)
  • 電源用USBケーブル
  • Ethernetケーブル
  • micro SDカード

micro SDカードにはOS類がインストール済みです。使用する前にSDカードをバックアップしておくのが良いと思います。macOSLinuxだったら、

dd if=/dev/rdisk<番号> of=athomserver.iso bs=16m

のようにddコマンドでバックアップできます。<番号>の部分は、SDカードをUSBアダプタにつけてマウントした時のディスク番号です。

サーバを動かす

サーバは全部設定済みなので、動かすのは簡単です。

  1. SDカードを指して、
  2. Ethernetケーブルを指して、
  3. 電源を接続する

だけです。DHCPでアドレスを取得するので、ルータのログを覗いて付与されたアドレスを調べます。あとは、そのアドレスに:8581をつけて、webブラウザで開けば使えます。例えば、http://192.168.4.12:8581を開きます。デフォルトのユーザ/パスワードは、admin/adminらしいです。ちなみにsshのユーザ/パスワードは、root/athom.techです。

このあとは、

  1. ログインして、
  2. 表示されるQRコードを使ってiPhoneからブリッジとして追加して、
  3. Zigbeeバイスをペアリングモードにすれば、

iPhone/Macのホーム.appから使えます。とても簡単です。唯一スキルが求められるのは、DHCPで割り当てられたアドレスを見つける技能くらいかと思います。

コストパーフォマンスは良くありません。Raspberry Pi 4を買って、最新のZigbeeアダプタを使えば、1クラス上の性能のサーバを同程度の価格で作れます。ただ、サーバをインストールして設定する手間が必要です。それに対して、市販のZigbeeゲートウェイと同じくらいの簡単な手順で、Zigbee + Homebridgeサーバを作ることができるので、入門機として良いのではないかと思います。

アップデートする

誰でも使える入門機の使い方としては無粋かもしれませんが、搭載されているソフトウェアを最新版にアップデートしました。

Homebridgeのアップデート

これは簡単です。WebページからHomebridge本体、UI, プラグインのどれも、更新ボタンを押すだけでアップデートされます。

Zigbee2MQTTなどのアップデート

sshでログインして

sudo apt update
sudo apt upgrade

などすれば良いと思います。Zigbee2MQTTに関しては、こちらの手順も有効かと思います。

OSのアップデート

これは多少の手間がかかりました。sshでログインすると以下のような表示が出ます。

  ___  ____  _   _____              
 / _ \|  _ \(_) |__  /___ _ __ ___  
| | | | |_) | |   / // _ \ '__/ _ \ 
| |_| |  __/| |  / /|  __/ | | (_) |
 \___/|_|   |_| /____\___|_|  \___/ 
                                    
Welcome to Armbian 21.02.3 Buster with Linux 5.15.48-sunxi

Armbianというディストリビューションがインストールされているようです。調べてみると、Orange PiなどのSingle Board Computer (SBC)という類のコンピュータ向けのOSのようです。表示のように、使われているのはBusterというバージョンですが、最新版はBullseyeらしいです。BusterからBullseyeへアップデートする方法が以下で紹介されていました。

forum.armbian.com

これによると、/etc/apt/sources.listに記述された参照先がBusterになっているので、aptで更新してもBusterの範囲での更新になるようです。なのでこの参照先をBullseyeに書き換えれば良いようでした。ということで

  1. /etc/apt/sources.listの中のbusterという文字をbullseyeに書き換えて
  2. apt updateして
  3. apt full-updateする

手順で、Bullseyeにアップデートできました。でもOSはアップデートできたのですが、sshでログインした時の表示はBusterのままでした。この対処法も上記のリンクに書かれていました。以下のようにすれば良いようです。

apt remove linux-buster-root-current-orangepizero
apt install armbian-bsp-cli-orangepizero

これで、ログインの時の表示も正しくなりました。

  ___  ____  _   _____              
 / _ \|  _ \(_) |__  /___ _ __ ___  
| | | | |_) | |   / // _ \ '__/ _ \ 
| |_| |  __/| |  / /|  __/ | | (_) |
 \___/|_|   |_| /____\___|_|  \___/ 
                                    
Welcome to Armbian 22.05.3 Bullseye with Linux 5.15.48-sunxi

まとめ

Apple HomeKitはアプリが秀逸なので、普通のiPhoneユーザにももっと使って欲しいところです。対応デバイスが限られていて高価な点も、Homebridgeを使えば対応できます。なので誰でもすぐに使えるHomebridgeサーバという商品コンセプトは面白いと思いました。

また、思いがけずOrange Pi Zeroを使うことになりましたが、Raspberry Pi Zeroよりもサーバ向きの構成なので、スマートホーム用途に向いていると感じました。

IKEAのZigbee製品TRÅDFRIスイッチ

ikea.comから引用)

IKEAZigbee製品は、技適も通っていてお手頃価格です。中でもシーソースイッチである「ワイヤレス調光器」は税込799円で買えます。Zigbee2MQTTでサポートされているので、Homebridge経由でHomeKitアクセサリとして使用できます。

IKEAZigbee製品

IKEAはTRÅDFRI(トロードフリ)というシリーズで、電球、スマートプラグ、人感センサ、シーソースイッチ、押しボタンスイッチ、リモコンスイッチなどのZigbee製品をお手頃価格で供給してくれてます。FYRTUR, KADRILJなどの名前のロールカーテンも使えるようです。こちらにZigbee2MQTT対応一覧があります(日本では扱っていない製品もあるようです)。

4,999円のゲートウェイ(下の写真の丸い製品)を買ってEthernet接続すればApple HomeKitにも接続できます。ゲートウェイは、Homebridgeに相当する機能を果たします。Ikea製品とHomeKit (HAP)のブリッジをしてくれます。これにより、Ikea製品がHomeKit画面に現れて、電源on/off、調光・調色などの操作が可能になります。

ikea.comから引用)

TRÅDFRIゲートウェイを使ってHomeKitに接続する方法はweb上にたくさん紹介されています。ですが、ゲートウェイは、TRÅDFRIの一部の製品の橋渡ししかしません。電球などはHomeKitからアクセスできますが、スイッチや人感センサはHomeKitから見えません。

Ikea製品の公式方法では、スイッチや人感センサ製品は、電球やカーテンなどの製品と1:1にペアリングして、使用することになってます。なのでスイッチや人感センサはHomeKit側には公開されないようです。

Zigbee2MQTTにペアリングする

Zigbee2MQTTとHomebridgeでZigbeeバイスをすでに活用している環境ならば、TRÅDFRIゲートウェイを使わずに直接IKEAバイスをコントロール可能です。そうすれば、スイッチや人感センサもHomeKitから使用できますし、ゲートウェイの費用も節約できます。IKEA TRÅDFRI製品はペアリングをするだけで、Zigbee2MQTTから使えるようになります。

Zigbee2MQTTのペアリングモードがoffに設定してある場合は、webインタフェース右上のPermit join (All)のメニューをクリックしてペアリングを許可します。すると5分間、ペアリングが可能になります。

 

 

一方、TRÅDFRIスイッチやセンサーの裏側には、ペアリングボタンが付いています。鎖マークが書かれたボタンです。このボタンを4回クリックするとペアリングモードに入ります。

電球の場合は、6回off/onを繰り返して、最後にonの状態で待ちます。ペアリングモードに入るための方法を説明したIKEAらしいお洒落な動画がこちらにあります。ペアリングを成功させるためには、Zigbee2MQTTが使っているアンテナを近づけた方が良いです。ただ、他にペアリングしようと競合する装置がなければ、2-3mくらい離れていてもペアリングしました。

mosquittoコマンドでサブスクライブしてけばペアリングの様子を確認できます。

mosquitto_sub -h localhost -t zigbee2mqtt/# -v

これはmosquittoがlocalhostで動き、ユーザ名・パスワードを設定していない場合の例です。色々メッセージが出てくるので、ペアリングの様子を確認できます。

ペアリングを切り離す方法(web方式)

Zigbee2MQTTでwebインタフェースを使用している場合、ペアリングしたデバイスを切り離す操作は簡単です。デバイス一覧からゴミ箱アイコンをクリックするだけです。

この後、オプションが表示されます。

Zigbee接続中のデバイスはこのままDeleteボタンを押します。接続していないデバイスを取り外すには、Force removeをonにしてからDeleteボタンを押します。次に接続した時にも切り離した状態にしたい場合は、Block from joining againをonにします。これで工場出荷状態の関係に戻ります。

ペアリングを切り離す方法(MQTT方式)

ペアリングしたデバイスは、MQTTのメッセージを使っても切り離せます。Zigbee2MQTTの本来の方式です。Webインタフェースも、内部ではMQTTメッセージ経由で操作してます。

MQTT経由でデバイスを切り離すためには、

mosquitto_pub -h localhost -t zigbee2mqtt/bridge/request/device/remove -m "0x9999999999999999"

のようなトピックス・メッセージをMQTTブローカーに流します。

mosquitto_pub -h localhost -t zigbee2mqtt/bridge/request/device/remove -m '{"id":"0x9999999999999999"}'

でも良いです。9999...の部分は、ZigbeeのIDです。mosquitto_subしたメッセージを見ていれば確認できますし、/opt/zigbee2mqtt/data/configuration.yamlファイルにも書かれています。ペアリングを切り離す操作も、別のターミナルウィンドウから、mosquitto_subしておけば動作確認できます。

ただ、この方法は、デバイスがペアリングして動いている時にしか使えません。デバイスからの応答が無いとエラーが表示されます。スリープしている場合は起動させる必要があります。

バイスが既にペアリングされていない、工場出荷時状態に戻してしまった、もしくは手元にないなどの場合は、強制的にremoveします。forceという項目をtrueにして送ります。

mosquitto_pub -h localhost -t zigbee2mqtt/bridge/request/device/remove -m '{"id":"0x9999999999999999","force":true}'

forceオプションをつけてremoveをしても、デバイスがペアリング状態のまま復活するとまた接続されます。

HomeKitから設定する

Zigbee2MQTTとペアリングができれば、Homebridgeの設定は不要で、そのまますぐにiPhone/Macのホーム.appにIKEA製品が表示されます。電球なら

こんな感じで、スイッチなら以下のようです。

スイッチをクリックすると、設定画面が現れます。以下は、押しボタン壁スイッチであるTRÅDFRIショートカットボタンの例です。物理的には押すだけのボタンが一つあるだけですが、設定画面には、論理的なボタンを4個、ボタン1からボタン4までのボタンを備えているように見えてます。

IKEAの押しボタンは、on、off、長押しの開始、長押しの終了の4個の操作を識別しているようで、それぞれがこの論理ボタンに対応するようです。試したところ、短くクリックするとボタン2が、長押しを開始するとボタン4が対応していました。この2操作の識別が容易だと考えたので、これらを使用することにしました。

IKEAボタンには、付属の「おやすみなさい」ラベルを取り付けて使うことにしました。

そこで、短くクリックすると照明やエアコンが停止するように設定しました。試したところ、ボタン2の1回押しが「短いクリック」に相当するようです。なのでこれを以下のように設定します。

さらに、長押しすると、照明が点灯してエアコンが始動するように設定しました。試したところ「長押し」はボタン4の1回押しに相当するようです。なのでこれを以下のように設定しました。

まとめ

IKEAのTRÅDFRIシリーズを、HomeKitに接続しました。通常はIKEAゲートウェイ製品を使ってHomeKitに接続しますが、Zigbee2MQTTとHomebridgeを使って使用しました。ゲートウェイ経由だと橋渡しされないスイッチ、リモコン、人感センサなども、この方式でHomeKitから使えるようになります。

Dockerを使ってHomebridgeとHome Assistantを導入する

普通のWindows向け小型パソコンのIntel NUCに、Ubuntuを入れて、dockerを動かして、それにHomebridgeとHome Assistantをインストールしました。

先日の記事ではこのNUCにHome Assistantのイメージをインストールしましたが、気が変わってHomebridgeとHome Assistantの両方をdockerで入れることにしました。コロコロ変わってすみません。

diysmarthome.hatenablog.com

仮想環境でサーバを動かす

OSの上で直接サーバデーモンを動かすのではなくて、仮想機械(VM)やコンテナのような仮想環境を作ってその上でサーバを動かす方式が流行っている気がします。大昔の大型コンピュータでも、VMの上で古いOSを動かして、古いプログラムを動かしていたらしいです。流行が繰り返しているのでしょうか。

今までHomebridgeを使ってましたが、Home Assistantも試してみたいと考えていました。Home Assistantはイメージでのインストールを推奨しています。なので当初は、Raspberry Piを1個新調して、そちらをHome Assistant専用にしようと考えてました。でもRaspberry Piが品不足で入手困難になってしまいました。それで、前回の記事では、もう一台予備で持っていたIntel NUCをHome Assistant専用サーバとして構成しました。ただ、このNUCも別の場所でサーバとして使いたく思うようになりました。それで、今Homebridgeで使用しているIntel NUCの上に、仮想環境を作り、Homebridgeと共存させることにしました。

Intel NUCで仮想環境を作るならば、流行りのもので、KVMかDockerでしょうか。ただ本格的なVMだと、メモリとかCPUコアのリソースを分配する調整が面倒に思います。それでコンテナ方式のDockerでサーバ構築することにしました。

Ubuntuをインストールする

ゼロから作り直す方がスッキリすると思い、初代Intel NUC DC3217IYEにUbuntuをインストールしなおしました。 搭載CPUはモバイル向け第3世代のIntel(R) Core(TM) i3-3217U CPU @ 1.80GHzです。メモリは8GB、ストレージは64GBのmSATA SSDです。Windowsが動く普通のパソコンなので、あちらこちらでうち捨てられている旧式のコンピュータのどれでも同じ方法で使えるはずです。スマートホームのサーバーとして蘇らせてあげましょう。

Ubuntuのインストール方法はいくらでも見つかると思いますので、あらすじだけ。

まずはUbuntuのサイトに行って、最新のUbuntuサーバー (22.04.1 LTS) のisoファイルを入手します。ここではMacにダウンロードしました。ubuntu-22.04.1-desktop-amd64.isoという名前の、1.4GBくらいのファイルでした。

次に、これが収まるサイズのUSBメモリ(今回は8GB)を用意して、ddコマンドで、

sudo dd of=/dev/rdisk5 if=ubuntu-22.04.1-desktop-amd64.iso bs=16m

のようにしてUSBメモリにコピーします。この例はUSBメモリがdisk5にある場合です。bsはコピーするブロックサイズの指定ですが、デフォルトだと遅いです。16MBくらいが最適らしいです。

最後に、このUSBメモリを、インストール先のパソコン(Intel NUC)に挿して起動すれば、Ubuntuのインストールを開始できます。インストール途中で、mosquittoやdockerをインストールするのか聞かれました。うっかりインストールをお願いしてしまったら、snapという枠組みでインストールされました。snapも、Dockerに近い考え方で、サーバを独立した環境で管理する方式のようです。でもその関係で、設定ファイルが素のままではリードオンリーになっていて、書き換え面倒でした。結局、削除しました。

Dockerとは

軽量の仮想機械のようなものかと理解してます。Linuxの上でWindowsを動かそうとすると、ハードウェアに近いレベルから仮想化しないとダメですが、Linuxの上で別のLinuxを動かすならば、共通で使えるカーネル部分のレベルで仮想化すれば十分なはずです。そうすれば無駄が少なくて効率よく実装できます。以下が構成図です。

(https://knowledge.sakura.ad.jp/13265/ から引用)

一つのコンピュータに多数のサーバを組み込んでいくと、依存関係が複雑になったり、どれかのサーバの不具合で他にも支障が出たりと、厄介です。でも別の仮想環境(コンテナと呼んでいるようです)でサーバを動かせば、個別に再起動したり、丸ごとバックアップしたり、実験的に動かしたりすることが容易です。

Docker CEをインストールする

Dockerにも色々なバージョンがあるようです。Docker Desktopというのが有料版で(個人利用はまだ無料らしいです)、Docker CEというのが無償版のようです。こちらの手順を参考にしてDocker CEをインストールしました。

パッケージリストを更新して:

sudo apt update

HTTP経由のレポジトリを使うパッケージをインストールして:

sudo apt install -y apt-transport-https

GPGキーをダウンロードして(wgetが無いと言われたので、メッセージに従ってsudo apt install wgetしました):

wget -qO - https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Docker CE repositoryを追加します:

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -sc) stable" | sudo tee /etc/apt/sources.list.d/docker.list

ここでいよいよDocker CEをインストールします:

sudo apt update
sudo apt install -y docker-ce

これでインストール終了のようです。aptコマンド以外は呪文みたいでした。

Docker CEを動かす

デフォルトでは、rootとsudoできるユーザだけがDockerを使えます。インストールの過程でdockerというグループが作られているので、それ以外のユーザがdockerを使えるようにするには、dockerグループに加えておけば良いようです。sudoコマンドを打つ手間が省けるので、自分をdockerグループに加えておきます。

sudo usermod -a -G docker $USER

これを有効にするには、一旦ログアウトして、ログインしなおします。動作を確認するために、dockerのversionを見ます。

docker version

それっぽい表示が出たので大丈夫のようでした。dockerサービスが動いているかどうか確認します:

sudo service docker status

このほか以下のコマンドで停止、起動、再起動ができます。

sudo service docker stop
sudo service docker start
sudo service docker restart

ちなみにこのページのガイドでは、serviceコマンドを使ってますが、いつも使っている、

sudo systemctl status docker

などのコマンドでも同じことができました。

Hello Worldの動作テスト

hello-worldを表示するイメージファイルがあるようです。それでテストできます。

docker run hello-world

このコマンドは、テスト用のイメージをダウンロードして、コンテナで動かして、メッセージを表示して、終了するものだそうです。

Docker CEを削除する方法

削除方法も書いてありました。#以下で補足して羅列します。

sudo apt purge --autoremove -y docker-ce
sudo groupdel docker #グループ削除
sudo ip link delete docker0 #network interface削除
#GPG keyとリポジトリを削除:
sudo rm -rf /usr/share/keyrings/docker-archive-keyring.gpg
sudo rm -rf /etc/apt/sources.list.d/docker.list
#Docker設定、イメージ、コンテナなどのディレクトリを削除
sudo rm -rf /etc/docker sudo rm -rf /var/lib/docker sudo rm -rf /run/docker sudo rm -rf /var/run/docker.sock sudo rm -rf /var/lib/containerd sudo rm -rf /opt/containerd

Homebridgeをインストールする

Homebridge本家のサイトからリンクされている、こちらのガイドに従いました。

github.com

ここではdocker-composeというユーティリティを使っているようです。Docker CE本体とは別に配布されているツールのようです。通常はdocker runコマンドに長いオプションを付けてでコンテナを起動するのですが、docker-composeコマンドはあらかじめymlファイルで定義した内容に従ってコンテナを起動します。何をどういうオプションで動かしたかもymlファイルで残るので、管理も楽そうです。

Homebridgeを動かすには、以下の内容のdocker-compose.ymlというファイルを作ります。どこでも良いようなので、ホームディレクトリに作りました。

version: '2'
services:
  homebridge:
    image: oznu/homebridge:ubuntu
    container_name: homebridge
    restart: always
    network_mode: host
    environment:
      - HOMEBRIDGE_CONFIG_UI_PORT=8581
    volumes:
      - ./homebridge:/homebridge

この後、docker-compose.ymlをおいたディレクトリで、

docker-compose up -d

コマンドを動かせば良いようです。今回は、docker-composeがインストールされていないと言われたので、メッセージに従って、

sudo apt install docker-compose

してインストールしました。インストール終了後、http://xxx.xxx.xxx.xxx:8581/に接続したところ動いてました。


Home Assistantをインストールする

Home Assistantもdocker-composeを使ってインストールしました。方法はこちらを参考にしました。

www.home-assistant.io

ここにdocker-compose.ymlの内容が書いてあります。多分、上のHomebridgeのインストールに使ったファイルに、ここに書かれているhomeassistantの部分を追加すれば良いはずです。以下の太字の部分を追加しました。

version: '2'
services:
  homebridge:
    image: oznu/homebridge:ubuntu
    container_name: homebridge
    restart: always
    network_mode: host
    environment:
      - HOMEBRIDGE_CONFIG_UI_PORT=8581
    volumes:
      - ./homebridge:/homebridge
  homeassistant:
    container_name: homeassistant
    image: "ghcr.io/home-assistant/home-assistant:stable"
    volumes:
      - /PATH_TO_YOUR_CONFIG:/config
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    privileged: true
    network_mode: host

これで、

docker-compose up -d

コマンドを動かした後、http://xxx.xxx.xxx.xxx:8581/に接続したところ動いてました。

まとめ

UbuntuにDockerを入れて、その上にコンテナとしてHomebridgeとHome Assistantをインストールしました。Home Assistantはイメージとしてインストールするのが推奨されているようなので、他のサーバも同居させるためには仮想マシンかDockerを使うのが良いと思いました。

今後、mosquittoやzigbee2mqttなども使う予定ですが、これらのサーバは、従来通り、大元のUbuntuにインストールする予定です。HomebridgeやHome Assistantはwebからのインタフェースが充実してますが、mosquittoなどは設定ファイルやログファイルを見る必要があるので、従来通りの運用が楽かと考えています。

格安のHomeKit対応WiFi 100Vスイッチ

Apple HomeKit (HAP) に対応した、WiFi接続するAC 90~250V用スイッチユニットがAliExpressで売られてました。送料込み672円と格安でしたので、試しに使ってみました。専用アプリでWiFiとHomeKit有効化を設定する必要がありますが、設定が終了すればHomeKitから安定して使用できました。

s.click.aliexpress.com

外観と内部構造

外観は小さな小箱で、左右にねじ止め端子の部分が用意されています。左右のそれぞれが入力・出力で、LとNの表記があります。ここに電源・器具の電圧線と中性線をそれぞれ取り付ければ良いようです。端子部分にはカバーもついてます。端子カバーを外すと、ねじ止めのターミナルがあります。ちょっと斜めに取り付けられてますが、半田付けはしっかりしてました。端子カバーもねじ止めできて、カバーの縁で配線を抑えられるように工夫されてます。よくできていると思いました。

本体とカバーは、ねじ止めではなくてはめ込みですが、ギターピックのようなもので簡単に開けられます。メインの基板には10Aのリレーが乗ってます。

ちょっと気になったのは、リレーが中性線側に入っていることです。電圧線側は常時直結されてます。こんな感じです。

電圧線側を遮断してくれた方が、出力側での感電の心配が少なくて良いように思いましたが、こういうものなのでしょうか?LとNは多分どちらに繋いでも良いと思うので、気になる場合は逆に接続しても良いかもしれません。もっとも、日本のアース無しコンセントや引掛シーリングに接続する場合は、どっちの配線がNまたはLになるのか不確定なので、どっちでも良いことではあります。

無線ユニットは、メイン基板に垂直に立てられてます。型番までは読めませんでしたが、Espressifのロゴと社名が読み取れます。

後ろに見えている黒い棒は、on/off/resetスイッチです。ケースの穴から飛び出しているので、外から操作できます。短く押すと手動でon/offし、5秒以上長押しすると工場出荷時状態にリセットされて設定可能になります。設定可能になると基板上のLEDが点滅を繰り返します。

専用アプリで設定

設定するにはiOSまたはAndroid用の専用アプリ、「DoHome」が必要です。アプリストアから入手できます。使用開始するにはメールアドレスを登録しないといけませんが、確認メールが来るわけでは無いので、出鱈目でも良いかもしれないです。それが分かってなかったので、macOSの「メールを非公開」機能で作成した捨てアドレスを使いました。

IoTガジェットを買うたびにメールを登録しないといけない風潮はなんとかしてほしいと思います。いろんなIoTデバイスやネット上のサイトでメールアドレスを聞かれる機会が多いので、「メールを非公開」機能はOSが捨てアドレスを管理してくれて便利です。

設定手順は、

  1. ボタン長押しして、LEDが点滅する状態(工場出荷時状態)にする
  2. スマホを2.4GHz WiFiに接続しておく
  3. DoHomeアプリを起動してスマートプラグ追加ボタンを押す
  4. スマホWiFi設定画面に切り替えてDoHome_XXXXというSSIDを見つけて選択する
  5. DoHomeアプリに戻って、接続が終了するまで待つ

です。これでDoHomeアプリに登録され、デバイスのアイコンが現れます。このアイコンを長押しすると、詳細設定が現れます。この中に、「HomeKit mode」という設定があるのでこれをonにしておきます。ちなみにその下の下にあるPowerup stateは、電源が再投入された時の動作を指定できます。停電から復帰した時や、大元のスイッチが操作された時の動作を、ここで指定できます。

ここまで設定できたら、このアプリを使うことはないので、捨ててしまっても良いでしょう。あとはiPhoneのホームでアクセサリを追加するだけです。コードは12345678です。

これでiPhone/Macから問題なく使えるようになりました。

格安スマートシーリングライトを作る

形状から、この製品は何かに組み込んでDIYするのに適していると思います。コンセントに接続する器具、例えばテーブルランプとか炬燵などが対象なら、電源プラグアダプタ型のスマートプラグの方が簡単です。

この製品は、電源プラグの無い(電源に直結する)器具に組み込んで、HomeKit対応させる部品として使うと良いかと思いました。そう考えると、シーリングライトの改造が最適かと考えました。

探してみましたが、HomeKit対応のシーリングライトは少し前に販売されていたものの、3万円近くして、今は品切れでした。HomebridgeやHome Assistantから使えるWiFi対応のシーリングライトも1万円近くします。それに対して、赤外線やBluetoothのリモコンがついただけのシーリングライトなら、3000円程度で多数販売されていて選択肢が多いです。これが700円の部品追加でHomeKit対応シーリングライトに改造できるので、素晴らしいのではないでしょうか。ということで、かなり以前に3000円で買ったシーリングライト

に、本機を取り付けました。このシーリングライトはリモコンが赤外線ではなくて無線(Bluetooth LEかな?)です。Nature Remoなどの赤外線コントローラが使えなくて、スマート化できなくて困ってました。開けてみると、結構な空きスペースがありましたので、ここに取り付けることにしました。

ただ、実物を当てて確認したら、中央にある照明器具取り付け用蝶ネジが意外と場所を取り、これが当たります。そこで、これも昔買ってお蔵入りになっていた、両面テープ付き磁石・鉄板を使って固定することにしました。照明器具を取り付けるときは磁石から離してネジを回すスペースを確保して、ネジを止めてから磁石で取り付けます。元々はスマホを車のダッシュボードなどに固定する目的の磁石なので、磁石も両面テープもかなり強力で外れる心配はありません。

蛍光灯をLEDに改造するついでに組み込む

以下の記事では、古い照明器具の蛍光灯を蛍光灯型LEDに交換しました。その際に、安定器などを取り外して空いたスペースにこのスイッチを組み込みました。古い昭和な照明器具が、見た目そのままでスマート照明に生まれ変わります。

diysmarthome.hatenablog.com

まとめ

AliExpressで格安で販売されていたHomeKit対応のスイッチデバイスを試しました。専用アプリでの設定が必須ですが、一旦設定すればHomeKitアクセサリとして安定して動作します。

これを市販のLEDシーリングライトに組み込んで、格安スマートライトをDIYしました。HomeKitからはon/offしかコントロールできませんので、明るさ調整したい場合は、onにして製品付属リモコンで設定します。以前から明るさ調整機能をほとんど使わなかったので、このシンプルな運用で十分でした。

Intel NUCにHome Assistantをインストールする

普通のWindows用小型デスクトップPCであるIntel NUCに、Home Assistantをインストールしました。初めて使うHome Assistantなので、いまだに使い方が良くわからないのですが、とりあえずはESPHome使ってLチカしました。Home AssistantはHomeKitブリッジとして使えるので、ESPHomeで作ったデバイスiPhone/Macのホームからも利用できました。

Intel NUCをサーバにする

Home AssistantはRaspberry Pi 4をサーバにしての動作例が多いです。でも手持ちのRaspberry Pi 4が故障してしまい、予備も無く、昨今の品不足で手に入らなくなってしまいました。それでお蔵入りだった初代Intel NUC DC3217IYEを引っ張り出しました。メモリは8GB、SSDはmSATAの64GB、CPUはCore i3-3217Uを搭載してます。現在、Homebridgeを動かしているマシンも同じ機種で、さらに1台予備があったのでそれを使いました。

ケースや冷却がしっかり作られた汎用コンピュータは、常時電源入れっぱなしのサーバーとして、Raspberry Piよりも適しているのではと思い始めてます。昔のCore i3ですが、それでも処理速度はRaspberry Pi 4の2倍くらいはありますし、mSATA SSDはSDカードより堅牢です。消費電力は多少多いですが、Macbook Airなどに搭載されているモバイルCPUシリーズなので省電力です。Raspberry Pi 4と比較すると、2.5倍程度の消費電力になります。具体的には、Raspberry Pi 4だと年間400円くらいの電気代が、1000円になる程度の差です。

初代Intel NUCは、中古でしか入手できませんが(7000円くらい)、品不足のRaspberry Piよりも入手容易かもしれないです。この機種以外にも、似たようなスペックの小型省電力中古デスクトップPCはたくさんあるので選択肢も多いです。Intel NUC以外にも、HPのEliteDesk、DellのOptiPlex、LenovoのThinkCentreなどの小型モデルが、スマートホームサーバーに向いていると思います。中古と新品の価格を比較するのはフェアでは無いですが、古い中古ならばRaspberry Pi 4の8GBモデルとあまり変わらない価格で入手できます。

汎用x86-64版を導入

汎用PCを使うので、Home Assistantも汎用x86-64版を使います。home-assistant.ioのサイトから、Generic x86-64のページに行き、その内容に従ってインストールします。

Home Assistantは、Linuxからaptコマンドなどを使ってコツコツインストールするのではなく、イメージを使ってインストールする方法を推奨しているようです。その方が問題が発生しにくいのは確かです。なので、

  1. OS込みのディスクイメージをボリュームに書き込む
  2. イメージをKVM, VirtualBox, Vmwareなどの仮想マシンで使う
  3. イメージをDockerなどで使う

などの方法が最初に書かれてます。WindowsMacで可能なのは2の方法だけです。3の方法は、主にQNAPなどのNASで使うことを想定しているようです。WindowsMacでネイティブに動くバージョンも配布しているHomebridgeに比べると割り切った実装です。今回は、休眠マシンを使うこともあり、ハードウェアを贅沢に使う感じの、1の方法でインストールしました。

まずは、Intel NUCのSSD (容量は64GB) をmSATAソケットから取り外し、mSATA - SATA変換基板に取り付け2.5インチSSDの形状にして、USB接続HDDケースに入れて、これをMacに取り付けました。MacからはUSB接続SSDとして認識されました。

次に、Home Assistantのページの記述に従って、Balena EtcherソフトウェアMac版をダウンロードして起動します。そして、Flash from URLを選んでページに書いてある最新のイメージのURLを指定します。

https://github.com/home-assistant/operating-system/releases/download/8.5/haos_generic-x86-64-8.5.img.xz

最後に書き込み先のドライブとして、USB接続したmSATA SSDを指定して、Flash!ボタンを押します。

この結果をディスクユーティリティで確認すると以下のようになってました。

このSSDを、元のIntel NUCのmSATAソケットに戻して、電源を入れればHome Assistantが起動します。この先はNUCをディスプレイ無しで運用する予定ですが、最初の起動だけはディスプレイに接続して動作を確認しました。

ここに書かれているように、http://homeassistant.local:8123に接続すれば、webページが開き、設定と操作が全てできるようになります。初めて使うHome Assistantでしたし、機能が豊富で複雑なので、色々試行錯誤しながら設定していきました。正直なところとても難しいです。

ESPHomeを使ってLチカする

まずは初心者向けに、LEDの点滅(Lチカ)でもやってみようと思いました。以前にコマンドラインから使ったESPHomeを、

diysmarthome.hatenablog.com

ご本家のHome Assistantで使ってみます。前回と同様にGPIO 13番ピンにLEDを取り付けたESP32開発基板を用意しました。これをHome Assistantが動いているIntel NUCのUSBポートに接続します。「設定」「アドオン」から「アドオンストア」に行ってESPHomeの通常版を導入します(他にベータ版や開発版がありました)。すると、「設定」「アドオン」にESPHomeが現れるので、開きます。

ここで「WEB UIを開く」を押したら、ESP32にプログラムをダウンロードできるようになりました。USBに接続したESP32に名前をつけて、以下のようなyamlファイルを作りました。内容は前回の記事のyamlとほぼ同じですが、今回はHome Assistantからも使えるように、apiを有効にしてあります。MQTTの設定は残してありますので、MQTTメッセージも流れます。

apiのkeyは自動的に作成されました。WiFiやMQTTのIDとパスワードなどは動かす環境に合わせて設定します。

esphome:
  name: espled

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

ota:
  password: "xxxxxxxxxxxxxxxxxx"

wifi:
  ssid: "xxxxxxxxx"
  password: "xxxxxxxx"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "espled Fallback Hotspot"
    password: "xxxxxxxx"

mqtt: 
  broker: 192.168.xxx.xxx
  username: xxxxxxxx
  password: xxxxxxxx
switch: - platform: gpio pin: 13 name: 'blue_led' captive_portal:

この後、「設定」「デバイスとサービス」のページで、完成したESP32を「ダッシュボードに追加」できます。その結果、「オーバービュー」のページに、このデバイスがスイッチとして現れました。操作するとESP32のLEDが点灯、消灯します。

前回の記事と同じですが、Homebridgeにはmqttthingプラグインが入れてあります。今回のyamlファイルに合わせて設定すると、Homebridgeのconfigファイルのmqttthingプラグインの部分は以下になりました。MQTTブローカーはHomebridgeと同じマシンで動いているので、こちらのIPアドレスlocalhostになってます。topicsはyamlファイルに現れる名前をつなげたものです。topics名が不明な場合は、Home AssistantでESP32を操作しながら、topicsの上階層(例えばespled/#)をサブスクライブすれば、topics名を知ることができます。

{
"type": "lightbulb-OnOff",
"name": "Blue LED",
"url": "mqtt://localhost:1883",
"username": "xxxxxxxx", "password": "xxxxxxxx", "topics": { "getOn": "espled/switch/blue_led/state", "setOn": "espled/switch/blue_led/command"
}, "onValue": "ON", "offValue": "OFF", "accessory": "mqttthing" },

その結果、iPhone/Macのホームに、MQTT連動した電球アクセサリが現れました。これはESP32がパブリッシュするMQTTメッセージに連動して表示が変化します。また、電球アイコンをクリックすれば、HomeKit側からもESP32のLEDを点灯・消灯できます。

HomeKitと連動する

Home Assistantの初期設定の過程で、おそらくHomeKitプロトコルが動いていることが検知された結果だと思いますが、HomeKitブリッジとして機能させるかどうかを聞かれました。設定したところ、HASS Bridge:XXXXXという名前で、Home AssistantがHomeKitのブリッジとして動き始めました。「設定」「デバイスとサービス」を見ると、「統合」のタブの場所にブリッジが現れています。

この後、Home Assistantの「通知」に現れるQRコードを使って、iPhoneのホームからブリッジを追加しました。すると、Home Assistantで作ったデバイスが、HomeKitのアクセサリとして現れるようになりました。ここで作ったESP32も表示されました。この結果、同じESP32が、MQTTブローカー経由と、Home Assistant経由で、それぞれ表示されました。

左がMQTT経由、右がHome Assistant経由のESP32です。違う経路でHomeKitに接続されていますが、同じデバイスなので、どちらかをon/offすると、もう一つも連動してon/offします。

まとめ

Home Assistantを初めて使ってみました。半導体不足の影響でRaspberry Piが入手できないので、お蔵入りしていた小型デスクトップコンピュータにインストールしました。Raspberry Piじゃ無くてもこれで良いように思いました。

慣れていないこともありますが、Home AssistantはHomebridgeに比べて複雑で、使い方がいまだによくわかりません。HomeKitを使う前提ならば、Homebridgeをメインに使っていくのが簡単で良いと思います。一方で、Home Assistantの高機能を活かせる用途では、そちらで設定をして、ブリッジ機能を使ってHomeKitから使用するのも良いと思いました。例えば今回試したESPHomeを使えば、Home Assistantでの開発とテストが容易です。なので、MQTTでも動くように設定しておけば、HomeKitから直接使用できて便利かと思います。

中性線なしで使えるZigbee壁スイッチをHomeKitで使う

AliExpressでZigbee方式の壁スイッチを買ってみました。Zemismartという会社の物理スイッチ方式の製品です。設置したところ、中性線の配線無しでLEDシーリングライトをon/offでき、またZigbee2MQTTとHomebridge経由でApple HomeKitから使用することができました。 こちらの製品です

壁スイッチのスマート化

既存の部屋照明をスマート化するにあたっては、壁スイッチを対応製品に交換するのが理想的かと思います。引掛シーリングや電球をスマートホーム対応製品に交換する方式は簡単ですが、残された壁スイッチでoffにされてしまうとシステム側から点灯できなくなります。またリモコンの赤外線信号でコントロールする場合、on/offボタンがトグル式であることが多く、その場合on/offの状態把握ができません。壁スイッチをスマートホーム対応製品に交換すれば、このような問題は全て解決します。

パナソニックの製品

国内で販売されていて、技適にもPSEにも承認された壁スイッチは、パナソニックのリンクモデルとリンクプラスという製品しか見当たりません。リンクモデルは古い製品で920MHzの電波を使っているようです。リンクプラスは新しい製品でBLEを使っているようです。次に説明する中性線問題にも対応しているので、低電力なBLEのリンクプラスを選択すべきです。また、どちらもEchonet liteに対応したブリッジがあるので、Home AssistantやHomebridgeから使用可能と思われます。価格は、1 Gang 壁スイッチが15,000円、ブリッジが32,500円、実売価格はセットで3万円くらいです。

www2.panasonic.biz

ただ、値段が高いのは致し方ないとしても、実は上記のサイトでアナウンスされているように、現在販売されていません。売れなかったので販売中止したのか、半導体不足で生産できないのか、はたまたMatter対応機を準備していてそれに切り替えるためなのか不明ですが、どこの販売サイトでも入荷未定な状態で購入することができません。

国内製品が壊滅状態なのに対して、AmazonやAliExpressなどでは、多数のスマート壁スイッチが安価に売られてます。それを試してみることにしました。

中性線が無い問題

既存の壁スイッチをスマートホーム対応製品に交換する場合に問題になることは、壁スイッチの場所に中性線が来ていないことです。家の中の単相電力線は、電圧がかかった電圧線と、外の変圧器で接地されている中性線の対で配線されてます。日本の一般的な照明配線では、壁スイッチに電圧線が、照明器具に中性線が配線されています。そして壁スイッチと照明器具が別の配線で接続されてます。

稀に、壁スイッチの場所にも、中性線が配線されていることもあります。スイッチに常時点灯するパイロットランプが付いている場合や、スイッチがコンセントと合体しているような場合です。中性線が配線されていれば、コンピュータ内蔵のスマートスイッチに置き換える場合に、コンピュータ用の電源を確実に得ることができます。

中性線が無くてもなんとかする方法

中性線が来ていなくても、電力を得ることは不可能ではありません。例えば下図のように配線すれば、スイッチがoff/onのいずれの場合でも、多少の電力を得ることができます。照明器具には、スイッチoffの場合に微弱な電流が流れてしまいますし、onの場合には供給電圧が低下してしまいます。また、照明器具が接続されていなかったり、省電力タイプの器具でインピーダンスが高い場合は、電力が得られずコンピュータが動作しない可能性もあります。


照明器具に流れる電流が足りない場合は、コンデンサを並列に入れて電流を増やす手法も使われます。コンデンサに電流が流れますが、電流と電圧との位相が違うので、コンデンサ部分での電力消費はありません。コンデンサを使う手法は、スマートスイッチだけでなく、蛍スイッチ(offの時にランプが灯るスイッチ)を使う時にも昔から使われていたようです。

スマート壁スイッチ製品の電源方式

AliExpressなどで多数販売されているスマート壁スイッチを調べてみました。接続は、WiFiZigbeeが多いようです。BLEは見当たりませんでした。電源の取り方については、

  1. 中性線が必須の製品
  2. 中性線無しでも使えるけどコンデンサが必要な製品
  3. 中性線も不要で追加のコンデンサも不要な製品

の3種類があるようです。中性線不要かつコンデンサ不要な製品は、省電力である必要があるため、WiFi方式ではなくZigbeeで通信する製品だけでした。今回試したZemismartの製品もZigbee接続です。販売サイトの説明では、中性線有りでも無しでもどちらでも動いて、中性線なしの場合もコンデンサは不要と紹介されていました。使用例の写真を見ると、Neutralの端子にはOptionalと書かれていて、中性線有無のどちらにも対応しているようです。

物理スイッチがあって、中性線不要・コンデンサ不要な製品は少ないので、1 gangバージョンを購入して試してみることにしました。

HomeKitへの接続方法

Zemismart壁スイッチは、本来はTuyaのZigbeeハブを併用することでLANに接続し、Tuyaのクラウド経由でAlexa, Googleから使う製品のようです。その場合、Tuyaが配布しているHomebridgeプラグインを使って、HomeKitからも使用できるはずです。

diysmarthome.hatenablog.com

しかし、販売ページを見るとZigbee2MQTTで動いたというコメントがありました。なので、Tuyaのハブやクラウドを使わなくても、Homebridgeから直接使えそうです。

マニュアルを見る

製品には、紙一枚のマニュアルが付いています。それを見ると、「スイッチの動作には中性線が必要」って書いてありました。とはいえ、実際の本体裏側にはやはりNeutral (Optional)と書いてあります。マニュアルのバージョンと製品バージョンが違うのかもしれません。また、販売サイトには、中性線で配線した方が安定するという書き込みもありました。使ってみないとわからないところかもしれません。

また、本体裏側にはAC 110V~240Vと書いてありましたが、マニュアルにはAC 100V~250Vと書いてあります。こちらはマニュアルを信じて楽観的に行きたいと思いました。

分解してみる

ネジを外すと簡単に開けられる構造だったので、中を確認しました。高電圧交流回路部分と、低電圧コンピュータ回路部分が別のユニットになっていて、コネクタで接続されています。どちらのユニットも白塗りの綺麗な基板で、間には絶縁用のプラスチック板が挟まっています。合理的で丁寧に作られている様子で安心できました。低電圧部分の基板の写真を以下に示します。

右下にあるパーツは、ESP8266のようです。

ネットで検索したところ、この配線を調べて、ESP8266をESPHomeでプログラムしなおしたという人がいました。

community.home-assistant.io


ESPHomeで使う場合は、接続はWiFiになります。ESPHomeならばMQTTも使えるので、汎用性は高いかと思いました。ただ、Zigbeeよりも電力を使うことになるかと思うので、この改造をするなら中性線配線が必要になるかもしれません。

古い壁スイッチを置き換える

今まで使っていたパナソニックの古い壁スイッチを外して、このスイッチに置き換えました。中性線は来ていない場所です。この製品はUS仕様ですが、壁の穴の形状・サイズ、2箇所の取り付けネジの位置は、US仕様と日本仕様で全く同じです。なので、ねじ止めし直すだけで交換できます。

壁に対する加工は不要なので、賃貸物件にお住まいの方も、現状復帰が可能です。ただ、日本の壁スイッチにはVVF線の被覆を12mmくらい剥いて差し込むのが普通ですが、このスイッチのターミナルの奥行きはもっと短くて7mmくらいです。なので古いスイッチを取り替える際には、銅線を5mmくらいカットして、接続しました。現場復帰する場合は、被覆をまた5mmくらい追加で剥がす必要があります。

この壁スイッチの先に接続されている照明器具はYeelingのLEDシーリングライトです。手動でon/offしたところ、問題なく点灯・消灯しました。中に電磁リレーが入っているようで、on/offするとカチッと音がします。他のLEDシーリングライトも試しましたが、同様に動作しました。中性線無し・コンデンサー無しでも、ちゃんと動いているようでした。

Zigbee2MQTTで動かす

次に、いよいよZigbee2MQTTとペアリングします。様子を確認するために、Homebridgeサーバー側で、

mosquitto_sub -h localhost -t zigbee2mqtt/# -v

のようにして、MQTTをメッセージをモニターしました。マニュアルによると、スイッチを15秒間長押しするとペアリングモードに入ると書いてあります。実際には数秒でLEDが点滅を始めてペアリングが開始しました。Zigbee2MQTTでサポートされていたようで、問題なく認識されました。MQTTから以下のようにIDを指定してpubすると、壁スイッチをon/offできます。トピックスの中の0xffffffffffffffffの部分は、サブスククライブの結果に表示されている、製品固有のZigbee IDを入れてください。

$ mosquitto_pub -h localhost -t zigbee2mqtt/0xffffffffffffffff/set -m off
$ mosquitto_pub -h localhost -t zigbee2mqtt/0xffffffffffffffff/set -m on

ペアリングが終了すると、Zigbee2MQTTプラグインを入れたHomebridgeにも自動的に登録されます。これにより、iPhoneMacのホーム.appにスイッチのボタンが自動的に現れ、操作できるようになりました。初期名前はZigbeeのID番号で、アイコン形状はスイッチだったのですが、名前を「あかり」に、アイコンを電球に変更しました。

追記:MQTTのログを見ると、TuYaのこちらの製品の互換製品のようです。

まとめ

AliExpressでZemismartという会社のZigbee接続壁スイッチを購入したところ、Apple HomeKitで問題なく動作しました。LEDシーリングライトと一緒に使った限りでは、中性線無しで動作しました。古い壁スイッチをスマート化するのに適した製品だと思います。白くて角が丸いデザインが、日本の家でよく見かけるPanasonicの現行製品(コスモワイド埋込スイッチ)と似ているので、雰囲気を合わせやすくて良いと思いました。

FFmpegを導入してHomeKitからwebカメラを使う

FFmpegは動画情報を変換したり転送するツールです。セキュリティカメラやビデオドアフォンを利用する上で必要になる場合が多いです。特にHomebridgeのプラグインなどのようにオープンソースのプロジェクトではほとんどFFmpegが利用されます。今回はMacUbuntuFFmpegをインストールして動作確認し、UbuntuのHomebridgeからUSBカメラを使ってみました。

Macにインストール

FFmpegって動画ファイル変換ソフトかと思ってたのですが、とても多機能なツールだったんですね。まずは手近なMacで使ってみました。MacFFmpegを使うためにはHomebrewを使います。Homebrewをインストールした後で、以下のコマンドでFFmpegをインストールできます。

% brew install ffmpeg

動作確認のためにバージョンを表示させました。

% ffmpeg -version

USBカメラ映像をMacで見る

次に、Macに接続された標準的なUSBカメラの映像を、FFmpegを使ってチェックします。Mac標準のPhoto Boothなどのアプリで確認できる映像をみようと思います。UVC(USB Video Class)という規格に対応したUSBカメラなら、Macの色々なアプリケーション、例えばMac標準のPhoto Boothなどで利用できます。Webカメラのほとんどが、またデジカメも一部がUVC規格です。試しに$15くらいのUSB接続顕微鏡を使ってみました。

検索してみると、macOSでは動画・音声の入出力に、avfoundationというフレームワークを使うようです。以下のコマンドでサポートされたデバイス名の一覧がわかるようです。

% ffmpeg -f avfoundation -list_devices true -i ""
[AVFoundation indev @ 0x7fd644104ec0] AVFoundation video devices:
[AVFoundation indev @ 0x7fd644104ec0] [0] USB2.0 Digital Camera
[AVFoundation indev @ 0x7fd644104ec0] [1] Capture screen 0
[AVFoundation indev @ 0x7fd644104ec0] AVFoundation audio devices:
[AVFoundation indev @ 0x7fd644104ec0] [0] USB2.0 Digital Camera
[AVFoundation indev @ 0x7fd644104ec0] [1] Built-in Input

接続したデバイスの名前は"USB2.0 Digital Camera"のようです。これがわかれば、ffmpegコマンドで動画データを扱えます。まずは、ffmpegコマンドの仲間の、ffplayというコマンドを使ってみます。ウィンドウが開いて動画が見られるので動作確認に適してます。

% ffplay -pixel_format uyvy422 -framerate 25 -f avfoundation -i "USB2.0 Digital Camera"

これで画像が出ました。写っているのは100円玉です。上記のコマンド例では、pixel_formatとframerateオプションを追加してます。これらのオプションを指定しないデフォルト設定ではエラーが出たので、エラーメッセージに合わせてこの2つを指定しました。

ffmpegコマンドは、基本的にはビデオフォーマット変換アプリなので、USBカメラから得た動画を、ファイルに保存します。以下のコマンドでQuickTimeで開けるファイルが完成します。キーボードのQを押すと動画取り込みを終了します。

% ffmpeg -pixel_format uyvy422 -framerate 25 -f avfoundation -i "USB2.0 Digital Camera" -pix_fmt yuv420p output2.mp4

結果のファイルをダブルクリックするとQuickTime Playerがファイルを開いてくれます。最後のパラメータはファイル名です。その前にpixel_formatを指定しています。こちらの指定は、出力フォーマットの指定です。これがなくても動画ファイルは作成されますが、その場合、QuickTime Playerでは再生できません。VLCなどの動作再生アプリなら開けます。QuickTime Plaayerで再生するためには、yuv420pに変換しておく必要がありました。

USBカメラ映像をUbuntuで見る

次に、Homebridgeを動かしているUbuntuマシンでもFFmpegを動かします。こちらは

apt install ffmpeg

コマンドでインストールしました。ちなみにRaspberry Piでも同様にffmpegをインストールできました。ここではUbuntuマシンで説明しますが、Raspberry Piでも同様です。

UbuntuマシンにUSBカメラを接続すると、/dev/video0に接続されました。これをffmpegコマンドの入力に指定します。ただ、/dev/video0のユーザ:グループは、root:videoになっていて、それ以外のユーザは読み込みが許可されていませんので、変更する必要があります。今回は、自分のアカウント(以下の例ではfoo)と、Homebridgeを実行するときに使用されるアカウントhomebridgeを、videoグループに割り当てました。/etc/groupの該当する行を以下のように書き換えます。

video:x:44:foo,homebridge

こうして/dev/video0を読める設定にしておけば、以下のコマンドでUSBカメラの映像を動画ファイルに保存することができます。

% ffmpeg -i /dev/video0 -pix_fmt yuv420p output.mp4

UbuntuにもGUI環境をインストールしておけばffplayコマンドで確認できたのかもしれません。しかしサーバーとしてGUIなしで動かしているので、ファイルを転送してMacで動作確認しました。これでFFmpeg動作を確認できました。

HomebridgeでUSBカメラを使う

Apple HomeKitでは、セキュリティカメラやビデオドアフォン(英語ではビデオドアベルというらしいです)の映像を利用できます。HomebridgeではFFmpegで取得できる動画データを、HomeKitで利用できるように提供するプラグインが用意されています。その中の一つ、Homebridge Camera FFmpegを使用しました。

github.com

これをインストールして、ffmpegの設定をすると、コンフィグファイルに以下の記述が追記されました。名前はMicroscopeとしました。

{
    "name": "Camera FFmpeg",
    "cameras": [
        {
            "name": "Microscope",
            "videoConfig": {
                "source": "-i /dev/video0"
            }
        }
    ],
    "platform": "Camera-ffmpeg"
}

その結果、iPhoneMacのホーム.appの画面に、以下のように動画が現れます。

この画面には、最後に取得された動画が静止画として表示されてます。この画像をクリックすると、全画面表示になり、現在の動画が表示されます。

以上はUbuntuでHomebridgeを動かしている場合です。Raspberry Piへのインストール方法が以下のサイトで説明されていましたが、こちらも同じような手順でした。github.crookster.org

エラーへの対応

以上で、大体すんなり動くのですが、たまにエラーが出て、ライブ映像が表示できなくなる場合がありました。Homebridgeのwebページのログに、「デバイスがビジーである」というようなメッセージも出ます。/dev/video0が、他のプロセスに使用されていて使えないという意味です。このような場合は、fuserコマンドをルート権限で使用すると、様子がわかります。

$ sudo fuser /dev/video0
/dev/video0:          1257m

ライブ映像を表示していない時は、video0は誰も使用していないはずなのですが、プロセスIDが1257番のプロセスが使用し続けているようです。psコマンドで調べると、

$ ps -aux | grep 1257
homebri+    1257 99.5  0.1  66008  8236 ?        R    17:49   2:44 /var/lib/homebridge/node_modules/homebridge-camera-ffmpeg/node_modules/ffmpeg-for-homebridge/ffmpeg -i /dev/video0 -frames:v 1 -f image2 - -hide_banner -loglevel error

homebridgeが使っているようでした。試行錯誤して、動画が表示されなくて、homebridgeを再起動したりした場合に、発行済みのFFmpegプロセスがそのまま残ってしまうようです。この場合は、sudo kill 1257で中断することで正常に動くようになりました。

まとめ

USB接続カメラからの動画データをFFmpegを使って取り込み、HomeKitでカメラ画像として使用できることを確認しました。今回使用したHomebridge Camera FFmpegプラグインは、機能豊富で、MQTTブローカーとの連携機能もあります。MQTT経由でモーションセンサや呼び鈴ボタンのイベントを受け付けることができるので、センサ付きセキュリティカメラやビデオドアフォンとして機能させることができます。Homebridgeサーバに安価なUSBカメラを取り付けるだけでサーバ周辺の映像を世界中から確認できるのは便利かと思いました。

ただ、エラーで止まってしまったときの対応が面倒なので、あまり実用的ではないかもしれません。RTSPプロトコルを使ったIPカメラの方が使いやすいかと思います。そのうち試したいと思ってます。