ESP8266/ESP32でGoogleSpreadSheetのセルを読む

先日ESP8266/ESP32でGoogle Spreadsheetのセルを書き込むコードを紹介しました。
今回はセルの内容を読み込む方法を紹介します。
この方法をベースにGoogle Apps Scriptでカレンダーの参照とか他にもいろいろできそうです。
僕はGoogle Calendarから日本の祝日を参照して、電子ペーパーの日めくりカレンダーを妄想中。

#使うもの
　　ArduinoIDE - ESP8266/ESP32
　　Google Apps Script
　　Google Spreadsheet
　　Sujay Phadkeさん作   HTTPSRedirect [リンク](https://github.com/electronicsguy/ESP8266/tree/master/HTTPSRedirect)

#ESP8266/ESP32からGoogle Apps Scriptを呼ぶ
　GScriptId      = Script作成で紹介されるIDをセットします。
　GSpreadsheetId = スプレッドシートIDです。
　GsheetName     = シート名です。　（全角文字未対応）
　cell           = 読み込むセルの位置です。

　戻り値
  client->getResponseBody() = Google Apps Scriptの戻り値(Script内のエラーならエラーメッセージが入るので、細工が必要です)
  
#ESP32で使う方法
   HTTPSRedirect.hソースでコメントされているstop()を動作する様にします。
    //stop(); // may not be required

    ※2024年2月追記 ESP32C3を使う為に最新のArduinoIDEやライブラリを適用しましたが、動きません。
    　　　　　　　　とりあえず旧ArduinoIDEと従来ESP32では動くので大事にしときます。
    ※2024年6月追記　ESP32C3向けに環境を整えていくと動作する様になりました。
                   多分何か勘違いしていたのだと思います。


#Google Scriptのソース
update:2018-08-18　 アクセス引数と引数の解析が気に入らないので大幅修正しました。
update:2022-12-19　 セルの範囲指定ができる様にGetValuesに書き換えました。
update:2024-06-13   Windows Python3.11.6のrequestsで利用できるのを確認
update:2024-06-13   VisualStudio2010Express c#のWebBrowserで利用できるのを確認


```js:GoogleScript.gs:
// ログ出力
function logOutput( message )
{
  Logger.log(message);
  return message;
}
// 戻り値の作成
function messageOutput( message )
{
  return ContentService.createTextOutput( logOutput(message) );
}
// doGet command分岐処理
function doGet(e){
  try{
    logOutput( e.parameter );
    var command = e.parameter.command;
    if( command == "cellRead" )     return messageOutput(doGetCellRead(e));
  }
  catch(f){ return  messageOutput("ERROR," + f.message);  }
  return messageOutput("ERROR,commandが判りません");
}

// doGetでのセル読み込み
function doGetCellRead(e)
{
  var sheetSS = SpreadsheetApp.openById( e.parameter.sheetid );
  var sheet = sheetSS.getSheetByName( e.parameter.sheet );
  var range = sheet.getRange( e.parameter.cell );
  return range.getValues();
}

function doPost(e) 
{
  return messageOutput("ERROR,処理できません");
}
```


#ESP8266のソース
update:2018-08-18 Google Scriptの変更に合わせて引数にcommandを追加しました
update:2022-12-19 ArduinoIDEのESP8266Ver3.0.2で動作するソースに変更しました

```cpp:
#include <ESP8266WiFi.h>
#include "HTTPSRedirect.h"

// Fill ssid and password with your network credentials
const char* ssid = "guest";
const char* password = "guest";

const char* host = "script.google.com";
const int httpsPort = 443;
// Replace with your own script id to make server side changes

// google scriptのscriptID
const char *GScriptId = "＝＝google SciptIDをセットします＝＝";
const char *GSpreadsheetId = "＝＝google SpreadsheetIDをセットします＝＝";
const char *GsheetName = "＝＝Sheet名をセットします＝＝";

// Fetch Google Calendar events for 1 week ahead
const String urlScriptID  = String("/macros/s/");
const String urlSheetID   = "/exec?command=cellRead&sheetid=";
const String urlSheetName = "&sheet=";
const String urlCell      = "&cell=";

void setup() {
  Serial.begin(115200);
  Serial.flush();
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
HTTPSRedirect* client = nullptr;
String payload = "";
bool flag;
if( client == nullptr ){
  // Use HTTPSRedirect class to create a new TLS connection
  client = new HTTPSRedirect(httpsPort);
  client->setInsecure();
  client->setPrintResponseBody(true);
  client->setContentTypeHeader("application/json");
  Serial.print("Connecting to ");  Serial.println(host);
  // Try to connect for a maximum of 5 times
  flag = false;
  for (int i=0; i<10; i++){
    int retval = client->connect(host, httpsPort);
    if (retval == 1) {
       flag = true;
       break;
    }
#ifdef GoogleSpreadSheet_LOG
    else
      Serial.println("Connection failed. Retrying...");
#endif
  }
  if (!flag){
#ifdef GoogleSpreadSheet_LOG
    Serial.print("Could not connect to server: ");
    Serial.println(host);
    Serial.println("Exiting...");
#endif
    delete client;
    client = nullptr;
    return;
  }
}
  String cell = "A8";  //読み込むセルをセットします
  String url = urlScriptID + GScriptId;
  url = url + urlSheetID + GSpreadsheetId;
  url = url + urlSheetName + GsheetName;
  url = url + urlCell + cell;
  Serial.println(url);
  client->GET(url, host);
  Serial.print( "Status      :");  Serial.println( client->getStatusCode() );
  Serial.print( "reasonPhrase:");  Serial.println( client->getReasonPhrase() );
  Serial.print( "body        :");  Serial.println( client->getResponseBody() );
  delete client;
  client = nullptr;
  delay(10000);
}
```

セルを読むのはGetで、書くのはPutだったりします。
どちらもGetで行うのがスマートですが、結果的にGetとPutの資料になっているので良いかなっと。
※GoogleSpreadSheetから一挙に読み込む形式GetValuesでの動作確認をしました。
　指定例　"A8"＝１セル(A8)　／　"A8:B9"＝４セル(A8,B8,A9,B9)