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:
Cabooman 2024-04-15 22:26:10 +02:00 committed by GitHub
parent e7f14084e3
commit 0fee07313a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
68 changed files with 1097 additions and 1510 deletions

View file

@ -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%
{ //Additional safety incase SOC% is 100, then do not charge battery further
//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%
{ //Additional safety incase SOC% is below 1, then do not charge battery further
//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);