mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Data layer introduction (#254)
* Active power, SOH * Total and remaining capacity * pre-commit, baby! * Typo * pre-commit wrestling * Temp min/max * Voltage and current * Min/max design voltage * BMS status, max charge/discharge, cell min/max * BMS status cleanup * Pre-commit, we meet again * Cell voltages and minor fixes * Cell number * SOC * Missed a spot * Event handling moved, Wh bugs fixed, time measurements improved * Pre-commit, old friend... * Battery chemistry * Update TESLA-MODEL-3-BATTERY.cpp * Total capacity/Wh max, soem default values * Good ol' pre-comm * Some prio/core cleanup, docs... * Contactor closing variables * Max charge/discharge amps * Data layer variable documentation * USER_SETTINGS comments * Charger comment * Update datalayer.h
This commit is contained in:
parent
e7f14084e3
commit
0fee07313a
68 changed files with 1097 additions and 1510 deletions
|
@ -60,28 +60,6 @@ uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory
|
|||
ModbusServerRTU MBserver(Serial2, 2000);
|
||||
#endif
|
||||
|
||||
// Common system parameters. Batteries map their values to these variables
|
||||
uint32_t system_capacity_Wh = BATTERY_WH_MAX; //Wh, 0-500000 Wh
|
||||
uint32_t system_remaining_capacity_Wh = BATTERY_WH_MAX; //Wh, 0-500000 Wh
|
||||
int16_t system_temperature_max_dC = 0; //C+1, -50.0 - 50.0
|
||||
int16_t system_temperature_min_dC = 0; //C+1, -50.0 - 50.0
|
||||
int32_t system_active_power_W = 0; //Watts, -200000 to 200000 W
|
||||
int16_t system_battery_current_dA = 0; //A+1, -1000 - 1000
|
||||
uint16_t system_battery_voltage_dV = 3700; //V+1, 0-1000.0 (0-10000)
|
||||
uint16_t system_max_design_voltage_dV = 5000; //V+1, 0-1000.0 (0-10000)
|
||||
uint16_t system_min_design_voltage_dV = 2500; //V+1, 0-1000.0 (0-10000)
|
||||
uint16_t system_scaled_SOC_pptt = 5000; //SOC%, 0-100.00 (0-10000)
|
||||
uint16_t system_real_SOC_pptt = 5000; //SOC%, 0-100.00 (0-10000)
|
||||
uint16_t system_SOH_pptt = 9900; //SOH%, 0-100.00 (0-10000)
|
||||
uint32_t system_max_discharge_power_W = 0; //Watts, 0 to 200000
|
||||
uint32_t system_max_charge_power_W = 4312; //Watts, 0 to 200000
|
||||
uint16_t system_cell_max_voltage_mV = 3700; //mV, 0-5000 , Stores the highest cell millivolt value
|
||||
uint16_t system_cell_min_voltage_mV = 3700; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages. Oversized to accomodate all setups
|
||||
uint8_t system_bms_status = ACTIVE; //ACTIVE - [0..5]<>[STANDBY,INACTIVE,DARKSTART,ACTIVE,FAULT,UPDATING]
|
||||
uint8_t system_number_of_cells = 0; //Total number of cell voltages, set by each battery
|
||||
bool system_LFP_Chemistry = false; //Set to true or false depending on cell chemistry
|
||||
|
||||
// Common charger parameters
|
||||
volatile float charger_setpoint_HV_VDC = 0.0f;
|
||||
volatile float charger_setpoint_HV_IDC = 0.0f;
|
||||
|
@ -104,6 +82,8 @@ MyTimer core_task_timer_10s(INTERVAL_10_S);
|
|||
int64_t mqtt_task_time_us;
|
||||
MyTimer mqtt_task_timer_10s(INTERVAL_10_S);
|
||||
|
||||
MyTimer loop_task_timer_10s(INTERVAL_10_S);
|
||||
|
||||
// Contactor parameters
|
||||
#ifdef CONTACTOR_CONTROL
|
||||
enum State { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
|
||||
|
@ -124,11 +104,9 @@ unsigned long prechargeStartTime = 0;
|
|||
unsigned long negativeStartTime = 0;
|
||||
unsigned long timeSpentInFaultedMode = 0;
|
||||
#endif
|
||||
bool batteryAllowsContactorClosing = false;
|
||||
bool inverterAllowsContactorClosing = true;
|
||||
|
||||
TaskHandle_t main_loop_task;
|
||||
TaskHandle_t wifi_loop_task;
|
||||
TaskHandle_t mqtt_loop_task;
|
||||
|
||||
// Initialization
|
||||
void setup() {
|
||||
|
@ -140,8 +118,8 @@ void setup() {
|
|||
init_webserver();
|
||||
init_mDNS();
|
||||
#ifdef MQTT
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, &mqtt_task_time_us, TASK_WIFI_PRIO,
|
||||
&main_loop_task, WIFI_CORE);
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, &mqtt_task_time_us, TASK_CONNECTIVITY_PRIO,
|
||||
&mqtt_loop_task, WIFI_CORE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -169,7 +147,16 @@ void setup() {
|
|||
}
|
||||
|
||||
// Perform main program functions
|
||||
void loop() {}
|
||||
void loop() {
|
||||
START_TIME_MEASUREMENT(loop_func);
|
||||
run_event_handling();
|
||||
END_TIME_MEASUREMENT_MAX(loop_func, datalayer.system.status.loop_task_10s_max_us);
|
||||
#ifdef FUNCTION_TIME_MEASUREMENT
|
||||
if (loop_task_timer_10s.elapsed()) {
|
||||
datalayer.system.status.loop_task_10s_max_us = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MQTT
|
||||
void mqtt_loop(void* task_time_us) {
|
||||
|
@ -179,11 +166,11 @@ void mqtt_loop(void* task_time_us) {
|
|||
while (true) {
|
||||
START_TIME_MEASUREMENT(mqtt);
|
||||
mqtt_loop();
|
||||
END_TIME_MEASUREMENT_MAX(mqtt, datalayer.system.status.time_mqtt_us);
|
||||
END_TIME_MEASUREMENT_MAX(mqtt, datalayer.system.status.mqtt_task_10s_max_us);
|
||||
|
||||
#ifdef FUNCTION_TIME_MEASUREMENT
|
||||
if (mqtt_task_timer_10s.elapsed()) {
|
||||
datalayer.system.status.time_mqtt_us = 0;
|
||||
datalayer.system.status.mqtt_task_10s_max_us = 0;
|
||||
}
|
||||
#endif
|
||||
delay(1);
|
||||
|
@ -219,7 +206,7 @@ void core_loop(void* task_time_us) {
|
|||
START_TIME_MEASUREMENT(wifi_ota);
|
||||
wifi_monitor();
|
||||
ElegantOTA.loop();
|
||||
END_TIME_MEASUREMENT(wifi_ota, datalayer.system.status.time_wifi_us);
|
||||
END_TIME_MEASUREMENT_MAX(wifi_ota, datalayer.system.status.time_wifi_us);
|
||||
#endif
|
||||
|
||||
START_TIME_MEASUREMENT(time_10ms);
|
||||
|
@ -252,21 +239,29 @@ void core_loop(void* task_time_us) {
|
|||
send_can2();
|
||||
#endif
|
||||
END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us);
|
||||
|
||||
START_TIME_MEASUREMENT(events);
|
||||
run_event_handling();
|
||||
END_TIME_MEASUREMENT_MAX(events, datalayer.system.status.time_events_us);
|
||||
END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.main_task_10s_max_us);
|
||||
END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us);
|
||||
#ifdef FUNCTION_TIME_MEASUREMENT
|
||||
datalayer.system.status.main_task_max_us =
|
||||
MAX(datalayer.system.status.main_task_10s_max_us, datalayer.system.status.main_task_max_us);
|
||||
|
||||
if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) {
|
||||
// Update worst case total time
|
||||
datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us;
|
||||
// Record snapshots of task times
|
||||
datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us;
|
||||
datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us;
|
||||
datalayer.system.status.time_snap_5s_us = datalayer.system.status.time_5s_us;
|
||||
datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us;
|
||||
datalayer.system.status.time_snap_wifi_us = datalayer.system.status.time_wifi_us;
|
||||
}
|
||||
|
||||
datalayer.system.status.core_task_max_us =
|
||||
MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us);
|
||||
if (core_task_timer_10s.elapsed()) {
|
||||
datalayer.system.status.time_wifi_us = 0;
|
||||
datalayer.system.status.time_comm_us = 0;
|
||||
datalayer.system.status.time_10ms_us = 0;
|
||||
datalayer.system.status.time_5s_us = 0;
|
||||
datalayer.system.status.time_cantx_us = 0;
|
||||
datalayer.system.status.time_events_us = 0;
|
||||
datalayer.system.status.main_task_10s_max_us = 0;
|
||||
datalayer.system.status.core_task_10s_max_us = 0;
|
||||
}
|
||||
#endif
|
||||
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
||||
|
@ -314,25 +309,25 @@ void init_stored_settings() {
|
|||
static uint32_t temp = 0;
|
||||
temp = settings.getUInt("BATTERY_WH_MAX", false);
|
||||
if (temp != 0) {
|
||||
BATTERY_WH_MAX = temp;
|
||||
datalayer.battery.info.total_capacity_Wh = temp;
|
||||
}
|
||||
temp = settings.getUInt("MAXPERCENTAGE", false);
|
||||
if (temp != 0) {
|
||||
MAXPERCENTAGE = temp;
|
||||
datalayer.battery.settings.max_percentage = temp * 10; // Multiply by 10 for backwards compatibility
|
||||
}
|
||||
temp = settings.getUInt("MINPERCENTAGE", false);
|
||||
if (temp != 0) {
|
||||
MINPERCENTAGE = temp;
|
||||
datalayer.battery.settings.min_percentage = temp * 10; // Multiply by 10 for backwards compatibility
|
||||
}
|
||||
temp = settings.getUInt("MAXCHARGEAMP", false);
|
||||
if (temp != 0) {
|
||||
MAXCHARGEAMP = temp;
|
||||
datalayer.battery.info.max_charge_amp_dA = temp;
|
||||
}
|
||||
temp = settings.getUInt("MAXDISCHARGEAMP", false);
|
||||
if (temp != 0) {
|
||||
MAXDISCHARGEAMP = temp;
|
||||
datalayer.battery.info.max_discharge_amp_dA = temp;
|
||||
temp = settings.getBool("USE_SCALED_SOC", false);
|
||||
USE_SCALED_SOC = temp; //This bool needs to be checked inside the temp!= block
|
||||
datalayer.battery.settings.soc_scaling_active = temp; //This bool needs to be checked inside the temp!= block
|
||||
} // No way to know if it wasnt reset otherwise
|
||||
|
||||
settings.end();
|
||||
|
@ -484,7 +479,8 @@ void inform_user_on_inverter() {
|
|||
#endif
|
||||
#endif
|
||||
#ifdef SOLAX_CAN
|
||||
inverterAllowsContactorClosing = false; // The inverter needs to allow first on this protocol
|
||||
datalayer.system.status.inverter_allows_contactor_closing =
|
||||
false; // The inverter needs to allow first on this protocol
|
||||
intervalUpdateValues = 800; // This protocol also requires the values to be updated faster
|
||||
#ifdef DEBUG_VIA_USB
|
||||
Serial.println("SOLAX CAN protocol selected");
|
||||
|
@ -618,7 +614,7 @@ void send_can2() {
|
|||
#ifdef CONTACTOR_CONTROL
|
||||
void handle_contactors() {
|
||||
// First check if we have any active errors, incase we do, turn off the battery
|
||||
if (system_bms_status == FAULT) {
|
||||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
timeSpentInFaultedMode++;
|
||||
} else {
|
||||
timeSpentInFaultedMode = 0;
|
||||
|
@ -642,14 +638,15 @@ void handle_contactors() {
|
|||
ledcWrite(NEGATIVE_PWM_Ch, 0);
|
||||
#endif
|
||||
|
||||
if (batteryAllowsContactorClosing && inverterAllowsContactorClosing) {
|
||||
if (datalayer.system.status.battery_allows_contactor_closing &&
|
||||
datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
contactorStatus = PRECHARGE;
|
||||
}
|
||||
}
|
||||
|
||||
// In case the inverter requests contactors to open, set the state accordingly
|
||||
if (contactorStatus == COMPLETED) {
|
||||
if (!inverterAllowsContactorClosing)
|
||||
if (!datalayer.system.status.inverter_allows_contactor_closing)
|
||||
contactorStatus = DISCONNECTED;
|
||||
// Skip running the state machine below if it has already completed
|
||||
return;
|
||||
|
@ -702,19 +699,37 @@ void handle_contactors() {
|
|||
#endif
|
||||
|
||||
void update_SOC() {
|
||||
if (USE_SCALED_SOC) { //User has configred a SOC window. Calculate a SOC% to send towards inverter
|
||||
static int16_t CalculatedSOC = 0;
|
||||
CalculatedSOC = system_real_SOC_pptt;
|
||||
CalculatedSOC = (10000) * (CalculatedSOC - (MINPERCENTAGE * 10)) / (MAXPERCENTAGE * 10 - MINPERCENTAGE * 10);
|
||||
if (CalculatedSOC < 0) { //We are in the real SOC% range of 0-MINPERCENTAGE%
|
||||
CalculatedSOC = 0;
|
||||
}
|
||||
if (CalculatedSOC > 10000) { //We are in the real SOC% range of MAXPERCENTAGE-100%
|
||||
CalculatedSOC = 10000;
|
||||
}
|
||||
system_scaled_SOC_pptt = CalculatedSOC;
|
||||
if (datalayer.battery.settings.soc_scaling_active) {
|
||||
/** SOC Scaling
|
||||
*
|
||||
* This is essentially a more static version of a stochastic oscillator (https://en.wikipedia.org/wiki/Stochastic_oscillator)
|
||||
*
|
||||
* The idea is this:
|
||||
*
|
||||
* real_soc - min_percent 3000 - 1000
|
||||
* ------------------------- = scaled_soc, or ----------- = 0.25
|
||||
* max_percent - min-percent 8000 - 1000
|
||||
*
|
||||
* Because we use integers, we want to account for the scaling:
|
||||
*
|
||||
* 10000 * (real_soc - min_percent) 10000 * (3000 - 1000)
|
||||
* -------------------------------- = scaled_soc, or --------------------- = 2500
|
||||
* max_percent - min_percent 8000 - 1000
|
||||
*
|
||||
* Or as a one-liner: (10000 * (real_soc - min_percentage)) / (max_percentage - min_percentage)
|
||||
*
|
||||
* Before we use real_soc, we must make sure that it's within the range of min_percentage and max_percentage.
|
||||
*/
|
||||
uint32_t calc_soc;
|
||||
// Make sure that the SOC starts out between min and max percentages
|
||||
calc_soc = CONSTRAIN(datalayer.battery.status.real_soc, datalayer.battery.settings.min_percentage,
|
||||
datalayer.battery.settings.max_percentage);
|
||||
// Perform scaling
|
||||
calc_soc = 10000 * (calc_soc - datalayer.battery.settings.min_percentage);
|
||||
calc_soc = calc_soc / (datalayer.battery.settings.max_percentage - datalayer.battery.settings.min_percentage);
|
||||
datalayer.battery.status.reported_soc = calc_soc;
|
||||
} else { // No SOC window wanted. Set scaled to same as real.
|
||||
system_scaled_SOC_pptt = system_real_SOC_pptt;
|
||||
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,12 +788,14 @@ void init_serialDataLink() {
|
|||
|
||||
void storeSettings() {
|
||||
settings.begin("batterySettings", false);
|
||||
settings.putUInt("BATTERY_WH_MAX", BATTERY_WH_MAX);
|
||||
settings.putUInt("MAXPERCENTAGE", MAXPERCENTAGE);
|
||||
settings.putUInt("MINPERCENTAGE", MINPERCENTAGE);
|
||||
settings.putUInt("MAXCHARGEAMP", MAXCHARGEAMP);
|
||||
settings.putUInt("MAXDISCHARGEAMP", MAXDISCHARGEAMP);
|
||||
settings.putBool("USE_SCALED_SOC", USE_SCALED_SOC);
|
||||
settings.putUInt("BATTERY_WH_MAX", datalayer.battery.info.total_capacity_Wh);
|
||||
settings.putUInt("MAXPERCENTAGE",
|
||||
datalayer.battery.settings.max_percentage / 10); // Divide by 10 for backwards compatibility
|
||||
settings.putUInt("MINPERCENTAGE",
|
||||
datalayer.battery.settings.min_percentage / 10); // Divide by 10 for backwards compatibility
|
||||
settings.putUInt("MAXCHARGEAMP", datalayer.battery.info.max_charge_amp_dA);
|
||||
settings.putUInt("MAXDISCHARGEAMP", datalayer.battery.info.max_discharge_amp_dA);
|
||||
settings.putBool("USE_SCALED_SOC", datalayer.battery.settings.soc_scaling_active);
|
||||
|
||||
settings.end();
|
||||
}
|
||||
|
|
|
@ -3,21 +3,7 @@
|
|||
/* This file contains all the battery settings and limits */
|
||||
/* They can be defined here, or later on in the WebUI */
|
||||
|
||||
/* Battery settings */
|
||||
volatile bool USE_SCALED_SOC =
|
||||
true; //Increases battery life. If true will rescale SOC between the configured min/max-percentage
|
||||
volatile uint32_t BATTERY_WH_MAX = 30000; //Battery size in Wh
|
||||
volatile uint16_t MAXPERCENTAGE =
|
||||
800; //80.0% , Max percentage the battery will charge to (Inverter gets 100% when reached)
|
||||
volatile uint16_t MINPERCENTAGE =
|
||||
200; //20.0% , Min percentage the battery will discharge to (Inverter gets 0% when reached)
|
||||
volatile uint16_t MAXCHARGEAMP =
|
||||
300; //30.0A , BYD CAN specific setting, Max charge in Amp (Some inverters needs to be limited)
|
||||
volatile uint16_t MAXDISCHARGEAMP =
|
||||
300; //30.0A , BYD CAN specific setting, Max discharge in Amp (Some inverters needs to be limited)
|
||||
|
||||
/* Charger settings (Optional, when generator charging) */
|
||||
/* Charger settings */
|
||||
/* Charger settings (Optional, when using generator charging) */
|
||||
volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack
|
||||
volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger
|
||||
volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger
|
||||
|
|
|
@ -58,14 +58,23 @@
|
|||
//#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function.
|
||||
//#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging
|
||||
|
||||
/* Battery limits: These are set in the USER_SETTINGS.cpp file, or later on via the Webserver */
|
||||
extern volatile uint32_t BATTERY_WH_MAX;
|
||||
extern volatile uint16_t MAXPERCENTAGE;
|
||||
extern volatile uint16_t MINPERCENTAGE;
|
||||
extern volatile uint16_t MAXCHARGEAMP;
|
||||
extern volatile uint16_t MAXDISCHARGEAMP;
|
||||
/* Battery settings */
|
||||
|
||||
// Predefined total energy capacity of the battery in Watt-hours
|
||||
#define BATTERY_WH_MAX 30000
|
||||
// Increases battery life. If true will rescale SOC between the configured min/max-percentage
|
||||
#define BATTERY_USE_SCALED_SOC true
|
||||
// 8000 = 80.0% , Max percentage the battery will charge to (Inverter gets 100% when reached)
|
||||
#define BATTERY_MAXPERCENTAGE 8000
|
||||
// 2000 = 20.0% , Min percentage the battery will discharge to (Inverter gets 0% when reached)
|
||||
#define BATTERY_MINPERCENTAGE 2000
|
||||
// 300 = 30.0A , BYD CAN specific setting, Max charge in Amp (Some inverters needs to be limited)
|
||||
#define BATTERY_MAX_CHARGE_AMP 300
|
||||
// 300 = 30.0A , BYD CAN specific setting, Max discharge in Amp (Some inverters needs to be limited)
|
||||
#define BATTERY_MAX_DISCHARGE_AMP 300
|
||||
|
||||
extern volatile uint8_t AccessPointEnabled;
|
||||
extern volatile bool USE_SCALED_SOC;
|
||||
extern const uint8_t wifi_channel;
|
||||
|
||||
/* Charger limits (Optional): Set in the USER_SETTINGS.cpp or later in the webserver */
|
||||
extern volatile float charger_setpoint_HV_VDC;
|
||||
|
@ -80,6 +89,4 @@ extern volatile float CHARGER_END_A;
|
|||
extern bool charger_HV_enabled;
|
||||
extern bool charger_aux12V_enabled;
|
||||
|
||||
extern const uint8_t wifi_channel;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef BMW_I3_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -414,39 +415,37 @@ static uint8_t increment_alive_counter(uint8_t counter) {
|
|||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
system_real_SOC_pptt = (battery_HVBatt_SOC * 10);
|
||||
datalayer.battery.status.real_soc = (battery_HVBatt_SOC * 10);
|
||||
|
||||
system_battery_voltage_dV = battery_volts; //Unit V+1 (5000 = 500.0V)
|
||||
datalayer.battery.status.voltage_dV = battery_volts; //Unit V+1 (5000 = 500.0V)
|
||||
|
||||
system_battery_current_dA = battery_current;
|
||||
datalayer.battery.status.current_dA = battery_current;
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX;
|
||||
datalayer.battery.status.remaining_capacity_Wh = (battery_energy_content_maximum_kWh * 1000); // Convert kWh to Wh
|
||||
|
||||
system_remaining_capacity_Wh = (battery_energy_content_maximum_kWh * 1000); // Convert kWh to Wh
|
||||
|
||||
system_SOH_pptt = battery_soh * 100;
|
||||
datalayer.battery.status.soh_pptt = battery_soh * 100;
|
||||
|
||||
if (battery_BEV_available_power_longterm_discharge > 65000) {
|
||||
system_max_discharge_power_W = 65000;
|
||||
datalayer.battery.status.max_discharge_power_W = 65000;
|
||||
} else {
|
||||
system_max_discharge_power_W = battery_BEV_available_power_longterm_discharge;
|
||||
datalayer.battery.status.max_discharge_power_W = battery_BEV_available_power_longterm_discharge;
|
||||
}
|
||||
if (battery_BEV_available_power_longterm_charge > 65000) {
|
||||
system_max_charge_power_W = 65000;
|
||||
datalayer.battery.status.max_charge_power_W = 65000;
|
||||
} else {
|
||||
system_max_charge_power_W = battery_BEV_available_power_longterm_charge;
|
||||
datalayer.battery.status.max_charge_power_W = battery_BEV_available_power_longterm_charge;
|
||||
}
|
||||
|
||||
battery_power = (system_battery_current_dA * (system_battery_voltage_dV / 100));
|
||||
battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100));
|
||||
|
||||
system_active_power_W = battery_power;
|
||||
datalayer.battery.status.active_power_W = battery_power;
|
||||
|
||||
system_temperature_min_dC = battery_temperature_min * 10; // Add a decimal
|
||||
datalayer.battery.status.temperature_min_dC = battery_temperature_min * 10; // Add a decimal
|
||||
|
||||
system_temperature_max_dC = battery_temperature_max * 10; // Add a decimal
|
||||
datalayer.battery.status.temperature_max_dC = battery_temperature_max * 10; // Add a decimal
|
||||
|
||||
system_cell_min_voltage_mV = system_cellvoltages_mV[0];
|
||||
system_cell_max_voltage_mV = system_cellvoltages_mV[1];
|
||||
datalayer.battery.status.cell_min_voltage_mV = datalayer.battery.status.cell_voltages_mV[0];
|
||||
datalayer.battery.status.cell_max_voltage_mV = datalayer.battery.status.cell_voltages_mV[1];
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -464,25 +463,25 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
Serial.println(" ");
|
||||
Serial.print("Values sent to inverter: ");
|
||||
Serial.print("Real SOC%: ");
|
||||
Serial.print(system_real_SOC_pptt * 0.01);
|
||||
Serial.print(datalayer.battery.status.real_soc * 0.01);
|
||||
Serial.print(" Battery voltage: ");
|
||||
Serial.print(system_battery_voltage_dV * 0.1);
|
||||
Serial.print(datalayer.battery.status.voltage_dV * 0.1);
|
||||
Serial.print(" Battery current: ");
|
||||
Serial.print(system_battery_current_dA * 0.1);
|
||||
Serial.print(datalayer.battery.status.current_dA * 0.1);
|
||||
Serial.print(" Wh when full: ");
|
||||
Serial.print(system_capacity_Wh);
|
||||
Serial.print(datalayer.battery.info.total_capacity_Wh);
|
||||
Serial.print(" Remaining Wh: ");
|
||||
Serial.print(system_remaining_capacity_Wh);
|
||||
Serial.print(datalayer.battery.status.remaining_capacity_Wh);
|
||||
Serial.print(" Max charge power: ");
|
||||
Serial.print(system_max_charge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_charge_power_W);
|
||||
Serial.print(" Max discharge power: ");
|
||||
Serial.print(system_max_discharge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_discharge_power_W);
|
||||
Serial.print(" Active power: ");
|
||||
Serial.print(system_active_power_W);
|
||||
Serial.print(datalayer.battery.status.active_power_W);
|
||||
Serial.print(" Min temp: ");
|
||||
Serial.print(system_temperature_min_dC * 0.1);
|
||||
Serial.print(datalayer.battery.status.temperature_min_dC * 0.1);
|
||||
Serial.print(" Max temp: ");
|
||||
Serial.print(system_temperature_max_dC * 0.1);
|
||||
Serial.print(datalayer.battery.status.temperature_max_dC * 0.1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -569,13 +568,13 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
case 0x426: // TODO: Figure out how to trigger sending of this. Does the SME require some CAN command?
|
||||
battery_cellvoltage_mux = rx_frame.data.u8[0];
|
||||
if (battery_cellvoltage_mux == 0) {
|
||||
system_cellvoltages_mV[0] = ((rx_frame.data.u8[1] * 10) + 1800);
|
||||
system_cellvoltages_mV[1] = ((rx_frame.data.u8[2] * 10) + 1800);
|
||||
system_cellvoltages_mV[2] = ((rx_frame.data.u8[3] * 10) + 1800);
|
||||
system_cellvoltages_mV[3] = ((rx_frame.data.u8[4] * 10) + 1800);
|
||||
system_cellvoltages_mV[4] = ((rx_frame.data.u8[5] * 10) + 1800);
|
||||
system_cellvoltages_mV[5] = ((rx_frame.data.u8[6] * 10) + 1800);
|
||||
system_cellvoltages_mV[5] = ((rx_frame.data.u8[7] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[0] = ((rx_frame.data.u8[1] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[1] = ((rx_frame.data.u8[2] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[2] = ((rx_frame.data.u8[3] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[3] = ((rx_frame.data.u8[4] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[4] = ((rx_frame.data.u8[5] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[5] = ((rx_frame.data.u8[6] * 10) + 1800);
|
||||
datalayer.battery.status.cell_voltages_mV[5] = ((rx_frame.data.u8[7] * 10) + 1800);
|
||||
}
|
||||
break;
|
||||
case 0x430: //BMS [1s] - Charging status of high-voltage battery - 2
|
||||
|
@ -622,13 +621,13 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
switch (cmdState) {
|
||||
case CELL_VOLTAGE:
|
||||
if (next_data >= 4) {
|
||||
system_cellvoltages_mV[0] = (message_data[0] << 8 | message_data[1]);
|
||||
system_cellvoltages_mV[2] = (message_data[2] << 8 | message_data[3]);
|
||||
datalayer.battery.status.cell_voltages_mV[0] = (message_data[0] << 8 | message_data[1]);
|
||||
datalayer.battery.status.cell_voltages_mV[2] = (message_data[2] << 8 | message_data[3]);
|
||||
}
|
||||
break;
|
||||
case CELL_VOLTAGE_AVG:
|
||||
if (next_data >= 30) {
|
||||
system_cellvoltages_mV[1] = (message_data[10] << 8 | message_data[11]) / 10;
|
||||
datalayer.battery.status.cell_voltages_mV[1] = (message_data[10] << 8 | message_data[11]) / 10;
|
||||
battery_capacity_cah = (message_data[4] << 8 | message_data[5]);
|
||||
}
|
||||
break;
|
||||
|
@ -669,7 +668,7 @@ void send_can_battery() {
|
|||
BMW_10B.data.u8[1] = 0x10; // Close contactors
|
||||
}
|
||||
|
||||
if (system_bms_status == FAULT) {
|
||||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
BMW_10B.data.u8[1] = 0x00; // Open contactors (TODO: test if this works)
|
||||
}
|
||||
|
||||
|
@ -808,8 +807,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("BMW i3 battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 2800; // 280.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 2800; // 280.0V under this, discharging further is disabled
|
||||
|
||||
digitalWrite(WUP_PIN, HIGH); // Wake up the battery
|
||||
}
|
||||
|
|
|
@ -7,29 +7,6 @@
|
|||
#define BATTERY_SELECTED
|
||||
|
||||
#define WUP_PIN 25
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef CHADEMO_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -90,16 +91,19 @@ uint8_t HighVoltageControlStatus = 0;
|
|||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||
|
||||
system_real_SOC_pptt = ChargingRate;
|
||||
datalayer.battery.status.real_soc = ChargingRate;
|
||||
|
||||
system_max_discharge_power_W = (MaximumDischargeCurrent * MaximumBatteryVoltage); //In Watts, Convert A to P
|
||||
datalayer.battery.status.max_discharge_power_W =
|
||||
(MaximumDischargeCurrent * MaximumBatteryVoltage); //In Watts, Convert A to P
|
||||
|
||||
system_battery_voltage_dV = TargetBatteryVoltage; //TODO: scaling?
|
||||
datalayer.battery.status.voltage_dV = TargetBatteryVoltage; //TODO: scaling?
|
||||
|
||||
system_capacity_Wh = ((RatedBatteryCapacity / 0.11) *
|
||||
datalayer.battery.info.total_capacity_Wh =
|
||||
((RatedBatteryCapacity / 0.11) *
|
||||
1000); //(Added in CHAdeMO v1.0.1), maybe handle hardcoded on lower protocol version?
|
||||
|
||||
system_remaining_capacity_Wh = (system_real_SOC_pptt / 100) * system_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);
|
||||
|
||||
/* Check if the Vehicle is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -197,7 +201,8 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Chademo battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 2000; // 200.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 2000; // 200.0V under this, discharging further is disabled
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,28 +6,6 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef IMIEV_CZERO_ION_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -39,30 +40,30 @@ static double max_temp_cel = 20.00;
|
|||
static double min_temp_cel = 19.00;
|
||||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
system_real_SOC_pptt = (uint16_t)(BMU_SOC * 100); //increase BMU_SOC range from 0-100 -> 100.00
|
||||
datalayer.battery.status.real_soc = (uint16_t)(BMU_SOC * 100); //increase BMU_SOC range from 0-100 -> 100.00
|
||||
|
||||
system_battery_voltage_dV = (uint16_t)(BMU_PackVoltage * 10); // Multiply by 10 and cast to uint16_t
|
||||
datalayer.battery.status.voltage_dV = (uint16_t)(BMU_PackVoltage * 10); // Multiply by 10 and cast to uint16_t
|
||||
|
||||
system_battery_current_dA = (BMU_Current * 10); //Todo, scaling?
|
||||
datalayer.battery.status.current_dA = (BMU_Current * 10); //Todo, scaling?
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value
|
||||
|
||||
system_remaining_capacity_Wh = (uint16_t)((system_real_SOC_pptt / 10000) * system_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);
|
||||
|
||||
//We do not know if the max charge power is sent by the battery. So we estimate the value based on SOC%
|
||||
if (system_scaled_SOC_pptt == 10000) { //100.00%
|
||||
system_max_charge_power_W = 0; //When battery is 100% full, set allowed charge W to 0
|
||||
if (datalayer.battery.status.reported_soc == 10000) { //100.00%
|
||||
datalayer.battery.status.max_charge_power_W = 0; //When battery is 100% full, set allowed charge W to 0
|
||||
} else {
|
||||
system_max_charge_power_W = 10000; //Otherwise we can push 10kW into the pack!
|
||||
datalayer.battery.status.max_charge_power_W = 10000; //Otherwise we can push 10kW into the pack!
|
||||
}
|
||||
|
||||
if (system_scaled_SOC_pptt < 200) { //2.00%
|
||||
system_max_discharge_power_W = 0; //When battery is empty (below 2%), set allowed discharge W to 0
|
||||
if (datalayer.battery.status.reported_soc < 200) { //2.00%
|
||||
datalayer.battery.status.max_discharge_power_W =
|
||||
0; //When battery is empty (below 2%), set allowed discharge W to 0
|
||||
} else {
|
||||
system_max_discharge_power_W = 10000; //Otherwise we can discharge 10kW from the pack!
|
||||
datalayer.battery.status.max_discharge_power_W = 10000; //Otherwise we can discharge 10kW from the pack!
|
||||
}
|
||||
|
||||
system_active_power_W = BMU_Power; //TODO: Scaling?
|
||||
datalayer.battery.status.active_power_W = BMU_Power; //TODO: Scaling?
|
||||
|
||||
static int n = sizeof(cell_voltages) / sizeof(cell_voltages[0]);
|
||||
max_volt_cel = cell_voltages[0]; // Initialize max with the first element of the array
|
||||
|
@ -96,16 +97,16 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
|
||||
//Map all cell voltages to the global array
|
||||
for (int i = 0; i < 88; ++i) {
|
||||
system_cellvoltages_mV[i] = (uint16_t)(cell_voltages[i] * 1000);
|
||||
datalayer.battery.status.cell_voltages_mV[i] = (uint16_t)(cell_voltages[i] * 1000);
|
||||
}
|
||||
|
||||
system_cell_max_voltage_mV = (uint16_t)(max_volt_cel * 1000);
|
||||
datalayer.battery.status.cell_max_voltage_mV = (uint16_t)(max_volt_cel * 1000);
|
||||
|
||||
system_cell_min_voltage_mV = (uint16_t)(min_volt_cel * 1000);
|
||||
datalayer.battery.status.cell_min_voltage_mV = (uint16_t)(min_volt_cel * 1000);
|
||||
|
||||
system_temperature_min_dC = (int16_t)(min_temp_cel * 10);
|
||||
datalayer.battery.status.temperature_min_dC = (int16_t)(min_temp_cel * 10);
|
||||
|
||||
system_temperature_min_dC = (int16_t)(max_temp_cel * 10);
|
||||
datalayer.battery.status.temperature_min_dC = (int16_t)(max_temp_cel * 10);
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -217,8 +218,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Mitsubishi i-MiEV / Citroen C-Zero / Peugeot Ion battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 3600; // 360.0V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 3160; // 316.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
3600; // 360.0V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 3160; // 316.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,29 +6,6 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef KIA_E_GMP_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -50,49 +51,48 @@ CANFDMessage EGMP_7E4_ack;
|
|||
|
||||
void set_cell_voltages(CANFDMessage frame, int start, int length, int startCell) {
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
system_cellvoltages_mV[startCell + i] = (frame.data[start + i] * 20);
|
||||
datalayer.battery.status.cell_voltages_mV[startCell + i] = (frame.data[start + i] * 20);
|
||||
}
|
||||
}
|
||||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
system_real_SOC_pptt = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||
datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||
|
||||
system_SOH_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
||||
datalayer.battery.status.soh_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
||||
|
||||
system_battery_voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0)
|
||||
datalayer.battery.status.voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0)
|
||||
|
||||
system_battery_current_dA = batteryAmps; //value is *10 (150 = 15.0)
|
||||
datalayer.battery.status.current_dA = batteryAmps; //value is *10 (150 = 15.0)
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX;
|
||||
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);
|
||||
|
||||
system_remaining_capacity_Wh = static_cast<int>((static_cast<double>(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX);
|
||||
|
||||
//system_max_charge_power_W = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts
|
||||
//datalayer.battery.status.max_charge_power_W = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts
|
||||
//The allowed charge power is not available. We estimate this value
|
||||
if (system_scaled_SOC_pptt == 10000) { // When scaled SOC is 100%, set allowed charge power to 0
|
||||
system_max_charge_power_W = 0;
|
||||
if (datalayer.battery.status.reported_soc == 10000) { // When scaled SOC is 100%, set allowed charge power to 0
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
} else { // No limits, max charging power allowed
|
||||
system_max_charge_power_W = MAXCHARGEPOWERALLOWED;
|
||||
datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED;
|
||||
}
|
||||
//system_max_discharge_power_W = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts
|
||||
if (system_scaled_SOC_pptt < 100) { // When scaled SOC is <1%, set allowed charge power to 0
|
||||
system_max_discharge_power_W = 0;
|
||||
//datalayer.battery.status.max_discharge_power_W = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts
|
||||
if (datalayer.battery.status.reported_soc < 100) { // When scaled SOC is <1%, set allowed charge power to 0
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
} else { // No limits, max charging power allowed
|
||||
system_max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
|
||||
datalayer.battery.status.max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
|
||||
}
|
||||
|
||||
powerWatt = ((batteryVoltage * batteryAmps) / 100);
|
||||
|
||||
system_active_power_W = powerWatt; //Power in watts, Negative = charging batt
|
||||
datalayer.battery.status.active_power_W = powerWatt; //Power in watts, Negative = charging batt
|
||||
|
||||
system_temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
||||
datalayer.battery.status.temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
||||
|
||||
system_temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
||||
datalayer.battery.status.temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
||||
|
||||
system_cell_max_voltage_mV = CellVoltMax_mV;
|
||||
datalayer.battery.status.cell_max_voltage_mV = CellVoltMax_mV;
|
||||
|
||||
system_cell_min_voltage_mV = CellVoltMin_mV;
|
||||
datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -111,7 +111,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
}
|
||||
|
||||
// Check if cell voltages are within allowed range
|
||||
cell_deviation_mV = (system_cell_max_voltage_mV - system_cell_min_voltage_mV);
|
||||
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
||||
|
||||
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
|
@ -125,9 +125,10 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
|
||||
if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
system_max_charge_power_W = 0;
|
||||
system_max_discharge_power_W = 0;
|
||||
if (datalayer.battery.status.bms_status ==
|
||||
FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
||||
|
@ -146,7 +147,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
Serial.print(" Amps | ");
|
||||
Serial.print((uint16_t)batteryVoltage / 10.0, 1);
|
||||
Serial.print(" Volts | ");
|
||||
Serial.print((int16_t)system_active_power_W);
|
||||
Serial.print((int16_t)datalayer.battery.status.active_power_W);
|
||||
Serial.println(" Watts");
|
||||
Serial.print("Allowed Charge ");
|
||||
Serial.print((uint16_t)allowedChargePower * 10);
|
||||
|
@ -329,7 +330,7 @@ void receive_canfd_battery(CANFDMessage frame) {
|
|||
set_cell_voltages(frame, 1, 5, 187);
|
||||
//set_cell_count();
|
||||
} else if (poll_data_pid == 5) {
|
||||
// system_number_of_cells = 98;
|
||||
// datalayer.battery.info.number_of_cells = 98;
|
||||
SOC_Display = frame.data[1] * 5;
|
||||
}
|
||||
break;
|
||||
|
@ -401,11 +402,12 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Hyundai E-GMP (Electric Global Modular Platform) battery selected");
|
||||
#endif
|
||||
|
||||
system_number_of_cells = 192; // TODO: will vary depending on battery
|
||||
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
||||
|
||||
system_max_design_voltage_dV =
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
8064; // TODO: define when battery is known, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 4320; // TODO: define when battery is known. discharging further is disabled
|
||||
datalayer.battery.info.min_design_voltage_dV =
|
||||
4320; // TODO: define when battery is known. discharging further is disabled
|
||||
|
||||
EGMP_7E4.id = 0x7E4;
|
||||
EGMP_7E4.ext = false;
|
||||
|
|
|
@ -12,29 +12,6 @@ extern ACAN2517FD canfd;
|
|||
#define MAXCHARGEPOWERALLOWED 10000
|
||||
#define MAXDISCHARGEPOWERALLOWED 10000
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef KIA_HYUNDAI_64_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -146,42 +147,42 @@ CAN_frame_t KIA64_7E4_ack = {
|
|||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
system_real_SOC_pptt = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||
datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||
|
||||
system_SOH_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
||||
datalayer.battery.status.soh_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%
|
||||
|
||||
system_battery_voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0)
|
||||
datalayer.battery.status.voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0)
|
||||
|
||||
system_battery_current_dA = -batteryAmps; //value is *10 (150 = 15.0) , invert the sign
|
||||
datalayer.battery.status.current_dA = -batteryAmps; //value is *10 (150 = 15.0) , invert the sign
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX;
|
||||
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);
|
||||
|
||||
system_remaining_capacity_Wh = static_cast<int>((static_cast<double>(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX);
|
||||
|
||||
//system_max_charge_power_W = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts
|
||||
//datalayer.battery.status.max_charge_power_W = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts
|
||||
//The allowed charge power is not available. We estimate this value
|
||||
if (system_scaled_SOC_pptt == 10000) { // When scaled SOC is 100%, set allowed charge power to 0
|
||||
system_max_charge_power_W = 0;
|
||||
if (datalayer.battery.status.reported_soc == 10000) { // When scaled SOC is 100%, set allowed charge power to 0
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
} else { // No limits, max charging power allowed
|
||||
system_max_charge_power_W = MAXCHARGEPOWERALLOWED;
|
||||
datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED;
|
||||
}
|
||||
//system_max_discharge_power_W = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts
|
||||
if (system_scaled_SOC_pptt < 100) { // When scaled SOC is <1%, set allowed charge power to 0
|
||||
system_max_discharge_power_W = 0;
|
||||
//datalayer.battery.status.max_discharge_power_W = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts
|
||||
if (datalayer.battery.status.reported_soc < 100) { // When scaled SOC is <1%, set allowed charge power to 0
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
} else { // No limits, max charging power allowed
|
||||
system_max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
|
||||
datalayer.battery.status.max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
|
||||
}
|
||||
|
||||
//Power in watts, Negative = charging batt
|
||||
system_active_power_W = ((system_battery_voltage_dV * system_battery_current_dA) / 100);
|
||||
datalayer.battery.status.active_power_W =
|
||||
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
|
||||
|
||||
system_temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
||||
datalayer.battery.status.temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C
|
||||
|
||||
system_temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
||||
datalayer.battery.status.temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C
|
||||
|
||||
system_cell_max_voltage_mV = CellVoltMax_mV;
|
||||
datalayer.battery.status.cell_max_voltage_mV = CellVoltMax_mV;
|
||||
|
||||
system_cell_min_voltage_mV = CellVoltMin_mV;
|
||||
datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -202,22 +203,22 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
//Map all cell voltages to the global array
|
||||
for (int i = 0; i < 98; ++i) {
|
||||
if (cellvoltages_mv[i] > 1000) {
|
||||
system_cellvoltages_mV[i] = cellvoltages_mv[i];
|
||||
datalayer.battery.status.cell_voltages_mV[i] = cellvoltages_mv[i];
|
||||
}
|
||||
}
|
||||
// Check if we have 98S or 90S battery
|
||||
if (system_cellvoltages_mV[97] > 0) {
|
||||
system_number_of_cells = 98;
|
||||
system_max_design_voltage_dV = 4040;
|
||||
system_min_design_voltage_dV = 3100;
|
||||
if (datalayer.battery.status.cell_voltages_mV[97] > 0) {
|
||||
datalayer.battery.info.number_of_cells = 98;
|
||||
datalayer.battery.info.max_design_voltage_dV = 4040;
|
||||
datalayer.battery.info.min_design_voltage_dV = 3100;
|
||||
} else {
|
||||
system_number_of_cells = 90;
|
||||
system_max_design_voltage_dV = 3870;
|
||||
system_min_design_voltage_dV = 2250;
|
||||
datalayer.battery.info.number_of_cells = 90;
|
||||
datalayer.battery.info.max_design_voltage_dV = 3870;
|
||||
datalayer.battery.info.min_design_voltage_dV = 2250;
|
||||
}
|
||||
|
||||
// Check if cell voltages are within allowed range
|
||||
cell_deviation_mV = (system_cell_max_voltage_mV - system_cell_min_voltage_mV);
|
||||
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
||||
|
||||
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
|
@ -231,9 +232,10 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
|
||||
if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
system_max_charge_power_W = 0;
|
||||
system_max_discharge_power_W = 0;
|
||||
if (datalayer.battery.status.bms_status ==
|
||||
FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
||||
|
@ -252,7 +254,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
Serial.print(" Amps | ");
|
||||
Serial.print((uint16_t)batteryVoltage / 10.0, 1);
|
||||
Serial.print(" Volts | ");
|
||||
Serial.print((int16_t)system_active_power_W);
|
||||
Serial.print((int16_t)datalayer.battery.status.active_power_W);
|
||||
Serial.println(" Watts");
|
||||
Serial.print("Allowed Charge ");
|
||||
Serial.print((uint16_t)allowedChargePower * 10);
|
||||
|
@ -602,8 +604,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Kia Niro / Hyundai Kona 64kWh battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,29 +9,6 @@
|
|||
#define MAXCHARGEPOWERALLOWED 10000
|
||||
#define MAXDISCHARGEPOWERALLOWED 10000
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -32000 to 32000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -159,84 +159,88 @@ void print_with_units(char* header, int value, char* units) {
|
|||
void update_values_battery() { /* This function maps all the values fetched via CAN to the correct parameters used for modbus */
|
||||
/* Start with mapping all values */
|
||||
|
||||
system_SOH_pptt = (LB_StateOfHealth * 100); //Increase range from 99% -> 99.00%
|
||||
datalayer.battery.status.soh_pptt = (LB_StateOfHealth * 100); //Increase range from 99% -> 99.00%
|
||||
|
||||
system_real_SOC_pptt = (LB_SOC * 10);
|
||||
datalayer.battery.status.real_soc = (LB_SOC * 10);
|
||||
|
||||
system_battery_voltage_dV = (LB_Total_Voltage2 * 5); //0.5V/bit, multiply by 5 to get Voltage+1decimal (350.5V = 701)
|
||||
datalayer.battery.status.voltage_dV =
|
||||
(LB_Total_Voltage2 * 5); //0.5V/bit, multiply by 5 to get Voltage+1decimal (350.5V = 701)
|
||||
|
||||
system_battery_current_dA = (LB_Current2 * 5); //0.5A/bit, multiply by 5 to get Amp+1decimal (5,5A = 11)
|
||||
datalayer.battery.status.current_dA = (LB_Current2 * 5); //0.5A/bit, multiply by 5 to get Amp+1decimal (5,5A = 11)
|
||||
|
||||
system_capacity_Wh = (LB_Max_GIDS * WH_PER_GID);
|
||||
datalayer.battery.info.total_capacity_Wh = (LB_Max_GIDS * WH_PER_GID);
|
||||
|
||||
system_remaining_capacity_Wh = LB_Wh_Remaining;
|
||||
datalayer.battery.status.remaining_capacity_Wh = LB_Wh_Remaining;
|
||||
|
||||
LB_Power =
|
||||
((LB_Total_Voltage2 * LB_Current2) / 4); //P = U * I (Both values are 0.5 per bit so the math is non-intuitive)
|
||||
|
||||
system_active_power_W = LB_Power;
|
||||
datalayer.battery.status.active_power_W = LB_Power;
|
||||
|
||||
//Update temperature readings. Method depends on which generation LEAF battery is used
|
||||
if (LEAF_Battery_Type == ZE0_BATTERY) {
|
||||
//Since we only have average value, send the minimum as -1.0 degrees below average
|
||||
system_temperature_min_dC = ((LB_AverageTemperature * 10) - 10); //Increase range from C to C+1, remove 1.0C
|
||||
system_temperature_max_dC = (LB_AverageTemperature * 10); //Increase range from C to C+1
|
||||
datalayer.battery.status.temperature_min_dC =
|
||||
((LB_AverageTemperature * 10) - 10); //Increase range from C to C+1, remove 1.0C
|
||||
datalayer.battery.status.temperature_max_dC = (LB_AverageTemperature * 10); //Increase range from C to C+1
|
||||
} else if (LEAF_Battery_Type == AZE0_BATTERY) {
|
||||
//Use the value sent constantly via CAN in 5C0 (only available on AZE0)
|
||||
system_temperature_min_dC = (LB_HistData_Temperature_MIN * 10); //Increase range from C to C+1
|
||||
system_temperature_max_dC = (LB_HistData_Temperature_MAX * 10); //Increase range from C to C+1
|
||||
datalayer.battery.status.temperature_min_dC = (LB_HistData_Temperature_MIN * 10); //Increase range from C to C+1
|
||||
datalayer.battery.status.temperature_max_dC = (LB_HistData_Temperature_MAX * 10); //Increase range from C to C+1
|
||||
} else { // ZE1 (TODO: Once the muxed value in 5C0 becomes known, switch to using that instead of this complicated polled value)
|
||||
if (temp_raw_min != 0) //We have a polled value available
|
||||
{
|
||||
temp_polled_min = ((Temp_fromRAW_to_F(temp_raw_min) - 320) * 5) / 9; //Convert from F to C
|
||||
temp_polled_max = ((Temp_fromRAW_to_F(temp_raw_max) - 320) * 5) / 9; //Convert from F to C
|
||||
if (temp_polled_min < temp_polled_max) { //Catch any edge cases from Temp_fromRAW_to_F function
|
||||
system_temperature_min_dC = temp_polled_min;
|
||||
system_temperature_max_dC = temp_polled_max;
|
||||
datalayer.battery.status.temperature_min_dC = temp_polled_min;
|
||||
datalayer.battery.status.temperature_max_dC = temp_polled_max;
|
||||
} else {
|
||||
system_temperature_min_dC = temp_polled_max;
|
||||
system_temperature_max_dC = temp_polled_min;
|
||||
datalayer.battery.status.temperature_min_dC = temp_polled_max;
|
||||
datalayer.battery.status.temperature_max_dC = temp_polled_min;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define power able to be discharged from battery
|
||||
if (LB_Discharge_Power_Limit > 60) { //if >60kW can be pulled from battery
|
||||
system_max_discharge_power_W = 60000; //cap value so we don't go over uint16 value
|
||||
datalayer.battery.status.max_discharge_power_W = 60000; //cap value so we don't go over uint16 value
|
||||
} else {
|
||||
system_max_discharge_power_W = (LB_Discharge_Power_Limit * 1000); //kW to W
|
||||
datalayer.battery.status.max_discharge_power_W = (LB_Discharge_Power_Limit * 1000); //kW to W
|
||||
}
|
||||
if (system_scaled_SOC_pptt == 0) { //Scaled SOC% value is 0.00%, we should not discharge battery further
|
||||
system_max_discharge_power_W = 0;
|
||||
if (datalayer.battery.status.reported_soc ==
|
||||
0) { //Scaled SOC% value is 0.00%, we should not discharge battery further
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
// Define power able to be put into the battery
|
||||
if (LB_Charge_Power_Limit > 60) { //if >60kW can be put into the battery
|
||||
system_max_charge_power_W = 60000; //cap value so we don't go over uint16 value
|
||||
datalayer.battery.status.max_charge_power_W = 60000; //cap value so we don't go over uint16 value
|
||||
} else {
|
||||
system_max_charge_power_W = (LB_Charge_Power_Limit * 1000); //kW to W
|
||||
datalayer.battery.status.max_charge_power_W = (LB_Charge_Power_Limit * 1000); //kW to W
|
||||
}
|
||||
if (system_scaled_SOC_pptt == 10000) //Scaled SOC% value is 100.00%
|
||||
if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00%
|
||||
{
|
||||
system_max_charge_power_W = 0; //No need to charge further, set max power to 0
|
||||
datalayer.battery.status.max_charge_power_W = 0; //No need to charge further, set max power to 0
|
||||
}
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
for (int i = 0; i < 96; ++i) {
|
||||
system_cellvoltages_mV[i] = cell_voltages[i];
|
||||
datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i];
|
||||
}
|
||||
|
||||
/*Extra safety functions below*/
|
||||
if (LB_GIDS < 10) //700Wh left in battery!
|
||||
{ //Battery is running abnormally low, some discharge logic might have failed. Zero it all out.
|
||||
set_event(EVENT_BATTERY_EMPTY, 0);
|
||||
system_real_SOC_pptt = 0;
|
||||
system_max_discharge_power_W = 0;
|
||||
datalayer.battery.status.real_soc = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
//Check if SOC% is plausible
|
||||
if (system_battery_voltage_dV >
|
||||
(system_max_design_voltage_dV - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
|
||||
if (datalayer.battery.status.voltage_dV >
|
||||
(datalayer.battery.info.max_design_voltage_dV -
|
||||
100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
|
||||
if (LB_SOC < 650) {
|
||||
set_event(EVENT_SOC_PLAUSIBILITY_ERROR, LB_SOC / 10); // Set event with the SOC as data
|
||||
} else {
|
||||
|
@ -246,22 +250,22 @@ void update_values_battery() { /* This function maps all the values fetched via
|
|||
|
||||
if (LB_Full_CHARGE_flag) { //Battery reports that it is fully charged stop all further charging incase it hasn't already
|
||||
set_event(EVENT_BATTERY_FULL, 0);
|
||||
system_max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
} else {
|
||||
clear_event(EVENT_BATTERY_FULL);
|
||||
}
|
||||
|
||||
if (LB_Capacity_Empty) { //Battery reports that it is fully discharged. Stop all further discharging incase it hasn't already
|
||||
set_event(EVENT_BATTERY_EMPTY, 0);
|
||||
system_max_discharge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
} else {
|
||||
clear_event(EVENT_BATTERY_EMPTY);
|
||||
}
|
||||
|
||||
if (LB_Relay_Cut_Request) { //LB_FAIL, BMS requesting shutdown and contactors to be opened
|
||||
//Note, this is sometimes triggered during the night while idle, and the BMS recovers after a while. Removed latching from this scenario
|
||||
system_max_discharge_power_W = 0;
|
||||
system_max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
}
|
||||
|
||||
if (LB_Failsafe_Status > 0) // 0 is normal, start charging/discharging
|
||||
|
@ -342,9 +346,10 @@ void update_values_battery() { /* This function maps all the values fetched via
|
|||
}
|
||||
}
|
||||
|
||||
if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
system_max_charge_power_W = 0;
|
||||
system_max_discharge_power_W = 0;
|
||||
if (datalayer.battery.status.bms_status ==
|
||||
FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
/*Finally print out values to serial if configured to do so*/
|
||||
|
@ -380,9 +385,9 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
LB_Failsafe_Status = (rx_frame.data.u8[1] & 0x07);
|
||||
LB_MainRelayOn_flag = (bool)((rx_frame.data.u8[3] & 0x20) >> 5);
|
||||
if (LB_MainRelayOn_flag) {
|
||||
batteryAllowsContactorClosing = true;
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
} else {
|
||||
batteryAllowsContactorClosing = false;
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
}
|
||||
LB_Full_CHARGE_flag = (bool)((rx_frame.data.u8[3] & 0x10) >> 4);
|
||||
LB_Interlock = (bool)((rx_frame.data.u8[3] & 0x08) >> 3);
|
||||
|
@ -518,8 +523,8 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
|
||||
cell_deviation_mV = (min_max_voltage[1] - min_max_voltage[0]);
|
||||
|
||||
system_cell_max_voltage_mV = min_max_voltage[1];
|
||||
system_cell_min_voltage_mV = min_max_voltage[0];
|
||||
datalayer.battery.status.cell_max_voltage_mV = min_max_voltage[1];
|
||||
datalayer.battery.status.cell_min_voltage_mV = min_max_voltage[0];
|
||||
|
||||
if (cell_deviation_mV > MAX_CELL_DEVIATION) {
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
|
||||
|
@ -841,9 +846,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Nissan LEAF battery selected");
|
||||
#endif
|
||||
|
||||
system_number_of_cells = 96;
|
||||
system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 2600; // 260.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.number_of_cells = 96;
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 2600; // 260.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,28 +7,6 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
uint16_t Temp_fromRAW_to_F(uint16_t temperature);
|
||||
bool is_message_corrupt(CAN_frame_t rx_frame);
|
||||
void setup_battery(void);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef RENAULT_KANGOO_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -54,55 +55,55 @@ static unsigned long GVL_pause = 0;
|
|||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
system_real_SOC_pptt = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00
|
||||
datalayer.battery.status.real_soc = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00
|
||||
|
||||
system_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%
|
||||
|
||||
system_battery_voltage_dV = LB_Battery_Voltage;
|
||||
datalayer.battery.status.voltage_dV = LB_Battery_Voltage;
|
||||
|
||||
system_battery_current_dA = LB_Current;
|
||||
datalayer.battery.status.current_dA = LB_Current;
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value
|
||||
|
||||
system_remaining_capacity_Wh = (uint16_t)((system_real_SOC_pptt / 10000) * system_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);
|
||||
|
||||
LB_Discharge_Power_Limit_Watts = (LB_Discharge_Power_Limit * 500); //Convert value fetched from battery to watts
|
||||
/* Define power able to be discharged from battery */
|
||||
if (LB_Discharge_Power_Limit_Watts > 60000) //if >60kW can be pulled from battery
|
||||
{
|
||||
system_max_discharge_power_W = 60000; //cap value so we don't go over the uint16 limit
|
||||
datalayer.battery.status.max_discharge_power_W = 60000; //cap value so we don't go over the uint16 limit
|
||||
} else {
|
||||
system_max_discharge_power_W = LB_Discharge_Power_Limit_Watts;
|
||||
datalayer.battery.status.max_discharge_power_W = LB_Discharge_Power_Limit_Watts;
|
||||
}
|
||||
if (system_scaled_SOC_pptt == 0) //Scaled SOC% value is 0.00%, we should not discharge battery further
|
||||
if (datalayer.battery.status.reported_soc == 0) //Scaled SOC% value is 0.00%, we should not discharge battery further
|
||||
{
|
||||
system_max_discharge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
LB_Charge_Power_Limit_Watts = (LB_Charge_Power_Limit * 500); //Convert value fetched from battery to watts
|
||||
/* Define power able to be put into the battery */
|
||||
if (LB_Charge_Power_Limit_Watts > 60000) //if >60kW can be put into the battery
|
||||
{
|
||||
system_max_charge_power_W = 60000; //cap value so we don't go over the uint16 limit
|
||||
datalayer.battery.status.max_charge_power_W = 60000; //cap value so we don't go over the uint16 limit
|
||||
} else {
|
||||
system_max_charge_power_W = LB_Charge_Power_Limit_Watts;
|
||||
datalayer.battery.status.max_charge_power_W = LB_Charge_Power_Limit_Watts;
|
||||
}
|
||||
if (system_scaled_SOC_pptt == 10000) //Scaled SOC% value is 100.00%
|
||||
if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00%
|
||||
{
|
||||
system_max_charge_power_W = 0; //No need to charge further, set max power to 0
|
||||
datalayer.battery.status.max_charge_power_W = 0; //No need to charge further, set max power to 0
|
||||
}
|
||||
|
||||
system_active_power_W = (system_battery_voltage_dV * LB_Current); //TODO: check if scaling is OK
|
||||
datalayer.battery.status.active_power_W =
|
||||
(datalayer.battery.status.voltage_dV * LB_Current); //TODO: check if scaling is OK
|
||||
|
||||
system_temperature_min_dC = (LB_MIN_TEMPERATURE * 10);
|
||||
datalayer.battery.status.temperature_min_dC = (LB_MIN_TEMPERATURE * 10);
|
||||
|
||||
system_temperature_max_dC = (LB_MAX_TEMPERATURE * 10);
|
||||
datalayer.battery.status.temperature_max_dC = (LB_MAX_TEMPERATURE * 10);
|
||||
|
||||
system_cell_min_voltage_mV = LB_Cell_Min_Voltage;
|
||||
datalayer.battery.status.cell_min_voltage_mV = LB_Cell_Min_Voltage;
|
||||
|
||||
system_cell_max_voltage_mV = LB_Cell_Max_Voltage;
|
||||
datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage;
|
||||
|
||||
cell_deviation_mV = (system_temperature_max_dC - system_temperature_min_dC);
|
||||
cell_deviation_mV = (datalayer.battery.status.temperature_max_dC - datalayer.battery.status.temperature_min_dC);
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -127,21 +128,21 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
#ifdef DEBUG_VIA_USB
|
||||
Serial.println("Values going to inverter:");
|
||||
Serial.print("SOH%: ");
|
||||
Serial.print(system_SOH_pptt);
|
||||
Serial.print(datalayer.battery.status.soh_pptt);
|
||||
Serial.print(", SOC% scaled: ");
|
||||
Serial.print(system_scaled_SOC_pptt);
|
||||
Serial.print(datalayer.battery.status.reported_soc);
|
||||
Serial.print(", Voltage: ");
|
||||
Serial.print(system_battery_voltage_dV);
|
||||
Serial.print(datalayer.battery.status.voltage_dV);
|
||||
Serial.print(", Max discharge power: ");
|
||||
Serial.print(system_max_discharge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_discharge_power_W);
|
||||
Serial.print(", Max charge power: ");
|
||||
Serial.print(system_max_charge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_charge_power_W);
|
||||
Serial.print(", Max temp: ");
|
||||
Serial.print(system_temperature_max_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_max_dC);
|
||||
Serial.print(", Min temp: ");
|
||||
Serial.print(system_temperature_min_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_min_dC);
|
||||
Serial.print(", BMS Status (3=OK): ");
|
||||
Serial.print(system_bms_status);
|
||||
Serial.print(datalayer.battery.status.bms_status);
|
||||
|
||||
Serial.println("Battery values: ");
|
||||
Serial.print("Real SOC: ");
|
||||
|
@ -248,8 +249,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Renault Kangoo battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,29 +12,6 @@
|
|||
3000 // Min Cell Voltage mV! if voltage goes under this, discharging further is disabled
|
||||
#define MAX_CELL_DEVIATION_MV 500 //LED turns yellow on the board if mv delta exceeds this value
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef RENAULT_ZOE_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -38,34 +39,33 @@ static unsigned long previousMillis1000 = 0; // will store last time a 1000ms C
|
|||
static unsigned long GVL_pause = 0;
|
||||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
system_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%
|
||||
|
||||
system_real_SOC_pptt = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00
|
||||
datalayer.battery.status.real_soc = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00
|
||||
|
||||
system_battery_voltage_dV = LB_Battery_Voltage;
|
||||
datalayer.battery.status.voltage_dV = LB_Battery_Voltage;
|
||||
|
||||
system_battery_current_dA = LB_Current;
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows
|
||||
datalayer.battery.status.current_dA = LB_Current;
|
||||
|
||||
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||
system_remaining_capacity_Wh = static_cast<int>((static_cast<double>(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX);
|
||||
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);
|
||||
|
||||
system_max_discharge_power_W;
|
||||
datalayer.battery.status.max_discharge_power_W;
|
||||
|
||||
system_max_charge_power_W;
|
||||
datalayer.battery.status.max_charge_power_W;
|
||||
|
||||
system_active_power_W;
|
||||
datalayer.battery.status.active_power_W;
|
||||
|
||||
system_temperature_min_dC;
|
||||
datalayer.battery.status.temperature_min_dC;
|
||||
|
||||
system_temperature_max_dC;
|
||||
datalayer.battery.status.temperature_max_dC;
|
||||
|
||||
system_cell_min_voltage_mV;
|
||||
datalayer.battery.status.cell_min_voltage_mV;
|
||||
|
||||
system_cell_max_voltage_mV;
|
||||
datalayer.battery.status.cell_max_voltage_mV;
|
||||
|
||||
cell_deviation_mV = (system_cell_max_voltage_mV - system_cell_min_voltage_mV);
|
||||
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -90,21 +90,21 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
#ifdef DEBUG_VIA_USB
|
||||
Serial.println("Values going to inverter:");
|
||||
Serial.print("SOH%: ");
|
||||
Serial.print(system_SOH_pptt);
|
||||
Serial.print(datalayer.battery.status.soh_pptt);
|
||||
Serial.print(", SOC% scaled: ");
|
||||
Serial.print(system_scaled_SOC_pptt);
|
||||
Serial.print(datalayer.battery.status.reported_soc);
|
||||
Serial.print(", Voltage: ");
|
||||
Serial.print(system_battery_voltage_dV);
|
||||
Serial.print(datalayer.battery.status.voltage_dV);
|
||||
Serial.print(", Max discharge power: ");
|
||||
Serial.print(system_max_discharge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_discharge_power_W);
|
||||
Serial.print(", Max charge power: ");
|
||||
Serial.print(system_max_charge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_charge_power_W);
|
||||
Serial.print(", Max temp: ");
|
||||
Serial.print(system_temperature_max_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_max_dC);
|
||||
Serial.print(", Min temp: ");
|
||||
Serial.print(system_temperature_min_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_min_dC);
|
||||
Serial.print(", BMS Status (3=OK): ");
|
||||
Serial.print(system_bms_status);
|
||||
Serial.print(datalayer.battery.status.bms_status);
|
||||
|
||||
Serial.println("Battery values: ");
|
||||
Serial.print("Real SOC: ");
|
||||
|
@ -158,8 +158,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Renault Zoe battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef RENAULT_ZOE_BATTERY_H
|
||||
#define RENAULT_ZOE_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
|
@ -12,29 +11,6 @@
|
|||
3000 // Min Cell Voltage mV! if voltage goes under this, discharging further is disabled
|
||||
#define MAX_CELL_DEVIATION_MV 500 //LED turns yellow on the board if mv delta exceeds this value
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef SANTA_FE_PHEV_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -56,25 +57,25 @@ CAN_frame_t SANTAFE_523 = {.FIR = {.B =
|
|||
|
||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
system_real_SOC_pptt;
|
||||
datalayer.battery.status.real_soc;
|
||||
|
||||
system_battery_voltage_dV;
|
||||
datalayer.battery.status.voltage_dV;
|
||||
|
||||
system_battery_current_dA;
|
||||
datalayer.battery.status.current_dA;
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX;
|
||||
datalayer.battery.info.total_capacity_Wh;
|
||||
|
||||
system_remaining_capacity_Wh;
|
||||
datalayer.battery.status.remaining_capacity_Wh;
|
||||
|
||||
system_max_discharge_power_W;
|
||||
datalayer.battery.status.max_discharge_power_W;
|
||||
|
||||
system_max_charge_power_W;
|
||||
datalayer.battery.status.max_charge_power_W;
|
||||
|
||||
system_active_power_W;
|
||||
datalayer.battery.status.active_power_W;
|
||||
|
||||
system_temperature_min_dC;
|
||||
datalayer.battery.status.temperature_min_dC;
|
||||
|
||||
system_temperature_max_dC;
|
||||
datalayer.battery.status.temperature_max_dC;
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
if (!CANstillAlive) {
|
||||
|
@ -181,8 +182,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Hyundai Santa Fe PHEV battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,28 +6,6 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
uint8_t CalculateCRC8(CAN_frame_t rx_frame);
|
||||
void setup_battery(void);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef SERIAL_LINK_RECEIVER
|
||||
#include <Arduino.h>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h"
|
||||
|
||||
|
@ -28,25 +28,30 @@ SerialDataLink dataLinkReceive(SerialReceiver, 0, 0x01, sendingNumVariables,
|
|||
static bool batteryFault = false; // used locally - mainly to indicate Battery CAN failure
|
||||
|
||||
void __getData() {
|
||||
system_real_SOC_pptt = (uint16_t)dataLinkReceive.getReceivedData(0);
|
||||
system_SOH_pptt = (uint16_t)dataLinkReceive.getReceivedData(1);
|
||||
system_battery_voltage_dV = (uint16_t)dataLinkReceive.getReceivedData(2);
|
||||
system_battery_current_dA = (int16_t)dataLinkReceive.getReceivedData(3);
|
||||
system_capacity_Wh = (uint32_t)(dataLinkReceive.getReceivedData(4) * 10); //add back missing decimal
|
||||
system_remaining_capacity_Wh = (uint32_t)(dataLinkReceive.getReceivedData(5) * 10); //add back missing decimal
|
||||
system_max_discharge_power_W = (uint32_t)(dataLinkReceive.getReceivedData(6) * 10); //add back missing decimal
|
||||
system_max_charge_power_W = (uint32_t)(dataLinkReceive.getReceivedData(7) * 10); //add back missing decimal
|
||||
uint16_t _system_bms_status = (uint16_t)dataLinkReceive.getReceivedData(8);
|
||||
system_active_power_W = (uint32_t)(dataLinkReceive.getReceivedData(9) * 10); //add back missing decimal
|
||||
system_temperature_min_dC = (int16_t)dataLinkReceive.getReceivedData(10);
|
||||
system_temperature_max_dC = (int16_t)dataLinkReceive.getReceivedData(11);
|
||||
system_cell_max_voltage_mV = (uint16_t)dataLinkReceive.getReceivedData(12);
|
||||
system_cell_min_voltage_mV = (uint16_t)dataLinkReceive.getReceivedData(13);
|
||||
system_LFP_Chemistry = (bool)dataLinkReceive.getReceivedData(14);
|
||||
batteryAllowsContactorClosing = (bool)dataLinkReceive.getReceivedData(15);
|
||||
datalayer.battery.status.real_soc = (uint16_t)dataLinkReceive.getReceivedData(0);
|
||||
datalayer.battery.status.soh_pptt = (uint16_t)dataLinkReceive.getReceivedData(1);
|
||||
datalayer.battery.status.voltage_dV = (uint16_t)dataLinkReceive.getReceivedData(2);
|
||||
datalayer.battery.status.current_dA = (int16_t)dataLinkReceive.getReceivedData(3);
|
||||
datalayer.battery.info.total_capacity_Wh =
|
||||
(uint32_t)(dataLinkReceive.getReceivedData(4) * 10); //add back missing decimal
|
||||
datalayer.battery.status.remaining_capacity_Wh =
|
||||
(uint32_t)(dataLinkReceive.getReceivedData(5) * 10); //add back missing decimal
|
||||
datalayer.battery.status.max_discharge_power_W =
|
||||
(uint32_t)(dataLinkReceive.getReceivedData(6) * 10); //add back missing decimal
|
||||
datalayer.battery.status.max_charge_power_W =
|
||||
(uint32_t)(dataLinkReceive.getReceivedData(7) * 10); //add back missing decimal
|
||||
uint16_t _datalayer.battery.status.bms_status = (uint16_t)dataLinkReceive.getReceivedData(8);
|
||||
datalayer.battery.status.active_power_W =
|
||||
(uint32_t)(dataLinkReceive.getReceivedData(9) * 10); //add back missing decimal
|
||||
datalayer.battery.status.temperature_min_dC = (int16_t)dataLinkReceive.getReceivedData(10);
|
||||
datalayer.battery.status.temperature_max_dC = (int16_t)dataLinkReceive.getReceivedData(11);
|
||||
datalayer.battery.status.cell_max_voltage_mV = (uint16_t)dataLinkReceive.getReceivedData(12);
|
||||
datalayer.battery.status.cell_min_voltage_mV = (uint16_t)dataLinkReceive.getReceivedData(13);
|
||||
datalayer.battery.info.chemistry = (battery_chemistry_enum)dataLinkReceive.getReceivedData(14);
|
||||
datalayer.system.status.battery_allows_contactor_closing = (bool)dataLinkReceive.getReceivedData(15);
|
||||
|
||||
batteryFault = false;
|
||||
if (_system_bms_status == FAULT) {
|
||||
if (_datalayer.battery.status.bms_status == FAULT) {
|
||||
batteryFault = true;
|
||||
set_event(EVENT_SERIAL_TRANSMITTER_FAILURE, 0);
|
||||
}
|
||||
|
@ -54,7 +59,7 @@ void __getData() {
|
|||
|
||||
void updateData() {
|
||||
// --- update with fresh data
|
||||
dataLinkReceive.updateData(0, inverterAllowsContactorClosing);
|
||||
dataLinkReceive.updateData(0, datalayer.system.status.inverter_allows_contactor_closing);
|
||||
//dataLinkReceive.updateData(1,var2); // For future expansion,
|
||||
//dataLinkReceive.updateData(2,var3); // if inverter needs to send data to battery
|
||||
}
|
||||
|
@ -99,8 +104,8 @@ void manageSerialLinkReceiver() {
|
|||
{
|
||||
__getData();
|
||||
reads++;
|
||||
lastGoodMaxCharge = system_max_charge_power_W;
|
||||
lastGoodMaxDischarge = system_max_discharge_power_W;
|
||||
lastGoodMaxCharge = datalayer.battery.status.max_charge_power_W;
|
||||
lastGoodMaxDischarge = datalayer.battery.status.max_discharge_power_W;
|
||||
//--- if BatteryFault then assume Data is stale
|
||||
if (!batteryFault)
|
||||
lastGood = currentTime;
|
||||
|
@ -116,13 +121,13 @@ void manageSerialLinkReceiver() {
|
|||
if (minutesLost > 0 && lastGood > 0) {
|
||||
// lose 25% each minute of data loss
|
||||
if (minutesLost < 4) {
|
||||
system_max_charge_power_W = (lastGoodMaxCharge * (4 - minutesLost)) / 4;
|
||||
system_max_discharge_power_W = (lastGoodMaxDischarge * (4 - minutesLost)) / 4;
|
||||
datalayer.battery.status.max_charge_power_W = (lastGoodMaxCharge * (4 - minutesLost)) / 4;
|
||||
datalayer.battery.status.max_discharge_power_W = (lastGoodMaxDischarge * (4 - minutesLost)) / 4;
|
||||
set_event(EVENT_SERIAL_RX_WARNING, minutesLost);
|
||||
} else {
|
||||
// Times Up -
|
||||
system_max_charge_power_W = 0;
|
||||
system_max_discharge_power_W = 0;
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
set_event(EVENT_SERIAL_RX_FAILURE, uint8_t(min(minutesLost, 255uL)));
|
||||
//----- Throw Error
|
||||
}
|
||||
|
@ -137,9 +142,9 @@ void manageSerialLinkReceiver() {
|
|||
}
|
||||
Serial.print(minutesLost);
|
||||
Serial.print(", max Charge = ");
|
||||
Serial.print(system_max_charge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_charge_power_W);
|
||||
Serial.print(", max Discharge = ");
|
||||
Serial.println(system_max_discharge_power_W);
|
||||
Serial.println(datalayer.battery.status.max_discharge_power_W);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,39 +181,39 @@ void manageSerialLinkReceiver() {
|
|||
void update_values_serial_link() {
|
||||
Serial.println("Values from battery: ");
|
||||
Serial.print("SOC: ");
|
||||
Serial.print(system_real_SOC_pptt);
|
||||
Serial.print(datalayer.battery.status.real_soc);
|
||||
Serial.print(" SOH: ");
|
||||
Serial.print(system_SOH_pptt);
|
||||
Serial.print(datalayer.battery.status.soh_pptt);
|
||||
Serial.print(" Voltage: ");
|
||||
Serial.print(system_battery_voltage_dV);
|
||||
Serial.print(datalayer.battery.status.voltage_dV);
|
||||
Serial.print(" Current: ");
|
||||
Serial.print(system_battery_current_dA);
|
||||
Serial.print(datalayer.battery.status.current_dA);
|
||||
Serial.print(" Capacity: ");
|
||||
Serial.print(system_capacity_Wh);
|
||||
Serial.print(datalayer.battery.info.total_capacity_Wh);
|
||||
Serial.print(" Remain cap: ");
|
||||
Serial.print(system_remaining_capacity_Wh);
|
||||
Serial.print(datalayer.battery.status.remaining_capacity_Wh);
|
||||
Serial.print(" Max discharge W: ");
|
||||
Serial.print(system_max_discharge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_discharge_power_W);
|
||||
Serial.print(" Max charge W: ");
|
||||
Serial.print(system_max_charge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_charge_power_W);
|
||||
Serial.print(" BMS status: ");
|
||||
Serial.print(system_bms_status);
|
||||
Serial.print(datalayer.battery.status.bms_status);
|
||||
Serial.print(" Power: ");
|
||||
Serial.print(system_active_power_W);
|
||||
Serial.print(datalayer.battery.status.active_power_W);
|
||||
Serial.print(" Temp min: ");
|
||||
Serial.print(system_temperature_min_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_min_dC);
|
||||
Serial.print(" Temp max: ");
|
||||
Serial.print(system_temperature_max_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_max_dC);
|
||||
Serial.print(" Cell max: ");
|
||||
Serial.print(system_cell_max_voltage_mV);
|
||||
Serial.print(datalayer.battery.status.cell_max_voltage_mV);
|
||||
Serial.print(" Cell min: ");
|
||||
Serial.print(system_cell_min_voltage_mV);
|
||||
Serial.print(datalayer.battery.status.cell_min_voltage_mV);
|
||||
Serial.print(" LFP : ");
|
||||
Serial.print(system_LFP_Chemistry);
|
||||
Serial.print(" batteryAllowsContactorClosing: ");
|
||||
Serial.print(batteryAllowsContactorClosing);
|
||||
Serial.print(" inverterAllowsContactorClosing: ");
|
||||
Serial.print(inverterAllowsContactorClosing);
|
||||
Serial.print(datalayer.battery.info.chemistry);
|
||||
Serial.print(" Battery Allows Contactor Closing: ");
|
||||
Serial.print(datalayer.system.status.battery_allows_contactor_closing);
|
||||
Serial.print(" Inverter Allows Contactor Closing: ");
|
||||
Serial.print(datalayer.system.status.inverter_allows_contactor_closing);
|
||||
|
||||
Serial.println("");
|
||||
}
|
||||
|
|
|
@ -5,35 +5,9 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/mackelec-SerialDataLink/SerialDataLink.h"
|
||||
|
||||
// https://github.com/mackelec/SerialDataLink
|
||||
|
||||
// These parameters need to be mapped on the battery side
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern bool system_LFP_Chemistry; //Set to true or false depending on cell chemistry
|
||||
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
|
||||
// Parameters to send to the transmitter
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
|
||||
void manageSerialLinkReceiver();
|
||||
void update_values_serial_link();
|
||||
void setup_battery(void);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef TESLA_MODEL_3_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -165,70 +166,69 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
//After values are mapped, we perform some safety checks, and do some serial printouts
|
||||
//Calculate the SOH% to send to inverter
|
||||
if (bat_beginning_of_life != 0) { //div/0 safeguard
|
||||
system_SOH_pptt =
|
||||
datalayer.battery.status.soh_pptt =
|
||||
static_cast<uint16_t>((static_cast<double>(nominal_full_pack_energy) / bat_beginning_of_life) * 10000.0);
|
||||
}
|
||||
//If the calculation went wrong, set SOH to 100%
|
||||
if (system_SOH_pptt > 10000) {
|
||||
system_SOH_pptt = 10000;
|
||||
if (datalayer.battery.status.soh_pptt > 10000) {
|
||||
datalayer.battery.status.soh_pptt = 10000;
|
||||
}
|
||||
//If the value is unavailable, set SOH to 99%
|
||||
if (nominal_full_pack_energy < REASONABLE_ENERGYAMOUNT) {
|
||||
system_SOH_pptt = 9900;
|
||||
datalayer.battery.status.soh_pptt = 9900;
|
||||
}
|
||||
|
||||
system_real_SOC_pptt = (soc_vi * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||
datalayer.battery.status.real_soc = (soc_vi * 10); //increase SOC range from 0-100.0 -> 100.00
|
||||
|
||||
system_battery_voltage_dV = (volts * 10); //One more decimal needed (370 -> 3700)
|
||||
datalayer.battery.status.voltage_dV = (volts * 10); //One more decimal needed (370 -> 3700)
|
||||
|
||||
system_battery_current_dA = amps; //13.0A
|
||||
|
||||
system_capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows
|
||||
datalayer.battery.status.current_dA = amps; //13.0A
|
||||
|
||||
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||
system_remaining_capacity_Wh =
|
||||
static_cast<uint32_t>((static_cast<double>(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX);
|
||||
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);
|
||||
|
||||
// Define the allowed discharge power
|
||||
system_max_discharge_power_W = (max_discharge_current * volts);
|
||||
datalayer.battery.status.max_discharge_power_W = (max_discharge_current * volts);
|
||||
// Cap the allowed discharge power if battery is empty, or discharge power is higher than the maximum discharge power allowed
|
||||
if (system_scaled_SOC_pptt == 0) {
|
||||
system_max_discharge_power_W = 0;
|
||||
} else if (system_max_discharge_power_W > MAXDISCHARGEPOWERALLOWED) {
|
||||
system_max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
|
||||
if (datalayer.battery.status.reported_soc == 0) {
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
} else if (datalayer.battery.status.max_discharge_power_W > MAXDISCHARGEPOWERALLOWED) {
|
||||
datalayer.battery.status.max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
|
||||
}
|
||||
|
||||
//The allowed charge power behaves strangely. We instead estimate this value
|
||||
if (system_scaled_SOC_pptt == 10000) { // When scaled SOC is 100.00%, set allowed charge power to 0
|
||||
system_max_charge_power_W = 0;
|
||||
if (datalayer.battery.status.reported_soc == 10000) { // When scaled SOC is 100.00%, set allowed charge power to 0
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
} else if (soc_vi > 990) {
|
||||
system_max_charge_power_W = FLOAT_MAX_POWER_W;
|
||||
datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W;
|
||||
} else if (soc_vi > RAMPDOWN_SOC) { // When real SOC is between RAMPDOWN_SOC-99%, ramp the value between Max<->0
|
||||
system_max_charge_power_W = MAXCHARGEPOWERALLOWED * (1 - (soc_vi - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC));
|
||||
datalayer.battery.status.max_charge_power_W =
|
||||
MAXCHARGEPOWERALLOWED * (1 - (soc_vi - RAMPDOWN_SOC) / (1000.0 - RAMPDOWN_SOC));
|
||||
//If the cellvoltages start to reach overvoltage, only allow a small amount of power in
|
||||
if (system_LFP_Chemistry) {
|
||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
|
||||
if (cell_max_v > (MAX_CELL_VOLTAGE_LFP - FLOAT_START_MV)) {
|
||||
system_max_charge_power_W = FLOAT_MAX_POWER_W;
|
||||
datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W;
|
||||
}
|
||||
} else { //NCM/A
|
||||
if (cell_max_v > (MAX_CELL_VOLTAGE_NCA_NCM - FLOAT_START_MV)) {
|
||||
system_max_charge_power_W = FLOAT_MAX_POWER_W;
|
||||
datalayer.battery.status.max_charge_power_W = FLOAT_MAX_POWER_W;
|
||||
}
|
||||
}
|
||||
} else { // No limits, max charging power allowed
|
||||
system_max_charge_power_W = MAXCHARGEPOWERALLOWED;
|
||||
datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED;
|
||||
}
|
||||
|
||||
power = ((volts / 10) * amps);
|
||||
system_active_power_W = power;
|
||||
datalayer.battery.status.active_power_W = power;
|
||||
|
||||
system_temperature_min_dC = min_temp;
|
||||
datalayer.battery.status.temperature_min_dC = min_temp;
|
||||
|
||||
system_temperature_max_dC = max_temp;
|
||||
datalayer.battery.status.temperature_max_dC = max_temp;
|
||||
|
||||
system_cell_max_voltage_mV = cell_max_v;
|
||||
datalayer.battery.status.cell_max_voltage_mV = cell_max_v;
|
||||
|
||||
system_cell_min_voltage_mV = cell_min_v;
|
||||
datalayer.battery.status.cell_min_voltage_mV = cell_min_v;
|
||||
|
||||
/* Value mapping is completed. Start to check all safeties */
|
||||
|
||||
|
@ -250,24 +250,25 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
|
||||
// NCM/A batteries have 96s, LFP has 102-106s
|
||||
// Drawback with this check is that it takes 3-5minutes before all cells have been counted!
|
||||
if (system_number_of_cells > 101) {
|
||||
system_LFP_Chemistry = true;
|
||||
if (datalayer.battery.info.number_of_cells > 101) {
|
||||
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||
}
|
||||
|
||||
//Once cell chemistry is determined, set maximum and minimum total pack voltage safety limits
|
||||
if (system_LFP_Chemistry) {
|
||||
system_max_design_voltage_dV = MAX_PACK_VOLTAGE_LFP;
|
||||
system_min_design_voltage_dV = MIN_PACK_VOLTAGE_LFP;
|
||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_LFP;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_LFP;
|
||||
} else { // NCM/A chemistry
|
||||
system_max_design_voltage_dV = MAX_PACK_VOLTAGE_NCMA;
|
||||
system_min_design_voltage_dV = MIN_PACK_VOLTAGE_NCMA;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_NCMA;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_NCMA;
|
||||
}
|
||||
|
||||
//Check if SOC% is plausible
|
||||
if (system_battery_voltage_dV >
|
||||
(system_max_design_voltage_dV - 20)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
|
||||
if (system_real_SOC_pptt < 5000) { //When SOC is less than 50.00% when approaching max voltage
|
||||
set_event(EVENT_SOC_PLAUSIBILITY_ERROR, system_real_SOC_pptt / 100);
|
||||
if (datalayer.battery.status.voltage_dV >
|
||||
(datalayer.battery.info.max_design_voltage_dV -
|
||||
20)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
|
||||
if (datalayer.battery.status.real_soc < 5000) { //When SOC is less than 50.00% when approaching max voltage
|
||||
set_event(EVENT_SOC_PLAUSIBILITY_ERROR, datalayer.battery.status.real_soc / 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,7 +286,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
set_event(EVENT_KWH_PLAUSIBILITY_ERROR, nominal_full_pack_energy);
|
||||
}
|
||||
|
||||
if (system_LFP_Chemistry) { //LFP limits used for voltage safeties
|
||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { //LFP limits used for voltage safeties
|
||||
if (cell_max_v >= MAX_CELL_VOLTAGE_LFP) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, (cell_max_v - MAX_CELL_VOLTAGE_LFP));
|
||||
}
|
||||
|
@ -311,9 +312,10 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
}
|
||||
}
|
||||
|
||||
if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
system_max_charge_power_W = 0;
|
||||
system_max_discharge_power_W = 0;
|
||||
if (datalayer.battery.status.bms_status ==
|
||||
FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
}
|
||||
|
||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
||||
|
@ -347,7 +349,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
Serial.print("YES, ");
|
||||
else
|
||||
Serial.print("NO, ");
|
||||
if (system_LFP_Chemistry) {
|
||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
|
||||
Serial.print("LFP chemistry detected!");
|
||||
}
|
||||
Serial.println("");
|
||||
|
@ -371,14 +373,14 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
Serial.println("");
|
||||
|
||||
Serial.println("Values passed to the inverter: ");
|
||||
print_SOC(" SOC: ", system_scaled_SOC_pptt);
|
||||
print_int_with_units(" Max discharge power: ", system_max_discharge_power_W, "W");
|
||||
print_SOC(" SOC: ", datalayer.battery.status.reported_soc);
|
||||
print_int_with_units(" Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W");
|
||||
Serial.print(", ");
|
||||
print_int_with_units(" Max charge power: ", system_max_charge_power_W, "W");
|
||||
print_int_with_units(" Max charge power: ", datalayer.battery.status.max_charge_power_W, "W");
|
||||
Serial.println("");
|
||||
print_int_with_units(" Max temperature: ", ((int16_t)system_temperature_min_dC * 0.1), "°C");
|
||||
print_int_with_units(" Max temperature: ", ((int16_t)datalayer.battery.status.temperature_min_dC * 0.1), "°C");
|
||||
Serial.print(", ");
|
||||
print_int_with_units(" Min temperature: ", ((int16_t)system_temperature_max_dC * 0.1), "°C");
|
||||
print_int_with_units(" Min temperature: ", ((int16_t)datalayer.battery.status.temperature_max_dC * 0.1), "°C");
|
||||
Serial.println("");
|
||||
#endif
|
||||
}
|
||||
|
@ -474,11 +476,11 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
{
|
||||
// Example, frame3=0x89,frame2=0x1D = 35101 / 10 = 3510mV
|
||||
volts = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) / 10;
|
||||
system_cellvoltages_mV[mux * 3] = volts;
|
||||
datalayer.battery.status.cell_voltages_mV[mux * 3] = volts;
|
||||
volts = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) / 10;
|
||||
system_cellvoltages_mV[1 + mux * 3] = volts;
|
||||
datalayer.battery.status.cell_voltages_mV[1 + mux * 3] = volts;
|
||||
volts = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) / 10;
|
||||
system_cellvoltages_mV[2 + mux * 3] = volts;
|
||||
datalayer.battery.status.cell_voltages_mV[2 + mux * 3] = volts;
|
||||
|
||||
// Track the max value of mux. If we've seen two 0 values for mux, we've probably gathered all
|
||||
// cell voltages. Then, 2 + mux_max * 3 + 1 is the number of cell voltages.
|
||||
|
@ -487,7 +489,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
mux_zero_counter++;
|
||||
if (mux_zero_counter == 2u) {
|
||||
// The max index will be 2 + mux_max * 3 (see above), so "+ 1" for the number of cells
|
||||
system_number_of_cells = 2 + 3 * mux_max + 1;
|
||||
datalayer.battery.info.number_of_cells = 2 + 3 * mux_max + 1;
|
||||
// Increase the counter arbitrarily another time to make the initial if-statement evaluate to false
|
||||
mux_zero_counter++;
|
||||
}
|
||||
|
@ -590,15 +592,15 @@ the first, for a few cycles, then stop all messages which causes the contactor
|
|||
}
|
||||
previousMillis30 = currentMillis;
|
||||
|
||||
if (inverterAllowsContactorClosing == 1) {
|
||||
if (system_bms_status == ACTIVE) {
|
||||
if (datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
send221still = 50;
|
||||
batteryAllowsContactorClosing = true;
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
ESP32Can.CANWriteFrame(&TESLA_221_1);
|
||||
ESP32Can.CANWriteFrame(&TESLA_221_2);
|
||||
} else { //system_bms_status == FAULT or inverter requested opening contactors
|
||||
} else { //datalayer.battery.status.bms_status == FAULT or inverter requested opening contactors
|
||||
if (send221still > 0) {
|
||||
batteryAllowsContactorClosing = false;
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
ESP32Can.CANWriteFrame(&TESLA_221_1);
|
||||
send221still--;
|
||||
}
|
||||
|
@ -632,9 +634,10 @@ void printFaultCodesIfActive() {
|
|||
if (pyroTestInProgress == 1) {
|
||||
Serial.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!");
|
||||
}
|
||||
if (inverterAllowsContactorClosing == 0) {
|
||||
if (datalayer.system.status.inverter_allows_contactor_closing == false) {
|
||||
Serial.println(
|
||||
"ERROR: Solar inverter does not allow for contactor closing. Check inverterAllowsContactorClosing parameter");
|
||||
"ERROR: Solar inverter does not allow for contactor closing. Check "
|
||||
"datalayer.system.status.inverter_allows_contactor_closing parameter");
|
||||
}
|
||||
// Check each symbol and print debug information if its value is 1
|
||||
printDebugIfActive(WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset");
|
||||
|
@ -704,12 +707,12 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
#endif
|
||||
|
||||
#ifdef LFP_CHEMISTRY
|
||||
system_LFP_Chemistry = true;
|
||||
system_max_design_voltage_dV = MAX_PACK_VOLTAGE_LFP;
|
||||
system_min_design_voltage_dV = MIN_PACK_VOLTAGE_LFP;
|
||||
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_LFP;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_LFP;
|
||||
#else
|
||||
system_max_design_voltage_dV = MAX_PACK_VOLTAGE_NCMA;
|
||||
system_min_design_voltage_dV = MIN_PACK_VOLTAGE_NCMA;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_NCMA;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_NCMA;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef TESLA_MODEL_3_BATTERY_H
|
||||
#define TESLA_MODEL_3_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
|
@ -19,30 +18,6 @@
|
|||
#define MAX_PACK_VOLTAGE_LFP 3880 // V+1, if pack voltage goes over this, charge stops
|
||||
#define MIN_PACK_VOLTAGE_LFP 2968 // V+1, if pack voltage goes below this, discharge stops
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern bool system_LFP_Chemistry; //Bool, 1=true, 0=false
|
||||
|
||||
void printFaultCodesIfActive();
|
||||
void printDebugIfActive(uint8_t symbol, const char* message);
|
||||
void print_int_with_units(char* header, int value, char* units);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef TEST_FAKE_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "TEST-FAKE-BATTERY.h"
|
||||
|
||||
|
@ -15,48 +16,48 @@ void print_units(char* header, int value, char* units) {
|
|||
}
|
||||
|
||||
void update_values_battery() { /* This function puts fake values onto the parameters sent towards the inverter */
|
||||
system_real_SOC_pptt = 5000; // 50.00%
|
||||
datalayer.battery.status.real_soc = 5000; // 50.00%
|
||||
|
||||
system_SOH_pptt = 9900; // 99.00%
|
||||
datalayer.battery.status.soh_pptt = 9900; // 99.00%
|
||||
|
||||
//system_battery_voltage_dV = 3700; // 370.0V , value set in startup in .ino file, editable via webUI
|
||||
//datalayer.battery.status.voltage_dV = 3700; // 370.0V , value set in startup in .ino file, editable via webUI
|
||||
|
||||
system_battery_current_dA = 0; // 0 A
|
||||
datalayer.battery.status.current_dA = 0; // 0 A
|
||||
|
||||
system_capacity_Wh = 30000; // 30kWh
|
||||
datalayer.battery.info.total_capacity_Wh = 30000; // 30kWh
|
||||
|
||||
system_remaining_capacity_Wh = 15000; // 15kWh
|
||||
datalayer.battery.status.remaining_capacity_Wh = 15000; // 15kWh
|
||||
|
||||
system_cell_max_voltage_mV = 3596;
|
||||
datalayer.battery.status.cell_max_voltage_mV = 3596;
|
||||
|
||||
system_cell_min_voltage_mV = 3500;
|
||||
datalayer.battery.status.cell_min_voltage_mV = 3500;
|
||||
|
||||
system_active_power_W = 0; // 0W
|
||||
datalayer.battery.status.active_power_W = 0; // 0W
|
||||
|
||||
system_temperature_min_dC = 50; // 5.0*C
|
||||
datalayer.battery.status.temperature_min_dC = 50; // 5.0*C
|
||||
|
||||
system_temperature_max_dC = 60; // 6.0*C
|
||||
datalayer.battery.status.temperature_max_dC = 60; // 6.0*C
|
||||
|
||||
system_max_discharge_power_W = 5000; // 5kW
|
||||
datalayer.battery.status.max_discharge_power_W = 5000; // 5kW
|
||||
|
||||
system_max_charge_power_W = 5000; // 5kW
|
||||
datalayer.battery.status.max_charge_power_W = 5000; // 5kW
|
||||
|
||||
for (int i = 0; i < 97; ++i) {
|
||||
system_cellvoltages_mV[i] = 3500 + i;
|
||||
datalayer.battery.status.cell_voltages_mV[i] = 3500 + i;
|
||||
}
|
||||
|
||||
/*Finally print out values to serial if configured to do so*/
|
||||
#ifdef DEBUG_VIA_USB
|
||||
Serial.println("FAKE Values going to inverter");
|
||||
print_units("SOH%: ", (system_SOH_pptt * 0.01), "% ");
|
||||
print_units(", SOC%: ", (system_scaled_SOC_pptt * 0.01), "% ");
|
||||
print_units(", Voltage: ", (system_battery_voltage_dV * 0.1), "V ");
|
||||
print_units(", Max discharge power: ", system_max_discharge_power_W, "W ");
|
||||
print_units(", Max charge power: ", system_max_charge_power_W, "W ");
|
||||
print_units(", Max temp: ", (system_temperature_max_dC * 0.1), "°C ");
|
||||
print_units(", Min temp: ", (system_temperature_min_dC * 0.1), "°C ");
|
||||
print_units(", Max cell voltage: ", system_cell_max_voltage_mV, "mV ");
|
||||
print_units(", Min cell voltage: ", system_cell_min_voltage_mV, "mV ");
|
||||
print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% ");
|
||||
print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% ");
|
||||
print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V ");
|
||||
print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W ");
|
||||
print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W ");
|
||||
print_units(", Max temp: ", (datalayer.battery.status.temperature_max_dC * 0.1), "°C ");
|
||||
print_units(", Min temp: ", (datalayer.battery.status.temperature_min_dC * 0.1), "°C ");
|
||||
print_units(", Max cell voltage: ", datalayer.battery.status.cell_max_voltage_mV, "mV ");
|
||||
print_units(", Min cell voltage: ", datalayer.battery.status.cell_min_voltage_mV, "mV ");
|
||||
Serial.println("");
|
||||
#endif
|
||||
}
|
||||
|
@ -88,8 +89,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Test mode with fake battery selected");
|
||||
#endif
|
||||
|
||||
system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 2450; // 245.0V under this, discharging further is disabled
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 2450; // 245.0V under this, discharging further is disabled
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,29 +4,6 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef VOLVO_SPA_BATTERY
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
@ -81,37 +82,36 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
|
||||
remaining_capacity = (78200 - CHARGE_ENERGY);
|
||||
|
||||
//system_real_SOC_pptt = SOC_BMS; // Use BMS reported SOC, havent figured out how to get the BMS to calibrate empty/full yet
|
||||
//datalayer.battery.status.real_soc = SOC_BMS; // Use BMS reported SOC, havent figured out how to get the BMS to calibrate empty/full yet
|
||||
SOC_CALC = remaining_capacity / 78; // Use calculated SOC based on remaining_capacity
|
||||
|
||||
system_real_SOC_pptt = SOC_CALC * 10;
|
||||
datalayer.battery.status.real_soc = SOC_CALC * 10;
|
||||
|
||||
if (BATT_U > MAX_U) // Protect if overcharged
|
||||
{
|
||||
system_real_SOC_pptt = 10000;
|
||||
datalayer.battery.status.real_soc = 10000;
|
||||
} else if (BATT_U < MIN_U) //Protect if undercharged
|
||||
{
|
||||
system_real_SOC_pptt = 0;
|
||||
datalayer.battery.status.real_soc = 0;
|
||||
}
|
||||
|
||||
system_battery_voltage_dV = BATT_U * 10;
|
||||
system_battery_current_dA = BATT_I * 10;
|
||||
system_capacity_Wh = BATTERY_WH_MAX;
|
||||
system_remaining_capacity_Wh = remaining_capacity; // Will wrap! Known limitation due to uint16_t size.
|
||||
datalayer.battery.status.voltage_dV = BATT_U * 10;
|
||||
datalayer.battery.status.current_dA = BATT_I * 10;
|
||||
datalayer.battery.status.remaining_capacity_Wh = remaining_capacity;
|
||||
|
||||
//system_max_discharge_power_W = HvBattPwrLimDchaSoft * 1000; // Use power limit reported from BMS, not trusted ATM
|
||||
system_max_discharge_power_W = 30000;
|
||||
system_max_charge_power_W = 30000;
|
||||
system_active_power_W = (BATT_U)*BATT_I;
|
||||
system_temperature_min_dC = BATT_T_MIN;
|
||||
system_temperature_max_dC = BATT_T_MAX;
|
||||
//datalayer.battery.status.max_discharge_power_W = HvBattPwrLimDchaSoft * 1000; // Use power limit reported from BMS, not trusted ATM
|
||||
datalayer.battery.status.max_discharge_power_W = 30000;
|
||||
datalayer.battery.status.max_charge_power_W = 30000;
|
||||
datalayer.battery.status.active_power_W = (BATT_U)*BATT_I;
|
||||
datalayer.battery.status.temperature_min_dC = BATT_T_MIN;
|
||||
datalayer.battery.status.temperature_max_dC = BATT_T_MAX;
|
||||
|
||||
system_cell_max_voltage_mV = CELL_U_MAX * 10; // Use min/max reported from BMS
|
||||
system_cell_min_voltage_mV = CELL_U_MIN * 10;
|
||||
datalayer.battery.status.cell_max_voltage_mV = CELL_U_MAX * 10; // Use min/max reported from BMS
|
||||
datalayer.battery.status.cell_min_voltage_mV = CELL_U_MIN * 10;
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
for (int i = 0; i < 108; ++i) {
|
||||
system_cellvoltages_mV[i] = cell_voltages[i];
|
||||
datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i];
|
||||
}
|
||||
|
||||
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
|
||||
|
@ -128,7 +128,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
|||
Serial.print("Calculated SOC%: ");
|
||||
Serial.println(SOC_CALC);
|
||||
Serial.print("Rescaled SOC%: ");
|
||||
Serial.println(system_scaled_SOC_pptt / 10);
|
||||
Serial.println(datalayer.battery.status.reported_soc / 100);
|
||||
Serial.print("Battery current: ");
|
||||
Serial.println(BATT_I);
|
||||
Serial.print("Battery voltage: ");
|
||||
|
@ -287,7 +287,7 @@ void receive_can_battery(CAN_frame_t rx_frame) {
|
|||
if ((rx_frame.data.u8[0] == 0x07) && (rx_frame.data.u8[1] == 0x62) && (rx_frame.data.u8[2] == 0x49) &&
|
||||
(rx_frame.data.u8[3] == 0x6D)) // SOH response frame
|
||||
{
|
||||
system_SOH_pptt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
|
||||
datalayer.battery.status.soh_pptt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
|
||||
} else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[1] == 0x0B) && (rx_frame.data.u8[2] == 0x62) &&
|
||||
(rx_frame.data.u8[3] == 0x4B)) // First response frame of cell voltages
|
||||
{
|
||||
|
@ -357,15 +357,15 @@ void send_can_battery() {
|
|||
ESP32Can.CANWriteFrame(&VOLVO_536); //Send 0x536 Network managing frame to keep BMS alive
|
||||
ESP32Can.CANWriteFrame(&VOLVO_372); //Send 0x372 ECMAmbientTempCalculated
|
||||
|
||||
if (system_bms_status == ACTIVE) {
|
||||
batteryAllowsContactorClosing = true;
|
||||
} else { //system_bms_status == FAULT or inverter requested opening contactors
|
||||
batteryAllowsContactorClosing = false;
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
} else { //datalayer.battery.status.bms_status == FAULT or inverter requested opening contactors
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
}
|
||||
}
|
||||
if (currentMillis - previousMillis60s >= INTERVAL_60_S) {
|
||||
previousMillis60s = currentMillis;
|
||||
if (system_bms_status == ACTIVE) {
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
readCellVoltages();
|
||||
}
|
||||
}
|
||||
|
@ -376,8 +376,9 @@ void setup_battery(void) { // Performs one time setup at startup
|
|||
Serial.println("Volvo SPA XC40 Recharge / Polestar2 78kWh battery selected");
|
||||
#endif
|
||||
|
||||
system_number_of_cells = 108;
|
||||
system_max_design_voltage_dV = 4540; // 454.0V, over this, charging is not possible (goes into forced discharge)
|
||||
system_min_design_voltage_dV = 2938; // 293.8V under this, discharging further is disabled
|
||||
datalayer.battery.info.number_of_cells = 108;
|
||||
datalayer.battery.info.max_design_voltage_dV =
|
||||
4540; // 454.0V, over this, charging is not possible (goes into forced discharge)
|
||||
datalayer.battery.info.min_design_voltage_dV = 2938; // 293.8V under this, discharging further is disabled
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,28 +6,6 @@
|
|||
|
||||
#define BATTERY_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void setup_battery(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "CHEVY-VOLT-CHARGER.h"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef NISSAN_LEAF_CHARGER
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "NISSAN-LEAF-CHARGER.h"
|
||||
|
@ -227,12 +228,13 @@ void send_can_nissanleaf_charger() {
|
|||
}
|
||||
|
||||
// if actual battery_voltage is less than setpoint got to max power set from web ui
|
||||
if (system_battery_voltage_dV < (CHARGER_SET_HV * 10)) { //system_battery_voltage_dV = V+1, 0-500.0 (0-5000)
|
||||
if (datalayer.battery.status.voltage_dV <
|
||||
(CHARGER_SET_HV * 10)) { //datalayer.battery.status.voltage_dV = V+1, 0-500.0 (0-5000)
|
||||
OBCpower = OBCpowerSetpoint;
|
||||
}
|
||||
|
||||
// decrement charger power if volt setpoint is reached
|
||||
if (system_battery_voltage_dV >= (CHARGER_SET_HV * 10)) {
|
||||
if (datalayer.battery.status.voltage_dV >= (CHARGER_SET_HV * 10)) {
|
||||
if (OBCpower > 0x64) {
|
||||
OBCpower--;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
|
||||
void send_can_nissanleaf_charger();
|
||||
void receive_can_nissanleaf_charger(CAN_frame_t rx_frame);
|
||||
|
||||
|
|
|
@ -1,83 +1,164 @@
|
|||
#ifndef _DATALAYER_H_
|
||||
#define _DATALAYER_H_
|
||||
|
||||
#include "../devboard/utils/soc_scaling.h"
|
||||
#include "../include.h"
|
||||
|
||||
typedef struct {
|
||||
/** float */
|
||||
float max_design_voltage_V;
|
||||
float min_design_voltage_V;
|
||||
|
||||
/** uint32_t */
|
||||
uint32_t total_capacity;
|
||||
/** Total energy capacity in Watt-hours */
|
||||
uint32_t total_capacity_Wh = BATTERY_WH_MAX;
|
||||
|
||||
/** uint16_t */
|
||||
uint16_t number_of_cells;
|
||||
/** The maximum intended packvoltage, in deciVolt. 4900 = 490.0 V */
|
||||
uint16_t max_design_voltage_dV = 5000;
|
||||
/** The minimum intended packvoltage, in deciVolt. 3300 = 330.0 V */
|
||||
uint16_t min_design_voltage_dV = 2500;
|
||||
/** BYD CAN specific setting, max charge in deciAmpere. 300 = 30.0 A */
|
||||
uint16_t max_charge_amp_dA = BATTERY_MAX_CHARGE_AMP;
|
||||
/** BYD CAN specific setting, max discharge in deciAmpere. 300 = 30.0 A */
|
||||
uint16_t max_discharge_amp_dA = BATTERY_MAX_DISCHARGE_AMP;
|
||||
|
||||
/** uint8_t */
|
||||
/** Total number of cells in the pack */
|
||||
uint8_t number_of_cells;
|
||||
|
||||
/** Other */
|
||||
battery_chemistry_enum chemistry;
|
||||
} DATALAYER_BATTERY_DATA_TYPE;
|
||||
/** Chemistry of the pack. NCA, NMC or LFP (so far) */
|
||||
battery_chemistry_enum chemistry = battery_chemistry_enum::NCA;
|
||||
} DATALAYER_BATTERY_INFO_TYPE;
|
||||
|
||||
typedef struct {
|
||||
/** float */
|
||||
float temperature_max_C;
|
||||
float temperature_min_C;
|
||||
float current_A;
|
||||
float voltage_V;
|
||||
float soh_pct;
|
||||
/** int32_t */
|
||||
/** Instantaneous battery power in Watts */
|
||||
int32_t active_power_W;
|
||||
|
||||
/** uint32_t */
|
||||
int32_t active_power_W;
|
||||
uint32_t remaining_capacity;
|
||||
/** Remaining energy capacity in Watt-hours */
|
||||
uint32_t remaining_capacity_Wh;
|
||||
/** Maximum allowed battery discharge power in Watts */
|
||||
uint32_t max_discharge_power_W = 0;
|
||||
/** Maximum allowed battery charge power in Watts */
|
||||
uint32_t max_charge_power_W = 0;
|
||||
|
||||
/** int16_t */
|
||||
/** Maximum temperature currently measured in the pack, in d°C. 150 = 15.0 °C */
|
||||
int16_t temperature_max_dC;
|
||||
/** Minimum temperature currently measured in the pack, in d°C. 150 = 15.0 °C */
|
||||
int16_t temperature_min_dC;
|
||||
/** Instantaneous battery current in deciAmpere. 95 = 9.5 A */
|
||||
int16_t current_dA;
|
||||
|
||||
/** uint16_t */
|
||||
uint32_t max_discharge_power_W;
|
||||
uint32_t max_charge_power_W;
|
||||
uint16_t cell_max_voltage_mV;
|
||||
uint16_t cell_min_voltage_mV;
|
||||
/** State of health in integer-percent x 100. 9900 = 99.00% */
|
||||
uint16_t soh_pptt = 9900;
|
||||
/** Instantaneous battery voltage in deciVolts. 3700 = 370.0 V */
|
||||
uint16_t voltage_dV = 3700;
|
||||
/** Maximum cell voltage currently measured in the pack, in mV */
|
||||
uint16_t cell_max_voltage_mV = 3700;
|
||||
/** Minimum cell voltage currently measured in the pack, in mV */
|
||||
uint16_t cell_min_voltage_mV = 3700;
|
||||
/** All cell voltages currently measured in the pack, in mV.
|
||||
* Use with battery.info.number_of_cells to get valid data.
|
||||
*/
|
||||
uint16_t cell_voltages_mV[MAX_AMOUNT_CELLS];
|
||||
/** The "real" SOC reported from the battery, in integer-percent x 100. 9550 = 95.50% */
|
||||
uint16_t real_soc;
|
||||
/** The SOC reported to the inverter, in integer-percent x 100. 9550 = 95.50%.
|
||||
* This value will either be scaled or not scaled depending on the value of
|
||||
* battery.settings.soc_scaling_active
|
||||
*/
|
||||
uint16_t reported_soc;
|
||||
|
||||
/** Other */
|
||||
// bms_status_enum bms_status; // Not ready yet
|
||||
ScaledSoc soc;
|
||||
/** The current BMS status */
|
||||
bms_status_enum bms_status = ACTIVE;
|
||||
} DATALAYER_BATTERY_STATUS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
DATALAYER_BATTERY_DATA_TYPE data;
|
||||
/** SOC scaling setting. Set to true to use SOC scaling */
|
||||
bool soc_scaling_active = BATTERY_USE_SCALED_SOC;
|
||||
/** Minimum percentage setting. Set this value to the lowest real SOC
|
||||
* you want the inverter to be able to use. At this real SOC, the inverter
|
||||
* will "see" 0% */
|
||||
uint16_t min_percentage = BATTERY_MINPERCENTAGE;
|
||||
/** Maximum percentage setting. Set this value to the highest real SOC
|
||||
* you want the inverter to be able to use. At this real SOC, the inverter
|
||||
* will "see" 100% */
|
||||
uint16_t max_percentage = BATTERY_MAXPERCENTAGE;
|
||||
} DATALAYER_BATTERY_SETTINGS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
DATALAYER_BATTERY_INFO_TYPE info;
|
||||
DATALAYER_BATTERY_STATUS_TYPE status;
|
||||
DATALAYER_BATTERY_SETTINGS_TYPE settings;
|
||||
} DATALAYER_BATTERY_TYPE;
|
||||
|
||||
typedef struct {
|
||||
// TODO
|
||||
} DATALAYER_SYSTEM_INFO_TYPE;
|
||||
|
||||
typedef struct {
|
||||
#ifdef FUNCTION_TIME_MEASUREMENT
|
||||
int64_t main_task_max_us = 0;
|
||||
int64_t main_task_10s_max_us = 0;
|
||||
/** Core task measurement variable */
|
||||
int64_t core_task_max_us = 0;
|
||||
/** Core task measurement variable, reset each 10 seconds */
|
||||
int64_t core_task_10s_max_us = 0;
|
||||
/** MQTT task measurement variable, reset each 10 seconds */
|
||||
int64_t mqtt_task_10s_max_us = 0;
|
||||
/** loop() task measurement variable, reset each 10 seconds */
|
||||
int64_t loop_task_10s_max_us = 0;
|
||||
|
||||
/** OTA/Wifi handling function measurement variable */
|
||||
int64_t time_wifi_us = 0;
|
||||
int64_t time_mqtt_us = 0;
|
||||
/** CAN RX or serial link function measurement variable */
|
||||
int64_t time_comm_us = 0;
|
||||
/** 10 ms function measurement variable */
|
||||
int64_t time_10ms_us = 0;
|
||||
/** 5 s function measurement variable */
|
||||
int64_t time_5s_us = 0;
|
||||
/** CAN TX function measurement variable */
|
||||
int64_t time_cantx_us = 0;
|
||||
int64_t time_events_us = 0;
|
||||
|
||||
/** Function measurement snapshot variable.
|
||||
* This will show the performance of OTA/Wifi handling when the total time reached a new worst case
|
||||
*/
|
||||
int64_t time_snap_wifi_us = 0;
|
||||
/** Function measurement snapshot variable.
|
||||
* This will show the performance of CAN RX or serial link when the total time reached a new worst case
|
||||
*/
|
||||
int64_t time_snap_comm_us = 0;
|
||||
/** Function measurement snapshot variable.
|
||||
* This will show the performance of the 10 ms functionality of the core task when the total time reached a new worst case
|
||||
*/
|
||||
int64_t time_snap_10ms_us = 0;
|
||||
/** Function measurement snapshot variable.
|
||||
* This will show the performance of the 5 s functionality of the core task when the total time reached a new worst case
|
||||
*/
|
||||
int64_t time_snap_5s_us = 0;
|
||||
/** Function measurement snapshot variable.
|
||||
* This will show the performance of CAN TX when the total time reached a new worst case
|
||||
*/
|
||||
int64_t time_snap_cantx_us = 0;
|
||||
#endif
|
||||
/** True if the battery allows for the contactors to close */
|
||||
bool battery_allows_contactor_closing = false;
|
||||
/** True if the inverter allows for the contactors to close */
|
||||
bool inverter_allows_contactor_closing = true;
|
||||
} DATALAYER_SYSTEM_STATUS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
DATALAYER_SYSTEM_STATUS_TYPE status;
|
||||
} DATALAYER_SYSTEM_TYPE;
|
||||
} DATALAYER_SYSTEM_SETTINGS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
bool batteryAllowsContactorClosing = false;
|
||||
bool inverterAllowsContactorClosing = true;
|
||||
} DATALAYER_SETTINGS_TYPE;
|
||||
DATALAYER_SYSTEM_INFO_TYPE info;
|
||||
DATALAYER_SYSTEM_STATUS_TYPE status;
|
||||
DATALAYER_SYSTEM_SETTINGS_TYPE settings;
|
||||
} DATALAYER_SYSTEM_TYPE;
|
||||
|
||||
class DataLayer {
|
||||
public:
|
||||
DATALAYER_BATTERY_TYPE battery;
|
||||
DATALAYER_SYSTEM_TYPE system;
|
||||
DATALAYER_SETTINGS_TYPE settings;
|
||||
};
|
||||
|
||||
extern DataLayer datalayer;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <freertos/FreeRTOS.h>
|
||||
#include "../../../USER_SETTINGS.h"
|
||||
#include "../../battery/BATTERIES.h"
|
||||
#include "../../datalayer/datalayer.h"
|
||||
#include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h"
|
||||
#include "../../lib/knolleary-pubsubclient/PubSubClient.h"
|
||||
#include "../utils/timer.h"
|
||||
|
@ -39,7 +40,7 @@ static void publish_cell_voltages(void) {
|
|||
static String state_topic = String("battery-emulator_") + String(hostname) + "/spec_data";
|
||||
|
||||
// If the cell voltage number isn't initialized...
|
||||
if (system_number_of_cells == 0u) {
|
||||
if (datalayer.battery.info.number_of_cells == 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -47,7 +48,7 @@ static void publish_cell_voltages(void) {
|
|||
mqtt_first_transmission = false;
|
||||
String topic = "homeassistant/sensor/battery-emulator/cell_voltage";
|
||||
|
||||
for (int i = 0; i < system_number_of_cells; i++) {
|
||||
for (int i = 0; i < datalayer.battery.info.number_of_cells; i++) {
|
||||
int cellNumber = i + 1;
|
||||
doc["name"] = "Battery Cell Voltage " + String(cellNumber);
|
||||
doc["object_id"] = "battery_voltage_cell" + String(cellNumber);
|
||||
|
@ -74,13 +75,13 @@ static void publish_cell_voltages(void) {
|
|||
doc.clear(); // clear after sending autoconfig
|
||||
} else {
|
||||
// If cell voltages haven't been populated...
|
||||
if (system_number_of_cells == 0u) {
|
||||
if (datalayer.battery.info.number_of_cells == 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonArray cell_voltages = doc["cell_voltages"].to<JsonArray>();
|
||||
for (size_t i = 0; i < system_number_of_cells; ++i) {
|
||||
cell_voltages.add(((float)system_cellvoltages_mV[i]) / 1000.0);
|
||||
for (size_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) {
|
||||
cell_voltages.add(((float)datalayer.battery.status.cell_voltages_mV[i]) / 1000.0);
|
||||
}
|
||||
|
||||
serializeJson(doc, mqtt_msg, sizeof(mqtt_msg));
|
||||
|
@ -150,16 +151,16 @@ static void publish_common_info(void) {
|
|||
}
|
||||
doc.clear();
|
||||
} else {
|
||||
doc["SOC"] = ((float)system_scaled_SOC_pptt) / 100.0;
|
||||
doc["SOC_real"] = ((float)system_real_SOC_pptt) / 100.0;
|
||||
doc["state_of_health"] = ((float)system_SOH_pptt) / 100.0;
|
||||
doc["temperature_min"] = ((float)((int16_t)system_temperature_min_dC)) / 10.0;
|
||||
doc["temperature_max"] = ((float)((int16_t)system_temperature_max_dC)) / 10.0;
|
||||
doc["stat_batt_power"] = ((float)((int16_t)system_active_power_W));
|
||||
doc["battery_current"] = ((float)((int16_t)system_battery_current_dA)) / 10.0;
|
||||
doc["cell_max_voltage"] = ((float)system_cell_max_voltage_mV) / 1000.0;
|
||||
doc["cell_min_voltage"] = ((float)system_cell_min_voltage_mV) / 1000.0;
|
||||
doc["battery_voltage"] = ((float)system_battery_voltage_dV) / 10.0;
|
||||
doc["SOC"] = ((float)datalayer.battery.status.reported_soc) / 100.0;
|
||||
doc["SOC_real"] = ((float)datalayer.battery.status.real_soc) / 100.0;
|
||||
doc["state_of_health"] = ((float)datalayer.battery.status.soh_pptt) / 100.0;
|
||||
doc["temperature_min"] = ((float)((int16_t)datalayer.battery.status.temperature_min_dC)) / 10.0;
|
||||
doc["temperature_max"] = ((float)((int16_t)datalayer.battery.status.temperature_max_dC)) / 10.0;
|
||||
doc["stat_batt_power"] = ((float)((int32_t)datalayer.battery.status.active_power_W));
|
||||
doc["battery_current"] = ((float)((int16_t)datalayer.battery.status.current_dA)) / 10.0;
|
||||
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["battery_voltage"] = ((float)datalayer.battery.status.voltage_dV) / 10.0;
|
||||
|
||||
serializeJson(doc, mqtt_msg);
|
||||
if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) {
|
||||
|
|
|
@ -41,19 +41,6 @@
|
|||
|
||||
extern const char* version_number; // The current software version, used for mqtt
|
||||
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000 , Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
|
||||
extern const char* mqtt_user;
|
||||
extern const char* mqtt_password;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "events.h"
|
||||
|
||||
#include "../../datalayer/datalayer.h"
|
||||
#ifndef UNIT_TEST
|
||||
#include <EEPROM.h>
|
||||
#endif
|
||||
|
@ -47,6 +47,7 @@ typedef struct {
|
|||
uint32_t time_seconds;
|
||||
MyTimer second_timer;
|
||||
MyTimer ee_timer;
|
||||
MyTimer update_timer;
|
||||
EVENTS_LEVEL_TYPE level;
|
||||
uint16_t event_log_head_index;
|
||||
uint16_t event_log_tail_index;
|
||||
|
@ -76,6 +77,7 @@ void run_event_handling(void) {
|
|||
update_event_time();
|
||||
run_sequence_on_target();
|
||||
check_ee_write();
|
||||
update_event_level();
|
||||
}
|
||||
|
||||
/* Initialization function */
|
||||
|
@ -165,6 +167,7 @@ void init_events(void) {
|
|||
events.second_timer.set_interval(1000);
|
||||
// Write to EEPROM every X minutes (if an event has been set)
|
||||
events.ee_timer.set_interval(EE_WRITE_PERIOD_MINUTES * 60 * 1000);
|
||||
events.update_timer.set_interval(2000);
|
||||
}
|
||||
|
||||
void set_event(EVENTS_ENUM_TYPE event, uint8_t data) {
|
||||
|
@ -307,7 +310,9 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) {
|
|||
// Check if the event is latching
|
||||
events.entries[event].state = latched ? EVENT_STATE_ACTIVE_LATCHED : EVENT_STATE_ACTIVE;
|
||||
|
||||
update_event_level();
|
||||
// Update event level, only upwards. Downward changes are done in Software.ino:loop()
|
||||
events.level = max(events.level, events.entries[event].level);
|
||||
|
||||
update_bms_status();
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
|
@ -320,13 +325,13 @@ static void update_bms_status(void) {
|
|||
case EVENT_LEVEL_INFO:
|
||||
case EVENT_LEVEL_WARNING:
|
||||
case EVENT_LEVEL_DEBUG:
|
||||
system_bms_status = ACTIVE;
|
||||
datalayer.battery.status.bms_status = ACTIVE;
|
||||
break;
|
||||
case EVENT_LEVEL_UPDATE:
|
||||
system_bms_status = UPDATING;
|
||||
datalayer.battery.status.bms_status = UPDATING;
|
||||
break;
|
||||
case EVENT_LEVEL_ERROR:
|
||||
system_bms_status = FAULT;
|
||||
datalayer.battery.status.bms_status = FAULT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -334,12 +339,13 @@ static void update_bms_status(void) {
|
|||
}
|
||||
|
||||
static void update_event_level(void) {
|
||||
events.level = EVENT_LEVEL_INFO;
|
||||
EVENTS_LEVEL_TYPE temporary_level = EVENT_LEVEL_INFO;
|
||||
for (uint8_t i = 0u; i < EVENT_NOF_EVENTS; i++) {
|
||||
if ((events.entries[i].state == EVENT_STATE_ACTIVE) || (events.entries[i].state == EVENT_STATE_ACTIVE_LATCHED)) {
|
||||
events.level = max(events.entries[i].level, events.level);
|
||||
temporary_level = max(events.entries[i].level, temporary_level);
|
||||
}
|
||||
}
|
||||
events.level = temporary_level;
|
||||
}
|
||||
|
||||
static void update_event_time(void) {
|
||||
|
|
|
@ -111,6 +111,4 @@ void run_event_handling(void);
|
|||
|
||||
void run_sequence_on_target(void);
|
||||
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
|
||||
#endif // __MYTIMER_H__
|
||||
|
|
|
@ -26,8 +26,8 @@ void run_sequence_on_target(void) {
|
|||
timer.set_interval(10000);
|
||||
events_test_state = ETOT_FIRST_WAIT;
|
||||
Serial.println("Events test: initialized");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
break;
|
||||
case ETOT_FIRST_WAIT:
|
||||
if (timer.elapsed()) {
|
||||
|
@ -36,8 +36,8 @@ void run_sequence_on_target(void) {
|
|||
set_event(EVENT_DUMMY_INFO, 123);
|
||||
set_event(EVENT_DUMMY_INFO, 234); // 234 should show, occurrence 1
|
||||
Serial.println("Events test: info event set, data: 234");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_INFO:
|
||||
|
@ -46,8 +46,8 @@ void run_sequence_on_target(void) {
|
|||
clear_event(EVENT_DUMMY_INFO);
|
||||
events_test_state = ETOT_INFO_CLEAR;
|
||||
Serial.println("Events test : info event cleared");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_INFO_CLEAR:
|
||||
|
@ -57,8 +57,8 @@ void run_sequence_on_target(void) {
|
|||
set_event(EVENT_DUMMY_DEBUG, 111);
|
||||
set_event(EVENT_DUMMY_DEBUG, 222); // 222 should show, occurrence 1
|
||||
Serial.println("Events test : debug event set, data: 222");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_DEBUG:
|
||||
|
@ -67,8 +67,8 @@ void run_sequence_on_target(void) {
|
|||
clear_event(EVENT_DUMMY_DEBUG);
|
||||
events_test_state = ETOT_DEBUG_CLEAR;
|
||||
Serial.println("Events test : info event cleared");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_DEBUG_CLEAR:
|
||||
|
@ -78,8 +78,8 @@ void run_sequence_on_target(void) {
|
|||
set_event(EVENT_DUMMY_WARNING, 234);
|
||||
set_event(EVENT_DUMMY_WARNING, 121); // 121 should show, occurrence 1
|
||||
Serial.println("Events test : warning event set, data: 121");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_WARNING:
|
||||
|
@ -88,8 +88,8 @@ void run_sequence_on_target(void) {
|
|||
clear_event(EVENT_DUMMY_WARNING);
|
||||
events_test_state = ETOT_WARNING_CLEAR;
|
||||
Serial.println("Events test : warning event cleared");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_WARNING_CLEAR:
|
||||
|
@ -99,8 +99,8 @@ void run_sequence_on_target(void) {
|
|||
set_event(EVENT_DUMMY_ERROR, 221);
|
||||
set_event(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1
|
||||
Serial.println("Events test : error event set, data: 133");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_ERROR:
|
||||
|
@ -109,8 +109,8 @@ void run_sequence_on_target(void) {
|
|||
clear_event(EVENT_DUMMY_ERROR);
|
||||
events_test_state = ETOT_ERROR_CLEAR;
|
||||
Serial.println("Events test : error event cleared");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_ERROR_CLEAR:
|
||||
|
@ -120,8 +120,8 @@ void run_sequence_on_target(void) {
|
|||
set_event_latched(EVENT_DUMMY_ERROR, 221);
|
||||
set_event_latched(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1
|
||||
Serial.println("Events test : latched error event set, data: 133");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_ERROR_LATCHED:
|
||||
|
@ -130,8 +130,8 @@ void run_sequence_on_target(void) {
|
|||
clear_event(EVENT_DUMMY_ERROR);
|
||||
events_test_state = ETOT_DONE;
|
||||
Serial.println("Events test : latched error event cleared?");
|
||||
Serial.print("system_bms_status: ");
|
||||
Serial.println(system_bms_status);
|
||||
Serial.print("datalayer.battery.status.bms_status: ");
|
||||
Serial.println(datalayer.battery.status.bms_status);
|
||||
}
|
||||
break;
|
||||
case ETOT_DONE:
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#include "soc_scaling.h"
|
||||
|
||||
float ScaledSoc::set_real_soc(float soc) {
|
||||
real_soc = soc;
|
||||
scaled_soc = map_float(real_soc, 0.0f, 100.0f, min_real_soc, max_real_soc);
|
||||
real_soc_initialized = true;
|
||||
return scaled_soc;
|
||||
}
|
||||
|
||||
float ScaledSoc::get_scaled_soc(void) {
|
||||
if (real_soc_initialized) {
|
||||
return scaled_soc;
|
||||
} else {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float ScaledSoc::get_real_soc(void) {
|
||||
if (real_soc_initialized) {
|
||||
return real_soc;
|
||||
} else {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float ScaledSoc::get_soc(void) {
|
||||
if (real_soc_initialized) {
|
||||
if (soc_scaling_active) {
|
||||
return scaled_soc;
|
||||
} else {
|
||||
return real_soc;
|
||||
}
|
||||
} else {
|
||||
return -1.0f;
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef __SOC_SCALING_H__
|
||||
#define __SOC_SCALING_H__
|
||||
|
||||
#include "value_mapping.h"
|
||||
|
||||
class ScaledSoc {
|
||||
private:
|
||||
float min_real_soc, max_real_soc, real_soc, scaled_soc;
|
||||
bool soc_scaling_active;
|
||||
bool real_soc_initialized = false;
|
||||
|
||||
public:
|
||||
ScaledSoc() : min_real_soc(20.0f), max_real_soc(80.0f), soc_scaling_active(true) {}
|
||||
ScaledSoc(float min_soc, float max_soc, bool scaling_active) {
|
||||
min_real_soc = min_soc;
|
||||
max_real_soc = max_soc;
|
||||
soc_scaling_active = scaling_active;
|
||||
}
|
||||
|
||||
// Set the real soc
|
||||
float set_real_soc(float soc);
|
||||
// Get scaled soc regardless of setting
|
||||
float get_scaled_soc(void);
|
||||
// Get real soc regardless of setting
|
||||
float get_real_soc(void);
|
||||
// Get scaled or real soc based on the scaling setting
|
||||
float get_soc(void);
|
||||
};
|
||||
#endif
|
|
@ -1,18 +1,10 @@
|
|||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
// enum bms_status_enum { STANDBY = 0, INACTIVE = 1, DARKSTART = 2, ACTIVE = 3, FAULT = 4, UPDATING = 5 };
|
||||
enum bms_status_enum { STANDBY = 0, INACTIVE = 1, DARKSTART = 2, ACTIVE = 3, FAULT = 4, UPDATING = 5 };
|
||||
enum battery_chemistry_enum { NCA, NMC, LFP };
|
||||
enum led_color { GREEN, YELLOW, RED, BLUE, RGB };
|
||||
|
||||
// Inverter definitions
|
||||
#define STANDBY 0
|
||||
#define INACTIVE 1
|
||||
#define DARKSTART 2
|
||||
#define ACTIVE 3
|
||||
#define FAULT 4
|
||||
#define UPDATING 5
|
||||
|
||||
#define DISCHARGING 1
|
||||
#define CHARGING 2
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "cellmonitor_html.h"
|
||||
#include <Arduino.h>
|
||||
#include "../../datalayer/datalayer.h"
|
||||
|
||||
String cellmonitor_processor(const String& var) {
|
||||
if (var == "ABC") {
|
||||
|
@ -37,10 +38,10 @@ String cellmonitor_processor(const String& var) {
|
|||
// Populate cell data
|
||||
content += "const data = [";
|
||||
for (uint8_t i = 0u; i < MAX_AMOUNT_CELLS; i++) {
|
||||
if (system_cellvoltages_mV[i] == 0) {
|
||||
if (datalayer.battery.status.cell_voltages_mV[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
content += String(system_cellvoltages_mV[i]) + ",";
|
||||
content += String(datalayer.battery.status.cell_voltages_mV[i]) + ",";
|
||||
}
|
||||
content += "];";
|
||||
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
|
||||
#include "../../include.h"
|
||||
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
|
||||
/**
|
||||
* @brief Replaces placeholder with content section in web page
|
||||
*
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "settings_html.h"
|
||||
#include <Arduino.h>
|
||||
#include "../../datalayer/datalayer.h"
|
||||
|
||||
String settings_processor(const String& var) {
|
||||
if (var == "ABC") {
|
||||
|
@ -13,20 +14,24 @@ String settings_processor(const String& var) {
|
|||
content += "<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||
|
||||
// Show current settings with edit buttons and input fields
|
||||
content += "<h4 style='color: white;'>Battery capacity: <span id='BATTERY_WH_MAX'>" + String(BATTERY_WH_MAX) +
|
||||
content += "<h4 style='color: white;'>Battery capacity: <span id='BATTERY_WH_MAX'>" +
|
||||
String(datalayer.battery.info.total_capacity_Wh) +
|
||||
" Wh </span> <button onclick='editWh()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: white;'>Rescale SOC: <span id='USE_SCALED_SOC'>" +
|
||||
String(USE_SCALED_SOC ? "<span>✓</span>" : "<span style='color: red;'>✕</span>") +
|
||||
content += "<h4 style='color: white;'>Rescale SOC: <span id='BATTERY_USE_SCALED_SOC'>" +
|
||||
String(datalayer.battery.settings.soc_scaling_active ? "<span>✓</span>"
|
||||
: "<span style='color: red;'>✕</span>") +
|
||||
"</span> <button onclick='editUseScaledSOC()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: " + String(USE_SCALED_SOC ? "white" : "darkgrey") +
|
||||
";'>SOC max percentage: " + String(MAXPERCENTAGE / 10.0, 1) +
|
||||
content += "<h4 style='color: " + String(datalayer.battery.settings.soc_scaling_active ? "white" : "darkgrey") +
|
||||
";'>SOC max percentage: " + String(datalayer.battery.settings.max_percentage / 100.0, 1) +
|
||||
" </span> <button onclick='editSocMax()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: " + String(USE_SCALED_SOC ? "white" : "darkgrey") +
|
||||
";'>SOC min percentage: " + String(MINPERCENTAGE / 10.0, 1) +
|
||||
content += "<h4 style='color: " + String(datalayer.battery.settings.soc_scaling_active ? "white" : "darkgrey") +
|
||||
";'>SOC min percentage: " + String(datalayer.battery.settings.min_percentage / 100.0, 1) +
|
||||
" </span> <button onclick='editSocMin()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: white;'>Max charge speed: " + String(MAXCHARGEAMP / 10.0, 1) +
|
||||
content +=
|
||||
"<h4 style='color: white;'>Max charge speed: " + String(datalayer.battery.info.max_charge_amp_dA / 10.0, 1) +
|
||||
" A </span> <button onclick='editMaxChargeA()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: white;'>Max discharge speed: " + String(MAXDISCHARGEAMP / 10.0, 1) +
|
||||
content += "<h4 style='color: white;'>Max discharge speed: " +
|
||||
String(datalayer.battery.info.max_discharge_amp_dA / 10.0, 1) +
|
||||
" A </span> <button onclick='editMaxDischargeA()'>Edit</button></h4>";
|
||||
// Close the block
|
||||
content += "</div>";
|
||||
|
@ -34,7 +39,8 @@ String settings_processor(const String& var) {
|
|||
#ifdef TEST_FAKE_BATTERY
|
||||
// Start a new block with blue background color
|
||||
content += "<div style='background-color: #2E37AD; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||
float voltageFloat = static_cast<float>(system_battery_voltage_dV) / 10.0; // Convert to float and divide by 10
|
||||
float voltageFloat =
|
||||
static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0; // Convert to float and divide by 10
|
||||
content += "<h4 style='color: white;'>Fake battery voltage: " + String(voltageFloat, 1) +
|
||||
" V </span> <button onclick='editFakeBatteryVoltage()'>Edit</button></h4>";
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
#include "../../../USER_SETTINGS.h" // Needed for WiFi ssid and password
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
|
||||
/**
|
||||
* @brief Replaces placeholder with content section in web page
|
||||
|
|
|
@ -68,7 +68,7 @@ void init_webserver() {
|
|||
server.on("/updateBatterySize", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
BATTERY_WH_MAX = value.toInt();
|
||||
datalayer.battery.info.total_capacity_Wh = value.toInt();
|
||||
storeSettings();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
|
@ -80,7 +80,7 @@ void init_webserver() {
|
|||
server.on("/updateUseScaledSOC", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
USE_SCALED_SOC = value.toInt();
|
||||
datalayer.battery.settings.soc_scaling_active = value.toInt();
|
||||
storeSettings();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
|
@ -92,7 +92,7 @@ void init_webserver() {
|
|||
server.on("/updateSocMax", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
MAXPERCENTAGE = value.toInt() * 10;
|
||||
datalayer.battery.settings.max_percentage = value.toInt() * 100;
|
||||
storeSettings();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
|
@ -104,7 +104,7 @@ void init_webserver() {
|
|||
server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
MINPERCENTAGE = value.toInt() * 10;
|
||||
datalayer.battery.settings.min_percentage = value.toInt() * 100;
|
||||
storeSettings();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
|
@ -116,7 +116,7 @@ void init_webserver() {
|
|||
server.on("/updateMaxChargeA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
MAXCHARGEAMP = value.toInt() * 10;
|
||||
datalayer.battery.info.max_charge_amp_dA = value.toInt() * 10;
|
||||
storeSettings();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
|
@ -128,7 +128,7 @@ void init_webserver() {
|
|||
server.on("/updateMaxDischargeA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
MAXDISCHARGEAMP = value.toInt() * 10;
|
||||
datalayer.battery.info.max_discharge_amp_dA = value.toInt() * 10;
|
||||
storeSettings();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
|
@ -146,7 +146,7 @@ void init_webserver() {
|
|||
String value = request->getParam("value")->value();
|
||||
float val = value.toFloat();
|
||||
|
||||
system_battery_voltage_dV = val * 10;
|
||||
datalayer.battery.status.voltage_dV = val * 10;
|
||||
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
});
|
||||
|
@ -184,7 +184,7 @@ void init_webserver() {
|
|||
String value = request->getParam("value")->value();
|
||||
float val = value.toFloat();
|
||||
|
||||
if (!(val <= MAXCHARGEAMP && val <= CHARGER_MAX_A)) {
|
||||
if (!(val <= datalayer.battery.info.max_charge_amp_dA && val <= CHARGER_MAX_A)) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
|
@ -372,16 +372,17 @@ String processor(const String& var) {
|
|||
content += "<h4>Software: " + String(version_number) + "</h4>";
|
||||
#ifdef FUNCTION_TIME_MEASUREMENT
|
||||
// Load information
|
||||
content += "<h4>Main task max load: " + String(datalayer.system.status.main_task_max_us) + " us</h4>";
|
||||
content += "<h4>Main task max load last 10 s: " + String(datalayer.system.status.main_task_10s_max_us) + " us</h4>";
|
||||
content += "<h4>MQTT task max load last 10 s: " + String(datalayer.system.status.time_mqtt_us) + " us</h4>";
|
||||
content += "<h4>Max function load last 10 s:</h4>";
|
||||
content += "<h4>Events function timing: " + String(datalayer.system.status.time_events_us) + " us</h4>";
|
||||
content += "<h4>10ms function timing: " + String(datalayer.system.status.time_10ms_us) + " us</h4>";
|
||||
content += "<h4>5s function timing: " + String(datalayer.system.status.time_5s_us) + " us</h4>";
|
||||
content += "<h4>CAN/serial RX function timing: " + String(datalayer.system.status.time_comm_us) + " us</h4>";
|
||||
content += "<h4>CAN TX function timing: " + String(datalayer.system.status.time_cantx_us) + " us</h4>";
|
||||
content += "<h4>Wifi and OTA function timing: " + String(datalayer.system.status.time_wifi_us) + " us</h4>";
|
||||
content += "<h4>Core task max load: " + String(datalayer.system.status.core_task_max_us) + " us</h4>";
|
||||
content += "<h4>Core task max load last 10 s: " + String(datalayer.system.status.core_task_10s_max_us) + " us</h4>";
|
||||
content += "<h4>MQTT task max load last 10 s: " + String(datalayer.system.status.mqtt_task_10s_max_us) + " us</h4>";
|
||||
content +=
|
||||
"<h4>loop() task max load last 10 s: " + String(datalayer.system.status.loop_task_10s_max_us) + " us</h4>";
|
||||
content += "<h4>Max load @ worst case execution of core task:</h4>";
|
||||
content += "<h4>10ms function timing: " + String(datalayer.system.status.time_snap_10ms_us) + " us</h4>";
|
||||
content += "<h4>5s function timing: " + String(datalayer.system.status.time_snap_5s_us) + " us</h4>";
|
||||
content += "<h4>CAN/serial RX function timing: " + String(datalayer.system.status.time_snap_comm_us) + " us</h4>";
|
||||
content += "<h4>CAN TX function timing: " + String(datalayer.system.status.time_snap_cantx_us) + " us</h4>";
|
||||
content += "<h4>Wifi and OTA function timing: " + String(datalayer.system.status.time_snap_wifi_us) + " us</h4>";
|
||||
#endif
|
||||
|
||||
wl_status_t status = WiFi.status();
|
||||
|
@ -507,14 +508,19 @@ String processor(const String& var) {
|
|||
content += "padding: 10px; margin-bottom: 10px; border-radius: 50px;'>";
|
||||
|
||||
// Display battery statistics within this block
|
||||
float socRealFloat = static_cast<float>(system_real_SOC_pptt) / 100.0; // Convert to float and divide by 100
|
||||
float socScaledFloat = static_cast<float>(system_scaled_SOC_pptt) / 100.0; // Convert to float and divide by 100
|
||||
float sohFloat = static_cast<float>(system_SOH_pptt) / 100.0; // Convert to float and divide by 100
|
||||
float voltageFloat = static_cast<float>(system_battery_voltage_dV) / 10.0; // Convert to float and divide by 10
|
||||
float currentFloat = static_cast<float>(system_battery_current_dA) / 10.0; // Convert to float and divide by 10
|
||||
float powerFloat = static_cast<float>(system_active_power_W); // Convert to float
|
||||
float tempMaxFloat = static_cast<float>(system_temperature_max_dC) / 10.0; // Convert to float
|
||||
float tempMinFloat = static_cast<float>(system_temperature_min_dC) / 10.0; // Convert to float
|
||||
float socRealFloat =
|
||||
static_cast<float>(datalayer.battery.status.real_soc) / 100.0; // Convert to float and divide by 100
|
||||
float socScaledFloat =
|
||||
static_cast<float>(datalayer.battery.status.reported_soc) / 100.0; // Convert to float and divide by 100
|
||||
float sohFloat =
|
||||
static_cast<float>(datalayer.battery.status.soh_pptt) / 100.0; // Convert to float and divide by 100
|
||||
float voltageFloat =
|
||||
static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0; // Convert to float and divide by 10
|
||||
float currentFloat =
|
||||
static_cast<float>(datalayer.battery.status.current_dA) / 10.0; // Convert to float and divide by 10
|
||||
float powerFloat = static_cast<float>(datalayer.battery.status.active_power_W); // Convert to float
|
||||
float tempMaxFloat = static_cast<float>(datalayer.battery.status.temperature_max_dC) / 10.0; // Convert to float
|
||||
float tempMinFloat = static_cast<float>(datalayer.battery.status.temperature_min_dC) / 10.0; // Convert to float
|
||||
|
||||
content += "<h4 style='color: white;'>Real SOC: " + String(socRealFloat, 2) + "</h4>";
|
||||
content += "<h4 style='color: white;'>Scaled SOC: " + String(socScaledFloat, 2) + "</h4>";
|
||||
|
@ -522,24 +528,24 @@ String processor(const String& var) {
|
|||
content += "<h4 style='color: white;'>Voltage: " + String(voltageFloat, 1) + " V</h4>";
|
||||
content += "<h4 style='color: white;'>Current: " + String(currentFloat, 1) + " A</h4>";
|
||||
content += formatPowerValue("Power", powerFloat, "", 1);
|
||||
content += formatPowerValue("Total capacity", system_capacity_Wh, "h", 0);
|
||||
content += formatPowerValue("Remaining capacity", system_remaining_capacity_Wh, "h", 1);
|
||||
content += formatPowerValue("Max discharge power", system_max_discharge_power_W, "", 1);
|
||||
content += formatPowerValue("Max charge power", system_max_charge_power_W, "", 1);
|
||||
content += "<h4>Cell max: " + String(system_cell_max_voltage_mV) + " mV</h4>";
|
||||
content += "<h4>Cell min: " + String(system_cell_min_voltage_mV) + " mV</h4>";
|
||||
content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 0);
|
||||
content += formatPowerValue("Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1);
|
||||
content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1);
|
||||
content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1);
|
||||
content += "<h4>Cell max: " + String(datalayer.battery.status.cell_max_voltage_mV) + " mV</h4>";
|
||||
content += "<h4>Cell min: " + String(datalayer.battery.status.cell_min_voltage_mV) + " mV</h4>";
|
||||
content += "<h4>Temperature max: " + String(tempMaxFloat, 1) + " C</h4>";
|
||||
content += "<h4>Temperature min: " + String(tempMinFloat, 1) + " C</h4>";
|
||||
if (system_bms_status == ACTIVE) {
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
content += "<h4>BMS Status: OK </h4>";
|
||||
} else if (system_bms_status == UPDATING) {
|
||||
} else if (datalayer.battery.status.bms_status == UPDATING) {
|
||||
content += "<h4>BMS Status: UPDATING </h4>";
|
||||
} else {
|
||||
content += "<h4>BMS Status: FAULT </h4>";
|
||||
}
|
||||
if (system_battery_current_dA == 0) {
|
||||
if (datalayer.battery.status.current_dA == 0) {
|
||||
content += "<h4>Battery idle</h4>";
|
||||
} else if (system_battery_current_dA < 0) {
|
||||
} else if (datalayer.battery.status.current_dA < 0) {
|
||||
content += "<h4>Battery discharging!</h4>";
|
||||
} else { // > 0
|
||||
content += "<h4>Battery charging!</h4>";
|
||||
|
@ -547,14 +553,14 @@ String processor(const String& var) {
|
|||
|
||||
content += "<h4>Automatic contactor closing allowed:</h4>";
|
||||
content += "<h4>Battery: ";
|
||||
if (batteryAllowsContactorClosing) {
|
||||
if (datalayer.system.status.battery_allows_contactor_closing == true) {
|
||||
content += "<span>✓</span>";
|
||||
} else {
|
||||
content += "<span style='color: red;'>✕</span>";
|
||||
}
|
||||
|
||||
content += " Inverter: ";
|
||||
if (inverterAllowsContactorClosing) {
|
||||
if (datalayer.system.status.inverter_allows_contactor_closing == true) {
|
||||
content += "<span>✓</span></h4>";
|
||||
} else {
|
||||
content += "<span style='color: red;'>✕</span></h4>";
|
||||
|
@ -604,8 +610,8 @@ String processor(const String& var) {
|
|||
#endif
|
||||
#ifdef NISSANLEAF_CHARGER
|
||||
float chgPwrDC = static_cast<float>(charger_stat_HVcur * 100);
|
||||
charger_stat_HVcur = chgPwrDC / (system_battery_voltage_dV / 10); // P/U=I
|
||||
charger_stat_HVvol = static_cast<float>(system_battery_voltage_dV / 10);
|
||||
charger_stat_HVcur = chgPwrDC / (datalayer.battery.status.voltage_dV / 10); // P/U=I
|
||||
charger_stat_HVvol = static_cast<float>(datalayer.battery.status.voltage_dV / 10);
|
||||
float ACvol = charger_stat_ACvol;
|
||||
float HVvol = charger_stat_HVvol;
|
||||
float HVcur = charger_stat_HVcur;
|
||||
|
|
|
@ -16,27 +16,6 @@
|
|||
#endif
|
||||
|
||||
extern const char* version_number; // The current software version, shown on webserver
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000 , Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
|
||||
extern const char* ssid;
|
||||
extern const char* password;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef BYD_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "BYD-CAN.h"
|
||||
|
@ -115,32 +116,38 @@ static bool initialDataSent = 0;
|
|||
|
||||
void update_values_can_byd() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
//Calculate values
|
||||
charge_current = ((system_max_charge_power_W * 10) /
|
||||
system_max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
charge_current =
|
||||
((datalayer.battery.status.max_charge_power_W * 10) /
|
||||
datalayer.battery.info.max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
//The above calculation results in (30 000*10)/3700=81A
|
||||
charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A)
|
||||
if (charge_current > MAXCHARGEAMP) {
|
||||
charge_current = MAXCHARGEAMP; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
if (charge_current > datalayer.battery.info.max_charge_amp_dA) {
|
||||
charge_current =
|
||||
datalayer.battery.info
|
||||
.max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
}
|
||||
|
||||
discharge_current = ((system_max_discharge_power_W * 10) /
|
||||
system_max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
discharge_current =
|
||||
((datalayer.battery.status.max_discharge_power_W * 10) /
|
||||
datalayer.battery.info.max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
//The above calculation results in (30 000*10)/3700=81A
|
||||
discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A)
|
||||
if (discharge_current > MAXDISCHARGEAMP) {
|
||||
if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) {
|
||||
discharge_current =
|
||||
MAXDISCHARGEAMP; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
datalayer.battery.info
|
||||
.max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
}
|
||||
|
||||
temperature_average = ((system_temperature_max_dC + system_temperature_min_dC) / 2);
|
||||
temperature_average =
|
||||
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
|
||||
|
||||
//Map values to CAN messages
|
||||
//Maxvoltage (eg 400.0V = 4000 , 16bits long)
|
||||
BYD_110.data.u8[0] = (system_max_design_voltage_dV >> 8);
|
||||
BYD_110.data.u8[1] = (system_max_design_voltage_dV & 0x00FF);
|
||||
BYD_110.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
BYD_110.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
//Minvoltage (eg 300.0V = 3000 , 16bits long)
|
||||
BYD_110.data.u8[2] = (system_min_design_voltage_dV >> 8);
|
||||
BYD_110.data.u8[3] = (system_min_design_voltage_dV & 0x00FF);
|
||||
BYD_110.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
BYD_110.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
//Maximum discharge power allowed (Unit: A+1)
|
||||
BYD_110.data.u8[4] = (discharge_current >> 8);
|
||||
BYD_110.data.u8[5] = (discharge_current & 0x00FF);
|
||||
|
@ -149,11 +156,11 @@ void update_values_can_byd() { //This function maps all the values fetched from
|
|||
BYD_110.data.u8[7] = (charge_current & 0x00FF);
|
||||
|
||||
//SOC (100.00%)
|
||||
BYD_150.data.u8[0] = (system_scaled_SOC_pptt >> 8);
|
||||
BYD_150.data.u8[1] = (system_scaled_SOC_pptt & 0x00FF);
|
||||
BYD_150.data.u8[0] = (datalayer.battery.status.reported_soc >> 8);
|
||||
BYD_150.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF);
|
||||
//StateOfHealth (100.00%)
|
||||
BYD_150.data.u8[2] = (system_SOH_pptt >> 8);
|
||||
BYD_150.data.u8[3] = (system_SOH_pptt & 0x00FF);
|
||||
BYD_150.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8);
|
||||
BYD_150.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF);
|
||||
//Maximum discharge power allowed (Unit: A+1)
|
||||
BYD_150.data.u8[4] = (discharge_current >> 8);
|
||||
BYD_150.data.u8[5] = (discharge_current & 0x00FF);
|
||||
|
@ -162,21 +169,21 @@ void update_values_can_byd() { //This function maps all the values fetched from
|
|||
BYD_150.data.u8[7] = (charge_current & 0x00FF);
|
||||
|
||||
//Voltage (ex 370.0)
|
||||
BYD_1D0.data.u8[0] = (system_battery_voltage_dV >> 8);
|
||||
BYD_1D0.data.u8[1] = (system_battery_voltage_dV & 0x00FF);
|
||||
BYD_1D0.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
BYD_1D0.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
//Current (ex 81.0A)
|
||||
BYD_1D0.data.u8[2] = (system_battery_current_dA >> 8);
|
||||
BYD_1D0.data.u8[3] = (system_battery_current_dA & 0x00FF);
|
||||
BYD_1D0.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
BYD_1D0.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
//Temperature average
|
||||
BYD_1D0.data.u8[4] = (temperature_average >> 8);
|
||||
BYD_1D0.data.u8[5] = (temperature_average & 0x00FF);
|
||||
|
||||
//Temperature max
|
||||
BYD_210.data.u8[0] = (system_temperature_max_dC >> 8);
|
||||
BYD_210.data.u8[1] = (system_temperature_max_dC & 0x00FF);
|
||||
BYD_210.data.u8[0] = (datalayer.battery.status.temperature_max_dC >> 8);
|
||||
BYD_210.data.u8[1] = (datalayer.battery.status.temperature_max_dC & 0x00FF);
|
||||
//Temperature min
|
||||
BYD_210.data.u8[2] = (system_temperature_min_dC >> 8);
|
||||
BYD_210.data.u8[3] = (system_temperature_min_dC & 0x00FF);
|
||||
BYD_210.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8);
|
||||
BYD_210.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF);
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
if (char1_151 != 0) {
|
||||
|
|
|
@ -6,29 +6,6 @@
|
|||
|
||||
#define INVERTER_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void update_values_can_byd();
|
||||
void send_can_byd();
|
||||
void receive_can_byd(CAN_frame_t rx_frame);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef BYD_MODBUS
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "BYD-MODBUS.h"
|
||||
|
||||
void update_modbus_registers_byd() {
|
||||
|
@ -34,19 +35,22 @@ void handle_update_data_modbusp201_byd() {
|
|||
static uint16_t system_data[13];
|
||||
system_data[0] = 0; // Id.: p201 Value.: 0 Scaled value.: 0 Comment.: Always 0
|
||||
system_data[1] = 0; // Id.: p202 Value.: 0 Scaled value.: 0 Comment.: Always 0
|
||||
if (system_capacity_Wh > 60000) {
|
||||
if (datalayer.battery.info.total_capacity_Wh > 60000) {
|
||||
system_data[2] = 60000;
|
||||
} else {
|
||||
system_data[2] =
|
||||
(system_capacity_Wh); // Id.: p203 Value.: 32000 Scaled value.: 32kWh Comment.: Capacity rated, maximum value is 60000 (60kWh)
|
||||
(datalayer.battery.info
|
||||
.total_capacity_Wh); // Id.: p203 Value.: 32000 Scaled value.: 32kWh Comment.: Capacity rated, maximum value is 60000 (60kWh)
|
||||
}
|
||||
system_data[3] = MAX_POWER; // Id.: p204 Value.: 32000 Scaled value.: 32kWh Comment.: Nominal capacity
|
||||
system_data[4] =
|
||||
MAX_POWER; // Id.: p205 Value.: 14500 Scaled value.: 30,42kW Comment.: Max Charge/Discharge Power=10.24kW (lowest value of 204 and 205 will be enforced by Gen24)
|
||||
system_data[5] =
|
||||
(system_max_design_voltage_dV); // Id.: p206 Value.: 3667 Scaled value.: 362,7VDC Comment.: Max Voltage, if higher charging is not possible (goes into forced discharge)
|
||||
(datalayer.battery.info
|
||||
.max_design_voltage_dV); // Id.: p206 Value.: 3667 Scaled value.: 362,7VDC Comment.: Max Voltage, if higher charging is not possible (goes into forced discharge)
|
||||
system_data[6] =
|
||||
(system_min_design_voltage_dV); // Id.: p207 Value.: 2776 Scaled value.: 277,6VDC Comment.: Min Voltage, if lower Gen24 disables battery
|
||||
(datalayer.battery.info
|
||||
.min_design_voltage_dV); // Id.: p207 Value.: 2776 Scaled value.: 277,6VDC Comment.: Min Voltage, if lower Gen24 disables battery
|
||||
system_data[7] =
|
||||
53248; // Id.: p208 Value.: 53248 Scaled value.: 53248 Comment.: Always 53248 for this BYD, Peak Charge power?
|
||||
system_data[8] = 10; // Id.: p209 Value.: 10 Scaled value.: 10 Comment.: Always 10
|
||||
|
@ -64,60 +68,69 @@ void handle_update_data_modbusp301_byd() {
|
|||
static uint16_t battery_data[24];
|
||||
|
||||
static uint8_t bms_char_dis_status = STANDBY;
|
||||
if (system_battery_current_dA == 0) {
|
||||
if (datalayer.battery.status.current_dA == 0) {
|
||||
bms_char_dis_status = STANDBY;
|
||||
} else if (system_battery_current_dA < 0) { //Negative value = Discharging
|
||||
} else if (datalayer.battery.status.current_dA < 0) { //Negative value = Discharging
|
||||
bms_char_dis_status = DISCHARGING;
|
||||
} else { //Positive value = Charging
|
||||
bms_char_dis_status = CHARGING;
|
||||
}
|
||||
|
||||
if (system_bms_status == ACTIVE) {
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
battery_data[8] =
|
||||
system_battery_voltage_dV; // Id.: p309 Value.: 3161 Scaled value.: 316,1VDC Comment.: Batt Voltage outer (0 if status !=3, maybe a contactor closes when active): 173.4V
|
||||
datalayer.battery.status
|
||||
.voltage_dV; // Id.: p309 Value.: 3161 Scaled value.: 316,1VDC Comment.: Batt Voltage outer (0 if status !=3, maybe a contactor closes when active): 173.4V
|
||||
} else {
|
||||
battery_data[8] = 0;
|
||||
}
|
||||
battery_data[0] =
|
||||
system_bms_status; // Id.: p301 Value.: 3 Scaled value.: 3 Comment.: status(*): ACTIVE - [0..5]<>[STANDBY,INACTIVE,DARKSTART,ACTIVE,FAULT,UPDATING]
|
||||
datalayer.battery.status
|
||||
.bms_status; // Id.: p301 Value.: 3 Scaled value.: 3 Comment.: status(*): ACTIVE - [0..5]<>[STANDBY,INACTIVE,DARKSTART,ACTIVE,FAULT,UPDATING]
|
||||
battery_data[1] = 0; // Id.: p302 Value.: 0 Scaled value.: 0 Comment.: always 0
|
||||
battery_data[2] = 128 + bms_char_dis_status; // Id.: p303 Value.: 130 Scaled value.: 130 Comment.: mode(*): normal
|
||||
battery_data[3] =
|
||||
system_scaled_SOC_pptt; // Id.: p304 Value.: 1700 Scaled value.: 50% Comment.: SOC: (50% would equal 5000)
|
||||
if (system_capacity_Wh > 60000) {
|
||||
datalayer.battery.status
|
||||
.reported_soc; // Id.: p304 Value.: 1700 Scaled value.: 50% Comment.: SOC: (50% would equal 5000)
|
||||
if (datalayer.battery.info.total_capacity_Wh > 60000) {
|
||||
battery_data[4] = 60000;
|
||||
} else {
|
||||
battery_data[4] = system_capacity_Wh; // Id.: p305 Value.: 32000 Scaled value.: 32kWh Comment.: tot cap:
|
||||
battery_data[4] =
|
||||
datalayer.battery.info.total_capacity_Wh; // Id.: p305 Value.: 32000 Scaled value.: 32kWh Comment.: tot cap:
|
||||
}
|
||||
if (system_remaining_capacity_Wh > 60000) {
|
||||
if (datalayer.battery.status.remaining_capacity_Wh > 60000) {
|
||||
battery_data[5] = 60000;
|
||||
} else {
|
||||
battery_data[5] =
|
||||
system_remaining_capacity_Wh; // Id.: p306 Value.: 13260 Scaled value.: 13,26kWh Comment.: remaining cap: 7.68kWh
|
||||
// Id.: p306 Value.: 13260 Scaled value.: 13,26kWh Comment.: remaining cap: 7.68kWh
|
||||
battery_data[5] = datalayer.battery.status.remaining_capacity_Wh;
|
||||
}
|
||||
if (system_max_discharge_power_W > 30000) {
|
||||
if (datalayer.battery.status.max_discharge_power_W > 30000) {
|
||||
battery_data[6] = 30000;
|
||||
} else {
|
||||
battery_data[6] =
|
||||
system_max_discharge_power_W; // Id.: p307 Value.: 25604 Scaled value.: 25,604kW Comment.: max/target discharge power: 0W (0W > restricts to no discharge)
|
||||
datalayer.battery.status
|
||||
.max_discharge_power_W; // Id.: p307 Value.: 25604 Scaled value.: 25,604kW Comment.: max/target discharge power: 0W (0W > restricts to no discharge)
|
||||
}
|
||||
|
||||
if (system_max_charge_power_W > 30000) {
|
||||
if (datalayer.battery.status.max_charge_power_W > 30000) {
|
||||
battery_data[7] = 30000;
|
||||
} else {
|
||||
battery_data[7] =
|
||||
system_max_charge_power_W; // Id.: p308 Value.: 25604 Scaled value.: 25,604kW Comment.: max/target charge power: 4.3kW (during charge), both 307&308 can be set (>0) at the same time
|
||||
datalayer.battery.status
|
||||
.max_charge_power_W; // Id.: p308 Value.: 25604 Scaled value.: 25,604kW Comment.: max/target charge power: 4.3kW (during charge), both 307&308 can be set (>0) at the same time
|
||||
}
|
||||
//Battery_data[8] set previously in function // Id.: p309 Value.: 3161 Scaled value.: 316,1VDC Comment.: Batt Voltage outer (0 if status !=3, maybe a contactor closes when active): 173.4V
|
||||
battery_data[9] =
|
||||
2000; // Id.: p310 Value.: 64121 Scaled value.: 6412,1W Comment.: Current Power to API: if>32768... -(65535-61760)=3775W
|
||||
battery_data[10] =
|
||||
system_battery_voltage_dV; // Id.: p311 Value.: 3161 Scaled value.: 316,1VDC Comment.: Batt Voltage inner: 173.2V
|
||||
datalayer.battery.status
|
||||
.voltage_dV; // Id.: p311 Value.: 3161 Scaled value.: 316,1VDC Comment.: Batt Voltage inner: 173.2V
|
||||
battery_data[11] = 2000; // Id.: p312 Value.: 64121 Scaled value.: 6412,1W Comment.: p310
|
||||
battery_data[12] =
|
||||
system_temperature_min_dC; // Id.: p313 Value.: 75 Scaled value.: 7,5 Comment.: temp min: 7 degrees (if below 0....65535-t)
|
||||
datalayer.battery.status
|
||||
.temperature_min_dC; // Id.: p313 Value.: 75 Scaled value.: 7,5 Comment.: temp min: 7 degrees (if below 0....65535-t)
|
||||
battery_data[13] =
|
||||
system_temperature_max_dC; // Id.: p314 Value.: 95 Scaled value.: 9,5 Comment.: temp max: 9 degrees (if below 0....65535-t)
|
||||
datalayer.battery.status
|
||||
.temperature_max_dC; // Id.: p314 Value.: 95 Scaled value.: 9,5 Comment.: temp max: 9 degrees (if below 0....65535-t)
|
||||
battery_data[14] = 0; // Id.: p315 Value.: 0 Scaled value.: 0 Comment.: always 0
|
||||
battery_data[15] = 0; // Id.: p316 Value.: 0 Scaled value.: 0 Comment.: always 0
|
||||
battery_data[16] = 16; // Id.: p317 Value.: 0 Scaled value.: 0 Comment.: counter charge hi
|
||||
|
@ -129,27 +142,29 @@ void handle_update_data_modbusp301_byd() {
|
|||
battery_data[21] =
|
||||
52064; // Id.: p322 Value.: 0 Scaled value.: 0 Comment.: counter discharge lo....65536*92+7448 = 6036760 Wh?
|
||||
battery_data[22] = 230; // Id.: p323 Value.: 0 Scaled value.: 0 Comment.: device temperature (23 degrees)
|
||||
battery_data[23] = system_SOH_pptt; // Id.: p324 Value.: 9900 Scaled value.: 99% Comment.: SOH
|
||||
battery_data[23] = datalayer.battery.status.soh_pptt; // Id.: p324 Value.: 9900 Scaled value.: 99% Comment.: SOH
|
||||
static uint16_t i = 300;
|
||||
memcpy(&mbPV[i], battery_data, sizeof(battery_data));
|
||||
}
|
||||
|
||||
void verify_temperature_modbus() {
|
||||
if (system_LFP_Chemistry) {
|
||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
|
||||
return; // Skip the following section
|
||||
}
|
||||
// This section checks if the battery temperature is negative, and incase it falls between -9.0 and -20.0C degrees
|
||||
// The Fronius Gen24 (and other Fronius inverters also affected), will stop charge/discharge if the battery gets colder than -10°C.
|
||||
// This is due to the original battery pack (BYD HVM), is a lithium iron phosphate battery, that cannot be charged in cold weather.
|
||||
// When using EV packs with NCM/LMO/NCA chemsitry, this is not a problem, since these chemistries are OK for outdoor cold use.
|
||||
if (system_temperature_min_dC < 0) {
|
||||
if (system_temperature_min_dC < -90 && system_temperature_min_dC > -200) { // Between -9.0 and -20.0C degrees
|
||||
system_temperature_min_dC = -90; //Cap value to -9.0C
|
||||
if (datalayer.battery.status.temperature_min_dC < 0) {
|
||||
if (datalayer.battery.status.temperature_min_dC < -90 &&
|
||||
datalayer.battery.status.temperature_min_dC > -200) { // Between -9.0 and -20.0C degrees
|
||||
datalayer.battery.status.temperature_min_dC = -90; //Cap value to -9.0C
|
||||
}
|
||||
}
|
||||
if (system_temperature_max_dC < 0) { // Signed value on negative side
|
||||
if (system_temperature_max_dC < -90 && system_temperature_max_dC > -200) { // Between -9.0 and -20.0C degrees
|
||||
system_temperature_max_dC = -90; //Cap value to -9.0C
|
||||
if (datalayer.battery.status.temperature_max_dC < 0) { // Signed value on negative side
|
||||
if (datalayer.battery.status.temperature_max_dC < -90 &&
|
||||
datalayer.battery.status.temperature_max_dC > -200) { // Between -9.0 and -20.0C degrees
|
||||
datalayer.battery.status.temperature_max_dC = -90; //Cap value to -9.0C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,24 +8,6 @@
|
|||
#define MAX_POWER 40960 //BYD Modbus specific value
|
||||
|
||||
extern uint16_t mbPV[MB_RTU_NUM_VALUES];
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
extern bool system_LFP_Chemistry; //Bool, true/false
|
||||
|
||||
void handle_static_data_modbus_byd();
|
||||
void verify_temperature_modbus();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef LUNA2000_MODBUS
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "LUNA2000-MODBUS.h"
|
||||
|
||||
void update_modbus_registers_luna2000() {
|
||||
|
@ -16,9 +17,9 @@ void handle_update_data_modbus32051() {
|
|||
system_data[2] = 110; //Goes between 110- -107 [NOTE, SIGNED VALUE]
|
||||
system_data[3] = 0; //Goes between 0 and -1 [NOTE, SIGNED VALUE]
|
||||
system_data[4] = 616; //Goes between 616- -520 [NOTE, SIGNED VALUE]
|
||||
system_data[5] = system_temperature_max_dC; //Temperature max?
|
||||
system_data[6] = system_temperature_min_dC; //Temperature min?
|
||||
system_data[7] = (system_scaled_SOC_pptt / 100); //SOC 0-100%, no decimals
|
||||
system_data[5] = datalayer.battery.status.temperature_max_dC; //Temperature max?
|
||||
system_data[6] = datalayer.battery.status.temperature_min_dC; //Temperature min?
|
||||
system_data[7] = (datalayer.battery.status.reported_soc / 100); //SOC 0-100%, no decimals
|
||||
system_data[8] = 98; //Always 98 in logs
|
||||
static uint16_t i = 2051;
|
||||
memcpy(&mbPV[i], system_data, sizeof(system_data));
|
||||
|
@ -28,17 +29,17 @@ void handle_update_data_modbus39500() {
|
|||
// Store the data into the array
|
||||
static uint16_t system_data[26];
|
||||
system_data[0] = 0;
|
||||
system_data[1] = system_capacity_Wh; //Capacity? 5000 with 5kWh battery
|
||||
system_data[1] = datalayer.battery.info.total_capacity_Wh; //Capacity? 5000 with 5kWh battery
|
||||
system_data[2] = 0;
|
||||
system_data[3] = system_capacity_Wh; //Capacity? 5000 with 5kWh battery
|
||||
system_data[3] = datalayer.battery.info.total_capacity_Wh; //Capacity? 5000 with 5kWh battery
|
||||
system_data[4] = 0;
|
||||
system_data[5] = 2500; //???
|
||||
system_data[6] = 0;
|
||||
system_data[7] = 2500; //???
|
||||
system_data[8] = (system_scaled_SOC_pptt / 100); //SOC 0-100%, no decimals
|
||||
system_data[8] = (datalayer.battery.status.reported_soc / 100); //SOC 0-100%, no decimals
|
||||
system_data[9] =
|
||||
1; //Running status, equiv to register 37762, 0 = Offline, 1 = Standby,2 = Running, 3 = Fault, 4 = sleep mode
|
||||
system_data[10] = system_battery_voltage_dV; //Battery bus voltage (766.5V = 7665)
|
||||
system_data[10] = datalayer.battery.status.voltage_dV; //Battery bus voltage (766.5V = 7665)
|
||||
system_data[11] = 9; //TODO: GOES LOWER WITH LOW SOC
|
||||
system_data[12] = 0;
|
||||
system_data[13] = 699; //TODO: GOES LOWER WITH LOW SOC
|
||||
|
@ -52,7 +53,7 @@ void handle_update_data_modbus39500() {
|
|||
system_data[21] = 0;
|
||||
system_data[22] = 0;
|
||||
system_data[23] = 0;
|
||||
system_data[24] = (system_scaled_SOC_pptt / 10); //SOC 0-100.0%, 1x decimal
|
||||
system_data[24] = (datalayer.battery.status.reported_soc / 10); //SOC 0-100.0%, 1x decimal
|
||||
system_data[25] = 0;
|
||||
system_data[26] = 1; //Always 1 in logs
|
||||
static uint16_t i = 9500;
|
||||
|
|
|
@ -7,27 +7,6 @@
|
|||
#define MB_RTU_NUM_VALUES 30000
|
||||
|
||||
extern uint16_t mbPV[MB_RTU_NUM_VALUES];
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void update_modbus_registers_luna2000();
|
||||
void handle_update_data_modbus32051();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef PYLON_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "PYLON-CAN.h"
|
||||
|
@ -184,53 +185,53 @@ void update_values_can_pylon() { //This function maps all the values fetched fr
|
|||
PYLON_4281.data.u8[3] = 0;
|
||||
|
||||
//Voltage (370.0)
|
||||
PYLON_4210.data.u8[0] = (system_battery_voltage_dV >> 8);
|
||||
PYLON_4210.data.u8[1] = (system_battery_voltage_dV & 0x00FF);
|
||||
PYLON_4211.data.u8[0] = (system_battery_voltage_dV >> 8);
|
||||
PYLON_4211.data.u8[1] = (system_battery_voltage_dV & 0x00FF);
|
||||
PYLON_4210.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
PYLON_4210.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
PYLON_4211.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
PYLON_4211.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
|
||||
//Current (15.0)
|
||||
PYLON_4210.data.u8[2] = (system_battery_current_dA >> 8);
|
||||
PYLON_4210.data.u8[3] = (system_battery_current_dA & 0x00FF);
|
||||
PYLON_4211.data.u8[2] = (system_battery_current_dA >> 8);
|
||||
PYLON_4211.data.u8[3] = (system_battery_current_dA & 0x00FF);
|
||||
PYLON_4210.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
PYLON_4210.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
PYLON_4211.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
PYLON_4211.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
|
||||
//SOC (100.00%)
|
||||
PYLON_4210.data.u8[6] = (system_scaled_SOC_pptt * 0.01); //Remove decimals
|
||||
PYLON_4211.data.u8[6] = (system_scaled_SOC_pptt * 0.01); //Remove decimals
|
||||
PYLON_4210.data.u8[6] = (datalayer.battery.status.reported_soc / 100); //Remove decimals
|
||||
PYLON_4211.data.u8[6] = (datalayer.battery.status.reported_soc / 100); //Remove decimals
|
||||
|
||||
//StateOfHealth (100.00%)
|
||||
PYLON_4210.data.u8[7] = (system_SOH_pptt * 0.01);
|
||||
PYLON_4211.data.u8[7] = (system_SOH_pptt * 0.01);
|
||||
PYLON_4210.data.u8[7] = (datalayer.battery.status.soh_pptt / 100);
|
||||
PYLON_4211.data.u8[7] = (datalayer.battery.status.soh_pptt / 100);
|
||||
|
||||
#ifdef INVERT_VOLTAGE //Useful for Sofar inverters \
|
||||
//Maxvoltage (eg 400.0V = 4000 , 16bits long) Discharge Cutoff Voltage
|
||||
PYLON_4220.data.u8[0] = (system_max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4220.data.u8[1] = (system_max_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[0] = (system_max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[1] = (system_max_design_voltage_dV >> 8);
|
||||
PYLON_4220.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4220.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
|
||||
//Minvoltage (eg 300.0V = 3000 , 16bits long) Charge Cutoff Voltage
|
||||
PYLON_4220.data.u8[2] = (system_min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4220.data.u8[3] = (system_min_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[2] = (system_min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[3] = (system_min_design_voltage_dV >> 8);
|
||||
PYLON_4220.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4220.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
#else
|
||||
//Minvoltage (eg 300.0V = 3000 , 16bits long) Charge Cutoff Voltage
|
||||
PYLON_4220.data.u8[0] = (system_min_design_voltage_dV >> 8);
|
||||
PYLON_4220.data.u8[1] = (system_min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[0] = (system_min_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[1] = (system_min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4220.data.u8[0] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
PYLON_4220.data.u8[1] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[0] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[1] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
|
||||
//Maxvoltage (eg 400.0V = 4000 , 16bits long) Discharge Cutoff Voltage
|
||||
PYLON_4220.data.u8[2] = (system_max_design_voltage_dV >> 8);
|
||||
PYLON_4220.data.u8[3] = (system_max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[2] = (system_max_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[3] = (system_max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4220.data.u8[2] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
PYLON_4220.data.u8[3] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
PYLON_4221.data.u8[2] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
PYLON_4221.data.u8[3] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
#endif
|
||||
|
||||
//In case we run into any errors/faults, we can set charge / discharge forbidden
|
||||
if (system_bms_status == FAULT) {
|
||||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
PYLON_4280.data.u8[0] = 0xAA;
|
||||
PYLON_4280.data.u8[1] = 0xAA;
|
||||
PYLON_4280.data.u8[2] = 0xAA;
|
||||
|
|
|
@ -1,33 +1,10 @@
|
|||
#ifndef PYLON_CAN_H
|
||||
#define PYLON_CAN_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define INVERTER_SELECTED
|
||||
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void update_values_can_pylon();
|
||||
void receive_can_pylon(CAN_frame_t rx_frame);
|
||||
void send_system_data();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../include.h"
|
||||
#ifdef SERIAL_LINK_TRANSMITTER
|
||||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "SERIAL-LINK-TRANSMITTER-INVERTER.h"
|
||||
|
||||
|
@ -25,7 +26,7 @@ SerialDataLink dataLinkTransmit(Serial2, 0x01, 0, BATTERY_SEND_NUM_VARIABLES, re
|
|||
void printSendingValues();
|
||||
|
||||
void _getData() {
|
||||
inverterAllowsContactorClosing = dataLinkTransmit.getReceivedData(0);
|
||||
datalayer.system.status.inverter_allows_contactor_closing = dataLinkTransmit.getReceivedData(0);
|
||||
//var2 = dataLinkTransmit.getReceivedData(1); // For future expansion,
|
||||
//var3 = dataLinkTransmit.getReceivedData(2); // if inverter needs to send data to battery
|
||||
}
|
||||
|
@ -107,8 +108,8 @@ void manageSerialLinkTransmitter() {
|
|||
Serial.println("SerialDataLink : max_target_discharge_power = 0");
|
||||
Serial.println("SerialDataLink : max_target_charge_power = 0");
|
||||
|
||||
system_max_discharge_power_W = 0;
|
||||
system_max_charge_power_W = 0;
|
||||
datalayer.battery.status.max_discharge_power_W = 0;
|
||||
datalayer.battery.status.max_charge_power_W = 0;
|
||||
set_event(EVENT_SERIAL_TX_FAILURE, 0);
|
||||
// throw error
|
||||
}
|
||||
|
@ -128,22 +129,24 @@ void manageSerialLinkTransmitter() {
|
|||
|
||||
if (currentTime - updateDataTime > INTERVAL_1_S) {
|
||||
updateDataTime = currentTime;
|
||||
dataLinkTransmit.updateData(0, system_real_SOC_pptt);
|
||||
dataLinkTransmit.updateData(1, system_SOH_pptt);
|
||||
dataLinkTransmit.updateData(2, system_battery_voltage_dV);
|
||||
dataLinkTransmit.updateData(3, system_battery_current_dA);
|
||||
dataLinkTransmit.updateData(4, system_capacity_Wh / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(5, system_remaining_capacity_Wh / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(6, system_max_discharge_power_W / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(7, system_max_charge_power_W / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(8, system_bms_status);
|
||||
dataLinkTransmit.updateData(9, system_active_power_W / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(10, system_temperature_min_dC);
|
||||
dataLinkTransmit.updateData(11, system_temperature_max_dC);
|
||||
dataLinkTransmit.updateData(12, system_cell_max_voltage_mV);
|
||||
dataLinkTransmit.updateData(13, system_cell_min_voltage_mV);
|
||||
dataLinkTransmit.updateData(14, (int16_t)system_LFP_Chemistry);
|
||||
dataLinkTransmit.updateData(15, batteryAllowsContactorClosing);
|
||||
dataLinkTransmit.updateData(0, datalayer.battery.status.real_soc);
|
||||
dataLinkTransmit.updateData(1, datalayer.battery.status.soh_pptt);
|
||||
dataLinkTransmit.updateData(2, datalayer.battery.status.voltage_dV);
|
||||
dataLinkTransmit.updateData(3, datalayer.battery.status.current_dA);
|
||||
dataLinkTransmit.updateData(4, datalayer.battery.info.total_capacity_Wh / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(5,
|
||||
datalayer.battery.status.remaining_capacity_Wh / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(6,
|
||||
datalayer.battery.status.max_discharge_power_W / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(7, datalayer.battery.status.max_charge_power_W / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(8, datalayer.battery.status.bms_status);
|
||||
dataLinkTransmit.updateData(9, datalayer.battery.status.active_power_W / 10); //u32, remove .0 to fit 16bit
|
||||
dataLinkTransmit.updateData(10, datalayer.battery.status.temperature_min_dC);
|
||||
dataLinkTransmit.updateData(11, datalayer.battery.status.temperature_max_dC);
|
||||
dataLinkTransmit.updateData(12, datalayer.battery.status.cell_max_voltage_mV);
|
||||
dataLinkTransmit.updateData(13, datalayer.battery.status.cell_min_voltage_mV);
|
||||
dataLinkTransmit.updateData(14, (int16_t)datalayer.battery.info.chemistry);
|
||||
dataLinkTransmit.updateData(15, datalayer.system.status.battery_allows_contactor_closing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,39 +154,39 @@ void manageSerialLinkTransmitter() {
|
|||
void printSendingValues() {
|
||||
Serial.println("Values from battery: ");
|
||||
Serial.print("SOC: ");
|
||||
Serial.print(system_real_SOC_pptt);
|
||||
Serial.print(datalayer.battery.status.real_soc);
|
||||
Serial.print(" SOH: ");
|
||||
Serial.print(system_SOH_pptt);
|
||||
Serial.print(datalayer.battery.status.soh_pptt);
|
||||
Serial.print(" Voltage: ");
|
||||
Serial.print(system_battery_voltage_dV);
|
||||
Serial.print(datalayer.battery.status.voltage_dV);
|
||||
Serial.print(" Current: ");
|
||||
Serial.print(system_battery_current_dA);
|
||||
Serial.print(datalayer.battery.status.current_dA);
|
||||
Serial.print(" Capacity: ");
|
||||
Serial.print(system_capacity_Wh);
|
||||
Serial.print(datalayer.battery.info.total_capacity_Wh);
|
||||
Serial.print(" Remain cap: ");
|
||||
Serial.print(system_remaining_capacity_Wh);
|
||||
Serial.print(datalayer.battery.status.remaining_capacity_Wh);
|
||||
Serial.print(" Max discharge W: ");
|
||||
Serial.print(system_max_discharge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_discharge_power_W);
|
||||
Serial.print(" Max charge W: ");
|
||||
Serial.print(system_max_charge_power_W);
|
||||
Serial.print(datalayer.battery.status.max_charge_power_W);
|
||||
Serial.print(" BMS status: ");
|
||||
Serial.print(system_bms_status);
|
||||
Serial.print(datalayer.battery.status.bms_status);
|
||||
Serial.print(" Power: ");
|
||||
Serial.print(system_active_power_W);
|
||||
Serial.print(datalayer.battery.status.active_power_W);
|
||||
Serial.print(" Temp min: ");
|
||||
Serial.print(system_temperature_min_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_min_dC);
|
||||
Serial.print(" Temp max: ");
|
||||
Serial.print(system_temperature_max_dC);
|
||||
Serial.print(datalayer.battery.status.temperature_max_dC);
|
||||
Serial.print(" Cell max: ");
|
||||
Serial.print(system_cell_max_voltage_mV);
|
||||
Serial.print(datalayer.battery.status.cell_max_voltage_mV);
|
||||
Serial.print(" Cell min: ");
|
||||
Serial.print(system_cell_min_voltage_mV);
|
||||
Serial.print(datalayer.battery.status.cell_min_voltage_mV);
|
||||
Serial.print(" LFP : ");
|
||||
Serial.print(system_LFP_Chemistry);
|
||||
Serial.print(" batteryAllowsContactorClosing: ");
|
||||
Serial.print(batteryAllowsContactorClosing);
|
||||
Serial.print(" inverterAllowsContactorClosing: ");
|
||||
Serial.print(inverterAllowsContactorClosing);
|
||||
Serial.print(datalayer.battery.info.chemistry);
|
||||
Serial.print(" Battery Allows Contactor Closing: ");
|
||||
Serial.print(datalayer.system.status.battery_allows_contactor_closing);
|
||||
Serial.print(" Inverter Allows Contactor Closing: ");
|
||||
Serial.print(datalayer.system.status.inverter_allows_contactor_closing);
|
||||
|
||||
Serial.println("");
|
||||
}
|
||||
|
|
|
@ -7,27 +7,6 @@
|
|||
|
||||
#define INVERTER_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool system_LFP_Chemistry; //Bool, true/false
|
||||
|
||||
// parameters received from receiver
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void manageSerialLinkTransmitter();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef SMA_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "SMA-CAN.h"
|
||||
|
@ -104,36 +105,42 @@ static uint16_t ampere_hours_remaining = 0;
|
|||
|
||||
void update_values_can_sma() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
//Calculate values
|
||||
charge_current = ((system_max_charge_power_W * 10) /
|
||||
system_max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
charge_current =
|
||||
((datalayer.battery.status.max_charge_power_W * 10) /
|
||||
datalayer.battery.info.max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
//The above calculation results in (30 000*10)/3700=81A
|
||||
charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A)
|
||||
if (charge_current > MAXCHARGEAMP) {
|
||||
charge_current = MAXCHARGEAMP; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
if (charge_current > datalayer.battery.info.max_charge_amp_dA) {
|
||||
charge_current =
|
||||
datalayer.battery.info
|
||||
.max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
}
|
||||
|
||||
discharge_current = ((system_max_discharge_power_W * 10) /
|
||||
system_max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
discharge_current =
|
||||
((datalayer.battery.status.max_discharge_power_W * 10) /
|
||||
datalayer.battery.info.max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
//The above calculation results in (30 000*10)/3700=81A
|
||||
discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A)
|
||||
if (discharge_current > MAXDISCHARGEAMP) {
|
||||
if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) {
|
||||
discharge_current =
|
||||
MAXDISCHARGEAMP; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
datalayer.battery.info
|
||||
.max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
}
|
||||
|
||||
temperature_average = ((system_temperature_max_dC + system_temperature_min_dC) / 2);
|
||||
temperature_average =
|
||||
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
|
||||
|
||||
ampere_hours_remaining =
|
||||
((system_remaining_capacity_Wh / system_battery_voltage_dV) * 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
|
||||
ampere_hours_remaining = ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
|
||||
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
|
||||
|
||||
//Map values to CAN messages
|
||||
//Maxvoltage (eg 400.0V = 4000 , 16bits long)
|
||||
SMA_358.data.u8[0] = (system_max_design_voltage_dV >> 8);
|
||||
SMA_358.data.u8[1] = (system_max_design_voltage_dV & 0x00FF);
|
||||
SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
//Minvoltage (eg 300.0V = 3000 , 16bits long)
|
||||
SMA_358.data.u8[2] =
|
||||
(system_min_design_voltage_dV >> 8); //Minvoltage behaves strange on SMA, cuts out at 56% of the set value?
|
||||
SMA_358.data.u8[3] = (system_min_design_voltage_dV & 0x00FF);
|
||||
SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >>
|
||||
8); //Minvoltage behaves strange on SMA, cuts out at 56% of the set value?
|
||||
SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
//Discharge limited current, 500 = 50A, (0.1, A)
|
||||
SMA_358.data.u8[4] = (discharge_current >> 8);
|
||||
SMA_358.data.u8[5] = (discharge_current & 0x00FF);
|
||||
|
@ -142,26 +149,26 @@ void update_values_can_sma() { //This function maps all the values fetched from
|
|||
SMA_358.data.u8[7] = (charge_current & 0x00FF);
|
||||
|
||||
//SOC (100.00%)
|
||||
SMA_3D8.data.u8[0] = (system_scaled_SOC_pptt >> 8);
|
||||
SMA_3D8.data.u8[1] = (system_scaled_SOC_pptt & 0x00FF);
|
||||
SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8);
|
||||
SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF);
|
||||
//StateOfHealth (100.00%)
|
||||
SMA_3D8.data.u8[2] = (system_SOH_pptt >> 8);
|
||||
SMA_3D8.data.u8[3] = (system_SOH_pptt & 0x00FF);
|
||||
SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8);
|
||||
SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF);
|
||||
//State of charge (AH, 0.1)
|
||||
SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8);
|
||||
SMA_3D8.data.u8[5] = (ampere_hours_remaining & 0x00FF);
|
||||
|
||||
//Voltage (370.0)
|
||||
SMA_4D8.data.u8[0] = (system_battery_voltage_dV >> 8);
|
||||
SMA_4D8.data.u8[1] = (system_battery_voltage_dV & 0x00FF);
|
||||
SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
//Current (TODO: signed OK?)
|
||||
SMA_4D8.data.u8[2] = (system_battery_current_dA >> 8);
|
||||
SMA_4D8.data.u8[3] = (system_battery_current_dA & 0x00FF);
|
||||
SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
//Temperature average
|
||||
SMA_4D8.data.u8[4] = (temperature_average >> 8);
|
||||
SMA_4D8.data.u8[5] = (temperature_average & 0x00FF);
|
||||
//Battery ready
|
||||
if (system_bms_status == ACTIVE) {
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
SMA_4D8.data.u8[6] = READY_STATE;
|
||||
} else {
|
||||
SMA_4D8.data.u8[6] = STOP_STATE;
|
||||
|
|
|
@ -1,33 +1,10 @@
|
|||
#ifndef SMA_CAN_H
|
||||
#define SMA_CAN_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define INVERTER_SELECTED
|
||||
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
#define READY_STATE 0x03
|
||||
#define STOP_STATE 0x02
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef SMA_TRIPOWER_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "SMA-TRIPOWER-CAN.h"
|
||||
|
@ -162,29 +163,35 @@ InvInitState invInitState = SYSTEM_FREQUENCY;
|
|||
|
||||
void update_values_can_sma_tripower() { //This function maps all the values fetched from battery CAN to the inverter CAN
|
||||
//Calculate values
|
||||
charge_current = ((system_max_charge_power_W * 10) /
|
||||
system_max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
charge_current =
|
||||
((datalayer.battery.status.max_charge_power_W * 10) /
|
||||
datalayer.battery.info.max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
//The above calculation results in (30 000*10)/3700=81A
|
||||
charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A)
|
||||
if (charge_current > MAXCHARGEAMP) {
|
||||
charge_current = MAXCHARGEAMP; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
if (charge_current > datalayer.battery.info.max_charge_amp_dA) {
|
||||
charge_current =
|
||||
datalayer.battery.info
|
||||
.max_charge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
}
|
||||
|
||||
discharge_current = ((system_max_discharge_power_W * 10) /
|
||||
system_max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
discharge_current =
|
||||
((datalayer.battery.status.max_discharge_power_W * 10) /
|
||||
datalayer.battery.info.max_design_voltage_dV); //Charge power in W , max volt in V+1decimal (P=UI, solve for I)
|
||||
//The above calculation results in (30 000*10)/3700=81A
|
||||
discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A)
|
||||
if (discharge_current > MAXDISCHARGEAMP) {
|
||||
if (discharge_current > datalayer.battery.info.max_discharge_amp_dA) {
|
||||
discharge_current =
|
||||
MAXDISCHARGEAMP; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
datalayer.battery.info
|
||||
.max_discharge_amp_dA; //Cap the value to the max allowed Amp. Some inverters cannot handle large values.
|
||||
}
|
||||
|
||||
temperature_average = ((system_temperature_max_dC + system_temperature_min_dC) / 2);
|
||||
temperature_average =
|
||||
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
|
||||
|
||||
ampere_hours_remaining =
|
||||
((system_remaining_capacity_Wh / system_battery_voltage_dV) * 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
|
||||
ampere_hours_max =
|
||||
((system_capacity_Wh / system_battery_voltage_dV) * 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
|
||||
ampere_hours_remaining = ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
|
||||
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
|
||||
ampere_hours_max = ((datalayer.battery.info.total_capacity_Wh / datalayer.battery.status.voltage_dV) *
|
||||
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
|
||||
|
||||
batteryState = OPERATE;
|
||||
inverterControlFlags = INVERTER_STAY_ON;
|
||||
|
@ -192,11 +199,11 @@ void update_values_can_sma_tripower() { //This function maps all the values fet
|
|||
//Map values to CAN messages
|
||||
// Battery Limits
|
||||
//Battery Max Charge Voltage (eg 400.0V = 4000 , 16bits long)
|
||||
SMA_00D.data.u8[0] = (system_max_design_voltage_dV >> 8);
|
||||
SMA_00D.data.u8[1] = (system_max_design_voltage_dV & 0x00FF);
|
||||
SMA_00D.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
SMA_00D.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
//Battery Min Discharge Voltage (eg 300.0V = 3000 , 16bits long)
|
||||
SMA_00D.data.u8[2] = (system_min_design_voltage_dV >> 8);
|
||||
SMA_00D.data.u8[3] = (system_min_design_voltage_dV & 0x00FF);
|
||||
SMA_00D.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
SMA_00D.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
//Discharge limited current, 500 = 50A, (0.1, A)
|
||||
SMA_00D.data.u8[4] = (discharge_current >> 8);
|
||||
SMA_00D.data.u8[5] = (discharge_current & 0x00FF);
|
||||
|
@ -206,11 +213,11 @@ void update_values_can_sma_tripower() { //This function maps all the values fet
|
|||
|
||||
// Battery State
|
||||
//SOC (100.00%)
|
||||
SMA_00F.data.u8[0] = (system_scaled_SOC_pptt >> 8);
|
||||
SMA_00F.data.u8[1] = (system_scaled_SOC_pptt & 0x00FF);
|
||||
SMA_00F.data.u8[0] = (datalayer.battery.status.reported_soc >> 8);
|
||||
SMA_00F.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF);
|
||||
//StateOfHealth (100.00%)
|
||||
SMA_00F.data.u8[2] = (system_SOH_pptt >> 8);
|
||||
SMA_00F.data.u8[3] = (system_SOH_pptt & 0x00FF);
|
||||
SMA_00F.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8);
|
||||
SMA_00F.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF);
|
||||
//State of charge (AH, 0.1)
|
||||
SMA_00F.data.u8[4] = (ampere_hours_remaining >> 8);
|
||||
SMA_00F.data.u8[5] = (ampere_hours_remaining & 0x00FF);
|
||||
|
@ -232,11 +239,11 @@ void update_values_can_sma_tripower() { //This function maps all the values fet
|
|||
|
||||
// Battery Measurements
|
||||
//Voltage (370.0)
|
||||
SMA_013.data.u8[0] = (system_battery_voltage_dV >> 8);
|
||||
SMA_013.data.u8[1] = (system_battery_voltage_dV & 0x00FF);
|
||||
SMA_013.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
SMA_013.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
//Current (TODO: signed OK?)
|
||||
SMA_013.data.u8[2] = (system_battery_current_dA >> 8);
|
||||
SMA_013.data.u8[3] = (system_battery_current_dA & 0x00FF);
|
||||
SMA_013.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
SMA_013.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
//Temperature average
|
||||
SMA_013.data.u8[4] = (temperature_average >> 8);
|
||||
SMA_013.data.u8[5] = (temperature_average & 0x00FF);
|
||||
|
@ -246,11 +253,11 @@ void update_values_can_sma_tripower() { //This function maps all the values fet
|
|||
|
||||
// Battery Temperature and Cellvoltages
|
||||
// Battery max temperature
|
||||
SMA_014.data.u8[0] = (system_temperature_max_dC >> 8);
|
||||
SMA_014.data.u8[1] = (system_temperature_max_dC & 0x00FF);
|
||||
SMA_014.data.u8[0] = (datalayer.battery.status.temperature_max_dC >> 8);
|
||||
SMA_014.data.u8[1] = (datalayer.battery.status.temperature_max_dC & 0x00FF);
|
||||
// Battery min temperature
|
||||
SMA_014.data.u8[2] = (system_temperature_min_dC >> 8);
|
||||
SMA_014.data.u8[3] = (system_temperature_min_dC & 0x00FF);
|
||||
SMA_014.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8);
|
||||
SMA_014.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF);
|
||||
// Battery Cell Voltage (sum)
|
||||
//SMA_014.data.u8[4] = (??? >> 8); //TODO scaling?
|
||||
//SMA_014.data.u8[5] = (??? & 0x00FF); //TODO scaling?
|
||||
|
|
|
@ -1,33 +1,10 @@
|
|||
#ifndef SMA_CAN_TRIPOWER_H
|
||||
#define SMA_CAN_TRIPOWER_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define INVERTER_SELECTED
|
||||
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
void update_values_can_sma_tripower();
|
||||
void send_can_sma_tripower();
|
||||
void receive_can_sma_tripower(CAN_frame_t rx_frame);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef SOFAR_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "SOFAR-CAN.h"
|
||||
|
@ -282,29 +283,29 @@ CAN_frame_t SOFAR_7C0 = {.FIR = {.B =
|
|||
void update_values_can_sofar() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
|
||||
//Maxvoltage (eg 400.0V = 4000 , 16bits long) Charge Cutoff Voltage
|
||||
SOFAR_351.data.u8[0] = (system_max_design_voltage_dV >> 8);
|
||||
SOFAR_351.data.u8[1] = (system_max_design_voltage_dV & 0x00FF);
|
||||
SOFAR_351.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
SOFAR_351.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
//SOFAR_351.data.u8[2] = DC charge current limitation (Default 25.0A)
|
||||
//SOFAR_351.data.u8[3] = DC charge current limitation
|
||||
//SOFAR_351.data.u8[4] = DC discharge current limitation (Default 25.0A)
|
||||
//SOFAR_351.data.u8[5] = DC discharge current limitation
|
||||
//Minvoltage (eg 300.0V = 3000 , 16bits long) Discharge Cutoff Voltage
|
||||
SOFAR_351.data.u8[6] = (system_min_design_voltage_dV >> 8);
|
||||
SOFAR_351.data.u8[7] = (system_min_design_voltage_dV & 0x00FF);
|
||||
SOFAR_351.data.u8[6] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
SOFAR_351.data.u8[7] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
|
||||
//SOC
|
||||
SOFAR_355.data.u8[0] = (system_scaled_SOC_pptt / 100);
|
||||
SOFAR_355.data.u8[2] = (system_SOH_pptt / 100);
|
||||
SOFAR_355.data.u8[0] = (datalayer.battery.status.reported_soc / 100);
|
||||
SOFAR_355.data.u8[2] = (datalayer.battery.status.soh_pptt / 100);
|
||||
//SOFAR_355.data.u8[6] = (AH_remaining >> 8);
|
||||
//SOFAR_355.data.u8[7] = (AH_remaining & 0x00FF);
|
||||
|
||||
//Voltage (370.0)
|
||||
SOFAR_356.data.u8[0] = (system_battery_voltage_dV >> 8);
|
||||
SOFAR_356.data.u8[1] = (system_battery_voltage_dV & 0x00FF);
|
||||
SOFAR_356.data.u8[2] = (system_battery_current_dA >> 8);
|
||||
SOFAR_356.data.u8[3] = (system_battery_current_dA & 0x00FF);
|
||||
SOFAR_356.data.u8[2] = (system_temperature_max_dC >> 8);
|
||||
SOFAR_356.data.u8[3] = (system_temperature_max_dC & 0x00FF);
|
||||
SOFAR_356.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
SOFAR_356.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
SOFAR_356.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
SOFAR_356.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
SOFAR_356.data.u8[2] = (datalayer.battery.status.temperature_max_dC >> 8);
|
||||
SOFAR_356.data.u8[3] = (datalayer.battery.status.temperature_max_dC & 0x00FF);
|
||||
}
|
||||
|
||||
void receive_can_sofar(CAN_frame_t rx_frame) {
|
||||
|
|
|
@ -1,37 +1,10 @@
|
|||
#ifndef SOFAR_CAN_H
|
||||
#define SOFAR_CAN_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
#define INVERTER_SELECTED
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
extern uint16_t min_voltage;
|
||||
extern uint16_t max_voltage;
|
||||
|
||||
void update_values_can_sofar();
|
||||
void send_can_sofar();
|
||||
void receive_can_sofar(CAN_frame_t rx_frame);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef SOLAX_CAN
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "SOLAX-CAN.h"
|
||||
|
||||
|
@ -123,7 +124,7 @@ void CAN_WriteFrame(CAN_frame_t* tx_frame) {
|
|||
void update_values_can_solax() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
// If not receiveing any communication from the inverter, open contactors and return to battery announce state
|
||||
if (millis() - LastFrameTime >= SolaxTimeout) {
|
||||
inverterAllowsContactorClosing = false;
|
||||
datalayer.system.status.inverter_allows_contactor_closing = false;
|
||||
STATE = BATTERY_ANNOUNCE;
|
||||
#ifndef DUAL_CAN
|
||||
ESP32Can.CANStop(); // Baud rate switching might have taken down the interface. Reboot it!
|
||||
|
@ -131,75 +132,78 @@ void update_values_can_solax() { //This function maps all the values fetched fr
|
|||
#endif
|
||||
}
|
||||
//Calculate the required values
|
||||
temperature_average = ((system_temperature_max_dC + system_temperature_min_dC) / 2);
|
||||
temperature_average =
|
||||
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
|
||||
|
||||
//system_max_charge_power_W (30000W max)
|
||||
if (system_scaled_SOC_pptt > 9999) //99.99%
|
||||
//datalayer.battery.status.max_charge_power_W (30000W max)
|
||||
if (datalayer.battery.status.reported_soc > 9999) //99.99%
|
||||
{ //Additional safety incase SOC% is 100, then do not charge battery further
|
||||
max_charge_rate_amp = 0;
|
||||
} else { //We can pass on the battery charge rate (in W) to the inverter (that takes A)
|
||||
if (system_max_charge_power_W >= 30000) {
|
||||
if (datalayer.battery.status.max_charge_power_W >= 30000) {
|
||||
max_charge_rate_amp = 75; //Incase battery can take over 30kW, cap value to 75A
|
||||
} else { //Calculate the W value into A
|
||||
max_charge_rate_amp = (system_max_charge_power_W / (system_battery_voltage_dV * 0.1)); // P/U = I
|
||||
max_charge_rate_amp =
|
||||
(datalayer.battery.status.max_charge_power_W / (datalayer.battery.status.voltage_dV * 0.1)); // P/U = I
|
||||
}
|
||||
}
|
||||
|
||||
//system_max_discharge_power_W (30000W max)
|
||||
if (system_scaled_SOC_pptt < 100) //1.00%
|
||||
//datalayer.battery.status.max_discharge_power_W (30000W max)
|
||||
if (datalayer.battery.status.reported_soc < 100) //1.00%
|
||||
{ //Additional safety incase SOC% is below 1, then do not charge battery further
|
||||
max_discharge_rate_amp = 0;
|
||||
} else { //We can pass on the battery discharge rate to the inverter
|
||||
if (system_max_discharge_power_W >= 30000) {
|
||||
if (datalayer.battery.status.max_discharge_power_W >= 30000) {
|
||||
max_discharge_rate_amp = 75; //Incase battery can be charged with over 30kW, cap value to 75A
|
||||
} else { //Calculate the W value into A
|
||||
max_discharge_rate_amp = (system_max_discharge_power_W / (system_battery_voltage_dV * 0.1)); // P/U = I
|
||||
max_discharge_rate_amp =
|
||||
(datalayer.battery.status.max_discharge_power_W / (datalayer.battery.status.voltage_dV * 0.1)); // P/U = I
|
||||
}
|
||||
}
|
||||
|
||||
// Batteries might be larger than uint16_t value can take
|
||||
if (system_capacity_Wh > 65000) {
|
||||
if (datalayer.battery.info.total_capacity_Wh > 65000) {
|
||||
capped_capacity_Wh = 65000;
|
||||
} else {
|
||||
capped_capacity_Wh = system_capacity_Wh;
|
||||
capped_capacity_Wh = datalayer.battery.info.total_capacity_Wh;
|
||||
}
|
||||
// Batteries might be larger than uint16_t value can take
|
||||
if (system_remaining_capacity_Wh > 65000) {
|
||||
if (datalayer.battery.status.remaining_capacity_Wh > 65000) {
|
||||
capped_remaining_capacity_Wh = 65000;
|
||||
} else {
|
||||
capped_remaining_capacity_Wh = system_remaining_capacity_Wh;
|
||||
capped_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
|
||||
}
|
||||
|
||||
//Put the values into the CAN messages
|
||||
//BMS_Limits
|
||||
SOLAX_1872.data.u8[0] = (uint8_t)system_max_design_voltage_dV;
|
||||
SOLAX_1872.data.u8[1] = (system_max_design_voltage_dV >> 8);
|
||||
SOLAX_1872.data.u8[2] = (uint8_t)system_min_design_voltage_dV;
|
||||
SOLAX_1872.data.u8[3] = (system_min_design_voltage_dV >> 8);
|
||||
SOLAX_1872.data.u8[0] = (uint8_t)datalayer.battery.info.max_design_voltage_dV;
|
||||
SOLAX_1872.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
SOLAX_1872.data.u8[2] = (uint8_t)datalayer.battery.info.min_design_voltage_dV;
|
||||
SOLAX_1872.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
SOLAX_1872.data.u8[4] = (uint8_t)(max_charge_rate_amp * 10);
|
||||
SOLAX_1872.data.u8[5] = ((max_charge_rate_amp * 10) >> 8);
|
||||
SOLAX_1872.data.u8[6] = (uint8_t)(max_discharge_rate_amp * 10);
|
||||
SOLAX_1872.data.u8[7] = ((max_discharge_rate_amp * 10) >> 8);
|
||||
|
||||
//BMS_PackData
|
||||
SOLAX_1873.data.u8[0] = (uint8_t)system_battery_voltage_dV; // OK
|
||||
SOLAX_1873.data.u8[1] = (system_battery_voltage_dV >> 8);
|
||||
SOLAX_1873.data.u8[2] = (int8_t)system_battery_current_dA; // OK, Signed (Active current in Amps x 10)
|
||||
SOLAX_1873.data.u8[3] = (system_battery_current_dA >> 8);
|
||||
SOLAX_1873.data.u8[4] = (uint8_t)(system_scaled_SOC_pptt / 100); //SOC (100.00%)
|
||||
SOLAX_1873.data.u8[0] = (uint8_t)datalayer.battery.status.voltage_dV; // OK
|
||||
SOLAX_1873.data.u8[1] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
SOLAX_1873.data.u8[2] = (int8_t)datalayer.battery.status.current_dA; // OK, Signed (Active current in Amps x 10)
|
||||
SOLAX_1873.data.u8[3] = (datalayer.battery.status.current_dA >> 8);
|
||||
SOLAX_1873.data.u8[4] = (uint8_t)(datalayer.battery.status.reported_soc / 100); //SOC (100.00%)
|
||||
//SOLAX_1873.data.u8[5] = //Seems like this is not required? Or shall we put SOC decimals here?
|
||||
SOLAX_1873.data.u8[6] = (uint8_t)(capped_remaining_capacity_Wh / 100);
|
||||
SOLAX_1873.data.u8[7] = ((capped_remaining_capacity_Wh / 100) >> 8);
|
||||
|
||||
//BMS_CellData
|
||||
SOLAX_1874.data.u8[0] = (int8_t)system_temperature_max_dC;
|
||||
SOLAX_1874.data.u8[1] = (system_temperature_max_dC >> 8);
|
||||
SOLAX_1874.data.u8[2] = (int8_t)system_temperature_min_dC;
|
||||
SOLAX_1874.data.u8[3] = (system_temperature_min_dC >> 8);
|
||||
SOLAX_1874.data.u8[4] = (uint8_t)(system_cell_max_voltage_mV);
|
||||
SOLAX_1874.data.u8[5] = (system_cell_max_voltage_mV >> 8);
|
||||
SOLAX_1874.data.u8[6] = (uint8_t)(system_cell_min_voltage_mV);
|
||||
SOLAX_1874.data.u8[7] = (system_cell_min_voltage_mV >> 8);
|
||||
SOLAX_1874.data.u8[0] = (int8_t)datalayer.battery.status.temperature_max_dC;
|
||||
SOLAX_1874.data.u8[1] = (datalayer.battery.status.temperature_max_dC >> 8);
|
||||
SOLAX_1874.data.u8[2] = (int8_t)datalayer.battery.status.temperature_min_dC;
|
||||
SOLAX_1874.data.u8[3] = (datalayer.battery.status.temperature_min_dC >> 8);
|
||||
SOLAX_1874.data.u8[4] = (uint8_t)(datalayer.battery.status.cell_max_voltage_mV);
|
||||
SOLAX_1874.data.u8[5] = (datalayer.battery.status.cell_max_voltage_mV >> 8);
|
||||
SOLAX_1874.data.u8[6] = (uint8_t)(datalayer.battery.status.cell_min_voltage_mV);
|
||||
SOLAX_1874.data.u8[7] = (datalayer.battery.status.cell_min_voltage_mV >> 8);
|
||||
|
||||
//BMS_Status
|
||||
SOLAX_1875.data.u8[0] = (uint8_t)temperature_average;
|
||||
|
@ -208,11 +212,11 @@ void update_values_can_solax() { //This function maps all the values fetched fr
|
|||
SOLAX_1875.data.u8[4] = (uint8_t)0; // Contactor Status 0=off, 1=on.
|
||||
|
||||
//BMS_PackTemps (strange name, since it has voltages?)
|
||||
SOLAX_1876.data.u8[2] = (uint8_t)system_cell_max_voltage_mV;
|
||||
SOLAX_1876.data.u8[3] = (system_cell_max_voltage_mV >> 8);
|
||||
SOLAX_1876.data.u8[2] = (uint8_t)datalayer.battery.status.cell_max_voltage_mV;
|
||||
SOLAX_1876.data.u8[3] = (datalayer.battery.status.cell_max_voltage_mV >> 8);
|
||||
|
||||
SOLAX_1876.data.u8[6] = (uint8_t)system_cell_min_voltage_mV;
|
||||
SOLAX_1876.data.u8[7] = (system_cell_min_voltage_mV >> 8);
|
||||
SOLAX_1876.data.u8[6] = (uint8_t)datalayer.battery.status.cell_min_voltage_mV;
|
||||
SOLAX_1876.data.u8[7] = (datalayer.battery.status.cell_min_voltage_mV >> 8);
|
||||
|
||||
//Unknown
|
||||
SOLAX_1877.data.u8[4] = (uint8_t)0x50; // Battery type
|
||||
|
@ -221,8 +225,8 @@ void update_values_can_solax() { //This function maps all the values fetched fr
|
|||
(uint8_t)0x02; // The above firmware version applies to:02 = Master BMS, 10 = S1, 20 = S2, 30 = S3, 40 = S4
|
||||
|
||||
//BMS_PackStats
|
||||
SOLAX_1878.data.u8[0] = (uint8_t)(system_battery_voltage_dV);
|
||||
SOLAX_1878.data.u8[1] = ((system_battery_voltage_dV) >> 8);
|
||||
SOLAX_1878.data.u8[0] = (uint8_t)(datalayer.battery.status.voltage_dV);
|
||||
SOLAX_1878.data.u8[1] = ((datalayer.battery.status.voltage_dV) >> 8);
|
||||
|
||||
SOLAX_1878.data.u8[4] = (uint8_t)capped_capacity_Wh;
|
||||
SOLAX_1878.data.u8[5] = (capped_capacity_Wh >> 8);
|
||||
|
@ -242,7 +246,7 @@ void receive_can_solax(CAN_frame_t rx_frame) {
|
|||
#ifdef DEBUG_VIA_USB
|
||||
Serial.println("Solax Battery State: Announce");
|
||||
#endif
|
||||
inverterAllowsContactorClosing = false;
|
||||
datalayer.system.status.inverter_allows_contactor_closing = false;
|
||||
SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on.
|
||||
for (int i = 0; i <= number_of_batteries; i++) {
|
||||
CAN_WriteFrame(&SOLAX_1872);
|
||||
|
@ -277,7 +281,7 @@ void receive_can_solax(CAN_frame_t rx_frame) {
|
|||
break;
|
||||
|
||||
case (CONTACTOR_CLOSED):
|
||||
inverterAllowsContactorClosing = true;
|
||||
datalayer.system.status.inverter_allows_contactor_closing = true;
|
||||
SOLAX_1875.data.u8[4] = (0x01); // Inform Inverter: Contactor 0=off, 1=on.
|
||||
CAN_WriteFrame(&SOLAX_1872);
|
||||
CAN_WriteFrame(&SOLAX_1873);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef SOLAX_CAN_H
|
||||
#define SOLAX_CAN_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "../lib/pierremolinaro-acan2515/ACAN2515.h"
|
||||
|
@ -9,28 +8,6 @@
|
|||
|
||||
extern ACAN2515 can;
|
||||
|
||||
extern uint32_t system_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern uint32_t system_remaining_capacity_Wh; //Wh, 0-500000Wh
|
||||
extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0
|
||||
extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0
|
||||
extern int32_t system_active_power_W; //W, -200000 to 200000
|
||||
extern int16_t system_battery_current_dA; //A+1, -1000 - 1000
|
||||
extern uint16_t system_battery_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_max_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_min_design_voltage_dV; //V+1, 0-1000.0 (0-10000)
|
||||
extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint32_t system_max_discharge_power_W; //W, 0-200000
|
||||
extern uint32_t system_max_charge_power_W; //W, 0-200000
|
||||
extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value
|
||||
extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value
|
||||
extern uint16_t system_cellvoltages_mV[MAX_AMOUNT_CELLS]; //Array with all cell voltages in mV
|
||||
extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery
|
||||
extern uint8_t system_bms_status; //Enum 0-5
|
||||
extern bool batteryAllowsContactorClosing; //Bool, true/false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, true/false
|
||||
|
||||
// Timeout in milliseconds
|
||||
#define SolaxTimeout 2000
|
||||
|
||||
|
|
|
@ -218,7 +218,7 @@ static bool _start_async_task(){
|
|||
return false;
|
||||
}
|
||||
if(!_async_service_task_handle){
|
||||
xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
|
||||
xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
|
||||
if(!_async_service_task_handle){
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,13 @@ extern "C" {
|
|||
#include "lwip/pbuf.h"
|
||||
}
|
||||
|
||||
#include "../../../system_settings.h"
|
||||
#include "../../../devboard/hal/hal.h"
|
||||
|
||||
//If core is not defined, then we are running in Arduino or PIO
|
||||
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
|
||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE 0 //any available core
|
||||
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
|
||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE //any available core
|
||||
#define CONFIG_ASYNC_TCP_USE_WDT 0 //if enabled, adds between 33us and 200us per event
|
||||
#endif
|
||||
|
||||
class AsyncClient;
|
||||
|
|
|
@ -9,9 +9,13 @@
|
|||
* Parameter: TASK_CONNECTIVITY_PRIO
|
||||
* Description:
|
||||
* Defines the priority of various wireless functionality (TCP, MQTT, etc)
|
||||
*
|
||||
* Parameter: TASK_MODBUS_PRIO
|
||||
* Description:
|
||||
* Defines the priority of MODBUS handling
|
||||
*/
|
||||
#define TASK_CORE_PRIO 4
|
||||
#define TASK_WIFI_PRIO 3
|
||||
#define TASK_CONNECTIVITY_PRIO 3
|
||||
#define TASK_MODBUS_PRIO 8
|
||||
|
||||
/** MAX AMOUNT OF CELLS
|
||||
|
@ -35,6 +39,11 @@
|
|||
* Description:
|
||||
* The period of whatever LED mode is active. If CLASSIC, then a ramp up and ramp down will finish in
|
||||
* LED_PERIOD_MS milliseconds
|
||||
*
|
||||
* Parameter: LED_EXECUTION_FREQUENCY
|
||||
* Description:
|
||||
* Defines how often the LED handling will run, basically the FPS. The animation will honor its overall
|
||||
* frequency but the animation will be choppier
|
||||
*/
|
||||
#define LED_MODE_DEFAULT FLOW
|
||||
#define LED_PERIOD_MS 3000
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue