ESP32を使って学習リモコンを作る(5) ソフトウエア webserver

赤外線リモコン スマートリモコン Smart Remote Controller Aruduino PlatformIO ESP32

本項では全画面表示が可能な図番に * を付けています。

ESP32を使って学習リモコンを作る(4) で説明した「赤外線リモコン送信( irSend )」に引き続きソフトウエアの要素技術「 webserver 」について説明します。  

はじめに

学習リモコンを製作して家電製品を制御するシステム構成を 図1 に示します。本機 ESP32-DevKitC-32E を使ったブレッドボードは赤外線リモコン波形学習(波形取込)と赤外線リモコン波形の送信機能を備えています。そして PC やスマートフォンの画面から GUI として Web ブラウザでこれらの機能を制御します。

ESP32-DevKitC-32E に webserver を実装して web ブラウザを実現します。

「Marchan」さんの 1-1.  非同期サーバーをクライアントから制御する① からコードを参照して webserver の確認を行います。コードはほぼそのまま使わせていただきますが、ブラウザ表示に必要な HTML、Java Script、CSS は独立させて別フォルダーに格納しました。

Arduino IDE 環境で作成されていますが、ここでは Visual Studio Code PlatformIO 拡張環境に適合させています。

図1 システム構成

 

ハードウエア

webserver は ESP32-DevkitC-32E のみで動作するのでこれまで使っていたハードウエアをそのまま使用することができます。 ESP32を使って学習リモコンを作る(4) で使ったブレッドボードをそのまま使います。(図2)

*図2 webserver 動作確認に使用するブレッドボード

 

プロジェクトを作成する

Visula Studio Code ( VSCode ) を開いて画面左端縦の「アクティビティバー」からアリさんマーク(赤丸)をクリックします。(図3)

*図3 Visual Studio Code を開く

プライマリサイドバーが表示されるので Create New Project をクリックします。(図4)

*図4 プライマリサイドバー

PIO Home 画面が表示されます。(図5)

*図5 PIO Home

画面中央から右寄りの Quick Access から + New Project をクリックすると、Project Wizard が表示されます。(図6)

*図6 Project Wizard

Project Wizard に従って入力します。(図7)
  Name:  PIO_WiFiAsyncTest_3 (何でもいいので任意のプロジェクト名を入力)
  Board: Espressif ESP32 Dev Module (プルダウンメニューから選択します)
  Framework: Arduino (プルダウンメニューから選択します)  

*図7 Project Wizard に入力した

Project Wizard で Finish をクリックするとプロジェクトが自動生成されます。(図8)

 

*図8 プロジェクトが自動生成された

ライブラリ

ESP Async WebServer と AsysncTCP の 2 つのライブラリが必要になります。ESP Async WebServer と AsysncTCP は Built-in で組み込まれているので何もする必要はありません。

webserver プロジェクト

自動生成されたプロジェクトに追加、変更を加えて webserver に対応させます。

platformio.ini ファイルに以下の 2 行を追加します。(図9)
  upload_port = COM3 (使用する PC に合わせます)
  monitor_speed = 115200

*図9 platformio.ini

main.cpp ファイルをクリックして自動生成されたプログラムを表示します。(図10)

*図10 main.cpp

main.cpp の内容を全て削除して代わりに次のコードを使います。(図11)

#include <asynceventsource.h>
#include <asyncwebsocket.h>
#include <asyncwebsynchronization.h>
#include <espasyncwebserver.h>
#include <spiffseditor.h>
#include <stringarray.h>
#include <webauthentication.h>
#include <webhandlerimpl.h>
#include <webresponseimpl.h>

#include <httpupdate.h>

#include <spiffs.h>

#include <arduino.h>
#include <wifi.h>
#include <espasyncwebserver.h>

/* Function Prototype */
void doInitialize();
void connectToWifi();
String editPlaceHolder(const String&);
String getMessage();
String getCurTime();

// ルーター接続情報
#define WIFI_SSID "xxxxxxxx"
#define WIFI_PASSWORD "yyyyyyyy"

// NTPサーバー時刻設定用
const char* ntpServer = "pool.ntp.org";
const int   gmtOffset_sec = 9 * 3600;

/* 基本属性定義  */
#define SPI_SPEED   115200
#define CST_ON      "ON"
#define CST_OFF     "OFF"

// Webサーバーオブジェクト
#define HTTP_PORT 80
AsyncWebServer server(HTTP_PORT);

/* LEDピン */
const int ledPin = 25;              // LED出力接続ピン
String ledState = "";               // 出力ピンの状態

/*****************************************************************************
 *                          Predetermined Sequence                           *
 *****************************************************************************/
void setup(){
    doInitialize();             // 初期化処理をして
    connectToWifi();            // Wi-Fiルーターに接続する
    configTime(gmtOffset_sec, 0, ntpServer);  // まず時刻を合わせる


    // SPIFFSのセットアップを追加
    if (!SPIFFS.begin(true)) {
      Serial.println("An Error has occurred while mounting SPIFFS");
      return;
    }

    // GETリクエストに対するハンドラーを登録して
    // index.htmlにアクセスされた時のレスポンス
    server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
      request->send(SPIFFS, "/index.html", String(), false, editPlaceHolder);
    });

    // style.cssにアクセスされた時のレスポンス
    server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
      request->send(SPIFFS, "/style.css", "text/css");
    });

   // js.jsにアクセスされた時のレスポンス
    server.on("/js.js", HTTP_GET, [](AsyncWebServerRequest * request) {
      request->send(SPIFFS, "/js.js", "js/js");
    });

    server.on("/curtime", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/plain", getCurTime().c_str());
    });
    server.on("/message", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/plain", getMessage().c_str());
    });
    server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
        if (ledState == CST_ON) {
            ledState = CST_OFF;
            digitalWrite(ledPin, LOW);
        } else {
            ledState = CST_ON;
            digitalWrite(ledPin, HIGH);
        }
        Serial.print("LED changed : ");
        Serial.println(ledState);
        request->send_P(200, "text/plain", getMessage().c_str());
    });
    // サーバーを開始する
    server.begin();
}
 
void loop(){
}

/*****************************************************************************
 *                          'GET' Request Handlers                           *
 *****************************************************************************/
/* プレースホルダー処理 */
String editPlaceHolder(const String& var) {
    if (var == "MESSAGE") {
        return getMessage();
    }
    else if (var == "CURTIME") {
        return getCurTime();
    }
}

/* 現在の日時を取得する */
String getCurTime() {
    struct tm timeinfo;
    char buf[64];

    if(getLocalTime(&timeinfo)) {
        sprintf(buf,"%04d/%02d/%02d %02d:%02d:%02d",
            timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday,
            timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
        //Serial.println(buf); //20240714
        return buf;
    }
}

/* LEDの状態を通知する */
String getMessage() {
    return ledState;
}

/*****************************< Other functions >*****************************/
/* 初期化処理 */
void doInitialize() {
    Serial.begin(SPI_SPEED);
    pinMode(ledPin, OUTPUT);           // GPIO設定:LED
    digitalWrite(ledPin, LOW);
    ledState = CST_OFF;
}

/****************************< Connect functions >****************************/
/* Wi-Fiルーターに接続する */
void connectToWifi() {
    Serial.print("Connecting to Wi-Fi ");
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    // モニターにローカル IPアドレスを表示する
    Serial.println("WiFi connected.");
    Serial.print("  *IP address: ");
    Serial.println(WiFi.localIP());
    server.begin();
}

図11 main.cpp に使うコード

このコードをコピーして main.cpp にペーストした結果です。(図12)
SSID “xxxxxxxx” と PASSWORD “yyyyyyyy” は Wi-Fi ルーターに合わせて変更します。

*図12 main.pp にペーストした結果

画面左端縦の「アクティビティバー」から「エクスプローラー」をクリックしてプロジェクトフォルダーの階層を表示させます。
プロジェクトフォルダー名の右のアイコンから「新しいフォルダー」をクリックします。
プロジェクトフォルダーの下位に入力窓が表示されるので「data」と入力します。(図13)

*図13 data フォルダーを作る

次にカーソルを「data 」フォルダに合わせて、プロジェクトフォルダー名の右の「新しいファイル」アイコンをクリックすると data フォルダーの下位に入力窓が表示されるので「index.html」と入力します。(図14)

*図14 index.html ファイルを作る

同様にして data フォルダーの下位に「js.js」ファイルを作ります。(図15)

*図15 js.js ファイルを作る

同様にして data フォルダーの下位に style.css ファイルを作ります。(図16)

*図16 style.css ファイルを作る

図14 で作成した index.html ファイルに次のコードをコピー/ペーストします。(図17)

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
p{ text-align:center; }
</style>
<link rel="stylesheet" href="./style.css"> 
<script src="js.js"></script>
</head>
<body>
<h1>Asynchronous Server</h1>
<p><table>
<tr><th>ELEMENT</th><th width="100">VALUE</th></tr>
<tr><td>LED status</td><td><span id="message" class="value">%MESSAGE%</span></td></tr>
<tr><td>Current time</td><td><span id="curtime" class="value">%CURTIME%</span></td></tr>
</table></p>
<br><button class='btn_on' onclick='btnClicked(this)' id='btn'>CHANGE</button>
<div class="button_on">
<input type="checkbox" id="btn1" name="button_on"onclick="btn1Click();">
<label id= "btn1_label" for="btn1">電源 ON</label>
</div>
</body> 
</html>

図17 index.html のコード

このコードをコピーして index.html ファイルにペーストした結果です。(図18)

*図18 index.html ファイルにペーストした

図15 で作成した js.js ファイルに次のコードをコピー/ペーストします。(図19)

var getCurTime = function () {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("curtime").innerHTML = this.responseText;
    }
  };
  xhr.open("GET", "/curtime", true);
  xhr.send(null);
}
  
var getMessage = function () {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById("message").innerHTML = this.responseText;
      }
    };
    xhr.open("GET", "/message", true);
    xhr.send(null);
}
  
function btnClicked(element) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/update", true);
  xhr.send(null);
}
  
setInterval(getCurTime, 500);
setInterval(getMessage, 200);
  
function btn1Click(){
  const button1 = document.getElementById('btn1');
  button1.checked= true;   //電源 ONボタンが押されたら、電源 ONボタンを継続してtrueにする。 
}

図19 js.js のコード

このコードをコピーして js.js ファイルにペーストした結果です。(図20)

*図20 js.js ファイルにペーストした

図16 で作成した style.css ファイルに次のコードをコピー/ペーストします。(図21)

html {font-family: Helvetica; display: inline-block; margin: 0px auto;text-align: center;
} 
h1 {font-size:28px;
}
body {text-align: center;
} 
table {border-collapse: collapse; margin-left:auto; margin-right:auto;
}
th {padding: 12px; background-color: #0000cd; color: white; border: solid 2px #c0c0c0;
}
tr {border: solid 2px #c0c0c0; padding: 12px;
}
td {border: solid 2px #c0c0c0; padding: 12px;
}
.value {color:blue; font-weight: bold; padding: 1px;
}
.btn_on {width:100px; height:43px; padding:1px 1px; vertical-align: middle; 
  text-decoration:none; font-size:16px; background-color:
  #668ad8; color: #FFF; border-bottom: solid 4px #627295; border-radius: 4px;
}
.btn_on:active {-webkit-transform: translateY(0px); transform: translateY(0px);
  border-bottom: none;
}
.button_on{display: flex;
}
.button_on label{display: block;
  width: 150px;
  background:silver; /*silvergray*/
  color: black;
  padding: 10px;
  margin: 0 auto;
  box-sizing: border-box;
  text-align: center;
  text-decoration: none;
  border-radius: 5px;
  cursor: pointer;
}
.button_on input:checked+label{background:tomato; 
  color: white;
}
.button_on input{display: none;
}

図21 style.css のコード

このコードをコピーして style.css ファイルにペーストした結果です。(図22)

*図22 style.css ファイルにペーストした

以上で webserver プロジェクトが完成です。

webserver プロジェクトの勘所

①WiFi

16    #include <WiFi.h>

WiFi が使えるようにヘッダーファイルをインクルードします。(main.cpp 16行目)

26    // ルーター接続情報
27    #define WIFI_SSID “xxxxxxxx”
28    #define WIFI_PASSWORD “yyyyyyyy”

ルーター接続情報として SSID と PASSWORD を定義します。(main.cpp 26~28 行目)SSID “xxxxxxxx” と PASSWORD “yyyyyyyy” は Wi-Fi ルーターに合わせて変更します。

145    /* Wi-Fiルーターに接続する */
146    void connectToWifi() {
147        Serial.print(“Connecting to Wi-Fi “);
148        WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
149        while (WiFi.status() != WL_CONNECTED) {
150            delay(500);
151            Serial.print(“.”);
152        }
153        Serial.println(“”);
154        // モニターにローカル IPアドレスを表示する
155        Serial.println(“WiFi connected.”);
156        Serial.print(”  *IP address: “);
157        Serial.println(WiFi.localIP());
158        server.begin();
159    }

WiFiルーターに接続してモニターにローカル IP アドレスを表示するセットアップシーケンスを記述します。(main.cpp 145~159行目)

②Async Web Server

17    #include <ESPAsyncWebServer.h>

非同期 Web サーバーを使えるようにヘッダーファイルをインクルードします。(main.cpp 17行目)

96    // Webサーバーオブジェクト
97    #define HTTP_PORT 80
98    AsyncWebServer server(HTTP_PORT);

HTTP ポートを定義して非同期 Web サーバーオブジェクトをインスタンス化します。(main.cpp 39~41行目)

96    // サーバーを開始する
97    server.begin();

セットアップにサーバー開始を記述します。(main.cpp 96~97行目)

③SPIFFS

ブラウザの表示は main.cpp から独立させて index.html、js.js および style.css の3つのファイルに記述して外部のフラッシュメモリーに保存します。これらの 3 ファイルを外部フラッシュメモリーから呼び出すために SPIFFS( Serial Peripheral Interface Flash File System )を使用します。

13    #include <SPIFFS.h>

SPIFFS が使えるようにヘッダーをインクルードします。(main.cpp 13行目)

35    #define SPI_SPEED 115200

外部メモリーと SPI 接続する場合のスピードを定義します。(main.cpp 35行目)

138    Serial.begin(SPI_SPEED);
SPI 接続の初期化を行います。(main.cpp 138行目)
56    // SPIFFSのセットアップを追加
57        if (!SPIFFS.begin(true)) {
58          Serial.println(“An Error has occurred while mounting SPIFFS”);
59          return;
60        }

SPI 接続エラーが発生した時にターミナルにメッセージを出力するセットアップを追加しました。(main.cpp 56~60行目)

Webページ

WiFi、Async Web Server、SPIFFS が動作するとブラウザに学習リモコンの制御ページが表示できます。 IP アドレスを入力すると、フラッシュメモリーから index.html、js.js および style.css の情報を読込んでブラウザに表示します。

64    server.on(“/”, HTTP_GET, [](AsyncWebServerRequest * request) {
65        request->send(SPIFFS, “/index.html“, String(), false, editPlaceHolder);
66    });

ブラウザから IP アドレスを入力するとトップページ “/” にアクセスします。
GET リクエスト “/” に対して SPIFFS を経由した /index.html ファイルをレスポンスとしてクライアントに通知します。このときサーバーからクライアントへ情報を伝えることができる内部変数を使うために別途定義されている editplaceHolder を参照しています。(main.cpp 64~66行目)

9    <link rel=”stylesheet” href=”./style.css“>

スタイルを定義している style.css ファイルを参照しています。(index.html 9行目)

68    // style.cssにアクセスされた時のレスポンス
69    server.on(“/style.css”, HTTP_GET, [](AsyncWebServerRequest * request) {
70        request->send(SPIFFS,/style.css“, “text/css”);
71    });

GET リクエスト “/style.css” に対して SPIFFS を経由した /style.css ファイルをレスポンスとしてクライアントに通知します。(main.cpp 68~71行目)

10    <script src=”js.js“></script>
Web ページを動的に制御する Java Script js.js ファイルを参照しています。(index.html 10行目)
73    // js.jsにアクセスされた時のレスポンス
74        server.on(“/js.js”, HTTP_GET, [](AsyncWebServerRequest * request) {
75          request->send(SPIFFS, /js.js, “js/js”);
76        });
GET リクエスト “/js.js に対して SPIFFS を経由した /js.js ファイルをレスポンスとしてクライアントに通知します。(main.cpp 73~76行目)

⑤現在時刻表示

1    var getCurTime = function () {
2      var xhr = new XMLHttpRequest();
3      xhr.onreadystatechange = function() {
4        if (this.readyState == 4 && this.status == 200) {
5          document.getElementById(“curtime”).innerHTML = this.responseText;
6        }
7      };
8      xhr.open(“GET”, “/curtime”, true);
9      xhr.send(null);
10   }

Java Script を使って現在時刻を更新する制御を行っています。
ページ全体を更新せずにサーバーからデータを受け取ることができる XMLHttpRequest() オブジェクトを使用します。ドキュメントの状態が変化した場合はコールバック関数 onreadystatechange で “curtime” の内容を更新します。そして “GET” リクエストメソッドを使って URL “/curtime” へ非同期通信リクエスト true をサーバーへ送信します。(js.js 1~10行目)

29    setInterval(getCurTime, 500);
Java Script 内で関数 getCurTime は 500ms 毎に繰り返し実行されます。(js.js 29行目)
78     server.on(“/curtime”, HTTP_GET, [](AsyncWebServerRequest *request){
79         request->send_P(200, “text/plain”, getCurTime().c_str());
80     });

GET リクエスト “/curtime に対して “text/plain” 形式で getCurTime().c_str() をレスポンスとしてクライアントに通知します。(main.cpp 78~80行目)

116    /* 現在の日時を取得する */
117    String getCurTime() {
118        struct tm timeinfo;
119        char buf[64];
120
121        if(getLocalTime(&timeinfo)) {
122            sprintf(buf,”%04d/%02d/%02d %02d:%02d:%02d”,
123                    timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday,
124                    timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
125            //Serial.println(buf); //20240714
126            return buf;
127        }
128    }
現在の日時を取得するために getCurTime() 関数を定義しています。(main.cpp 116~128行目)
106    /* プレースホルダー処理 */
107    String editPlaceHolder(const String& var) {
108        if (var == “MESSAGE”) {
109            return getMessage();
110        }
111        else if (var == CURTIME) {
112            return getCurTime();
113        }
114    }

getCurTime() 関数の結果を内部変数として参照できるようにプレースホルダーで定義します。変数が “CURTIME” の場合戻り値は getCurTime() になります。(main.cpp 106~114行目)

64    server.on(“/”, HTTP_GET, [](AsyncWebServerRequest * request) {
65        request->send(SPIFFS, “/index.html“, String(), false, editPlaceHolder);
66    });
GET リクエスト “/” に対して SPIFFS を経由した /index.html ファイルをレスポンスとしてクライアントに通知します。このときサーバーからクライアントへ情報を伝えるための内部変数を使うために定義されている editplaceHolder を参照しています。(main.cpp 64~66行目)
17    <tr><td>Current time</td><td><span id=”curtime” class=”value”>%CURTIME%</span></td></tr>
editPlaceHolder を介して変数 CURTIME は %CURTIME% として index.html で参照されます。(index.htl 17行目)
⑥メッセージ表示
現在時刻の表示と同様の処理を行うことで main.cpp からのメッセージを Web ブラウザに表示することができます。内部変数 MESSAGE を使用して Java Script から 200ms 毎に内容を更新しています。
⑦ボタン処理
19    <br><button class=’btn_on’ onclick=’btnClicked(this)’ id=’btn’>CHANGE</button>
Web ブラウザにボタン btn を表示します。(index.html 19行目)
23    function btnClicked(element) {
24        var xhr = new XMLHttpRequest();
25        xhr.open(“GET”, “/update”, true);
26        xhr.send(null);
27    }
ボタン btn がクリックされると XMLHttpRequest() オブジェクトを使ってインスタンスを生成します。そして “GET” リクエストメソッドを使って URL “/update” へ非同期通信リクエスト true をサーバーへ送信します。(js.js 23~27行目)
84     server.on(“/update”, HTTP_GET, [](AsyncWebServerRequest *request){
85            if (ledState == CST_ON) {
86                ledState = CST_OFF;
87                digitalWrite(ledPin, LOW);
88            } else {
89                ledState = CST_ON;
90                digitalWrite(ledPin, HIGH);
91            }
92            Serial.print(“LED changed : “);
93            Serial.println(ledState);
94            request->send_P(200, “text/plain”, getMessage().c_str());
95        });

GET リクエスト “/update”  に対する main.cpp 内の処理が定義されています。ここでは LED の状態が CST_ON の場合は 端子 ledpin に LOW を出力して LED を OFF にします。そうでなければ LED の状態を CST_ON にして端子 ledpin に HIGH を出力して LED を ON にします。
ターミナルに ”LED cahnged :” + ledState(LED の状態)を出力します。
最後にリクエストに対するレスポンスとして “/text/plain” で getMessage().c_str() をクライアントに通知します。(main.cpp 84~95行目)

130    /* LEDの状態を通知する */
131    String getMessage() {
132        return ledState;
133    }

LED の状態を通知するために ledstate を戻り値にして getMessage() 関数を定義しています。(main.cpp 130~133行目)

106    /* プレースホルダー処理 */
107    String editPlaceHolder(const String& var) {
108        if (var == MESSAGE) {
109            return getMessage();
110        }
111       else if (var == “CURTIME”) {
112            return getCurTime();
113       }
114    }

getMessage() 関数の結果を内部変数として参照できるようにプレースホルダーで定義します。変数が “MESSAGE” の場合戻り値は getMessage() になります。(main.cpp 106~114行目)

=================================================

Async Web Server を使った情報伝達を簡単に整理すると次のようになります。(図23)

 クライアント サーバー : リクエスト(状態の変化)を通知
 クライアント サーバー : レスポンス(任意の文字列)を通知

図23 クライアント・サーバー

ファームウエアビルド

PROJECT TASKS から Build をクリックするとビルドが開始されて [SUCCESS] と表示されると完了です。(図24)

*図24 Build 完了

ファームウエア書込み

ESP32-DevKitC-32E を USB ケーブルで PC に接続します。 PROJECT TASKS から Upload をクリックするとファームウェアの書込みが開始されて [SUCCESS] と表示されると完了です。(図25)

*図25 ファームウエアの書き込みが完了した

ファイルシステムイメージビルド

Web サーバーに必要な HTML、Java Script、CSS の各ファイルは data フォルダーに格納されています。これらのファイルをビルドするにはファイルシステムイメージビルドを使用します。
PROJECT TASKS から Build Filesystem Image をクリックするとビルドが開始されて [SUCCESS] と表示されると完了です。(図26)

*図26 Build Filesystem Image が完了した

ファイルシステムイメージ書込み

PROJECT TASKS から Upload Filesystem Image をクリックするとファイルシステムイメージの書込みが開始されて [SUCCESS] と表示されると完了です。(図27)

*図27 ファイルシステムイメージ書込み完了

ファームウエア実行

PROJECT TASKS から Monitor をクリックするとファームウェアの実行が開始されて、ターミナルウインドウにメッセージが表示されます。(図28)

  Connecting to Wi-Fi
  WiFi Connected
  *IP address: 192.168.xx.xx

ここで表示された IP アドレスをメモしておきます。
(なお IP address は Wi-Fi ルータの環境によって変化します。)

*図28 ターミナルウインドウにメッセージ表示

ブラウザアプリを開いて先ほどメモした IP アドレスを入力すると画面が表示されます。(図29)
Current time の表示がリアルタイムで更新されていれば正常に動作しています。

*図29 ブラウザアプリに IP アドレスを入力した

ブラウザからの制御

ブラウザ画面で「change」ボタンをクリックすると LED status が OFF から ON に変化します。(図30)

*図30 change ボタンを押すと LED status が OFF から ON に変化する。

同時にターミナル出力に「 LED cahnged : ON 」のメッセージが出力されます。(図31)

*図31 「 LED changed : ON 」が出力された

ブラウザから制御した時の流れは次のようになります。

  クライアント CHANGE ボタン押下
→ クライアント “/update” リクエスト
→ サーバー   ledstate “ON”
→ サーバー   ”LED changed : ON” のメッセージをターミナル出力
→ サーバー   ledstate “ON” をクライアントに文字列でレスポンス

参考)ブラウザ画面で「電源 ON」ボタンをクリックするとボタンの色がグレーからオレンジに変わります。これは本機で使うための機能を先行して JavaScript で動作確認しました。

次回は フラッシュメモリ読書 について説明します。

リンク

ESP32を使って学習リモコンを作る(1) 学習リモコンでどんなことができるの?
ESP32を使って学習リモコンを作る(2) ハードウエア
ESP32を使って学習リモコンを作る(3) ソフトウエア 赤外線リモコン受信( irReceive )
ESP32を使って学習リモコンを作る(4) ソフトウエア 赤外線リモコン送信( irSend )
ESP32を使って学習リモコンを作る(5) ソフトウエア webserver
ESP32を使って学習リモコンを作る(6) ソフトウエア FLASH 読書き(SPIFFS)
ESP32を使って学習リモコンを作る(7) ソフトウエア 本機のプロジェクト
ESP32を使って学習リモコンを作る(8) ソフトウエア 本機プロジェクトの勘所
ESP32を使って学習リモコンを作る(9) ハードウエア設計の勘所
ESP32を使って学習リモコンを作る(10) 学習リモコンを操作した時のターミナル出力
Smart_Remote_Controller プロジェクト GitHub

(YI)

 

コメント

error: Content is protected !!
タイトルとURLをコピーしました