目的:
クライアントからの POST 要求で LED ON/OFF できるようにする。POST 受信処理:
クライアントからのメッセージは、リクエスト行 (GET / POST 等 )
リクエストヘッダ
空行
メッセージボディ (POST のデータ等)
の順に送られ、GET要求の場合は メッセージボディが無く、POST要求ではメッセージボディに送信データが入る。
POST受信処理では、空行の後のメッセージボディを受信して解析する必要がある。
リクエスト行から空行の間は、行単位(最後が '\r\n'で終了) の為、GET要求の受信処理では行単位で処理 ( readStringUntil('\n') で 行末('\n') までを種付く) していたが、メッセージボディの最後は ('\r\n') になるとは限らない為、readStringUntil('\n')で データを取得すると、('\n') が見つからずに タイムアウト (Default 1秒) まで待たされる。この為、受信バイト数分を取得 (メッセージボディ全てを一度に取得) して処理することとした。
例:
LED ON/OFF (固定 IPアドレス) の スケッチ に POST 受信処理を追加した例を以下に示す。WEB画面:
GET 用の ON, OFF ボタン と
POST 用 の ON, OFF ボタン を 設置
POST 用 の ON, OFF ボタン を 設置
POST_ON, POST_OFF 押下時、POST要求を発行
スケッチ:
// +==========================================================================+
// | WiFi LED ON/OFF TEST ( GET / POST ) |
// +==========================================================================+
//
#include <WiFi.h> // WiFi 用
//
// ----------------------------------------------------------------------------
// 各種設定 --
// ----------------------------------------------------------------------------
const char* ssid = "hogehoge" ; // WiFi AP SSID
const char* password = "hogehogepassy"; // WiFi AP パスワード
//
String html; // HTML 格納用
//
IPAddress ip(192, 168, 1, 32); // ESP32 IPアドレス
IPAddress gateway(192,168, 1, 1); // ゲートウェイアドレス
IPAddress subnet(255, 255, 255, 0); // サブネットマスク
IPAddress DNS(192, 168, 1, 90); // DNS アドレス
//
WiFiServer server(80); //
//
// ----------------------------------------------------------------------------
// 初期設定 --
// ----------------------------------------------------------------------------
void setup() //
{ //
Serial.begin(115200); // シリアル出力開始
pinMode(2, OUTPUT); // LED 用 PIN 設定
//
WiFi.config(ip, gateway, subnet, DNS); // ESP32 WiFi 設定
delay(10); //
//
Serial.println(); // デバッグ用出力
Serial.print("Connecting to "); //
Serial.println(ssid); //
//
WiFi.begin(ssid, password); // WiFi 開始
//
while (WiFi.status() != WL_CONNECTED) { //
delay(500); //
Serial.print("."); //
} //
//
Serial.println(""); // デバッグ用出力
Serial.println("WiFi connected."); //
Serial.println("IP address: "); //
Serial.println(WiFi.localIP()); //
//
server.begin(); // WiFi サーバ 開始
//
} //
//
// ----------------------------------------------------------------------------
// メインループ --
// ----------------------------------------------------------------------------
void loop(){ //
String line = "" ; // データ格納用
char buf[257] ; //
int n ;
bool post_req = false ; // ポスト要求フラグ
WiFiClient client = server.available(); // listen for incoming clients
//
if (client) { // if you get a client,
Serial.println("***** Client access start *****"); // デバッグ用出力
while (client.connected()) { // client が接続されている間
if (client.available()) { // client からのデータがある間
line = client.readStringUntil('\n'); // データを1行分取得
Serial.println(line); // デバッグ用出力
if (line.indexOf("POST /") != -1) { // "POST /" 受信の場合
post_req = true ; // LED on
} //
if (line.indexOf("GET /?on") != -1) { // "GET /?on" 受信の場合
digitalWrite(2, HIGH); // LED on
} //
if (line.indexOf("GET /?off") != -1) { // "GET /?off" 受信の場合
digitalWrite(2, LOW); // LED off
} //
// 空行を受信した場合 --------------- //
if (line.length() == 1 && line[0] == '\r'){ // 空行の場合
if (post_req) { // POST 要求の場合
line = "" ; // データ格納用変数初期化
while (n=client.available()) { // 残りデータを全て受信
if (n<256){ //
client.readBytes(buf,n) ; //
buf[n] = 0 ; //
} else { //
client.readBytes(buf,256) ; //
buf[256] = 0 ; //
} //
line += buf ; //
} //
// POST データ処理 ------------- //
Serial.println(line); // デバッグ用出力
if (line.indexOf("post_on") != -1) { // "on" の場合
digitalWrite(2, HIGH); // LED on
} //
if (line.indexOf("post_off") != -1) { // "off" の場合
digitalWrite(2, LOW); // LED off
} //
} //
// 終了処理 ---------------------------//
send_response(client) ; //
Serial.println("Send HTML !!"); //
break; // break while loop
} //
} //
} //
delay(1); // give the web browser time to receive the data
// close the connection: --------------------//
client.stop(); //
Serial.println("Client Disconnected."); //
Serial.println("--------------------------------------------------");
} //
} //
// ------------------------------------------------------------------
void send_response(WiFiClient client) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
// the content of the HTTP response follows the header:
client.print("<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>" ) ;
client.print("<style>input {margin:8px;width:100px;}div {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}</style>" ) ;
client.print("<title>Color LED Controller</title></head>" ) ;
client.print("<body><div><p>LED ON/OFF</p>" ) ;
client.print("<form method='get'>" ) ;
client.print("<input type='submit' name='on' value='GET_ON' /><input type='submit' name='off' value='GET_OFF' />" ) ;
client.print("</form>" ) ;
client.print("<form method='post'>" ) ;
client.print("<input type='submit' name='post_on' value='POST_ON' /><input type='submit' name='post_off' value='POST_OFF' />" ) ;
client.print("</form>" ) ;
client.print("</div></body></html>" ) ;
client.println();
Serial.println( " --- send responce --- ");
}
以下、メモ
・詳細は コメント参照。
(行#58~60)
POST処理用 変数定義。
(行#69~71)
リクエスト行が POST の場合に POST処理フラグを立てる。
(行#80~100)
POST 処理フラグが 立っていた場合のPOST処理。
(行#81~91) で メッセージボディのデータを取得。
readStringUntil('\n') や readString() を使用すると、タイムアウト(Default 1000mS) まで待ってしまい、ボタンを押下してから LED の ON/OFF まで 1秒かかる。
この為、残りデータ数 (client.available() の戻り値) 分を client.readBytes() で取得している。
(行#92~98) で メッセージボディのデータを処理。
処理内容は、GET と同様。

0 件のコメント:
コメントを投稿