mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 02:39:57 +02:00
Add more Stellantis info
This commit is contained in:
parent
0967f7cab1
commit
801bce9d8b
3 changed files with 62 additions and 18 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue