ESP32のすゝめ

#はじめに
この記事は[Aizu Advent Calendar 2020](https://adventar.org/calendars/5037)23日目の記事です。
時間がギリギリで少し適当な節がありますが、ご了承ください。

##ESP32 とは
>ESP32シリーズは Wi-FiとBluetoothを内蔵する低コスト、低消費電力なSoCのマイクロコントローラ (Wikipediaより)

ということらしいです。
下記に自分が思った利点を簡単にまとめます。

###Wi-Fiが扱える

**Webサーバ**や**アクセスポイント**、**Webクライアント**になる。
GETを送れば、Webからマイコンを操作できます。(今回はこれを説明します。)

###Bluetoothが扱える

**スマホとの通信**や**Bluetoothマウス・キーボード**になる。
特にBluetoothマウス・キーボードを使えば、ゲームコントローラーの自作も可能。

###安い

RaspberryPiなどの他のBluetoothやWi-Fiを扱えるマイコンに比べて安いです。
今回説明していく、Arduino互換のESP32はAmazonで1000円ぐらいです。

##WebからLEDを操作

実際にESP32で、簡単なWebサーバを作って、WebからLEDを操作していこうと思います。

###1.Webページを作る

操作用のWebページを作っていきます。
※CSSとJavaScriptはHTMLファイルの中に直接書いてください。
※ダブルクォーテーションはなるべく使わずにシングルクォーテーションを使ってください。
![ESPWebページ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467463/f6095d0a-fdd0-4ac2-b567-87dd1c5fe497.png)


```html:ctrl.html
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' name='viewport' content='width =device-width, initial-scale=1'>
    <title>ESP32 RGB LED controller</title>
    <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
    <style>
        .btn{
            width:30%;
            font-size:100px;
        }
    </style>
</head>
<body>
    <script>
        $.ajaxSetup({ timeout: 1000 });
        function Send(btn) {
            $.get('/' + btn);
            { Connection: close };
        }
    </script>
    <input type='button' class='btn' id='cold' value='H' onclick='Send("H")'/>
    <input type='button' class='btn' id='stop' value='L' onclick='Send("L")'/>

</body>
</html>
```

JS部分の説明をしていきます

```javascript:16行目
$.ajaxSetup({ timeout: 1000 });
```

Ajax通信のタイムアウトを設定しています。
<br>

```javascript:Send関数
function Send(btn) {
    $.get('/' + btn);
    { Connection: close };
}
```

ESP側に`"/"+btn`のGETを送ります。
つまり、Hのボタンを押すと、`/H`が、Lのボタンを押すと`/L`が送られます。

###2.ESP32に書き込むプログラムを作る

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

const char* ssid     = "ssid";
const char* password = "password";

const String HTML="さっき作ったWebページ(改行なし)";
WiFiServer server(80);
const int LED=23;

void setup()
{
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New Client.");
    String header="";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c=='\r')continue;
        header.concat(String(c));
        if (c == '\n') {
          Serial.print(header);
          if(header.indexOf("GET")>=0){
            if(header.indexOf("/H")>=0){
              digitalWrite(LED,HIGH);
            }else if(header.indexOf("/L")>=0){
              digitalWrite(LED,LOW);
            }else{
              client.println("HTTP/1.1 200 OK");
              client.println("Content-type:text/html");
              client.println("Connection: close");
              client.println();
              client.println(HTML);
            }
            break;
          }
        }
      }
    }
    client.stop();
    Serial.println("Client Disconnected.");
  }
}
```

ほとんど、おまじないなので重要な部分だけ説明していきます。

```c++:3,4行目
const char* ssid     = "ssid";
const char* password = "password";
```
ここには、自分の家のルータのssidとパスワードを入れてください。
因みに、Windowsの人はモバイルホットスポットを使うと楽だと思います。
<br>

```c++:6行目
const String HTML="さっき作ったWebページ(改行なし)";
```
ここには、先ほど作ったWebページを改行を無くして代入してください。
改行をなくすには、[このようなサイト](https://html-css-javascript.com/n-space-tab/)が便利です。
<br>

<details><summary>setup関数はほとんどおまじないなので、軽い説明だけです。</summary><div>

```c++:setup関数
void setup()
{
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password); //WiFiに接続

  while (WiFi.status() != WL_CONNECTED) { //接続できるまでループ
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP()); //IPアドレスの表示
  server.begin(); //Webサーバの開始
}
```

</div></details>
<br>

```c++:loop関数のwhileの中
while (client.connected()) { // Webサーバに接続している間、ループする
  if (client.available()) { //ESP32にデータが送られている場合に実行
    char c = client.read(); //送られてきたデータを一文字読み込む
    if (c == '\r')continue; //\rは無視
    header.concat(String(c)); //headerの末尾にcを追加する
    if (c == '\n') {
      Serial.print(header);
      if (header.indexOf("GET") >= 0) { //GETだったら実行
        if (header.indexOf("/H") >= 0) { // /Hなら、LEDを光らせる
          digitalWrite(LED, HIGH);
        } else if (header.indexOf("/L") >= 0) { // /Lなら、LEDを消す
          digitalWrite(LED, LOW);
        } else { // /等の場合はWebページを送る
          client.println("HTTP/1.1 200 OK");
          client.println("Content-type:text/html");
          client.println("Connection: close");
          client.println();
          client.println(HTML);
        }
        break;
      }
    }
  }
}
```

簡単に説明すると、
1. GETなどのデータが`header`に入り、
2. それがGETの`/H`や`/L`だった場合はLEDを制御して、
3. GETの`/`の場合はWebページ(`HTML`)のデータを送る。

## まとめ
ESP32は**安い&簡単**にBluetooth通信やWebの通信が取り扱えます。
皆さんも、RaspberryPiだけでなくESP32も使っていきましょう!
今度、書けなかったBluetoothに関する記事を書こうと思っています。