From 5b53f2f55420838c416206f41c51e3c157f01b26 Mon Sep 17 00:00:00 2001 From: pietfried Date: Fri, 20 Sep 2024 21:52:37 +0200 Subject: [PATCH 01/33] 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 | 6 +-- 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, 102 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 2f4a439e2..784e9f37c 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) @@ -184,4 +177,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 a6b205615..103266bbb 100644 --- a/modules/EvseManager/evse/evse_managerImpl.cpp +++ b/modules/EvseManager/evse/evse_managerImpl.cpp @@ -421,10 +421,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 5125a23ff..cef7cb0dd 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -101,16 +101,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 631584657..f11980354 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -76,7 +76,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, @@ -90,7 +90,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)), @@ -107,7 +107,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; diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index bfa555f05..3e8c658ea 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -298,6 +298,20 @@ This module currently deviates from the MREC specification in the following poin **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 implemented 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). + Certificate Management ---------------------- diff --git a/modules/OCPP/manifest.yaml b/modules/OCPP/manifest.yaml index d158c8542..e54d97dfa 100644 --- a/modules/OCPP/manifest.yaml +++ b/modules/OCPP/manifest.yaml @@ -77,10 +77,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 b9ddffd2f..b27ccae77 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -662,8 +662,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); @@ -1223,17 +1223,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 dea85f514..981283701 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -60,7 +60,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), @@ -74,7 +74,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) { } @@ -90,7 +90,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 bdc641913..0ef5aa8bc 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 From 94227c52eb8faa6a279deacab35733986853b43e Mon Sep 17 00:00:00 2001 From: pietfried Date: Fri, 20 Sep 2024 22:09:37 +0200 Subject: [PATCH 02/33] extended documentation for OCPP module Signed-off-by: pietfried --- modules/OCPP/doc.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index 3e8c658ea..ca82fb9da 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -299,19 +299,27 @@ This module currently deviates from the MREC specification in the following poin (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 implemented 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 +The integration of the composite schedules are turned out by the optional requirement(s) `evse_manager_energy_sink`(interface: `external_energy_limits`) +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 +has two EVSEs you need to connect three modules that implement the `external_energy_limits` 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). +This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves +the composite schedules for all EVSEs (including evse id 0) and calls the `set_external_limits` command of the respective requirement that implements +the `external_energy_limits` interface. In addition, the config parameter `PublishChargingScheduleIntervalS` defines a periodic interval to retrieve +the composite schedule also in case no charging profiles have been changed. The configuration paramater `PublishChargingScheduleDurationS` defines +the duration in seconds of the requested composite schedules starting now. The value configured for `PublishChargingScheduleDurationS` shall be greater +than the value configured for `PublishChargingScheduleIntervalS` because otherwise time periods could be missed by the application. + + Certificate Management ---------------------- From 250a0c4112a4d31466fbff2ab57afd80abad564f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Thu, 10 Oct 2024 14:59:52 +0200 Subject: [PATCH 03/33] addressed requested changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- modules/API/API.cpp | 37 ++++++++++++++++++++----------------- modules/OCPP/OCPP.cpp | 2 +- modules/OCPP/doc.rst | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/modules/API/API.cpp b/modules/API/API.cpp index c64d550dd..65eee0b82 100644 --- a/modules/API/API.cpp +++ b/modules/API/API.cpp @@ -489,12 +489,15 @@ void API::init() { std::string cmd_set_limit = cmd_base + "set_limit_amps"; - this->mqtt.subscribe(cmd_set_limit, [&evse, &r_evse_manager_energy_sink = this->r_evse_manager_energy_sink, + const auto& evse_energy_sink = this->r_evse_manager_energy_sink.at(evse_id); + + this->mqtt.subscribe(cmd_set_limit, [&evse_manager_check = this->evse_manager_check, + &evse_energy_sink = evse_energy_sink, evse_id](const std::string& data) { try { const auto external_limits = get_external_limits(data, false); - this->evse_manager_check.wait_ready(); - r_evse_manager_energy_sink.at(evse_id - 1)->call_set_external_limits(external_limits); + evse_manager_check.wait_ready(); + evse_energy_sink->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) { @@ -504,20 +507,20 @@ void API::init() { std::string cmd_set_limit_watts = cmd_base + "set_limit_watts"; - 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."; - } - }); - + this->mqtt.subscribe(cmd_set_limit_watts, [&evse_manager_check = this->evse_manager_check, + &evse_energy_sink = evse_energy_sink, + evse_id](const std::string& data) { + try { + const auto external_limits = get_external_limits(data, true); + evse_manager_check.wait_ready(); + evse_energy_sink->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."; + } + }); + 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; diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index cef7cb0dd..40bd70104 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -103,7 +103,7 @@ void OCPP::set_external_limits(const std::mapr_evse_manager_energy_sink.empty()) { EVLOG_debug << "OCPP sets the following external limits for connector 0: \n" << limits; - this->r_evse_manager_energy_sink.at(0)->call_set_external_limits(limits); + this->r_evse_manager_energy_sink.first()->call_set_external_limits(limits); } else { EVLOG_debug << "OCPP cannot set external limits for connector 0. No " "sink is configured."; diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index ca82fb9da..58f8ef212 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -305,7 +305,7 @@ OCPP1.6 defines the SmartCharging feature profile to allow the CSMS to control o 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`(interface: `external_energy_limits`) +The integration of the composite schedules are implemented through the optional requirement(s) `evse_manager_energy_sink`(interface: `external_energy_limits`) 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 `external_energy_limits` interface: One representing evse id 0 and From 84c1a2e7b6db6078306b2ff05ab22984b29e7c98 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Fri, 4 Oct 2024 18:19:03 +0200 Subject: [PATCH 04/33] Install ev-cli locally and depend on templates files for generation Signed-off-by: Kai-Uwe Hermann --- CMakeLists.txt | 2 ++ cmake/ev-cli.cmake | 2 +- cmake/everest-generate.cmake | 2 +- scripts/get_package_location.py | 54 +++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100755 scripts/get_package_location.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 611097fab..31ecaac1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,8 @@ ev_setup_python_executable( PYTHON_VENV_PATH ${${PROJECT_NAME}_PYTHON_VENV_PATH} ) +set(EVEREST_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") + # Already include CTest here to allow it to find tests defined in subdirectories like lib and modules if(EVEREST_CORE_BUILD_TESTING) include(CTest) diff --git a/cmake/ev-cli.cmake b/cmake/ev-cli.cmake index b75f38a42..b0477c596 100644 --- a/cmake/ev-cli.cmake +++ b/cmake/ev-cli.cmake @@ -98,4 +98,4 @@ function(set_ev_cli_template_properties) MODULE_TEMPLATES "${MODULE_TEMPLATES}" TYPES_TEMPLATES "${TYPES_TEMPLATES}" ) -endfunction() +endfunction() \ No newline at end of file diff --git a/cmake/everest-generate.cmake b/cmake/everest-generate.cmake index ccfa78a73..bbfe81839 100644 --- a/cmake/everest-generate.cmake +++ b/cmake/everest-generate.cmake @@ -743,4 +743,4 @@ endfunction() set(EVEREST_EXCLUDE_MODULES "" CACHE STRING "A list of modules that will not be built") set(EVEREST_INCLUDE_MODULES "" CACHE STRING "A list of modules that will be built. If the list is empty, all modules will be built.") -option(EVEREST_EXCLUDE_CPP_MODULES "Exclude all C++ modules from the build" OFF) +option(EVEREST_EXCLUDE_CPP_MODULES "Exclude all C++ modules from the build" OFF) \ No newline at end of file diff --git a/scripts/get_package_location.py b/scripts/get_package_location.py new file mode 100755 index 000000000..72d66041f --- /dev/null +++ b/scripts/get_package_location.py @@ -0,0 +1,54 @@ +#!/usr/bin/env -S python3 -tt +# -*- coding: utf-8 -*- +# +# SPDX-License-Identifier: Apache-2.0 +# Copyright Pionix GmbH and Contributors to EVerest +# +""" +author: kai-uwe.hermann@pionix.de +""" + +import argparse +from importlib.metadata import Distribution, PackageNotFoundError +import json + + +__version__ = '0.1.0' + + +class EVerestParsingException(SystemExit): + pass + + +def main(): + parser = argparse.ArgumentParser( + description='EVerest get package location') + parser.add_argument('--version', action='version', + version=f'%(prog)s {__version__}') + parser.add_argument('--package-name', type=str, + help='Name of the package that the location should be retrieved from', default=None) + args = parser.parse_args() + + if not 'package_name' in args or not args.package_name: + raise EVerestParsingException('Please provide a valid package name') + + direct_url = "" + try: + direct_url = Distribution.from_name( + args.package_name).read_text('direct_url.json') + except PackageNotFoundError as e: + raise EVerestParsingException(e) + url = json.loads(direct_url).get('url', None) + + if url and url.startswith('file://'): + url = url.replace('file://', '') + print(f'{url}') + else: + raise EVerestParsingException() + + +if __name__ == '__main__': + try: + main() + except EVerestParsingException as e: + raise SystemExit(e) From f8526028e90f6d405992dd4fe13b6f3d22d17743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Fri, 11 Oct 2024 13:48:25 +0200 Subject: [PATCH 05/33] Fixed issue when recursively creating Market objects. Changed vector of children to unique_ptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- modules/EnergyManager/Market.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/EnergyManager/Market.cpp b/modules/EnergyManager/Market.cpp index 439b39070..dc488041d 100644 --- a/modules/EnergyManager/Market.cpp +++ b/modules/EnergyManager/Market.cpp @@ -245,7 +245,7 @@ Market::Market(types::energy::EnergyFlowRequest& _energy_flow_request, const flo // Recursion: create one Market for each child for (auto& flow_child : _energy_flow_request.children) { - _children.emplace_back(flow_child, _nominal_ac_voltage, this); + _children.emplace_back(std::make_unique(flow_child, _nominal_ac_voltage, this)); } } @@ -267,7 +267,7 @@ void Market::get_list_of_evses(std::vector& list) { } for (auto& child : _children) { - child.get_list_of_evses(list); + child->get_list_of_evses(list); } } @@ -278,7 +278,7 @@ std::vector Market::get_list_of_evses() { } for (auto& child : _children) { - child.get_list_of_evses(list); + child->get_list_of_evses(list); } return list; } From 0e2c47b1dd83406e15ab041cdac9937365cb599d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Mon, 14 Oct 2024 13:03:59 +0200 Subject: [PATCH 06/33] * Changed all ocpp configs to meet the new connection requirements for the energy management * Using the mapping of the requirement to determine the connect requirement to call based on the evse id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- config/config-sil-energy-management.yaml | 31 +++++- config/config-sil-ocpp-custom-extension.yaml | 67 +++++++++++- config/config-sil-ocpp-pnc.yaml | 71 ++++++++++++- config/config-sil-ocpp.yaml | 48 +++++++-- config/config-sil-ocpp201-pnc.yaml | 67 +++++++++++- config/config-sil-ocpp201.yaml | 66 +++++++++++- modules/API/API.cpp | 104 +++++++++++++------ modules/API/API.hpp | 9 +- modules/API/README.md | 4 + modules/API/manifest.yaml | 2 +- modules/OCPP/OCPP.cpp | 60 ++++++++--- modules/OCPP/OCPP.hpp | 8 +- modules/OCPP/doc.rst | 2 +- modules/OCPP/manifest.yaml | 2 +- modules/OCPP201/OCPP201.cpp | 65 +++++++++--- modules/OCPP201/OCPP201.hpp | 12 ++- modules/OCPP201/manifest.yaml | 2 +- 17 files changed, 520 insertions(+), 100 deletions(-) diff --git a/config/config-sil-energy-management.yaml b/config/config-sil-energy-management.yaml index 199f8b5e8..17ef597c5 100644 --- a/config/config-sil-energy-management.yaml +++ b/config/config-sil-energy-management.yaml @@ -159,25 +159,52 @@ active_modules: connections: price_information: [] energy_consumer: - - module_id: evse_manager_1 + - module_id: evse_manager_1_sink implementation_id: energy_grid - - module_id: evse_manager_2 + - module_id: evse_manager_2_sink implementation_id: energy_grid powermeter: - module_id: yeti_driver_1 implementation_id: powermeter + evse_manager_1_sink: + module: EnergyNode + evse: 1 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_1 + implementation_id: energy_grid + evse_manager_2_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_2 + implementation_id: energy_grid api: module: API connections: evse_manager: - module_id: evse_manager_1 implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse random_delay: - module_id: evse_manager_1 implementation_id: random_delay error_history: - module_id: error_history implementation_id: error_history + evse_energy_sink: + - module_id: evse_manager_1_sink + implementation_id: external_limits + - module_id: evse_manager_2_sink + implementation_id: external_limits error_history: module: ErrorHistory config_implementation: diff --git a/config/config-sil-ocpp-custom-extension.yaml b/config/config-sil-ocpp-custom-extension.yaml index 0a13a162e..258a18992 100644 --- a/config/config-sil-ocpp-custom-extension.yaml +++ b/config/config-sil-ocpp-custom-extension.yaml @@ -152,6 +152,13 @@ active_modules: data_transfer: - module_id: ocpp_extension implementation_id: data_transfer + evse_energy_sink: + - module_id: grid_connection_point + implementation_id: external_limits + - module_id: evse_manager_1_ocpp_sink + implementation_id: external_limits + - module_id: evse_manager_2_ocpp_sink + implementation_id: external_limits evse_security: module: EvseSecurity config_module: @@ -175,30 +182,84 @@ active_modules: energy_trunk: - module_id: grid_connection_point implementation_id: energy_grid - grid_connection_point: + evse_manager_1_ocpp_sink: module: EnergyNode + evse: 1 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 + evse_manager_2_ocpp_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: - module_id: evse_manager_2 implementation_id: energy_grid + evse_manager_1_api_sink: + evse: 1 + module: EnergyNode + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_1_ocpp_sink + implementation_id: energy_grid powermeter: - module_id: yeti_driver_1 implementation_id: powermeter + evse_manager_2_api_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_2_ocpp_sink + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_2 + implementation_id: powermeter + grid_connection_point: + module: EnergyNode + evse: 0 + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1_api_sink + implementation_id: energy_grid + - module_id: evse_manager_2_api_sink + implementation_id: energy_grid api: module: API connections: evse_manager: - module_id: evse_manager_1 implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + ocpp: + - module_id: ocpp + implementation_id: ocpp_generic error_history: - module_id: error_history implementation_id: error_history + evse_energy_sink: + - module_id: evse_manager_1_api_sink + implementation_id: external_limits + - module_id: evse_manager_2_api_sink + implementation_id: external_limits error_history: module: ErrorHistory config_implementation: diff --git a/config/config-sil-ocpp-pnc.yaml b/config/config-sil-ocpp-pnc.yaml index 9771903a6..ad05e2c63 100644 --- a/config/config-sil-ocpp-pnc.yaml +++ b/config/config-sil-ocpp-pnc.yaml @@ -28,6 +28,8 @@ active_modules: ac_hlc_enabled: true ac_hlc_use_5percent: false ac_enforce_hlc: false + external_ready_to_start_charging: true + request_zero_power_in_idle: true connections: bsp: - module_id: yeti_driver_1 @@ -53,6 +55,8 @@ active_modules: ac_hlc_enabled: false ac_hlc_use_5percent: false ac_enforce_hlc: false + external_ready_to_start_charging: true + request_zero_power_in_idle: true connections: bsp: - module_id: yeti_driver_2 @@ -157,6 +161,13 @@ active_modules: security: - module_id: evse_security implementation_id: main + evse_energy_sink: + - module_id: grid_connection_point + implementation_id: external_limits + - module_id: evse_manager_1_ocpp_sink + implementation_id: external_limits + - module_id: evse_manager_2_ocpp_sink + implementation_id: external_limits evse_security: module: EvseSecurity config_module: @@ -169,30 +180,84 @@ active_modules: energy_trunk: - module_id: grid_connection_point implementation_id: energy_grid - grid_connection_point: + evse_manager_1_ocpp_sink: module: EnergyNode + evse: 1 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 + evse_manager_2_ocpp_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: - module_id: evse_manager_2 implementation_id: energy_grid + evse_manager_1_api_sink: + evse: 1 + module: EnergyNode + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_1_ocpp_sink + implementation_id: energy_grid powermeter: - module_id: yeti_driver_1 implementation_id: powermeter + evse_manager_2_api_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_2_ocpp_sink + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_2 + implementation_id: powermeter + grid_connection_point: + module: EnergyNode + evse: 0 + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1_api_sink + implementation_id: energy_grid + - module_id: evse_manager_2_api_sink + implementation_id: energy_grid api: module: API connections: evse_manager: - module_id: evse_manager_1 implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + ocpp: + - module_id: ocpp + implementation_id: ocpp_generic error_history: - module_id: error_history implementation_id: error_history + evse_energy_sink: + - module_id: evse_manager_1_api_sink + implementation_id: external_limits + - module_id: evse_manager_2_api_sink + implementation_id: external_limits error_history: module: ErrorHistory config_implementation: diff --git a/config/config-sil-ocpp.yaml b/config/config-sil-ocpp.yaml index 9c1636286..24426ffe7 100644 --- a/config/config-sil-ocpp.yaml +++ b/config/config-sil-ocpp.yaml @@ -161,12 +161,12 @@ active_modules: display_message: - module_id: display_message implementation_id: display_message - evse_manager_energy_sink: + evse_energy_sink: - module_id: grid_connection_point implementation_id: external_limits - - module_id: evse_manager_1_sink + - module_id: evse_manager_1_ocpp_sink implementation_id: external_limits - - module_id: evse_manager_2_sink + - module_id: evse_manager_2_ocpp_sink implementation_id: external_limits display_message: module: TerminalCostAndPriceMessage @@ -181,15 +181,14 @@ 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 - evse_manager_1_sink: + evse_manager_1_ocpp_sink: module: EnergyNode + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -197,32 +196,54 @@ active_modules: energy_consumer: - module_id: evse_manager_1 implementation_id: energy_grid + evse_manager_2_ocpp_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_2 + implementation_id: energy_grid + evse_manager_1_api_sink: + evse: 1 + module: EnergyNode + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_1_ocpp_sink + implementation_id: energy_grid powermeter: - module_id: yeti_driver_1 implementation_id: powermeter - evse_manager_2_sink: + evse_manager_2_api_sink: module: EnergyNode + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 connections: energy_consumer: - - module_id: evse_manager_2 + - module_id: evse_manager_2_ocpp_sink implementation_id: energy_grid powermeter: - module_id: yeti_driver_2 implementation_id: powermeter grid_connection_point: module: EnergyNode + evse: 0 config_module: fuse_limit_A: 40.0 phase_count: 3 connections: price_information: [] energy_consumer: - - module_id: evse_manager_1_sink + - module_id: evse_manager_1_api_sink implementation_id: energy_grid - - module_id: evse_manager_2_sink + - module_id: evse_manager_2_api_sink implementation_id: energy_grid api: module: API @@ -230,12 +251,19 @@ active_modules: evse_manager: - module_id: evse_manager_1 implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse ocpp: - module_id: ocpp implementation_id: ocpp_generic error_history: - module_id: error_history implementation_id: error_history + evse_energy_sink: + - module_id: evse_manager_1_api_sink + implementation_id: external_limits + - module_id: evse_manager_2_api_sink + implementation_id: external_limits error_history: module: ErrorHistory config_implementation: diff --git a/config/config-sil-ocpp201-pnc.yaml b/config/config-sil-ocpp201-pnc.yaml index 834e353bf..315cdcb5b 100644 --- a/config/config-sil-ocpp201-pnc.yaml +++ b/config/config-sil-ocpp201-pnc.yaml @@ -128,6 +128,13 @@ active_modules: security: - module_id: evse_security implementation_id: main + evse_energy_sink: + - module_id: grid_connection_point + implementation_id: external_limits + - module_id: evse_manager_1_ocpp_sink + implementation_id: external_limits + - module_id: evse_manager_2_ocpp_sink + implementation_id: external_limits evse_security: module: EvseSecurity config_module: @@ -163,30 +170,84 @@ active_modules: energy_trunk: - module_id: grid_connection_point implementation_id: energy_grid - grid_connection_point: + evse_manager_1_ocpp_sink: module: EnergyNode + evse: 1 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 + evse_manager_2_ocpp_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: - module_id: evse_manager_2 implementation_id: energy_grid + evse_manager_1_api_sink: + evse: 1 + module: EnergyNode + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_1_ocpp_sink + implementation_id: energy_grid powermeter: - module_id: yeti_driver_1 implementation_id: powermeter + evse_manager_2_api_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_2_ocpp_sink + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_2 + implementation_id: powermeter + grid_connection_point: + module: EnergyNode + evse: 0 + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1_api_sink + implementation_id: energy_grid + - module_id: evse_manager_2_api_sink + implementation_id: energy_grid api: module: API connections: evse_manager: - module_id: evse_manager_1 implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + ocpp: + - module_id: ocpp + implementation_id: ocpp_generic error_history: - module_id: error_history implementation_id: error_history + evse_energy_sink: + - module_id: evse_manager_1_api_sink + implementation_id: external_limits + - module_id: evse_manager_2_api_sink + implementation_id: external_limits error_history: module: ErrorHistory config_implementation: diff --git a/config/config-sil-ocpp201.yaml b/config/config-sil-ocpp201.yaml index 93ba79bb1..8c6a15868 100644 --- a/config/config-sil-ocpp201.yaml +++ b/config/config-sil-ocpp201.yaml @@ -127,9 +127,13 @@ active_modules: security: - module_id: evse_security implementation_id: main - connector_zero_sink: + evse_energy_sink: - module_id: grid_connection_point implementation_id: external_limits + - module_id: evse_manager_1_ocpp_sink + implementation_id: external_limits + - module_id: evse_manager_2_ocpp_sink + implementation_id: external_limits persistent_store: module: PersistentStore evse_security: @@ -163,30 +167,84 @@ active_modules: energy_trunk: - module_id: grid_connection_point implementation_id: energy_grid - grid_connection_point: + evse_manager_1_ocpp_sink: module: EnergyNode + evse: 1 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 + evse_manager_2_ocpp_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: - module_id: evse_manager_2 implementation_id: energy_grid + evse_manager_1_api_sink: + evse: 1 + module: EnergyNode + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_1_ocpp_sink + implementation_id: energy_grid powermeter: - module_id: yeti_driver_1 implementation_id: powermeter + evse_manager_2_api_sink: + module: EnergyNode + evse: 2 + config_module: + fuse_limit_A: 32.0 + phase_count: 3 + connections: + energy_consumer: + - module_id: evse_manager_2_ocpp_sink + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_2 + implementation_id: powermeter + grid_connection_point: + module: EnergyNode + evse: 0 + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1_api_sink + implementation_id: energy_grid + - module_id: evse_manager_2_api_sink + implementation_id: energy_grid api: module: API connections: evse_manager: - module_id: evse_manager_1 implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + ocpp: + - module_id: ocpp + implementation_id: ocpp_generic error_history: - module_id: error_history implementation_id: error_history + evse_energy_sink: + - module_id: evse_manager_1_api_sink + implementation_id: external_limits + - module_id: evse_manager_2_api_sink + implementation_id: external_limits error_history: module: ErrorHistory config_implementation: diff --git a/modules/API/API.cpp b/modules/API/API.cpp index 65eee0b82..6b6e4c99f 100644 --- a/modules/API/API.cpp +++ b/modules/API/API.cpp @@ -265,6 +265,17 @@ SessionInfo::operator std::string() { void API::init() { invoke_init(*p_main); + + // ensure all evse_energy_sink(s) that are connected have an evse id mapping + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to and evse."); + } + } + this->limit_decimal_places = std::make_unique(this->config); std::vector connectors; std::string var_connectors = this->api_base + "connectors"; @@ -489,37 +500,40 @@ void API::init() { std::string cmd_set_limit = cmd_base + "set_limit_amps"; - const auto& evse_energy_sink = this->r_evse_manager_energy_sink.at(evse_id); - - this->mqtt.subscribe(cmd_set_limit, [&evse_manager_check = this->evse_manager_check, - &evse_energy_sink = evse_energy_sink, - evse_id](const std::string& data) { - try { - const auto external_limits = get_external_limits(data, false); - evse_manager_check.wait_ready(); - evse_energy_sink->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."; - } - }); + if (this->is_evse_sink_configured(evse_id)) { + auto& evse_energy_sink = this->get_evse_sink_by_evse_id(evse_id); - std::string cmd_set_limit_watts = cmd_base + "set_limit_watts"; - - this->mqtt.subscribe(cmd_set_limit_watts, [&evse_manager_check = this->evse_manager_check, - &evse_energy_sink = evse_energy_sink, - evse_id](const std::string& data) { - try { - const auto external_limits = get_external_limits(data, true); - evse_manager_check.wait_ready(); - evse_energy_sink->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, [&evse_manager_check = this->evse_manager_check, + &evse_energy_sink = evse_energy_sink](const std::string& data) { + try { + const auto external_limits = get_external_limits(data, false); + evse_manager_check.wait_ready(); + evse_energy_sink.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."; + } + }); + + std::string cmd_set_limit_watts = cmd_base + "set_limit_watts"; + + this->mqtt.subscribe(cmd_set_limit_watts, [&evse_manager_check = this->evse_manager_check, + &evse_energy_sink = evse_energy_sink](const std::string& data) { + try { + const auto external_limits = get_external_limits(data, true); + evse_manager_check.wait_ready(); + evse_energy_sink.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."; + } + }); + } else { + EVLOG_warning << "No evse energy sink configured for evse_id: " << evse_id + << ". API module does therefore not allow control of amps or power limits for this EVSE"; + } std::string cmd_force_unlock = cmd_base + "force_unlock"; this->mqtt.subscribe(cmd_force_unlock, [this, &evse](const std::string& data) { @@ -636,6 +650,36 @@ void API::init() { })); } +bool API::is_evse_sink_configured(const int32_t evse_id) { + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return true; + } + } + return false; +} + +external_energy_limitsIntf& API::get_evse_sink_by_evse_id(const int32_t evse_id) { + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return *evse_sink; + } + } + throw std::runtime_error("No mapping configured for evse"); +} + void API::ready() { invoke_ready(*p_main); diff --git a/modules/API/API.hpp b/modules/API/API.hpp index 88be2f696..9805ad4ab 100644 --- a/modules/API/API.hpp +++ b/modules/API/API.hpp @@ -159,7 +159,7 @@ class API : public Everest::ModuleBase { std::vector> r_evse_manager, std::vector> r_ocpp, std::vector> r_random_delay, std::vector> r_error_history, - std::vector> r_evse_manager_energy_sink, Conf& config) : + std::vector> r_evse_energy_sink, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), p_main(std::move(p_main)), @@ -167,7 +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)), + r_evse_energy_sink(std::move(r_evse_energy_sink)), config(config){}; Everest::MqttProvider& mqtt; @@ -176,7 +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 std::vector> r_evse_energy_sink; const Conf& config; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 @@ -212,6 +212,9 @@ class API : public Everest::ModuleBase { std::string ocpp_connection_status = "unknown"; const std::string api_base = "everest_api/"; + + bool is_evse_sink_configured(const int32_t evse_id); + external_energy_limitsIntf& get_evse_sink_by_evse_id(const int32_t evse_id); // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 }; diff --git a/modules/API/README.md b/modules/API/README.md index 24d6a2c42..afb4c211b 100644 --- a/modules/API/README.md +++ b/modules/API/README.md @@ -244,9 +244,13 @@ If any arbitrary payload is published to this topic charging will be paused by t ### everest_api/evse_manager/cmd/set_limit_amps Command to set an amps limit for this EVSE that will be considered within the EnergyManager. This does not automatically imply that this limit will be set by the EVSE because the energymanagement might consider limitations from other sources, too. The payload can be a positive or negative number. +📌 **Note:** You have to configure one evse_energy_sink connection per EVSE within the configuration file in order to use this topic! + ### everest_api/evse_manager/cmd/set_limit_watts Command to set a watt limit for this EVSE that will be considered within the EnergyManager. This does not automatically imply that this limit will be set by the EVSE because the energymanagement might consider limitations from other sources, too. The payload can be a positive or negative number. +📌 **Note:** You have to configure one evse_energy_sink connection per EVSE within the configuration file in order to use this topic! + ### everest_api/evse_manager/cmd/force_unlock Command to force unlock a connector on the EVSE. They payload should be a positive integer identifying the connector that should be unlocked. If the payload is empty or cannot be converted to an integer connector 1 is assumed. diff --git a/modules/API/manifest.yaml b/modules/API/manifest.yaml index 6e8ac30e3..ff5ad813d 100644 --- a/modules/API/manifest.yaml +++ b/modules/API/manifest.yaml @@ -189,7 +189,7 @@ requires: interface: error_history min_connections: 0 max_connections: 1 - evse_manager_energy_sink: + evse_energy_sink: interface: external_energy_limits min_connections: 0 max_connections: 128 diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index 40bd70104..d15c71858 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -77,6 +77,12 @@ void OCPP::set_external_limits(const std::mapis_evse_sink_configured(connector_id)) { + EVLOG_warning << "Can not apply external limits! No evse energy sink configured for evse_id: " << connector_id; + continue; + } + types::energy::ExternalLimits limits; std::vector schedule_import; for (const auto period : schedule.chargingSchedulePeriod) { @@ -99,23 +105,39 @@ void OCPP::set_external_limits(const std::mapget_evse_sink_by_evse_id(connector_id); + evse_sink.call_set_external_limits(limits); + } +} - if (connector_id == 0) { - if (!this->r_evse_manager_energy_sink.empty()) { - EVLOG_debug << "OCPP sets the following external limits for connector 0: \n" << limits; - this->r_evse_manager_energy_sink.first()->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_energy_sink.at(connector_id)->call_set_external_limits(limits); +bool OCPP::is_evse_sink_configured(const int32_t evse_id) { + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return true; } } + return false; +} + +external_energy_limitsIntf& OCPP::get_evse_sink_by_evse_id(const int32_t evse_id) { + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return *evse_sink; + } + } + throw std::runtime_error("No mapping configured for evse"); } void OCPP::publish_charging_schedules( @@ -350,6 +372,16 @@ void OCPP::init() { invoke_init(*p_auth_provider); invoke_init(*p_data_transfer); + // ensure all evse_energy_sink(s) that are connected have an evse id mapping + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to and evse."); + } + } + const auto error_handler = [this](const Everest::error::Error& error) { const auto evse_id = error.origin.mapping.has_value() ? error.origin.mapping.value().evse : 0; const auto error_info = get_error_info(error); diff --git a/modules/OCPP/OCPP.hpp b/modules/OCPP/OCPP.hpp index f11980354..dd5adcac2 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -76,7 +76,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_evse_manager_energy_sink, + std::vector> r_evse_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, @@ -90,7 +90,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_evse_manager_energy_sink(std::move(r_evse_manager_energy_sink)), + r_evse_energy_sink(std::move(r_evse_energy_sink)), r_reservation(std::move(r_reservation)), r_auth(std::move(r_auth)), r_system(std::move(r_system)), @@ -107,7 +107,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_evse_manager_energy_sink; + const std::vector> r_evse_energy_sink; const std::unique_ptr r_reservation; const std::unique_ptr r_auth; const std::unique_ptr r_system; @@ -141,6 +141,8 @@ class OCPP : public Everest::ModuleBase { std::filesystem::path ocpp_share_path; ocpp::v16::ChargingRateUnit composite_schedule_charging_rate_unit; void set_external_limits(const std::map& charging_schedules); + bool is_evse_sink_configured(const int32_t evse_id); + external_energy_limitsIntf& get_evse_sink_by_evse_id(const int32_t evse_id); void publish_charging_schedules(const std::map& charging_schedules); void init_evse_subscriptions(); // initialize subscriptions to all EVSEs provided by r_evse_manager diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index 58f8ef212..d3f271393 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -305,7 +305,7 @@ OCPP1.6 defines the SmartCharging feature profile to allow the CSMS to control o 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 implemented through the optional requirement(s) `evse_manager_energy_sink`(interface: `external_energy_limits`) +The integration of the composite schedules are implemented through the optional requirement(s) `evse_energy_sink`(interface: `external_energy_limits`) 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 `external_energy_limits` interface: One representing evse id 0 and diff --git a/modules/OCPP/manifest.yaml b/modules/OCPP/manifest.yaml index e54d97dfa..46fbbac5c 100644 --- a/modules/OCPP/manifest.yaml +++ b/modules/OCPP/manifest.yaml @@ -77,7 +77,7 @@ requires: interface: evse_manager min_connections: 1 max_connections: 128 - evse_manager_energy_sink: + evse_energy_sink: interface: external_energy_limits min_connections: 0 max_connections: 129 diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index b27ccae77..b7b756d71 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -275,6 +275,16 @@ void OCPP201::init() { invoke_init(*p_auth_provider); invoke_init(*p_auth_validator); + // ensure all evse_energy_sink(s) that are connected have an evse id mapping + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to and evse."); + } + } + this->init_evse_maps(); for (size_t evse_id = 1; evse_id <= this->r_evse_manager.size(); evse_id++) { @@ -663,7 +673,7 @@ 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 - // r_evse_manager_energy_sink + // r_evse_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); @@ -1201,6 +1211,12 @@ void OCPP201::set_external_limits(const std::vectoris_evse_sink_configured(evse_id)) { + EVLOG_warning << "Can not apply external limits! No evse energy sink configured for evse_id: " << evse_id; + continue; + } + types::energy::ExternalLimits limits; std::vector schedule_import; @@ -1222,24 +1238,39 @@ void OCPP201::set_external_limits(const std::vectorr_evse_manager_energy_sink.empty()) { - EVLOG_debug << "OCPP sets the following external limits for evse 0: \n" << 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_energy_sink.at(composite_schedule.evseId)->call_set_external_limits(limits); + auto& evse_sink = this->get_evse_sink_by_evse_id(evse_id); + evse_sink.call_set_external_limits(limits); + } +} + +bool OCPP201::is_evse_sink_configured(const int32_t evse_id) { + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return true; + } + } + return false; +} + +external_energy_limitsIntf& OCPP201::get_evse_sink_by_evse_id(const int32_t evse_id) { + for (const auto& evse_sink : this->r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return *evse_sink; } } + throw std::runtime_error("No mapping configured for evse"); } } // namespace module diff --git a/modules/OCPP201/OCPP201.hpp b/modules/OCPP201/OCPP201.hpp index 981283701..258da2655 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -60,7 +60,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_evse_manager_energy_sink, + std::vector> r_evse_energy_sink, std::vector> r_display_message, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), @@ -74,7 +74,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_evse_manager_energy_sink(std::move(r_evse_manager_energy_sink)), + r_evse_energy_sink(std::move(r_evse_energy_sink)), r_display_message(std::move(r_display_message)), config(config) { } @@ -90,7 +90,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_evse_manager_energy_sink; + const std::vector> r_evse_energy_sink; const std::vector> r_display_message; const Conf& config; @@ -157,8 +157,12 @@ class OCPP201 : public Everest::ModuleBase { /// \brief This function publishes the given \p composite_schedules via the ocpp interface void publish_charging_schedules(const std::vector& composite_schedules); - /// \brief This function applies given \p composite_schedules for each evse_manager and the connector_zero_sink + /// \brief This function applies given \p composite_schedules for each connected evse_energy_sink void set_external_limits(const std::vector& composite_schedules); + + bool is_evse_sink_configured(const int32_t evse_id); + external_energy_limitsIntf& get_evse_sink_by_evse_id(const int32_t evse_id); + // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 }; diff --git a/modules/OCPP201/manifest.yaml b/modules/OCPP201/manifest.yaml index 0ef5aa8bc..2293fe8d0 100644 --- a/modules/OCPP201/manifest.yaml +++ b/modules/OCPP201/manifest.yaml @@ -90,7 +90,7 @@ requires: interface: auth min_connections: 1 max_connections: 1 - evse_manager_energy_sink: + evse_energy_sink: interface: external_energy_limits min_connections: 0 max_connections: 128 From b40c35567c648b606262a506b5c662a4b1a55d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Mon, 14 Oct 2024 18:28:38 +0200 Subject: [PATCH 07/33] Revert changes accidentally added during rebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- CMakeLists.txt | 2 -- scripts/get_package_location.py | 54 --------------------------------- 2 files changed, 56 deletions(-) delete mode 100755 scripts/get_package_location.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 31ecaac1a..611097fab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,8 +65,6 @@ ev_setup_python_executable( PYTHON_VENV_PATH ${${PROJECT_NAME}_PYTHON_VENV_PATH} ) -set(EVEREST_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") - # Already include CTest here to allow it to find tests defined in subdirectories like lib and modules if(EVEREST_CORE_BUILD_TESTING) include(CTest) diff --git a/scripts/get_package_location.py b/scripts/get_package_location.py deleted file mode 100755 index 72d66041f..000000000 --- a/scripts/get_package_location.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env -S python3 -tt -# -*- coding: utf-8 -*- -# -# SPDX-License-Identifier: Apache-2.0 -# Copyright Pionix GmbH and Contributors to EVerest -# -""" -author: kai-uwe.hermann@pionix.de -""" - -import argparse -from importlib.metadata import Distribution, PackageNotFoundError -import json - - -__version__ = '0.1.0' - - -class EVerestParsingException(SystemExit): - pass - - -def main(): - parser = argparse.ArgumentParser( - description='EVerest get package location') - parser.add_argument('--version', action='version', - version=f'%(prog)s {__version__}') - parser.add_argument('--package-name', type=str, - help='Name of the package that the location should be retrieved from', default=None) - args = parser.parse_args() - - if not 'package_name' in args or not args.package_name: - raise EVerestParsingException('Please provide a valid package name') - - direct_url = "" - try: - direct_url = Distribution.from_name( - args.package_name).read_text('direct_url.json') - except PackageNotFoundError as e: - raise EVerestParsingException(e) - url = json.loads(direct_url).get('url', None) - - if url and url.startswith('file://'): - url = url.replace('file://', '') - print(f'{url}') - else: - raise EVerestParsingException() - - -if __name__ == '__main__': - try: - main() - except EVerestParsingException as e: - raise SystemExit(e) From 26842c7c229d354994abab935ec0cfd5b48f0603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Mon, 14 Oct 2024 18:28:55 +0200 Subject: [PATCH 08/33] Revised OCPP module documentation and added section for OCPP201 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- modules/OCPP/OCPP.cpp | 3 ++- modules/OCPP/doc.rst | 7 +++++-- modules/OCPP201/doc.rst | 24 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index d15c71858..43e6d1824 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -79,7 +79,8 @@ void OCPP::set_external_limits(const std::mapis_evse_sink_configured(connector_id)) { - EVLOG_warning << "Can not apply external limits! No evse energy sink configured for evse_id: " << connector_id; + EVLOG_warning << "Can not apply external limits! No evse energy sink configured for evse_id: " + << connector_id; continue; } diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index d3f271393..3b6a58363 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -309,8 +309,11 @@ The integration of the composite schedules are implemented through the optional 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 `external_energy_limits` 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). +two representing your actual EVSEs. + +📌 **Note:** You have to configure an evse mapping for each module connected via the evse_energy_sink connection. This allows the module to identify +which requirement to use when communication the limits for the EVSEs. For more information about the module mapping please see +`3-tier module mappings `_. This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves the composite schedules for all EVSEs (including evse id 0) and calls the `set_external_limits` command of the respective requirement that implements diff --git a/modules/OCPP201/doc.rst b/modules/OCPP201/doc.rst index 8d7df4918..361898a24 100644 --- a/modules/OCPP201/doc.rst +++ b/modules/OCPP201/doc.rst @@ -310,3 +310,27 @@ In addition to that, the charging station periodically updates the OCSP response The OCSP response is cached and can be used as part of the ISO15118 TLS handshake with EVs. The OCSP update is by default performed every seven days. The timestamp of the last update is stored persistently, so that this process is not necessarily performed at every start up. + +Energy Management and Smart Charging Integration +------------------------------------------------ + +OCPP2.0.1 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 OCPP2.0.1 specification. + +The integration of the composite schedules are implemented through the optional requirement(s) `evse_energy_sink`(interface: `external_energy_limits`) +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 `external_energy_limits` interface: One representing evse id 0 and +two representing your actual EVSEs. + +📌 **Note:** You have to configure an evse mapping for each module connected via the evse_energy_sink connection. This allows the module to identify +which requirement to use when communication the limits for the EVSEs. For more information about the module mapping please see +`3-tier module mappings `_. + +This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves +the composite schedules for all EVSEs (including evse id 0) and calls the `set_external_limits` command of the respective requirement that implements +the `external_energy_limits` interface. In addition, the config parameter `CompositeScheduleIntervalS` defines a periodic interval to retrieve +the composite schedule also in case no charging profiles have been changed. The configuration paramater `RequestCompositeScheduleDurationS` defines +the duration in seconds of the requested composite schedules starting now. The value configured for `RequestCompositeScheduleDurationS` shall be greater +than the value configured for `CompositeScheduleIntervalS` because otherwise time periods could be missed by the application. From 97286398b6ecb2166d90ad611231e9de92e42042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Tue, 15 Oct 2024 11:46:57 +0200 Subject: [PATCH 09/33] Removed catching out_of_range. Can't be thrown anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- modules/API/API.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/API/API.cpp b/modules/API/API.cpp index 6b6e4c99f..b6b204252 100644 --- a/modules/API/API.cpp +++ b/modules/API/API.cpp @@ -511,8 +511,6 @@ void API::init() { evse_energy_sink.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."; } }); @@ -526,8 +524,6 @@ void API::init() { evse_energy_sink.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."; } }); } else { From 1e93b9ec50488b698b43285a27d26e65a961d3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Tue, 15 Oct 2024 12:00:52 +0200 Subject: [PATCH 10/33] revert changes within EnergyManager that accidentally got in while rebasing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- modules/EnergyManager/Market.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/EnergyManager/Market.cpp b/modules/EnergyManager/Market.cpp index dc488041d..439b39070 100644 --- a/modules/EnergyManager/Market.cpp +++ b/modules/EnergyManager/Market.cpp @@ -245,7 +245,7 @@ Market::Market(types::energy::EnergyFlowRequest& _energy_flow_request, const flo // Recursion: create one Market for each child for (auto& flow_child : _energy_flow_request.children) { - _children.emplace_back(std::make_unique(flow_child, _nominal_ac_voltage, this)); + _children.emplace_back(flow_child, _nominal_ac_voltage, this); } } @@ -267,7 +267,7 @@ void Market::get_list_of_evses(std::vector& list) { } for (auto& child : _children) { - child->get_list_of_evses(list); + child.get_list_of_evses(list); } } @@ -278,7 +278,7 @@ std::vector Market::get_list_of_evses() { } for (auto& child : _children) { - child->get_list_of_evses(list); + child.get_list_of_evses(list); } return list; } From 50f41e3bdc7bd65c77ec8da303bdcffbea86d147 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Fri, 4 Oct 2024 18:19:03 +0200 Subject: [PATCH 11/33] Install ev-cli locally and depend on templates files for generation Signed-off-by: Kai-Uwe Hermann --- CMakeLists.txt | 2 ++ scripts/get_package_location.py | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100755 scripts/get_package_location.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 611097fab..31ecaac1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,8 @@ ev_setup_python_executable( PYTHON_VENV_PATH ${${PROJECT_NAME}_PYTHON_VENV_PATH} ) +set(EVEREST_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") + # Already include CTest here to allow it to find tests defined in subdirectories like lib and modules if(EVEREST_CORE_BUILD_TESTING) include(CTest) diff --git a/scripts/get_package_location.py b/scripts/get_package_location.py new file mode 100755 index 000000000..72d66041f --- /dev/null +++ b/scripts/get_package_location.py @@ -0,0 +1,54 @@ +#!/usr/bin/env -S python3 -tt +# -*- coding: utf-8 -*- +# +# SPDX-License-Identifier: Apache-2.0 +# Copyright Pionix GmbH and Contributors to EVerest +# +""" +author: kai-uwe.hermann@pionix.de +""" + +import argparse +from importlib.metadata import Distribution, PackageNotFoundError +import json + + +__version__ = '0.1.0' + + +class EVerestParsingException(SystemExit): + pass + + +def main(): + parser = argparse.ArgumentParser( + description='EVerest get package location') + parser.add_argument('--version', action='version', + version=f'%(prog)s {__version__}') + parser.add_argument('--package-name', type=str, + help='Name of the package that the location should be retrieved from', default=None) + args = parser.parse_args() + + if not 'package_name' in args or not args.package_name: + raise EVerestParsingException('Please provide a valid package name') + + direct_url = "" + try: + direct_url = Distribution.from_name( + args.package_name).read_text('direct_url.json') + except PackageNotFoundError as e: + raise EVerestParsingException(e) + url = json.loads(direct_url).get('url', None) + + if url and url.startswith('file://'): + url = url.replace('file://', '') + print(f'{url}') + else: + raise EVerestParsingException() + + +if __name__ == '__main__': + try: + main() + except EVerestParsingException as e: + raise SystemExit(e) From b50efc8bacff787b7658aadf085cffcf70602b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Wed, 30 Oct 2024 10:56:21 +0100 Subject: [PATCH 12/33] Revert some changes to cmake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- CMakeLists.txt | 2 -- scripts/get_package_location.py | 54 --------------------------------- 2 files changed, 56 deletions(-) delete mode 100755 scripts/get_package_location.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 31ecaac1a..611097fab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,8 +65,6 @@ ev_setup_python_executable( PYTHON_VENV_PATH ${${PROJECT_NAME}_PYTHON_VENV_PATH} ) -set(EVEREST_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") - # Already include CTest here to allow it to find tests defined in subdirectories like lib and modules if(EVEREST_CORE_BUILD_TESTING) include(CTest) diff --git a/scripts/get_package_location.py b/scripts/get_package_location.py deleted file mode 100755 index 72d66041f..000000000 --- a/scripts/get_package_location.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env -S python3 -tt -# -*- coding: utf-8 -*- -# -# SPDX-License-Identifier: Apache-2.0 -# Copyright Pionix GmbH and Contributors to EVerest -# -""" -author: kai-uwe.hermann@pionix.de -""" - -import argparse -from importlib.metadata import Distribution, PackageNotFoundError -import json - - -__version__ = '0.1.0' - - -class EVerestParsingException(SystemExit): - pass - - -def main(): - parser = argparse.ArgumentParser( - description='EVerest get package location') - parser.add_argument('--version', action='version', - version=f'%(prog)s {__version__}') - parser.add_argument('--package-name', type=str, - help='Name of the package that the location should be retrieved from', default=None) - args = parser.parse_args() - - if not 'package_name' in args or not args.package_name: - raise EVerestParsingException('Please provide a valid package name') - - direct_url = "" - try: - direct_url = Distribution.from_name( - args.package_name).read_text('direct_url.json') - except PackageNotFoundError as e: - raise EVerestParsingException(e) - url = json.loads(direct_url).get('url', None) - - if url and url.startswith('file://'): - url = url.replace('file://', '') - print(f'{url}') - else: - raise EVerestParsingException() - - -if __name__ == '__main__': - try: - main() - except EVerestParsingException as e: - raise SystemExit(e) From 6d061cc7533ae00deadd9534e83a4214e3272d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Mon, 4 Nov 2024 15:41:27 +0100 Subject: [PATCH 13/33] Updated config module mappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- config/config-sil-energy-management.yaml | 14 ++++++-- config/config-sil-ocpp-custom-extension.yaml | 38 +++++++++++++++----- config/config-sil-ocpp-pnc.yaml | 36 ++++++++++++++----- config/config-sil-ocpp.yaml | 36 ++++++++++++++----- config/config-sil-ocpp201-pnc.yaml | 36 ++++++++++++++----- config/config-sil-ocpp201.yaml | 36 ++++++++++++++----- 6 files changed, 149 insertions(+), 47 deletions(-) diff --git a/config/config-sil-energy-management.yaml b/config/config-sil-energy-management.yaml index 17ef597c5..f8bc6de4c 100644 --- a/config/config-sil-energy-management.yaml +++ b/config/config-sil-energy-management.yaml @@ -15,6 +15,9 @@ active_modules: supported_ISO15118_2: true evse_manager_1: module: EvseManager + mapping: + module: + evse: 1 config_module: connector_id: 1 evse_id: DE*PNX*E12345*1 @@ -43,6 +46,9 @@ active_modules: implementation_id: charger evse_manager_2: module: EvseManager + mapping: + module: + evse: 2 config_module: connector_id: 2 evse_id: DE*PNX*E12345*2 @@ -168,7 +174,9 @@ active_modules: implementation_id: powermeter evse_manager_1_sink: module: EnergyNode - evse: 1 + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -178,7 +186,9 @@ active_modules: implementation_id: energy_grid evse_manager_2_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 diff --git a/config/config-sil-ocpp-custom-extension.yaml b/config/config-sil-ocpp-custom-extension.yaml index 258a18992..bd18e3ab8 100644 --- a/config/config-sil-ocpp-custom-extension.yaml +++ b/config/config-sil-ocpp-custom-extension.yaml @@ -15,7 +15,9 @@ active_modules: supported_ISO15118_2: true evse_manager_1: module: EvseManager - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 evse_id: "1" @@ -25,6 +27,7 @@ active_modules: ac_hlc_enabled: false ac_hlc_use_5percent: false ac_enforce_hlc: false + external_ready_to_start_charging: true connections: bsp: - module_id: yeti_driver_1 @@ -40,7 +43,9 @@ active_modules: implementation_id: charger evse_manager_2: module: EvseManager - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 evse_id: "2" @@ -50,6 +55,7 @@ active_modules: ac_hlc_enabled: false ac_hlc_use_5percent: false ac_enforce_hlc: false + external_ready_to_start_charging: true connections: bsp: - module_id: yeti_driver_2 @@ -65,12 +71,16 @@ active_modules: implementation_id: charger yeti_driver_1: module: JsYetiSimulator - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 yeti_driver_2: module: JsYetiSimulator - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 slac: @@ -184,7 +194,9 @@ active_modules: implementation_id: energy_grid evse_manager_1_ocpp_sink: module: EnergyNode - evse: 1 + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -194,7 +206,9 @@ active_modules: implementation_id: energy_grid evse_manager_2_ocpp_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -203,8 +217,10 @@ active_modules: - module_id: evse_manager_2 implementation_id: energy_grid evse_manager_1_api_sink: - evse: 1 module: EnergyNode + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -217,7 +233,9 @@ active_modules: implementation_id: powermeter evse_manager_2_api_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -230,7 +248,9 @@ active_modules: implementation_id: powermeter grid_connection_point: module: EnergyNode - evse: 0 + mapping: + module: + evse: 0 config_module: fuse_limit_A: 40.0 phase_count: 3 diff --git a/config/config-sil-ocpp-pnc.yaml b/config/config-sil-ocpp-pnc.yaml index ad05e2c63..e5b092279 100644 --- a/config/config-sil-ocpp-pnc.yaml +++ b/config/config-sil-ocpp-pnc.yaml @@ -18,7 +18,9 @@ active_modules: is_cert_install_needed: true evse_manager_1: module: EvseManager - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 evse_id: "DE*PNX*00001" @@ -45,7 +47,9 @@ active_modules: implementation_id: charger evse_manager_2: module: EvseManager - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 evse_id: "2" @@ -72,12 +76,16 @@ active_modules: implementation_id: charger yeti_driver_1: module: JsYetiSimulator - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 yeti_driver_2: module: JsYetiSimulator - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 slac: @@ -182,7 +190,9 @@ active_modules: implementation_id: energy_grid evse_manager_1_ocpp_sink: module: EnergyNode - evse: 1 + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -192,7 +202,9 @@ active_modules: implementation_id: energy_grid evse_manager_2_ocpp_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -201,8 +213,10 @@ active_modules: - module_id: evse_manager_2 implementation_id: energy_grid evse_manager_1_api_sink: - evse: 1 module: EnergyNode + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -215,7 +229,9 @@ active_modules: implementation_id: powermeter evse_manager_2_api_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -228,7 +244,9 @@ active_modules: implementation_id: powermeter grid_connection_point: module: EnergyNode - evse: 0 + mapping: + module: + evse: 0 config_module: fuse_limit_A: 40.0 phase_count: 3 diff --git a/config/config-sil-ocpp.yaml b/config/config-sil-ocpp.yaml index 24426ffe7..d279bcb45 100644 --- a/config/config-sil-ocpp.yaml +++ b/config/config-sil-ocpp.yaml @@ -16,7 +16,9 @@ active_modules: persistent_store: module: PersistentStore evse_manager_1: - evse: 1 + mapping: + module: + evse: 1 module: EvseManager config_module: connector_id: 1 @@ -47,7 +49,9 @@ active_modules: implementation_id: main evse_manager_2: module: EvseManager - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 evse_id: "2" @@ -73,13 +77,17 @@ active_modules: - module_id: iso15118_charger implementation_id: charger yeti_driver_1: - evse: 1 module: JsYetiSimulator + mapping: + module: + evse: 1 config_module: connector_id: 1 yeti_driver_2: - evse: 2 module: JsYetiSimulator + mapping: + module: + evse: 2 config_module: connector_id: 2 slac: @@ -188,7 +196,9 @@ active_modules: implementation_id: energy_grid evse_manager_1_ocpp_sink: module: EnergyNode - evse: 1 + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -198,7 +208,9 @@ active_modules: implementation_id: energy_grid evse_manager_2_ocpp_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -207,8 +219,10 @@ active_modules: - module_id: evse_manager_2 implementation_id: energy_grid evse_manager_1_api_sink: - evse: 1 module: EnergyNode + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -221,7 +235,9 @@ active_modules: implementation_id: powermeter evse_manager_2_api_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -234,7 +250,9 @@ active_modules: implementation_id: powermeter grid_connection_point: module: EnergyNode - evse: 0 + mapping: + module: + evse: 0 config_module: fuse_limit_A: 40.0 phase_count: 3 diff --git a/config/config-sil-ocpp201-pnc.yaml b/config/config-sil-ocpp201-pnc.yaml index 315cdcb5b..f3f8ac76a 100644 --- a/config/config-sil-ocpp201-pnc.yaml +++ b/config/config-sil-ocpp201-pnc.yaml @@ -18,7 +18,9 @@ active_modules: is_cert_install_needed: true evse_manager_1: module: EvseManager - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 evse_id: "DE*PNX*00001" @@ -43,7 +45,9 @@ active_modules: implementation_id: charger evse_manager_2: module: EvseManager - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 evse_id: "2" @@ -68,12 +72,16 @@ active_modules: implementation_id: charger yeti_driver_1: module: JsYetiSimulator - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 yeti_driver_2: module: JsYetiSimulator - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 slac: @@ -172,7 +180,9 @@ active_modules: implementation_id: energy_grid evse_manager_1_ocpp_sink: module: EnergyNode - evse: 1 + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -182,7 +192,9 @@ active_modules: implementation_id: energy_grid evse_manager_2_ocpp_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -191,8 +203,10 @@ active_modules: - module_id: evse_manager_2 implementation_id: energy_grid evse_manager_1_api_sink: - evse: 1 module: EnergyNode + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -205,7 +219,9 @@ active_modules: implementation_id: powermeter evse_manager_2_api_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -218,7 +234,9 @@ active_modules: implementation_id: powermeter grid_connection_point: module: EnergyNode - evse: 0 + mapping: + module: + evse: 0 config_module: fuse_limit_A: 40.0 phase_count: 3 diff --git a/config/config-sil-ocpp201.yaml b/config/config-sil-ocpp201.yaml index 8c6a15868..2ae3bcfdf 100644 --- a/config/config-sil-ocpp201.yaml +++ b/config/config-sil-ocpp201.yaml @@ -15,7 +15,9 @@ active_modules: supported_ISO15118_2: true evse_manager_1: module: EvseManager - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 evse_id: "1" @@ -41,7 +43,9 @@ active_modules: implementation_id: charger evse_manager_2: module: EvseManager - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 evse_id: "2" @@ -67,12 +71,16 @@ active_modules: implementation_id: charger yeti_driver_1: module: JsYetiSimulator - evse: 1 + mapping: + module: + evse: 1 config_module: connector_id: 1 yeti_driver_2: module: JsYetiSimulator - evse: 2 + mapping: + module: + evse: 2 config_module: connector_id: 2 slac: @@ -169,7 +177,9 @@ active_modules: implementation_id: energy_grid evse_manager_1_ocpp_sink: module: EnergyNode - evse: 1 + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -179,7 +189,9 @@ active_modules: implementation_id: energy_grid evse_manager_2_ocpp_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -188,8 +200,10 @@ active_modules: - module_id: evse_manager_2 implementation_id: energy_grid evse_manager_1_api_sink: - evse: 1 module: EnergyNode + mapping: + module: + evse: 1 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -202,7 +216,9 @@ active_modules: implementation_id: powermeter evse_manager_2_api_sink: module: EnergyNode - evse: 2 + mapping: + module: + evse: 2 config_module: fuse_limit_A: 32.0 phase_count: 3 @@ -215,7 +231,9 @@ active_modules: implementation_id: powermeter grid_connection_point: module: EnergyNode - evse: 0 + mapping: + module: + evse: 0 config_module: fuse_limit_A: 40.0 phase_count: 3 From a55757d98e7b16d83e9eee12b506bb22677464ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:10:16 +0100 Subject: [PATCH 14/33] Update modules/OCPP/doc.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: barsnick Signed-off-by: Piet Gömpel <37657534+Pietfried@users.noreply.github.com> --- modules/OCPP/doc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index 3b6a58363..213a22827 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -302,7 +302,7 @@ 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 +This module integrates the composite schedule(s) within EVerest's 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 implemented through the optional requirement(s) `evse_energy_sink`(interface: `external_energy_limits`) From d0e3b75026955389ab6281050eaa5a439c70436d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:10:25 +0100 Subject: [PATCH 15/33] Update modules/OCPP/doc.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: barsnick Signed-off-by: Piet Gömpel <37657534+Pietfried@users.noreply.github.com> --- modules/OCPP/doc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index 213a22827..19893b26a 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -305,7 +305,7 @@ OCPP1.6 defines the SmartCharging feature profile to allow the CSMS to control o This module integrates the composite schedule(s) within EVerest's 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 implemented through the optional requirement(s) `evse_energy_sink`(interface: `external_energy_limits`) +The integration of the composite schedules is implemented through the optional requirement(s) `evse_energy_sink` (interface: `external_energy_limits`) 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 `external_energy_limits` interface: One representing evse id 0 and From adfe3fbd7ebad95ee471676df6823d873cbb527d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:10:39 +0100 Subject: [PATCH 16/33] Update modules/OCPP/doc.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: barsnick Signed-off-by: Piet Gömpel <37657534+Pietfried@users.noreply.github.com> --- modules/OCPP/doc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index 19893b26a..87028c3fd 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -312,7 +312,7 @@ has two EVSEs you need to connect three modules that implement the `external_ene two representing your actual EVSEs. 📌 **Note:** You have to configure an evse mapping for each module connected via the evse_energy_sink connection. This allows the module to identify -which requirement to use when communication the limits for the EVSEs. For more information about the module mapping please see +which requirement to use when communicating the limits for the EVSEs. For more information about the module mapping please see `3-tier module mappings `_. This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves From 21f2abd14ea40178c9f58855f553ad450b612119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:10:48 +0100 Subject: [PATCH 17/33] Update modules/OCPP/doc.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: barsnick Signed-off-by: Piet Gömpel <37657534+Pietfried@users.noreply.github.com> --- modules/OCPP/doc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index 87028c3fd..4611bcdc3 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -318,7 +318,7 @@ which requirement to use when communicating the limits for the EVSEs. For more i This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves the composite schedules for all EVSEs (including evse id 0) and calls the `set_external_limits` command of the respective requirement that implements the `external_energy_limits` interface. In addition, the config parameter `PublishChargingScheduleIntervalS` defines a periodic interval to retrieve -the composite schedule also in case no charging profiles have been changed. The configuration paramater `PublishChargingScheduleDurationS` defines +the composite schedule also in case no charging profiles have been changed. The configuration parameter `PublishChargingScheduleDurationS` defines the duration in seconds of the requested composite schedules starting now. The value configured for `PublishChargingScheduleDurationS` shall be greater than the value configured for `PublishChargingScheduleIntervalS` because otherwise time periods could be missed by the application. From b439ad4cd09d529ed80579bec754c9b8ae380b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:10:56 +0100 Subject: [PATCH 18/33] Update modules/OCPP201/doc.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: barsnick Signed-off-by: Piet Gömpel <37657534+Pietfried@users.noreply.github.com> --- modules/OCPP201/doc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP201/doc.rst b/modules/OCPP201/doc.rst index 361898a24..155802b7c 100644 --- a/modules/OCPP201/doc.rst +++ b/modules/OCPP201/doc.rst @@ -318,7 +318,7 @@ OCPP2.0.1 defines the SmartCharging feature profile to allow the CSMS to control 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 OCPP2.0.1 specification. -The integration of the composite schedules are implemented through the optional requirement(s) `evse_energy_sink`(interface: `external_energy_limits`) +The integration of the composite schedules is implemented through the optional requirement(s) `evse_energy_sink` (interface: `external_energy_limits`) 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 `external_energy_limits` interface: One representing evse id 0 and From e520998072ed0072b899ba8f0176aedb1ae97033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= <37657534+Pietfried@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:11:03 +0100 Subject: [PATCH 19/33] Update modules/OCPP201/doc.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: barsnick Signed-off-by: Piet Gömpel <37657534+Pietfried@users.noreply.github.com> --- modules/OCPP201/doc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP201/doc.rst b/modules/OCPP201/doc.rst index 155802b7c..2cd884c6f 100644 --- a/modules/OCPP201/doc.rst +++ b/modules/OCPP201/doc.rst @@ -331,6 +331,6 @@ which requirement to use when communication the limits for the EVSEs. For more i This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves the composite schedules for all EVSEs (including evse id 0) and calls the `set_external_limits` command of the respective requirement that implements the `external_energy_limits` interface. In addition, the config parameter `CompositeScheduleIntervalS` defines a periodic interval to retrieve -the composite schedule also in case no charging profiles have been changed. The configuration paramater `RequestCompositeScheduleDurationS` defines +the composite schedule also in case no charging profiles have been changed. The configuration parameter `RequestCompositeScheduleDurationS` defines the duration in seconds of the requested composite schedules starting now. The value configured for `RequestCompositeScheduleDurationS` shall be greater than the value configured for `CompositeScheduleIntervalS` because otherwise time periods could be missed by the application. From fedd0e00cb2375f47c3e333eb9c3553d5863a64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Tue, 5 Nov 2024 15:04:46 +0100 Subject: [PATCH 20/33] Addressed requested changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- cmake/ev-cli.cmake | 2 +- lib/staging/ocpp/CMakeLists.txt | 1 + modules/OCPP201/doc.rst | 4 ++-- modules/OCPP201/manifest.yaml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/ev-cli.cmake b/cmake/ev-cli.cmake index b0477c596..b75f38a42 100644 --- a/cmake/ev-cli.cmake +++ b/cmake/ev-cli.cmake @@ -98,4 +98,4 @@ function(set_ev_cli_template_properties) MODULE_TEMPLATES "${MODULE_TEMPLATES}" TYPES_TEMPLATES "${TYPES_TEMPLATES}" ) -endfunction() \ No newline at end of file +endfunction() diff --git a/lib/staging/ocpp/CMakeLists.txt b/lib/staging/ocpp/CMakeLists.txt index 70aa3ad41..591e0f234 100644 --- a/lib/staging/ocpp/CMakeLists.txt +++ b/lib/staging/ocpp/CMakeLists.txt @@ -58,3 +58,4 @@ target_link_libraries(ocpp_conversions everest::ocpp everest::framework ) + diff --git a/modules/OCPP201/doc.rst b/modules/OCPP201/doc.rst index 2cd884c6f..812026e71 100644 --- a/modules/OCPP201/doc.rst +++ b/modules/OCPP201/doc.rst @@ -315,7 +315,7 @@ Energy Management and Smart Charging Integration ------------------------------------------------ OCPP2.0.1 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 +This module integrates the composite schedule(s) within EVerest's energy management. For further information about smart charging and the composite schedule calculation please refer to the OCPP2.0.1 specification. The integration of the composite schedules is implemented through the optional requirement(s) `evse_energy_sink` (interface: `external_energy_limits`) @@ -325,7 +325,7 @@ has two EVSEs you need to connect three modules that implement the `external_ene two representing your actual EVSEs. 📌 **Note:** You have to configure an evse mapping for each module connected via the evse_energy_sink connection. This allows the module to identify -which requirement to use when communication the limits for the EVSEs. For more information about the module mapping please see +which requirement to use when communicating the limits for the EVSEs. For more information about the module mapping please see `3-tier module mappings `_. This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves diff --git a/modules/OCPP201/manifest.yaml b/modules/OCPP201/manifest.yaml index 2293fe8d0..6023fc249 100644 --- a/modules/OCPP201/manifest.yaml +++ b/modules/OCPP201/manifest.yaml @@ -93,7 +93,7 @@ requires: evse_energy_sink: interface: external_energy_limits min_connections: 0 - max_connections: 128 + max_connections: 129 display_message: interface: display_message min_connections: 0 From 1f8632679d56067c74bf14dbbdd29bc09b29a652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piet=20G=C3=B6mpel?= Date: Tue, 5 Nov 2024 15:05:22 +0100 Subject: [PATCH 21/33] Moved duplicated code to seperate library in lib/staging for accessing external_energy_limits reference by evse id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piet Gömpel --- lib/staging/CMakeLists.txt | 1 + .../external_energy_limits/CMakeLists.txt | 22 ++++++++++ .../external_energy_limits.cpp | 41 +++++++++++++++++++ .../external_energy_limits.hpp | 23 +++++++++++ modules/API/API.cpp | 36 ++-------------- modules/API/API.hpp | 3 -- modules/API/CMakeLists.txt | 1 + modules/OCPP/CMakeLists.txt | 1 + modules/OCPP/OCPP.cpp | 35 ++-------------- modules/OCPP/OCPP.hpp | 2 - modules/OCPP201/CMakeLists.txt | 1 + modules/OCPP201/OCPP201.cpp | 35 ++-------------- modules/OCPP201/OCPP201.hpp | 3 -- 13 files changed, 100 insertions(+), 104 deletions(-) create mode 100644 lib/staging/external_energy_limits/CMakeLists.txt create mode 100644 lib/staging/external_energy_limits/external_energy_limits.cpp create mode 100644 lib/staging/external_energy_limits/external_energy_limits.hpp diff --git a/lib/staging/CMakeLists.txt b/lib/staging/CMakeLists.txt index 75f6d0c89..0611d08ad 100644 --- a/lib/staging/CMakeLists.txt +++ b/lib/staging/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(can_dpm1000) +add_subdirectory(external_energy_limits) if(EVEREST_DEPENDENCY_ENABLED_LIBEVSE_SECURITY) add_subdirectory(evse_security) add_subdirectory(tls) diff --git a/lib/staging/external_energy_limits/CMakeLists.txt b/lib/staging/external_energy_limits/CMakeLists.txt new file mode 100644 index 000000000..cdf7f3fac --- /dev/null +++ b/lib/staging/external_energy_limits/CMakeLists.txt @@ -0,0 +1,22 @@ +# External Energy Limits + +add_library(external_energy_limits STATIC) +add_library(everest::external_energy_limits ALIAS external_energy_limits) + +target_sources(external_energy_limits + PRIVATE + external_energy_limits.cpp +) + +target_include_directories(external_energy_limits + PUBLIC + $ + "$" +) + +add_dependencies(external_energy_limits generate_cpp_files) + +target_link_libraries(external_energy_limits + PRIVATE + everest::framework +) \ No newline at end of file diff --git a/lib/staging/external_energy_limits/external_energy_limits.cpp b/lib/staging/external_energy_limits/external_energy_limits.cpp new file mode 100644 index 000000000..b16a0f756 --- /dev/null +++ b/lib/staging/external_energy_limits/external_energy_limits.cpp @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Pionix GmbH and Contributors to EVerest + +#include + +namespace external_energy_limits { + +bool is_evse_sink_configured(const std::vector>& r_evse_energy_sink, + const int32_t evse_id) { + for (const auto& evse_sink : r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return true; + } + } + return false; +} + +external_energy_limitsIntf& +get_evse_sink_by_evse_id(const std::vector>& r_evse_energy_sink, + const int32_t evse_id) { + for (const auto& evse_sink : r_evse_energy_sink) { + if (not evse_sink->get_mapping().has_value()) { + EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " + "r_evse_energy_sink with module_id: " + << evse_sink->module_id; + throw std::runtime_error("No mapping configured for evse_id: " + evse_id); + } + if (evse_sink->get_mapping().value().evse == evse_id) { + return *evse_sink; + } + } + throw std::runtime_error("No mapping configured for evse"); +} + +} // namespace external_energy_limits \ No newline at end of file diff --git a/lib/staging/external_energy_limits/external_energy_limits.hpp b/lib/staging/external_energy_limits/external_energy_limits.hpp new file mode 100644 index 000000000..73792d81a --- /dev/null +++ b/lib/staging/external_energy_limits/external_energy_limits.hpp @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Pionix GmbH and Contributors to EVerest + +#pragma once + +#include + +namespace external_energy_limits { + +/// \brief Checks if \p r_evse_energy_sink vector contains an element that has a mapping to the given \p evse_id +/// \param r_evse_energy_sink +/// \param evse_id +/// \return +bool is_evse_sink_configured(const std::vector>& r_evse_energy_sink, + const int32_t evse_id); + +/// \brief Returns the reference of external_energy_limitsIntf in \p r_evse_energy_sink that maps to the given \p +/// evse_id \param r_evse_energy_sink \param evse_id \return +external_energy_limitsIntf& +get_evse_sink_by_evse_id(const std::vector>& r_evse_energy_sink, + const int32_t evse_id); + +} // namespace external_energy_limits diff --git a/modules/API/API.cpp b/modules/API/API.cpp index b6b204252..4be0bc531 100644 --- a/modules/API/API.cpp +++ b/modules/API/API.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest #include "API.hpp" +#include #include #include @@ -500,8 +501,9 @@ void API::init() { std::string cmd_set_limit = cmd_base + "set_limit_amps"; - if (this->is_evse_sink_configured(evse_id)) { - auto& evse_energy_sink = this->get_evse_sink_by_evse_id(evse_id); + if (external_energy_limits::is_evse_sink_configured(this->r_evse_energy_sink, evse_id)) { + auto& evse_energy_sink = + external_energy_limits::get_evse_sink_by_evse_id(this->r_evse_energy_sink, evse_id); this->mqtt.subscribe(cmd_set_limit, [&evse_manager_check = this->evse_manager_check, &evse_energy_sink = evse_energy_sink](const std::string& data) { @@ -646,36 +648,6 @@ void API::init() { })); } -bool API::is_evse_sink_configured(const int32_t evse_id) { - for (const auto& evse_sink : this->r_evse_energy_sink) { - if (not evse_sink->get_mapping().has_value()) { - EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " - "r_evse_energy_sink with module_id: " - << evse_sink->module_id; - throw std::runtime_error("No mapping configured for evse_id: " + evse_id); - } - if (evse_sink->get_mapping().value().evse == evse_id) { - return true; - } - } - return false; -} - -external_energy_limitsIntf& API::get_evse_sink_by_evse_id(const int32_t evse_id) { - for (const auto& evse_sink : this->r_evse_energy_sink) { - if (not evse_sink->get_mapping().has_value()) { - EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " - "r_evse_energy_sink with module_id: " - << evse_sink->module_id; - throw std::runtime_error("No mapping configured for evse_id: " + evse_id); - } - if (evse_sink->get_mapping().value().evse == evse_id) { - return *evse_sink; - } - } - throw std::runtime_error("No mapping configured for evse"); -} - void API::ready() { invoke_ready(*p_main); diff --git a/modules/API/API.hpp b/modules/API/API.hpp index 9805ad4ab..d4ea8880d 100644 --- a/modules/API/API.hpp +++ b/modules/API/API.hpp @@ -212,9 +212,6 @@ class API : public Everest::ModuleBase { std::string ocpp_connection_status = "unknown"; const std::string api_base = "everest_api/"; - - bool is_evse_sink_configured(const int32_t evse_id); - external_energy_limitsIntf& get_evse_sink_by_evse_id(const int32_t evse_id); // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 }; diff --git a/modules/API/CMakeLists.txt b/modules/API/CMakeLists.txt index 6f0333fb6..d1da6d21d 100644 --- a/modules/API/CMakeLists.txt +++ b/modules/API/CMakeLists.txt @@ -12,6 +12,7 @@ ev_setup_cpp_module() target_link_libraries(${MODULE_NAME} PRIVATE ryml::ryml + everest::external_energy_limits ) target_sources(${MODULE_NAME} PRIVATE diff --git a/modules/OCPP/CMakeLists.txt b/modules/OCPP/CMakeLists.txt index 6b7b946ae..86f4fdae7 100644 --- a/modules/OCPP/CMakeLists.txt +++ b/modules/OCPP/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries(${MODULE_NAME} everest::ocpp everest::ocpp_evse_security everest::ocpp_conversions + everest::external_energy_limits ) target_compile_options(${MODULE_NAME} diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index 43e6d1824..6998e590d 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace module { @@ -78,7 +79,7 @@ void OCPP::set_external_limits(const std::mapis_evse_sink_configured(connector_id)) { + if (not external_energy_limits::is_evse_sink_configured(this->r_evse_energy_sink, connector_id)) { EVLOG_warning << "Can not apply external limits! No evse energy sink configured for evse_id: " << connector_id; continue; @@ -106,41 +107,11 @@ void OCPP::set_external_limits(const std::mapget_evse_sink_by_evse_id(connector_id); + auto& evse_sink = external_energy_limits::get_evse_sink_by_evse_id(this->r_evse_energy_sink, connector_id); evse_sink.call_set_external_limits(limits); } } -bool OCPP::is_evse_sink_configured(const int32_t evse_id) { - for (const auto& evse_sink : this->r_evse_energy_sink) { - if (not evse_sink->get_mapping().has_value()) { - EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " - "r_evse_energy_sink with module_id: " - << evse_sink->module_id; - throw std::runtime_error("No mapping configured for evse_id: " + evse_id); - } - if (evse_sink->get_mapping().value().evse == evse_id) { - return true; - } - } - return false; -} - -external_energy_limitsIntf& OCPP::get_evse_sink_by_evse_id(const int32_t evse_id) { - for (const auto& evse_sink : this->r_evse_energy_sink) { - if (not evse_sink->get_mapping().has_value()) { - EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " - "r_evse_energy_sink with module_id: " - << evse_sink->module_id; - throw std::runtime_error("No mapping configured for evse_id: " + evse_id); - } - if (evse_sink->get_mapping().value().evse == evse_id) { - return *evse_sink; - } - } - throw std::runtime_error("No mapping configured for evse"); -} - void OCPP::publish_charging_schedules( const std::map& charging_schedules) { // publish the schedule over mqtt diff --git a/modules/OCPP/OCPP.hpp b/modules/OCPP/OCPP.hpp index dd5adcac2..cc47f165f 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -141,8 +141,6 @@ class OCPP : public Everest::ModuleBase { std::filesystem::path ocpp_share_path; ocpp::v16::ChargingRateUnit composite_schedule_charging_rate_unit; void set_external_limits(const std::map& charging_schedules); - bool is_evse_sink_configured(const int32_t evse_id); - external_energy_limitsIntf& get_evse_sink_by_evse_id(const int32_t evse_id); void publish_charging_schedules(const std::map& charging_schedules); void init_evse_subscriptions(); // initialize subscriptions to all EVSEs provided by r_evse_manager diff --git a/modules/OCPP201/CMakeLists.txt b/modules/OCPP201/CMakeLists.txt index d9b0bf101..9779599f4 100644 --- a/modules/OCPP201/CMakeLists.txt +++ b/modules/OCPP201/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries(${MODULE_NAME} everest::ocpp everest::ocpp_evse_security everest::ocpp_conversions + everest::external_energy_limits ) target_compile_options(${MODULE_NAME} diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index b7b756d71..2bbe72463 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace module { @@ -1212,7 +1213,7 @@ void OCPP201::set_external_limits(const std::vectoris_evse_sink_configured(evse_id)) { + if (not external_energy_limits::is_evse_sink_configured(this->r_evse_energy_sink, evse_id)) { EVLOG_warning << "Can not apply external limits! No evse energy sink configured for evse_id: " << evse_id; continue; } @@ -1238,39 +1239,9 @@ void OCPP201::set_external_limits(const std::vectorget_evse_sink_by_evse_id(evse_id); + auto& evse_sink = external_energy_limits::get_evse_sink_by_evse_id(this->r_evse_energy_sink, evse_id); evse_sink.call_set_external_limits(limits); } } -bool OCPP201::is_evse_sink_configured(const int32_t evse_id) { - for (const auto& evse_sink : this->r_evse_energy_sink) { - if (not evse_sink->get_mapping().has_value()) { - EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " - "r_evse_energy_sink with module_id: " - << evse_sink->module_id; - throw std::runtime_error("No mapping configured for evse_id: " + evse_id); - } - if (evse_sink->get_mapping().value().evse == evse_id) { - return true; - } - } - return false; -} - -external_energy_limitsIntf& OCPP201::get_evse_sink_by_evse_id(const int32_t evse_id) { - for (const auto& evse_sink : this->r_evse_energy_sink) { - if (not evse_sink->get_mapping().has_value()) { - EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " - "r_evse_energy_sink with module_id: " - << evse_sink->module_id; - throw std::runtime_error("No mapping configured for evse_id: " + evse_id); - } - if (evse_sink->get_mapping().value().evse == evse_id) { - return *evse_sink; - } - } - throw std::runtime_error("No mapping configured for evse"); -} - } // namespace module diff --git a/modules/OCPP201/OCPP201.hpp b/modules/OCPP201/OCPP201.hpp index 258da2655..ddff7352f 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -160,9 +160,6 @@ class OCPP201 : public Everest::ModuleBase { /// \brief This function applies given \p composite_schedules for each connected evse_energy_sink void set_external_limits(const std::vector& composite_schedules); - bool is_evse_sink_configured(const int32_t evse_id); - external_energy_limitsIntf& get_evse_sink_by_evse_id(const int32_t evse_id); - // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 }; From 26d33441f5cf73868c866fd3bbd1e1ff30db4adb Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 15:58:41 +0100 Subject: [PATCH 22/33] Update everest-framework to v0.18.0 and everest-utils to v0.4.0 Signed-off-by: Kai-Uwe Hermann --- dependencies.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.yaml b/dependencies.yaml index 7ed370979..5474d2067 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -4,7 +4,7 @@ --- everest-framework: git: https://github.com/EVerest/everest-framework.git - git_tag: v0.17.2 + git_tag: v0.18.0 options: [ "BUILD_TESTING OFF", "everest-framework_USE_PYTHON_VENV ${PROJECT_NAME}_USE_PYTHON_VENV", @@ -90,7 +90,7 @@ ext-mbedtls: # everest-testing and ev-dev-tools everest-utils: git: https://github.com/EVerest/everest-utils.git - git_tag: 3eb4c1b90c14f35a0cc19a96b850c095166c3177 + git_tag: v0.4.0 # unit testing gtest: From 4c812ad4f6c919bd696bf950a79dd434481384b6 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 16:19:51 +0100 Subject: [PATCH 23/33] Update everestrs in Cargo.tom and Cargo.lock Signed-off-by: Kai-Uwe Hermann --- modules/Cargo.lock | 4 ++-- modules/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/Cargo.lock b/modules/Cargo.lock index a298e2e5b..6dff048a6 100644 --- a/modules/Cargo.lock +++ b/modules/Cargo.lock @@ -401,7 +401,7 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "everestrs" version = "0.1.0" -source = "git+https://github.com/everest/everest-framework.git?rev=3e767e2a5652d3acb97d01fc88aae2f04f3f5282#3e767e2a5652d3acb97d01fc88aae2f04f3f5282" +source = "git+https://github.com/everest/everest-framework.git?tag=v0.18.0#bb3d3a91bb50031d21aa3d43220801a9eb69a6bd" dependencies = [ "argh", "cxx", @@ -415,7 +415,7 @@ dependencies = [ [[package]] name = "everestrs-build" version = "0.1.0" -source = "git+https://github.com/everest/everest-framework.git?rev=3e767e2a5652d3acb97d01fc88aae2f04f3f5282#3e767e2a5652d3acb97d01fc88aae2f04f3f5282" +source = "git+https://github.com/everest/everest-framework.git?tag=v0.18.0#bb3d3a91bb50031d21aa3d43220801a9eb69a6bd" dependencies = [ "anyhow", "argh", diff --git a/modules/Cargo.toml b/modules/Cargo.toml index f3f573b8f..a6415fe40 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -8,5 +8,5 @@ members = [ ] [workspace.dependencies] -everestrs = { git = "https://github.com/everest/everest-framework.git", rev = "3e767e2a5652d3acb97d01fc88aae2f04f3f5282" } -everestrs-build = { git = "https://github.com/everest/everest-framework.git", rev = "3e767e2a5652d3acb97d01fc88aae2f04f3f5282" } +everestrs = { git = "https://github.com/everest/everest-framework.git", tag = "v0.18.0" } +everestrs-build = { git = "https://github.com/everest/everest-framework.git", tag = "v0.18.0" } From 31734a72ff92a78172370efc2031c87db30eb8c1 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 17:00:53 +0100 Subject: [PATCH 24/33] Bump required ev-cli version to 0.4.0 Signed-off-by: Kai-Uwe Hermann --- cmake/ev-project-bootstrap.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ev-project-bootstrap.cmake b/cmake/ev-project-bootstrap.cmake index 0e37b9272..e9f5ce6db 100644 --- a/cmake/ev-project-bootstrap.cmake +++ b/cmake/ev-project-bootstrap.cmake @@ -1,6 +1,6 @@ set_property( GLOBAL - PROPERTY EVEREST_REQUIRED_EV_CLI_VERSION "0.3.0" + PROPERTY EVEREST_REQUIRED_EV_CLI_VERSION "0.4.0" ) # FIXME (aw): clean up this inclusion chain From fae74226a950166719161f2eae603ad406394347 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 17:59:31 +0100 Subject: [PATCH 25/33] Replace removed Requirement constructor usage in test Signed-off-by: Kai-Uwe Hermann --- modules/EvseManager/tests/evse_board_supportIntfStub.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/EvseManager/tests/evse_board_supportIntfStub.hpp b/modules/EvseManager/tests/evse_board_supportIntfStub.hpp index 9ed3c0364..c8fe7e49d 100644 --- a/modules/EvseManager/tests/evse_board_supportIntfStub.hpp +++ b/modules/EvseManager/tests/evse_board_supportIntfStub.hpp @@ -12,7 +12,7 @@ namespace module::stub { struct evse_board_supportIntfStub : public evse_board_supportIntf { explicit evse_board_supportIntfStub(ModuleAdapterStub& adapter) : - evse_board_supportIntf(&adapter, Requirement("requirement", 1), "EvseManager") { + evse_board_supportIntf(&adapter, Requirement{"requirement", 1}, "EvseManager") { } }; From e3afe4b18d21bf3186625b4d2b525e751bfd8f6e Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 18:01:31 +0100 Subject: [PATCH 26/33] Add missing nullopt for mapping in interface stub of test Signed-off-by: Kai-Uwe Hermann --- modules/EvseManager/tests/evse_board_supportIntfStub.hpp | 2 +- modules/EvseV2G/tests/evse_securityIntfStub.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/EvseManager/tests/evse_board_supportIntfStub.hpp b/modules/EvseManager/tests/evse_board_supportIntfStub.hpp index c8fe7e49d..c64342848 100644 --- a/modules/EvseManager/tests/evse_board_supportIntfStub.hpp +++ b/modules/EvseManager/tests/evse_board_supportIntfStub.hpp @@ -12,7 +12,7 @@ namespace module::stub { struct evse_board_supportIntfStub : public evse_board_supportIntf { explicit evse_board_supportIntfStub(ModuleAdapterStub& adapter) : - evse_board_supportIntf(&adapter, Requirement{"requirement", 1}, "EvseManager") { + evse_board_supportIntf(&adapter, Requirement{"requirement", 1}, "EvseManager", std::nullopt) { } }; diff --git a/modules/EvseV2G/tests/evse_securityIntfStub.hpp b/modules/EvseV2G/tests/evse_securityIntfStub.hpp index d2a388e0a..5768457c6 100644 --- a/modules/EvseV2G/tests/evse_securityIntfStub.hpp +++ b/modules/EvseV2G/tests/evse_securityIntfStub.hpp @@ -23,7 +23,7 @@ class evse_securityIntfStub : public ModuleAdapterStub, public evse_securityIntf functions; public: - evse_securityIntfStub() : evse_securityIntf(this, Requirement("", 0), "EvseSecurity") { + evse_securityIntfStub() : evse_securityIntf(this, Requirement{"", 0}, "EvseSecurity", std::nullopt) { functions["get_verify_file"] = &evse_securityIntfStub::get_verify_file; functions["get_leaf_certificate_info"] = &evse_securityIntfStub::get_leaf_certificate_info; } From 3baf9e8c231276cdd678e9b3b2e68b229d2a1bf5 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 18:04:54 +0100 Subject: [PATCH 27/33] Adapt operator< of Requirement to new free function for test Signed-off-by: Kai-Uwe Hermann --- modules/EvseV2G/tests/requirement.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/EvseV2G/tests/requirement.cpp b/modules/EvseV2G/tests/requirement.cpp index cec9c44a7..8bbd5db72 100644 --- a/modules/EvseV2G/tests/requirement.cpp +++ b/modules/EvseV2G/tests/requirement.cpp @@ -5,8 +5,6 @@ #include "utils/types.hpp" -Requirement::Requirement(const std::string& requirement_id_, size_t index_) { -} -bool Requirement::operator<(const Requirement& rhs) const { +bool operator<(const Requirement& lhs, const Requirement& rhs) { return true; } From 1943b723fcd20549e95a4f7beb586cbafc700c45 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 19:36:41 +0100 Subject: [PATCH 28/33] Update everest-testing to fix integration test failures Signed-off-by: Kai-Uwe Hermann --- dependencies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index 5474d2067..56e5dfac7 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -90,7 +90,7 @@ ext-mbedtls: # everest-testing and ev-dev-tools everest-utils: git: https://github.com/EVerest/everest-utils.git - git_tag: v0.4.0 + git_tag: a4ab7febd19dea48657cd61915be862515ff13e7 # FIXME: switch to tag once everest-utils PR is merged # unit testing gtest: From b5eda5f75fa4c869f837ba98164399d49d27aadb Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 5 Nov 2024 19:58:38 +0100 Subject: [PATCH 29/33] Bump everest-utils version to v0.4.1 to use fixed everest-testing Signed-off-by: Kai-Uwe Hermann --- dependencies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index 56e5dfac7..c4f43b788 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -90,7 +90,7 @@ ext-mbedtls: # everest-testing and ev-dev-tools everest-utils: git: https://github.com/EVerest/everest-utils.git - git_tag: a4ab7febd19dea48657cd61915be862515ff13e7 # FIXME: switch to tag once everest-utils PR is merged + git_tag: v0.4.1 # unit testing gtest: From 2d1743228b7d01b6a5c4e35a3b1d2ef1cd39a49b Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Wed, 6 Nov 2024 10:22:04 +0100 Subject: [PATCH 30/33] Fix typos Signed-off-by: Kai-Uwe Hermann --- modules/API/API.cpp | 2 +- modules/OCPP/OCPP.cpp | 2 +- modules/OCPP201/OCPP201.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/API/API.cpp b/modules/API/API.cpp index 4be0bc531..fd56c74b6 100644 --- a/modules/API/API.cpp +++ b/modules/API/API.cpp @@ -273,7 +273,7 @@ void API::init() { EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " "r_evse_energy_sink with module_id: " << evse_sink->module_id; - throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to and evse."); + throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to an evse."); } } diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index 6998e590d..e6ba0a6bc 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -350,7 +350,7 @@ void OCPP::init() { EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " "r_evse_energy_sink with module_id: " << evse_sink->module_id; - throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to and evse."); + throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to an evse."); } } diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index 2bbe72463..1a6772577 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -282,7 +282,7 @@ void OCPP201::init() { EVLOG_critical << "Please configure an evse mapping your configuration file for the connected " "r_evse_energy_sink with module_id: " << evse_sink->module_id; - throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to and evse."); + throw std::runtime_error("At least one connected evse_energy_sink misses a mapping to an evse."); } } From 106a16d268fffedd544db6285ba9425739672897 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Wed, 6 Nov 2024 13:45:36 +0100 Subject: [PATCH 31/33] Bump ev-cli dependency Signed-off-by: Kai-Uwe Hermann --- dependencies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index c4f43b788..f2598a30b 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -90,7 +90,7 @@ ext-mbedtls: # everest-testing and ev-dev-tools everest-utils: git: https://github.com/EVerest/everest-utils.git - git_tag: v0.4.1 + git_tag: 2b07fbc53059b85bfc34cc3d4750584d5a206564 # FIXME: update to v0.4.2 once it is tagged # unit testing gtest: From adf275d8cbedf764ca9ead558ec5edd462a11e69 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Wed, 6 Nov 2024 20:34:21 +0100 Subject: [PATCH 32/33] Bump everest-utils Signed-off-by: Kai-Uwe Hermann --- dependencies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index f2598a30b..a5c49232d 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -90,7 +90,7 @@ ext-mbedtls: # everest-testing and ev-dev-tools everest-utils: git: https://github.com/EVerest/everest-utils.git - git_tag: 2b07fbc53059b85bfc34cc3d4750584d5a206564 # FIXME: update to v0.4.2 once it is tagged + git_tag: d7dcc9db8127f3dfb326ea596e1bc7c69b38f14e # FIXME: update to v0.4.2 once it is tagged # unit testing gtest: From 57a8e3808e975a05ad909cc6cf7f0865ab873ce9 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Thu, 7 Nov 2024 11:40:36 +0100 Subject: [PATCH 33/33] Bump everest-utils to 0.4.2 Signed-off-by: Kai-Uwe Hermann --- dependencies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index a5c49232d..7454fdafc 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -90,7 +90,7 @@ ext-mbedtls: # everest-testing and ev-dev-tools everest-utils: git: https://github.com/EVerest/everest-utils.git - git_tag: d7dcc9db8127f3dfb326ea596e1bc7c69b38f14e # FIXME: update to v0.4.2 once it is tagged + git_tag: v0.4.2 # unit testing gtest: