ATOM liteを使って見守りボタンを作ってみた

# きっかけ
先月義母が亡くなりました。
義母も義父も要介護で、老々介護ながらなんとかお互いにケアしながらやっていましたが、とうとう義父独り暮らしになってしまいました。。
義父独りで居る時に何かあったらどうする？家族で色々検討しましたが、なかなかフィットするサービスがありません。
腕時計タイプで常に監視してくれるようなサービスもありますが、自分が着ける側だったら常に監視されてるみたいできっといやだろうな。。カメラで監視するのもいいけど、やっぱり最大限プライバシーは保ちたい。。
家族であれこれ議論した結果、対策として、
1. Amazon Echo Showの「呼びかけ」機能でいつでもTV電話できるようにする
2. 緊急連絡ボタンを押すと家族に一斉連絡が来るようにする

を実施することにしました。

# 要件
1は買って設定するだけなので簡単です。問題は2です。
調べたところ、それらしいものは色々あるのですがなかなか「これだ！」というものがありません。
Bluetooth接続のボタンとスマホを連携して通知する、みたいなものは結構あるのですが、そもそも義父はガラケーなのと、常にスマホを身に着けるような習慣もついていません。
いざ倒れた時にできることは限られています。なるべくシンプルに、いつもの場所に置いてあるボタンを押すだけで良いようにしたい。しかも通信も安定したものを使いたい…。

# 実現手段の検討
家族への一斉連絡手段はLINEグループ一択でした。だってみんな使ってるし。
LINE Notifyを使えば比較的簡単に実現できそうです。
緊急連絡ボタンのほうはあれこれ考えた結果、うちに転がっているM5StackのATOM Liteを使って実現することにしました。ATOM LiteならWifi接続もできるし、ボタンも自分で最適なものが選択できそうです。
![plan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143766/bf1da8dd-deeb-7ac2-ad5e-8de91f1b6de3.png)


# 実装
## ハードウェアの検討と実装
緊急時に押しやすいボタン、緊急時に押しやすいボタン…。Amazonで一生懸命探しました。
結局[機械の緊急停止に使うようなプッシュスイッチ](https://amzn.asia/d/bGfqBVS)を選択。
ATOM Liteの裏面にはM2のネジ穴がついてるので、スイッチとATOM Liteをネジで固定し、GPIOの配線もスイッチに穴を開けて内部へ配線。
![DSC_2545.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143766/9e0bf0c6-777e-5cb5-5691-e420cdfbdebe.jpeg)


## LINE Notifyの設定
LINE Notifyのページにログインしてグループに投稿するためのアクセストークンを発行します。
このあたりの手順は参考事例が色々あると思いますので検索してみてください。
[LINE Notify](https://notify-bot.line.me/ja/)

## 通知プログラムの実装
ATOM Liteのプログラムの実装はPlatformIOで行いました。
※ プログラムを参考にする場合は各自の責任において利用してください
```main.cpp
#include <M5Atom.h>
#include <WiFiClientSecure.h>

boolean switch_flg = false;
const char* message_array[] = {"緊急連絡ボタンが解除されました。","緊急連絡ボタンが押されました！"};
const int PUSH_BUTTON_ON  = 1;
const int PUSH_BUTTON_OFF = 0;

// Wi-Fi
const char* ssid = "xxxxxxxxxx";     // WifiのSSID
const char* password = "xxxxxxxxxx"; // Wifiのパスワード
WiFiClientSecure client;

// Line Notify
const char* host = "notify-api.line.me";
const char* token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // 取得したアクセストークン

// LED
const int brightness = 16;
const CRGB LED_YELLOW = (brightness << 16) | (brightness << 8) | 0;
const CRGB LED_BLUE = (0 << 16) | (0 << 8) | brightness;
const CRGB LED_RED = (brightness << 16) | (0 << 8) | 0;
const CRGB LED_GREEN = (0 << 16) | (brightness << 8) | 0;
const CRGB LED_OFF = (0 << 16) | (0 << 8) | 0;


// LINE Notify
int request_line_notify(String message) {
  int rc = 1;
  client.setInsecure();
  if (!client.connect(host, 443)) {
    return rc;
  }
  String query = String("message=") + 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);
  client.flush();
  client.stop();
  rc = 0;
  return rc;
}

// Button操作時処理
int button_action(int pushbutton){
  M5.dis.drawpix(0, LED_GREEN);
  if(!request_line_notify(message_array[pushbutton])){
    M5.dis.drawpix(0, LED_BLUE);
    delay(1000);
    return 0;
  }else{
    M5.dis.drawpix(0, LED_RED);
    delay(1000);
    return 1;
  }
}

void setup() {
  M5.begin(true, false, true);
  pinMode(32, INPUT_PULLUP);
  M5.dis.drawpix(0, LED_OFF);

  // Wi-Fi connection
  WiFi.begin(ssid, password);
  while(WiFi.status() != WL_CONNECTED){
    M5.dis.drawpix(0, LED_YELLOW); 
    delay(300);
    M5.dis.drawpix(0, LED_OFF); 
    delay(2000);
  }
  M5.dis.drawpix(0, LED_BLUE);
  delay(2000);
}

void loop() {
  M5.update();

  if(WiFi.status() != WL_CONNECTED){
    M5.dis.drawpix(0, LED_RED); 
    delay(1000);
    ESP.restart();
  }

  if(digitalRead(32)){
    if(!switch_flg){
        switch_flg = true;
        if(button_action(PUSH_BUTTON_ON)){
          ESP.restart();
        }
    }
  }else{
    if(switch_flg){
        switch_flg = false;
        if(button_action(PUSH_BUTTON_OFF)){
          ESP.restart();
        }
    }
  }
  
  M5.dis.drawpix(0, LED_OFF);
  delay(1);
}
```
以下のような動きをします。
- 電源Onと同時にWifiに接続しに行く。Wifi未接続の状態はLEDが黄色点滅。
Wifi接続が確立するとLEDが1秒間青色に点灯後、消灯。
- ボタンが押されるとLEDが緑色に点灯し、LINE Notifyへメッセージを送信。
メッセージ送信処理が完了するとLEDが1秒間青色に点灯後、消灯。
- ボタンがリリースされるとLEDが緑色に点灯し、LINE Notifyへメッセージを送信。
メッセージ送信処理が完了するとLEDが1秒間青色に点灯後、消灯。
- Wifiの接続が失われる等、正しく通知が行えない状態の場合はLEDが1秒間赤色に点灯後、本体をリセット。(電源Onの状態に戻る)

![VID_107801016_203958_777_240_240.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143766/3794eb8b-b1d0-eae4-1971-0ed8697b51aa.gif)

実装上で悩んだ所は特にありませんでした。
強いて言うなら最初client.stop()をしていなくて、ボタンを何回か押すとheapが圧迫されて動作が不安定になり「？」ってなったぐらい。

今回作ったのと同じものを何個か作って、居間、寝室、脱衣所等に設置しようと思います。

# さいごに
今回は身内の見守り用に作りましたが、こういうボタンって結構使い道があるかもなと思いました。
例えば飲食店で要注意の客が現れた時にさりげなく通知してヘルプを呼ぶとか。。

久しぶりに物作るとやっぱり楽しいですね。^^