TKK_E32230469/firmware_iot_esp12f/mqtt.h

213 lines
6.5 KiB
C

#ifndef MQTT_H
#define MQTT_H
#include <PubSubClient.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
// Topics
const char* mqtt_topic_state = "ups/dev15/state";
const char* mqtt_topic_cmd = "ups/dev15/cmd";
WiFiClient espClient;
PubSubClient mqttClient(espClient);
unsigned long lastMqttReconnectAttempt = 0;
unsigned long lastMqttPublish = 0;
const unsigned long mqttPublishInterval = 2000; // Publish state every 2 seconds
// Forward declaration
void mqttPublishState();
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
messageTemp += (char)payload[i];
}
Serial.println();
// Parse command
if (String(topic) == mqtt_topic_cmd) {
DynamicJsonDocument doc(256);
DeserializationError error = deserializeJson(doc, payload, length);
if (!error) {
String cmd = doc["cmd"].as<String>();
String v = doc["val"].as<String>();
bool updated = false;
if (cmd == "on") {
bool tgtState = v != "0";
if (tgtState != powerOutputActive) {
// This function is defined in upsSvr.h / main logic
// Note: mqtt.h is included after or before? Need to ensure it can call setOutputPowerState
// Actually, setOutputPowerState is declared in upsCfg.h maybe?
// If compilation fails, we can just set the flag. Wait, let's use the function since it's global.
setOutputPowerState(tgtState);
updated = true;
}
} else if (cmd == "auto") {
uint8_t tmpAutoOnMode = v.toInt();
if ((tmpAutoOnMode != cfgAutoOn) && (tmpAutoOnMode <= 2)) {
cfgAutoOn = tmpAutoOnMode;
configChanged = true;
updated = true;
}
} else if (cmd == "shutdown") {
uint16_t tSec = v.toInt();
if (tSec > 999) tSec = 999;
uint32_t nanoT = ((uint32_t)tSec) * 1000000UL;
if (nanoT < 999999) nanoT = 999999;
bool ok = setPersistentShutdown(nanoT);
if (cfgShutdownInSeconds != tSec && ok) {
cfgShutdownInSeconds = tSec;
configChanged = true;
updated = true;
}
} else if (cmd == "shutlv") {
int16_t lv = v.toInt();
if (lv >= 0 && lv <= 5) {
if (lv != cfgShutdownSuggestion) {
cfgShutdownSuggestion = lv;
configChanged = true;
updated = true;
}
}
} else if (cmd == "cm") {
int16_t i = v.toInt();
if (i >= 0 && i <= 9) {
cfgChargeMode = i;
configChanged = true;
updated = true;
}
} else if (cmd == "coil") {
int16_t i = v.toInt();
if (i >= 0 && i <= 5) {
cfgInputLostTriggerChargeMode = i;
configChanged = true;
updated = true;
}
} else if (cmd == "covp") {
int16_t i = v.toInt();
if (i > 1) i = 1;
if (i != cfgChargeOvervoltageProtection) {
cfgChargeOvervoltageProtection = i;
configChanged = true;
updated = true;
}
} else if (cmd == "rofc") {
int16_t i = v.toInt();
if (i > 0 && needFullChargeOnce) {
resetOnGoingFullChargeAfterLineLost();
updated = true;
}
} else if (cmd == "car") {
int16_t i = v.toInt();
if (i > 1) i = 1;
if (i != cfgChargeAutomaticReducer) {
cfgChargeAutomaticReducer = i;
configChanged = true;
updated = true;
}
}
if (updated) {
mqttPublishState();
}
}
}
}
boolean mqttReconnect() {
String clientId = "UPS_DEV15_" + String(random(0xffff), HEX);
Serial.print("Attempting MQTT connection as ");
Serial.println(clientId);
if (mqttClient.connect(clientId.c_str())) {
Serial.println("MQTT Connected");
// Once connected, publish an announcement...
mqttClient.publish("ups/dev15/status", "online");
// ... and resubscribe
mqttClient.subscribe(mqtt_topic_cmd);
} else {
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
}
return mqttClient.connected();
}
void mqttInit() {
mqttClient.setServer(mqtt_server, mqtt_port);
mqttClient.setBufferSize(1024); // Increase buffer size for large JSON payloads
mqttClient.setCallback(mqttCallback);
}
void mqttPublishState() {
DynamicJsonDocument jsonDoc(1024);
String jsonResponse;
uint8_t lineActiveState = isUpsPoweredFromBattery() ? 2 : isInputLinePowered() ? 1 : isUpsOn() ? 2 : 0;
jsonDoc["success"] = 2;
jsonDoc["on"] = powerOutputActive ? 1 : 0;
jsonDoc["state"] = isUpsOn() ? 1 : 0;
jsonDoc["v"] = String(batteryVoltage, 2);
jsonDoc["batt"] = batteryLevel;
jsonDoc["battP"] = batteryPercentage;
jsonDoc["line"] = lineActiveState;
jsonDoc["uptime"] = millis() / 1000;
jsonDoc["auto"] = cfgAutoOn;
jsonDoc["battBlink"] = isUpsBatteryIndicatorChargingOrBlink() ? 1 : 0;
jsonDoc["battCritical"] = isUpsBatteryCritical() ? 1 : 0;
jsonDoc["chargeLv"] = getRawBatteryLevelFromPercentage(batteryPercentage);
jsonDoc["battMax"] = 4;
jsonDoc["timedShutdown"] = (persistentShutdown && powerOutputActive) ? 1 : 0;
jsonDoc["shutdownRemain"] = getPersistentShutdownTick() / 1000000;
jsonDoc["shutdownSuggestMode"] = cfgShutdownSuggestion;
jsonDoc["shutdownSuggest"] = getShutdownSuggestionFlag() ? 1 : 0;
jsonDoc["shutLastTimer"] = cfgShutdownInSeconds;
jsonDoc["chgError"] = chargeError;
jsonDoc["charging"] = getChargingState();
jsonDoc["chgMode"] = cfgChargeMode;
jsonDoc["chgOVP"] = cfgChargeOvervoltageProtection;
jsonDoc["chgReducer"] = cfgChargeAutomaticReducer;
jsonDoc["chgFullTrig"] = cfgInputLostTriggerChargeMode;
jsonDoc["chgOFC"] = needFullChargeOnce ? 1 : 0;
serializeJson(jsonDoc, jsonResponse);
mqttClient.publish(mqtt_topic_state, jsonResponse.c_str());
}
void mqttRoutine() {
if (!mqttClient.connected()) {
long now = millis();
if (now - lastMqttReconnectAttempt > 5000) {
lastMqttReconnectAttempt = now;
// Attempt to reconnect
if (mqttReconnect()) {
lastMqttReconnectAttempt = 0;
}
}
} else {
mqttClient.loop();
// Publish state periodically
long now = millis();
if (now - lastMqttPublish > mqttPublishInterval) {
lastMqttPublish = now;
mqttPublishState();
}
}
}
#endif