Merge pull request #1370 from dalathegreat/feature/stellantis-contactors-event

Stellantis: Add SOH candidate and contactor opening event
This commit is contained in:
Daniel Öster 2025-07-31 14:51:41 +03:00 committed by GitHub
commit a547fb201e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 52 additions and 3 deletions

View file

@ -123,6 +123,7 @@ void EcmpBattery::update_values() {
datalayer_extended.stellantisECMP.pid_time_spent_over_55c = pid_time_spent_over_55c;
datalayer_extended.stellantisECMP.pid_contactor_closing_counter = pid_contactor_closing_counter;
datalayer_extended.stellantisECMP.pid_date_of_manufacture = pid_date_of_manufacture;
datalayer_extended.stellantisECMP.pid_SOH_cell_1 = pid_SOH_cell_1;
if (battery_InterlockOpen) {
set_event(EVENT_HVIL_FAILURE, 0);
@ -135,6 +136,12 @@ void EcmpBattery::update_values() {
} else {
clear_event(EVENT_12V_LOW);
}
if (pid_reason_open == 7) { //Invalid status
set_event(EVENT_CONTACTOR_OPEN, 0);
} else {
clear_event(EVENT_CONTACTOR_OPEN);
}
}
void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
@ -578,8 +585,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
(rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
break;
case PID_ENERGY_CAPACITY:
pid_energy_capacity = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) |
(rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
pid_energy_capacity = (rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6]);
break;
case PID_HIGH_CELL_NUM:
pid_highest_cell_voltage_num = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
@ -720,6 +726,33 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (incoming_poll) //Multiframe responses
{
case PID_ALL_CELL_SOH:
switch (rx_frame.data.u8[0]) {
case 0x10:
pid_SOH_cell_1 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
break;
case 0x21:
break;
case 0x22:
break;
case 0x23:
break;
case 0x24:
break;
case 0x25:
break;
case 0x26:
break;
case 0x27:
break;
case 0x28:
break;
case 0x29:
break;
default:
break;
}
break;
case PID_ALL_CELL_VOLTAGES:
switch (rx_frame.data.u8[0]) {
case 0x10:
@ -1291,6 +1324,11 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
case PID_DATE_OF_MANUFACTURE:
ECMP_POLL.data.u8[2] = (uint8_t)((PID_DATE_OF_MANUFACTURE & 0xFF00) >> 8);
ECMP_POLL.data.u8[3] = (uint8_t)(PID_DATE_OF_MANUFACTURE & 0x00FF);
poll_state = PID_ALL_CELL_SOH;
break;
case PID_ALL_CELL_SOH:
ECMP_POLL.data.u8[2] = (uint8_t)((PID_ALL_CELL_SOH & 0xFF00) >> 8);
ECMP_POLL.data.u8[3] = (uint8_t)(PID_ALL_CELL_SOH & 0x00FF);
poll_state = PID_WELD_CHECK; // Loop back to beginning
break;
default:

View file

@ -136,6 +136,7 @@ class EcmpBattery : public CanBattery {
uint32_t pid_time_spent_over_55c = NOT_SAMPLED_YET;
uint32_t pid_contactor_closing_counter = NOT_SAMPLED_YET;
uint32_t pid_date_of_manufacture = NOT_SAMPLED_YET;
uint16_t pid_SOH_cell_1 = NOT_SAMPLED_YET;
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent
@ -197,7 +198,7 @@ class EcmpBattery : public CanBattery {
static const uint16_t PID_SW_VERSION_NUM = 0xF195; //Not supported on all batteris
static const uint16_t PID_FACTORY_MODE_CONTROL = 0xD900;
static const uint16_t PID_BATTERY_SERIAL = 0xD901;
static const uint16_t PID_ALL_CELL_SOH = 0xD4B5; //Very long message reply, too much data for this integration
static const uint16_t PID_ALL_CELL_SOH = 0xD4B5;
static const uint16_t PID_AUX_FUSE_STATE = 0xD86C;
static const uint16_t PID_BATTERY_STATE = 0xD811;
static const uint16_t PID_PRECHARGE_SHORT_CIRCUIT = 0xD4D8;

View file

@ -376,6 +376,11 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer {
? "N/A"
: String(datalayer_extended.stellantisECMP.pid_contactor_closing_counter)) +
" cycles</h4>";
content += "<h4>State of Health Cell-1: " +
(datalayer_extended.stellantisECMP.pid_SOH_cell_1 == 255
? "N/A"
: String(datalayer_extended.stellantisECMP.pid_SOH_cell_1)) +
"</h4>";
return content;
}

View file

@ -312,6 +312,7 @@ typedef struct {
uint32_t pid_time_spent_over_55c = 0;
uint32_t pid_contactor_closing_counter = 0;
uint32_t pid_date_of_manufacture = 0;
uint16_t pid_SOH_cell_1 = 0;
} DATALAYER_INFO_ECMP;
typedef struct {

View file

@ -40,6 +40,7 @@ void init_events(void) {
events.entries[EVENT_CAN_CHARGER_MISSING].level = EVENT_LEVEL_INFO;
events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CONTACTOR_WELDED].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CONTACTOR_OPEN].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CPU_OVERHEATING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CPU_OVERHEATED].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR;
@ -191,6 +192,8 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Inverter not sending messages via CAN for the last 60 seconds. Check wiring!";
case EVENT_CONTACTOR_WELDED:
return "Contactors sticking/welded. Inspect battery with caution!";
case EVENT_CONTACTOR_OPEN:
return "Battery decided to open contactors. Inspect battery!";
case EVENT_CPU_OVERHEATING:
return "Battery-Emulator CPU overheating! Increase airflow/cooling to increase hardware lifespan!";
case EVENT_CPU_OVERHEATED:

View file

@ -22,6 +22,7 @@
XX(EVENT_CAN_NATIVE_TX_FAILURE) \
XX(EVENT_CHARGE_LIMIT_EXCEEDED) \
XX(EVENT_CONTACTOR_WELDED) \
XX(EVENT_CONTACTOR_OPEN) \
XX(EVENT_CPU_OVERHEATING) \
XX(EVENT_CPU_OVERHEATED) \
XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \