From 75c66cb6d3c191e00f0681eca474529a924884cc Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Mon, 9 Jun 2025 22:29:52 +0300 Subject: [PATCH 01/14] Eliminate CAN_SHUNT_SELECTED define --- Software/src/battery/BMW-SBOX.h | 1 - Software/src/battery/Shunt.h | 3 +++ Software/src/devboard/webserver/settings_html.cpp | 8 ++++---- Software/src/devboard/webserver/webserver.cpp | 10 +++++----- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index 97ef3cd5..ad4046f6 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -2,7 +2,6 @@ #define BMW_SBOX_CONTROL_H #include "../include.h" -#define CAN_SHUNT_SELECTED #define SELECTED_SHUNT_CLASS BmwSbox #include "Shunt.h" diff --git a/Software/src/battery/Shunt.h b/Software/src/battery/Shunt.h index 6672d998..55b0c849 100644 --- a/Software/src/battery/Shunt.h +++ b/Software/src/battery/Shunt.h @@ -11,6 +11,9 @@ class CanShunt : public Transmitter, CanReceiver { virtual void transmit_can(unsigned long currentMillis) = 0; virtual void handle_incoming_can_frame(CAN_frame rx_frame) = 0; + // The name of the comm interface the shunt is using. + virtual String interface_name() { return getCANInterfaceName(can_config.shunt); } + void transmit(unsigned long currentMillis) { if (allowed_to_send_CAN) { transmit_can(currentMillis); diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 1d55e063..13439de5 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -40,10 +40,10 @@ String settings_processor(const String& var) { String(inverter->interface_name()) + ""; } -#ifdef CAN_SHUNT_SELECTED - content += "

Shunt Interface: " + - String(getCANInterfaceName(can_config.shunt)) + "

"; -#endif //CAN_SHUNT_SELECTED + if (shunt) { + content += + "

Shunt Interface: " + shunt->interface_name() + "

"; + } // Close the block content += ""; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 0cbc0838..77f8fae3 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -960,11 +960,11 @@ String processor(const String& var) { } content += ""; -#ifdef CAN_SHUNT_SELECTED - content += "

Shunt protocol: "; - content += datalayer.system.info.shunt_protocol; - content += "

"; -#endif + if (shunt) { + content += "

Shunt protocol: "; + content += datalayer.system.info.shunt_protocol; + content += "

"; + } if (charger) { content += "

Charger protocol: "; From c101f1a7b11e6514c27adeb4738d629497fa7d84 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Mon, 9 Jun 2025 22:40:27 +0300 Subject: [PATCH 02/14] Initial changes --- Software/src/battery/BATTERIES.h | 19 +------------------ Software/src/battery/BMW-I3-BATTERY.h | 3 ++- Software/src/battery/BMW-IX-BATTERY.h | 3 ++- Software/src/battery/BMW-PHEV-BATTERY.h | 3 ++- Software/src/battery/BMW-SBOX.h | 2 ++ Software/src/battery/BOLT-AMPERA-BATTERY.h | 3 ++- Software/src/battery/BYD-ATTO-3-BATTERY.h | 3 ++- Software/src/battery/CELLPOWER-BMS.h | 1 - Software/src/battery/CHADEMO-BATTERY.h | 1 - Software/src/battery/CMFA-EV-BATTERY.h | 1 - Software/src/battery/DALY-BMS.h | 3 --- Software/src/battery/ECMP-BATTERY.h | 1 - Software/src/battery/FOXESS-BATTERY.h | 1 - .../src/battery/GEELY-GEOMETRY-C-BATTERY.h | 1 - .../src/battery/IMIEV-CZERO-ION-BATTERY.h | 1 - Software/src/battery/JAGUAR-IPACE-BATTERY.h | 1 - Software/src/battery/KIA-E-GMP-BATTERY.h | 1 - Software/src/battery/KIA-HYUNDAI-64-BATTERY.h | 1 - .../src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h | 1 - Software/src/battery/MEB-BATTERY.h | 1 - Software/src/battery/MG-5-BATTERY.h | 1 - Software/src/battery/NISSAN-LEAF-BATTERY.h | 1 - Software/src/battery/ORION-BMS.h | 1 - Software/src/battery/PYLON-BATTERY.h | 1 - .../src/battery/RANGE-ROVER-PHEV-BATTERY.h | 1 - Software/src/battery/RENAULT-KANGOO-BATTERY.h | 1 - Software/src/battery/RENAULT-TWIZY.h | 1 - .../src/battery/RENAULT-ZOE-GEN1-BATTERY.h | 1 - .../src/battery/RENAULT-ZOE-GEN2-BATTERY.h | 1 - Software/src/battery/RJXZS-BMS.h | 1 - Software/src/battery/SANTA-FE-PHEV-BATTERY.h | 1 - Software/src/battery/SIMPBMS-BATTERY.h | 1 - Software/src/battery/SONO-BATTERY.h | 1 - Software/src/battery/TESLA-BATTERY.h | 1 - Software/src/battery/TEST-FAKE-BATTERY.h | 1 - Software/src/battery/VOLVO-SPA-BATTERY.h | 1 - .../src/battery/VOLVO-SPA-HYBRID-BATTERY.h | 1 - Software/src/include.h | 2 +- 38 files changed, 14 insertions(+), 56 deletions(-) diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index a1e38da3..eaad5bd8 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -11,29 +11,12 @@ extern Battery* battery2; void setup_can_shunt(); -#ifdef BMW_SBOX -#include "BMW-SBOX.h" -#endif - -#ifdef BMW_I3_BATTERY #include "BMW-I3-BATTERY.h" -#endif - -#ifdef BMW_IX_BATTERY #include "BMW-IX-BATTERY.h" -#endif - -#ifdef BMW_PHEV_BATTERY #include "BMW-PHEV-BATTERY.h" -#endif - -#ifdef BOLT_AMPERA_BATTERY +#include "BMW-SBOX.h" #include "BOLT-AMPERA-BATTERY.h" -#endif - -#ifdef BYD_ATTO_3_BATTERY #include "BYD-ATTO-3-BATTERY.h" -#endif #ifdef CELLPOWER_BMS #include "CELLPOWER-BMS.h" diff --git a/Software/src/battery/BMW-I3-BATTERY.h b/Software/src/battery/BMW-I3-BATTERY.h index 9a60a0ce..cf79f4db 100644 --- a/Software/src/battery/BMW-I3-BATTERY.h +++ b/Software/src/battery/BMW-I3-BATTERY.h @@ -7,8 +7,9 @@ #include "BMW-I3-HTML.h" #include "CanBattery.h" -#define BATTERY_SELECTED +#ifdef BMW_I3_BATTERY #define SELECTED_BATTERY_CLASS BmwI3Battery +#endif class BmwI3Battery : public CanBattery { public: diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index 68935fad..ed67cb10 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -5,8 +5,9 @@ #include "BMW-IX-HTML.h" #include "CanBattery.h" -#define BATTERY_SELECTED +#ifdef BMW_IX_BATTERY #define SELECTED_BATTERY_CLASS BmwIXBattery +#endif class BmwIXBattery : public CanBattery { public: diff --git a/Software/src/battery/BMW-PHEV-BATTERY.h b/Software/src/battery/BMW-PHEV-BATTERY.h index c50992c5..98f0e640 100644 --- a/Software/src/battery/BMW-PHEV-BATTERY.h +++ b/Software/src/battery/BMW-PHEV-BATTERY.h @@ -5,8 +5,9 @@ #include "BMW-PHEV-HTML.h" #include "CanBattery.h" -#define BATTERY_SELECTED +#ifdef BMW_PHEV_BATTERY #define SELECTED_BATTERY_CLASS BmwPhevBattery +#endif class BmwPhevBattery : public CanBattery { public: diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index ad4046f6..1909c48b 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -2,7 +2,9 @@ #define BMW_SBOX_CONTROL_H #include "../include.h" +#ifdef BMW_SBOX #define SELECTED_SHUNT_CLASS BmwSbox +#endif #include "Shunt.h" diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h index 57fdba84..bf3e6fac 100644 --- a/Software/src/battery/BOLT-AMPERA-BATTERY.h +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -6,8 +6,9 @@ #include "BOLT-AMPERA-HTML.h" #include "CanBattery.h" -#define BATTERY_SELECTED +#ifdef BOLT_AMPERA_BATTERY #define SELECTED_BATTERY_CLASS BoltAmperaBattery +#endif class BoltAmperaBattery : public CanBattery { public: diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.h b/Software/src/battery/BYD-ATTO-3-BATTERY.h index 84baa4d5..7d665622 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.h +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.h @@ -18,8 +18,9 @@ //#define SKIP_TEMPERATURE_SENSOR_NUMBER 1 /* Do not modify the rows below */ -#define BATTERY_SELECTED +#ifdef BYD_ATTO_3_BATTERY #define SELECTED_BATTERY_CLASS BydAttoBattery +#endif #define CELLCOUNT_EXTENDED 126 #define CELLCOUNT_STANDARD 104 diff --git a/Software/src/battery/CELLPOWER-BMS.h b/Software/src/battery/CELLPOWER-BMS.h index 15a4662f..eef6b0d2 100644 --- a/Software/src/battery/CELLPOWER-BMS.h +++ b/Software/src/battery/CELLPOWER-BMS.h @@ -5,7 +5,6 @@ #include "CELLPOWER-HTML.h" #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS CellPowerBms class CellPowerBms : public CanBattery { diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index 7e50841f..57851095 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -11,7 +11,6 @@ // other measurement sources may be added in the future #define ISA_SHUNT -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS ChademoBattery class ChademoBattery : public CanBattery { diff --git a/Software/src/battery/CMFA-EV-BATTERY.h b/Software/src/battery/CMFA-EV-BATTERY.h index 0455838e..ebd51231 100644 --- a/Software/src/battery/CMFA-EV-BATTERY.h +++ b/Software/src/battery/CMFA-EV-BATTERY.h @@ -5,7 +5,6 @@ #include "CMFA-EV-HTML.h" #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS CmfaEvBattery class CmfaEvBattery : public CanBattery { diff --git a/Software/src/battery/DALY-BMS.h b/Software/src/battery/DALY-BMS.h index a8902f85..0ca1b020 100644 --- a/Software/src/battery/DALY-BMS.h +++ b/Software/src/battery/DALY-BMS.h @@ -13,9 +13,6 @@ #define POWER_PER_DEGREE_C 60 // max power added/removed per degree above/below 0°C #define POWER_AT_0_DEGREE_C 800 // power at 0°C -/* Do not modify any rows below*/ -#define BATTERY_SELECTED -#define RS485_BATTERY_SELECTED #define SELECTED_BATTERY_CLASS DalyBms class DalyBms : public RS485Battery { diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index ad3fb041..46e4a8c3 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -6,7 +6,6 @@ #include "CanBattery.h" #include "ECMP-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS EcmpBattery class EcmpBattery : public CanBattery { diff --git a/Software/src/battery/FOXESS-BATTERY.h b/Software/src/battery/FOXESS-BATTERY.h index b5102b8e..429f2a61 100644 --- a/Software/src/battery/FOXESS-BATTERY.h +++ b/Software/src/battery/FOXESS-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS FoxessBattery class FoxessBattery : public CanBattery { diff --git a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h index f724c937..16a126fb 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h +++ b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h @@ -6,7 +6,6 @@ #include "CanBattery.h" #include "GEELY-GEOMETRY-C-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS GeelyGeometryCBattery #define POLL_SOC 0x4B35 diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h index 7ed242a4..14008d61 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS ImievCZeroIonBattery class ImievCZeroIonBattery : public CanBattery { diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.h b/Software/src/battery/JAGUAR-IPACE-BATTERY.h index f91444a0..5c9435eb 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.h +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.h @@ -3,7 +3,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS JaguarIpaceBattery #define MAX_PACK_VOLTAGE_DV 4546 //5000 = 500.0V diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.h b/Software/src/battery/KIA-E-GMP-BATTERY.h index 13e8b6eb..01ec6fb3 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.h +++ b/Software/src/battery/KIA-E-GMP-BATTERY.h @@ -9,7 +9,6 @@ extern ACAN2517FD canfd; #define ESTIMATE_SOC_FROM_CELLVOLTAGE -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS KiaEGmpBattery class KiaEGmpBattery : public CanBattery { diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 62dbbde0..ba0181c4 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -7,7 +7,6 @@ #include "CanBattery.h" #include "KIA-HYUNDAI-64-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS KiaHyundai64Battery class KiaHyundai64Battery : public CanBattery { diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h index 915fdcef..16753590 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS KiaHyundaiHybridBattery class KiaHyundaiHybridBattery : public CanBattery { diff --git a/Software/src/battery/MEB-BATTERY.h b/Software/src/battery/MEB-BATTERY.h index 7895247c..c20f479d 100644 --- a/Software/src/battery/MEB-BATTERY.h +++ b/Software/src/battery/MEB-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" #include "MEB-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS MebBattery class MebBattery : public CanBattery { diff --git a/Software/src/battery/MG-5-BATTERY.h b/Software/src/battery/MG-5-BATTERY.h index ee34249a..4078d38c 100644 --- a/Software/src/battery/MG-5-BATTERY.h +++ b/Software/src/battery/MG-5-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS Mg5Battery class Mg5Battery : public CanBattery { diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 16a68bc2..c29783a6 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -7,7 +7,6 @@ #include "CanBattery.h" #include "NISSAN-LEAF-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS NissanLeafBattery #define EXTENDED_DATA_PTR (&datalayer_extended.nissanleaf) diff --git a/Software/src/battery/ORION-BMS.h b/Software/src/battery/ORION-BMS.h index e2785059..d06c2c90 100644 --- a/Software/src/battery/ORION-BMS.h +++ b/Software/src/battery/ORION-BMS.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS OrionBms class OrionBms : public CanBattery { diff --git a/Software/src/battery/PYLON-BATTERY.h b/Software/src/battery/PYLON-BATTERY.h index cf21aeb5..16843368 100644 --- a/Software/src/battery/PYLON-BATTERY.h +++ b/Software/src/battery/PYLON-BATTERY.h @@ -6,7 +6,6 @@ #include "../include.h" #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS PylonBattery class PylonBattery : public CanBattery { diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h index d1f1b13a..fcde6148 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS RangeRoverPhevBattery class RangeRoverPhevBattery : public CanBattery { diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.h b/Software/src/battery/RENAULT-KANGOO-BATTERY.h index 535f0369..cadca65f 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.h +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS RenaultKangooBattery class RenaultKangooBattery : public CanBattery { diff --git a/Software/src/battery/RENAULT-TWIZY.h b/Software/src/battery/RENAULT-TWIZY.h index f4ab501c..25f15c03 100644 --- a/Software/src/battery/RENAULT-TWIZY.h +++ b/Software/src/battery/RENAULT-TWIZY.h @@ -3,7 +3,6 @@ #include "../include.h" #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS RenaultTwizyBattery class RenaultTwizyBattery : public CanBattery { diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h index 1e566b04..ea38c3a9 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h @@ -4,7 +4,6 @@ #include "CanBattery.h" #include "RENAULT-ZOE-GEN1-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS RenaultZoeGen1Battery #define MAX_PACK_VOLTAGE_DV 4200 //5000 = 500.0V diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h index b3b2b5d7..faae6e73 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" #include "RENAULT-ZOE-GEN2-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS RenaultZoeGen2Battery class RenaultZoeGen2Battery : public CanBattery { diff --git a/Software/src/battery/RJXZS-BMS.h b/Software/src/battery/RJXZS-BMS.h index baabbbb5..e6283f7a 100644 --- a/Software/src/battery/RJXZS-BMS.h +++ b/Software/src/battery/RJXZS-BMS.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS RjxzsBms class RjxzsBms : public CanBattery { diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h index f73e80e3..2b240ba7 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h @@ -5,7 +5,6 @@ #include "../include.h" #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS SantaFePhevBattery class SantaFePhevBattery : public CanBattery { diff --git a/Software/src/battery/SIMPBMS-BATTERY.h b/Software/src/battery/SIMPBMS-BATTERY.h index ac33580d..7c5be60e 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.h +++ b/Software/src/battery/SIMPBMS-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS SimpBmsBattery class SimpBmsBattery : public CanBattery { diff --git a/Software/src/battery/SONO-BATTERY.h b/Software/src/battery/SONO-BATTERY.h index 47907f5e..de62dcdd 100644 --- a/Software/src/battery/SONO-BATTERY.h +++ b/Software/src/battery/SONO-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS SonoBattery class SonoBattery : public CanBattery { diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 7b60cb91..9910c838 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -5,7 +5,6 @@ #include "CanBattery.h" #include "TESLA-HTML.h" -#define BATTERY_SELECTED #ifdef TESLA_MODEL_3Y_BATTERY #define SELECTED_BATTERY_CLASS TeslaModel3YBattery #endif diff --git a/Software/src/battery/TEST-FAKE-BATTERY.h b/Software/src/battery/TEST-FAKE-BATTERY.h index ed79c8b1..1223a634 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.h +++ b/Software/src/battery/TEST-FAKE-BATTERY.h @@ -4,7 +4,6 @@ #include "../include.h" #include "CanBattery.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS TestFakeBattery class TestFakeBattery : public CanBattery { diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.h b/Software/src/battery/VOLVO-SPA-BATTERY.h index 4ea009ed..b958d5da 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-BATTERY.h @@ -6,7 +6,6 @@ #include "CanBattery.h" #include "VOLVO-SPA-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS VolvoSpaBattery class VolvoSpaBattery : public CanBattery { diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h index 70b58cb8..e553dce7 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h @@ -6,7 +6,6 @@ #include "CanBattery.h" #include "VOLVO-SPA-HYBRID-HTML.h" -#define BATTERY_SELECTED #define SELECTED_BATTERY_CLASS VolvoSpaHybridBattery class VolvoSpaHybridBattery : public CanBattery { diff --git a/Software/src/include.h b/Software/src/include.h index d06d89dd..daacf9b0 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -39,7 +39,7 @@ #endif #endif -#ifndef BATTERY_SELECTED +#if !defined(COMMON_IMAGE) && !defined(SELECTED_BATTERY_CLASS) #error No battery selected! Choose one from the USER_SETTINGS.h file #endif From 7d7b6a0d10ecb202f05332e509fd93be31139ab0 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Mon, 9 Jun 2025 23:04:13 +0300 Subject: [PATCH 03/14] More changes --- Software/src/battery/CELLPOWER-BMS.h | 2 ++ Software/src/battery/CHADEMO-BATTERY.h | 6 ++++-- Software/src/battery/CMFA-EV-BATTERY.h | 2 ++ Software/src/battery/FOXESS-BATTERY.h | 2 ++ Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h | 7 ++++++- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Software/src/battery/CELLPOWER-BMS.h b/Software/src/battery/CELLPOWER-BMS.h index eef6b0d2..d5ba8d78 100644 --- a/Software/src/battery/CELLPOWER-BMS.h +++ b/Software/src/battery/CELLPOWER-BMS.h @@ -5,7 +5,9 @@ #include "CELLPOWER-HTML.h" #include "CanBattery.h" +#ifdef CELLPOWER_BMS #define SELECTED_BATTERY_CLASS CellPowerBms +#endif class CellPowerBms : public CanBattery { public: diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index 57851095..5108cced 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -4,14 +4,16 @@ #include "../include.h" #include "CanBattery.h" +#ifdef CHADEMO_BATTERY +#define SELECTED_BATTERY_CLASS ChademoBattery + //Contactor control is required for CHADEMO support #define CONTACTOR_CONTROL //ISA shunt is currently required for CHADEMO support // other measurement sources may be added in the future #define ISA_SHUNT - -#define SELECTED_BATTERY_CLASS ChademoBattery +#endif class ChademoBattery : public CanBattery { public: diff --git a/Software/src/battery/CMFA-EV-BATTERY.h b/Software/src/battery/CMFA-EV-BATTERY.h index ebd51231..625601ae 100644 --- a/Software/src/battery/CMFA-EV-BATTERY.h +++ b/Software/src/battery/CMFA-EV-BATTERY.h @@ -5,7 +5,9 @@ #include "CMFA-EV-HTML.h" #include "CanBattery.h" +#ifdef CMFA_EV_BATTERY #define SELECTED_BATTERY_CLASS CmfaEvBattery +#endif class CmfaEvBattery : public CanBattery { public: diff --git a/Software/src/battery/FOXESS-BATTERY.h b/Software/src/battery/FOXESS-BATTERY.h index 429f2a61..b7ce01e3 100644 --- a/Software/src/battery/FOXESS-BATTERY.h +++ b/Software/src/battery/FOXESS-BATTERY.h @@ -5,7 +5,9 @@ #include "CanBattery.h" +#ifdef FOXESS_BATTERY #define SELECTED_BATTERY_CLASS FoxessBattery +#endif class FoxessBattery : public CanBattery { public: diff --git a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h index 16a126fb..75634c5c 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h +++ b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h @@ -6,7 +6,9 @@ #include "CanBattery.h" #include "GEELY-GEOMETRY-C-HTML.h" +#ifdef GEELY_GEOMETRY_C_BATTERY #define SELECTED_BATTERY_CLASS GeelyGeometryCBattery +#endif #define POLL_SOC 0x4B35 #define POLL_CC2_VOLTAGE 0x4BCF @@ -212,7 +214,10 @@ class GeelyGeometryCBattery : public CanBattery { uint16_t poll_unknown7 = 0; uint16_t poll_unknown8 = 0; int16_t poll_temperature[6] = {0}; -#define TEMP_OFFSET 30 //TODO, not calibrated yet, best guess + + //TODO, not calibrated yet, best guess + static const int TEMP_OFFSET = 30; + uint8_t poll_software_version[16] = {0}; uint8_t poll_hardware_version[16] = {0}; }; From 02917dcbea0a66c6f804e897338aff47c049414f Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Tue, 17 Jun 2025 23:19:26 +0300 Subject: [PATCH 04/14] More batteries to common image --- Software/src/battery/BATTERIES.cpp | 181 +++-- Software/src/battery/BMW-SBOX.cpp | 2 +- Software/src/battery/BMW-SBOX.h | 1 + Software/src/battery/Battery.cpp | 6 + Software/src/battery/Battery.h | 76 +- Software/src/battery/CHADEMO-SHUNTS.h | 3 + Software/src/battery/CMFA-EV-BATTERY.cpp | 2 +- Software/src/battery/CMFA-EV-BATTERY.h | 1 + Software/src/battery/CanBattery.cpp | 8 + Software/src/battery/CanBattery.h | 6 +- Software/src/battery/DALY-BMS.cpp | 2 +- Software/src/battery/DALY-BMS.h | 1 + Software/src/battery/ECMP-BATTERY.cpp | 2 +- Software/src/battery/ECMP-BATTERY.h | 147 ++-- Software/src/battery/FOXESS-BATTERY.cpp | 2 +- Software/src/battery/FOXESS-BATTERY.h | 1 + .../src/battery/GEELY-GEOMETRY-C-BATTERY.cpp | 2 +- .../src/battery/GEELY-GEOMETRY-C-BATTERY.h | 1 + .../src/battery/IMIEV-CZERO-ION-BATTERY.cpp | 2 +- .../src/battery/IMIEV-CZERO-ION-BATTERY.h | 1 + Software/src/battery/JAGUAR-IPACE-BATTERY.h | 1 + Software/src/battery/KIA-E-GMP-BATTERY.cpp | 2 +- Software/src/battery/KIA-E-GMP-BATTERY.h | 1 + .../src/battery/KIA-HYUNDAI-64-BATTERY.cpp | 2 +- Software/src/battery/KIA-HYUNDAI-64-BATTERY.h | 1 + .../battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp | 2 +- .../src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h | 1 + Software/src/battery/MEB-BATTERY.cpp | 2 +- Software/src/battery/MEB-BATTERY.h | 1 + Software/src/battery/MG-5-BATTERY.h | 1 + Software/src/battery/ORION-BMS.cpp | 2 +- Software/src/battery/ORION-BMS.h | 1 + Software/src/battery/PYLON-BATTERY.h | 1 + .../src/battery/RANGE-ROVER-PHEV-BATTERY.cpp | 2 +- .../src/battery/RANGE-ROVER-PHEV-BATTERY.h | 1 + .../src/battery/RENAULT-KANGOO-BATTERY.cpp | 2 +- Software/src/battery/RENAULT-KANGOO-BATTERY.h | 1 + Software/src/battery/RENAULT-TWIZY.cpp | 2 +- Software/src/battery/RENAULT-TWIZY.h | 1 + .../src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp | 2 +- .../src/battery/RENAULT-ZOE-GEN1-BATTERY.h | 1 + .../src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp | 2 +- .../src/battery/RENAULT-ZOE-GEN2-BATTERY.h | 1 + Software/src/battery/RJXZS-BMS.cpp | 2 +- Software/src/battery/RJXZS-BMS.h | 1 + .../src/battery/SANTA-FE-PHEV-BATTERY.cpp | 2 +- Software/src/battery/SANTA-FE-PHEV-BATTERY.h | 1 + Software/src/battery/SIMPBMS-BATTERY.cpp | 2 +- Software/src/battery/SIMPBMS-BATTERY.h | 1 + Software/src/battery/SONO-BATTERY.cpp | 2 +- Software/src/battery/SONO-BATTERY.h | 1 + Software/src/battery/VOLVO-SPA-BATTERY.cpp | 2 +- Software/src/battery/VOLVO-SPA-BATTERY.h | 1 + .../src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp | 4 +- .../src/battery/VOLVO-SPA-HYBRID-BATTERY.h | 1 + Software/src/communication/can/CanReceiver.h | 1 - .../comm_contactorcontrol.cpp | 22 +- .../contactorcontrol/comm_contactorcontrol.h | 1 + Software/src/communication/nvm/comm_nvm.cpp | 1 + Software/src/communication/nvm/comm_nvm.h | 18 +- Software/src/devboard/safety/safety.cpp | 279 +++---- Software/src/devboard/utils/types.h | 3 + .../src/devboard/webserver/settings_html.cpp | 23 +- Software/src/devboard/webserver/webserver.cpp | 759 +++++++++--------- 64 files changed, 885 insertions(+), 722 deletions(-) create mode 100644 Software/src/battery/Battery.cpp create mode 100644 Software/src/battery/CanBattery.cpp diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index f001dd4a..89d5f89c 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -19,6 +19,8 @@ std::vector supported_battery_types() { extern const char* name_for_type(BatteryType type) { switch (type) { + case BatteryType::None: + return "None"; case BatteryType::BmwI3: return BmwI3Battery::Name; case BatteryType::BmwIx: @@ -31,19 +33,67 @@ extern const char* name_for_type(BatteryType type) { return CellPowerBms::Name; case BatteryType::Chademo: return ChademoBattery::Name; + case BatteryType::CmfaEv: + return CmfaEvBattery::Name; + case BatteryType::Foxess: + return FoxessBattery::Name; + case BatteryType::GeelyGeometryC: + return GeelyGeometryCBattery::Name; + case BatteryType::OrionBms: + return OrionBms::Name; + case BatteryType::Sono: + return SonoBattery::Name; + case BatteryType::StellantisEcmp: + return EcmpBattery::Name; + case BatteryType::ImievCZeroIon: + return ImievCZeroIonBattery::Name; + case BatteryType::JaguarIpace: + return JaguarIpaceBattery::Name; + case BatteryType::KiaEGmp: + return KiaEGmpBattery::Name; + case BatteryType::KiaHyundai64: + return KiaHyundai64Battery::Name; + case BatteryType::KiaHyundaiHybrid: + return KiaHyundaiHybridBattery::Name; + case BatteryType::Meb: + return MebBattery::Name; + case BatteryType::Mg5: + return Mg5Battery::Name; case BatteryType::NissanLeaf: return NissanLeafBattery::Name; - case BatteryType::TestFake: - return TestFakeBattery::Name; + case BatteryType::Pylon: + return PylonBattery::Name; + case BatteryType::DalyBms: + return DalyBms::Name; + case BatteryType::RjxzsBms: + return RjxzsBms::Name; + case BatteryType::RangeRoverPhev: + return RangeRoverPhevBattery::Name; + case BatteryType::RenaultKangoo: + return RenaultKangooBattery::Name; + case BatteryType::RenaultTwizy: + return RenaultTwizyBattery::Name; + case BatteryType::RenaultZoe1: + return RenaultZoeGen1Battery::Name; + case BatteryType::RenaultZoe2: + return RenaultZoeGen2Battery::Name; + case BatteryType::SantaFePhev: + return SantaFePhevBattery::Name; + case BatteryType::SimpBms: + return SimpBmsBattery::Name; case BatteryType::TeslaModel3Y: return TeslaModel3YBattery::Name; case BatteryType::TeslaModelSX: return TeslaModelSXBattery::Name; - case BatteryType::None: - return "None"; + case BatteryType::TestFake: + return TestFakeBattery::Name; + case BatteryType::VolvoSpa: + return VolvoSpaBattery::Name; + case BatteryType::VolvoSpaHybrid: + return VolvoSpaHybridBattery::Name; + default: + return nullptr; } - - return nullptr; } #ifdef COMMON_IMAGE @@ -54,51 +104,92 @@ extern const char* name_for_type(BatteryType type) { BatteryType user_selected_battery_type = BatteryType::NissanLeaf; bool user_selected_second_battery = false; -void setup_battery() { +Battery* create_battery(BatteryType type) { + switch (type) { + case BatteryType::None: + return nullptr; + case BatteryType::BmwI3: + return new BmwI3Battery(); + case BatteryType::BmwIx: + return new BmwIXBattery(); + case BatteryType::BoltAmpera: + return new BoltAmperaBattery(); + case BatteryType::BydAtto3: + return new BydAttoBattery(); + case BatteryType::CellPowerBms: + return new CellPowerBms(); + case BatteryType::Chademo: + return new ChademoBattery(); + case BatteryType::CmfaEv: + return new CmfaEvBattery(); + case BatteryType::Foxess: + return new FoxessBattery(); + case BatteryType::GeelyGeometryC: + return new GeelyGeometryCBattery(); + case BatteryType::OrionBms: + return new OrionBms(); + case BatteryType::Sono: + return new SonoBattery(); + case BatteryType::StellantisEcmp: + return new EcmpBattery(); + case BatteryType::ImievCZeroIon: + return new ImievCZeroIonBattery(); + case BatteryType::JaguarIpace: + return new JaguarIpaceBattery(); + case BatteryType::KiaEGmp: + return new KiaEGmpBattery(); + case BatteryType::KiaHyundai64: + return new KiaHyundai64Battery(); + case BatteryType::KiaHyundaiHybrid: + return new KiaHyundaiHybridBattery(); + case BatteryType::Meb: + return new MebBattery(); + case BatteryType::Mg5: + return new Mg5Battery(); + case BatteryType::NissanLeaf: + return new NissanLeafBattery(); + case BatteryType::Pylon: + return new PylonBattery(); + case BatteryType::DalyBms: + return new DalyBms(); + case BatteryType::RjxzsBms: + return new RjxzsBms(); + case BatteryType::RangeRoverPhev: + return new RangeRoverPhevBattery(); + case BatteryType::RenaultKangoo: + return new RenaultKangooBattery(); + case BatteryType::RenaultTwizy: + return new RenaultTwizyBattery(); + case BatteryType::RenaultZoe1: + return new RenaultZoeGen1Battery(); + case BatteryType::RenaultZoe2: + return new RenaultZoeGen2Battery(); + case BatteryType::SantaFePhev: + return new SantaFePhevBattery(); + case BatteryType::SimpBms: + return new SimpBmsBattery(); + case BatteryType::TeslaModel3Y: + return new TeslaModel3YBattery(); + case BatteryType::TeslaModelSX: + return new TeslaModelSXBattery(); + case BatteryType::TestFake: + return new TestFakeBattery(); + case BatteryType::VolvoSpa: + return new VolvoSpaBattery(); + case BatteryType::VolvoSpaHybrid: + return new VolvoSpaHybridBattery(); + default: + return nullptr; + } +} +void setup_battery() { if (battery) { // Let's not create the battery again. return; } - switch (user_selected_battery_type) { - case BatteryType::BmwI3: - battery = new BmwI3Battery(); - break; - case BatteryType::BmwIx: - battery = new BmwIXBattery(); - break; - case BatteryType::BoltAmpera: - battery = new BoltAmperaBattery(); - break; - case BatteryType::BydAtto3: - battery = new BydAttoBattery(); - break; - case BatteryType::CellPowerBms: - battery = new CellPowerBms(); - break; - case BatteryType::Chademo: - battery = new ChademoBattery(); - break; - case BatteryType::CmfaEv: - battery = new CmfaEvBattery(); - break; - case BatteryType::DalyBms: - battery = new DalyBms(); - break; - case BatteryType::NissanLeaf: - battery = new NissanLeafBattery(); - break; - case BatteryType::TeslaModel3Y: - battery = new TeslaModel3YBattery(); - break; - case BatteryType::TeslaModelSX: - battery = new TeslaModelSXBattery(); - break; - case BatteryType::TestFake: - battery = new TestFakeBattery(); - break; - } + battery = create_battery(user_selected_battery_type); if (battery) { battery->setup(); diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index 506aa310..69760107 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -178,6 +178,6 @@ void BmwSbox::transmit_can(unsigned long currentMillis) { } void BmwSbox::setup() { - strncpy(datalayer.system.info.shunt_protocol, "BMW SBOX", 63); + strncpy(datalayer.system.info.shunt_protocol, Name, 63); datalayer.system.info.shunt_protocol[63] = '\0'; } diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index 1909c48b..ea2bd72c 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -13,6 +13,7 @@ class BmwSbox : public CanShunt { void setup(); void transmit_can(unsigned long currentMillis); void handle_incoming_can_frame(CAN_frame rx_frame); + static constexpr char* Name = "BMW SBOX"; private: /** Minimum input voltage required to enable relay control **/ diff --git a/Software/src/battery/Battery.cpp b/Software/src/battery/Battery.cpp new file mode 100644 index 00000000..02280f52 --- /dev/null +++ b/Software/src/battery/Battery.cpp @@ -0,0 +1,6 @@ +#include "Battery.h" +#include "../datalayer/datalayer.h" + +float Battery::get_voltage() { + return static_cast(datalayer.battery.status.voltage_dV) / 10.0; +} diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index a323f20a..61a798d6 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -1,47 +1,47 @@ #ifndef BATTERY_H #define BATTERY_H -#include "../datalayer/datalayer.h" +#include #include "src/devboard/webserver/BatteryHtmlRenderer.h" enum class BatteryType { None = 0, - BmwSbox, - BmwI3, - BmwIx, - BoltAmpera, - BydAtto3, - CellPowerBms, - Chademo, - CmfaEv, - Foxess, - GeelyGeometryC, - OrionBms, - Sono, - StellantisEcmp, - ImievCZeroIon, - JaguarIpace, - KiaEGmp, - KiaHyundai64, - KiaHyundaiHybrid, - Meb, - Mg5, - NissanLeaf, - Pylon, - DalyBms, - RjxzsBms, - RangeRoverPhev, - RenaultKangoo, - RenaultTwizy, - RenaultZoe1, - RenaultZoe2, - SantaFePhev, - SimpBms, - TeslaModel3Y, - TeslaModelSX, - TestFake, - VolvoSpa, - VolvoSpaHybrid, + BmwSbox = 1, + BmwI3 = 2, + BmwIx = 3, + BoltAmpera = 4, + BydAtto3 = 5, + CellPowerBms = 6, + Chademo = 7, + CmfaEv = 8, + Foxess = 9, + GeelyGeometryC = 10, + OrionBms = 11, + Sono = 12, + StellantisEcmp = 13, + ImievCZeroIon = 14, + JaguarIpace = 15, + KiaEGmp = 16, + KiaHyundai64 = 17, + KiaHyundaiHybrid = 18, + Meb = 19, + Mg5 = 20, + NissanLeaf = 21, + Pylon = 22, + DalyBms = 23, + RjxzsBms = 24, + RangeRoverPhev = 25, + RenaultKangoo = 26, + RenaultTwizy = 27, + RenaultZoe1 = 28, + RenaultZoe2 = 29, + SantaFePhev = 30, + SimpBms = 31, + TeslaModel3Y = 32, + TeslaModelSX = 33, + TestFake = 34, + VolvoSpa = 35, + VolvoSpaHybrid = 36, Highest }; @@ -95,7 +95,7 @@ class Battery { virtual void set_factory_mode() {} virtual void set_fake_voltage(float v) {} - virtual float get_voltage() { return static_cast(datalayer.battery.status.voltage_dV) / 10.0; } + virtual float get_voltage(); // This allows for battery specific SOC plausibility calculations to be performed. virtual bool soc_plausible() { return true; } diff --git a/Software/src/battery/CHADEMO-SHUNTS.h b/Software/src/battery/CHADEMO-SHUNTS.h index ce23bb1a..7a3cf855 100644 --- a/Software/src/battery/CHADEMO-SHUNTS.h +++ b/Software/src/battery/CHADEMO-SHUNTS.h @@ -1,6 +1,9 @@ #ifndef CHADEMO_SHUNTS_H #define CHADEMO_SHUNTS_H +#include +#include "../devboard/utils/types.h" + uint16_t get_measured_voltage(); uint16_t get_measured_current(); void ISA_handleFrame(CAN_frame* frame); diff --git a/Software/src/battery/CMFA-EV-BATTERY.cpp b/Software/src/battery/CMFA-EV-BATTERY.cpp index eaa82140..34d47059 100644 --- a/Software/src/battery/CMFA-EV-BATTERY.cpp +++ b/Software/src/battery/CMFA-EV-BATTERY.cpp @@ -940,7 +940,7 @@ void CmfaEvBattery::transmit_can(unsigned long currentMillis) { } void CmfaEvBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "CMFA platform, 27 kWh battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 72; diff --git a/Software/src/battery/CMFA-EV-BATTERY.h b/Software/src/battery/CMFA-EV-BATTERY.h index 625601ae..b1dcb3da 100644 --- a/Software/src/battery/CMFA-EV-BATTERY.h +++ b/Software/src/battery/CMFA-EV-BATTERY.h @@ -15,6 +15,7 @@ class CmfaEvBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "CMFA platform, 27 kWh battery"; BatteryHtmlRenderer& get_status_renderer() { return renderer; } diff --git a/Software/src/battery/CanBattery.cpp b/Software/src/battery/CanBattery.cpp new file mode 100644 index 00000000..69366999 --- /dev/null +++ b/Software/src/battery/CanBattery.cpp @@ -0,0 +1,8 @@ +#include "CanBattery.h" +#include "../../src/include.h" + +CanBattery::CanBattery() { + can_interface = can_config.battery; + register_transmitter(this); + register_can_receiver(this, can_interface); +} diff --git a/Software/src/battery/CanBattery.h b/Software/src/battery/CanBattery.h index 936c2a74..0b8b0467 100644 --- a/Software/src/battery/CanBattery.h +++ b/Software/src/battery/CanBattery.h @@ -22,11 +22,7 @@ class CanBattery : public Battery, Transmitter, CanReceiver { protected: CAN_Interface can_interface; - CanBattery() { - can_interface = can_config.battery; - register_transmitter(this); - register_can_receiver(this, can_interface); - } + CanBattery(); CanBattery(CAN_Interface interface) { can_interface = interface; diff --git a/Software/src/battery/DALY-BMS.cpp b/Software/src/battery/DALY-BMS.cpp index dfb635c4..d949445a 100644 --- a/Software/src/battery/DALY-BMS.cpp +++ b/Software/src/battery/DALY-BMS.cpp @@ -60,7 +60,7 @@ void DalyBms::update_values() { } void DalyBms::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "DALY RS485", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = CELL_COUNT; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/DALY-BMS.h b/Software/src/battery/DALY-BMS.h index f597fa2e..1c5a2015 100644 --- a/Software/src/battery/DALY-BMS.h +++ b/Software/src/battery/DALY-BMS.h @@ -13,6 +13,7 @@ class DalyBms : public RS485Battery { void update_values(); void transmit_rs485(unsigned long currentMillis); void receive(); + static constexpr char* Name = "DALY RS485"; private: /* Tweak these according to your battery build */ diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 04a04f02..7f6d3d59 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -1516,7 +1516,7 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) { } void EcmpBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Stellantis ECMP battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 108; datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index e473b52a..c6f0f451 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -16,6 +16,7 @@ class EcmpBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Stellantis ECMP battery"; bool supports_clear_isolation() { return true; } void clear_isolation() { datalayer_extended.stellantisECMP.UserRequestIsolationReset = true; } @@ -38,8 +39,8 @@ class EcmpBattery : public CanBattery { static const int MAX_CELL_DEVIATION_MV = 100; static const int MAX_CELL_VOLTAGE_MV = 4250; static const int MIN_CELL_VOLTAGE_MV = 2700; -#define NOT_SAMPLED_YET 255 -#define COMPLETED_STATE 0 + static const int NOT_SAMPLED_YET = 255; + static const int COMPLETED_STATE = 0; bool battery_RelayOpenRequest = false; bool battery_InterlockOpen = false; uint8_t ContactorResetStatemachine = 0; @@ -143,77 +144,77 @@ class EcmpBattery : public CanBattery { unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was sent unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent unsigned long previousMillis5000 = 0; // will store last time a 1000ms CAN Message was sent -#define PID_WELD_CHECK 0xD814 -#define PID_CONT_REASON_OPEN 0xD812 -#define PID_CONTACTOR_STATUS 0xD813 -#define PID_NEG_CONT_CONTROL 0xD44F -#define PID_NEG_CONT_STATUS 0xD453 -#define PID_POS_CONT_CONTROL 0xD44E -#define PID_POS_CONT_STATUS 0xD452 -#define PID_CONTACTOR_NEGATIVE 0xD44C -#define PID_CONTACTOR_POSITIVE 0xD44D -#define PID_PRECHARGE_RELAY_CONTROL 0xD44B -#define PID_PRECHARGE_RELAY_STATUS 0xD451 -#define PID_RECHARGE_STATUS 0xD864 -#define PID_DELTA_TEMPERATURE 0xD878 -#define PID_COLDEST_MODULE 0xD446 -#define PID_LOWEST_TEMPERATURE 0xD87D -#define PID_AVERAGE_TEMPERATURE 0xD877 -#define PID_HIGHEST_TEMPERATURE 0xD817 -#define PID_HOTTEST_MODULE 0xD445 -#define PID_AVG_CELL_VOLTAGE 0xD43D -#define PID_CURRENT 0xD816 -#define PID_INSULATION_NEG 0xD87C -#define PID_INSULATION_POS 0xD87B -#define PID_MAX_CURRENT_10S 0xD876 -#define PID_MAX_DISCHARGE_10S 0xD873 -#define PID_MAX_DISCHARGE_30S 0xD874 -#define PID_MAX_CHARGE_10S 0xD871 -#define PID_MAX_CHARGE_30S 0xD872 -#define PID_ENERGY_CAPACITY 0xD860 -#define PID_HIGH_CELL_NUM 0xD43B -#define PID_LOW_CELL_NUM 0xD43C -#define PID_SUM_OF_CELLS 0xD438 -#define PID_CELL_MIN_CAPACITY 0xD413 -#define PID_CELL_VOLTAGE_MEAS_STATUS 0xD48A -#define PID_INSULATION_RES 0xD47A -#define PID_PACK_VOLTAGE 0xD815 -#define PID_HIGH_CELL_VOLTAGE 0xD870 -#define PID_ALL_CELL_VOLTAGES 0xD440 //Multi-frame -#define PID_LOW_CELL_VOLTAGE 0xD86F -#define PID_BATTERY_ENERGY 0xD865 -#define PID_BATTERY_ENERGY 0xD865 -#define PID_CELLBALANCE_STATUS 0xD46F //Multi-frame? -#define PID_CELLBALANCE_HWERR_MASK 0xD470 //Multi-frame -#define PID_CRASH_COUNTER 0xD42F -#define PID_WIRE_CRASH 0xD87F -#define PID_CAN_CRASH 0xD48D -#define PID_HISTORY_DATA 0xD465 -#define PID_LOWSOC_COUNTER 0xD492 //Not supported on all batteris -#define PID_LAST_CAN_FAILURE_DETAIL 0xD89E //Not supported on all batteris -#define PID_HW_VERSION_NUM 0xF193 //Not supported on all batteris -#define PID_SW_VERSION_NUM 0xF195 //Not supported on all batteris -#define PID_FACTORY_MODE_CONTROL 0xD900 -#define PID_BATTERY_SERIAL 0xD901 -#define PID_ALL_CELL_SOH 0xD4B5 //Very long message reply, too much data for this integration -#define PID_AUX_FUSE_STATE 0xD86C -#define PID_BATTERY_STATE 0xD811 -#define PID_PRECHARGE_SHORT_CIRCUIT 0xD4D8 -#define PID_ESERVICE_PLUG_STATE 0xD86A -#define PID_MAINFUSE_STATE 0xD86B -#define PID_MOST_CRITICAL_FAULT 0xD481 -#define PID_CURRENT_TIME 0xD47F -#define PID_TIME_SENT_BY_CAR 0xD4CA -#define PID_12V 0xD822 -#define PID_12V_ABNORMAL 0xD42B -#define PID_HVIL_IN_VOLTAGE 0xD46B -#define PID_HVIL_OUT_VOLTAGE 0xD46A -#define PID_HVIL_STATE 0xD869 -#define PID_BMS_STATE 0xD45A -#define PID_VEHICLE_SPEED 0xD802 -#define PID_TIME_SPENT_OVER_55C 0xE082 -#define PID_CONTACTOR_CLOSING_COUNTER 0xD416 -#define PID_DATE_OF_MANUFACTURE 0xF18B + + static const uint16_t PID_WELD_CHECK = 0xD814; + static const uint16_t PID_CONT_REASON_OPEN = 0xD812; + static const uint16_t PID_CONTACTOR_STATUS = 0xD813; + static const uint16_t PID_NEG_CONT_CONTROL = 0xD44F; + static const uint16_t PID_NEG_CONT_STATUS = 0xD453; + static const uint16_t PID_POS_CONT_CONTROL = 0xD44E; + static const uint16_t PID_POS_CONT_STATUS = 0xD452; + static const uint16_t PID_CONTACTOR_NEGATIVE = 0xD44C; + static const uint16_t PID_CONTACTOR_POSITIVE = 0xD44D; + static const uint16_t PID_PRECHARGE_RELAY_CONTROL = 0xD44B; + static const uint16_t PID_PRECHARGE_RELAY_STATUS = 0xD451; + static const uint16_t PID_RECHARGE_STATUS = 0xD864; + static const uint16_t PID_DELTA_TEMPERATURE = 0xD878; + static const uint16_t PID_COLDEST_MODULE = 0xD446; + static const uint16_t PID_LOWEST_TEMPERATURE = 0xD87D; + static const uint16_t PID_AVERAGE_TEMPERATURE = 0xD877; + static const uint16_t PID_HIGHEST_TEMPERATURE = 0xD817; + static const uint16_t PID_HOTTEST_MODULE = 0xD445; + static const uint16_t PID_AVG_CELL_VOLTAGE = 0xD43D; + static const uint16_t PID_CURRENT = 0xD816; + static const uint16_t PID_INSULATION_NEG = 0xD87C; + static const uint16_t PID_INSULATION_POS = 0xD87B; + static const uint16_t PID_MAX_CURRENT_10S = 0xD876; + static const uint16_t PID_MAX_DISCHARGE_10S = 0xD873; + static const uint16_t PID_MAX_DISCHARGE_30S = 0xD874; + static const uint16_t PID_MAX_CHARGE_10S = 0xD871; + static const uint16_t PID_MAX_CHARGE_30S = 0xD872; + static const uint16_t PID_ENERGY_CAPACITY = 0xD860; + static const uint16_t PID_HIGH_CELL_NUM = 0xD43B; + static const uint16_t PID_LOW_CELL_NUM = 0xD43C; + static const uint16_t PID_SUM_OF_CELLS = 0xD438; + static const uint16_t PID_CELL_MIN_CAPACITY = 0xD413; + static const uint16_t PID_CELL_VOLTAGE_MEAS_STATUS = 0xD48A; + static const uint16_t PID_INSULATION_RES = 0xD47A; + static const uint16_t PID_PACK_VOLTAGE = 0xD815; + static const uint16_t PID_HIGH_CELL_VOLTAGE = 0xD870; + static const uint16_t PID_ALL_CELL_VOLTAGES = 0xD440; //Multi-frame + static const uint16_t PID_LOW_CELL_VOLTAGE = 0xD86F; + static const uint16_t PID_BATTERY_ENERGY = 0xD865; + static const uint16_t PID_CELLBALANCE_STATUS = 0xD46F; //Multi-frame? + static const uint16_t PID_CELLBALANCE_HWERR_MASK = 0xD470; //Multi-frame + static const uint16_t PID_CRASH_COUNTER = 0xD42F; + static const uint16_t PID_WIRE_CRASH = 0xD87F; + static const uint16_t PID_CAN_CRASH = 0xD48D; + static const uint16_t PID_HISTORY_DATA = 0xD465; + static const uint16_t PID_LOWSOC_COUNTER = 0xD492; //Not supported on all batteris + static const uint16_t PID_LAST_CAN_FAILURE_DETAIL = 0xD89E; //Not supported on all batteris + static const uint16_t PID_HW_VERSION_NUM = 0xF193; //Not supported on all batteris + static const uint16_t PID_SW_VERSION_NUM = 0xF195; //Not supported on all batteris + static const uint16_t PID_FACTORY_MODE_CONTROL = 0xD900; + static const uint16_t PID_BATTERY_SERIAL = 0xD901; + static const uint16_t PID_ALL_CELL_SOH = 0xD4B5; //Very long message reply, too much data for this integration + static const uint16_t PID_AUX_FUSE_STATE = 0xD86C; + static const uint16_t PID_BATTERY_STATE = 0xD811; + static const uint16_t PID_PRECHARGE_SHORT_CIRCUIT = 0xD4D8; + static const uint16_t PID_ESERVICE_PLUG_STATE = 0xD86A; + static const uint16_t PID_MAINFUSE_STATE = 0xD86B; + static const uint16_t PID_MOST_CRITICAL_FAULT = 0xD481; + static const uint16_t PID_CURRENT_TIME = 0xD47F; + static const uint16_t PID_TIME_SENT_BY_CAR = 0xD4CA; + static const uint16_t PID_12V = 0xD822; + static const uint16_t PID_12V_ABNORMAL = 0xD42B; + static const uint16_t PID_HVIL_IN_VOLTAGE = 0xD46B; + static const uint16_t PID_HVIL_OUT_VOLTAGE = 0xD46A; + static const uint16_t PID_HVIL_STATE = 0xD869; + static const uint16_t PID_BMS_STATE = 0xD45A; + static const uint16_t PID_VEHICLE_SPEED = 0xD802; + static const uint16_t PID_TIME_SPENT_OVER_55C = 0xE082; + static const uint16_t PID_CONTACTOR_CLOSING_COUNTER = 0xD416; + static const uint16_t PID_DATE_OF_MANUFACTURE = 0xF18B; uint16_t poll_state = PID_WELD_CHECK; uint16_t incoming_poll = 0; diff --git a/Software/src/battery/FOXESS-BATTERY.cpp b/Software/src/battery/FOXESS-BATTERY.cpp index 20d7f105..4225d509 100644 --- a/Software/src/battery/FOXESS-BATTERY.cpp +++ b/Software/src/battery/FOXESS-BATTERY.cpp @@ -572,7 +572,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) { } void FoxessBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "FoxESS HV2600/ECS4100 OEM battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 0; //Startup with no cells, populates later when we know packsize datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/FOXESS-BATTERY.h b/Software/src/battery/FOXESS-BATTERY.h index b7ce01e3..e5143dc6 100644 --- a/Software/src/battery/FOXESS-BATTERY.h +++ b/Software/src/battery/FOXESS-BATTERY.h @@ -15,6 +15,7 @@ class FoxessBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "FoxESS HV2600/ECS4100 OEM battery"; private: static const int MAX_PACK_VOLTAGE_DV = 4672; //467.2V for HS20.8 (used during startup, refined later) diff --git a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp index 11269d08..ede65130 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp +++ b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.cpp @@ -660,7 +660,7 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) { } void GeelyGeometryCBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Geely Geometry C", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer_battery->info.number_of_cells = 102; //70kWh pack has 102S, startup in this mode diff --git a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h index 6d6d7c44..abba1220 100644 --- a/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h +++ b/Software/src/battery/GEELY-GEOMETRY-C-BATTERY.h @@ -16,6 +16,7 @@ class GeelyGeometryCBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Geely Geometry C"; BatteryHtmlRenderer& get_status_renderer() { return renderer; } diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index 6e31a616..69e4478e 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -190,7 +190,7 @@ void ImievCZeroIonBattery::transmit_can(unsigned long currentMillis) { } void ImievCZeroIonBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "I-Miev / C-Zero / Ion Triplet", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h index df3dc437..1c6dc127 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h @@ -15,6 +15,7 @@ class ImievCZeroIonBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "I-Miev / C-Zero / Ion Triplet"; private: static const int MAX_PACK_VOLTAGE_DV = 3696; //5000 = 500.0V diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.h b/Software/src/battery/JAGUAR-IPACE-BATTERY.h index c997bef4..e97ccab5 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.h +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.h @@ -13,6 +13,7 @@ class JaguarIpaceBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Jaguar I-PACE"; private: static const int MAX_PACK_VOLTAGE_DV = 4546; //5000 = 500.0V diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index d6f5bd4f..43576212 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -1090,7 +1090,7 @@ void KiaEGmpBattery::transmit_can(unsigned long currentMillis) { } void KiaEGmpBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.h b/Software/src/battery/KIA-E-GMP-BATTERY.h index 66edc935..faabeb27 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.h +++ b/Software/src/battery/KIA-E-GMP-BATTERY.h @@ -19,6 +19,7 @@ class KiaEGmpBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Kia/Hyundai EGMP platform"; private: uint16_t estimateSOC(uint16_t packVoltage, uint16_t cellCount, int16_t currentAmps); diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index ad95ac77..f0c2a7cc 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -464,7 +464,7 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) { } void KiaHyundai64Battery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 80f17277..943dfa53 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -35,6 +35,7 @@ class KiaHyundai64Battery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Kia/Hyundai 64/40kWh battery"; BatteryHtmlRenderer& get_status_renderer() { return renderer; } diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index f7a03814..1372dd8f 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -214,7 +214,7 @@ void KiaHyundaiHybridBattery::transmit_can(unsigned long currentMillis) { } void KiaHyundaiHybridBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai Hybrid", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h index 343eadca..35503754 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h @@ -15,6 +15,7 @@ class KiaHyundaiHybridBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Kia/Hyundai Hybrid"; private: static const int MAX_PACK_VOLTAGE_DV = 2550; //5000 = 500.0V diff --git a/Software/src/battery/MEB-BATTERY.cpp b/Software/src/battery/MEB-BATTERY.cpp index 776c3597..0ac01e26 100644 --- a/Software/src/battery/MEB-BATTERY.cpp +++ b/Software/src/battery/MEB-BATTERY.cpp @@ -2035,7 +2035,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) { } void MebBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volkswagen Group MEB platform via CAN-FD", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 108; //Startup in 108S mode. We figure out the actual count later. datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; //Defined later to correct pack size diff --git a/Software/src/battery/MEB-BATTERY.h b/Software/src/battery/MEB-BATTERY.h index 69def6a3..33e93434 100644 --- a/Software/src/battery/MEB-BATTERY.h +++ b/Software/src/battery/MEB-BATTERY.h @@ -17,6 +17,7 @@ class MebBattery : public CanBattery { virtual void transmit_can(unsigned long currentMillis); bool supports_real_BMS_status() { return true; } bool supports_charged_energy() { return true; } + static constexpr char* Name = "Volkswagen Group MEB platform via CAN-FD"; BatteryHtmlRenderer& get_status_renderer() { return renderer; } diff --git a/Software/src/battery/MG-5-BATTERY.h b/Software/src/battery/MG-5-BATTERY.h index 9e9680e6..2c343bdf 100644 --- a/Software/src/battery/MG-5-BATTERY.h +++ b/Software/src/battery/MG-5-BATTERY.h @@ -15,6 +15,7 @@ class Mg5Battery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "MG 5 battery"; private: static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V diff --git a/Software/src/battery/ORION-BMS.cpp b/Software/src/battery/ORION-BMS.cpp index 40876223..a8688b56 100644 --- a/Software/src/battery/ORION-BMS.cpp +++ b/Software/src/battery/ORION-BMS.cpp @@ -114,7 +114,7 @@ void OrionBms::transmit_can(unsigned long currentMillis) { } void OrionBms::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "DIY battery with Orion BMS (Victron setting)", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = NUMBER_OF_CELLS; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/ORION-BMS.h b/Software/src/battery/ORION-BMS.h index fe549693..6fa17fc3 100644 --- a/Software/src/battery/ORION-BMS.h +++ b/Software/src/battery/ORION-BMS.h @@ -15,6 +15,7 @@ class OrionBms : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "DIY battery with Orion BMS (Victron setting)"; private: /* Change the following to suit your battery */ diff --git a/Software/src/battery/PYLON-BATTERY.h b/Software/src/battery/PYLON-BATTERY.h index 308d7d07..9b5bb88d 100644 --- a/Software/src/battery/PYLON-BATTERY.h +++ b/Software/src/battery/PYLON-BATTERY.h @@ -31,6 +31,7 @@ class PylonBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Pylon compatible battery"; private: /* Change the following to suit your battery */ diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index 7d481ff5..bfa50b6d 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -207,7 +207,7 @@ void RangeRoverPhevBattery::transmit_can(unsigned long currentMillis) { } void RangeRoverPhevBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Range Rover 13kWh PHEV battery (L494/L405)", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h index 9c69fbe7..d3d4da37 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h @@ -15,6 +15,7 @@ class RangeRoverPhevBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Range Rover 13kWh PHEV battery (L494/L405)"; private: /* Change the following to suit your battery */ diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index 903389d1..db43b95b 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -181,7 +181,7 @@ void RenaultKangooBattery::transmit_can(unsigned long currentMillis) { } void RenaultKangooBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Kangoo", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.h b/Software/src/battery/RENAULT-KANGOO-BATTERY.h index 68bb2939..3a6f6732 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.h +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.h @@ -15,6 +15,7 @@ class RenaultKangooBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Renault Kangoo"; private: static const int MAX_PACK_VOLTAGE_DV = 4150; //5000 = 500.0V diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index 051a5ee7..21aa8a46 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -118,7 +118,7 @@ void RenaultTwizyBattery::transmit_can(unsigned long currentMillis) { } void RenaultTwizyBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Twizy", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 14; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RENAULT-TWIZY.h b/Software/src/battery/RENAULT-TWIZY.h index 5796bb73..f2388a4f 100644 --- a/Software/src/battery/RENAULT-TWIZY.h +++ b/Software/src/battery/RENAULT-TWIZY.h @@ -13,6 +13,7 @@ class RenaultTwizyBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Renault Twizy"; private: static const int MAX_PACK_VOLTAGE_DV = 579; // 57.9V at 100% SOC (with 70% SOH, new one might be higher) diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index d9985494..fa64d9f4 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -513,7 +513,7 @@ void RenaultZoeGen1Battery::transmit_can(unsigned long currentMillis) { } void RenaultZoeGen1Battery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer_battery->info.number_of_cells = 96; diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h index 093ccf6d..8b15d164 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h @@ -31,6 +31,7 @@ class RenaultZoeGen1Battery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Renault Zoe Gen1 22/40kWh"; BatteryHtmlRenderer& get_status_renderer() { return renderer; } diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index 4bb230c8..4970f7bd 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -704,7 +704,7 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) { } void RenaultZoeGen2Battery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen2 50kWh", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.system.status.battery_allows_contactor_closing = true; datalayer.battery.info.number_of_cells = 96; diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h index ce3d37d0..2d908345 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h @@ -15,6 +15,7 @@ class RenaultZoeGen2Battery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Renault Zoe Gen2 50kWh"; bool supports_reset_NVROL() { return true; } diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index ff62bb8c..fda2c42b 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -516,7 +516,7 @@ void RjxzsBms::transmit_can(unsigned long currentMillis) { } void RjxzsBms::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "RJXZS BMS, DIY battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/RJXZS-BMS.h b/Software/src/battery/RJXZS-BMS.h index 4c85ae5d..569c62e5 100644 --- a/Software/src/battery/RJXZS-BMS.h +++ b/Software/src/battery/RJXZS-BMS.h @@ -15,6 +15,7 @@ class RjxzsBms : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "RJXZS BMS, DIY battery"; private: /* Tweak these according to your battery build */ diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 2b7dbe64..783e42b4 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -319,7 +319,7 @@ void SantaFePhevBattery::transmit_can(unsigned long currentMillis) { } void SantaFePhevBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer_battery->info.number_of_cells = 96; datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h index b7b385ee..c926a883 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h @@ -27,6 +27,7 @@ class SantaFePhevBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Santa Fe PHEV"; private: DATALAYER_BATTERY_TYPE* datalayer_battery; diff --git a/Software/src/battery/SIMPBMS-BATTERY.cpp b/Software/src/battery/SIMPBMS-BATTERY.cpp index e997b3ea..3d6e8379 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.cpp +++ b/Software/src/battery/SIMPBMS-BATTERY.cpp @@ -92,7 +92,7 @@ void SimpBmsBattery::transmit_can(unsigned long currentMillis) { } void SimpBmsBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "SIMPBMS battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = CELL_COUNT; datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/SIMPBMS-BATTERY.h b/Software/src/battery/SIMPBMS-BATTERY.h index 0e799ab2..4d415147 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.h +++ b/Software/src/battery/SIMPBMS-BATTERY.h @@ -15,6 +15,7 @@ class SimpBmsBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "SIMPBMS battery"; private: /* DEFAULT VALUES BMS will send configured */ diff --git a/Software/src/battery/SONO-BATTERY.cpp b/Software/src/battery/SONO-BATTERY.cpp index ab7eb043..47631cc2 100644 --- a/Software/src/battery/SONO-BATTERY.cpp +++ b/Software/src/battery/SONO-BATTERY.cpp @@ -140,7 +140,7 @@ void SonoBattery::transmit_can(unsigned long currentMillis) { } void SonoBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Sono Motors Sion 64kWh LFP ", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 96; datalayer.system.status.battery_allows_contactor_closing = true; diff --git a/Software/src/battery/SONO-BATTERY.h b/Software/src/battery/SONO-BATTERY.h index 51b46222..b1e366ad 100644 --- a/Software/src/battery/SONO-BATTERY.h +++ b/Software/src/battery/SONO-BATTERY.h @@ -15,6 +15,7 @@ class SonoBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Sono Motors Sion 64kWh LFP "; private: static const int MAX_PACK_VOLTAGE_DV = 5000; //5000 = 500.0V diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index 66d67afd..fe27647c 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -377,7 +377,7 @@ void VolvoSpaBattery::transmit_can(unsigned long currentMillis) { } void VolvoSpaBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 69/78kWh SPA battery", 63); + strncpy(datalayer.system.info.battery_protocol, Name, 63); datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 0; // Initializes when all cells have been read datalayer.battery.info.total_capacity_Wh = 78200; //Startout in 78kWh mode (This value used for SOC calc) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.h b/Software/src/battery/VOLVO-SPA-BATTERY.h index f29c580a..1e90237c 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-BATTERY.h @@ -16,6 +16,7 @@ class VolvoSpaBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Volvo / Polestar 69/78kWh SPA battery"; bool supports_reset_DTC() { return true; } void reset_DTC() { datalayer_extended.VolvoPolestar.UserRequestDTCreset = true; } diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp index 258afcb0..19507a7c 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.cpp @@ -552,8 +552,8 @@ void VolvoSpaHybridBattery::transmit_can(unsigned long currentMillis) { } } -void VolvoSpaHybridBattery::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volvo PHEV battery", 63); //changed +void VolvoSpaHybridBattery::setup(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, Name, 63); //changed datalayer.system.info.battery_protocol[63] = '\0'; datalayer.battery.info.number_of_cells = 102; //was 108, changed datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; diff --git a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h index ec3de17f..e31c9967 100644 --- a/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-HYBRID-BATTERY.h @@ -16,6 +16,7 @@ class VolvoSpaHybridBattery : public CanBattery { virtual void handle_incoming_can_frame(CAN_frame rx_frame); virtual void update_values(); virtual void transmit_can(unsigned long currentMillis); + static constexpr char* Name = "Volvo PHEV battery"; bool supports_reset_DTC() { return true; } void reset_DTC() { datalayer_extended.VolvoHybrid.UserRequestDTCreset = true; } diff --git a/Software/src/communication/can/CanReceiver.h b/Software/src/communication/can/CanReceiver.h index 22a9ba58..2a510606 100644 --- a/Software/src/communication/can/CanReceiver.h +++ b/Software/src/communication/can/CanReceiver.h @@ -2,7 +2,6 @@ #define _CANRECEIVER_H #include "src/devboard/utils/types.h" -#include "src/include.h" class CanReceiver { public: diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 3b2238a6..08fee8f0 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -29,6 +29,13 @@ const bool remote_bms_reset_default = true; #endif bool remote_bms_reset = remote_bms_reset_default; +#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY +const bool contactor_control_enabled_double_battery_default = true; +#else +const bool contactor_control_enabled_double_battery_default = false; +#endif +bool contactor_control_enabled_double_battery = contactor_control_enabled_double_battery_default; + // TODO: Ensure valid values at run-time // Parameters @@ -105,12 +112,15 @@ void init_contactors() { set(PRECHARGE_PIN, OFF); } -#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY - pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT); - set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); - pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT); - set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); -#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY +#if defined(SECOND_POSITIVE_CONTACTOR_PIN) && defined(SECOND_NEGATIVE_CONTACTOR_PIN) + if (contactor_control_enabled_double_battery) { + pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT); + set(SECOND_POSITIVE_CONTACTOR_PIN, OFF); + pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT); + set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF); + } +#endif + // Init BMS contactor #if defined HW_STARK || defined HW_3LB // This hardware has dedicated pin, always enable on start pinMode(BMS_POWER, OUTPUT); //LilyGo is omitted from this, only enabled if user selects PERIODIC_BMS_RESET diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h index 9a7b7b00..e18e8431 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.h +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.h @@ -8,6 +8,7 @@ // Settings that can be changed at run-time extern bool contactor_control_enabled; +extern bool contactor_control_enabled_double_battery; extern bool pwm_contactor_control; extern bool periodic_bms_reset; extern bool remote_bms_reset; diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index fec14290..4ce46a17 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -81,6 +81,7 @@ void init_stored_settings() { user_selected_charger_type = (ChargerType)settings.getUInt("CHGTYPE", (int)ChargerType::None); user_selected_second_battery = settings.getBool("DBLBTR", false); contactor_control_enabled = settings.getBool("CNTCTRL", false); + contactor_control_enabled_double_battery = settings.getBool("CNTCTRLDBL", false); pwm_contactor_control = settings.getBool("PWMCNTCTRL", false); periodic_bms_reset = settings.getBool("PERBMSRESET", false); remote_bms_reset = settings.getBool("REMBMSRESET", false); diff --git a/Software/src/communication/nvm/comm_nvm.h b/Software/src/communication/nvm/comm_nvm.h index f472fbfc..023a757b 100644 --- a/Software/src/communication/nvm/comm_nvm.h +++ b/Software/src/communication/nvm/comm_nvm.h @@ -34,21 +34,25 @@ void store_settings_equipment_stop(); */ void store_settings(); +// Wraps the Preferences object begin/end calls, so that the scope of this object +// runs them automatically (via constructor/destructor). class BatteryEmulatorSettingsStore { public: - BatteryEmulatorSettingsStore() { settings.begin("batterySettings", false); } + BatteryEmulatorSettingsStore(bool readOnly = false) { + if (!settings.begin("batterySettings", readOnly)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 0); + } + } ~BatteryEmulatorSettingsStore() { settings.end(); } - BatteryType get_batterytype() { return (BatteryType)settings.getUInt("BATTTYPE", (int)BatteryType::None); } + uint32_t getUInt(const char* name, uint32_t defaultValue) { return settings.getUInt(name, defaultValue); } - void set_batterytype(BatteryType type) { settings.putUInt("BATTTYPE", (int)type); } + void saveUInt(const char* name, uint32_t value) { settings.putUInt(name, value); } - InverterProtocolType get_invertertype() { - return (InverterProtocolType)settings.getUInt("INVTYPE", (int)InverterProtocolType::None); - } + bool getBool(const char* name) { return settings.getBool(name, false); } - void set_invertertype(InverterProtocolType type) { settings.putUInt("INVTYPE", (int)type); } + void saveBool(const char* name, bool value) { settings.putBool(name, value); } private: Preferences settings; diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index a276d5ee..8c26de32 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -55,161 +55,166 @@ void update_machineryprotection() { } // Start checking that the battery is within reason. Incase we see any funny business, raise an event! + // Don't check any battery issues if battery is not configured + if (battery) { - // Pause function is on OR we have a critical fault event active - if (emulator_pause_request_ON || (datalayer.battery.status.bms_status == FAULT)) { - datalayer.battery.status.max_discharge_power_W = 0; - datalayer.battery.status.max_charge_power_W = 0; - } - - // Battery is overheated! - if (datalayer.battery.status.temperature_max_dC > BATTERY_MAXTEMPERATURE) { - set_event(EVENT_BATTERY_OVERHEAT, datalayer.battery.status.temperature_max_dC); - } else { - clear_event(EVENT_BATTERY_OVERHEAT); - } - - // Battery is frozen! - if (datalayer.battery.status.temperature_min_dC < BATTERY_MINTEMPERATURE) { - set_event(EVENT_BATTERY_FROZEN, datalayer.battery.status.temperature_min_dC); - } else { - clear_event(EVENT_BATTERY_FROZEN); - } - - if (labs(datalayer.battery.status.temperature_max_dC - datalayer.battery.status.temperature_min_dC) > - BATTERY_MAX_TEMPERATURE_DEVIATION) { - set_event_latched(EVENT_BATTERY_TEMP_DEVIATION_HIGH, - datalayer.battery.status.temperature_max_dC - datalayer.battery.status.temperature_min_dC); - } else { - clear_event(EVENT_BATTERY_TEMP_DEVIATION_HIGH); - } - - // Battery voltage is over designed max voltage! - if (datalayer.battery.status.voltage_dV > datalayer.battery.info.max_design_voltage_dV) { - set_event(EVENT_BATTERY_OVERVOLTAGE, datalayer.battery.status.voltage_dV); - datalayer.battery.status.max_charge_power_W = 0; - } else { - clear_event(EVENT_BATTERY_OVERVOLTAGE); - } - - // Battery voltage is under designed min voltage! - if (datalayer.battery.status.voltage_dV < datalayer.battery.info.min_design_voltage_dV) { - set_event(EVENT_BATTERY_UNDERVOLTAGE, datalayer.battery.status.voltage_dV); - datalayer.battery.status.max_discharge_power_W = 0; - } else { - clear_event(EVENT_BATTERY_UNDERVOLTAGE); - } - - // Cell overvoltage, further charging not possible. Battery might be imbalanced. - if (datalayer.battery.status.cell_max_voltage_mV >= datalayer.battery.info.max_cell_voltage_mV) { - set_event(EVENT_CELL_OVER_VOLTAGE, 0); - datalayer.battery.status.max_charge_power_W = 0; - } - // Cell CRITICAL overvoltage, critical latching error without automatic reset. Requires user action to inspect battery. - if (datalayer.battery.status.cell_max_voltage_mV >= (datalayer.battery.info.max_cell_voltage_mV + CELL_CRITICAL_MV)) { - set_event(EVENT_CELL_CRITICAL_OVER_VOLTAGE, 0); - } - - // Cell undervoltage. Further discharge not possible. Battery might be imbalanced. - if (datalayer.battery.status.cell_min_voltage_mV <= datalayer.battery.info.min_cell_voltage_mV) { - set_event(EVENT_CELL_UNDER_VOLTAGE, 0); - datalayer.battery.status.max_discharge_power_W = 0; - } - //Cell CRITICAL undervoltage. critical latching error without automatic reset. Requires user action to inspect battery. - if (datalayer.battery.status.cell_min_voltage_mV <= (datalayer.battery.info.min_cell_voltage_mV - CELL_CRITICAL_MV)) { - set_event(EVENT_CELL_CRITICAL_UNDER_VOLTAGE, 0); - } - - // Battery is fully charged. Dont allow any more power into it - // Normally the BMS will send 0W allowed, but this acts as an additional layer of safety - if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00% - { - if (!battery_full_event_fired) { - set_event(EVENT_BATTERY_FULL, 0); - battery_full_event_fired = true; + // Pause function is on OR we have a critical fault event active + if (emulator_pause_request_ON || (datalayer.battery.status.bms_status == FAULT)) { + datalayer.battery.status.max_discharge_power_W = 0; + datalayer.battery.status.max_charge_power_W = 0; } - datalayer.battery.status.max_charge_power_W = 0; - } else { - clear_event(EVENT_BATTERY_FULL); - battery_full_event_fired = false; - } - // Battery is empty. Do not allow further discharge. - // Normally the BMS will send 0W allowed, but this acts as an additional layer of safety - if (datalayer.battery.status.bms_status == ACTIVE) { - if (datalayer.battery.status.reported_soc == 0) { //Scaled SOC% value is 0.00% - if (!battery_empty_event_fired) { - set_event(EVENT_BATTERY_EMPTY, 0); - battery_empty_event_fired = true; - } + // Battery is overheated! + if (datalayer.battery.status.temperature_max_dC > BATTERY_MAXTEMPERATURE) { + set_event(EVENT_BATTERY_OVERHEAT, datalayer.battery.status.temperature_max_dC); + } else { + clear_event(EVENT_BATTERY_OVERHEAT); + } + + // Battery is frozen! + if (datalayer.battery.status.temperature_min_dC < BATTERY_MINTEMPERATURE) { + set_event(EVENT_BATTERY_FROZEN, datalayer.battery.status.temperature_min_dC); + } else { + clear_event(EVENT_BATTERY_FROZEN); + } + + if (labs(datalayer.battery.status.temperature_max_dC - datalayer.battery.status.temperature_min_dC) > + BATTERY_MAX_TEMPERATURE_DEVIATION) { + set_event_latched(EVENT_BATTERY_TEMP_DEVIATION_HIGH, + datalayer.battery.status.temperature_max_dC - datalayer.battery.status.temperature_min_dC); + } else { + clear_event(EVENT_BATTERY_TEMP_DEVIATION_HIGH); + } + + // Battery voltage is over designed max voltage! + if (datalayer.battery.status.voltage_dV > datalayer.battery.info.max_design_voltage_dV) { + set_event(EVENT_BATTERY_OVERVOLTAGE, datalayer.battery.status.voltage_dV); + datalayer.battery.status.max_charge_power_W = 0; + } else { + clear_event(EVENT_BATTERY_OVERVOLTAGE); + } + + // Battery voltage is under designed min voltage! + if (datalayer.battery.status.voltage_dV < datalayer.battery.info.min_design_voltage_dV) { + set_event(EVENT_BATTERY_UNDERVOLTAGE, datalayer.battery.status.voltage_dV); datalayer.battery.status.max_discharge_power_W = 0; } else { - clear_event(EVENT_BATTERY_EMPTY); - battery_empty_event_fired = false; + clear_event(EVENT_BATTERY_UNDERVOLTAGE); } - } - // Battery is extremely degraded, not fit for secondlifestorage! - if (datalayer.battery.status.soh_pptt < 2500) { - set_event(EVENT_SOH_LOW, datalayer.battery.status.soh_pptt); - } else { - clear_event(EVENT_SOH_LOW); - } + // Cell overvoltage, further charging not possible. Battery might be imbalanced. + if (datalayer.battery.status.cell_max_voltage_mV >= datalayer.battery.info.max_cell_voltage_mV) { + set_event(EVENT_CELL_OVER_VOLTAGE, 0); + datalayer.battery.status.max_charge_power_W = 0; + } + // Cell CRITICAL overvoltage, critical latching error without automatic reset. Requires user action to inspect battery. + if (datalayer.battery.status.cell_max_voltage_mV >= + (datalayer.battery.info.max_cell_voltage_mV + CELL_CRITICAL_MV)) { + set_event(EVENT_CELL_CRITICAL_OVER_VOLTAGE, 0); + } - if (battery && !battery->soc_plausible()) { - set_event(EVENT_SOC_PLAUSIBILITY_ERROR, datalayer.battery.status.real_soc); - } + // Cell undervoltage. Further discharge not possible. Battery might be imbalanced. + if (datalayer.battery.status.cell_min_voltage_mV <= datalayer.battery.info.min_cell_voltage_mV) { + set_event(EVENT_CELL_UNDER_VOLTAGE, 0); + datalayer.battery.status.max_discharge_power_W = 0; + } + //Cell CRITICAL undervoltage. critical latching error without automatic reset. Requires user action to inspect battery. + if (datalayer.battery.status.cell_min_voltage_mV <= + (datalayer.battery.info.min_cell_voltage_mV - CELL_CRITICAL_MV)) { + set_event(EVENT_CELL_CRITICAL_UNDER_VOLTAGE, 0); + } - // Check diff between highest and lowest cell - cell_deviation_mV = - std::abs(datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV); - if (cell_deviation_mV > datalayer.battery.info.max_cell_voltage_deviation_mV) { - set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20)); - } else { - clear_event(EVENT_CELL_DEVIATION_HIGH); - } - - // Inverter is charging with more power than battery wants! - if (datalayer.battery.status.active_power_W > 0) { // Charging - if (datalayer.battery.status.active_power_W > (datalayer.battery.status.max_charge_power_W + 2000)) { - if (charge_limit_failures > MAX_CHARGE_DISCHARGE_LIMIT_FAILURES) { - set_event(EVENT_CHARGE_LIMIT_EXCEEDED, 0); // Alert when 2kW over requested max - } else { - charge_limit_failures++; + // Battery is fully charged. Dont allow any more power into it + // Normally the BMS will send 0W allowed, but this acts as an additional layer of safety + if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00% + { + if (!battery_full_event_fired) { + set_event(EVENT_BATTERY_FULL, 0); + battery_full_event_fired = true; } + datalayer.battery.status.max_charge_power_W = 0; } else { - clear_event(EVENT_CHARGE_LIMIT_EXCEEDED); - charge_limit_failures = 0; + clear_event(EVENT_BATTERY_FULL); + battery_full_event_fired = false; } - } - // Inverter is pulling too much power from battery! - if (datalayer.battery.status.active_power_W < 0) { // Discharging - if (-datalayer.battery.status.active_power_W > (datalayer.battery.status.max_discharge_power_W + 2000)) { - if (discharge_limit_failures > MAX_CHARGE_DISCHARGE_LIMIT_FAILURES) { - set_event(EVENT_DISCHARGE_LIMIT_EXCEEDED, 0); // Alert when 2kW over requested max + // Battery is empty. Do not allow further discharge. + // Normally the BMS will send 0W allowed, but this acts as an additional layer of safety + if (datalayer.battery.status.bms_status == ACTIVE) { + if (datalayer.battery.status.reported_soc == 0) { //Scaled SOC% value is 0.00% + if (!battery_empty_event_fired) { + set_event(EVENT_BATTERY_EMPTY, 0); + battery_empty_event_fired = true; + } + datalayer.battery.status.max_discharge_power_W = 0; } else { - discharge_limit_failures++; + clear_event(EVENT_BATTERY_EMPTY); + battery_empty_event_fired = false; } - } else { - clear_event(EVENT_DISCHARGE_LIMIT_EXCEEDED); - discharge_limit_failures = 0; } - } - // Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error - if (!datalayer.battery.status.CAN_battery_still_alive) { - set_event(EVENT_CAN_BATTERY_MISSING, can_config.battery); - } else { - datalayer.battery.status.CAN_battery_still_alive--; - clear_event(EVENT_CAN_BATTERY_MISSING); - } + // Battery is extremely degraded, not fit for secondlifestorage! + if (datalayer.battery.status.soh_pptt < 2500) { + set_event(EVENT_SOH_LOW, datalayer.battery.status.soh_pptt); + } else { + clear_event(EVENT_SOH_LOW); + } - // Too many malformed CAN messages recieved! - if (datalayer.battery.status.CAN_error_counter > MAX_CAN_FAILURES) { - set_event(EVENT_CAN_CORRUPTED_WARNING, can_config.battery); - } else { - clear_event(EVENT_CAN_CORRUPTED_WARNING); + if (battery && !battery->soc_plausible()) { + set_event(EVENT_SOC_PLAUSIBILITY_ERROR, datalayer.battery.status.real_soc); + } + + // Check diff between highest and lowest cell + cell_deviation_mV = + std::abs(datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV); + if (cell_deviation_mV > datalayer.battery.info.max_cell_voltage_deviation_mV) { + set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20)); + } else { + clear_event(EVENT_CELL_DEVIATION_HIGH); + } + + // Inverter is charging with more power than battery wants! + if (datalayer.battery.status.active_power_W > 0) { // Charging + if (datalayer.battery.status.active_power_W > (datalayer.battery.status.max_charge_power_W + 2000)) { + if (charge_limit_failures > MAX_CHARGE_DISCHARGE_LIMIT_FAILURES) { + set_event(EVENT_CHARGE_LIMIT_EXCEEDED, 0); // Alert when 2kW over requested max + } else { + charge_limit_failures++; + } + } else { + clear_event(EVENT_CHARGE_LIMIT_EXCEEDED); + charge_limit_failures = 0; + } + } + + // Inverter is pulling too much power from battery! + if (datalayer.battery.status.active_power_W < 0) { // Discharging + if (-datalayer.battery.status.active_power_W > (datalayer.battery.status.max_discharge_power_W + 2000)) { + if (discharge_limit_failures > MAX_CHARGE_DISCHARGE_LIMIT_FAILURES) { + set_event(EVENT_DISCHARGE_LIMIT_EXCEEDED, 0); // Alert when 2kW over requested max + } else { + discharge_limit_failures++; + } + } else { + clear_event(EVENT_DISCHARGE_LIMIT_EXCEEDED); + discharge_limit_failures = 0; + } + } + + // Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error + if (!datalayer.battery.status.CAN_battery_still_alive) { + set_event(EVENT_CAN_BATTERY_MISSING, can_config.battery); + } else { + datalayer.battery.status.CAN_battery_still_alive--; + clear_event(EVENT_CAN_BATTERY_MISSING); + } + + // Too many malformed CAN messages recieved! + if (datalayer.battery.status.CAN_error_counter > MAX_CAN_FAILURES) { + set_event(EVENT_CAN_CORRUPTED_WARNING, can_config.battery); + } else { + clear_event(EVENT_CAN_CORRUPTED_WARNING); + } } if (inverter && inverter->interface_type() == InverterInterfaceType::Can) { diff --git a/Software/src/devboard/utils/types.h b/Software/src/devboard/utils/types.h index b06379fe..98a73726 100644 --- a/Software/src/devboard/utils/types.h +++ b/Software/src/devboard/utils/types.h @@ -42,6 +42,9 @@ enum PrechargeState { #define CAN_STILL_ALIVE 60 // Set by battery each time we get a CAN message. Decrements every second. When reaching 0, sets event +typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface; +extern const char* getCANInterfaceName(CAN_Interface interface); + /* CAN Frame structure */ typedef struct { bool FD; diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 223990f0..da08a3fd 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -107,29 +107,24 @@ String settings_processor(const String& var) { "
"; content += ""; content += ""; content += ""; - //content += ""; // TODO: Generalize settings: define settings in one place and use the definitions to render // UI and handle load/save - render_checkbox(content, "Double battery", settings.get_doublebattery(), "dblbtr"); - render_checkbox(content, "Contactor control", get_bool("CNTCTRL"), "contctrl"); - render_checkbox(content, "PWM contactor control", get_bool("PWMCNTCTRL"), "pwmcontctrl"); - render_checkbox(content, "Periodic BMS reset", get_bool("PERBMSRESET"), "PERBMSRESET"); - render_checkbox(content, "Remote BMS reset", get_bool("REMBMSRESET"), "REMBMSRESET"); + render_checkbox(content, "Double battery", settings.getBool("DBLBTR"), "dblbtr"); + render_checkbox(content, "Contactor control", settings.getBool("CNTCTRL"), "contctrl"); + render_checkbox(content, "Contactor control double battery", settings.getBool("CNTCTRLDBL"), "contctrldbl"); + render_checkbox(content, "PWM contactor control", settings.getBool("PWMCNTCTRL"), "pwmcontctrl"); + render_checkbox(content, "Periodic BMS reset", settings.getBool("PERBMSRESET"), "PERBMSRESET"); + render_checkbox(content, "Remote BMS reset", settings.getBool("REMBMSRESET"), "REMBMSRESET"); - /* content += - "
Save
"; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index a8208c62..9525b262 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -4,6 +4,7 @@ #include "../../../USER_SECRETS.h" #include "../../battery/BATTERIES.h" #include "../../battery/Battery.h" +#include "../../communication/contactorcontrol/comm_contactorcontrol.h" #include "../../communication/nvm/comm_nvm.h" #include "../../datalayer/datalayer.h" #include "../../datalayer/datalayer_extended.h" @@ -39,7 +40,7 @@ const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral"; String importedLogs = ""; // Store the uploaded logfile contents in RAM bool isReplayRunning = false; // Global flag to track replay state -// True when user has updated settings and a reboot is needed. +// True when user has updated settings that need a reboot to be effective. bool settingsUpdated = false; CAN_frame currentFrame = {.FD = true, .ext_ID = false, .DLC = 64, .ID = 0x12F, .data = {0}}; @@ -389,30 +390,32 @@ void init_webserver() { #ifdef COMMON_IMAGE // Handles the form POST from UI to save certain settings: battery/inverter type and double battery on/off server.on("/saveSettings", HTTP_POST, [](AsyncWebServerRequest* request) { + BatteryEmulatorSettingsStore settings; + int params = request->params(); - // dblbtr not present in form content if not checked. - bool secondBattery = false; for (int i = 0; i < params; i++) { auto p = request->getParam(i); if (p->name() == "inverter") { auto type = static_cast(atoi(p->value().c_str())); - store_uint("INVTYPE", (int)type); + settings.saveUInt("INVTYPE", (int)type); } else if (p->name() == "battery") { auto type = static_cast(atoi(p->value().c_str())); - store_uint("BATTTYPE", (int)type); + settings.saveUInt("BATTTYPE", (int)type); } else if (p->name() == "charger") { auto type = static_cast(atoi(p->value().c_str())); - store_uint("CHGTYPE", (int)type); + settings.saveUInt("CHGTYPE", (int)type); } else if (p->name() == "dblbtr") { - store_bool("DBLBTR", p->value() == "on"); + settings.saveBool("DBLBTR", p->value() == "on"); } else if (p->name() == "contctrl") { - store_bool("CNTCTRL", p->value() == "on"); + settings.saveBool("CNTCTRL", p->value() == "on"); + } else if (p->name() == "contctrldbl") { + settings.saveBool("CNTCTRLDBL", p->value() == "on"); } else if (p->name() == "pwmcontctrl") { - store_bool("PWMCNTCTRL", p->value() == "on"); + settings.saveBool("PWMCNTCTRL", p->value() == "on"); } else if (p->name() == "PERBMSRESET") { - store_bool("PERBMSRESET", p->value() == "on"); + settings.saveBool("PERBMSRESET", p->value() == "on"); } else if (p->name() == "REMBMSRESET") { - store_bool("REMBMSRESET", p->value() == "on"); + settings.saveBool("REMBMSRESET", p->value() == "on"); } } @@ -937,6 +940,10 @@ String processor(const String& var) { // Show version number content += "

Software: " + String(version_number); + +#ifdef COMMON_IMAGE + content += " (Common image) "; +#endif // Show hardware used: #ifdef HW_LILYGO content += " Hardware: LilyGo T-CAN485"; @@ -980,315 +987,98 @@ String processor(const String& var) { // Close the block content += ""; - // Start a new block with a specific background color - content += "
"; + if (inverter || battery || shunt || charger) { + // Start a new block with a specific background color + content += "
"; - // Display which components are used - if (inverter) { - content += "

Inverter protocol: "; - content += datalayer.system.info.inverter_protocol; - content += " "; - content += datalayer.system.info.inverter_brand; - content += "

"; + // Display which components are used + if (inverter) { + content += "

Inverter protocol: "; + content += datalayer.system.info.inverter_protocol; + content += " "; + content += datalayer.system.info.inverter_brand; + content += "

"; + } + + if (battery) { + content += "

Battery protocol: "; + content += datalayer.system.info.battery_protocol; + if (battery2) { + content += " (Double battery)"; + } + if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { + content += " (LFP)"; + } + content += "

"; + } + + if (shunt) { + content += "

Shunt protocol: "; + content += datalayer.system.info.shunt_protocol; + content += "

"; + } + + if (charger) { + content += "

Charger protocol: "; + content += charger->name(); + content += "

"; + } + + // Close the block + content += "
"; } if (battery) { - content += "

Battery protocol: "; - content += datalayer.system.info.battery_protocol; if (battery2) { - content += " (Double battery)"; - } - if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { - content += " (LFP)"; - } - content += "

"; - } - - if (shunt) { - content += "

Shunt protocol: "; - content += datalayer.system.info.shunt_protocol; - content += "

"; - } - - if (charger) { - content += "

Charger protocol: "; - content += charger->name(); - content += "

"; - } - - // Close the block - content += "
"; - - if (battery2) { - // Start a new block with a specific background color. Color changes depending on BMS status - content += "
"; - content += "
(datalayer.battery.status.real_soc) / 100.0; // Convert to float and divide by 100 - float socScaledFloat = - static_cast(datalayer.battery.status.reported_soc) / 100.0; // Convert to float and divide by 100 - float sohFloat = - static_cast(datalayer.battery.status.soh_pptt) / 100.0; // Convert to float and divide by 100 - float voltageFloat = - static_cast(datalayer.battery.status.voltage_dV) / 10.0; // Convert to float and divide by 10 - float currentFloat = - static_cast(datalayer.battery.status.current_dA) / 10.0; // Convert to float and divide by 10 - float powerFloat = static_cast(datalayer.battery.status.active_power_W); // Convert to float - float tempMaxFloat = static_cast(datalayer.battery.status.temperature_max_dC) / 10.0; // Convert to float - float tempMinFloat = static_cast(datalayer.battery.status.temperature_min_dC) / 10.0; // Convert to float - float maxCurrentChargeFloat = - static_cast(datalayer.battery.status.max_charge_current_dA) / 10.0; // Convert to float - float maxCurrentDischargeFloat = - static_cast(datalayer.battery.status.max_discharge_current_dA) / 10.0; // Convert to float - uint16_t cell_delta_mv = - datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV; - - if (datalayer.battery.settings.soc_scaling_active) - content += "

Scaled SOC: " + String(socScaledFloat, 2) + - "% (real: " + String(socRealFloat, 2) + "%)

"; - else - content += "

SOC: " + String(socRealFloat, 2) + "%

"; - - content += "

SOH: " + String(sohFloat, 2) + "%

"; - content += "

Voltage: " + String(voltageFloat, 1) + - " V   Current: " + String(currentFloat, 1) + " A

"; - content += formatPowerValue("Power", powerFloat, "", 1); - - if (datalayer.battery.settings.soc_scaling_active) - content += "

Scaled total capacity: " + - formatPowerValue(datalayer.battery.info.reported_total_capacity_Wh, "h", 1) + - " (real: " + formatPowerValue(datalayer.battery.info.total_capacity_Wh, "h", 1) + ")

"; - else - content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 1); - - if (datalayer.battery.settings.soc_scaling_active) - content += "

Scaled remaining capacity: " + - formatPowerValue(datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1) + - " (real: " + formatPowerValue(datalayer.battery.status.remaining_capacity_Wh, "h", 1) + ")

"; - else - content += formatPowerValue("Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1); - - if (datalayer.system.settings.equipment_stop_active) { - content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1, "red"); - content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1, "red"); - content += "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; - content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; - } else { - content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1); - content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1); - content += "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A"; - if (datalayer.battery.settings.user_settings_limit_discharge) { - content += " (Manual)

"; + // Start a new block with a specific background color. Color changes depending on BMS status + content += "
"; + content += "
"; - if (cell_delta_mv > datalayer.battery.info.max_cell_voltage_deviation_mV) { - content += "

Cell delta: " + String(cell_delta_mv) + " mV

"; - } else { - content += "

Cell delta: " + String(cell_delta_mv) + " mV

"; - } - content += - "

Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + " °C

"; - - content += "

System status: "; - switch (datalayer.battery.status.bms_status) { - case ACTIVE: - content += String("OK"); - break; - case UPDATING: - content += String("UPDATING"); - break; - case FAULT: - content += String("FAULT"); - break; - case INACTIVE: - content += String("INACTIVE"); - break; - case STANDBY: - content += String("STANDBY"); - break; - default: - content += String("??"); - break; - } - content += "

"; - - if (battery && battery->supports_real_BMS_status()) { - content += "

Battery BMS status: "; - switch (datalayer.battery.status.real_bms_status) { - case BMS_ACTIVE: - content += String("OK"); - break; - case BMS_FAULT: - content += String("FAULT"); - break; - case BMS_DISCONNECTED: - content += String("DISCONNECTED"); - break; - case BMS_STANDBY: - content += String("STANDBY"); - break; - default: - content += String("??"); - break; - } - content += "

"; - } - - if (datalayer.battery.status.current_dA == 0) { - content += "

Battery idle

"; - } else if (datalayer.battery.status.current_dA < 0) { - content += "

Battery discharging!"; - if (datalayer.battery.settings.inverter_limits_discharge) { - content += " (Inverter limiting)

"; - } else { - if (datalayer.battery.settings.user_settings_limit_discharge) { - content += " (Settings limiting)

"; - } else { - content += " (Battery limiting)

"; - } - } - content += ""; - } else { // > 0 , positive current - content += "

Battery charging!"; - if (datalayer.battery.settings.inverter_limits_charge) { - content += " (Inverter limiting)

"; - } else { - if (datalayer.battery.settings.user_settings_limit_charge) { - content += " (Settings limiting)"; - } else { - content += " (Battery limiting)"; - } - } - } - - content += "

Battery allows contactor closing: "; - if (datalayer.system.status.battery_allows_contactor_closing == true) { - content += ""; - } else { - content += ""; - } - - content += " Inverter allows contactor closing: "; - if (datalayer.system.status.inverter_allows_contactor_closing == true) { - content += "

"; - } else { - content += ""; - } - if (emulator_pause_status == NORMAL) - content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; - else - content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; - -#ifdef CONTACTOR_CONTROL - content += "

Contactors controlled by emulator, state: "; - if (datalayer.system.status.contactors_engaged) { - content += "ON"; - } else { - content += "OFF"; - } - content += "

"; - - content += "

Precharge: ("; - content += PRECHARGE_TIME_MS; - content += " ms) Cont. Neg.: "; -#ifdef PWM_CONTACTOR_CONTROL - if (datalayer.system.status.contactors_engaged) { - content += "Economized"; - content += " Cont. Pos.: "; - content += "Economized"; - } else { - content += ""; - content += " Cont. Pos.: "; - content += ""; - } - -#else // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded - if (digitalRead(NEGATIVE_CONTACTOR_PIN) == HIGH) { - content += ""; - } else { - content += ""; - } - - content += " Cont. Pos.: "; - if (digitalRead(POSITIVE_CONTACTOR_PIN) == HIGH) { - content += ""; - } else { - content += ""; - } -#endif //no PWM_CONTACTOR_CONTROL - content += "

"; -#endif - - // Close the block - content += ""; - - if (battery2) { - content += "
"; // Display battery statistics within this block - socRealFloat = - static_cast(datalayer.battery2.status.real_soc) / 100.0; // Convert to float and divide by 100 - //socScaledFloat; // Same value used for bat2 - sohFloat = static_cast(datalayer.battery2.status.soh_pptt) / 100.0; // Convert to float and divide by 100 - voltageFloat = - static_cast(datalayer.battery2.status.voltage_dV) / 10.0; // Convert to float and divide by 10 - currentFloat = - static_cast(datalayer.battery2.status.current_dA) / 10.0; // Convert to float and divide by 10 - powerFloat = static_cast(datalayer.battery2.status.active_power_W); // Convert to float - tempMaxFloat = static_cast(datalayer.battery2.status.temperature_max_dC) / 10.0; // Convert to float - tempMinFloat = static_cast(datalayer.battery2.status.temperature_min_dC) / 10.0; // Convert to float - cell_delta_mv = datalayer.battery2.status.cell_max_voltage_mV - datalayer.battery2.status.cell_min_voltage_mV; + float socRealFloat = + static_cast(datalayer.battery.status.real_soc) / 100.0; // Convert to float and divide by 100 + float socScaledFloat = + static_cast(datalayer.battery.status.reported_soc) / 100.0; // Convert to float and divide by 100 + float sohFloat = + static_cast(datalayer.battery.status.soh_pptt) / 100.0; // Convert to float and divide by 100 + float voltageFloat = + static_cast(datalayer.battery.status.voltage_dV) / 10.0; // Convert to float and divide by 10 + float currentFloat = + static_cast(datalayer.battery.status.current_dA) / 10.0; // Convert to float and divide by 10 + float powerFloat = static_cast(datalayer.battery.status.active_power_W); // Convert to float + float tempMaxFloat = static_cast(datalayer.battery.status.temperature_max_dC) / 10.0; // Convert to float + float tempMinFloat = static_cast(datalayer.battery.status.temperature_min_dC) / 10.0; // Convert to float + float maxCurrentChargeFloat = + static_cast(datalayer.battery.status.max_charge_current_dA) / 10.0; // Convert to float + float maxCurrentDischargeFloat = + static_cast(datalayer.battery.status.max_discharge_current_dA) / 10.0; // Convert to float + uint16_t cell_delta_mv = + datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV; if (datalayer.battery.settings.soc_scaling_active) content += "

Scaled SOC: " + String(socScaledFloat, 2) + @@ -1303,117 +1093,342 @@ String processor(const String& var) { if (datalayer.battery.settings.soc_scaling_active) content += "

Scaled total capacity: " + - formatPowerValue(datalayer.battery2.info.reported_total_capacity_Wh, "h", 1) + - " (real: " + formatPowerValue(datalayer.battery2.info.total_capacity_Wh, "h", 1) + ")

"; + formatPowerValue(datalayer.battery.info.reported_total_capacity_Wh, "h", 1) + + " (real: " + formatPowerValue(datalayer.battery.info.total_capacity_Wh, "h", 1) + ")"; else - content += formatPowerValue("Total capacity", datalayer.battery2.info.total_capacity_Wh, "h", 1); + content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 1); if (datalayer.battery.settings.soc_scaling_active) content += "

Scaled remaining capacity: " + - formatPowerValue(datalayer.battery2.status.reported_remaining_capacity_Wh, "h", 1) + - " (real: " + formatPowerValue(datalayer.battery2.status.remaining_capacity_Wh, "h", 1) + ")

"; + formatPowerValue(datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1) + + " (real: " + formatPowerValue(datalayer.battery.status.remaining_capacity_Wh, "h", 1) + ")"; else - content += formatPowerValue("Remaining capacity", datalayer.battery2.status.remaining_capacity_Wh, "h", 1); + content += formatPowerValue("Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1); if (datalayer.system.settings.equipment_stop_active) { content += - formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1, "red"); - content += formatPowerValue("Max charge power", datalayer.battery2.status.max_charge_power_W, "", 1, "red"); + formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1, "red"); + content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1, "red"); content += "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; } else { - content += formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1); - content += formatPowerValue("Max charge power", datalayer.battery2.status.max_charge_power_W, "", 1); - content += - "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; - content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; + content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1); + content += formatPowerValue("Max charge power", datalayer.battery.status.max_charge_power_W, "", 1); + content += "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A"; + if (datalayer.battery.settings.user_settings_limit_discharge) { + content += " (Manual)

"; + } else { + content += " (BMS)"; + } + content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A"; + if (datalayer.battery.settings.user_settings_limit_charge) { + content += " (Manual)

"; + } else { + content += " (BMS)"; + } } - content += "

Cell min/max: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV / " + - String(datalayer.battery2.status.cell_max_voltage_mV) + " mV

"; - if (cell_delta_mv > datalayer.battery2.info.max_cell_voltage_deviation_mV) { + content += "

Cell min/max: " + String(datalayer.battery.status.cell_min_voltage_mV) + " mV / " + + String(datalayer.battery.status.cell_max_voltage_mV) + " mV

"; + if (cell_delta_mv > datalayer.battery.info.max_cell_voltage_deviation_mV) { content += "

Cell delta: " + String(cell_delta_mv) + " mV

"; } else { content += "

Cell delta: " + String(cell_delta_mv) + " mV

"; } content += "

Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + " °C

"; - if (datalayer.battery.status.bms_status == ACTIVE) { - content += "

System status: OK

"; - } else if (datalayer.battery.status.bms_status == UPDATING) { - content += "

System status: UPDATING

"; - } else { - content += "

System status: FAULT

"; + + content += "

System status: "; + switch (datalayer.battery.status.bms_status) { + case ACTIVE: + content += String("OK"); + break; + case UPDATING: + content += String("UPDATING"); + break; + case FAULT: + content += String("FAULT"); + break; + case INACTIVE: + content += String("INACTIVE"); + break; + case STANDBY: + content += String("STANDBY"); + break; + default: + content += String("??"); + break; } - if (datalayer.battery2.status.current_dA == 0) { - content += "

Battery idle

"; - } else if (datalayer.battery2.status.current_dA < 0) { - content += "

Battery discharging!

"; - } else { // > 0 - content += "

Battery charging!

"; + content += ""; + + if (battery && battery->supports_real_BMS_status()) { + content += "

Battery BMS status: "; + switch (datalayer.battery.status.real_bms_status) { + case BMS_ACTIVE: + content += String("OK"); + break; + case BMS_FAULT: + content += String("FAULT"); + break; + case BMS_DISCONNECTED: + content += String("DISCONNECTED"); + break; + case BMS_STANDBY: + content += String("STANDBY"); + break; + default: + content += String("??"); + break; + } + content += "

"; } - content += "

Automatic contactor closing allowed:

"; - content += "

Battery: "; - if (datalayer.system.status.battery2_allowed_contactor_closing == true) { + if (datalayer.battery.status.current_dA == 0) { + content += "

Battery idle

"; + } else if (datalayer.battery.status.current_dA < 0) { + content += "

Battery discharging!"; + if (datalayer.battery.settings.inverter_limits_discharge) { + content += " (Inverter limiting)

"; + } else { + if (datalayer.battery.settings.user_settings_limit_discharge) { + content += " (Settings limiting)"; + } else { + content += " (Battery limiting)"; + } + } + content += ""; + } else { // > 0 , positive current + content += "

Battery charging!"; + if (datalayer.battery.settings.inverter_limits_charge) { + content += " (Inverter limiting)

"; + } else { + if (datalayer.battery.settings.user_settings_limit_charge) { + content += " (Settings limiting)"; + } else { + content += " (Battery limiting)"; + } + } + } + + content += "

Battery allows contactor closing: "; + if (datalayer.system.status.battery_allows_contactor_closing == true) { content += ""; } else { content += ""; } - content += " Inverter: "; + content += " Inverter allows contactor closing: "; if (datalayer.system.status.inverter_allows_contactor_closing == true) { content += "

"; } else { content += ""; } - if (emulator_pause_status == NORMAL) content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; else content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; -#ifdef CONTACTOR_CONTROL - content += "

Contactors controlled by emulator, state: "; - if (datalayer.system.status.contactors_battery2_engaged) { - content += "ON"; - } else { - content += "OFF"; - } - content += "

"; -#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY - content += "

Cont. Neg.: "; -#ifdef PWM_CONTACTOR_CONTROL - if (datalayer.system.status.contactors_battery2_engaged) { - content += "Economized"; - content += " Cont. Pos.: "; - content += "Economized"; - } else { - content += ""; - content += " Cont. Pos.: "; - content += ""; + if (contactor_control_enabled) { + content += "

Contactors controlled by emulator, state: "; + if (datalayer.system.status.contactors_engaged) { + content += "ON"; + } else { + content += "OFF"; + } + content += "

"; + + content += "

Precharge: ("; + content += PRECHARGE_TIME_MS; + content += " ms) Cont. Neg.: "; + + if (pwm_contactor_control) { + if (datalayer.system.status.contactors_engaged) { + content += "Economized"; + content += " Cont. Pos.: "; + content += "Economized"; + } else { + content += ""; + content += " Cont. Pos.: "; + content += ""; + } + } else { // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded + if (digitalRead(NEGATIVE_CONTACTOR_PIN) == HIGH) { + content += ""; + } else { + content += ""; + } + + content += " Cont. Pos.: "; + if (digitalRead(POSITIVE_CONTACTOR_PIN) == HIGH) { + content += ""; + } else { + content += ""; + } + } + content += "

"; } -#else // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded - if (digitalRead(SECOND_NEGATIVE_CONTACTOR_PIN) == HIGH) { - content += ""; - } else { - content += ""; - } - - content += " Cont. Pos.: "; - if (digitalRead(SECOND_POSITIVE_CONTACTOR_PIN) == HIGH) { - content += ""; - } else { - content += ""; - } -#endif //no PWM_CONTACTOR_CONTROL - content += ""; -#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY -#endif // CONTACTOR_CONTROL - - content += "
"; + // Close the block content += ""; + + if (battery2) { + content += "
"; + + // Display battery statistics within this block + socRealFloat = + static_cast(datalayer.battery2.status.real_soc) / 100.0; // Convert to float and divide by 100 + //socScaledFloat; // Same value used for bat2 + sohFloat = + static_cast(datalayer.battery2.status.soh_pptt) / 100.0; // Convert to float and divide by 100 + voltageFloat = + static_cast(datalayer.battery2.status.voltage_dV) / 10.0; // Convert to float and divide by 10 + currentFloat = + static_cast(datalayer.battery2.status.current_dA) / 10.0; // Convert to float and divide by 10 + powerFloat = static_cast(datalayer.battery2.status.active_power_W); // Convert to float + tempMaxFloat = static_cast(datalayer.battery2.status.temperature_max_dC) / 10.0; // Convert to float + tempMinFloat = static_cast(datalayer.battery2.status.temperature_min_dC) / 10.0; // Convert to float + cell_delta_mv = datalayer.battery2.status.cell_max_voltage_mV - datalayer.battery2.status.cell_min_voltage_mV; + + if (datalayer.battery.settings.soc_scaling_active) + content += "

Scaled SOC: " + String(socScaledFloat, 2) + + "% (real: " + String(socRealFloat, 2) + "%)

"; + else + content += "

SOC: " + String(socRealFloat, 2) + "%

"; + + content += "

SOH: " + String(sohFloat, 2) + "%

"; + content += "

Voltage: " + String(voltageFloat, 1) + + " V   Current: " + String(currentFloat, 1) + " A

"; + content += formatPowerValue("Power", powerFloat, "", 1); + + if (datalayer.battery.settings.soc_scaling_active) + content += "

Scaled total capacity: " + + formatPowerValue(datalayer.battery2.info.reported_total_capacity_Wh, "h", 1) + + " (real: " + formatPowerValue(datalayer.battery2.info.total_capacity_Wh, "h", 1) + ")

"; + else + content += formatPowerValue("Total capacity", datalayer.battery2.info.total_capacity_Wh, "h", 1); + + if (datalayer.battery.settings.soc_scaling_active) + content += "

Scaled remaining capacity: " + + formatPowerValue(datalayer.battery2.status.reported_remaining_capacity_Wh, "h", 1) + + " (real: " + formatPowerValue(datalayer.battery2.status.remaining_capacity_Wh, "h", 1) + ")

"; + else + content += formatPowerValue("Remaining capacity", datalayer.battery2.status.remaining_capacity_Wh, "h", 1); + + if (datalayer.system.settings.equipment_stop_active) { + content += + formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1, "red"); + content += formatPowerValue("Max charge power", datalayer.battery2.status.max_charge_power_W, "", 1, "red"); + content += + "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; + content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; + } else { + content += formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1); + content += formatPowerValue("Max charge power", datalayer.battery2.status.max_charge_power_W, "", 1); + content += + "

Max discharge current: " + String(maxCurrentDischargeFloat, 1) + " A

"; + content += "

Max charge current: " + String(maxCurrentChargeFloat, 1) + " A

"; + } + + content += "

Cell min/max: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV / " + + String(datalayer.battery2.status.cell_max_voltage_mV) + " mV

"; + if (cell_delta_mv > datalayer.battery2.info.max_cell_voltage_deviation_mV) { + content += "

Cell delta: " + String(cell_delta_mv) + " mV

"; + } else { + content += "

Cell delta: " + String(cell_delta_mv) + " mV

"; + } + content += "

Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + + " °C

"; + if (datalayer.battery.status.bms_status == ACTIVE) { + content += "

System status: OK

"; + } else if (datalayer.battery.status.bms_status == UPDATING) { + content += "

System status: UPDATING

"; + } else { + content += "

System status: FAULT

"; + } + if (datalayer.battery2.status.current_dA == 0) { + content += "

Battery idle

"; + } else if (datalayer.battery2.status.current_dA < 0) { + content += "

Battery discharging!

"; + } else { // > 0 + content += "

Battery charging!

"; + } + + content += "

Automatic contactor closing allowed:

"; + content += "

Battery: "; + if (datalayer.system.status.battery2_allowed_contactor_closing == true) { + content += ""; + } else { + content += ""; + } + + content += " Inverter: "; + if (datalayer.system.status.inverter_allows_contactor_closing == true) { + content += "

"; + } else { + content += ""; + } + + if (emulator_pause_status == NORMAL) + content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; + else + content += "

Power status: " + String(get_emulator_pause_status().c_str()) + "

"; + + if (contactor_control_enabled) { + content += "

Contactors controlled by emulator, state: "; + if (datalayer.system.status.contactors_battery2_engaged) { + content += "ON"; + } else { + content += "OFF"; + } + content += "

"; + + if (contactor_control_enabled_double_battery) { + content += "

Cont. Neg.: "; + if (pwm_contactor_control) { + if (datalayer.system.status.contactors_battery2_engaged) { + content += "Economized"; + content += " Cont. Pos.: "; + content += "Economized"; + } else { + content += ""; + content += " Cont. Pos.: "; + content += ""; + } + } else { // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded +#if defined(SECOND_POSITIVE_CONTACTOR_PIN) && defined(SECOND_NEGATIVE_CONTACTOR_PIN) + if (digitalRead(SECOND_NEGATIVE_CONTACTOR_PIN) == HIGH) { + content += ""; + } else { + content += ""; + } + + content += " Cont. Pos.: "; + if (digitalRead(SECOND_POSITIVE_CONTACTOR_PIN) == HIGH) { + content += ""; + } else { + content += ""; + } +#endif + } + content += "

"; + } + } + content += "
"; + content += ""; + } } if (charger) { From 9c036915509055eab6893edc802d81b051c42811 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 18:58:32 +0300 Subject: [PATCH 05/14] Fix battery and inverter selection in UI --- Software/src/battery/BATTERIES.cpp | 2 +- Software/src/battery/Battery.h | 2 +- Software/src/charger/CHARGERS.cpp | 2 +- Software/src/charger/CanCharger.h | 2 +- .../src/devboard/webserver/settings_html.cpp | 97 +++++++------ Software/src/devboard/webserver/webserver.cpp | 37 ++++- Software/src/inverter/AFORE-CAN.cpp | 2 +- Software/src/inverter/AFORE-CAN.h | 1 + Software/src/inverter/FOXESS-CAN.cpp | 2 +- Software/src/inverter/FOXESS-CAN.h | 1 + Software/src/inverter/GROWATT-HV-CAN.cpp | 2 +- Software/src/inverter/GROWATT-HV-CAN.h | 1 + Software/src/inverter/GROWATT-LV-CAN.cpp | 2 +- Software/src/inverter/GROWATT-LV-CAN.h | 1 + Software/src/inverter/INVERTERS.cpp | 135 ++++++++++++++++-- Software/src/inverter/InverterProtocol.h | 25 +++- Software/src/inverter/KOSTAL-RS485.cpp | 2 +- Software/src/inverter/KOSTAL-RS485.h | 1 + Software/src/inverter/PYLON-CAN.cpp | 2 +- Software/src/inverter/PYLON-CAN.h | 1 + Software/src/inverter/PYLON-LV-CAN.cpp | 2 +- Software/src/inverter/PYLON-LV-CAN.h | 1 + Software/src/inverter/SCHNEIDER-CAN.cpp | 2 +- Software/src/inverter/SCHNEIDER-CAN.h | 1 + Software/src/inverter/SMA-BYD-H-CAN.cpp | 2 +- Software/src/inverter/SMA-BYD-H-CAN.h | 1 + Software/src/inverter/SMA-BYD-HVS-CAN.cpp | 2 +- Software/src/inverter/SMA-BYD-HVS-CAN.h | 1 + Software/src/inverter/SMA-LV-CAN.cpp | 2 +- Software/src/inverter/SMA-LV-CAN.h | 1 + Software/src/inverter/SMA-TRIPOWER-CAN.cpp | 2 +- Software/src/inverter/SMA-TRIPOWER-CAN.h | 1 + Software/src/inverter/SOFAR-CAN.cpp | 2 +- Software/src/inverter/SOFAR-CAN.h | 1 + Software/src/inverter/SOLAX-CAN.cpp | 2 +- Software/src/inverter/SOLAX-CAN.h | 1 + Software/src/inverter/SUNGROW-CAN.cpp | 2 +- Software/src/inverter/SUNGROW-CAN.h | 1 + 38 files changed, 260 insertions(+), 87 deletions(-) diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index 89d5f89c..e7f4bf12 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -17,7 +17,7 @@ std::vector supported_battery_types() { return types; } -extern const char* name_for_type(BatteryType type) { +extern const char* name_for_battery_type(BatteryType type) { switch (type) { case BatteryType::None: return "None"; diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index 61a798d6..187b29d0 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -46,7 +46,7 @@ enum class BatteryType { }; extern std::vector supported_battery_types(); -extern const char* name_for_type(BatteryType type); +extern const char* name_for_battery_type(BatteryType type); extern BatteryType user_selected_battery_type; extern bool user_selected_second_battery; diff --git a/Software/src/charger/CHARGERS.cpp b/Software/src/charger/CHARGERS.cpp index b0aee330..6ba343b9 100644 --- a/Software/src/charger/CHARGERS.cpp +++ b/Software/src/charger/CHARGERS.cpp @@ -14,7 +14,7 @@ std::vector supported_charger_types() { return types; } -extern const char* name_for_type(ChargerType type) { +extern const char* name_for_charger_type(ChargerType type) { switch (type) { case ChargerType::ChevyVolt: return ChevyVoltCharger::Name; diff --git a/Software/src/charger/CanCharger.h b/Software/src/charger/CanCharger.h index f8586740..5f8efed4 100644 --- a/Software/src/charger/CanCharger.h +++ b/Software/src/charger/CanCharger.h @@ -12,7 +12,7 @@ enum class ChargerType { None, NissanLeaf, ChevyVolt, Highest }; extern ChargerType user_selected_charger_type; extern std::vector supported_charger_types(); -extern const char* name_for_type(ChargerType type); +extern const char* name_for_charger_type(ChargerType type); // Generic base class for all chargers class Charger { diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index da08a3fd..241e4e3c 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -8,61 +8,56 @@ extern bool settingsUpdated; -#ifdef COMMON_IMAGE -String battery_options(BatteryType selected) { - String options; +template +constexpr auto to_underlying(E e) noexcept { + return static_cast>(e); +} - auto batteries = supported_battery_types(); - for (BatteryType type : batteries) { +template +std::vector enum_values() { + static_assert(std::is_enum_v, "Template argument must be an enum type."); + + constexpr auto count = to_underlying(EnumType::Highest); + std::vector values; + for (int i = 1; i < count; ++i) { + values.push_back(static_cast(i)); + } + return values; +} + +template +std::vector> enum_values_and_names(Func name_for_type) { + auto values = enum_values(); + + std::vector> pairs; + + for (auto& type : values) { auto name = name_for_type(type); if (name != nullptr) { - options += - (""; + pairs.push_back(std::pair(String(name), type)); } } - return options; + std::sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); + + pairs.insert(pairs.begin(), std::pair(name_for_type(EnumType::None), EnumType::None)); + + return pairs; } -String inverter_options(InverterProtocolType selected) { +template +String options_for_enum(TEnum selected, Func name_for_type) { String options; - - auto inverters = supported_inverter_protocols(); - - for (InverterProtocolType type : inverters) { - auto name = name_for_type(type); - if (name != nullptr) { - options += - (""; - } + auto values = enum_values_and_names(name_for_type); + for (const auto& [name, type] : values) { + options += + (""; } - return options; } -String charger_options(ChargerType selected) { - String options; - - auto chargers = supported_charger_types(); - - for (ChargerType type : chargers) { - auto name = name_for_type(type); - if (name != nullptr) { - options += - (""; - } - } - - return options; -} -#endif - void render_checkbox(String& content, const char* label, bool enabled, const char* name) { content += ""; content += ""; content += ""; content += ""; content += ""; // TODO: Generalize settings: define settings in one place and use the definitions to render // UI and handle load/save - render_checkbox(content, "Double battery", settings.getBool("DBLBTR"), "dblbtr"); - render_checkbox(content, "Contactor control", settings.getBool("CNTCTRL"), "contctrl"); - render_checkbox(content, "Contactor control double battery", settings.getBool("CNTCTRLDBL"), "contctrldbl"); - render_checkbox(content, "PWM contactor control", settings.getBool("PWMCNTCTRL"), "pwmcontctrl"); + render_checkbox(content, "Double battery", settings.getBool("DBLBTR"), "DBLBTR"); + render_checkbox(content, "Contactor control", settings.getBool("CNTCTRL"), "CNTCTRL"); + render_checkbox(content, "Contactor control double battery", settings.getBool("CNTCTRLDBL"), "CNTCTRLDBL"); + render_checkbox(content, "PWM contactor control", settings.getBool("PWMCNTCTRL"), "PWMCNTCTRL"); render_checkbox(content, "Periodic BMS reset", settings.getBool("PERBMSRESET"), "PERBMSRESET"); render_checkbox(content, "Remote BMS reset", settings.getBool("REMBMSRESET"), "REMBMSRESET"); diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 9525b262..b0716f47 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -1,6 +1,7 @@ #include "webserver.h" #include #include +#include #include "../../../USER_SECRETS.h" #include "../../battery/BATTERIES.h" #include "../../battery/Battery.h" @@ -387,13 +388,27 @@ void init_webserver() { request->send(200, "text/html", response); }); + struct BoolSetting { + const char* name; + bool existingValue; + bool newValue; + }; + + const char* boolSettingNames[] = {"DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "REMBMSRESET"}; + #ifdef COMMON_IMAGE // Handles the form POST from UI to save certain settings: battery/inverter type and double battery on/off - server.on("/saveSettings", HTTP_POST, [](AsyncWebServerRequest* request) { + server.on("/saveSettings", HTTP_POST, [boolSettingNames](AsyncWebServerRequest* request) { BatteryEmulatorSettingsStore settings; - int params = request->params(); - for (int i = 0; i < params; i++) { + std::vector boolSettings; + + for (auto& name : boolSettingNames) { + boolSettings.push_back({name, settings.getBool(name), false}); + } + + int numParams = request->params(); + for (int i = 0; i < numParams; i++) { auto p = request->getParam(i); if (p->name() == "inverter") { auto type = static_cast(atoi(p->value().c_str())); @@ -404,8 +419,8 @@ void init_webserver() { } else if (p->name() == "charger") { auto type = static_cast(atoi(p->value().c_str())); settings.saveUInt("CHGTYPE", (int)type); - } else if (p->name() == "dblbtr") { - settings.saveBool("DBLBTR", p->value() == "on"); + } /*else if (p->name() == "dblbtr") { + newDoubleBattery = p->value() == "on"; } else if (p->name() == "contctrl") { settings.saveBool("CNTCTRL", p->value() == "on"); } else if (p->name() == "contctrldbl") { @@ -416,6 +431,18 @@ void init_webserver() { settings.saveBool("PERBMSRESET", p->value() == "on"); } else if (p->name() == "REMBMSRESET") { settings.saveBool("REMBMSRESET", p->value() == "on"); + }*/ + + for (auto& boolSetting : boolSettings) { + if (p->name() == boolSetting.name) { + boolSetting.newValue = p->value() == "on"; + } + } + } + + for (auto& boolSetting : boolSettings) { + if (boolSetting.existingValue != boolSetting.newValue) { + settings.saveBool(boolSetting.name, boolSetting.newValue); } } diff --git a/Software/src/inverter/AFORE-CAN.cpp b/Software/src/inverter/AFORE-CAN.cpp index 8f2545a7..7cffecbe 100644 --- a/Software/src/inverter/AFORE-CAN.cpp +++ b/Software/src/inverter/AFORE-CAN.cpp @@ -171,6 +171,6 @@ void AforeCanInverter::transmit_can(unsigned long currentMillis) { } void AforeCanInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Afore battery over CAN", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/AFORE-CAN.h b/Software/src/inverter/AFORE-CAN.h index 9f5cdd9d..1311fda2 100644 --- a/Software/src/inverter/AFORE-CAN.h +++ b/Software/src/inverter/AFORE-CAN.h @@ -14,6 +14,7 @@ class AforeCanInverter : public CanInverterProtocol { void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); void update_values(); + static constexpr char* Name = "Afore battery over CAN"; private: /* The code is following the Afore 2.3 CAN standard, little-endian, 500kbps, from 2023.08.07 */ diff --git a/Software/src/inverter/FOXESS-CAN.cpp b/Software/src/inverter/FOXESS-CAN.cpp index 5d9019d2..7fb0b96c 100644 --- a/Software/src/inverter/FOXESS-CAN.cpp +++ b/Software/src/inverter/FOXESS-CAN.cpp @@ -562,6 +562,6 @@ void FoxessCanInverter::map_can_frame_to_variable(CAN_frame rx_frame) { } } void FoxessCanInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "FoxESS compatible HV2600/ECS4100 battery", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/FOXESS-CAN.h b/Software/src/inverter/FOXESS-CAN.h index 454f79bb..6b240ca0 100644 --- a/Software/src/inverter/FOXESS-CAN.h +++ b/Software/src/inverter/FOXESS-CAN.h @@ -14,6 +14,7 @@ class FoxessCanInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "FoxESS compatible HV2600/ECS4100 battery"; private: int16_t temperature_average = 0; diff --git a/Software/src/inverter/GROWATT-HV-CAN.cpp b/Software/src/inverter/GROWATT-HV-CAN.cpp index b19543cd..7bfc0511 100644 --- a/Software/src/inverter/GROWATT-HV-CAN.cpp +++ b/Software/src/inverter/GROWATT-HV-CAN.cpp @@ -451,6 +451,6 @@ void GrowattHvInverter::transmit_can(unsigned long currentMillis) { } 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); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/GROWATT-HV-CAN.h b/Software/src/inverter/GROWATT-HV-CAN.h index 16658119..72ffe7dc 100644 --- a/Software/src/inverter/GROWATT-HV-CAN.h +++ b/Software/src/inverter/GROWATT-HV-CAN.h @@ -14,6 +14,7 @@ class GrowattHvInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Growatt High Voltage protocol via CAN"; private: //Total number of Cells (1-512) diff --git a/Software/src/inverter/GROWATT-LV-CAN.cpp b/Software/src/inverter/GROWATT-LV-CAN.cpp index ca420583..4a5915fe 100644 --- a/Software/src/inverter/GROWATT-LV-CAN.cpp +++ b/Software/src/inverter/GROWATT-LV-CAN.cpp @@ -204,6 +204,6 @@ void GrowattLvInverter::transmit_can(unsigned long currentMillis) { } 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); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/GROWATT-LV-CAN.h b/Software/src/inverter/GROWATT-LV-CAN.h index a3d52f5a..a2a49c6a 100644 --- a/Software/src/inverter/GROWATT-LV-CAN.h +++ b/Software/src/inverter/GROWATT-LV-CAN.h @@ -14,6 +14,7 @@ class GrowattLvInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Growatt Low Voltage (48V) protocol via CAN"; private: //Actual content messages diff --git a/Software/src/inverter/INVERTERS.cpp b/Software/src/inverter/INVERTERS.cpp index cd9556d8..f242368f 100644 --- a/Software/src/inverter/INVERTERS.cpp +++ b/Software/src/inverter/INVERTERS.cpp @@ -14,22 +14,65 @@ std::vector supported_inverter_protocols() { return types; } -extern const char* name_for_type(InverterProtocolType type) { +extern const char* name_for_inverter_type(InverterProtocolType type) { switch (type) { - case InverterProtocolType::BydCan: - return BydCanInverter::Name; - break; - case InverterProtocolType::BydModbus: - return BydModbusInverter::Name; - break; - case InverterProtocolType::FerroampCan: - return FerroampCanInverter::Name; - break; case InverterProtocolType::None: return "None"; - break; - } + case InverterProtocolType::AforeCan: + return AforeCanInverter::Name; + + case InverterProtocolType::BydCan: + return BydCanInverter::Name; + + case InverterProtocolType::BydModbus: + return BydModbusInverter::Name; + + case InverterProtocolType::FerroampCan: + return FerroampCanInverter::Name; + + case InverterProtocolType::Foxess: + return FoxessCanInverter::Name; + + case InverterProtocolType::GrowattHv: + return GrowattHvInverter::Name; + + case InverterProtocolType::GrowattLv: + return GrowattLvInverter::Name; + + case InverterProtocolType::Kostal: + return KostalInverterProtocol::Name; + + case InverterProtocolType::Pylon: + return PylonInverter::Name; + + case InverterProtocolType::PylonLv: + return PylonLvInverter::Name; + + case InverterProtocolType::Schneider: + return SchneiderInverter::Name; + + case InverterProtocolType::SmaBydH: + return SmaBydHInverter::Name; + + case InverterProtocolType::SmaBydHvs: + return SmaBydHvsInverter::Name; + + case InverterProtocolType::SmaLv: + return SmaLvInverter::Name; + + case InverterProtocolType::SmaTripower: + return SmaTripowerInverter::Name; + + case InverterProtocolType::Sofar: + return SofarInverter::Name; + + case InverterProtocolType::Solax: + return SolaxInverter::Name; + + case InverterProtocolType::Sungrow: + return SungrowInverter::Name; + } return nullptr; } @@ -44,15 +87,83 @@ void setup_inverter() { } switch (user_selected_inverter_protocol) { + case InverterProtocolType::AforeCan: + inverter = new AforeCanInverter(); + break; + case InverterProtocolType::BydCan: inverter = new BydCanInverter(); break; + case InverterProtocolType::BydModbus: inverter = new BydModbusInverter(); break; + case InverterProtocolType::FerroampCan: inverter = new FerroampCanInverter(); break; + + case InverterProtocolType::Foxess: + inverter = new FoxessCanInverter(); + break; + + case InverterProtocolType::GrowattHv: + inverter = new GrowattHvInverter(); + break; + + case InverterProtocolType::GrowattLv: + inverter = new GrowattLvInverter(); + break; + + case InverterProtocolType::Kostal: + inverter = new KostalInverterProtocol(); + break; + + case InverterProtocolType::Pylon: + inverter = new PylonInverter(); + break; + + case InverterProtocolType::PylonLv: + inverter = new PylonLvInverter(); + break; + + case InverterProtocolType::Schneider: + inverter = new SchneiderInverter(); + break; + + case InverterProtocolType::SmaBydH: + inverter = new SmaBydHInverter(); + break; + + case InverterProtocolType::SmaBydHvs: + inverter = new SmaBydHvsInverter(); + break; + + case InverterProtocolType::SmaLv: + inverter = new SmaLvInverter(); + break; + + case InverterProtocolType::SmaTripower: + inverter = new SmaTripowerInverter(); + break; + + case InverterProtocolType::Sofar: + inverter = new SofarInverter(); + break; + + case InverterProtocolType::Solax: + inverter = new SolaxInverter(); + break; + + case InverterProtocolType::Sungrow: + inverter = new SungrowInverter(); + break; + + case InverterProtocolType::None: + case InverterProtocolType::Highest: + default: + inverter = nullptr; // Or handle as error + break; } if (inverter) { diff --git a/Software/src/inverter/InverterProtocol.h b/Software/src/inverter/InverterProtocol.h index 565e0581..bd786ff3 100644 --- a/Software/src/inverter/InverterProtocol.h +++ b/Software/src/inverter/InverterProtocol.h @@ -1,12 +1,33 @@ #ifndef INVERTER_PROTOCOL_H #define INVERTER_PROTOCOL_H -enum class InverterProtocolType { None = 0, BydCan, BydModbus, FerroampCan, Highest }; +enum class InverterProtocolType { + None = 0, + AforeCan, + BydCan, + BydModbus, + FerroampCan, + Foxess, + GrowattHv, + GrowattLv, + Kostal, + Pylon, + PylonLv, + Schneider, + SmaBydH, + SmaBydHvs, + SmaLv, + SmaTripower, + Sofar, + Solax, + Sungrow, + Highest +}; extern InverterProtocolType user_selected_inverter_protocol; extern std::vector supported_inverter_protocols(); -extern const char* name_for_type(InverterProtocolType type); +extern const char* name_for_inverter_type(InverterProtocolType type); enum class InverterInterfaceType { Can, Rs485, Modbus }; diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 37ef14b6..94f2c910 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -304,7 +304,7 @@ void KostalInverterProtocol::receive() // Runs as fast as possible to handle th void KostalInverterProtocol::setup(void) { // Performs one time setup at startup datalayer.system.status.inverter_allows_contactor_closing = false; dbg_message("inverter_allows_contactor_closing -> false"); - strncpy(datalayer.system.info.inverter_protocol, "BYD battery via Kostal RS485", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; Serial2.begin(baud_rate(), SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN); diff --git a/Software/src/inverter/KOSTAL-RS485.h b/Software/src/inverter/KOSTAL-RS485.h index fdf748cb..44a25396 100644 --- a/Software/src/inverter/KOSTAL-RS485.h +++ b/Software/src/inverter/KOSTAL-RS485.h @@ -22,6 +22,7 @@ class KostalInverterProtocol : public Rs485InverterProtocol { void setup(); void receive(); void update_values(); + static constexpr char* Name = "BYD battery via Kostal RS485"; private: int baud_rate() { return 57600; } diff --git a/Software/src/inverter/PYLON-CAN.cpp b/Software/src/inverter/PYLON-CAN.cpp index de00361f..5de88ffa 100644 --- a/Software/src/inverter/PYLON-CAN.cpp +++ b/Software/src/inverter/PYLON-CAN.cpp @@ -354,6 +354,6 @@ void PylonInverter::send_system_data() { //System equipment information } void PylonInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Pylontech battery over CAN bus", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/PYLON-CAN.h b/Software/src/inverter/PYLON-CAN.h index c744ab82..76079fce 100644 --- a/Software/src/inverter/PYLON-CAN.h +++ b/Software/src/inverter/PYLON-CAN.h @@ -14,6 +14,7 @@ class PylonInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Pylontech battery over CAN bus"; private: void send_system_data(); diff --git a/Software/src/inverter/PYLON-LV-CAN.cpp b/Software/src/inverter/PYLON-LV-CAN.cpp index 3ce16cba..21c9aeac 100644 --- a/Software/src/inverter/PYLON-LV-CAN.cpp +++ b/Software/src/inverter/PYLON-LV-CAN.cpp @@ -146,6 +146,6 @@ void PylonLvInverter::transmit_can(unsigned long currentMillis) { } void PylonLvInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Pylontech LV battery over CAN bus", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/PYLON-LV-CAN.h b/Software/src/inverter/PYLON-LV-CAN.h index b22c6b07..8ffcb784 100644 --- a/Software/src/inverter/PYLON-LV-CAN.h +++ b/Software/src/inverter/PYLON-LV-CAN.h @@ -14,6 +14,7 @@ class PylonLvInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Pylontech LV battery over CAN bus"; private: void send_system_data(); diff --git a/Software/src/inverter/SCHNEIDER-CAN.cpp b/Software/src/inverter/SCHNEIDER-CAN.cpp index af869c7a..d0579b76 100644 --- a/Software/src/inverter/SCHNEIDER-CAN.cpp +++ b/Software/src/inverter/SCHNEIDER-CAN.cpp @@ -227,6 +227,6 @@ void SchneiderInverter::transmit_can(unsigned long currentMillis) { } void SchneiderInverter::setup(void) { // Performs one time setup - strncpy(datalayer.system.info.inverter_protocol, "Schneider V2 SE BMS CAN", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/SCHNEIDER-CAN.h b/Software/src/inverter/SCHNEIDER-CAN.h index ace28795..b9c02f8d 100644 --- a/Software/src/inverter/SCHNEIDER-CAN.h +++ b/Software/src/inverter/SCHNEIDER-CAN.h @@ -14,6 +14,7 @@ class SchneiderInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Schneider V2 SE BMS CAN"; private: static const int STATE_OFFLINE = 0; diff --git a/Software/src/inverter/SMA-BYD-H-CAN.cpp b/Software/src/inverter/SMA-BYD-H-CAN.cpp index a0b5d2ba..6407ebbe 100644 --- a/Software/src/inverter/SMA-BYD-H-CAN.cpp +++ b/Software/src/inverter/SMA-BYD-H-CAN.cpp @@ -260,7 +260,7 @@ void SmaBydHInverter::transmit_can_init() { } void SmaBydHInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "BYD over SMA CAN", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); diff --git a/Software/src/inverter/SMA-BYD-H-CAN.h b/Software/src/inverter/SMA-BYD-H-CAN.h index 911a46cc..bf18265e 100644 --- a/Software/src/inverter/SMA-BYD-H-CAN.h +++ b/Software/src/inverter/SMA-BYD-H-CAN.h @@ -14,6 +14,7 @@ class SmaBydHInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "BYD over SMA CAN"; private: static const int READY_STATE = 0x03; diff --git a/Software/src/inverter/SMA-BYD-HVS-CAN.cpp b/Software/src/inverter/SMA-BYD-HVS-CAN.cpp index a14fbb42..bd9dd8d0 100644 --- a/Software/src/inverter/SMA-BYD-HVS-CAN.cpp +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.cpp @@ -278,7 +278,7 @@ void SmaBydHvsInverter::transmit_can(unsigned long currentMillis) { } void SmaBydHvsInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); diff --git a/Software/src/inverter/SMA-BYD-HVS-CAN.h b/Software/src/inverter/SMA-BYD-HVS-CAN.h index ab29460d..8e761559 100644 --- a/Software/src/inverter/SMA-BYD-HVS-CAN.h +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.h @@ -14,6 +14,7 @@ class SmaBydHvsInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "BYD Battery-Box HVS over SMA CAN"; private: static const int READY_STATE = 0x03; diff --git a/Software/src/inverter/SMA-LV-CAN.cpp b/Software/src/inverter/SMA-LV-CAN.cpp index cd206aaf..c78157bf 100644 --- a/Software/src/inverter/SMA-LV-CAN.cpp +++ b/Software/src/inverter/SMA-LV-CAN.cpp @@ -109,6 +109,6 @@ void SmaLvInverter::transmit_can(unsigned long currentMillis) { } void SmaLvInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "SMA Low Voltage (48V) protocol via CAN", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/SMA-LV-CAN.h b/Software/src/inverter/SMA-LV-CAN.h index c8ff13ed..4c62a32e 100644 --- a/Software/src/inverter/SMA-LV-CAN.h +++ b/Software/src/inverter/SMA-LV-CAN.h @@ -14,6 +14,7 @@ class SmaLvInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "SMA Low Voltage (48V) protocol via CAN"; private: static const int READY_STATE = 0x03; diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 7e031f63..f7dbeebf 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -183,7 +183,7 @@ void SmaTripowerInverter::transmit_can_init() { } void SmaTripowerInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index dadb7493..fcd7f099 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -14,6 +14,7 @@ class SmaTripowerInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "SMA Tripower CAN"; private: const int READY_STATE = 0x03; diff --git a/Software/src/inverter/SOFAR-CAN.cpp b/Software/src/inverter/SOFAR-CAN.cpp index ca8485a6..a4c6c1aa 100644 --- a/Software/src/inverter/SOFAR-CAN.cpp +++ b/Software/src/inverter/SOFAR-CAN.cpp @@ -68,6 +68,6 @@ void SofarInverter::transmit_can(unsigned long currentMillis) { } void SofarInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Sofar BMS (Extended Frame) over CAN bus", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/SOFAR-CAN.h b/Software/src/inverter/SOFAR-CAN.h index 13ee83b4..678c79f0 100644 --- a/Software/src/inverter/SOFAR-CAN.h +++ b/Software/src/inverter/SOFAR-CAN.h @@ -14,6 +14,7 @@ class SofarInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Sofar BMS (Extended Frame) over CAN bus"; private: unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index b66fa3f3..187ec772 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -208,7 +208,7 @@ void SolaxInverter::map_can_frame_to_variable(CAN_frame rx_frame) { } void SolaxInverter::setup(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first } diff --git a/Software/src/inverter/SOLAX-CAN.h b/Software/src/inverter/SOLAX-CAN.h index 169ca9c8..5b5cf672 100644 --- a/Software/src/inverter/SOLAX-CAN.h +++ b/Software/src/inverter/SOLAX-CAN.h @@ -14,6 +14,7 @@ class SolaxInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "SolaX Triple Power LFP over CAN bus"; private: // Timeout in milliseconds diff --git a/Software/src/inverter/SUNGROW-CAN.cpp b/Software/src/inverter/SUNGROW-CAN.cpp index 0331a4c7..40d2b8be 100644 --- a/Software/src/inverter/SUNGROW-CAN.cpp +++ b/Software/src/inverter/SUNGROW-CAN.cpp @@ -354,6 +354,6 @@ void SungrowInverter::transmit_can(unsigned long currentMillis) { } void SungrowInverter::setup(void) { // Performs one time setup at startup over CAN bus - strncpy(datalayer.system.info.inverter_protocol, "Sungrow SBR064 battery over CAN bus", 63); + strncpy(datalayer.system.info.inverter_protocol, Name, 63); datalayer.system.info.inverter_protocol[63] = '\0'; } diff --git a/Software/src/inverter/SUNGROW-CAN.h b/Software/src/inverter/SUNGROW-CAN.h index 5947b9d3..4088759b 100644 --- a/Software/src/inverter/SUNGROW-CAN.h +++ b/Software/src/inverter/SUNGROW-CAN.h @@ -14,6 +14,7 @@ class SungrowInverter : public CanInverterProtocol { void update_values(); void transmit_can(unsigned long currentMillis); void map_can_frame_to_variable(CAN_frame rx_frame); + static constexpr char* Name = "Sungrow SBR064 battery over CAN bus"; private: unsigned long previousMillis500ms = 0; From a663e027f22932e5826f44e387d2ce9084533897 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 19:12:58 +0300 Subject: [PATCH 06/14] Remove CAN definitions from user settings header --- Software/USER_SETTINGS.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index c17f7bc9..57b92625 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -2,6 +2,7 @@ #define __USER_SETTINGS_H__ #include #include +#include "src/devboard/utils/types.h" /* This file contains all the battery/inverter protocol settings Battery-Emulator software */ /* To switch between batteries/inverters, uncomment a line to enable, comment out to disable. */ @@ -173,7 +174,6 @@ /* Do not change any code below this line */ /* Only change battery specific settings above and in "USER_SETTINGS.cpp" */ -typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface; typedef struct { CAN_Interface battery; CAN_Interface inverter; @@ -181,7 +181,6 @@ typedef struct { CAN_Interface charger; CAN_Interface shunt; } CAN_Configuration; -extern const char* getCANInterfaceName(CAN_Interface interface); extern volatile CAN_Configuration can_config; extern volatile uint8_t AccessPointEnabled; extern const uint8_t wifi_channel; From 435f201553c5a832b4325cddbee93ff21274985b Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 19:33:29 +0300 Subject: [PATCH 07/14] Make battery selection check in cpp file to avoid header file conflicts --- Software/src/battery/BATTERIES.cpp | 4 ++++ Software/src/include.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index e7f4bf12..91384952 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -4,6 +4,10 @@ #include "CanBattery.h" #include "RS485Battery.h" +#if !defined(COMMON_IMAGE) && !defined(SELECTED_BATTERY_CLASS) +#error No battery selected! Choose one from the USER_SETTINGS.h file +#endif + Battery* battery = nullptr; Battery* battery2 = nullptr; diff --git a/Software/src/include.h b/Software/src/include.h index daacf9b0..6a72f9b4 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -39,10 +39,6 @@ #endif #endif -#if !defined(COMMON_IMAGE) && !defined(SELECTED_BATTERY_CLASS) -#error No battery selected! Choose one from the USER_SETTINGS.h file -#endif - #if defined(LOG_CAN_TO_SD) || defined(LOG_TO_SD) #if !defined(HW_LILYGO) #error The SD card logging feature is only available on LilyGo hardware From 742650268c3b01342b121f02e7ae243dca79b3ef Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 20:27:01 +0300 Subject: [PATCH 08/14] More conditional compilation for Chademo and BMS --- Software/src/battery/BATTERIES.cpp | 4 ++++ Software/src/battery/CHADEMO-BATTERY.cpp | 4 ++++ .../contactorcontrol/comm_contactorcontrol.cpp | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index 91384952..185c7540 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -35,8 +35,10 @@ extern const char* name_for_battery_type(BatteryType type) { return BydAttoBattery::Name; case BatteryType::CellPowerBms: return CellPowerBms::Name; +#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms case BatteryType::Chademo: return ChademoBattery::Name; +#endif case BatteryType::CmfaEv: return CmfaEvBattery::Name; case BatteryType::Foxess: @@ -122,8 +124,10 @@ Battery* create_battery(BatteryType type) { return new BydAttoBattery(); case BatteryType::CellPowerBms: return new CellPowerBms(); +#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms case BatteryType::Chademo: return new ChademoBattery(); +#endif case BatteryType::CmfaEv: return new CmfaEvBattery(); case BatteryType::Foxess: diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index 8ea592fb..6adf68db 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -4,6 +4,8 @@ #include "../include.h" #include "CHADEMO-SHUNTS.h" +#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms + /* CHADEMO handling runs at 6.25 times the rate of most other code, so, rather than the * default value of 12 (for 12 iterations of the 5s value update loop) * 5 for a 60s timeout, * instead use 75 for 75*0.8s = 60s @@ -987,3 +989,5 @@ void ChademoBattery::setup(void) { // Performs one time setup at startup setupMillis = millis(); } + +#endif diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 08fee8f0..f04b2c1f 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -130,6 +130,7 @@ void init_contactors() { digitalWrite(BMS_2_POWER, HIGH); #endif //BMS_2_POWER #endif // HW with dedicated BMS pins +#ifdef BMS_POWER if (periodic_bms_reset || remote_bms_reset) { pinMode(BMS_POWER, OUTPUT); digitalWrite(BMS_POWER, HIGH); @@ -138,6 +139,7 @@ void init_contactors() { digitalWrite(BMS_2_POWER, HIGH); #endif //BMS_2_POWER } +#endif } static void dbg_contactors(const char* state) { @@ -156,7 +158,9 @@ void handle_contactors() { datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); #endif +#ifdef BMS_POWER handle_BMSpower(); // Some batteries need to be periodically power cycled +#endif #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); @@ -281,6 +285,7 @@ This makes the BMS recalculate all SOC% and avoid memory leaks During that time we also set the emulator state to paused in order to not try and send CAN messages towards the battery Feature is only used if user has enabled PERIODIC_BMS_RESET in the USER_SETTINGS */ +#ifdef BMS_POWER void handle_BMSpower() { if (periodic_bms_reset || remote_bms_reset) { // Get current time @@ -314,6 +319,7 @@ void handle_BMSpower() { } } } +#endif void start_bms_reset() { if (periodic_bms_reset || remote_bms_reset) { @@ -329,7 +335,9 @@ void start_bms_reset() { // We try to keep contactors engaged during this pause, and just ramp power down to 0. setBatteryPause(true, false, false, false); +#ifdef BMS_POWER digitalWrite(BMS_POWER, LOW); // Remove power by setting the BMS power pin to LOW +#endif #ifdef BMS_2_POWER digitalWrite(BMS_2_POWER, LOW); // Same for battery 2 #endif From 2d30370777acb56ef5ddc4e666b0cf92b9b30d49 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 20:52:01 +0300 Subject: [PATCH 09/14] Make conflicting globals static --- .../communication/contactorcontrol/comm_contactorcontrol.cpp | 2 +- .../src/communication/precharge_control/precharge_control.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index f04b2c1f..ccc898db 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -65,7 +65,7 @@ const int OFF = 0; #define PWM_ON_DUTY 1023 #define PWM_Positive_Channel 0 #define PWM_Negative_Channel 1 -unsigned long prechargeStartTime = 0; +static unsigned long prechargeStartTime = 0; unsigned long negativeStartTime = 0; unsigned long prechargeCompletedTime = 0; unsigned long timeSpentInFaultedMode = 0; diff --git a/Software/src/communication/precharge_control/precharge_control.cpp b/Software/src/communication/precharge_control/precharge_control.cpp index 6b792e04..a695a0cd 100644 --- a/Software/src/communication/precharge_control/precharge_control.cpp +++ b/Software/src/communication/precharge_control/precharge_control.cpp @@ -18,9 +18,9 @@ #define ON 1 #define OFF 0 #endif -unsigned long prechargeStartTime = 0; +static unsigned long prechargeStartTime = 0; static uint32_t freq = Precharge_default_PWM_Freq; -uint16_t delta_freq = 1; +static uint16_t delta_freq = 1; static int32_t prev_external_voltage = 20000; // Initialization functions From 71e30a01eeb556d92fc2c9d8fd7a0ebdb2576dbc Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 21:11:57 +0300 Subject: [PATCH 10/14] Retain common image binary --- .github/workflows/compile-common-image-lilygo.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/compile-common-image-lilygo.yml b/.github/workflows/compile-common-image-lilygo.yml index 31ef7372..9e74cb63 100644 --- a/.github/workflows/compile-common-image-lilygo.yml +++ b/.github/workflows/compile-common-image-lilygo.yml @@ -50,3 +50,8 @@ jobs: - name: Compile Sketch run: arduino-cli compile --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DCOMMON_IMAGE -DHW_LILYGO" ./Software + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + path: esp32.esp32.esp32/Software.ino.bin From b88dc219c7e10f01055b295d46a60a7e16e7e243 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Wed, 18 Jun 2025 21:21:55 +0300 Subject: [PATCH 11/14] Fix binary path --- .github/workflows/compile-common-image-lilygo.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-common-image-lilygo.yml b/.github/workflows/compile-common-image-lilygo.yml index 9e74cb63..40cf16fc 100644 --- a/.github/workflows/compile-common-image-lilygo.yml +++ b/.github/workflows/compile-common-image-lilygo.yml @@ -49,9 +49,9 @@ jobs: arduino-cli core install esp32:esp32 - name: Compile Sketch - run: arduino-cli compile --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DCOMMON_IMAGE -DHW_LILYGO" ./Software + run: arduino-cli compile --output-dir ./ --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DCOMMON_IMAGE -DHW_LILYGO" ./Software - name: Upload artifact uses: actions/upload-artifact@v4 with: - path: esp32.esp32.esp32/Software.ino.bin + path: Software.ino.bin From 8ba7d09ec7a28f391a10c5eb99b509a01041ca11 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Thu, 19 Jun 2025 17:20:35 +0300 Subject: [PATCH 12/14] Remove redudant code --- Software/src/communication/nvm/comm_nvm.cpp | 26 +-------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 4ce46a17..a4a9b9d1 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -7,14 +7,10 @@ Preferences settings; // Store user settings // Initialization functions -static void begin() { - settings.begin("batterySettings", false); -} - void init_stored_settings() { static uint32_t temp = 0; // ATTENTION ! The maximum length for settings keys is 15 characters - begin(); + settings.begin("batterySettings", false); // Always get the equipment stop status datalayer.system.settings.equipment_stop_active = settings.getBool("EQUIPMENT_STOP", false); @@ -142,23 +138,3 @@ void store_settings() { settings.end(); // Close preferences handle } - -void store_uint(const char* key, uint32_t value) { - begin(); - settings.putUInt(key, value); -} - -void store_bool(const char* key, bool value) { - begin(); - settings.putBool(key, value); -} - -uint32_t get_uint(const char* key, uint32_t defaultValue) { - begin(); - return settings.getUInt(key, defaultValue); -} - -bool get_bool(const char* key) { - begin(); - return settings.getBool(key, false); -} From 86503ff485334adb675a29d8bacd50039742c844 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Fri, 20 Jun 2025 10:00:28 +0300 Subject: [PATCH 13/14] Inverter indicates whether it controls contactors at run-time --- .../contactorcontrol/comm_contactorcontrol.cpp | 7 ++++--- Software/src/inverter/InverterProtocol.h | 5 +++++ Software/src/inverter/SMA-BYD-H-CAN.h | 4 ++++ Software/src/inverter/SMA-BYD-HVS-CAN.h | 4 ++++ Software/src/inverter/SMA-TRIPOWER-CAN.h | 4 ++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index ccc898db..7fd2c506 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -154,9 +154,10 @@ static void dbg_contactors(const char* state) { // Main functions of the handle_contactors include checking if inverter allows for closing, checking battery 2, checking BMS power output, and actual contactor closing/precharge via GPIO void handle_contactors() { // TODO: This must be determined at run-time! -#if defined(SMA_BYD_H_CAN) || defined(SMA_BYD_HVS_CAN) || defined(SMA_TRIPOWER_CAN) - datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); -#endif + + if (inverter && inverter->controls_contactor()) { + datalayer.system.status.inverter_allows_contactor_closing = inverter->allows_contactor_closing(); + } #ifdef BMS_POWER handle_BMSpower(); // Some batteries need to be periodically power cycled diff --git a/Software/src/inverter/InverterProtocol.h b/Software/src/inverter/InverterProtocol.h index bd786ff3..46705e59 100644 --- a/Software/src/inverter/InverterProtocol.h +++ b/Software/src/inverter/InverterProtocol.h @@ -40,6 +40,11 @@ class InverterProtocol { // This function maps all the values fetched from battery to the correct battery emulator data structures virtual void update_values() = 0; + + // If true, this inverter supports a signal to control contactor (allows_contactor_closing) + virtual bool controls_contactor() { return false; } + + virtual bool allows_contactor_closing() { return false; } }; extern InverterProtocol* inverter; diff --git a/Software/src/inverter/SMA-BYD-H-CAN.h b/Software/src/inverter/SMA-BYD-H-CAN.h index bf18265e..1f9c3268 100644 --- a/Software/src/inverter/SMA-BYD-H-CAN.h +++ b/Software/src/inverter/SMA-BYD-H-CAN.h @@ -3,6 +3,7 @@ #include "../include.h" #include "CanInverterProtocol.h" +#include "src/devboard/hal/hal.h" #ifdef SMA_BYD_H_CAN #define SELECTED_INVERTER_CLASS SmaBydHInverter @@ -16,6 +17,9 @@ class SmaBydHInverter : public CanInverterProtocol { void map_can_frame_to_variable(CAN_frame rx_frame); static constexpr char* Name = "BYD over SMA CAN"; + virtual bool controls_contactor() { return true; } + virtual bool allows_contactor_closing() { return digitalRead(INVERTER_CONTACTOR_ENABLE_PIN) == 1; } + private: static const int READY_STATE = 0x03; static const int STOP_STATE = 0x02; diff --git a/Software/src/inverter/SMA-BYD-HVS-CAN.h b/Software/src/inverter/SMA-BYD-HVS-CAN.h index 8e761559..bb537e09 100644 --- a/Software/src/inverter/SMA-BYD-HVS-CAN.h +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.h @@ -3,6 +3,7 @@ #include "../include.h" #include "CanInverterProtocol.h" +#include "src/devboard/hal/hal.h" #ifdef SMA_BYD_HVS_CAN #define SELECTED_INVERTER_CLASS SmaBydHvsInverter @@ -16,6 +17,9 @@ class SmaBydHvsInverter : public CanInverterProtocol { void map_can_frame_to_variable(CAN_frame rx_frame); static constexpr char* Name = "BYD Battery-Box HVS over SMA CAN"; + virtual bool controls_contactor() { return true; } + virtual bool allows_contactor_closing() { return digitalRead(INVERTER_CONTACTOR_ENABLE_PIN) == 1; } + private: static const int READY_STATE = 0x03; static const int STOP_STATE = 0x02; diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index fcd7f099..9c19607c 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -3,6 +3,7 @@ #include "../include.h" #include "CanInverterProtocol.h" +#include "src/devboard/hal/hal.h" #ifdef SMA_TRIPOWER_CAN #define SELECTED_INVERTER_CLASS SmaTripowerInverter @@ -16,6 +17,9 @@ class SmaTripowerInverter : public CanInverterProtocol { void map_can_frame_to_variable(CAN_frame rx_frame); static constexpr char* Name = "SMA Tripower CAN"; + virtual bool controls_contactor() { return true; } + virtual bool allows_contactor_closing() { return digitalRead(INVERTER_CONTACTOR_ENABLE_PIN) == 1; } + private: const int READY_STATE = 0x03; const int STOP_STATE = 0x02; From 62b413bf377ec1fd5130373d382f9c4446cfbe16 Mon Sep 17 00:00:00 2001 From: Jaakko Haakana Date: Fri, 20 Jun 2025 10:00:55 +0300 Subject: [PATCH 14/14] Remove TODO --- .../communication/contactorcontrol/comm_contactorcontrol.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 7fd2c506..61417439 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -153,8 +153,6 @@ static void dbg_contactors(const char* state) { // Main functions of the handle_contactors include checking if inverter allows for closing, checking battery 2, checking BMS power output, and actual contactor closing/precharge via GPIO void handle_contactors() { - // TODO: This must be determined at run-time! - if (inverter && inverter->controls_contactor()) { datalayer.system.status.inverter_allows_contactor_closing = inverter->allows_contactor_closing(); }