diff --git a/Software/Software.ino b/Software/Software.ino index 9b543578..29ddfb45 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -88,11 +88,6 @@ void setup() { &logging_loop_task, WIFI_CORE); #endif -#ifdef MQTT - xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task, - WIFI_CORE); -#endif - init_CAN(); init_contactors(); @@ -126,6 +121,12 @@ void setup() { }; // Start tasks + +#ifdef MQTT + xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task, + WIFI_CORE); +#endif + xTaskCreatePinnedToCore((TaskFunction_t)&core_loop, "core_loop", 4096, NULL, TASK_CORE_PRIO, &main_loop_task, CORE_FUNCTION_CORE); #ifdef PERIODIC_BMS_RESET_AT diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index bc380ef0..9a862f37 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -47,6 +47,9 @@ class Battery { // This allows for battery specific SOC plausibility calculations to be performed. virtual bool soc_plausible() { return true; } + // Battery reports total_charged_battery_Wh and total_discharged_battery_Wh + virtual bool supports_charged_energy() { return false; } + virtual BatteryHtmlRenderer& get_status_renderer() { return defaultRenderer; } private: diff --git a/Software/src/battery/MEB-BATTERY.h b/Software/src/battery/MEB-BATTERY.h index 184d5c8f..7895247c 100644 --- a/Software/src/battery/MEB-BATTERY.h +++ b/Software/src/battery/MEB-BATTERY.h @@ -15,6 +15,7 @@ class MebBattery : public CanBattery { virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); bool supports_real_BMS_status() { return true; } + bool supports_charged_energy() { return true; } BatteryHtmlRenderer& get_status_renderer() { return renderer; } diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index cbbab2e3..7b60cb91 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -30,6 +30,8 @@ class TeslaBattery : public CanBattery { bool supports_reset_BMS() { return true; } void reset_BMS() { datalayer.battery.settings.user_requests_tesla_bms_reset = true; } + bool supports_charged_energy() { return true; } + BatteryHtmlRenderer& get_status_renderer() { return renderer; } private: diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 6baaec41..3a28dbce 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -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 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(); - 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(); + 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; }