Androidのメモとか

そふとうぇあえんじにゃーの備忘録

ESP8266からGoogle Apps Scriptを叩くのはちょっと面倒

一定のつらみ。

Google Apps ScriptのWebAPIは厳しい

GASのWebAPIをESP8266から叩くときに、2つの大きな問題があります。

  1. HTTPSに対応すること
  2. HTTPリダイレクトに対応すること

HTTPS対応

いままではポート80にアクセスしていましたが、HTTPSになると443にアクセスしなければなりません。また、それでだけでは不十分で、通常のHTTP接続を行ってくれる便利クラスのインスタンスのコンストラクタで、フィンガープリントなる文字列を引数に与えなければなりません。

www.grc.com

そこで、便利なのがこのサイト。アクセスしたいアドレスを打ち込むだけで、フィンガープリントを生成してくれます。ターミナルから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というライブラリを使って実装をしてみます。

github.com

サンプルコードも載っているので非常にわかりやすいです。

いざ実装

今回は、以前作ったポキオ基板v2を使って実装してみます。

relativelayout.hatenablog.com

ESP8266 HTTP REDIRECTION

基本的にはESPr Developerで、IO4がマイコン内蔵RGB LEDとつながっています。また、アクセスする先は、前回作ったpokioという文字列を返すだけのGASのWebAPIです。

relativelayout.hatenablog.com

クソコードはこんな感じ。

#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は正しく返ってきています(笑)

「Androidのメモとか」は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。

このブログは個人的なメモ書きであったり、考えを書く場所であります。執筆者の所属する団体や企業のコメントや意向とは無関係であります。また、このブログは必ずしも正しいことが書かれているとは限らず、誤字脱字や意図せず誤った情報を載せる場合がありえます。それが原因で読者が不利益を被ったとしても、執筆者はいかなる責任も負いません。ありがとうございます。