From 147173bddd93a8632b742d323e97d295b54d9c08 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 12:42:02 +0000 Subject: [PATCH 01/55] retrieves time from NTP and calculate ms between now and a given time in the next 24 hours --- Software/src/devboard/utils/ntp_time.cpp | 64 ++++++++++++++++++++++++ Software/src/devboard/utils/ntp_time.h | 14 ++++++ 2 files changed, 78 insertions(+) create mode 100644 Software/src/devboard/utils/ntp_time.cpp create mode 100644 Software/src/devboard/utils/ntp_time.h diff --git a/Software/src/devboard/utils/ntp_time.cpp b/Software/src/devboard/utils/ntp_time.cpp new file mode 100644 index 00000000..c1d269ee --- /dev/null +++ b/Software/src/devboard/utils/ntp_time.cpp @@ -0,0 +1,64 @@ +#include "ntp_time.h" +#include "../../include.h" +#include "time.h" + +const unsigned long millisInADay = 24 * 60 * 60 * 1000; // 24 hours in milliseconds + +unsigned long long getNtpTimeInMillis() { + configTzTime(time_zone, ntpServer1, ntpServer2); + struct tm timeinfo; + + // Wait for time to be set + for (int i = 0; i < 5; i++) { + if (getLocalTime(&timeinfo)) { + logging.println("Time retrieved from NTP Server"); + break; + } + delay(1000); + logging.println("Waiting for NTP time..."); + } + + if (!getLocalTime(&timeinfo)) { + logging.println("Failed to obtain time"); + return 0; + } + + // Convert to milliseconds + time_t epochTime = mktime(&timeinfo); + return static_cast(epochTime) * 1000; +} + +// Function to calculate the difference in milliseconds to the next target time +unsigned long long millisToNextTargetTime(unsigned long long currentMillis, int targetTime) { + int hour = targetTime / 100; + int minute = targetTime % 100; + + time_t currentTime = currentMillis / 1000; // Convert milliseconds to seconds + struct tm* timeinfo = localtime(¤tTime); + + // Set timeinfo to the target time on the next day + timeinfo->tm_hour = hour; + timeinfo->tm_min = minute; + timeinfo->tm_sec = 0; + + // Increment day if the current time is past the target time + if (mktime(timeinfo) <= currentTime) { + timeinfo->tm_mday += 1; + } + time_t nextTargetTime = mktime(timeinfo); + unsigned long long nextTargetMillis = static_cast(nextTargetTime) * 1000; + return nextTargetMillis - currentMillis; +} + +unsigned long long getTimeOffsetfromNowUntil(int targetTime) { + logging.println("Getting time offset from now until " + String(targetTime)); + unsigned long long timeinMillis = getNtpTimeInMillis(); + if (timeinMillis != 0) { + logging.println("Time in millis: " + String(timeinMillis)); + unsigned long long timeOffsetUntilTargetTime = millisInADay - (millisToNextTargetTime(timeinMillis, targetTime)); + logging.println("Time offset until target time: " + String(timeOffsetUntilTargetTime)); + return timeOffsetUntilTargetTime; + } else + + return 0; +} diff --git a/Software/src/devboard/utils/ntp_time.h b/Software/src/devboard/utils/ntp_time.h new file mode 100644 index 00000000..e1ab97fd --- /dev/null +++ b/Software/src/devboard/utils/ntp_time.h @@ -0,0 +1,14 @@ +#ifndef __NTPTIME_H__ +#define __NTPTIME_H__ + +extern const char* ntpServer1; +extern const char* ntpServer2; +extern const char* time_zone; + +void init_mqtt(void); +void mqtt_loop(void); +unsigned long long getNtpTimeInMillis(); +unsigned long long millisToNextTargetTime(unsigned long long currentMillis, int targetTime); +unsigned long long getTimeOffsetfromNowUntil(int targetTime); + +#endif From eadb48bfa973db056da9a51275310a20f29d2d34 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 12:43:03 +0000 Subject: [PATCH 02/55] update bms-reset if statement to include a ntp offset --- .../communication/contactorcontrol/comm_contactorcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 6a828983..ee3e0cfb 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -249,7 +249,7 @@ void handle_BMSpower() { #ifdef PERIODIC_BMS_RESET // Check if 24 hours have passed since the last power removal - if (currentTime - lastPowerRemovalTime >= powerRemovalInterval) { + if ((currentTime + bmsResetTimeOffset) - lastPowerRemovalTime >= powerRemovalInterval) { start_bms_reset(); } #endif //PERIODIC_BMS_RESET From e064a04a5274d0bf7372dbc201032c802073ad7b Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 12:46:08 +0000 Subject: [PATCH 03/55] set the bmsResetTimeOffset intial value. This ensures bms reset will fall back to just resetting 24 hours after emulator starts if NTP fails or user doesnt set BMS-RESET-AT --- Software/Software.ino | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Software/Software.ino b/Software/Software.ino index f08546d5..f30df1b2 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -44,6 +44,7 @@ #include "src/devboard/mqtt/mqtt.h" #endif // MQTT #endif // WIFI +volatile unsigned long long bmsResetTimeOffset = 0; // The current software version, shown on webserver const char* version_number = "8.4.0"; @@ -52,7 +53,6 @@ const char* version_number = "8.4.0"; uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers unsigned long previousMillis10ms = 0; unsigned long previousMillisUpdateVal = 0; - // Task time measurement for debugging and for setting CPU load events int64_t core_task_time_us; MyTimer core_task_timer_10s(INTERVAL_10_S); @@ -124,6 +124,11 @@ void setup() { xTaskCreatePinnedToCore((TaskFunction_t)&core_loop, "core_loop", 4096, &core_task_time_us, TASK_CORE_PRIO, &main_loop_task, CORE_FUNCTION_CORE); +#ifdef PERIODIC_BMS_RESET_AT + bmsResetTimeOffset = getTimeOffsetfromNowUntil(PERIODIC_BMS_RESET_AT); + logging.println("bmsResetTimeOffset"); + logging.println(bmsResetTimeOffset); +#endif } // Perform main program functions From cca68fc90b095c0bc7007dd3f2f87e7dde6662be Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 12:48:05 +0000 Subject: [PATCH 04/55] we are hitting NTP so user can choose their emulator timezone or favourite ntp server --- Software/USER_SETTINGS.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 3026ac80..7ddeb02c 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -66,3 +66,11 @@ volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of cha volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete + +#ifdef PERIODIC_BMS_RESET_AT +// A list of rules for your zone can be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h +const char* time_zone = + "GMT0BST,M3.5.0/1,M10.5.0"; // TimeZone rule for Europe/London including daylight adjustment rules (optional) +const char* ntpServer1 = "pool.ntp.org"; +const char* ntpServer2 = "time.nist.gov"; +#endif From 920143a45ae579efe06a01995efc00552615a102 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 12:51:07 +0000 Subject: [PATCH 05/55] user minimum settings for using the PERIODIC_BMS_RESET_AT --- Software/USER_SETTINGS.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index e6aa4339..93ee0657 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -74,8 +74,9 @@ //#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) //#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF -//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF +#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +#define PERIODIC_BMS_RESET_AT 525 +// Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement @@ -186,3 +187,5 @@ extern IPAddress subnet; #endif #endif // __USER_SETTINGS_H__ + +extern volatile unsigned long long bmsResetTimeOffset; From e3aa09a0a17a963ae3bca24d1f5b52e75b6d02df Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 14:16:32 +0000 Subject: [PATCH 06/55] include ntp_time only on for bmsresetat --- Software/Software.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Software/Software.ino b/Software/Software.ino index f30df1b2..a45bfedc 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -44,6 +44,9 @@ #include "src/devboard/mqtt/mqtt.h" #endif // MQTT #endif // WIFI +#ifdef PERIODIC_BMS_RESET_AT +#include "src/devboard/utils/ntp_time.h" +#endif volatile unsigned long long bmsResetTimeOffset = 0; // The current software version, shown on webserver From 4796e114a8b5375325328fa0900699199000d700 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 14:18:28 +0000 Subject: [PATCH 07/55] user specific settings for testing BMS RESET AT --- Software/USER_SETTINGS.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 93ee0657..d09fcf93 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -24,7 +24,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY -//#define NISSAN_LEAF_BATTERY +#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -46,7 +46,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus //#define GROWATT_LV_CAN //Enable this line to emulate a "48V Growatt Low Voltage battery" over CAN bus @@ -63,20 +63,21 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO +#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) +#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) //#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! #define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF #define PERIODIC_BMS_RESET_AT 525 -// Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. +// Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. +// Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. PERIODIC_BMS_RESET must be enabled. /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement @@ -95,7 +96,7 @@ //#define LOG_TO_SD //Enable this line to log diagnostic data to SD card //#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) /* CAN options */ @@ -110,7 +111,7 @@ #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. +// #define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) @@ -125,13 +126,13 @@ // may break compatibility with previous versions of MQTT naming. Please refer to USER_SETTINGS.cpp for configuration options. /* Home Assistant options */ -#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required +// #define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required /* Battery settings */ // Predefined total energy capacity of the battery in Watt-hours -#define BATTERY_WH_MAX 30000 +#define BATTERY_WH_MAX 24000 // Increases battery life. If true will rescale SOC between the configured min/max-percentage -#define BATTERY_USE_SCALED_SOC true +#define BATTERY_USE_SCALED_SOC false // 8000 = 80.0% , Max percentage the battery will charge to (Inverter gets 100% when reached) #define BATTERY_MAXPERCENTAGE 8000 // 2000 = 20.0% , Min percentage the battery will discharge to (Inverter gets 0% when reached) From 401a4eb90c21c9d735dc79b0e8e335a267af604b Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 3 Feb 2025 21:29:43 +0000 Subject: [PATCH 08/55] bms reset at --- Software/Software.ino | 2 -- Software/USER_SETTINGS.h | 18 +++++++++--------- Software/src/devboard/utils/ntp_time.h | 2 -- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index a45bfedc..93e88c4b 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -129,8 +129,6 @@ void setup() { &main_loop_task, CORE_FUNCTION_CORE); #ifdef PERIODIC_BMS_RESET_AT bmsResetTimeOffset = getTimeOffsetfromNowUntil(PERIODIC_BMS_RESET_AT); - logging.println("bmsResetTimeOffset"); - logging.println(bmsResetTimeOffset); #endif } diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index d09fcf93..9544fea2 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -24,7 +24,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY -#define NISSAN_LEAF_BATTERY +//#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -46,7 +46,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus //#define GROWATT_LV_CAN //Enable this line to emulate a "48V Growatt Low Voltage battery" over CAN bus @@ -63,19 +63,19 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO +// #define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) -//#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. -//#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF -#define PERIODIC_BMS_RESET_AT 525 +// #define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) +// #define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) +// #define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +// #define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! +// #define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +// #define PERIODIC_BMS_RESET_AT 525 // Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. // Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. PERIODIC_BMS_RESET must be enabled. diff --git a/Software/src/devboard/utils/ntp_time.h b/Software/src/devboard/utils/ntp_time.h index e1ab97fd..d4946104 100644 --- a/Software/src/devboard/utils/ntp_time.h +++ b/Software/src/devboard/utils/ntp_time.h @@ -5,8 +5,6 @@ extern const char* ntpServer1; extern const char* ntpServer2; extern const char* time_zone; -void init_mqtt(void); -void mqtt_loop(void); unsigned long long getNtpTimeInMillis(); unsigned long long millisToNextTargetTime(unsigned long long currentMillis, int targetTime); unsigned long long getTimeOffsetfromNowUntil(int targetTime); From ce2dc6ecf3d440fc94069d5028e5a9c729f24045 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Tue, 4 Feb 2025 22:03:47 +0000 Subject: [PATCH 09/55] remove delay to avoid blocking --- Software/src/devboard/utils/ntp_time.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Software/src/devboard/utils/ntp_time.cpp b/Software/src/devboard/utils/ntp_time.cpp index c1d269ee..5c7de035 100644 --- a/Software/src/devboard/utils/ntp_time.cpp +++ b/Software/src/devboard/utils/ntp_time.cpp @@ -14,7 +14,6 @@ unsigned long long getNtpTimeInMillis() { logging.println("Time retrieved from NTP Server"); break; } - delay(1000); logging.println("Waiting for NTP time..."); } From de66ec0e952dfd981182ce831823610e81f0d4f5 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Tue, 4 Feb 2025 22:08:54 +0000 Subject: [PATCH 10/55] add only BMS RESET AT --- Software/USER_SETTINGS.h | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 9544fea2..5795e8d3 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -46,7 +46,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus //#define GROWATT_LV_CAN //Enable this line to emulate a "48V Growatt Low Voltage battery" over CAN bus @@ -63,21 +63,22 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -// #define HW_LILYGO +//#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -// #define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) -// #define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -// #define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. -// #define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -// #define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF -// #define PERIODIC_BMS_RESET_AT 525 -// Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. -// Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. PERIODIC_BMS_RESET must be enabled. +//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) +//#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) +//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +//#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! +//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF +//#define PERIODIC_BMS_RESET_AT 525 +//Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. +//Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. PERIODIC_BMS_RESET must be enabled. /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement @@ -96,7 +97,7 @@ //#define LOG_TO_SD //Enable this line to log diagnostic data to SD card //#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) /* CAN options */ @@ -111,7 +112,7 @@ #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -// #define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. +#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) @@ -126,13 +127,13 @@ // may break compatibility with previous versions of MQTT naming. Please refer to USER_SETTINGS.cpp for configuration options. /* Home Assistant options */ -// #define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required +#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required /* Battery settings */ // Predefined total energy capacity of the battery in Watt-hours -#define BATTERY_WH_MAX 24000 +#define BATTERY_WH_MAX 30000 // Increases battery life. If true will rescale SOC between the configured min/max-percentage -#define BATTERY_USE_SCALED_SOC false +#define BATTERY_USE_SCALED_SOC true // 8000 = 80.0% , Max percentage the battery will charge to (Inverter gets 100% when reached) #define BATTERY_MAXPERCENTAGE 8000 // 2000 = 20.0% , Min percentage the battery will discharge to (Inverter gets 0% when reached) @@ -188,5 +189,3 @@ extern IPAddress subnet; #endif #endif // __USER_SETTINGS_H__ - -extern volatile unsigned long long bmsResetTimeOffset; From bbfe680e1643bbfd88a048b8aa422a16f72e8557 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Thu, 6 Feb 2025 14:54:33 +0000 Subject: [PATCH 11/55] reset timeoffset to 0 after first bms reset to ensure reset occurs every 24 hours there after --- Software/USER_SETTINGS.h | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 5795e8d3..04d61358 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -24,7 +24,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY -//#define NISSAN_LEAF_BATTERY +#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -43,6 +43,10 @@ //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ +//#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus +//#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus +//#define BYD_SMA //Enable this line to emulate a SMA compatible "BYD Battery-Box HVS 10.2KW battery" over CAN bus +#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 @@ -63,24 +67,26 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO +#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT +/* Other options */ +// #define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) +//#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) +// #define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting +#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) //#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -//#define PERIODIC_BMS_RESET_AT 525 -//Enable PERIODIC_BMS_RESET_AT to have the emulator perform the BMS Reset at a particular time. -//Requires access to Internet / NTP Server. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. PERIODIC_BMS_RESET must be enabled. - +#define PERIODIC_BMS_RESET_AT 525 // In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. /* Shunt/Contactor settings (Optional) */ + //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement /* Select charger used (Optional) */ @@ -112,7 +118,9 @@ #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. +#define WEBSERVER_AUTH_REQUIRED \ + true //Set this line to true to activate webserver authentication (this line must not be commented). Refer to USER_SETTINGS.cpp for setting the credentials. +// #define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) @@ -172,6 +180,7 @@ extern volatile float CHARGER_MIN_HV; extern volatile float CHARGER_MAX_POWER; extern volatile float CHARGER_MAX_A; extern volatile float CHARGER_END_A; +extern volatile unsigned long long bmsResetTimeOffset; #ifdef EQUIPMENT_STOP_BUTTON typedef enum { LATCHING_SWITCH = 0, MOMENTARY_SWITCH = 1 } STOP_BUTTON_BEHAVIOR; From 5a5624521d6e95cb91c2a811b6219c9b9017e491 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Thu, 6 Feb 2025 20:55:41 +0000 Subject: [PATCH 12/55] reset timeoffset to 0 after first bms reset to ensure reset occurs every 24 hours there after --- Software/USER_SETTINGS.h | 2 +- .../communication/contactorcontrol/comm_contactorcontrol.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 04d61358..d9d7d212 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -103,7 +103,7 @@ //#define LOG_TO_SD //Enable this line to log diagnostic data to SD card //#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) /* CAN options */ diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index ee3e0cfb..b6a0d1e1 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -274,7 +274,8 @@ void start_bms_reset() { #if defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) if (!datalayer.system.status.BMS_reset_in_progress) { lastPowerRemovalTime = currentTime; // Record the time when BMS reset was started - + // we are now resetting at the correct time. We don't need to offset anymore + bmsResetTimeOffset = 0; // Set a flag to let the rest of the system know we are cutting power to the BMS. // The battery CAN sending routine will then know not to try to send anything towards battery while active datalayer.system.status.BMS_reset_in_progress = true; From 60e6d578381512aa298c27008be1d421641eb2cc Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Thu, 6 Feb 2025 21:00:14 +0000 Subject: [PATCH 13/55] revert USER_SETTINGS.h to main --- Software/USER_SETTINGS.h | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index d9d7d212..627df7f2 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -24,7 +24,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY -#define NISSAN_LEAF_BATTERY +//#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -43,10 +43,6 @@ //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ -//#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus -//#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus -//#define BYD_SMA //Enable this line to emulate a SMA compatible "BYD Battery-Box HVS 10.2KW battery" over CAN bus -#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 @@ -67,26 +63,23 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO +//#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT -/* Other options */ -// #define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -//#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) -// #define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting -#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) +//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) //#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF #define PERIODIC_BMS_RESET_AT 525 // In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. -/* Shunt/Contactor settings (Optional) */ +/* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement /* Select charger used (Optional) */ @@ -103,7 +96,7 @@ //#define LOG_TO_SD //Enable this line to log diagnostic data to SD card //#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) -#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) /* CAN options */ @@ -118,9 +111,7 @@ #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WEBSERVER_AUTH_REQUIRED \ - true //Set this line to true to activate webserver authentication (this line must not be commented). Refer to USER_SETTINGS.cpp for setting the credentials. -// #define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future. +#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) @@ -180,7 +171,6 @@ extern volatile float CHARGER_MIN_HV; extern volatile float CHARGER_MAX_POWER; extern volatile float CHARGER_MAX_A; extern volatile float CHARGER_END_A; -extern volatile unsigned long long bmsResetTimeOffset; #ifdef EQUIPMENT_STOP_BUTTON typedef enum { LATCHING_SWITCH = 0, MOMENTARY_SWITCH = 1 } STOP_BUTTON_BEHAVIOR; From aab9f876d9d1024edd3d8697cc9b98129051ca39 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Fri, 7 Feb 2025 20:41:43 +0000 Subject: [PATCH 14/55] add BMS RESET events --- Software/src/devboard/utils/events.cpp | 10 ++++++++++ Software/src/devboard/utils/events.h | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index a2f0dfbd..704456c0 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -218,6 +218,9 @@ void init_events(void) { events.entries[EVENT_MQTT_DISCONNECT].level = EVENT_LEVEL_INFO; events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SD_INIT_FAILED].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_BMS_RESET].level = EVENT_LEVEL_INFO; + events.entries[EVENT_BMS_RESET_AT_INIT_SUCCESS].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_BMS_RESET_AT_INIT_FAILED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger... @@ -446,6 +449,13 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "EQUIPMENT STOP ACTIVATED!!!"; case EVENT_SD_INIT_FAILED: return "SD card initialization failed, check hardware. Power must be removed to reset the SD card."; + case EVENT_BMS_RESET: + return "BMS Reset Event Completed."; + case EVENT_BMS_RESET_AT_INIT_SUCCESS: + return "Successfully Syncronised with the NTP Server BMS will reset every 24 hours at defined time"; + case EVENT_BMS_RESET_AT_INIT_FAILED: + return "Failed to syncronise with the NTP Server BMS will reset every 24 hours from when the emulator was " + "powered on"; default: return ""; } diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 4874ee65..b8bf9a04 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -116,7 +116,10 @@ XX(EVENT_EQUIPMENT_STOP) \ XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ XX(EVENT_SD_INIT_FAILED) \ - XX(EVENT_NOF_EVENTS) + XX(EVENT_NOF_EVENTS) \ + XX(EVENT_BMS_RESET) \ + XX(EVENT_BMS_RESET_AT_INIT_SUCCESS) \ + XX(EVENT_BMS_RESET_AT_INIT_FAILED) typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE; From 760de7f2fac45a9a23fc551a0d57fb402f418684 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Fri, 7 Feb 2025 20:42:30 +0000 Subject: [PATCH 15/55] add BMS RESET event --- .../communication/contactorcontrol/comm_contactorcontrol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index b6a0d1e1..dea1afac 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -266,6 +266,7 @@ void handle_BMSpower() { setBatteryPause(false, false, false, false); datalayer.system.status.BMS_reset_in_progress = false; // Reset the power removal flag + set_event(EVENT_BMS_RESET, 0); } #endif //defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) } @@ -277,7 +278,7 @@ void start_bms_reset() { // we are now resetting at the correct time. We don't need to offset anymore bmsResetTimeOffset = 0; // Set a flag to let the rest of the system know we are cutting power to the BMS. - // The battery CAN sending routine will then know not to try to send anything towards battery while active + // The battery CAN sending routine will then know not to try guto send anything towards battery while active datalayer.system.status.BMS_reset_in_progress = true; // Set emulator state to paused (Max Charge/Discharge = 0 & CAN = stop) From c4eae97cdae6afd6655103049a4a28e3642cd3f4 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Fri, 7 Feb 2025 20:43:12 +0000 Subject: [PATCH 16/55] add BMS RESET event --- Software/Software.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Software/Software.ino b/Software/Software.ino index 93e88c4b..fec6158f 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -129,6 +129,11 @@ void setup() { &main_loop_task, CORE_FUNCTION_CORE); #ifdef PERIODIC_BMS_RESET_AT bmsResetTimeOffset = getTimeOffsetfromNowUntil(PERIODIC_BMS_RESET_AT); + if (bmsResetTimeOffset == 0) { + set_event(EVENT_BMS_RESET_AT_INIT_FAILED, 0); + } else { + set_event(EVENT_BMS_RESET_AT_INIT_SUCCESS, 0); + } #endif } From b75d5fb20fdf89ccee45f8b0297b8cb23ba573c9 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Sat, 8 Feb 2025 14:40:09 +0000 Subject: [PATCH 17/55] add PERIODIC BMS RESET Events --- Software/Software.ino | 4 +- .../comm_contactorcontrol.cpp | 2 +- Software/src/devboard/utils/events.cpp | 16 +- Software/src/devboard/utils/events.h | 190 +++++++++--------- 4 files changed, 106 insertions(+), 106 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index fec6158f..afc4615b 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -130,9 +130,9 @@ void setup() { #ifdef PERIODIC_BMS_RESET_AT bmsResetTimeOffset = getTimeOffsetfromNowUntil(PERIODIC_BMS_RESET_AT); if (bmsResetTimeOffset == 0) { - set_event(EVENT_BMS_RESET_AT_INIT_FAILED, 0); + set_event(EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED, 0); } else { - set_event(EVENT_BMS_RESET_AT_INIT_SUCCESS, 0); + set_event(EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS, 0); } #endif } diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index dea1afac..7cfcbaf8 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -266,7 +266,7 @@ void handle_BMSpower() { setBatteryPause(false, false, false, false); datalayer.system.status.BMS_reset_in_progress = false; // Reset the power removal flag - set_event(EVENT_BMS_RESET, 0); + set_event(EVENT_PERIODIC_BMS_RESET, 0); } #endif //defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) } diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 704456c0..d5e2f267 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -218,9 +218,9 @@ void init_events(void) { events.entries[EVENT_MQTT_DISCONNECT].level = EVENT_LEVEL_INFO; events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR; events.entries[EVENT_SD_INIT_FAILED].level = EVENT_LEVEL_WARNING; - events.entries[EVENT_BMS_RESET].level = EVENT_LEVEL_INFO; - events.entries[EVENT_BMS_RESET_AT_INIT_SUCCESS].level = EVENT_LEVEL_WARNING; - events.entries[EVENT_BMS_RESET_AT_INIT_FAILED].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_PERIODIC_BMS_RESET].level = EVENT_LEVEL_INFO; + events.entries[EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS].level = EVENT_LEVEL_INFO; + events.entries[EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED].level = EVENT_LEVEL_WARNING; events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger... @@ -449,12 +449,12 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "EQUIPMENT STOP ACTIVATED!!!"; case EVENT_SD_INIT_FAILED: return "SD card initialization failed, check hardware. Power must be removed to reset the SD card."; - case EVENT_BMS_RESET: + case EVENT_PERIODIC_BMS_RESET: return "BMS Reset Event Completed."; - case EVENT_BMS_RESET_AT_INIT_SUCCESS: - return "Successfully Syncronised with the NTP Server BMS will reset every 24 hours at defined time"; - case EVENT_BMS_RESET_AT_INIT_FAILED: - return "Failed to syncronise with the NTP Server BMS will reset every 24 hours from when the emulator was " + case EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS: + return "Successfully syncronised with the NTP Server. BMS will reset every 24 hours at defined time"; + case EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED: + return "Failed to syncronise with the NTP Server. BMS will reset every 24 hours from when the emulator was " "powered on"; default: return ""; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index b8bf9a04..b5a96170 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -25,101 +25,101 @@ * - Increment EE_MAGIC_HEADER_VALUE in case you've changed the order */ -#define EVENTS_ENUM_TYPE(XX) \ - XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ - XX(EVENT_CANMCP2515_INIT_FAILURE) \ - XX(EVENT_CANFD_BUFFER_FULL) \ - XX(EVENT_CAN_BUFFER_FULL) \ - XX(EVENT_CAN_OVERRUN) \ - XX(EVENT_CAN_CORRUPTED_WARNING) \ - XX(EVENT_CAN_BATTERY_MISSING) \ - XX(EVENT_CAN_BATTERY2_MISSING) \ - XX(EVENT_CAN_CHARGER_MISSING) \ - XX(EVENT_CAN_INVERTER_MISSING) \ - XX(EVENT_CAN_NATIVE_TX_FAILURE) \ - XX(EVENT_CHARGE_LIMIT_EXCEEDED) \ - XX(EVENT_CONTACTOR_WELDED) \ - XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \ - XX(EVENT_WATER_INGRESS) \ - XX(EVENT_12V_LOW) \ - XX(EVENT_SOC_PLAUSIBILITY_ERROR) \ - XX(EVENT_SOC_UNAVAILABLE) \ - XX(EVENT_STALE_VALUE) \ - XX(EVENT_KWH_PLAUSIBILITY_ERROR) \ - XX(EVENT_BALANCING_START) \ - XX(EVENT_BALANCING_END) \ - XX(EVENT_BATTERY_EMPTY) \ - XX(EVENT_BATTERY_FULL) \ - XX(EVENT_BATTERY_FUSE) \ - XX(EVENT_BATTERY_FROZEN) \ - XX(EVENT_BATTERY_CAUTION) \ - XX(EVENT_BATTERY_CHG_STOP_REQ) \ - XX(EVENT_BATTERY_DISCHG_STOP_REQ) \ - XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \ - XX(EVENT_BATTERY_OVERHEAT) \ - XX(EVENT_BATTERY_OVERVOLTAGE) \ - XX(EVENT_BATTERY_UNDERVOLTAGE) \ - XX(EVENT_BATTERY_VALUE_UNAVAILABLE) \ - XX(EVENT_BATTERY_ISOLATION) \ - XX(EVENT_BATTERY_REQUESTS_HEAT) \ - XX(EVENT_BATTERY_WARMED_UP) \ - XX(EVENT_VOLTAGE_DIFFERENCE) \ - XX(EVENT_SOH_DIFFERENCE) \ - XX(EVENT_SOH_LOW) \ - XX(EVENT_HVIL_FAILURE) \ - XX(EVENT_PRECHARGE_FAILURE) \ - XX(EVENT_INTERNAL_OPEN_FAULT) \ - XX(EVENT_INVERTER_OPEN_CONTACTOR) \ - XX(EVENT_INTERFACE_MISSING) \ - XX(EVENT_MODBUS_INVERTER_MISSING) \ - XX(EVENT_ERROR_OPEN_CONTACTOR) \ - XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \ - XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \ - XX(EVENT_CELL_UNDER_VOLTAGE) \ - XX(EVENT_CELL_OVER_VOLTAGE) \ - XX(EVENT_CELL_DEVIATION_HIGH) \ - XX(EVENT_UNKNOWN_EVENT_SET) \ - XX(EVENT_OTA_UPDATE) \ - XX(EVENT_OTA_UPDATE_TIMEOUT) \ - XX(EVENT_DUMMY_INFO) \ - XX(EVENT_DUMMY_DEBUG) \ - XX(EVENT_DUMMY_WARNING) \ - XX(EVENT_DUMMY_ERROR) \ - XX(EVENT_PERSISTENT_SAVE_INFO) \ - XX(EVENT_SERIAL_RX_WARNING) \ - XX(EVENT_SERIAL_RX_FAILURE) \ - XX(EVENT_SERIAL_TX_FAILURE) \ - XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \ - XX(EVENT_EEPROM_WRITE) \ - XX(EVENT_RESET_UNKNOWN) \ - XX(EVENT_RESET_POWERON) \ - XX(EVENT_RESET_EXT) \ - XX(EVENT_RESET_SW) \ - XX(EVENT_RESET_PANIC) \ - XX(EVENT_RESET_INT_WDT) \ - XX(EVENT_RESET_TASK_WDT) \ - XX(EVENT_RESET_WDT) \ - XX(EVENT_RESET_DEEPSLEEP) \ - XX(EVENT_RESET_BROWNOUT) \ - XX(EVENT_RESET_SDIO) \ - XX(EVENT_RESET_USB) \ - XX(EVENT_RESET_JTAG) \ - XX(EVENT_RESET_EFUSE) \ - XX(EVENT_RESET_PWR_GLITCH) \ - XX(EVENT_RESET_CPU_LOCKUP) \ - XX(EVENT_PAUSE_BEGIN) \ - XX(EVENT_PAUSE_END) \ - XX(EVENT_WIFI_CONNECT) \ - XX(EVENT_WIFI_DISCONNECT) \ - XX(EVENT_MQTT_CONNECT) \ - XX(EVENT_MQTT_DISCONNECT) \ - XX(EVENT_EQUIPMENT_STOP) \ - XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ - XX(EVENT_SD_INIT_FAILED) \ - XX(EVENT_NOF_EVENTS) \ - XX(EVENT_BMS_RESET) \ - XX(EVENT_BMS_RESET_AT_INIT_SUCCESS) \ - XX(EVENT_BMS_RESET_AT_INIT_FAILED) +#define EVENTS_ENUM_TYPE(XX) \ + XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ + XX(EVENT_CANMCP2515_INIT_FAILURE) \ + XX(EVENT_CANFD_BUFFER_FULL) \ + XX(EVENT_CAN_BUFFER_FULL) \ + XX(EVENT_CAN_OVERRUN) \ + XX(EVENT_CAN_CORRUPTED_WARNING) \ + XX(EVENT_CAN_BATTERY_MISSING) \ + XX(EVENT_CAN_BATTERY2_MISSING) \ + XX(EVENT_CAN_CHARGER_MISSING) \ + XX(EVENT_CAN_INVERTER_MISSING) \ + XX(EVENT_CAN_NATIVE_TX_FAILURE) \ + XX(EVENT_CHARGE_LIMIT_EXCEEDED) \ + XX(EVENT_CONTACTOR_WELDED) \ + XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \ + XX(EVENT_WATER_INGRESS) \ + XX(EVENT_12V_LOW) \ + XX(EVENT_SOC_PLAUSIBILITY_ERROR) \ + XX(EVENT_SOC_UNAVAILABLE) \ + XX(EVENT_STALE_VALUE) \ + XX(EVENT_KWH_PLAUSIBILITY_ERROR) \ + XX(EVENT_BALANCING_START) \ + XX(EVENT_BALANCING_END) \ + XX(EVENT_BATTERY_EMPTY) \ + XX(EVENT_BATTERY_FULL) \ + XX(EVENT_BATTERY_FUSE) \ + XX(EVENT_BATTERY_FROZEN) \ + XX(EVENT_BATTERY_CAUTION) \ + XX(EVENT_BATTERY_CHG_STOP_REQ) \ + XX(EVENT_BATTERY_DISCHG_STOP_REQ) \ + XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \ + XX(EVENT_BATTERY_OVERHEAT) \ + XX(EVENT_BATTERY_OVERVOLTAGE) \ + XX(EVENT_BATTERY_UNDERVOLTAGE) \ + XX(EVENT_BATTERY_VALUE_UNAVAILABLE) \ + XX(EVENT_BATTERY_ISOLATION) \ + XX(EVENT_BATTERY_REQUESTS_HEAT) \ + XX(EVENT_BATTERY_WARMED_UP) \ + XX(EVENT_VOLTAGE_DIFFERENCE) \ + XX(EVENT_SOH_DIFFERENCE) \ + XX(EVENT_SOH_LOW) \ + XX(EVENT_HVIL_FAILURE) \ + XX(EVENT_PRECHARGE_FAILURE) \ + XX(EVENT_INTERNAL_OPEN_FAULT) \ + XX(EVENT_INVERTER_OPEN_CONTACTOR) \ + XX(EVENT_INTERFACE_MISSING) \ + XX(EVENT_MODBUS_INVERTER_MISSING) \ + XX(EVENT_ERROR_OPEN_CONTACTOR) \ + XX(EVENT_CELL_CRITICAL_UNDER_VOLTAGE) \ + XX(EVENT_CELL_CRITICAL_OVER_VOLTAGE) \ + XX(EVENT_CELL_UNDER_VOLTAGE) \ + XX(EVENT_CELL_OVER_VOLTAGE) \ + XX(EVENT_CELL_DEVIATION_HIGH) \ + XX(EVENT_UNKNOWN_EVENT_SET) \ + XX(EVENT_OTA_UPDATE) \ + XX(EVENT_OTA_UPDATE_TIMEOUT) \ + XX(EVENT_DUMMY_INFO) \ + XX(EVENT_DUMMY_DEBUG) \ + XX(EVENT_DUMMY_WARNING) \ + XX(EVENT_DUMMY_ERROR) \ + XX(EVENT_PERSISTENT_SAVE_INFO) \ + XX(EVENT_SERIAL_RX_WARNING) \ + XX(EVENT_SERIAL_RX_FAILURE) \ + XX(EVENT_SERIAL_TX_FAILURE) \ + XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \ + XX(EVENT_EEPROM_WRITE) \ + XX(EVENT_RESET_UNKNOWN) \ + XX(EVENT_RESET_POWERON) \ + XX(EVENT_RESET_EXT) \ + XX(EVENT_RESET_SW) \ + XX(EVENT_RESET_PANIC) \ + XX(EVENT_RESET_INT_WDT) \ + XX(EVENT_RESET_TASK_WDT) \ + XX(EVENT_RESET_WDT) \ + XX(EVENT_RESET_DEEPSLEEP) \ + XX(EVENT_RESET_BROWNOUT) \ + XX(EVENT_RESET_SDIO) \ + XX(EVENT_RESET_USB) \ + XX(EVENT_RESET_JTAG) \ + XX(EVENT_RESET_EFUSE) \ + XX(EVENT_RESET_PWR_GLITCH) \ + XX(EVENT_RESET_CPU_LOCKUP) \ + XX(EVENT_PAUSE_BEGIN) \ + XX(EVENT_PAUSE_END) \ + XX(EVENT_WIFI_CONNECT) \ + XX(EVENT_WIFI_DISCONNECT) \ + XX(EVENT_MQTT_CONNECT) \ + XX(EVENT_MQTT_DISCONNECT) \ + XX(EVENT_EQUIPMENT_STOP) \ + XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \ + XX(EVENT_SD_INIT_FAILED) \ + XX(EVENT_PERIODIC_BMS_RESET) \ + XX(EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS) \ + XX(EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED) \ + XX(EVENT_NOF_EVENTS) typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE; From 1360c9250c30955d3d528bd13669389d059dad60 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Sat, 8 Feb 2025 15:07:59 +0000 Subject: [PATCH 18/55] wait a couple of seconds after re applying power to BMS before un pausing it --- .../contactorcontrol/comm_contactorcontrol.cpp | 13 ++++++++++--- Software/src/datalayer/datalayer.h | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 7cfcbaf8..815abe22 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -41,8 +41,10 @@ unsigned long timeSpentInFaultedMode = 0; #endif unsigned long currentTime = 0; unsigned long lastPowerRemovalTime = 0; +unsigned long bmsPowerOnTime = 0; const unsigned long powerRemovalInterval = 24 * 60 * 60 * 1000; // 24 hours in milliseconds const unsigned long powerRemovalDuration = 30000; // 30 seconds in milliseconds +const unsigned long bmsWarmupDuration = 3000; void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) { #ifdef PWM_CONTACTOR_CONTROL @@ -254,18 +256,23 @@ void handle_BMSpower() { } #endif //PERIODIC_BMS_RESET - // If power has been removed for 30 seconds, restore the power and resume the emulator + // If power has been removed for 30 seconds, restore the power if (datalayer.system.status.BMS_reset_in_progress && currentTime - lastPowerRemovalTime >= powerRemovalDuration) { // Reapply power to the BMS digitalWrite(BMS_POWER, HIGH); #ifdef BMS_2_POWER digitalWrite(BMS_2_POWER, HIGH); // Same for battery 2 #endif + bmsPowerOnTime = currentTime; + datalayer.system.status.BMS_reset_in_progress = false; // Reset the power removal flag + datalayer.system.status.BMS_startup_in_progress = true; // Set the BMS warmup flag + } + //if power has been restored we need to wait a couple of seconds to unpause the battery + if (datalayer.system.status.BMS_startup_in_progress && currentTime - bmsPowerOnTime >= bmsWarmupDuration) { - //Resume from the power pause setBatteryPause(false, false, false, false); - datalayer.system.status.BMS_reset_in_progress = false; // Reset the power removal flag + datalayer.system.status.BMS_startup_in_progress = false; // Reset the BMS warmup removal flag set_event(EVENT_PERIODIC_BMS_RESET, 0); } #endif //defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index e85cb81c..0cb54bdb 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -280,6 +280,8 @@ typedef struct { #endif /** True if the BMS is being reset, by cutting power towards it */ bool BMS_reset_in_progress = false; + /** True if the BMS is starting up */ + bool BMS_startup_in_progress = false; } DATALAYER_SYSTEM_STATUS_TYPE; typedef struct { From 105fa26c66ced9d5bf5009b58bb87bc56dabed7d Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Sat, 8 Feb 2025 15:59:04 +0000 Subject: [PATCH 19/55] wait a couple of seconds after re applying power to BMS before un pausing it --- Software/src/battery/NISSAN-LEAF-BATTERY.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index ddd7c91e..14d14a0a 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1067,7 +1067,7 @@ void transmit_can_battery() { unsigned long currentMillis = millis(); - if (datalayer.system.status.BMS_reset_in_progress) { + if (datalayer.system.status.BMS_reset_in_progress || datalayer.system.status.BMS_startup_in_progress) { // Transmitting towards battery is halted while BMS is being reset // Reset sending counters to avoid overrun messages when reset is over previousMillis10 = currentMillis; From 254886c7dda5067293afdc9c320dfcfea61bb8ce Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Sat, 8 Feb 2025 21:47:02 +0000 Subject: [PATCH 20/55] merge to main --- Software/USER_SETTINGS.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 2f3ea317..d67a8b14 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -76,7 +76,8 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! //#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -#define PERIODIC_BMS_RESET_AT 525 // In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. +// PERIODIC_BMS_RESET_AT In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp +#define PERIODIC_BMS_RESET_AT 525 /* Shunt/Contactor settings (Optional) */ //#define BMW_SBOX // SBOX relay control & battery current/voltage measurement @@ -140,6 +141,8 @@ #define BATTERY_MAXTEMPERATURE 500 // -250 = -25.0 °C , Min temperature (Will produce a battery frozen event if below) #define BATTERY_MINTEMPERATURE -250 +// 150 = 15.0 °C , Max difference between min and max temperature (Will produce a battery temperature deviation event if greater) +#define BATTERY_MAX_TEMPERATURE_DEVIATION 150 // 300 = 30.0A , Max charge in Amp (Some inverters needs to be limited) #define BATTERY_MAX_CHARGE_AMP 300 // 300 = 30.0A , Max discharge in Amp (Some inverters needs to be limited) @@ -186,4 +189,8 @@ extern IPAddress subnet; #define DEBUG_LOG #endif +#if defined(MEB_BATTERY) +#define PRECHARGE_CONTROL +#endif + #endif // __USER_SETTINGS_H__ From 4a281ba2f4b373c9ff859995c25ebce896dd3e41 Mon Sep 17 00:00:00 2001 From: rha Date: Mon, 10 Feb 2025 06:32:44 +0200 Subject: [PATCH 21/55] Kostal rx handling rewritten --- Software/src/inverter/KOSTAL-RS485.cpp | 206 ++++++++++++------------- Software/src/inverter/KOSTAL-RS485.h | 1 + 2 files changed, 103 insertions(+), 104 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index b8a6f18e..4a6dcb10 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -20,6 +20,7 @@ static unsigned long currentMillis; static unsigned long startupMillis = 0; static unsigned long contactorMillis = 0; +static uint8_t rx_index = 0; static boolean RX_allow = false; union f32b { @@ -28,14 +29,17 @@ union f32b { }; uint8_t BATTERY_INFO[40] = { - 0x06, 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header - 0x01, 0x08, 0x80, 0x43, // 256.063 Nominal voltage / 5*51.2=256 first byte 0x01 or 0x04 - 0xE4, 0x70, 0x8A, 0x5C, // These might be Umin & Unax, Uint16 - 0xB5, 0x02, 0xD3, 0x01, // Battery Serial number? Modbus register 527 - 0x01, 0x05, 0xC8, 0x41, // 25.0024 ? - 0xC2, 0x18, // Battery Firmware, modbus register 586 - 0x01, 0x03, 0x59, 0x42, // 0x00005942 = 54.25 ?? - 0x01, 0x01, 0x01, 0x02, 0x05, 0x02, 0xA0, 0x01, 0x01, 0x02, + 0x00, 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header + 0x00, 0x00, 0x80, 0x43, // 256.063 Nominal voltage / 5*51.2=256 first byte 0x01 or 0x04 + 0xE4, 0x70, 0x8A, 0x5C, // Manufacture date (Epoch time) (BYD: GetBatteryInfo this[0x10ac]) + 0xB5, 0x00, 0xD3, 0x00, // Battery Serial number? Modbus register 527 - 0x10b0 + 0x00, 0x00, 0xC8, 0x41, // 0x10b4 + 0xC2, 0x18, // Battery Firmware, modbus register 586 (0x10b8) + 0x00, // Static (BYD: GetBatteryInfo this[0x10ba]) + 0x00, // ? + 0x59, 0x42, // Static (BYD: GetBatteryInfo this[0x10bc]) + 0x00, 0x00, // Static (BYD: GetBatteryInfo this[0x10be]) + 0x00, 0x00, 0x05, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x4D, // CRC 0x00}; // @@ -59,11 +63,11 @@ uint8_t CyclicData[64] = { 0xFE, 0x04, // Cycle count, 0x00, // Byte 56 - 0x40, // When SOC=100 Byte57=0x40, at startup 0x03 (about 7 times), otherwise 0x02 + 0x00, // When SOC=100 Byte57 seen as 0x40, 0x64, // SOC , Bit 58 0x00, // Unknown, 0x00, // Unknown, - 0x02, // Unknown, Mostly 0x02. seen also 0x01 + 0x01, // Unknown, Byte 61, 1 only at first frame 0x00, // CRC (inverted sum of bytes 1-62 + 0xC0), Bit 62 0x00}; @@ -80,7 +84,6 @@ uint8_t frame3[9] = { uint8_t frame4[8] = {0x07, 0xE3, 0xFF, 0x02, 0xFF, 0x29, 0xF4, 0x00}; uint8_t frameB1[10] = {0x07, 0x63, 0xFF, 0x02, 0xFF, 0x29, 0x5E, 0x02, 0x16, 0x00}; -uint8_t frameB1b[8] = {0x07, 0xE3, 0xFF, 0x02, 0xFF, 0x29, 0xF4, 0x00}; uint8_t RS485_RXFRAME[300]; @@ -117,6 +120,18 @@ static void dbg_frame(byte* frame, int len, const char* prefix) { } logging.println(""); #endif +#ifdef DEBUG_KOSTAL_RS485_DATA_USB + Serial.print(prefix); + Serial.print(": "); + for (uint8_t i = 0; i < len; i++) { + if (frame[i] < 0x10) { + Serial.print("0"); + } + Serial.print(frame[i], HEX); + Serial.print(" "); + } + Serial.println(""); +#endif } static void dbg_message(const char* msg) { @@ -154,20 +169,20 @@ byte calculate_kostal_crc(byte* lfc, int len) { return (byte)(-sum & 0xff); } -byte calculate_frame1_crc(byte* lfc, int lastbyte) { +bool check_kostal_frame_crc(int len) { unsigned int sum = 0; - for (int i = 0; i < lastbyte; ++i) { - sum += lfc[i]; - } - return ((byte) ~(sum - 0x28) & 0xff); -} - -bool check_kostal_frame_crc() { - unsigned int sum = 0; - for (int i = 1; i < 8; ++i) { + int zeropointer = RS485_RXFRAME[0]; + int last_zero = 0; + for (int i = 1; i < len - 2; ++i) { + if (i == zeropointer + last_zero) { + zeropointer = RS485_RXFRAME[i]; + last_zero = i; + RS485_RXFRAME[i] = 0x00; + } sum += RS485_RXFRAME[i]; } - if (((~sum + 1) & 0xff) == (RS485_RXFRAME[8] & 0xff)) { + + if ((-sum & 0xff) == (RS485_RXFRAME[len - 2] & 0xff)) { return (true); } else { return (false); @@ -185,9 +200,7 @@ void update_RS485_registers_inverter() { if (datalayer.system.status.battery_allows_contactor_closing & datalayer.system.status.inverter_allows_contactor_closing) { float2frame(CyclicData, (float)datalayer.battery.status.voltage_dV / 10, 6); // Confirmed OK mapping - CyclicData[0] = 0x0A; } else { - CyclicData[0] = 0x06; float2frame(CyclicData, 0.0, 6); } // Set nominal voltage to value between min and max voltage set by battery (Example 400 and 300 results in 350V) @@ -196,13 +209,13 @@ void update_RS485_registers_inverter() { datalayer.battery.info.min_design_voltage_dV); float2frame(BATTERY_INFO, (float)nominal_voltage_dV / 10, 6); + float2frame(CyclicData, (float)datalayer.battery.info.max_design_voltage_dV / 10, 10); float2frame(CyclicData, (float)average_temperature_dC / 10, 14); - // Some current values causes communication error, must be resolved, why. - // float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 18); // Peak discharge? current (2 byte float) - // float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 22); + float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 18); // Last current + float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 22); // Should be Avg current(1s) float2frame(CyclicData, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); @@ -242,8 +255,6 @@ void update_RS485_registers_inverter() { register_content_ok = true; - BATTERY_INFO[38] = calculate_frame1_crc(BATTERY_INFO, 38); - if (incoming_message_counter > 0) { incoming_message_counter--; } @@ -255,8 +266,6 @@ void update_RS485_registers_inverter() { } } -static uint8_t rx_index = 0; - void receive_RS485() // Runs as fast as possible to handle the serial stream { currentMillis = millis(); @@ -265,97 +274,84 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream contactorMillis = currentMillis; } if (currentMillis - contactorMillis >= INTERVAL_2_S & !RX_allow) { - RX_allow = true; dbg_message("RX_allow -> true"); + RX_allow = true; } - if (startupMillis) { - if (((currentMillis - startupMillis) >= INTERVAL_2_S & currentMillis - startupMillis <= 7000) & - datalayer.system.status.inverter_allows_contactor_closing) { - // Disconnect allowed only, when curren zero - if (datalayer.battery.status.current_dA == 0) { - datalayer.system.status.inverter_allows_contactor_closing = false; - dbg_message("inverter_allows_contactor_closing -> false"); - } - } else if (((currentMillis - startupMillis) >= 7000) & - datalayer.system.status.inverter_allows_contactor_closing == false) { - datalayer.system.status.inverter_allows_contactor_closing = true; - dbg_message("inverter_allows_contactor_closing -> true"); - } - } - - if (B1_delay) { - if ((currentMillis - B1_last_millis) > INTERVAL_1_S) { - send_kostal(frameB1b, 8); - B1_delay = false; - dbg_message("B1_delay -> false"); - } - } else if (Serial2.available()) { + if (Serial2.available()) { RS485_RXFRAME[rx_index] = Serial2.read(); if (RX_allow) { rx_index++; if (RS485_RXFRAME[rx_index - 1] == 0x00) { - if ((rx_index == 10) && (RS485_RXFRAME[0] == 0x09) && register_content_ok) { + if ((rx_index > 9) && register_content_ok) { dbg_frame(RS485_RXFRAME, 10, "RX"); - rx_index = 0; - if (check_kostal_frame_crc()) { + if (check_kostal_frame_crc(rx_index)) { incoming_message_counter = RS485_HEALTHY; - bool headerA = true; - bool headerB = true; - for (uint8_t i = 0; i < 5; i++) { - if (RS485_RXFRAME[i + 1] != KOSTAL_FRAMEHEADER[i]) { - headerA = false; - } - if (RS485_RXFRAME[i + 1] != KOSTAL_FRAMEHEADER2[i]) { - headerB = false; - } - } - // "frame B1", maybe reset request, seen after battery power on/partial data - if (headerB && (RS485_RXFRAME[6] == 0x5E) && (RS485_RXFRAME[7] == 0xFF)) { - send_kostal(frameB1, 10); - B1_delay = true; - dbg_message("B1_delay -> true"); - B1_last_millis = currentMillis; - } - - // "frame B1", maybe reset request, seen after battery power on/partial data - if (headerB && (RS485_RXFRAME[6] == 0x5E) && (RS485_RXFRAME[7] == 0x04)) { - send_kostal(frame4, 8); - // This needs more reverse engineering, disabled... - } - - if (headerA && (RS485_RXFRAME[6] == 0x4A) && (RS485_RXFRAME[7] == 0x08)) { // "frame 1" - send_kostal(BATTERY_INFO, 40); - if (!startupMillis) { - startupMillis = currentMillis; + if (RS485_RXFRAME[1] == 'c') { + if (RS485_RXFRAME[6] == 0x47) { + // Set time function - Do nothing. + send_kostal(frame4, 8); // ACK } - } - if (headerA && (RS485_RXFRAME[6] == 0x4A) && (RS485_RXFRAME[7] == 0x04)) { // "frame 2" - update_values_battery(); - update_RS485_registers_inverter(); - if (f2_startup_count < 15) { - f2_startup_count++; + if (RS485_RXFRAME[6] == 0x5E) { + // Set State function + if (RS485_RXFRAME[7] == 0x00) { + // Allow contactor closing + datalayer.system.status.inverter_allows_contactor_closing = true; + dbg_message("inverter_allows_contactor_closing -> true"); + send_kostal(frame4, 8); // ACK + } else if (RS485_RXFRAME[7] == 0x04) { + // INVALID STATE, no ACK sent + } else { + // Battery deep sleep? + send_kostal(frame4, 8); // ACK + } + } + } else if (RS485_RXFRAME[1] == 'b') { + if (RS485_RXFRAME[6] == 0x50) { + //Reverse polarity, do nothing + } else { + int code = RS485_RXFRAME[6] + RS485_RXFRAME[7] * 0x100; + if (code == 0x44a) { + //Send cyclic data + update_values_battery(); + update_RS485_registers_inverter(); + if (f2_startup_count < 15) { + f2_startup_count++; + } + byte tmpframe[64]; //copy values to prevent data manipulation during rewrite/crc calculation + memcpy(tmpframe, CyclicData, 64); + tmpframe[62] = calculate_kostal_crc(tmpframe, 62); + null_stuffer(tmpframe, 64); + send_kostal(tmpframe, 64); + CyclicData[61] = 0x00; + } + if (code == 0x84a) { + //Send battery info + byte tmpframe[40]; //copy values to prevent data manipulation during rewrite/crc calculation + memcpy(tmpframe, BATTERY_INFO, 40); + tmpframe[38] = calculate_kostal_crc(tmpframe, 38); + null_stuffer(tmpframe, 40); + send_kostal(tmpframe, 40); + datalayer.system.status.inverter_allows_contactor_closing = true; + dbg_message("inverter_allows_contactor_closing -> true"); + if (!startupMillis) { + startupMillis = currentMillis; + } + } + if (code == 0x353) { + //Send battery error + send_kostal(frame3, 9); + } } - byte tmpframe[64]; //copy values to prevent data manipulation during rewrite/crc calculation - memcpy(tmpframe, CyclicData, 64); - - tmpframe[62] = calculate_kostal_crc(tmpframe, 62); - null_stuffer(tmpframe, 64); - send_kostal(tmpframe, 64); - } - if (headerA && (RS485_RXFRAME[6] == 0x53) && (RS485_RXFRAME[7] == 0x03)) { // "frame 3" - send_kostal(frame3, 9); } } - } else { - dbg_frame(RS485_RXFRAME, 10, "RX (dropped)"); + rx_index = 0; } rx_index = 0; } } - if (rx_index >= 10) { - dbg_frame(RS485_RXFRAME, 10, "RX (!RX_allow)"); + if (rx_index >= 299) { rx_index = 0; } } @@ -364,6 +360,8 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream void setup_inverter(void) { // Performs one time setup at startup strncpy(datalayer.system.info.inverter_protocol, "BYD battery via Kostal RS485", 63); datalayer.system.info.inverter_protocol[63] = '\0'; + datalayer.system.status.inverter_allows_contactor_closing = false; + dbg_message("inverter_allows_contactor_closing -> false"); } #endif diff --git a/Software/src/inverter/KOSTAL-RS485.h b/Software/src/inverter/KOSTAL-RS485.h index 6f638ac6..a0d1f0be 100644 --- a/Software/src/inverter/KOSTAL-RS485.h +++ b/Software/src/inverter/KOSTAL-RS485.h @@ -5,6 +5,7 @@ #define RS485_INVERTER_SELECTED //#define DEBUG_KOSTAL_RS485_DATA // Enable this line to get TX / RX printed out via logging +#define DEBUG_KOSTAL_RS485_DATA_USB // Enable this line to get TX / RX printed out via USB #if defined(DEBUG_KOSTAL_RS485_DATA) && !defined(DEBUG_LOG) #error "enable LOG_TO_SD, DEBUG_VIA_USB or DEBUG_VIA_WEB in order to use DEBUG_KOSTAL_RS485_DATA" From 68573e4e9c0b400102c254b8a953d025d05da5e7 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 10 Feb 2025 12:12:52 +0000 Subject: [PATCH 22/55] add extern declaration for bmsReset --- Software/USER_SETTINGS.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index d67a8b14..4d4af5b9 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -24,7 +24,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY -//#define NISSAN_LEAF_BATTERY +#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -46,7 +46,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus //#define GROWATT_LV_CAN //Enable this line to emulate a "48V Growatt Low Voltage battery" over CAN bus @@ -63,18 +63,18 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -//#define HW_LILYGO +#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) +#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) //#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF // PERIODIC_BMS_RESET_AT In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp #define PERIODIC_BMS_RESET_AT 525 @@ -111,8 +111,9 @@ #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. -#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. +#define WEBSERVER_AUTH_REQUIRED +//#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. +//#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) @@ -126,7 +127,7 @@ // may break compatibility with previous versions of MQTT naming. Please refer to USER_SETTINGS.cpp for configuration options. /* Home Assistant options */ -#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required +// #define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required /* Battery settings */ // Predefined total energy capacity of the battery in Watt-hours @@ -174,6 +175,8 @@ extern volatile float CHARGER_MAX_POWER; extern volatile float CHARGER_MAX_A; extern volatile float CHARGER_END_A; +extern volatile unsigned long long bmsResetTimeOffset; + #ifdef EQUIPMENT_STOP_BUTTON typedef enum { LATCHING_SWITCH = 0, MOMENTARY_SWITCH = 1 } STOP_BUTTON_BEHAVIOR; extern volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior; From ac209e17f429030bc7fdf22f9badf7ce8c6f63ae Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 10 Feb 2025 12:17:21 +0000 Subject: [PATCH 23/55] add extern declaration for bmsReset --- Software/USER_SETTINGS.h | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 4d4af5b9..d195758c 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -24,7 +24,7 @@ //#define KIA_HYUNDAI_HYBRID_BATTERY //#define MEB_BATTERY //#define MG_5_BATTERY -#define NISSAN_LEAF_BATTERY +//#define NISSAN_LEAF_BATTERY //#define PYLON_BATTERY //#define RJXZS_BMS //#define RANGE_ROVER_PHEV_BATTERY @@ -46,7 +46,7 @@ //#define AFORE_CAN //Enable this line to emulate an "Afore battery" over CAN bus //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 -#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define GROWATT_HV_CAN //Enable this line to emulate a "Growatt High Voltage v1.10 battery" over CAN bus //#define GROWATT_LV_CAN //Enable this line to emulate a "48V Growatt Low Voltage battery" over CAN bus @@ -63,20 +63,20 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO +//#define HW_LILYGO //#define HW_STARK //#define HW_3LB //#define HW_DEVKIT /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) -#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) +//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins) //#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins) -#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. +//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled. //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! -#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF +//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -// PERIODIC_BMS_RESET_AT In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp +// PERIODIC_BMS_RESET_AT Uses NTP server, internet required. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp #define PERIODIC_BMS_RESET_AT 525 /* Shunt/Contactor settings (Optional) */ @@ -111,9 +111,8 @@ #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WEBSERVER_AUTH_REQUIRED -//#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. -//#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. +#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. +#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) @@ -127,7 +126,7 @@ // may break compatibility with previous versions of MQTT naming. Please refer to USER_SETTINGS.cpp for configuration options. /* Home Assistant options */ -// #define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required +#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required /* Battery settings */ // Predefined total energy capacity of the battery in Watt-hours @@ -142,8 +141,6 @@ #define BATTERY_MAXTEMPERATURE 500 // -250 = -25.0 °C , Min temperature (Will produce a battery frozen event if below) #define BATTERY_MINTEMPERATURE -250 -// 150 = 15.0 °C , Max difference between min and max temperature (Will produce a battery temperature deviation event if greater) -#define BATTERY_MAX_TEMPERATURE_DEVIATION 150 // 300 = 30.0A , Max charge in Amp (Some inverters needs to be limited) #define BATTERY_MAX_CHARGE_AMP 300 // 300 = 30.0A , Max discharge in Amp (Some inverters needs to be limited) @@ -192,8 +189,4 @@ extern IPAddress subnet; #define DEBUG_LOG #endif -#if defined(MEB_BATTERY) -#define PRECHARGE_CONTROL -#endif - #endif // __USER_SETTINGS_H__ From 03b50c0ca529dc56e27e4537b93f0a1ad2a6bab1 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 10 Feb 2025 21:39:42 +0000 Subject: [PATCH 24/55] rebase from main --- Software/USER_SETTINGS.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index d195758c..345fe5ed 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -76,7 +76,8 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! //#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -// PERIODIC_BMS_RESET_AT Uses NTP server, internet required. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp +//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF +// PERIODIC_BMS_RESET_AT In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp #define PERIODIC_BMS_RESET_AT 525 /* Shunt/Contactor settings (Optional) */ From 26358748adebef3d33210eccdf760c35de49e373 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Mon, 10 Feb 2025 21:45:15 +0000 Subject: [PATCH 25/55] rebase from main --- Software/USER_SETTINGS.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 345fe5ed..53a1176c 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -76,7 +76,6 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! //#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF // PERIODIC_BMS_RESET_AT In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp #define PERIODIC_BMS_RESET_AT 525 From d1fb7a95c917c1b9a5398004e6f12d036bd0a4c1 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Fri, 14 Feb 2025 23:13:27 +0000 Subject: [PATCH 26/55] merge period bms reset offset with main; --- Software/USER_SETTINGS.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 059814f4..eb50b5bc 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -78,7 +78,7 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! //#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF //#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF -// PERIODIC_BMS_RESET_AT In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp +// PERIODIC_BMS_RESET_AT Uses NTP server, internet required. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp #define PERIODIC_BMS_RESET_AT 525 /* Shunt/Contactor settings (Optional) */ @@ -143,6 +143,8 @@ #define BATTERY_MAXTEMPERATURE 500 // -250 = -25.0 °C , Min temperature (Will produce a battery frozen event if below) #define BATTERY_MINTEMPERATURE -250 +// 150 = 15.0 °C , Max difference between min and max temperature (Will produce a battery temperature deviation event if greater) +#define BATTERY_MAX_TEMPERATURE_DEVIATION 150 // 300 = 30.0A , Max charge in Amp (Some inverters needs to be limited) #define BATTERY_MAX_CHARGE_AMP 300 // 300 = 30.0A , Max discharge in Amp (Some inverters needs to be limited) @@ -191,4 +193,8 @@ extern IPAddress subnet; #define DEBUG_LOG #endif +#if defined(MEB_BATTERY) +#define PRECHARGE_CONTROL +#endif + #endif // __USER_SETTINGS_H__ From db91f91750b824d92d021313f88b7d42add36526 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 22 Feb 2025 06:44:51 +0200 Subject: [PATCH 27/55] Kostal battery info: Nominal capacity --- Software/src/inverter/KOSTAL-RS485.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 4a6dcb10..07217987 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -33,7 +33,7 @@ uint8_t BATTERY_INFO[40] = { 0x00, 0x00, 0x80, 0x43, // 256.063 Nominal voltage / 5*51.2=256 first byte 0x01 or 0x04 0xE4, 0x70, 0x8A, 0x5C, // Manufacture date (Epoch time) (BYD: GetBatteryInfo this[0x10ac]) 0xB5, 0x00, 0xD3, 0x00, // Battery Serial number? Modbus register 527 - 0x10b0 - 0x00, 0x00, 0xC8, 0x41, // 0x10b4 + 0x00, 0x00, 0xC8, 0x41, // Nominal Capacity (0x10b4) 0xC2, 0x18, // Battery Firmware, modbus register 586 (0x10b8) 0x00, // Static (BYD: GetBatteryInfo this[0x10ba]) 0x00, // ? From b14dd98b22cd1f2329d86d58febbed39c22cd99c Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 22 Feb 2025 07:10:30 +0200 Subject: [PATCH 28/55] Kostal status frame crc calculation & null stuffing --- Software/src/inverter/KOSTAL-RS485.cpp | 30 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 07217987..87ea82ec 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -74,16 +74,21 @@ uint8_t CyclicData[64] = { // FE 04 01 40 xx 01 01 02 yy (fully charged) // FE 02 01 02 xx 01 01 02 yy (charging or discharging) -uint8_t frame3[9] = { - 0x08, 0xE2, 0xFF, 0x02, 0xFF, 0x29, //header - 0x06, //Unknown +//uint8_t frame3[9] = { +// 0x08, 0xE2, 0xFF, 0x02, 0xFF, 0x29, //header +// 0x06, //Unknown (battery status/error?) +// 0xEF, //CRC +// 0x00 //endbyte +//}; + +uint8_t STATUS_FRAME[9] = { + 0x00, 0xE2, 0xFF, 0x02, 0xFF, 0x29, //header + 0x06, //Unknown (battery status/error?) 0xEF, //CRC 0x00 //endbyte }; -uint8_t frame4[8] = {0x07, 0xE3, 0xFF, 0x02, 0xFF, 0x29, 0xF4, 0x00}; - -uint8_t frameB1[10] = {0x07, 0x63, 0xFF, 0x02, 0xFF, 0x29, 0x5E, 0x02, 0x16, 0x00}; +uint8_t ACKframe[8] = {0x07, 0xE3, 0xFF, 0x02, 0xFF, 0x29, 0xF4, 0x00}; uint8_t RS485_RXFRAME[300]; @@ -291,7 +296,7 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream if (RS485_RXFRAME[1] == 'c') { if (RS485_RXFRAME[6] == 0x47) { // Set time function - Do nothing. - send_kostal(frame4, 8); // ACK + send_kostal(ACKframe, 8); // ACK } if (RS485_RXFRAME[6] == 0x5E) { // Set State function @@ -299,12 +304,12 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream // Allow contactor closing datalayer.system.status.inverter_allows_contactor_closing = true; dbg_message("inverter_allows_contactor_closing -> true"); - send_kostal(frame4, 8); // ACK + send_kostal(ACKframe, 8); // ACK } else if (RS485_RXFRAME[7] == 0x04) { // INVALID STATE, no ACK sent } else { // Battery deep sleep? - send_kostal(frame4, 8); // ACK + send_kostal(ACKframe, 8); // ACK } } } else if (RS485_RXFRAME[1] == 'b') { @@ -340,8 +345,11 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream } } if (code == 0x353) { - //Send battery error - send_kostal(frame3, 9); + //Send battery error/status + memcpy(tmpframe, STATUS_FRAME, 9); + tmpframe[7] = calculate_kostal_crc(tmpframe, 7); + null_stuffer(tmpframe, 9); + send_kostal(tmpframe, 9); } } } From 4bcb0d69e1b18cc476c991c74269058ee9195db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sat, 22 Feb 2025 16:26:33 +0200 Subject: [PATCH 29/55] Add cellvoltage reading for BYD Atto 3 --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 0e855925..679eb582 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -36,6 +36,8 @@ static int16_t BMS_highest_cell_temperature = 0; static int16_t BMS_average_cell_temperature = 0; static uint16_t BMS_lowest_cell_voltage_mV = 3300; static uint16_t BMS_highest_cell_voltage_mV = 3300; +static uint8_t battery_frame_index = 0; +static uint16_t battery_cellvoltages[126] = {0}; #ifdef DOUBLE_BATTERY static int16_t battery2_temperature_ambient = 0; static int16_t battery2_daughterboard_temperatures[10]; @@ -52,6 +54,8 @@ static int16_t BMS2_highest_cell_temperature = 0; static int16_t BMS2_average_cell_temperature = 0; static uint16_t BMS2_lowest_cell_voltage_mV = 3300; static uint16_t BMS2_highest_cell_voltage_mV = 3300; +static uint8_t battery2_frame_index = 0; +static uint16_t battery2_cellvoltages[126] = {0}; #endif //DOUBLE_BATTERY #define POLL_FOR_BATTERY_SOC 0x05 #define POLL_FOR_BATTERY_VOLTAGE 0x08 @@ -135,6 +139,9 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV; + //Map all cell voltages to the global array + memcpy(datalayer.battery.status.cell_voltages_mV, battery_cellvoltages, 126 * sizeof(uint16_t)); + #ifdef SKIP_TEMPERATURE_SENSOR_NUMBER // Initialize min and max variables for temperature calculation battery_calc_min_temperature = battery_daughterboard_temperatures[0]; @@ -253,6 +260,15 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { break; case 0x43D: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_frame_index = rx_frame.data.u8[0]; + + if (battery_frame_index <= 0x29) { + uint8_t base_index = battery_frame_index * 3; + for (uint8_t i = 0; i < 3; i++) { + battery_cellvoltages[base_index + i] = + (((rx_frame.data.u8[2 * (i + 1)] & 0x0F) << 8) | rx_frame.data.u8[2 * i + 1]); + } + } break; case 0x444: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -479,6 +495,9 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.temperature_min_dC = BMS2_lowest_cell_temperature * 10; // Add decimals datalayer.battery2.status.temperature_max_dC = BMS2_highest_cell_temperature * 10; + + //Map all cell voltages to the global array + memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages, 126 * sizeof(uint16_t)); } void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { @@ -547,6 +566,14 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { break; case 0x43D: datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery2_frame_index = rx_frame.data.u8[0]; + if (battery2_frame_index <= 0x29) { + uint8_t base2_index = battery2_frame_index * 3; + for (uint8_t i = 0; i < 3; i++) { + battery2_cellvoltages[base2_index + i] = + (((rx_frame.data.u8[2 * (i + 1)] & 0x0F) << 8) | rx_frame.data.u8[2 * i + 1]); + } + } break; case 0x444: datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; From fc0e9008487c55b1d351caae3b0c6e0f7c32dd5b Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 22 Feb 2025 18:22:18 +0200 Subject: [PATCH 30/55] Kostal: BMW S-box tweak and some patching --- Software/src/inverter/KOSTAL-RS485.cpp | 48 +++++++++++++++++++------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 87ea82ec..afea8c3b 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -214,24 +214,36 @@ void update_RS485_registers_inverter() { datalayer.battery.info.min_design_voltage_dV); float2frame(BATTERY_INFO, (float)nominal_voltage_dV / 10, 6); - float2frame(CyclicData, (float)datalayer.battery.info.max_design_voltage_dV / 10, 10); float2frame(CyclicData, (float)average_temperature_dC / 10, 14); - float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 18); // Last current - float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 22); // Should be Avg current(1s) +#ifdef BMW_SBOX + float2frame(CyclicData, (float)(datalayer.shunt.measured_amperage_mA / 100) / 10, 18); + float2frame(CyclicData, (float)(datalayer.shunt.measured_avg1S_amperage_mA / 100) / 10, 22); - float2frame(CyclicData, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); - - // When SOC = 100%, drop down allowed charge current down. - - if ((datalayer.battery.status.reported_soc / 100) < 100) { - float2frame(CyclicData, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); + if (datalayer.shunt.contactors_engaged) { + CyclicData[59] = 0; } else { + CyclicData[59] = 2; + } + + if (datalayer.shunt.precharging || datalayer.shunt.contactors_engaged) { + CyclicData[56] = 1; + float2frame(CyclicData, (float)datalayer.battery.status.max_discharge_current_dA / 10, + 26); // Maximum discharge current + float2frame(CyclicData, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); // Maximum charge current + } else { + CyclicData[56] = 0; + float2frame(CyclicData, 0.0, 26); float2frame(CyclicData, 0.0, 34); } +#else + + float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 18); // Last current + float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 22); // Should be Avg current(1s) + // On startup, byte 56 seems to be always 0x00 couple of frames,. if (f2_startup_count < 9) { CyclicData[56] = 0x00; @@ -246,6 +258,18 @@ void update_RS485_registers_inverter() { CyclicData[59] = 0x00; } +#endif + + float2frame(CyclicData, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); + + // When SOC = 100%, drop down allowed charge current down. + + if ((datalayer.battery.status.reported_soc / 100) < 100) { + float2frame(CyclicData, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); + } else { + float2frame(CyclicData, 0.0, 34); + } + if (nominal_voltage_dV > 0) { float2frame(CyclicData, (float)(datalayer.battery.info.total_capacity_Wh / nominal_voltage_dV * 10), 30); // BAttery capacity Ah @@ -346,6 +370,7 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream } if (code == 0x353) { //Send battery error/status + byte tmpframe[9]; //copy values to prevent data manipulation during rewrite/crc calculation memcpy(tmpframe, STATUS_FRAME, 9); tmpframe[7] = calculate_kostal_crc(tmpframe, 7); null_stuffer(tmpframe, 9); @@ -366,10 +391,9 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream } void setup_inverter(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.inverter_protocol, "BYD battery via Kostal RS485", 63); - datalayer.system.info.inverter_protocol[63] = '\0'; 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); + datalayer.system.info.inverter_protocol[63] = '\0'; } - #endif From 6a93beb0e000d05dff8e6053b28f9a83560dc5e4 Mon Sep 17 00:00:00 2001 From: rha Date: Sat, 22 Feb 2025 18:42:05 +0200 Subject: [PATCH 31/55] Kostal cyclic data byte definition --- Software/src/inverter/KOSTAL-RS485.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index afea8c3b..50d02477 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -62,7 +62,7 @@ uint8_t CyclicData[64] = { 0x7D, 0x3F, 0x55, 0x40, // MinCellVolt (float), Bit 50-53 0xFE, 0x04, // Cycle count, - 0x00, // Byte 56 + 0x00, // Byte 56, charge/discharge control, 0=disable, 1=enable 0x00, // When SOC=100 Byte57 seen as 0x40, 0x64, // SOC , Bit 58 0x00, // Unknown, From c300b6d7f83630db8a07a65c13e362305e7d60f0 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:49 +0100 Subject: [PATCH 32/55] kostal: more comments for BATTERY_INFO --- Software/src/inverter/KOSTAL-RS485.cpp | 27 +++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 50d02477..48928aab 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -29,17 +29,22 @@ union f32b { }; uint8_t BATTERY_INFO[40] = { - 0x00, 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header - 0x00, 0x00, 0x80, 0x43, // 256.063 Nominal voltage / 5*51.2=256 first byte 0x01 or 0x04 - 0xE4, 0x70, 0x8A, 0x5C, // Manufacture date (Epoch time) (BYD: GetBatteryInfo this[0x10ac]) - 0xB5, 0x00, 0xD3, 0x00, // Battery Serial number? Modbus register 527 - 0x10b0 - 0x00, 0x00, 0xC8, 0x41, // Nominal Capacity (0x10b4) - 0xC2, 0x18, // Battery Firmware, modbus register 586 (0x10b8) - 0x00, // Static (BYD: GetBatteryInfo this[0x10ba]) - 0x00, // ? - 0x59, 0x42, // Static (BYD: GetBatteryInfo this[0x10bc]) - 0x00, 0x00, // Static (BYD: GetBatteryInfo this[0x10be]) - 0x00, 0x00, 0x05, 0x00, 0xA0, 0x00, 0x00, 0x00, + 0x00, // First zero byte pointer + 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header + 0x00, 0x00, 0x80, 0x43, // 256.063 Nominal voltage / 5*51.2=256 + 0xE4, 0x70, 0x8A, 0x5C, // Manufacture date (Epoch time) (BYD: GetBatteryInfo this[0x10ac]) + 0xB5, 0x00, 0xD3, 0x00, // Battery Serial number? Modbus register 527 - 0x10b0 + 0x00, 0x00, 0xC8, 0x41, // Nominal Capacity (0x10b4) + 0xC2, 0x18, // Battery Firmware, modbus register 586 (0x10b8) + 0x00, // Static (BYD: GetBatteryInfo this[0x10ba]) + 0x00, // ? + 0x59, 0x42, // Vendor identifier + // 0x59 0x42 -> 'YB' -> BYD + // 0x59 0x44 -> 'YD' -> Dyness + 0x00, 0x00, // Static (BYD: GetBatteryInfo this[0x10be]) + 0x00, 0x00, + 0x05, 0x00, // Number of blocks in series (uint16) + 0xA0, 0x00, 0x00, 0x00, 0x4D, // CRC 0x00}; // From 84edfbe368fe8f476b028ebe31e0f18dd55673a8 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:50 +0100 Subject: [PATCH 33/55] kostal: restructure comments for CyclicData --- Software/src/inverter/KOSTAL-RS485.cpp | 40 +++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 48928aab..c33ef2a3 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -52,28 +52,28 @@ uint8_t BATTERY_INFO[40] = { uint8_t CyclicData[64] = { 0x00, // First zero byte pointer - 0xE2, 0xFF, 0x02, 0xFF, 0x29, // frame Header - 0x1D, 0x5A, 0x85, 0x43, // Current Voltage (float) Modbus register 216, Bytes 6-9 - 0x00, 0x00, 0x8D, 0x43, // Max Voltage (2 byte float), Bytes 12-13 - 0x00, 0x00, 0xAC, 0x41, // BAttery Temperature (2 byte float) Modbus register 214, Bytes 16-17 - 0x00, 0x00, 0x00, 0x00, // Peak Current (1s period?), Bytes 18-21 - 0x00, 0x00, 0x00, 0x00, // Avg current (1s period?), Bytes 22-25 - 0x00, 0x00, 0x48, 0x42, // Max discharge current (2 byte float), Bit 26-29, // Sunspec: ADisChaMax - 0x00, 0x00, 0xC8, 0x41, // Battery gross capacity, Ah (2 byte float) , Bytes 30-33, Modbus 512 - 0x00, 0x00, 0xA0, 0x41, // Max charge current (2 byte float) Bit 36-37, ZERO WHEN SOC=100 // Sunspec: AChaMax - 0xCD, 0xCC, 0xB4, 0x41, // MaxCellTemp (4 byte float) Bit 38-41 - 0x00, 0x00, 0xA4, 0x41, // MinCellTemp (4 byte float) Bit 42-45 - 0xA4, 0x70, 0x55, 0x40, // MaxCellVolt (float), Bit 46-49 - 0x7D, 0x3F, 0x55, 0x40, // MinCellVolt (float), Bit 50-53 + 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header + 0x1D, 0x5A, 0x85, 0x43, // Current Voltage (float32) Bytes 6- 9 Modbus register 216 + 0x00, 0x00, 0x8D, 0x43, // Max Voltage (float32) Bytes 10-13 + 0x00, 0x00, 0xAC, 0x41, // Battery Temperature (float32) Bytes 14-17 Modbus register 214 + 0x00, 0x00, 0x00, 0x00, // Peak Current (1s period?) (float32) Bytes 18-21 + 0x00, 0x00, 0x00, 0x00, // Avg current (1s period?) (float32) Bytes 22-25 + 0x00, 0x00, 0x48, 0x42, // Max discharge current (float32) Bytes 26-29 Sunspec: ADisChaMax + 0x00, 0x00, 0xC8, 0x41, // Battery gross capacity, Ah (float32) Bytes 30-33 Modbus register 512 + 0x00, 0x00, 0xA0, 0x41, // Max charge current (float32) Bytes 34-37 0.0f when SoC is 100%, Sunspec: AChaMax + 0xCD, 0xCC, 0xB4, 0x41, // MaxCellTemp (float32) Bytes 38-41 + 0x00, 0x00, 0xA4, 0x41, // MinCellTemp (float32) Bytes 42-45 + 0xA4, 0x70, 0x55, 0x40, // MaxCellVolt (float32) Bytes 46-49 + 0x7D, 0x3F, 0x55, 0x40, // MinCellVolt (float32) Bytes 50-53 - 0xFE, 0x04, // Cycle count, + 0xFE, 0x04, // Bytes 54-55, Cycle count (uint16) 0x00, // Byte 56, charge/discharge control, 0=disable, 1=enable - 0x00, // When SOC=100 Byte57 seen as 0x40, - 0x64, // SOC , Bit 58 - 0x00, // Unknown, - 0x00, // Unknown, - 0x01, // Unknown, Byte 61, 1 only at first frame - 0x00, // CRC (inverted sum of bytes 1-62 + 0xC0), Bit 62 + 0x00, // Byte 57, When SoC is 100%, seen as 0x40 + 0x64, // Byte 58, SoC (uint8) + 0x00, // Byte 59, Unknown + 0x00, // Byte 60, Unknown + 0x01, // Byte 61, Unknown, 1 only at first frame, 0 otherwise + 0x00, // CRC, Byte 62 0x00}; // FE 04 01 40 xx 01 01 02 yy (fully charged) From da9117ba20858e9683e10d2c7cc19f13addd4581 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:50 +0100 Subject: [PATCH 34/55] kostal: CyclicData -> CYCLIC_DATA --- Software/src/inverter/KOSTAL-RS485.cpp | 66 +++++++++++++------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index c33ef2a3..0ba7b71d 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -48,9 +48,9 @@ uint8_t BATTERY_INFO[40] = { 0x4D, // CRC 0x00}; // -// values in CyclicData will be overwritten at update_modbus_registers_inverter() +// values in CYCLIC_DATA will be overwritten at update_modbus_registers_inverter() -uint8_t CyclicData[64] = { +uint8_t CYCLIC_DATA[64] = { 0x00, // First zero byte pointer 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header 0x1D, 0x5A, 0x85, 0x43, // Current Voltage (float32) Bytes 6- 9 Modbus register 216 @@ -209,9 +209,9 @@ void update_RS485_registers_inverter() { if (datalayer.system.status.battery_allows_contactor_closing & datalayer.system.status.inverter_allows_contactor_closing) { - float2frame(CyclicData, (float)datalayer.battery.status.voltage_dV / 10, 6); // Confirmed OK mapping + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.voltage_dV / 10, 6); // Confirmed OK mapping } else { - float2frame(CyclicData, 0.0, 6); + float2frame(CYCLIC_DATA, 0.0, 6); } // Set nominal voltage to value between min and max voltage set by battery (Example 400 and 300 results in 350V) nominal_voltage_dV = @@ -219,73 +219,73 @@ void update_RS485_registers_inverter() { datalayer.battery.info.min_design_voltage_dV); float2frame(BATTERY_INFO, (float)nominal_voltage_dV / 10, 6); - float2frame(CyclicData, (float)datalayer.battery.info.max_design_voltage_dV / 10, 10); + float2frame(CYCLIC_DATA, (float)datalayer.battery.info.max_design_voltage_dV / 10, 10); - float2frame(CyclicData, (float)average_temperature_dC / 10, 14); + float2frame(CYCLIC_DATA, (float)average_temperature_dC / 10, 14); #ifdef BMW_SBOX - float2frame(CyclicData, (float)(datalayer.shunt.measured_amperage_mA / 100) / 10, 18); - float2frame(CyclicData, (float)(datalayer.shunt.measured_avg1S_amperage_mA / 100) / 10, 22); + float2frame(CYCLIC_DATA, (float)(datalayer.shunt.measured_amperage_mA / 100) / 10, 18); + float2frame(CYCLIC_DATA, (float)(datalayer.shunt.measured_avg1S_amperage_mA / 100) / 10, 22); if (datalayer.shunt.contactors_engaged) { - CyclicData[59] = 0; + CYCLIC_DATA[59] = 0; } else { - CyclicData[59] = 2; + CYCLIC_DATA[59] = 2; } if (datalayer.shunt.precharging || datalayer.shunt.contactors_engaged) { - CyclicData[56] = 1; - float2frame(CyclicData, (float)datalayer.battery.status.max_discharge_current_dA / 10, + CYCLIC_DATA[56] = 1; + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); // Maximum discharge current - float2frame(CyclicData, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); // Maximum charge current + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); // Maximum charge current } else { - CyclicData[56] = 0; - float2frame(CyclicData, 0.0, 26); - float2frame(CyclicData, 0.0, 34); + CYCLIC_DATA[56] = 0; + float2frame(CYCLIC_DATA, 0.0, 26); + float2frame(CYCLIC_DATA, 0.0, 34); } #else - float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 18); // Last current - float2frame(CyclicData, (float)datalayer.battery.status.current_dA / 10, 22); // Should be Avg current(1s) + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.current_dA / 10, 18); // Last current + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.current_dA / 10, 22); // Should be Avg current(1s) // On startup, byte 56 seems to be always 0x00 couple of frames,. if (f2_startup_count < 9) { - CyclicData[56] = 0x00; + CYCLIC_DATA[56] = 0x00; } else { - CyclicData[56] = 0x01; + CYCLIC_DATA[56] = 0x01; } // On startup, byte 59 seems to be always 0x02 couple of frames,. if (f2_startup_count < 14) { - CyclicData[59] = 0x02; + CYCLIC_DATA[59] = 0x02; } else { - CyclicData[59] = 0x00; + CYCLIC_DATA[59] = 0x00; } #endif - float2frame(CyclicData, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); // When SOC = 100%, drop down allowed charge current down. if ((datalayer.battery.status.reported_soc / 100) < 100) { - float2frame(CyclicData, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); } else { - float2frame(CyclicData, 0.0, 34); + float2frame(CYCLIC_DATA, 0.0, 34); } if (nominal_voltage_dV > 0) { - float2frame(CyclicData, (float)(datalayer.battery.info.total_capacity_Wh / nominal_voltage_dV * 10), + float2frame(CYCLIC_DATA, (float)(datalayer.battery.info.total_capacity_Wh / nominal_voltage_dV * 10), 30); // BAttery capacity Ah } - float2frame(CyclicData, (float)datalayer.battery.status.temperature_max_dC / 10, 38); - float2frame(CyclicData, (float)datalayer.battery.status.temperature_min_dC / 10, 42); + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.temperature_max_dC / 10, 38); + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.temperature_min_dC / 10, 42); - float2frame(CyclicData, (float)datalayer.battery.status.cell_max_voltage_mV / 1000, 46); - float2frame(CyclicData, (float)datalayer.battery.status.cell_min_voltage_mV / 1000, 50); + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.cell_max_voltage_mV / 1000, 46); + float2frame(CYCLIC_DATA, (float)datalayer.battery.status.cell_min_voltage_mV / 1000, 50); - CyclicData[58] = (byte)(datalayer.battery.status.reported_soc / 100); // Confirmed OK mapping + CYCLIC_DATA[58] = (byte)(datalayer.battery.status.reported_soc / 100); // Confirmed OK mapping register_content_ok = true; @@ -354,11 +354,11 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream f2_startup_count++; } byte tmpframe[64]; //copy values to prevent data manipulation during rewrite/crc calculation - memcpy(tmpframe, CyclicData, 64); + memcpy(tmpframe, CYCLIC_DATA, 64); tmpframe[62] = calculate_kostal_crc(tmpframe, 62); null_stuffer(tmpframe, 64); send_kostal(tmpframe, 64); - CyclicData[61] = 0x00; + CYCLIC_DATA[61] = 0x00; } if (code == 0x84a) { //Send battery info From 0c5c08199d1233c1e4dec20604f0ef07449c0fd5 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:50 +0100 Subject: [PATCH 35/55] kostal: ACKframe -> ACK_FRAME --- Software/src/inverter/KOSTAL-RS485.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 0ba7b71d..32f0812d 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -93,7 +93,7 @@ uint8_t STATUS_FRAME[9] = { 0x00 //endbyte }; -uint8_t ACKframe[8] = {0x07, 0xE3, 0xFF, 0x02, 0xFF, 0x29, 0xF4, 0x00}; +uint8_t ACK_FRAME[8] = {0x07, 0xE3, 0xFF, 0x02, 0xFF, 0x29, 0xF4, 0x00}; uint8_t RS485_RXFRAME[300]; @@ -325,7 +325,7 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream if (RS485_RXFRAME[1] == 'c') { if (RS485_RXFRAME[6] == 0x47) { // Set time function - Do nothing. - send_kostal(ACKframe, 8); // ACK + send_kostal(ACK_FRAME, 8); // ACK } if (RS485_RXFRAME[6] == 0x5E) { // Set State function @@ -333,12 +333,12 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream // Allow contactor closing datalayer.system.status.inverter_allows_contactor_closing = true; dbg_message("inverter_allows_contactor_closing -> true"); - send_kostal(ACKframe, 8); // ACK + send_kostal(ACK_FRAME, 8); // ACK } else if (RS485_RXFRAME[7] == 0x04) { // INVALID STATE, no ACK sent } else { // Battery deep sleep? - send_kostal(ACKframe, 8); // ACK + send_kostal(ACK_FRAME, 8); // ACK } } } else if (RS485_RXFRAME[1] == 'b') { From 4830a69c321475741afade7579306f64422c3c33 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:50 +0100 Subject: [PATCH 36/55] kostal: disable DEBUG_KOSTAL_RS485_DATA_USB by default --- Software/src/inverter/KOSTAL-RS485.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/inverter/KOSTAL-RS485.h b/Software/src/inverter/KOSTAL-RS485.h index a0d1f0be..9009f2e4 100644 --- a/Software/src/inverter/KOSTAL-RS485.h +++ b/Software/src/inverter/KOSTAL-RS485.h @@ -5,7 +5,7 @@ #define RS485_INVERTER_SELECTED //#define DEBUG_KOSTAL_RS485_DATA // Enable this line to get TX / RX printed out via logging -#define DEBUG_KOSTAL_RS485_DATA_USB // Enable this line to get TX / RX printed out via USB +//#define DEBUG_KOSTAL_RS485_DATA_USB // Enable this line to get TX / RX printed out via USB #if defined(DEBUG_KOSTAL_RS485_DATA) && !defined(DEBUG_LOG) #error "enable LOG_TO_SD, DEBUG_VIA_USB or DEBUG_VIA_WEB in order to use DEBUG_KOSTAL_RS485_DATA" From 9aee4a2a98083c44474e82c778d60aa69b332d2a Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:50 +0100 Subject: [PATCH 37/55] kostal: make helper functions static --- Software/src/inverter/KOSTAL-RS485.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 32f0812d..de57b3ba 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -99,7 +99,7 @@ uint8_t RS485_RXFRAME[300]; bool register_content_ok = false; -void float2frame(byte* arr, float value, byte framepointer) { +static void float2frame(byte* arr, float value, byte framepointer) { f32b g; g.f = value; arr[framepointer] = g.b[0]; @@ -153,7 +153,7 @@ static void dbg_message(const char* msg) { /* https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing#Encoding_examples */ -void null_stuffer(byte* lfc, int len) { +static void null_stuffer(byte* lfc, int len) { int last_null_byte = 0; for (int i = 0; i < len; i++) { if (lfc[i] == '\0') { @@ -168,7 +168,7 @@ static void send_kostal(byte* frame, int len) { Serial2.write(frame, len); } -byte calculate_kostal_crc(byte* lfc, int len) { +static byte calculate_kostal_crc(byte* lfc, int len) { unsigned int sum = 0; if (lfc[0] != 0) { logging.printf("WARNING: first byte should be 0, but is 0x%02x\n", lfc[0]); @@ -179,7 +179,7 @@ byte calculate_kostal_crc(byte* lfc, int len) { return (byte)(-sum & 0xff); } -bool check_kostal_frame_crc(int len) { +static bool check_kostal_frame_crc(int len) { unsigned int sum = 0; int zeropointer = RS485_RXFRAME[0]; int last_zero = 0; From c600bf7b77a33618d2b12eae6ec816a76a6debc2 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:28:50 +0100 Subject: [PATCH 38/55] kostal: minor comment fixes --- Software/src/inverter/KOSTAL-RS485.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index de57b3ba..0335407f 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -267,8 +267,7 @@ void update_RS485_registers_inverter() { float2frame(CYCLIC_DATA, (float)datalayer.battery.status.max_discharge_current_dA / 10, 26); - // When SOC = 100%, drop down allowed charge current down. - + // When SoC is 100%, drop down allowed charge current. if ((datalayer.battery.status.reported_soc / 100) < 100) { float2frame(CYCLIC_DATA, (float)datalayer.battery.status.max_charge_current_dA / 10, 34); } else { @@ -277,7 +276,7 @@ void update_RS485_registers_inverter() { if (nominal_voltage_dV > 0) { float2frame(CYCLIC_DATA, (float)(datalayer.battery.info.total_capacity_Wh / nominal_voltage_dV * 10), - 30); // BAttery capacity Ah + 30); // Battery capacity Ah } float2frame(CYCLIC_DATA, (float)datalayer.battery.status.temperature_max_dC / 10, 38); float2frame(CYCLIC_DATA, (float)datalayer.battery.status.temperature_min_dC / 10, 42); @@ -285,7 +284,7 @@ void update_RS485_registers_inverter() { float2frame(CYCLIC_DATA, (float)datalayer.battery.status.cell_max_voltage_mV / 1000, 46); float2frame(CYCLIC_DATA, (float)datalayer.battery.status.cell_min_voltage_mV / 1000, 50); - CYCLIC_DATA[58] = (byte)(datalayer.battery.status.reported_soc / 100); // Confirmed OK mapping + CYCLIC_DATA[58] = (byte)(datalayer.battery.status.reported_soc / 100); register_content_ok = true; From 7a25669b873402ee7f5d31abfd8147d7d530a9ad Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:31:13 +0100 Subject: [PATCH 39/55] kosta: switcheroo --- Software/src/inverter/KOSTAL-RS485.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 0335407f..aaa1ba4c 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -73,7 +73,7 @@ uint8_t CYCLIC_DATA[64] = { 0x00, // Byte 59, Unknown 0x00, // Byte 60, Unknown 0x01, // Byte 61, Unknown, 1 only at first frame, 0 otherwise - 0x00, // CRC, Byte 62 + 0x00, // Byte 62, CRC 0x00}; // FE 04 01 40 xx 01 01 02 yy (fully charged) From 92964987cc6f426462f2ad33a17fcadcb6439052 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:35:18 +0100 Subject: [PATCH 40/55] kostal: disable clang-format for BATTERY_INFO and CYCLIC_DATA --- Software/src/inverter/KOSTAL-RS485.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index aaa1ba4c..16422559 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -28,6 +28,7 @@ union f32b { byte b[4]; }; +// clang-format off uint8_t BATTERY_INFO[40] = { 0x00, // First zero byte pointer 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header @@ -45,11 +46,13 @@ uint8_t BATTERY_INFO[40] = { 0x00, 0x00, 0x05, 0x00, // Number of blocks in series (uint16) 0xA0, 0x00, 0x00, 0x00, - 0x4D, // CRC - 0x00}; // + 0x4D, // CRC + 0x00}; +// clang-format on // values in CYCLIC_DATA will be overwritten at update_modbus_registers_inverter() +// clang-format off uint8_t CYCLIC_DATA[64] = { 0x00, // First zero byte pointer 0xE2, 0xFF, 0x02, 0xFF, 0x29, // Frame header @@ -75,6 +78,7 @@ uint8_t CYCLIC_DATA[64] = { 0x01, // Byte 61, Unknown, 1 only at first frame, 0 otherwise 0x00, // Byte 62, CRC 0x00}; +// clang-format on // FE 04 01 40 xx 01 01 02 yy (fully charged) // FE 02 01 02 xx 01 01 02 yy (charging or discharging) From 1182028aad678c3468f5531ed88f07e3156da69e Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Sat, 22 Feb 2025 22:35:44 +0100 Subject: [PATCH 41/55] kostal: remove commented code --- Software/src/inverter/KOSTAL-RS485.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 16422559..7cad5478 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -83,13 +83,6 @@ uint8_t CYCLIC_DATA[64] = { // FE 04 01 40 xx 01 01 02 yy (fully charged) // FE 02 01 02 xx 01 01 02 yy (charging or discharging) -//uint8_t frame3[9] = { -// 0x08, 0xE2, 0xFF, 0x02, 0xFF, 0x29, //header -// 0x06, //Unknown (battery status/error?) -// 0xEF, //CRC -// 0x00 //endbyte -//}; - uint8_t STATUS_FRAME[9] = { 0x00, 0xE2, 0xFF, 0x02, 0xFF, 0x29, //header 0x06, //Unknown (battery status/error?) From 2173335929d84b1e38ac745fbe6ef665299c8c21 Mon Sep 17 00:00:00 2001 From: rha Date: Sun, 23 Feb 2025 07:54:02 +0200 Subject: [PATCH 42/55] Kostal: Removed inverter_allows_contactor_closing from battery info frame handling --- Software/src/inverter/KOSTAL-RS485.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 7cad5478..fc54704c 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -363,8 +363,6 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream tmpframe[38] = calculate_kostal_crc(tmpframe, 38); null_stuffer(tmpframe, 40); send_kostal(tmpframe, 40); - datalayer.system.status.inverter_allows_contactor_closing = true; - dbg_message("inverter_allows_contactor_closing -> true"); if (!startupMillis) { startupMillis = currentMillis; } From 401b70368277a88ba58e138e28d224ca2687a04a Mon Sep 17 00:00:00 2001 From: Marijn van Galen Date: Sun, 23 Feb 2025 14:25:53 +0100 Subject: [PATCH 43/55] Change magic nummers to define. --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index 679eb582..e0371b9d 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -37,7 +37,8 @@ static int16_t BMS_average_cell_temperature = 0; static uint16_t BMS_lowest_cell_voltage_mV = 3300; static uint16_t BMS_highest_cell_voltage_mV = 3300; static uint8_t battery_frame_index = 0; -static uint16_t battery_cellvoltages[126] = {0}; +#define NOF_CELLS 126 +static uint16_t battery_cellvoltages[NOF_CELLS] = {0}; #ifdef DOUBLE_BATTERY static int16_t battery2_temperature_ambient = 0; static int16_t battery2_daughterboard_temperatures[10]; @@ -55,7 +56,7 @@ static int16_t BMS2_average_cell_temperature = 0; static uint16_t BMS2_lowest_cell_voltage_mV = 3300; static uint16_t BMS2_highest_cell_voltage_mV = 3300; static uint8_t battery2_frame_index = 0; -static uint16_t battery2_cellvoltages[126] = {0}; +static uint16_t battery2_cellvoltages[NOF_CELLS] = {0}; #endif //DOUBLE_BATTERY #define POLL_FOR_BATTERY_SOC 0x05 #define POLL_FOR_BATTERY_VOLTAGE 0x08 @@ -262,7 +263,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery_frame_index = rx_frame.data.u8[0]; - if (battery_frame_index <= 0x29) { + if (battery_frame_index < (NOF_CELLS / 3)) { uint8_t base_index = battery_frame_index * 3; for (uint8_t i = 0; i < 3; i++) { battery_cellvoltages[base_index + i] = @@ -567,7 +568,7 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { case 0x43D: datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; battery2_frame_index = rx_frame.data.u8[0]; - if (battery2_frame_index <= 0x29) { + if (battery2_frame_index < (NOF_CELLS / 3)) { uint8_t base2_index = battery2_frame_index * 3; for (uint8_t i = 0; i < 3; i++) { battery2_cellvoltages[base2_index + i] = From dd51f5c1057965d0ca07fbc4296e7b5d107db6bf Mon Sep 17 00:00:00 2001 From: Marijn van Galen Date: Sun, 23 Feb 2025 14:28:21 +0100 Subject: [PATCH 44/55] Change two left behind 126 nummers to NOF_CELLS. --- Software/src/battery/BYD-ATTO-3-BATTERY.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index e0371b9d..e78d08c7 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -141,7 +141,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV; //Map all cell voltages to the global array - memcpy(datalayer.battery.status.cell_voltages_mV, battery_cellvoltages, 126 * sizeof(uint16_t)); + memcpy(datalayer.battery.status.cell_voltages_mV, battery_cellvoltages, NOF_CELLS * sizeof(uint16_t)); #ifdef SKIP_TEMPERATURE_SENSOR_NUMBER // Initialize min and max variables for temperature calculation @@ -498,7 +498,7 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.temperature_max_dC = BMS2_highest_cell_temperature * 10; //Map all cell voltages to the global array - memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages, 126 * sizeof(uint16_t)); + memcpy(datalayer.battery2.status.cell_voltages_mV, battery2_cellvoltages, NOF_CELLS * sizeof(uint16_t)); } void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { From 1aeb8b9c467be9e2ee8ca61ad35a6a68ae93d28a Mon Sep 17 00:00:00 2001 From: rha Date: Sun, 23 Feb 2025 19:45:31 +0200 Subject: [PATCH 45/55] Kostal: rx_index uint8 => uint16 --- Software/src/inverter/KOSTAL-RS485.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index fc54704c..cacb0817 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -20,7 +20,7 @@ static unsigned long currentMillis; static unsigned long startupMillis = 0; static unsigned long contactorMillis = 0; -static uint8_t rx_index = 0; +static uint16_t rx_index = 0; static boolean RX_allow = false; union f32b { From 69af8251b8118bff26c362e1103c2a9821e8dc6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 24 Feb 2025 15:02:21 +0200 Subject: [PATCH 46/55] Make LED modes customizable --- Software/USER_SETTINGS.h | 8 ++++++++ Software/src/datalayer/datalayer.h | 4 ++++ Software/src/devboard/utils/led_handler.cpp | 10 +++++----- Software/src/devboard/utils/led_handler.h | 8 +++----- Software/src/devboard/utils/types.h | 1 + Software/src/system_settings.h | 17 ----------------- 6 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 0baa8ae2..95166a56 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -155,6 +155,14 @@ // 3000 = 300.0V, Target discharge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true #define BATTERY_MAX_DISCHARGE_VOLTAGE 3000 +/* LED settings. Optional customization for how the blinking pattern on the LED should behave. +* CLASSIC - Slow up/down ramp. If CLASSIC, then a ramp up and ramp down will finish in LED_PERIOD_MS milliseconds +* FLOW - Ramp up/down depending on flow of energy +* HEARTBEAT - Heartbeat-like LED pattern that reacts to the system state with color and BPM +*/ +#define LED_MODE HEARTBEAT +#define LED_PERIOD_MS 3000 + /* 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; diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index b1a02cbc..dc480ed3 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -97,6 +97,10 @@ typedef struct { /** The current battery status, which for now has the name real_bms_status */ real_bms_status_enum real_bms_status = BMS_DISCONNECTED; + + /** LED mode, customizable by user */ + led_mode_enum led_mode = LED_MODE; + } DATALAYER_BATTERY_STATUS_TYPE; typedef struct { diff --git a/Software/src/devboard/utils/led_handler.cpp b/Software/src/devboard/utils/led_handler.cpp index 0879c36a..e8e53de3 100644 --- a/Software/src/devboard/utils/led_handler.cpp +++ b/Software/src/devboard/utils/led_handler.cpp @@ -16,7 +16,7 @@ static const float heartbeat_peak1 = 0.80; static const float heartbeat_peak2 = 0.55; static const float heartbeat_deviation = 0.05; -static LED led(LED_MODE_DEFAULT); +static LED led(datalayer.battery.status.led_mode); void led_init(void) { led.init(); @@ -31,14 +31,14 @@ led_color led_get_color() { void LED::exe(void) { // Update brightness - switch (mode) { - case led_mode::FLOW: + switch (datalayer.battery.status.led_mode) { + case led_mode_enum::FLOW: flow_run(); break; - case led_mode::HEARTBEAT: + case led_mode_enum::HEARTBEAT: heartbeat_run(); break; - case led_mode::CLASSIC: + case led_mode_enum::CLASSIC: default: classic_run(); break; diff --git a/Software/src/devboard/utils/led_handler.h b/Software/src/devboard/utils/led_handler.h index 6296e1c6..dd1403b5 100644 --- a/Software/src/devboard/utils/led_handler.h +++ b/Software/src/devboard/utils/led_handler.h @@ -4,8 +4,6 @@ #include "../../include.h" #include "../../lib/adafruit-Adafruit_NeoPixel/Adafruit_NeoPixel.h" -enum led_mode { CLASSIC, FLOW, HEARTBEAT }; - class LED { public: led_color color = led_color::GREEN; @@ -14,9 +12,9 @@ class LED { : pixels(1, LED_PIN, NEO_GRB + NEO_KHZ800), max_brightness(LED_MAX_BRIGHTNESS), brightness(LED_MAX_BRIGHTNESS), - mode(led_mode::CLASSIC) {} + mode(led_mode_enum::CLASSIC) {} - LED(led_mode mode) + LED(led_mode_enum mode) : pixels(1, LED_PIN, NEO_GRB + NEO_KHZ800), max_brightness(LED_MAX_BRIGHTNESS), brightness(LED_MAX_BRIGHTNESS), @@ -29,7 +27,7 @@ class LED { Adafruit_NeoPixel pixels; uint8_t max_brightness; uint8_t brightness; - led_mode mode; + led_mode_enum mode; void classic_run(void); void flow_run(void); diff --git a/Software/src/devboard/utils/types.h b/Software/src/devboard/utils/types.h index f4bb4093..0d1195a2 100644 --- a/Software/src/devboard/utils/types.h +++ b/Software/src/devboard/utils/types.h @@ -7,6 +7,7 @@ enum bms_status_enum { STANDBY = 0, INACTIVE = 1, DARKSTART = 2, ACTIVE = 3, FAU enum real_bms_status_enum { BMS_DISCONNECTED = 0, BMS_STANDBY = 1, BMS_ACTIVE = 2, BMS_FAULT = 3 }; enum battery_chemistry_enum { NCA, NMC, LFP }; enum led_color { GREEN, YELLOW, RED, BLUE }; +enum led_mode_enum { CLASSIC, FLOW, HEARTBEAT }; enum PrechargeState { AUTO_PRECHARGE_IDLE, AUTO_PRECHARGE_START, diff --git a/Software/src/system_settings.h b/Software/src/system_settings.h index 76450751..93da44a9 100644 --- a/Software/src/system_settings.h +++ b/Software/src/system_settings.h @@ -37,21 +37,4 @@ */ #define MAX_AMOUNT_CELLS 192 -/** LED - * - * Parameter: LED_MODE_DEFAULT - * Description: - * The default LED mode. Available modes: - * CLASSIC - slow up/down ramp - * FLOW - slow ramp up or down depending on flow of energy - * HEARTBEAT - Heartbeat-like LED pattern that reacts to the system state with color and BPM - * - * Parameter: LED_PERIOD_MS - * Description: - * The period of whatever LED mode is active. If CLASSIC, then a ramp up and ramp down will finish in - * LED_PERIOD_MS milliseconds -*/ -#define LED_MODE_DEFAULT FLOW -#define LED_PERIOD_MS 3000 - #endif From 131312a8cd381bb4fdb5fc36d1746e68e77b6967 Mon Sep 17 00:00:00 2001 From: Jamie Jones Date: Mon, 24 Feb 2025 13:07:51 +0000 Subject: [PATCH 47/55] Functional SimpBMS support --- Software/USER_SETTINGS.h | 1 + Software/src/battery/BATTERIES.h | 4 + Software/src/battery/SIMPBMS-BATTERY.cpp | 191 ++++++++++++++++++ Software/src/battery/SIMPBMS-BATTERY.h | 19 ++ .../webserver/advanced_battery_html.cpp | 11 +- 5 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 Software/src/battery/SIMPBMS-BATTERY.cpp create mode 100644 Software/src/battery/SIMPBMS-BATTERY.h diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 5b56850c..c50b0c36 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -34,6 +34,7 @@ //#define RENAULT_ZOE_GEN2_BATTERY //#define SONO_BATTERY //#define SANTA_FE_PHEV_BATTERY +//#define SIMPBMS_BATTERY //#define STELLANTIS_ECMP_BATTERY //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 5ad2417f..78de9ae7 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -114,6 +114,10 @@ void setup_can_shunt(); #include "SANTA-FE-PHEV-BATTERY.h" #endif +#ifdef SIMPBMS_BATTERY +#include "SIMPBMS-BATTERY.h" +#endif + #if defined(TESLA_MODEL_SX_BATTERY) || defined(TESLA_MODEL_3Y_BATTERY) #define TESLA_BATTERY #include "TESLA-BATTERY.h" diff --git a/Software/src/battery/SIMPBMS-BATTERY.cpp b/Software/src/battery/SIMPBMS-BATTERY.cpp new file mode 100644 index 00000000..7767378a --- /dev/null +++ b/Software/src/battery/SIMPBMS-BATTERY.cpp @@ -0,0 +1,191 @@ +#include "../include.h" +#ifdef SIMPBMS_BATTERY +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" +#include "SIMPBMS-BATTERY.h" + +#define SIMPBMS_MAX_CELLS 128 + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent + +//Actual content messages + +static int16_t celltemperature_max_dC = 0; +static int16_t celltemperature_min_dC = 0; +static int16_t current_dA = 0; +static uint16_t voltage_dV = 0; +static uint16_t cellvoltage_max_mV = 3700; +static uint16_t cellvoltage_min_mV = 3700; +static uint16_t charge_cutoff_voltage = 0; +static uint16_t discharge_cutoff_voltage = 0; +static int16_t max_charge_current = 0; +static int16_t max_discharge_current = 0; +static uint8_t ensemble_info_ack = 0; +static uint8_t cells_in_series = 0; +static uint8_t voltage_level = 0; +static uint8_t ah_total = 0; +static uint8_t SOC = 0; +static uint8_t SOH = 0; +static uint8_t charge_forbidden = 0; +static uint8_t discharge_forbidden = 0; +static uint16_t cellvoltages_mV[SIMPBMS_MAX_CELLS] = {0}; + + +void update_values_battery() { + + datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00 + + datalayer.battery.status.soh_pptt = (SOH * 100); //Increase decimals from 100% -> 100.00% + + datalayer.battery.status.voltage_dV = voltage_dV; //value is *10 (3700 = 370.0) + + datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign + + datalayer.battery.status.max_charge_power_W = (max_charge_current * (voltage_dV / 10)); + + datalayer.battery.status.max_discharge_power_W = (max_discharge_current * (voltage_dV / 10)); + + datalayer.battery.info.total_capacity_Wh = ah_total * (voltage_dV / 10); + + datalayer.battery.status.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); + + datalayer.battery.status.cell_max_voltage_mV = cellvoltage_max_mV; + + datalayer.battery.status.cell_min_voltage_mV = cellvoltage_min_mV; + + datalayer.battery.status.temperature_min_dC = celltemperature_min_dC; + + datalayer.battery.status.temperature_max_dC = celltemperature_max_dC; + + datalayer.battery.info.max_design_voltage_dV = charge_cutoff_voltage; + + datalayer.battery.info.min_design_voltage_dV = discharge_cutoff_voltage; + + memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mV, SIMPBMS_MAX_CELLS * sizeof(uint16_t)); + + datalayer.battery.info.number_of_cells = cells_in_series; +} + +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + switch (rx_frame.ID) { + case 0x355: + SOC = (rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]; + SOH = (rx_frame.data.u8[3] << 8) + rx_frame.data.u8[2]; + + break; + case 0x351: + //discharge and charge limits + charge_cutoff_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + discharge_cutoff_voltage = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); + max_charge_current = (((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2])) /10 ; + max_discharge_current = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4])) / 10; + break; + case 0x356: + //current status + current_dA = ((rx_frame.data.u8[3]<< 8) + rx_frame.data.u8[2]) / 1000; + voltage_dV = ((rx_frame.data.u8[1]<< 8) + rx_frame.data.u8[0]) / 10 ; + break; + case 0x373: + //min/max values + cellvoltage_max_mV = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); + cellvoltage_min_mV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + celltemperature_max_dC = (((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) - 273.15) * 10; + celltemperature_min_dC = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) - 273.15) * 10; + break; + case 0x372: + //cells_in_series = rx_frame.data.u8[0]; + if (rx_frame.data.u8[3] > 0 && rx_frame.data.u8[3] <= SIMPBMS_MAX_CELLS) { + uint8_t cellnumber = rx_frame.data.u8[3]; + if (cellnumber > cells_in_series) { + cells_in_series = cellnumber; + } + cellvoltages_mV[cellnumber - 1] = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); + } + + break; + case 0x379: + ah_total = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + // msg.buf[0] = lowByte(settings.CAP); + // msg.buf[1] = highByte(settings.CAP); + // msg.buf[2] = lowByte(uint16_t(amphours)); + // msg.buf[3] = highByte(uint16_t(amphours)); + + break; + // case 0x7310: + // case 0x7311: + // ensemble_info_ack = true; + // // This message contains software/hardware version info. No interest to us + // break; + // case 0x7320: + // case 0x7321: + // ensemble_info_ack = true; + // battery_module_quantity = rx_frame.data.u8[0]; + // battery_modules_in_series = rx_frame.data.u8[2]; + // cell_quantity_in_module = rx_frame.data.u8[3]; + // voltage_level = rx_frame.data.u8[4]; + // ah_number = rx_frame.data.u8[6]; + // break; + // case 0x4210: + // case 0x4211: + // voltage_dV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + // current_dA = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 30000; + // SOC = rx_frame.data.u8[6]; + // SOH = rx_frame.data.u8[7]; + // break; + // case 0x4220: + // case 0x4221: + // charge_cutoff_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + // discharge_cutoff_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); + // max_charge_current = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * 0.1) - 3000; + // max_discharge_current = (((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) * 0.1) - 3000; + // break; + // case 0x4230: + // case 0x4231: + // cellvoltage_max_mV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); + // cellvoltage_min_mV = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); + // break; + // case 0x4240: + // case 0x4241: + // celltemperature_max_dC = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) - 1000; + // celltemperature_min_dC = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 1000; + // break; + + default: + break; + } +} + +void transmit_can_battery() { + unsigned long currentMillis = millis(); + // Send 1s CAN Message + if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { + + previousMillis1000 = currentMillis; + + // transmit_can_frame(&PYLON_3010, can_config.battery); // Heartbeat + // transmit_can_frame(&PYLON_4200, can_config.battery); // Ensemble OR System equipment info, depends on frame0 + // transmit_can_frame(&PYLON_8200, can_config.battery); // Control device quit sleep status + // transmit_can_frame(&PYLON_8210, can_config.battery); // Charge command + + // if (ensemble_info_ack) { + // PYLON_4200.data.u8[0] = 0x00; //Request system equipment info + // } + } +} + +void setup_battery(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, "SIMPBMS battery", 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; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.system.status.battery_allows_contactor_closing = true; + +} + +#endif diff --git a/Software/src/battery/SIMPBMS-BATTERY.h b/Software/src/battery/SIMPBMS-BATTERY.h new file mode 100644 index 00000000..44e1e2eb --- /dev/null +++ b/Software/src/battery/SIMPBMS-BATTERY.h @@ -0,0 +1,19 @@ +#ifndef SIMPBMS_BATTERY_H +#define SIMPBMS_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED + +/* DEFAULT VALUES BMS will send configured */ +#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V +#define MIN_PACK_VOLTAGE_DV 1500 +#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CELL_DEVIATION_MV 500 +#define CELL_COUNT 96 + +void setup_battery(void); +void transmit_can_frame(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index bbb226b9..3a70d325 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -471,6 +471,15 @@ String advanced_battery_processor(const String& var) { content += "

Voltage OBD2: " + String(datalayer_extended.bydAtto3.voltage_polled) + "

"; #endif //BYD_ATTO_3_BATTERY +#ifdef SIMPBMS_BATTERY + content += "

Max Design Voltage: " + String(datalayer.battery.info.max_design_voltage_dV) + " dV

"; + content += "

Min Design Voltage: " + String(datalayer.battery.info.min_design_voltage_dV) + " dV

"; + content += "

Max Charge Current: " + String(datalayer.battery.status.max_charge_current_dA) + " dA

"; + content += "

Max Discharge Current: " + String(datalayer.battery.status.max_discharge_current_dA) + " dA

"; + content += "

Pack Voltage: " + String( datalayer.battery.status.voltage_dV) + " dV

"; + content += "

Reported Current: " + String( datalayer.battery.status.current_dA) + " dA

"; + content += "

Series Cells: " + String(datalayer.battery.info.number_of_cells) + " dV

"; +#endif #ifdef TESLA_BATTERY float beginning_of_life = static_cast(datalayer_extended.tesla.battery_beginning_of_life); float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct) * 0.4; @@ -1315,7 +1324,7 @@ String advanced_battery_processor(const String& var) { !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && \ - !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info + !defined(KIA_HYUNDAI_64_BATTERY) && !defined(SIMPBMS_BATTERY)//Only the listed types have extra info content += "No extra information available for this battery type"; #endif From e256df469b9078bc418449dcee509044ee1cc0ad Mon Sep 17 00:00:00 2001 From: Jamie Jones Date: Tue, 25 Feb 2025 09:37:45 +0000 Subject: [PATCH 48/55] Removing commented out code --- Software/src/battery/SIMPBMS-BATTERY.cpp | 53 +----------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/Software/src/battery/SIMPBMS-BATTERY.cpp b/Software/src/battery/SIMPBMS-BATTERY.cpp index 7767378a..e13b320f 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.cpp +++ b/Software/src/battery/SIMPBMS-BATTERY.cpp @@ -108,50 +108,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { break; case 0x379: ah_total = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); - // msg.buf[0] = lowByte(settings.CAP); - // msg.buf[1] = highByte(settings.CAP); - // msg.buf[2] = lowByte(uint16_t(amphours)); - // msg.buf[3] = highByte(uint16_t(amphours)); break; - // case 0x7310: - // case 0x7311: - // ensemble_info_ack = true; - // // This message contains software/hardware version info. No interest to us - // break; - // case 0x7320: - // case 0x7321: - // ensemble_info_ack = true; - // battery_module_quantity = rx_frame.data.u8[0]; - // battery_modules_in_series = rx_frame.data.u8[2]; - // cell_quantity_in_module = rx_frame.data.u8[3]; - // voltage_level = rx_frame.data.u8[4]; - // ah_number = rx_frame.data.u8[6]; - // break; - // case 0x4210: - // case 0x4211: - // voltage_dV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); - // current_dA = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 30000; - // SOC = rx_frame.data.u8[6]; - // SOH = rx_frame.data.u8[7]; - // break; - // case 0x4220: - // case 0x4221: - // charge_cutoff_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); - // discharge_cutoff_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); - // max_charge_current = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * 0.1) - 3000; - // max_discharge_current = (((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) * 0.1) - 3000; - // break; - // case 0x4230: - // case 0x4231: - // cellvoltage_max_mV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); - // cellvoltage_min_mV = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); - // break; - // case 0x4240: - // case 0x4241: - // celltemperature_max_dC = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) - 1000; - // celltemperature_min_dC = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 1000; - // break; + default: break; @@ -162,17 +121,7 @@ void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 1s CAN Message if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { - previousMillis1000 = currentMillis; - - // transmit_can_frame(&PYLON_3010, can_config.battery); // Heartbeat - // transmit_can_frame(&PYLON_4200, can_config.battery); // Ensemble OR System equipment info, depends on frame0 - // transmit_can_frame(&PYLON_8200, can_config.battery); // Control device quit sleep status - // transmit_can_frame(&PYLON_8210, can_config.battery); // Charge command - - // if (ensemble_info_ack) { - // PYLON_4200.data.u8[0] = 0x00; //Request system equipment info - // } } } From f54440458b36201c7bc2359c289f0f2c00faa27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Tue, 25 Feb 2025 11:43:51 +0200 Subject: [PATCH 49/55] Make kWh more accurate --- Software/src/battery/BMW-I3-BATTERY.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index 09152d04..3e771507 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -216,7 +216,7 @@ static uint32_t battery_BEV_available_power_shortterm_charge = 0; static uint32_t battery_BEV_available_power_shortterm_discharge = 0; static uint32_t battery_BEV_available_power_longterm_charge = 0; static uint32_t battery_BEV_available_power_longterm_discharge = 0; -static uint16_t battery_energy_content_maximum_kWh = 0; +static uint16_t battery_energy_content_maximum_Wh = 0; static uint16_t battery_display_SOC = 0; static uint16_t battery_volts = 0; static uint16_t battery_HVBatt_SOC = 0; @@ -284,7 +284,7 @@ static uint32_t battery2_BEV_available_power_shortterm_charge = 0; static uint32_t battery2_BEV_available_power_shortterm_discharge = 0; static uint32_t battery2_BEV_available_power_longterm_charge = 0; static uint32_t battery2_BEV_available_power_longterm_discharge = 0; -static uint16_t battery2_energy_content_maximum_kWh = 0; +static uint16_t battery2_energy_content_maximum_Wh = 0; static uint16_t battery2_display_SOC = 0; static uint16_t battery2_volts = 0; static uint16_t battery2_HVBatt_SOC = 0; @@ -373,7 +373,7 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.current_dA = battery2_current; - datalayer.battery2.info.total_capacity_Wh = (battery2_energy_content_maximum_kWh * 1000); // Convert kWh to Wh + datalayer.battery2.info.total_capacity_Wh = battery2_energy_content_maximum_Wh; datalayer.battery2.status.remaining_capacity_Wh = battery2_predicted_energy_charge_condition; @@ -443,7 +443,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.current_dA = battery_current; - datalayer.battery.info.total_capacity_Wh = (battery_energy_content_maximum_kWh * 1000); // Convert kWh to Wh + datalayer.battery.info.total_capacity_Wh = battery_energy_content_maximum_Wh; datalayer.battery.status.remaining_capacity_Wh = battery_predicted_energy_charge_condition; @@ -611,10 +611,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { battery_request_abort_charging = (rx_frame.data.u8[0] & 0x30) >> 4; battery_prediction_duration_charging_minutes = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); battery_prediction_time_end_of_charging_minutes = rx_frame.data.u8[4]; - battery_energy_content_maximum_kWh = (((rx_frame.data.u8[6] & 0x0F) << 8 | rx_frame.data.u8[5])) / 50; - if (battery_energy_content_maximum_kWh > 33) { + battery_energy_content_maximum_Wh = (((rx_frame.data.u8[6] & 0x0F) << 8) | rx_frame.data.u8[5]) * 20; + if (battery_energy_content_maximum_Wh > 33000) { detectedBattery = BATTERY_120AH; - } else if (battery_energy_content_maximum_kWh > 20) { + } else if (battery_energy_content_maximum_Wh > 20000) { detectedBattery = BATTERY_94AH; } else { detectedBattery = BATTERY_60AH; @@ -797,10 +797,10 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { battery2_request_abort_charging = (rx_frame.data.u8[0] & 0x30) >> 4; battery2_prediction_duration_charging_minutes = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); battery2_prediction_time_end_of_charging_minutes = rx_frame.data.u8[4]; - battery2_energy_content_maximum_kWh = (((rx_frame.data.u8[6] & 0x0F) << 8 | rx_frame.data.u8[5])) / 50; - if (battery2_energy_content_maximum_kWh > 33) { + battery2_energy_content_maximum_Wh = (((rx_frame.data.u8[6] & 0x0F) << 8) | rx_frame.data.u8[5]) * 20; + if (battery2_energy_content_maximum_Wh > 33000) { detectedBattery2 = BATTERY_120AH; - } else if (battery2_energy_content_maximum_kWh > 20) { + } else if (battery2_energy_content_maximum_Wh > 20000) { detectedBattery2 = BATTERY_94AH; } else { detectedBattery2 = BATTERY_60AH; From 916d40696584baac22322d06617047bc3d1cef29 Mon Sep 17 00:00:00 2001 From: Jamie Jones Date: Tue, 25 Feb 2025 16:38:45 +0000 Subject: [PATCH 50/55] Feedback from PR, removing code that's not needed. --- Software/src/battery/SIMPBMS-BATTERY.cpp | 7 +------ .../src/devboard/webserver/advanced_battery_html.cpp | 11 +---------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Software/src/battery/SIMPBMS-BATTERY.cpp b/Software/src/battery/SIMPBMS-BATTERY.cpp index e13b320f..6df18292 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.cpp +++ b/Software/src/battery/SIMPBMS-BATTERY.cpp @@ -26,7 +26,7 @@ static uint8_t cells_in_series = 0; static uint8_t voltage_level = 0; static uint8_t ah_total = 0; static uint8_t SOC = 0; -static uint8_t SOH = 0; +static uint8_t SOH = 99; static uint8_t charge_forbidden = 0; static uint8_t discharge_forbidden = 0; static uint16_t cellvoltages_mV[SIMPBMS_MAX_CELLS] = {0}; @@ -118,11 +118,6 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { } void transmit_can_battery() { - unsigned long currentMillis = millis(); - // Send 1s CAN Message - if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { - previousMillis1000 = currentMillis; - } } void setup_battery(void) { // Performs one time setup at startup diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 95e8d52f..9ff6b81a 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -481,15 +481,6 @@ String advanced_battery_processor(const String& var) { content += "

Temperature sensor 10: " + String(datalayer_extended.bydAtto3.battery_temperatures[9]) + "

"; #endif //BYD_ATTO_3_BATTERY -#ifdef SIMPBMS_BATTERY - content += "

Max Design Voltage: " + String(datalayer.battery.info.max_design_voltage_dV) + " dV

"; - content += "

Min Design Voltage: " + String(datalayer.battery.info.min_design_voltage_dV) + " dV

"; - content += "

Max Charge Current: " + String(datalayer.battery.status.max_charge_current_dA) + " dA

"; - content += "

Max Discharge Current: " + String(datalayer.battery.status.max_discharge_current_dA) + " dA

"; - content += "

Pack Voltage: " + String( datalayer.battery.status.voltage_dV) + " dV

"; - content += "

Reported Current: " + String( datalayer.battery.status.current_dA) + " dA

"; - content += "

Series Cells: " + String(datalayer.battery.info.number_of_cells) + " dV

"; -#endif #ifdef TESLA_BATTERY float beginning_of_life = static_cast(datalayer_extended.tesla.battery_beginning_of_life); float battTempPct = static_cast(datalayer_extended.tesla.battery_battTempPct) * 0.4; @@ -1424,7 +1415,7 @@ String advanced_battery_processor(const String& var) { !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \ - !defined(KIA_HYUNDAI_64_BATTERY) && !defined(SIMPBMS_BATTERY) //Only the listed types have extra info + !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif From 68b2144c829ec123176bb922b490eb9f9b8aa94e Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Tue, 25 Feb 2025 22:36:52 +0000 Subject: [PATCH 51/55] merge with main --- Software/src/devboard/utils/events.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index cdd53193..28c45310 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -25,7 +25,6 @@ * - Increment EE_MAGIC_HEADER_VALUE in case you've changed the order */ - #define EVENTS_ENUM_TYPE(XX) \ XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ XX(EVENT_CANMCP2515_INIT_FAILURE) \ @@ -121,7 +120,6 @@ XX(EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS) \ XX(EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED) \ XX(EVENT_BATTERY_TEMP_DEVIATION_HIGH) \ - XX(EVENT_NOF_EVENTS) typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE; From b85be44d3d56646078988c2e2778880a98674e41 Mon Sep 17 00:00:00 2001 From: laughingguffly Date: Tue, 25 Feb 2025 23:01:50 +0000 Subject: [PATCH 52/55] merge with main --- Software/src/devboard/utils/events.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 28c45310..2ecf022b 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -107,6 +107,7 @@ XX(EVENT_RESET_EFUSE) \ XX(EVENT_RESET_PWR_GLITCH) \ XX(EVENT_RESET_CPU_LOCKUP) \ + XX(EVENT_RJXZS_LOG) \ XX(EVENT_PAUSE_BEGIN) \ XX(EVENT_PAUSE_END) \ XX(EVENT_WIFI_CONNECT) \ From 69154e26d50212562e3d145269992539dacd9dce Mon Sep 17 00:00:00 2001 From: Jamie Jones Date: Wed, 26 Feb 2025 15:54:18 +0000 Subject: [PATCH 53/55] Running pre-commit --- Software/src/battery/SIMPBMS-BATTERY.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Software/src/battery/SIMPBMS-BATTERY.cpp b/Software/src/battery/SIMPBMS-BATTERY.cpp index 6df18292..5feedb3d 100644 --- a/Software/src/battery/SIMPBMS-BATTERY.cpp +++ b/Software/src/battery/SIMPBMS-BATTERY.cpp @@ -31,7 +31,6 @@ static uint8_t charge_forbidden = 0; static uint8_t discharge_forbidden = 0; static uint16_t cellvoltages_mV[SIMPBMS_MAX_CELLS] = {0}; - void update_values_battery() { datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00 @@ -80,13 +79,13 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { //discharge and charge limits charge_cutoff_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); discharge_cutoff_voltage = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); - max_charge_current = (((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2])) /10 ; + max_charge_current = (((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2])) / 10; max_discharge_current = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4])) / 10; break; case 0x356: //current status - current_dA = ((rx_frame.data.u8[3]<< 8) + rx_frame.data.u8[2]) / 1000; - voltage_dV = ((rx_frame.data.u8[1]<< 8) + rx_frame.data.u8[0]) / 10 ; + current_dA = ((rx_frame.data.u8[3] << 8) + rx_frame.data.u8[2]) / 1000; + voltage_dV = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[0]) / 10; break; case 0x373: //min/max values @@ -97,12 +96,12 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { break; case 0x372: //cells_in_series = rx_frame.data.u8[0]; - if (rx_frame.data.u8[3] > 0 && rx_frame.data.u8[3] <= SIMPBMS_MAX_CELLS) { + if (rx_frame.data.u8[3] > 0 && rx_frame.data.u8[3] <= SIMPBMS_MAX_CELLS) { uint8_t cellnumber = rx_frame.data.u8[3]; if (cellnumber > cells_in_series) { cells_in_series = cellnumber; } - cellvoltages_mV[cellnumber - 1] = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); + cellvoltages_mV[cellnumber - 1] = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); } break; @@ -110,15 +109,13 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) { ah_total = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]); break; - default: break; } } -void transmit_can_battery() { -} +void transmit_can_battery() {} void setup_battery(void) { // Performs one time setup at startup strncpy(datalayer.system.info.battery_protocol, "SIMPBMS battery", 63); @@ -129,7 +126,6 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; datalayer.system.status.battery_allows_contactor_closing = true; - } #endif From cfea5932102d5fb55931326245fa2e51a951e428 Mon Sep 17 00:00:00 2001 From: Jamie Jones Date: Wed, 26 Feb 2025 19:26:10 +0000 Subject: [PATCH 54/55] Fixing the formatting issue --- Software/src/devboard/webserver/advanced_battery_html.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 9ff6b81a..10421fef 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -1415,7 +1415,7 @@ String advanced_battery_processor(const String& var) { !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ !defined(MEB_BATTERY) && !defined(VOLVO_SPA_BATTERY) && !defined(VOLVO_SPA_HYBRID_BATTERY) && \ - !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info + !defined(KIA_HYUNDAI_64_BATTERY) //Only the listed types have extra info content += "No extra information available for this battery type"; #endif From bba8783037cb62daa8acd006129632c83b68d264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 2 Mar 2025 20:17:46 +0200 Subject: [PATCH 55/55] Make default LED Classic --- Software/USER_SETTINGS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 95166a56..64615d75 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -160,7 +160,7 @@ * FLOW - Ramp up/down depending on flow of energy * HEARTBEAT - Heartbeat-like LED pattern that reacts to the system state with color and BPM */ -#define LED_MODE HEARTBEAT +#define LED_MODE CLASSIC #define LED_PERIOD_MS 3000 /* Do not change any code below this line */