趣味の開発ノート

ITの学習やプログラミング・ノーコードアプリ開発のことなど。

【M5Stack】Wi-Fiへ接続してセンサデータをSpreadsheetに送信する

M5Stackでの電子工作の学習中。

前回、センサデータの取得まで行った。

nouka-it.hatenablog.com

今回は、

  • M5StackをWi-Fiへ接続する
  • センサデータをSpreadsheetに送信する

というところまでを試してみる。

学習の流れ

WiFi接続〜Spreadsheetへの送信はこちらの書籍のCHAPTER 6のスケッチを写経して学び、以前のセンサデータを取得するスケッチと組み合わせた。

WiFiへ接続する

M5StackだとそのままでWiFi通信が可能。
ライブラリのインストールなどせず、スケッチを書くだけでWiFiへの接続ができる。

書籍で学んだスケッチを使ったけど、Arduino IDEで見られるM5Stackライブラリのサンプルスケッチにもありそうだなあ。

Spreadsheetへデータを飛ばす

データの保存先にはSpreadsheetを選択。
自分は普段スプレッドシート + GASを扱っているのでこれが一番やりやすいと思った。

ただ、これがなかなかひと手間かかる。
M5Stackとスプレッドシートの間に、GASを噛ませてwebhookでデータを受け取れるようにしてあげる必要がある。

とりあえず今回書いたスケッチでは、練習のために5秒間隔でデータを送ってSpreadsheetに格納するようにしてみた。

実装手順

  • データを格納するSpreadsheetを用意
  • GASスクリプトを用意
    • doPost()関数でセンサデータをJSONで受け取り、スプレッドシートへ書き込む処理を記述
    • ウェブアプリとしてデプロイ、URLを発行
  • Arduino IDEで必要なライブラリをインストール(後述)
  • Arduino IDEでスケッチ記述

必要なライブラリ

  • ArduinoJson:Webhookでpostするために必要

ここまでのコード

まとめる。

▼GASスクリプト

function doPost(e){

  const date = new Date();

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  const params = JSON.parse(e.postData.getDataAsString());
  const [humidity, temperature, moisture] = [params.humidity, params.temperature, params.moisture];

  // データ追加
  sheet.insertRows(2, 1)
  sheet.getRange(2, 1, 1, 4).setValues([[date, humidity, temperature, moisture]]);

  const output = ContentService.createTextOutput();
  output.setMimeType(contentService.MimeType.JSON);
  output.setValue(JSON.stringify({ message: "success!" }));

  return output;
}

Arduino IDEでのスケッチ

#include <M5Stack.h>
#include <DHT.h>
#include <HTTPClient.h>
#include <WiFi.h>
#include <ArduinoJson.h>

#define WIFI_SSID "(自身のSSIDを記述)"
#define WIFI_PASSWORD "(自身のWiFiパスワードを記述)"

// スプレッドシートへデータを飛ばすWebhook URL
const char *host = "(GASでデプロイしたURLを記述)";

// JSON設定
StaticJsonDocument<255> json_request;
char buffer[255];

// dht設定
const int PIN_DHT = 5;
DHT dht(PIN_DHT, DHT11);

// センサー値
float humidity;                // 湿度
float temperature;             // 温度
uint16_t moisture = 0;         // 土壌水分


/* setup関数 */
void setup() {
  M5.begin();
  dht.begin();
  
  // Wi-Fi接続
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  WiFi.setSleep(false); // btnA連打バグへの対応
  Serial.print("connectiong");
  while(WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();

  // WiFi Connected
  Serial.println("¥nWiFi Connected.");
  Serial.println(WiFi.localIP());
  M5.Lcd.setTextSize(3);
  M5.Lcd.println("WiFi Connected:");
  M5.Lcd.println(WiFi.localIP());
  M5.Lcd.println("");
  
}

/* センサーの値送信 */
void sendValues(){
  json_request["humidity"] = humidity;
  json_request["temperature"] = temperature;
  json_request["moisture"] = moisture;
  serializeJson(json_request, buffer, sizeof(buffer));

  HTTPClient http;
  http.begin(host);
  http.addHeader("Content-Type", "application/json");
  int status_code = http.POST((uint8_t*)buffer, strlen(buffer));
  Serial.println(status_code);
  if(status_code > 0){
    if(status_code == HTTP_CODE_FOUND){
      String payload = http.getString();
      Serial.println(payload);

      M5.Lcd.setCursor(10, 100);
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(3);
      M5.Lcd.println("Send Done!");
    }  
  } else {
    Serial.printf("[HTTP] GET... failed, error: %s¥n", http.errorToString(status_code).c_str());
  }
  http.end();

}


/* loop関数 */
void loop(){

  // 各センサの値を読み込む
  delay(3000);
  humidity = dht.readHumidity();
  temperature = dht.readTemperature();  
  moisture = analogRead(36);

  // 画面への出力
  M5.Lcd.clear(BLACK);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(1);
  M5.Lcd.drawString("M5STACK SENSORS:", 0, 0, 4);

  M5.Lcd.setTextColor(YELLOW);
  M5.Lcd.drawString("Humidity:", 0, 30, 4); // 湿度
  M5.Lcd.drawFloat(humidity, 0, 0, 60, 4);
  M5.Lcd.drawString("%", 50, 60, 4);
  
  M5.Lcd.setTextColor(GREEN);
  M5.Lcd.drawString("Temperature:", 0, 90, 4); // 温度
  M5.Lcd.drawFloat(temperature, 0, 0, 120, 4);
  M5.Lcd.drawString("C", 50, 120, 4);
 
  M5.Lcd.setTextColor(BLUE);
  M5.Lcd.drawString("Moisture:", 0, 150, 4); // 土壌水分
  M5.Lcd.drawFloat(moisture, 0, 0, 180, 4);

  // センサーの値を送る
  sendValues();

}