うごくものをつくる

個人的な学習ノート

基礎技術メモ

ESP32のWebサーバーへブラウザから値を送り、変数として使用する方法

ESP32にブラウザから何らかの値や文字列を送り、それをESP32側で変数として使用したい、というときのためのやり方メモ。

目次

ESP32のWebサーバーについて

ESP32はWi-Fi接続機能が搭載されており、Webサーバーとして稼働させることができる。とあるURLにアクセスを受けたときどのような処理をするかをプログラムしておくことで、マイコンに所定の操作をさせることができる。

// 下記は記事中での説明のために必要な部分のみ抜粋しているので、これだけをコピペしてもESP32は動かない。
void setup(){
  server.on("/", root);
}

void root()
{
  // ファイルを読み込む
  File file = SPIFFS.open("/index.html", "r");
  
  server.sendHeader("Cache-Control", "public, max-age=86400"); // cache設定
  server.send(200, "text/html", file.readString());
  
  file.close();
}

たとえばこのようにArduinoフレームワークで開発する場合、ブラウザからESP32サーバーのルートディレクトリにアクセスがあったときにroot()を実行する、ということを、server.on()で設定する。

上の例においてroot()の具体的な中身は、SPIFFSに保存しておいたHTMLファイルであるindex.htmlを読み込み、それを送信する、という内容である。(SPIFFSに保存したHTMLファイルを読み込むのではなく、ソースコード上に直接HTMLタグを記入し送信することでページ表示させても良い。)

もちろん、HTMLページを表示させる以外の処理をここに書いても良くて、例えばアクセスを受けたら用意しておいた変数の値を1増やすことで、何回アクセスを受けたのかをカウントするといったこともできる。これを使って、アクセス回数が偶数のときにLEDを点灯させて、奇数のときに消す、みたいな処理をさせることもできる。

単純にLEDをのオンオフを切り替えるだけであればこのようなやり方でいいし、オンにする専用のページ、オフにする専用のページというのを用意しても良い。

// 下記は記事中での説明のために必要な部分のみ抜粋しているので、これだけをコピペしてもESP32は動かない。
void setup(){
 pinMode(2, OUTPUT);
  server.on("/on", led_on);
  server.on("/off", led_off);
}

void led_on(){
  digitalWrite(2, HIGH);
}

void led_off(){
  digitalWrite(2, LOW);
}

こんな感じ。ESP32のサーバー名をmyserverに設定してLAN内で稼働しているとき、http://myserver.local/on にアクセスするとGPIO2に接続したLEDが点灯し、http://myserver.local/offにアクセスすると消灯する。

このようにして様々なページにアクセスするたびに所定の動作をさせているのが、過去に作成し本ブログでも紹介したスマートリモコンである。

ただ、単にURLにアクセスするだけではなくこちらから何らかの値を送信し、ESP32にそれを使ってもらうような動作をさせたいこともあるだろう。例えば、数値を送るとそのduty比でLEDを点灯させる、とか。

ESP32でPostリクエストを受ける

先ほどのserver.on()では、アクセスがあったときにroot()を実行するように設定していたが、先ほどの設定のしかただとどのようなアクセスであってもroot()が実行される。

ブラウザから送られた値を読み込むためには、ページを表示するためのアクセス(GETリクエスト)と、値を送信するためのアクセス(POSTリクエスト)によって、それぞれ異なる動作をさせる必要がある。よって、server.on()にてGETリクエストなのかPOSTリクエストなのかを区別するよう、以下のように書き換える。

  server.on("/", HTTP_GET, get);//初期ページにGETリクエストがあったとき、get()を実行
  server.on("/", HTTP_POST, post);//初期ページにPOSTリクエストがあったとき、post()を実行

このように、同じURL宛てのアクセスであっても、その種類が”読み込み”なのか、それとも”送信”なのかによって呼び出す関数を変えることができる。

Formを使って値を送信する。

値を送信するために、入力フォームと送信ボタンを持つHTMLページを作る。そして、ページが読み込まれたときにこれを表示する。というわけで先程作ったget()にて、このWebページを作成し、ブラウザ側に送信して表示させよう。

void get(){
  String HTML = "<!DOCTYPE html> \n<html lang=\"ja\">";
  HTML += "<HTML><HEAD><meta charset ='UTF-8'><TITLE>トップページ</TITLE></HEAD>";
  HTML += "<BODY><p><B>送信したい値を入力してください。</B></p>";
  HTML += "<p><form method=\"POST\" target=_self>";
  HTML += "<input type=\"text\" name=\"senddata\">";
  HTML += "<input type=\"submit\" value=\"送信\"></p></form>";
  HTML += "</BODY></HTML>";

  server.send(200, "text/html", HTML);
}

このHTMLページはブラウザで開くとこんな感じである。

入力フォームと送信ボタン以外は何もないシンプルなページだが、設定しておくべきことがいくつかある。

一つは<form>タグにおいて、method=”POST”としておく。これで、送信ボタンでPOSTリクエストを送りますよというのを明示しておく。

さらに、target=_selfとする。これはデータの送信先であり、_selfのときは今のページ(URL)にそのまま送信する。先ほどのpost()関数はget()関数と同じURLにアクセスを受けたときに起動するものとしたので、データの送信先は自分自身としておかなければならない。

次に、入力フォームを作る<input>タグ内にて、名前をちゃんとつけておく。名前は任意だが、ここではname=”senddata”とすることで、この入力フォーム内に入れられたデータにsenddataという名前をつけておく。この名前は送信されたデータを読み込むときに必要である。

server.arg()でformのデータを受信する

さて、先ほどのページで送信ボタンを押すと、ESP32にPOSTリクエストが送信されることで、post()が呼び出される。リクエストを受け取ったESP32が入力フォームの中身を読み取るには、次のようにする。

void post(){
  String formInput = server.arg("senddata");

  String HTML = "<!DOCTYPE html> \n<html lang=\"ja\">";
  HTML += "<HTML><HEAD><meta charset ='UTF-8'><TITLE>トップページ</TITLE></HEAD>";
  HTML += "<BODY><p><B>あなたが送信した文字列は、" + formInput + "です。</B></p>";
  HTML += "</BODY></HTML>";

  server.send(200, "text/html", HTML);
}

server.arg()は、POSTリクエストのうち、指定した名前と同じ名前のデータを読み取り、String型で返す。先ほど<input>タグにてデータの名前をsenddataとしたので、ここでもserver.arg(“senddata”)とすることで、senddataと名前の付いているデータの中身を読んでもらう。

読み込んだ文字列はそのままWebページに表示する。

こんな感じで文字を入力して送信ボタンを押すと……

こんな感じで、送信した文字列がちゃんとWebページ内に文章として表示されている。

あとは、読み込んだ文字列が事前に設定した文字列と一致していたら○○を実行……のようにしてブラウザからESP32を制御するコマンドを送ってもいいし、文字列を数値に変換して、LEDの点滅duty比やサーボモーターの角度などに用いても良い(※入力フォームで半角数値を入れても、読み取る段階ではString型になっているので、数値として使いたいならint型などに適宜変換が必要)。

まとめ

・server.on()にて、POSTリクエストを受けたときに呼び出す関数を設定する。

・POSTで送信するデータには、ちゃんと名前をつけておく。

・server.arg()で、つけた名前のデータを読み込む。

これで、ブラウザ側からESP32に値を送り、それをマイコンの内部変数として自由に使うことができるので、とても便利になった。

今回のソースコード全体は以下の通り。

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>

//Wi-Fi接続の初期設定
//自宅のWi-Fiルーターの情報を入れる(2.4GHz)
const char* ssid = "Wi-Fi_SSID";
const char* password = "Wi-Fi_Password";

WebServer server(80); //ポートは80番を使用
const char *serverName = "myserver";
HTTPClient client;

void get();
void post();

void setup() {
WiFi.begin(ssid, password);
  Serial.begin(115200);
  delay(10);//内部レジスタ待ち
  while (WiFi.status() != WL_CONNECTED) //WiFiに接続完了していない間…
  {
    //何もせず接続待ち待機
  }

  //設定した名前でmDNSを開始
  if (!MDNS.begin(serverName))
  {
    //Serial.println("mDNS Failed");
    while (1);
  }
  MDNS.addService("http", "tcp", 80);//Webサーバーを開始
  Serial.print("My server Name is,");
  Serial.println(serverName);

  server.on("/", HTTP_GET, get);//初期ページにGETリクエストがあったとき、getを実行
  server.on("/", HTTP_POST, post);//初期ページにPOSTリクエストがあったとき、postを実行
  server.begin();
}

void loop() {
  server.handleClient();
}

void get(){
  String HTML = "<!DOCTYPE html> \n<html lang=\"ja\">";
  HTML += "<HTML><HEAD><meta charset ='UTF-8'><TITLE>トップページ</TITLE></HEAD>";
  HTML += "<BODY><p><B>送信したい値を入力してください。</B></p>";
  HTML += "<p><form method=\"POST\" target=_self>";
  HTML += "<input type=\"text\" name=\"senddata\">";
  HTML += "<input type=\"submit\" value=\"送信\"></p></form>";
  HTML += "</BODY></HTML>";

  server.send(200, "text/html", HTML);
}

void post(){
  String formInput = server.arg("senddata");

  String HTML = "<!DOCTYPE html> \n<html lang=\"ja\">";
  HTML += "<HTML><HEAD><meta charset ='UTF-8'><TITLE>トップページ</TITLE></HEAD>";
  HTML += "<BODY><p><B>あなたが送信した文字列は、" + formInput + "です。</B></p>";
  HTML += "</BODY></HTML>";

  server.send(200, "text/html", HTML);
}

今回はmyserverという名前に設定したので、上記のコード内のWi-FiのSSIDとパスワードをご自分のものに書き換えてからESP32に書き込み、同じWi-Fiルーターにつながっているパソコンやスマホなどからhttp://myserver.local/にアクセスすると、今回と同じことができる。

おわり

Header illustration by Freepik Storyset

返信する

メールアドレスが公開されることはありません。 が付いている欄は必須項目です