M5AtomでTinyGSMを利用してLTE通信（HTTP）を行いAmbientにデータを送信する

## やりたいこと
　M5AtomのIOユニットで取得したデータをLTE回線からAmbientへアップロードします。
　LTE回線はmineoのDプランを利用しました。
## 参考元
- [SIM7500JCでTinyGSMのHttpClientを動かしてみた](https://qiita.com/kaz19610303/items/9ab5d1dcbeb54d9b8488)
- [GitHub（vshymanskyy/TinyGSM）](https://github.com/vshymanskyy/TinyGSM)
## 反省点（注意点）
- LTE接続を確立したのちEXT-IO2の値読取りを行うと、LTEが切断されてしまう事象が発生しました。知識不足でこちらは解消できず、値読取り後に毎回LTE接続を行うため、読取りからデータ送信まで10～30秒ほどかかります。
- 本当はMQTTでAzure Iot Hubに送信したかったのですが、MQTTをTLSで暗号化してデータ送信する方法が分らず、ひとまずHttpで送信可能なAmbientにデータを送信することにしました。
## 前提条件
### 機器構成
![機器構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1503733/142b0d0d-658a-e75f-17d2-0e5b6063edfb.png)
### 使用ライブラリ
- M5Atom
- TinyGSM
- ArduinoHttpClient
## ソースコード
    // TinyGSM（LTE接続用）
    #define TINY_GSM_MODEM_SIM7080
    #define TINY_GSM_RX_BUFFER 650
    #define TINY_GSM_DEBUG SerialMon
    #define GSM_AUTOBAUD_MIN 9600
    #define GSM_AUTOBAUD_MAX 115200
    #define SerialAT Serial1
    #include <TinyGsmClient.h>

    // ArduinoHttpClient（Http通信用）
    #include <ArduinoHttpClient.h>
    #define SerialMon Serial

    // M5EXTIO2（IO入力用）
    #include "M5_EXTIO2.h"

    // SIMカードのAPN設定
    const char apn[]      = "mineo-d.jp";
    const char gprsUser[] = "mineo@k-opti.com";
    const char gprsPass[] = "mineo";

    // 接続先設定
    const char server[]   = "ambidata.io";
    const char chanelid[] = "12345" 
    const char writekey[] = "abcdefghijklmnop";
    const char resource[] = "/api/v2/channels/" + chanelid + "/data";
    const int  port       = 80;

    // ADCユニット設定
    M5_EXTIO2 extio;

    // TinyGSM設定
    TinyGsm        modem(SerialAT);
    TinyGsmClient client(modem);

    // HttpClient設定
    HttpClient    http(client, server, port);

    // LTE接続
    void ConnectLTE() {
        SerialMon.println("restart modem");
        modem.restart();
        
        SerialMon.println("wait for network connected ");
        // Set GSM module baud rate
        SerialAT.begin(115200, SERIAL_8N1, 32, 26);
        TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
        delay(6000);
        
        // Restart takes quite some time
        // To skip it, call init() instead of restart()
        SerialMon.println("Initializing modem...");
        modem.restart();
        
        modem.gprsConnect(apn, gprsUser, gprsPass);
        SerialMon.print("Waiting for network...");
        if (!modem.waitForNetwork()) {
        SerialMon.println(" fail");
        delay(10000);
        return;
        }
        SerialMon.println(" success");
        
        if (modem.isNetworkConnected()) { 
        SerialMon.println("Network connected"); 
        }
        return;
    }

    // 初期設定
    void setup() {
        // Set console baud rate
        M5.begin();
        SerialMon.begin(115200);
        M5.dis.drawpix(0,CRGB::Blue);
        delay(10);
        
        // EXTIO2設定
        Wire.begin(26, 32);
        extio.begin(&Wire, 26, 32, 0x45);
        extio.setAllPinMode(ADC_INPUT_MODE);
    }

    void loop() {
        // LEDを緑色に点灯する
        M5.dis.drawpix(0,CRGB::Green);
        // ADCの入力値を取得する
        double d1 = extio.getAnalogInput(0, _12bit);
        double d2 = extio.getAnalogInput(1, _12bit);
        double d3 = extio.getAnalogInput(2, _12bit);
        // LTE接続確認
        if(!modem.isGprsConnected()) { // 未接続の場合、接続処理
            // LEDを青色に点灯する
            M5.dis.drawpix(0,CRGB::Blue);
            // 接続処理
            ConnectLTE();
        }
        // Http通信（POST）
        if(modem.isGprsConnected()) { // LTE接続確認
            // LEDを白色に点灯する
            M5.dis.drawpix(0,CRGB::White);
            // POST送信設定
            String contentType = "application/json";
            String postData = ""
                "{"
                    "\"writeKey\" : \"" + (String)writekey + "\","
                    "\"d1\" : \"" + (String)d1 + "\","
                    "\"d2\" : \"" + (String)d2 + "\","
                    "\"d3\" : \"" + (String)d3 + "\""
                "}";
            SerialMon.print(F("POST data : "));
            SerialMon.println(postData);
            // 送信実行
            SerialMon.print(F("Performing HTTP GET request... "));
            int err = http.post(resource,contentType,postData);
            // 送信成否判定
            if (err != 0) {
                SerialMon.println(F("failed to connect"));
                return;
            }
            // 結果取得
            int status = http.responseStatusCode();
            SerialMon.print(F("Response status code: "));
            SerialMon.println(status);
            if (!status) {
                return;
            }
            // Responceヘッダ取得
            SerialMon.println(F("Response Headers:"));
            while (http.headerAvailable()) {
            String headerName  = http.readHeaderName();
            String headerValue = http.readHeaderValue();
            SerialMon.println("    " + headerName + " : " + headerValue);
            }
            // 受信データ取得
            int length = http.contentLength();
            if (length >= 0) {
                SerialMon.print(F("Content length is: "));
                SerialMon.println(length);
            }
            if (http.isResponseChunked()) {
                SerialMon.println(F("The response is chunked"));
            }
            
            String body = http.responseBody();
            SerialMon.println(F("Response:"));
            SerialMon.println(body);
            
            SerialMon.print(F("Body length is: "));
            SerialMon.println(body.length());
            // Http接続終了
            http.stop();
            SerialMon.println(F("Server disconnected"));
            delay(60000);
        } else {
            // LEDを青色に点灯する
            M5.dis.drawpix(0,CRGB::Blue);
            // 接続処理
            ConnectLTE();
        }
    }