Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add Beta BMW PHEV Support #804

Merged
merged 35 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a9c37d1
Initial PHEV Demo
wjcloudy Jan 6, 2025
9b25921
add user setting for phev
wjcloudy Jan 6, 2025
5e54ee2
balancing status support
wjcloudy Jan 6, 2025
aa0a92e
Enable balancing
wjcloudy Jan 7, 2025
33c0705
Cell rest break status added
wjcloudy Jan 7, 2025
9301648
extra balancing status
wjcloudy Jan 7, 2025
2ebc42e
formatting fix
wjcloudy Jan 7, 2025
d2e8e51
Various improvements
wjcloudy Jan 7, 2025
484fa62
fixes
wjcloudy Jan 7, 2025
253b383
fixes/cleanup
wjcloudy Jan 7, 2025
01f11c3
add more values
wjcloudy Jan 8, 2025
5d3362c
advanced values fix
wjcloudy Jan 8, 2025
ba1845e
Add UDS Multi-frame, cell voltages, min max and SOH
wjcloudy Jan 8, 2025
5347909
add battery design voltage
wjcloudy Jan 8, 2025
5a65b22
add Can Alive messages
wjcloudy Jan 8, 2025
a584499
Merge pull request #773 from dalathegreat/main
wjcloudy Jan 9, 2025
8998dc4
Publish Cell Delta Value for Battery 1 + 2
wjcloudy Jan 9, 2025
533b13f
96 Cell default for now
wjcloudy Jan 9, 2025
1751798
Cleanup & Fix
wjcloudy Jan 10, 2025
bafe5cb
Stale allowance change
wjcloudy Jan 10, 2025
18596c9
Valve state text fix
wjcloudy Jan 10, 2025
b57ab8b
Add sanity checks to cell temps.
wjcloudy Jan 10, 2025
3d0d576
Add battery wakeup support (Native CAN only)
wjcloudy Jan 11, 2025
5de4b1e
Formatting fixes for wakeup support
wjcloudy Jan 11, 2025
551e1af
Ignore invalid cell temps
wjcloudy Jan 11, 2025
55d8565
Merge pull request #783 from dalathegreat/main
wjcloudy Jan 11, 2025
7d08e42
Small fixes and cleanup
wjcloudy Jan 12, 2025
218d260
Merge branch 'main' into feature/bmw-phev-sme-support
wjcloudy Jan 12, 2025
47eb917
Merge branch 'main' into feature/bmw-phev-sme-support
wjcloudy Jan 12, 2025
b7e42a0
Fix errors on startup
wjcloudy Jan 12, 2025
b348fc3
Fixes for invalid values and stale tracker
wjcloudy Jan 14, 2025
991ee02
Add isolation Test
wjcloudy Jan 15, 2025
28591ae
Only fast poll values that change quickly
wjcloudy Jan 15, 2025
3ec9de9
Add BMW-PHEV to the build system
wjcloudy Jan 19, 2025
8c2e299
Add PHEV to all combination workflow
wjcloudy Jan 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/compile-all-batteries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
battery:
- BMW_I3_BATTERY
- BMW_IX_BATTERY
- BMW_PHEV_BATTERY
- BYD_ATTO_3_BATTERY
- CELLPOWER_BMS
- CHADEMO_BATTERY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
battery:
- BMW_I3_BATTERY
- BMW_IX_BATTERY
- BMW_PHEV_BATTERY
- BYD_ATTO_3_BATTERY
- CELLPOWER_BMS
- CHADEMO_BATTERY
Expand Down
1 change: 1 addition & 0 deletions Software/USER_SETTINGS.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Software/src/battery/BATTERIES.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1,088 changes: 1,088 additions & 0 deletions Software/src/battery/BMW-PHEV-BATTERY.cpp

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions Software/src/battery/BMW-PHEV-BATTERY.h
Original file line number Diff line number Diff line change
@@ -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
57 changes: 57 additions & 0 deletions Software/src/datalayer/datalayer_extended.h
Original file line number Diff line number Diff line change
Expand Up @@ -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% */
Expand Down Expand Up @@ -614,6 +670,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;
Expand Down
6 changes: 6 additions & 0 deletions Software/src/devboard/mqtt/mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
126 changes: 122 additions & 4 deletions Software/src/devboard/webserver/advanced_battery_html.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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>";
Expand Down Expand Up @@ -1142,10 +1259,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

Expand Down
Loading