Determine double battery usage in MQTT at run-time

This commit is contained in:
Jaakko Haakana 2025-06-01 21:15:42 +03:00
parent 8cb4884af7
commit 3789d72833
5 changed files with 68 additions and 60 deletions

View file

@ -89,11 +89,8 @@ SensorConfig sensorConfigTemplate[] = {
{"bms_status", "BMS Status", "", "", ""},
{"pause_status", "Pause Status", "", "", ""}};
#ifdef DOUBLE_BATTERY
// Enough space for two batteries
SensorConfig sensorConfigs[((sizeof(sensorConfigTemplate) / sizeof(sensorConfigTemplate[0])) * 2) - 2];
#else
SensorConfig sensorConfigs[sizeof(sensorConfigTemplate) / sizeof(sensorConfigTemplate[0])];
#endif // DOUBLE_BATTERY
void create_sensor_configs() {
int number_of_templates = sizeof(sensorConfigTemplate) / sizeof(sensorConfigTemplate[0]);
@ -101,16 +98,17 @@ void create_sensor_configs() {
SensorConfig config = sensorConfigTemplate[i];
config.value_template = strdup(("{{ value_json." + std::string(config.object_id) + " }}").c_str());
sensorConfigs[i] = config;
#ifdef DOUBLE_BATTERY
if (config.object_id == "pause_status" || config.object_id == "bms_status") {
continue;
if (battery2) {
if (config.object_id == "pause_status" || config.object_id == "bms_status") {
continue;
}
sensorConfigs[i + number_of_templates] = config;
sensorConfigs[i + number_of_templates].name = strdup(String(config.name + String(" 2")).c_str());
sensorConfigs[i + number_of_templates].object_id = strdup(String(config.object_id + String("_2")).c_str());
sensorConfigs[i + number_of_templates].value_template =
strdup(("{{ value_json." + std::string(config.object_id) + "_2 }}").c_str());
}
sensorConfigs[i + number_of_templates] = config;
sensorConfigs[i + number_of_templates].name = strdup(String(config.name + String(" 2")).c_str());
sensorConfigs[i + number_of_templates].object_id = strdup(String(config.object_id + String("_2")).c_str());
sensorConfigs[i + number_of_templates].value_template =
strdup(("{{ value_json." + std::string(config.object_id) + "_2 }}").c_str());
#endif // DOUBLE_BATTERY
}
}
@ -164,7 +162,8 @@ static String generateButtonTopic(const char* subtype) {
return topic_name + "/command/" + String(subtype);
}
void set_battery_attributes(JsonDocument& doc, const DATALAYER_BATTERY_TYPE& battery, const String& suffix) {
void set_battery_attributes(JsonDocument& doc, const DATALAYER_BATTERY_TYPE& battery, const String& suffix,
bool supports_charged) {
doc["SOC" + suffix] = ((float)battery.status.reported_soc) / 100.0;
doc["SOC_real" + suffix] = ((float)battery.status.real_soc) / 100.0;
doc["state_of_health" + suffix] = ((float)battery.status.soh_pptt) / 100.0;
@ -185,13 +184,14 @@ void set_battery_attributes(JsonDocument& doc, const DATALAYER_BATTERY_TYPE& bat
doc["remaining_capacity" + suffix] = ((float)battery.status.reported_remaining_capacity_Wh);
doc["max_discharge_power" + suffix] = ((float)battery.status.max_discharge_power_W);
doc["max_charge_power" + suffix] = ((float)battery.status.max_charge_power_W);
#if defined(MEB_BATTERY) || defined(TESLA_BATTERY)
if (datalayer.battery.status.total_charged_battery_Wh != 0 &&
datalayer.battery.status.total_discharged_battery_Wh != 0) {
doc["charged_energy" + suffix] = ((float)datalayer.battery.status.total_charged_battery_Wh);
doc["discharged_energy" + suffix] = ((float)datalayer.battery.status.total_discharged_battery_Wh);
if (supports_charged) {
if (datalayer.battery.status.total_charged_battery_Wh != 0 &&
datalayer.battery.status.total_discharged_battery_Wh != 0) {
doc["charged_energy" + suffix] = ((float)datalayer.battery.status.total_charged_battery_Wh);
doc["discharged_energy" + suffix] = ((float)datalayer.battery.status.total_discharged_battery_Wh);
}
}
#endif
}
static std::vector<EventData> order_events;
@ -231,14 +231,15 @@ static bool publish_common_info(void) {
//only publish these values if BMS is active and we are comunication with the battery (can send CAN messages to the battery)
if (datalayer.battery.status.CAN_battery_still_alive && allowed_to_send_CAN && millis() > BOOTUP_TIME) {
set_battery_attributes(doc, datalayer.battery, "");
set_battery_attributes(doc, datalayer.battery, "", battery->supports_charged_energy());
}
#ifdef DOUBLE_BATTERY
//only publish these values if BMS is active and we are comunication with the battery (can send CAN messages to the battery)
if (datalayer.battery2.status.CAN_battery_still_alive && allowed_to_send_CAN && millis() > BOOTUP_TIME) {
set_battery_attributes(doc, datalayer.battery2, "_2");
if (battery2) {
//only publish these values if BMS is active and we are comunication with the battery (can send CAN messages to the battery)
if (datalayer.battery2.status.CAN_battery_still_alive && allowed_to_send_CAN && millis() > BOOTUP_TIME) {
set_battery_attributes(doc, datalayer.battery2, "_2", battery2->supports_charged_energy());
}
}
#endif // DOUBLE_BATTERY
serializeJson(doc, mqtt_msg);
if (mqtt_publish(state_topic.c_str(), mqtt_msg, false) == false) {
#ifdef DEBUG_LOG
@ -256,9 +257,7 @@ static bool publish_common_info(void) {
static bool publish_cell_voltages(void) {
static JsonDocument doc;
static String state_topic = topic_name + "/spec_data";
#ifdef DOUBLE_BATTERY
static String state_topic_2 = topic_name + "/spec_data_2";
#endif // DOUBLE_BATTERY
#ifdef HA_AUTODISCOVERY
bool failed_to_publish = false;
@ -280,24 +279,26 @@ static bool publish_cell_voltages(void) {
}
doc.clear(); // clear after sending autoconfig
}
#ifdef DOUBLE_BATTERY
// If the cell voltage number isn't initialized...
if (datalayer.battery2.info.number_of_cells != 0u) {
for (int i = 0; i < datalayer.battery.info.number_of_cells; i++) {
int cellNumber = i + 1;
set_battery_voltage_attributes(doc, i, cellNumber, state_topic_2, object_id_prefix + "2_", " 2");
set_common_discovery_attributes(doc);
if (battery2) {
// TODO: Combine this identical block with the previous one.
// If the cell voltage number isn't initialized...
if (datalayer.battery2.info.number_of_cells != 0u) {
serializeJson(doc, mqtt_msg, sizeof(mqtt_msg));
if (mqtt_publish(generateCellVoltageAutoConfigTopic(cellNumber, "_2_").c_str(), mqtt_msg, true) == false) {
failed_to_publish = true;
return false;
for (int i = 0; i < datalayer.battery.info.number_of_cells; i++) {
int cellNumber = i + 1;
set_battery_voltage_attributes(doc, i, cellNumber, state_topic_2, object_id_prefix + "2_", " 2");
set_common_discovery_attributes(doc);
serializeJson(doc, mqtt_msg, sizeof(mqtt_msg));
if (mqtt_publish(generateCellVoltageAutoConfigTopic(cellNumber, "_2_").c_str(), mqtt_msg, true) == false) {
failed_to_publish = true;
return false;
}
}
doc.clear(); // clear after sending autoconfig
}
doc.clear(); // clear after sending autoconfig
}
#endif // DOUBLE_BATTERY
}
if (failed_to_publish == false) {
ha_cell_voltages_published = true;
@ -324,27 +325,27 @@ static bool publish_cell_voltages(void) {
doc.clear();
}
#ifdef DOUBLE_BATTERY
// If cell voltages have been populated...
if (datalayer.battery2.info.number_of_cells != 0u &&
datalayer.battery2.status.cell_voltages_mV[datalayer.battery2.info.number_of_cells - 1] != 0u) {
if (battery2) {
// If cell voltages have been populated...
if (datalayer.battery2.info.number_of_cells != 0u &&
datalayer.battery2.status.cell_voltages_mV[datalayer.battery2.info.number_of_cells - 1] != 0u) {
JsonArray cell_voltages = doc["cell_voltages"].to<JsonArray>();
for (size_t i = 0; i < datalayer.battery2.info.number_of_cells; ++i) {
cell_voltages.add(((float)datalayer.battery2.status.cell_voltages_mV[i]) / 1000.0);
}
JsonArray cell_voltages = doc["cell_voltages"].to<JsonArray>();
for (size_t i = 0; i < datalayer.battery2.info.number_of_cells; ++i) {
cell_voltages.add(((float)datalayer.battery2.status.cell_voltages_mV[i]) / 1000.0);
}
serializeJson(doc, mqtt_msg, sizeof(mqtt_msg));
serializeJson(doc, mqtt_msg, sizeof(mqtt_msg));
if (!mqtt_publish(state_topic_2.c_str(), mqtt_msg, false)) {
if (!mqtt_publish(state_topic_2.c_str(), mqtt_msg, false)) {
#ifdef DEBUG_LOG
logging.println("Cell voltage MQTT msg could not be sent");
logging.println("Cell voltage MQTT msg could not be sent");
#endif // DEBUG_LOG
return false;
return false;
}
doc.clear();
}
doc.clear();
}
#endif // DOUBLE_BATTERY
return true;
}