最近、「ESP32 & Arduino 電子工作プログラミング入門」という本を購入したため、復習の意味を兼ねて、ESP32をWebサーバにして、Groveセンサーを制御するプログラムを作ってみます。
本の中では、「第5章 各種のライブラリを使う」のところに「ESP32をWebサーバとして動作させる」という章があり、ここを参考にしながら進めていきます。
ここではスピーカーと接続して音を鳴らすサンプルになっていますが、今回はGroveセンサーのLEDをON/OFFしたいと思います。
環境
今回は、ESP32-DevKitCを使用します。
開発環境はArduino IDEを使用します。
ハードウェア
まず、LEDのピンは以下のようになっています。
こちらを参考にして、それぞれを、ESP32-DevKitCのピンに割り当てます。
Seeeduino | Grove-Red Led | ESP32-DevKitC |
---|---|---|
5V | Red | 5V |
GND | Black | GND |
Not Conencted | White | Not Connect |
D2 | Yellow | IO4(No.26) |
これらをブレッドボード経由で接続します。
ケーブルの色を合わせると、接続するところを間違えずに済みます。
(ESP32-DevKitCの文字が小さいのが辛いですが ^^;)
ソフトウェア
プログラムは以下のようになります。
宣言
まず、ヘッダファイルを呼び出します。
Webサーバとして作成するときには「WebServer」クラスを使用します。
#include <WiFi.h>
#include <WebServer.h>
WebServerクラスのインスタンスを、外部変数として作成します。
ポート番号は80を指定します。
WebServer server(80)
今回はWiFiでネットに接続するため、アクセスポイントのSSIDとパスワードを指定します。
(下では仮の文字列にしてあります)
const char* ssid = "wifi_ssid";
const char* pass = "wifi_pass";
初期化
初期化関数「setup()」内で、以下の処理を行います。
- シリアルポートの初期化
- WiFiのアクセスポイントに接続
- Groveセンサーの初期化
- Webサーバの起動
まず、シリアルポートとの速度を指定して開始します。
// シリアルポートの初期化
Serial.begin(115200);
続いて、WiFiのアクセスポイントの接続します。
// WiFiのアクセスポイントに接続
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// ESP32のIPアドレスを出力
Serial.println("WiFi Connected.");
Serial.print("IP = ");
Serial.println(WiFi.localIP());
動作させるとき、WebサーバのIPアドレスがわからないとアクセスできませんので、シリアルポートに出力します。
次に、今回使用するLEDの初期化を行います。
pinMode(4, OUTPUT);
今回は、IO4から出力しますので、そのように設定しています。
最後にWebサーバを起動します。
起動する際、アドレスごとにコールバック関数を定義しておきます。
// 処理するアドレスを定義
server.on("/", handleRoot);
server.on("/led", handleLED);
server.onNotFound(handleNotFound);
// Webサーバーを起動
server.begin();
それぞれ、「/」「/led」「それ以外」にアクセスされたときの処理を行う関数を定義します。
処理ループ
処理ループ関数「loop()」内では、「WebServer.handleClient()」を呼び出すだけになっており、実際の処理は、初期化時に指定したコールバック関数内で記述します。
void loop()
{
server.handleClient();
}
コールバック関数
初期化時に指定した、以下の関数に処理を記述します。
- 初期画面
- LEDをON/OFFする
- 存在しないアドレスが指定された時
まず、初期画面を作成します。
void handleRoot(void)
{
String html;
// HTMLを組み立てる
html = "<!DOCTYPE html>";
html += "<html>";
html += "<head>";
html += "<meta charset=\"utf-8\">";
html += "<title>LEDをON/OFFする</title>";
html += "</head>";
html += "<body>";
html += "<p>リンクをクリックするとLEDがON/OFFします</p>";
html += "<ul>";
html += "<li><a href=\"/led?s=on\">ON</a></li>";
html += "<li><a href=\"/led?s=off\">OFF</a></li>";
html += "</ul>";
html += "</body>";
html += "</html>";
// HTMLを出力する
server.send(200, "text/html", html);
}
この画面では、LEDをON/OFFするためのURLへのリンクをHTMLで記述しています。
この程度の内容なので短いですが、もっと長くなるようであれば、もうちょっと記述方法を工夫したほうがよいかもしれません。
次に、LEDをON/OFFするコールバック関数を作成します。
void handleLED(void)
{
String msg;
// 「/led?s=○」のパラメータが指定されているかどうかを確認
if (server.hasArg("s"))
{
// 「○」の値に応じて、LEDをON/OFFする
if (server.arg("s").equals("on"))
{
digitalWrite(4, HIGH);
msg = "LEDをONにしました";
}
else if (server.arg("s").equals("off"))
{
digitalWrite(4, LOW);
msg = "LEDをOFFにしました";
}
else
{
msg = "パラメータが正しく指定されていません";
}
}
// 変数msgの文字列を送信する
server.send(200, "text/plain; charset=utf-8", msg);
}
「/led」が呼ばれた際のパラメータで、LEDをON/OFFするようにしています。
まずパラメータ名が「s」であるかを確認し、その値が「on」「off」であるかを確認しています。
それぞれ、IO4に対してHIGH/LOWの値を指定して、LEDのON/OFFを実現し、画面にもその結果を表示するようにしています。
(HTMLで書くほどではないので、ただのテキストで出力しています)
最後に、存在しないアドレスが指定された時の処理を作成します。
void handleNotFound(void)
{
server.send(404, "text/plain", "Not Found.");
}
ただ「Not Found」と出力しているだけです。
実行
実行してみると、シリアルモニタにWebサーバのIPアドレスが表示されます。
そのIPアドレスに、Webブラウザでアクセスすると、以下のような画面が表示されます。
まとめ
ゴリゴリHTMLを書くのが面倒ですが、コールバックの仕組みを使えば、簡単にセンサーの制御ができます。
またGroveセンサーも問題なくつなぐことができます。
ソースコード
#include <WiFi.h>
#include <WebServer.h>
WebServer server(80);
// WiFi情報
const char* ssid = "wifi_ssid";
const char* pass = "wifi_pass";
// 初期画面
void handleRoot(void)
{
String html;
// HTMLを組み立てる
html = "<!DOCTYPE html>";
html += "<html>";
html += "<head>";
html += "<meta charset=\"utf-8\">";
html += "<title>LEDをON/OFFする</title>";
html += "</head>";
html += "<body>";
html += "<p>リンクをクリックするとLEDがON/OFFします</p>";
html += "<ul>";
html += "<li><a href=\"/led?s=on\">ON</a></li>";
html += "<li><a href=\"/led?s=off\">OFF</a></li>";
html += "</ul>";
html += "</body>";
html += "</html>";
// HTMLを出力する
server.send(200, "text/html", html);
}
// LEDのON/OFF
void handleLED(void)
{
String msg;
// 「/led?s=○」のパラメータが指定されているかどうかを確認
if (server.hasArg("s"))
{
// 「○」の値に応じて、LEDをON/OFFする
if (server.arg("s").equals("on"))
{
digitalWrite(4, HIGH);
msg = "LEDをONにしました";
}
else if (server.arg("s").equals("off"))
{
digitalWrite(4, LOW);
msg = "LEDをOFFにしました";
}
else
{
msg = "パラメータが正しく指定されていません";
}
}
// 変数msgの文字列を送信する
server.send(200, "text/plain; charset=utf-8", msg);
}
// 存在しないアドレスが指定された時の処理
void handleNotFound(void)
{
server.send(404, "text/plain", "Not Found.");
}
// 初期化
void setup()
{
// シリアルポートの初期化
Serial.begin(115200);
// WiFiのアクセスポイントに接続
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// ESP32のIPアドレスを出力
Serial.println("WiFi Connected.");
Serial.print("IP = ");
Serial.println(WiFi.localIP());
// Groveセンサーの初期化
pinMode(4, OUTPUT);
// 処理するアドレスを定義
server.on("/", handleRoot);
server.on("/led", handleLED);
server.onNotFound(handleNotFound);
// Webサーバーを起動
server.begin();
}
// 処理ループ
void loop()
{
server.handleClient();
}