Skip to content

Commit

Permalink
prevent relay switching too much with shaper
Browse files Browse the repository at this point in the history
filtering shaper input
  • Loading branch information
KipK committed Apr 2, 2023
1 parent 4be7f09 commit 43ca7b6
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 32 deletions.
10 changes: 8 additions & 2 deletions src/app_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ uint32_t divert_min_charge_time;

// Current Shaper settings
uint32_t current_shaper_max_pwr;
double current_shaper_smoothing_factor;
uint32_t current_shaper_min_pause_time; // in seconds
uint32_t current_shaper_data_maxinterval; // in seconds

// Tesla Client settings
String tesla_access_token;
Expand Down Expand Up @@ -161,7 +164,7 @@ ConfigOpt *opts[] =
new ConfigOptDefenition<String>(mqtt_vehicle_soc, "", "mqtt_vehicle_soc", "mc"),
new ConfigOptDefenition<String>(mqtt_vehicle_range, "", "mqtt_vehicle_range", "mr"),
new ConfigOptDefenition<String>(mqtt_vehicle_eta, "", "mqtt_vehicle_eta", "met"),
new ConfigOptDefenition<String>(mqtt_announce_topic, "openevse/announce/"+ESPAL.getShortId(), "mqtt_announce_topic", "ma"),
new ConfigOptDefenition<String>(mqtt_announce_topic, "openevse/announce/" + ESPAL.getShortId(), "mqtt_announce_topic", "ma"),

// OCPP 1.6 Settings
new ConfigOptDefenition<String>(ocpp_server, "", "ocpp_server", "ows"),
Expand All @@ -179,7 +182,10 @@ ConfigOpt *opts[] =
new ConfigOptDefenition<uint32_t>(divert_min_charge_time, (10 * 60), "divert_min_charge_time", "dt"),

// Current Shaper settings
new ConfigOptDefenition<uint32_t>(current_shaper_max_pwr, 0 , "current_shaper_max_pwr", "smp"),
new ConfigOptDefenition<uint32_t>(current_shaper_max_pwr, 0, "current_shaper_max_pwr", "smp"),
new ConfigOptDefenition<double>(current_shaper_smoothing_factor, 0.05, "current_shaper_smoothing_factor", "ssf"),
new ConfigOptDefenition<uint32_t>(current_shaper_min_pause_time, 300, "current_shaper_min_pause_time", "spt"),
new ConfigOptDefenition<uint32_t>(current_shaper_data_maxinterval, 120, "current_shaper_data_maxinterval", "sdm"),

// Tesla client settings
new ConfigOptSecret(tesla_access_token, "", "tesla_access_token", "tat"),
Expand Down
3 changes: 3 additions & 0 deletions src/app_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ extern uint32_t scheduler_start_window;

//Shaper settings
extern uint32_t current_shaper_max_pwr;
extern double current_shaper_smoothing_factor;
extern uint32_t current_shaper_min_pause_time;
extern uint32_t current_shaper_data_maxinterval;

// 24-bits of Flags
extern uint32_t flags;
Expand Down
112 changes: 85 additions & 27 deletions src/current_shaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ CurrentShaperTask shaper;
CurrentShaperTask::CurrentShaperTask() : MicroTasks::Task() {
_changed = false;
_enabled = false;
_max_pwr = 0;
_live_pwr = 0;
_smoothed_live_pwr = 0;
_chg_cur = 0;
_max_cur = 0;
_pause_timer = 0;
_timer = 0;
_updated = false;
}

CurrentShaperTask::~CurrentShaperTask() {
Expand All @@ -18,42 +26,64 @@ void CurrentShaperTask::setup() {
}

unsigned long CurrentShaperTask::loop(MicroTasks::WakeReason reason) {

if (_enabled) {
EvseProperties props;
if (_changed) {
props.setMaxCurrent(_max_cur);
if (_max_cur < evse.getMinCurrent() ) {
if (_max_cur < evse.getMinCurrent()) {
// pause temporary, not enough amps available
props.setState(EvseState::Disabled);
if (!_pause_timer)
{
_pause_timer = millis();
}

}
else {
else if (millis() - _pause_timer >= current_shaper_min_pause_time * 1000)
{
_pause_timer = 0;
props.setState(EvseState::None);
}
_changed = false;
_updated = true;
_timer = millis();
evse.claim(EvseClient_OpenEVSE_Shaper,EvseManager_Priority_Safety, props);
StaticJsonDocument<128> event;
event["shaper"] = 1;
event["shaper_live_pwr"] = _live_pwr;
event["shaper_max_pwr"] = _max_pwr;
event["shaper_cur"] = _max_cur;
event["shaper_updated"] = _updated;
event_send(event);
_changed = false;
// claim only if we have change
if (evse.getState() != props.getState() || evse.getChargeCurrent() != props.getChargeCurrent())
{
evse.claim(EvseClient_OpenEVSE_Shaper, EvseManager_Priority_Safety, props);
StaticJsonDocument<128> event;
event["shaper"] = 1;
event["shaper_live_pwr"] = _live_pwr;
event["shaper_smoothed_live_pwr"] = _smoothed_live_pwr;
event["shaper_max_pwr"] = _max_pwr;
event["shaper_cur"] = _max_cur;
event["shaper_updated"] = _updated;
event_send(event);
}
}
if (millis() - _timer > EVSE_SHAPER_FAILSAFE_TIME) {
else if ( !_updated || millis() - _timer > current_shaper_data_maxinterval * 1000 )
{
//available power has not been updated since EVSE_SHAPER_FAILSAFE_TIME, pause charge
DBUGF("shaper_live_pwr has not been updated in time, pausing charge");
_updated = false;
props.setState(EvseState::Disabled);
evse.claim(EvseClient_OpenEVSE_Shaper,EvseManager_Priority_Limit, props);
StaticJsonDocument<128> event;
event["shaper"] = 1;
event["shaper_live_pwr"] = _live_pwr;
event["shaper_max_pwr"] = _max_pwr;
event["shaper_cur"] = _max_cur;
event["shaper_updated"] = _updated;
event_send(event);

if (_updated) {
_pause_timer = millis();
_updated = false;
}

if (evse.getState(EvseClient_OpenEVSE_Shaper) != EvseState::Disabled)
{
props.setState(EvseState::Disabled);
evse.claim(EvseClient_OpenEVSE_Shaper, EvseManager_Priority_Limit, props);
StaticJsonDocument<128> event;
event["shaper"] = 1;
event["shaper_live_pwr"] = _live_pwr;
event["shaper_smoothed_live_pwr"] = _smoothed_live_pwr;
event["shaper_max_pwr"] = _max_pwr;
event["shaper_cur"] = _max_cur;
event["shaper_updated"] = _updated;
event_send(event);
}
}
}
else {
Expand All @@ -73,8 +103,9 @@ void CurrentShaperTask::begin(EvseManager &evse) {
this -> _evse = &evse;
this -> _max_pwr = current_shaper_max_pwr;
this -> _live_pwr = 0;
this -> _smoothed_live_pwr = 0;
this -> _max_cur = 0;
this -> _updated = false;
this -> _updated = false;
MicroTask.startTask(this);
StaticJsonDocument<128> event;
event["shaper"] = 1;
Expand Down Expand Up @@ -118,20 +149,47 @@ void CurrentShaperTask::shapeCurrent() {
_updated = true;
// adding self produced energy to total
int max_pwr = _max_pwr;
// filtering live_pwr for getting out of pause
uint32_t updt_time = (millis() - _timer) / 1000;

int livepwr;
if (_pause_timer == 0) {
_smoothed_live_pwr = _live_pwr;
livepwr = _live_pwr;
}
else {
// default filtering would consider an update each 10sec.
// Calculating the smoothing factor considering current interval.
if (_live_pwr > _smoothed_live_pwr) {
_smoothed_live_pwr = _live_pwr;
}
else {
double factor = (updt_time * current_shaper_smoothing_factor) / EVSE_SHAPER_FILTER_TAU;
_smoothed_live_pwr = (_live_pwr * factor) + (_smoothed_live_pwr * (1 - factor));
DBUGVAR(_smoothed_live_pwr);
}
livepwr = _smoothed_live_pwr;
}

if (livepwr > _max_pwr) {
livepwr = max_pwr;
}
if (config_divert_enabled() == true) {
if (mqtt_solar != "") {
max_pwr += solar;
}
}
if(!config_threephase_enabled()) {
_max_cur = round(((max_pwr - _live_pwr) / evse.getVoltage()) + (evse.getAmps()));
_max_cur = round(((max_pwr - livepwr) / evse.getVoltage()) + (evse.getAmps()));
}

else {
_max_cur = round(((max_pwr - _live_pwr) / evse.getVoltage() / 3) + (evse.getAmps()));
_max_cur = round(((max_pwr - livepwr) / evse.getVoltage() / 3) + (evse.getAmps()));
}


if (_max_cur > evse.getMaxConfiguredCurrent()) {
_max_cur = evse.getMaxConfiguredCurrent();
}

_changed = true;
}
Expand Down
10 changes: 7 additions & 3 deletions src/current_shaper.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
#ifndef EVSE_SHAPER_LOOP_TIME
#define EVSE_SHAPER_LOOP_TIME 2000
#endif
#ifndef EVSE_SHAPER_FAILSAFE_TIME
#define EVSE_SHAPER_FAILSAFE_TIME 360000
#endif

#ifndef EVSE_SHAPER_FILTER_TAU
#define EVSE_SHAPER_FILTER_TAU 10 // 10 sec
#endif


#include "emonesp.h"
#include <MicroTasks.h>
Expand All @@ -27,9 +29,11 @@ class CurrentShaperTask: public MicroTasks::Task
bool _changed;
int _max_pwr; // total current available from the grid
int _live_pwr; // current available to EVSE
int _smoothed_live_pwr; // filtered live power for getting out of pause only
uint8_t _chg_cur; // calculated charge current to claim
uint8_t _max_cur; // shaper calculated max current
uint32_t _timer;
uint32_t _pause_timer;
bool _updated;

protected:
Expand Down

0 comments on commit 43ca7b6

Please sign in to comment.