!!ご注意!!
この記事はIoT素人が自分の目的を達成するためにテキトウに調べて実践したことをテキトウにまとめています。間違った情報や非効率的な情報が混ざっている可能性があります!
それでもいいよって方は、ゆっくりしていってね
本題
みょんなことからIoTデバイス(ESP32)とGASを活用した模擬製品開発をすることとなった。
IoTデバイスとGASの活用例といえば、温度センサなどのデータを一定時間ごとにスプレッドシートに記録するというものをよく見かける。
これはIoTデバイスがGASにデータを送信する例と言えよう。
赤矢印が測定データの流れみたいな感じで描いてみた
では、受信はどうやってやればいいのだろうか?
例えば何かのセンサーのデータによってサーボモーターを動かすとか止めるとかしたいとする。このときセンサーとサーボは別々のIoTデバイスに接続されているとする。
用途は意味不明だがまあ仮にこんな構成があったとする。(温度センサーで測った値を丸形の温度計で再現するのだろうか?)
送信の場合、GASはいつでも待っていてくれるので任意のタイミングでhttps://script.google.com/macros/s/hogefuga/exec
にHTTPリクエストのGETやPOSTを投げてやればできる。
では受信はどうしようか?鯖立てなんてしたらもはやそれはIoTの域を超えている気がする
ここで思いつく。
HTTPリクエストがあるのならその応答のHTTPレスポンスもあるのでは?
どうやらGASではdoGet()またはdoPost()の最後でContentService.createTextOutput()やHtmlService.createHtmlOutput()をreturnしてやればHTTPレスポンスを応答できるようだ。
つまり、受信側ではダミーのGETまたはPOSTを定期的に送り付けて、それを受けたGASにレスポンスとして必要なデータを返してもらえばいいのだ。
実装
function doGet(e){
var params = e.parameter; //URLの?name=value&name2=value2のようなものを取得
var dummy=params.dummy; //dummy= の値を取得。未指定ならundefinedになる
//var name=params.name; //必要に応じてGETリクエストで受け取るほかの変数も定義しておく
if(dummy!==undefined){ //dummyに何かしらの値が設定されているとき=受信したがっている
var sendtext=sheet.getRange("A1").getValue(); //例えばA1に送信したいデータが書き込まれているとき
/*
var response = ContentService.createTextOutput("受信させたいテキスト");
response.setMimeType(ContentService.MimeType.TEXT);
return response;
*/
//本来はこれでテキストのみを送信する予定だったが、
//ESP32ではリダイレクト処理がうまくできなかったためContentServiceは利用不可とみた
var response = HtmlService.createHtmlOutput(`message:${sendtext}:endmessage`);
//この方法だと無駄にHTMLが書かれるがリダイレクト対策にはこれしかない(と思う)
//「message:」と「:endmessage」はわかりやすい何か名前を自分で決めてもよい
return response;
}
}
//サーボ用。これはどこかのサイトで見かけてコピペしたもの。
#include <WiFi.h>
#include <WiFiMulti.h>
WiFiMulti wifiMulti;
#include <HTTPClient.h>
HTTPClient http;
#define SERVO_PIN 26
#define SERVO_CH 0
#define PWM_HZ 50
#define PWM_BIT 16 // 16bit(0~65535)
#define MAX 7800 // 65535 / 20 * 2.4 ≒ 7864
#define MIN 1700 // 65535 / 20 * 0.5 ≒ 1638
//GASのURL
String url="https://script.google.com/macros/s/hogefuga/exec";
void setup(){
//ESP32デバイスの初期化とか
//WiFi接続とか
}
//GASにデータを送信する関数
String sendDataToGAS(String payload) {
//開始
String geturl=url+payload; //かなりテキトウな実装
http.begin(geturl);
int httpRespCode;
httpRespCode=http.GET();
if(httpRespCode!=200){
return "error";
}
String str=http.getString();
//切断
http.end();
//"message:"から":endmessage"までを取得
int startindex=str.indexOf("message:");
int endindex=str.indexOf(":endmessage",startindex);
return str.substring(startindex+8,endindex); //+8というのはmessage:の分の長さ
}
void loop() {
String payload="?dummy=1";
String result=sendDataToGAS(payload);
//resultは"error"とか文字列型の数字とかだったりすると思うからあとは自由にどうぞ
//例:angle=result.toInt(); みたいにしてから、
//int duty_cycle = map(angle, 0, 180, MIN, MAX);
//ledcWrite(SERVO_CH, duty_cycle);
}
ちなみに2秒に1回くらいしか受信できません。
僕の知識ではこれが限界でした…