ESP32でドアの鍵の監視をしてみた

# ESP32を使ってサムターンを監視
ESP32と赤外線センサーを使ってサムターンの状態を監視して、鍵の状態を外部に送信するプログラムを作って見ました。

# 使った部品
[OSOYOO Arduino用 Raspberry Pi 5 対応 IR赤外線障害物回避 センサモジュール](https://www.amazon.co.jp/gp/product/B07CG5L5NQ/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)
とESP32を使いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693363/6611226b-9063-ca55-73ff-e2e6f131b585.png)
こんな感じで赤外線センサーをサムターンに向けておいて、鍵が閉まるとセンサーに反応が来るので「施錠されている」反応がなければ「解錠されている」と判断してDiscordに通知をするプログラム書いてみました。

# 実装
今回大学の部室のドアが空いているのか閉まっているのか知りたかったため、大学のWiFiに直接つなぐ必要があり苦労しました。EAP認証で接続する必要があるため[ESP32でWPA2-enterpriseに接続する（EPA-PEAP）](https://qiita.com/itinoe/items/fb59699661af1d7c3405)を参考にしたのですが、エラーが出てしまいうまく接続できませんでした。調べて見ると、どうやらこのコードに問題があったようで修正されたコードが[github](https://github.com/esphome/esphome/pull/2815/files)に上がっていたのでこちらも参考にしました。
```
#include <WiFi.h>     //Wifi library
#include <esp_wpa2.h> //wpa2 library for connections to Enterprise networks
#include <WiFiClient.h>
#include <HTTPClient.h>

#include "env.h" // wifiパスワードなどの環境変数を読み込む。
/* src/env.h
#include <string>

std::string userName = "<ユーザー名>";
std::string password = "<パスワード>";
std::string discordUrl = "<WebhookのURL>";
*/

#define EAP_IDENTITY "anonymous" // if connecting from another corporation, use
#define EAP_USERNAME userName.c_str()
#define EAP_PASSWORD password.c_str() // your Eduroam password
const char *ssid = "<SSID>";   // (Eduroam) SSID
const char *host = "<ホストドメイン>";       // external server domain for HTTP connection after authentification Example"arduino.php5.sk"

const unsigned key_state = 33; // センサーのピン番号
char state_text;               // 状態のテキスト
bool current_state = NULL;     // 現在の状態
bool last_state = NULL;        // 最後の状態

void wifiConnect()
{
  //
  Serial.println();
  Serial.print("Connecting to network: ");
  Serial.println(ssid);
  // WiFi.disconnectはtrueを入れないと切ってくれない
  WiFi.disconnect(true); // disconnect form wifi to set new wifi connection
  // WiFi.modeは必須
  WiFi.mode(WIFI_STA); // init wifi mode
  esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY));
  // provide identity
  esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_USERNAME, strlen(EAP_USERNAME));
  // provide username --> identity and username is same
  esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD));
  // provide password
  esp_wifi_sta_wpa2_ent_enable();
  WiFi.begin(ssid); // connect to wifi
  delay(1000);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    ESP.restart(); // エラーが発生した場合は再起動
  }
  Serial.println(WiFi.localIP()); // IPアドレスを表示
  digitalWrite(2, HIGH);          // LEDを点灯
  return;
}

// セットアップ
void setup()
{
  Serial.begin(115200);                // シリアル通信を初期化
  pinMode(key_state, INPUT);           // センサーからの入力を設定
  last_state = digitalRead(key_state); // 現在の状態で初期化
  pinMode(2, OUTPUT);                  // LEDを設定
  wifiConnect();                       // WiFi接続
}

void loop()
{
  if (WiFi.status() != WL_CONNECTED)
  {                       // WiFi接続が切れた場合
    digitalWrite(2, LOW); // LEDを消灯
    wifiConnect();        // WiFi接続
  }

  current_state = digitalRead(key_state); // 現在の状態を取得
  HTTPClient http;                        // HTTPクライアントを初期化
  // 状態が変化した場合
  if (current_state != last_state)
  {
    last_state = current_state;                              // 最後の状態を更新
    String state_text = current_state ? "Opened" : "Closed"; // 状態のテキストを設定
    Serial.println("State: " + state_text);                  // 状態を表示

    if (WiFi.status() == WL_CONNECTED)
    {                                                                      // WiFi接続を確認
      http.begin(discordUrl.c_str());                                      // HTTP接続を初期化
      http.addHeader("Content-Type", "application/x-www-form-urlencoded"); // ヘッダーを追加
      String payload = "content=" + state_text;                            // ペイロードを設定
      int httpResponseCode = http.POST(payload);                           // POSTリクエストを送信
      Serial.println("HTTP Response code: " + String(httpResponseCode));   // HTTPレスポンスコードを表示
      // レスポンスコードが204の場合は成功
      if (httpResponseCode == 204)
      {
        Serial.println("Success");
      }
      else
      { // 失敗した場合は再送信
        while (!http.connected())
        {
          http.POST(payload);
          delay(3000);
        }
      }
    }
  }
  http.end();   // HTTP接続を閉じる
  delay(10000); // 10秒待機
}
```

## 参考文献
> https://github.com/esphome/esphome/pull/2815/files
> https://qiita.com/itinoe/items/fb59699661af1d7c3405