Add more Stellantis info

This commit is contained in:
Daniel Öster 2025-05-10 19:56:36 +03:00
parent 0967f7cab1
commit 801bce9d8b
3 changed files with 62 additions and 18 deletions

View file

@ -2,16 +2,15 @@
#ifdef STELLANTIS_ECMP_BATTERY #ifdef STELLANTIS_ECMP_BATTERY
#include <algorithm> // For std::min and std::max #include <algorithm> // For std::min and std::max
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For More Battery Info page
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "ECMP-BATTERY.h" #include "ECMP-BATTERY.h"
/* TODO: /* TODO:
This integration is still ongoing. Here is what still needs to be done in order to use this battery type This integration is still ongoing. Here is what still needs to be done in order to use this battery type
- Find battery voltage
- Find/estimate charge/discharge limits
- Find temperature
- Figure out contactor closing - Figure out contactor closing
- Which CAN messages need to be sent towards the battery? - Which CAN messages need to be sent towards the battery?
- Handle 54/70kWh cellcounting properly
*/ */
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
@ -27,6 +26,13 @@ CAN_frame ECMP_XXX = {.FD = false,
static uint16_t battery_voltage = 37000; static uint16_t battery_voltage = 37000;
static uint16_t battery_soc = 0; static uint16_t battery_soc = 0;
static int16_t battery_current = 0; static int16_t battery_current = 0;
static uint8_t battery_MainConnectorState = 0;
static bool battery_RelayOpenRequest = false;
static uint16_t battery_AllowedMaxChargeCurrent = 0;
static uint16_t battery_AllowedMaxDischargeCurrent = 0;
static uint16_t battery_insulationResistanceKOhm = 0;
static int16_t battery_highestTemperature = 0;
static int16_t battery_lowestTemperature = 0;
static uint16_t cellvoltages[108]; static uint16_t cellvoltages[108];
void update_values_battery() { void update_values_battery() {
@ -35,20 +41,20 @@ void update_values_battery() {
datalayer.battery.status.soh_pptt; datalayer.battery.status.soh_pptt;
datalayer.battery.status.voltage_dV = (battery_voltage / 10); datalayer.battery.status.voltage_dV = battery_voltage * 10;
datalayer.battery.status.current_dA = battery_current * 10; datalayer.battery.status.current_dA = battery_current * 10;
datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100); ((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
datalayer.battery.status.max_charge_power_W; datalayer.battery.status.max_charge_power_W = battery_AllowedMaxChargeCurrent * battery_voltage;
datalayer.battery.status.max_discharge_power_W; datalayer.battery.status.max_discharge_power_W = battery_AllowedMaxDischargeCurrent * battery_voltage;
datalayer.battery.status.temperature_min_dC; datalayer.battery.status.temperature_min_dC = battery_lowestTemperature * 10;
datalayer.battery.status.temperature_max_dC; datalayer.battery.status.temperature_max_dC = battery_highestTemperature * 10;
// Initialize min and max, lets find which cells are min and max! // Initialize min and max, lets find which cells are min and max!
uint16_t min_cell_mv_value = std::numeric_limits<uint16_t>::max(); uint16_t min_cell_mv_value = std::numeric_limits<uint16_t>::max();
@ -69,29 +75,46 @@ void update_values_battery() {
datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value;
datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value;
// Update extended datalayer (More Battery Info page)
datalayer_extended.stellantisECMP.MainConnectorState = battery_MainConnectorState;
datalayer_extended.stellantisECMP.InsulationResistance = battery_insulationResistanceKOhm;
} }
void handle_incoming_can_frame_battery(CAN_frame rx_frame) { void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
switch (rx_frame.ID) { switch (rx_frame.ID) {
case 0x125: case 0x125: //Common
battery_soc = (rx_frame.data.u8[0] << 2) | battery_soc = (rx_frame.data.u8[0] << 2) |
(rx_frame.data.u8[1] >> 6); // Byte1, bit 7 length 10 (0x3FE when abnormal) (0-1000 ppt) (rx_frame.data.u8[1] >> 6); // Byte1, bit 7 length 10 (0x3FE when abnormal) (0-1000 ppt)
battery_MainConnectorState = ((rx_frame.data.u8[2] & 0x30) >>
4); //Byte2 , bit 4, length 2 ((00 contactors open, 01 precharged, 11 invalid))
battery_voltage =
(rx_frame.data.u8[3] << 1) | (rx_frame.data.u8[4] >> 7); //Byte 4, bit 7, length 9 (0x1FE if invalid)
battery_current = (((rx_frame.data.u8[4] & 0x7F) << 5) | (rx_frame.data.u8[5] >> 3)) - battery_current = (((rx_frame.data.u8[4] & 0x7F) << 5) | (rx_frame.data.u8[5] >> 3)) -
600; // Byte5, Bit 3 length 12 (0xFFE when abnormal) (-600 to 600 , offset -600) 600; // Byte5, Bit 3 length 12 (0xFFE when abnormal) (-600 to 600 , offset -600)
//battery_RelayOpenRequest = // Byte 5, bit 6, length 1 (0 no request, 1 battery requests contactor opening)
//Stellantis doc seems wrong, could Byte5 be misspelled as Byte2? Bit will otherwise collide with battery_current
break; break;
case 0x127: case 0x127: //DFM specific
battery_AllowedMaxChargeCurrent =
(rx_frame.data.u8[0] << 2) |
((rx_frame.data.u8[1] & 0xC0) >> 6); //Byte 1, bit 7, length 10 (0-600A) [0x3FF if invalid]
battery_AllowedMaxDischargeCurrent =
((rx_frame.data.u8[2] & 0x3F) << 4) |
(rx_frame.data.u8[3] >> 4); //Byte 2, bit 5, length 10 (0-600A) [0x3FF if invalid]
break; break;
case 0x129: case 0x129: //PSA specific
break; break;
case 0x31B: case 0x31B:
break; break;
case 0x358: case 0x358: //Common
battery_highestTemperature = rx_frame.data.u8[6] - 40;
battery_lowestTemperature = rx_frame.data.u8[7] - 40;
break; break;
case 0x359: case 0x359:
break; break;
case 0x361: case 0x361:
battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; //TODO, not confirmed
break; break;
case 0x362: case 0x362:
break; break;
@ -101,7 +124,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break; break;
case 0x594: case 0x594:
break; break;
case 0x6D0: case 0x6D0: //Common
battery_insulationResistanceKOhm =
(rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; //Byte 2, bit 7, length 16 (0-60000 kOhm)
break; break;
case 0x6D1: case 0x6D1:
break; break;
@ -298,9 +323,8 @@ void transmit_can_battery(unsigned long currentMillis) {
} }
void setup_battery(void) { // Performs one time setup at startup void setup_battery(void) { // Performs one time setup at startup
#ifdef DEBUG_VIA_USB strncpy(datalayer.system.info.battery_protocol, "Stellantis ECMP battery", 63);
Serial.println("ECMP battery selected"); datalayer.system.info.battery_protocol[63] = '\0';
#endif
datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.number_of_cells = 108;
datalayer.battery.info.max_design_voltage_dV = 4546; // 454.6V, charging over this is not possible datalayer.battery.info.max_design_voltage_dV = 4546; // 454.6V, charging over this is not possible
datalayer.battery.info.min_design_voltage_dV = 3210; // 321.0V, under this, discharging further is disabled datalayer.battery.info.min_design_voltage_dV = 3210; // 321.0V, under this, discharging further is disabled

View file

@ -290,6 +290,11 @@ typedef struct {
uint64_t cumulative_energy_in_regen = 0; uint64_t cumulative_energy_in_regen = 0;
} DATALAYER_INFO_CMFAEV; } DATALAYER_INFO_CMFAEV;
typedef struct {
uint8_t MainConnectorState = 0;
uint16_t InsulationResistance = 0;
} DATALAYER_INFO_ECMP;
typedef struct { typedef struct {
uint8_t total_cell_count = 0; uint8_t total_cell_count = 0;
int16_t battery_12V = 0; int16_t battery_12V = 0;
@ -775,6 +780,7 @@ class DataLayerExtended {
DATALAYER_INFO_BYDATTO3 bydAtto3; DATALAYER_INFO_BYDATTO3 bydAtto3;
DATALAYER_INFO_CELLPOWER cellpower; DATALAYER_INFO_CELLPOWER cellpower;
DATALAYER_INFO_CMFAEV CMFAEV; DATALAYER_INFO_CMFAEV CMFAEV;
DATALAYER_INFO_ECMP stellantisECMP;
DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64; DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64;
DATALAYER_INFO_TESLA tesla; DATALAYER_INFO_TESLA tesla;
DATALAYER_INFO_NISSAN_LEAF nissanleaf; DATALAYER_INFO_NISSAN_LEAF nissanleaf;

View file

@ -456,6 +456,19 @@ String advanced_battery_processor(const String& var) {
"<h4>Cumulative energy regen: " + String(datalayer_extended.CMFAEV.cumulative_energy_in_regen) + "Wh</h4>"; "<h4>Cumulative energy regen: " + String(datalayer_extended.CMFAEV.cumulative_energy_in_regen) + "Wh</h4>";
#endif //CMFA_EV_BATTERY #endif //CMFA_EV_BATTERY
#ifdef STELLANTIS_ECMP_BATTERY
content += "<h4>Main Connector State: ";
if (datalayer_extended.stellantisECMP.MainConnectorState == 0) {
content += "Contactors open</h4>";
} else if (datalayer_extended.stellantisECMP.MainConnectorState == 0x01) {
content += "Precharged</h4>";
} else {
content += "Invalid</h4>";
}
content +=
"<h4>Insulation Resistance: " + String(datalayer_extended.stellantisECMP.InsulationResistance) + "kOhm</h4>";
#endif //STELLANTIS_ECMP_BATTERY
#ifdef KIA_HYUNDAI_64_BATTERY #ifdef KIA_HYUNDAI_64_BATTERY
content += "<h4>Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S</h4>"; content += "<h4>Cells: " + String(datalayer_extended.KiaHyundai64.total_cell_count) + "S</h4>";
content += "<h4>12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V / 10.0, 1) + "</h4>"; content += "<h4>12V voltage: " + String(datalayer_extended.KiaHyundai64.battery_12V / 10.0, 1) + "</h4>";
@ -1487,7 +1500,8 @@ String advanced_battery_processor(const String& var) {
!defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \
!defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \
!defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \ !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \
!defined(KIA_HYUNDAI_64_BATTERY) && !defined(CMFA_EV_BATTERY) //Only the listed types have extra info !defined(KIA_HYUNDAI_64_BATTERY) && !defined(CMFA_EV_BATTERY) && \
!defined(STELLANTIS_ECMP_BATTERY) //Only the listed types have extra info
content += "No extra information available for this battery type"; content += "No extra information available for this battery type";
#endif #endif