Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Inverter handling #276

Merged
merged 2 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 35 additions & 131 deletions Software/Software.ino
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT);
#endif

// ModbusRTU parameters
#if defined(BYD_MODBUS) || defined(LUNA2000_MODBUS)
#ifdef MODBUS_INVERTER_SELECTED
#define MB_RTU_NUM_VALUES 30000
uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory
// Create a ModbusRTU server instance listening on Serial2 with 2000ms timeout
Expand Down Expand Up @@ -135,7 +135,7 @@ void setup() {

init_serialDataLink();

inform_user_on_inverter();
init_inverter();

init_battery();

Expand Down Expand Up @@ -416,7 +416,7 @@ void init_contactors() {
}

void init_modbus() {
#if defined(BYD_MODBUS) || defined(LUNA2000_MODBUS)
#ifdef MODBUS_INVERTER_SELECTED
// Set up Modbus RTU Server
pinMode(RS485_EN_PIN, OUTPUT);
digitalWrite(RS485_EN_PIN, HIGH);
Expand All @@ -443,50 +443,10 @@ void init_modbus() {
#endif
}

void inform_user_on_inverter() {
// Inform user what Inverter is used
#ifdef BYD_CAN
#ifdef DEBUG_VIA_USB
Serial.println("BYD CAN protocol selected");
#endif
#endif
#ifdef BYD_MODBUS
#ifdef DEBUG_VIA_USB
Serial.println("BYD Modbus RTU protocol selected");
#endif
#endif
#ifdef LUNA2000_MODBUS
#ifdef DEBUG_VIA_USB
Serial.println("Luna2000 Modbus RTU protocol selected");
#endif
#endif
#ifdef PYLON_CAN
#ifdef DEBUG_VIA_USB
Serial.println("PYLON CAN protocol selected");
#endif
#endif
#ifdef SMA_CAN
#ifdef DEBUG_VIA_USB
Serial.println("SMA CAN protocol selected");
#endif
#endif
#ifdef SMA_TRIPOWER_CAN
#ifdef DEBUG_VIA_USB
Serial.println("SMA Tripower CAN protocol selected");
#endif
#endif
#ifdef SOFAR_CAN
#ifdef DEBUG_VIA_USB
Serial.println("SOFAR CAN protocol selected");
#endif
#endif
void init_inverter() {
#ifdef SOLAX_CAN
datalayer.system.status.inverter_allows_contactor_closing =
false; // The inverter needs to allow first on this protocol
datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first
intervalUpdateValues = 800; // This protocol also requires the values to be updated faster
#ifdef DEBUG_VIA_USB
Serial.println("SOLAX CAN protocol selected");
#endif
#endif
}

Expand All @@ -510,99 +470,61 @@ void receive_can() { // This section checks if we have a complete CAN message i
// Depending on which battery/inverter is selected, we forward this to their respective CAN routines
CAN_frame_t rx_frame;
if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 0) == pdTRUE) {
if (rx_frame.FIR.B.FF == CAN_frame_std) { // New standard frame
// Battery
#ifndef SERIAL_LINK_RECEIVER
receive_can_battery(rx_frame);
#endif
// Inverter
#ifdef BYD_CAN
receive_can_byd(rx_frame);
// Battery
#ifndef SERIAL_LINK_RECEIVER // Only needs to see inverter
receive_can_battery(rx_frame);
#endif
#ifdef SMA_CAN
receive_can_sma(rx_frame);
// Inverter
#ifdef CAN_INVERTER_SELECTED
receive_can_inverter(rx_frame);
#endif
#ifdef SMA_TRIPOWER_CAN
receive_can_sma_tripower(rx_frame);
// Charger
#ifdef CHARGER_SELECTED
receive_can_charger(rx_frame);
#endif
// Charger
#if defined(CHEVYVOLT_CHARGER) || defined(NISSANLEAF_CHARGER)
receive_can_charger(rx_frame);
#endif
} else { // New extended frame
#ifdef PYLON_CAN
receive_can_pylon(rx_frame);
#endif
#ifdef SOFAR_CAN
receive_can_sofar(rx_frame);
#endif
#ifdef SOLAX_CAN
receive_can_solax(rx_frame);
#endif
}
}
}

void send_can() {
// Send CAN messages
// Inverter
#ifdef BYD_CAN
send_can_byd();
#endif
#ifdef SMA_CAN
send_can_sma();
#endif
#ifdef SMA_TRIPOWER_CAN
send_can_sma_tripower();
#endif
#ifdef SOFAR_CAN
send_can_sofar();
#endif
// Battery
send_can_battery();
// Inverter
#ifdef CAN_INVERTER_SELECTED
send_can_inverter();
#endif
// Charger
#if defined(CHEVYVOLT_CHARGER) || defined(NISSANLEAF_CHARGER)
#ifdef CHARGER_SELECTED
send_can_charger();
#endif
}

#ifdef DUAL_CAN
void receive_can2() { // This function is similar to receive_can, but just takes care of inverters in the 2nd bus.
// Depending on which inverter is selected, we forward this to their respective CAN routines
CAN_frame_t rx_frame2; // Struct with ESP32Can library format, compatible with the rest of the program
CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use thw MCP2515 library
CAN_frame_t rx_frame_can2; // Struct with ESP32Can library format, compatible with the rest of the program
CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use thw MCP2515 library

if (can.available()) {
can.receive(MCP2515Frame);

rx_frame2.MsgID = MCP2515Frame.id;
rx_frame2.FIR.B.FF = MCP2515Frame.ext ? CAN_frame_ext : CAN_frame_std;
rx_frame2.FIR.B.RTR = MCP2515Frame.rtr ? CAN_RTR : CAN_no_RTR;
rx_frame2.FIR.B.DLC = MCP2515Frame.len;
rx_frame_can2.MsgID = MCP2515Frame.id;
rx_frame_can2.FIR.B.FF = MCP2515Frame.ext ? CAN_frame_ext : CAN_frame_std;
rx_frame_can2.FIR.B.RTR = MCP2515Frame.rtr ? CAN_RTR : CAN_no_RTR;
rx_frame_can2.FIR.B.DLC = MCP2515Frame.len;
for (uint8_t i = 0; i < MCP2515Frame.len; i++) {
rx_frame2.data.u8[i] = MCP2515Frame.data[i];
rx_frame_can2.data.u8[i] = MCP2515Frame.data[i];
}

if (rx_frame2.FIR.B.FF == CAN_frame_std) { // New standard frame
#ifdef BYD_CAN
receive_can_byd(rx_frame2);
#ifdef CAN_INVERTER_SELECTED
receive_can_inverter(rx_frame_can2);
#endif
} else { // New extended frame
#ifdef PYLON_CAN
receive_can_pylon(rx_frame2);
#endif
#ifdef SOLAX_CAN
receive_can_solax(rx_frame2);
#endif
}
}
}

void send_can2() {
// Send CAN
// Inverter
#ifdef BYD_CAN
send_can_byd();
#ifdef CAN_INVERTER_SELECTED
send_can_inverter(); //Note this will only send to CAN1, unless we use SOLAX
#endif
}
#endif
Expand Down Expand Up @@ -732,31 +654,13 @@ void update_SOC() {

void update_values() {
// Battery
update_values_battery(); // Map the fake values to the correct registers
update_values_battery();
// Inverter
#ifdef BYD_CAN
update_values_can_byd();
#endif
#ifdef BYD_MODBUS
update_modbus_registers_byd();
#ifdef CAN_INVERTER_SELECTED
update_values_can_inverter();
#endif
#ifdef LUNA2000_MODBUS
update_modbus_registers_luna2000();
#endif
#ifdef PYLON_CAN
update_values_can_pylon();
#endif
#ifdef SMA_CAN
update_values_can_sma();
#endif
#ifdef SMA_TRIPOWER_CAN
update_values_can_sma_tripower();
#endif
#ifdef SOFAR_CAN
update_values_can_sofar();
#endif
#ifdef SOLAX_CAN
update_values_can_solax();
#ifdef MODBUS_INVERTER_SELECTED
update_modbus_registers_inverter();
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion Software/src/include.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#error CAN-FD AND DUAL-CAN CANNOT BE USED SIMULTANEOUSLY
#endif

#if defined(BYD_MODBUS) || defined(LUNA2000_MODBUS)
#ifdef MODBUS_INVERTER_SELECTED
#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER)
// Check that Dual LilyGo via RS485 option isn't enabled, this collides with Modbus!
#error MODBUS CANNOT BE USED IN DOUBLE LILYGO SETUPS! CHECK USER SETTINGS!
Expand Down
6 changes: 3 additions & 3 deletions Software/src/inverter/BYD-CAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ static uint16_t inverter_SOC = 0;
static long inverter_timestamp = 0;
static bool initialDataSent = 0;

void update_values_can_byd() { //This function maps all the values fetched from battery CAN to the correct CAN messages
void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages
//Calculate values
charge_current =
((datalayer.battery.status.max_charge_power_W * 10) /
Expand Down Expand Up @@ -199,7 +199,7 @@ void update_values_can_byd() { //This function maps all the values fetched from
#endif
}

void receive_can_byd(CAN_frame_t rx_frame) {
void receive_can_inverter(CAN_frame_t rx_frame) {
switch (rx_frame.MsgID) {
case 0x151: //Message originating from BYD HVS compatible inverter. Reply with CAN identifier!
if (rx_frame.data.u8[0] & 0x01) { //Battery requests identification
Expand Down Expand Up @@ -229,7 +229,7 @@ void receive_can_byd(CAN_frame_t rx_frame) {
}
}

void send_can_byd() {
void send_can_inverter() {
unsigned long currentMillis = millis();
// Send initial CAN data once on bootup
if (!initialDataSent) {
Expand Down
6 changes: 1 addition & 5 deletions Software/src/inverter/BYD-CAN.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
#ifndef BYD_CAN_H
#define BYD_CAN_H
#include <Arduino.h>
#include "../include.h"
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"

#define INVERTER_SELECTED
#define CAN_INVERTER_SELECTED

void update_values_can_byd();
void send_can_byd();
void receive_can_byd(CAN_frame_t rx_frame);
void send_intial_data();

#endif
3 changes: 1 addition & 2 deletions Software/src/inverter/BYD-MODBUS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
#include "../datalayer/datalayer.h"
#include "BYD-MODBUS.h"

void update_modbus_registers_byd() {
//Updata for ModbusRTU Server for BYD
void update_modbus_registers_inverter() {
verify_temperature_modbus();
handle_update_data_modbusp201_byd();
handle_update_data_modbusp301_byd();
Expand Down
3 changes: 1 addition & 2 deletions Software/src/inverter/BYD-MODBUS.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define BYD_MODBUS_H
#include "../include.h"

#define INVERTER_SELECTED
#define MODBUS_INVERTER_SELECTED

#define MB_RTU_NUM_VALUES 30000
#define MAX_POWER 40960 //BYD Modbus specific value
Expand All @@ -13,5 +13,4 @@ void handle_static_data_modbus_byd();
void verify_temperature_modbus();
void handle_update_data_modbusp201_byd();
void handle_update_data_modbusp301_byd();
void update_modbus_registers_byd();
#endif
11 changes: 11 additions & 0 deletions Software/src/inverter/INVERTERS.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,15 @@
#include "SERIAL-LINK-TRANSMITTER-INVERTER.h"
#endif

#ifdef CAN_INVERTER_SELECTED
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" // This include is annoying, consider defining a frame type in types.h
void update_values_can_inverter();
void receive_can_inverter(CAN_frame_t rx_frame);
void send_can_inverter();
#endif

#ifdef MODBUS_INVERTER_SELECTED
void update_modbus_registers_inverter();
#endif

#endif
3 changes: 1 addition & 2 deletions Software/src/inverter/LUNA2000-MODBUS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
#include "../datalayer/datalayer.h"
#include "LUNA2000-MODBUS.h"

void update_modbus_registers_luna2000() {
//Updata for ModbusRTU Server for Luna2000
void update_modbus_registers_inverter() {
handle_update_data_modbus32051();
handle_update_data_modbus39500();
}
Expand Down
3 changes: 1 addition & 2 deletions Software/src/inverter/LUNA2000-MODBUS.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
#define LUNA2000_MODBUS_H
#include "../include.h"

#define INVERTER_SELECTED
#define MODBUS_INVERTER_SELECTED

#define MB_RTU_NUM_VALUES 30000

extern uint16_t mbPV[MB_RTU_NUM_VALUES];

void update_modbus_registers_luna2000();
void handle_update_data_modbus32051();
void handle_update_data_modbus39500();
#endif
8 changes: 6 additions & 2 deletions Software/src/inverter/PYLON-CAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ CAN_frame_t PYLON_4291 = {.FIR = {.B =
.MsgID = 0x4291,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};

void update_values_can_pylon() { //This function maps all the values fetched from battery CAN to the correct CAN messages
void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages
//There are more mappings that could be added, but this should be enough to use as a starting point
// Note we map both 0 and 1 messages

Expand Down Expand Up @@ -243,7 +243,7 @@ void update_values_can_pylon() { //This function maps all the values fetched fr
}
}

void receive_can_pylon(CAN_frame_t rx_frame) {
void receive_can_inverter(CAN_frame_t rx_frame) {
switch (rx_frame.MsgID) {
case 0x4200: //Message originating from inverter. Depending on which data is required, act accordingly
if (rx_frame.data.u8[0] == 0x02) {
Expand All @@ -258,6 +258,10 @@ void receive_can_pylon(CAN_frame_t rx_frame) {
}
}

void send_can_inverter() {
// No periodic sending, we only react on received can messages
}

void send_setup_info() { //Ensemble information
#ifdef SEND_0
ESP32Can.CANWriteFrame(&PYLON_7310);
Expand Down
Loading
Loading