diff --git a/include/Battery.h b/include/Battery.h index ffb6f47d8..b5f5ace63 100644 --- a/include/Battery.h +++ b/include/Battery.h @@ -29,7 +29,6 @@ class BatteryClass { Task _loopTask; - uint32_t _lastMqttPublish = 0; mutable std::mutex _mutex; std::unique_ptr _upProvider = nullptr; }; diff --git a/include/BatteryStats.h b/include/BatteryStats.h index 8ff129f41..36eed06a3 100644 --- a/include/BatteryStats.h +++ b/include/BatteryStats.h @@ -23,15 +23,24 @@ class BatteryStats { // convert stats to JSON for web application live view virtual void getLiveViewData(JsonVariant& root) const; - virtual void mqttPublish() const; + void mqttLoop(); + + // the interval at which all battery datums will be re-published, even + // if they did not change. used to calculate Home Assistent expiration. + virtual uint32_t getMqttFullPublishIntervalMs() const; bool isValid() const { return _lastUpdateSoC > 0 && _lastUpdate > 0; } protected: + virtual void mqttPublish() const; + String _manufacturer = "unknown"; uint8_t _SoC = 0; uint32_t _lastUpdateSoC = 0; uint32_t _lastUpdate = 0; + + private: + uint32_t _lastMqttPublish = 0; }; class PylontechBatteryStats : public BatteryStats { @@ -89,6 +98,8 @@ class JkBmsBatteryStats : public BatteryStats { void mqttPublish() const final; + uint32_t getMqttFullPublishIntervalMs() const final { return 60 * 1000; } + void updateFrom(JkBms::DataPointContainer const& dp); private: diff --git a/include/MqttHandlePylontechHass.h b/include/MqttHandleBatteryHass.h similarity index 78% rename from include/MqttHandlePylontechHass.h rename to include/MqttHandleBatteryHass.h index 64f5a841f..f328a6f88 100644 --- a/include/MqttHandlePylontechHass.h +++ b/include/MqttHandleBatteryHass.h @@ -4,11 +4,10 @@ #include #include -class MqttHandlePylontechHassClass { +class MqttHandleBatteryHassClass { public: void init(Scheduler& scheduler); - void publishConfig(); - void forceUpdate(); + void forceUpdate() { _doPublish = true; } private: void loop(); @@ -19,9 +18,8 @@ class MqttHandlePylontechHassClass { Task _loopTask; - bool _wasConnected = false; - bool _updateForced = false; + bool _doPublish = true; String serial = "0001"; // pseudo-serial, can be replaced in future with real serialnumber }; -extern MqttHandlePylontechHassClass MqttHandlePylontechHass; \ No newline at end of file +extern MqttHandleBatteryHassClass MqttHandleBatteryHass; diff --git a/src/Battery.cpp b/src/Battery.cpp index 9fdc6e273..381fdc952 100644 --- a/src/Battery.cpp +++ b/src/Battery.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "Battery.h" #include "MessageOutput.h" -#include "MqttSettings.h" #include "PylontechCanReceiver.h" #include "JkBmsController.h" #include "VictronSmartShunt.h" @@ -76,14 +75,5 @@ void BatteryClass::loop() _upProvider->loop(); - CONFIG_T& config = Configuration.get(); - - if (!MqttSettings.getConnected() - || (millis() - _lastMqttPublish) < (config.Mqtt.PublishInterval * 1000)) { - return; - } - - _upProvider->getStats()->mqttPublish(); - - _lastMqttPublish = millis(); + _upProvider->getStats()->mqttLoop(); } diff --git a/src/BatteryStats.cpp b/src/BatteryStats.cpp index c2c9d9d02..606a372fd 100644 --- a/src/BatteryStats.cpp +++ b/src/BatteryStats.cpp @@ -5,6 +5,7 @@ #include "Configuration.h" #include "MqttSettings.h" #include "JkBmsDataPoints.h" +#include "MqttSettings.h" template static void addLiveViewInSection(JsonVariant& root, @@ -187,6 +188,31 @@ void JkBmsBatteryStats::getJsonData(JsonVariant& root, bool verbose) const } } +void BatteryStats::mqttLoop() +{ + auto& config = Configuration.get(); + + if (!MqttSettings.getConnected() + || (millis() - _lastMqttPublish) < (config.Mqtt.PublishInterval * 1000)) { + return; + } + + mqttPublish(); + + _lastMqttPublish = millis(); +} + +uint32_t BatteryStats::getMqttFullPublishIntervalMs() const +{ + auto& config = Configuration.get(); + + // this is the default interval, see mqttLoop(). mqttPublish() + // implementations in derived classes may choose to publish some values + // with a lower frequency and hence implement this method with a different + // return value. + return config.Mqtt.PublishInterval * 1000; +} + void BatteryStats::mqttPublish() const { MqttSettings.publish(F("battery/manufacturer"), _manufacturer); @@ -236,11 +262,10 @@ void JkBmsBatteryStats::mqttPublish() const Label::BatterySoCPercent // already published by base class }; - CONFIG_T& config = Configuration.get(); - - // publish all topics every minute, unless the retain flag is enabled - bool fullPublish = _lastFullMqttPublish + 60 * 1000 < millis(); - fullPublish &= !config.Mqtt.Retain; + // regularly publish all topics regardless of whether or not their value changed + bool neverFullyPublished = _lastFullMqttPublish == 0; + bool intervalElapsed = _lastFullMqttPublish + getMqttFullPublishIntervalMs() < millis(); + bool fullPublish = neverFullyPublished || intervalElapsed; for (auto iter = _dataPoints.cbegin(); iter != _dataPoints.cend(); ++iter) { // skip data points that did not change since last published diff --git a/src/MqttHandleBatteryHass.cpp b/src/MqttHandleBatteryHass.cpp new file mode 100644 index 000000000..7cad09222 --- /dev/null +++ b/src/MqttHandleBatteryHass.cpp @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "PylontechCanReceiver.h" +#include "Battery.h" +#include "MqttHandleBatteryHass.h" +#include "Configuration.h" +#include "MqttSettings.h" +#include "Utils.h" + +MqttHandleBatteryHassClass MqttHandleBatteryHass; + +void MqttHandleBatteryHassClass::init(Scheduler& scheduler) +{ + scheduler.addTask(_loopTask); + _loopTask.setCallback(std::bind(&MqttHandleBatteryHassClass::loop, this)); + _loopTask.setIterations(TASK_FOREVER); + _loopTask.enable(); +} + +void MqttHandleBatteryHassClass::loop() +{ + CONFIG_T& config = Configuration.get(); + + if (!config.Battery.Enabled) { return; } + + if (!config.Mqtt.Hass.Enabled) { return; } + + // TODO(schlimmchen): this cannot make sure that transient + // connection problems are actually always noticed. + if (!MqttSettings.getConnected()) { + _doPublish = true; + return; + } + + // only publish HA config once when (re-)connecting + // to the MQTT broker or on config changes. + if (!_doPublish) { return; } + + // the MQTT battery provider does not re-publish the SoC under a different + // known topic. we don't know the manufacture either. HASS auto-discovery + // for that provider makes no sense. + if (config.Battery.Provider != 2) { + publishSensor("Manufacturer", "mdi:factory", "manufacturer"); + publishSensor("Data Age", "mdi:timer-sand", "dataAge", "duration", "measurement", "s"); + publishSensor("State of Charge (SoC)", "mdi:battery-medium", "stateOfCharge", "battery", "measurement", "%"); + } + + switch (config.Battery.Provider) { + case 0: // Pylontech Battery + publishSensor("Battery voltage", NULL, "voltage", "voltage", "measurement", "V"); + publishSensor("Battery current", NULL, "current", "current", "measurement", "A"); + publishSensor("Temperature", NULL, "temperature", "temperature", "measurement", "°C"); + publishSensor("State of Health (SOH)", "mdi:heart-plus", "stateOfHealth", NULL, "measurement", "%"); + publishSensor("Charge voltage (BMS)", NULL, "settings/chargeVoltage", "voltage", "measurement", "V"); + publishSensor("Charge current limit", NULL, "settings/chargeCurrentLimitation", "current", "measurement", "A"); + publishSensor("Discharge current limit", NULL, "settings/dischargeCurrentLimitation", "current", "measurement", "A"); + + publishBinarySensor("Alarm Discharge current", "mdi:alert", "alarm/overCurrentDischarge", "1", "0"); + publishBinarySensor("Warning Discharge current", "mdi:alert-outline", "warning/highCurrentDischarge", "1", "0"); + + publishBinarySensor("Alarm Temperature low", "mdi:thermometer-low", "alarm/underTemperature", "1", "0"); + publishBinarySensor("Warning Temperature low", "mdi:thermometer-low", "warning/lowTemperature", "1", "0"); + + publishBinarySensor("Alarm Temperature high", "mdi:thermometer-high", "alarm/overTemperature", "1", "0"); + publishBinarySensor("Warning Temperature high", "mdi:thermometer-high", "warning/highTemperature", "1", "0"); + + publishBinarySensor("Alarm Voltage low", "mdi:alert", "alarm/underVoltage", "1", "0"); + publishBinarySensor("Warning Voltage low", "mdi:alert-outline", "warning/lowVoltage", "1", "0"); + + publishBinarySensor("Alarm Voltage high", "mdi:alert", "alarm/overVoltage", "1", "0"); + publishBinarySensor("Warning Voltage high", "mdi:alert-outline", "warning/highVoltage", "1", "0"); + + publishBinarySensor("Alarm BMS internal", "mdi:alert", "alarm/bmsInternal", "1", "0"); + publishBinarySensor("Warning BMS internal", "mdi:alert-outline", "warning/bmsInternal", "1", "0"); + + publishBinarySensor("Alarm High charge current", "mdi:alert", "alarm/overCurrentCharge", "1", "0"); + publishBinarySensor("Warning High charge current", "mdi:alert-outline", "warning/highCurrentCharge", "1", "0"); + + publishBinarySensor("Charge enabled", "mdi:battery-arrow-up", "charging/chargeEnabled", "1", "0"); + publishBinarySensor("Discharge enabled", "mdi:battery-arrow-down", "charging/dischargeEnabled", "1", "0"); + publishBinarySensor("Charge immediately", "mdi:alert", "charging/chargeImmediately", "1", "0"); + break; + case 1: // JK BMS + // caption icon topic dev. class state class unit + publishSensor("Voltage", "mdi:battery-charging", "BatteryVoltageMilliVolt", "voltage", "measurement", "mV"); + publishSensor("Current", "mdi:current-dc", "BatteryCurrentMilliAmps", "current", "measurement", "mA"); + publishSensor("BMS Temperature", "mdi:thermometer", "BmsTempCelsius", "temperature", "measurement", "°C"); + publishSensor("Cell Voltage Diff", "mdi:battery-alert", "CellDiffMilliVolt", "voltage", "measurement", "mV"); + publishSensor("Charge Cycles", "mdi:counter", "BatteryCycles"); + publishSensor("Cycle Capacity", "mdi:battery-sync", "BatteryCycleCapacity"); + + publishBinarySensor("Charging Possible", "mdi:battery-arrow-up", "status/ChargingActive", "1", "0"); + publishBinarySensor("Discharging Possible", "mdi:battery-arrow-down", "status/DischargingActive", "1", "0"); + publishBinarySensor("Balancing Active", "mdi:scale-balance", "status/BalancingActive", "1", "0"); + +#define PBS(a, b, c) publishBinarySensor("Alarm: " a, "mdi:" b, "alarms/" c, "1", "0") + PBS("Low Capacity", "battery-alert-variant-outline", "LowCapacity"); + PBS("BMS Overtemperature", "thermometer-alert", "BmsOvertemperature"); + PBS("Charging Overvoltage", "fuse-alert", "ChargingOvervoltage"); + PBS("Discharge Undervoltage", "fuse-alert", "DischargeUndervoltage"); + PBS("Battery Overtemperature", "thermometer-alert", "BatteryOvertemperature"); + PBS("Charging Overcurrent", "fuse-alert", "ChargingOvercurrent"); + PBS("Discharging Overcurrent", "fuse-alert", "DischargeOvercurrent"); + PBS("Cell Voltage Difference", "battery-alert", "CellVoltageDifference"); + PBS("Battery Box Overtemperature", "thermometer-alert", "BatteryBoxOvertemperature"); + PBS("Battery Undertemperature", "thermometer-alert", "BatteryUndertemperature"); + PBS("Cell Overvoltage", "battery-alert", "CellOvervoltage"); + PBS("Cell Undervoltage", "battery-alert", "CellUndervoltage"); +#undef PBS + break; + case 2: // SoC from MQTT + break; + case 3: // Victron SmartShunt + break; + } + + _doPublish = false; +} + +void MqttHandleBatteryHassClass::publishSensor(const char* caption, const char* icon, const char* subTopic, const char* deviceClass, const char* stateClass, const char* unitOfMeasurement ) +{ + String sensorId = caption; + sensorId.replace(" ", "_"); + sensorId.replace(".", ""); + sensorId.replace("(", ""); + sensorId.replace(")", ""); + sensorId.toLowerCase(); + + String configTopic = "sensor/dtu_battery_" + serial + + "/" + sensorId + + "/config"; + + String statTopic = MqttSettings.getPrefix() + "battery/"; + // omit serial to avoid a breaking change + // statTopic.concat(serial); + // statTopic.concat("/"); + statTopic.concat(subTopic); + + DynamicJsonDocument root(1024); + if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { + return; + } + root["name"] = caption; + root["stat_t"] = statTopic; + root["uniq_id"] = serial + "_" + sensorId; + + if (icon != NULL) { + root["icon"] = icon; + } + + if (unitOfMeasurement != NULL) { + root["unit_of_meas"] = unitOfMeasurement; + } + + JsonObject deviceObj = root.createNestedObject("dev"); + createDeviceInfo(deviceObj); + + if (Configuration.get().Mqtt.Hass.Expire) { + root["exp_aft"] = Battery.getStats()->getMqttFullPublishIntervalMs() * 3; + } + if (deviceClass != NULL) { + root["dev_cla"] = deviceClass; + } + if (stateClass != NULL) { + root["stat_cla"] = stateClass; + } + + char buffer[512]; + serializeJson(root, buffer); + publish(configTopic, buffer); + +} + +void MqttHandleBatteryHassClass::publishBinarySensor(const char* caption, const char* icon, const char* subTopic, const char* payload_on, const char* payload_off) +{ + String sensorId = caption; + sensorId.replace(" ", "_"); + sensorId.replace(".", ""); + sensorId.replace("(", ""); + sensorId.replace(")", ""); + sensorId.replace(":", ""); + sensorId.toLowerCase(); + + String configTopic = "binary_sensor/dtu_battery_" + serial + + "/" + sensorId + + "/config"; + + String statTopic = MqttSettings.getPrefix() + "battery/"; + // omit serial to avoid a breaking change + // statTopic.concat(serial); + // statTopic.concat("/"); + statTopic.concat(subTopic); + + DynamicJsonDocument root(1024); + if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { + return; + } + root["name"] = caption; + root["uniq_id"] = serial + "_" + sensorId; + root["stat_t"] = statTopic; + root["pl_on"] = payload_on; + root["pl_off"] = payload_off; + + if (icon != NULL) { + root["icon"] = icon; + } + + JsonObject deviceObj = root.createNestedObject("dev"); + createDeviceInfo(deviceObj); + + char buffer[512]; + serializeJson(root, buffer); + publish(configTopic, buffer); +} + +void MqttHandleBatteryHassClass::createDeviceInfo(JsonObject& object) +{ + object["name"] = "Battery(" + serial + ")"; + + auto& config = Configuration.get(); + if (config.Battery.Provider == 1) { + object["name"] = "JK BMS (" + Battery.getStats()->getManufacturer() + ")"; + } + + object["ids"] = serial; + object["cu"] = String("http://") + NetworkSettings.localIP().toString(); + object["mf"] = "OpenDTU"; + object["mdl"] = Battery.getStats()->getManufacturer(); + object["sw"] = AUTO_GIT_HASH; +} + +void MqttHandleBatteryHassClass::publish(const String& subtopic, const String& payload) +{ + String topic = Configuration.get().Mqtt.Hass.Topic; + topic += subtopic; + MqttSettings.publishGeneric(topic.c_str(), payload.c_str(), Configuration.get().Mqtt.Hass.Retain); +} diff --git a/src/MqttHandlePylontechHass.cpp b/src/MqttHandlePylontechHass.cpp deleted file mode 100644 index d4afbb2d3..000000000 --- a/src/MqttHandlePylontechHass.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "PylontechCanReceiver.h" -#include "Battery.h" -#include "MqttHandlePylontechHass.h" -#include "Configuration.h" -#include "MqttSettings.h" -#include "MessageOutput.h" -#include "Utils.h" - -MqttHandlePylontechHassClass MqttHandlePylontechHass; - -void MqttHandlePylontechHassClass::init(Scheduler& scheduler) -{ - scheduler.addTask(_loopTask); - _loopTask.setCallback(std::bind(&MqttHandlePylontechHassClass::loop, this)); - _loopTask.setIterations(TASK_FOREVER); - _loopTask.enable(); -} - -void MqttHandlePylontechHassClass::loop() -{ - CONFIG_T& config = Configuration.get(); - if (!config.Battery.Enabled) { - return; - } - if (_updateForced) { - publishConfig(); - _updateForced = false; - } - - if (MqttSettings.getConnected() && !_wasConnected) { - // Connection established - _wasConnected = true; - publishConfig(); - } else if (!MqttSettings.getConnected() && _wasConnected) { - // Connection lost - _wasConnected = false; - } -} - -void MqttHandlePylontechHassClass::forceUpdate() -{ - _updateForced = true; -} - -void MqttHandlePylontechHassClass::publishConfig() -{ - CONFIG_T& config = Configuration.get(); - if ((!config.Mqtt.Hass.Enabled) || (!config.Battery.Enabled)) { - return; - } - - if (!MqttSettings.getConnected()) { - return; - } - - // device info - publishSensor("Manufacturer", "mdi:factory", "manufacturer"); - - // battery info - publishSensor("Battery voltage", NULL, "voltage", "voltage", "measurement", "V"); - publishSensor("Battery current", NULL, "current", "current", "measurement", "A"); - publishSensor("Temperature", NULL, "temperature", "temperature", "measurement", "°C"); - publishSensor("State of Charge (SOC)", NULL, "stateOfCharge", "battery", "measurement", "%"); - publishSensor("State of Health (SOH)", "mdi:heart-plus", "stateOfHealth", NULL, "measurement", "%"); - publishSensor("Charge voltage (BMS)", NULL, "settings/chargeVoltage", "voltage", "measurement", "V"); - publishSensor("Charge current limit", NULL, "settings/chargeCurrentLimitation", "current", "measurement", "A"); - publishSensor("Discharge current limit", NULL, "settings/dischargeCurrentLimitation", "current", "measurement", "A"); - - publishBinarySensor("Alarm Discharge current", "mdi:alert", "alarm/overCurrentDischarge", "1", "0"); - publishBinarySensor("Warning Discharge current", "mdi:alert-outline", "warning/highCurrentDischarge", "1", "0"); - - publishBinarySensor("Alarm Temperature low", "mdi:thermometer-low", "alarm/underTemperature", "1", "0"); - publishBinarySensor("Warning Temperature low", "mdi:thermometer-low", "warning/lowTemperature", "1", "0"); - - publishBinarySensor("Alarm Temperature high", "mdi:thermometer-high", "alarm/overTemperature", "1", "0"); - publishBinarySensor("Warning Temperature high", "mdi:thermometer-high", "warning/highTemperature", "1", "0"); - - publishBinarySensor("Alarm Voltage low", "mdi:alert", "alarm/underVoltage", "1", "0"); - publishBinarySensor("Warning Voltage low", "mdi:alert-outline", "warning/lowVoltage", "1", "0"); - - publishBinarySensor("Alarm Voltage high", "mdi:alert", "alarm/overVoltage", "1", "0"); - publishBinarySensor("Warning Voltage high", "mdi:alert-outline", "warning/highVoltage", "1", "0"); - - publishBinarySensor("Alarm BMS internal", "mdi:alert", "alarm/bmsInternal", "1", "0"); - publishBinarySensor("Warning BMS internal", "mdi:alert-outline", "warning/bmsInternal", "1", "0"); - - publishBinarySensor("Alarm High charge current", "mdi:alert", "alarm/overCurrentCharge", "1", "0"); - publishBinarySensor("Warning High charge current", "mdi:alert-outline", "warning/highCurrentCharge", "1", "0"); - - publishBinarySensor("Charge enabled", "mdi:battery-arrow-up", "charging/chargeEnabled", "1", "0"); - publishBinarySensor("Discharge enabled", "mdi:battery-arrow-down", "charging/dischargeEnabled", "1", "0"); - publishBinarySensor("Charge immediately", "mdi:alert", "charging/chargeImmediately", "1", "0"); - - yield(); -} - -void MqttHandlePylontechHassClass::publishSensor(const char* caption, const char* icon, const char* subTopic, const char* deviceClass, const char* stateClass, const char* unitOfMeasurement ) -{ - String sensorId = caption; - sensorId.replace(" ", "_"); - sensorId.replace(".", ""); - sensorId.replace("(", ""); - sensorId.replace(")", ""); - sensorId.toLowerCase(); - - String configTopic = "sensor/dtu_battery_" + serial - + "/" + sensorId - + "/config"; - - String statTopic = MqttSettings.getPrefix() + "battery/"; - // omit serial to avoid a breaking change - // statTopic.concat(serial); - // statTopic.concat("/"); - statTopic.concat(subTopic); - - DynamicJsonDocument root(1024); - if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { - return; - } - root["name"] = caption; - root["stat_t"] = statTopic; - root["uniq_id"] = serial + "_" + sensorId; - - if (icon != NULL) { - root["icon"] = icon; - } - - if (unitOfMeasurement != NULL) { - root["unit_of_meas"] = unitOfMeasurement; - } - - JsonObject deviceObj = root.createNestedObject("dev"); - createDeviceInfo(deviceObj); - - if (Configuration.get().Mqtt.Hass.Expire) { - root["exp_aft"] = Configuration.get().Mqtt.PublishInterval * 3; - } - if (deviceClass != NULL) { - root["dev_cla"] = deviceClass; - } - if (stateClass != NULL) { - root["stat_cla"] = stateClass; - } - - char buffer[512]; - serializeJson(root, buffer); - publish(configTopic, buffer); - -} - -void MqttHandlePylontechHassClass::publishBinarySensor(const char* caption, const char* icon, const char* subTopic, const char* payload_on, const char* payload_off) -{ - String sensorId = caption; - sensorId.replace(" ", "_"); - sensorId.replace(".", ""); - sensorId.replace("(", ""); - sensorId.replace(")", ""); - sensorId.toLowerCase(); - - String configTopic = "binary_sensor/dtu_battery_" + serial - + "/" + sensorId - + "/config"; - - String statTopic = MqttSettings.getPrefix() + "battery/"; - // omit serial to avoid a breaking change - // statTopic.concat(serial); - // statTopic.concat("/"); - statTopic.concat(subTopic); - - DynamicJsonDocument root(1024); - if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { - return; - } - root["name"] = caption; - root["uniq_id"] = serial + "_" + sensorId; - root["stat_t"] = statTopic; - root["pl_on"] = payload_on; - root["pl_off"] = payload_off; - - if (icon != NULL) { - root["icon"] = icon; - } - - JsonObject deviceObj = root.createNestedObject("dev"); - createDeviceInfo(deviceObj); - - char buffer[512]; - serializeJson(root, buffer); - publish(configTopic, buffer); -} - -void MqttHandlePylontechHassClass::createDeviceInfo(JsonObject& object) -{ - object["name"] = "Battery(" + serial + ")"; - object["ids"] = serial; - object["cu"] = String("http://") + NetworkSettings.localIP().toString(); - object["mf"] = "OpenDTU"; - object["mdl"] = Battery.getStats()->getManufacturer(); - object["sw"] = AUTO_GIT_HASH; -} - -void MqttHandlePylontechHassClass::publish(const String& subtopic, const String& payload) -{ - String topic = Configuration.get().Mqtt.Hass.Topic; - topic += subtopic; - MqttSettings.publishGeneric(topic.c_str(), payload.c_str(), Configuration.get().Mqtt.Hass.Retain); -} diff --git a/src/WebApi_battery.cpp b/src/WebApi_battery.cpp index eec84d7b7..b96eb2cf6 100644 --- a/src/WebApi_battery.cpp +++ b/src/WebApi_battery.cpp @@ -7,7 +7,7 @@ #include "AsyncJson.h" #include "Battery.h" #include "Configuration.h" -#include "PylontechCanReceiver.h" +#include "MqttHandleBatteryHass.h" #include "WebApi.h" #include "WebApi_battery.h" #include "WebApi_errors.h" @@ -111,4 +111,5 @@ void WebApiBatteryClass::onAdminPost(AsyncWebServerRequest* request) request->send(response); Battery.updateSettings(); + MqttHandleBatteryHass.forceUpdate(); } diff --git a/src/main.cpp b/src/main.cpp index 38fcbc2e6..dd080832e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ #include "MqttHandleDtu.h" #include "MqttHandleHass.h" #include "MqttHandleVedirectHass.h" -#include "MqttHandlePylontechHass.h" +#include "MqttHandleBatteryHass.h" #include "MqttHandleInverter.h" #include "MqttHandleInverterTotal.h" #include "MqttHandleVedirect.h" @@ -116,6 +116,7 @@ void setup() MqttHandleVedirect.init(scheduler); MqttHandleHass.init(scheduler); MqttHandleVedirectHass.init(scheduler); + MqttHandleBatteryHass.init(scheduler); MqttHandleHuawei.init(scheduler); MqttHandlePowerLimiter.init(scheduler); MessageOutput.println("done");