Google Apps Script (GAS)に定期的にデータを上げるための開発メモ。
ポイント1
定期実行はArduinoのMsTimer2の代わりにTickerライブラリを使う
- 参考: https://qiita.com/exabugs/items/34aab51eb2d35207629b
- WiFi通信のような処理はonTickerな関数ではなくloop内に設置する。
サンプルコード
TickerTest.ino
# include <Ticker.h>
Ticker ticker;
bool bSend = false;
void setup() {
ticker.attach_ms(1000, onTicker);
}
void loop() {
if (bSend) {
//GASへPOSTする処理
bSend = false;
}
}
void onTicker() {
bSend = true;
}
ポイント2
GASへ送る方法
- HTTPSRedirectを使う
- https://github.com/electronicsguy/ESP8266/tree/master/HTTPSRedirect
- ESP8266のボードバージョンは2.4.0を使う
準備1:fingerprintを取得
- opensslをインストール
- powerdhellで
echo | .\openssl s_client -connect script.google.com:443 |& .\openssl x509 -fingerprint -noout
を実行 - `const char* fingerprint = "XX:XX:XX:.....:XX";とする
準備2:GASでdoPost(e)なコードを用意する
-
concole.log(e.postData.contents)
とかやればとりあえすStackdriverのログに残ると思う - json.parseとかでjsonをパースできるね
GASのサンプルコード
コード.gs
function doPost(e) {
console.log(e.postData.contents); //Stackdriverのログへ
}
サンプルコード
https://github.com/electronicsguy/ESP8266/tree/master/HTTPSRedirect
のGooggleDocs.inoの改変です(サンプルがとても複雑なので)
コードに残っている課題
- HTTPSRedirectのオブジェクト確保まわり
- メモリを食いつぶしてwdtで落ちる問題とか
- たまに送信できなくなる
GAStest.ino
# include <ESP8266WiFi.h>
# include "HTTPSRedirect.h"
# include "DebugMacros.h"
// Fill ssid and password with your network credentials
const char* ssid = "*****";
const char* password = "*****";
const char* host = "script.google.com";
// Replace with your own script id to make server side changes
const char *GScriptId = "XXXXXXXXXXXX";
String url = String("/macros/s/") + GScriptId + "/exec";
const int httpsPort = 443;
// echo | openssl s_client -connect script.google.com:443 |& openssl x509 -fingerprint -noout
const char* fingerprint = "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX";
HTTPSRedirect* client = nullptr;
bool bClient = false;
const int MAX_CONNECT = 20;
int error_count = 0;
int connect_count = 0;
bool bSend;
//Ticker timer lib
Ticker ticker;
static const int TIMER_DELAY = 30 * 1000;
void setup() {
//start serial
Serial.begin(115200); //for debug
Serial.println("");
Serial.flush();
wifiMulti.addAP("****", "*****");
//start timer
ticker.attach_ms(TIMER_DELAY, onTimer);
Serial.println("setup end");
}
void loop() { //nothing again...
static wl_status_t prevWifiStatus = WL_IDLE_STATUS;
wl_status_t wifiStatus = wifiMulti.run();
if ( prevWifiStatus != wifiStatus ) {
prevWifiStatus = wifiStatus;
if ( wifiStatus == WL_CONNECTED) {
Serial.println("WiFi connected");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
else {
Serial.print("WiFi error: ");
switch(wifiStatus){
case WL_NO_SHIELD:
Serial.println("WL_NO_SHIELD");
break;
case WL_IDLE_STATUS:
Serial.println("WL_IDLE_STATUS");
break;
case WL_NO_SSID_AVAIL:
Serial.println("WL_NO_SSID_AVAIL");
break;
case WL_SCAN_COMPLETED:
Serial.println("WL_SCAN_COMPLETED");
break;
case WL_CONNECT_FAILED:
Serial.println("WL_CONNECT_FAILED");
break;
case WL_CONNECTION_LOST:
Serial.println("WL_CONNECTION_LOST");
break;
case WL_DISCONNECTED:
Serial.println("WL_DISCONNECTED");
break;
}
//wifiがつながってなかったらloopを抜けて送信をしない
return;
}
}
if (!bSend) return;
Serial.println("Send Start.");
if (!bClient) {
client = new HTTPSRedirect(httpsPort);
bClient = true;
client->setPrintResponseBody(true);
client->setContentTypeHeader("application/json");
}
if (client != nullptr) {
if (!client->connected()) {
client->connect(host, httpsPort);
}
}
else {
Serial.println("Error creating client object!");
error_count = 5;
return;
}
String payload = "{ \"value1\" : \"12345\" , \"humidity\" : \"67890\"}";
if (client->POST(url, host, payload, false)) {
Serial.println("loop POST");
connect_count++;
}
else {
++error_count;
Serial.print("Error-count while connecting: ");
Serial.println(error_count);
}
if (connect_count > MAX_CONNECT) {
//error_count = 5;
connect_count = 0;
bClient = false;
delete client;
return;
}
if (error_count > 3) {
Serial.println("Halting processor...");
delete client;
client = nullptr;
Serial.flush();
ESP.deepSleep(0);
}
bSend = false;
Serial.println("Send Finished.");
}
void onTimer() {
Serial.println("plz Send.");
bSend = true;
}