郵便受けに投函されたらSlack/LINEに通知してみた

# 概要
## 解決したい課題
マンションに住んでいるのですが、帰宅時の導線上に郵便受けがなく、部屋のドアを開けるまでにちょっと遠回りしないといけない構造になっており、郵便受けを開けに行くのをサボりがちな毎日。　　
またリモートワークになっていることもあり、中身があるかどうかわからない郵便受けを開けに行くのがなかなかストレスでした。
最近は自治体のワクチン接種のお知らせが来てないかを毎日チェックしてます。まだ来てない。

そんなわけで毎日郵便受けを開けに行くことなく、郵便受けに何かが入ったかどうかを検知したい。

## 解決方針
郵便受けの口（投函側）が空いたかどうかを検知し、LINEまたはSlackに対して通知をしたいと思います。
郵便受けの回りは当然Wi-Fiも飛んでいないので、LTE回線を利用できるIoTデバイスを利用しました。

基本的には[こちらの記事](https://qiita.com/Yuta_Fujiwara/items/8adf89f8b5b89d75ae64)を参考に、[SORACOM LTE-M Button Plus](https://soracom.jp/store/5207/)を用いて実装しました（※実際に購入したのは[IoT 体験キット 〜磁気センサー〜](https://soracom.jp/products/kit/magnetic_sensor_kit/)の方）。
こちらの記事ではjavascriptで実装されていたので、自分は慣れてるPythonで実装。ついでにLINEへの通知も実装しました。

https://qiita.com/Yuta_Fujiwara/items/8adf89f8b5b89d75ae64

# 実装
![postal_notify.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254900/98f8d6f8-a218-42c3-6471-d9b9387289c7.png)


GitHubにupしました。

https://github.com/ck-fm0211/notification-from-mailbox

```python
from flask import abort, Response
import os
from datetime import datetime, timezone, timedelta
import requests
import json

def notify_from_mailbox(request):

    JST = timezone(timedelta(hours=+9), 'JST')
    dt_now = datetime.now(JST)

    if request.method != 'POST':
        print(f'This is not post request: {request.method}')
        return Response(response=f'This is not post request: {request.method}', status=400)

    request_dict = request.get_json()

    # バッテリー情報を取得する
    if request_dict['batteryLevel'] >= 0.5:
        battery_notification = 'バッテリー残量は充分です'
    else:
        battery_notification = 'そろそろバッテリーが切れます'

    notify_message = "ポストに投函がありました。\n" \
    + f"投函時刻：{dt_now.strftime('%Y年%m月%d日 %H:%M:%S')}\n" \
    + f"{battery_notification}\n" \
    + f"<debug> clickType: {request_dict['clickType']}"

    # Slackへ送信
    slack_payload = {"token": os.environ['SLACK_TOKEN'],
                    "channel": os.environ['SLACK_CHANNEL'],
                    "username": "ポスト投函通知",
                    "text": f"<!channel> {notify_message}"}

    slack_res = requests.post('https://slack.com/api/chat.postMessage', data=slack_payload)

    # LINEへ通知
    headers = {
        "Authorization": f"Bearer {os.environ['LINE_ACCESS_TOKEN']}",
    }

    files = {
        "message": (None, notify_message),
    }

    line_res = requests.post("https://notify-api.line.me/api/notify", headers=headers, files=files)

    return {"slack": slack_res.json(), "line": line_res.json()}

```

上記をGCP Cloud Functionsにデプロイし、そのエンドポイントをSORACOMのコンソールから指定すればOK。
- SORACOMの設定: https://soracom.jp/recipes_index/2966/
- Slackの設定: https://www.whizz-tech.co.jp/5857/
- LINEの設定: https://rooter.jp/web-crawling/line-notify_with_python/

## 独自の部分
LINEへの通知以外に、参考にした記事から実装を少し変えたのは２点あります。

### バッテリー残量を通知
SORACOM LTE-M Button Plusは単４電池で動かしていますが、電池の残量も合わせて通知してくれています。

```json:SORACOM&#x20;LTE-M&#x20;Button&#x20;Plusの通知内容
{
    "clickType": 1,
    "clickTypeName": "SINGLE",
    "batteryLevel": 1,
    "binaryParserEnabled": true
}
```

この`batteryLevel`が0.5を切ったら通知内容にバッテリー残量が少ないことを通知するようにしています。

### clickTypeによる判定を削除
`clickType`とは、SORACOM LTE-M Button Plusのボタンをどのように押したかの情報が入っています。

| `clickType` | 意味 |
|:-:|:-:|
| `1` | シングルクリック |
| `2` | ダブルクリック |
| `3` | 長押し |

郵便受けの口がどのように開くかは郵便屋さんの操作次第であるため、`clickType`が1,2,3いずれになるかは予想が付きませんでした。そのため`clickType`による処理の分岐はやめておきました。
一応、通知内容にどの`clickType`だったかを入れるようにしているので、運用していく中で必要に応じて処理を入れることもあるかもしれません。

## ちょっとハマったところ
~~SORACOM公式の実装例と実物とで、配線の色の組み合わせがどうも違うみたいでした。実装例では「赤」「灰」のコードの組み合わせになっているのですが、それだとどうしても動かず、試しに「赤」「白」の組み合わせにしたら思い通りに動いたため、初期不良かあるいは実装例に誤りがあるのではないかと思われます。~~

[追記]
実装例をよく見たら
> A: お手元のセンサー部のケーブル色が「赤・白・灰」における動作

> B: お手元のセンサー部のケーブル色が「茶・白・灰」における動作

の2種類が書いてあった。「赤・白・灰」の方を見ながらやってたけど、手元にあるのは「茶・白・灰」だった。
なので実装例通りの配線でした。初期不良とか疑って申し訳ありませんでした。

# 完成
![SORACOMLTE-MButtonPlus設置.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254900/3ad38ca1-0a2f-e743-479a-9dcf6cb745f2.png)

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254900/d310f9cd-835f-27b7-7274-cd8ddf9817d2.gif)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254900/876ddd51-1a28-403e-3220-70d7888706b3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254900/9490fb4e-36b8-2ac4-9684-10d621a34024.png)

# まとめ
参考記事のおかげもあり、とてもかんたんに実装できました。

実装の運用はこれからですが、生活が潤いそう。

Cloud FunctionsからAlexaへ通知して、郵便受けに物が入ったらAlexaに教えてもらう、みたいなのもできそうだなと思いました。

# 参考
https://qiita.com/Yuta_Fujiwara/items/8adf89f8b5b89d75ae64

https://soracom.jp/store/5237/

https://soracom.jp/recipes_index/2966/

https://users.soracom.io/ja-jp/guides/iot-devices/lte-m-button-plus/faq/#%E3%83%87%E3%83%BC%E3%82%BF%E9%80%9A%E4%BF%A1%E9%87%8F%E3%81%AF%E3%81%A9%E3%81%AE%E3%81%8F%E3%82%89%E3%81%84%E3%81%A7%E3%81%99%E3%81%8B

https://www.whizz-tech.co.jp/5857/

https://rooter.jp/web-crawling/line-notify_with_python/