mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
parent
681f57dfcc
commit
a84a1d6580
9 changed files with 1302 additions and 4 deletions
1
.github/workflows/compile-all-batteries.yml
vendored
1
.github/workflows/compile-all-batteries.yml
vendored
|
@ -51,6 +51,7 @@ jobs:
|
|||
battery:
|
||||
- BMW_I3_BATTERY
|
||||
- BMW_IX_BATTERY
|
||||
- BMW_PHEV_BATTERY
|
||||
- BYD_ATTO_3_BATTERY
|
||||
- CELLPOWER_BMS
|
||||
- CHADEMO_BATTERY
|
||||
|
|
|
@ -56,6 +56,7 @@ jobs:
|
|||
battery:
|
||||
- BMW_I3_BATTERY
|
||||
- BMW_IX_BATTERY
|
||||
- BMW_PHEV_BATTERY
|
||||
- BYD_ATTO_3_BATTERY
|
||||
- CELLPOWER_BMS
|
||||
- CHADEMO_BATTERY
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
/* Select battery used */
|
||||
//#define BMW_I3_BATTERY
|
||||
//#define BMW_IX_BATTERY
|
||||
//#define BMW_PHEV_BATTERY
|
||||
//#define BOLT_AMPERA_BATTERY
|
||||
//#define BYD_ATTO_3_BATTERY
|
||||
//#define CELLPOWER_BMS
|
||||
|
|
|
@ -17,6 +17,10 @@ void setup_can_shunt();
|
|||
#include "BMW-IX-BATTERY.h"
|
||||
#endif
|
||||
|
||||
#ifdef BMW_PHEV_BATTERY
|
||||
#include "BMW-PHEV-BATTERY.h"
|
||||
#endif
|
||||
|
||||
#ifdef BOLT_AMPERA_BATTERY
|
||||
#include "BOLT-AMPERA-BATTERY.h"
|
||||
#endif
|
||||
|
|
1088
Software/src/battery/BMW-PHEV-BATTERY.cpp
Normal file
1088
Software/src/battery/BMW-PHEV-BATTERY.cpp
Normal file
File diff suppressed because it is too large
Load diff
22
Software/src/battery/BMW-PHEV-BATTERY.h
Normal file
22
Software/src/battery/BMW-PHEV-BATTERY.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef BMW_PHEV_BATTERY_H
|
||||
#define BMW_PHEV_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
#define MAX_PACK_VOLTAGE_DV 4650 //4650 = 465.0V
|
||||
#define MIN_PACK_VOLTAGE_DV 3000
|
||||
#define MAX_CELL_DEVIATION_MV 250
|
||||
#define MAX_CELL_VOLTAGE_MV 4300 //Battery is put into emergency stop if one cell goes over this value
|
||||
#define MIN_CELL_VOLTAGE_MV 2800 //Battery is put into emergency stop if one cell goes below this value
|
||||
#define MAX_DISCHARGE_POWER_ALLOWED_W 10000
|
||||
#define MAX_CHARGE_POWER_ALLOWED_W 10000
|
||||
#define MAX_CHARGE_POWER_WHEN_TOPBALANCING_W 500
|
||||
#define RAMPDOWN_SOC 9000 // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00%
|
||||
#define STALE_PERIOD_CONFIG \
|
||||
3600000; //Number of milliseconds before critical values are classed as stale/stuck 1800000 = 3600 seconds / 60mins
|
||||
void setup_battery(void);
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
|
||||
#endif
|
|
@ -64,6 +64,62 @@ typedef struct {
|
|||
|
||||
} DATALAYER_INFO_BMWIX;
|
||||
|
||||
typedef struct {
|
||||
/** uint8_t */
|
||||
/** Status isolation external, 0 not evaluated, 1 OK, 2 error active, 3 Invalid signal*/
|
||||
uint8_t ST_iso_ext = 0;
|
||||
/** uint8_t */
|
||||
/** Status isolation external, 0 not evaluated, 1 OK, 2 error active, 3 Invalid signal*/
|
||||
uint8_t ST_iso_int = 0;
|
||||
/** uint8_t */
|
||||
/** Status cooling valve error, 0 not evaluated, 1 OK valve closed, 2 error active valve open, 3 Invalid signal*/
|
||||
uint8_t ST_valve_cooling = 0;
|
||||
/** uint8_t */
|
||||
/** Status interlock error, 0 not evaluated, 1 OK, 2 error active, 3 Invalid signal*/
|
||||
uint8_t ST_interlock = 0;
|
||||
/** uint8_t */
|
||||
/** Status precharge, 0 no statement, 1 Not active closing not blocked, 2 error precharge blocked, 3 Invalid signal*/
|
||||
uint8_t ST_precharge = 0;
|
||||
/** uint8_t */
|
||||
/** Status DC switch, 0 contactors open, 1 precharge ongoing, 2 contactors engaged, 3 Invalid signal*/
|
||||
uint8_t ST_DCSW = 0;
|
||||
/** uint8_t */
|
||||
/** Status emergency, 0 not evaluated, 1 OK, 2 error active, 3 Invalid signal*/
|
||||
uint8_t ST_EMG = 0;
|
||||
/** uint8_t */
|
||||
/** Status welding detection, 0 Contactors OK, 1 One contactor welded, 2 Two contactors welded, 3 Invalid signal*/
|
||||
uint8_t ST_WELD = 0;
|
||||
/** uint8_t */
|
||||
/** Status isolation, 0 not evaluated, 1 OK, 2 error active, 3 Invalid signal*/
|
||||
uint8_t ST_isolation = 0;
|
||||
/** uint8_t */
|
||||
/** Status cold shutoff valve, 0 OK, 1 Short circuit to GND, 2 Short circuit to 12V, 3 Line break, 6 Driver error, 12 Stuck, 13 Stuck, 15 Invalid Signal*/
|
||||
uint8_t ST_cold_shutoff_valve = 0;
|
||||
/** uint16_t */
|
||||
/** Terminal 30 - 12V SME Supply Voltage */
|
||||
uint16_t T30_Voltage = 0;
|
||||
/** Status HVIL, 1 HVIL OK, 0 HVIL disconnected*/
|
||||
uint8_t hvil_status = 0;
|
||||
/** Min/Max Cell SOH*/
|
||||
uint16_t min_soh_state = 0;
|
||||
uint16_t max_soh_state = 0;
|
||||
int32_t allowable_charge_amps = 0;
|
||||
int32_t allowable_discharge_amps = 0;
|
||||
int16_t balancing_status = 0;
|
||||
int16_t battery_voltage_after_contactor = 0;
|
||||
unsigned long min_cell_voltage_data_age = 0;
|
||||
unsigned long max_cell_voltage_data_age = 0;
|
||||
int32_t iso_safety_int_kohm = 0; //STAT_ISOWIDERSTAND_INT_WERT
|
||||
int32_t iso_safety_ext_kohm = 0; //STAT_ISOWIDERSTAND_EXT_STD_WERT
|
||||
int32_t iso_safety_trg_kohm = 0;
|
||||
int32_t iso_safety_ext_plausible = 0; //STAT_ISOWIDERSTAND_EXT_TRG_PLAUS
|
||||
int32_t iso_safety_int_plausible = 0;
|
||||
int32_t iso_safety_trg_plausible = 0;
|
||||
int32_t iso_safety_kohm = 0; //STAT_R_ISO_ROH_01_WERT
|
||||
int32_t iso_safety_kohm_quality = 0; //STAT_R_ISO_ROH_QAL_01_INFO Quality of measurement 0-21 (higher better)
|
||||
|
||||
} DATALAYER_INFO_BMWPHEV;
|
||||
|
||||
typedef struct {
|
||||
/** uint16_t */
|
||||
/** SOC% raw battery value. Might not always reach 100% */
|
||||
|
@ -619,6 +675,7 @@ class DataLayerExtended {
|
|||
public:
|
||||
DATALAYER_INFO_BOLTAMPERA boltampera;
|
||||
DATALAYER_INFO_BMWIX bmwix;
|
||||
DATALAYER_INFO_BMWPHEV bmwphev;
|
||||
DATALAYER_INFO_BMWI3 bmwi3;
|
||||
DATALAYER_INFO_BYDATTO3 bydAtto3;
|
||||
DATALAYER_INFO_CELLPOWER cellpower;
|
||||
|
|
|
@ -59,6 +59,7 @@ SensorConfig sensorConfigs[] = {
|
|||
{"battery_current", "Battery Current", "{{ value_json.battery_current }}", "A", "current"},
|
||||
{"cell_max_voltage", "Cell Max Voltage", "{{ value_json.cell_max_voltage }}", "V", "voltage"},
|
||||
{"cell_min_voltage", "Cell Min Voltage", "{{ value_json.cell_min_voltage }}", "V", "voltage"},
|
||||
{"cell_voltage_delta", "Cell Voltage Delta", "{{ value_json.cell_voltage_delta }}", "mV", "voltage"},
|
||||
{"battery_voltage", "Battery Voltage", "{{ value_json.battery_voltage }}", "V", "voltage"},
|
||||
{"total_capacity", "Battery Total Capacity", "{{ value_json.total_capacity }}", "Wh", "energy"},
|
||||
{"remaining_capacity", "Battery Remaining Capacity (scaled)", "{{ value_json.remaining_capacity }}", "Wh",
|
||||
|
@ -79,6 +80,7 @@ SensorConfig sensorConfigs[] = {
|
|||
{"battery_current_2", "Battery 2 Current", "{{ value_json.battery_current_2 }}", "A", "current"},
|
||||
{"cell_max_voltage_2", "Cell Max Voltage 2", "{{ value_json.cell_max_voltage_2 }}", "V", "voltage"},
|
||||
{"cell_min_voltage_2", "Cell Min Voltage 2", "{{ value_json.cell_min_voltage_2 }}", "V", "voltage"},
|
||||
{"cell_voltage_delta_2", "Cell Voltage Delta 2", "{{ value_json.cell_voltage_delta_2 }}", "mV", "voltage"},
|
||||
{"battery_voltage_2", "Battery 2 Voltage", "{{ value_json.battery_voltage_2 }}", "V", "voltage"},
|
||||
{"total_capacity_2", "Battery 2 Total Capacity", "{{ value_json.total_capacity_2 }}", "Wh", "energy"},
|
||||
{"remaining_capacity_2", "Battery 2 Remaining Capacity (scaled)", "{{ value_json.remaining_capacity_2 }}", "Wh",
|
||||
|
@ -174,6 +176,8 @@ static void publish_common_info(void) {
|
|||
datalayer.battery.status.cell_voltages_mV[datalayer.battery.info.number_of_cells - 1] != 0u) {
|
||||
doc["cell_max_voltage"] = ((float)datalayer.battery.status.cell_max_voltage_mV) / 1000.0;
|
||||
doc["cell_min_voltage"] = ((float)datalayer.battery.status.cell_min_voltage_mV) / 1000.0;
|
||||
doc["cell_voltage_delta"] = ((float)datalayer.battery.status.cell_max_voltage_mV) -
|
||||
((float)datalayer.battery.status.cell_min_voltage_mV);
|
||||
}
|
||||
doc["total_capacity"] = ((float)datalayer.battery.info.total_capacity_Wh);
|
||||
doc["remaining_capacity_real"] = ((float)datalayer.battery.status.remaining_capacity_Wh);
|
||||
|
@ -197,6 +201,8 @@ static void publish_common_info(void) {
|
|||
datalayer.battery2.status.cell_voltages_mV[datalayer.battery2.info.number_of_cells - 1] != 0u) {
|
||||
doc["cell_max_voltage_2"] = ((float)datalayer.battery2.status.cell_max_voltage_mV) / 1000.0;
|
||||
doc["cell_min_voltage_2"] = ((float)datalayer.battery2.status.cell_min_voltage_mV) / 1000.0;
|
||||
doc["cell_voltage_delta_2"] = ((float)datalayer.battery2.status.cell_max_voltage_mV) -
|
||||
((float)datalayer.battery2.status.cell_min_voltage_mV);
|
||||
}
|
||||
doc["total_capacity_2"] = ((float)datalayer.battery2.info.total_capacity_Wh);
|
||||
doc["remaining_capacity_real_2"] = ((float)datalayer.battery2.status.remaining_capacity_Wh);
|
||||
|
|
|
@ -96,6 +96,123 @@ String advanced_battery_processor(const String& var) {
|
|||
content += "<h4>Pyro Status PSS6: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss6])) + "</h4>";
|
||||
#endif //BMW_IX_BATTERY
|
||||
|
||||
#ifdef BMW_PHEV_BATTERY
|
||||
content +=
|
||||
"<h4>Battery Voltage after Contactor: " + String(datalayer_extended.bmwphev.battery_voltage_after_contactor) +
|
||||
" dV</h4>";
|
||||
content += "<h4>Allowed Discharge Power: " + String(datalayer.battery.status.max_discharge_power_W) + " W</h4>";
|
||||
content += "<h4>Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W</h4>";
|
||||
static const char* balanceText[5] = {"0 Balancing Inactive - Balancing not needed", "1 Balancing Active",
|
||||
"2 Balancing Inactive - Cells not in rest break wait 10mins",
|
||||
"3 Balancing Inactive", "4 Unknown"};
|
||||
content += "<h4>Balancing: " + String((balanceText[datalayer_extended.bmwphev.balancing_status])) + "</h4>";
|
||||
static const char* pyroText[5] = {"0 Value Invalid", "1 Successfully Blown", "2 Disconnected",
|
||||
"3 Not Activated - Pyro Intact", "4 Unknown"};
|
||||
static const char* statusText[16] = {
|
||||
"Not evaluated", "OK", "Error!", "Invalid signal", "", "", "", "", "", "", "", "", "", "", "", ""};
|
||||
content += "<h4>Interlock: " + String(statusText[datalayer_extended.bmwphev.ST_interlock]) + "</h4>";
|
||||
content += "<h4>Isolation external: " + String(statusText[datalayer_extended.bmwphev.ST_iso_ext]) + "</h4>";
|
||||
content += "<h4>Isolation internal: " + String(statusText[datalayer_extended.bmwphev.ST_iso_int]) + "</h4>";
|
||||
content += "<h4>Isolation: " + String(statusText[datalayer_extended.bmwphev.ST_isolation]) + "</h4>";
|
||||
content += "<h4>Cooling valve: " + String(statusText[datalayer_extended.bmwphev.ST_valve_cooling]) + "</h4>";
|
||||
content += "<h4>Emergency: " + String(statusText[datalayer_extended.bmwphev.ST_EMG]) + "</h4>";
|
||||
static const char* prechargeText[16] = {"Not evaluated",
|
||||
"Not active, closing not blocked",
|
||||
"Error precharge blocked",
|
||||
"Invalid signal",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""};
|
||||
content += "<h4>Precharge: " + String(prechargeText[datalayer_extended.bmwphev.ST_precharge]) +
|
||||
"</h4>"; //Still unclear of enum
|
||||
static const char* DCSWText[16] = {"Contactors open",
|
||||
"Precharge ongoing",
|
||||
"Contactors engaged",
|
||||
"Invalid signal",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""};
|
||||
content += "<h4>Contactor status: " + String(DCSWText[datalayer_extended.bmwphev.ST_DCSW]) + "</h4>";
|
||||
static const char* contText[16] = {"Contactors OK",
|
||||
"One contactor welded!",
|
||||
"Two contactors welded!",
|
||||
"Invalid signal",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""};
|
||||
content += "<h4>Contactor weld: " + String(contText[datalayer_extended.bmwphev.ST_WELD]) + "</h4>";
|
||||
static const char* valveText[16] = {"OK",
|
||||
"Short circuit to GND",
|
||||
"Short circuit to 12V",
|
||||
"Line break",
|
||||
"",
|
||||
"",
|
||||
"Driver error",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Stuck",
|
||||
"Stuck",
|
||||
"",
|
||||
"Invalid Signal"};
|
||||
content +=
|
||||
"<h4>Cold shutoff valve: " + String(valveText[datalayer_extended.bmwphev.ST_cold_shutoff_valve]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Min Cell Voltage Data Age: " + String(datalayer_extended.bmwphev.min_cell_voltage_data_age) + " ms</h4>";
|
||||
content +=
|
||||
"<h4>Max Cell Voltage Data Age: " + String(datalayer_extended.bmwphev.max_cell_voltage_data_age) + " ms</h4>";
|
||||
content += "<h4>Max Design Voltage: " + String(datalayer.battery.info.max_design_voltage_dV) + " dV</h4>";
|
||||
content += "<h4>Min Design Voltage: " + String(datalayer.battery.info.min_design_voltage_dV) + " dV</h4>";
|
||||
content += "<h4>BMS Allowed Charge Amps: " + String(datalayer_extended.bmwphev.allowable_charge_amps) + " A</h4>";
|
||||
content +=
|
||||
"<h4>BMS Allowed Disharge Amps: " + String(datalayer_extended.bmwphev.allowable_discharge_amps) + " A</h4>";
|
||||
content += "<h4>Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "</h4>";
|
||||
content += "<h4>iso_safety_int_kohm: " + String(datalayer_extended.bmwphev.iso_safety_int_kohm) + "</h4>";
|
||||
content += "<h4>iso_safety_ext_kohm: " + String(datalayer_extended.bmwphev.iso_safety_ext_kohm) + "</h4>";
|
||||
content += "<h4>iso_safety_trg_kohm: " + String(datalayer_extended.bmwphev.iso_safety_trg_kohm) + "</h4>";
|
||||
content += "<h4>iso_safety_ext_plausible: " + String(datalayer_extended.bmwphev.iso_safety_ext_plausible) + "</h4>";
|
||||
content += "<h4>iso_safety_int_plausible: " + String(datalayer_extended.bmwphev.iso_safety_int_plausible) + "</h4>";
|
||||
content += "<h4>iso_safety_trg_plausible: " + String(datalayer_extended.bmwphev.iso_safety_trg_plausible) + "</h4>";
|
||||
content += "<h4>iso_safety_kohm: " + String(datalayer_extended.bmwphev.iso_safety_kohm) + "</h4>";
|
||||
content += "<h4>iso_safety_kohm_quality: " + String(datalayer_extended.bmwphev.iso_safety_kohm_quality) + "</h4>";
|
||||
content += "<br>";
|
||||
content += "<h4>Todo";
|
||||
content += "<br>";
|
||||
content += "<h4>Max Cell Design Voltage: " + String(datalayer.battery.info.max_cell_voltage_mV) + " mV</h4>";
|
||||
content += "<h4>Min Cell Design Voltage: " + String(datalayer.battery.info.min_cell_voltage_mV) + " mV</h4>";
|
||||
content += "<h4>T30 Terminal Voltage: " + String(datalayer_extended.bmwphev.T30_Voltage) + " mV</h4>";
|
||||
content += "<br>";
|
||||
#endif //BMW_PHEV_BATTERY
|
||||
|
||||
#ifdef BMW_I3_BATTERY
|
||||
content += "<h4>SOC raw: " + String(datalayer_extended.bmwi3.SOC_raw) + "</h4>";
|
||||
content += "<h4>SOC dash: " + String(datalayer_extended.bmwi3.SOC_dash) + "</h4>";
|
||||
|
@ -1139,10 +1256,11 @@ String advanced_battery_processor(const String& var) {
|
|||
content += "<button onclick='Volvo_BECMecuReset()'>Restart BECM module</button>";
|
||||
#endif // VOLVO_SPA_BATTERY
|
||||
|
||||
#if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_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(MEB_BATTERY) && \
|
||||
!defined(VOLVO_SPA_BATTERY) && !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info
|
||||
#if !defined(BMW_PHEV_BATTERY) && !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_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(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && \
|
||||
!defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info
|
||||
content += "No extra information available for this battery type";
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue