mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Feature: Add configurable limit to charge/discharge on BYD Modbus (#290)
* Add configurable limit to charge/discharge BYD modbus + optimizations
This commit is contained in:
parent
00e4dde9db
commit
e5c408fb7c
1 changed files with 40 additions and 100 deletions
|
@ -3,6 +3,14 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "BYD-MODBUS.h"
|
||||
|
||||
// For modbus register definitions, see https://gitlab.com/pelle8/inverter_resources/-/blob/main/byd_registers_modbus_rtu.md
|
||||
|
||||
static uint8_t bms_char_dis_status = STANDBY;
|
||||
static uint32_t user_configured_max_discharge_W = 0;
|
||||
static uint32_t user_configured_max_charge_W = 0;
|
||||
static uint32_t max_discharge_W = 0;
|
||||
static uint32_t max_charge_W = 0;
|
||||
|
||||
void update_modbus_registers_inverter() {
|
||||
verify_temperature_modbus();
|
||||
handle_update_data_modbusp201_byd();
|
||||
|
@ -27,46 +35,20 @@ void handle_static_data_modbus_byd() {
|
|||
memcpy(&mbPV[i], data_array_pointers[arr_idx], data_size);
|
||||
i += data_size / sizeof(uint16_t);
|
||||
}
|
||||
static uint16_t init_p201[13] = {0, 0, 0, MAX_POWER, MAX_POWER, 0, 0, 53248, 10, 53248, 10, 0, 0};
|
||||
memcpy(&mbPV[200], init_p201, sizeof(init_p201));
|
||||
static uint16_t init_p301[24] = {0, 0, 128, 0, 0, 0, 0, 0, 0, 2000, 0, 2000,
|
||||
75, 95, 0, 0, 16, 22741, 0, 0, 13, 52064, 230, 9900};
|
||||
memcpy(&mbPV[300], init_p301, sizeof(init_p301));
|
||||
}
|
||||
|
||||
void handle_update_data_modbusp201_byd() {
|
||||
// Store the data into the array
|
||||
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 (datalayer.battery.info.total_capacity_Wh > 60000) {
|
||||
system_data[2] = 60000;
|
||||
} else {
|
||||
system_data[2] =
|
||||
(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] =
|
||||
(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] =
|
||||
(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
|
||||
system_data[9] =
|
||||
53248; // Id.: p210 Value.: 53248 Scaled value.: 53248 Comment.: Always 53248 for this BYD, Peak Discharge power?
|
||||
system_data[10] = 10; // Id.: p211 Value.: 10 Scaled value.: 10 Comment.: Always 10
|
||||
system_data[11] = 0; // Id.: p212 Value.: 0 Scaled value.: 0 Comment.: Always 0
|
||||
system_data[12] = 0; // Id.: p213 Value.: 0 Scaled value.: 0 Comment.: Always 0
|
||||
static uint16_t i = 200;
|
||||
memcpy(&mbPV[i], system_data, sizeof(system_data));
|
||||
mbPV[202] = std::min(datalayer.battery.info.total_capacity_Wh, 60000u); //Cap capacity to 60kWh if needed
|
||||
mbPV[205] = (datalayer.battery.info.max_design_voltage_dV); // Max Voltage, if higher Gen24 forces discharge
|
||||
mbPV[206] = (datalayer.battery.info.min_design_voltage_dV); // Min Voltage, if lower Gen24 disables battery
|
||||
}
|
||||
|
||||
void handle_update_data_modbusp301_byd() {
|
||||
// Store the data into the array
|
||||
static uint16_t battery_data[24];
|
||||
|
||||
static uint8_t bms_char_dis_status = STANDBY;
|
||||
if (datalayer.battery.status.current_dA == 0) {
|
||||
bms_char_dis_status = STANDBY;
|
||||
} else if (datalayer.battery.status.current_dA < 0) { //Negative value = Discharging
|
||||
|
@ -74,76 +56,34 @@ void handle_update_data_modbusp301_byd() {
|
|||
} else { //Positive value = Charging
|
||||
bms_char_dis_status = CHARGING;
|
||||
}
|
||||
// Convert max discharge Amp value to max Watt
|
||||
user_configured_max_discharge_W =
|
||||
((datalayer.battery.info.max_discharge_amp_dA * datalayer.battery.info.max_design_voltage_dV) / 100);
|
||||
// Use the smaller value, battery reported value OR user configured value
|
||||
max_discharge_W = std::min(datalayer.battery.status.max_discharge_power_W, user_configured_max_discharge_W);
|
||||
|
||||
// Convert max charge Amp value to max Watt
|
||||
user_configured_max_charge_W =
|
||||
((datalayer.battery.info.max_charge_amp_dA * datalayer.battery.info.max_design_voltage_dV) / 100);
|
||||
// Use the smaller value, battery reported value OR user configured value
|
||||
max_charge_W = std::min(datalayer.battery.status.max_charge_power_W, user_configured_max_charge_W);
|
||||
|
||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||
battery_data[8] =
|
||||
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
|
||||
mbPV[308] = datalayer.battery.status.voltage_dV;
|
||||
} else {
|
||||
battery_data[8] = 0;
|
||||
mbPV[308] = 0;
|
||||
}
|
||||
battery_data[0] =
|
||||
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] =
|
||||
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] =
|
||||
datalayer.battery.info.total_capacity_Wh; // Id.: p305 Value.: 32000 Scaled value.: 32kWh Comment.: tot cap:
|
||||
}
|
||||
if (datalayer.battery.status.remaining_capacity_Wh > 60000) {
|
||||
battery_data[5] = 60000;
|
||||
} else {
|
||||
// Id.: p306 Value.: 13260 Scaled value.: 13,26kWh Comment.: remaining cap: 7.68kWh
|
||||
battery_data[5] = datalayer.battery.status.remaining_capacity_Wh;
|
||||
}
|
||||
if (datalayer.battery.status.max_discharge_power_W > 30000) {
|
||||
battery_data[6] = 30000;
|
||||
} else {
|
||||
battery_data[6] =
|
||||
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 (datalayer.battery.status.max_charge_power_W > 30000) {
|
||||
battery_data[7] = 30000;
|
||||
} else {
|
||||
battery_data[7] =
|
||||
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] =
|
||||
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] =
|
||||
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] =
|
||||
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
|
||||
battery_data[17] =
|
||||
22741; // Id.: p318 Value.: 0 Scaled value.: 0 Comment.: counter charge lo....65536*101+9912 = 6629048 Wh?
|
||||
battery_data[18] = 0; // Id.: p319 Value.: 0 Scaled value.: 0 Comment.: always 0
|
||||
battery_data[19] = 0; // Id.: p320 Value.: 0 Scaled value.: 0 Comment.: always 0
|
||||
battery_data[20] = 13; // Id.: p321 Value.: 0 Scaled value.: 0 Comment.: counter discharge hi
|
||||
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] = 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));
|
||||
mbPV[300] = datalayer.battery.status.bms_status;
|
||||
mbPV[302] = 128 + bms_char_dis_status;
|
||||
mbPV[303] = datalayer.battery.status.reported_soc;
|
||||
mbPV[304] = std::min(datalayer.battery.info.total_capacity_Wh, 60000u); //Cap capacity to 60kWh if needed
|
||||
mbPV[305] = std::min(datalayer.battery.status.remaining_capacity_Wh, 60000u); //Cap capacity to 60kWh if needed
|
||||
mbPV[306] = std::min(max_discharge_W, 30000u); //Cap to 30000 if exceeding
|
||||
mbPV[307] = std::min(max_charge_W, 30000u); //Cap to 30000 if exceeding
|
||||
mbPV[310] = datalayer.battery.status.voltage_dV;
|
||||
mbPV[312] = datalayer.battery.status.temperature_min_dC;
|
||||
mbPV[313] = datalayer.battery.status.temperature_max_dC;
|
||||
mbPV[323] = datalayer.battery.status.soh_pptt;
|
||||
}
|
||||
|
||||
void verify_temperature_modbus() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue