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

DIYする

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

センサとブザーを繋ぐ

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

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

セキュリティシステム

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

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

この製品は、壁に取り付けるコントローラに、無線接続の人感センサ6個、ドア開閉磁石センサ8個、警報ブザー、リモコンスイッチ2個が付属しています。コントローラの操作パネル、またはリモコンから、セキュリティモードに設定すると、異常があった時にブザーを鳴らしてくれます。さらにWiFiやGSM経由で異常を知らせてくれるようです。この構成で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を再起動します。するとiPhoneやMacのホームに、ダミーのセキュリティシステムアクセサリが現れました。名前は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に設定する」などのオートメーションを作ることができます。

また、動作モードを変更するとiPhoneやMacに通知が来ます。なので、設定状態をいつも確認することができます。さらには、警報が鳴る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で使用する警報レベルを指定しています。セキュリティシステムの状態は、デフォルトでは数値で表現されていて、以下のように割り当てられてます。

  • 0: 警戒レベル0 在宅 STAY_ARM (SS)
  • 1: 警戒レベル1 不在 AWAY_ARM (AA)
  • 2: 警戒レベル2 夜間 NIGHT_ARM (NA)
  • 3: 警戒レベル3 オフ DISARM (D)
  • 4: トリガーされた (T)

restrictTargetStateには、0から3の中から、使用する警戒レベルを指定します。ここでは、

  • 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でサポートされていて、遠隔地から状況を把握できて便利です。しばらく使い続けて使い勝手を確認したいと思います。

追記:この後、DIYセキュリティシステムに窓開閉センサーを追加しました。こちらをご覧ください。

ESP32でDIYしたセキュリティシステムに窓センサ (@672円) を追加する
以前DIYしたHomKitセキュリティシステムに、窓開閉センサを追加しました。センサはZigbee方式で送料込単価672円でした。センサが反応したら警報レベルに従ってブザーを鳴らす仕掛けをDIYすれば、あとはHomeKitが適切に対応してく...

コメント

タイトルとURLをコピーしました