Skip to content

Commit

Permalink
Initial draft for EnergyManagement refactor:
Browse files Browse the repository at this point in the history
* Remove set_external_limits from evse_manager inteface
* Change requirement to apply limits of API and OCPP modules from evse_manager to external_energy_limits

TODOs:
* Adjust all EVerest configuration files
* Add documentation to API and OCPP modules
* EnergyManager currently seg faults

Signed-off-by: pietfried <pietgoempel@gmail.com>
  • Loading branch information
Pietfried committed Oct 10, 2024
1 parent b4f7d83 commit 00524dc
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 50 deletions.
37 changes: 32 additions & 5 deletions config/config-sil-ocpp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,13 @@ active_modules:
display_message:
- module_id: display_message
implementation_id: display_message
connector_zero_sink:
evse_manager_energy_sink:
- module_id: grid_connection_point
implementation_id: external_limits
- module_id: evse_manager_1_sink
implementation_id: external_limits
- module_id: evse_manager_2_sink
implementation_id: external_limits
display_message:
module: TerminalCostAndPriceMessage
connections:
Expand All @@ -177,26 +181,49 @@ active_modules:
token_provider_1:
module: DummyTokenProviderManual
energy_manager:
config_module:
debug: true
module: EnergyManager
connections:
energy_trunk:
- module_id: grid_connection_point
implementation_id: energy_grid
grid_connection_point:
evse_manager_1_sink:
module: EnergyNode
config_module:
fuse_limit_A: 40.0
fuse_limit_A: 32.0
phase_count: 3
connections:
price_information: []
energy_consumer:
- module_id: evse_manager_1
implementation_id: energy_grid
powermeter:
- module_id: yeti_driver_1
implementation_id: powermeter
evse_manager_2_sink:
module: EnergyNode
config_module:
fuse_limit_A: 32.0
phase_count: 3
connections:
energy_consumer:
- module_id: evse_manager_2
implementation_id: energy_grid
powermeter:
- module_id: yeti_driver_1
- module_id: yeti_driver_2
implementation_id: powermeter
grid_connection_point:
module: EnergyNode
config_module:
fuse_limit_A: 40.0
phase_count: 3
connections:
price_information: []
energy_consumer:
- module_id: evse_manager_1_sink
implementation_id: energy_grid
- module_id: evse_manager_2_sink
implementation_id: energy_grid
api:
module: API
connections:
Expand Down
9 changes: 1 addition & 8 deletions interfaces/evse_manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,6 @@ cmds:
result:
description: Returns true if unlocking sequence was successfully executed
type: boolean
set_external_limits:
description: Set additional external energy flow limits at this node.
arguments:
value:
description: UUID of node that this limit applies to
type: object
$ref: /energy#/ExternalLimits
set_get_certificate_response:
description: >-
CertificateInstallationRes/CertificateUpdateRes - Set the new/updated Contract Certificate (including the certificate chain)
Expand Down Expand Up @@ -181,4 +174,4 @@ vars:
Contains the selected protocol used for charging for informative purposes
type: string
errors:
- reference: /errors/evse_manager
- reference: /errors/evse_manager
34 changes: 21 additions & 13 deletions modules/API/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ void API::init() {

evse_manager_check.set_total(r_evse_manager.size());

int evse_id = 1;
for (auto& evse : this->r_evse_manager) {
auto& session_info = this->info.emplace_back(std::make_unique<SessionInfo>());
auto& hw_caps = this->hw_capabilities_str.emplace_back("");
Expand Down Expand Up @@ -487,11 +488,13 @@ void API::init() {
});

std::string cmd_set_limit = cmd_base + "set_limit_amps";
this->mqtt.subscribe(cmd_set_limit, [this, &evse](const std::string& data) {

this->mqtt.subscribe(cmd_set_limit, [&evse, &r_evse_manager_energy_sink = this->r_evse_manager_energy_sink,
evse_id](const std::string& data) {
try {
const auto external_limits = get_external_limits(data, false);
this->evse_manager_check.wait_ready();
evse->call_set_external_limits(external_limits);
r_evse_manager_energy_sink.at(evse_id - 1)->call_set_external_limits(external_limits);
} catch (const std::invalid_argument& e) {
EVLOG_warning << "Invalid limit: No conversion of given input could be performed.";
} catch (const std::out_of_range& e) {
Expand All @@ -500,17 +503,21 @@ void API::init() {
});

std::string cmd_set_limit_watts = cmd_base + "set_limit_watts";
this->mqtt.subscribe(cmd_set_limit_watts, [this, &evse](const std::string& data) {
try {
const auto external_limits = get_external_limits(data, true);
this->evse_manager_check.wait_ready();
evse->call_set_external_limits(external_limits);
} catch (const std::invalid_argument& e) {
EVLOG_warning << "Invalid limit: No conversion of given input could be performed.";
} catch (const std::out_of_range& e) {
EVLOG_warning << "Invalid limit: Out of range.";
}
});

this->mqtt.subscribe(
cmd_set_limit_watts,
[&evse, &r_evse_manager_energy_sink = this->r_evse_manager_energy_sink, evse_id](const std::string& data) {
try {
const auto external_limits = get_external_limits(data, true);
this->evse_manager_check.wait_ready();
r_evse_manager_energy_sink.at(evse_id - 1)->call_set_external_limits(external_limits); // FIX access
} catch (const std::invalid_argument& e) {
EVLOG_warning << "Invalid limit: No conversion of given input could be performed.";
} catch (const std::out_of_range& e) {
EVLOG_warning << "Invalid limit: Out of range.";
}
});

std::string cmd_force_unlock = cmd_base + "force_unlock";
this->mqtt.subscribe(cmd_force_unlock, [this, &evse](const std::string& data) {
int connector_id = 1;
Expand Down Expand Up @@ -565,6 +572,7 @@ void API::init() {
});
}
}
evse_id++;
}

std::string var_ocpp_connection_status = this->api_base + "ocpp/var/connection_status";
Expand Down
6 changes: 5 additions & 1 deletion modules/API/API.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// headers for required interface implementations
#include <generated/interfaces/error_history/Interface.hpp>
#include <generated/interfaces/evse_manager/Interface.hpp>
#include <generated/interfaces/external_energy_limits/Interface.hpp>
#include <generated/interfaces/ocpp/Interface.hpp>
#include <generated/interfaces/uk_random_delay/Interface.hpp>

Expand Down Expand Up @@ -157,14 +158,16 @@ class API : public Everest::ModuleBase {
API(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider, std::unique_ptr<emptyImplBase> p_main,
std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager, std::vector<std::unique_ptr<ocppIntf>> r_ocpp,
std::vector<std::unique_ptr<uk_random_delayIntf>> r_random_delay,
std::vector<std::unique_ptr<error_historyIntf>> r_error_history, Conf& config) :
std::vector<std::unique_ptr<error_historyIntf>> r_error_history,
std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_manager_energy_sink, Conf& config) :
ModuleBase(info),
mqtt(mqtt_provider),
p_main(std::move(p_main)),
r_evse_manager(std::move(r_evse_manager)),
r_ocpp(std::move(r_ocpp)),
r_random_delay(std::move(r_random_delay)),
r_error_history(std::move(r_error_history)),
r_evse_manager_energy_sink(std::move(r_evse_manager_energy_sink)),
config(config){};

Everest::MqttProvider& mqtt;
Expand All @@ -173,6 +176,7 @@ class API : public Everest::ModuleBase {
const std::vector<std::unique_ptr<ocppIntf>> r_ocpp;
const std::vector<std::unique_ptr<uk_random_delayIntf>> r_random_delay;
const std::vector<std::unique_ptr<error_historyIntf>> r_error_history;
const std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_manager_energy_sink;
const Conf& config;

// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
Expand Down
4 changes: 4 additions & 0 deletions modules/API/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ requires:
interface: error_history
min_connections: 0
max_connections: 1
evse_manager_energy_sink:
interface: external_energy_limits
min_connections: 0
max_connections: 128
enable_external_mqtt: true
metadata:
license: https://opensource.org/licenses/Apache-2.0
Expand Down
4 changes: 0 additions & 4 deletions modules/EvseManager/evse/evse_managerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,6 @@ bool evse_managerImpl::handle_stop_transaction(types::evse_manager::StopTransact
return mod->charger->cancel_transaction(request);
};

void evse_managerImpl::handle_set_external_limits(types::energy::ExternalLimits& value) {
mod->update_local_energy_limit(value);
}

void evse_managerImpl::handle_set_get_certificate_response(
types::iso15118_charger::ResponseExiStreamStatus& certificate_reponse) {
mod->r_hlc[0]->call_certificate_response(certificate_reponse);
Expand Down
1 change: 0 additions & 1 deletion modules/EvseManager/evse/evse_managerImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class evse_managerImpl : public evse_managerImplBase {
virtual bool handle_resume_charging() override;
virtual bool handle_stop_transaction(types::evse_manager::StopTransactionRequest& request) override;
virtual bool handle_force_unlock(int& connector_id) override;
virtual void handle_set_external_limits(types::energy::ExternalLimits& value) override;
virtual void handle_set_get_certificate_response(
types::iso15118_charger::ResponseExiStreamStatus& certificate_response) override;
virtual bool handle_external_ready_to_start_charging() override;
Expand Down
9 changes: 6 additions & 3 deletions modules/OCPP/OCPP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,19 @@ void OCPP::set_external_limits(const std::map<int32_t, ocpp::v16::EnhancedChargi
limits.schedule_import.emplace(schedule_import);

if (connector_id == 0) {
if (!this->r_connector_zero_sink.empty()) {
if (!this->r_evse_manager_energy_sink.empty()) {
EVLOG_debug << "OCPP sets the following external limits for connector 0: \n" << limits;
this->r_connector_zero_sink.at(0)->call_set_external_limits(limits);
this->r_evse_manager_energy_sink.at(0)->call_set_external_limits(limits);
} else {
EVLOG_debug << "OCPP cannot set external limits for connector 0. No "
"sink is configured.";
}
} else {
if (this->r_evse_manager_energy_sink.size() <= connector_id) {
EVLOG_warning << "Missing connection to evse_manager_energy_sink for evse_id: " << connector_id;
}
EVLOG_debug << "OCPP sets the following external limits for connector " << connector_id << ": \n" << limits;
this->r_evse_manager.at(connector_id - 1)->call_set_external_limits(limits);
this->r_evse_manager_energy_sink.at(connector_id)->call_set_external_limits(limits);
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions modules/OCPP/OCPP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class OCPP : public Everest::ModuleBase {
std::unique_ptr<ocpp_data_transferImplBase> p_data_transfer, std::unique_ptr<ocppImplBase> p_ocpp_generic,
std::unique_ptr<session_costImplBase> p_session_cost,
std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager,
std::vector<std::unique_ptr<external_energy_limitsIntf>> r_connector_zero_sink,
std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_manager_energy_sink,
std::unique_ptr<reservationIntf> r_reservation, std::unique_ptr<authIntf> r_auth,
std::unique_ptr<systemIntf> r_system, std::unique_ptr<evse_securityIntf> r_security,
std::vector<std::unique_ptr<ocpp_data_transferIntf>> r_data_transfer,
Expand All @@ -89,7 +89,7 @@ class OCPP : public Everest::ModuleBase {
p_ocpp_generic(std::move(p_ocpp_generic)),
p_session_cost(std::move(p_session_cost)),
r_evse_manager(std::move(r_evse_manager)),
r_connector_zero_sink(std::move(r_connector_zero_sink)),
r_evse_manager_energy_sink(std::move(r_evse_manager_energy_sink)),
r_reservation(std::move(r_reservation)),
r_auth(std::move(r_auth)),
r_system(std::move(r_system)),
Expand All @@ -106,7 +106,7 @@ class OCPP : public Everest::ModuleBase {
const std::unique_ptr<ocppImplBase> p_ocpp_generic;
const std::unique_ptr<session_costImplBase> p_session_cost;
const std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager;
const std::vector<std::unique_ptr<external_energy_limitsIntf>> r_connector_zero_sink;
const std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_manager_energy_sink;
const std::unique_ptr<reservationIntf> r_reservation;
const std::unique_ptr<authIntf> r_auth;
const std::unique_ptr<systemIntf> r_system;
Expand Down Expand Up @@ -162,6 +162,7 @@ class OCPP : public Everest::ModuleBase {
};

// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1

} // namespace module
Expand Down
14 changes: 14 additions & 0 deletions modules/OCPP/doc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ of the limited maximum characters of the `info` field.
`Faulted` value as follows: "When a Charge Point or connector has reported an error and is not available for energy delivery . (Inoperative).".
This module therefore only reports `Faulted` when the Charge Point is not available for energy delivery.

Energy Management and Smart Charging Integration
================================================

OCPP1.6 defines the SmartCharging feature profile to allow the CSMS to control or influence the power consumption of the charging station.
This module integrates the composite schedule(s) within EVerests energy management. For further information about smart charging and the
composite schedule calculation please refer to the OCPP1.6 specification.

The integration of the composite schedules are turned out by the optional requirement(s) `evse_manager_energy_sink` of this module.
Depending on the number of EVSEs configured, each composite limit is communicated via a seperate sink, including the composite schedule
for EVSE with id 0 (representing the whole charging station). The easiest way to explain this is with an example. If your charging station
has two EVSEs you need to connect three modules that implement the `evse_manager_energy_sink` interface: One representing evse id 0 and
two representing your actual EVSEs. Note that it is important to specify the connections in the EVerest config file in the correct order
(0,1,2).

Interaction with EVSE Manager
=============================

Expand Down
4 changes: 2 additions & 2 deletions modules/OCPP/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ requires:
interface: evse_manager
min_connections: 1
max_connections: 128
connector_zero_sink:
evse_manager_energy_sink:
interface: external_energy_limits
min_connections: 0
max_connections: 1
max_connections: 129
reservation:
interface: reservation
min_connections: 1
Expand Down
14 changes: 9 additions & 5 deletions modules/OCPP201/OCPP201.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,8 @@ void OCPP201::ready() {

const auto composite_schedule_unit = get_unit_or_default(this->config.RequestCompositeScheduleUnit);

// this callback publishes the schedules within EVerest and applies the schedules for the individual evse_manager(s)
// and the connector_zero_sink
// this callback publishes the schedules within EVerest and applies the schedules for the individual
// r_evse_manager_energy_sink
const auto charging_schedules_callback = [this, composite_schedule_unit]() {
const auto composite_schedules = this->charge_point->get_all_composite_schedules(
this->config.RequestCompositeScheduleDurationS, composite_schedule_unit);
Expand Down Expand Up @@ -1187,17 +1187,21 @@ void OCPP201::set_external_limits(const std::vector<ocpp::v201::CompositeSchedul
limits.schedule_import = schedule_import;

if (composite_schedule.evseId == 0) {
if (!this->r_connector_zero_sink.empty()) {
if (!this->r_evse_manager_energy_sink.empty()) {
EVLOG_debug << "OCPP sets the following external limits for evse 0: \n" << limits;
this->r_connector_zero_sink.at(0)->call_set_external_limits(limits);
this->r_evse_manager_energy_sink.at(0)->call_set_external_limits(limits);
} else {
EVLOG_debug << "OCPP cannot set external limits for evse 0. No "
"sink is configured.";
}
} else {
if (this->r_evse_manager_energy_sink.size() <= composite_schedule.evseId) {
EVLOG_warning << "Missing connection to evse_manager_energy_sink for evse_id: "
<< composite_schedule.evseId;
}
EVLOG_debug << "OCPP sets the following external limits for evse " << composite_schedule.evseId << ": \n"
<< limits;
this->r_evse_manager.at(composite_schedule.evseId - 1)->call_set_external_limits(limits);
this->r_evse_manager_energy_sink.at(composite_schedule.evseId)->call_set_external_limits(limits);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions modules/OCPP201/OCPP201.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class OCPP201 : public Everest::ModuleBase {
std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager, std::unique_ptr<systemIntf> r_system,
std::unique_ptr<evse_securityIntf> r_security,
std::vector<std::unique_ptr<ocpp_data_transferIntf>> r_data_transfer, std::unique_ptr<authIntf> r_auth,
std::vector<std::unique_ptr<external_energy_limitsIntf>> r_connector_zero_sink,
std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_manager_energy_sink,
std::vector<std::unique_ptr<display_messageIntf>> r_display_message, Conf& config) :
ModuleBase(info),
mqtt(mqtt_provider),
Expand All @@ -76,7 +76,7 @@ class OCPP201 : public Everest::ModuleBase {
r_security(std::move(r_security)),
r_data_transfer(std::move(r_data_transfer)),
r_auth(std::move(r_auth)),
r_connector_zero_sink(std::move(r_connector_zero_sink)),
r_evse_manager_energy_sink(std::move(r_evse_manager_energy_sink)),
r_display_message(std::move(r_display_message)),
config(config) {
}
Expand All @@ -93,7 +93,7 @@ class OCPP201 : public Everest::ModuleBase {
const std::unique_ptr<evse_securityIntf> r_security;
const std::vector<std::unique_ptr<ocpp_data_transferIntf>> r_data_transfer;
const std::unique_ptr<authIntf> r_auth;
const std::vector<std::unique_ptr<external_energy_limitsIntf>> r_connector_zero_sink;
const std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_manager_energy_sink;
const std::vector<std::unique_ptr<display_messageIntf>> r_display_message;
const Conf& config;

Expand Down
4 changes: 2 additions & 2 deletions modules/OCPP201/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ requires:
interface: auth
min_connections: 1
max_connections: 1
connector_zero_sink:
evse_manager_energy_sink:
interface: external_energy_limits
min_connections: 0
max_connections: 1
max_connections: 128
display_message:
interface: display_message
min_connections: 0
Expand Down

0 comments on commit 00524dc

Please sign in to comment.