#include "mqtt_link.h" #include #include #include #include "config.h" #include "devices.h" #include "time_sync.h" static WiFiClient wifiClient; static PubSubClient mqttClient(wifiClient); // devices/{device_id}/commands -> device_id, или "" если топик не подходит. static String deviceIdFromCommandTopic(const String& topic) { if (!topic.startsWith("devices/") || !topic.endsWith("/commands")) { return ""; } return topic.substring(8, topic.length() - 9); // strip "devices/" and "/commands" } void mqttPublishAck(const String& deviceId, JsonDocument& state) { JsonDocument ackDoc; ackDoc["state"] = state.as(); char buf[256]; size_t len = serializeJson(ackDoc, buf, sizeof(buf)); String topic = "devices/" + deviceId + "/ack"; mqttClient.publish(topic.c_str(), (const uint8_t*)buf, len, false); } static void onMessage(char* topic, byte* payload, unsigned int length) { String deviceId = deviceIdFromCommandTopic(String(topic)); if (deviceId.isEmpty()) { return; } JsonDocument cmd; DeserializationError err = deserializeJson(cmd, payload, length); if (err) { Serial.print("[mqtt] invalid command payload on "); Serial.println(topic); return; } String action = cmd["action"] | ""; double level = cmd["level"] | 0.0; if (action.isEmpty()) { Serial.print("[mqtt] command missing action on "); Serial.println(topic); return; } JsonDocument state; if (devicesApplyCommand(deviceId, action, level, state)) { mqttPublishAck(deviceId, state); } } void mqttBegin() { mqttClient.setServer(MQTT_BROKER_HOST, MQTT_BROKER_PORT); mqttClient.setCallback(onMessage); } void mqttEnsureConnected() { if (mqttClient.connected()) { return; } Serial.print("[mqtt] connecting to "); Serial.print(MQTT_BROKER_HOST); if (mqttClient.connect(MQTT_CLIENT_ID)) { Serial.println(" connected"); mqttClient.subscribe("devices/+/commands", 1); } else { Serial.print(" failed, rc="); Serial.println(mqttClient.state()); } } void mqttLoop() { mqttClient.loop(); } void mqttPublishTelemetry(const String& deviceId, const String& sensorType, double value) { JsonDocument doc; doc["device_id"] = deviceId; doc["zone_id"] = ZONE_ID; doc["sensor_type"] = sensorType; doc["value"] = value; doc["timestamp"] = nowRFC3339(); char buf[256]; size_t len = serializeJson(doc, buf, sizeof(buf)); String topic = "devices/" + deviceId + "/telemetry"; mqttClient.publish(topic.c_str(), (const uint8_t*)buf, len, false); }