【プログラム】NodeMCUでLEDをWifi制御(押している間だけ)

Osoyoo社のNodeMCU ESP2866系 NodeMCU(ESP-12F搭載)

Wifi経由で、スマホに表示されているボタンを、押している間だけLEDが点灯し、離すと消灯するプログラムです。
ロボットカーなど、モーターを作動させる場合、ボタンから指を離せば停止するので、リモートコントロールしやすくなります。

1. 準備

  1. Arduino IDEにESP8266のボードマネージャーがインストールされていることを確認してください。
  2. 以下のコードをArduino IDEにコピーします。
  3. コード内の YOUR_WIFI_SSIDYOUR_WIFI_PASSWORD を、ご自宅のWi-FiのSSIDとパスワードに置き換えてください。
  4. D1とD2ピンにLEDを接続します。

2. ソースコード

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// --- Wi-Fi設定 ---
const char* ssid = "YOUR_WIFI_SSID";     // ご自宅のWi-Fi SSID
const char* password = "YOUR_WIFI_PASSWORD"; // Wi-Fiのパスワード

// Webサーバーを80番ポートで起動
ESP8266WebServer server(80);

// LEDのピンを定義
const int ledPinD1 = D1;
const int ledPinD2 = D2;

// HTMLとJavaScriptを格納する変数
// R"rawliteral(...)rawliteral" を使うと、複数行の文字列をそのまま記述できて便利です
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <title>NodeMCU LED Control</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      margin-top: 50px;
      background-color: #f0f0f0;
    }
    h1 {
      color: #333;
    }
    .button-container {
      margin-top: 30px;
    }
    .led-button {
      display: inline-block;
      padding: 30px 50px;
      font-size: 24px;
      cursor: pointer;
      border: none;
      border-radius: 10px;
      color: white;
      margin: 15px;
      user-select: none; /* ボタンのテキスト選択を防ぐ */
      -webkit-user-select: none; /* iOS Safari用 */
      transition: background-color 0.2s;
    }
    #btnD1 { background-color: #f44336; } /* 赤色 */
    #btnD2 { background-color: #2196F3; } /* 青色 */
    .led-button:active {
      filter: brightness(85%);
    }
  </style>
</head>
<body>

  <h1>LED コントローラー</h1>
  <div class="button-container">
    <button id="btnD1" class="led-button">D1 LED</button>
    <button id="btnD2" class="led-button">D2 LED</button>
  </div>

  <script>
    function setupButtonEvents(buttonId, ledNum) {
      const button = document.getElementById(buttonId);

      // ボタンが押された時の処理 (PCのマウスとスマホのタッチの両方に対応)
      button.addEventListener('mousedown', () => sendRequest(ledNum, 'on'));
      button.addEventListener('touchstart', (e) => {
        e.preventDefault(); // スマホの長押しメニューを無効化
        sendRequest(ledNum, 'on');
      });

      // ボタンが離された時の処理
      button.addEventListener('mouseup', () => sendRequest(ledNum, 'off'));
      button.addEventListener('mouseleave', () => sendRequest(ledNum, 'off')); // カーソルがボタンから外れた場合
      button.addEventListener('touchend', () => sendRequest(ledNum, 'off'));
    }

    // NodeMCUにHTTPリクエストを送信する関数
    function sendRequest(ledNum, state) {
      fetch(`/led${ledNum}/${state}`)
        .then(response => {
          if (!response.ok) {
            console.error('Request failed');
          }
        })
        .catch(error => console.error('Error:', error));
    }

    // 各ボタンにイベントを設定
    setupButtonEvents('btnD1', 1);
    setupButtonEvents('btnD2', 2);
  </script>

</body>
</html>
)rawliteral";

// ルートURL ("/") にアクセスがあった時にHTMLを返す関数
void handleRoot() {
  server.send(200, "text/html", html);
}

// LEDを制御するURLにアクセスがあった時の処理
void handleLED() {
  // D1のON/OFF
  if (server.uri() == "/led1/on") {
    digitalWrite(ledPinD1, HIGH);
    server.send(200, "text/plain", "D1 ON");
  } else if (server.uri() == "/led1/off") {
    digitalWrite(ledPinD1, LOW);
    server.send(200, "text/plain", "D1 OFF");
  }
  // D2のON/OFF
  else if (server.uri() == "/led2/on") {
    digitalWrite(ledPinD2, HIGH);
    server.send(200, "text/plain", "D2 ON");
  } else if (server.uri() == "/led2/off") {
    digitalWrite(ledPinD2, LOW);
    server.send(200, "text/plain", "D2 OFF");
  } else {
    server.send(404, "text/plain", "Not Found");
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPinD1, OUTPUT);
  pinMode(ledPinD2, OUTPUT);
  digitalWrite(ledPinD1, LOW);
  digitalWrite(ledPinD2, LOW);

  // Wi-Fi接続開始
  Serial.println("");
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  // 接続が完了するまで待つ
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // NodeMCUのIPアドレスをシリアルモニタに表示
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // URLと関数の紐付け
  server.on("/", handleRoot);
  server.on("/led1/on", handleLED);
  server.on("/led1/off", handleLED);
  server.on("/led2/on", handleLED);
  server.on("/led2/off", handleLED);

  // Webサーバーを開始
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  // クライアントからのリクエストを処理
  server.handleClient();
}

3. 使い方

  1. 上記のコードをNodeMCUに書き込みます。
  2. Arduino IDEのシリアルモニターを開き、IP Address: の後に表示されるIPアドレスをメモします。
  3. スマートフォンを、NodeMCUが接続しているのと同じWi-Fiネットワークに接続します。
  4. スマートフォンのウェブブラウザを開き、メモしたIPアドレス(例: http://192.168.1.123/)を入力してアクセスします。
  5. 表示されたウェブページのボタンを押している間だけ、対応するLEDが点灯します。指を離すと消灯します。

4. ONとOFFが逆バージョン

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// --- Wi-Fi設定 ---
const char* ssid = "YOUR_WIFI_SSID";     // ご自宅のWi-Fi SSID
const char* password = "YOUR_WIFI_PASSWORD"; // Wi-Fiのパスワード

// Webサーバーを80番ポートで起動
ESP8266WebServer server(80);

// LEDのピンを定義
const int ledPinD1 = D1;
const int ledPinD2 = D2;

// HTMLとJavaScriptを格納する変数
// R"rawliteral(...)rawliteral" を使うと、複数行の文字列をそのまま記述できて便利です
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <title>NodeMCU LED Control</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      margin-top: 50px;
      background-color: #f0f0f0;
    }
    h1 {
      color: #333;
    }
    .button-container {
      margin-top: 30px;
    }
    .led-button {
      display: inline-block;
      padding: 30px 50px;
      font-size: 24px;
      cursor: pointer;
      border: none;
      border-radius: 10px;
      color: white;
      margin: 15px;
      user-select: none; /* ボタンのテキスト選択を防ぐ */
      -webkit-user-select: none; /* iOS Safari用 */
      transition: background-color 0.2s;
    }
    #btnD1 { background-color: #f44336; } /* 赤色 */
    #btnD2 { background-color: #2196F3; } /* 青色 */
    .led-button:active {
      filter: brightness(85%);
    }
  </style>
</head>
<body>

  <h1>LED コントローラー</h1>
  <div class="button-container">
    <button id="btnD1" class="led-button">D1 LED</button>
    <button id="btnD2" class="led-button">D2 LED</button>
  </div>

  <script>
    function setupButtonEvents(buttonId, ledNum) {
      const button = document.getElementById(buttonId);

      // ボタンが押された時の処理 (PCのマウスとスマホのタッチの両方に対応)
      button.addEventListener('mousedown', () => sendRequest(ledNum, 'on'));
      button.addEventListener('touchstart', (e) => {
        e.preventDefault(); // スマホの長押しメニューを無効化
        sendRequest(ledNum, 'on');
      });

      // ボタンが離された時の処理
      button.addEventListener('mouseup', () => sendRequest(ledNum, 'off'));
      button.addEventListener('mouseleave', () => sendRequest(ledNum, 'off')); // カーソルがボタンから外れた場合
      button.addEventListener('touchend', () => sendRequest(ledNum, 'off'));
    }

    // NodeMCUにHTTPリクエストを送信する関数
    function sendRequest(ledNum, state) {
      fetch(`/led${ledNum}/${state}`)
        .then(response => {
          if (!response.ok) {
            console.error('Request failed');
          }
        })
        .catch(error => console.error('Error:', error));
    }

    // 各ボタンにイベントを設定
    setupButtonEvents('btnD1', 1);
    setupButtonEvents('btnD2', 2);
  </script>

</body>
</html>
)rawliteral";

// ルートURL ("/") にアクセスがあった時にHTMLを返す関数
void handleRoot() {
  server.send(200, "text/html", html);
}

// LEDを制御するURLにアクセスがあった時の処理
void handleLED() {
  // D1のON/OFF
  if (server.uri() == "/led1/on") {
    digitalWrite(ledPinD1, LOW); // ★変更点: HIGH -> LOW
    server.send(200, "text/plain", "D1 ON");
  } else if (server.uri() == "/led1/off") {
    digitalWrite(ledPinD1, HIGH); // ★変更点: LOW -> HIGH
    server.send(200, "text/plain", "D1 OFF");
  }
  // D2のON/OFF
  else if (server.uri() == "/led2/on") {
    digitalWrite(ledPinD2, LOW); // ★変更点: HIGH -> LOW
    server.send(200, "text/plain", "D2 ON");
  } else if (server.uri() == "/led2/off") {
    digitalWrite(ledPinD2, HIGH); // ★変更点: LOW -> HIGH
    server.send(200, "text/plain", "D2 OFF");
  } else {
    server.send(404, "text/plain", "Not Found");
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPinD1, OUTPUT);
  pinMode(ledPinD2, OUTPUT);
  digitalWrite(ledPinD1, HIGH); // ★変更点: LOW -> HIGH (初期状態をOFFに)
  digitalWrite(ledPinD2, HIGH); // ★変更点: LOW -> HIGH (初期状態をOFFに)

  // Wi-Fi接続開始
  Serial.println("");
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  // 接続が完了するまで待つ
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // NodeMCUのIPアドレスをシリアルモニタに表示
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // URLと関数の紐付け
  server.on("/", handleRoot);
  server.on("/led1/on", handleLED);
  server.on("/led1/off", handleLED);
  server.on("/led2/on", handleLED);
  server.on("/led2/off", handleLED);

  // Webサーバーを開始
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  // クライアントからのリクエストを処理
  server.handleClient();
}

コメント