Skip to content

Commit

Permalink
Limit now handled by wifi module
Browse files Browse the repository at this point in the history
new /limit API endpoint
Added classes:
Limit
LimitProperties
LimitType class

POST { "type": type, "value": value, "auto_release" : optional bool }
type actually possible are : 'time", "energy", "soc", "range"
only time & energy are implemented.

Disable state when time or energy session > defined limit.
Release disable claim when car is disconnected.

time_limit in minutes
session_energy in w/h
  • Loading branch information
KipK committed Jan 31, 2023
1 parent e65fbe9 commit b20f1db
Show file tree
Hide file tree
Showing 4 changed files with 410 additions and 1 deletion.
246 changes: 246 additions & 0 deletions src/limit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
#if defined(ENABLE_DEBUG) && !defined(ENABLE_DEBUG_LIMIT)
#undef ENABLE_DEBUG
#endif

#include "limit.h"
#include "debug.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <MicroTasks.h>
#include "evse_man.h"

// ---------------------------------------------
//
// LimitType Class
//
//----------------------------------------------

uint8_t LimitType::fromString(const char *value)
{
// Cheat a bit and just check the first char
switch (value[0]) {
// None
case ('n'):
_value = LimitType::None;
break;
//Time
case ('t'):
_value = LimitType::Time;
break;
//Energy
case ('e'):
_value = LimitType::Energy;
break;
//Soc
case ('s'):
_value = LimitType::Soc;
break;
//Range
case ('r'):
_value = LimitType::Range;
break;
}
return _value;
}
const char *LimitType::toString()
{
return LimitType::None == _value ? "none" :
LimitType::Time == _value ? "time" :
LimitType::Energy == _value ? "energy" :
LimitType::Soc == _value ? "soc" :
LimitType::Range == _value ? "range" :
"unknown";
}

LimitType LimitType::operator= (const Value val) {
_value = val;
return *this;
}

// ---------------------------------------------
//
// LimitProperties Class
//
//----------------------------------------------
LimitProperties::LimitProperties()
{
_type = LimitType::None;
_value = 0;
_auto_release = true;
};

LimitProperties::~LimitProperties()
{
DBUGLN("LimitProperties Destructor");

};

void LimitProperties::init()
{
_type = LimitType::None;
_value = 0;
_auto_release = true;
};

LimitType LimitProperties::getType() {
return _type;
};

bool LimitProperties::setType(LimitType type)
{
_type = type;
return true;
};

uint32_t LimitProperties::getValue() {
return _value;
};

bool LimitProperties::setValue(uint32_t value)
{
_value = value;
return true;
};

bool LimitProperties::getAutoRelease() {
return _auto_release;
};

bool LimitProperties::deserialize(JsonObject &obj)
{
if(obj.containsKey("type")) {
_type.fromString(obj["type"]);
}
if(obj.containsKey("value")) {
_value = obj["value"];
}
if(obj.containsKey("auto_release")) {
_auto_release = obj["auto_release"];
}
return _type > 0 && _value > 0;

};

bool LimitProperties::serialize(JsonObject &obj)
{

obj["type"] = _type.toString();
obj["value"] = _value;
obj["auto_release"] = _auto_release;
return true;
};

// ---------------------------------------------
//
// Limit Class
//
//----------------------------------------------

//global instance
Limit limit;

Limit::Limit() : Limit::Task() {
_limit_properties.init();
};

Limit::~Limit() {
_evse -> release(EvseClient_OpenEVSE_Limit);
};

void Limit::setup() {

};

void Limit::begin(EvseManager &evse) {
// todo get saved default limit
DBUGLN("Starting Limit task");
this -> _evse = &evse;
MicroTask.startTask(this);
};

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


if (hasLimit()) {
LimitType type = _limit_properties.getType();
uint32_t value = _limit_properties.getValue();
bool auto_release = _limit_properties.getAutoRelease();

if (_evse->isCharging() ) {
_has_vehicle = true;
bool limit_reached = false;
switch (type) {
case LimitType::Time:
limit_reached = limitTime(value);
break;
case LimitType::Energy:
limit_reached = limitEnergy(value);
break;
}
if (limit_reached) {
// Limit reached, disabling EVSE
if (_evse->getClaimProperties(EvseClient_OpenEVSE_Limit).getState() == EvseState::None) {
DBUGLN("Limit as expired, disable evse");
EvseProperties props;
props.setState(EvseState::Disabled);
props.setAutoRelease(true);
_evse->claim(EvseClient_OpenEVSE_Limit, EvseManager_Priority_Limit, props);
}
}

}
else if ( _has_vehicle && !_evse->isVehicleConnected()) {
_has_vehicle = false;
// if auto release is set, reset Limit properties
if (auto_release) {
_limit_properties.init();
}
}

}

return EVSE_LIMIT_LOOP_TIME;
};

bool Limit::limitTime(uint32_t val) {
if ( val != 0 && _evse->getSessionElapsed() > 0 && _evse->getSessionElapsed()/60 >= val ) {
// Time limit done
return false;
}
else return true;
};

bool Limit::limitEnergy(uint32_t val) {
if ( val != 0 && _evse->getSessionEnergy() > 0 && (uint32_t)_evse->getSessionEnergy() >= val ) {
// Time limit done
return false;
}
else return true;
};

bool Limit::hasLimit() {
return _limit_properties.getType() != LimitType::None;
};

bool Limit::set(String json) {
LimitProperties props;
if (props.deserialize(json)) {
set(props);
return true;
}
else return false;
};

bool Limit::set(LimitProperties props) {
_limit_properties = props;
return true;
};

bool Limit::clear() {
_limit_properties.init();
return true;
};

LimitProperties Limit::getLimitProperties() {
return _limit_properties;
};
87 changes: 87 additions & 0 deletions src/limit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifndef _OPENEVSE_LIMIT_H
#define _OPENEVSE_LIMIT_H


#ifndef EVSE_LIMIT_LOOP_TIME
#define EVSE_LIMIT_LOOP_TIME 1000
#endif
#include <Arduino.h>
#include <ArduinoJson.h>
#include <MicroTasks.h>
#include "evse_man.h"

class LimitType {

public:
enum Value : uint8_t {
None,
Time,
Energy,
Soc,
Range
};

LimitType() = default;
constexpr LimitType(Value value) : _value(value) { }
uint8_t fromString(const char *value);
const char *toString();

operator Value() const { return _value; }
explicit operator bool() = delete; // Prevent usage: if(state)
LimitType operator= (const Value val);

private:
Value _value;
};

class LimitProperties : virtual public JsonSerialize<512> {
private:
LimitType _type;
uint32_t _value;
bool _auto_release;
public:
LimitProperties();
~LimitProperties();
void init();
bool setType(LimitType type);
bool setValue(uint32_t value);
LimitType getType();
uint32_t getValue();
bool getAutoRelease();

using JsonSerialize::deserialize;
virtual bool deserialize(JsonObject &obj);
using JsonSerialize::serialize;
virtual bool serialize(JsonObject &obj);

};

class Limit: public MicroTasks::Task
{
private:
EvseManager *_evse;
LimitProperties _limit_properties;
bool _has_vehicle;
bool limitTime(uint32_t val);
bool limitEnergy(uint32_t val);
bool limitSoc(uint32_t val);
bool limitRange(uint32_t val);

protected:
void setup();
unsigned long loop(MicroTasks::WakeReason reason);


public:
Limit();
~Limit();
void begin(EvseManager &evse);
bool hasLimit();
bool set(String json);
bool set(LimitProperties props);
bool clear();
LimitProperties getLimitProperties();
};

extern Limit limit;
#endif
3 changes: 2 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "ocpp.h"
#include "rfid.h"
#include "current_shaper.h"
#include "limit.h"

#if defined(ENABLE_PN532)
#include "pn532.h"
Expand Down Expand Up @@ -125,7 +126,7 @@ void setup()
evse.begin();
scheduler.begin();
divert.begin();

limit.begin(evse);
lcd.begin(evse, scheduler, manual);
#if defined(ENABLE_PN532)
pn532.begin();
Expand Down
Loading

0 comments on commit b20f1db

Please sign in to comment.