From 00524dc8388a1f5d8309b162dd461afd32e1a3ad Mon Sep 17 00:00:00 2001 From: pietfried Date: Fri, 20 Sep 2024 21:52:37 +0200 Subject: [PATCH] Initial draft for EnergyManagement refactor: * 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 --- config/config-sil-ocpp.yaml | 37 ++++++++++++++++--- interfaces/evse_manager.yaml | 9 +---- modules/API/API.cpp | 34 ++++++++++------- modules/API/API.hpp | 6 ++- modules/API/manifest.yaml | 4 ++ modules/EvseManager/evse/evse_managerImpl.cpp | 4 -- modules/EvseManager/evse/evse_managerImpl.hpp | 1 - modules/OCPP/OCPP.cpp | 9 +++-- modules/OCPP/OCPP.hpp | 7 ++-- modules/OCPP/doc.rst | 14 +++++++ modules/OCPP/manifest.yaml | 4 +- modules/OCPP201/OCPP201.cpp | 14 ++++--- modules/OCPP201/OCPP201.hpp | 6 +-- modules/OCPP201/manifest.yaml | 4 +- 14 files changed, 103 insertions(+), 50 deletions(-) diff --git a/config/config-sil-ocpp.yaml b/config/config-sil-ocpp.yaml index 7ad065089..9c1636286 100644 --- a/config/config-sil-ocpp.yaml +++ b/config/config-sil-ocpp.yaml @@ -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: @@ -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: diff --git a/interfaces/evse_manager.yaml b/interfaces/evse_manager.yaml index 39c14a01e..b3d829f2c 100644 --- a/interfaces/evse_manager.yaml +++ b/interfaces/evse_manager.yaml @@ -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) @@ -181,4 +174,4 @@ vars: Contains the selected protocol used for charging for informative purposes type: string errors: - - reference: /errors/evse_manager \ No newline at end of file + - reference: /errors/evse_manager diff --git a/modules/API/API.cpp b/modules/API/API.cpp index 68c4900df..c64d550dd 100644 --- a/modules/API/API.cpp +++ b/modules/API/API.cpp @@ -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()); auto& hw_caps = this->hw_capabilities_str.emplace_back(""); @@ -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) { @@ -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; @@ -565,6 +572,7 @@ void API::init() { }); } } + evse_id++; } std::string var_ocpp_connection_status = this->api_base + "ocpp/var/connection_status"; diff --git a/modules/API/API.hpp b/modules/API/API.hpp index 7f83c9ec3..88be2f696 100644 --- a/modules/API/API.hpp +++ b/modules/API/API.hpp @@ -16,6 +16,7 @@ // headers for required interface implementations #include #include +#include #include #include @@ -157,7 +158,8 @@ class API : public Everest::ModuleBase { API(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider, std::unique_ptr p_main, std::vector> r_evse_manager, std::vector> r_ocpp, std::vector> r_random_delay, - std::vector> r_error_history, Conf& config) : + std::vector> r_error_history, + std::vector> r_evse_manager_energy_sink, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), p_main(std::move(p_main)), @@ -165,6 +167,7 @@ class API : public Everest::ModuleBase { 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; @@ -173,6 +176,7 @@ class API : public Everest::ModuleBase { const std::vector> r_ocpp; const std::vector> r_random_delay; const std::vector> r_error_history; + const std::vector> r_evse_manager_energy_sink; const Conf& config; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 diff --git a/modules/API/manifest.yaml b/modules/API/manifest.yaml index ec1b0e9fb..6e8ac30e3 100644 --- a/modules/API/manifest.yaml +++ b/modules/API/manifest.yaml @@ -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 diff --git a/modules/EvseManager/evse/evse_managerImpl.cpp b/modules/EvseManager/evse/evse_managerImpl.cpp index 168b678c5..6124482dd 100644 --- a/modules/EvseManager/evse/evse_managerImpl.cpp +++ b/modules/EvseManager/evse/evse_managerImpl.cpp @@ -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); diff --git a/modules/EvseManager/evse/evse_managerImpl.hpp b/modules/EvseManager/evse/evse_managerImpl.hpp index f9db90dad..58ac2e3fb 100644 --- a/modules/EvseManager/evse/evse_managerImpl.hpp +++ b/modules/EvseManager/evse/evse_managerImpl.hpp @@ -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; diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index f86c1b1f2..52cc6b771 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -100,16 +100,19 @@ void OCPP::set_external_limits(const std::mapr_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); } } } diff --git a/modules/OCPP/OCPP.hpp b/modules/OCPP/OCPP.hpp index deb467907..375848298 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -75,7 +75,7 @@ class OCPP : public Everest::ModuleBase { std::unique_ptr p_data_transfer, std::unique_ptr p_ocpp_generic, std::unique_ptr p_session_cost, std::vector> r_evse_manager, - std::vector> r_connector_zero_sink, + std::vector> r_evse_manager_energy_sink, std::unique_ptr r_reservation, std::unique_ptr r_auth, std::unique_ptr r_system, std::unique_ptr r_security, std::vector> r_data_transfer, @@ -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)), @@ -106,7 +106,7 @@ class OCPP : public Everest::ModuleBase { const std::unique_ptr p_ocpp_generic; const std::unique_ptr p_session_cost; const std::vector> r_evse_manager; - const std::vector> r_connector_zero_sink; + const std::vector> r_evse_manager_energy_sink; const std::unique_ptr r_reservation; const std::unique_ptr r_auth; const std::unique_ptr r_system; @@ -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 diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index b1fbce819..e1a6ecd8a 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -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 ============================= diff --git a/modules/OCPP/manifest.yaml b/modules/OCPP/manifest.yaml index c9ae86032..09bf9206a 100644 --- a/modules/OCPP/manifest.yaml +++ b/modules/OCPP/manifest.yaml @@ -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 diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index f397c9b4c..8a3ac4d41 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -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); @@ -1187,17 +1187,21 @@ void OCPP201::set_external_limits(const std::vectorr_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); } } } diff --git a/modules/OCPP201/OCPP201.hpp b/modules/OCPP201/OCPP201.hpp index 253a06715..53165ba62 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -61,7 +61,7 @@ class OCPP201 : public Everest::ModuleBase { std::vector> r_evse_manager, std::unique_ptr r_system, std::unique_ptr r_security, std::vector> r_data_transfer, std::unique_ptr r_auth, - std::vector> r_connector_zero_sink, + std::vector> r_evse_manager_energy_sink, std::vector> r_display_message, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), @@ -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) { } @@ -93,7 +93,7 @@ class OCPP201 : public Everest::ModuleBase { const std::unique_ptr r_security; const std::vector> r_data_transfer; const std::unique_ptr r_auth; - const std::vector> r_connector_zero_sink; + const std::vector> r_evse_manager_energy_sink; const std::vector> r_display_message; const Conf& config; diff --git a/modules/OCPP201/manifest.yaml b/modules/OCPP201/manifest.yaml index 126267b11..630a0e504 100644 --- a/modules/OCPP201/manifest.yaml +++ b/modules/OCPP201/manifest.yaml @@ -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