LoginSignup
8
6

【ESP32・MicroPython】ドアホンが鳴ったらLINEに通知する

Last updated at Posted at 2022-09-13

はじめに

平日のテレワークは2Fで作業しており、1Fにあるドアホンの「ピンポーン」に気が付かないことが多々あった。そこで、
ドアホンが鳴ったらLINEに通知するガジェットをESP32のMicroPythonで作成した。
今やありきたりのネタであるが、検索でヒットした当Qiitaやブログ記事とはちょっと違う点があるので、そこを中心にまとめる。

1. トリガーはドアホンのA接点

いくつか拝見した記事では、ドアホン親機のモニターの輝度やピンポーンのをセンサーで検知するものがほとんどであった。
我が家のドアホン親機(Panasonic VL-MV30)には、ドアホンの「ピンポーン」に連動してONになる便利なA接点が用意されていたので、これをプルアップしたGPIOに接続するだけでトリガーの実装は楽にできた(一方はGNDへ接続)。
Door_Phone.png

最小適用負荷:DC5V/1mAの記載があるが、こんなにも電流は流れないはず。電圧も3.3V。

なお、ドアホンに応答しない場合、最長30秒間ONが継続するため、その間に何度もLINEに通知しないロジックが必要。と言っても、LINEに通知後、while文OFFになるのを待つだけ。

2. LINEへの通知はrequestsモジュールのpost

いくつか拝見した記事では、Arduino化したESP32(C++)しか見当たらず、MicroPythonでの例は見つけられなかったが、PCによるPythonでの実装例は簡単に見つけられる。

Python3 (PC)
import requests
import json

url = 'https://notify-api.line.me/api/notify'
headers = {
    'Authorization': 'Bearer ' + TOKEN
}
data = {
    'message': '通知したいメッセージ'
}
response = requests.post(url, headers=headers, data=data).json()
print(response)
# {'status': 200, 'message': 'ok'}

PCで試したところ、わずか数行のコードで実現できることが確認できた。しかし、MicroPythonのurequestsでは、なぜかサーバに拒否されてしまう。

MicroPython (ESP32)
import urequests as requests
import ujson as json

url = 'https://notify-api.line.me/api/notify'
headers = {
    'Authorization': 'Bearer ' + TOKEN
}
data = {
    'message': '通知したいメッセージ'
}
response = requests.post(url, headers=headers, data=data).json()
#Traceback (most recent call last):
#  File "<stdin>", line 13, in <module>
#  File "urequests.py", line 120, in post
#  File "urequests.py", line 82, in request
#TypeError: object with buffer protocol required

postパラメタの渡し方が悪いのか?

MicroPython (ESP32) 変更分のみ
data = 'message=通知したいメッセージ'
response = requests.post(url, headers=headers, data=data).json()
print(response)
# {'message': 'message: must not be empty', 'status': 400}

messageを指定しているつもりだが?
Content-Typeの指定が必要か?

MicroPython (ESP32) 変更分のみ
headers = {
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Authorization': 'Bearer ' + TOKEN
}
response = requests.post(url, headers=headers, data=data).json()
print(response)
# {'message': 'ok', 'status': 200}

試行錯誤の結果、上記のコードにたどり着くまでにかなりの時間を要した。うまく動作したコードは以下の通り。

MicroPython (ESP32)で うまく動作したコード
import urequests as requests
import ujson as json

url = 'https://notify-api.line.me/api/notify'
headers = {
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Authorization': 'Bearer ' + TOKEN
}
data = 'message=通知したいメッセージ' #quote処理が必要
response = requests.post(url, headers=headers, data=data).json()

本来ならquote処理が必要だが、MicroPythonにurllib.parseが無い・・・

MicroPython
import urllib.parse
data = 'message={}'.format(quote('通知したいメッセージ'))

こう書きたい所であるが、今回は固定メッセージのため、必要なら手動quoteで逃げる。

3. 運用

24H365D運用だが、ESP32がそんな連続運転に耐えるのか不明のため、1日1回強制リセットすることにした。午前3時にmachine.reset()して基本は24H運用。
boot.pyでWifiに接続済みの前提)

MicroPython (ESP32) 午前3時の判定と強制リセット
import machine
import time
import ntptime

ntptime.settime() #ntpによる時刻合わせ

JST_OFFSET = 9 * 60 * 60   # +09:00
def time_out(t):
    now = time.localtime(time.time() + JST_OFFSET)
    _, _, _, hour, minute, second, _, _ = now
    if hour == 3 and minute == 0 and 0 <= second <= 3:
        machine.reset() #再起動 (再起動には3秒以上かかる前提)

tim = Timer(-1)
tim.init(period=1000, mode=Timer.PERIODIC, callback=time_out)

深夜・未明にドアホンが押されることは通常では考えられないため、例えば、22時から翌朝6時まではDeepSleepする運用も考えられる。

MicroPython (ESP32) 22時の判定と翌朝6時までDeepSleep
# 変更分のみ
def time_out(t):
    now = time.localtime(time.time() + JST_OFFSET)
    _, _, _, hour, minute, second, _, _ = now
    if hour == 22 and minute == 0 and 0 <= second <= 3:
        sleep_time = (6 - 22 + 24) * 60 * 60 * 1000
        machine.deepsleep(sleep_time) #スリープ&再起動

DeepSleepからの目覚めは強制リセットと同じ動きとなるので、好都合でもある。

おわりに

何かの参考になれば幸いです。

こんなことが簡単に実現できてしまうとは、ホント便利な時代ですね。
ESP32だけなので、500円もあれば作れます(書き込み装置が別途必要)。
機会があれば、自作の書き込み装置も紹介したい。 ⇒ ご参照ください。『ESP32書き込みボード』)

今回は14〜5年前のドアホンでしたが、もしかして最新のテレビドアホンは、最初からWifiに繋がってたりして・・・

以上

8
6
4

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
8
6