Improvement: Add Battery Pause Feature for Max Charge/Discharge Power and OTA Update Optimization

This commit is contained in:
amarofarinha 2024-09-13 15:32:54 +01:00
parent ccb2db87ec
commit 856a0838d1
23 changed files with 1004 additions and 773 deletions

View file

@ -376,6 +376,10 @@ void update_values_battery2() { //This function maps all the values fetched via
datalayer.battery2.status.soh_pptt = battery2_soh * 100;
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
if (battery2_BEV_available_power_longterm_discharge > 65000) {
datalayer.battery2.status.max_discharge_power_W = 65000;
} else {
@ -397,9 +401,9 @@ void update_values_battery2() { //This function maps all the values fetched via
datalayer.battery2.status.cell_min_voltage_mV = datalayer.battery2.status.cell_voltages_mV[0];
datalayer.battery2.status.cell_max_voltage_mV = datalayer.battery2.status.cell_voltages_mV[1];
}
}
void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer
void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer
if (!battery_awake) {
return;
}
@ -416,9 +420,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.soh_pptt = battery_soh * 100;
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = battery_BEV_available_power_longterm_discharge;
datalayer.battery.status.max_charge_power_W = battery_BEV_available_power_longterm_charge;
}
battery_power = (datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100));
@ -499,9 +507,9 @@ void update_values_battery() { //This function maps all the values fetched via
Serial.print(" Max temp: ");
Serial.print(datalayer.battery.status.temperature_max_dC * 0.1);
#endif
}
}
void receive_can_battery(CAN_frame rx_frame) {
void receive_can_battery(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2
battery_awake = true;
@ -629,7 +637,8 @@ void receive_can_battery(CAN_frame rx_frame) {
battery_ID2 = rx_frame.data.u8[0];
break;
case 0x607: //BMS - responses to message requests on 0x615
if ((cmdState == CELL_VOLTAGE_CELLNO || cmdState == CELL_VOLTAGE_CELLNO_LAST) && (rx_frame.data.u8[0] == 0xF4)) {
if ((cmdState == CELL_VOLTAGE_CELLNO || cmdState == CELL_VOLTAGE_CELLNO_LAST) &&
(rx_frame.data.u8[0] == 0xF4)) {
if (rx_frame.DLC == 6) {
transmit_can(&BMW_6F4_CELL_CONTINUE, can_config.battery); // tell battery to send the cellvoltage
}
@ -679,8 +688,8 @@ void receive_can_battery(CAN_frame rx_frame) {
default:
break;
}
}
void receive_can_battery2(CAN_frame rx_frame) {
}
void receive_can_battery2(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2
battery2_awake = true;
@ -854,8 +863,8 @@ void receive_can_battery2(CAN_frame rx_frame) {
default:
break;
}
}
void send_can_battery() {
}
void send_can_battery() {
unsigned long currentMillis = millis();
if (battery_awake) {
@ -1114,9 +1123,9 @@ void send_can_battery() {
previousMillis5000 = currentMillis;
previousMillis10000 = currentMillis;
}
}
}
void setup_battery(void) { // Performs one time setup at startup
void setup_battery(void) { // Performs one time setup at startup
#ifdef DEBUG_VIA_USB
Serial.println("BMW i3 battery selected");
#endif
@ -1136,6 +1145,6 @@ void setup_battery(void) { // Performs one time setup at startup
#endif
pinMode(WUP_PIN, OUTPUT);
digitalWrite(WUP_PIN, HIGH); // Wake up the battery
}
}
#endif

View file

@ -101,9 +101,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = 10000; //TODO: Map from CAN later on
datalayer.battery.status.max_charge_power_W = 10000; //TODO: Map from CAN later on
}
datalayer.battery.status.active_power_W =
(datalayer.battery.status.current_dA * (datalayer.battery.status.voltage_dV / 100));

View file

@ -114,8 +114,13 @@ void update_values_battery() {
datalayer.battery.status.real_soc = x102_chg_session.StateOfCharge;
datalayer.battery.status.max_discharge_power_W =
(x200_discharge_limits.MaximumDischargeCurrent * x100_chg_lim.MaximumBatteryVoltage); //In Watts, Convert A to P
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = 10000; //TODO: Map from CAN later on
datalayer.battery.status.max_charge_power_W = 1000;
}
datalayer.battery.status.voltage_dV = get_measured_voltage() * 10;

View file

@ -48,10 +48,14 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
//We do not know the max charge/discharge power is sent by the battery. We hardcode value for now.
datalayer.battery.status.max_charge_power_W = 10000; // 10kW //TODO: Fix when CAN is decoded
datalayer.battery.status.max_discharge_power_W = 10000; // 10kW //TODO: Fix when CAN is decoded
datalayer.battery.status.max_charge_power_W = 10000; // 10kW //TODO: Fix when CAN is decoded
}
datalayer.battery.status.active_power_W = BMU_Power; //TODO: Scaling?

View file

@ -89,11 +89,14 @@ void update_values_battery() {
datalayer.battery.status.temperature_max_dC = HVBattCellTempHottest * 10; // C to dC
datalayer.battery.status.max_discharge_power_W =
HVBattDischargeContiniousPowerLimit * 10; // kWh+2 to W (TODO: Check that scaling is right way)
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = HVBattDischargeContiniousPowerLimit * 10; // kWh+2 to W
datalayer.battery.status.max_charge_power_W =
HVBattChargeContiniousPowerLimit * 10; // kWh+2 to W (TODO: Check that scaling is right way)
}
if (HVBattHVILError) { // Alert user incase the high voltage interlock is not OK
set_event(EVENT_HVIL_FAILURE, 0);

View file

@ -310,13 +310,17 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
//datalayer.battery.status.max_charge_power_W = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts
//The allowed charge power is not available. We hardcode this value for now
datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED;
//datalayer.battery.status.max_discharge_power_W = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts
//The allowed discharge power is not available. We hardcode this value for now
datalayer.battery.status.max_discharge_power_W = MAXDISCHARGEPOWERALLOWED;
}
powerWatt = ((batteryVoltage * batteryAmps) / 100);

View file

@ -123,9 +123,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_charge_power_W = allowedChargePower * 10;
datalayer.battery.status.max_discharge_power_W = allowedDischargePower * 10;
}
//Power in watts, Negative = charging batt
datalayer.battery.status.active_power_W =

View file

@ -64,9 +64,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = available_discharge_power * 10;
datalayer.battery.status.max_charge_power_W = available_charge_power * 10;
}
//Power in watts, Negative = charging batt
datalayer.battery.status.active_power_W =

View file

@ -6,6 +6,7 @@
#endif
#include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "../devboard/utils/pause.h"
/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
@ -228,9 +229,13 @@ void update_values_battery() { /* This function maps all the values fetched via
}
}
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = (battery_Discharge_Power_Limit * 1000); //kW to W
datalayer.battery.status.max_charge_power_W = (battery_Charge_Power_Limit * 1000); //kW to W
}
/*Extra safety functions below*/
if (battery_GIDS < 10) //700Wh left in battery!
@ -379,9 +384,13 @@ void update_values_battery2() { // Handle the values coming in from battery #2
}
}
if (emulator_pause_request_ON) {
datalayer.battery2.status.max_discharge_power_W = 0;
datalayer.battery2.status.max_charge_power_W = 0;
} else {
datalayer.battery2.status.max_discharge_power_W = (battery2_Discharge_Power_Limit * 1000); //kW to W
datalayer.battery2.status.max_charge_power_W = (battery2_Charge_Power_Limit * 1000); //kW to W
}
/*Extra safety functions below*/
if (battery2_GIDS < 10) //700Wh left in battery!

View file

@ -63,9 +63,13 @@ void update_values_battery() {
datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
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.status.cell_max_voltage_mV = cellvoltage_max_mV;

View file

@ -87,13 +87,19 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
/* Define power able to be discharged from battery */
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W =
(LB_Discharge_Power_Limit * 500); //Convert value fetched from battery to watts
LB_Charge_Power_Limit_Watts = (LB_Charge_Power_Limit * 500); //Convert value fetched from battery to watts
//The above value is 0 on some packs. We instead hardcode this now.
datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_W;
}
datalayer.battery.status.active_power_W =
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);

View file

@ -47,9 +47,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = 5000; //TODO: Take from CAN
datalayer.battery.status.max_charge_power_W = LB_Charge_Power_W;
}
datalayer.battery.status.active_power_W;

View file

@ -81,9 +81,13 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = allowedDischargePower * 10;
datalayer.battery.status.max_charge_power_W = allowedChargePower * 10;
}
//Power in watts, Negative = charging batt
datalayer.battery.status.active_power_W =

View file

@ -278,6 +278,10 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
if (emulator_pause_request_ON) {
datalayer.battery.status.max_charge_power_W = 0;
datalayer.battery.status.max_discharge_power_W = 0;
} else {
// Define the allowed discharge power
datalayer.battery.status.max_discharge_power_W = (battery_max_discharge_current * battery_volts);
// Cap the allowed discharge power if higher than the maximum discharge power allowed
@ -305,6 +309,7 @@ void update_values_battery() { //This function maps all the values fetched via
} else { // No limits, max charging power allowed
datalayer.battery.status.max_charge_power_W = MAXCHARGEPOWERALLOWED;
}
}
datalayer.battery.status.active_power_W = ((battery_volts / 10) * battery_amps);

View file

@ -1,6 +1,8 @@
#include "../include.h"
#ifdef TEST_FAKE_BATTERY
#include "../datalayer/datalayer.h"
#include "../devboard/utils/pause.h"
#include "TEST-FAKE-BATTERY.h"
/* Do not change code below unless you are sure what you are doing */
@ -44,9 +46,13 @@ void update_values_battery() { /* This function puts fake values onto the parame
datalayer.battery.status.temperature_max_dC = 60; // 6.0*C
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
datalayer.battery.status.max_discharge_power_W = 5000; // 5kW
datalayer.battery.status.max_charge_power_W = 5000; // 5kW
}
for (int i = 0; i < 97; ++i) {
datalayer.battery.status.cell_voltages_mV[i] = 3500 + i;

View file

@ -83,9 +83,14 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.current_dA = BATT_I * 10;
datalayer.battery.status.remaining_capacity_Wh = remaining_capacity;
if (emulator_pause_request_ON) {
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
} else {
//datalayer.battery.status.max_discharge_power_W = HvBattPwrLimDchaSoft * 1000; // Use power limit reported from BMS, not trusted ATM
datalayer.battery.status.max_discharge_power_W = 30000;
datalayer.battery.status.max_charge_power_W = 30000;
}
datalayer.battery.status.active_power_W = (BATT_U)*BATT_I;
datalayer.battery.status.temperature_min_dC = BATT_T_MIN;
datalayer.battery.status.temperature_max_dC = BATT_T_MAX;

View file

@ -8,6 +8,7 @@
#include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h"
#include "../../lib/knolleary-pubsubclient/PubSubClient.h"
#include "../utils/events.h"
#include "../utils/pause.h"
#include "../utils/timer.h"
WiFiClient espClient;
@ -56,6 +57,7 @@ SensorConfig sensorConfigs[] = {
{"max_charge_power", "Battery Emulator Battery Max Charge Power", "{{ value_json.max_charge_power }}", "W",
"power"},
{"bms_status", "Battery Emulator BMS Status", "{{ value_json.bms_status }}", "", ""},
{"pause_status", "Battery Emulator Pause Status", "{{ value_json.pause_status }}", "", ""},
};
@ -112,6 +114,11 @@ static void publish_common_info(void) {
} else {
#endif // HA_AUTODISCOVERY
doc["bms_status"] = getBMSStatus(datalayer.battery.status.bms_status);
doc["pause_status"] = get_emulator_pause_status();
//only publish these values if BMS is active and we are comunication with the battery (can send CAN messages to the battery)
if (datalayer.battery.status.bms_status == ACTIVE && can_send_CAN) {
doc["SOC"] = ((float)datalayer.battery.status.reported_soc) / 100.0;
doc["SOC_real"] = ((float)datalayer.battery.status.real_soc) / 100.0;
doc["state_of_health"] = ((float)datalayer.battery.status.soh_pptt) / 100.0;
@ -130,7 +137,7 @@ static void publish_common_info(void) {
doc["remaining_capacity"] = ((float)datalayer.battery.status.remaining_capacity_Wh);
doc["max_discharge_power"] = ((float)datalayer.battery.status.max_discharge_power_W);
doc["max_charge_power"] = ((float)datalayer.battery.status.max_charge_power_W);
doc["bms_status"] = getBMSStatus(datalayer.battery.status.bms_status);
}
serializeJson(doc, mqtt_msg);
if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) {

View file

@ -198,6 +198,8 @@ void init_events(void) {
events.entries[EVENT_RESET_EFUSE].level = EVENT_LEVEL_INFO;
events.entries[EVENT_RESET_PWR_GLITCH].level = EVENT_LEVEL_INFO;
events.entries[EVENT_RESET_CPU_LOCKUP].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_PAUSE_BEGIN].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_PAUSE_END].level = EVENT_LEVEL_INFO;
events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger...
@ -367,6 +369,10 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Info: The board was reset due to a detected power glitch";
case EVENT_RESET_CPU_LOCKUP:
return "Warning: The board was reset due to CPU lockup. Inform developers!";
case EVENT_PAUSE_BEGIN:
return "Warning: The emulator is trying to pause the battery.";
case EVENT_PAUSE_END:
return "Info: The emulator is attempting to resume battery operation from pause.";
default:
return "";
}

View file

@ -93,6 +93,8 @@
XX(EVENT_RESET_EFUSE) \
XX(EVENT_RESET_PWR_GLITCH) \
XX(EVENT_RESET_CPU_LOCKUP) \
XX(EVENT_PAUSE_BEGIN) \
XX(EVENT_PAUSE_END) \
XX(EVENT_NOF_EVENTS)
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;

View file

@ -0,0 +1,73 @@
#include "pause.h"
#include "../../datalayer/datalayer.h"
#include "events.h"
bool emulator_pause_request_ON = false;
bool emulator_pause_CAN_send_ON = false;
bool can_send_CAN = true;
battery_pause_status emulator_pause_status = NORMAL;
void setBatteryPause(bool pause_battery,bool pause_CAN) {
emulator_pause_CAN_send_ON = pause_CAN;
if (pause_battery) {
set_event(EVENT_PAUSE_BEGIN, 1);
emulator_pause_request_ON = true;
datalayer.battery.status.max_discharge_power_W = 0;
datalayer.battery.status.max_charge_power_W = 0;
#ifdef DOUBLE_BATTERY
datalayer.battery2.status.max_discharge_power_W = 0;
datalayer.battery2.status.max_charge_power_W = 0;
#endif
emulator_pause_status = PAUSING;
} else {
clear_event(EVENT_PAUSE_BEGIN);
set_event(EVENT_PAUSE_END, 0);
emulator_pause_request_ON = false;
emulator_pause_CAN_send_ON = false;
emulator_pause_status = RESUMING;
}
}
/// @brief handle emulator pause status
/// @return true if CAN messages should be sent to battery, false if not
void emulator_pause_state_send_CAN_battery() {
if (emulator_pause_status == NORMAL)
can_send_CAN = true;
// in some inverters this values are not accurate, so we need to check if we are consider 1.8 amps as the limit
if (emulator_pause_request_ON && emulator_pause_status == PAUSING && datalayer.battery.status.current_dA < 18 &&
datalayer.battery.status.current_dA > -18 ) {
emulator_pause_status = PAUSED;
}
if (!emulator_pause_request_ON && emulator_pause_status == RESUMING) {
emulator_pause_status = NORMAL;
can_send_CAN = true;
}
can_send_CAN = (!emulator_pause_CAN_send_ON || emulator_pause_status == NORMAL);
}
std::string get_emulator_pause_status() {
switch (emulator_pause_status) {
case NORMAL:
return "RUNNING";
case PAUSING:
return "PAUSING";
case PAUSED:
return "PAUSED";
case RESUMING:
return "RESUMING";
default:
return "UNKNOWN";
}
}

View file

@ -0,0 +1,17 @@
#ifndef _PAUSE_H_
#define _PAUSE_H_
#include <string>
//battery pause status
enum battery_pause_status { NORMAL = 0, PAUSING = 1, PAUSED = 2, RESUMING = 3 };
extern bool emulator_pause_request_ON;
extern bool emulator_pause_CAN_send_ON;
extern battery_pause_status emulator_pause_status;
extern bool can_send_CAN;
void setBatteryPause(bool pause_battery,bool pause_CAN) ;
void emulator_pause_state_send_CAN_battery();
std::string get_emulator_pause_status();
#endif

View file

@ -3,6 +3,7 @@
#include "../../datalayer/datalayer.h"
#include "../utils/events.h"
#include "../utils/led_handler.h"
#include "../utils/pause.h"
#include "../utils/timer.h"
// Create AsyncWebServer object on port 80
@ -159,6 +160,19 @@ void init_webserver() {
}
});
// Route for pause/resume Battery emulator
server.on("/pause", HTTP_GET, [](AsyncWebServerRequest* request) {
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
return request->requestAuthentication();
if (request->hasParam("p")) {
String valueStr = request->getParam("p")->value();
setBatteryPause(valueStr == "true" || valueStr == "1", false);
request->send(200, "text/plain", "Updated successfully");
} else {
request->send(400, "text/plain", "Bad Request");
}
});
// Route for editing SOCMin
server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) {
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
@ -414,10 +428,8 @@ void wifi_monitor() {
if (ota_active && ota_timeout_timer.elapsed()) {
// OTA timeout, try to restore can and clear the update event
ESP32Can.CANInit();
clear_event(EVENT_OTA_UPDATE);
set_event(EVENT_OTA_UPDATE_TIMEOUT, 0);
ota_active = false;
onOTAEnd(false);
}
}
@ -702,6 +714,12 @@ String processor(const String& var) {
} else {
content += "<span style='color: red;'>&#10005;</span></h4>";
}
if (emulator_pause_status == NORMAL)
content += "<h4>Pause status: " + String(get_emulator_pause_status().c_str()) + " </h4>";
else
content +=
"<h4 style='color: red;'>Pause status: " + String(get_emulator_pause_status().c_str()) +
" </h4>";
// Close the block
content += "</div>";
@ -778,6 +796,12 @@ String processor(const String& var) {
} else {
content += "<span style='color: red;'>&#10005;</span></h4>";
}
if (emulator_pause_status == NORMAL)
content += "<h4>Pause status: " + String(get_emulator_pause_status().c_str()) + " </h4>";
else
content +=
"<h4 style='color: red;'>Pause status: " + String(get_emulator_pause_status().c_str()) +
" </h4>";
content += "</div>";
content += "</div>";
@ -839,6 +863,11 @@ String processor(const String& var) {
content += "</div>";
#endif // defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
if (emulator_pause_request_ON)
content += "<button onclick='PauseBattery(false)'>Resume Battery</button>";
else
content += "<button onclick='PauseBattery(true)'>Pause Battery</button>";
content += "<button onclick='OTA()'>Perform OTA update</button>";
content += " ";
content += "<button onclick='Settings()'>Change Settings</button>";
@ -872,6 +901,12 @@ String processor(const String& var) {
content += " setTimeout(function(){ window.open(\"/\",\"_self\"); }, 1000);";
content += "}";
}
content += "function PauseBattery(pause){";
content +=
"var xhr=new "
"XMLHttpRequest();xhr.onload=function() { "
"window.location.reload();};xhr.open('GET','/pause?p='+pause,true);xhr.send();";
content += "}";
content += "</script>";
@ -886,8 +921,10 @@ String processor(const String& var) {
}
void onOTAStart() {
//try to Pause the battery
setBatteryPause(true, true);
// Log when OTA has started
ESP32Can.CANStop();
set_event(EVENT_OTA_UPDATE, 0);
// If already set, make a new attempt
@ -909,6 +946,9 @@ void onOTAProgress(size_t current, size_t final) {
}
void onOTAEnd(bool success) {
//try to Resume the battery
setBatteryPause(false, false);
// Log when OTA has finished
if (success) {
#ifdef DEBUG_VIA_USB
@ -918,9 +958,6 @@ void onOTAEnd(bool success) {
#ifdef DEBUG_VIA_USB
Serial.println("There was an error during OTA update!");
#endif // DEBUG_VIA_USB
// If we fail without a timeout, try to restore CAN
ESP32Can.CANInit();
}
ota_active = false;
clear_event(EVENT_OTA_UPDATE);

View file

@ -43,6 +43,15 @@ void ElegantOTAClass::begin(ELEGANTOTA_WEBSERVER *server, const char * username,
return request->requestAuthentication();
}
// Pre-OTA update callback
if (preUpdateCallback != NULL) preUpdateCallback();
// Sleep for 3 seconds to allow asynchronous preUpdateCallback tasks to complete
unsigned long sleepStart = millis();
while (millis() - sleepStart < 3000) { // Sleep for 3 second
delay(1); // Yield to other tasks
}
// Get header x-ota-mode value, if present
OTA_Mode mode = OTA_MODE_FIRMWARE;
// Get mode from arg
@ -73,7 +82,7 @@ void ElegantOTAClass::begin(ELEGANTOTA_WEBSERVER *server, const char * username,
#endif
// Pre-OTA update callback
if (preUpdateCallback != NULL) preUpdateCallback();
//if (preUpdateCallback != NULL) preUpdateCallback();
// Start update process
#if defined(ESP8266)