2026年4月29日水曜日

ESP32スマートチェッカー

 

 

//2026.4.29

#include <WiFi.h>

#include <WebServer.h>

#include <WebSocketsServer.h> // 「WebSockets」ライブラリをインストールしてください


// WiFi設定

const char* ssid = "OPPO Reno5 A";

const char* password = "x676eixd";


WebServer server(80);

WebSocketsServer webSocket = WebSocketsServer(81);


const int ledPin = 2; // 内蔵LEDピン

unsigned long targetTime = 0; // 点灯予定時刻

bool isWaiting = false;       // 点灯待機フラグ


// スマートフォンに配信するHTMLファイル

const char index_html[] PROGMEM = R"rawliteral(

<!DOCTYPE html>

<html>

<head>

  <meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">


  <style>

    body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; position: fixed; font-family: sans-serif; background: #f0f2f5; }

    .container { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; }

    input { font-size: 24px; padding: 15px; width: 70%; text-align: center; border: 2px solid #ddd; border-radius: 10px; margin-bottom: 20px; }

    .btn { font-size: 20px; padding: 15px 40px; color: white; border: none; border-radius: 10px; cursor: pointer; width: 60%; margin: 10px; }

    #onBtn { background: #28a745; }

    #offBtn { background: #dc3545; }

  </style>

</head>

<body>

  <div class="container">

    <h2>LED Controller</h2>

    <input type="number" id="secInput" placeholder="点灯までの秒数">

    <button id="onBtn" class="btn" onclick="send('ON')">ON (タイマー)</button>

    <button id="offBtn" class="btn" onclick="send('OFF')">OFF (即時消灯)</button>

    <p id="status">接続待機中...</p>

  </div>

  <script>

    // ブラウザからESP32のIPに対してWebSocket接続

    const socket = new WebSocket('ws://' + location.hostname + ':81');

    socket.onopen = () => { document.getElementById('status').innerText = '接続済み (Secure)'; };

    

    function send(cmd) {

      const sec = document.getElementById('secInput').value || 0;

      // 「コマンド,秒数」の形式で送信

      socket.send(cmd + ',' + sec);

      document.getElementById('status').innerText = cmd === 'ON' ? sec + '秒後に点灯します' : '消灯しました';

    }

    // スクロール防止

    document.addEventListener('touchmove', (e) => e.preventDefault(), { passive: false });

  </script>

</body>

</html>

)rawliteral";


void handleRoot() {

  server.send(200, "text/html", index_html);

}


void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {

  if (type == WStype_TEXT) {

    String msg = String((char*)payload);

    int commaIndex = msg.indexOf(',');

    String cmd = msg.substring(0, commaIndex);

    int seconds = msg.substring(commaIndex + 1).toInt();


    if (cmd == "ON") {

      targetTime = millis() + (seconds * 1000);

      isWaiting = true;

      Serial.printf("%d秒後の点灯を予約しました\n", seconds);

    } else if (cmd == "OFF") {

      isWaiting = false;

      targetTime = 0;

      digitalWrite(ledPin, LOW);

      Serial.println("即時消灯");

    }

  }

}


void setup() {

  Serial.begin(115200);

  pinMode(ledPin, OUTPUT);

  digitalWrite(ledPin, LOW);


  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }


  server.on("/", handleRoot);

  server.begin();


  webSocket.begin();

  webSocket.onEvent(webSocketEvent);


  Serial.println("\nサーバー開始");

  Serial.print("接続先IP: "); Serial.println(WiFi.localIP());

}


void loop() {

  server.handleClient();

  webSocket.loop();


  // タイマー管理:待機フラグが立っており、予定時刻を過ぎたら点灯

  if (isWaiting && millis() >= targetTime) {

    digitalWrite(ledPin, HIGH);

    isWaiting = false;

    Serial.println("点灯します。");

  }

}