みかづきブログ・カスタム

基本的にはちょちょいのほいです。

M5StickC Plus2で取得したGPS座標をCloud Firestoreにデータを保存する 🔥

こちら、下記3つの記事の組み合わせです。

blog.kimizuka.org
blog.kimizuka.org
blog.kimizuka.org

M5StickC Plus2でGPS座標を取得して、Cloud Firestorに送信します。

準備するもの

Firebase側の実装

❶ パッケージを用意する

yarn add firebase firebase-tools

❷ package.jsonを編集する

package.json
{
  "name": "functions-gps",
  "scripts": {
    "login": "firebase login",
    "init": "firebase init",
    "emulate": "firebase emulators:start",
    "deploy": "firebase deploy"
  },
  "dependencies": {
    "firebase": "^10.13.0",
    "firebase-tools": "^13.15.3"
  }
}

❸ Firebaseのコンソールからプロジェクトをつくり、Cloud Firestore、Cloud Functionsを有効にする

  • ルールはテストモードで開始する
  • ロケーションは近いところを選ぶ
  • ロケーションは近いところを選ぶ

firebase.google.com

❹ Firebaseプロジェクトを初期化する

ログイン
yarn run login
初期化
yarn run init

初期化後、❸で作成したプロジェクトに紐付けます。

必要なものを有効化
◉ Firestore: Configure security rules and indexes files for Firestore
◉ Functions: Configure a Cloud Functions directory and its files
◉ Emulators: Set up local emulators for Firebase products
必要なエミュレータを有効化
◉ Functions Emulator
◉ Firestore Emulator

いろいろ選択肢が出てきますが、基本的にEnterを連打でOKです。

❺ コードを書く

firebase.json
{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "functions": [
    {
      "source": "functions",
      "codebase": "default",
      "ignore": [
        "node_modules",
        ".git",
        "firebase-debug.log",
        "firebase-debug.*.log",
        "*.local"
      ]
    }
  ],
  "emulators": {
    "functions": {
      "port": 5001
    },
    "firestore": {
      "port": 8080
    },
    "ui": {
      "enabled": true
    },
    "singleProjectMode": true
  }
}
functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const { initializeApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore');

initializeApp();

exports.gps = onRequest({
  region: ['asia-northeast1'],
}, async (request, response) => {
  const { doc, lat, long } = request.query;

  if (target && lat && long) {
    try {
      await getFirestore().collection('gps').doc(doc).set({
        value: new GeoPoint(Number(lat), Number(long))
      });

      response.send({
        doc,
        lat,
        long
      });
    } catch (err) {
      logger.error(err);
    }
  }

  response.send({
    doc: null,
    lat: 0,
    long: 0
  });
});

❻ エミュレータで確認する

yarn emulate

http://127.0.0.1:4000/logs?q=metadata.emulator.name%3D%22functions%22 にアクセスすると、デプロイしたfunctionのURLが確認できます。

関数名は、http://127.0.0.1:(ポート番号)/(プロジェクト名)/(リージョン)/(関数名)となるので、

  • functionsのポートを「5001」
  • プロジェクト名が「functions-gps」
  • リージョンが「asia-northeast1(東京)」
  • 関数名が「gps」

ならば、

http://127.0.0.1:5001/functions-gps/asia-northeast1/gps

となります。

クエリパラメータで、doc、lat、lngを指定できるようにしてあるので、

http://127.0.0.1:5001/functions-gps/asia-northeast1/gps?doc=doc&lat=35.6895014&long=139.6917337

にアクセスすると、

{"doc":"doc","lat":"35.6895014","long":"139.6917337"}

というJSONを返しつつ、
Cloud Firestoreに緯度経度が保存されます。

❼ デプロイする

yarn deploy

M5StickC Plus2側の実装

Arduinoを使って、下記コードをM5StickC Plus2に書き込みます。

#include <M5StickCPlus2.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>
#include <TinyGPS++.h>

const char* ssid = ""; // WiFiのssid
const char* password = ""; // WiFiのパスワード
String gpsBaseUrl = ""; // Cloud FunctionのURL
String doc = ""; // Cloud Firestoreのdocument

HardwareSerial GPSRaw(2);
TinyGPSPlus gps;

void setup() {
  M5.begin();
  M5.Lcd.setRotation(1);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(2);

  GPSRaw.begin(9600, SERIAL_8N1, 33, 32);

  M5.Lcd.print("SSID:");
  M5.Lcd.println(ssid);

  WiFi.begin(ssid, password);

  M5.Lcd.print("Connecting");

  while (WiFi.status() != WL_CONNECTED) {
    delay(1 * 1000);
    M5.Lcd.print(".");
  }

  M5.Lcd.println("");
  M5.Lcd.print("IP:");
  M5.Lcd.println(WiFi.localIP());
}

void loop() {
  double lat = 0;
  double lng = 0;

  M5.Lcd.setCursor(0, 0);
  M5.Lcd.fillScreen(BLACK);

  while (GPSRaw.available() > 0) {
    if (gps.encode(GPSRaw.read())) {
      break;
    }
  }

  if (gps.location.isValid()) {
    lat = gps.location.lat();
    lng = gps.location.lng();
    M5.Lcd.printf("lat:%.6f\n", lat);
    M5.Lcd.printf("lng:%.6f\n", lng);

    HTTPClient http;
    String gpsUrl = gpsBaseUrl + "?doc=" + doc + "&lat=" + String(lat, 6) + "&long=" + String(lng, 6);

    http.begin(gpsUrl);
    int httpCode = http.GET();

    if (httpCode > 0) {
      if (httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        JSONVar json = JSON.parse(payload);

        if (json.hasOwnProperty("target")) {
          String target = json["target"];

          M5.Lcd.println(target);
        }
      }
    }

    http.end();
  } else {
    M5.Lcd.println("ERROR:GPS");
  }

  delay(60 * 1000);
}

書き込み後、M5StickC Plus2とGPSユニットを繋げばOKです。
1分に1度、取得した緯度経度をCloud Firestoreに保存してくれるはずです。