IoTデバイスがGASからデータを"受信"する方法

# ！！ご注意！！
### この記事はIoT素人が自分の目的を達成するためにテキトウに調べて実践したことをテキトウにまとめています。間違った情報や非効率的な情報が混ざっている可能性があります！
それでもいいよって方は、ゆっくりしていってね

# 本題
みょんなことからIoTデバイス(ESP32)とGASを活用した模擬製品開発をすることとなった。
IoTデバイスとGASの活用例といえば、温度センサなどのデータを一定時間ごとにスプレッドシートに記録するというものをよく見かける。
これはIoTデバイスがGASにデータを**送信**する例と言えよう。
<img width=70% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/c4e2a0d1-76ee-4481-741a-51a4bfa3029e.png>
赤矢印が測定データの流れみたいな感じで描いてみた

では、**受信**はどうやってやればいいのだろうか？
例えば何かのセンサーのデータによってサーボモーターを動かすとか止めるとかしたいとする。このときセンサーとサーボは別々のIoTデバイスに接続されているとする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/2d291025-b6fd-4f9a-f788-9bac1aad22f6.png)
用途は意味不明だがまあ仮にこんな構成があったとする。(温度センサーで測った値を丸形の温度計で再現するのだろうか？)

送信の場合、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にレスポンスとして必要なデータを返してもらえばいいのだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/c2d5c7e5-399b-5743-95a6-232eb950dc98.png)

# 実装
```js:AppsScriptの コード.gs
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;
    }
}
```
```cpp:サーボ用.ino
//サーボ用。これはどこかのサイトで見かけてコピペしたもの。
#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回くらいしか受信できません。
僕の知識ではこれが限界でした…