#author("2021-10-15T22:46:38+09:00","ocha","ocha")
#author("2021-10-15T22:47:07+09:00","ocha","ocha")
[[How2Homebridge]]

** はじめに [#m4bb9e15]

HomeKitのデバイスを、他のコンピュータのコマンドラインから動かす方法を説明します。
Homebridge, Mosquittoを使います。


Raspberry Piの上に、Homebridge, Mosquittoが動いていて、
Appleのホーム.appのにHomebridgeが接続されていて、
パソコン(Mac)の上にMosquittoのクライアント機能がインストールされていることが前提です。
以下のページを見てください。

[[How2Homebridge]]

[[How2MQTT]]

** MQTT Thingプラグインをインストールする [#h2247cfe]

Homebridgeのコントロールページから、プラグインを選び、検索窓にmqttthingとタイプします。するとHomebridge Mqttthingというプラグインが現れます。

#ref(mqttt2.png);

これをインストールします。
インストールが終わると設定画面が出ます。これはいつでも設定できるのですが、
とりあえず、Stateless Programmable Switchを選んでみます。
また、名前をSwitch1とし、MQTTのタイプ名も適当に入れておきます。
タイプ名は、mqtttで始まるようにしました。MQTTTプラグイン関係であることがわかりやすいかとおもいました。

#ref(mqttt3.png);

これで保存して、Homebridgeを再起動します(右上方の電源スイッチのようなアイコンを押す)。
再起動後に、アクセサリのタブを見ると、押しボタンスイッチのようなアイコンが見えます。
stateless programmable switchは、テレビのリモコンみたいに押しボタン方式のスイッチです。

#ref(mqttt5.png);

コンフィグボタンを押すと、Homebridgeの全体の設定が見えます。まだMQTT Thingしか入れてないのでわかりやすいです。

#ref(mqttt4.png);

このうち、

 "accessories": [
         {
             "type": "statelessProgrammableSwitch",
             "name": "Switch1",
             "topics": {
                 "getOnline": "mqttt/online",
                 "getSwitch": "mqttt/switch"
             },
             "accessory": "mqttthing"
         }
     ],

の部分がMQTT Thingの部分です。このプラグインのページに詳しい説明があります。

https://github.com/arachnetech/homebridge-mqttthing#readme

変更したり書き換えたりする場合は、このコンフィグファイルを編集するのが簡単で良いと思います。
テレビのリモコンのように、多数の押しボタンスイッチをまとめて定義することもできます。
LEDの調光器リモコンのように、on/off/明るさ/色合いなどのスイッチをまとめて定義するのに便利です。
これ以外にも多くの特性を持つデバイスが用意されています。

** MQTT Thingで使えるデバイス [#o5b0db87]

ここではstateless programmable switchを使いましたが、他にも多数のデバイスが使えます。

stateless programmable switchは、(HomeKitから見て)入力専用ですが、
Switchは入出力に対応しています。
設定して、mosquitto_subコマンドでモニターすると動きがわかります。
これを使えば、HomeKitからのon/offを受け取ってLEDを光らせるなどの仕掛けをArduinoで作れます。 


** ホーム.appで設定する [#d858e51d]

HomebridgeがHomeKit環境に登録してあれば、ここで定義したSwitch1がホーム.appに現れています。

#ref(mqttt6.png);

このアイコンを右クリックして、「設定」を選ぶと動作をしてできます。

#ref(mqttt7.png);

1回押し、2回押し(ダブルクリック)、長押しの選択があります。ここでは1回押しで、隣のIkeaの電球、をonにする設定をしました。

#ref(mqttt8.png);

** MQTTへの出版で電球をonにする [#w8a7e69d]

今までの設定で、

- MQTTサーバのアドレスは192.168.0.134
- Switch1のトピックは mqttt/switch

でした。Switch1には、1回押し、2回押し(ダブルクリック)、長押しの3種類があります。それぞれに対応するメッセージは、1,2,Lです。
これは設定ファイルで変更することも可能ですが、1,2,Lがデフォルトです。
なので、MQTTの出版をすれば、IKEAの電球をonにできます。パソコンから、

 % mosquitto_pub -h 192.168.0.134 -t mqttt/switch -m 1

とすれば良いです。他のターミナルのウィンドウから、

 % mosquitto_sub -h 192.168.0.134 -t # -v 

として、メッセージをモニターしておくとデバッグに役立ちます。

** 電球をon/offとトグルする [#q51cebb9]

電球をoffにしたい場合は、2回押しや長押しに電球offを割り当てても良いです。
また、1回押しのたびに反転することもできます。
1回押しに実行されるショートカットを以下のように記述すれば良いです。

#ref(mqttt9.png);

これで、

 % mosquitto_pub -h 192.168.0.134 -t mqttt/switch -m 1

とするたびに、電球がon/offします。

** PythonからMQTTブローカにアクセスする [#k0790222]

pahoというライブラリを使いました。

https://www.eclipse.org/paho/index.php?page=clients/python/index.php

以下のプログラムでHomeKitで設定された灯を点滅させることができました。

 #!/Library/Frameworks/Python.framework/Versions/3.9/bin/python3
 
 import paho.mqtt.client as mqtt     # import MQTT lib.
 
 broker_address="192.168.0.134" 
 client = mqtt.Client()              #create new instance
 client.connect(broker_address)      #connect to broker
 client.publish("mqttt/switch","1")  #publish

** ArduinoからMQTTブローカにアクセスする [#i3acb8a3]

同じくArduinoからの例です。

https://github.com/knolleary/pubsubclient

にある、pubsubclientライブラリを使ってます。

上のページにあるサンプルを参考にしたプログラムが以下です。
ここでは、13番に接続したスイッチが押された時に、MQTTに1を送ります。それでHomeKitが灯をon/offしてくれるはずです。

元のサンプルは、送受信に対応していたので、subscribeの部分も残ってます。その部分は今回は使っていないです。
HomeKitからの指示でArduinoでLEDを点灯させるなどの場合には、このcallbackの関数のところに、その処理を書けば良いです。。
WiFiの設定もしているので、長いですが、多分これで動きます。

 
 #include <WiFi.h>
 #include <PubSubClient.h>
 
 //input & output ping
 const int PUSHSW=13; //external push switch
 
 //WiFi
 const char SSID[] = "siiolab408_2G";
 const char PASSWORD[] = "xxxxxxx";
 //PubSubClient (MQTT)
 const char mqttbroker[] = "192.168.0.134"; //MQTT broker address
 const int mqttport=1883; //MQTT port
 const char subtopic[] = "mqttthing/sub"; //mqtt topic to subscribe これは今回使用しません
 const char pubtopic[] = "mqttthing/switch"; //mqtt topic to publish 
 char clientID[] = "ESP32_xx:xx:xx:xx:xx:xx"; //MAC address is set in setup()
 WiFiClient wifiClient; 
 PubSubClient mqttClient(wifiClient);
 
 //購読の結果が返ってきたら呼び出される関数
 void callback(char* topic, byte* payload, unsigned int length) {
   Serial.print("Message arrived [");Serial.print(topic);Serial.print("] ");
   String msg = String((char*) payload);
   Serial.println(msg); 
 //必要ならばこの後に、得られたメッセージに従った処理を書く
 //payload[length]='\0'; //メッセージの最後を0にしてC言語型文字列にする
 //String msg = String((char*) payload); //それをStringインスタンスに変換する
 //if(msg.compareTo("true")==0) { 
 //    digitalWrite(xxxx, LOW);//メッセージに従った処理を書く
 //  }
 }
 
 //connecting MQTT
 void connectMQTT() {
   mqttClient.setServer(mqttbroker, mqttport);
   mqttClient.setCallback(callback);
   Serial.println("Attempting MQTT connection. ");
   // Loop until we're reconnected
   while (! mqttClient.connected() ) {
     // Attempt to connect
     if (mqttClient.connect(clientID)) {
       Serial.println("Connected. ");
       // Once connected, publish an announcement...
       mqttClient.publish(pubtopic,"Arduino is ready.");
       // ... and subscribe
       mqttClient.subscribe(subtopic);
     } else {
       Serial.print("Failed, rc=");
       Serial.print(mqttClient.state());
       Serial.println(", try again in 5 seconds. ");
       // Wait 5 seconds before retrying
       delay(5000);
     }
   }
 }
 
 //connecting WiFi
 void connectWiFi() {
   WiFi.begin(SSID, PASSWORD);
   Serial.print("Attempting WiFi connection. SSID: "); Serial.print(SSID);
   while (WiFi.status() != WL_CONNECTED) {
       Serial.print(".");
       delay(1000);
   }
   Serial.print("\nWiFi connected. Assigned address is: ");
   Serial.println(WiFi.localIP());
 }
 
 void setup() {
   pinMode(PUSHSW, INPUT_PULLUP);
   Serial.begin(115200);        //  ESP standard speed 115200
   while (!Serial) ;            //  wait for serial port to connect.
   String wifiMACString = WiFi.macAddress(); //WiFi MAC address
   wifiMACString.toCharArray(&clientID[6], 18, 0); //"EPS32_xx:xx:xx:xx:xx:xx"
   Serial.print("\nMQTT clientID: ");Serial.println(clientID);
   
   connectWiFi();
   connectMQTT();
 }
 
 
 //last state of the PUSHSW
 int lastSWstate;
 
 void loop() {
   
   if( WiFi.status() == WL_DISCONNECTED) 
     connectWiFi();
   if (! mqttClient.connected()) 
     connectMQTT();
     
   mqttClient.loop();
 
   int newSWstate=digitalRead(PUSHSW);
   if(lastSWstate!=newSWstate) { //update only when SW changed
      if(newSWstate==LOW) mqttClient.publish(pubtopic,"1");
   }
  lastSWstate=newSWstate;
  
   delay(500);
  delay(500);
 }

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS