Управление реле по UDP: Беспроводное решение с ESP8266, ESP32 и Easy HMI.

Вы уже, наверное, в курсе, что Easy HMI получил поддержку беспроводной связи по UDP. Если нет, то ознакомьтесь с новыми возможностями тут. А так как есть беспроводной интерфейс, неплохо было бы сделать удаленное управление реле. Что, в свою очередь, позволит управлять светом, вытяжкой, вентилятором, чайником, кофемашиной, обогревателем и другими устройствами и приборами. Для реализации данной идеи можно использовать готовые модули на базе ESP32 и/или ESP8266. Я уже рассказывал про модуль ESP12F Relay X4 (LC-Relay-ESP12-4R-MV – по даташиту). Сегодня напишем код для управления данным модулем и также посмотрим, как можно управлять по UDP 2, 3, 5, 10 и даже 12 группами реле с одного сенсорного дисплея. Думаете, это невозможно реализовать? Давайте разберемся!

Создаем интерфейс управления реле по UDP в среде разработки Easy HMI.

Как писал ранее, Easy HMI получил поддержку беспроводной связи по UDP. Об этом рассказывал вот в этой статье. На момент написания данного поста UDP поддерживают только наши дисплеи AT HMI, но в ближайшее время выложу прошивку с поддержкой UDP для дисплеев ESP32-2432S024, ESP32-2432S028, ESP32-2432S032, ESP32-3248S035. Подписывайтесь на группу в ВК, чтобы не пропустить последние новости.

Создаем интерфейс управления реле по UDP в среде разработки Easy HMI.

Процесс создания интерфейса для управления реле по UDP не сильно отличается от создания интерфейса для управления по UART. Но есть одна особенность. Чтобы отследить, получило ли устройство команду от дисплея, сделаем обратную связь. И для этого кнопки управления реле сделаем без фиксации. Зачем это нужно, рассмотрим, когда будем писать код для устройства управления реле, например, для ESP12F Relay X4.

Процесс создания интерфейса для управления реле по UDP.

И главный момент: нужно в программе Easy HMI активировать работу по UDP. Это нужно сделать в разделе Настройки. Все, интерфейс сделан и внесены настройки для беспроводной работы.

И главный момент: нужно в программе Easy HMI активировать работу по UDP.

Краткое описание модуля ESP12F Relay X4.

Перед написанием кода нужно разобраться с модулем ESP12F Relay X4 и определить, к каким пинам подключены реле. На плате есть колодка подключения перемычек для реле и аналоговый вход. Если не припаять перемычки, то реле не будут управляться от ESP8266.

Колодка подключения перемычек для реле и аналоговый вход.

Pin Описание
ADC Аналоговый вход. Диапазон входного напряжения 0 ~ 1В, диапазон значений: 0 ~ 1024
EN Включить пин, подтянут по умолчанию
GPIO16 Используется перемычка RY1 для включения реле 1
GPIO14 Используется перемычка RY2 для включения реле 2
GPIO12 Используется перемычка RY3 для включения реле 3
GPIO13 Используется перемычка RY4 для включения реле 4

Загрузка прошивки в модуль ESP12F Relay X4.

На плате есть колодка подключения программатора.

Колодка подключения программатора.

Pin Описание
5V Питание 5V
TX Подключить к RX программатора
RX Подключить к TX программатора
GPIO0 Подтягивается к GND для программирования
GND Пин для подтяжки GPIO0 к GND
GND Пин подключения к GND программатора

Подключаем любой USB-TTL конвертер, не забываем, что нужно при загрузке подтянуть GPIO0 к GND (установить перемычку). Я буду использовать конвертер на PL2303HX. Подключаем по схеме:

  • TXD <------> RXD
  • RXD <------> TXD
  • +5V <------> +5V
  • GND <------> GND
  • GPIO0 <------> GND

После загрузки нужно убрать перемычку GPIO0 <------> GND и перезагрузить модуль. Подробнее про модуль ESP12F Relay X4 читайте в этой статье.

Подключаем любой USB-TTL конвертер, не забываем, что нужно при загрузке подтянуть GPIO0 к GND

Код для модуля ESP12F Relay X4 (подойдет также для ESP8266, ESP32).

Написал максимально простой код с минимумом массивов и циклов. В текущей версии Easy HMI нельзя менять логин и пароль точки доступа. Я над этим работаю. И, возможно, на момент, когда вы читаете данную статью, эти настройки уже доступны.

/*
Управление реле по UDP: Беспроводное решение с ESP8266, ESP32 и Easy HMI.
https://arduino-tex.ru/news/218/upravlenie-rele-po-udp-besprovodnoe-reshenie-s-esp8266-esp32-i.html
*/
#if defined(ESP8266)
#include <ESP8266WiFi.h>    // Библиотека WiFi для ESP8266
#endif
#if defined(ESP32)
#include "WiFi.h"           // Библиотека WiFi для ESP32
#endif
#include <WiFiUdp.h>        // Библиотека UDP для передачи датаграмм через WiFi
WiFiUDP udp;                // Объект UDP для отправки и приёма сообщений
// --- Настройка UDP ---
const char* ssid = "ATHMI_AP";                // Имя WiFi сети
const char* password = "C3ej7769Kjh";         // Пароль WiFi сети
IPAddress receiverIp(192, 168, 4, 1);          // IP-адрес устройства, которому отправляются команды
const uint16_t receiverPort = 49356;           // Порт, на который слушает получатель
// Можно менять настройки в зависимости от проекта
#define DEBUG 1                                // Включение/выключение отладочных сообщений (1 - включить)
const bool level = 1;                          // Уровень сигнала для реле: 1 - HIGH активность, 0 - LOW активность
const byte relays_num = 4;                     // Количество реле в проекте
byte relays[relays_num] = { 16, 14, 12, 13 };  // Пины к которым подключены реле
bool flag_ON[relays_num] = { false };          // Статус реле: включено или выключено, по умолчанию — выкл.
void setup() {
  if (DEBUG) {
    Serial.begin(115200);                      // Инициализация serial для отладки
    Serial.println("Start program");
  }
  // Инициализация пинов реле как выходов
  for (byte i = 0; i < relays_num; i++) {
    pinMode(relays[i], OUTPUT);
    if (!level)
      digitalWrite(relays[i], HIGH);           // Если уровень LOW активный, то по умолчанию ставим пин в HIGH
  }
  // Подключение к WiFi сети
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(600);
    Serial.println("Connecting to WiFi...");
  }
  Serial.print("Connected to WiFi with IP: ");
  Serial.println(WiFi.localIP());
  // Запуск UDP-сервера на указанный порт
  udp.begin(receiverPort);
}
void loop() {
  // Проверка, есть ли входящий UDP пакет
  if (udp.parsePacket()) {
    char incomingPacket[16];                         // Буфер для получения команды
    int len = udp.read(incomingPacket, 16);          // Чтение данных
    if (len > 0) {
      incomingPacket[len] = '\0';                     // Добавляем нулевой символ для строки
      if (DEBUG)
        Serial.println(incomingPacket);               // Вывод команды для отладки
      // Обработка команд для кнопок А1A (управление реле 1)
      if (strstr(incomingPacket, "BtA1A=1") != NULL) { // Нажата кнопка А1A (вкл. реле 1)
        flag_ON[0] = !flag_ON[0];                      // Инвертировать состояние реле
        SetRelays(1, flag_ON[0]);                      // Установить реле
        delay(160);
        // Обновление цвета кнопки (например, для индикатора)
        if (flag_ON[0])
          SendBtColor(0xA1A, 0xFA8072, 0xFF4500);    // Цвет "включено"
        else
          SendBtColor(0xA1A, 0x32CD32, 0x2E8B57);    // Цвет "выключено"
      }
      if (strstr(incomingPacket, "BtA1D=1") != NULL) { // Отпущена кнопка А1D (выкл. реле 2)
        flag_ON[1] = !flag_ON[1];                      // Инвертировать состояние второго реле
        SetRelays(2, flag_ON[1]);
        delay(160);
        if (flag_ON[1])
          SendBtColor(0xA1D, 0xFA8072, 0xFF4500);
        else
          SendBtColor(0xA1D, 0x32CD32, 0x2E8B57);
      }
      // Аналогично для реле 3 (A20)
      if (strstr(incomingPacket, "BtA20=1") != NULL) {
        flag_ON[2] = !flag_ON[2];
        SetRelays(3, flag_ON[2]);
        delay(160);
        if (flag_ON[2])
          SendBtColor(0xA20, 0xFA8072, 0xFF4500);
        else
          SendBtColor(0xA20, 0x32CD32, 0x2E8B57);
      }
      // Аналогично для реле 4 (A23)
      if (strstr(incomingPacket, "BtA23=1") != NULL) {
        flag_ON[3] = !flag_ON[3];
        SetRelays(4, flag_ON[3]);
        delay(160);
        if (flag_ON[3])
          SendBtColor(0xA23, 0xFA8072, 0xFF4500);
        else
          SendBtColor(0xA23, 0x32CD32, 0x2E8B57);
      }
      // Команда "Включить все" (A14)
      if (strstr(incomingPacket, "BtA14=1") != NULL) {
        // Меняем цвет всех кнопок на "включено"
        SendBtColor(0xA1A, 0xFA8072, 0xFF4500);
        SendBtColor(0xA1D, 0xFA8072, 0xFF4500);
        SendBtColor(0xA20, 0xFA8072, 0xFF4500);
        SendBtColor(0xA23, 0xFA8072, 0xFF4500);
        // Включаем все реле
        for (byte i = 1; i <= relays_num; i++) {
          SetRelays(i, 1);
          flag_ON[i - 1] = true;
        }
      }
      // Команда "Выключить все" (A17)
      if (strstr(incomingPacket, "BtA17=1") != NULL) {
        // Меняем цвет всех кнопок на "выключено"
        SendBtColor(0xA1A, 0x32CD32, 0x2E8B57);
        SendBtColor(0xA1D, 0x32CD32, 0x2E8B57);
        SendBtColor(0xA20, 0x32CD32, 0x2E8B57);
        SendBtColor(0xA23, 0x32CD32, 0x2E8B57);
        // Выключаем все реле
        for (byte i = 1; i <= relays_num; i++) {
          SetRelays(i, 0);
          flag_ON[i - 1] = false;
        }
      }
    }
  }
}
// Функция для управления состоянием реле по номеру (1-4) и состоянию (true/false)
void SetRelays(uint8_t num_relay, bool flag_relay) {
  // В зависимости от уровня (HIGH или LOW активность) выставляем состояние пина
  digitalWrite(relays[num_relay - 1], level == 0 ? !flag_relay : flag_relay);
}
// --== Функции для отправки цвета на дисплей или кнопку ==---//
// Эта функция отправляет UDP-пакет с командами для подсветки кнопки
// num_element - ID элемента (например, кнопки), data_color и data_color2 - цвета в формате 0xRRGGBB
void SendBtColor(uint16_t num_element, uint32_t data_color, uint32_t data_color2) {
  // Проверяем подключение WiFi
  if (WiFi.status() != WL_CONNECTED) {
    return;  // Выходим, если нет соединения
  }
  char buffer_local[46];  // Буфер для формирования команды
  // Формат строки: bt.{ID}.col={цвет1};{цвет2}
  snprintf(buffer_local, sizeof(buffer_local), "bt.%X.col=%08lX;%08lX", num_element, data_color, data_color2);
  // Отправляем UDP-пакет
  udp.beginPacket(receiverIp, receiverPort);
  udp.print(buffer_local);
  udp.endPacket();  // Завершаем отправку
}

Пояснения кода:

  • #include: ESP8266WiFi.h или WiFi.h нужны для работы с Wi-Fi, а WiFiUdp.h — для общения по сети UDP.
  • const char* ssid = "ATHMI_AP";: ssid — это имя точки доступа Wi-Fi сети.
  • const char* password = "C3ej7769Kjh";: password — пароль от точки доступа Wi-Fi сети.
  • IPAddress receiverIp(192, 168, 4, 1);: Это IP-адрес устройства, которому ESP будет отправлять ответы (например, цвет кнопки изменился).
  • const uint16_t receiverPort = 49356;: Порт — это как номер квартиры в доме (IP-адрес). ESP будет "слушать" команды, приходящие на этот порт, и отправлять ответы на этот же порт удаленного устройства.
  • #define DEBUG 1;: Если стоит 1, то в "Монитор порта" в Arduino IDE будут выводиться сообщения о том, что делает программа. Это помогает найти ошибки. Если поставить 0, сообщения выводиться не будут.
  • const bool level = 1;: Реле бывают разные. Одни включаются, когда на них подают высокий сигнал (HIGH), другие — когда низкий (LOW). Эта настройка говорит, какой тип реле у вас. 1 — для реле высокого уровня.
  • byte relays[] = { 16, 14, 12, 13 };: Это номера "ножек" (пинов) на ESP, к которым вы подключили реле. Например, 16 — это пин D0 на NodeMCU (ESP8266).
  • bool flag_ON[] = { false };: Это "флажки", которые запоминают, включено реле (true) или выключено (false).
  • void setup() { ... };: Этот код выполняется один раз, когда ESP включается. Здесь он настраивает пины реле, подключается к Wi-Fi и начинает слушать UDP-команды.
  • void loop() { ... };: Этот код работает в бесконечном цикле после setup(). Он постоянно проверяет, не пришла ли новая команда по UDP. Если пришла, он ее обрабатывает.
  • if (strstr(incomingPacket, "BtA1A=1") != NULL);: Программа ищет в полученной команде (incomingPacket) определенный текст, например, "BtA1A=1". Если находит, значит, нужно выполнить действие для кнопки с ID A1A (например, включить/выключить первое реле).
  • SetRelays(1, flag_ON[0]);: Эта строчка вызывает специальную функцию SetRelays, чтобы изменить состояние реле. 1 — это номер реле, flag_ON[0] — его новое состояние (включить или выключить).
  • SendBtColor(0xA1A, 0xFA8072, 0xFF4500);: Эта функция отправляет команду на ваше управляющее устройство (HMI), чтобы оно изменило цвет кнопки с ID кнопки 0xA1A. (0xFA8072 — цвет 1 и 0xFF4500 — цвет 2) — это коды цветов.
  • digitalWrite(relays[num_relay - 1], ...);: Это команда, которая физически подает или снимает напряжение с пина реле, заставляя его щелкнуть (включиться или выключиться).

Отличие от работы по UART заключается в отправке ведомым устройством кода на смену цвета кнопки при нажатии кнопки SendBtColor(0xA1A, 0xFA8072, 0xFF4500). (Вот почему мы сделали кнопки интерфейса без фиксации: меняем цвет командой от подчиненного устройства). В коде есть массив флагов flag_ON[], который хранит, в каком состоянии сейчас конкретное реле. Контроль за реле и цветом кнопки происходит на подчиненном устройстве, а не на дисплее. Что гарантирует, что устройство и состояние кнопки 100% соответствуют. И если вдруг подчиненное устройство недоступно, то на дисплее не будет происходить изменение состояния кнопки при нажатии. Это гарантированная защита для безопасной работы по беспроводной сети. Также можно добавить функцию автоподключения к Wi-Fi, если вдруг соединение оборвалось. Но это опционально и необходимо только в некоторых случаях.

Управление несколькими независимыми устройствами по UDP.

Управлять можно не только одним устройством и одной группой подключенных реле к одному устройству. На данный момент дисплей поддерживает работу максимум с 6 подчиненными устройствами. И к каждому устройству можно подключить несколько групп реле. Написал оптимальный код и вынес все настройки в начало кода. Код ниже настроен для работы с модулем ESP12F Relay X4.

Управление несколькими независимыми устройствами по UDP.

#define DEBUG 1  // Отладка: 1 - вкл.  0 - выкл.
const bool level = 1;                                             // 1 - реле высокого уровня 0 - реле низкого уровня
const byte relays_num = 4;                                        // Количество реле
byte relays[relays_num] = { 16, 14, 12, 13 };                     // Пины подключения реле
uint16_t button_id[relays_num] = { 0xA1A, 0xA1D, 0xA20, 0xA23 };  // Адрес кнопок для реле
uint16_t button_on_off[2] = { 0xA14, 0xA17 };                     // Адрес кнопок: вкл. все, выкл. все реле
bool flag_ON[relays_num] = { false };                             //сотоянеие реле по умолчанию выкл.

И если вы используете мой пример интерфейса для дисплея, тут менять ничего не нужно. Достаточно загрузить его в плату. В коде можно изменить необходимые параметры или оставить без изменений:

  • DEBUG – Отвечает за вывод в монитор порта отладочной информации. 1 - вкл., 0 - выкл.
  • level – отвечает за тип подключенного реле для группы 1. 1 - реле высокого уровня, 0 - реле низкого уровня.
  • relays_num – Количество подключенных реле в группе 1. Максимум 16.
  • relays[relays_num] – массив пинов ESP32, к которым подключены реле группы 1.
  • button_id[relays_num] – массив ID кнопок управления реле группы 1. Менять не нужно, если используете мой интерфейс.
  • button_on_off[2] - Массив ID кнопок: button_on_off[0] (0xA14) - вкл. все, button_on_off[1] (0xA17) - выкл. все реле для группы 1.
  • bool flag_ON[] = { false }; – Это "флажки", которые запоминают, включено реле (true) или выключено (false). Менять не нужно!

Данный код бесплатно можно скачать в группе для владельцев ATHMI дисплеев или по подписке на Boosty.

Управление вторым устройством с дисплея.

Давайте в интерфейс дисплея добавим вторую страницу с 8 кнопками. Учитывая особенность работы по беспроводной сети, нужно, чтобы кнопки были без фиксации. Получим вот такие 2 страницы интерфейса для дисплея.

Управление вторым устройством с дисплея.

Подключим 8 реле к ESP32 (можно также использовать и ESP8266).

Изменим шапку кода под управление 8 реле и изменим ID кнопок. Получим такой результат.

Подключим 8 реле к ESP32 (можно также использовать и ESP8266).

 const bool level = 0;                                             // 1 - реле высокого уровня 0 - реле низкого уровня
const byte relays_num = 8;                                        // Количество реле
byte relays[relays_num] = { 15, 2, 4, 5, 18, 19, 21, 22 };                     // Пины подключения реле
uint16_t button_id[relays_num] = { 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112 };  // Адрес кнопок для реле
uint16_t button_on_off[2] = { 0x114, 0x117 };                     // Адрес кнопок: вкл. все, выкл. все реле
bool flag_ON[relays_num] = { false };                             //сотоянеие реле по умолчанию выкл.

Данный код бесплатно можно скачать в группе для владельцев ATHMI дисплеев или по подписке на Boosty.

Загружаем код в ESP32 и проверяем, как все работает. Также можно добавить еще одну группу реле, как в примере управления реле по UART.

Загружаем код в ESP32 и проверяем, как все работает. Также можно добавить еще одну группу реле, как в примере управления реле по UART. А на дисплее сделать 3 страницу и управлять 3 группой реле.

Загружаем код в ESP32 и проверяем, как все работает. Также можно добавить еще одну группу реле, как в примере управления реле по UART.

Таким образом можно организовать управление 6 ведомыми устройствами. А так как у нас к одному устройству можно подключить не одну группу, то получается, что можно организовать до 6-12 независимых групп реле. Интерфейс дисплея также позволяет создать до 6 страниц. А если взять дисплей большего размера, то можно вывести большее количество кнопок для управления и организовать работу с 2-3 группами реле на одной странице. Выводы о количестве групп, которыми можно управлять, используя ПО Easy HMI по UDP, делайте сами.

Плюсы и минусы:

UDP позволяет управлять группами реле, расположенных в разных местах, не прокладывая дополнительные провода. А обратная связь позволяет точно определить, какое реле сработало и подключено ли устройство к дисплею. Что гарантирует стабильную и качественную работу.

Но тут есть и ложка дегтя, которая связана как раз с беспроводным способом передачи по UDP. UDP действует по принципу "отправил и забыл" и не заботится о том, доставлен ли пакет или нет. Как раз тут могут возникать ситуации, когда данные не получит подчиненное устройство или ответ от подчиненного устройства не дойдет на дисплей. Но это крайне маловероятно, если соблюдать несколько условий:

  • Располагать устройства в радиусе стабильной связи.
  • Обеспечить хорошее электропитание для устройств.
  • При необходимости использовать устройства с внешней антенной.

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

Запланированное расширение функционала.

  1. Я уже добавил возможность передавать от подчиненного устройства другим подчиненным устройствам булеву или целочисленную переменную. Что позволит создавать взаимосвязанную систему. Например, 1 устройство измеряет температуру и влажность, отправляя показания на дисплей. При достижении заданного значения температуры или влажности, устройство понимает, что данные превышены, и отправляет флаг для пересылки другому устройству. Устройство, к которому подключено реле, получает данный флаг и открывает вытяжку, отправляя на дисплей информацию, что вытяжка включена.
  2. Полным ходом идет процесс внедрения своего псевдоязыка программирования, что позволит не только использовать свободные пины дисплея, но и задавать различные сценарии взаимодействия элементов интерфейса. Например, применительно к текущему проекту: не нужно будет отправлять цвет кнопки, достаточно отправить булеву переменную. И дисплей сменит цвет кнопки по заранее созданному сценарию.

Заключение.

Несмотря на то, что данное решение неприменимо там, где требуется 100% стабильность работы, но для использования в домашней автоматизации и других проектах, управление устройствами по UDP имеет большие перспективы на дальнейшее развитие и внедрение в проекты для личного использования и мелкосерийного производства.


По все вопросам вы можете написать мне в соц. сетях:

Понравился проект Управление реле по UDP: Беспроводное решение с ESP8266, ESP32 и Easy HMI? Не забудь поделиться с друзьями в соц. сетях.

А также подписаться на наш канал на YouTube, вступить в группу Вконтакте, в Telegram.

Спасибо за внимание!

Технологии начинаются с простого!

Фотографии к статье

Файлы для скачивания

Код для модуля ESP12F Relay X4 (подойдет также для ESP8266, ESP32) Код для модуля ESP12F Relay X4 (подойдет также для ESP8266, ESP32).ino8 Kb 18 Скачать
Интерфейс управления реле в Easy HMI Интерфейс управления реле в Easy HMI.zip25 Kb 5 Скачать

Комментарии

Ваше Имя*


Разработка проектов