Smart HomeをDIYする

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

品薄Raspberry Pi 4が買えたのでHomebridgeを引越した

ずっと品切れだったRaspberry Pi 4が入手できたので、

をインストールしました。補助記憶にはUSBメモリを使い、電源とファンも強化しました。

Homebridgeサーバ遍歴

Homebridgeなどのサーバー用に、最初はRaspberry Pi Zero Wを使ってました。実用的に動作しましたが、再起動に時間がかかるので、後にRaspberry Pi 4 (2GB)に移行しました。起動が高速になって快適でした。Homebridgeの使用メモリは0.4GBくらいなので2GBで十分でした。

そのRaspberry Pi 4が、半年前くらいに起動しなくなりました。またSDカードの破損だろうと思ったのですが(SDカードの破損は3回以上経験してます)どうも違うようです。起動プロセスの最後の方で停止してます。ビデオチップの故障のような気がしました。

しかし、半導体不足により品薄になってしまったので、新しいRaspberry Pi 4が買えず、Intel NUCにUbuntuをインストールしてHomebridgeを使ってました。Intel NUCはそれなりに調子良く動いていました。

品薄だけど買えた

そうしていたら、たまたまタイミング良くRaspberry Pi 4を買うことができました。しばらく前からスイッチサイエンスでRaspberry Pi 4 (4GB)の入荷お知らせメールを申し込んでいました。どうせ買い換えるなら、メモリ容量を増やしてみようかと思いました。ただ人気のようで、連絡メールに気づいてもすでに売り切れていることばかりでした。今回は、たまたますぐにメールに気づき、購入できました。4GBモデルの在庫を確認したところ、メールが来てから5分後には品切れになってました。

世の中では、Homebridgeを動かすためにRaspberry Piを使うケースが多いです。Raspberry Piで色々な動作検証をした方が有用なブログ記事になると思い、Homebridgeを引っ越すことにしました。ということでRaspberry Piに出戻りします。

記憶媒体USBメモリ

SDカードが何度も壊れたので、USBメモリを使いました。今までの経験では、USBメモリよりもSDカードの方が壊れやすいと思ってたのですが、ネットで探したところではそのような話は書かれてませんでした。しばらくはUSBメモリを使って、耐久性の問題があれば、次はUSB経由のSATAドライブを試したいと思います。

以前は、Raspberry PiをUSB起動させる設定がすごく面倒でした。でも最近のファームウェアではデフォルトで起動可能になってます。そこで、小型USB 3.0メモリで、信頼できそうなブランド品を探しました。

小型で出っ張りが少なく隣接のUSBソケットの邪魔にならず、それでいて楽に抜き差しできる引っかかりもあります。Raspberry Piの同じサイドにあるUSBコネクタやEthernetコネクタの出っ張りに比べるとかなり短いので、もう少し大きめのUSBメモリでも良かったかもしれません。

SDカードに比べて信頼性が上がると共に、速度にも期待しました。それで、Raspberry Pi用に使用する前に、macOSのAmorphousDiskMarkというソフトでベンチマークしてみました。今まで使用していたTranscendの業務用と言われてた

  • SDカードが、Read 24 MB/s, Write 13 MB/s

だったのに対して、同じ条件で、

でした。時間がかかっていた再起動はほとんどRead動作だと思うので、速度向上が期待できます。

余談ですが、このSDカードのベンチマークはなかなか優秀で、USB 2.0のUSBメモリを使うとここまでの速度は出ません。なので、速度を改善する目的でUSB起動を行うなら、USB 3.0ポートのあるRaspberry Pi 4を使う必要があると思いました。USB 2.0しか搭載していないRaspberry Piだと、速度向上のメリットは無いと思います。SDカードって意外と高速で優秀だったんですね。

このSanDiskUSBメモリAmazonレビューを見ると、大きなサイズのファイルを2分間くらいにわたって書き込み続けると、発熱で速度が落ちると書いてあります。確かに、次に説明するHomebridgeイメージを書き込む作業では、そこそこ熱くなってました。でもHomebridge動作中は、ほんのり温かい程度の発熱です。発熱に関しても、今後の様子を見てみようと思います。

Raspberry Pi Imagerで起動USBを作る

USBメモリにも、SDカードと同様にRaspberry Pi Imagerでインストールできます。

www.raspberrypi.com

Raspberry Pi Imagerの「OSを選ぶ」から、Homebridgeを選びます。

右下の歯車アイコンを押すと、起動の設定ができます。ディスプレイは接続しない予定なので、sshを有効にしておきます。スクショでは選択していませんが、公開鍵認証のみにしておきました。ユーザ名もいつも使っている名前にしました。セキュリティも上がるし、sshするときにユーザ名を入れなくて良いので楽です。またここで、時差を設定しておけばログの日時などが日本時間になるので楽です。Ethernetを使う予定ですが、バックアップとして2.4GHzのWiFiも設定もしました。

「ストレージを選ぶ」からUSBメモリを選んで、「書き込む」ボタンを押せば作成終了です。Homebridgeを書き込んだUSBメモリを入れてRaspberry Piを起動します。

固定アドレスにする

これで、適当なブラウザからhttp://raspberrypi.local:8581を開けば、Homebridgeを使用できます。

デフォルトではアドレスをDHCPで取得してます。MQTTブローカなどを起動するので、固定アドレスにしておきたいです。そこで、Homebridgeの設定を進める前に、固定アドレスにしました。/etc/dhcpcd.confの

# Example static IP configuration:

のコメントのある付近を参考にして書き直します。

# Example static IP configuration:
interface eth0
static ip_address=192.168.xxx.xxx/24
static routers=192.168.xxx.1
static domain_name_servers=192.168.xxx.1 1.1.1.1 1.0.0.1

この後、dhcpcdを再起動したら、固定アドレスで動作しました。

$ sudo systemctl restart dhcpcd

バックアップから復元

ここまで非常に順調でしたので、このままIntel NUCの環境を移行することにしました。なので、Homebridgeのバックアップ機能を使って、今までのHomebridge環境の設定ファイルを新しいHomebridgeに移行しました。このように移行すれば、プラグインの復元と設定、ブリッジのIDなどが全て引き継がれます。HomeKitの再設定も不要です。ユーザ名とパスワードも引き継がれます。

しかしこれで再起動してもエラーが出ます。MQTTブローカとZigbee2MQTTが足りないからです。

Mosquittoのインストール

次にこちらに書いた手順で、MQTTブローカであるMosquittoをインストールしました。

diysmarthome.hatenablog.com

基本的には、aptコマンドでインストールするだけです。

sudo apt install mosquitto mosquitto-clients

また、OS起動時に自動的にMQTTブローカが立ち上がるように以下の設定をしました。

sudo systemctl enable mosquitto.service

Intel NUCの環境では、ユーザアカウント、パスワード付きで動作させてました。同じ設定を実現するために、古い環境(Intel NUCコンピュータ)から

  • /etc/mosquitto/mosquitto.conf
  • /etc/mosquitto/password.txt

の2個の設定ファイルをコピーし、Raspberry Pi 4に複写しました。

Zigbee2MQTTをインストール

次にZigbee2MQTTを、公式ページの手順に従ってインストールしました。

www.zigbee2mqtt.io

HomebridgeにはNode.jsが含まれているかと思ってたのですが、入ってませんでした。のでZigbee2MQTT公式ページの手順に従って、

sudo curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt install -y nodejs git make g++ gcc

としました。apt-getではなく、aptで統一しようと思っているので、aptを使いました。この後も公式ページの手順に従って、zigbee2mqttのディレクトリを作り、ユーザを設定して、

sudo mkdir /opt/zigbee2mqtt
sudo chown -R ${USER}: /opt/zigbee2mqtt

 Zigbee2MQTTのリポジトリをクローンしてディペンデンシーをインストールします(カタカナの意味がちょっとよくわかってないです)。

git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
npm ci
npm start

この後、/opt/zigbee2mqtt/data/configuration.yaml ファイルに設定を書きます。公式ページに説明があります。今回は、Intel NUCで設定した内容そのままなのでコピーすることにしました。yamlファイルだけでなく、Zigbeeバイスのデータベースも全て移動します。そのためには、/opt/zigbee2mqtt/data の中のファイルを全部持ってくれば良いです。(実際にはdataディレクトリの内容をtarでまとめて、scpでコピーしました。)これでペアリング済みのZigbeeバイスの情報が引き継がれるので、新たにペアリングする必要はないです。

最後に、systemctlコマンドでサーバとして起動させるために、/etc/systemd/system/zigbee2mqtt.service ファイルを作り、以下の内容にしました。Userの部分は、ログインしているユーザ名にします。Pi Imagerでユーザを指定した場合は、それに書き換えてください。

[Unit]
Description=zigbee2mqtt
After=network.target

[Service]
ExecStart=/usr/bin/npm start
WorkingDirectory=/opt/zigbee2mqtt
StandardOutput=null
StandardError=inherit
Restart=always
RestartSec=10s
User=pi

[Install]
WantedBy=multi-user.target

これで

cd /opt/zigbee2mqtt
npm start

とすると、いろいろ準備をしてくれた後起動するはずです。コントロールCで止めます。また、

sudo systemctl enable zigbee2mqtt.service

とすれば、以後、自動的に起動します。とりあえず起動しておきたいので、

sudo systemctl start zigbee2mqtt.service

としておきます。

Homebridge再構築に必要な作業

今回、Intel NUCで動作しているHomebridgeを、Raspberry Pi 4に移行しました。この際に必要だったインストール作業をまとめておくと以下です。将来何かトラブルがあって、Homebridgeを再構築する必要があったときに役立つかと思います。

  1. Homebridgeをインストールする
  2. Homebridgeを復元する
  3. Mosquittoを再インストールする。
  4. /etc/mosquittoにあるmosquitto.confとpassword.txtを復元
  5. Zigbee2MQTTを再インストールする
  6. /ope/zigbee2mqtt/data以下を復元

ということで、バックアップしておくと良いファイルは、

  • Homebridgeのバックアップアーカイブファイル
  • /etc/mosquitto以下の2ファイル
  • /opt/zigbee2mqtt/data以下の全ファイル

の3種類でした。

Raspberry Piの冷却

基板のままの状態でここまでの作業をしていると、Raspberry Piがとても熱くなってました。手で触ると、熱さでヒリヒリするくらいです。Homebridgeの設定ページの温度表示は60度近くになってます。心なしか動作が低下して、応答が途切れることもありました。不安定になっているようです。

試しに、USB給電の直径10cmくらいの扇風機で微風を当ててみたところ、温度はどんどん低下して37度くらいになりました。冷却は必須のようです。そこで、基板のまま使うのはやめて、今まで使用していたファン付きケースに入れました。こちらのケースです。

製品には小さなヒートシンクもついていますが、Raspberry Piの冷却には、ヒートシンクを使うよりも風を当てるのが効果的だと思います。このファンは5V用なのですが、前のRaspberry Piでは静音を狙って3.3Vで動かしてました。それも故障の原因だったかもしれません。今回は定格の5Vで動かすことにしました。ファンが小さいので、USB扇風機ほどの効果はありませんでしたが、それでも40度ほどで動作するようになりました。

Raspberry Piの電源

以前のRaspberry Pi 4では、Homebridgeのwebページに「電圧が低下した」という警告が出ることがありました。今回も、出力電流が2.1AのUSB電源アダプタに接続していたら、同様の警告が出ました。初期のUSB電源電力の規格は小さく、どのUSB電源でもRaspberry Piで使えるというわけではないようです。調べてみたところ、USB 2.0の電源電流規格は0.5A、USB 3.0, 3.1 Type-Aでも0.9Aらしいです。Type Cになっても、登場当時の5Vの電流は1.5Aで、後の規格で3Aになったようです。

Raspberry Pi 4には、5V 3Aくらいの電源が必要と巷では言われてます。(実測報告では1Aも必要なかったらしいですが)なので、電流容量の大きいUSB ACアダプタを使う必要があると思われます。手元のUSB電源アダプタを探ったら、Qualcomm quick charge 3.0対応のType-Aソケット式ACアダプタが見つかりました。これと同じものです。

quick chargeという規格は、Type-C PD (Power Delivery)と同様に、機器とネゴシエーションして電圧を上げて供給電力を増やす仕組みです。一見するとただのType-Aコネクタですが、対応デバイスには20Vまでの高電圧を出します。一方で非対応デバイスには5Vだけを供給します。ただquick charge 2.0以降ならば、5Vであっても、Type-C並に3A流せることになってます。

Raspberry Pi専用として売られている電源を買わなくても、入手が容易な、Type-C PD対応のUSB電源か、もしくはquick charge 2.0以降のUSB電源を用意すれば、必要とされる5V 3Aの電力を得られます。

まとめ

壊れてしまったRaspberry Pi 4の交換をしました。問題なく動作しています。Intel NUCを使った時の懸案事項だった、Zigbee2MQTTが10分おきにオフラインになってしまう問題も、発生しなくなりました。Raspberry Piは、もともとは教育現場で子供達が短時間使うために作られたコンピュータです。常時稼働させるためには、環境を整える必要があります。それで、記憶媒体はSDカードより堅牢と思われるUSBメモリにして、冷却ファン付きケースに入れて、電源も強化しました。

電気錠のJEM-A端子にESP32を接続してHomebridge / HomeKitで使う

玄関などの電気錠コントローラには、JEM-A端子がついていることが多いです。JEM-A端子は2値の入力と出力の端子を持つ日本電気工業会の標準規格です。この端子にESP32を接続して、MQTTブローカー経由でHomebridgeとインタフェースして、Apple HomeKitのLock Mechanismアクセサリとして動作させました。インタフェースさえ確立すれば、あとはAppleのアプリが適切に制御してくれます。

JEMA端子

エアコンについていたJEM-A端子を使う話をこちらに書きましので参考にしてください。

diysmarthome.hatenablog.com

以下おさらいです。JEM-A端子は、日本電機工業会規格(JEM)で定められた機器のオンオフの制御とその状態モニタを行う端子です。電気錠のほかに、エアコン、電動シャッター、床暖房、照明器具などに付いてます。4ピンの端子で、2本が制御信号、2本がモニタ信号です。おそらくは制御信号端子のところに押しボタンスイッチをつけて、モニター信号端子のところにLEDをつけて、人がスイッチを押すたびに、On/Offするようなアナログな仕組みを前提にしているのではないかと思います。これをコンピュータ回路と接続する場合には、フォトカプラなどで絶縁して使うのが一般的らしいです。

下の回路図は、ネットで見つけたパナソニックのJEMAアダプタの回路図です。電気錠のJEM-A端子に、自社のインターフォンを接続するためのアダプタのようです。右側が他社製品のJEM-A端子で、左側がパナソニック製品の機器側です。JEM-A端子側には100Ωの保護抵抗を直列に入れてフォトカプラが接続されています。

panasonic.bizから引用)

電気錠のJEM-A端子

改造対象の電気錠にもJEM-A端子がついています。電気錠とコントローラは、10年くらい前のMIWAの製品です。電気錠制御盤の端に、JEM-A端子というラベルがあります。色々調べてみると、日本製の電気錠にJEM-A端子がついているのはお約束のようでした。インターフォンと連携するために用意されているようです。「ちょっと待ってください、今開けますから」と言って、インターフォンのボタンを押すと電気錠が解錠されるようなユーザシナリオ実現のために、Panasonicのようなインターフォンメーカーと、MIWAのような錠前メーカーが連携するためにある端子のようです。

JEM-A端子に使われるコネクタはXHコネクタと呼ばれるものです。これの4ピンです。

https://www.jst-mfg.com/product/pdf/jpn/XH.pdf

秋月とか千石とか共立とかマルツとかで1個当たり10円程度で売ってます。ピンや圧着工具(手元になかったのでとりあえずはんだ付けしました)なども必要です。圧着工具は、半田付けすれば無しでもなんとかなりますが、コネクタを外す工具は、絶対に持っていた方が良いです。ペンチやマイナスドライバーで外そうとすると苦労しますし、コネクタやケーブルを損傷させる可能性があります。

今回の電気錠は、オートロックのモードに設定されていました。解錠をしてもしばらく経過すると自動的に施錠されます。その時間を5秒から60秒にDIPスイッチで設定できます。モニター端子は、施錠の時にon (HIGH), 解錠の時にoff (LOW)になるようです。なので、もしコンピュータから解錠するとしたら、その手順は、

  1. コンピュータからJEM-A制御信号に250msの信号を送る
  2. 解錠される
  3. JEM-Aモニター信号が指定の時間(5~60s)offになり、その後onに戻る
  4. コンピュータはこの信号をモニターして解錠・施錠状態を表示する
  5. 施錠される

の順番になるのではと考えました。自動的に施錠される(オートロックされる)ので、施錠のために制御信号を送る必要はないと思われます。

一方で、人が手作業でドアを開錠した場合にも、モニター信号は反応すると思います。なのでそのイベントをiPhoneに通知できれば、手動による解錠も知ることができるかと思います。

JEM-A端子の電気特性を調べる

JEM-A端子には、コントロール用にC1, C2端子が、モニター用にM1, M2端子があります。これらにテスターを当てて電圧を調べました。コントロール端子、モニター端子(onの場合)とも、開放時の電圧は4.9Vでした。TTLレベルの回路のようです。使いやすそうで良かったです。また、それぞれに1kΩの付加抵抗を接続した時、C1-C2端子は0.8V、M1-M2端子は3.2Vでした。この結果、内部は以下のようになっていると予想しました。エアコンのJEM-A端子と似ているけど微妙に違います。規格PDFが有料かつ公開不可なので謎ですが、割と緩い規格なのかもしれません。

C1-C2には単に押しボタンスイッチを直結しても大丈夫のようです。フォトカプラも直結で大丈夫だと思われます。M1, M2の電圧は、施錠状態の時に5V、解錠状態の時に1.4Vになるようでした。500Ωの抵抗が入っている様子なので、M1-M2にもLED直結で問題ないと思います。フォトカプラに直結しても、中のLEDが明るめに点灯しそうですが、大丈夫と思われます。

ESP32に接続する

エアコンの端子とあまり変わりはなかったので、前回エアコンのJEM-A端子に接続した時と同じ回路で、ESP32を電気錠に接続することにしました。エアコンよりもM1側の内部抵抗が低いので、R1は大きくしても良かったのですが、現在の値でもTLP621の推奨動作条件順電流(16mA)の40%くらいと想定されるので、このままにしておきました。R2の100Ωは、単なる気休めで、なくても良いと思います。R3も、この値だと10mAくらいになり推奨順電流の60%くらいです。省エネということで。

まずは前回同様ブレッドボードに作りました(写真は前回の使い回しです)。ユニバーサル基板に実装出来たら追記します。

MQTTThingを設定する

ハードウェアは出来上がったので、今度はHomebridge側を構築します。Homebridgeで鍵 (Lock Mechanism) アクセサリを作れるプラグインはたくさんあります。今回はMQTTThingを使いました。MQTTを使えば動作の確認やデバッグが簡単ですし、将来、Apple HomeKit以外のシステム(例えばHome Assistant)で使うことになっても対応できます。

MQTTについてはこちらをご覧ください。

 

diysmarthome.hatenablog.com

 

HomebridgeにMQTTThingプラグインをインストールして、以下のように設定しました。MQTTブローカーがlocalhostで動いていて、ユーザもパスワードも設定なしの場合です。高いセキュリティが要求されるアクセサリなので、後でパスワード設定しておきます。

電気錠の名前はFront Doorとしましたが、これはホームアプリで上書き変更できます。「玄関」などにすればSiriにお願いするときも日本語発音で伝わりやすいかもしれません。ちなみに英語で名前をつけた場合も、「フロントドア」とカタカナ発音でSiriに伝わります。

{
    "accessory": "mqttthing",
    "type": "lockMechanism",
    "name": "Front Door",
    "topics":
    {
        "getLockCurrentState": "mqttthing/lock/getCS",
        "getLockTargetState": "mqttthing/lock/getTS",
        "setLockTargetState": "mqttthing/lock/setTS"
    }
}

使用するTopicsは、

  • mqttthing/lock/getCS
  • mqttthing/lock/getTS
  • mqttthing/lock/setTS

としました。プラグイン名のmqttthingで始まるように設定しました。その先の名前も、サブクルライブする時にまとめてチェックしやすいように階層にしました。CS, TSは、Current State, Target Stateの略です。

使用するメッセージは、デフォルトのままなので指定していませんが、

  • U
  • S
  • J
  • ?

の文字です。それぞれ "Unsecured", "Secured", "Jammed", "Unknown"の意味です。このメッセージもコンフィグファイルで変更できますが、今回はデフォルトのままで使いました。Jと?は使用しないです。

なお、トピックス名のgetとset、targetとcurrentが、HomeKitの中でどのように使い分けられているかについて詳しい説明は以下をご覧ください。

diysmarthome.hatenablog.com

施錠開錠のエミュレーション

Lock Mechanismがどのように動作するのを知る目的で、iPhoneMacのホームアプリから操作をして、動作と流れるMQTTメッセージを確認しました。人がターミナルの上でMQTTのメッセージを見て、必要ならばメッセージをmosquitto_pubコマンドを使ってパブリッシュします。ESP32が行うべき処理のエミュレーションになります。これを元にESP32をプログラミングすれば良いわけです。

ホームアプリから解錠施錠する場合

先の手順でHomebridgeで設定して再起動するだけで、iPhoneMacのホームに、電気錠アクセサリが自動的に現れます。

この先、どういうメッセージが流されているのか確認するために、MQTTをサブスクライブしておきます。

$ mosquitto_sub -h localhost -t mqttthing/lock/# -v

上記の「施錠済み」の状態で鍵アイコンをクリックすると、

「開錠中...」になります。MQTTには、以下のメッセージが流れました。

mqttthing/lock/setTS U

set Target State, つまりこの値(ここでは開錠)を目標に設定してほしいという依頼が流れたようです。このメッセージを受け取ったESP32は、電気錠を解錠すれば良いわけです。JEM-Aの制御端子を250msの間onにします。そしてJEM-Aのモニター端子をチェックして、これがonになったら、開錠が達成できたことになります。そこで、開錠できた事をget Current Stateで知らせます。

$ mosquitto_pub -h localhost -t mqttthing/lock/getCS -m U

すると表示が「施錠済み」に戻ります。

ここで再び鍵アイコンをクリックすると、set Target StateトピックスにSが流れます。表示は「施錠中...」になります。

そこで、get Current StateとしてSを流せば、

$ mosquitto_pub -h localhost -t mqttthing/lock/getCS -m S

すると表示が「施錠済み」に戻ります。

ここまでのMQTTメッセージの流れをまとめておくと以下になります。iPhoneのボタンを押して、解錠を試みて、解錠されたところで、施錠を試みて、施錠されるという順番です。

  1. mqttthing/lock/setTS U(鍵アイコンをクリック:解錠中...になる)
  2. mqttthing/lock/getCS U(解錠済みになる、他デバイスに通知)
  3. mqttthing/lock/setTS S(鍵アイコンをクリック:施錠中...になる)
  4. mqttthing/lock/getCS S(施錠済みになる、他デバイスに通知)

ESP32でのプログラムでは、setTSトピックスに開錠・施錠の設定指示が流れてきたら対応して、設定が終わったらgetCSで回答するという手順を作れば良いわけです。

他のiPhoneから解錠施錠される場合

HomeKitは、必要に応じてアクセサリの状態を通知してくれます。Lock Mechanismアクセサリの場合、自分の端末で操作していないのに、鍵の状態(Current Status)が変更されると、通知が来ます。例えばiPhoneで鍵を操作するとMacに通知が来て、Macで操作するとiPhoneに通知がきます。不正に鍵を開けられる場合に通知が来るので安全です。

Get Target Stateの使い方

ここまでの説明で出番のなかった、Get Target Stateはどういう場合に使うのでしょうか?getなのでHAPの外の世界の事象で発生するメッセージです。なので、例えば壁に電気錠を開錠・施錠する物理的なマニュアルスイッチが設置されていて、これが押された場合に、get Target Stateを使います。すると、iPhoneなどの表示が、開錠中...または施錠中...の表示になります。マニュアルスイッチで操作された後、施錠の状態が変化するはずですが、その結果をget Current Stateで伝えておくと、ホームの表示が更新されるとともに、通知が表示されます。

   

このように、get Target Stateとget Current Stateはこの順番で、セットで流す必要があります。逆の順番で流すと表示が混乱します。例えば、施錠済みの状態で、

get Current State でUを流すと、ボタンは解錠状態の白になるものの、アイコンは施錠状態、文字表示は「施錠中...」という表示になってしまいます。Targetが示されずにいきなりCurrentが変更されて混乱している様子です。これを治すにはget Target StateにUを流します。

一方、get Target StateにUを流し、get Current StateにUを流すという順番でメッセージを送れば、解錠中...の状態を経て、正しく解錠済みの表示になります。

   

ということで、外部マニュアルスイッチによって操作された場合は、get Target Stateとget Current Stateの両方を、この順番で流しておく必要があります。

ESP32のプログラミング

この手順を、ESP32にプログラムする手順を考えます。以下の処理をすれば良いです。

  • set TSを受け取ったらJEM-Aの制御線にパルスを出す(HomeKitからの依頼)
  • JEM-Aのモニタ線が変化した場合:
    1. これがHomeKitからの依頼で変化した場合はget CSでモニタ線状態を送信し、
    2. これが外部からの操作ならばget TSとget CSを送信する

これを実現するために、HomeKitからの依頼によりJEM-Aにパルスを送ったかどうかを記録しておくためのフラグを一つ用意して、以下のようなプログラムを考えました。

boolean:「MQTTからの要請で設定した」= false;

MTQQのsetTSトピックスにメッセージが来た時の処理
  受け取ったメッセージ(UまたはS)と現状が違ったら     JEM-Aの制御線に250msのパルスを送る     (施錠状態の時は5~60秒間解錠、解錠状態の場合は施錠される)    「MQTTからの要請で設定した」フラグをtrueにする loopの中でJEM-Aモニタ線が変化した時の処理   もし「MQTTからの要請で設定した」フラグ==falseならば     get Target Stateに今の状態(UまたはS)を送る(外部からの操作)   get Target Stateに今の状態(UまたはS)を送る   「MQTTからの要請で設定した」=falseにする

JEM-A端子のM1, M2の値は、LEDを繋いでみた限りでは綺麗に切り替わってました。チャッタリングのような過渡的なノイズはない様子です。でも念のために、JEM-A端子の値が300ミリ秒間変化しない場合に動作するようプログラムしました。実際に完成したプログラムは以下になりました。(ちょっと長いです)

//ESP32 lock mechanism with EspMQTTClient library.
// Aug. 28, 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_U 1   //value for the lock is Unsecure (Unlocked)
#define JEMA_S 0   //value for the lock is Secure (Locked)

int JEMA_current; //current status of the lock
boolean JEMA_pulsed; //if a pluse has been sent to JEMAOUT

//WiFi
const char SSID[] = "XXXXXXXX"; //WiFi SSID
const char PASS[] = "xxxxxxxx"; //WiFi password
//MQTT
char CLIENTID[] = "ESP32_xx:xx:xx:xx:xx:xx"; //MAC address is set in setup()
//for example, this will be set to "ESP32_84:CC:A8:7A:5F:44"
const char  MQTTADD[] = "192.168.xxx.xxx"; //Broker IP address
const short MQTTPORT = 1883; //Broker port
const char  MQTTUSER[] = "";//Can be omitted if not needed
const char  MQTTPASS[] = "";//Can be omitted if not needed
const char  SUBTOPIC[] = "mqttthing/lock/setTS"; //mqtt topic to subscribe
const char  PUBTARGET[] = "mqttthing/lock/getTS"; //mqtt topic to publish
const char  PUBCURRENT[] = "mqttthing/lock/getCS"; //mqtt topic to publish
const char  PUBDEBUG[] = "mqttthing/lock/debug"; //for debug message

void setup() {
  //Digital I/O
  pinMode(JEMAOUT, OUTPUT);
  pinMode(JEMAIN, INPUT_PULLUP);
  JEMA_current=digitalRead(JEMAIN);
  //Serial
  Serial.begin(115200);
  while (!Serial);
  Serial.println("ESP32 Lock Mechanism 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/lock/setTS
  //Serial.println(msg);
  client->publish(PUBDEBUG, "Set TS received.");
  boolean newValue, changed=false;
  if(msg.compareTo("U")==0) { //target state is Unsecure (unlock)
    if(digitalRead(JEMAIN) == JEMA_U) return; //already Unsecured (unlocked). do nothing.
  }
  else if(msg.compareTo("S")==0) { //target state is Secure (lock)
    if(digitalRead(JEMAIN) == JEMA_S) return; //already Secured. do nothing.
  }
  //now send a pluse to toggle the electric lock
  digitalWrite(JEMAOUT, JEMA_ON); //activate JEM-A control line for 0.25 sec
  delay(250); 
  digitalWrite(JEMAOUT, JEMA_OFF);
  JEMA_pulsed=true;//flag to show a pulse has sent.
}

int counter, lastvalue;//counter and memory for same-JEMAIN-value check

void onConnectionEstablished() {
  Serial.println("WiFi/MQTT onnection established.");
  client->subscribe(SUBTOPIC, onMessageReceived); //set callback function
  client->publish(PUBDEBUG, "ESP32 Lock Mechanism is ready.");
  JEMA_current=digitalRead(JEMAIN);//update the current state
  JEMA_pulsed=false;//reset the pulse-flag.
  lastvalue=999; //force update at next loop()
}

void loop() {
  client->loop();  
  delay(10); //10ms delay
  
  int newvalue = digitalRead(JEMAIN);//get current JEMA value
  if(newvalue != lastvalue) {
    lastvalue = newvalue;
    counter=0;//set the counter
  }else if(++counter == 30) {//when 300ms passed after last change
    if(JEMA_current == newvalue) return; //no change, do nothing.
    //JEMA monitor status has chenged
    if(newvalue == JEMA_S){
      if(!JEMA_pulsed) client->publish(PUBTARGET,"S");
      client->publish(PUBCURRENT,"S");
    }
    else if(newvalue == JEMA_U){
      if(!JEMA_pulsed) client->publish(PUBTARGET,"U");
      client->publish(PUBCURRENT,"U");
    }
    JEMA_pulsed = false;
    JEMA_current = newvalue;
  }
}

あとはHomeKitにお任せ

以上で、

の接続が完了しました。ここまで設定すれば、iPhoneMacのホームに設定した電気錠が現れます。そして、電気錠としてのあるべき振る舞いは全てHomeKitが面倒を見てくれます。

まずは、世界中のどこからでも、iPhoneMacのホームから解錠ができます。他の端末や手動で解錠された場合は通知が来ます。

次に、家族、同居人、オフィスならば同僚、一時的な滞在者など、Apple IDを持っている人なら解錠できる人として追加できますし、いつでも削除できます。解錠操作は、登録されたApple IDで二段階認証されたiPhoneまたはMacからのみ可能です。パスワードを共有する方式よりも安全です。

さらには、Siriも電気錠を正しく扱ってくれます。電気錠DIYでありがちなエピソードに、外から大声で叫んだら、家の中のスマートスピーカーが反応して解錠してしまうというオチがあります。今回作った電気錠も、「へいSiri、玄関を開けて」というように発声してSiriに開けてもらうことが可能です。「ドアを開けて」など、多少揺らぎのある発話をしても解錠してくれます。ただし音声解錠は、解錠する権限を持つユーザのiPhoneApple Watchに、持ち主の声でお願いした時だけです。HomePodやMacのSiriにお願いしても、すぐには解錠しません。「続きの操作は個人用デバイスで行う必要があります」と音声応答した後、手元のiPhoneに確認の通知がきます。これをタップすることで解錠されます。Lock Mechanismは、照明やエアコンなどの通常のアクセサリよりセキュアな扱いがされています。

まとめ

JEM-A端子が付いているオートロックの電気錠に、フォトカプラ経由でESP32を接続して、MQTTメッセージで解錠できる電気錠にしました。これをHomebridge+MQTTThingプラグインと組み合わせることで、HomeKitのLock Mechanizmアクセサリにしました。これでどこからでも電気錠を解錠できますし、通知も来ます。Siriにお願いして解錠することもできました。

Tuyaの格安WiFi磁気接触センサ(363円)をHomebridge / HomeKitで使う

AliExpressで格安で売っていた磁気接触センサを使ってみました。TuyaのスマホアプリでWiFi設定して、HomebridgeのTuya公式プラグインを使うことで、HomeKitから使用することができました。

追記)ここで紹介したTuyaのクラウドは最近になって無料期間1ヶ月の制限が導入されたようです。もしかしたら下記で紹介したLocalTuyaで使えるかもしれません。しかし結構大変なので、少し高いですがZigbee対応のセンサを買うのが良いと思います。

diysmarthome.hatenablog.com

TuyaのWiFi磁気接触センサ

購入したのはこちらのセンサです。先月買った時は送料込みで363円でした。今は543円に値上がりしてますが、それでも格安だと思います。磁気スイッチと磁石を使ったWiFi接続方式のセンサで、ドアや窓に取り付けて開閉状態を検出します。販売ページには、磁石側の大きさが43 x 10 x 14 mm、本体側の大きさが68 x 23 x 19 mmと書かれてました。実測したところもう少し大きくて、磁石側の大きさが43.9 x 12.3 x 16.6 mm、本体側の大きさは69.9 x 24.3 x 22 mmでした。(取り付けてしまってから計測したので、実測値はあまり正確ではないです)

Zigbeeのセンサは1,000円くらいで売られているのですが、WiFiの方が技術がこなれているのか安いようです。ただ消費電力が大きいため電池が単4x2でした。Zigbeeのものはコイン電池が普通なので、それと比べると本体サイズが大きいです。届いた箱はこんな感じです。

箱の外観

中身はこんな感じ。

製品写真

本体裏蓋はスライドすると開きます。中に単4電池が2本入ります。この価格なので電池は付属していません。

電池ケース

スマホアプリに登録

まずはTuyaのアプリ、Tuya Smartに登録して、WiFiの設定をします。詳細は以前の記事に書いてありますので、ご覧ください。

diysmarthome.hatenablog.com

Tuya Smartにセンサを登録する手順は以下です。

  1. iPhoneを2.4GHz WiFiに接続しておく
  2. Tuya Smartを起動する
  3. Tuya Smartで「デバイスを追加」を選ぶ
  4. Tuya Smartで「ドアセンサー (WiFi) 」を選ぶ
  5. センサのリセット穴に添付のピンを挿して長押ししてリセット

以下はこの時のスマホ画面です。

   

これでデバイスが追加されます。

この後、センサに磁石を近づけたり、離したりすると、2~3秒で通知が来て、表示されるようになりました。この後Tuyaのアプリは使わないので、iPhoneの「設定」から通知をoffにしておきました。

Tuya開発者ページで設定

Home AssistantやHomebridgeなどでTuyaのデバイスを利用する際、そのデバイスZigbeeバイスならば、Zigbee2MQTTを使えます。

でも今回はWiFiバイスなので、Tuyaのクラウド経由で情報を得る方法を用います。そのためにTuya開発者ページで登録して、スマホアプリと連携設定して、IDを得る必要があります。これも以下で行ったのと同じような手順です。

diysmarthome.hatenablog.com

手順は以下です。

  1. Tuyaの開発者ページに行ってアカウントを作る
  2. そこでcloud projectを作る
  3. そのprojectにスマホのTuya Smartアプリを登録する
  4. これで得られるIDなどをHomebridgeプラグインに設定する

今回は、1から3の手順は終了しているので、4番目のステップ、Homebridgeの設定だけを行いました。

Tuya公式プラグインを入れる

次は、Homebridgeの設定です。前回はIRリモコンに特化したプラグインを入れましたが、今回はセンサーなので、Tuyaの公式プラグインを試してみようと思います。Homebridge Tuya Platformという名前のプラグインです。

github.com

tuyaというアカウントが提供している公式プラグインです。このプラグインに必要な情報は以下の4種類です。

  1. "username": "xxxx@xxxx.com",
  2. "password": "XXXXXX",
  3. "accessId": "xxxxxxxxxxxxxxxx",
  4. "accessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

usernameとpaasswordは、スマホアプリで使ったものです。捨てメールアドレスを使ったので、そのアドレスと、その時に設定したパスワードを使用します。

accessIdとaccessKeyは、Tuya開発者サイトで作ったプロジェクトのAccess ID/Client IDと、Access Secret/Client Secretの文字列です。

プラグインGUI設定画面では、このほかに、Project Typeを設定します。これはPaaSにしておきます。またPaaS Platformの指定もあります。今回はTuya Smartというスマホアプリを使っているので、それを指定します。いずれもポップアップメニューから選択するだけなので簡単です。なお、Tuyaからは、Smart Lifeというアプリも出てます。こちらを使った場合はそれを指定します。その結果、コンフィグファイルの設定で確認すると以下のようになりました。

 {
    "options": {
        "username": "xxxx@xxxx.com",
        "password": "XXXXXX",
        "accessId": "xxxxxxxxxxxxxxxx",
        "accessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "lang": "en",
        "projectType": "2",
        "appSchema": "tuyaSmart",
        "countryCode": 81,
        "debug": false
    },
    "name": "TuyaPlatform",
    "platform": "TuyaPlatform"
},

これでHomebridgeを再起動すると、センサがHomeKitに現れます。

これを開くと、オートメーションを追加したり、通知を設定することができます。

とりあえず、センサーが開放(磁石が離れる)とLED電球が点灯し、センサが閉鎖する(磁石が近づく)と消灯するオートメーションを設定して、テストしました。防犯システムとして使うなら、セキュリティシステムのアクセサリを併用すると良いです。

diysmarthome.hatenablog.com

取り付け具合

アルミサッシに取り付けました。2枚の引き戸の重なる部分に、良い具合におさまりました。この場所ならば、どのように扉が開けられても反応します。Zigbee製品に比べて本体が大きめですが、問題なく取り付けられました。本体底部の単4電池部分が、アルミサッシの金属枠側に来るので、アンテナ位置がサッシ枠から離れ、電波の飛びも問題なさそうです。

応答速度

ただし、反応が遅いのが気になりました。磁石が近づく、または離れる動作をした後、Homebridgeに反映されるまで30秒ほどかかります。スマホのTuya Smartアプリにはほぼ瞬時に通知が来ますが、Tuya開発者サイトのプロジェクトからの通知は、30秒弱(だいたい25秒)経ってから届くようです。

Tuya Smartアプリの動作ももう少し調べてみました。iPhoneWiFi接続にして、このセンサと同じLANにある状態では、ほぼ瞬時、おそらく2~3秒で、アプリが更新されます。ところが、iPhoneWiFiをoffにして、キャリア接続にしたところ、更新されるまでにやはり20秒以上かかりました。おそらくはLAN側から来た問い合わせにはすぐに返答する一方で、クラウドへの報告は20秒間隔くらいで実施しているのではないかと思います。そのぶん省電力になっているとは思うので、応答速度と電池寿命のトレードオフでこの設定になったのかと思います。

防犯センサーのような用途なら問題のない遅延時間だと思います。検出した結果がすぐに必要な場合や、さらにはこれを分解してワイヤレス押しボタンを作るとか考える場合には、30秒弱の応答時間は辛いかもしれません。

まとめ

格安のTuyaのWiFiドアセンサをHomeKitから使えるようにしました。何よりこのコストパーフォマンスはすごいと思いました。家の全てのドアと窓に取り付けても大した金額にならないのではないでしょうか。ちゃんと稼働して、磁石検出を取りこぼすような不具合はありませんでした。応答時間が30秒弱かかる点が欠点ですが、それが許容されるような用途なら、安価で使いやすいと思います。電池は単4なので寿命が長そうですが、WiFiなのでどうでしょうか。今後長期使用して報告します。

Tuyaの格安 (530円) WiFi赤外線リモコンをHomeKitで使う

Tuyaの黒くて丸いWiFi接続赤外線リモコンがAliExpressで送料無料530円で売られていたので、つい買ってしまいました。Homebridgeのプラグインを使ったら、Apple HomeKitから使えました。今は値上がりしてしまいましたが、各部屋においても良いくらいの価格かと思います。少し高いですがAmazonでも売ってます。

追記)ここで紹介したTuyaのクラウドは最近になって無料期間1ヶ月の制限が導入されたようです。

diysmarthome.hatenablog.com

Tuya Smartで設定

まずは、iPhoneAndroidのTuya Smartアプリをダウンロードします。いつものようにメールアドレスで登録する方式なので、macOSの「メールを非公開」機能で作った捨てメアドを使いました。IoT時代にこの機能は必須です。

アプリから、デバイスを追加を選び、電気製品・その他にあるスマートリモコンを選びます。そこで、2.4GHzのWiFiSSIDとパスワードを入力します。次に、デバイスをリセットします。

リモコンの裏にリセットスイッチがあるので、長押しします。すると青色LEDが点滅を始めて、メニューを押すとSmart IRという名前のデバイスが登録されました。このデバイスの中に、「+リモートコントロールパネルを追加する」ボタンがあるので、それを押します。

次にリモコンでコントロールする相手を設定します。ここではエアコンを登録したかったので、エアコンを選びます。この先の「ブランドを選択」する場面で、メーカー名(パナソニック)を選んだところ、すぐにコントロールできました。

Homebridgeプラグインを入れる

Tuya Smartアプリでは、Google HomeAmazon Alexaなどの設定ができるようです。でもHomeKitから使いたいので、Homebridgeのプラグインを探しました。「Tuya」という文字で検索すると多数のプラグインが見つかりました。名前にTuyaの文字が入っているプラグインだけでも、26個あります。みんなが頑張って使えるようにしているようです。その中から、今回はHomebridge Tuya IR Platformというプラグインを選びました。Tuyaが作っている公式のプラグインもありましたが、今回は赤外リモコンしか使わないので、わかりやすくて良いかなと思いました。更新頻度も高いようです。

github.com

Tuyaの開発者ページに登録

Tuyaデバイスの機能を使うためには、Tuyaの開発者ページに登録して、使用しているデバイスに関する情報を入手する必要があります。クラウドでコントロールされているIoTデバイスではよくある手順です。デバイス情報を使って、クラウドに制御を依頼すると、手元のデバイスが動作します。

Tuyaで、デバイスの情報を得る手順は以下でした。

  1. Tuyaの開発者ページに行ってアカウントを作る
  2. そこでcloud projectを作る
  3. そのprojectにスマホのTuya Smartアプリを登録する
  4. これで得られる秘密の番号をHomebridgeプラグインに設定する

いつものことですが、ここからちょっとややこしくなります。

1, 2, 3のステップはこちらにも説明があります。Tuyaの公式プラグインの説明にも、同じような手順が書いてあります。そちらには説明ビデオへのリンクもあります。ただ、開発ページのメニューが変更されているようで、ビデオ通りにはいかず、わかりにくかったです。

アカウントを作る

まずは、Tuyaの開発者ページに行って開発者アカウントを作ります。またメアドが必要でしたので、先ほどスマホアプリの登録で使った捨てメアドを使い回しました。

cloud projectを作る

次にcloud projectを作ります。左のメニューから、Cloudを選び、そこで現れるメニューからDevelopmentを選びます。

そして右上のCreate Cloud Projectを選びます。

次にプロジェクトの詳細を入力します。Project Nameは任意です。適当に名前をつけます。Descri[ptionは書かなくてもokです。Industryは適当に選んでおけば良いようです。一番上に出てくるSmart Homeで良いでしょう。Development Methodは、よくわかりませんがビデオのチュートリアルではSmart Homeを選んでいるので、そうしました。

Data Centerの設定は、近所を選んでおけば良いと思います。日本の場合は、Western America Data Centerがデフォルトらしいですので、それが無難かと思います。複数選べますし、ビデオチュートリアルでも2〜3箇所選んでいる例が多いので、Chinaも選択しても良いかもしれないです。

次に、Authorize API Serviceという選択肢が現れます。右にある4個がすでに選ばれていて、さらに左から追加したいものを加えるという指示です。

後から変えられるような気もしましたが、変更方法がよくわかりませんでした。そもそもどれを選んだら良いかわかりません。プラグインのページに貼ってあるTuyaのビデオををみたら、Device Status Notificationを追加せよとあるので、それを追加します。

プロジェクトとスマホアプリを連携

ここまでは、順調でした。しかし、ステップ3の、Tuya Smartアプリのアカウントをリンクする段階で手こずりました。プロジェクトを選択すると、いくつかのタブが現れます。ここで、Link Tuya App Acountを選ぶと、iPhoneのTuya Smartアプリと連携してくれます。

Add App Acountボタンを押すと、QTコードが現れます。このコードは一時的なもので、時間が経つと無効になります。その場合はもう一回、生成してもらいます。どうやらこのコードを、iPhoneのTuya Smartアプリで読ませれば良いようです。

ただその方法がわかりにくかったです。iPhoneのTuya Smartアプリでプロフィールのページを開くと、右上に小さなアイコンがあります。それをタップするとカメラが起動してQRコードが読めるようになります。これでプロジェクトとスマホアプリのアカウントが連携するはずです。

しかし、実際には「操作が許可されない」というメッセージが出て先に進みませんでした。いろいろ注意事項を読むと、「中国本土の人は、国の規制があってクラウド開発に特別な許可が必要」というような内容が書いてありました。なんで中国の規制に引っかかったのだろうと思い、My AccountのBasic Informationを確認したら、Country/Regionの設定がChinaになってました。設定した覚えがなかったのですが、アカウント登録のデフォルトがChinaで見落としていたのかもしれません。日本に訂正しました。念のために、データセンタからもChinaを除外しましたが、後から試したらデータセンタは関係ないようでした。

この後、パーミッションの設定ページが出ます。デフォルトでは自動で、Readのみだったので、自動でRead, Write, Manage全部okにしておきました。

秘密の番号を手に入れる

これで開発者サイトへの登録が完了し、クラウド経由からデバイスを制御するために必要なIDが得られるようになります。まずは、プロジェクトを登録した段階で、以下の2個のIDが手に入ります。プロジェクトのOverviewを見ると書いてあります。

いずれも長ったらしい英数字です。Access Secret/Client Secretの方は、目のマークをクリックすると現れます。これも最初は、表示してもらえませんでした。ユーザ登録をする際に、デフォルトでなぜか国籍がChinaになってしまっていたようです。それで、先の中国国籍者制約で、制限がかかっていたようです。ユーザプロファイルのCountry/RegionをJapanに訂正したところ、シークレット番号を表示してもらえるようになりました。

プロジェクトのAll Devicesタブを開けるとデバイス一覧が現れ、そこに、

  • Device ID

が書かれてます。これも長い謎の英数字です。IRリモコン本体と、登録したエアコンの両方のデバイスが見えましたが、IRリモコンのIDを使うようです。エアコンのIDは自動検出してくれるようです。

Homebridgeに設定する

こうして得られた3つの英数字を、HomebridgeのTuyaのプラグインに設定します。

Device Regionは多分データセンターの場所のことだと思いました。他はデフォルトでokでした。コンフィグファイルの方では以下のように設定されていました。

{
    "name": "TuyaIR",
    "tuyaAPIClientId": "xxxxxxxxxxxxxxxx",
    "tuyaAPISecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "deviceRegion": "us",
    "smartIR": [
        {
            "deviceId": "xxxxxxxxxxxxxxxx",
            "autoFetchRemotesFromServer": true,
            "configuredRemotes": [
                {
                    "model": "Unknown",
                    "brand": "Unknown"
                }
            ]
        }
    ],
    "platform": "TuyaIR"
}

設定を保存して、Homebridgeを再起動します。しばらくすると、iPhoneMacの画面に、自動的にリモコンが現れました。タイミングにもよるとは思いますが、ホーム.appにアクセサリが表示されるまでに時間がかかることがあります。15分くらいは気長に待つのが良いです。

     

まとめ

Tuyaの赤外線リモコンユニットをHomeKitで使えるようにしました。Tuyaの製品は他社に比べてお買い得だと思います。購入時よりも今は値上がりしてしまいましたが、それでも1000円くらいで買えます。各部屋に1個ずつおいても良いくらいです。高価なNature Remoと比較して、機能や性能がそれほど見劣りする様子はありません。ただ、現在温度の設定が出ないので、温度センサを持っていないのかもしれません。スマホアプリの日本語表示もところどころ変ですが、設定時にしか使用しないので問題ありません。また、Homebridgeに登録するための手間は、どちらも同じくらいでした。

今回はTuyaのリモコンを使いましたが、Tuya公式プラグインを使えばTuyaデバイスが全てHomeKitから使えるようになるらしいです。機会があれば他のTuyaデバイスも試してみたいです。

TuyaのZigbee壁スイッチ

スマホやスマートスピーカでon/offできるようになっても、手っ取り早く操作できる昔ながらの壁スイッチが欲しいことがあります。IKEAのスイッチに続き、別の壁取り付けZigbeeスイッチを試してみました。Tuyaのヨーロッパ風壁スイッチです。壁には、両面テープ、またはネジで固定します。薄いので、通常の壁スイッチのように見えます。送料込みで1,491円でした。1連、2連、3連がありますが、どれも同じ値段です。

開けてみる

箱の写真は3連ですが、買ったのは1連です。箱は共通のようです。

1連は、のっぺりとしてあまりスイッチらしく見えないです。

ケースは、噛み合わせで固定されています。かなり硬いですが、電池交換やねじ止めする際には、開ける必要があります。中には、スイッチと周辺回路が3個分用意されてました。1,2,3連で同じ内部基板を使っているだろうとは思いましたが、部品まで載ってました。なので価格も同じということのようです。もっとも2個のスイッチは押しても反応しません。プログラムが違うのか、ジャンパー線・抵抗で構成を設定してあるのかと思います。

こちらは裏側です。

使われている本体チップには、機種名の記載がなくて不明です。QRコードの書かれたシールを剥がしてみましたが、その下にも何も書かれていません。形状やピンの様子から、Tuyaが提供しているZigbeeモジュールのようです。

solution.tuya.com

Zigbee2MQTTで使用可能

Zigbee2MQTTで使用可能なのかどうか不明でしたが、可能でした。電池を取り付けて、長押しして、ペアリングモードにしたところ認識されて、Homebridge, HomeKitにスイッチとして表示されました。

バッテリ残量低下の表示が出ますが、実際には新品バッテリを入れてあります。動作には支障ありません。設定を見ると、TuyaのTS0041という製品として認識されているようです。

スイッチ動作は3種類

スイッチアクションには、1回押し、2回押し、長押し(シングルクリック、タブルクリック、ロングプレス)の3種類があります。それぞれに動作をプログラムできます。照明のon/offに対応させるならば、シングルクリックでon、ダブルクリックでoffと設定するのが良いです。

長押しは、ペアリングと紛らわしいので、使用しない方が良いです。マニュアルには、5秒押し続けると長押しになり、10秒押し続けるとでペアリングになると書かれてます。しかし、実際には、約3秒で長押し、約5秒でペアリングになりました。いずれにしても、不用意に長押しし過ぎると、ペアリングモードに入ってしまいます。ペアリングのやり直しになると、新しいスイッチが登録されたことになり、せっかく設定した動作が消えてしまいます。ペアリングに入る条件をもっと稀な操作に設定するか、IKEAのTRÅDFRIスイッチのように、ペアリング専用のスイッチを用意して欲しかったと思います。

長押し動作が洗練されていないことも、誤ったペアリング動作を誘発しています。例えばIKEAのTRÅDFRIスイッチは、長押ししたまま規定の時間が経過すると、長押しイベントが発生します。なので、長押ししている間に期待した動作が確認できた時点で、指を離せば良いわけです。それに対してTuYaのスイッチは、指を離した段階で、ようやく長押しイベントが発生します。指を離すまで、長押しに成功したかどうかわかりません。そのために、長く押しすぎて、ペアリングモードに入りやすくなってます。

まとめ

TuyaのZigbee壁スイッチを使ってみました。Zigbee2MQTTですぐに動きました。ただ、IKEAのTRÅDFRIスイッチの方が、

  • 技適マークがある
  • 価格が安い、または同程度(on/offスイッチは799円、プッシュスイッチは1,499円)
  • 通販の納期が早い、IKEAの店頭に行けばすぐに買える
  • 電池残量が正しく表示される
  • 長押し動作の使い勝手が良い
  • 間違ってペアリングモードに入る心配が無い

というメリットがあり、IKEA製品の方が良いと思います。でも、通常のヨーロッパ型壁スイッチにそっくりな外観は魅力です。IKEAのスイッチは、磁石固定方式なので、外して好きな場所から使用できます。その一方で、固定された普通の壁スイッチを期待する初見ユーザにはわかりにくいかもしれません。

HomeKitでスマホ通知機能付きセキュリティシステムを作る

人感センサ、扉開閉センサなどのHomeKitアクセサリに連動するセキュリティシステムをHomebridge / HomeKitで作りました。HomeKitで定義されているSecurity Systemsカテゴリのアクセサリとして動きます。家を空けてどこに出かけていてもiPhoneに通知が届きます。

センサとブザーを繋ぐ

人感センサや開閉センサをブザーに接続すれば防犯装置が作れます。例えば100Vで鳴動する電磁ベルやブザーを、スマートプラグに接続して、センサをトリガーにonすれば簡単な警報装置が作れます。HomeKitならば、「新規オートメーション」から、「センサが何かを検知したとき」を選んで、スマートプラグをonにすれば良いです。

でも実用性を考えると、いろいろ欲しい機能が出てきます。警報が鳴ったら警備員さんが来てくれたら嬉しいですが、そこまで求めなくても技術的になんとかなりそうな機能は多いです。例えば、外出中に通知が欲しい、簡単に警戒状態のon/offをしたい、その状態をわかりやすく把握したいなど、作り込みたいところです。

セキュリティシステム

HomeKitアクセサリのカテゴリにセキュリティシステムというのがあります。これを使えば、セキュリティシステムに欲しい機能が実現できるのではと考えました。Homebridgeのmqttthingプラグインはセキュリティシステムアクセサリをサポートしているので、これを入れて、MQTTブローカに色々メッセージを送って、アクセサリの機能を調べてみました。

その結果、HomeKitのセキュリティシステムとは、以下のような製品を想定しているのだと理解できました。(写真をクリックするとAliExpressのページに飛びます。)

この製品は、壁に取り付けるコントローラに、無線接続の人感センサ6個、ドア開閉磁石センサ8個、警報ブザー、リモコンスイッチ2個が付属しています。コントローラの操作パネル、またはリモコンから、セキュリティモードに設定すると、異常があった時にブザーを鳴らしてくれます。さらにWiFiGSM経由で異常を知らせてくれるようです。この構成で16,000円なのは安いと思いました。HomeKitのセキュリティシステムアクセサリは、HAPから警戒モードのon/off/切り替えが可能なコントローラを想定しているようです。

自作セキュリティシステム構想

この商品は、Tuya社のシステムに準拠しているようです。Tuyaのデバイス類をHomebridgeから扱えるようにするプラグインが、Tuya社から提供されてます。それを使えば、もしかしたこれもHomeKitから使用できるのかもしれません。でもTuyaのシステムは(他のIoT製品もたいていそうですが)インターネット上のクラウドサービスを前提にしています。Home Assistantの人たちもが言っているように、クラウドにはできる限り頼りたくないです。

そこで、これと同じようなセキュリティシステムを、下の写真のような構成で自作することにしました。センサからの信号を受けて、警戒モードに従って警報器を鳴らす本体コントローラをESP32で作ります。警報器(ブザー)は、ESP32のGPIOでon/offします。コントローラには、テンキーやディスプレイは取り付けず、人とのインタフェースは、HomeKitに任せます。またセンサ類も、Homebridge, HomeKitのシステムを使います。リモコンの代わりがiPhoneです。もちろん無線の壁取り付けスイッチなどをセキュリティモードのon/offに使っても良いです。HomeKitからiPhoneに通知できるので、遠隔地からのモニター機能もこれで実現できます。

警報器(アラーム)を決める

大きな音の出るブザーやベルを探します。電圧は、100Vでも12/24Vでも良いでしょう。見た目とか音の良さから、古風な電鈴(電磁ベル)も良いかもしれません。

AliExpressだと少し安いですが、AC 100/110V用のものはあまり無く240V ACが多いです。一般的にベルよりはブザーの方が安価です。AliExpressで数百円くらいのものが売られていたので、とりあえず買ってみました。LEDもついていて、点滅します。防犯用というよりは、制御室や工場にありそうな警告灯のような製品かもしれないです。DC12V用の製品を買いました。経験的に12Vくらいまでならそれほど感電する心配はありません。でも24Vになるとけっこうきます。

ESP32の回路を考える

今回のESP32のハードウェア的な仕事は、警報器として使うDC 12Vブザーをon/offすることです。DC 12Vのon/offならばパワーFETでできそうです。以下の回路を考えました。

2SK4017には保護ダイオードが入っているようなので、出力側の心配は不要と考えました。耐圧は60Vくらいあります。今回は12Vですが、24Vのブザーでもokのはずです。ゲートからGNDに入れた10kΩは、offになった時のゲートの電荷を逃すために必要とのことで入れました。GPIO13とゲートの間に入れた100ΩはFETへの突入電流などを抑える効果があるそうで、数十Ωから数百Ωあると良いらしいです。FETの入力側ゲート電圧は、仕様書によると閾値電圧が最大で2.5Vでした。100Ωと10kΩの分圧ならばESP32の3.3V出力でもいけそうです。実測で3.2Vくらいは印加できてました。

FETにスイッチされる側には、ねじ止めのターミナルを用意しました。この片方にDC12VのACアダプタを接続し、もう片方に12V用のブザーを接続すればon/offできます。さらに、警報状態の表示のために、GPIO12番にLEDも接続しました。ESP32に押しボタンスイッチを取り付ければ、警報状態の切り替えも出来るかもしれませんが、操作することはないと思い止めました。

Security Systemアクセサリの動作確認

先の述べたように、HomeKitにはSecurity Systemsというカテゴリのアクセサリが用意されています。この動作の詳細を調べました。

Security Systemsは、センサを感知して警報を鳴らすタイプのアクセサリです。mqttthingプラグインを入れて、ダミーのアクセサリを作り動作を見てみます。mqttthingを使うと、mosquitto_sub, mosquitto_pubコマンドでアクセサリの振る舞いを確認して、アクセサリを操作できるので、動作確認がわかりやすいです。

mqttthingの設定から、新規のSecurity Systemアクセサリを選び、適当なMQTTトピックス名を設定して、Homebridgeを再起動します。するとiPhoneMacのホームに、ダミーのセキュリティシステムアクセサリが現れました。名前はSecurity Systemにしました。

クリックすると、在宅、不在、夜間、オフの選択肢が現れます。

在宅、不在、夜間、オフは、MQTTのメッセージでは、デフォルトでそれぞれSA, AA, NA, Dの文字列で表現されてます。STAY_ARM, AWAY_ARM, NIGHT_ARM, DISARMEDの略です。さらに、警報が鳴っている状態のT (ALAEM_TRIGGERED)もあります。それぞれが想定する状態は以下です:

  • 在宅 (SA):人がいる場合の警報レベル。例えば、火災報知器、ガス漏れ、普段は開けることのない扉などが反応したら警報を鳴らす。
  • 不在 (AA):家族全員が外出しているなど、人がいない場合の警報レベル。どのセンサが反応した場合でも警報を鳴らす。
  • 夜間 (NA):夜間の警報レベル。例えば、戸締り関連のセンサ類、屋外のセンサ類に反応があれば警報を鳴らすが、屋内の人感センサはオフにする。
  • オフ (D):全てのセンサをオフにする。警報は鳴らない。

これを全部使用する必要はなく、configファイルで選択できます。例えば、AAとDだけを使えば、一番簡単な、警報on/offスイッチになります。

HomeKitからは、セキュリティシステムアクセサリの動作モードの取得と設定が可能です。なので例えば、「警報が鳴るT状態になったら照明を点灯する」とか、「家に誰もいなくなったら警報レベルAAに設定する」などのオートメーションを作ることができます。

また、動作モードを変更するとiPhoneMacに通知が来ます。なので、設定状態をいつも確認することができます。さらには、警報が鳴るT状態になると、「重大な通知」が送られます。

「重大な通知」は通常に比べて特別扱いの通知で、iPhoneがロックされていても、少し大きめの音が鳴り、緊急状態を知らせてくれます。他の通常通知と同様、設定でoffにすることも可能です。

アクセサリの用意

セキュリティシステムを作るにあたり、次の2つのアクセサリをmqttthingを使って作りました。実態はどちらもESP32で、MQTTブローカー経由のメッセージに反応して動作します。

  • Security Systemアクセサリ:セキュリティレベルの取得と切り替えを担当する
  • Alarm Buzzerアクセサリ:警報アラームのon/offをするスイッチ。センサからの通知を受け付ける。

     

人感センサ、開閉センサなどは、検出時にAlarm Buzzerをonにするようオートメーション設定をしておきます。鳴動し続けるのが困るようならば、例えば3分て停止するように設定します。

他にも必要なセンサがあれば、すべてAlarm Buzzerをonにするように設定しておきます。それで、実際に警報ブザーを鳴らすかどうかは、Security Systemの設定によって、ESP32が判断します。

Homebridgeの設定

Homebridgeには、これらの2つのアクセサリをmqttthingで設定します。それぞれの設定内容は以下です。restrictTargetStateで使用する警報レベルを指定しています。ここでは、

1: 不在 (AA)

3: オフ (D)

を使用するよう設定してます。

{
    "type": "securitySystem",
    "name": "Security System",
    "topics": {
        "setTargetState": "mqttthing/security/setTargetState",
        "getTargetState": "mqttthing/security/getTargetState",
        "getCurrentState": "mqttthing/security/getCurrentState"
    },
    "restrictTargetState": [1, 3],
    "accessory": "mqttthing"
},
{
    "type": "switch",
    "name": "Alarm Buzzer",
    "topics": {
        "getOn": "mqttthing/security/getCurrentState",
        "setOn": "mqttthing/security/setTargetState"
    },
    "accessory": "mqttthing"
},

2つのアクセサリは、どちらもESP32が担当します。そこでトピック名を共通にして、後のプログラミングを簡単にしています。

MQTTメッセージとESP32の応答

MQTTブローカを介して交換されるメッセージを図示しておきます。ホーム.appで人がセキュリティシステムのモードをAAまたはDに切り替えると、setTargetStateトピックにAAまたはDのメッセージが流れます。

一方、センサに反応があると、setTargetStateトピックにtrueのメッセージが流れます。反応が止まればfalseが流れます。

ESP32はこのトピックをサブスクライブしておきます。そして、メッセージAAもしくはDを受け取ったら、内部の状態をそれにセットし、getCurrentStateトピックにAAもしくはDメッセージを流します。これでホーム.app上のアイコンの表示が変化します。

また、メッセージtrueを受け取って尚且つ自身の状態がAA(警戒状態)だったら、ブザーを鳴らします。またgetCurrentStateにTを流して、ホーム.appにも知らせます。

アイコンの変化とMQTTメッセージの関係を順番に例示します。まず、最初はSecurity SystemがD状態だっとします。

ここで、iPhoneでonにする操作をすると、MQTTのsetTargetStateトピックにAAが流れます。アイコンは「警戒状態に移行中・・・」になります。

これを受け取ったESP32が、内部状態を設定して、getCurrentStateトピックにAAを流すと、アイコンは「不在」に変わります。色も警戒色になります。デバイスからgetCurrentStateが返されて初めて、警戒状態に設定されることで、確実な動作を確認できるよう配慮されてます。

この状態で、getCurrentStateにTが流れると、以下のように作動済みになります。この時、前述のように「重大な通知」が配信されます。

ESP32のプログラム

ESP32にこの動きをプログラムした結果が下記です。

//ESP32 security system (AA Alarm) with EspMQTTClient library.

#include "EspMQTTClient.h"
EspMQTTClient *client;

//input & output pins and values
#define ALARMOUT 13 //GPIO for a relay to activate alarm buzzer.
#define ARMEDLED 12  //GPIO for armed-indicator LED.

//security level. Only AA (Away Arm) and D (Disarm) are used.
#define level_SA 0  //Stay Arm, not used in this version
#define level_AA 1  //Away Arm
#define level_NA 2  //Night Arm, not used in this version
#define level_D 3   //Disarm
int currentLevel=level_D; //current security level 0=SA, 1=AA, 2=NA, 3=D

//WiFi
const char SSID[] = "XXXXXXXX"; //WiFi SSID
const char PASS[] = "xxxxxxxx"; //WiFi password
//MQTT
char CLIENTID[] = "ESP32_xx:xx:xx:xx:xx:xx"; //MAC address is set in setup()
//for example, this will be set to "ESP32_84:CC:A8:7A:5F:44"
const char  MQTTADD[] = "192.168.xxx.xxx"; //Broker IP address
const short MQTTPORT = 1883; //Broker port
const char  MQTTUSER[] = "";//Can be omitted if not needed
const char  MQTTPASS[] = "";//Can be omitted if not needed
const char  SUBTOPIC[] = "mqttthing/security/setTargetState"; //mqtt topic to subscribe
const char  PUBTARGET[] = "mqttthing/security/getTargetState"; //mqtt topic to publish
const char  PUBCURRENT[] = "mqttthing/security/getCurrentState"; //mqtt topic to publish
const char  PUBDEBUG[] = "mqttthing/security/debug"; //for debug message

void setup() {
  //Digital I/O
  pinMode(ALARMOUT, OUTPUT);
  pinMode(ARMEDLED, OUTPUT);
  digitalWrite(ALARMOUT, LOW); //set alarm off
  digitalWrite(ARMEDLED, LOW); //set LED off
  currentLevel=level_D; //set disarm
  //Serial
  Serial.begin(115200);
  while (!Serial);
  Serial.println("ESP32 Security System 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 onConnectionEstablished() {
  Serial.println("WiFi/MQTT onnection established.");
  client->subscribe(SUBTOPIC, onMessageReceived); //set callback function
  client->publish(PUBDEBUG, "ESP32 Security System is ready.");
}

void onMessageReceived(const String& msg) { // topic = mqttthing/security/setTargetState
  //Serial.println(msg);
  client->publish(PUBDEBUG, "Set TS received.");
  
  if(msg.compareTo("AA")==0) { //is set AA (Away Arm)
    currentLevel = level_AA;
    //inicate with a 0.2 second beep
    digitalWrite(ALARMOUT, HIGH); delay(200); digitalWrite(ALARMOUT, LOW);
    digitalWrite(ARMEDLED, HIGH); //turn LED on
    client->publish(PUBCURRENT,"false"); //turn off the button JIC it is on
    client->publish(PUBCURRENT,"AA");
  }
  else if(msg.compareTo("D")==0){ //target state is D (Disarm)
    currentLevel = level_D;
    digitalWrite(ARMEDLED, LOW); //turn the LED off
    digitalWrite(ALARMOUT, LOW); //turn the alarm off JIC it is on
    client->publish(PUBCURRENT,"false"); //turn the button off JIC it is on
    client->publish(PUBCURRENT,"D");
  }
  else if(msg.compareTo("false")==0) { //a sensor turned off the switch
    if(currentLevel == level_AA){ // if AA, alarm likely to be triggered
      client->publish(PUBCURRENT,"AA"); //return to AA from T 
      digitalWrite(ALARMOUT, LOW); //turn the alarm off
    }
  }
  else if(msg.compareTo("true")==0) { //sensor turned on the switch
    if(currentLevel == level_AA){ //if it is armed
      client->publish(PUBCURRENT,"T"); //trigger the security system
      digitalWrite(ALARMOUT, HIGH); //turn on the alarm buzzer
    }
    else{ //if currentLevel is level_D
      delay(500); //do nothing but just delay for 500 ms.
      client->publish(PUBCURRENT,"false"); //turn off the button on the Home.app
    }
  }
}

void loop() {
  client->loop();
}

セキュリティシステムをAAモードに設定した場合には、ブザーを0.2秒鳴らして知らせています。

またセキュリティモードがDの時に、センサから通知があった場合は、Alarm Buzzerのアイコンを0.5秒だけonにしてそのことを知らせてます。この場合はブザーを鳴らしません。センサの動作確認として便利かと思います。

ブレッドボードで試作する

回路とプログラムの動作確認のために、ブレッドボードで試作しました。12VのACアダプタも接続して、FETの動作も確認しました。(最初の試作でドレインとソースを逆にしていて動かなかったのは内緒です)

ホーム.appの操作、アイコンの表示、センサの動作、MQTTメッセージの流れ、プログラムの動作を、いろいろなシーケンスを試して確認しました。訂正すべき点がたくさんあったので、こういうテストは必須でした。

ユニバーサル基板で工作する

回路とプログラムの動作確認ができたところで、ユニバーサル基板で配線しました。Fritzingのプリント基板設計機能を使うと、部品配置を検討できて便利ですね。

適当なサイズの基板がなかったので、少し大きめです。壁に貼り付けて使うことになるので、大きくても良いかと思いました。

あまり綺麗じゃない裏側です。

これを壁に取り付けます。ブザー用の12V DCとESP32 dev用の5V DCの2個のACアダプタを使うので、テーブルタブレットも取り付けました。

こちらがブザーです。上記のサイトで売られている商品はDC12V用が青色で、DC24V用が赤色でした。これはDC12V用です。

まとめ

HomebridgeとESP32を使って、センサに反応があると警報器が鳴るセキュリティシステムを作りました。設定や通知がHomeKitでサポートされていて、遠隔地から状況を把握できて便利です。しばらく使い続けて使い勝手を確認したいと思います。

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よりもサーバ向きの構成なので、スマートホーム用途に向いていると感じました。