mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 02:39:57 +02:00
Convert Growatt inverters to use the base class
This commit is contained in:
parent
f22be6489b
commit
204594bdd0
4 changed files with 239 additions and 219 deletions
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef GROWATT_HV_CAN
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "GROWATT-HV-CAN.h"
|
||||
|
||||
|
@ -21,143 +22,8 @@ FCC - Full charge capacity
|
|||
RM - Remaining capacity
|
||||
BMS - Battery Information Collector*/
|
||||
|
||||
//Total number of Cells (1-512)
|
||||
//(Total number of Cells = number of Packs in parallel * number of Modules in series * number of Cells in the module)
|
||||
#define TOTAL_NUMBER_OF_CELLS 300
|
||||
// Number of Modules in series (1-32)
|
||||
#define NUMBER_OF_MODULES_IN_SERIES 20
|
||||
// Number of packs in parallel (1-65536)
|
||||
#define NUMBER_OF_PACKS_IN_PARALLEL 1
|
||||
//Manufacturer abbreviation, part 1
|
||||
#define MANUFACTURER_ASCII_0 0x47 //G
|
||||
#define MANUFACTURER_ASCII_1 0x54 //T
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
|
||||
//Actual content messages
|
||||
CAN_frame GROWATT_3110 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3110,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3120 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3120,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3130 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3130,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3140 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3140,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3150 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3150,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3160 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3160,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3170 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3170,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3180 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3180,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3190 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3190,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3200 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3200,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3210 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3210,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3220 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3220,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3230 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3230,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3240 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3240,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3250 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3250,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3260 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3260,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3270 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3270,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3280 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3280,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3290 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3290,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3F00 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3F00,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
static unsigned long previousMillis1s = 0; // will store last time a 1s CAN Message was send
|
||||
static unsigned long previousMillisBatchSend = 0;
|
||||
static uint32_t unix_time = 0;
|
||||
static uint16_t ampere_hours_remaining = 0;
|
||||
static uint16_t ampere_hours_full = 0;
|
||||
static uint16_t send_times = 0; // Overflows every 18hours. Cumulative number, plus 1 for each transmission
|
||||
static uint8_t safety_specification = 0;
|
||||
static uint8_t charging_command = 0;
|
||||
static uint8_t discharging_command = 0;
|
||||
static uint8_t shielding_external_communication_failure = 0;
|
||||
static uint8_t clearing_battery_fault =
|
||||
0; //When PCS receives the forced charge Mark 1 and Cell under- voltage protection fault, it will send 0XAA
|
||||
static uint8_t ISO_detection_command = 0;
|
||||
static uint8_t sleep_wakeup_control = 0;
|
||||
static uint8_t PCS_working_status = 0; //00 standby, 01 operating
|
||||
static uint8_t serial_number_counter = 0; //0-1-2-0-1-2...
|
||||
static uint8_t can_message_batch_index = 0;
|
||||
static const uint8_t delay_between_batches_ms = 10;
|
||||
static bool inverter_alive = false;
|
||||
static bool time_to_send_1s_data = false;
|
||||
|
||||
void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
void GrowattHvInverter::
|
||||
update_values() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
|
||||
if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0
|
||||
ampere_hours_remaining =
|
||||
|
@ -493,7 +359,7 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
|||
GROWATT_3F00.data.u8[7] = 0; // RESERVED
|
||||
}
|
||||
|
||||
void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
|
||||
void GrowattHvInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x3010: // Heartbeat command, 1000ms
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
|
@ -523,7 +389,7 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
|
|||
}
|
||||
}
|
||||
|
||||
void transmit_can_inverter(unsigned long currentMillis) {
|
||||
void GrowattHvInverter::transmit_can(unsigned long currentMillis) {
|
||||
|
||||
if (!inverter_alive) {
|
||||
return; //Dont send messages towards inverter until it has started
|
||||
|
@ -585,7 +451,7 @@ void transmit_can_inverter(unsigned long currentMillis) {
|
|||
}
|
||||
}
|
||||
|
||||
void setup_inverter(void) { // Performs one time setup at startup over CAN bus
|
||||
void GrowattHvInverter::setup(void) { // Performs one time setup at startup over CAN bus
|
||||
strncpy(datalayer.system.info.inverter_protocol, "Growatt High Voltage protocol via CAN", 63);
|
||||
datalayer.system.info.inverter_protocol[63] = '\0';
|
||||
}
|
||||
|
|
|
@ -2,9 +2,154 @@
|
|||
#define GROWATT_HV_CAN_H
|
||||
#include "../include.h"
|
||||
|
||||
#define CAN_INVERTER_SELECTED
|
||||
#include "CanInverterProtocol.h"
|
||||
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
void setup_inverter(void);
|
||||
#define CAN_INVERTER_SELECTED
|
||||
#define SELECTED_INVERTER_CLASS GrowattHvInverter
|
||||
|
||||
class GrowattHvInverter : public CanInverterProtocol {
|
||||
public:
|
||||
void setup();
|
||||
void update_values();
|
||||
void transmit_can(unsigned long currentMillis);
|
||||
void map_can_frame_to_variable(CAN_frame rx_frame);
|
||||
|
||||
private:
|
||||
//Total number of Cells (1-512)
|
||||
//(Total number of Cells = number of Packs in parallel * number of Modules in series * number of Cells in the module)
|
||||
#define TOTAL_NUMBER_OF_CELLS 300
|
||||
// Number of Modules in series (1-32)
|
||||
#define NUMBER_OF_MODULES_IN_SERIES 20
|
||||
// Number of packs in parallel (1-65536)
|
||||
#define NUMBER_OF_PACKS_IN_PARALLEL 1
|
||||
//Manufacturer abbreviation, part 1
|
||||
#define MANUFACTURER_ASCII_0 0x47 //G
|
||||
#define MANUFACTURER_ASCII_1 0x54 //T
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
|
||||
//Actual content messages
|
||||
CAN_frame GROWATT_3110 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3110,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3120 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3120,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3130 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3130,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3140 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3140,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3150 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3150,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3160 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3160,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3170 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3170,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3180 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3180,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3190 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3190,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3200 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3200,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3210 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3210,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3220 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3220,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3230 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3230,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3240 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3240,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3250 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3250,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3260 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3260,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3270 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3270,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3280 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3280,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3290 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3290,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_3F00 = {.FD = false,
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.ID = 0x3F00,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
unsigned long previousMillis1s = 0; // will store last time a 1s CAN Message was send
|
||||
unsigned long previousMillisBatchSend = 0;
|
||||
uint32_t unix_time = 0;
|
||||
uint16_t ampere_hours_remaining = 0;
|
||||
uint16_t ampere_hours_full = 0;
|
||||
uint16_t send_times = 0; // Overflows every 18hours. Cumulative number, plus 1 for each transmission
|
||||
uint8_t safety_specification = 0;
|
||||
uint8_t charging_command = 0;
|
||||
uint8_t discharging_command = 0;
|
||||
uint8_t shielding_external_communication_failure = 0;
|
||||
uint8_t clearing_battery_fault =
|
||||
0; //When PCS receives the forced charge Mark 1 and Cell under- voltage protection fault, it will send 0XAA
|
||||
uint8_t ISO_detection_command = 0;
|
||||
uint8_t sleep_wakeup_control = 0;
|
||||
uint8_t PCS_working_status = 0; //00 standby, 01 operating
|
||||
uint8_t serial_number_counter = 0; //0-1-2-0-1-2...
|
||||
uint8_t can_message_batch_index = 0;
|
||||
const uint8_t delay_between_batches_ms = 10;
|
||||
bool inverter_alive = false;
|
||||
bool time_to_send_1s_data = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../include.h"
|
||||
#ifdef GROWATT_LV_CAN
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "GROWATT-LV-CAN.h"
|
||||
|
||||
|
@ -10,76 +11,8 @@ Big-endian
|
|||
|
||||
The inverter replies data every second (standard frame/decimal)0x301:*/
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
|
||||
//Actual content messages
|
||||
CAN_frame GROWATT_311 = {.FD = false, //Voltage and charge limits and status
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x311,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_312 = {.FD = false, //status bits , pack number, total cell number
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x312,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_313 = {.FD = false, //voltage, current, temp, soc, soh
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x313,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_314 = {.FD = false, //capacity, delta V, cycle count
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x314,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_319 = {.FD = false, //max/min cell voltage, num of cell max/min, protect pack ID
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x319,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_320 = {.FD = false, //manufacturer name, hw ver, sw ver, date and time
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x320,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_321 = {.FD = false, //Update status, ID
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x321,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//Cellvoltages
|
||||
CAN_frame GROWATT_315 = {.FD = false, //Cells 1-4
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x315,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_316 = {.FD = false, //Cells 5-8
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x316,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_317 = {.FD = false, //Cells 9-12
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x317,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_318 = {.FD = false, //Cells 13-16
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x318,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
#define VOLTAGE_OFFSET_DV 40 //Offset in deciVolt from max charge voltage and min discharge voltage
|
||||
#define MAX_VOLTAGE_DV 630
|
||||
#define MIN_VOLTAGE_DV 410
|
||||
|
||||
static uint16_t cell_delta_mV = 0;
|
||||
static uint16_t ampere_hours_remaining = 0;
|
||||
static uint16_t ampere_hours_full = 0;
|
||||
|
||||
void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
void GrowattLvInverter::
|
||||
update_values() { //This function maps all the values fetched from battery CAN to the correct CAN messages
|
||||
|
||||
cell_delta_mV = datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV;
|
||||
|
||||
|
@ -246,7 +179,7 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
|||
GROWATT_318.data.u8[7] = (datalayer.battery.status.cell_voltages_mV[15] & 0x00FF);
|
||||
}
|
||||
|
||||
void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
|
||||
void GrowattLvInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
|
||||
switch (rx_frame.ID) {
|
||||
case 0x301:
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
|
@ -267,11 +200,11 @@ void map_can_frame_to_variable_inverter(CAN_frame rx_frame) {
|
|||
}
|
||||
}
|
||||
|
||||
void transmit_can_inverter(unsigned long currentMillis) {
|
||||
void GrowattLvInverter::transmit_can(unsigned long currentMillis) {
|
||||
// No periodic sending for this battery type. Data is sent when inverter requests it
|
||||
}
|
||||
|
||||
void setup_inverter(void) { // Performs one time setup at startup over CAN bus
|
||||
void GrowattLvInverter::setup(void) { // Performs one time setup at startup over CAN bus
|
||||
strncpy(datalayer.system.info.inverter_protocol, "Growatt Low Voltage (48V) protocol via CAN", 63);
|
||||
datalayer.system.info.inverter_protocol[63] = '\0';
|
||||
}
|
||||
|
|
|
@ -2,9 +2,85 @@
|
|||
#define GROWATT_LV_CAN_H
|
||||
#include "../include.h"
|
||||
|
||||
#define CAN_INVERTER_SELECTED
|
||||
#include "CanInverterProtocol.h"
|
||||
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
void setup_inverter(void);
|
||||
#define CAN_INVERTER_SELECTED
|
||||
#define SELECTED_INVERTER_CLASS GrowattLvInverter
|
||||
|
||||
class GrowattLvInverter : public CanInverterProtocol {
|
||||
public:
|
||||
void setup();
|
||||
void update_values();
|
||||
void transmit_can(unsigned long currentMillis);
|
||||
void map_can_frame_to_variable(CAN_frame rx_frame);
|
||||
|
||||
private:
|
||||
//Actual content messages
|
||||
CAN_frame GROWATT_311 = {.FD = false, //Voltage and charge limits and status
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x311,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_312 = {.FD = false, //status bits , pack number, total cell number
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x312,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_313 = {.FD = false, //voltage, current, temp, soc, soh
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x313,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_314 = {.FD = false, //capacity, delta V, cycle count
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x314,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_319 = {.FD = false, //max/min cell voltage, num of cell max/min, protect pack ID
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x319,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_320 = {.FD = false, //manufacturer name, hw ver, sw ver, date and time
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x320,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_321 = {.FD = false, //Update status, ID
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x321,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//Cellvoltages
|
||||
CAN_frame GROWATT_315 = {.FD = false, //Cells 1-4
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x315,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_316 = {.FD = false, //Cells 5-8
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x316,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_317 = {.FD = false, //Cells 9-12
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x317,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
CAN_frame GROWATT_318 = {.FD = false, //Cells 13-16
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x318,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
#define VOLTAGE_OFFSET_DV 40 //Offset in deciVolt from max charge voltage and min discharge voltage
|
||||
#define MAX_VOLTAGE_DV 630
|
||||
#define MIN_VOLTAGE_DV 410
|
||||
|
||||
uint16_t cell_delta_mV = 0;
|
||||
uint16_t ampere_hours_remaining = 0;
|
||||
uint16_t ampere_hours_full = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue