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に限らず、他のフレームワークでも同じような用語が使われていると思いますので、参考になれば幸いです。