mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Merge and fix conflicts
This commit is contained in:
commit
57f8d2618e
25 changed files with 2383 additions and 227 deletions
|
@ -50,7 +50,7 @@
|
|||
volatile unsigned long long bmsResetTimeOffset = 0;
|
||||
|
||||
// The current software version, shown on webserver
|
||||
const char* version_number = "8.14.dev";
|
||||
const char* version_number = "8.15.dev";
|
||||
|
||||
// Interval timers
|
||||
volatile unsigned long currentMillis = 0;
|
||||
|
@ -123,6 +123,8 @@ void setup() {
|
|||
// Start tasks
|
||||
|
||||
#ifdef MQTT
|
||||
init_mqtt();
|
||||
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task,
|
||||
WIFI_CORE);
|
||||
#endif
|
||||
|
@ -191,8 +193,6 @@ void connectivity_loop(void*) {
|
|||
void mqtt_loop(void*) {
|
||||
esp_task_wdt_add(NULL); // Register this task with WDT
|
||||
|
||||
init_mqtt();
|
||||
|
||||
while (true) {
|
||||
START_TIME_MEASUREMENT(mqtt);
|
||||
mqtt_loop();
|
||||
|
|
|
@ -73,14 +73,17 @@ class Battery {
|
|||
virtual bool supports_reset_SOH() { return false; }
|
||||
virtual bool supports_reset_BECM() { return false; }
|
||||
virtual bool supports_contactor_close() { return false; }
|
||||
virtual bool supports_contactor_reset() { return false; }
|
||||
virtual bool supports_set_fake_voltage() { return false; }
|
||||
virtual bool supports_manual_balancing() { return false; }
|
||||
virtual bool supports_real_BMS_status() { return false; }
|
||||
virtual bool supports_toggle_SOC_method() { return false; }
|
||||
virtual bool supports_factory_mode_method() { return false; }
|
||||
|
||||
virtual void clear_isolation() {}
|
||||
virtual void reset_BMS() {}
|
||||
virtual void reset_crash() {}
|
||||
virtual void reset_contactor() {}
|
||||
virtual void reset_NVROL() {}
|
||||
virtual void reset_DTC() {}
|
||||
virtual void read_DTC() {}
|
||||
|
@ -89,6 +92,7 @@ class Battery {
|
|||
virtual void request_open_contactors() {}
|
||||
virtual void request_close_contactors() {}
|
||||
virtual void toggle_SOC_method() {}
|
||||
virtual void set_factory_mode() {}
|
||||
|
||||
virtual void set_fake_voltage(float v) {}
|
||||
virtual float get_voltage() { return static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0; }
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,18 @@ class EcmpBattery : public CanBattery {
|
|||
virtual void update_values();
|
||||
virtual void transmit_can(unsigned long currentMillis);
|
||||
|
||||
bool supports_clear_isolation() { return true; }
|
||||
void clear_isolation() { datalayer_extended.stellantisECMP.UserRequestIsolationReset = true; }
|
||||
|
||||
bool supports_factory_mode_method() { return true; }
|
||||
void set_factory_mode() { datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = true; }
|
||||
|
||||
bool supports_reset_crash() { return true; }
|
||||
void reset_crash() { datalayer_extended.stellantisECMP.UserRequestCollisionReset = true; }
|
||||
|
||||
bool supports_contactor_reset() { return true; }
|
||||
void reset_contactor() { datalayer_extended.stellantisECMP.UserRequestContactorReset = true; }
|
||||
|
||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||
|
||||
private:
|
||||
|
@ -26,9 +38,25 @@ class EcmpBattery : public CanBattery {
|
|||
static const int MAX_CELL_DEVIATION_MV = 100;
|
||||
static const int MAX_CELL_VOLTAGE_MV = 4250;
|
||||
static const int MIN_CELL_VOLTAGE_MV = 2700;
|
||||
|
||||
#define NOT_SAMPLED_YET 255
|
||||
#define COMPLETED_STATE 0
|
||||
bool battery_RelayOpenRequest = false;
|
||||
bool battery_InterlockOpen = false;
|
||||
uint8_t ContactorResetStatemachine = 0;
|
||||
uint8_t CollisionResetStatemachine = 0;
|
||||
uint8_t IsolationResetStatemachine = 0;
|
||||
uint8_t DisableIsoMonitoringStatemachine = 0;
|
||||
uint8_t timeSpentDisableIsoMonitoring = 0;
|
||||
uint8_t timeSpentContactorReset = 0;
|
||||
uint8_t timeSpentCollisionReset = 0;
|
||||
uint8_t timeSpentIsolationReset = 0;
|
||||
uint8_t countIsolationReset = 0;
|
||||
uint8_t counter_10ms = 0;
|
||||
uint8_t counter_20ms = 0;
|
||||
uint8_t counter_50ms = 0;
|
||||
uint8_t counter_100ms = 0;
|
||||
uint8_t counter_010 = 0;
|
||||
uint32_t ticks_552 = 0x0BC8CFC6;
|
||||
uint8_t battery_MainConnectorState = 0;
|
||||
int16_t battery_current = 0;
|
||||
uint16_t battery_voltage = 370;
|
||||
|
@ -37,27 +65,368 @@ class EcmpBattery : public CanBattery {
|
|||
uint16_t battery_AllowedMaxChargeCurrent = 0;
|
||||
uint16_t battery_AllowedMaxDischargeCurrent = 0;
|
||||
uint16_t battery_insulationResistanceKOhm = 0;
|
||||
uint8_t battery_insulation_failure_diag = 0;
|
||||
int16_t battery_highestTemperature = 0;
|
||||
int16_t battery_lowestTemperature = 0;
|
||||
uint8_t pid_welding_detection = NOT_SAMPLED_YET;
|
||||
uint8_t pid_reason_open = NOT_SAMPLED_YET;
|
||||
uint8_t pid_contactor_status = NOT_SAMPLED_YET;
|
||||
uint8_t pid_negative_contactor_control = NOT_SAMPLED_YET;
|
||||
uint8_t pid_negative_contactor_status = NOT_SAMPLED_YET;
|
||||
uint8_t pid_positive_contactor_control = NOT_SAMPLED_YET;
|
||||
uint8_t pid_positive_contactor_status = NOT_SAMPLED_YET;
|
||||
uint8_t pid_contactor_negative = NOT_SAMPLED_YET;
|
||||
uint8_t pid_contactor_positive = NOT_SAMPLED_YET;
|
||||
uint8_t pid_precharge_relay_control = NOT_SAMPLED_YET;
|
||||
uint8_t pid_precharge_relay_status = NOT_SAMPLED_YET;
|
||||
uint8_t pid_recharge_status = NOT_SAMPLED_YET;
|
||||
uint8_t pid_delta_temperature = NOT_SAMPLED_YET;
|
||||
uint8_t pid_coldest_module = NOT_SAMPLED_YET;
|
||||
uint8_t pid_lowest_temperature = NOT_SAMPLED_YET;
|
||||
uint8_t pid_average_temperature = NOT_SAMPLED_YET;
|
||||
uint8_t pid_highest_temperature = NOT_SAMPLED_YET;
|
||||
uint8_t pid_hottest_module = NOT_SAMPLED_YET;
|
||||
uint16_t pid_avg_cell_voltage = NOT_SAMPLED_YET;
|
||||
int32_t pid_current = NOT_SAMPLED_YET;
|
||||
uint32_t pid_insulation_res_neg = NOT_SAMPLED_YET;
|
||||
uint32_t pid_insulation_res_pos = NOT_SAMPLED_YET;
|
||||
uint32_t pid_max_current_10s = NOT_SAMPLED_YET;
|
||||
uint32_t pid_max_discharge_10s = NOT_SAMPLED_YET;
|
||||
uint32_t pid_max_discharge_30s = NOT_SAMPLED_YET;
|
||||
uint32_t pid_max_charge_10s = NOT_SAMPLED_YET;
|
||||
uint32_t pid_max_charge_30s = NOT_SAMPLED_YET;
|
||||
uint32_t pid_energy_capacity = NOT_SAMPLED_YET;
|
||||
uint8_t pid_highest_cell_voltage_num = NOT_SAMPLED_YET;
|
||||
uint8_t pid_lowest_cell_voltage_num = NOT_SAMPLED_YET;
|
||||
uint16_t pid_sum_of_cells = NOT_SAMPLED_YET;
|
||||
uint16_t pid_cell_min_capacity = NOT_SAMPLED_YET;
|
||||
uint8_t pid_cell_voltage_measurement_status = NOT_SAMPLED_YET;
|
||||
uint32_t pid_insulation_res = NOT_SAMPLED_YET;
|
||||
uint16_t pid_pack_voltage = NOT_SAMPLED_YET;
|
||||
uint16_t pid_high_cell_voltage = NOT_SAMPLED_YET;
|
||||
uint16_t pid_low_cell_voltage = NOT_SAMPLED_YET;
|
||||
uint8_t pid_battery_energy = NOT_SAMPLED_YET;
|
||||
uint32_t pid_crash_counter = NOT_SAMPLED_YET;
|
||||
uint8_t pid_wire_crash = NOT_SAMPLED_YET;
|
||||
uint8_t pid_CAN_crash = NOT_SAMPLED_YET;
|
||||
uint32_t pid_history_data = NOT_SAMPLED_YET;
|
||||
uint32_t pid_lowsoc_counter = NOT_SAMPLED_YET;
|
||||
uint32_t pid_last_can_failure_detail = NOT_SAMPLED_YET;
|
||||
uint32_t pid_hw_version_num = NOT_SAMPLED_YET;
|
||||
uint32_t pid_sw_version_num = NOT_SAMPLED_YET;
|
||||
uint32_t pid_factory_mode_control = NOT_SAMPLED_YET;
|
||||
uint8_t pid_battery_serial[13] = {0};
|
||||
uint32_t pid_aux_fuse_state = NOT_SAMPLED_YET;
|
||||
uint32_t pid_battery_state = NOT_SAMPLED_YET;
|
||||
uint32_t pid_precharge_short_circuit = NOT_SAMPLED_YET;
|
||||
uint32_t pid_eservice_plug_state = NOT_SAMPLED_YET;
|
||||
uint32_t pid_mainfuse_state = NOT_SAMPLED_YET;
|
||||
uint32_t pid_most_critical_fault = NOT_SAMPLED_YET;
|
||||
uint32_t pid_current_time = NOT_SAMPLED_YET;
|
||||
uint32_t pid_time_sent_by_car = NOT_SAMPLED_YET;
|
||||
uint32_t pid_12v = 12345; //Initialized to over 12V to not trigger low 12V event
|
||||
uint32_t pid_12v_abnormal = NOT_SAMPLED_YET;
|
||||
uint32_t pid_hvil_in_voltage = NOT_SAMPLED_YET;
|
||||
uint32_t pid_hvil_out_voltage = NOT_SAMPLED_YET;
|
||||
uint32_t pid_hvil_state = NOT_SAMPLED_YET;
|
||||
uint32_t pid_bms_state = NOT_SAMPLED_YET;
|
||||
uint32_t pid_vehicle_speed = NOT_SAMPLED_YET;
|
||||
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;
|
||||
|
||||
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent
|
||||
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
||||
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
|
||||
unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was sent
|
||||
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
||||
unsigned long previousMillis250 = 0; // will store last time a 250ms CAN Message was sent
|
||||
unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was sent
|
||||
unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent
|
||||
unsigned long previousMillis5000 = 0; // will store last time a 1000ms CAN Message was sent
|
||||
#define PID_WELD_CHECK 0xD814
|
||||
#define PID_CONT_REASON_OPEN 0xD812
|
||||
#define PID_CONTACTOR_STATUS 0xD813
|
||||
#define PID_NEG_CONT_CONTROL 0xD44F
|
||||
#define PID_NEG_CONT_STATUS 0xD453
|
||||
#define PID_POS_CONT_CONTROL 0xD44E
|
||||
#define PID_POS_CONT_STATUS 0xD452
|
||||
#define PID_CONTACTOR_NEGATIVE 0xD44C
|
||||
#define PID_CONTACTOR_POSITIVE 0xD44D
|
||||
#define PID_PRECHARGE_RELAY_CONTROL 0xD44B
|
||||
#define PID_PRECHARGE_RELAY_STATUS 0xD451
|
||||
#define PID_RECHARGE_STATUS 0xD864
|
||||
#define PID_DELTA_TEMPERATURE 0xD878
|
||||
#define PID_COLDEST_MODULE 0xD446
|
||||
#define PID_LOWEST_TEMPERATURE 0xD87D
|
||||
#define PID_AVERAGE_TEMPERATURE 0xD877
|
||||
#define PID_HIGHEST_TEMPERATURE 0xD817
|
||||
#define PID_HOTTEST_MODULE 0xD445
|
||||
#define PID_AVG_CELL_VOLTAGE 0xD43D
|
||||
#define PID_CURRENT 0xD816
|
||||
#define PID_INSULATION_NEG 0xD87C
|
||||
#define PID_INSULATION_POS 0xD87B
|
||||
#define PID_MAX_CURRENT_10S 0xD876
|
||||
#define PID_MAX_DISCHARGE_10S 0xD873
|
||||
#define PID_MAX_DISCHARGE_30S 0xD874
|
||||
#define PID_MAX_CHARGE_10S 0xD871
|
||||
#define PID_MAX_CHARGE_30S 0xD872
|
||||
#define PID_ENERGY_CAPACITY 0xD860
|
||||
#define PID_HIGH_CELL_NUM 0xD43B
|
||||
#define PID_LOW_CELL_NUM 0xD43C
|
||||
#define PID_SUM_OF_CELLS 0xD438
|
||||
#define PID_CELL_MIN_CAPACITY 0xD413
|
||||
#define PID_CELL_VOLTAGE_MEAS_STATUS 0xD48A
|
||||
#define PID_INSULATION_RES 0xD47A
|
||||
#define PID_PACK_VOLTAGE 0xD815
|
||||
#define PID_HIGH_CELL_VOLTAGE 0xD870
|
||||
#define PID_ALL_CELL_VOLTAGES 0xD440 //Multi-frame
|
||||
#define PID_LOW_CELL_VOLTAGE 0xD86F
|
||||
#define PID_BATTERY_ENERGY 0xD865
|
||||
#define PID_BATTERY_ENERGY 0xD865
|
||||
#define PID_CELLBALANCE_STATUS 0xD46F //Multi-frame?
|
||||
#define PID_CELLBALANCE_HWERR_MASK 0xD470 //Multi-frame
|
||||
#define PID_CRASH_COUNTER 0xD42F
|
||||
#define PID_WIRE_CRASH 0xD87F
|
||||
#define PID_CAN_CRASH 0xD48D
|
||||
#define PID_HISTORY_DATA 0xD465
|
||||
#define PID_LOWSOC_COUNTER 0xD492 //Not supported on all batteris
|
||||
#define PID_LAST_CAN_FAILURE_DETAIL 0xD89E //Not supported on all batteris
|
||||
#define PID_HW_VERSION_NUM 0xF193 //Not supported on all batteris
|
||||
#define PID_SW_VERSION_NUM 0xF195 //Not supported on all batteris
|
||||
#define PID_FACTORY_MODE_CONTROL 0xD900
|
||||
#define PID_BATTERY_SERIAL 0xD901
|
||||
#define PID_ALL_CELL_SOH 0xD4B5 //Very long message reply, too much data for this integration
|
||||
#define PID_AUX_FUSE_STATE 0xD86C
|
||||
#define PID_BATTERY_STATE 0xD811
|
||||
#define PID_PRECHARGE_SHORT_CIRCUIT 0xD4D8
|
||||
#define PID_ESERVICE_PLUG_STATE 0xD86A
|
||||
#define PID_MAINFUSE_STATE 0xD86B
|
||||
#define PID_MOST_CRITICAL_FAULT 0xD481
|
||||
#define PID_CURRENT_TIME 0xD47F
|
||||
#define PID_TIME_SENT_BY_CAR 0xD4CA
|
||||
#define PID_12V 0xD822
|
||||
#define PID_12V_ABNORMAL 0xD42B
|
||||
#define PID_HVIL_IN_VOLTAGE 0xD46B
|
||||
#define PID_HVIL_OUT_VOLTAGE 0xD46A
|
||||
#define PID_HVIL_STATE 0xD869
|
||||
#define PID_BMS_STATE 0xD45A
|
||||
#define PID_VEHICLE_SPEED 0xD802
|
||||
#define PID_TIME_SPENT_OVER_55C 0xE082
|
||||
#define PID_CONTACTOR_CLOSING_COUNTER 0xD416
|
||||
#define PID_DATE_OF_MANUFACTURE 0xF18B
|
||||
|
||||
CAN_frame ECMP_382 = {
|
||||
.FD = false, //BSI_Info (VCU) PSA specific
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x382,
|
||||
.data = {0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //09 20 on AC charge. 0A 20 on DC charge
|
||||
CAN_frame ECMP_0F0 = {.FD = false, //VCU (Common)
|
||||
uint16_t poll_state = PID_WELD_CHECK;
|
||||
uint16_t incoming_poll = 0;
|
||||
|
||||
CAN_frame ECMP_010 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x010, .data = {0xB4}};
|
||||
CAN_frame ECMP_041 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x041, .data = {0x00}};
|
||||
CAN_frame ECMP_0A6 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 2,
|
||||
.ID = 0x0A6,
|
||||
.data = {0x02, 0x00}}; //Content changes after 12minutes of runtime (not emulated)
|
||||
CAN_frame ECMP_0F0 = {.FD = false, //VCU2_0F0 (Common) 20ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x0F0,
|
||||
.data = {0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}};
|
||||
uint8_t data_0F0_20[16] = {0xFF, 0x0E, 0x1D, 0x2C, 0x3B, 0x4A, 0x59, 0x68,
|
||||
0x77, 0x86, 0x95, 0xA4, 0xB3, 0xC2, 0xD1, 0xE0};
|
||||
uint8_t data_0F0_00[16] = {0xF1, 0x00, 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A,
|
||||
0x79, 0x88, 0x97, 0xA6, 0xB5, 0xC4, 0xD3, 0xE2};
|
||||
CAN_frame ECMP_0F2 = {.FD = false, //CtrlMCU1_0F2 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x0F2,
|
||||
.data = {0x7D, 0x00, 0x4E, 0x20, 0x00, 0x00, 0x60, 0x0D}};
|
||||
CAN_frame ECMP_0AE = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x0AE, .data = {0x04, 0x77, 0x7A, 0x5E, 0xDF}};
|
||||
CAN_frame ECMP_110 = {.FD = false, //??? 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x110,
|
||||
.data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x87, 0x05}};
|
||||
CAN_frame ECMP_111 = {.FD = false, //??? 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 8,
|
||||
.ID = 0x111,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_112 = {.FD = false, //MCU1_112 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, only CRC changes at end
|
||||
.DLC = 8,
|
||||
.ID = 0x112,
|
||||
.data = {0x4E, 0x20, 0x00, 0x0F, 0xA0, 0x7D, 0x00, 0x0A}};
|
||||
CAN_frame ECMP_114 = {.FD = false, //??? 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 8,
|
||||
.ID = 0x114,
|
||||
.data = {0x00, 0x00, 0x00, 0x7D, 0x07, 0xD0, 0x7D, 0x00}};
|
||||
CAN_frame ECMP_0C5 = {.FD = false, //DC2_0C5 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 8,
|
||||
.ID = 0x0C5,
|
||||
.data = {0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_17B = {.FD = false, //VCU_PCANInfo_17B 10ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x17B,
|
||||
.data = {0x00, 0x00, 0x00, 0x7E, 0x78, 0x00, 0x00, 0x0F}}; // NOTE. Changes on BMS state
|
||||
CAN_frame ECMP_230 = {.FD = false, //OBC3_230 50ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 8,
|
||||
.ID = 0x230,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_27A = {
|
||||
.FD = false, //VCU_BSI_Wakeup_27A message 50ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8, //Contains SEV main state, position of the BSI shunt park, ACC status
|
||||
.ID = 0x27A, // electric network state, powetrain status, Wakeups, diagmux, APC activation
|
||||
.data = {0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_31E = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x31E,
|
||||
.data = {0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}};
|
||||
CAN_frame ECMP_31D = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 8,
|
||||
.ID = 0x31D,
|
||||
.data = {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42}};
|
||||
CAN_frame ECMP_3D0 = {.FD = false, //Not in logs, but makes speed go to 0km/h in diag tool when we send this
|
||||
.ext_ID = false, //Only sent in idle state
|
||||
.DLC = 8,
|
||||
.ID = 0x3D0,
|
||||
.data = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_345 = {.FD = false, //DC1_345 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x345,
|
||||
.data = {0x45, 0x57, 0x00, 0x04, 0x00, 0x00, 0x06, 0x31}};
|
||||
CAN_frame ECMP_351 = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x351,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0E}};
|
||||
CAN_frame ECMP_372 = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x372,
|
||||
.data = {0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // NOTE. Changes on BMS state
|
||||
CAN_frame ECMP_37F = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // Seems to be a bunch of temperature measurements? Static for now
|
||||
.DLC = 8,
|
||||
.ID = 0x37F,
|
||||
.data = {0x45, 0x49, 0x51, 0x45, 0x45, 0x00, 0x45, 0x45}};
|
||||
CAN_frame ECMP_382 = {
|
||||
//BSIInfo_382 (VCU) PSA specific 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.FD = false, //Same content always, fully static
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x382, //Frame1 has rollerbenchmode request, frame2 has generic powertrain cycle sync status
|
||||
.data = {0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_383 = {.FD = false, //??? 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x383,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_3A2 = {.FD = false, //OBC2_3A2 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x3A2,
|
||||
.data = {0x03, 0xE8, 0x00, 0x00, 0x81, 0x00, 0x08, 0x02}};
|
||||
CAN_frame ECMP_3A3 = {.FD = false, //OBC1_3A3 100ms periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x3A3,
|
||||
.data = {0x4A, 0x4A, 0x40, 0x00, 0x00, 0x08, 0x00, 0x0F}};
|
||||
CAN_frame ECMP_439 = {.FD = false, //??? 1s periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 8,
|
||||
.ID = 0x439,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame ECMP_486 = {.FD = false, //??? 1s periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, // NOTE. Changes on BMS state
|
||||
.DLC = 8,
|
||||
.ID = 0x486,
|
||||
.data = {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
CAN_frame ECMP_552 = {.FD = false, //VCU_552 1s periodic (Perfectly handled in Battery-Emulator)
|
||||
.ext_ID = false,
|
||||
.DLC = 8, //552 seems to be tracking time in byte 0-3
|
||||
.ID = 0x552, // distance in km in byte 4-6, temporal reset counter in byte 7
|
||||
.data = {0x00, 0x02, 0x95, 0x6D, 0x00, 0xD7, 0xB5, 0xFE}};
|
||||
CAN_frame ECMP_55F = {.FD = false, //5s periodic (Perfectly emulated in Battery-Emulator)
|
||||
.ext_ID = false, //Same content always, fully static
|
||||
.DLC = 1,
|
||||
.ID = 0x55F,
|
||||
.data = {0x82}};
|
||||
CAN_frame ECMP_591 = {.FD = false, //1s periodic
|
||||
.ext_ID = false, //Always static in HV mode
|
||||
.DLC = 8,
|
||||
.ID = 0x591,
|
||||
.data = {0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
CAN_frame ECMP_786 = {.FD = false, //1s periodic
|
||||
.ext_ID = false, //Always static in HV mode
|
||||
.DLC = 8,
|
||||
.ID = 0x786,
|
||||
.data = {0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
CAN_frame ECMP_794 = {.FD = false, //Unsure who sends this. Could it be BMU?
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x794,
|
||||
.data = {0xB8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; // NOTE. Changes on BMS state
|
||||
CAN_frame ECMP_POLL = {.FD = false, .ext_ID = false, .DLC = 4, .ID = 0x6B4, .data = {0x03, 0x22, 0xD8, 0x66}};
|
||||
CAN_frame ECMP_ACK = {.FD = false, //Ack frame
|
||||
.ext_ID = false,
|
||||
.DLC = 3,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x30, 0x00, 0x00}};
|
||||
CAN_frame ECMP_DIAG_START = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x6B4, .data = {0x02, 0x10, 0x03}};
|
||||
//Start diagnostic session (extended diagnostic session, mode 0x10 with sub-mode 0x03)
|
||||
CAN_frame ECMP_CONTACTOR_RESET_START = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x01, 0xDD, 0x35}};
|
||||
CAN_frame ECMP_CONTACTOR_RESET_PROGRESS = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x03, 0xDD, 0x35}};
|
||||
CAN_frame ECMP_COLLISION_RESET_START = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x01, 0xDF, 0x60}};
|
||||
CAN_frame ECMP_COLLISION_RESET_PROGRESS = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x03, 0xDF, 0x60}};
|
||||
CAN_frame ECMP_ISOLATION_RESET_START = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x01, 0xDF, 0x46}};
|
||||
CAN_frame ECMP_ISOLATION_RESET_PROGRESS = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x03, 0xDF, 0x46}};
|
||||
CAN_frame ECMP_RESET_DONE = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x6B4, .data = {0x02, 0x3E, 0x00}};
|
||||
CAN_frame ECMP_FACTORY_MODE_ACTIVATION = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x2E, 0xD9, 0x00, 0x01}};
|
||||
CAN_frame ECMP_FACTORY_MODE_ACTIVATION_NEW = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 4,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x2E, 0x19, 0x01}};
|
||||
CAN_frame ECMP_DISABLE_ISOLATION_REQ = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 5,
|
||||
.ID = 0x6B4,
|
||||
.data = {0x04, 0x31, 0x02, 0xDF, 0xE1}};
|
||||
uint8_t data_010_CRC[8] = {0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E, 0xF0, 0xD2};
|
||||
uint8_t data_3A2_CRC[16] = {0x0C, 0x1B, 0x2A, 0x39, 0x48, 0x57,
|
||||
0x66, 0x75, 0x84, 0x93, 0xA2, 0xB1}; // NOTE. Changes on BMS state
|
||||
uint8_t data_345_content[16] = {0x04, 0xF5, 0xE6, 0xD7, 0xC8, 0xB9, 0xAA, 0x9B, // NOTE. Changes on BMS state
|
||||
0x8C, 0x7D, 0x6E, 0x5F, 0x40, 0x31, 0x22, 0x13};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _ECMP_HTML_H
|
||||
#define _ECMP_HTML_H
|
||||
#ifndef _ECMP_BATTERY_HTML_H
|
||||
#define _ECMP_BATTERT_HTML_H
|
||||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
|
@ -9,7 +9,6 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer {
|
|||
public:
|
||||
String get_status_html() {
|
||||
String content;
|
||||
|
||||
content += "<h4>Main Connector State: ";
|
||||
if (datalayer_extended.stellantisECMP.MainConnectorState == 0) {
|
||||
content += "Contactors open</h4>";
|
||||
|
@ -20,6 +19,363 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer {
|
|||
}
|
||||
content +=
|
||||
"<h4>Insulation Resistance: " + String(datalayer_extended.stellantisECMP.InsulationResistance) + "kOhm</h4>";
|
||||
content += "<h4>Interlock: ";
|
||||
if (datalayer_extended.stellantisECMP.InterlockOpen == true) {
|
||||
content += "BROKEN!</h4>";
|
||||
} else {
|
||||
content += "Seated OK</h4>";
|
||||
}
|
||||
content += "<h4>Insulation Diag: ";
|
||||
if (datalayer_extended.stellantisECMP.InsulationDiag == 0) {
|
||||
content += "No failure</h4>";
|
||||
} else if (datalayer_extended.stellantisECMP.InsulationDiag == 1) {
|
||||
content += "Symmetric failure</h4>";
|
||||
} else { //4 Invalid, 5-7 illegal, wrap em under one text
|
||||
content += "N/A</h4>";
|
||||
}
|
||||
content += "<h4>Contactor weld check: ";
|
||||
if (datalayer_extended.stellantisECMP.pid_welding_detection == 0) {
|
||||
content += "OK</h4>";
|
||||
} else if (datalayer_extended.stellantisECMP.pid_welding_detection == 255) {
|
||||
content += "N/A</h4>";
|
||||
} else { //Problem
|
||||
content += "WELDED!" + String(datalayer_extended.stellantisECMP.pid_welding_detection) + "</h4>";
|
||||
}
|
||||
|
||||
content += "<h4>Contactor opening reason: ";
|
||||
if (datalayer_extended.stellantisECMP.pid_reason_open == 7) {
|
||||
content += "Invalid Status</h4>";
|
||||
} else if (datalayer_extended.stellantisECMP.pid_reason_open == 255) {
|
||||
content += "N/A</h4>";
|
||||
} else { //Problem (Also status 0 might be OK?)
|
||||
content += "Unknown" + String(datalayer_extended.stellantisECMP.pid_reason_open) + "</h4>";
|
||||
}
|
||||
|
||||
content += "<h4>Status of power switch: " +
|
||||
(datalayer_extended.stellantisECMP.pid_contactor_status == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_contactor_status)) +
|
||||
"</h4>";
|
||||
content += "<h4>Negative power switch control: " +
|
||||
(datalayer_extended.stellantisECMP.pid_negative_contactor_control == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_negative_contactor_control)) +
|
||||
"</h4>";
|
||||
content += "<h4>Negative power switch status: " +
|
||||
(datalayer_extended.stellantisECMP.pid_negative_contactor_status == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_negative_contactor_status)) +
|
||||
"</h4>";
|
||||
content += "<h4>Positive power switch control: " +
|
||||
(datalayer_extended.stellantisECMP.pid_positive_contactor_control == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_positive_contactor_control)) +
|
||||
"</h4>";
|
||||
content += "<h4>Positive power switch status: " +
|
||||
(datalayer_extended.stellantisECMP.pid_positive_contactor_status == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_positive_contactor_status)) +
|
||||
"</h4>";
|
||||
content += "<h4>Contactor negative: " +
|
||||
(datalayer_extended.stellantisECMP.pid_contactor_negative == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_contactor_negative)) +
|
||||
"</h4>";
|
||||
content += "<h4>Contactor positive: " +
|
||||
(datalayer_extended.stellantisECMP.pid_contactor_positive == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_contactor_positive)) +
|
||||
"</h4>";
|
||||
content += "<h4>Precharge control: " +
|
||||
(datalayer_extended.stellantisECMP.pid_precharge_relay_control == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_precharge_relay_control)) +
|
||||
"</h4>";
|
||||
content += "<h4>Precharge status: " +
|
||||
(datalayer_extended.stellantisECMP.pid_precharge_relay_status == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_precharge_relay_status)) +
|
||||
"</h4>";
|
||||
content += "<h4>Recharge Status: " +
|
||||
(datalayer_extended.stellantisECMP.pid_recharge_status == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_recharge_status)) +
|
||||
"</h4>";
|
||||
content += "<h4>Delta temperature: " +
|
||||
(datalayer_extended.stellantisECMP.pid_delta_temperature == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_delta_temperature)) +
|
||||
"°C</h4>";
|
||||
content += "<h4>Lowest temperature: " +
|
||||
(datalayer_extended.stellantisECMP.pid_lowest_temperature == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_lowest_temperature)) +
|
||||
"°C</h4>";
|
||||
content += "<h4>Average temperature: " +
|
||||
(datalayer_extended.stellantisECMP.pid_average_temperature == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_average_temperature)) +
|
||||
"°C</h4>";
|
||||
content += "<h4>Highest temperature: " +
|
||||
(datalayer_extended.stellantisECMP.pid_highest_temperature == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_highest_temperature)) +
|
||||
"°C</h4>";
|
||||
content += "<h4>Coldest module: " +
|
||||
(datalayer_extended.stellantisECMP.pid_coldest_module == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_coldest_module)) +
|
||||
"</h4>";
|
||||
content += "<h4>Hottest module: " +
|
||||
(datalayer_extended.stellantisECMP.pid_hottest_module == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_hottest_module)) +
|
||||
"</h4>";
|
||||
content += "<h4>Average cell voltage: " +
|
||||
(datalayer_extended.stellantisECMP.pid_avg_cell_voltage == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_avg_cell_voltage)) +
|
||||
" mV</h4>";
|
||||
content +=
|
||||
"<h4>High precision current: " +
|
||||
(datalayer_extended.stellantisECMP.pid_current == 255 ? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_current)) +
|
||||
" mA</h4>";
|
||||
content += "<h4>Insulation resistance neg-gnd: " +
|
||||
(datalayer_extended.stellantisECMP.pid_insulation_res_neg == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_insulation_res_neg)) +
|
||||
" kOhm</h4>";
|
||||
content += "<h4>Insulation resistance pos-gnd: " +
|
||||
(datalayer_extended.stellantisECMP.pid_insulation_res_pos == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_insulation_res_pos)) +
|
||||
" kOhm</h4>";
|
||||
content += "<h4>Max current 10s: " +
|
||||
(datalayer_extended.stellantisECMP.pid_max_current_10s == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_max_current_10s)) +
|
||||
"</h4>";
|
||||
content += "<h4>Max discharge power 10s: " +
|
||||
(datalayer_extended.stellantisECMP.pid_max_discharge_10s == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_max_discharge_10s)) +
|
||||
"</h4>";
|
||||
content += "<h4>Max discharge power 30s: " +
|
||||
(datalayer_extended.stellantisECMP.pid_max_discharge_30s == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_max_discharge_30s)) +
|
||||
"</h4>";
|
||||
content += "<h4>Max charge power 10s: " +
|
||||
(datalayer_extended.stellantisECMP.pid_max_charge_10s == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_max_charge_10s)) +
|
||||
"</h4>";
|
||||
content += "<h4>Max charge power 30s: " +
|
||||
(datalayer_extended.stellantisECMP.pid_max_charge_30s == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_max_charge_30s)) +
|
||||
"</h4>";
|
||||
content += "<h4>Energy capacity: " +
|
||||
(datalayer_extended.stellantisECMP.pid_energy_capacity == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_energy_capacity)) +
|
||||
"</h4>";
|
||||
content += "<h4>Highest cell number: " +
|
||||
(datalayer_extended.stellantisECMP.pid_highest_cell_voltage_num == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_highest_cell_voltage_num)) +
|
||||
"</h4>";
|
||||
content += "<h4>Lowest cell voltage number: " +
|
||||
(datalayer_extended.stellantisECMP.pid_lowest_cell_voltage_num == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_lowest_cell_voltage_num)) +
|
||||
"</h4>";
|
||||
content += "<h4>Sum of all cell voltages: " +
|
||||
(datalayer_extended.stellantisECMP.pid_sum_of_cells == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_sum_of_cells)) +
|
||||
" dV</h4>";
|
||||
content += "<h4>Cell min capacity: " +
|
||||
(datalayer_extended.stellantisECMP.pid_cell_min_capacity == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_cell_min_capacity)) +
|
||||
"</h4>";
|
||||
content += "<h4>Cell voltage measurement status: " +
|
||||
(datalayer_extended.stellantisECMP.pid_cell_voltage_measurement_status == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_cell_voltage_measurement_status)) +
|
||||
"</h4>";
|
||||
content += "<h4>Battery Insulation Resistance: " +
|
||||
(datalayer_extended.stellantisECMP.pid_insulation_res == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_insulation_res)) +
|
||||
" kOhm</h4>";
|
||||
content += "<h4>Pack voltage: " +
|
||||
(datalayer_extended.stellantisECMP.pid_pack_voltage == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_pack_voltage)) +
|
||||
" dV</h4>";
|
||||
content += "<h4>Highest cell voltage: " +
|
||||
(datalayer_extended.stellantisECMP.pid_high_cell_voltage == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_high_cell_voltage)) +
|
||||
" mV</h4>";
|
||||
content += "<h4>Lowest cell voltage: " +
|
||||
(datalayer_extended.stellantisECMP.pid_low_cell_voltage == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_low_cell_voltage)) +
|
||||
" mV</h4>";
|
||||
content += "<h4>Battery Energy: " +
|
||||
(datalayer_extended.stellantisECMP.pid_battery_energy == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_battery_energy)) +
|
||||
"</h4>";
|
||||
content += "<h4>Collision information Counter: " +
|
||||
(datalayer_extended.stellantisECMP.pid_crash_counter == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_crash_counter)) +
|
||||
"</h4>";
|
||||
content += "<h4>Collision Counter recieved by Wire: " +
|
||||
(datalayer_extended.stellantisECMP.pid_wire_crash == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_wire_crash)) +
|
||||
"</h4>";
|
||||
content += "<h4>Collision data sent from car to battery: " +
|
||||
(datalayer_extended.stellantisECMP.pid_CAN_crash == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_CAN_crash)) +
|
||||
"</h4>";
|
||||
content += "<h4>History data: " +
|
||||
(datalayer_extended.stellantisECMP.pid_history_data == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_history_data)) +
|
||||
"</h4>";
|
||||
content += "<h4>Low SOC counter: " +
|
||||
(datalayer_extended.stellantisECMP.pid_lowsoc_counter == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_lowsoc_counter)) +
|
||||
"</h4>";
|
||||
content += "<h4>Last CAN failure detail: " +
|
||||
(datalayer_extended.stellantisECMP.pid_last_can_failure_detail == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_last_can_failure_detail)) +
|
||||
"</h4>";
|
||||
content += "<h4>HW version number: " +
|
||||
(datalayer_extended.stellantisECMP.pid_hw_version_num == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_hw_version_num)) +
|
||||
"</h4>";
|
||||
content += "<h4>SW version number: " +
|
||||
(datalayer_extended.stellantisECMP.pid_sw_version_num == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_sw_version_num)) +
|
||||
"</h4>";
|
||||
content += "<h4>Factory mode: " +
|
||||
(datalayer_extended.stellantisECMP.pid_factory_mode_control == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_factory_mode_control)) +
|
||||
"</h4>";
|
||||
char readableSerialNumber[14]; // One extra space for null terminator
|
||||
memcpy(readableSerialNumber, datalayer_extended.stellantisECMP.pid_battery_serial,
|
||||
sizeof(datalayer_extended.stellantisECMP.pid_battery_serial));
|
||||
readableSerialNumber[13] = '\0'; // Null terminate the string
|
||||
content += "<h4>Battery serial: " + String(readableSerialNumber) + "</h4>";
|
||||
uint8_t day = (datalayer_extended.stellantisECMP.pid_date_of_manufacture >> 16) & 0xFF;
|
||||
uint8_t month = (datalayer_extended.stellantisECMP.pid_date_of_manufacture >> 8) & 0xFF;
|
||||
uint8_t year = datalayer_extended.stellantisECMP.pid_date_of_manufacture & 0xFF;
|
||||
content += "<h4>Date of manufacture: " + String(day) + "/" + String(month) + "/" + String(year) + "</h4>";
|
||||
content += "<h4>Aux fuse state: " +
|
||||
(datalayer_extended.stellantisECMP.pid_aux_fuse_state == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_aux_fuse_state)) +
|
||||
"</h4>";
|
||||
content += "<h4>Battery state: " +
|
||||
(datalayer_extended.stellantisECMP.pid_battery_state == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_battery_state)) +
|
||||
"</h4>";
|
||||
content += "<h4>Precharge short circuit: " +
|
||||
(datalayer_extended.stellantisECMP.pid_precharge_short_circuit == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_precharge_short_circuit)) +
|
||||
"</h4>";
|
||||
content += "<h4>Service plug state: " +
|
||||
(datalayer_extended.stellantisECMP.pid_eservice_plug_state == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_eservice_plug_state)) +
|
||||
"</h4>";
|
||||
content += "<h4>Main fuse state: " +
|
||||
(datalayer_extended.stellantisECMP.pid_mainfuse_state == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_mainfuse_state)) +
|
||||
"</h4>";
|
||||
content += "<h4>Most critical fault: " +
|
||||
(datalayer_extended.stellantisECMP.pid_most_critical_fault == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_most_critical_fault)) +
|
||||
"</h4>";
|
||||
content += "<h4>Current time: " +
|
||||
(datalayer_extended.stellantisECMP.pid_current_time == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_current_time)) +
|
||||
" ticks</h4>";
|
||||
content += "<h4>Time sent by car: " +
|
||||
(datalayer_extended.stellantisECMP.pid_time_sent_by_car == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_time_sent_by_car)) +
|
||||
" ticks</h4>";
|
||||
content +=
|
||||
"<h4>12V: " +
|
||||
(datalayer_extended.stellantisECMP.pid_12v == 255 ? "N/A" : String(datalayer_extended.stellantisECMP.pid_12v)) +
|
||||
"</h4>";
|
||||
content += "<h4>12V abnormal: ";
|
||||
if (datalayer_extended.stellantisECMP.pid_12v_abnormal == 255) {
|
||||
content += "N/A</h4>";
|
||||
} else if (datalayer_extended.stellantisECMP.pid_12v_abnormal == 0) {
|
||||
content += "No</h4>";
|
||||
} else {
|
||||
content += "Yes</h4>";
|
||||
}
|
||||
content += "<h4>HVIL IN Voltage: " +
|
||||
(datalayer_extended.stellantisECMP.pid_hvil_in_voltage == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_hvil_in_voltage)) +
|
||||
"mV</h4>";
|
||||
content += "<h4>HVIL Out Voltage: " +
|
||||
(datalayer_extended.stellantisECMP.pid_hvil_out_voltage == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_hvil_out_voltage)) +
|
||||
"mV</h4>";
|
||||
content += "<h4>HVIL State: " +
|
||||
(datalayer_extended.stellantisECMP.pid_hvil_state == 255
|
||||
? "N/A"
|
||||
: (datalayer_extended.stellantisECMP.pid_hvil_state == 0
|
||||
? "OK"
|
||||
: String(datalayer_extended.stellantisECMP.pid_hvil_state))) +
|
||||
"</h4>";
|
||||
content += "<h4>BMS State: " +
|
||||
(datalayer_extended.stellantisECMP.pid_bms_state == 255
|
||||
? "N/A"
|
||||
: (datalayer_extended.stellantisECMP.pid_bms_state == 0
|
||||
? "OK"
|
||||
: String(datalayer_extended.stellantisECMP.pid_bms_state))) +
|
||||
"</h4>";
|
||||
content += "<h4>Vehicle speed: " +
|
||||
(datalayer_extended.stellantisECMP.pid_vehicle_speed == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_vehicle_speed)) +
|
||||
" km/h</h4>";
|
||||
content += "<h4>Time spent over 55c: " +
|
||||
(datalayer_extended.stellantisECMP.pid_time_spent_over_55c == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_time_spent_over_55c)) +
|
||||
" minutes</h4>";
|
||||
content += "<h4>Contactor lifetime closing counter: " +
|
||||
(datalayer_extended.stellantisECMP.pid_contactor_closing_counter == 255
|
||||
? "N/A"
|
||||
: String(datalayer_extended.stellantisECMP.pid_contactor_closing_counter)) +
|
||||
" cycles</h4>";
|
||||
|
||||
return content;
|
||||
}
|
||||
|
|
|
@ -113,8 +113,9 @@ void KiaHyundai64Battery::
|
|||
void KiaHyundai64Battery::update_number_of_cells() {
|
||||
//If we have cell values and number_of_cells not initialized yet
|
||||
if (cellvoltages_mv[0] > 0 && datalayer_battery->info.number_of_cells == 0) {
|
||||
// Check if we have 98S or 90S battery
|
||||
if (datalayer_battery->status.cell_voltages_mV[97] > 0) {
|
||||
// Check if we have 98S or 90S battery. If the 98th cell is valid range, we are on a 98S battery
|
||||
if ((datalayer_battery->status.cell_voltages_mV[97] > 2000) &&
|
||||
(datalayer_battery->status.cell_voltages_mV[97] < 4300)) {
|
||||
datalayer_battery->info.number_of_cells = 98;
|
||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
||||
|
|
|
@ -14,52 +14,6 @@ Still TODO:
|
|||
/*
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
static uint16_t LB_SOC = 50;
|
||||
static uint16_t LB_Display_SOC = 50;
|
||||
static uint16_t LB_SOH = 99;
|
||||
static int16_t LB_Average_Temperature = 0;
|
||||
static uint32_t LB_Charging_Power_W = 0;
|
||||
static uint32_t LB_Regen_allowed_W = 0;
|
||||
static uint32_t LB_Discharge_allowed_W = 0;
|
||||
static int16_t LB_Current = 0;
|
||||
static int16_t LB_Cell_minimum_temperature = 0;
|
||||
static int16_t LB_Cell_maximum_temperature = 0;
|
||||
static uint16_t LB_Cell_minimum_voltage = 3700;
|
||||
static uint16_t LB_Cell_maximum_voltage = 3700;
|
||||
static uint16_t LB_kWh_Remaining = 0;
|
||||
static uint16_t LB_Battery_Voltage = 3700;
|
||||
static uint8_t LB_Heartbeat = 0;
|
||||
static uint8_t LB_CUV = 0;
|
||||
static uint8_t LB_HVBIR = 0;
|
||||
static uint8_t LB_HVBUV = 0;
|
||||
static uint8_t LB_EOCR = 0;
|
||||
static uint8_t LB_HVBOC = 0;
|
||||
static uint8_t LB_HVBOT = 0;
|
||||
static uint8_t LB_HVBOV = 0;
|
||||
static uint8_t LB_COV = 0;
|
||||
static uint8_t frame0 = 0;
|
||||
static uint8_t current_poll = 0;
|
||||
static uint8_t requested_poll = 0;
|
||||
static uint8_t group = 0;
|
||||
static uint16_t cellvoltages[96];
|
||||
static uint32_t calculated_total_pack_voltage_mV = 370000;
|
||||
static uint8_t highbyte_cell_next_frame = 0;
|
||||
static uint16_t SOC_polled = 50;
|
||||
static int16_t cell_1_temperature_polled = 0;
|
||||
static int16_t cell_2_temperature_polled = 0;
|
||||
static int16_t cell_3_temperature_polled = 0;
|
||||
static int16_t cell_4_temperature_polled = 0;
|
||||
static int16_t cell_5_temperature_polled = 0;
|
||||
static int16_t cell_6_temperature_polled = 0;
|
||||
static int16_t cell_7_temperature_polled = 0;
|
||||
static int16_t cell_8_temperature_polled = 0;
|
||||
static int16_t cell_9_temperature_polled = 0;
|
||||
static int16_t cell_10_temperature_polled = 0;
|
||||
static int16_t cell_11_temperature_polled = 0;
|
||||
static int16_t cell_12_temperature_polled = 0;
|
||||
static uint16_t battery_mileage_in_km = 0;
|
||||
static uint16_t kWh_from_beginning_of_battery_life = 0;
|
||||
static bool looping_over_20 = false;
|
||||
|
||||
CAN_frame ZOE_423 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
|
@ -89,20 +43,20 @@ static uint8_t counter_423 = 0;
|
|||
|
||||
void RenaultZoeGen1Battery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
datalayer.battery.status.soh_pptt = (LB_SOH * 100); // Increase range from 99% -> 99.00%
|
||||
datalayer_battery->status.soh_pptt = (LB_SOH * 100); // Increase range from 99% -> 99.00%
|
||||
|
||||
datalayer.battery.status.real_soc = SOC_polled;
|
||||
//datalayer.battery.status.real_soc = LB_Display_SOC; //Alternative would be to use Dash SOC%
|
||||
datalayer_battery->status.real_soc = SOC_polled;
|
||||
//datalayer_battery->status.real_soc = LB_Display_SOC; //Alternative would be to use Dash SOC%
|
||||
|
||||
datalayer.battery.status.current_dA = LB_Current * 10; //Convert A to dA
|
||||
datalayer_battery->status.current_dA = LB_Current * 10; //Convert A to dA
|
||||
|
||||
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
||||
datalayer_battery->status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||
(static_cast<double>(datalayer_battery->status.real_soc) / 10000) * datalayer_battery->info.total_capacity_Wh);
|
||||
|
||||
datalayer.battery.status.max_discharge_power_W = LB_Discharge_allowed_W;
|
||||
datalayer_battery->status.max_discharge_power_W = LB_Discharge_allowed_W;
|
||||
|
||||
datalayer.battery.status.max_charge_power_W = LB_Regen_allowed_W;
|
||||
datalayer_battery->status.max_charge_power_W = LB_Regen_allowed_W;
|
||||
|
||||
int16_t temperatures[] = {cell_1_temperature_polled, cell_2_temperature_polled, cell_3_temperature_polled,
|
||||
cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled,
|
||||
|
@ -113,52 +67,53 @@ void RenaultZoeGen1Battery::
|
|||
int16_t min_temperature = *std::min_element(temperatures, temperatures + 12);
|
||||
int16_t max_temperature = *std::max_element(temperatures, temperatures + 12);
|
||||
|
||||
datalayer.battery.status.temperature_min_dC = min_temperature * 10;
|
||||
datalayer_battery->status.temperature_min_dC = min_temperature * 10;
|
||||
|
||||
datalayer.battery.status.temperature_max_dC = max_temperature * 10;
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 96 * sizeof(uint16_t));
|
||||
datalayer_battery->status.temperature_max_dC = max_temperature * 10;
|
||||
|
||||
// Calculate total pack voltage on packs that require this. Only calculate once all cellvotages have been read
|
||||
if (datalayer.battery.status.cell_voltages_mV[95] > 0) {
|
||||
calculated_total_pack_voltage_mV = datalayer.battery.status.cell_voltages_mV[0];
|
||||
for (uint8_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) {
|
||||
calculated_total_pack_voltage_mV += datalayer.battery.status.cell_voltages_mV[i];
|
||||
if (datalayer_battery->status.cell_voltages_mV[95] > 0) {
|
||||
calculated_total_pack_voltage_mV = datalayer_battery->status.cell_voltages_mV[0];
|
||||
for (uint8_t i = 0; i < datalayer_battery->info.number_of_cells; ++i) {
|
||||
calculated_total_pack_voltage_mV += datalayer_battery->status.cell_voltages_mV[i];
|
||||
}
|
||||
}
|
||||
|
||||
datalayer.battery.status.cell_min_voltage_mV = LB_Cell_minimum_voltage;
|
||||
datalayer.battery.status.cell_max_voltage_mV = LB_Cell_maximum_voltage;
|
||||
datalayer.battery.status.voltage_dV = static_cast<uint32_t>((calculated_total_pack_voltage_mV / 100)); // mV to dV
|
||||
datalayer_battery->status.cell_min_voltage_mV = LB_Cell_minimum_voltage;
|
||||
datalayer_battery->status.cell_max_voltage_mV = LB_Cell_maximum_voltage;
|
||||
datalayer_battery->status.voltage_dV = ((calculated_total_pack_voltage_mV / 100)); // mV to dV
|
||||
|
||||
//Update extended datalayer
|
||||
datalayer_extended.zoe.CUV = LB_CUV;
|
||||
datalayer_extended.zoe.HVBIR = LB_HVBIR;
|
||||
datalayer_extended.zoe.HVBUV = LB_HVBUV;
|
||||
datalayer_extended.zoe.EOCR = LB_EOCR;
|
||||
datalayer_extended.zoe.HVBOC = LB_HVBOC;
|
||||
datalayer_extended.zoe.HVBOT = LB_HVBOT;
|
||||
datalayer_extended.zoe.HVBOV = LB_HVBOV;
|
||||
datalayer_extended.zoe.COV = LB_COV;
|
||||
if (datalayer_zoe) {
|
||||
datalayer_zoe->CUV = LB_CUV;
|
||||
datalayer_zoe->HVBIR = LB_HVBIR;
|
||||
datalayer_zoe->HVBUV = LB_HVBUV;
|
||||
datalayer_zoe->EOCR = LB_EOCR;
|
||||
datalayer_zoe->HVBOC = LB_HVBOC;
|
||||
datalayer_zoe->HVBOT = LB_HVBOT;
|
||||
datalayer_zoe->HVBOV = LB_HVBOV;
|
||||
datalayer_zoe->COV = LB_COV;
|
||||
datalayer_zoe->mileage_km = battery_mileage_in_km;
|
||||
datalayer_zoe->alltime_kWh = kWh_from_beginning_of_battery_life;
|
||||
}
|
||||
}
|
||||
|
||||
void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x155: //10ms - Charging power, current and SOC - Confirmed sent by: Fluence ZE40, Zoe 22/41kWh, Kangoo 33kWh
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
LB_Charging_Power_W = rx_frame.data.u8[0] * 300;
|
||||
LB_Current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500);
|
||||
LB_Display_SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
|
||||
break;
|
||||
|
||||
case 0x42E: //NOTE: Not present on 41kWh battery!
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
LB_Battery_Voltage = (((((rx_frame.data.u8[3] << 8) | (rx_frame.data.u8[4])) >> 5) & 0x3ff) * 0.5); //0.5V/bit
|
||||
LB_Average_Temperature = (((((rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6])) >> 5) & 0x7F) - 40);
|
||||
break;
|
||||
case 0x424: //100ms - Charge limits, Temperatures, SOH - Confirmed sent by: Fluence ZE40, Zoe 22/41kWh, Kangoo 33kWh
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
LB_CUV = (rx_frame.data.u8[0] & 0x03);
|
||||
LB_HVBIR = (rx_frame.data.u8[0] & 0x0C) >> 2;
|
||||
LB_HVBUV = (rx_frame.data.u8[0] & 0x30) >> 4;
|
||||
|
@ -175,35 +130,35 @@ void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
LB_Cell_maximum_temperature = (rx_frame.data.u8[7] - 40);
|
||||
break;
|
||||
case 0x425: //100ms Cellvoltages and kWh remaining - Confirmed sent by: Fluence ZE40
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
LB_Cell_maximum_voltage = (((((rx_frame.data.u8[4] & 0x03) << 7) | (rx_frame.data.u8[5] >> 1)) * 10) + 1000);
|
||||
LB_Cell_minimum_voltage = (((((rx_frame.data.u8[6] & 0x01) << 8) | rx_frame.data.u8[7]) * 10) + 1000);
|
||||
break;
|
||||
case 0x427: // NOTE: Not present on 41kWh battery!
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
LB_kWh_Remaining = (((((rx_frame.data.u8[6] << 8) | (rx_frame.data.u8[7])) >> 6) & 0x3ff) * 0.1);
|
||||
break;
|
||||
case 0x445: //100ms - Confirmed sent by: Fluence ZE40
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x4AE: //3000ms
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
//Sent only? by 41kWh battery (potential use for detecting which generation we are on)
|
||||
break;
|
||||
case 0x4AF: //100ms
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
//Sent only? by 41kWh battery (potential use for detecting which generation we are on)
|
||||
break;
|
||||
case 0x654: //SOC
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
LB_SOC = rx_frame.data.u8[3];
|
||||
break;
|
||||
case 0x658: //SOH - NOTE: Not present on 41kWh battery! (Is this message on 21kWh?)
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
//LB_SOH = (rx_frame.data.u8[4] & 0x7F);
|
||||
break;
|
||||
case 0x659: //3000ms - Confirmed sent by: Fluence ZE40
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x7BB: //Reply from active polling
|
||||
frame0 = rx_frame.data.u8[0];
|
||||
|
@ -436,6 +391,8 @@ void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
}
|
||||
if (requested_poll == GROUP2_CELLVOLTAGES_2_POLL) {
|
||||
cellvoltages[95] = (highbyte_cell_next_frame << 8) | rx_frame.data.u8[1];
|
||||
//All cells read, map them to the global array
|
||||
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages, 96 * sizeof(uint16_t));
|
||||
}
|
||||
if (requested_poll == GROUP5_TEMPERATURE_POLL) {
|
||||
//2A,FF,FF,FF,FF,FF,3A,3A,
|
||||
|
@ -559,10 +516,10 @@ void RenaultZoeGen1Battery::setup(void) { // Performs one time setup at startup
|
|||
strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", 63);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
datalayer.battery.info.number_of_cells = 96;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||
datalayer_battery->info.number_of_cells = 96;
|
||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||
datalayer_battery->info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
||||
datalayer_battery->info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,23 @@
|
|||
|
||||
class RenaultZoeGen1Battery : public CanBattery {
|
||||
public:
|
||||
// Use this constructor for the second battery.
|
||||
RenaultZoeGen1Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_ZOE* extended, CAN_Interface targetCan)
|
||||
: CanBattery(targetCan) {
|
||||
datalayer_battery = datalayer_ptr;
|
||||
allows_contactor_closing = nullptr;
|
||||
datalayer_zoe = extended;
|
||||
|
||||
calculated_total_pack_voltage_mV = 0;
|
||||
}
|
||||
|
||||
// Use the default constructor to create the first or single battery.
|
||||
RenaultZoeGen1Battery() {
|
||||
datalayer_battery = &datalayer.battery;
|
||||
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||
datalayer_zoe = &datalayer_extended.zoe;
|
||||
}
|
||||
|
||||
virtual void setup(void);
|
||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||
virtual void update_values();
|
||||
|
@ -25,6 +42,59 @@ class RenaultZoeGen1Battery : public CanBattery {
|
|||
static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value
|
||||
|
||||
RenaultZoeGen1HtmlRenderer renderer;
|
||||
|
||||
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||
DATALAYER_INFO_ZOE* datalayer_zoe;
|
||||
|
||||
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||
bool* allows_contactor_closing;
|
||||
|
||||
uint16_t LB_SOC = 50;
|
||||
uint16_t LB_Display_SOC = 50;
|
||||
uint16_t LB_SOH = 99;
|
||||
int16_t LB_Average_Temperature = 0;
|
||||
uint32_t LB_Charging_Power_W = 0;
|
||||
uint32_t LB_Regen_allowed_W = 0;
|
||||
uint32_t LB_Discharge_allowed_W = 0;
|
||||
int16_t LB_Current = 0;
|
||||
int16_t LB_Cell_minimum_temperature = 0;
|
||||
int16_t LB_Cell_maximum_temperature = 0;
|
||||
uint16_t LB_Cell_minimum_voltage = 3700;
|
||||
uint16_t LB_Cell_maximum_voltage = 3700;
|
||||
uint16_t LB_kWh_Remaining = 0;
|
||||
uint16_t LB_Battery_Voltage = 3700;
|
||||
uint8_t LB_Heartbeat = 0;
|
||||
uint8_t LB_CUV = 0;
|
||||
uint8_t LB_HVBIR = 0;
|
||||
uint8_t LB_HVBUV = 0;
|
||||
uint8_t LB_EOCR = 0;
|
||||
uint8_t LB_HVBOC = 0;
|
||||
uint8_t LB_HVBOT = 0;
|
||||
uint8_t LB_HVBOV = 0;
|
||||
uint8_t LB_COV = 0;
|
||||
uint8_t frame0 = 0;
|
||||
uint8_t current_poll = 0;
|
||||
uint8_t requested_poll = 0;
|
||||
uint8_t group = 0;
|
||||
uint16_t cellvoltages[96];
|
||||
uint32_t calculated_total_pack_voltage_mV = 370000;
|
||||
uint8_t highbyte_cell_next_frame = 0;
|
||||
uint16_t SOC_polled = 5000;
|
||||
int16_t cell_1_temperature_polled = 0;
|
||||
int16_t cell_2_temperature_polled = 0;
|
||||
int16_t cell_3_temperature_polled = 0;
|
||||
int16_t cell_4_temperature_polled = 0;
|
||||
int16_t cell_5_temperature_polled = 0;
|
||||
int16_t cell_6_temperature_polled = 0;
|
||||
int16_t cell_7_temperature_polled = 0;
|
||||
int16_t cell_8_temperature_polled = 0;
|
||||
int16_t cell_9_temperature_polled = 0;
|
||||
int16_t cell_10_temperature_polled = 0;
|
||||
int16_t cell_11_temperature_polled = 0;
|
||||
int16_t cell_12_temperature_polled = 0;
|
||||
uint16_t battery_mileage_in_km = 0;
|
||||
uint16_t kWh_from_beginning_of_battery_life = 0;
|
||||
bool looping_over_20 = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,8 @@ class RenaultZoeGen1HtmlRenderer : public BatteryHtmlRenderer {
|
|||
content += "<h4>HVBOT " + String(datalayer_extended.zoe.HVBOT) + "</h4>";
|
||||
content += "<h4>HVBOV " + String(datalayer_extended.zoe.HVBOV) + "</h4>";
|
||||
content += "<h4>COV " + String(datalayer_extended.zoe.COV) + "</h4>";
|
||||
|
||||
content += "<h4>Battery mileage " + String(datalayer_extended.zoe.mileage_km) + " km</h4>";
|
||||
content += "<h4>Alltime energy " + String(datalayer_extended.zoe.alltime_kWh) + " kWh</h4>";
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -87,7 +87,6 @@ void RenaultZoeGen2Battery::update_values() {
|
|||
datalayer_extended.zoePH2.battery_balance_capacity_wake = battery_balance_capacity_wake;
|
||||
datalayer_extended.zoePH2.battery_balance_time_wake = battery_balance_time_wake;
|
||||
datalayer_extended.zoePH2.battery_bms_state = battery_bms_state;
|
||||
datalayer_extended.zoePH2.battery_balance_switches = battery_balance_switches;
|
||||
datalayer_extended.zoePH2.battery_energy_complete = battery_energy_complete;
|
||||
datalayer_extended.zoePH2.battery_energy_partial = battery_energy_partial;
|
||||
datalayer_extended.zoePH2.battery_slave_failures = battery_slave_failures;
|
||||
|
@ -207,30 +206,119 @@ void RenaultZoeGen2Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
battery_bms_state = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
break;
|
||||
case POLL_BALANCE_SWITCHES:
|
||||
if (rx_frame.data.u8[0] == 0x10) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// Byte 4 - 7 (bits 0-31)
|
||||
for (int byte_i = 0; byte_i < 4; byte_i++) {
|
||||
battery_balancing_shunts[byte_i * 8 + i] = (rx_frame.data.u8[4 + byte_i] & (1 << i)) >> i;
|
||||
}
|
||||
}
|
||||
if (rx_frame.data.u8[0] == 0x23) {
|
||||
battery_balancing_shunts[0] = (rx_frame.data.u8[4] & 0x80) >> 7;
|
||||
battery_balancing_shunts[1] = (rx_frame.data.u8[4] & 0x40) >> 6;
|
||||
battery_balancing_shunts[2] = (rx_frame.data.u8[4] & 0x20) >> 5;
|
||||
battery_balancing_shunts[3] = (rx_frame.data.u8[4] & 0x10) >> 4;
|
||||
battery_balancing_shunts[4] = (rx_frame.data.u8[4] & 0x08) >> 3;
|
||||
battery_balancing_shunts[5] = (rx_frame.data.u8[4] & 0x04) >> 2;
|
||||
battery_balancing_shunts[6] = (rx_frame.data.u8[4] & 0x02) >> 1;
|
||||
battery_balancing_shunts[7] = (rx_frame.data.u8[4] & 0x01);
|
||||
|
||||
battery_balancing_shunts[8] = (rx_frame.data.u8[5] & 0x80) >> 7;
|
||||
battery_balancing_shunts[9] = (rx_frame.data.u8[5] & 0x40) >> 6;
|
||||
battery_balancing_shunts[10] = (rx_frame.data.u8[5] & 0x20) >> 5;
|
||||
battery_balancing_shunts[11] = (rx_frame.data.u8[5] & 0x10) >> 4;
|
||||
battery_balancing_shunts[12] = (rx_frame.data.u8[5] & 0x08) >> 3;
|
||||
battery_balancing_shunts[13] = (rx_frame.data.u8[5] & 0x04) >> 2;
|
||||
battery_balancing_shunts[14] = (rx_frame.data.u8[5] & 0x02) >> 1;
|
||||
battery_balancing_shunts[15] = (rx_frame.data.u8[5] & 0x01);
|
||||
|
||||
battery_balancing_shunts[16] = (rx_frame.data.u8[6] & 0x80) >> 7;
|
||||
battery_balancing_shunts[17] = (rx_frame.data.u8[6] & 0x40) >> 6;
|
||||
battery_balancing_shunts[18] = (rx_frame.data.u8[6] & 0x20) >> 5;
|
||||
battery_balancing_shunts[19] = (rx_frame.data.u8[6] & 0x10) >> 4;
|
||||
battery_balancing_shunts[20] = (rx_frame.data.u8[6] & 0x08) >> 3;
|
||||
battery_balancing_shunts[21] = (rx_frame.data.u8[6] & 0x04) >> 2;
|
||||
battery_balancing_shunts[22] = (rx_frame.data.u8[6] & 0x02) >> 1;
|
||||
battery_balancing_shunts[23] = (rx_frame.data.u8[6] & 0x01);
|
||||
|
||||
battery_balancing_shunts[24] = (rx_frame.data.u8[7] & 0x80) >> 7;
|
||||
battery_balancing_shunts[25] = (rx_frame.data.u8[7] & 0x40) >> 6;
|
||||
battery_balancing_shunts[26] = (rx_frame.data.u8[7] & 0x20) >> 5;
|
||||
battery_balancing_shunts[27] = (rx_frame.data.u8[7] & 0x10) >> 4;
|
||||
battery_balancing_shunts[28] = (rx_frame.data.u8[7] & 0x08) >> 3;
|
||||
battery_balancing_shunts[29] = (rx_frame.data.u8[7] & 0x04) >> 2;
|
||||
battery_balancing_shunts[30] = (rx_frame.data.u8[7] & 0x02) >> 1;
|
||||
battery_balancing_shunts[31] = (rx_frame.data.u8[7] & 0x01);
|
||||
}
|
||||
if (rx_frame.data.u8[0] == 0x21) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// Byte 1 to 7 (bits 32-87)
|
||||
for (int byte_i = 0; byte_i < 7; byte_i++) {
|
||||
battery_balancing_shunts[32 + byte_i * 8 + i] = (rx_frame.data.u8[1 + byte_i] & (1 << i)) >> i;
|
||||
}
|
||||
}
|
||||
if (rx_frame.data.u8[0] == 0x24) {
|
||||
battery_balancing_shunts[32] = (rx_frame.data.u8[1] & 0x80) >> 7;
|
||||
battery_balancing_shunts[33] = (rx_frame.data.u8[1] & 0x40) >> 6;
|
||||
battery_balancing_shunts[34] = (rx_frame.data.u8[1] & 0x20) >> 5;
|
||||
battery_balancing_shunts[35] = (rx_frame.data.u8[1] & 0x10) >> 4;
|
||||
battery_balancing_shunts[36] = (rx_frame.data.u8[1] & 0x08) >> 3;
|
||||
battery_balancing_shunts[37] = (rx_frame.data.u8[1] & 0x04) >> 2;
|
||||
battery_balancing_shunts[38] = (rx_frame.data.u8[1] & 0x02) >> 1;
|
||||
battery_balancing_shunts[39] = (rx_frame.data.u8[1] & 0x01);
|
||||
|
||||
battery_balancing_shunts[40] = (rx_frame.data.u8[2] & 0x80) >> 7;
|
||||
battery_balancing_shunts[41] = (rx_frame.data.u8[2] & 0x40) >> 6;
|
||||
battery_balancing_shunts[42] = (rx_frame.data.u8[2] & 0x20) >> 5;
|
||||
battery_balancing_shunts[43] = (rx_frame.data.u8[2] & 0x10) >> 4;
|
||||
battery_balancing_shunts[44] = (rx_frame.data.u8[2] & 0x08) >> 3;
|
||||
battery_balancing_shunts[45] = (rx_frame.data.u8[2] & 0x04) >> 2;
|
||||
battery_balancing_shunts[46] = (rx_frame.data.u8[2] & 0x02) >> 1;
|
||||
battery_balancing_shunts[47] = (rx_frame.data.u8[2] & 0x01);
|
||||
|
||||
battery_balancing_shunts[48] = (rx_frame.data.u8[3] & 0x80) >> 7;
|
||||
battery_balancing_shunts[49] = (rx_frame.data.u8[3] & 0x40) >> 6;
|
||||
battery_balancing_shunts[50] = (rx_frame.data.u8[3] & 0x20) >> 5;
|
||||
battery_balancing_shunts[51] = (rx_frame.data.u8[3] & 0x10) >> 4;
|
||||
battery_balancing_shunts[52] = (rx_frame.data.u8[3] & 0x08) >> 3;
|
||||
battery_balancing_shunts[53] = (rx_frame.data.u8[3] & 0x04) >> 2;
|
||||
battery_balancing_shunts[54] = (rx_frame.data.u8[3] & 0x02) >> 1;
|
||||
battery_balancing_shunts[55] = (rx_frame.data.u8[3] & 0x01);
|
||||
|
||||
battery_balancing_shunts[56] = (rx_frame.data.u8[4] & 0x80) >> 7;
|
||||
battery_balancing_shunts[57] = (rx_frame.data.u8[4] & 0x40) >> 6;
|
||||
battery_balancing_shunts[58] = (rx_frame.data.u8[4] & 0x20) >> 5;
|
||||
battery_balancing_shunts[59] = (rx_frame.data.u8[4] & 0x10) >> 4;
|
||||
battery_balancing_shunts[60] = (rx_frame.data.u8[4] & 0x08) >> 3;
|
||||
battery_balancing_shunts[61] = (rx_frame.data.u8[4] & 0x04) >> 2;
|
||||
battery_balancing_shunts[62] = (rx_frame.data.u8[4] & 0x02) >> 1;
|
||||
battery_balancing_shunts[63] = (rx_frame.data.u8[4] & 0x01);
|
||||
|
||||
battery_balancing_shunts[64] = (rx_frame.data.u8[5] & 0x80) >> 7;
|
||||
battery_balancing_shunts[65] = (rx_frame.data.u8[5] & 0x40) >> 6;
|
||||
battery_balancing_shunts[66] = (rx_frame.data.u8[5] & 0x20) >> 5;
|
||||
battery_balancing_shunts[67] = (rx_frame.data.u8[5] & 0x10) >> 4;
|
||||
battery_balancing_shunts[68] = (rx_frame.data.u8[5] & 0x08) >> 3;
|
||||
battery_balancing_shunts[69] = (rx_frame.data.u8[5] & 0x04) >> 2;
|
||||
battery_balancing_shunts[70] = (rx_frame.data.u8[5] & 0x02) >> 1;
|
||||
battery_balancing_shunts[71] = (rx_frame.data.u8[5] & 0x01);
|
||||
|
||||
battery_balancing_shunts[72] = (rx_frame.data.u8[6] & 0x80) >> 7;
|
||||
battery_balancing_shunts[73] = (rx_frame.data.u8[6] & 0x40) >> 6;
|
||||
battery_balancing_shunts[74] = (rx_frame.data.u8[6] & 0x20) >> 5;
|
||||
battery_balancing_shunts[75] = (rx_frame.data.u8[6] & 0x10) >> 4;
|
||||
battery_balancing_shunts[76] = (rx_frame.data.u8[6] & 0x08) >> 3;
|
||||
battery_balancing_shunts[77] = (rx_frame.data.u8[6] & 0x04) >> 2;
|
||||
battery_balancing_shunts[78] = (rx_frame.data.u8[6] & 0x02) >> 1;
|
||||
battery_balancing_shunts[79] = (rx_frame.data.u8[6] & 0x01);
|
||||
|
||||
battery_balancing_shunts[80] = (rx_frame.data.u8[7] & 0x80) >> 7;
|
||||
battery_balancing_shunts[81] = (rx_frame.data.u8[7] & 0x40) >> 6;
|
||||
battery_balancing_shunts[82] = (rx_frame.data.u8[7] & 0x20) >> 5;
|
||||
battery_balancing_shunts[83] = (rx_frame.data.u8[7] & 0x10) >> 4;
|
||||
battery_balancing_shunts[84] = (rx_frame.data.u8[7] & 0x08) >> 3;
|
||||
battery_balancing_shunts[85] = (rx_frame.data.u8[7] & 0x04) >> 2;
|
||||
battery_balancing_shunts[86] = (rx_frame.data.u8[7] & 0x02) >> 1;
|
||||
battery_balancing_shunts[87] = (rx_frame.data.u8[7] & 0x01);
|
||||
}
|
||||
if (rx_frame.data.u8[0] == 0x22) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// Byte 1 (bits 88-95)
|
||||
battery_balancing_shunts[88 + i] = (rx_frame.data.u8[1] & (1 << i)) >> i;
|
||||
}
|
||||
if (rx_frame.data.u8[0] == 0x25) {
|
||||
battery_balancing_shunts[88] = (rx_frame.data.u8[1] & 0x80) >> 7;
|
||||
battery_balancing_shunts[89] = (rx_frame.data.u8[1] & 0x40) >> 6;
|
||||
battery_balancing_shunts[90] = (rx_frame.data.u8[1] & 0x20) >> 5;
|
||||
battery_balancing_shunts[91] = (rx_frame.data.u8[1] & 0x10) >> 4;
|
||||
battery_balancing_shunts[92] = (rx_frame.data.u8[1] & 0x08) >> 3;
|
||||
battery_balancing_shunts[93] = (rx_frame.data.u8[1] & 0x04) >> 2;
|
||||
battery_balancing_shunts[94] = (rx_frame.data.u8[1] & 0x02) >> 1;
|
||||
battery_balancing_shunts[95] = (rx_frame.data.u8[1] & 0x01);
|
||||
|
||||
memcpy(datalayer.battery.status.cell_balancing_status, battery_balancing_shunts, 96 * sizeof(bool));
|
||||
}
|
||||
battery_balance_switches = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
break;
|
||||
case POLL_ENERGY_COMPLETE:
|
||||
battery_energy_complete = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
|
@ -572,8 +660,6 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
|||
if (datalayer_extended.zoePH2.UserRequestNVROLReset) {
|
||||
// Send NVROL reset frames
|
||||
transmit_reset_nvrol_frames();
|
||||
// after transmitting the NVROL reset frames, set the nvrol reset flag to false, to continue normal operation
|
||||
datalayer_extended.zoePH2.UserRequestNVROLReset = false;
|
||||
} else {
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
|
@ -608,7 +694,6 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
|||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
}
|
||||
|
||||
// 1000mss
|
||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
previousMillis1000 = currentMillis;
|
||||
|
||||
|
@ -652,38 +737,53 @@ void RenaultZoeGen2Battery::transmit_can_frame_376(void) {
|
|||
}
|
||||
|
||||
void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
||||
// NVROL reset, part 1: send 0x021003AAAAAAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
// wait 100 ms
|
||||
wait_ms(100);
|
||||
// NVROL reset, part 2: send 0x043101B00900AAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x04, 0x31, 0x01, 0xB0, 0x09, 0x00, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
|
||||
// wait 1 s
|
||||
wait_ms(1000);
|
||||
|
||||
// Enable temporisation before sleep, part 1: send 0x021003AAAAAAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
// wait 100 ms
|
||||
wait_ms(100);
|
||||
// Enable temporisation before sleep, part 2: send 0x042E928101AAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x04, 0x2E, 0x92, 0x81, 0x01, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
|
||||
// Set data back to init values
|
||||
ZOE_POLL_18DADBF1.data = {0x03, 0x22, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
poll_index = 0;
|
||||
|
||||
// after transmitting these frames, wait 30 s
|
||||
wait_ms(30000);
|
||||
}
|
||||
|
||||
void RenaultZoeGen2Battery::wait_ms(int duration_ms) {
|
||||
unsigned long freezeMillis = millis();
|
||||
while (millis() - freezeMillis < duration_ms) {
|
||||
// Do nothing - just wait
|
||||
switch (NVROLstateMachine) {
|
||||
case 0:
|
||||
startTimeNVROL = millis();
|
||||
// NVROL reset, part 1: send 0x021003AAAAAAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
NVROLstateMachine = 1;
|
||||
break;
|
||||
case 1: // wait 100 ms
|
||||
if ((millis() - startTimeNVROL) > INTERVAL_100_MS) {
|
||||
// NVROL reset, part 2: send 0x043101B00900AAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x04, 0x31, 0x01, 0xB0, 0x09, 0x00, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
startTimeNVROL = millis(); //Reset time start, so we can check time for next step
|
||||
NVROLstateMachine = 2;
|
||||
}
|
||||
break;
|
||||
case 2: // wait 1 s
|
||||
if ((millis() - startTimeNVROL) > INTERVAL_1_S) {
|
||||
// Enable temporisation before sleep, part 1: send 0x021003AAAAAAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
startTimeNVROL = millis(); //Reset time start, so we can check time for next step
|
||||
NVROLstateMachine = 3;
|
||||
}
|
||||
break;
|
||||
case 3: //Wait 100ms
|
||||
if ((millis() - startTimeNVROL) > INTERVAL_100_MS) {
|
||||
// Enable temporisation before sleep, part 2: send 0x042E928101AAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x04, 0x2E, 0x92, 0x81, 0x01, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||
// Set data back to init values, we are done with the ZOE_POLL_18DADBF1 frame
|
||||
ZOE_POLL_18DADBF1.data = {0x03, 0x22, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
poll_index = 0;
|
||||
NVROLstateMachine = 4;
|
||||
}
|
||||
break;
|
||||
case 4: //Wait 30s
|
||||
if ((millis() - startTimeNVROL) > INTERVAL_30_S) {
|
||||
// after sleeping, set the nvrol reset flag to false, to continue normal operation of sending CAN messages
|
||||
datalayer_extended.zoePH2.UserRequestNVROLReset = false;
|
||||
// reset state machine, we are done!
|
||||
NVROLstateMachine = 0;
|
||||
}
|
||||
break;
|
||||
default: //Something went catastrophically wrong. Reset state machine
|
||||
NVROLstateMachine = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,8 @@ class RenaultZoeGen2Battery : public CanBattery {
|
|||
static const int POLL_CELL_93 = 0x9081;
|
||||
static const int POLL_CELL_94 = 0x9082;
|
||||
static const int POLL_CELL_95 = 0x9083;
|
||||
|
||||
volatile unsigned long startTimeNVROL = 0;
|
||||
uint8_t NVROLstateMachine = 0;
|
||||
uint16_t battery_soc = 0;
|
||||
uint16_t battery_usable_soc = 5000;
|
||||
uint16_t battery_soh = 10000;
|
||||
|
|
|
@ -40,7 +40,6 @@ class RenaultZoeGen2HtmlRenderer : public BatteryHtmlRenderer {
|
|||
"<h4>balance capacity wake: " + String(datalayer_extended.zoePH2.battery_balance_capacity_wake) + "</h4>";
|
||||
content += "<h4>balance time wake: " + String(datalayer_extended.zoePH2.battery_balance_time_wake) + "</h4>";
|
||||
content += "<h4>bms state: " + String(datalayer_extended.zoePH2.battery_bms_state) + "</h4>";
|
||||
content += "<h4>balance switches: " + String(datalayer_extended.zoePH2.battery_balance_switches) + "</h4>";
|
||||
content += "<h4>energy complete: " + String(datalayer_extended.zoePH2.battery_energy_complete) + "</h4>";
|
||||
content += "<h4>energy partial: " + String(datalayer_extended.zoePH2.battery_energy_partial) + "</h4>";
|
||||
content += "<h4>slave failures: " + String(datalayer_extended.zoePH2.battery_slave_failures) + "</h4>";
|
||||
|
|
|
@ -297,6 +297,78 @@ typedef struct {
|
|||
typedef struct {
|
||||
uint8_t MainConnectorState = 0;
|
||||
uint16_t InsulationResistance = 0;
|
||||
uint8_t InsulationDiag = 0;
|
||||
bool InterlockOpen = false;
|
||||
bool UserRequestContactorReset = false;
|
||||
bool UserRequestCollisionReset = false;
|
||||
bool UserRequestIsolationReset = false;
|
||||
bool UserRequestDisableIsoMonitoring = false;
|
||||
uint8_t pid_welding_detection = 0;
|
||||
uint8_t pid_reason_open = 0;
|
||||
uint8_t pid_contactor_status = 0;
|
||||
uint8_t pid_negative_contactor_control = 0;
|
||||
uint8_t pid_negative_contactor_status = 0;
|
||||
uint8_t pid_positive_contactor_control = 0;
|
||||
uint8_t pid_positive_contactor_status = 0;
|
||||
uint8_t pid_contactor_negative = 0;
|
||||
uint8_t pid_contactor_positive = 0;
|
||||
uint8_t pid_precharge_relay_control = 0;
|
||||
uint8_t pid_precharge_relay_status = 0;
|
||||
uint8_t pid_recharge_status = 0;
|
||||
uint8_t pid_delta_temperature = 0;
|
||||
uint8_t pid_coldest_module = 0;
|
||||
uint8_t pid_lowest_temperature = 0;
|
||||
uint8_t pid_average_temperature = 0;
|
||||
uint8_t pid_highest_temperature = 0;
|
||||
uint8_t pid_hottest_module = 0;
|
||||
uint16_t pid_avg_cell_voltage = 0;
|
||||
int32_t pid_current = 0;
|
||||
uint32_t pid_insulation_res_neg = 0;
|
||||
uint32_t pid_insulation_res_pos = 0;
|
||||
uint32_t pid_max_current_10s = 0;
|
||||
uint32_t pid_max_discharge_10s = 0;
|
||||
uint32_t pid_max_discharge_30s = 0;
|
||||
uint32_t pid_max_charge_10s = 0;
|
||||
uint32_t pid_max_charge_30s = 0;
|
||||
uint32_t pid_energy_capacity = 0;
|
||||
uint8_t pid_highest_cell_voltage_num = 0;
|
||||
uint8_t pid_lowest_cell_voltage_num = 0;
|
||||
uint16_t pid_sum_of_cells = 0;
|
||||
uint16_t pid_cell_min_capacity = 0;
|
||||
uint8_t pid_cell_voltage_measurement_status = 0;
|
||||
uint32_t pid_insulation_res = 0;
|
||||
uint16_t pid_pack_voltage = 0;
|
||||
uint16_t pid_high_cell_voltage = 0;
|
||||
uint16_t pid_low_cell_voltage = 0;
|
||||
uint8_t pid_battery_energy = 0;
|
||||
uint32_t pid_crash_counter = 0;
|
||||
uint8_t pid_wire_crash = 0;
|
||||
uint8_t pid_CAN_crash = 0;
|
||||
uint32_t pid_history_data = 0;
|
||||
uint32_t pid_lowsoc_counter = 0;
|
||||
uint32_t pid_last_can_failure_detail = 0;
|
||||
uint32_t pid_hw_version_num = 0;
|
||||
uint32_t pid_sw_version_num = 0;
|
||||
uint32_t pid_factory_mode_control = 0;
|
||||
uint8_t pid_battery_serial[13] = {0};
|
||||
uint32_t pid_aux_fuse_state = 0;
|
||||
uint32_t pid_battery_state = 0;
|
||||
uint32_t pid_precharge_short_circuit = 0;
|
||||
uint32_t pid_eservice_plug_state = 0;
|
||||
uint32_t pid_mainfuse_state = 0;
|
||||
uint32_t pid_most_critical_fault = 0;
|
||||
uint32_t pid_current_time = 0;
|
||||
uint32_t pid_time_sent_by_car = 0;
|
||||
uint32_t pid_12v = 0;
|
||||
uint32_t pid_12v_abnormal = 0;
|
||||
uint32_t pid_hvil_in_voltage = 0;
|
||||
uint32_t pid_hvil_out_voltage = 0;
|
||||
uint32_t pid_hvil_state = 0;
|
||||
uint32_t pid_bms_state = 0;
|
||||
uint32_t pid_vehicle_speed = 0;
|
||||
uint32_t pid_time_spent_over_55c = 0;
|
||||
uint32_t pid_contactor_closing_counter = 0;
|
||||
uint32_t pid_date_of_manufacture = 0;
|
||||
} DATALAYER_INFO_ECMP;
|
||||
|
||||
typedef struct {
|
||||
|
@ -754,6 +826,8 @@ typedef struct {
|
|||
uint8_t HVBOT = 0;
|
||||
uint8_t HVBOV = 0;
|
||||
uint8_t COV = 0;
|
||||
uint16_t mileage_km = 0;
|
||||
uint16_t alltime_kWh = 0;
|
||||
} DATALAYER_INFO_ZOE;
|
||||
|
||||
typedef struct {
|
||||
|
@ -788,7 +862,6 @@ typedef struct {
|
|||
uint16_t battery_balance_capacity_wake = 0;
|
||||
uint16_t battery_balance_time_wake = 0;
|
||||
uint16_t battery_bms_state = 0;
|
||||
uint16_t battery_balance_switches = 0;
|
||||
uint16_t battery_energy_complete = 0;
|
||||
uint16_t battery_energy_partial = 0;
|
||||
uint16_t battery_slave_failures = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <list>
|
||||
#include "../../../USER_SECRETS.h"
|
||||
#include "../../../USER_SETTINGS.h"
|
||||
#include "../../battery/BATTERIES.h"
|
||||
|
@ -74,7 +75,7 @@ static std::function<bool(Battery*)> supports_charged = [](Battery* b) {
|
|||
return b->supports_charged_energy();
|
||||
};
|
||||
|
||||
SensorConfig sensorConfigTemplate[] = {
|
||||
SensorConfig batterySensorConfigTemplate[] = {
|
||||
{"SOC", "SOC (Scaled)", "", "%", "battery", always},
|
||||
{"SOC_real", "SOC (real)", "", "%", "battery", always},
|
||||
{"state_of_health", "State Of Health", "", "%", "battery", always},
|
||||
|
@ -93,34 +94,36 @@ SensorConfig sensorConfigTemplate[] = {
|
|||
{"max_discharge_power", "Battery Max Discharge Power", "", "W", "power", always},
|
||||
{"max_charge_power", "Battery Max Charge Power", "", "W", "power", always},
|
||||
{"charged_energy", "Battery Charged Energy", "", "Wh", "energy", supports_charged},
|
||||
{"discharged_energy", "Battery Discharged Energy", "", "Wh", "energy", supports_charged},
|
||||
{"bms_status", "BMS Status", "", "", "", always},
|
||||
{"pause_status", "Pause Status", "", "", "", always}};
|
||||
{"discharged_energy", "Battery Discharged Energy", "", "Wh", "energy", supports_charged}};
|
||||
|
||||
// Enough space for two batteries
|
||||
SensorConfig sensorConfigs[((sizeof(sensorConfigTemplate) / sizeof(sensorConfigTemplate[0])) * 2) - 2];
|
||||
SensorConfig globalSensorConfigTemplate[] = {{"bms_status", "BMS Status", "", "", "", always},
|
||||
{"pause_status", "Pause Status", "", "", "", always}};
|
||||
|
||||
void create_sensor_configs() {
|
||||
int number_of_templates = sizeof(sensorConfigTemplate) / sizeof(sensorConfigTemplate[0]);
|
||||
static std::list<SensorConfig> sensorConfigs;
|
||||
|
||||
for (int i = 0; i < number_of_templates; i++) {
|
||||
SensorConfig config = sensorConfigTemplate[i];
|
||||
void create_battery_sensor_configs() {
|
||||
for (auto& config : batterySensorConfigTemplate) {
|
||||
config.value_template = strdup(("{{ value_json." + std::string(config.object_id) + " }}").c_str());
|
||||
sensorConfigs[i] = config;
|
||||
|
||||
sensorConfigs.push_back(config);
|
||||
|
||||
if (battery2) {
|
||||
if (config.object_id == "pause_status" || config.object_id == "bms_status") {
|
||||
continue;
|
||||
}
|
||||
sensorConfigs[i + number_of_templates] = config;
|
||||
sensorConfigs[i + number_of_templates].name = strdup(String(config.name + String(" 2")).c_str());
|
||||
sensorConfigs[i + number_of_templates].object_id = strdup(String(config.object_id + String("_2")).c_str());
|
||||
sensorConfigs[i + number_of_templates].value_template =
|
||||
strdup(("{{ value_json." + std::string(config.object_id) + "_2 }}").c_str());
|
||||
config.value_template = strdup(("{{ value_json." + std::string(config.object_id) + "_2 }}").c_str());
|
||||
config.name = strdup(String(config.name + String(" 2")).c_str());
|
||||
config.object_id = strdup(String(config.object_id + String("_2")).c_str());
|
||||
|
||||
sensorConfigs.push_back(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_global_sensor_configs() {
|
||||
for (auto& config : globalSensorConfigTemplate) {
|
||||
config.value_template = strdup(("{{ value_json." + std::string(config.object_id) + " }}").c_str());
|
||||
sensorConfigs.push_back(config);
|
||||
}
|
||||
}
|
||||
|
||||
SensorConfig buttonConfigs[] = {{"BMSRESET", "Reset BMS"},
|
||||
{"PAUSE", "Pause charge/discharge"},
|
||||
{"RESUME", "Resume charge/discharge"},
|
||||
|
@ -210,9 +213,7 @@ static bool publish_common_info(void) {
|
|||
static String state_topic = topic_name + "/info";
|
||||
#ifdef HA_AUTODISCOVERY
|
||||
if (ha_common_info_published == false) {
|
||||
for (int i = 0; i < sizeof(sensorConfigs) / sizeof(sensorConfigs[0]); i++) {
|
||||
SensorConfig& config = sensorConfigs[i];
|
||||
|
||||
for (auto& config : sensorConfigs) {
|
||||
if (!config.condition(battery)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -542,9 +543,9 @@ static void mqtt_event_handler(void* handler_args, esp_event_base_t base, int32_
|
|||
}
|
||||
|
||||
void init_mqtt(void) {
|
||||
|
||||
#ifdef HA_AUTODISCOVERY
|
||||
create_sensor_configs();
|
||||
create_battery_sensor_configs();
|
||||
create_global_sensor_configs();
|
||||
#endif // HA_AUTODISCOVERY
|
||||
#ifdef MQTT_MANUAL_TOPIC_OBJECT_NAME
|
||||
// Use custom topic name, object ID prefix, and device name from user settings
|
||||
|
@ -560,12 +561,12 @@ void init_mqtt(void) {
|
|||
device_id = "battery-emulator";
|
||||
#endif
|
||||
|
||||
char clientId[64]; // Adjust the size as needed
|
||||
snprintf(clientId, sizeof(clientId), "BatteryEmulatorClient-%s", WiFi.getHostname());
|
||||
String clientId = String("BatteryEmulatorClient-") + WiFi.getHostname();
|
||||
|
||||
mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_TCP;
|
||||
mqtt_cfg.broker.address.hostname = MQTT_SERVER;
|
||||
mqtt_cfg.broker.address.port = MQTT_PORT;
|
||||
mqtt_cfg.credentials.client_id = clientId;
|
||||
mqtt_cfg.credentials.client_id = clientId.c_str();
|
||||
mqtt_cfg.credentials.username = MQTT_USER;
|
||||
mqtt_cfg.credentials.authentication.password = MQTT_PASSWORD;
|
||||
lwt_topic = topic_name + "/status";
|
||||
|
|
|
@ -101,6 +101,7 @@ void init_events(void) {
|
|||
events.entries[EVENT_SERIAL_RX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_SERIAL_TX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_SERIAL_TRANSMITTER_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_SMA_PAIRING].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_RESET_UNKNOWN].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_RESET_POWERON].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_RESET_EXT].level = EVENT_LEVEL_INFO;
|
||||
|
@ -305,6 +306,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
|
|||
return "Error in serial function: No ACK from receiver!";
|
||||
case EVENT_SERIAL_TRANSMITTER_FAILURE:
|
||||
return "Error in serial function: Some ERROR level fault in transmitter, received by receiver";
|
||||
case EVENT_SMA_PAIRING:
|
||||
return "SMA inverter trying to pair, contactors will close and open according to Enable line";
|
||||
case EVENT_OTA_UPDATE:
|
||||
return "OTA update started!";
|
||||
case EVENT_OTA_UPDATE_TIMEOUT:
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
XX(EVENT_SERIAL_RX_FAILURE) \
|
||||
XX(EVENT_SERIAL_TX_FAILURE) \
|
||||
XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \
|
||||
XX(EVENT_SMA_PAIRING) \
|
||||
XX(EVENT_TASK_OVERRUN) \
|
||||
XX(EVENT_RESET_UNKNOWN) \
|
||||
XX(EVENT_RESET_POWERON) \
|
||||
|
|
|
@ -34,6 +34,7 @@ enum PrechargeState {
|
|||
#define INTERVAL_2_S 2000
|
||||
#define INTERVAL_5_S 5000
|
||||
#define INTERVAL_10_S 10000
|
||||
#define INTERVAL_30_S 30000
|
||||
#define INTERVAL_60_S 60000
|
||||
|
||||
#define INTERVAL_10_MS_DELAYED 15
|
||||
|
|
|
@ -28,6 +28,11 @@ std::vector<BatteryCommand> battery_commands = {
|
|||
[](Battery* b) {
|
||||
b->reset_NVROL();
|
||||
}},
|
||||
{"resetContactor", "Perform contactor reset", "reset contactors?",
|
||||
[](Battery* b) { return b && b->supports_contactor_reset(); },
|
||||
[](Battery* b) {
|
||||
b->reset_contactor();
|
||||
}},
|
||||
{"resetDTC", "Erase DTC", "erase DTCs?", [](Battery* b) { return b && b->supports_reset_DTC(); },
|
||||
[](Battery* b) {
|
||||
b->reset_DTC();
|
||||
|
@ -56,6 +61,11 @@ std::vector<BatteryCommand> battery_commands = {
|
|||
[](Battery* b) {
|
||||
b->reset_SOH();
|
||||
}},
|
||||
{"setFactoryMode", "Set Factory Mode", "set factory mode and disable isolation measurement?",
|
||||
[](Battery* b) { return b && b->supports_factory_mode_method(); },
|
||||
[](Battery* b) {
|
||||
b->set_factory_mode();
|
||||
}},
|
||||
{"toggleSOC", "Toggle SOC method",
|
||||
"toggle SOC method? This will toggle between ESTIMATED and MEASURED SOC methods.",
|
||||
[](Battery* b) { return b && b->supports_toggle_SOC_method(); },
|
||||
|
|
|
@ -519,7 +519,7 @@ void init_webserver() {
|
|||
if (request->hasParam("stop")) {
|
||||
String valueStr = request->getParam("stop")->value();
|
||||
if (valueStr == "true" || valueStr == "1") {
|
||||
setBatteryPause(true, false, true);
|
||||
setBatteryPause(true, false, true); //Pause battery, do not pause CAN, equipment stop on (store to flash)
|
||||
} else {
|
||||
setBatteryPause(false, false, false);
|
||||
}
|
||||
|
@ -1488,7 +1488,7 @@ String processor(const String& var) {
|
|||
content +=
|
||||
"<br/><br/><button style=\"background:red;color:white;cursor:pointer;\""
|
||||
" onclick=\""
|
||||
"if(confirm('This action will open contactors on the battery and stop all CAN communications. Are you "
|
||||
"if(confirm('This action will attempt to open contactors on the battery. Are you "
|
||||
"sure?')) { estop(true); }\""
|
||||
">Open Contactors</button><br/>";
|
||||
else
|
||||
|
@ -1496,7 +1496,8 @@ String processor(const String& var) {
|
|||
"<br/><br/><button style=\"background:green;color:white;cursor:pointer;\""
|
||||
"20px;font-size:16px;font-weight:bold;cursor:pointer;border-radius:5px; margin:10px;"
|
||||
" onclick=\""
|
||||
"if(confirm('This action will restore the battery state. Are you sure?')) { estop(false); }\""
|
||||
"if(confirm('This action will attempt to close contactors and enable power transfer. Are you sure?')) { "
|
||||
"estop(false); }\""
|
||||
">Close Contactors</button><br/>";
|
||||
content += "<script>";
|
||||
content += "function OTA() { window.location.href = '/update'; }";
|
||||
|
|
|
@ -216,6 +216,8 @@ void SmaBydHInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
|
|||
#ifdef DEBUG_LOG
|
||||
logging.println("Received 0x5E7: SMA pairing request");
|
||||
#endif // DEBUG_LOG
|
||||
pairing_events++;
|
||||
set_event(EVENT_SMA_PAIRING, pairing_events);
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
transmit_can_init();
|
||||
break;
|
||||
|
|
|
@ -23,6 +23,7 @@ class SmaBydHInverter : public CanInverterProtocol {
|
|||
|
||||
unsigned long previousMillis100ms = 0;
|
||||
|
||||
uint8_t pairing_events = 0;
|
||||
uint32_t inverter_time = 0;
|
||||
uint16_t inverter_voltage = 0;
|
||||
int16_t inverter_current = 0;
|
||||
|
|
|
@ -206,6 +206,8 @@ void SmaBydHvsInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
|
|||
#ifdef DEBUG_LOG
|
||||
logging.println("Received 0x5E7: SMA pairing request");
|
||||
#endif // DEBUG_LOG
|
||||
pairing_events++;
|
||||
set_event(EVENT_SMA_PAIRING, pairing_events);
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
transmit_can_init = true;
|
||||
break;
|
||||
|
|
|
@ -27,6 +27,7 @@ class SmaBydHvsInverter : public CanInverterProtocol {
|
|||
7; //TODO, tweak to as low as possible before performance issues/crashes appear
|
||||
bool transmit_can_init = false;
|
||||
|
||||
uint8_t pairing_events = 0;
|
||||
uint32_t inverter_time = 0;
|
||||
uint16_t inverter_voltage = 0;
|
||||
int16_t inverter_current = 0;
|
||||
|
|
|
@ -100,6 +100,11 @@ void SmaTripowerInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
|
|||
//Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA
|
||||
break;
|
||||
case 0x660: //Message originating from SMA inverter - Pairing request
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Received 0x660: SMA pairing request");
|
||||
#endif // DEBUG_LOG
|
||||
pairing_events++;
|
||||
set_event(EVENT_SMA_PAIRING, pairing_events);
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
transmit_can_init();
|
||||
break;
|
||||
|
|
|
@ -41,6 +41,7 @@ class SmaTripowerInverter : public CanInverterProtocol {
|
|||
uint32_t inverter_time = 0;
|
||||
uint16_t inverter_voltage = 0;
|
||||
int16_t inverter_current = 0;
|
||||
uint8_t pairing_events = 0;
|
||||
bool pairing_completed = false;
|
||||
int16_t temperature_average = 0;
|
||||
uint16_t ampere_hours_remaining = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue