
В этом проекте управления диммером с помощью веб-сервера мы рассмотрим, как создать на основе ESP8266 и ESP32 веб-сервер с ползунком для управления уровнем напряжения диммера, подключённого к GPIO-выводу ESP8266 / ESP32.
Для этого мы добавим на страницу веб-сервера HTML-ползунок. Перемещая ползунок, вы задаёте его значение, которое в свою очередь устанавливает уровень диммирования.
Кроме того, мы используем библиотеку WiFiManager, которая позволяет подключать проект диммера на базе ESP8266/ESP32 к различным точкам доступа (AP) без необходимости жёстко прописывать и загружать новый код на плату. Также с помощью библиотеки WiFiManager можно добавлять пользовательские параметры (переменные или адрес/порт MQTT-сервера) и управлять подключением к нескольким SSID.
Ниже приведены 2 примера кода. Первый — для одноканального диммера, второй — для 4-канального диммера с 4 ползунками на веб-странице.
Код для 1-канального ДИММЕРА
- #include <AsyncTCP.h>
- #include <RBDdimmer.h> //https://rocketcontroller.com/dimmer-connection-to-microcontroller-and-arduino-library-examples/
- #define outputPin 16
- #define zerocross 5 // назначение выводов
- dimmerLamp dimmer(outputPin, zerocross); //инициализация порта для диммера для плат ESP8266, ESP32, Arduino Due
- #if defined(ESP8266)
- #include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
- #else
- #include <WiFi.h> //Для ESP32
- #endif
- #include <ESPAsyncWebServer.h>
- #include <ESPAsyncWiFiManager.h> //https://github.com/knolleary/pubsubclient
- //вызывается при переходе WiFiManager в режим конфигурации
- void configModeCallback (AsyncWiFiManager *myWiFiManager) {
- Serial.println("Entered config mode");
- Serial.println(WiFi.softAPIP());
- //если использовался автоматически сгенерированный SSID, вывести его
- Serial.println(myWiFiManager->getConfigPortalSSID());
- }
- AsyncWebServer server(80);
- DNSServer dns;
- String sliderValue = "0";
- const char* PARAM_INPUT = "value";
- const char index_html[] PROGMEM = R"rawliteral(
- <!DOCTYPE HTML><html>
- <head>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>Dimmer ESP Controller</title>
- <style>
- html {font-family: Arial; display: inline-block; text-align: center;}
- h2 {font-size: 2.3rem;}
- p {font-size: 1.9rem;}
- body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
- .slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #FFD65C;
- outline: none; -webkit-transition: .2s; transition: opacity .2s;}
- .slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background: #003249; cursor: pointer;}
- .slider::-moz-range-thumb { width: 35px; height: 35px; background: #003249; cursor: pointer; }
- .button { background-color: #003249; border: none; color: white; padding: 16px 40px;}
- </style>
- </head>
- <body>
- <h2>RocketController Dimmer</h2>
- <p><span id="textSliderValue">%SLIDERVALUE%</span></p>
- <p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="100" value="%SLIDERVALUE%" step="1" class="slider"></p>
- </br>
- <p><a href=/output/on\><button class=\"button\">WiFi RST</button></a></p>
- <script>
- function updateSliderPWM(element) {
- var sliderValue = document.getElementById("pwmSlider").value;
- document.getElementById("textSliderValue").innerHTML = sliderValue;
- console.log(sliderValue);
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/slider?value="+sliderValue, true);
- xhr.send();
- }
- </script>
- </body>
- </html>
- )rawliteral";
- // Заменяет заполнитель на секцию с кнопкой на веб-странице
- String processor(const String& var){
- //Serial.println(var);
- if (var == "SLIDERVALUE"){
- return sliderValue;
- }
- return String();
- }
- void setup() {
- // поместите ваш код инициализации здесь, выполняется один раз:
- Serial.begin(115200);
- dimmer.begin(NORMAL_MODE, OND);
- //WiFiManager. Локальная инициализация. После завершения работы нет необходимости хранить объект
- AsyncWiFiManager wifiManager(&server,&dns);
- //сброс настроек — для тестирования
- //wifiManager.resetSettings();
- //установка колбэка, который вызывается при неудачном подключении к предыдущему WiFi и переходе в режим точки доступа
- //wifiManager.setAPCallback(configModeCallback);
- //получает ssid и пароль, пытается подключиться
- //и входит в блокирующий цикл ожидания конфигурации
- if (!wifiManager.autoConnect("WiFi-Dimmer")) {
- Serial.println("failed to connect and hit timeout");
- //сбросить и попробовать снова, или перевести в глубокий сон
- //ESP.resetSettings();
- //ESP.reset();
- //ESP.restart();
- delay(1000);
- }
- //если вы дошли до этой строки, подключение к WiFi выполнено
- Serial.println("connected!");
- // Маршрут для корневой / веб-страницы
- server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
- request->send_P(200, "text/html", index_html, processor);
- });
- // Отправка GET-запроса на <ESP_IP>/slider?value=<inputMessage>
- server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
- String inputMessage;
- // Получение значения input1 по адресу <ESP_IP>/slider?value=<inputMessage>
- if (request->hasParam(PARAM_INPUT)) {
- inputMessage = request->getParam(PARAM_INPUT)->value();
- sliderValue = inputMessage;
- dimmer.setPower(sliderValue.toInt()); //ДИММИРОВАНИЕ
- }
- else {
- inputMessage = "No message sent";
- }
- //Serial.println(inputMessage);
- Serial.println(sliderValue);
- request->send(200, "text/plain", "OK");
- });
- // Запуск сервера
- server.begin();
- }
- void loop() {
- // поместите ваш основной код здесь, выполняется циклически:
- }
Код для 4-канального ДИММЕРА
- #include <AsyncTCP.h>
- #include <RBDdimmer.h> //https://rocketcontroller.com/dimmer-connection-to-microcontroller-and-arduino-library-examples/
- #define outputPin 16
- #define zerocross 5 // назначение выводов
- dimmerLamp dimmer(outputPin, zerocross); //инициализация порта для диммера для плат ESP8266, ESP32, Arduino Due
- #if defined(ESP8266)
- #include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
- #else
- #include <WiFi.h> //для ESP32
- #endif
- #include <ESPAsyncWebServer.h>
- #include <ESPAsyncWiFiManager.h> //https://github.com/knolleary/pubsubclient
- //вызывается при переходе WiFiManager в режим конфигурации
- void configModeCallback (AsyncWiFiManager *myWiFiManager) {
- Serial.println("Entered config mode");
- Serial.println(WiFi.softAPIP());
- //если использовался автоматически сгенерированный SSID, вывести его
- Serial.println(myWiFiManager->getConfigPortalSSID());
- }
- AsyncWebServer server(80);
- DNSServer dns;
- //=====
- String sliderValue = "0";
- String sliderValue2 = "0";
- String sliderValue3 = "0";
- String sliderValue4 = "0";
- const char* PARAM_INPUT = "value";
- const char index_html[] PROGMEM = R"rawliteral(
- <!DOCTYPE HTML><html>
- <head>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>Dimmer ESP Controller</title>
- <style>
- html {font-family: Arial; display: inline-block; text-align: center;}
- h2 {font-size: 2.3rem;}
- p {font-size: 1.9rem;}
- body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
- .slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #FFD65C;
- outline: none; -webkit-transition: .2s; transition: opacity .2s;}
- .slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background: #003249; cursor: pointer;}
- .slider::-moz-range-thumb { width: 35px; height: 35px; background: #003249; cursor: pointer; }
- .button { background-color: #003249; border: none; color: white; padding: 16px 40px;}
- </style>
- </head>
- <body>
- <h2>Dimmer ESP Controller</h2>
- <p><span id="textSliderValue">%SLIDERVALUE%</span></p>
- <p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="100" value="%SLIDERVALUE%" step="1" class="slider"></p>
- </br>
- <h2>Dimmer ESP Controller2</h2>
- <p><span id="textSliderValue2">%SLIDERVALUE2%</span></p>
- <p><input type="range" onchange="updateSliderPWM2(this)" id="pwmSlider" min="0" max="100" value2="%SLIDERVALUE2%" step="1" class="slider"></p>
- </br>
- <h2>Dimmer ESP Controller3</h2>
- <p><span id="textSliderValue3">%SLIDERVALUE3%</span></p>
- <p><input type="range" onchange="updateSliderPWM3(this)" id="pwmSlider" min="0" max="100" value3="%SLIDERVALUE3%" step="1" class="slider"></p>
- </br>
- <h2>Dimmer ESP Controller4</h2>
- <p><span id="textSliderValue4">%SLIDERVALUE4%</span></p>
- <p><input type="range" onchange="updateSliderPWM4(this)" id="pwmSlider" min="0" max="100" value4="%SLIDERVALUE4%" step="1" class="slider"></p>
- </br>
- <p><a href=/output/on\><button class=\"button\">WiFi RST</button></a></p>
- <script>
- function updateSliderPWM (element) {
- var sliderValue = document.getElementById("pwmSlider").value;
- document.getElementById("textSliderValue").innerHTML = sliderValue;
- console.log(sliderValue);
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/slider?value="+sliderValue, true);
- xhr.send();
- }
- function updateSliderPWM2 (element) {
- var sliderValue2 = document.getElementById("pwmSlider2").value2;
- document.getElementById("textSliderValue2").innerHTML = sliderValue2;
- console.log(sliderValue2);
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/slider?value="+sliderValue2, true);
- xhr.send();
- }
- function updateSliderPWM3 (element) {
- var sliderValue3 = document.getElementById("pwmSlider3").value3;
- document.getElementById("textSliderValue3").innerHTML = sliderValue3;
- console.log(sliderValue3);
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/slider?value="+sliderValue3, true);
- xhr.send();
- }
- function updateSliderPWM4 (element) {
- var sliderValue4 = document.getElementById("pwmSlider4").value4;
- document.getElementById("textSliderValue4").innerHTML = sliderValue4;
- console.log(sliderValue4);
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/slider?value="+sliderValue4, true);
- xhr.send();
- }
- </script>
- </body>
- </html>
- )rawliteral";
- // Заменяет заполнитель на секцию с кнопкой на веб-странице
- String processor(const String& var){
- //Serial.println(var);
- if (var == "SLIDERVALUE"){
- return sliderValue;
- }
- if (var == "SLIDERVALUE2"){
- return sliderValue2;
- }
- if (var == "SLIDERVALUE3"){
- return sliderValue3;
- }
- if (var == "SLIDERVALUE4"){
- return sliderValue4;
- }
- return String();
- }
- void setup() {
- // поместите ваш код инициализации здесь, выполняется один раз:
- Serial.begin(115200);
- dimmer.begin(NORMAL_MODE, OND);
- //WiFiManager
- //Локальная инициализация. После завершения работы нет необходимости хранить объект
- AsyncWiFiManager wifiManager(&server,&dns);
- //сброс настроек — для тестирования
- //wifiManager.resetSettings();
- //установка колбэка, который вызывается при неудачном подключении к предыдущему WiFi и переходе в режим точки доступа
- //wifiManager.setAPCallback(configModeCallback);
- //получает ssid и пароль, пытается подключиться
- //и входит в блокирующий цикл ожидания конфигурации
- if (!wifiManager.autoConnect("WiFi-Dimmer")) {
- Serial.println("failed to connect and hit timeout");
- //сбросить и попробовать снова, или перевести в глубокий сон
- //ESP.resetSettings();
- //ESP.reset();
- //ESP.restart();
- delay(1000);
- }
- //если вы дошли до этой строки, подключение к WiFi выполнено
- Serial.println("connected...yeey :)");
- // Маршрут для корневой / веб-страницы
- server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
- request->send_P(200, "text/html", index_html, processor);
- });
- // Отправка GET-запроса на <ESP_IP>/slider?value=<inputMessage>
- server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
- String inputMessage;
- // Получение значения input1 по адресу <ESP_IP>/slider?value=<inputMessage>
- if (request->hasParam(PARAM_INPUT)) {
- inputMessage = request->getParam(PARAM_INPUT)->value();
- sliderValue = inputMessage;
- dimmer.setPower(sliderValue.toInt());
- }
- String inputMessage2;
- // Получение значения input1 по адресу <ESP_IP>/slider?value=<inputMessage>
- if (request->hasParam(PARAM_INPUT)) {
- inputMessage2 = request->getParam(PARAM_INPUT)->value();
- sliderValue2 = inputMessage2;
- }
- else {
- inputMessage = "No message sent";
- }
- //Serial.println(inputMessage);
- Serial.println(sliderValue);
- Serial.print("DIM2");
- Serial.println(sliderValue2);
- Serial.print("DIM3");
- Serial.println(sliderValue3);
- Serial.print("DIM4");
- Serial.println(sliderValue4);
- request->send(200, "text/plain", "OK");
- });
- // Запуск сервера
- server.begin();
- }
- void loop() {
- // поместите ваш основной код здесь, выполняется циклически:
- }
Шаг 1. Настройка доступа к Wi-Fi.
WiFiManager — отличная библиотека для использования в проектах на ESP8266/ESP32, поскольку с ней вам больше не нужно жёстко прописывать сетевые учётные данные (SSID и пароль). ESP автоматически подключится к известной сети или создаст точку доступа, которую можно использовать для настройки сетевых параметров. Вот как работает этот процесс:
- Когда ESP8266/ESP32 загружается, он переходит в режим станции (Station mode) и пытается подключиться к ранее сохранённой точке доступа (известная комбинация SSID и пароля);
- Если подключение не удаётся, ESP переходит в режим точки доступа;
- С помощью любого устройства с Wi-Fi и браузером подключитесь к созданной точке доступа (WiFi-Dimmer);
- После подключения к «WiFi-Dimmer» откройте IP-адрес по умолчанию 192.168.4.1, чтобы открыть веб-страницу для настройки SSID и пароля;
- После задания нового SSID и пароля ESP перезагружается и пытается подключиться;
Если подключение установлено, процесс завершён успешно. В противном случае ESP снова перейдёт в режим точки доступа.

Шаг 2. Веб-сервер с ползунком и диммирование.
- ESP8266/ESP32 размещает веб-сервер с веб-страницей, содержащей ползунок;
- Когда вы перемещаете ползунок, на ESP8266/ESP32 отправляется HTTP-запрос с новым значением ползунка;
- HTTP-запрос имеет следующий формат: GET/slider?value=SLIDERVALUE, где SLIDERVALUE — число от 0 до 100;
- Из HTTP-запроса ESP8266/ESP32 получает текущее значение ползунка;
- ESP8266 устанавливает уровень диммера в соответствии со значением ползунка: dimmer.setPower(sliderValue.toInt()); //ДИММИРОВАНИЕ;
Для 4-канального диммера на веб-странице отображаются 4 ползунка.
