Make Solax use type settings in COMMON_IMAGE mode, add ignore contactors feature

This commit is contained in:
Jonny 2025-08-16 12:20:30 +01:00
parent efd6ca1349
commit a718d99672
2 changed files with 59 additions and 12 deletions

View file

@ -4,11 +4,7 @@
#include "../datalayer/datalayer.h" #include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h" #include "../devboard/utils/events.h"
#include "../devboard/utils/logging.h" #include "../devboard/utils/logging.h"
#include "../inverter/INVERTERS.h"
#define NUMBER_OF_MODULES 0
#define BATTERY_TYPE 0x50
// If you are having BattVoltFault issues, configure the above values according to wiki page
// https://github.com/dalathegreat/Battery-Emulator/wiki/Solax-inverters
// __builtin_bswap64 needed to convert to ESP32 little endian format // __builtin_bswap64 needed to convert to ESP32 little endian format
// Byte[4] defines the requested contactor state: 1 = Closed , 0 = Open // Byte[4] defines the requested contactor state: 1 = Closed , 0 = Open
@ -18,7 +14,7 @@
void SolaxInverter:: void SolaxInverter::
update_values() { //This function maps all the values fetched from battery CAN to the correct CAN messages update_values() { //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 not receiveing any communication from the inverter, open contactors and return to battery announce state
if (millis() - LastFrameTime >= SolaxTimeout) { if (millis() - LastFrameTime >= SolaxTimeout && !configured_ignore_contactors) {
datalayer.system.status.inverter_allows_contactor_closing = false; datalayer.system.status.inverter_allows_contactor_closing = false;
STATE = BATTERY_ANNOUNCE; STATE = BATTERY_ANNOUNCE;
} }
@ -73,7 +69,7 @@ void SolaxInverter::
//BMS_Status //BMS_Status
SOLAX_1875.data.u8[0] = (uint8_t)temperature_average; SOLAX_1875.data.u8[0] = (uint8_t)temperature_average;
SOLAX_1875.data.u8[1] = (temperature_average >> 8); SOLAX_1875.data.u8[1] = (temperature_average >> 8);
SOLAX_1875.data.u8[2] = (uint8_t)NUMBER_OF_MODULES; // Number of slave batteries SOLAX_1875.data.u8[2] = (uint8_t)configured_number_of_modules; // Number of slave batteries
SOLAX_1875.data.u8[4] = (uint8_t)0; // Contactor Status 0=off, 1=on. SOLAX_1875.data.u8[4] = (uint8_t)0; // Contactor Status 0=off, 1=on.
//BMS_PackTemps (strange name, since it has voltages?) //BMS_PackTemps (strange name, since it has voltages?)
@ -88,7 +84,7 @@ void SolaxInverter::
SOLAX_1876.data.u8[7] = (datalayer.battery.status.cell_min_voltage_mV >> 8); SOLAX_1876.data.u8[7] = (datalayer.battery.status.cell_min_voltage_mV >> 8);
//Unknown //Unknown
SOLAX_1877.data.u8[4] = (uint8_t)BATTERY_TYPE; // Battery type (Default 0x50) SOLAX_1877.data.u8[4] = (uint8_t)configured_battery_type; // Battery type (Default 0x50)
SOLAX_1877.data.u8[6] = (uint8_t)0x22; // Firmware version? SOLAX_1877.data.u8[6] = (uint8_t)0x22; // Firmware version?
SOLAX_1877.data.u8[7] = SOLAX_1877.data.u8[7] =
(uint8_t)0x02; // The above firmware version applies to:02 = Master BMS, 10 = S1, 20 = S2, 30 = S3, 40 = S4 (uint8_t)0x02; // The above firmware version applies to:02 = Master BMS, 10 = S1, 20 = S2, 30 = S3, 40 = S4
@ -129,6 +125,26 @@ void SolaxInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
if (rx_frame.ID == 0x1871 && rx_frame.data.u8[0] == (0x01) || if (rx_frame.ID == 0x1871 && rx_frame.data.u8[0] == (0x01) ||
rx_frame.ID == 0x1871 && rx_frame.data.u8[0] == (0x02)) { rx_frame.ID == 0x1871 && rx_frame.data.u8[0] == (0x02)) {
LastFrameTime = millis(); LastFrameTime = millis();
if (configured_ignore_contactors) {
// Skip the state machine since we're not going to open/close contactors,
// and the Solax would otherwise wait forever for us to do so.
datalayer.system.status.inverter_allows_contactor_closing = true;
SOLAX_1875.data.u8[4] = (0x01); // Inform Inverter: Contactor 0=off, 1=on.
transmit_can_frame(&SOLAX_187E);
transmit_can_frame(&SOLAX_187A);
transmit_can_frame(&SOLAX_1872);
transmit_can_frame(&SOLAX_1873);
transmit_can_frame(&SOLAX_1874);
transmit_can_frame(&SOLAX_1875);
transmit_can_frame(&SOLAX_1876);
transmit_can_frame(&SOLAX_1877);
transmit_can_frame(&SOLAX_1878);
transmit_can_frame(&SOLAX_100A001);
return;
}
switch (STATE) { switch (STATE) {
case (BATTERY_ANNOUNCE): case (BATTERY_ANNOUNCE):
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
@ -209,6 +225,25 @@ void SolaxInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
} }
bool SolaxInverter::setup(void) { // Performs one time setup at startup bool SolaxInverter::setup(void) { // Performs one time setup at startup
// Use user selected values if nonzero, otherwise use defaults
if (user_selected_inverter_modules > 0) {
configured_number_of_modules = user_selected_inverter_modules;
} else {
configured_number_of_modules = NUMBER_OF_MODULES;
}
if (user_selected_inverter_battery_type > 0) {
configured_battery_type = user_selected_inverter_battery_type;
} else {
configured_battery_type = BATTERY_TYPE;
}
configured_ignore_contactors = user_selected_inverter_ignore_contactors;
if (!configured_ignore_contactors) {
// Only prevent closing if we're not ignoring contactors
datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first
}
return true; return true;
} }

View file

@ -17,6 +17,11 @@ class SolaxInverter : public CanInverterProtocol {
static constexpr const char* Name = "SolaX Triple Power LFP over CAN bus"; static constexpr const char* Name = "SolaX Triple Power LFP over CAN bus";
private: private:
static const int NUMBER_OF_MODULES = 0;
static const int BATTERY_TYPE = 0x50;
// If you are having BattVoltFault issues, configure the above values according to wiki page
// https://github.com/dalathegreat/Battery-Emulator/wiki/Solax-inverters
// Timeout in milliseconds // Timeout in milliseconds
static const int SolaxTimeout = 2000; static const int SolaxTimeout = 2000;
@ -34,6 +39,13 @@ class SolaxInverter : public CanInverterProtocol {
uint16_t capped_capacity_Wh; uint16_t capped_capacity_Wh;
uint16_t capped_remaining_capacity_Wh; uint16_t capped_remaining_capacity_Wh;
int configured_number_of_modules = 0;
int configured_battery_type = 0;
// If true, the integration will ignore the inverter's requests to open the
// battery contactors. Useful for batteries that can't open contactors on
// request.
bool configured_ignore_contactors = false;
//CAN message translations from this amazing repository: https://github.com/rand12345/solax_can_bus //CAN message translations from this amazing repository: https://github.com/rand12345/solax_can_bus
CAN_frame SOLAX_1801 = {.FD = false, CAN_frame SOLAX_1801 = {.FD = false,