
В тази статия ще комбинираме всички научени умения от предишните ни проекти и ще ги приложим в създаването на пълноценен проект с ESP8266 D1 Mini. Ще изградим система за контрол на релета, управление чрез физически бутони и уеб интерфейс, както и четене на данни от сензори като DHT11 за температура и влажност. Също така а ще четем стойности от аналогов вход. Този проект ще послужи като основа за по-сложни IoT решения, които ще предложим в бъдещи статии.
Предишни статий които ще използваме за основа на този проект:
- Управление на 4 релета през WEB с ESP8266
- Изчитане на DHT11 и DHT22 с ESP8266
- Изчитане на бутон с ESP8266: Два примера с Arduino IDE
- Управление на LED с потенциометър и ESP8266 чрез PWM
Основната концепция на проекта
Проектът се състои от следните основни компоненти:
- Контрол на релета – ще управляваме четири релета, които могат да включват и изключват електрически устройства.
- Физически бутони – четири бутона ще бъдат използвани за управление на релетата. Те ще работят с дебаунс логика, за да предотвратим неправилни отчети при бързо натискане.
- Уеб интерфейс – ще създадем уеб сървър, чрез който ще можем да контролираме релетата дистанционно, да четем стойностите на бутоните и аналоговия вход, както и данни за температурата и влажността от сензора DHT11.
- DHT11 сензор – ще четем данни за температурата и влажността от този сензор, което ще ни даде възможност да следим околната среда. Може да свалите библиотеката от тук.
DHT11 диаграма на пиновете (pinout)

DHT11 конфигурация на пиновете
Характеристики на ESP8266 D1 Mini
ESP8266 D1 Mini е малка и мощна платформа, подходяща за IoT проекти. Тя разполага с вградени Wi-Fi възможности, които ще използваме, за да създадем уеб сървър. С помощта на библиотеката ESP8266WebServer, ще създадем интерактивен уеб интерфейс за управление на системата.
Прочетете повече за тази платформа в ревюто ни за нея: ESP8266 D1 Mini – Малък, но Мощен Wi-Fi Микроконтролер
Код на проекта за контрол на четири релета чрез бутони и WEB интерфейс
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
// Пинове за релетата
#define RELAY_1 D0
#define RELAY_2 D6
#define RELAY_3 D7
#define RELAY_4 D8
// Пинове за бутоните
#define BUTTON_1 D4
#define BUTTON_2 D3
#define BUTTON_3 D2
#define BUTTON_4 D1
// Аналогов вход
#define ANALOG_IN A0
// Пин за DHT22
#define DHTPIN D5
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// Wi-Fi настройки
const char* ssid = "xxxxxxxx"; // заместете с името на вашата WiFi мрежа
const char* password = "xxxxxxxx"; // заместете с вашата WiFi парола
// Създаваме уеб сървър на порт 80
ESP8266WebServer server(80);
// Променливи за състоянията на релетата
bool relay1State = false;
bool relay2State = false;
bool relay3State = false;
bool relay4State = false;
// Променливи за състоянията на бутоните и броячи
int button1Counter = 0;
int button2Counter = 0;
int button3Counter = 0;
int button4Counter = 0;
// Променливи за време и дебаунс
unsigned long lastButtonPress1 = 0;
unsigned long lastButtonPress2 = 0;
unsigned long lastButtonPress3 = 0;
unsigned long lastButtonPress4 = 0;
const unsigned long debounceDelay = 250; // 250 ms debounce delay
void setup() {
Serial.begin(115200);
// Настройка на релетата като изходи и изключването им
pinMode(RELAY_1, OUTPUT);
pinMode(RELAY_2, OUTPUT);
pinMode(RELAY_3, OUTPUT);
pinMode(RELAY_4, OUTPUT);
// Настройваме релетата да са изключени по подразбиране при рестарт (LOW = изключено)
digitalWrite(RELAY_1, LOW); // По-ниско състояние = изключено
digitalWrite(RELAY_2, LOW);
digitalWrite(RELAY_3, LOW);
digitalWrite(RELAY_4, LOW);
// Настройка на бутоните като входове с активирани вътрешни pull-up резистори
pinMode(BUTTON_1, INPUT_PULLUP);
pinMode(BUTTON_2, INPUT_PULLUP);
pinMode(BUTTON_3, INPUT_PULLUP);
pinMode(BUTTON_4, INPUT_PULLUP);
// Инициализация на DHT
dht.begin();
// Свързване към Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Уеб интерфейс за управление
server.on("/", handleRoot);
server.on("/toggleRelay1", toggleRelay1);
server.on("/toggleRelay2", toggleRelay2);
server.on("/toggleRelay3", toggleRelay3);
server.on("/toggleRelay4", toggleRelay4);
// Пътища за външно четене на състояния
server.on("/readButtons", readButtons);
server.on("/readAnalog", readAnalog);
server.on("/readRelays", readRelays);
server.on("/readDHT", readDHT); // Четене на данни от DHT
server.begin();
}
void loop() {
// Проверка за натискане на бутоните с дебаунс
checkButton(BUTTON_1, button1Counter, lastButtonPress1, RELAY_1, relay1State);
checkButton(BUTTON_2, button2Counter, lastButtonPress2, RELAY_2, relay2State);
checkButton(BUTTON_3, button3Counter, lastButtonPress3, RELAY_3, relay3State);
checkButton(BUTTON_4, button4Counter, lastButtonPress4, RELAY_4, relay4State);
// Обработка на заявки от уеб сървъра
server.handleClient();
}
// Проверка на бутон с дебаунс логика
void checkButton(int buttonPin, int &counter, unsigned long &lastPress, int relayPin, bool &relayState) {
if (digitalRead(buttonPin) == LOW) {
if (millis() - lastPress > debounceDelay) {
counter++;
if (counter == 2) counter = 0; // Нулиране на брояча след две натискания
lastPress = millis();
relayState = (counter % 2 == 1); // Променяме състоянието на релето според брояча (вкл/изкл)
digitalWrite(relayPin, relayState ? HIGH : LOW); // LOW = изключено, HIGH = включено
}
}
}
// Главна страница с HTML интерфейс за управление на релетата и показване на състоянието на бутоните и аналоговия вход
void handleRoot() {
String html = "<!DOCTYPE html><html><head>";
html += "<style>";
html += "body { font-family: Arial; text-align: center; background-color: #f4f4f4; padding: 20px; }";
html += "table { margin: auto; border-collapse: collapse; width: 80%; }";
html += "table, th, td { border: 1px solid #ccc; padding: 10px; }";
html += "button { padding: 10px 20px; font-size: 16px; border: none; background-color: #007bff; color: white; border-radius: 5px; }";
html += "button:hover { background-color: #0056b3; }";
html += "</style>";
html += "</head><body>";
html += "<h1>ESP8266 Relay & WEB & Button Control + DHT & analogIN</h1>";
// Създаване на таблица с релета, бутони и сензори
html += "<table>";
html += "<tr><th>Component</th><th>Status</th><th>Action</th></tr>";
// Показване на състоянието на релетата
html += "<tr><td>Relay 1</td><td>" + String(relay1State ? "ON" : "OFF") + "</td>";
html += "<td><button id='relay1Btn' onclick=\"location.href='/toggleRelay1'\">Toggle</button></td></tr>";
html += "<tr><td>Relay 2</td><td>" + String(relay2State ? "ON" : "OFF") + "</td>";
html += "<td><button id='relay2Btn' onclick=\"location.href='/toggleRelay2'\">Toggle</button></td></tr>";
html += "<tr><td>Relay 3</td><td>" + String(relay3State ? "ON" : "OFF") + "</td>";
html += "<td><button id='relay3Btn' onclick=\"location.href='/toggleRelay3'\">Toggle</button></td></tr>";
html += "<tr><td>Relay 4</td><td>" + String(relay4State ? "ON" : "OFF") + "</td>";
html += "<td><button id='relay4Btn' onclick=\"location.href='/toggleRelay4'\">Toggle</button></td></tr>";
// Показване на броячите на бутоните
html += "<tr><td>Button 1</td><td>" + String(button1Counter) + "</td><td></td></tr>";
html += "<tr><td>Button 2</td><td>" + String(button2Counter) + "</td><td></td></tr>";
html += "<tr><td>Button 3</td><td>" + String(button3Counter) + "</td><td></td></tr>";
html += "<tr><td>Button 4</td><td>" + String(button4Counter) + "</td><td></td></tr>";
// Четене на аналогов вход
int analogValue = analogRead(ANALOG_IN);
html += "<tr><td>Analog Value</td><td>" + String(analogValue) + "</td><td></td></tr>";
// Показване на температурата и влажността от DHT
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
html += "<tr><td>Temperature</td><td>" + String(temperature) + " ℃</td><td></td></tr>";
html += "<tr><td>Humidity</td><td>" + String(humidity) + " %</td><td></td></tr>";
html += "</table>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Функции за управление на релетата от уеб интерфейса
void toggleRelay1() {
relay1State = !relay1State;
button1Counter = relay1State ? 1 : 0; // Актуализиране на брояча
digitalWrite(RELAY_1, relay1State ? HIGH : LOW);
handleRoot();
}
void toggleRelay2() {
relay2State = !relay2State;
button2Counter = relay2State ? 1 : 0;
digitalWrite(RELAY_2, relay2State ? HIGH : LOW);
handleRoot();
}
void toggleRelay3() {
relay3State = !relay3State;
button3Counter = relay3State ? 1 : 0;
digitalWrite(RELAY_3, relay3State ? HIGH : LOW);
handleRoot();
}
void toggleRelay4() {
relay4State = !relay4State;
button4Counter = relay4State ? 1 : 0;
digitalWrite(RELAY_4, relay4State ? HIGH : LOW);
handleRoot();
}
// Четене на състоянието на бутоните
void readButtons() {
String message = "";
message += "Button 1 Counter: " + String(button1Counter) + "\n";
message += "Button 2 Counter: " + String(button2Counter) + "\n";
message += "Button 3 Counter: " + String(button3Counter) + "\n";
message += "Button 4 Counter: " + String(button4Counter) + "\n";
server.send(200, "text/plain", message);
}
// Четене на аналоговия вход
void readAnalog() {
int analogValue = analogRead(ANALOG_IN);
server.send(200, "text/plain", String(analogValue));
}
// Четене на състоянието на релетата
void readRelays() {
String message = "";
message += "Relay 1: " + String(relay1State ? "ON" : "OFF") + "\n";
message += "Relay 2: " + String(relay2State ? "ON" : "OFF") + "\n";
message += "Relay 3: " + String(relay3State ? "ON" : "OFF") + "\n";
message += "Relay 4: " + String(relay4State ? "ON" : "OFF") + "\n";
server.send(200, "text/plain", message);
}
// Четене на температурата и влажността от DHT
void readDHT() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
String message = "Temperature: " + String(temperature) + " ℃\n";
message += "Humidity: " + String(humidity) + " %\n";
server.send(200, "text/plain", message);
}
WEB визуализация на кода:

Обяснение на кода
Използвани и библиотеки
Първо включваме необходимите библиотеки:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
- ESP8266WiFi.h – Тази библиотека ни дава възможност да свързваме ESP8266 към Wi-Fi мрежа.
- ESP8266WebServer.h – Позволява ни да създадем уеб сървър и да обработваме HTTP заявки.
- DHT.h – Използваме тази библиотека за работа с DHT11 сензора за температура и влажност. Може да свалите тази библиотека от тук.
Пинове и хардуерни настройки
Дефинираме пиновете, към които са свързани релетата, бутоните и сензорите:
#define RELAY_1 D0
#define RELAY_2 D6
#define RELAY_3 D7
#define RELAY_4 D8
#define BUTTON_1 D4
#define BUTTON_2 D3
#define BUTTON_3 D2
#define BUTTON_4 D1
#define ANALOG_IN A0
#define DHTPIN D5
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
- Релета: Те се свързват към пиновете D0, D6, D7 и D8 и ще управляват включването и изключването на устройства.
- Бутони: Четирите бутона са свързани към пиновете D4, D3, D2 и D1 и ще контролират съответните релета.
- Аналогов вход: Аналоговият вход A0 ще чете стойности от аналогов датчик.
- DHT11 сензор: Свързан към D5, ще чете температура и влажност.
Wi-Fi свързване
В следващия блок код свързваме ESP8266 към Wi-Fi мрежата:
const char* ssid = "xxxxxxxx"; // заместете с името на вашата WiFi мрежа
const char* password = "xxxxxxxx"; // заместете с вашата WiFi парола
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
- WiFi.begin() – Започва връзката към мрежата, използвайки SSID и паролата.
- WL_CONNECTED – Докато устройството не се свърже с Wi-Fi мрежата, то продължава да се опитва.
Уеб сървър и HTTP пътища
Създаваме уеб сървър на порт 80 и дефинираме HTTP пътища за различни функционалности:
ESP8266WebServer server(80);
server.on("/", handleRoot);
server.on("/toggleRelay1", toggleRelay1);
server.on("/toggleRelay2", toggleRelay2);
server.on("/toggleRelay3", toggleRelay3);
server.on("/toggleRelay4", toggleRelay4);
server.on("/readButtons", readButtons);
server.on("/readAnalog", readAnalog);
server.on("/readRelays", readRelays);
server.on("/readDHT", readDHT);
server.begin();
- handleRoot() – Главната страница, която показва текущото състояние на релетата, бутоните и сензорите.
- toggleRelay1() до toggleRelay4() – Пътища за включване и изключване на съответните релета.
- readButtons(), readAnalog(), readRelays(), readDHT() – Пътища за четене на състоянията на бутоните, аналоговия вход, релетата и DHT11 сензора.
Физическо управление с бутони
Логиката за работа с бутоните включва дебаунс и поддържа броячи за натискания:
void checkButton(int buttonPin, int &counter, unsigned long &lastPress, int relayPin, bool &relayState) {
if (digitalRead(buttonPin) == LOW) {
if (millis() - lastPress > debounceDelay) {
counter++;
if (counter == 2) counter = 0;
lastPress = millis();
relayState = (counter % 2 == 1);
digitalWrite(relayPin, relayState ? HIGH : LOW);
}
}
}
- Debounce логика: За да се избегнат многократни отчети при еднократно натискане, използваме времева проверка (debouncing).
- Контрол на релетата: С всяко натискане на бутона броячът се увеличава и според стойността му релето се включва или изключва.
Четене на данни от DHT11
Четенето на данни от DHT11 сензора се извършва чрез библиотеката DHT.h:
void readDHT() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
String message = "Temperature: " + String(temperature) + " ℃\n";
message += "Humidity: " + String(humidity) + " %\n";
server.send(200, "text/plain", message);
}
- readTemperature() и readHumidity() – Извикваме тези функции, за да получим стойностите за температура и влажност.
Главната страница на уеб интерфейса
HTML страницата, показвана при посещение на уеб сървъра, дава информация за състоянието на всички компоненти:
void handleRoot() {
String html = "<html><head><title>ESP8266 Control</title></head><body>";
html += "<h1>ESP8266 Relay & Button Control</h1>";
html += "<p>Relay 1: " + String(relay1State ? "ON" : "OFF") + "</p>";
html += "<p>Button 1 Counter: " + String(button1Counter) + "</p>";
html += "<p>Temperature: " + String(dht.readTemperature()) + " ℃</p>";
html += "<p>Humidity: " + String(dht.readHumidity()) + " %</p>";
html += "</body></html>";
server.send(200, "text/html", html);
}
Заключение
Този проект комбинира няколко различни технологии и принципи, за да създаде интегрирана IoT система. В бъдещите ни статии ще предложим начини за разширяване на този проект, добавяйки нови функции и сензори.