Смарт релета с ESP8266, MQTT и Web интерфейс

ESP8266 управление на двe релета чрез MQTT, уеб интерфейс и OTA ъпдейт

Въведение

ESP8266-01 е един от най-популярните Wi-Fi микроконтролери за „умни“ проекти. С негова помощ можем лесно да изградим домашна автоматизация, която да се управлява както локално през уеб интерфейс, така и дистанционно чрез MQTT сървър.
В тази статия ще разгледаме проект за двурелеен контролер с ESP8266-01, който поддържа:

  • управление през MQTT брокер (например Mosquitto). За да разберете как да направите собствен MQTT сървър може да прочетете статията ни: Инсталиране на Mosquitto MQTT Broker на Raspberry Pi 4
  • Вграден уеб интерфейс за директен контрол. За целта използваме платформата от пректа ни: ESP8266-01 двуканален WEB релеен борд
  • fallback Access Point (AP) режим при липса на Wi-Fi връзка,
  • възможност за OTA обновяване (Over-The-Air).

Проектът е подходящ за домашна автоматизация – например за управление на осветление, вентилатори или други уреди до 220V чрез реле.


Схематично решение на борда ESP8266-01 MQTT

Проектът използва ESP8266-01 (NodeMCU или Wemos D1 mini) и два релета. Релетата са свързани към GPIO0 и GPIO2 на микроконтролера. При подаване на команда, пиновете се активират логически HIGH и релеят включва товара.

Основна схема:

  • GPIO0 → Relay 1
  • GPIO2 → Relay 2
  • VCC (5V или 3.3V според модула) → Реле борд
  • GND → обща маса

⚠️ Внимание: При работа с 220V мрежа използвайте подходящи модули и изолация за безопасност.


Код на проекта ESP8266-01 и MQTT за управление на две релета

По-долу е целият код, който трябва да качите на ESP8266 чрез Arduino IDE.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <DNSServer.h>

// ================= Променливи за всеки борд ===============

const char* WiFi_ssid = "XXXXXXXX";   // Името на WiFi мрежата
const char* WiFi_password = "XXXXXXXX";  // Паролата на WiFi мрежата

const char* WiFi_ap_ssid = "ESP8266_Two_Relay_AP_3"; //AP WiFi-SSID
const char* WiFi_ap_pass = "12345678"; //AP WiFi-PASS

const char* MQTT_clientID = "esp8266_Two_Relay_Board_3"; // MQTT MQTT/ID
const char* MQTT_topicRelay1 = "board_3/relay_1"; // MQTT Topic Board/Relay
const char* MQTT_topicRelay2 = "board_3/relay_2"; // MQTT Topic Board/Relay

const char* OTA_setHostname("ESP8266_TwoRelay_board-3 "); // OTA name
const char* OTA_setPassword("XXXXXXXX"); // OTA password

// ======================= WiFi настройки =======================
const char* ssid     = WiFi_ssid;
const char* password = WiFi_password;

// AP fallback настройки
const char* ap_ssid = WiFi_ap_ssid;
const char* ap_pass = WiFi_ap_pass;

// ======================= MQTT настройки =======================
const char* mqtt_server = "ххх.ххх.ххх.ххх";  // IP на MQTT сървъра
const char* mqtt_user   = "ххххххххх";  // user за оторизация на MQTT
const char* mqtt_pass   = "ххххххххх";  // pass за оторизация на  MQTT
const char* clientID    = MQTT_clientID;

const char* topicRelay1 = MQTT_topicRelay1;
const char* topicRelay2 = MQTT_topicRelay2;

// ======================= Пинове =======================
#define RELAY1 0  // GPIO0
#define RELAY2 2  // GPIO2

// Логика на релетата (активно HIGH)
#define RELAY_ON  HIGH
#define RELAY_OFF LOW

// ======================= Обекти =======================
WiFiClient espClient;
PubSubClient client(espClient);
ESP8266WebServer server(80);
DNSServer dnsServer;

// ======================= Променливи =======================
bool relay1State = false;
bool relay2State = false;
bool wifiConnected = false;
const byte DNS_PORT = 53;

// ======================= MQTT Callback =======================
void callback(char* topic, byte* payload, unsigned int length) {
  String msg;
  for (unsigned int i = 0; i < length; i++) {
    msg += (char)payload[i];
  }
  msg.trim();

  if (String(topic) == topicRelay1) {
    if (msg == "ON") {
      digitalWrite(RELAY1, RELAY_ON);
      relay1State = true;
    } else if (msg == "OFF") {
      digitalWrite(RELAY1, RELAY_OFF);
      relay1State = false;
    }
  }

  if (String(topic) == topicRelay2) {
    if (msg == "ON") {
      digitalWrite(RELAY2, RELAY_ON);
      relay2State = true;
    } else if (msg == "OFF") {
      digitalWrite(RELAY2, RELAY_OFF);
      relay2State = false;
    }
  }
}

// ======================= WiFi свързване =======================
void setup_wifi() {
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid, password);

  unsigned long startAttemptTime = millis();

  // чакаме до 10 секунди
  while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 10000) {
    delay(500);
  }

  if (WiFi.status() == WL_CONNECTED) {
    wifiConnected = true;
  } else {
    // fallback AP + captive portal
    WiFi.softAP(ap_ssid, ap_pass);
    dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
    wifiConnected = false;
  }
}

// ======================= MQTT свързване =======================
void reconnect() {
  while (wifiConnected && !client.connected()) {
    if (client.connect(clientID, mqtt_user, mqtt_pass)) {
      client.subscribe(topicRelay1);
      client.subscribe(topicRelay2);
    } else {
      delay(5000);
    }
  }
}

// ======================= Web интерфейс =======================
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<title>ESP8266 Two Relay</title>";
  html += "<style>body{font-family:Arial;text-align:center;margin-top:50px;}";
  html += "button{padding:15px 30px;margin:10px;font-size:18px;border:none;";
  html += "border-radius:8px;cursor:pointer;}";
  html += ".on{background:#4CAF50;color:white;}";
  html += ".off{background:#f44336;color:white;}</style></head><body>";
  html += "<h1>ESP8266 Relay Control</h1>";
  html += "<p>Relay 1: ";
  html += relay1State ? "ON" : "OFF";
  html += "</p>";
  html += "<a href='/relay1/on'><button class='on'>Relay 1 ON</button></a>";
  html += "<a href='/relay1/off'><button class='off'>Relay 1 OFF</button></a><br>";
  html += "<p>Relay 2: ";
  html += relay2State ? "ON" : "OFF";
  html += "</p>";
  html += "<a href='/relay2/on'><button class='on'>Relay 2 ON</button></a>";
  html += "<a href='/relay2/off'><button class='off'>Relay 2 OFF</button></a>";
  html += "</body></html>";

  server.send(200, "text/html", html);
}

void handleRelay1On()  { digitalWrite(RELAY1, RELAY_ON);  relay1State = true;  if (wifiConnected) client.publish(topicRelay1, "ON");  handleRoot(); }
void handleRelay1Off() { digitalWrite(RELAY1, RELAY_OFF); relay1State = false; if (wifiConnected) client.publish(topicRelay1, "OFF"); handleRoot(); }
void handleRelay2On()  { digitalWrite(RELAY2, RELAY_ON);  relay2State = true;  if (wifiConnected) client.publish(topicRelay2, "ON");  handleRoot(); }
void handleRelay2Off() { digitalWrite(RELAY2, RELAY_OFF); relay2State = false; if (wifiConnected) client.publish(topicRelay2, "OFF"); handleRoot(); }

// ======================= Setup =======================
void setup() {
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);

  // При старт изключваме релетата
  digitalWrite(RELAY1, RELAY_OFF);
  digitalWrite(RELAY2, RELAY_OFF);
  relay1State = false;
  relay2State = false;

  setup_wifi();

  if (wifiConnected) {
    client.setServer(mqtt_server, 1883);
    client.setCallback(callback);
  }

  server.on("/", handleRoot);
  server.on("/relay1/on", handleRelay1On);
  server.on("/relay1/off", handleRelay1Off);
  server.on("/relay2/on", handleRelay2On);
  server.on("/relay2/off", handleRelay2Off);
  server.begin();

  // OTA настройки (работи само при WiFi STA връзка)
  if (wifiConnected) {
    ArduinoOTA.setHostname(OTA_setHostname);
    ArduinoOTA.setPassword(OTA_setPassword);
    ArduinoOTA.begin();
  }
}

// ======================= Loop =======================
void loop() {
  if (wifiConnected) {
    if (!client.connected()) {
      reconnect();
    }
    client.loop();
    ArduinoOTA.handle();
  } else {
    dnsServer.processNextRequest(); // captive portal DNS
  }
  server.handleClient();
}

Обяснение на кода

1. Импорт на библиотеки

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <DNSServer.h>
  • ESP8266WiFi.h – управление на Wi-Fi връзката.
  • PubSubClient.hMQTT клиент.
  • ESP8266WebServer.h – мини HTTP сървър за уеб интерфейса.
  • ESP8266mDNS.hmDNS поддръжка (локално име на устройството).
  • ArduinoOTA.hOTA обновяване.
  • DNSServer.hDNS за captive portal (при fallback AP).

2. Настройки за Wi-Fi и MQTT

const char* WiFi_ssid = "хххххххх";
const char* WiFi_password = "хххххххх";

const char* mqtt_server = "ххх.ххх.ххх.ххх";
const char* mqtt_user   = "хххххххх";
const char* mqtt_pass   = "хххххххх";
  • Устройството първо се опитва да се свърже към зададената Wi-Fi мрежа.
  • Ако не успее, преминава в Access Point режим с SSID ESP8266_Two_Relay_AP_3.
  • MQTT клиентът използва конкретен сървър, потребител и парола.

3. Пинове и логика

#define RELAY1 0  // GPIO0
#define RELAY2 2  // GPIO2

#define RELAY_ON  HIGH
#define RELAY_OFF LOW
  • Определят се пиновете за релетата и логиката им (тук – активно HIGH).

4. MQTT Callback

void callback(char* topic, byte* payload, unsigned int length) {
  // Проверява входящите съобщения
}
  • При получаване на съобщение по topic (board_3/relay_1 или board_3/relay_2), се включва или изключва съответното реле.
  • Поддържаните команди са: ON и OFF.

5. Wi-Fi свързване

void setup_wifi() {
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid, password);
  ...
}
  • Опит за свързване към домашната мрежа.
  • Ако не успее до 10 секунди → активира се AP режим.

6. MQTT свързване

void reconnect() {
  while (wifiConnected && !client.connected()) {
    if (client.connect(clientID, mqtt_user, mqtt_pass)) {
      client.subscribe(topicRelay1);
      client.subscribe(topicRelay2);
    }
  }
}
  • Автоматично възстановяване на връзката към брокера.
  • Абониране за топиците на релетата.

7. Уеб интерфейс

void handleRoot() {
  String html = "..."; // HTML с бутони за релета
  server.send(200, "text/html", html);
}
  • Устройството предоставя уеб страница с бутони за включване/изключване на двете релета.
  • При промяна, състоянието се отразява и в MQTT топика.

8. OTA обновяване

ArduinoOTA.setHostname(OTA_setHostname);
ArduinoOTA.setPassword(OTA_setPassword);
ArduinoOTA.begin();
  • Позволява ъпдейт на фърмуера през Wi-Fi, без нужда от кабелно качване.

MQTT топици и команди

Устройството използва два топика:

  • board_3/relay_1
  • board_3/relay_2

Команди:

  • ON → включва съответното реле.
  • OFF → изключва съответното реле.

Пример:

mosquitto_pub -h ххх.ххх.ххх.ххх -u хххххххх-P хххххххх -t board_3/relay_1 -m "ON"

Настройка на MQTT панел

Можете да използвате приложение като MQTT Dash (Android) или Node-RED Dashboard, за да управлявате релетата.

  • Добавете два бутона – по един за всеки топик.
  • Задайте стойности ON и OFF.
  • Така получавате удобен мобилен интерфейс за контрол.

Обобщение

С помощта на ESP8266 и два релета създадохме универсален модул за домашна автоматизация. Той може да се управлява през:

  • уеб браузър (вграден интерфейс),
  • MQTT брокер (удобно за интеграция в Home Assistant, Node-RED и др.),
  • OTA обновяване за лесна поддръжка.

Клип на аналогичен проект може да видите тук.


Заключение

Проектът показва как ESP8266 може да обедини няколко ключови технологии – Wi-Fi, MQTT, уеб интерфейс и OTA – в един практичен контролер. С малки промени кодът може да се адаптира за повече релета или различни приложения.

Translate »