ESP8266 как multicast транслятор в MQTT

Продолжая тему управления Xiaomi Gateway. Решение на Node-Red с двумя UDP нодами, оказалось не совсем рабочим: через какое-то время Node-Red перестает получать сообщения со слушающей ноды, при этом продолжая успешно их отправлять с другой. Вполне возможно, что две ноды, висящих на одном порту – это все таки не совсем правильно, а поэтому пришлось думать как этого избежать. А заодно попробовать и решить остальные мои To-Do.

Напомню завязку проблемы: шлюз Xiaomi находится в другом сегменте сети относительно основного сервера управления умным домом. В связи с этим невозможно получить рассылаемые шлюзом сообщения о текущем сессионном токене.

Варианты в голову приходили самые разные, включая установку еще одного НА на другую малину и размещение ее в сети смарт устройств. Но все таки я его отмел, как не самое рациональное. Но потом вспомнил, что у меня валяются несколько модулей esp8266, которые вполне можно задействовать. Все таки цена вопроса по сравнению с малиной отличается в разы, а мощностей под мою задачу esp8266 вполне достаточно.

А задачу для себя я сформулировал так: получать все мультикаст сообщения от шлюза и отправлять их в MQTT-брокер. А уж что с ними делать дальше – тут вопросов не возникает.

Сказано – сделано. До этого я использовал только ESPEasy, поэтому первым делом полез искать нет ли у них подходящих плагинов под мою задачу. Но либо плохо искал, либо хорошо спрятали, либо просто действительно нет, но ничего подходящего не нашел. Ок, хочешь сделать что-то хорошо да хоть как-нибудь – сделай это сам. Поэтому через несколько часов изыскания и попыток вспомнить как же писать на С++, родился следующий код:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>


const char* ssid = ""; // Enter your WiFi name
const char* password =  ""; // Enter WiFi password
const char* mqttServer = ""; // Enter MQTT Broker name or IP
const int mqttPort = 1883;
const char* mqttUser = ""; // Enter MQTT User
const char* mqttPassword = ""; // Enter MQTT Password

unsigned int multicast_port = 9898;
IPAddress multicast_ip_addr=IPAddress(224, 0, 0, 50);
char incomingPacket[255];

WiFiUDP Udp;
WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
    Serial.begin(115200);
    Serial.println();
    Serial.printf("Connecting to %s ", ssid);
    WiFi.hostname("ESP-MQTT-Translator");
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }

    Serial.println("Connected to the WiFi network");

    Udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, multicast_port);
    Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), multicast_port);

    client.setServer(mqttServer, mqttPort);

    while (!client.connected()) {
        Serial.print("Connecting to MQTT...");
 
        if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
            Serial.println("connected");  
        } else {
            Serial.print("failed with state ");
            Serial.print(client.state());
            delay(2000);
        }
    }
}

void loop() {
    int packetSize = Udp.parsePacket();
    if (packetSize) {
        Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
        int len = Udp.read(incomingPacket, 255);
        if (len > 0) {
            incomingPacket[len] = 0;
        }

        char jsonPacket[255];
        strcpy(jsonPacket, incomingPacket);

        const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
        DynamicJsonDocument doc(capacity);
        deserializeJson(doc, jsonPacket);

        char topic[30] = "esp/";
        strcat (topic, doc["sid"].as<char*>());

        Serial.printf("UDP packet contents: %s\n", incomingPacket);
        client.publish(topic, incomingPacket);
    }

    if(WiFi.status() != WL_CONNECTED) {
      setup();
    }    

    client.loop();
}

(Актуальный код всегда можно так же найти на GitHub)

Записываем значение параметров для подключения к Wi-Fi и для MQTT-брокера, заливаем его на esp через Arduino IDE и все. Теперь esp начнет слушать мультикаст сообщения от шлюза и отправлять их в MQTT в топик esp/SID_ШЛЮЗА

Для отладки получаемая информация так же пишется в консоль, и ее можно посмотреть через Arduino IDE

Ну а как модифицировать Node-Red флоу, для работы с этой информацией – напишу с следующей публикации.

Один ответ к «ESP8266 как multicast транслятор в MQTT»

Добавить комментарий

Ваш адрес email не будет опубликован.