M5StackとGPSユニット、通信ユニットを組み合わせてGPSロガーを作成してみました。(『M5Stack/ATOMとGPSユニットを使って位置情報をクラウドに保存する / M5シリーズUIFlowからKintoneに直接データをアップロードする』の続きになります。)
前回の記事ではWi-Fi環境を使いkintoneへアップロードしていましたが、今回はIoT回線(SORACOM)を使ってアップロードしています。
SORACOM以外のIoT回線でもCAT-Mユニットが対応するSIMと通信方式であれば接続できます。
今回のサンプルプログラムではkintoneのAPI呼び出しを簡略化するためにSORACOM独自のゲートウェイサービスを使用しているので、SORACOM以外のIoT回線に転用する際は適宜環境に合わせてアレンジが必要です。
// // M5Stack Grayに接続したGPSユニットとCAT-Mユニットを使い計測したGPS位置情 // 報をSORACOMを経由してkintoneにアップロードするプログラム // // PORT A: CAT-Mユニット // PORT B: GPSユニット // PORT C: 未使用 // // 《事前準備》 // 1)kintone上には以下のフィールドを持つアプリを定義する // gps_id: GPS計測機器ID // gps_datetime: 日時 // latitude: 緯度 // longitude: 経度 // altitude: 高度 // accx: X方向加速度 // accy: Y方向加速度 // accz: Z方向加速度 // // 2)SORACOM Beamからkintone上のアプリへアクセスできるように設定する // https://soracom.jp/services/beam/ // // This software is distributed under the license of NYSL. // http://www.kmonos.net/nysl/ // #define TINY_GSM_MODEM_SIM7080 #define M5STACK_MPU6886 #include <M5Stack.h> #include <TinyGsmClient.h> #include <TinyGPS++.h> // SORACOMのAPN const char GSM_APN[] = "soracom.io"; // SORACOM接続時のユーザ名 const char GSM_USERNAME[] = "sora"; // SORACOM接続時のパスワード const char GSM_PASSWORD[] = "sora"; // SORACOM Beam サーバ const char API_SERVER[] = "beam.soracom.io"; // SORACOM Beam URL const char API_RESORCE[] = "/k/v1/record.json"; // SORACOM Beam ポート const uint16_t API_PORT = 8888; // kintoneアプリのアプリID(kintone環境に合わせて修正) const char APP_ID[] = "1"; // GPSを計測機器のID const char GPS_ID[] = "M5_001"; TinyGsm modem(Serial1); TinyGsmClient client(modem); TinyGPSPlus gps; // kintoneのアップロードデータ編集用 char kintone_payload[512]; float accx0, accy0, accz0; float accxT, accyT, acczT; float accx, accy, accz; void setup() { M5.begin(true, false, true, true); M5.Power.begin(); M5.Lcd.setTextColor(WHITE); M5.Lcd.setTextSize(2); Serial.begin(115200); M5.Lcd.println("Initializing..."); // M5センサ初期化 M5.IMU.Init(); // シリアル初期化 Serial1.begin(9600, SERIAL_8N1, 22, 21); // Modem: M5Stack Gray Serial2.begin(9600, SERIAL_8N1, 36, 26); // GPS: M5Stack Gray delay(100); // モデム初期化 M5.Lcd.println("Restart modem"); modem.restart(); // modem.gprsConnect(GSM_APN, GSM_USERNAME, GSM_PASSWORD); // ネットワーク登録待ち M5.Lcd.print("Wait for network"); while (!modem.waitForNetwork()) { M5.Lcd.print("."); } M5.Lcd.println(""); // 接続 modem.gprsConnect(GSM_APN, GSM_USERNAME, GSM_PASSWORD); // データ通信接続待ち M5.Lcd.print("Wait for connection"); while (!modem.isNetworkConnected()) { M5.Lcd.print("."); } M5.Lcd.println(""); // // 起動時点の加速度を取得 // // ここで加速度を読み取ろうとするとネットワーク接続断 // M5.IMU.getAccelData(&accx0, &accy0, &accz0); } void loop() { // // ここで加速度を読み取ろうとするとネットワーク接続断またはプログラムが落ちる // M5.IMU.getAccelData(&accxT, &accyT, &acczT); // accx = accxT - accx0; // accy = accyT - accy0; // accz = acczT - accz0; // 稼働時間を見るためにローカル時間を取得 struct tm tm; getLocalTime(&tm); // GPS計測 while (Serial2.available() > 0) { gps.encode(Serial2.read()); } // 計測値を表示 M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(2); M5.Lcd.setTextColor(WHITE); M5.Lcd.setCursor(0, 0); M5.Lcd.printf("LOCAL=%04d/%02d/%02d %02d:%02d:%02d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); M5.Lcd.printf(" GPS=%04d/%02d/%02d %02d:%02d:%02d\n", gps.date.year(), gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), gps.time.second()); M5.Lcd.printf("\n\n"); M5.Lcd.printf(" LAT=%.6f\n", gps.location.lat()); M5.Lcd.printf(" LNG=%.6f\n", gps.location.lng()); M5.Lcd.printf(" ALT=%.2f\n", gps.altitude.meters()); M5.Lcd.printf("\n\n"); M5.Lcd.printf("ACC-X=%f\n", accx); M5.Lcd.printf("ACC-Y=%f\n", accy); M5.Lcd.printf("ACC-Z=%f\n", accz); // データ通信接続ができていない場合、接続を試みる if(!modem.isGprsConnected()) { M5.Lcd.print("\nReconnecting"); modem.gprsConnect(GSM_APN, GSM_USERNAME, GSM_PASSWORD); while (!modem.isNetworkConnected()) { M5.Lcd.print("."); } } // SORACOM Beam経由でkintoneにデータをアップロードする sprintf(kintone_payload, "{\"app\":\"%s\", \"record\":{\"gps_id\":{\"value\":\"%s\"},\"gps_datetime\":{\"value\":\"%04d/%02d/%02d %02d:%02d:%02d\"},\"latitude\":{\"value\":\"%3.6f\"},\"longitude\":{\"value\":\"%3.6f\"},\"altitude\":{\"value\":\"%.2f\"},\"accx\":{\"value\":\"%.4f\"},\"accy\":{\"value\":\"%.4f\"},\"accz\":{\"value\":\"%.4f\"}}}", APP_ID, GPS_ID, gps.date.year(), gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), gps.time.second(), gps.location.lat(), gps.location.lng(), gps.altitude.meters(), accx, accy, accz); client.connect(API_SERVER, API_PORT); client.printf("POST %s HTTP/1.1\r\n", API_RESORCE); client.printf("Host: %s\r\n", API_SERVER); client.printf("Content-Length: %lu\r\n", strlen(kintone_payload)); client.printf("Connection: close\r\n\r\n"); client.println(kintone_payload); while (client.connected()) { String line = client.readStringUntil('\n'); if (line == "\r") { break; } } client.stop(); delay(500); }
できあがったGPSロガーを持ち歩き市街地~山間部、一般道・高速道をドライブしてみました。
人家もまばらな峠付近で5分程度通信が行えない状況がありましたが、その他の地域では非常に良好な通信状態が維持できていることを確認しました。(SORACOMはpaln-Dを契約)
参考までに通信が途切れた地域を掲載します。
[…] 通信ユニットとIoT回線を使いスタンドアロンでも動きGPSロガーを「M5Stack+GPSユニット+通信ユニット+IoT回線でGPSロガーを作る」 で公開しました。 […]
興味深い情報をありがとうございます。
SIMCOMのSIM7080GはGNSSとLTEを同時に使うことができないようですね。
GNSSの機能を使うと通信が切れるのは謎だったのですが、ここで同じ経験をしている人がいらっしゃいました。
https://stackoverflow.com/questions/61857667/sim7080g-module-cant-send-data-over-tcp-while-using-gnss/61884727#61884727
チップのドキュメントに書いていないのは反則かと笑