BYD CAN inverter protocol class

This commit is contained in:
Jaakko Haakana 2025-05-06 21:33:33 +03:00
parent 2b608e48b9
commit d934a3b796
5 changed files with 153 additions and 95 deletions

View file

@ -1,91 +1,13 @@
#include "../include.h"
#ifdef BYD_CAN
#include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h"
#include "BYD-CAN.h"
/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send
static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
#define VOLTAGE_OFFSET_DV 20
CAN_frame BYD_250 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x250,
.data = {FW_MAJOR_VERSION, FW_MINOR_VERSION, 0x00, 0x66, (uint8_t)((BATTERY_WH_MAX / 100) >> 8),
(uint8_t)(BATTERY_WH_MAX / 100), 0x02,
0x09}}; //0-1 FW version , Capacity kWh byte4&5 (example 24kWh = 240)
CAN_frame BYD_290 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x290,
.data = {0x06, 0x37, 0x10, 0xD9, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_2D0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x2D0,
.data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //BYD
CAN_frame BYD_3D0_0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //Battery
CAN_frame BYD_3D0_1 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr
CAN_frame BYD_3D0_2 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H
CAN_frame BYD_3D0_3 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS
//Actual content messages
CAN_frame BYD_110 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x110,
.data = {0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_150 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x150,
.data = {0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00}};
CAN_frame BYD_190 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x190,
.data = {0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_1D0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x1D0,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08}};
CAN_frame BYD_210 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x210,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
static int16_t temperature_average = 0;
static uint16_t inverter_voltage = 0;
static uint16_t inverter_SOC = 0;
static int16_t inverter_current = 0;
static int16_t inverter_temperature = 0;
static uint16_t remaining_capacity_ah = 0;
static uint16_t fully_charged_capacity_ah = 0;
static long inverter_timestamp = 0;
static bool initialDataSent = false;
static bool inverterStartedUp = false;
void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages
void BydCanInverter::
update_values() { //This function maps all the values fetched from battery CAN to the correct CAN messages
/* Calculate temperature */
temperature_average =
@ -167,7 +89,7 @@ void update_values_can_inverter() { //This function maps all the values fetched
BYD_210.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF);
}
void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
void BydCanInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x151: //Message originating from BYD HVS compatible inverter. Reply with CAN identifier!
inverterStartedUp = true;
@ -204,7 +126,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
}
}
void transmit_can_inverter(unsigned long currentMillis) {
void BydCanInverter::transmit_can(unsigned long currentMillis) {
if (!inverterStartedUp) {
//Avoid sending messages towards inverter, unless it has woken up and sent something to us first
@ -239,7 +161,7 @@ void transmit_can_inverter(unsigned long currentMillis) {
}
}
void send_intial_data() {
void BydCanInverter::send_intial_data() {
transmit_can_frame(&BYD_250, can_config.inverter);
transmit_can_frame(&BYD_290, can_config.inverter);
transmit_can_frame(&BYD_2D0, can_config.inverter);
@ -248,7 +170,8 @@ void send_intial_data() {
transmit_can_frame(&BYD_3D0_2, can_config.inverter);
transmit_can_frame(&BYD_3D0_3, can_config.inverter);
}
void setup_inverter(void) { // Performs one time setup at startup over CAN bus
void BydCanInverter::setup(void) { // Performs one time setup at startup over CAN bus
strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box Premium HVS over CAN Bus", 63);
datalayer.system.info.inverter_protocol[63] = '\0';
}

View file

@ -3,11 +3,101 @@
#include "../include.h"
#define CAN_INVERTER_SELECTED
#define SELECTED_INVERTER_CLASS BydCanInverter
#define FW_MAJOR_VERSION 0x03
#define FW_MINOR_VERSION 0x29
class BydCanInverter : public CanInverterProtocol {
public:
void setup();
void send_intial_data();
void transmit_can_frame(CAN_frame* tx_frame, int interface);
void setup_inverter(void);
void transmit_can(unsigned long currentMillis);
void map_can_frame_to_variable(CAN_frame rx_frame);
private:
void update_values();
unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send
unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
#define VOLTAGE_OFFSET_DV 20
CAN_frame BYD_250 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x250,
.data = {FW_MAJOR_VERSION, FW_MINOR_VERSION, 0x00, 0x66, (uint8_t)((BATTERY_WH_MAX / 100) >> 8),
(uint8_t)(BATTERY_WH_MAX / 100), 0x02,
0x09}}; //0-1 FW version , Capacity kWh byte4&5 (example 24kWh = 240)
CAN_frame BYD_290 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x290,
.data = {0x06, 0x37, 0x10, 0xD9, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_2D0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x2D0,
.data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //BYD
CAN_frame BYD_3D0_0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //Battery
CAN_frame BYD_3D0_1 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr
CAN_frame BYD_3D0_2 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H
CAN_frame BYD_3D0_3 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS
//Actual content messages
CAN_frame BYD_110 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x110,
.data = {0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_150 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x150,
.data = {0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00}};
CAN_frame BYD_190 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x190,
.data = {0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_1D0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x1D0,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08}};
CAN_frame BYD_210 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x210,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
int16_t temperature_average = 0;
uint16_t inverter_voltage = 0;
uint16_t inverter_SOC = 0;
int16_t inverter_current = 0;
int16_t inverter_temperature = 0;
uint16_t remaining_capacity_ah = 0;
uint16_t fully_charged_capacity_ah = 0;
long inverter_timestamp = 0;
bool initialDataSent = false;
bool inverterStartedUp = false;
};
#endif

View file

@ -3,7 +3,7 @@
#include "../include.h"
#define MODBUS_INVERTER_SELECTED
#define OO_INVERTER_PROTOCOL_SELECTED
#define SELECTED_INVERTER_CLASS BydModbusInverter
#define MB_RTU_NUM_VALUES 13100
#define MAX_POWER 40960 //BYD Modbus specific value

View file

@ -3,22 +3,54 @@
// These functions adapt the old C-style global functions inverter-API to the
// object-oriented inverter protocol API.
#ifdef OO_INVERTER_PROTOCOL_SELECTED
#ifdef SELECTED_INVERTER_CLASS
ModbusInverterProtocol* inverter;
InverterProtocol* inverter;
#ifdef CAN_INVERTER_SELECTED
CanInverterProtocol* can_inverter;
#endif
#ifdef MODBUS_INVERTER_SELECTED
ModbusInverterProtocol* modbus_inverter;
#endif
void setup_inverter() {
// Currently only a single inverter protocol is implemented as a class
inverter = new BydModbusInverter();
#ifdef MODBUS_INVERTER_SELECTED
modbus_inverter = new SELECTED_INVERTER_CLASS();
inverter = modbus_inverter;
#endif
#ifdef CAN_INVERTER_SELECTED
can_inverter = new SELECTED_INVERTER_CLASS();
inverter = can_inverter;
#endif
inverter->setup();
}
#ifdef MODBUS_INVERTER_SELECTED
void update_modbus_registers_inverter() {
inverter->update_modbus_registers();
modbus_inverter->update_modbus_registers();
}
void handle_static_data_modbus() {
inverter->handle_static_data();
modbus_inverter->handle_static_data();
}
#endif
#ifdef CAN_INVERTER_SELECTED
void update_values_can_inverter() {
can_inverter->update_values();
}
void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
can_inverter->map_can_frame_to_variable(rx_frame);
}
void transmit_can_inverter(unsigned long currentMillis) {
can_inverter->transmit_can(currentMillis);
}
#endif
#endif

View file

@ -14,6 +14,18 @@ class ModbusInverterProtocol : public InverterProtocol {
virtual void handle_static_data();
};
class CanInverterProtocol : public InverterProtocol {
public:
virtual void send_intial_data() = 0;
//This function maps all the values fetched from battery CAN to the correct CAN messages
virtual void update_values() = 0;
virtual void transmit_can(unsigned long currentMillis) = 0;
virtual void map_can_frame_to_variable(CAN_frame rx_frame) = 0;
};
#include "../../USER_SETTINGS.h"
#ifdef AFORE_CAN
@ -96,6 +108,7 @@ class ModbusInverterProtocol : public InverterProtocol {
void update_values_can_inverter();
void map_can_frame_to_variable_inverter(CAN_frame rx_frame);
void transmit_can_inverter(unsigned long currentMillis);
void setup_inverter();
#endif
#ifdef MODBUS_INVERTER_SELECTED