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

# はじめに 

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


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

いくつか拝見した記事では、ドアホン親機のモニターの`輝度`やピンポーンの`音`をセンサーで検知するものがほとんどであった。
我が家のドアホン親機（Panasonic VL-MV30）には、ドアホンの「ピンポーン」に連動して`ON`になる便利な`A接点`が用意されていたので、これをプルアップしたGPIOに接続するだけでトリガーの実装は楽にできた（一方はGNDへ接続）。
![Door_Phone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/acd16b2d-62a2-b61f-2dc4-f998d970d2f9.png)

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

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


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

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

```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では、なぜかサーバに拒否されてしまう。


```python: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パラメタの渡し方が悪いのか？


```python: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`の指定が必要か？

```python: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}
```

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

```python: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`が無い・・・
```python:MicroPython
import urllib.parse
data = 'message={}'.format(quote('通知したいメッセージ'))
```

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


# 3. 運用

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

```python: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`する運用も考えられる。

```python: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円もあれば作れます（書き込み装置が別途必要）。
（~~<i>機会があれば、自作の書き込み装置も紹介したい。</i>~~ ⇒ ご参照ください。『[ESP32書き込みボード](https://qiita.com/nak435/items/500c877bcaa3d38b939a)』）


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

**以上**