WIFI環境でESP32を使ったサーバーを立ててみよう！

 今後のために、偶然家に眠っていたESP32を使って、LAN環境で簡単なレスポンスを行うサーバーを作ってみようと思います。ESP32への書き込みはArduino IDEを使用します。
# Arduino IDEでのESP32用セットアップ
①まずArduino IDEを開き、「ファイル」の「環境設定」を選択します。
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/c2c8679b-1d1b-a487-2343-6c5c364e0cda.png)


②環境設定の画面下部にある追加のボードマネージャのURLに以下のURLを入力し、「OK」を押します。
https://dl.espressif.com/dl/package_esp32_index.json
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/2480fdf4-c62f-d878-4eb2-2cde870e8c2b.png)



③メイン画面に戻り、「ツール」の「ボード」タグから「ボードマネージャ」を選択します。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/e2f4b438-b7fb-85cd-5adc-045b01f4212a.png)


④検索画面で「esp32」と検索し、一番上に出てきたものをインストール。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/4f6b3745-506d-0e19-cc47-5e0168f01174.png)


⑤メイン画面に戻り、「ツール」の「ボード」タグ「ESP32 Arduino」から「ESP32 Dev Module」が選択できるようになっていれば完了です。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/d102b15e-ac3b-96c1-0c97-9bcfd0693560.png)


# ESP32のサーバー用ライブラリのインストール
　この[GitHub](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer/src)にアクセスして、zipファイルをダウンロードしてください。
　Arduino IDEの画面から「スケッチ」の「ライブラリをインクルード」タグから「.ZIP形式のライブラリをインストール」を選択し、先ほどダウンロードしたZIPファイルを選択するだけです。

![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/312858b9-1979-c4d9-e52f-d3a8adc045ce.png)

![画像7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/3627291f-7eac-a420-a06f-77f0ea4ce165.png)



# ESP32①何もしないサーバ
```C++:test.ino
#include <WiFi.h>
#include <WebServer.h>

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

//  メインプログラム
void setup() {
  //  シリアルモニタ（動作ログ）
  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.begin();                     //  ウェブサーバ開始
}
void loop() {
  Server.handleClient();
}


```
　ssidとpassには自分の環境のものを入力してください。ただし、ESP32は5GHzに対応していないことに注意してください。そのため、WifiのSSIDを入力する際には2.4GHzのアクセスポイントを使用しないとエラーが出ます。

## ①のコードの内容と結果
　①を実行し、シリアルモニタを見ると以下のようなログが出力されていると思います。
![画像8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/8ada15d8-3876-3877-6281-0113f8924869.png)
　最後の行で出力されているIPアドレスに、chromeで接続するとこのような結果になっていることが確認できます。　
![画像9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/081cd6ee-ca58-3ece-6ec1-a0416355b3e0.png)
　返すものがないため`Not found`となっていますが、このようになっていればサーバが正しく稼働している状態です。
### WiFi.mode(WIFI_STA)
　この関数はWifiの動作モードを設定する関数です。設定結果が成功の場合`true`、失敗の場合`false`を返します。`WIFI_STA`とはWifiをステーションモードで使用するということです。ステーションモードで使用すると、ESP32が設定したWifiの子機として使用されるため、クライアント側は同じWifi環境であればアクセスポイントを変更せずにそのまま接続できます。

### WiFi.begin(ssid, pass)
　Wifiのアクセスポイントの接続する関数です。この`ssid`と`pass`には`char型`のポインタで定義したWifiの設定がそのまま引数として入っています。

### while (WiFi.status() != WL_CONNECTED)
　`WiFi.status()`が現在のWifiの接続状態を`enum型`で返します。`WL_CONNECTED`は`WiFi.status()`がWifiに接続完了したときに返す値です。つまり、この`while`はWifiに接続されるまで繰り返すということです。

### if (WiFi.status() == WL_CONNECT_FAILED)
　先ほどの`while`の中にあるこの`if`は、Wifi接続失敗を意味する`WL_CONNECT_FAILED`が`WiFi.status()`から返されたときに行う処理です。

### Server.begin()
　上記までの内容で、Wifiには接続されている状態であるため、`Server.begin()`を使ってServerを開始します。

### WiFi.localIP()
　現在割り当てられているIPアドレスを返します。

### Server.handleClient()
　`Server.handleClient()`は登録した情報に従ってクライアントからのリクエストを処理する関数です。`loop`内で呼び出します。

# ESP32②テキストを返すサーバ
```C++:TextReturn.ino
#include <WiFi.h>
#include <WebServer.h>

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


//  メインプログラム
void setup() {
  //  シリアルモニタ（動作ログ）
  Serial.begin(115200);               //  ESP 標準の通信速度 115200
  delay(100);                    
  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.onNotFound(SendeNotFound);
  Server.begin();                     //  ウェブサーバ開始
}

void SendMessage() {
  Serial.println("SendMessage");
  String message = "Thank you for visiting my server";
  Server.send(200, "text/plain", message); // 値をクライアントに返す
}

void SendeNotFound() {
  Serial.println("SendNotFound");
  Server.send(404, "text/plain", "404 not found");
}

void loop() {
  Server.handleClient();
}

```
## ②のコードの内容と結果
　①と同じく出力されたIPアドレスに接続するとこのようになります。
![画像11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/963ea2f6-9462-ab8a-141f-5fbd6c7fd3c5.png)
　①と違ったテキストが表示されていると思います。また、同じIPアドレスの適当なパスに接続してみるとこのようになります。
![画像12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/6b436495-a93a-cb5e-4768-b2bd80ddf286.png)
　①の結果と似ていますが、少し違うことが分かります。
### Server.on("/", SendMessage)
　`Server.on`関数は第一引数のパスにクライアントからアクセスがあった際、第二引数の関数を呼び出すというものです。ここでは、パスは設定せずIPアドレスにアクセスされると`SendMessage`関数を実行するという内容になっています。

### Server.onNotFound(SendeNotFound)
　`Server.onNotFound`関数は`Server.on`関数で設定されていないパスにアクセスがあった際に呼び出される関数です。呼び出された際には引数に指定した関数が実行されます。
### Server.send(200, "text/plain", message)
　`Server.send`関数はクライアントにレスポンスを送信する関数です。第一引数に`HTTPステータスコード`、第二引数に`コンテンツタイプ`、第三引数に`コンテンツ`をとります。この関数は`SendMessage`の内部で呼び出されている関数であるため、成功レスポンスである200を返しています。クライアントに送信する変数の`message`はテキストであるためコンテンツタイプは`text/plain`となります。
　コンテンツタイプの種類はたくさんあります。
https://qiita.com/AkihiroTakamura/items/b93fbe511465f52bffaa

### Server.send(404, "text/plain", "404 not found")
　上記と同じ関数、`Server.onNotFound`のときに呼び出される関数のでのレスポンスなので、クライアントエラーレスポンスの404を返します。コンテンツタイプ、コンテンツについては同じです。

# ESP32③HTMLを返す動的なサーバ
```C++:HtmlReturn.ino
#include <WiFi.h>
#include <WebServer.h>

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

void SendMessage() {
  //  レスポンス文字列の生成（'\n' は改行; '\' は行継続）
  Counter++;
  Serial.println("SendMessage");
  String message = "\
<html lang=\"ja\">\n\
<meta charset=\"utf-8\">\n\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\
<head>\n\
  <title>HTML</title>\n\
</head>\n\
<body style=\"font-family: sans-serif; background-color: #008080;\" >\n\
  <h1>North Vilによるウェブサーバー</h1>\n\
  <h3>あなたはこのサーバの "
                   + String(Counter)
                   + "人目のお客さまです！</h3>\n\
</body>\n\
</html>\n";

  String celebrate = "\
<html lang=\"ja\">\n\
<meta charset=\"utf-8\">\n\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\
<head>\n\
  <title>HTML</title>\n\
</head>\n\
<body style=\"font-family: sans-serif; background-color: #008080;\" >\n\
  <h1>North Vilによるウェブサーバー</h1>\n\
  <h2>あなたはこのサーバの記念すべき "
                     + String(Counter)
                     + "人目のお客さまです!!!!!</h2>\n\
</body>\n\
</html>\n";

  //  クライアントにレスポンスを返す
  if (Counter % 10 != 0) {
    Server.send(200, "text/html", message);
  } else {
    Server.send(200, "text/html", celebrate);
  }
}


void SendNotFound() {
  Serial.println("SendNotFound");
  Server.send(404, "text/plain", "404 not found...");
}

//  メインプログラム
void setup() {
  //  シリアルモニタ（動作ログ）
  Serial.begin(115200);               //  ESP 標準の通信速度 115200
  delay(100);                         
  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.onNotFound(SendNotFound);  //  不正アクセス時の応答
  Server.begin();                     //  ウェブサーバ開始
}
void loop() {
  Server.handleClient();
}

```
## ③のコードの内容と結果
　HTMLを返すことで、やっと少しだけウェブサイトっぽい見た目になりました。Counter変数でクライアントがリクエストするたびに人数が増えていくように設定しており、`Server.send`に`if`を追加して、10人単位でのみHTMLが専用のものに切り替わります。また、②のようなテキストのみでは日本語を表示させることはできませんが、HTMLを使用することで日本語も使用できます。


![画像14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/308d2ed6-7708-ec2b-b48a-56ffe632a5c4.png)


![画像15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2430628/9d2b0589-ba40-9873-95fc-e5c49b8ab52d.png)

### Server.send(200, "text/html", message)
　②のコードとは違い、レスポンスがHTMLなのでコンテンツタイプを`text/html`と変更しています。

# 終わり
　ESP32は買ったはいいものの、当初の自分には難しく持て余していたので多少なりとも使ってあげられてよかったと思います。
　初めてのQiita投稿なので至らぬ点等あったと思いますが、最後まで見ていただきありがとうございました。

https://qiita.com/northVil/items/fbdb2c3a52ebc32eaf7f

# 参考URL
WebServerライブラリリファレンス
https://garretlab.web.fc2.com/arduino/esp32/reference/libraries/WebServer/
ESP32ライブラリリファレンス
https://garretlab.web.fc2.com/arduino/esp32/reference/libraries/WiFi/
Content-Typeの一覧
https://qiita.com/AkihiroTakamura/items/b93fbe511465f52bffaa
M5StackでWifiをAPとSTAとで使い分ける
https://qiita.com/nnn112358/items/fbb4f24505c6ef8082cd
HTTP レスポンスステータスコード
https://developer.mozilla.org/ja/docs/Web/HTTP/Status
ESP32をWebサーバーにして応答させてみる
https://labo.mycabin.net/electronics/arduino-esp32/466/
ESP-WROOM-32をHTTPで制御する
https://ideal-reality.com/computer/arduino/esp32-http-server/
こじ研　トンペイーノを WiFi につないでみる
https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial0wifi.html