インターホンやテレビドアホン、かつてはいろいろなメーカーが出していた。今はおそらくパナソニックとアイホン(iPhoneの商標はアイホン株式会社のライセンスにもとづき使用されています、のアイホン)の2社がシェアのほとんどではなかろうか。
我が家のそれはパナソニック製だが当然ネットには非対応。本体に録画機能があって留守中に誰かが来たことはわかるが、それは帰宅して本体を見るまではわからない。そう、固定電話の留守番電話みたいなもので「新着あり」表示が点灯しているのを見て初めて「ああ、誰か来たんだな」ということがわかる程度。
今ならネットに対応し、リアルタイムで外部からスマホで応答するようなものもあるかもしれないが、あってもきっと高い。まぁ壊れるまで買い替えるようなものでもないし、そういうのは決まって専用アプリが必要とか、子機だけ異様に高いとか、どこかがクソ仕様なのは昔から決まっている。
ので・・・ひとまず本体VL-MV39の裏を見ると、この機種には「A接点出力」があるではないか。
取説によれば、A接点に接続可能な機器として挙げられているのは「光るチャイム、メロディサイン、警報ランプ付ブザー、回転灯」など。つまり「玄関の呼出ボタンを押すと連動してこれらがONとなる端子」と理解できる。つまりこの端子を拝借して、ここがONしたらネットに通知するようにすれば「ネット対応」にできるわけだ(一方通行だけどないよりマシ)。
自宅のWi-Fiを経由してネットに飛ばし、自分のスマホ宛に通知する仕掛けが出来れば「何かカッコイイ」し、何よりリアルタイムにどこにいても来客があったことは確認できる、というよりは(もちろん、防犯的にはそれでも良いと思う)、誰かが来たことがあらかじめわかっていれば帰宅してから本体の録画をチェックすればいいのであって、そのチェック忘れの防止にもなるわけだ。今回の目的はどちらかと言えばそっち。
そう、いつの間にか「新着あり」表示が点灯していて録画を見ると何件も溜まっていたなんてことは常である。とはいえ、郵便屋さんと宅配の人がほとんどで、再配達の伝票があればそこで突き合わせてOKなんだけど。それ以外ってセールスとか宗教とか得体の知れないやつだけど、たまに近所の人とかが来てることがあって「あれ、何だろう?」と気になったりはするしね。
というわけで、ここにESP32を使用する。通知はLINE Notifyが簡単で良い。ほんで、こんな具合にA接点出力とGPIOをつないでプログラムをごにょごにょと書く。OTA対応で書いた。
#include <WiFi.h> //Wi-Fi
#include <WiFiClientSecure.h> //Wi-Fi
#include <ESPmDNS.h> //OTA
#include <WiFiUdp.h> //OTA
#include <ArduinoOTA.h> //OTA
#define A_SW 13
#define JST 3600 * 9
#define PUSH_SHORT 100
String hostname = "INTPHONE";
boolean button = 0;
// WiFi設定
const char* ssid = "Your SSID";
const char* password = "Your PASSWORD";
IPAddress ip(192, 168, 11, 240); //ESP32のIPアドレスを固定する場合のアドレス
IPAddress subnet(255, 255, 255, 0); //ESP32のIPアドレス固定する場合のサブネット
IPAddress gateway(192, 168, 11, 1); //ルーターのゲートウェイを入れる
IPAddress DNS(192, 168, 11, 1);
bool done = true;
RTC_DATA_ATTR int bootCount = 0;
void setup() {
pinMode(A_SW, INPUT_PULLUP);
WiFi.config(ip, gateway, subnet, DNS);
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
// WiFi接続
WiFi.disconnect(true, true);
WiFi.mode(WIFI_STA);
WiFi.setHostname(hostname.c_str());
WiFi.begin(ssid, password);
while (done) {
Serial.print("Wi-Fi connecting");
auto last = millis();
while (WiFi.status() != WL_CONNECTED && last + 5000 > millis()) {
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
done = false;
} else {
Serial.println("Retry");
WiFi.disconnect(true, true);
//WiFi.reconnect();
ESP.restart();
}
}
Serial.println("Wi-Fi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
configTime(JST, 0, "pool.ntp.org", "jp.pool.ntp.org");
delay(5000);
send_Line("起動OK!");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else
type = "filesystem";
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
// Close=0 Open=1
// the loop routine runs over and over again forever:
void loop() {
ArduinoOTA.handle();
///////////////////////
time_t t;
struct tm* tm;
static const char* wd[7] = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
t = time(NULL);
tm = localtime(&t);
/*
Serial.printf("%04d/%02d/%02d(%s) %02d:%02d:%02d\n",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
wd[tm->tm_wday],
tm->tm_hour, tm->tm_min, tm->tm_sec);
*/
// 毎日06:05にRestart(ハングアップ対策)
if ((tm->tm_hour == 06) && (tm->tm_min == 05) && (tm->tm_sec == 00)) {
ESP.restart();
}
unsigned long gauge = 0;
while (!digitalRead(A_SW)) {
gauge++;
}
if (gauge > PUSH_SHORT) {
button = !button;
send_Line("おや?誰か来たよ!");
delay(60000);
}
}
// LINE Notify設定
const char* host = "notify-api.line.me";
const char* token = "Your TOKEN";
// LINE通知
void send_Line(String message) {
// HTTPSへアクセス(SSL通信)するためのライブラリ
WiFiClientSecure client;
// サーバー証明書の検証を行わずに接続する場合に必要
client.setInsecure();
Serial.println("LINE Connection Try!");
// LINEのAPIサーバにSSL接続(ポート443:https)
if (!client.connect(host, 443)) {
delay(2000); //2秒
Serial.println("LINE Connection failed");
delay(2000); //2秒
ESP.restart();
return;
}
Serial.println("LINE Connected Success!");
// リクエスト送信
String query = String("message=") + "\n" + message;
String request = String("") + "POST /api/notify HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Authorization: Bearer " + token + "\r\n" + "Content-Length: " + String(query.length()) + "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n\r\n" + query + "\r\n";
client.print(request);
delay(5000); //5秒
// 受信完了まで待機
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
break;
}
}
String line = client.readStringUntil('\n');
}
USBから書き込んで、動作確認したら完了。なお、インターホン本体にAC100Vが直接接続されているモノは電気工事士でないと電源は外すことが出来ない(私は電気工事士免状を持っているので無問題)。玄関子機への配線や、コンセントタイプの電源であればもちろん無資格で外すことは可能。一旦外してボックスを追加してESP32を収納し、内部から電源を取って動作するように加工した。信頼できる超小型の5V電源ってiPhone純正の充電器くらいしか思い浮かばないんだけど、インターホン本体内部から5V取れたらそうしようかな。壁付けから宙に浮いて見えるようになって、むしろカッコイイ(とは言わない配線や基板が剥き出しのものがごちゃごちゃするのは美しくないのでそれよりはマシ)。
これが
こうなったわけだが、
そんなに違和感ない。
玄関ドアの開閉通知はこっちに記載。
コメント