diff --git a/dependencies.yaml b/dependencies.yaml index 47dafc3c44..f486cdf54b 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -67,7 +67,7 @@ libevse-security: # OCPP libocpp: git: https://github.com/EVerest/libocpp.git - git_tag: 2c727f86e9ff988bdf13fcf5b049f0d5c3650384 + git_tag: v0.31.0 cmake_condition: "EVEREST_DEPENDENCY_ENABLED_LIBOCPP" # Josev Josev: diff --git a/modules/EVSE/OCPP/OCPP.cpp b/modules/EVSE/OCPP/OCPP.cpp index 6ff6d3c724..80561e1f1d 100644 --- a/modules/EVSE/OCPP/OCPP.cpp +++ b/modules/EVSE/OCPP/OCPP.cpp @@ -338,6 +338,18 @@ void OCPP::init_evse_subscriptions() { this->process_session_event(evse_id, session_event); }); + + evse->subscribe_powermeter_public_key_ocmf([this, evse_id](std::string public_key_ocmf) { + if (!this->started) { + this->event_queue.emplace(evse_id, PowermeterPublicKey{public_key_ocmf}); + return; + } + + if (!this->charge_point->set_powermeter_public_key(evse_id, public_key_ocmf)) { + EVLOG_error << "Failed to set powermeter public key for evse_id: " << evse_id; + } + }); + evse_id++; } @@ -1077,6 +1089,9 @@ void OCPP::ready() { [&](const types::system::FirmwareUpdateStatus& fw) { charge_point->on_firmware_update_status_notification( fw.request_id, conversions::to_ocpp_firmware_status_notification(fw.firmware_update_status)); + }, + [&](const PowermeterPublicKey public_key) { + this->charge_point->set_powermeter_public_key(queued_event.evse_id, public_key.value); }}, queued_event.data); } diff --git a/modules/EVSE/OCPP/OCPP.hpp b/modules/EVSE/OCPP/OCPP.hpp index 9c89cb84ac..30e2825c72 100644 --- a/modules/EVSE/OCPP/OCPP.hpp +++ b/modules/EVSE/OCPP/OCPP.hpp @@ -48,15 +48,18 @@ struct ErrorRaised : public Everest::error::Error {}; struct ErrorCleared : public Everest::error::Error {}; +struct PowermeterPublicKey { + std::string value; +}; using EventData = std::variant; + types::system::FirmwareUpdateStatus, PowermeterPublicKey>; struct Event { - EventData data; int32_t evse_id; + EventData data; - explicit Event(int32_t evse_id_, EventData data_) : evse_id(evse_id_), data(std::move(data_)) { + Event(int32_t evse_id_, EventData data_) : evse_id(evse_id_), data(std::move(data_)) { } }; diff --git a/modules/Simulation/YetiSimulator/powermeter/powermeterImpl.cpp b/modules/Simulation/YetiSimulator/powermeter/powermeterImpl.cpp index fce29a3569..10b02aade9 100644 --- a/modules/Simulation/YetiSimulator/powermeter/powermeterImpl.cpp +++ b/modules/Simulation/YetiSimulator/powermeter/powermeterImpl.cpp @@ -10,6 +10,7 @@ void powermeterImpl::init() { } void powermeterImpl::ready() { + this->publish_public_key_ocmf("TESTPUBLICKEY" + std::to_string(this->mod->config.connector_id)); } types::powermeter::TransactionStartResponse diff --git a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-two-connectors.yaml b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-two-connectors.yaml index c7b97e877b..beb7ee70ba 100644 --- a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-two-connectors.yaml +++ b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-two-connectors.yaml @@ -44,7 +44,7 @@ active_modules: yeti_driver_2: module: YetiSimulator config_module: - connector_id: 1 + connector_id: 2 car_simulator_1: module: EvManager config_module: diff --git a/tests/ocpp_tests/test_sets/ocpp16/eichrecht.py b/tests/ocpp_tests/test_sets/ocpp16/eichrecht.py new file mode 100644 index 0000000000..6c222b61c4 --- /dev/null +++ b/tests/ocpp_tests/test_sets/ocpp16/eichrecht.py @@ -0,0 +1,127 @@ +import pytest + +from everest.testing.core_utils.controller.test_controller_interface import ( + TestController, +) +from everest.testing.ocpp_utils.charge_point_utils import ( + wait_for_and_validate, + TestUtility, +) +from everest.testing.ocpp_utils.central_system import ChargePoint16 +from everest.testing.ocpp_utils.fixtures import test_utility, charge_point_v16 +from everest_test_utils import get_everest_config_path_str + +from ocpp.v16 import call_result + + +@pytest.mark.asyncio +@pytest.mark.everest_core_config( + get_everest_config_path_str("everest-config-two-connectors.yaml") +) +async def test_meter_public_key( + charge_point_v16: ChargePoint16, test_utility: TestUtility +): + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[1]"]) + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + call_result.GetConfiguration( + [{"key": "MeterPublicKey[1]", "readonly": True, "value": "TESTPUBLICKEY1"}] + ), + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[2]"]) + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + call_result.GetConfiguration( + [{"key": "MeterPublicKey[2]", "readonly": True, "value": "TESTPUBLICKEY2"}] + ), + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[3]"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[3]"]} + ) + + test_utility.messages.clear() + + response : call_result.GetConfiguration = await charge_point_v16.get_configuration_req() + + assert any( + entry['key'] == "MeterPublicKey[1]" and entry['value'] == "TESTPUBLICKEY1" + for entry in response.configuration_key) + + assert any( + entry['key'] == "MeterPublicKey[2]" and entry['value'] == "TESTPUBLICKEY2" + for entry in response.configuration_key) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[]"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[]"]} + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[MeterPublicKey[1]]"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[MeterPublicKey[1]]"]} + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[1X"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[1X"]} + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[1X]"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[1X]"]} + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[banana]"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[banana]"]} + ) + + await charge_point_v16.get_configuration_req(key=["MeterPublicKey[0]"]) + + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "GetConfiguration", + {"unknownKey": ["MeterPublicKey[0]"]} + ) + + await charge_point_v16.change_configuration_req( + key="MeterPublicKey[1]", value="TEST" + ) + assert await wait_for_and_validate( + test_utility, + charge_point_v16, + "ChangeConfiguration", + {"status": "Rejected"} + )