在宅勤務が増加すると、勤務先の状況が気になります。そこで室温と湿度を計測、記録をインターネット上で記録するIoTをラピッドプロトタイピングしてみました。
装置はM5StickCとgrove接続の湿度センサー(DHT11)です。Amazonで入手しました。
記録側はGoogle Apps Scriptを用いることにしました。Spreadsheetに1行ずつ、計測データを追記していきます。
function doPost(ee) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var values = JSON.parse(ee.postData.getDataAsString());
sheet.appendRow([new Date(), values.humi, values.temp]);
}
データ用のスプレッドシートを作成し、ツール→スクリプトエディタで、上記のようなコードを記入します。
その後、公開→Webアプリケーションとして導入し、そのURLをメモします。
M5StickC側のプログラムは以下のようなものになります。DHT11用のAdafruit社のライブラリをあらかじめインストールしてください。
#include <M5StickC.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include "DHT.h"
#define DHTPIN 33
#define DHTTYPE DHT11
const char* ssid = "!!! input WiFi SSID Name !!!";
const char* password = "!!! input WiFi Password !!!";
const char* published_url = "!!! input Google Spreadsheet scripts web application URL !!!";
DHT dht(DHTPIN, DHTTYPE);
void setup() {
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.print("wifi connect...");
WiFi.mode(WIFI_STA);
WiFi.disconnect(true);
delay(1000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println("DHT11 init...");
dht.begin();
delay(1000);
}
void loop() {
M5.update();
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println(F("Failed to read from DHT sensor!"));
} else {
Serial.print(h);
Serial.print("" );
Serial.println(t);
M5.Lcd.setCursor(0, 0);
M5.Lcd.print("humi : ");
M5.Lcd.print(h);
M5.Lcd.print(" temp : ");
M5.Lcd.println(t);
char json[64];
sprintf(json, "{\"humi\": \"%f\" , \"temp\": \"%f\" }", h, t);
HTTPClient http;
http.begin(published_url);
int httpCode = http.POST(json);
if (httpCode > 0) {
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.println("http fail");
}
http.end();
}
delay(60000);
}
この例では1分ごとに計測値を送信しています。末尾のdelayの引数(ms)がそれを決めています。通常は室温や湿度はそんなに急激に変化しないので、もっと長めでもよいと思います。
Google Apps Scriptで更に定期的にデータをチェックすれば死活監視もできますね、としましたが、死活監視も作成しました(2020/05/06)。
var PROPERTY_NAME = "humi_rec_locationname_prevResult";
function healthCheck() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var lastRow = sheet.getLastRow();
var lastDate = sheet.getRange(lastRow, 1).getValue();
var diffDateMinutes = ((new Date()).getTime() - lastDate.getTime()) / (1000 * 60);
var properties = PropertiesService.getScriptProperties();
var prevResult = properties.getProperty(PROPERTY_NAME);
if (prevResult == null) {
prevResult = "success";
}
if (diffDateMinutes > 60) {
if (prevResult == "success") {
const recipient = '送信先メールアドレス';
const subject = 'Is your Humi IoT device stopped?';
const body = 'Plase check your Humi IoT device. There has been no communication since then for over 60 minutes.';
GmailApp.sendEmail(recipient, subject, body);
properties.setProperty(PROPERTY_NAME, "fail");
console.log("success to fail : send mail");
} else {
console.log("fail to fail : nothing");
}
} else {
properties.setProperty(PROPERTY_NAME, "success");
if (prevResult == "success") {
console.log("success to success : nothing");
} else {
console.log("fail to success : nothing");
}
}
}
先のdoPost関数の後に上を書きます。この例では成功→失敗時にメールで通知するようにしています。失敗するたびに送信すると大量のメールが届いてたいへんなことになるので、プロパティを用いて前回のチェック結果を参照しています。
その上で、一度動作試験をしてください。メール送信のための権限が増えるのでそのチェックが入ります。途絶えた場合の処理を検証するには時間差を求めている行で+100などして実行してください(戻すことを忘れないように)。
次に「編集」→「現在のプロジェクトのトリガー」をクリックし、「トリガーを追加」します。作成した「healthCheck」関数を、時間主導型、分ベース、30分おき、今すぐ通知を受け付ける、あたりに設定します。
埃から防ぐためのケースはM5StickCの入っていたケースをそのまま再利用しました。あまり発熱はしないと思いますが、室温・気温が適切に計測できるようにするため、空気の流れを確保できるように両側に穴を開けました。