WebページからESP32のGPIO出力を切り替える【ESP32, ESPAsyncWebServer】
はじめに
以前、ESP32でWebサーバーを立てる方法をご紹介しました。
今回はこれを応用し、WebページからESP32のGPIO出力を切り替えるプログラムを作成します。
構成イメージ
以前と同じようにESP32のWi-Fi設定をsoftAPモードに設定し、Webサーバーを動かします。
また、ESP32のGPIOにLEDを接続します。今回は例としてGPIO25に接続します。
ライブラリの準備
Arduino IDEに、必要なライブラリをインストールしていきます。
「ESPAsyncWebServer」、「AsyncTCP」、「Sketch data upload」に加えて、
Webページとのデータのやりとりで使用するJSONを扱えるライブラリの「ArduinoJSON」をインストールします。
Arduino IDEの「ツール」→「ライブラリを管理…」でライブラリマネージャーを開き、「ArduinoJSON」で検索してインストールします。
プログラム
Arduino IDEで以下のようなプログラムを作成・保存して、ESP32に書き込みます。
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
#include <ArduinoJson.h>
const char ssid[] = "ESP32AP-TEST";
const char pass[] = "12345678"; // パスワードは8文字以上
const IPAddress ip(192,168,123,45);
const IPAddress subnet(255,255,255,0);
AsyncWebServer server(80); // ポート設定
// Jsonオブジェクトの初期化
StaticJsonDocument<512> doc;
#define LED_PIN 25
uint8_t led_status; //LEDの状態制御用変数
void setup()
{
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT); // GPIO25を出力設定に
// SPIFFSのセットアップ
if(!SPIFFS.begin(true)){
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
WiFi.softAP(ssid, pass); // SSIDとパスの設定
delay(100); // このdelayを入れないと失敗する場合がある
WiFi.softAPConfig(ip, ip, subnet); // IPアドレス、ゲートウェイ、サブネットマスクの設定
IPAddress myIP = WiFi.softAPIP(); // WiFi.softAPIP()でWiFi起動
// 各種情報を表示
Serial.print("SSID: ");
Serial.println(ssid);
Serial.print("AP IP address: ");
Serial.println(myIP);
// GETリクエストに対するハンドラーを登録
// rootにアクセスされた時のレスポンス
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html");
});
// style.cssにアクセスされた時のレスポンス
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
// LED の制御変数の変更リクエスト
server.on(
"/post_test",
HTTP_POST,
[](AsyncWebServerRequest * request){},
NULL,
[](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {
String resjson = "";
for (size_t i = 0; i < len; i++) {
//Serial.write(data[i]);
resjson.concat(char(data[i]));
}
Serial.println(resjson);
DeserializationError error = deserializeJson(doc, resjson);
if(error){
Serial.println("deserializeJson() faild");
request->send(400);
}
else{
led_status = doc["LED_STATUS"]; //zz Tilt Motor Default SPEED
request->send(200);
}
});
led_status = 0;
// サーバースタート
server.begin();
Serial.println("Server start!");
}
void loop() {
// LED状態変更
if(led_status == 0){
digitalWrite(LED_PIN, LOW);
}
else{
digitalWrite(LED_PIN, HIGH);
}
delay(100);
}
「data」フォルダの中に「index.html」と「style.css」を以下の内容で作成・保存して、「ESP32 Sketch Data Upload」を実行して書き込みます。
・ index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" charset="UTF-8">
<title>ESP32 Web Server</title>
<link rel="icon" href="data:,">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>ESP32 Web Server</h1>
<br>
<div id="btn_msg" style="visibility:hidden;">送信OK</div>
<br>
<button type="button" onclick="btn_do_on()" id="btn_led_on">ON</button>
<br>
<button type="button" onclick="btn_do_off()" id="btn_led_off">OFF</button>
</body>
<script>
// json返り値のテンプレート
var json_temp = {
LED_STATUS: 0
}
// 送信ステータス表示
function btn_msg_display(msg_txt, txt_color){
var id_btn_msg = document.getElementById("btn_msg")
id_btn_msg.style.color = txt_color;
id_btn_msg.textContent = msg_txt;
id_btn_msg.style.visibility ="visible";
}
// タイムスタンプ文字列の作成
function get_time_stamp() {
var now_time = new Date();
var now_date = ('000' + now_time.getFullYear()).slice(-4) + '-' + ('0' + (now_time.getMonth() + 1)).slice(-2) + '-' + ('0' + now_time.getDate()).slice(-2);
var now_time_val = ('0' + now_time.getHours()).slice(-2) + ':' + ('0' + now_time.getMinutes()).slice(-2) + ':' + ('0' + now_time.getSeconds()).slice(-2);
var time_stamp = now_date + " " + now_time_val + " ";
return time_stamp;
}
// LEDの状態変更リクエストの送信
function send_status(send_status){
var str_status = "";
if(send_status == 0){
str_status = "LED_OFF";
}
else{
str_status = "LED_ON";
}
// JSONデータの作成
var send_json = json_temp;
send_json.LED_STATUS = send_status;
send_json = JSON.stringify(send_json);
// リクエストを送信
var xhr = new XMLHttpRequest()
xhr.open("POST", "/post_test", true)
xhr.setRequestHeader("Content-Type", "application/json")
xhr.timeout = 5000; // タイムアウト設定(ms)
xhr.onload = () => {
btn_msg_display(get_time_stamp() + str_status + " 送信 OK", "#00aa00");
};
xhr.onerror = () => {
btn_msg_display(get_time_stamp() + str_status + " 送信 NG", "#ff0000");
};
xhr.ontimeout = () => {
btn_msg_display(get_time_stamp() + str_status + " 送信 タイムアウト", "#ff0000");
};
xhr.send(send_json)
}
// ONボタン動作
function btn_do_on(){
send_status(1);
}
// OFFボタン動作
function btn_do_off(){
send_status(0);
}
</script>
</html>
・ style.css
html {
font-family: Helvetica;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h1{
color: #0F3376;
padding: 30px;
font-size: 1.5rem;
}
button{
font-size: 2.0rem;
width: 180px;
height: 75px;
margin: 10px;
border-radius: 3px;
}
#btn_led_on{
color: #cc0000;
border: solid 2px #cc0000;
background-color: #ffcccc;
}
#btn_led_off{
color: #00cccc;
border: solid 2px #00cccc;
background-color: 7acccc;
}
動作
PCやスマホ等をESP32のアクセスポイントに接続し、Webブラウザから設定したIPアドレス(例: 192.168.123.45)にアクセスします。
画面上の「ON」ボタンを押すとLEDが点灯します。
「OFF」ボタンを押すとLEDが消灯します。
おわりに
WebページからESP32のGPIO出力を切り替えるプログラムをご紹介しました。
このプロラグムを利用すれば、プログラムの設定値をスマホ等のWebブラウザから手軽に変更できるようになります。
様々な応用ができそうなので、今後のものづくりに生かしていきたいと思います。