From a904613e365aba7f9f9e12d1d01b5da73f1780c8 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] * 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 1ec7439be..cd9253020 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 92129de9d..976ee1218 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -76,6 +76,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) { @@ -98,23 +104,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( @@ -335,6 +357,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 375848298..d8f614c84 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -75,7 +75,7 @@ class OCPP : public Everest::ModuleBase { std::unique_ptr p_data_transfer, std::unique_ptr p_ocpp_generic, std::unique_ptr p_session_cost, std::vector> r_evse_manager, - std::vector> r_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, @@ -89,7 +89,7 @@ class OCPP : public Everest::ModuleBase { p_ocpp_generic(std::move(p_ocpp_generic)), p_session_cost(std::move(p_session_cost)), r_evse_manager(std::move(r_evse_manager)), - r_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)), @@ -106,7 +106,7 @@ class OCPP : public Everest::ModuleBase { const std::unique_ptr p_ocpp_generic; const std::unique_ptr p_session_cost; const std::vector> r_evse_manager; - const std::vector> r_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; @@ -139,6 +139,8 @@ class OCPP : public Everest::ModuleBase { // insert your private definitions here std::filesystem::path ocpp_share_path; 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 c1b382fec..589a071fb 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -38,7 +38,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 09bf9206a..4969c716c 100644 --- a/modules/OCPP/manifest.yaml +++ b/modules/OCPP/manifest.yaml @@ -59,7 +59,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 c3f7f5052..ed673a01e 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -276,6 +276,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++) { @@ -654,7 +664,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); @@ -1192,6 +1202,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; @@ -1213,24 +1229,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 a90b22075..afea294fc 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -61,7 +61,7 @@ class OCPP201 : public Everest::ModuleBase { std::vector> r_evse_manager, std::unique_ptr r_system, std::unique_ptr r_security, std::vector> r_data_transfer, std::unique_ptr r_auth, - std::vector> r_evse_manager_energy_sink, + std::vector> r_evse_energy_sink, std::vector> r_display_message, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), @@ -76,7 +76,7 @@ class OCPP201 : public Everest::ModuleBase { r_security(std::move(r_security)), r_data_transfer(std::move(r_data_transfer)), r_auth(std::move(r_auth)), - r_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) { } @@ -93,7 +93,7 @@ class OCPP201 : public Everest::ModuleBase { const std::unique_ptr r_security; const std::vector> r_data_transfer; const std::unique_ptr r_auth; - const std::vector> r_evse_manager_energy_sink; + const std::vector> r_evse_energy_sink; const std::vector> r_display_message; const Conf& config; @@ -160,8 +160,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 630a0e504..7cddc3339 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