Merge pull request #1475 from dalathegreat/improvement/even-more-webserver-settings

Improvement: Move Contactor settings to common-image
This commit is contained in:
Daniel Öster 2025-09-01 13:54:16 +03:00 committed by GitHub
commit 7cc5d368d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 76 additions and 68 deletions

View file

@ -14,15 +14,6 @@
//#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 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
/* Shunt/Contactor settings (Optional) */
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement

View file

@ -9,9 +9,6 @@
#ifdef CHADEMO_BATTERY
#define SELECTED_BATTERY_CLASS ChademoBattery
//Contactor control is required for CHADEMO support
#define CONTACTOR_CONTROL
#endif
class ChademoBattery : public CanBattery {

View file

@ -3,45 +3,16 @@
#include "../../devboard/safety/safety.h"
#include "../../inverter/INVERTERS.h"
#ifdef CONTACTOR_CONTROL
const bool contactor_control_enabled_default = true;
#else
const bool contactor_control_enabled_default = false;
#endif
bool contactor_control_enabled = contactor_control_enabled_default;
#ifdef PWM_CONTACTOR_CONTROL
const bool pwn_contactor_control_default = true;
#else
const bool pwn_contactor_control_default = false;
#endif
bool pwm_contactor_control = pwn_contactor_control_default;
#ifdef PERIODIC_BMS_RESET
const bool periodic_bms_reset_default = true;
#else
const bool periodic_bms_reset_default = false;
#endif
bool periodic_bms_reset = periodic_bms_reset_default;
#ifdef REMOTE_BMS_RESET
const bool remote_bms_reset_default = true;
#else
const bool remote_bms_reset_default = false;
#endif
bool remote_bms_reset = remote_bms_reset_default;
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
const bool contactor_control_enabled_double_battery_default = true;
#else
const bool contactor_control_enabled_double_battery_default = false;
#endif
bool contactor_control_enabled_double_battery = contactor_control_enabled_double_battery_default;
// TODO: Ensure valid values at run-time
// User can update all these values via Settings page
bool contactor_control_enabled = false; //Should GPIO contactor control be performed?
uint16_t precharge_time_ms = 100; //Precharge time in ms. Adjust depending on capacitance in inverter
bool pwm_contactor_control = false; //Should the contactors be economized via PWM after they are engaged?
bool contactor_control_enabled_double_battery = false; //Should a contactor for the secondary battery be operated?
bool remote_bms_reset = false; //Is it possible to actuate BMS reset via MQTT?
bool periodic_bms_reset = false; //Should periodic BMS reset be performed each 24h?
// Parameters
enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
State contactorStatus = DISCONNECTED;
@ -60,11 +31,11 @@ const int OFF = 0;
500 // Time after negative contactor is turned on, to start precharge (not actual precharge time!)
#define PRECHARGE_COMPLETED_TIME_MS \
1000 // After successful precharge, resistor is turned off after this delay (and contactors are economized if PWM enabled)
#define PWM_Freq 20000 // 20 kHz frequency, beyond audible range
#define PWM_Res 10 // 10 Bit resolution 0 to 1023, maps 'nicely' to 0% 100%
#define PWM_HOLD_DUTY 250
#define PWM_OFF_DUTY 0
uint16_t pwm_frequency = 20000;
uint16_t pwm_hold_duty = 250;
#define PWM_ON_DUTY 1023
#define PWM_RESOLUTION 10
#define PWM_OFF_DUTY 0 //No need to have this userconfigurable
#define PWM_Positive_Channel 0
#define PWM_Negative_Channel 1
static unsigned long prechargeStartTime = 0;
@ -108,8 +79,8 @@ bool init_contactors() {
if (pwm_contactor_control) {
// Setup PWM Channel Frequency and Resolution
ledcAttachChannel(posPin, PWM_Freq, PWM_Res, PWM_Positive_Channel);
ledcAttachChannel(negPin, PWM_Freq, PWM_Res, PWM_Negative_Channel);
ledcAttachChannel(posPin, pwm_frequency, PWM_RESOLUTION, PWM_Positive_Channel);
ledcAttachChannel(negPin, pwm_frequency, PWM_RESOLUTION, PWM_Negative_Channel);
// Set all pins OFF (0% PWM)
ledcWrite(posPin, PWM_OFF_DUTY);
ledcWrite(negPin, PWM_OFF_DUTY);
@ -245,7 +216,7 @@ void handle_contactors() {
break;
case POSITIVE:
if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) {
if (currentTime - negativeStartTime >= precharge_time_ms) {
set(posPin, ON, PWM_ON_DUTY);
dbg_contactors("POSITIVE");
prechargeCompletedTime = currentTime;
@ -256,8 +227,8 @@ void handle_contactors() {
case PRECHARGE_OFF:
if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) {
set(prechargePin, OFF);
set(negPin, ON, PWM_HOLD_DUTY);
set(posPin, ON, PWM_HOLD_DUTY);
set(negPin, ON, pwm_hold_duty);
set(posPin, ON, pwm_hold_duty);
dbg_contactors("PRECHARGE_OFF");
contactorStatus = COMPLETED;
datalayer.system.status.contactors_engaged = 1;

View file

@ -10,6 +10,9 @@ extern bool contactor_control_enabled_double_battery;
extern bool pwm_contactor_control;
extern bool periodic_bms_reset;
extern bool remote_bms_reset;
extern uint16_t precharge_time_ms;
extern uint16_t pwm_frequency;
extern uint16_t pwm_hold_duty;
/**
* @brief Handle BMS power output

View file

@ -138,8 +138,11 @@ void init_stored_settings() {
equipment_stop_behavior = (STOP_BUTTON_BEHAVIOR)settings.getUInt("EQSTOP", (int)STOP_BUTTON_BEHAVIOR::NOT_CONNECTED);
user_selected_second_battery = settings.getBool("DBLBTR", false);
contactor_control_enabled = settings.getBool("CNTCTRL", false);
precharge_time_ms = settings.getUInt("PRECHGMS", 100);
contactor_control_enabled_double_battery = settings.getBool("CNTCTRLDBL", false);
pwm_contactor_control = settings.getBool("PWMCNTCTRL", false);
pwm_frequency = settings.getUInt("PWMFREQ", 20000);
pwm_hold_duty = settings.getUInt("PWMHOLD", 250);
periodic_bms_reset = settings.getBool("PERBMSRESET", false);
remote_bms_reset = settings.getBool("REMBMSRESET", false);
use_canfd_as_can = settings.getBool("CANFDASCAN", false);

View file

@ -557,6 +557,18 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti
return String(settings.getUInt("CANFREQ", 8));
}
if (var == "PRECHGMS") {
return String(settings.getUInt("PRECHGMS", 100));
}
if (var == "PWMFREQ") {
return String(settings.getUInt("PWMFREQ", 20000));
}
if (var == "PWMHOLD") {
return String(settings.getUInt("PWMHOLD", 250));
}
if (var == "DIGITALHVIL") {
return settings.getBool("DIGITALHVIL") ? "checked" : "";
}
@ -781,6 +793,16 @@ const char* getCANInterfaceName(CAN_Interface interface) {
display: contents;
}
form .if-pwmcntctrl { display: none; }
form[data-pwmcntctrl="true"] .if-pwmcntctrl {
display: contents;
}
form .if-cntctrl { display: none; }
form[data-cntctrl="true"] .if-cntctrl {
display: contents;
}
form .if-sofar { display: none; }
form[data-inverter="17"] .if-sofar {
display: contents;
@ -932,7 +954,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {
</select>
</div>
<label>Can Addon Frequency: </label>
<label>Can-addon frequency Mhz: </label>
<input name='CANFREQ' type='text' value="%CANFREQ%" pattern="^[0-9]+$" />
<label>Equipment stop button: </label><select name='EQSTOP'>
@ -943,21 +965,33 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<input type='checkbox' name='DBLBTR' value='on' style='margin-left: 0;' %DBLBTR% />
<div class="if-dblbtr">
<label>Battery 2 comm I/F: </label><select name='BATT2COMM'>
%BATT2COMM%
</select>
<label>Battery 2 comm I/F: </label>
<select name='BATT2COMM'>
%BATT2COMM%
</select>
<label>Contactor control via GPIO double battery: </label>
<input type='checkbox' name='CNTCTRLDBL' value='on' style='margin-left: 0;' %CNTCTRLDBL% />
</div>
<label>Contactor control: </label>
<label>Contactor control via GPIO: </label>
<input type='checkbox' name='CNTCTRL' value='on' style='margin-left: 0;' %CNTCTRL% />
<div class="if-dblbtr">
<label>Contactor control double battery: </label>
<input type='checkbox' name='CNTCTRLDBL' value='on' style='margin-left: 0;' %CNTCTRLDBL% />
</div>
<div class="if-cntctrl">
<label>Precharge time ms: </label>
<input name='PRECHGMS' type='text' value="%PRECHGMS%" pattern="^[0-9]+$" />
<label>PWM contactor control: </label>
<input type='checkbox' name='PWMCNTCTRL' value='on' style='margin-left: 0;' %PWMCNTCTRL% />
<label>PWM contactor control: </label>
<input type='checkbox' name='PWMCNTCTRL' value='on' style='margin-left: 0;' %PWMCNTCTRL% />
<div class="if-pwmcntctrl">
<label>PWM Frequency Hz: </label>
<input name='PWMFREQ' type='text' value="%PWMFREQ%" pattern="^[0-9]+$" />
<label>PWM Hold 0-1023: </label>
<input name='PWMHOLD' type='text' value="%PWMHOLD%" pattern="^[0-9]+$" />
</div>
</div>
<label>Periodic BMS reset: </label>
<input type='checkbox' name='PERBMSRESET' value='on' style='margin-left: 0;' %PERBMSRESET% />

View file

@ -515,6 +515,15 @@ void init_webserver() {
} else if (p->name() == "CANFREQ") {
auto type = atoi(p->value().c_str());
settings.saveUInt("CANFREQ", type);
} else if (p->name() == "PRECHGMS") {
auto type = atoi(p->value().c_str());
settings.saveUInt("PRECHGMS", type);
} else if (p->name() == "PWMFREQ") {
auto type = atoi(p->value().c_str());
settings.saveUInt("PWMFREQ", type);
} else if (p->name() == "PWMHOLD") {
auto type = atoi(p->value().c_str());
settings.saveUInt("PWMHOLD", type);
} else if (p->name() == "GTWCOUNTRY") {
auto type = atoi(p->value().c_str());
settings.saveUInt("GTWCOUNTRY", type);