ESP-WROOM-32をHTTPで制御する
                ESP-WROOM-32(以下ESP32)をWiFi経由で制御するのに、RESTful APIのようにGETで値の取得、POSTで値の設定をしたかったけど、HTTPのPOSTメソッドを受けるサーバーについての情報が少なかったので、ここにまとめます。
ちなみに、Arduino IDEを使用しています。
サンプル
コード
#include <WiFi.h>
#include <WebServer.h>
const char* ssid     = "yourssid"; // 自分のSSIDに書き換える
const char* password = "yourpassword"; // 自分のパスワードに書き換える
WebServer server(80);
String target = "Initial String"; // この変数をPOSTメソッドで書き換える
void setup() {
  // シリアルコンソールのセットアップ
  Serial.begin(115200);
  delay(10);
  Serial.println();
  
  // WiFiに接続
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected.");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  // アクセスされた際に行う関数を登録する
  server.on("/target", HTTP_ANY, [](){
    if (server.method() == HTTP_POST) { // POSTメソッドでアクセスされた場合
      target = server.arg("plain"); // server.arg("plain")でリクエストボディが取れる。targetに格納
    }
    server.send(200, "text/plain", target); // 値をクライアントに返す
  });
  // 登録されてないパスにアクセスがあった場合
  server.onNotFound([](){
    server.send(404, "text/plain", "Not Found."); // 404を返す
  });
  server.begin();
}
void loop() {
  // put your main code here, to run repeatedly:
  server.handleClient();
}実行結果
簡単な解説
WebServer
SimpleWiFiServerで利用されているWiFiServerクラスはHTTPリクエストのパースを行ってくれないので、ここではWebServerクラスを利用します。
server.on
サーバーを起動する前に、onメンバ関数で、特定のパス(URL)にアクセスされた際の動作を登録します。
第1引数にパス、第2引数にアクセスされた際に実行する関数を指定します。
サンプルコードのように引数内に直接処理を記述する他、以下のように存在する関数を直接渡すこともできます。
void handleTarget() {
  // 省略
}
void setup() {
  // 省略
  // アクセスされた際に行う関数を登録する
  server.on("/target", handleTarget);
  // 省略
}また、今回GETとPOST両方使うため指定していませんが、引数を3つにして第2引数に受け付けるHTTPメソッドを指定することができます。(その場合関数は第3引数に)
更に、POSTメソッドでファイルなど1度に処理できない大きなデータが送られた場合は途中で第4引数に指定された関数が実行されます。(今回そんなことは想定してないので省略)
今回僕の目的では不要だったので利用していませんが、気になる場合は以下リファレンスを見てください。
第4引数についてはArduinoOTA内にあるOTAWebUpdaterというスケッチ例が参考になるかも。
server.arg
このメンバ関数でリクエストパラメータを取得できるみたい。plainにリクエストボディが格納されてた。
curlコマンドで-H "Content-Type: text/plain"を省略すると何も入ってなかったので、リクエストのContent-Typeでおそらく動作が変わる。
server.args関数でリクエストパラメータの数、server.argNameでリクエストパラメータの名前を取得できるので、困ったときはforで回してシリアルコンソールに流してみるといいかも。
server.onNotFound
server.onで登録されていないURLやメソッドでアクセスされた場合に実行される関数を登録します。
server.send
クライアントに返事を返します。第1引数にステータスコード、第2引数にContent-Type、第3引数にレスポンスボディを指定します。
第2引数にtext/html、第3引数にHTMLのコードを入れるとブラウザから開けるWebページをESP32で配信できたりするけど、今回の目的はあくまで値の取得と設定をRESTful APIっぽくしたかっただけなので、text/plainで十分。
server.handleClient
loop関数内で呼んでね
まとめ
リクエストボディの取得方法が分からなくて躓いた。
server.argはHTMLフォームで送信(application/x-www-form-urlencoded)とかすると変わってくれるのかな?試してないから分からないけど。
とりあえず簡単にESP32を操作できるようになったのでめでたしめでたし。
というか、普通にGETだけ使う場合でもプログラムが簡単になるので、フラッシュメモリの容量が足りないとか、特殊な理由がない限りWiFiServerクラスよりもWebServerクラスを使った方がいいと思う。
多分SimpleWiFiServerのスケッチ例がWiFiServerを使ってるからみんなこれを使うんだろうね。
コメント