ESP32とLINE Notifyを使ってナースコール的なのを作る

# ESP32とLINE Notifyを使ってナースコール的なのを作る

![esp32_overview.png](https://qiita-image-store.s3.amazonaws.com/0/42735/cdcb1d05-71a3-f00f-f547-b939c4812fb0.png)

## はじめに

トイレなど見守りが必要に急になってしまいました。
そこで、介護が必要になってしまった両親のために作りました。
ナースコールみたいにボタンが押したら近くにいなくてもわかるようになったらいいかなぁっていうところから始めました。

## 構成

ナースコールに相当する押しボタン、[ESP32](https://ja.wikipedia.org/wiki/ESP32)、[LINE Notify](https://notify-bot.line.me/ja/)を使って自分のLINEに通知します。

![overall.png](https://qiita-image-store.s3.amazonaws.com/0/42735/3af285a2-30bf-b5b4-4f6b-e64a2e1b7eac.png)

## 試作

まず試作として、M5Stackを利用してボタンを押したらLINEに通知をできるようにしました。

### 試作１：Wi-Fiアクセスポイントに接続する

インターネットに接続するために、まずはWi-Fiアクセスポイント(以下AP)に接続をまずしてみます。
includeに下記の２つを追加しました。

```c
#include <WiFi.h>
#include <WiFiMulti.h>
```

AP接続するコードを作りました。関数化してあとで流用しやすいようにします。

```c
const char* ssid = "ssid";
const char* password = "password";
void wifiConnect() {
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);  // Wi-Fi接続
  while (WiFi.status() != WL_CONNECTED) {  // Wi-Fi 接続待ち
    delay(100);
    Serial.printf(".");
  }
  Serial.println("\nwifi connect ok");
}
```

最後に`setup()`内に先ほどのAP接続するコードを追加し、起動したらすぐに実行されるようにします。

```c
// The setup() function runs once each time the micro-controller starts
void setup() {
  // init lcd, serial, not init sd card
  M5.begin(true, false, true);

  wifiConnect();
  
```

これでM5Stackに書き込みし実行するとAPに接続できました。

### 試作２：LINE Notifyに通知してみる。

[「猫の食生活」を超音波距離センサーでLINEに通知してみた─にゃんてっく☆やせないアイツ【vol5】](https://next.rikunabi.com/journal/20170719_t12_iq/)の記事で使われていた[こちらのコード](https://github.com/kyoro/nyantech/blob/master/nekomogu/nekomogu_line_notify/nekomogu_line_notify.ino#L36-L69)を使わせていただきました。

私の方で通知するメッセージを書き換えたかったので少しだけ改良しました。
includeに下記の３つを追加しました。

```c
#include <ssl_client.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
```

通知するコードは次の通りです。引数に文字列を渡せるようにしました。

```c
void send(String message) {
  const char* host = "notify-api.line.me";
  const char* token = "hogehoge_token";
  WiFiClientSecure client;
  Serial.println("Try");
  //LineのAPIサーバに接続
  if (!client.connect(host, 443)) {
    Serial.println("Connection failed");
    return;
  }
  Serial.println("Connected");
  //リクエストを送信
  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);
 
  //受信終了まで待つ 
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
    if (line == "\r") {
      break;
    }
  }
  
  String line = client.readStringUntil('\n');
  Serial.println(line);
}
```

上記サンプルコードでは、トークンを **hogehoge_token** としていますが、実際はLine Notifyページにてトークンを発行した文字列に置き換えてください。

通知するコードは出来上がったので`loop()`内でボタン押下をチェックして通知してみることにしました。

M5Stackサンプルスケッチ(BASIC>Button)をベースに下記のように書き換えました。（書き換えた場所のみ記載してあります。）

```c
// Add the main program code into the continuous loop() function
void loop() {
  M5.update();
 
  // if want use Releasefor; suggest use Release in press event
  if (M5.BtnA.wasReleased()) {
    M5.Lcd.print('A');
    send("A Button");
  } else if (M5.BtnB.wasReleased()) {
    M5.Lcd.print('B');
    send("B Button");
  } else if (M5.BtnC.wasReleased()) {
    M5.Lcd.print('C');
    send("C Button");
    			︙
```

これをM5Stackに書き込み実行すると各ボタンを押すとLINEに通知されました。

## 実際に作る

ESP8266で作ろとしましたが、どうしても同じように作っても通知できませんでした。（ボタンを数個しかつけないのでこれで十分なのですが・・・）
ということで、M5Stackと同じESP32を使うことにしました。  

### プルアップ配線

ボタンなどのスイッチのON/OFFの状態をマイコンで取得するにはプルアップ配線をしてあげる必要があります。  
google検索してみたら[意外と知られていない？INPUT_PULLUP | スイッチサイエンス マガジン](http://mag.switch-science.com/2013/05/23/input_pullup/)を記事を見つけました。  

記事中に下記のように記載されていました。
> INPUTキーワードの代わりにINPUT_PULLUPキーワードを使ってみましょう。このキーワードを使うと、そのピンがINPUTモードになると共に、マイコンチップ内部のプルアップ抵抗が有効になります
([意外と知られていない？INPUT_PULLUP | スイッチサイエンス マガジン](http://mag.switch-science.com/2013/05/23/input_pullup/)より引用)

今回はこちらを活用したいと思います。
なのでスイッチの一方をGNDへ、もう一方をGPIOに接続してあげます。
秋月電子で購入した[ＥＳＰ３２－ＤｅｖＫｉｔＣ　ＥＳＰ－ＷＲＯＯＭ－３２開発ボード](http://akizukidenshi.com/catalog/g/gM-11819/)を使い、GPIO12,14,27を使いました。

まずは、`setup()`に **INPUT_PULLUP** を指定します。
今回は、GPIO12,14,27にスイッチを配線します。

```c
#define SWITCH1 12
#define SWITCH2 14
#define SWITCH3 27

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  Serial.println("setup start");
  pinMode(SWITCH1, INPUT_PULLUP);
  pinMode(SWITCH2, INPUT_PULLUP);
  pinMode(SWITCH3, INPUT_PULLUP);
  
  wifiConnect();
}
```

### ボタン検出とLINEへの通知

`loop()`内で、ボタンの押下状態を取得し、押下されていればLINEに通知します。

```c
void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(SWITCH1) == LOW) {
    send("白色ボタン");
  } else if (digitalRead(SWITCH2) == LOW) {
    send("黄色ボタン");
  } else if (digitalRead(SWITCH3) == LOW) {
    send("呼び出しボタン");
  }
}
```

実行してみると狙い通り通知されました。

![Line_Timeline.png](https://qiita-image-store.s3.amazonaws.com/0/42735/ade11f8b-6f01-368a-c30a-c25d337d310c.png)

## 最後に

今回は、スイッチに [エルパ にぎり押ボタンスイッチ](http://elpadirect.com/shopdetail/000000000068/) を使いました。
他にも押しボタンスイッチをつけました。

## 実機の写真

TAKACHI TW5-3-9にいれましたが、もう少し大きい方がいいと思いました。

![esp32_top.png](https://qiita-image-store.s3.amazonaws.com/0/42735/0c221ddd-3867-3b4e-5628-accf92327885.png)
![esp32_back.png](https://qiita-image-store.s3.amazonaws.com/0/42735/94fa6110-9db7-2bf5-5732-789f680bec7e.png)