BREAKING CHANGE: allow multiple OpenDTU-OnBattery instances at same HASS

This breaks existing HASS automation, as entity names and MQTT topics change!

* include dtu-unique-id in DPL MQTT HASS topics to allow multiple DTUs to be controlled
* fix filename "src/MqttHandlVedirectHass.cpp"
* refactor: use values from 'MqttHandleHass', add 'via_device' to all HASS devices
* set step size for power limiter voltage values
This commit is contained in:
Andreas Böhm 2024-07-23 21:27:14 +02:00 committed by GitHub
parent 6ee6eaf0b2
commit e3f9da75b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 32 additions and 26 deletions

View File

@ -56,6 +56,9 @@ public:
void publishConfig();
void forceUpdate();
static String getDtuUniqueId();
static String getDtuUrl();
private:
void loop();
void publish(const String& subtopic, const String& payload);
@ -71,9 +74,6 @@ private:
static void createDeviceInfo(JsonDocument& doc, const String& name, const String& identifiers, const String& configuration_url, const String& manufacturer, const String& model, const String& sw_version, const String& via_device = "");
static String getDtuUniqueId();
static String getDtuUrl();
Task _loopTask;
bool _wasConnected = false;

View File

@ -13,9 +13,9 @@ public:
private:
void loop();
void publish(const String& subtopic, const String& payload);
void publishNumber(const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, const int16_t min, const int16_t max);
void publishNumber(const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, const int16_t min, const int16_t max, const float step);
void publishSelect(const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic);
void createDeviceInfo(JsonObject& object);
void createDeviceInfo(JsonDocument& root);
Task _loopTask;

View File

@ -5,6 +5,7 @@
#include "MqttHandleBatteryHass.h"
#include "Configuration.h"
#include "MqttSettings.h"
#include "MqttHandleHass.h"
#include "Utils.h"
#include "__compiled_constants.h"
@ -294,10 +295,11 @@ void MqttHandleBatteryHassClass::createDeviceInfo(JsonObject& object)
}
object["ids"] = serial;
object["cu"] = String("http://") + NetworkSettings.localIP().toString();
object["cu"] = MqttHandleHass.getDtuUrl();
object["mf"] = "OpenDTU";
object["mdl"] = Battery.getStats()->getManufacturer();
object["sw"] = __COMPILED_GIT_HASH__;
object["via_device"] = MqttHandleHass.getDtuUniqueId();
}
void MqttHandleBatteryHassClass::publish(const String& subtopic, const String& payload)

View File

@ -3,6 +3,7 @@
* Copyright (C) 2022 Thomas Basler and others
*/
#include "MqttHandlePowerLimiterHass.h"
#include "MqttHandleHass.h"
#include "Configuration.h"
#include "MqttSettings.h"
#include "NetworkSettings.h"
@ -69,32 +70,32 @@ void MqttHandlePowerLimiterHassClass::publishConfig()
// as this project revolves around Hoymiles inverters, 16 - 60 V is a reasonable voltage range
publishNumber("DPL battery voltage start threshold", "mdi:battery-charging",
"config", "threshold/voltage/start", "threshold/voltage/start", "V", 16, 60);
"config", "threshold/voltage/start", "threshold/voltage/start", "V", 16, 60, 0.1);
publishNumber("DPL battery voltage stop threshold", "mdi:battery-charging",
"config", "threshold/voltage/stop", "threshold/voltage/stop", "V", 16, 60);
"config", "threshold/voltage/stop", "threshold/voltage/stop", "V", 16, 60, 0.1);
if (config.Vedirect.Enabled) {
publishNumber("DPL full solar passthrough start voltage",
"mdi:transmission-tower-import", "config",
"threshold/voltage/full_solar_passthrough_start",
"threshold/voltage/full_solar_passthrough_start", "V", 16, 60);
"threshold/voltage/full_solar_passthrough_start", "V", 16, 60, 0.1);
publishNumber("DPL full solar passthrough stop voltage",
"mdi:transmission-tower-import", "config",
"threshold/voltage/full_solar_passthrough_stop",
"threshold/voltage/full_solar_passthrough_stop", "V", 16, 60);
"threshold/voltage/full_solar_passthrough_stop", "V", 16, 60, 0.1);
}
if (config.Battery.Enabled && !config.PowerLimiter.IgnoreSoc) {
publishNumber("DPL battery SoC start threshold", "mdi:battery-charging",
"config", "threshold/soc/start", "threshold/soc/start", "%", 0, 100);
"config", "threshold/soc/start", "threshold/soc/start", "%", 0, 100, 1.0);
publishNumber("DPL battery SoC stop threshold", "mdi:battery-charging",
"config", "threshold/soc/stop", "threshold/soc/stop", "%", 0, 100);
"config", "threshold/soc/stop", "threshold/soc/stop", "%", 0, 100, 1.0);
if (config.Vedirect.Enabled) {
publishNumber("DPL full solar passthrough SoC",
"mdi:transmission-tower-import", "config",
"threshold/soc/full_solar_passthrough",
"threshold/soc/full_solar_passthrough", "%", 0, 100);
"threshold/soc/full_solar_passthrough", "%", 0, 100, 1.0);
}
}
}
@ -108,7 +109,7 @@ void MqttHandlePowerLimiterHassClass::publishSelect(
selectId.replace(" ", "_");
selectId.toLowerCase();
const String configTopic = "select/powerlimiter/" + selectId + "/config";
const String configTopic = "select/" + MqttHandleHass.getDtuUniqueId() + "/" + selectId + "/config";
const String cmdTopic = MqttSettings.getPrefix() + "powerlimiter/cmd/" + commandTopic;
const String statTopic = MqttSettings.getPrefix() + "powerlimiter/status/" + stateTopic;
@ -116,7 +117,7 @@ void MqttHandlePowerLimiterHassClass::publishSelect(
JsonDocument root;
root["name"] = caption;
root["uniq_id"] = selectId;
root["uniq_id"] = MqttHandleHass.getDtuUniqueId() + "_" + selectId;
if (strcmp(icon, "")) {
root["ic"] = icon;
}
@ -128,8 +129,7 @@ void MqttHandlePowerLimiterHassClass::publishSelect(
options.add("1");
options.add("2");
JsonObject deviceObj = root["dev"].to<JsonObject>();
createDeviceInfo(deviceObj);
createDeviceInfo(root);
if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) {
return;
@ -143,14 +143,14 @@ void MqttHandlePowerLimiterHassClass::publishSelect(
void MqttHandlePowerLimiterHassClass::publishNumber(
const char* caption, const char* icon, const char* category,
const char* commandTopic, const char* stateTopic, const char* unitOfMeasure,
const int16_t min, const int16_t max)
const int16_t min, const int16_t max, const float step)
{
String numberId = caption;
numberId.replace(" ", "_");
numberId.toLowerCase();
const String configTopic = "number/powerlimiter/" + numberId + "/config";
const String configTopic = "number/" + MqttHandleHass.getDtuUniqueId() + "/" + numberId + "/config";
const String cmdTopic = MqttSettings.getPrefix() + "powerlimiter/cmd/" + commandTopic;
const String statTopic = MqttSettings.getPrefix() + "powerlimiter/status/" + stateTopic;
@ -158,7 +158,7 @@ void MqttHandlePowerLimiterHassClass::publishNumber(
JsonDocument root;
root["name"] = caption;
root["uniq_id"] = numberId;
root["uniq_id"] = MqttHandleHass.getDtuUniqueId() + "_" + numberId;
if (strcmp(icon, "")) {
root["ic"] = icon;
}
@ -168,6 +168,7 @@ void MqttHandlePowerLimiterHassClass::publishNumber(
root["unit_of_meas"] = unitOfMeasure;
root["min"] = min;
root["max"] = max;
root["step"] = step;
root["mode"] = "box";
auto const& config = Configuration.get();
@ -175,8 +176,7 @@ void MqttHandlePowerLimiterHassClass::publishNumber(
root["exp_aft"] = config.Mqtt.PublishInterval * 3;
}
JsonObject deviceObj = root["dev"].to<JsonObject>();
createDeviceInfo(deviceObj);
createDeviceInfo(root);
if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) {
return;
@ -187,14 +187,16 @@ void MqttHandlePowerLimiterHassClass::publishNumber(
publish(configTopic, buffer);
}
void MqttHandlePowerLimiterHassClass::createDeviceInfo(JsonObject& object)
void MqttHandlePowerLimiterHassClass::createDeviceInfo(JsonDocument& root)
{
JsonObject object = root["dev"].to<JsonObject>();
object["name"] = "Dynamic Power Limiter";
object["ids"] = "0002";
object["cu"] = String("http://") + NetworkSettings.localIP().toString();
object["ids"] = MqttHandleHass.getDtuUniqueId() + "_DPL";
object["cu"] = MqttHandleHass.getDtuUrl();
object["mf"] = "OpenDTU";
object["mdl"] = "Dynamic Power Limiter";
object["sw"] = __COMPILED_GIT_HASH__;
object["via_device"] = MqttHandleHass.getDtuUniqueId();
}
void MqttHandlePowerLimiterHassClass::publish(const String& subtopic, const String& payload)

View File

@ -5,6 +5,7 @@
#include "MqttHandleVedirectHass.h"
#include "Configuration.h"
#include "MqttSettings.h"
#include "MqttHandleHass.h"
#include "NetworkSettings.h"
#include "MessageOutput.h"
#include "VictronMppt.h"
@ -212,10 +213,11 @@ void MqttHandleVedirectHassClass::createDeviceInfo(JsonObject &object,
String serial = mpptData.serialNr_SER;
object["name"] = "Victron(" + serial + ")";
object["ids"] = serial;
object["cu"] = String("http://") + NetworkSettings.localIP().toString();
object["cu"] = MqttHandleHass.getDtuUrl();
object["mf"] = "OpenDTU";
object["mdl"] = mpptData.getPidAsString();
object["sw"] = __COMPILED_GIT_HASH__;
object["via_device"] = MqttHandleHass.getDtuUniqueId();
}
void MqttHandleVedirectHassClass::publish(const String& subtopic, const String& payload)