M5Stackから位置情報をambientに記録し、LINEに結果を通知してみた。

#はじめに
祝！2019年初投稿！:flag_jp:
今回は、去年頃から話題になりつつあるM5Stackマイコンについて書こうと思います。M5Stack始めてみたいけど、ネット上で情報が少なすぎてどうしたらいいか分からないっていう方必見です。M5Stackに触れて5日ほどしか経ってませんので、以下記事でおかしい点ありましたらご指摘よろしくお願いします。

- プロフィール
  - 学生webエンジニア(Ruby on Rails)
  - 趣味でマイコンをちょくちょく弄ってた経験あり

- 対象読者
  - M5stackでセンサリングしたい
  - M5stackで何か表示したい
  - センサリングしたデータをネット上で確認したい
  - M5stackからwebhookしてLINEやslackに通知したい 

###M5Stackとは
ESP32がベースとなった、ディスプレイ・バッテリー・ボタン・スピーカー・WiFiアンテナ・SDカードスロットなどひっくるめて一つになったマイコン。Arduino IDE での開発ができ、M5Cloudというpythonで描けるクラウド型開発環境もあるらしい

#使うもの
- m5stack basic (https://www.switch-science.com/catalog/3647/)  
スイッチサイエンスで購入
- M5Stack用GPSモジュール V2(https://www.switch-science.com/catalog/3861/)  
スイッチサイエンスで購入  
GPSの外部アンテナから伸びる端子を画像のように接続しなければ位置情報が取得できないので注意!!(内蔵アンテナを使う方法がわかる方、ぜひ教えてください)![image-1528798279626.jpg](https://qiita-image-store.s3.amazonaws.com/0/234751/3cada5d3-6ee8-c498-cb27-468ac8769dc0.jpeg)

#開発環境
macOS High Sierra
本記事ではmacを使用することを前提にしますが、windowsでもさほど手順は変わらないはずです。
以下の記事を参考にしてArduino IDEの導入をしました。
https://qiita.com/hmmrjn/items/2b2da09eecffcbdbad85

#作るもの
具体的な目標物を決めます。
今回は、日々の犬の散歩ルートの時系列位置情報を取得し、ambientを用いてGooglemap上に記された地図データを保存し、そのURLをLINEで通知するというものを作る。

#作成手順
作成手順は順を追って三つに分けます

1. M5stackがGPS信号を受信出来ているかチェックする。 
2. M5stackがambientにGPSデータを送信する。
3. M5stackからLINEに通知を送る。

##1. M5stackがGPS信号を受信出来ているかチェックする
まず以下の写真のようにM5StackとGPSモジュールが積まれてアンテナが伸びているか確認する ![IMG_0104.JPG](https://qiita-image-store.s3.amazonaws.com/0/234751/d0094aa2-fe74-06ad-3ee1-1f9366a33213.jpeg)
Arduino IDEを開いて、以下のスケッチ例を開いて書き込む。
これだけ！
<img width="1037" alt="スクリーンショット 2019-01-03 1.43.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/234751/f00b9262-3b85-864b-4031-f80faf5456a2.png">
シリアルモニタを開いて
<img width="513" alt="スクリーンショット 2019-01-03 1.46.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/234751/96a71deb-6923-25d4-6bc2-03bd05876bce.png">
GPSの生データが取得出来ていればOK
信号が来なかったり、,,,,,,,99,99,99 こんな感じだったら取得できていませんorz
マイコンの接続、アンテナを再確認してください。
##2. M5stackからambientにGPSデータを送信する
####webでの設定
ambient(https://ambidata.io/)
でユーザー登録してログインしておく
「チャネルを作る」から作成されたチャネルの、チャネルID・リードキー・ライトキーを控えておく。チャネルに入り、チャートを追加して地図グラフを作っておく。ここのチャートの項目についてはまだ詳しくないのですが、一つのチャネルで他8つのデータが管理できるようです。公開チャネルにするか非公開チャネルにするかは自由で。LINEで共有する場合は公開にしましょう。
![スクリーンショット 2019-01-03 1.59.48.png](https://qiita-image-store.s3.amazonaws.com/0/234751/dfb58a6e-10f9-8f3b-0c92-67c0829649be.png)

####Arduino IDE
プログラムは以下のサイトを参考にして一部改変しています。
https://ambidata.io/samples/m5stack/m5stack_pulse_gps/
リンク先でも記されているように、GPS生データを緯度・経度の扱いやすいデータに変換するために、[TinyGPS++](http://arduiniana.org/libraries/tinygpsplus/)ライブラリを使うことを推奨します。リンク先のzipファイルをダウンロードして下写真のようにzip形式のライブラリをインクルードしときましょう。
![スクリーンショット 2019-01-03 12.43.16.png](https://qiita-image-store.s3.amazonaws.com/0/234751/132bada7-43d5-6622-5717-48f7b863b42e.png)
以下にプログラムを記します。コメントで説明書きしています。(間違ってるかも！？ご指摘ください)


```c

#include <M5Stack.h>  //M5stack使うよ
#include <TinyGPS++.h>  //GPS生データをうまいこと処理してくれるライブラリ使うよ
#include "Ambient.h"  //Ambient使うよ

HardwareSerial GPS_s(2);  //GPSの信号端子

TinyGPSPlus gps;　 //GPSデータのインスタンス的な
WiFiClient client;  //WiFi接続に関するインスタンス的な
Ambient ambient; 　//Ambientのインスタンス的な

const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxxx";
unsigned int channelId = xxxx; // AmbientのチャネルIDを入力
const char* writeKey = "xxxxxxxxxxxxxxx"; // ライトキーを入力
const char* userKey = "xxxxxxxxxxxxxxx"; //ユーザーキーを入力
```
void setup 内で必要な処理は 

- wifi接続確認
- Ambientの初期化

```c
void setup() {
    M5.begin();

    WiFi.begin(ssid, password);  // Wi-Fi接続
    while (WiFi.status() != WL_CONNECTED) {  // Wi-Fi 接続待ち
        delay(100);
        M5.Lcd.printf(".");
    }
    M5.Lcd.println("\nwifi connect ok");

    ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
}
```
最低限setup内はこれがあれば大丈夫でしょう。
しかしWifiの接続が速い時もあれば、かなり待つ時もあるのは仕様でしょうか。。。
void loop 内は以下のようにしました。定数の値は適当に定めてください。

- 緯度・経度のデータをambientに飛ばす

がメインの処理になります。ボタンAを押すとGPSデータが記録されます。

```c

void loop() {
    M5.update();
    if(M5.BtnA.wasPressed()) {
        M5.Lcd.println("Chase start!!");
        while(1){
           delay(REDRAW);
           if (++loopcount > PERIOD * 1000 / REDRAW) {
              char buf[16];
      
              loopcount = 0;
      
              while (!gps.location.isUpdated()) {
                  while (GPS_s.available() > 0) {
                      if (gps.encode(GPS_s.read())) {
                          break;
                      }
                      delay(0);
                  }
              }
              M5.Lcd.printf("lat: %5.2f, lng: %5.2f\r\n", gps.location.lat(), gps.location.lng());
              dtostrf(gps.location.lat(), 12, 8, buf);
              ambient.set(9, buf);
              dtostrf(gps.location.lng(), 12, 8, buf);
              ambient.set(10, buf);
              ambient.send();
           }  
        }
    }
}
```
ambientチャネル内に地図が表示され現在地がポイントされていたら成功です。

##3.M5stackからLINEに通知を送る
さて、散歩ルートの時系列位置データが記録できたので、今度はそのambientチャネルのリンクをLINEで共有して通知できるようにしましょう。
二つの方法があります。

- [IFTTT](https://ifttt.com/discover)を使いwebhookシステムを使ってLINEに通知させる
- [LINE Notify](https://notify-bot.line.me/ja/)を使い直接URLを叩く

前者だと1:1の通信(自分とのチャットなど)しかできないようです。今回は家族LINEのようなグループチャット内で通知させることを考えているので、後者のやり方を説明します。前者のやり方は以下のサイトが大変参考になります。:pray:
https://thousandiy.wordpress.com/2017/10/17/esp32_ifttt_line/
(もし、IFTTTを使ったグループチャットへの通知ができる場合はぜひ教えてください:relaxed:)

###LINE Notifyを使い直接URLを叩く
####webでの設定
[LINE Notify](https://notify-bot.line.me/ja/)にアクセスし、ログインしてマイページにいきます。
![スクリーンショット 2019-01-03 13.15.01.png](https://qiita-image-store.s3.amazonaws.com/0/234751/be5bc8c3-0544-209f-823f-dd1ed4399d1e.png)
通知するトークルームを選択して、トークンを発行し控えます。
以上です！
 
####Arduino IDE
GPSデータは上述の方法で取得できていると思うので、肝心のLINE NotifyのURLの叩き方(パラメータ付与したPOSTリクエスト)を記述します。
HTTPClient.hをインクルードしておきます。send関数なんか作っておいて引数に送りたい文字列を指定して、messageパラメータにその文字列を代入します。urlの後ろに?でパラメータを指定できます。リクエストヘッダに以下のように先ほど控えたトークンを記すのを忘れないようにしましょう。
httpResponseCodeにステータスコードを格納しておけばエラー処理ができます。

```c
#include <HTTPClient.h>

void send(String value1) {
    //略(大事なとこだけ)
    HTTPClient http;
    http.begin("https://notify-api.line.me/api/notify?message=" + value1);
    http.addHeader("Authorization", "Bearer XXxxxXXXxxxxxxXXXXXXXxxxX");  //リクエストヘッダに先ほど控えたトークンをセット
    int httpResponseCode = http.POST("POSTING from M5stack");
}
```

余談ですけど、SSL化されたページ(https)へのリクエストなのにSSL証明書の確認はいらないんですかね...?slackの時は証明書発行したような。。。(ここらへん素人なので全然わかりません、教えてください！)

さて、メインの処理でこのsend関数を呼び出してあげればOKです！今回はサンプリングしたGPSデータから距離(m)を算出し送るようにしてます。ambientチャネルのURLも送ります。
最後に電源OFF!

```c
void loop() {
  //略
  if (M5.BtnB.wasPressed()){
    M5.Lcd.println("finish walking!!");
    send(String(distance) + "m");  //散歩距離(GPSから算出した)
    send("https://ambidata.io/ch/channel.html?id=xxxx&private=true");  //idはチャネルID
    M5.powerOFF();  //電源OFF
  }
}
```
指定したLINEトークルームに通知が来ていれば成功！

#実際に運用してみる
実際に試す前に、完成したシステムの全様を以下の動画にまとめましたのでご覧ください。
https://youtu.be/Skmwk9skz34
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/Skmwk9skz34/0.jpg)](https://youtu.be/Skmwk9skz34)

###犬と散歩してみる
犬も不安そうな表情で見つめてきます:rolling_eyes:
![kinakinasampo.JPG](https://qiita-image-store.s3.amazonaws.com/0/234751/cd9f7924-b0ff-6980-7ecd-4b2ec01d626e.jpeg)
ちゃんととれてるうううぅ!!
<img width="355" alt="スクリーンショット 2019-01-01 16.41.18.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/234751/50a11cc5-ea3a-fa84-29c2-b3fa530da897.jpeg">
LINEの通知はこんな感じです(これは別日にシステムテスト時に撮ったものですが)
<img width="375" alt="IMG_1646.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/234751/6b41c44f-cd65-6a0b-518e-f12804c06d25.png">


#おわりに
M5Stackの入門、できましたでしょうか！？
この記事を見て、一人でも参考になったという方がいたら幸いです。
全コード参考にしたいという方はTwitter,Facebookまでご連絡ください。

#追記
全コードを参考にしたい方向けに、youtubeのコメント欄に本プロジェクトのリポジトリを載せました:point_up: