ESP32/ESP8266 RGB светодиодная лента с веб-сервером для выбора цвета

В этом проекте мы покажем, как дистанционно управлять RGB светодиодной лентой с помощью ESP8266 или ESP32 через веб-сервер с цветовой палитрой.

ESP32 или ESP8266 RGB светодиодная лента с веб-сервером для выбора цвета

Мы будем управлять 5В RGB светодиодной лентой, а код будет написан в Arduino IDE.

Для лучшего понимания этого проекта вам может быть полезно сначала ознакомиться с несколькими руководствами (этот шаг необязателен):

Видеоруководство

Вы можете посмотреть видеоруководство или продолжить чтение этой страницы для получения письменных инструкций.

Обзор проекта

Прежде чем начать, давайте посмотрим, как работает этот проект:

Как работает ESP32/ESP8266 RGB светодиодная лента с веб-сервером для выбора цвета
  • Веб-сервер ESP32/ESP8266 отображает цветовую палитру.

  • Когда вы выбираете цвет, ваш браузер отправляет запрос на URL, содержащий параметры R, G и B выбранного цвета.

  • ESP32/ESP8266 получает запрос и разделяет значение для каждого параметра цвета.

  • Затем отправляет ШИМ-сигнал с соответствующим значением на GPIO, которые управляют лентой.

Необходимые компоненты

Для этого проекта вам понадобятся следующие компоненты:

Вы можете использовать приведённые выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!

Схема подключения

Для этого проекта мы будем использовать RGB светодиодную ленту, которая питается от 5В.

5В RGB светодиодная лента

Примечание

Существуют другие похожие ленты, которые требуют 12В для работы. Вы всё равно можете использовать их с предоставленным кодом, но вам потребуется подходящий источник питания.

В этом примере мы будем питать светодиодную ленту и ESP32 или ESP8266 от одного источника питания 5В.

ESP32 – схема подключения

Следуйте схеме ниже для подключения ленты к ESP32.

ESP32 5В RGB светодиодная лента -- принципиальная схема

ESP8266 – схема подключения

Следуйте схеме ниже для подключения ленты к ESP8266.

ESP8266 5В RGB светодиодная лента -- принципиальная схема

NPN транзисторы

В этой схеме мы используем NPN транзистор S8050. Однако, в зависимости от количества светодиодов в вашей ленте, вам может потребоваться NPN транзистор, способный выдерживать больший постоянный ток на выводе коллектора.

ESP32/ESP8266 RGB светодиодная лента -- схема с NPN транзисторами

Чтобы определить максимальный ток, потребляемый вашей светодиодной лентой, можно измерить ток, когда все светодиоды горят на максимальной яркости (когда установлен белый цвет).

Поскольку мы используем 12 светодиодов, максимальный ток составляет приблизительно 630 мА при полной яркости белого цвета. Поэтому мы можем использовать NPN транзистор S8050, который выдерживает до 700 мА.

ESP32/ESP8266 RGB светодиодная лента -- потребление тока

Примечание

Лента потребляет максимальный ток, когда вы устанавливаете белый цвет (это то же самое, что установить все три цвета на максимальную яркость). Установка других цветов потребляет меньше тока, поэтому вы, вероятно, не будете использовать ленту при максимальном токе.

Код для ESP32

Мы будем программировать ESP32 с помощью Arduino IDE, поэтому убедитесь, что у вас установлено дополнение ESP32 перед продолжением:

После сборки схемы скопируйте следующий код в Arduino IDE для программирования ESP32.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com
*********/

// Load Wi-Fi library
#include <WiFi.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Decode HTTP GET value
String redString = "0";
String greenString = "0";
String blueString = "0";
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

// Variable to store the HTTP request
String header;

// Red, green, and blue pins for PWM control
const int redPin = 13;     // 13 corresponds to GPIO13
const int greenPin = 12;   // 12 corresponds to GPIO12
const int bluePin = 14;    // 14 corresponds to GPIO14

// Setting PWM frequency, channels and bit resolution
const int freq = 5000;
const int redChannel = 0;
const int greenChannel = 1;
const int blueChannel = 2;
// Bit resolution 2^8 = 256
const int resolution = 8;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  // configure LED PWM functionalitites
  ledcAttachChannel(redPin, freq, resolution, redChannel);
  ledcAttachChannel(greenPin, freq, resolution, greenChannel);
  ledcAttachChannel(bluePin, freq, resolution, blueChannel);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
            client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
            client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
            client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
            client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
            client.println("<script>function update(picker) {document.getElementById('rgb').textContent = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
            client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
            // The HTTP response ends with another blank line
            client.println();

            // Request sample: /?r201g32b255&
            // Red = 201 | Green = 32 | Blue = 255
            if(header.indexOf("GET /?r") >= 0) {
              pos1 = header.indexOf('r');
              pos2 = header.indexOf('g');
              pos3 = header.indexOf('b');
              pos4 = header.indexOf('&');
              redString = header.substring(pos1+1, pos2);
              greenString = header.substring(pos2+1, pos3);
              blueString = header.substring(pos3+1, pos4);
              /*Serial.println(redString.toInt());
              Serial.println(greenString.toInt());
              Serial.println(blueString.toInt());*/
              ledcWrite(redPin, redString.toInt());
              ledcWrite(greenPin, greenString.toInt());
              ledcWrite(bluePin, blueString.toInt());
            }
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Посмотреть исходный код

Перед загрузкой кода не забудьте вставить ваши сетевые учётные данные, чтобы ESP мог подключиться к вашей локальной сети.

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

Если вы ранее создавали веб-сервер на ESP32, этот код не сильно отличается. Он добавляет цветовую палитру на веб-страницу и декодирует запрос для управления цветом ленты. Поэтому мы рассмотрим только те части, которые относятся к данному проекту.

Код для ESP8266

Мы будем программировать ESP8266 с помощью Arduino IDE. Для загрузки кода на ESP8266 вам сначала необходимо установить дополнение ESP8266, если вы этого ещё не сделали (Установка платы ESP8266 в Arduino IDE).

После сборки схемы скопируйте следующий код в Arduino IDE для программирования ESP8266.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com
*********/

// Load Wi-Fi library
#include <ESP8266WiFi.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Decode HTTP GET value
String redString = "0";
String greenString = "0";
String blueString = "0";
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

// Variable to store the HTTP request
String header;

// Red, green, and blue pins for PWM control
const int redPin = 13;     // 13 corresponds to GPIO13
const int greenPin = 12;   // 12 corresponds to GPIO12
const int bluePin = 14;    // 14 corresponds to GPIO14

// Setting PWM bit resolution
const int resolution = 256;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);

  // configure LED PWM resolution/range and set pins to LOW
  analogWriteRange(resolution);
  analogWrite(redPin, 0);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 0);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
            client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
            client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
            client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
            client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
            client.println("<script>function update(picker) {document.getElementById('rgb').textContent = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
            client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
            // The HTTP response ends with another blank line
            client.println();

            // Request sample: /?r201g32b255&
            // Red = 201 | Green = 32 | Blue = 255
            if(header.indexOf("GET /?r") >= 0) {
              pos1 = header.indexOf('r');
              pos2 = header.indexOf('g');
              pos3 = header.indexOf('b');
              pos4 = header.indexOf('&');
              redString = header.substring(pos1+1, pos2);
              greenString = header.substring(pos2+1, pos3);
              blueString = header.substring(pos3+1, pos4);
              /*Serial.println(redString.toInt());
              Serial.println(greenString.toInt());
              Serial.println(blueString.toInt());*/
              analogWrite(redPin, redString.toInt());
              analogWrite(greenPin, greenString.toInt());
              analogWrite(bluePin, blueString.toInt());
            }
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Посмотреть исходный код

Перед загрузкой кода не забудьте вставить ваши сетевые учётные данные, чтобы ESP мог подключиться к вашей локальной сети.

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

Если вы ранее создавали веб-сервер на ESP8266, этот код не сильно отличается. Он добавляет цветовую палитру на веб-страницу и декодирует запрос для управления цветом ленты. Поэтому мы рассмотрим только те части, которые относятся к данному проекту.

Как работает код

Скетчи для ESP32 и ESP8266 очень похожи и отличаются лишь в нескольких местах: в используемой библиотеке Wi-Fi и в способе генерации ШИМ-сигналов. Мы рассмотрим это в данном разделе.

Скетч для ESP32 использует библиотеку WiFi.h.

#include <WiFi.h>

Скетч для ESP8266 использует библиотеку ESP8266WiFi.h.

#include <ESP8266WiFi.h>

Следующие строки определяют строковые переменные для хранения параметров R, G и B из запроса.

String redString = "0";
String greenString = "0";
String blueString = "0";

Следующие четыре переменные используются для последующего декодирования HTTP-запроса.

int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

Создайте три переменные для GPIO, которые будут управлять параметрами R, G и B ленты. В данном случае мы используем GPIO 13, GPIO 12 и GPIO 14.

const int redPin = 13;
const int greenPin = 12;
const int bluePin = 14;

Эти GPIO должны выводить ШИМ-сигналы, поэтому сначала нужно настроить свойства ШИМ. Установите частоту ШИМ-сигнала на 5000 Гц. Затем назначьте ШИМ-канал для каждого цвета (это не требуется в скетче для ESP8266).

const int freq = 5000;
const int redChannel = 0;
const int greenChannel = 1;
const int blueChannel = 2;

И наконец, установите разрешение ШИМ-каналов на 8 бит (не требуется в скетче для ESP8266).

const int resolution = 8;

В setup() создайте LEDC-пины с ранее определёнными свойствами ШИМ (не требуется в скетче для ESP8266).

ledcAttachChannel(redPin, freq, resolution, redChannel);
ledcAttachChannel(greenPin, freq, resolution, greenChannel);
ledcAttachChannel(bluePin, freq, resolution, blueChannel);

Подробнее о ШИМ с ESP32: ESP32 ШИМ с Arduino IDE (аналоговый выход)

Следующий фрагмент кода отображает цветовую палитру на веб-странице и формирует запрос на основе выбранного цвета.

client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
client.println("<script>function update(picker) {document.getElementById('rgb').textContent = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
// The HTTP response ends with another blank line
client.println();

Когда вы выбираете цвет, вы получаете запрос в следующем формате.

/?r201g32b255&

Поэтому нам нужно разобрать эту строку, чтобы получить параметры R, G и B. Параметры сохраняются в переменных redString, greenString и blueString и могут иметь значения от 0 до 255.

pos1 = header.indexOf('r');
pos2 = header.indexOf('g');
pos3 = header.indexOf('b');
pos4 = header.indexOf('&');
redString = header.substring(pos1+1, pos2);
greenString = header.substring(pos2+1, pos3);
blueString = header.substring(pos3+1, pos4);

Для управления лентой с помощью ESP32 используйте функцию ledcWrite() для генерации ШИМ-сигналов со значениями, декодированными из HTTP-запроса.

ledcWrite(redPin, redString.toInt());
ledcWrite(greenPin, greenString.toInt());
ledcWrite(bluePin, blueString.toInt());

Примечание

Подробнее о ШИМ с ESP32: ESP32 ШИМ с Arduino IDE.

Для управления лентой с помощью ESP8266 достаточно использовать функцию analogWrite() для генерации ШИМ-сигналов со значениями, декодированными из HTTP-запроса.

analogWrite(redPin, redString.toInt());
analogWrite(greenPin, greenString.toInt());
analogWrite(bluePin, blueString.toInt())

Поскольку мы получаем значения в строковой переменной, нам нужно преобразовать их в целые числа с помощью метода toInt().

Подробнее о ШИМ с ESP8266: ESP8266 NodeMCU ШИМ с Arduino IDE – управление яркостью светодиода (аналоговый выход)

Демонстрация

После ввода ваших сетевых учётных данных выберите правильную плату и COM-порт, затем загрузите код на ESP32 или ESP8266.

После загрузки откройте монитор порта на скорости 115200 бод и нажмите кнопку Enable/Reset на ESP. Вы должны увидеть IP-адрес платы.

Демонстрация ESP32/ESP8266 RGB светодиодная лента

Откройте браузер и введите IP-адрес ESP. Теперь используйте цветовую палитру для выбора цвета ленты.

Веб-сервер -- демонстрация ESP32/ESP8266 RGB светодиодная лента

Затем нажмите кнопку «Change Color», чтобы цвет вступил в силу.

Демонстрация ESP32/ESP8266 5В RGB светодиодная лента -- веб-сервер с выбором цвета

Чтобы выключить RGB светодиодную ленту, выберите чёрный цвет.

Наиболее насыщенные цвета (в верхней части палитры) дадут лучшие результаты.

ESP32/ESP8266 5В RGB светодиодная лента -- веб-сервер с выбором цвета, лучшие цвета

Теперь вы можете использовать ленту для украшения дома: под кроватью, за телевизором, под кухонным шкафом и многое другое.

Заключение

В этой статье вы узнали, как дистанционно управлять RGB светодиодной лентой с помощью веб-сервера на ESP32 или ESP8266 в вашей локальной сети.

Надеемся, это руководство было для вас полезным. Если вам понравился этот проект, вам также могут быть интересны:

Узнайте больше об ESP32 с нашими ресурсами:

Примечание

Это отрывок из курса: Изучите ESP32 с Arduino IDE. Если вам нравится ESP32 и вы хотите узнать о нём больше, мы рекомендуем записаться на курс Изучите ESP32 с Arduino IDE.

Источник: :doc:`ESP32/ESP8266 RGB LED Strip with Color Picker Web Server <../esp32-esp8266-rgb-led-strip-web-server/index>` by Rui Santos, Random Nerd Tutorials