Проект с ESP8266 D1 Mini: Контрол на четири релета чрез бутони и WEB интерфейс и изчитане на сензори

Проект с ESP8266 D1 Mini Контрол на четири релета чрез бутони и WEB интерфейс и изчитане на сензори

В тази статия ще комбинираме всички научени умения от предишните ни проекти и ще ги приложим в създаването на пълноценен проект с ESP8266 D1 Mini. Ще изградим система за контрол на релета, управление чрез физически бутони и уеб интерфейс, както и четене на данни от сензори като DHT11 за температура и влажност. Също така а ще четем стойности от аналогов вход. Този проект ще послужи като основа за по-сложни IoT решения, които ще предложим в бъдещи статии.

Предишни статий които ще използваме за основа на този проект:

Основната концепция на проекта

Проектът се състои от следните основни компоненти:

  1. Контрол на релета – ще управляваме четири релета, които могат да включват и изключват електрически устройства.
  2. Физически бутони – четири бутона ще бъдат използвани за управление на релетата. Те ще работят с дебаунс логика, за да предотвратим неправилни отчети при бързо натискане.
  3. Уеб интерфейс – ще създадем уеб сървър, чрез който ще можем да контролираме релетата дистанционно, да четем стойностите на бутоните и аналоговия вход, както и данни за температурата и влажността от сензора DHT11.
  4. DHT11 сензор – ще четем данни за температурата и влажността от този сензор, което ще ни даде възможност да следим околната среда. Може да свалите библиотеката от тук.

DHT11 диаграма на пиновете (pinout)

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 визуализация на кода:

Проект с ESP8266 D1 Mini Контрол на четири релета чрез бутони и 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 система. В бъдещите ни статии ще предложим начини за разширяване на този проект, добавяйки нови функции и сензори.