ドアホンが鳴ったらGoogleHome,Slack,Discordに通知する
リモートワークなどで玄関から遠い部屋で作業をしていると、ドアホンのチャイムがちょっと聞こえにくいことがありませんか?
これを解決するために、Google HomeやSlack,Discordなどへ通知する方法です。
特徴
- グループ登録すれば複数のGoogle Homeに対してブロードキャストすることができます。家の各所にGoogle Homeを設置すれば死角なしです。
- Discord,Slackへの通知すれば、ヘッドホンをしながらPCを使っていても安心。
- 外出先からもチャイムの確認ができます。
- チャイムが何日何時何分に鳴ったか、長期間のログになります。
使用可能なドアホン
作例ではドアホンはPanasonicのVL-MV38を使っています。この機種は「A接点出力」という機能がついており、チャイムが鳴った時に、2接点が短絡します。パナソニックのドアホンのうち、「電気錠制御(外部機器制御)」機能があるものが、おそらくA接点出力を持っていると思います。各製品の説明書、スペック表に明記されていると思うので確認ください。
このA接点出力をESP32で検知し、WIFI経由でGoogle HomeやAPI経由でSlack,Discordにメッセージ通知します。手順がやや複雑なので今回は実装しませんでしたが、LINEなどにも可能と思います。
ESP32のプログラム
ESP32は、ここではVSCode/PlatformIO環境で説明しています。
#include <Arduino.h>
#define USE_SLACK
#define USE_DISCORD
#define USE_GOOGLEHOME
#define WIFI_SSID "SSID"
#define WIFI_PWD "PASSWD"
#define SLACK_TOKEN "xoxb-000000000000-0000000000000-XXXXXXXXXXXXXXXXXXXXXXXX"
#define SLACK_CHANNEL "XXXXXXXX"
#define GOOGLEHOME_TARGET "書斎"
#define DISCORD_WEBHOOK "https://discord.com/api/webhooks/000000000000000000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#define PIN_SW GPIO_NUM_27
#include <HTTPClient.h>
#ifdef USE_GOOGLEHOME
#include <WebServer.h>
#include <LittleFS.h>
#include <esp8266-google-home-notifier.h>
#define MP3FILENAME "chime.mp3"
String myURL;
char *mp3Data;
int mp3DataSize;
WebServer server(80);
GoogleHomeNotifier ghn;
#endif
#ifdef USE_GOOGLEHOME
void webServer(void *) {
server.on("/", [](){
server.send(200, "text/html", "OK");
});
server.on("/" MP3FILENAME, [](){
server.send_P(200,"audio/mp3",mp3Data,mp3DataSize);
});
server.begin();
for(;;){
server.handleClient();
delay(1);
}
}
#endif
#ifdef USE_DISCORD
bool DiscordMessage(const char *text)
{
bool ret = false;
HTTPClient http;
if( http.begin(DISCORD_WEBHOOK) ==false) {
return false;
}
http.addHeader("Content-Type","application/json; charset=utf-8");
int httpCode = http.POST(String("{\"content\":\"")+text+"\"}");
if( (httpCode == 200)||(httpCode == 204) ){
ret = true;
}
else{
Serial.printf("Error %d\n",httpCode);
}
http.end();
return ret;
}
#endif
#ifdef USE_SLACK
bool SlackMessage(const char *text, const char *channel)
{
bool ret = false;
HTTPClient http;
if( http.begin("https://slack.com/api/chat.postMessage") ==false) {
return false;
}
http.addHeader("Content-Type","application/json; charset=utf-8");
http.addHeader("Authorization", "Bearer " SLACK_TOKEN);
String data = String("{\"text\":\"") + text + "\"," + "\"channel\":\"" + channel + "\"}";
int httpCode = http.POST(data);
if( httpCode == 200 ){
ret = true;
}
else{
Serial.printf("Error %d\nret=%s\n",httpCode,http.getString().c_str());
}
http.end();
return ret;
}
#endif
void setup() {
Serial.begin(115200);
// connect to WIFI
WiFi.begin(WIFI_SSID, WIFI_PWD);
while(WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.print(".");
}
Serial.println(WiFi.localIP());
#ifdef USE_GOOGLEHOME
/* read mp3 data from littleFS */
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
File file = LittleFS.open("/" MP3FILENAME, "r");
mp3DataSize = file.size();
mp3Data = (char *)malloc(mp3DataSize);
file.readBytes(mp3Data,mp3DataSize);
file.close();
myURL = String("http://") + WiFi.localIP().toString() + "/" + MP3FILENAME;
Serial.println(myURL);
#endif
pinMode(PIN_SW,INPUT_PULLUP);
Serial.printf("Poll GPIO-%d\n",PIN_SW);
#ifdef USE_GOOGLEHOME
if (ghn.device(GOOGLEHOME_TARGET, "ja") != true) {
Serial.println(ghn.getLastError());
return;
}
xTaskCreatePinnedToCore(webServer, "webserver", 4096, NULL, 1, NULL, 0); //Core 0
#endif
}
void loop()
{
static int swBefore=0;
bool sw = digitalRead(PIN_SW);
if( sw != swBefore ){
swBefore = sw;
Serial.println(sw);
if(sw == 0){
Serial.println("チャイムがなりました");
#ifdef USE_GOOGLEHOME
ghn.play(myURL.c_str());
#endif
#ifdef USE_SLACK
SlackMessage("チャイムがなりました", SLACK_CHANNEL);
#endif
#ifdef USE_DISCORD
DiscordMessage("チャイムがなりました");
#endif
}
}
// 60秒以上 WIFI接続が途切れていたらリセットする
static int ncTimer = 0;
if (WiFi.status() != WL_CONNECTED){
ncTimer++;
if (ncTimer > 60){
ESP.restart();
}
delay(1000);
}
else{
ncTimer = 0;
}
delay(10);
}
3行目から、環境設定になります。適宜、変更が必要になります。
通知先の設定
#define USE_SLACK
#define USE_DISCORD
#define USE_GOOGLEHOME
それぞれ、通知したくない行をコメントアウトします。
WIFIの設定
#define WIFI_SSID "SSID"
#define WIFI_PWD "PASSWD"
接続するWIFIのSSIDとパスワードに変更します。Google Homeを使う場合は、同一セグメントにGoogle Homeが接続されている必要があります。
Slack,Discordを使う場合は、外部へのネットワーク接続ができる必要があります。
#define PIN_SW GPIO_NUM_27
ドアホンのA接続を検知するGPIOのピンを指定します。プルアップ入力可能なピンにする必要があります。(GPIO0~33)
Google Homeの設定
GOOGLEHOME_TARGETに、音声を再生させたいGoogle Homeの名前を書きます。グループ名を指定すると、グループ全体のGoogle Homeが一斉に音声再生します。
#define GOOGLEHOME_TARGET "書斎"
Google Home Notifierライブラリのインストール
Google Homeを鳴らすために、esp8266-google-home-notifier ライブラリを使います。
PlatformIOでは、PIOHomeのLibrariesからインストールできます
LittleFSにmp3ファイルを設置する (mp3ファイルを再生したい場合)
今回はGoogle Homeからチャイム音を流したかったため、mp3ファイルを使うことにしました。mp3ファイルはESP32に置き、ESP32自体がWebサーバとなってGoogle Homeからの要求を受け、mp3ファイルを送信します。mp3ファイルはESP32上のフラッシュに LittleFS (ファイルシステム)として予め書き込んでおきます。(SPIFFSは非推奨になったようですので)
手順は下記を参考にしました。
platform.ini に以下の1行を追加し、LittleFSを使用することを指定します
board_build.filesystem = littlefs
プロジェクトフォルダ直下に、data フォルダを作成し、その下にmp3ファイルを置きます。
プロジェクトフォルダはWindowsの場合、 (ドキュメントフォルダ)/PlatformIO/Projects/(プロジェクト名) がデフォルトです。
PlatformIOの PLOJECT TASKS / (ボード名) / Platform / Upload Filesystem Image をクリックすると、data フォルダ下のファイルが LittleFSに書き込まれます。
合成音声を再生したい場合
mp3音声ではなく、Google Homeの合成音声を再生させたい場合、LittleFSの設定とmp3ファイルの設置は必要ありません。
loop()内の1行を以下を参考に書き換えてください
void loop()
{
...(略)
//ghn.play(myURL.c_str()); ← コメントアウトする
ghn.notify("チャイムがなりました");
Discordへの通知
PCからDiscordのアプリを起動し、メッセージを投稿したいサーバを右クリック、サーバー設定>連携サービス から ウエブフック を作成します。
名前、アイコンは適当に。投稿したいチャンネルを選んで、 [ウェブフックURLをコピー] します。
コピーしたURLで、DISCORD_WEBHOOKを書き換えます。
#define DISCORD_WEBHOOK "https://discord.com/api/webhooks/000000000000000000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Slackへの通知
Slackのアプリケーションページにアクセスします。(ワークスペースへのログインが必要です)
[Create New App] - [From scrach] でアプリを作成します
App Nameはアプリの名前を適当に、投稿したいワークスペースを選択して、[Create App] します
左メニューから Featues の OAuth & Permissions を選び、 Scopes / Bot Token Scopes の [Add an OAuth Scope] をクリックし、 chat:write を追加します。
[Install to Workspace]します。許可を求めてきますので[許可]します。
コピーしたトークンで、SLACK_TOKENを書き換えます
#define SLACK_TOKEN "xoxb-000000000000-0000000000000-XXXXXXXXXXXXXXXXXXXXXXXX"
動作確認
プログラムの設定が終了したら、ESP32から2本、線を出し、1本はGND,1本は プログラムで指定した PIN_SW につなぎます。
プログラムが起動し、WIFIが無事に接続されたら、2本の線をショートさせて、それぞれの通知がうまく動作するかを確認します。
あとは、ドアホンの裏のA接点端子にこの2本線を接続すれば終了です。(向きはないので逆につないでも大丈夫です)