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
#include <algorithm> // For std::min and std::max
#include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h" //For More Battery Info page
#include "../devboard/utils/events.h"
#include "ECMP-BATTERY.h"
/* TODO:
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
- 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 */
@ -27,6 +26,13 @@ CAN_frame ECMP_XXX = {.FD = false,
static uint16_t battery_voltage = 37000;
static uint16_t battery_soc = 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];
void update_values_battery() {
@ -35,20 +41,20 @@ void update_values_battery() {
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.active_power_W = //Power in watts, Negative = charging batt
((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!
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_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) {
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
switch (rx_frame.ID) {
case 0x125:
case 0x125: //Common
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)
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)) -
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;
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;
case 0x129:
case 0x129: //PSA specific
break;
case 0x31B:
break;
case 0x358:
case 0x358: //Common
battery_highestTemperature = rx_frame.data.u8[6] - 40;
battery_lowestTemperature = rx_frame.data.u8[7] - 40;
break;
case 0x359:
break;
case 0x361:
battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; //TODO, not confirmed
break;
case 0x362:
break;
@ -101,7 +124,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break;
case 0x594:
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;
case 0x6D1:
break;
@ -298,9 +323,8 @@ void transmit_can_battery(unsigned long currentMillis) {
}
void setup_battery(void) { // Performs one time setup at startup
#ifdef DEBUG_VIA_USB
Serial.println("ECMP battery selected");
#endif
strncpy(datalayer.system.info.battery_protocol, "Stellantis ECMP battery", 63);
datalayer.system.info.battery_protocol[63] = '\0';
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.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;
} DATALAYER_INFO_CMFAEV;
typedef struct {
uint8_t MainConnectorState = 0;
uint16_t InsulationResistance = 0;
} DATALAYER_INFO_ECMP;
typedef struct {
uint8_t total_cell_count = 0;
int16_t battery_12V = 0;
@ -775,6 +780,7 @@ class DataLayerExtended {
DATALAYER_INFO_BYDATTO3 bydAtto3;
DATALAYER_INFO_CELLPOWER cellpower;
DATALAYER_INFO_CMFAEV CMFAEV;
DATALAYER_INFO_ECMP stellantisECMP;
DATALAYER_INFO_KIAHYUNDAI64 KiaHyundai64;
DATALAYER_INFO_TESLA tesla;
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>";
#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
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>";
@ -1487,7 +1500,8 @@ String advanced_battery_processor(const String& var) {
!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(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";
#endif