一定のつらみ。
Google Apps ScriptのWebAPIは厳しい
GASのWebAPIをESP8266から叩くときに、2つの大きな問題があります。
- HTTPSに対応すること
- HTTPリダイレクトに対応すること
HTTPS対応
いままではポート80にアクセスしていましたが、HTTPSになると443にアクセスしなければなりません。また、それでだけでは不十分で、通常のHTTP接続を行ってくれる便利クラスのインスタンスのコンストラクタで、フィンガープリントなる文字列を引数に与えなければなりません。
そこで、便利なのがこのサイト。アクセスしたいアドレスを打ち込むだけで、フィンガープリントを生成してくれます。ターミナルからSSLのコマンドを売ったりする必要はありません。
HTTPリダイレクト対応
Google Apps Scriptで作ったWebAPIは、アドレスにアクセスしても別のアドレスにリダイレクトされてしまいます。
Content Service | Apps Script | Google Developers
For security reasons, content returned by the Content service isn't served from script.google.com, but instead redirected to a one-time URL at script.googleusercontent.com.
ただし、ESP8266の実装でよく使われるHTTPClientやWifiClient (WifiClientSecure)はリダイレクションに対応していないようで、上手く動作しません。そこで、今回はHTTPSRedirectというライブラリを使って実装をしてみます。
サンプルコードも載っているので非常にわかりやすいです。
いざ実装
今回は、以前作ったポキオ基板v2を使って実装してみます。
基本的にはESPr Developerで、IO4がマイコン内蔵RGB LEDとつながっています。また、アクセスする先は、前回作ったpokio
という文字列を返すだけのGASのWebAPIです。
クソコードはこんな感じ。
#include <ESP8266WiFi.h> #include <Adafruit_NeoPixel.h> #include <HTTPSRedirect.h> #define PIN 4 #define NUMLED 1 #define SSID "xxxxx" #define PASSWORD "yyyyy" #define HTTPS_PORT 443 #define HOST "script.google.com" #define URL "/macros/s/zzzzz/exec" #define FINGERPRINT "FI NG ER PR IN T!" HTTPSRedirect* client = nullptr; Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMLED, PIN, NEO_RGB + NEO_KHZ800); void setup() { // Serialの初期化 Serial.begin(115200); Serial.println(""); // マイコン内蔵RGB LEDの初期化 pixels.begin(); } void loop() { // Wi-Fi接続開始 connectWifi(); // Google Apps Scriptを叩く Serial.println(doRedirectGet()); // Wi-Fi接続終了 disconnectWifi(); delay(10000); } // Wi-Fi接続 void connectWifi() { WiFi.mode(WIFI_STA); WiFi.begin(SSID, PASSWORD); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); blinkWhite(3); } Serial.println("Wi-Fi connected"); } // Wi-Fi切断 void disconnectWifi() { WiFi.disconnect(); Serial.println("Wi-Fi disconnected"); } // 白い点滅 void blinkWhite(int sec) { int count = 0; while (count < sec) { for (int i = 0; i < 256; i += 5) { setColor( i, i, i); } for (int i = 255; i >= 0; i -= 5) { setColor( i, i, i); } count++; } } // LEDを指定した色で光らせる void setColor(int r, int g, int b) { for (int i = 0 ; i < NUMLED; i++) { pixels.setPixelColor(i, pixels.Color(r, g, b)); pixels.show(); } delay(10); } // Redirectを回避してHTTP-GETする String doRedirectGet() { String body = ""; client = new HTTPSRedirect(HTTPS_PORT); if (!client->connect(HOST, HTTPS_PORT)) { Serial.println("connection failed"); return body; } if (!client->verify(FINGERPRINT, HOST)) { Serial.println("certificate doesn't match"); } client->GET(URL, HOST); body = client->getResponseBody(); delete client; client = nullptr; return body; }
動作確認
Serial Monitorの出力はこんな感じ。
.Wi-Fi connected pokio Wi-Fi disconnected
いい感じですね。たまに、
..Wi-Fi connected certificate doesn't match pokio Wi-Fi disconnected
こんな感じでフィンガープリントでの認証が通らない時もありますが、それでもAPIは正しく返ってきています(笑)