5.11 Web制御スマートファーム
5.11.1 ESP32ボードをネットワークに接続する
ESP32ボードはWi-Fi(2.4G)とBluetooth(4.2)を搭載しており、Wi-Fiに簡単に接続したり、ネットワーク上の他のデバイスと通信したりできます。
準備するもの:
2.4 GHz Wi-Fi(モバイルホットスポットまたはルーターでも可)
Wi-Fi名とパスワード
同じWi-Fiに接続できる電話/IPAD/コンピューター
Arduino IDEには、Wi-Fi設定とESP32 Wi-Fiネットワーク監視をサポートするライブラリファイル <WiFi.h> が用意されています。
A. 基地局モード(STAまたはWi-Fiクライアント側モード):このモードでは、ESP32はWi-Fiホットスポット(AP)に接続します。
B. APモード(Soft-APまたはWi-Fiホットスポットモード):このモードでは、他のWi-FiデバイスがESP32に接続します。
C. AP-STAモード:このモードでは、ESP32はWi-Fiホットスポットであると同時に、別のWi-Fiホットスポットに接続するWi-Fiデバイスでもあります。
D. これらのモードは、WPA、WPA2、WEPなどの複数の安全モードと互換性があります。
E. アクティブスキャンとパッシブスキャンを含むWi-Fiホットスポットのスキャンが可能です。
F. IEEE802.11 Wi-Fiパケットを監視するためのプロミスキャスモードをサポートしています。
Wi-Fiの詳細については、以下を参照してください。
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html
ESPRESSIF公式サイト:https://www.espressif.com.cn/en/home
Arduino IDEで5.11.0Connect-the-ESP32-to-the-Networkコードを開きます。
#include <WiFi.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
void setup() {
Serial.begin(9600);
//Initialize Wifi
WiFi.begin(ssid, password);
//Scan for wifi. If connection fails, stay in connecting, and execute "while" loop
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
//Connected. Print the IP address
Serial.println("Connected to WiFi");
Serial.println(WiFi.localIP());
}
void loop() {
}
コード内のyour_SSIDをWi-Fiの名前に、your_PASSWORDをWi-Fiのパスワードに変更します。
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
ESP32 Dev ModuleボードとCOMポートを選択し、コードをアップロードします。

テスト結果:
コードをアップロードすると、ボードはWi-Fiネットワークに接続し、シリアルモニターにIPアドレスを表示します。

5.11.2 ウェブサイトのセットアップ - HELLOWORLD
Wi-Fiに接続している限り、ESP32のWebサーバーライブラリはウェブページを提供できます。以下のサンプルコードでは、「Hello, World!」を表示する簡単なウェブサイトをセットアップします。
Arduino IDEで5.11.1WiFi-HTML-HELLOWORLDコードを開きます。
#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
WebServer server(80); //Set the server port to 80. Enter the website by IP address rather than the port number.
//Initialize the website
void handleRoot() {
//Used to send HTTP to the client-side for response, sending 200 means success.
server.send(200, "text/html", "<h1>Hello, World!</h1>");
}
void setup() {
Serial.begin(9600);
//Initialize wifi
WiFi.begin(ssid, password);
//Scan for wifi. If connection fails, stay in connecting, and execute "while" loop
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
//Connected. Print the IP address
Serial.println("Connected to WiFi");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
//Start server
server.begin();
Serial.println("Web server started");
}
void loop() {
server.handleClient();
}
コード内のyour_SSIDをWi-Fiの名前に、your_PASSWORDをWi-Fiのパスワードに変更します。その後、コードをアップロードします。
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
ESP32 Dev ModuleボードとCOMポートを選択し、コードをアップロードします。

テスト結果:
このサンプルコードでは、ESP32のWebServerライブラリを使用してWebサーバーを構築します。handleRoot()関数はルートパスでの処理を要求し、クライアント側に「Hello, World!」のHTML応答を送信します。次に、setup()はルートを設定し、server.begin()はWebサーバーを開始します。
シリアルモニターをクリックしてIPアドレスを表示します。

注:PC、携帯電話、ESP32ボードが同じネットワークに接続されている場合、PCと携帯電話で同時にこのウェブサイトにアクセスできます。
PCブラウザまたは電話ブラウザでIPにアクセスします。

注:2.4 GHz Wi-Fiが必要です。5Gではありません。IPアドレスにアクセスするPCまたは携帯電話は、ESP32ボードと同じWi-Fiに接続されている必要があります。

5.11.3 Web制御スマートファーム

Arduino IDEで5.11.2WiFi-HTML-Smart-Farmコードを開きます。
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <LiquidCrystal_I2C.h>
#include <dht11.h>
#include <ESP32Servo.h>
// Pin Definitions
#define DHT11PIN 17 // 温度および湿度センサーピン
#define LEDPIN 27 // LEDピン
#define SERVOPIN 26 // サーボピン
#define FANPIN1 19 // ファン IN+ ピン
#define FANPIN2 18 // ファン IN- ピン
#define STEAMPIN 35 // 蒸気センサーピン
#define LIGHTPIN 34 // フォトレジスターピン
#define SOILHUMIDITYPIN 32 // 土壌湿度センサーピン
#define WATERLEVELPIN 33 // 水位センサーピン
#define RELAYPIN 25 // リレーピン
// センサーとコンポーネントの初期化
dht11 DHT11;
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo myservo; // サーボを制御するためのサーボオブジェクト
// WiFi認証情報
const char *SSID = "your_SSID";
const char *PASS = "your_PASSWORD";
// WebServerオブジェクトの作成
WebServer server(80);
// 状態を制御するための変数
static int A = 0;
static int B = 0;
static int C = 0;
// HTML Webページコンテンツ
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<title>TEST HTML ESP32</title>
<head>
<meta charset="utf-8">
<style>
html, body {
margin: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: #f0f0f0;
}
/* The main button container */
.btn {
display: flex;
justify-content: center; /* Center the buttons */
gap: 10px; /* Add space between buttons */
width: 320px; /* Set width to ensure buttons are tightly packed */
flex-wrap: wrap; /* Allow buttons to wrap to new lines if needed */
margin-bottom: 20px; /* Space between buttons and data display */
}
/* Button style */
.btn button {
width: 70px; /* Set width for buttons */
height: 70px; /* Set height for buttons */
border: none;
font-size: 16px;
color: #fff;
background-color: #89e689;
cursor: pointer;
}
.btn button:active {
top: 2px;
}
/* The data display area */
#dht {
text-align: center; /* Center the text */
width: 320px; /* Same width as the button container */
color: #fff;
background-color: #47a047;
font-size: 18px; /* Adjust font size for readability */
padding: 10px;
border-radius: 10px; /* Rounded corners */
box-sizing: border-box;
margin-bottom: 10px; /* Add space between the data display and buttons */
}
</style>
</head>
<body>
<!-- Display area for sensor data -->
<div id="dht"></div>
<!-- Button row -->
<div class="btn">
<button id="btn-led" onclick="setLED()">LED</button>
<button id="btn-fan" onclick="setFan()">Fan</button>
<button id="btn-feeding" onclick="setFeeding()">Feeding</button>
<button id="btn-watering" onclick="setWatering()">Watering</button>
</div>
<script>
function setLED() {
var payload = "A";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/set?value=" + payload, true);
xhr.send();
}
function setFan() {
var payload = "B";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/set?value=" + payload, true);
xhr.send();
}
function setFeeding() {
var payload = "C";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/set?value=" + payload, true);
xhr.send();
}
function setWatering() {
var payload = "D";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/set?value=" + payload, true);
xhr.send();
}
setInterval(function () {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("dht").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/dht", true);
xhttp.send();
}, 1000)
</script>
</body>
</html>
)rawliteral";
// センサーデータをHTML形式にマージする関数
String Merge_Data(void) {
String dataBuffer;
String Humidity;
String Temperature;
String Steam;
String Light;
String SoilHumidity;
String WaterLevel;
// DHT11センサーの読み取り
int chk = DHT11.read(DHT11PIN);
// 他のセンサーの読み取り
Steam = String(analogRead(STEAMPIN) / 4095.0 * 100);
Light = String(analogRead(LIGHTPIN));
int shvalue = analogRead(SOILHUMIDITYPIN) / 4095.0 * 100 * 2.3;
shvalue = shvalue > 100 ? 100 : shvalue;
SoilHumidity = String(shvalue);
int wlvalue = analogRead(WATERLEVELPIN) / 4095.0 * 100 * 2.5;
wlvalue = wlvalue > 100 ? 100 : wlvalue;
WaterLevel = String(wlvalue);
Temperature = String(DHT11.temperature);
Humidity = String(DHT11.humidity);
// HTMLコンテンツの構築
dataBuffer += "<p>";
dataBuffer += "<h1>Sensor Data</h1>";
dataBuffer += "<b>Temperature:</b><b>" + Temperature + "</b><b>℃</b><br/>";
dataBuffer += "<b>Humidity:</b><b>" + Humidity + "</b><b>%rh</b><br/>";
dataBuffer += "<b>WaterLevel:</b><b>" + WaterLevel + "</b><b>%</b><br/>";
dataBuffer += "<b>Steam:</b><b>" + Steam + "</b><b>%</b><br/>";
dataBuffer += "<b>Light:</b><b>" + Light + "</b><br/>";
dataBuffer += "<b>SoilHumidity:</b><b>" + SoilHumidity + "</b><b>%</b><br/>";
dataBuffer += "</p>";
return dataBuffer;
}
// 受信したHTTPリクエストに基づいてアクションを設定
void Config_Callback() {
if (server.hasArg("value")) {
String HTTP_Payload = server.arg("value");
Serial.printf("[%lu]%s\r\n", millis(), HTTP_Payload.c_str());
if (HTTP_Payload == "A") {
if (A) {
digitalWrite(LEDPIN, LOW);
A = 0;
} else {
digitalWrite(LEDPIN, HIGH);
A = 1;
}
}
if (HTTP_Payload == "B") {
if (B) {
digitalWrite(FANPIN1, LOW);
digitalWrite(FANPIN2, LOW);
B = 0;
} else {
delay(500);
digitalWrite(FANPIN1, HIGH);
digitalWrite(FANPIN2, LOW);
delay(500);
B = 1;
}
}
if (HTTP_Payload == "C") {
if (C) {
myservo.write(80);
delay(500);
C = 0;
} else {
C = 1;
myservo.write(180);
delay(500);
}
}
if (HTTP_Payload == "D") {
digitalWrite(RELAYPIN, HIGH);
delay(400);
digitalWrite(RELAYPIN, LOW);
delay(650);
}
}
server.send(200, "text/plain", "OK");
}
// 無効なURLアクセスを処理
void notFound() {
server.send(404, "text/plain", "Not found");
}
void setup() {
Serial.begin(9600);
// WiFiに接続
WiFi.begin(SSID, PASS);
while (!WiFi.isConnected()) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// ピンを設定
pinMode(LEDPIN, OUTPUT);
pinMode(STEAMPIN, INPUT);
pinMode(LIGHTPIN, INPUT);
pinMode(SOILHUMIDITYPIN, INPUT);
pinMode(WATERLEVELPIN, INPUT);
pinMode(RELAYPIN, OUTPUT);
pinMode(FANPIN1, OUTPUT);
pinMode(FANPIN2, OUTPUT);
delay(1000);
// サーボをピンに接続
myservo.attach(SERVOPIN);
myservo.write(180);
// LCDを初期化
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("IP:");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
// サーバールートを設定
server.on("/", HTTP_GET, []() {
server.send(200, "text/html", index_html);
});
server.on("/dht", HTTP_GET, []() {
server.send(200, "text/plain", Merge_Data().c_str());
});
server.on("/set", HTTP_GET, Config_Callback);
server.onNotFound(notFound);
// サーバーを開始
server.begin();
}
void loop() {
server.handleClient();
}
コード内の your_SSID をWi-Fiの名前に、your_PASSWORD をWi-Fiのパスワードに変更してください。その後、コードをアップロードします。
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";
ESP32 Dev Module ボードと COM ポートを選択し、コードをアップロードします。

テスト結果:
注: PC、携帯電話、ESP32ボードが同じネットワークに接続されている場合、PCと携帯電話で同時にこのウェブサイトにアクセスできます。
LCD1602からIPアドレスを表示:

携帯電話またはPCのブラウザにIPアドレスを入力すると、ページ上部にセンサー値が表示され、下のボタンでLED、ファン、給餌室、ウォーターポンプを制御できます。

注: 2.4 GHz Wi-Fiが必要です。5Gは不可。IPアドレスにアクセスするPCまたは携帯電話は、ESP32ボードと同じWi-Fiに接続されている必要があります。
