Skip to content

Commit

Permalink
Merge pull request #847 from laughingguffly/feature/bms_reset_at_with…
Browse files Browse the repository at this point in the history
…_ntp

Periodic BMS reset now at a specific time with the help of NTP
  • Loading branch information
dalathegreat authored Feb 26, 2025
2 parents cd9f7df + b85be44 commit a0fa8ac
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 101 deletions.
13 changes: 12 additions & 1 deletion Software/Software.ino
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
#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
const char* version_number = "8.7.dev";
Expand All @@ -52,7 +56,6 @@ const char* version_number = "8.7.dev";
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);
Expand Down Expand Up @@ -135,6 +138,14 @@ void setup() {
// Start tasks
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);
if (bmsResetTimeOffset == 0) {
set_event(EVENT_PERIODIC_BMS_RESET_AT_INIT_FAILED, 0);
} else {
set_event(EVENT_PERIODIC_BMS_RESET_AT_INIT_SUCCESS, 0);
}
#endif
}

// Perform main program functions
Expand Down
8 changes: 8 additions & 0 deletions Software/USER_SETTINGS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions Software/USER_SETTINGS.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,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 PERIODIC_BMS_RESET_AT 525

/* Shunt/Contactor settings (Optional) */
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement
Expand Down Expand Up @@ -176,6 +178,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;
Expand Down
2 changes: 1 addition & 1 deletion Software/src/battery/NISSAN-LEAF-BATTERY.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -249,23 +251,29 @@ 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

// 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)
}
Expand All @@ -274,9 +282,10 @@ 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
// 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)
Expand Down
2 changes: 2 additions & 0 deletions Software/src/datalayer/datalayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,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;
#ifdef PRECHARGE_CONTROL
/** State of automatic precharge sequence */
PrechargeState precharge_status = AUTO_PRECHARGE_IDLE;
Expand Down
10 changes: 10 additions & 0 deletions Software/src/devboard/utils/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,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_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_BATTERY_TEMP_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING;

events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger...
Expand Down Expand Up @@ -453,6 +456,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_PERIODIC_BMS_RESET:
return "BMS Reset Event Completed.";
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 "";
}
Expand Down
189 changes: 96 additions & 93 deletions Software/src/devboard/utils/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,99 +25,102 @@
* - 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_RJXZS_LOG) \
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_BATTERY_TEMP_DEVIATION_HIGH) \
#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_RJXZS_LOG) \
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_BATTERY_TEMP_DEVIATION_HIGH) \
XX(EVENT_NOF_EVENTS)

typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
Expand Down
Loading

0 comments on commit a0fa8ac

Please # to comment.