ESP32を使った簡単なIoT

[前回](https://qiita.com/northVil/items/f5cfee1cfd38ece59bb5)作ったサーバは文字をページ表示させることと`Wifi`ライブラリの使い方を学ぶことがメインでした。今回はIoTに活用していくために、Webサーバにボタンを配置し、ボタンからESP32を操作することを目的とします。

# ボタン操作でLチカ
　Arduino IDEでESP32環境を作った際にスケッチ例として自動的インストールされる`SimpleWiFiServer`というものもありますが、個人的には[こちら](https://kit.socinno.com/3_3_r/)の方が分かりやすいと思ったのでこちらを参考にさせていただきました。細かいところを変更しオリジナルを加えたものが`LED.ino`になります。
　ESP32のピン配置はこのサイトが見やすかったです。
https://ht-deko.com/arduino/esp-wroom-32.html


```C++:LED.ino
#include <WiFi.h>
#include <WebServer.h>

const char *ssid = "Buffalo-A-aaaa";        // WifiのSSID
const char *pass = "abcdefghijklm";    //  Wifiのパスワード
WebServer Server(80);         //  ポート番号（HTTP）


//  クライアントにウェブページ（HTML）を返す関数
void SendMessage() {
  //  レスポンス文字列の生成（'\n' は改行; '\' は行継続）
  Serial.println("SendMessage");
  String message =   "<html lang=\"ja\">\n\
    <meta charset=\"utf-8\">\n\
    <center>\
    <h2>LED制御</h2>\
    <p><button type='button' onclick='location.href=\"/on\"' \
      style='width:200px;height:40px;'>LED-ON</button></p>\
    <p><button type='button' onclick='location.href=\"/off\"' \
      style='width:200px;height:40px;'>LED-OFF</button></p>\
  </center>";
  //  クライアントにレスポンスを返す
  Server.send(200, "text/html", message);
}

void OnSendMessage() {
  Serial.println("OnSendMessage");
  String message =   "<html lang=\"ja\">\n\
    <meta charset=\"utf-8\">\n\
    <center>\
    <h2>LED制御</h2>\
    <p><button type='button' onclick='location.href=\"/off\"' \
      style='width:200px;height:40px;'>LED-OFF</button></p>\
  </center>";
  //  クライアントにレスポンスを返す
  Server.send(200, "text/html", message);
  //LEDをONにする
  digitalWrite(5, HIGH);
}
void OffSendMessage() {
  Serial.println("OffSendMessage");
  String message =   "<html lang=\"ja\">\n\
    <meta charset=\"utf-8\">\n\
    <center>\
    <h2>LED制御</h2>\
    <p><button type='button' onclick='location.href=\"/on\"' \
      style='width:200px;height:40px;'>LED-ON</button></p>\
  </center>";
  //  クライアントにレスポンスを返す
  Server.send(200, "text/html", message);
  //LEDをOFFにする
  digitalWrite(5, LOW);
}
//  クライアントにエラーメッセージを返す関数
void SendNotFound() {
  Serial.println("SendNotFound");
  Server.send(404, "text/plain", "404 not found...");
}

//  メインプログラム
void setup() {
  pinMode(5, OUTPUT);
  //  シリアルモニタ（動作ログ）
  Serial.begin(115200);               //  ESP 標準の通信速度 115200
  delay(100);                         //  100ms ほど待ってからログ出力可
  Serial.println("\n*** Starting ***");
  //  無線 LAN に接続
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);             
  Serial.println("Connecting...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    if (WiFi.status() == WL_CONNECT_FAILED) {
      Serial.println("Can't connect");
    }
  }
  Serial.println("Connected");
  Serial.println(WiFi.localIP());     //  ESP 自身の IP アドレスをログ出力
  //  ウェブサーバの設定
  Server.on("/", SendMessage);         //  ルートアクセス時の応答関数を設定
  Server.on("/on", OnSendMessage);
  Server.on("/off", OffSendMessage);
  Server.onNotFound(SendNotFound);  //  不正アクセス時の応答関数を設定
  Server.begin();                     //  ウェブサーバ開始
}
void loop() {
  //  クライアントからの要求を処理する
  Server.handleClient();
}

```
## `LED.ino`の実行結果
　Webサーバにアクセスしたときのブラウザ画面とシリアルモニタ
![スクリーンショット (918).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/ebca084b-4b39-8c22-ee85-cf37aa7e148a.png)



　ONボタンを押したときブラウザ画面とシリアルモニタ

![スクリーンショット (919).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/cf6d2618-4cef-e7b4-136c-6e5c82f91a5d.png)



　OFFボタンを押したときブラウザ画面とシリアルモニタ

![スクリーンショット (920).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/a23fe588-ec3a-8c09-5de0-7f4714991dc8.png)

## プログラムの内容
　基本的な中身は[前回](https://qiita.com/northVil/items/f5cfee1cfd38ece59bb5)とほとんど同じです。変更しているのは、クライアントへ返す変数`message`とボタンに対応した`Server.on`関数です。ボタンを押した際の動作は上記実行結果の通りで、ONボタンを押したときにはOFFボタンのみが画面に残り、OFFボタンを押したときはONボタンのみが画面に残るようにHTMLを対応させています。
　LEDはIO5番に接続しています。

### ボタンの動作
　ボタンはクリックさせることでHTMLで指定したURLにクライアントを移動させることができます。今回はONボタンがクリックされると`/on`へ、OFFボタンがクリックされると`/off`へ移動させています。この移動先のURLに合わせた`Server.on`関数を作成するとそのボタンがクリックされた後`Server.on`で指定した動作やレスポンスを返すことができます。

# ボタン操作でセンサの値を確認する
　それでは先ほどのプログラム`LED.ino`を応用して、LEDなどの出力ではなくセンサの入力値をサーバから確認できるようにしてみましょう。
　今回使用するセンサは$ I^{2}C $接続で温度、湿度、気圧を測定できるBME280を使用しました。また、`Adafruit_Sensor`と`BME280`という専用ライブラリが用意されているので簡単に操作できます。

```C++:BME280.ino
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
Adafruit_BME280 bme;

float temp;
float pressure;
float humid;

const char *ssid = "Buffalo-A-aaaa";      //  WifiのSSID
const char *pass = "abcdefghijklm";    //  Wifiのパスワード
WebServer Server(80);         //  ポート番号（HTTP）


//  クライアントにウェブページ（HTML）を返す関数
void SendMessage() {
  //  レスポンス文字列の生成（'\n' は改行; '\' は行継続）
  Serial.println("SendMessage");
  String message =   "<html lang=\"ja\">\n\
    <meta charset=\"utf-8\">\n\
    <center>\
    <h2>BME280の値</h2>\
    <p><button type='button' onclick='location.href=\"/bme\"' \
      style='width:250px;height:40px;'>気温・湿度・気圧を知る</button></p>\
  </center>";
  //  クライアントにレスポンスを返す
  Server.send(200, "text/html", message);
}

void BmeSendMessage() {
  Serial.println("BmeSendMessage");
  temp = bme.readTemperature();
  humid = bme.readHumidity();
  pressure = bme.readPressure();

  Serial.println("気温　" + String(temp));
  Serial.println("湿度　" + String(humid));
  Serial.println("気圧　" + String(pressure / 100));

  String message =   "<html lang=\"ja\">\n\
    <meta charset=\"utf-8\">\n\
    <center>\
    <h2>BME280の値</h2>\
    <h3>温度：　" + String(temp) + "°C, 湿度：　" + String(humid) + "%, 気圧：　" + String(pressure / 100) + "hPa</h3>\
    <p><button type='button' onclick='location.href=\"/bme\"' \
      style='width:250px;height:40px;'>気温・湿度・気圧を知る</button></p>\
  </center>";
  //  クライアントにレスポンスを返す
  Server.send(200, "text/html", message);
}

//  クライアントにエラーメッセージを返す関数
void SendNotFound() {
  Serial.println("SendNotFound");
  Server.send(404, "text/plain", "404 not found...");
}

//  メインプログラム
void setup() {
  pinMode(5, OUTPUT);
  //  シリアルモニタ（動作ログ）
  Serial.begin(115200);               //  ESP 標準の通信速度 115200
  delay(100);                         //  100ms ほど待ってからログ出力可
  Serial.println("\n*** Starting ***");
  //  無線 LAN に接続
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);            
  Serial.println("Connecting...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    if (WiFi.status() == WL_CONNECT_FAILED) {
      Serial.println("Can't connect");
    }
  }
  Serial.println("Connected");
  Serial.println(WiFi.localIP());     //  ESP 自身の IP アドレスをログ出力
  //  ウェブサーバの設定
  Server.on("/", SendMessage);         //  ルートアクセス時の応答関数を設定
  Server.on("/bme", BmeSendMessage);
  Server.onNotFound(SendNotFound);  //  不正アクセス時の応答関数を設定
  Server.begin();                     //  ウェブサーバ開始
  //BME280
  bool status;
  status = bme.begin(0x76);
  while (!status) {
    Serial.println("BME280 sensorが使えません");
    delay(1000);
  }
}
void loop() {
  //  クライアントからの要求を処理する
  Server.handleClient();
}

```

## `BME280.ino`の実行結果
　Webサーバにアクセスしたときのブラウザ画面とシリアルモニタ
![スクリーンショット (923).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/b985c6fe-310a-8b3d-93cb-a7c0e4c57426.png)
![ルートディレクトリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/80549f2d-f5d5-138a-6b1e-024da4aa7131.png)



　ボタンをクリックしたときのブラウザ画面とシリアルモニタ
![スクリーンショット (924).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/4337b066-653e-15cf-d99e-1b86448f7592.png)
![BME.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/361954a0-4da5-b782-d02f-2f117e9ef7b6.png)

## プログラムの内容
　レスポンスするHTMLとボタンを変更しています。BME280を使い方はこのサイトを参考にしました。
https://wak-tech.com/archives/1642
　私の使用した`BME280`はデフォルトで気圧の値が[Pa]単位だったので[hPa]にするために`pressure`変数を100で割っています。

# まとめ
　WebサーバからESP32を制御できるとIoTとして活用ができるようになります。ただ、結局のところ現段階ではただセンサの値を見たりボタンで制御するだけしかできません。今後他のAPIを組み合わせて、LINEなどと同期できれば、より生活に密着したIoT機器を自作することができると思うので機会があればやってみようと思います。
　最後までご覧いただきありがとうございました。間違い等あるかもしれませんが温かい目で見守っていただけると幸いです。

# 参考文献
https://qiita.com/northVil/items/f5cfee1cfd38ece59bb5
https://ht-deko.com/arduino/esp-wroom-32.html
https://kit.socinno.com/3_3_r/
https://wak-tech.com/archives/1642