82
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ドアホンが鳴ったらGoogleHome,Slack,Discordに通知する (ESP32)

Last updated at Posted at 2022-07-09

ドアホンが鳴ったらGoogleHome,Slack,Discordに通知する

リモートワークなどで玄関から遠い部屋で作業をしていると、ドアホンのチャイムがちょっと聞こえにくいことがありませんか?
これを解決するために、Google HomeやSlack,Discordなどへ通知する方法です。無題のプレゼンテーション.jpg

特徴

  • グループ登録すれば複数の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環境で説明しています。

main.cpp
#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行目から、環境設定になります。適宜、変更が必要になります。

通知先の設定

main.cpp
#define USE_SLACK
#define USE_DISCORD
#define USE_GOOGLEHOME

それぞれ、通知したくない行をコメントアウトします。

WIFIの設定

main.cpp
#define WIFI_SSID "SSID"
#define WIFI_PWD "PASSWD"

接続するWIFIのSSIDとパスワードに変更します。Google Homeを使う場合は、同一セグメントにGoogle Homeが接続されている必要があります。
Slack,Discordを使う場合は、外部へのネットワーク接続ができる必要があります。

main.cpp
#define PIN_SW  GPIO_NUM_27

ドアホンのA接続を検知するGPIOのピンを指定します。プルアップ入力可能なピンにする必要があります。(GPIO0~33)

Google Homeの設定

GOOGLEHOME_TARGETに、音声を再生させたいGoogle Homeの名前を書きます。グループ名を指定すると、グループ全体のGoogle Homeが一斉に音声再生します。

main.cpp
#define GOOGLEHOME_TARGET "書斎"

Google Home Notifierライブラリのインストール

Google Homeを鳴らすために、esp8266-google-home-notifier ライブラリを使います。

PlatformIOでは、PIOHomeのLibrariesからインストールできます
image.png

LittleFSにmp3ファイルを設置する (mp3ファイルを再生したい場合)

今回はGoogle Homeからチャイム音を流したかったため、mp3ファイルを使うことにしました。mp3ファイルはESP32に置き、ESP32自体がWebサーバとなってGoogle Homeからの要求を受け、mp3ファイルを送信します。mp3ファイルはESP32上のフラッシュに LittleFS (ファイルシステム)として予め書き込んでおきます。(SPIFFSは非推奨になったようですので)

手順は下記を参考にしました。

platform.ini に以下の1行を追加し、LittleFSを使用することを指定します

platform.ini
board_build.filesystem = littlefs

プロジェクトフォルダ直下に、data フォルダを作成し、その下にmp3ファイルを置きます。
プロジェクトフォルダはWindowsの場合、 (ドキュメントフォルダ)/PlatformIO/Projects/(プロジェクト名) がデフォルトです。
image.png

PlatformIOの PLOJECT TASKS / (ボード名) / Platform / Upload Filesystem Image をクリックすると、data フォルダ下のファイルが LittleFSに書き込まれます。
image.png

合成音声を再生したい場合

mp3音声ではなく、Google Homeの合成音声を再生させたい場合、LittleFSの設定とmp3ファイルの設置は必要ありません。
loop()内の1行を以下を参考に書き換えてください

main.cpp
void loop()
{
 ...()
      //ghn.play(myURL.c_str());  ← コメントアウトする
      ghn.notify("チャイムがなりました");

Discordへの通知

PCからDiscordのアプリを起動し、メッセージを投稿したいサーバを右クリック、サーバー設定>連携サービス から ウエブフック を作成します。
名前、アイコンは適当に。投稿したいチャンネルを選んで、 [ウェブフックURLをコピー] します。
image.png

コピーしたURLで、DISCORD_WEBHOOKを書き換えます。

main.cpp
#define DISCORD_WEBHOOK "https://discord.com/api/webhooks/000000000000000000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Slackへの通知

Slackのアプリケーションページにアクセスします。(ワークスペースへのログインが必要です)

[Create New App] - [From scrach] でアプリを作成します
image.png

App Nameはアプリの名前を適当に、投稿したいワークスペースを選択して、[Create App] します
image.png

左メニューから FeatuesOAuth & Permissions を選び、 Scopes / Bot Token Scopes[Add an OAuth Scope] をクリックし、 chat:write を追加します。
image.png

[Install to Workspace]します。許可を求めてきますので[許可]します。
image.png

BotのTokenが生成されるのでコピーします。
image.png

コピーしたトークンで、SLACK_TOKENを書き換えます

main.cpp
#define SLACK_TOKEN "xoxb-000000000000-0000000000000-XXXXXXXXXXXXXXXXXXXXXXXX"

動作確認

プログラムの設定が終了したら、ESP32から2本、線を出し、1本はGND,1本は プログラムで指定した PIN_SW につなぎます。
プログラムが起動し、WIFIが無事に接続されたら、2本の線をショートさせて、それぞれの通知がうまく動作するかを確認します。

あとは、ドアホンの裏のA接点端子にこの2本線を接続すれば終了です。(向きはないので逆につないでも大丈夫です)

image1png image2jpg
82
76
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
82
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?