From 4cf7ca0868f1d498ea1e47a8c0be8800764566ea Mon Sep 17 00:00:00 2001 From: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:33:17 +0000 Subject: [PATCH 01/18] smart_charging, charge_point: Implement K12FR02 Creates an initial implementation for handling K12 that takes in an external limit and its delta from previous limits and determines whether or not to send a notification to the CSMS. We expose a public function on the ChargePoint so that some external system (such as the energy manager) may call it to alert us of the external limit. Signed-off-by: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> --- doc/ocpp_201_status.md | 2 +- include/ocpp/v201/charge_point.hpp | 10 +++++ include/ocpp/v201/smart_charging.hpp | 14 +++++++ lib/ocpp/v201/charge_point.cpp | 9 ++++ lib/ocpp/v201/smart_charging.cpp | 15 +++++++ .../mocks/smart_charging_handler_mock.hpp | 5 +++ tests/lib/ocpp/v201/test_charge_point.cpp | 17 ++++++++ .../ocpp/v201/test_smart_charging_handler.cpp | 42 +++++++++++++++++++ 8 files changed, 113 insertions(+), 1 deletion(-) diff --git a/doc/ocpp_201_status.md b/doc/ocpp_201_status.md index 43e4afb7e..8721e0d0f 100644 --- a/doc/ocpp_201_status.md +++ b/doc/ocpp_201_status.md @@ -1390,7 +1390,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir | ID | Status | Remark | |-----------|--------|--------| | K12.FR.01 | | | -| K12.FR.02 | | | +| K12.FR.02 | ✅ | | | K12.FR.03 | | | | K12.FR.04 | | | | K12.FR.05 | | | diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index f2893498e..3f8c7fa4c 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -249,6 +249,13 @@ class ChargePointInterface { /// virtual void on_variable_changed(const SetVariableData& set_variable_data) = 0; + /// \brief Notifies the ChargePoint that a new external limit has been set. This may send a + /// NotifyChargingLimitRequest if the \p percentage_delta is greater than our LimitChangeSignificance. + /// \param limit the new external limit + /// \param percentage_delta the percent changed from the existing limits + virtual void on_external_limits_changed(const std::variant& limit, + double percentage_delta) = 0; + /// \brief Data transfer mechanism initiated by charger /// \param vendorId /// \param messageId @@ -819,6 +826,9 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_variable_changed(const SetVariableData& set_variable_data) override; + void on_external_limits_changed(const std::variant& limit, + double percentage_delta) override; + std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, const std::optional& data) override; diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 2c1d9aa87..b2ed95466 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -6,12 +6,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -97,6 +99,10 @@ class SmartChargingHandlerInterface { const ocpp::DateTime& start_time, const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit) = 0; + + virtual std::optional + handle_external_limits_changed(const std::variant& limit, + double percentage_delta) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -165,6 +171,14 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { const int32_t evse_id, std::optional charging_rate_unit) override; + /// + /// \brief Determines whether or not we should notify the CSMS of a change to our limits + /// based on \p percentage_delta and builds the notification. + /// + std::optional + handle_external_limits_changed(const std::variant& limit, + double percentage_delta) const override; + protected: /// /// \brief validates the existence of the given \p evse_id according to the specification diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 2b8a12d1a..a1fa0fd83 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1013,6 +1013,15 @@ void ChargePoint::on_variable_changed(const SetVariableData& set_variable_data) this->handle_variable_changed(set_variable_data); } +void ChargePoint::on_external_limits_changed(const std::variant& limit, + double percentage_delta) { + auto request = this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta); + if (request.has_value()) { + ocpp::Call call(request.value(), this->message_queue->createMessageId()); + this->send(call); + } +} + bool ChargePoint::send(CallError call_error) { this->message_queue->push(call_error); return true; diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 8dddb1f05..d9bd195d0 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -9,6 +9,7 @@ #include "ocpp/v201/ctrlr_component_variables.hpp" #include "ocpp/v201/device_model.hpp" #include "ocpp/v201/evse.hpp" +#include "ocpp/v201/messages/NotifyChargingLimit.hpp" #include "ocpp/v201/messages/SetChargingProfile.hpp" #include "ocpp/v201/ocpp_enums.hpp" #include "ocpp/v201/ocpp_types.hpp" @@ -614,4 +615,18 @@ CompositeSchedule SmartChargingHandler::calculate_composite_schedule( return composite_schedule; } +std::optional +SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, + double percentage_delta) const { + std::optional request = {}; + + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + const float limit_change_significance = this->device_model->get_value(limit_change_cv); + if (percentage_delta > limit_change_significance) { + request = NotifyChargingLimitRequest{}; + } + + return request; +} + } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 544d40777..07e8e3c38 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -3,12 +3,15 @@ #include "gmock/gmock.h" #include +#include #include #include "ocpp/v201/messages/SetChargingProfile.hpp" #include "ocpp/v201/ocpp_enums.hpp" #include "ocpp/v201/smart_charging.hpp" +typedef std::variant ChargingLimitVariant; + namespace ocpp::v201 { class SmartChargingHandlerMock : public SmartChargingHandlerInterface { public: @@ -28,5 +31,7 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { (std::vector & valid_profiles, const ocpp::DateTime& start_time, const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit)); + MOCK_METHOD(std::optional, handle_external_limits_changed, + (const ChargingLimitVariant& limit, double percentage_delta), (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 1ce4c4851..5911a21b9 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -17,12 +17,14 @@ #include "ocpp/v201/smart_charging.hpp" #include "ocpp/v201/types.hpp" #include "smart_charging_handler_mock.hpp" +#include "smart_charging_test_utils.hpp" #include "gmock/gmock.h" #include #include #include #include #include +#include static const int DEFAULT_EVSE_ID = 1; static const int DEFAULT_PROFILE_ID = 1; @@ -941,4 +943,19 @@ TEST_F(ChargePointFunctionalityTestFixtureV201, K02FR05_TransactionEnds_WillDele TriggerReasonEnum::StopAuthorized, {}, {}, ChargingStateEnum::EVConnected); } +TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + float limit = 100.0; + double deltaChanged = 0.2; + + const std::variant new_limit(limit); + + EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(new_limit, deltaChanged)); + + charge_point->on_external_limits_changed(new_limit, deltaChanged); +} + } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 4615edc96..5f4b4a0e8 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1678,4 +1678,46 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K05FR02_RequestStartTransactionReque ASSERT_THAT(sut, testing::Eq(ProfileValidationResultEnum::RequestStartTransactionNonTxProfile)); } +TEST_F(SmartChargingHandlerTestFixtureV201, + K12FR02_HandleExternalLimitsChanged_LimitChangeSignificanceNotMet_ReturnNone) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.5", + "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsFalse()); +} + +TEST_F(SmartChargingHandlerTestFixtureV201, + K12FR02_HandleExternalLimitsChanged_LimitChangeSignificanceEqual_ReturnNone) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.2", + "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsFalse()); +} + +TEST_F(SmartChargingHandlerTestFixtureV201, + K12FR02_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_ReturnNotifyChargingLimitRequest) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); +} + } // namespace ocpp::v201 From 7cbfaed963ddda9329a723327f6d7e2507ae6815 Mon Sep 17 00:00:00 2001 From: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:30:22 +0000 Subject: [PATCH 02/18] smart_charging: Implement K12FR03 Ensure we either build a charging schedule from a given limit or use the given charging schedule and return it in our notification to the CSMS. Signed-off-by: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> --- doc/ocpp_201_status.md | 2 +- lib/ocpp/v201/smart_charging.cpp | 24 +++++ .../ocpp/v201/test_smart_charging_handler.cpp | 90 +++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/doc/ocpp_201_status.md b/doc/ocpp_201_status.md index 8721e0d0f..23682680e 100644 --- a/doc/ocpp_201_status.md +++ b/doc/ocpp_201_status.md @@ -1391,7 +1391,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir |-----------|--------|--------| | K12.FR.01 | | | | K12.FR.02 | ✅ | | -| K12.FR.03 | | | +| K12.FR.03 | ✅ | | | K12.FR.04 | | | | K12.FR.05 | | | diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index d9bd195d0..2bbc3e70c 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace std::chrono; @@ -615,6 +616,17 @@ CompositeSchedule SmartChargingHandler::calculate_composite_schedule( return composite_schedule; } +ChargingSchedule create_schedule_from_limit(const float limit) { + return ChargingSchedule{ + .id = 0, + .chargingRateUnit = ChargingRateUnitEnum::A, + .chargingSchedulePeriod = {ChargingSchedulePeriod{ + .startPeriod = 0, + .limit = limit, + }}, + }; +} + std::optional SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, double percentage_delta) const { @@ -622,8 +634,20 @@ SmartChargingHandler::handle_external_limits_changed(const std::variantdevice_model->get_value(limit_change_cv); + + const auto& notify_charging_limit_cv = ControllerComponentVariables::NotifyChargingLimitWithSchedules; + const std::optional notify_with_schedules = + this->device_model->get_optional_value(notify_charging_limit_cv); + if (percentage_delta > limit_change_significance) { request = NotifyChargingLimitRequest{}; + if (notify_with_schedules.has_value() && notify_with_schedules.value()) { + if (const auto* limit_f = std::get_if(&limit)) { + request->chargingSchedule = {{create_schedule_from_limit(*limit_f)}}; + } else if (const auto* limit_s = std::get_if(&limit)) { + request->chargingSchedule = {{*limit_s}}; + } + } } return request; diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 5f4b4a0e8..1f7d3e5a9 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -33,6 +33,8 @@ #include #include +#include "smart_charging_test_utils.hpp" + namespace ocpp::v201 { static const int NR_OF_EVSES = 2; @@ -1720,4 +1722,92 @@ TEST_F(SmartChargingHandlerTestFixtureV201, ASSERT_THAT(resp.has_value(), testing::IsTrue()); } +TEST_F( + SmartChargingHandlerTestFixtureV201, + K12FR03_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_EnableChargingLimitWithSchedulesTrue_IncludesScheduleFromInteger) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + const auto& notify_charging_limit_cv = ControllerComponentVariables::NotifyChargingLimitWithSchedules; + device_model->set_value(notify_charging_limit_cv.component, notify_charging_limit_cv.variable.value(), + AttributeEnum::Actual, "true", "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + + auto charging_schedule = ChargingSchedule{.id = 0, + .chargingRateUnit = ChargingRateUnitEnum::A, + .chargingSchedulePeriod = {ChargingSchedulePeriod{ + .startPeriod = 0, + .limit = new_limit, + }}}; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingSchedule.value(), testing::Contains(charging_schedule)); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K12FR03_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_EnableChargingLimitWithSchedulesTrue_IncludesGivenSchedule) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + const auto& notify_charging_limit_cv = ControllerComponentVariables::NotifyChargingLimitWithSchedules; + device_model->set_value(notify_charging_limit_cv.component, notify_charging_limit_cv.variable.value(), + AttributeEnum::Actual, "true", "test"); + + double deltaChanged = 0.2; + + auto charging_schedule = ChargingSchedule{.id = 0, + .chargingRateUnit = ChargingRateUnitEnum::W, + .chargingSchedulePeriod = {ChargingSchedulePeriod{ + .startPeriod = 0, + .limit = 20, + }}}; + + auto resp = handler.handle_external_limits_changed(charging_schedule, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingSchedule.value(), testing::Contains(charging_schedule)); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K12FR03_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_EnableChargingLimitWithSchedulesUnset_NoSchedule) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K12FR03_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_EnableChargingLimitWithSchedulesFalse_NoSchedule) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + const auto& notify_charging_limit_cv = ControllerComponentVariables::NotifyChargingLimitWithSchedules; + device_model->set_value(notify_charging_limit_cv.component, notify_charging_limit_cv.variable.value(), + AttributeEnum::Actual, "false", "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); +} + } // namespace ocpp::v201 From 82da45ee52969182bc278572cf11b0967cb64299 Mon Sep 17 00:00:00 2001 From: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:51:26 +0000 Subject: [PATCH 03/18] smart_charging, charge_point: Implement K12.FR.04 Take in the charging limit source, and ensure we don't propagate a source of CSO in the off chance we receive it. Signed-off-by: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> --- doc/ocpp_201_status.md | 2 +- include/ocpp/v201/charge_point.hpp | 9 ++-- include/ocpp/v201/smart_charging.hpp | 8 +-- lib/ocpp/v201/charge_point.cpp | 4 +- lib/ocpp/v201/smart_charging.cpp | 10 +++- .../mocks/smart_charging_handler_mock.hpp | 3 +- tests/lib/ocpp/v201/test_charge_point.cpp | 5 +- .../ocpp/v201/test_smart_charging_handler.cpp | 50 ++++++++++++++++--- 8 files changed, 69 insertions(+), 22 deletions(-) diff --git a/doc/ocpp_201_status.md b/doc/ocpp_201_status.md index 23682680e..d69e4e4c0 100644 --- a/doc/ocpp_201_status.md +++ b/doc/ocpp_201_status.md @@ -1392,7 +1392,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir | K12.FR.01 | | | | K12.FR.02 | ✅ | | | K12.FR.03 | ✅ | | -| K12.FR.04 | | | +| K12.FR.04 | ✅ | | | K12.FR.05 | | | ## SmartCharging - Reset / Release External Charging Limit diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 3f8c7fa4c..7dac35e51 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -253,8 +253,9 @@ class ChargePointInterface { /// NotifyChargingLimitRequest if the \p percentage_delta is greater than our LimitChangeSignificance. /// \param limit the new external limit /// \param percentage_delta the percent changed from the existing limits - virtual void on_external_limits_changed(const std::variant& limit, - double percentage_delta) = 0; + /// \param source the source of the external limit (NOTE: Should never be CSO) + virtual void on_external_limits_changed(const std::variant& limit, double percentage_delta, + ChargingLimitSourceEnum source) = 0; /// \brief Data transfer mechanism initiated by charger /// \param vendorId @@ -826,8 +827,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_variable_changed(const SetVariableData& set_variable_data) override; - void on_external_limits_changed(const std::variant& limit, - double percentage_delta) override; + void on_external_limits_changed(const std::variant& limit, double percentage_delta, + ChargingLimitSourceEnum source) override; std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index b2ed95466..cdaae33da 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -101,8 +101,8 @@ class SmartChargingHandlerInterface { std::optional charging_rate_unit) = 0; virtual std::optional - handle_external_limits_changed(const std::variant& limit, - double percentage_delta) const = 0; + handle_external_limits_changed(const std::variant& limit, double percentage_delta, + ChargingLimitSourceEnum source) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -176,8 +176,8 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { /// based on \p percentage_delta and builds the notification. /// std::optional - handle_external_limits_changed(const std::variant& limit, - double percentage_delta) const override; + handle_external_limits_changed(const std::variant& limit, double percentage_delta, + ChargingLimitSourceEnum source) const override; protected: /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index a1fa0fd83..72153806a 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1014,8 +1014,8 @@ void ChargePoint::on_variable_changed(const SetVariableData& set_variable_data) } void ChargePoint::on_external_limits_changed(const std::variant& limit, - double percentage_delta) { - auto request = this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta); + double percentage_delta, ChargingLimitSourceEnum source) { + auto request = this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta, source); if (request.has_value()) { ocpp::Call call(request.value(), this->message_queue->createMessageId()); this->send(call); diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 2bbc3e70c..9ebda84b8 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -629,7 +629,14 @@ ChargingSchedule create_schedule_from_limit(const float limit) { std::optional SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, - double percentage_delta) const { + double percentage_delta, ChargingLimitSourceEnum source) const { + // K12.FR.04 + if (source == ChargingLimitSourceEnum::CSO) { + // The spec does not define what we should do when the source + // given is CSO. Here we just throw. + throw std::invalid_argument("The source of an external limit should not be CSO."); + } + std::optional request = {}; const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; @@ -641,6 +648,7 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant limit_change_significance) { request = NotifyChargingLimitRequest{}; + request->chargingLimit = {.chargingLimitSource = source}; if (notify_with_schedules.has_value() && notify_with_schedules.value()) { if (const auto* limit_f = std::get_if(&limit)) { request->chargingSchedule = {{create_schedule_from_limit(*limit_f)}}; diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 07e8e3c38..3299e2100 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -32,6 +32,7 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit)); MOCK_METHOD(std::optional, handle_external_limits_changed, - (const ChargingLimitVariant& limit, double percentage_delta), (const, override)); + (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source), + (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 5911a21b9..036e3bd1d 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -950,12 +950,13 @@ TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { float limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; const std::variant new_limit(limit); - EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(new_limit, deltaChanged)); + EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(new_limit, deltaChanged, source)); - charge_point->on_external_limits_changed(new_limit, deltaChanged); + charge_point->on_external_limits_changed(new_limit, deltaChanged, source); } } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 1f7d3e5a9..26713349a 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -10,6 +10,7 @@ #include "ocpp/v201/device_model_storage_sqlite.hpp" #include "ocpp/v201/init_device_model_db.hpp" #include "ocpp/v201/ocpp_types.hpp" +#include "gtest/gtest.h" #include #include #include @@ -31,6 +32,7 @@ #include "comparators.hpp" #include +#include #include #include "smart_charging_test_utils.hpp" @@ -1688,8 +1690,9 @@ TEST_F(SmartChargingHandlerTestFixtureV201, float new_limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsFalse()); } @@ -1702,8 +1705,9 @@ TEST_F(SmartChargingHandlerTestFixtureV201, float new_limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsFalse()); } @@ -1716,8 +1720,9 @@ TEST_F(SmartChargingHandlerTestFixtureV201, float new_limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); } @@ -1734,6 +1739,7 @@ TEST_F( float new_limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; auto charging_schedule = ChargingSchedule{.id = 0, .chargingRateUnit = ChargingRateUnitEnum::A, @@ -1742,7 +1748,7 @@ TEST_F( .limit = new_limit, }}}; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); @@ -1760,6 +1766,7 @@ TEST_F( AttributeEnum::Actual, "true", "test"); double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; auto charging_schedule = ChargingSchedule{.id = 0, .chargingRateUnit = ChargingRateUnitEnum::W, @@ -1768,7 +1775,7 @@ TEST_F( .limit = 20, }}}; - auto resp = handler.handle_external_limits_changed(charging_schedule, deltaChanged); + auto resp = handler.handle_external_limits_changed(charging_schedule, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); @@ -1784,8 +1791,9 @@ TEST_F( float new_limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); @@ -1803,11 +1811,39 @@ TEST_F( float new_limit = 100.0; double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); } +TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_NotificationIncludesSource) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::SO; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); +} + +TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ThrowsIfSourceIsCSO) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + float new_limit = 100.0; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::CSO; + + EXPECT_THROW(handler.handle_external_limits_changed(new_limit, deltaChanged, source), std::invalid_argument); +} + } // namespace ocpp::v201 From 47a7f0aa6157f198ce0778888ef26b1e735abe4d Mon Sep 17 00:00:00 2001 From: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:20:04 +0000 Subject: [PATCH 04/18] smart_charging: Add type for constant limits When receiving an external limit from another system, we need to know two things: the limit, and what unit the limit is in. Previously we only knew the limit (if we're not given a schedule) and made up a unit. Now when we receive a constant charging limit we take it as the new type ConstantChargingLimit, which holds the limit and the unit. Signed-off-by: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> --- include/ocpp/v201/charge_point.hpp | 8 ++-- include/ocpp/v201/smart_charging.hpp | 16 +++++-- lib/ocpp/v201/charge_point.cpp | 2 +- lib/ocpp/v201/smart_charging.cpp | 17 ++++--- .../mocks/smart_charging_handler_mock.hpp | 2 +- tests/lib/ocpp/v201/test_charge_point.cpp | 7 ++- .../ocpp/v201/test_smart_charging_handler.cpp | 46 ++++++++++++++----- 7 files changed, 69 insertions(+), 29 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 7dac35e51..87501123f 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -254,8 +254,8 @@ class ChargePointInterface { /// \param limit the new external limit /// \param percentage_delta the percent changed from the existing limits /// \param source the source of the external limit (NOTE: Should never be CSO) - virtual void on_external_limits_changed(const std::variant& limit, double percentage_delta, - ChargingLimitSourceEnum source) = 0; + virtual void on_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) = 0; /// \brief Data transfer mechanism initiated by charger /// \param vendorId @@ -827,8 +827,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_variable_changed(const SetVariableData& set_variable_data) override; - void on_external_limits_changed(const std::variant& limit, double percentage_delta, - ChargingLimitSourceEnum source) override; + void on_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) override; std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index cdaae33da..fb3a7c202 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -4,6 +4,7 @@ #ifndef OCPP_V201_SMART_CHARGING_HPP #define OCPP_V201_SMART_CHARGING_HPP +#include "ocpp/v201/comparators.hpp" #include #include #include @@ -58,6 +59,13 @@ enum class AddChargingProfileSource { RequestStartTransactionRequest }; +struct ConstantChargingLimit { + float limit; + ChargingRateUnitEnum charging_rate_unit; +}; + +bool operator==(const ConstantChargingLimit& a, const ConstantChargingLimit& b); + namespace conversions { /// \brief Converts the given ProfileValidationResultEnum \p e to human readable string /// \returns a string representation of the ProfileValidationResultEnum @@ -101,8 +109,8 @@ class SmartChargingHandlerInterface { std::optional charging_rate_unit) = 0; virtual std::optional - handle_external_limits_changed(const std::variant& limit, double percentage_delta, - ChargingLimitSourceEnum source) const = 0; + handle_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -176,8 +184,8 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { /// based on \p percentage_delta and builds the notification. /// std::optional - handle_external_limits_changed(const std::variant& limit, double percentage_delta, - ChargingLimitSourceEnum source) const override; + handle_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) const override; protected: /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 72153806a..3492819d1 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1013,7 +1013,7 @@ void ChargePoint::on_variable_changed(const SetVariableData& set_variable_data) this->handle_variable_changed(set_variable_data); } -void ChargePoint::on_external_limits_changed(const std::variant& limit, +void ChargePoint::on_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) { auto request = this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta, source); if (request.has_value()) { diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 9ebda84b8..9cbf3dc10 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -27,6 +27,11 @@ using namespace std::chrono; namespace ocpp::v201 { +bool operator==(const ConstantChargingLimit& a, const ConstantChargingLimit& b) { + return std::fabs(a.limit - b.limit) <= std::numeric_limits::epsilon() && + a.charging_rate_unit == b.charging_rate_unit; +} + namespace conversions { std::string profile_validation_result_to_string(ProfileValidationResultEnum e) { switch (e) { @@ -616,19 +621,19 @@ CompositeSchedule SmartChargingHandler::calculate_composite_schedule( return composite_schedule; } -ChargingSchedule create_schedule_from_limit(const float limit) { +ChargingSchedule create_schedule_from_limit(const ConstantChargingLimit limit) { return ChargingSchedule{ .id = 0, - .chargingRateUnit = ChargingRateUnitEnum::A, + .chargingRateUnit = limit.charging_rate_unit, .chargingSchedulePeriod = {ChargingSchedulePeriod{ .startPeriod = 0, - .limit = limit, + .limit = limit.limit, }}, }; } std::optional -SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, +SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) const { // K12.FR.04 if (source == ChargingLimitSourceEnum::CSO) { @@ -650,8 +655,8 @@ SmartChargingHandler::handle_external_limits_changed(const std::variantchargingLimit = {.chargingLimitSource = source}; if (notify_with_schedules.has_value() && notify_with_schedules.value()) { - if (const auto* limit_f = std::get_if(&limit)) { - request->chargingSchedule = {{create_schedule_from_limit(*limit_f)}}; + if (const auto* limit_c = std::get_if(&limit)) { + request->chargingSchedule = {{create_schedule_from_limit(*limit_c)}}; } else if (const auto* limit_s = std::get_if(&limit)) { request->chargingSchedule = {{*limit_s}}; } diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 3299e2100..7d020c44f 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -10,7 +10,7 @@ #include "ocpp/v201/ocpp_enums.hpp" #include "ocpp/v201/smart_charging.hpp" -typedef std::variant ChargingLimitVariant; +typedef std::variant ChargingLimitVariant; namespace ocpp::v201 { class SmartChargingHandlerMock : public SmartChargingHandlerInterface { diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 036e3bd1d..68a374ae2 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -948,11 +948,14 @@ TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); - float limit = 100.0; + ConstantChargingLimit limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - const std::variant new_limit(limit); + const std::variant new_limit(limit); EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(new_limit, deltaChanged, source)); diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 26713349a..c0872cf05 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1688,7 +1688,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.5", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; @@ -1703,7 +1706,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.2", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; @@ -1718,7 +1724,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; @@ -1729,7 +1738,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, TEST_F( SmartChargingHandlerTestFixtureV201, - K12FR03_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_EnableChargingLimitWithSchedulesTrue_IncludesScheduleFromInteger) { + K12FR03_HandleExternalLimitsChanged_LimitChangeSignificanceExceeded_EnableChargingLimitWithSchedulesTrue_IncludesScheduleFromConstantLimit) { const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); @@ -1737,15 +1746,18 @@ TEST_F( device_model->set_value(notify_charging_limit_cv.component, notify_charging_limit_cv.variable.value(), AttributeEnum::Actual, "true", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 50.0, + .charging_rate_unit = ChargingRateUnitEnum::W, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; auto charging_schedule = ChargingSchedule{.id = 0, - .chargingRateUnit = ChargingRateUnitEnum::A, + .chargingRateUnit = new_limit.charging_rate_unit, .chargingSchedulePeriod = {ChargingSchedulePeriod{ .startPeriod = 0, - .limit = new_limit, + .limit = new_limit.limit, }}}; auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); @@ -1789,7 +1801,10 @@ TEST_F( device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; @@ -1809,7 +1824,10 @@ TEST_F( device_model->set_value(notify_charging_limit_cv.component, notify_charging_limit_cv.variable.value(), AttributeEnum::Actual, "false", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; @@ -1824,7 +1842,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::SO; @@ -1839,7 +1860,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); - float new_limit = 100.0; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::CSO; From f288997db9a47fba67940e41cf68542877272520 Mon Sep 17 00:00:00 2001 From: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:59:51 +0000 Subject: [PATCH 05/18] misc: Add evse_id to external limits handler Signed-off-by: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> --- include/ocpp/v201/charge_point.hpp | 7 +++- include/ocpp/v201/smart_charging.hpp | 6 ++- lib/ocpp/v201/charge_point.cpp | 7 +++- lib/ocpp/v201/smart_charging.cpp | 4 +- .../mocks/smart_charging_handler_mock.hpp | 3 +- tests/lib/ocpp/v201/test_charge_point.cpp | 7 +++- .../ocpp/v201/test_smart_charging_handler.cpp | 42 +++++++++++++++---- 7 files changed, 57 insertions(+), 19 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 87501123f..df63769bd 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -251,10 +251,12 @@ class ChargePointInterface { /// \brief Notifies the ChargePoint that a new external limit has been set. This may send a /// NotifyChargingLimitRequest if the \p percentage_delta is greater than our LimitChangeSignificance. + /// \param evse_id ID of the EVSE with the external limit /// \param limit the new external limit /// \param percentage_delta the percent changed from the existing limits /// \param source the source of the external limit (NOTE: Should never be CSO) - virtual void on_external_limits_changed(const std::variant& limit, + virtual void on_external_limits_changed(std::optional evse_id, + const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) = 0; /// \brief Data transfer mechanism initiated by charger @@ -827,7 +829,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_variable_changed(const SetVariableData& set_variable_data) override; - void on_external_limits_changed(const std::variant& limit, + void on_external_limits_changed(std::optional evse_id, + const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) override; std::optional data_transfer_req(const CiString<255>& vendorId, diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index fb3a7c202..76bedec89 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -109,7 +109,8 @@ class SmartChargingHandlerInterface { std::optional charging_rate_unit) = 0; virtual std::optional - handle_external_limits_changed(const std::variant& limit, + handle_external_limits_changed(std::optional evse_id, + const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) const = 0; }; @@ -184,7 +185,8 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { /// based on \p percentage_delta and builds the notification. /// std::optional - handle_external_limits_changed(const std::variant& limit, + handle_external_limits_changed(std::optional evse_id, + const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) const override; protected: diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 3492819d1..afd18d23c 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Pionix GmbH and Contributors to EVerest +#include #include #include #include @@ -1013,9 +1014,11 @@ void ChargePoint::on_variable_changed(const SetVariableData& set_variable_data) this->handle_variable_changed(set_variable_data); } -void ChargePoint::on_external_limits_changed(const std::variant& limit, +void ChargePoint::on_external_limits_changed(std::optional evse_id, + const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) { - auto request = this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta, source); + auto request = + this->smart_charging_handler->handle_external_limits_changed(evse_id, limit, percentage_delta, source); if (request.has_value()) { ocpp::Call call(request.value(), this->message_queue->createMessageId()); this->send(call); diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 9cbf3dc10..24de0b2b2 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -633,7 +633,8 @@ ChargingSchedule create_schedule_from_limit(const ConstantChargingLimit limit) { } std::optional -SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, +SmartChargingHandler::handle_external_limits_changed(std::optional evse_id, + const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) const { // K12.FR.04 if (source == ChargingLimitSourceEnum::CSO) { @@ -653,6 +654,7 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant limit_change_significance) { request = NotifyChargingLimitRequest{}; + request->evseId = evse_id; request->chargingLimit = {.chargingLimitSource = source}; if (notify_with_schedules.has_value() && notify_with_schedules.value()) { if (const auto* limit_c = std::get_if(&limit)) { diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 7d020c44f..1b222951b 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -32,7 +32,8 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit)); MOCK_METHOD(std::optional, handle_external_limits_changed, - (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source), + (std::optional evse_id, const ChargingLimitVariant& limit, double percentage_delta, + ChargingLimitSourceEnum source), (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 68a374ae2..ad8142a2e 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -21,6 +21,7 @@ #include "gmock/gmock.h" #include #include +#include #include #include #include @@ -957,9 +958,11 @@ TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { const std::variant new_limit(limit); - EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(new_limit, deltaChanged, source)); + const std::optional evse_id(DEFAULT_EVSE_ID); - charge_point->on_external_limits_changed(new_limit, deltaChanged, source); + EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(evse_id, new_limit, deltaChanged, source)); + + charge_point->on_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); } } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index c0872cf05..6885d80a0 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -10,6 +10,7 @@ #include "ocpp/v201/device_model_storage_sqlite.hpp" #include "ocpp/v201/init_device_model_db.hpp" #include "ocpp/v201/ocpp_types.hpp" +#include "gmock/gmock.h" #include "gtest/gtest.h" #include #include @@ -1695,7 +1696,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsFalse()); } @@ -1713,7 +1714,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsFalse()); } @@ -1731,7 +1732,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); } @@ -1760,7 +1761,7 @@ TEST_F( .limit = new_limit.limit, }}}; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); @@ -1787,7 +1788,7 @@ TEST_F( .limit = 20, }}}; - auto resp = handler.handle_external_limits_changed(charging_schedule, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, charging_schedule, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); @@ -1808,7 +1809,7 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); @@ -1831,7 +1832,7 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); @@ -1849,7 +1850,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::SO; - auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); @@ -1867,7 +1868,30 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::CSO; - EXPECT_THROW(handler.handle_external_limits_changed(new_limit, deltaChanged, source), std::invalid_argument); + EXPECT_THROW(handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source), + std::invalid_argument); +} + +TEST_F(SmartChargingHandlerTestFixtureV201, K12_HandleExternalLimitsChanged_RequestHasGivenEvseId) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + auto evse_id = 12; + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::SO; + + auto resp = handler.handle_external_limits_changed(evse_id, new_limit, deltaChanged, source); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); + ASSERT_THAT(resp->evseId.has_value(), testing::IsTrue()); + ASSERT_THAT(resp->evseId.value(), testing::Eq(evse_id)); } } // namespace ocpp::v201 From 9cb819acff11b37832cac28c1bcfe022a79ba220 Mon Sep 17 00:00:00 2001 From: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:15:42 +0000 Subject: [PATCH 06/18] misc: Move evse_id param for external limits funcs Signed-off-by: Christopher Davis <150722105+christopher-davis-afs@users.noreply.github.com> --- include/ocpp/v201/charge_point.hpp | 12 +++++------ include/ocpp/v201/smart_charging.hpp | 12 +++++------ lib/ocpp/v201/charge_point.cpp | 8 ++++---- lib/ocpp/v201/smart_charging.cpp | 6 +++--- .../mocks/smart_charging_handler_mock.hpp | 4 ++-- tests/lib/ocpp/v201/test_charge_point.cpp | 4 ++-- .../ocpp/v201/test_smart_charging_handler.cpp | 20 +++++++++---------- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index df63769bd..a9414ff74 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -255,9 +255,9 @@ class ChargePointInterface { /// \param limit the new external limit /// \param percentage_delta the percent changed from the existing limits /// \param source the source of the external limit (NOTE: Should never be CSO) - virtual void on_external_limits_changed(std::optional evse_id, - const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) = 0; + virtual void on_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) = 0; /// \brief Data transfer mechanism initiated by charger /// \param vendorId @@ -829,9 +829,9 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_variable_changed(const SetVariableData& set_variable_data) override; - void on_external_limits_changed(std::optional evse_id, - const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) override; + void on_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) override; std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 76bedec89..0216e6e89 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -109,9 +109,9 @@ class SmartChargingHandlerInterface { std::optional charging_rate_unit) = 0; virtual std::optional - handle_external_limits_changed(std::optional evse_id, - const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const = 0; + handle_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -185,9 +185,9 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { /// based on \p percentage_delta and builds the notification. /// std::optional - handle_external_limits_changed(std::optional evse_id, - const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const override; + handle_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) const override; protected: /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index afd18d23c..6d17ea482 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1014,11 +1014,11 @@ void ChargePoint::on_variable_changed(const SetVariableData& set_variable_data) this->handle_variable_changed(set_variable_data); } -void ChargePoint::on_external_limits_changed(std::optional evse_id, - const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) { +void ChargePoint::on_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) { auto request = - this->smart_charging_handler->handle_external_limits_changed(evse_id, limit, percentage_delta, source); + this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta, source, evse_id); if (request.has_value()) { ocpp::Call call(request.value(), this->message_queue->createMessageId()); this->send(call); diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 24de0b2b2..caa4428b9 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -633,9 +633,9 @@ ChargingSchedule create_schedule_from_limit(const ConstantChargingLimit limit) { } std::optional -SmartChargingHandler::handle_external_limits_changed(std::optional evse_id, - const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const { +SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) const { // K12.FR.04 if (source == ChargingLimitSourceEnum::CSO) { // The spec does not define what we should do when the source diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 1b222951b..c4141db08 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -32,8 +32,8 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit)); MOCK_METHOD(std::optional, handle_external_limits_changed, - (std::optional evse_id, const ChargingLimitVariant& limit, double percentage_delta, - ChargingLimitSourceEnum source), + (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id), (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index ad8142a2e..fb2398d35 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -960,9 +960,9 @@ TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { const std::optional evse_id(DEFAULT_EVSE_ID); - EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(evse_id, new_limit, deltaChanged, source)); + EXPECT_CALL(*smart_charging_handler, handle_external_limits_changed(new_limit, deltaChanged, source, evse_id)); - charge_point->on_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + charge_point->on_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); } } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 6885d80a0..15eedb09c 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1696,7 +1696,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsFalse()); } @@ -1714,7 +1714,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsFalse()); } @@ -1732,7 +1732,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); } @@ -1761,7 +1761,7 @@ TEST_F( .limit = new_limit.limit, }}}; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); @@ -1788,7 +1788,7 @@ TEST_F( .limit = 20, }}}; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, charging_schedule, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(charging_schedule, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); @@ -1809,7 +1809,7 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); @@ -1832,7 +1832,7 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); @@ -1850,7 +1850,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::SO; - auto resp = handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); @@ -1868,7 +1868,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::CSO; - EXPECT_THROW(handler.handle_external_limits_changed(DEFAULT_EVSE_ID, new_limit, deltaChanged, source), + EXPECT_THROW(handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID), std::invalid_argument); } @@ -1886,7 +1886,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12_HandleExternalLimitsChanged_Requ double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::SO; - auto resp = handler.handle_external_limits_changed(evse_id, new_limit, deltaChanged, source); + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, evse_id); ASSERT_THAT(resp.has_value(), testing::IsTrue()); ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); From 17fe4cacc18b325a15077a0b3632c4d016bafc49 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:57:59 +0000 Subject: [PATCH 07/18] smartcharging: added handler for clearing external constraint Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/smart_charging.hpp | 9 +++++++++ lib/ocpp/v201/smart_charging.cpp | 11 +++++++++++ .../mocks/smart_charging_handler_mock.hpp | 4 ++++ .../ocpp/v201/test_smart_charging_handler.cpp | 19 +++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 0216e6e89..200ede1a2 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -5,6 +5,7 @@ #define OCPP_V201_SMART_CHARGING_HPP #include "ocpp/v201/comparators.hpp" +#include "ocpp/v201/messages/ClearedChargingLimit.hpp" #include #include #include @@ -112,6 +113,10 @@ class SmartChargingHandlerInterface { handle_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const = 0; + + virtual ClearedChargingLimitRequest + handle_external_limits_cleared(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -189,6 +194,10 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const override; + virtual ClearedChargingLimitRequest + handle_external_limits_cleared(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) const override; + protected: /// /// \brief validates the existence of the given \p evse_id according to the specification diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index caa4428b9..539498e1b 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -9,6 +9,7 @@ #include "ocpp/v201/ctrlr_component_variables.hpp" #include "ocpp/v201/device_model.hpp" #include "ocpp/v201/evse.hpp" +#include "ocpp/v201/messages/ClearedChargingLimit.hpp" #include "ocpp/v201/messages/NotifyChargingLimit.hpp" #include "ocpp/v201/messages/SetChargingProfile.hpp" #include "ocpp/v201/ocpp_enums.hpp" @@ -668,4 +669,14 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, + double percentage_delta, ChargingLimitSourceEnum source) const { + // K13.FR.02 + ClearedChargingLimitRequest request = {}; + request.chargingLimitSource = source; + + return request; +} + } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index c4141db08..3b05afcf7 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -6,6 +6,7 @@ #include #include +#include "ocpp/v201/messages/ClearedChargingLimit.hpp" #include "ocpp/v201/messages/SetChargingProfile.hpp" #include "ocpp/v201/ocpp_enums.hpp" #include "ocpp/v201/smart_charging.hpp" @@ -35,5 +36,8 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id), (const, override)); + MOCK_METHOD(ClearedChargingLimitRequest, handle_external_limits_cleared, + (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source), + (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 15eedb09c..9cd78c189 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1894,4 +1894,23 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12_HandleExternalLimitsChanged_Requ ASSERT_THAT(resp->evseId.value(), testing::Eq(evse_id)); } +TEST_F(SmartChargingHandlerTestFixtureV201, + K13FR02_HandleClearedChargingLimitRequest_ReturnsClearedChargingLimitRequest) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.5", + "test"); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_external_limits_cleared(new_limit, deltaChanged, source); + + // Not sure what else to assert on this get sent no matter what. + ASSERT_THAT(resp.chargingLimitSource, testing::Eq(source)); +} + } // namespace ocpp::v201 From 287b4b0b56c00949922ccc1bbc311d513e55d6dc Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:44:51 +0000 Subject: [PATCH 08/18] smartcharging: updated return to handle both request types Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/smart_charging.hpp | 7 +++++-- lib/ocpp/v201/smart_charging.cpp | 13 ++++++++----- .../ocpp/v201/mocks/smart_charging_handler_mock.hpp | 3 ++- tests/lib/ocpp/v201/test_smart_charging_handler.cpp | 7 +++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 200ede1a2..186710354 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -6,8 +6,11 @@ #include "ocpp/v201/comparators.hpp" #include "ocpp/v201/messages/ClearedChargingLimit.hpp" +#include "ocpp/v201/messages/TransactionEvent.hpp" #include #include +#include +#include #include #include @@ -114,7 +117,7 @@ class SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const = 0; - virtual ClearedChargingLimitRequest + virtual std::pair> handle_external_limits_cleared(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) const = 0; }; @@ -194,7 +197,7 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const override; - virtual ClearedChargingLimitRequest + virtual std::pair> handle_external_limits_cleared(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source) const override; diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 539498e1b..927143e2f 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include using namespace std::chrono; @@ -669,14 +670,16 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant> SmartChargingHandler::handle_external_limits_cleared(const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const { + double percentage_delta, ChargingLimitSourceEnum source) const { // K13.FR.02 - ClearedChargingLimitRequest request = {}; - request.chargingLimitSource = source; + ClearedChargingLimitRequest cleared_charging_limit_request = {}; + cleared_charging_limit_request.chargingLimitSource = source; - return request; + auto requests = std::make_pair(cleared_charging_limit_request, std::nullopt); + + return requests; } } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 3b05afcf7..fad285c02 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -36,7 +36,8 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id), (const, override)); - MOCK_METHOD(ClearedChargingLimitRequest, handle_external_limits_cleared, + MOCK_METHOD((std::pair>), + handle_external_limits_cleared, (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source), (const, override)); }; diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 9cd78c189..876676563 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1909,8 +1909,11 @@ TEST_F(SmartChargingHandlerTestFixtureV201, auto resp = handler.handle_external_limits_cleared(new_limit, deltaChanged, source); - // Not sure what else to assert on this get sent no matter what. - ASSERT_THAT(resp.chargingLimitSource, testing::Eq(source)); + auto cleared_charging_limit_request = resp.first; + auto transaction_event_request = resp.second; + + ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); + ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); } } // namespace ocpp::v201 From 2e95cf4aed2096a8c0d41d6959661d4de0f55a59 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:00:31 +0000 Subject: [PATCH 09/18] smartcharging: added logic to check limit change significance and send TransactionEventRequest Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- lib/ocpp/v201/smart_charging.cpp | 13 +++++- .../ocpp/v201/test_smart_charging_handler.cpp | 46 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 927143e2f..81a4657ce 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -677,7 +677,18 @@ SmartChargingHandler::handle_external_limits_cleared(const std::variant transaction_event_request = {}; + + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + const float limit_change_significance = this->device_model->get_value(limit_change_cv); + + // K13.FR.03 + if (percentage_delta > limit_change_significance) { + transaction_event_request = TransactionEventRequest{}; + transaction_event_request->triggerReason = TriggerReasonEnum::ChargingRateChanged; + } + + auto requests = std::make_pair(cleared_charging_limit_request, transaction_event_request); return requests; } diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 876676563..4de1258a7 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1916,4 +1916,50 @@ TEST_F(SmartChargingHandlerTestFixtureV201, ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); } +TEST_F(SmartChargingHandlerTestFixtureV201, + K13FR02_HandleClearedChargingLimitRequest_LimitChangeSignificanceEqual_ReturnsClearedChargingLimitRequest) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.2", + "test"); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_cleared_charging_limit(new_limit, deltaChanged, source); + + auto cleared_charging_limit_request = resp.first; + auto transaction_event_request = resp.second; + + ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); + ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K13FR02_HandleClearedChargingLimitRequest_LimitChangeSignificanceExceeded_ReturnsClearedChargingLimitRequestAndTransactionEventRequest) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_cleared_charging_limit(new_limit, deltaChanged, source); + + auto cleared_charging_limit_request = resp.first; + auto transaction_event_request = resp.second; + + ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); + ASSERT_THAT(transaction_event_request.has_value(), testing::IsTrue()); + ASSERT_THAT(transaction_event_request.value().triggerReason, TriggerReasonEnum::ChargingRateChanged); +} + } // namespace ocpp::v201 From ba21483b472d0d3a259819360c300be71ec81702 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:21:19 +0000 Subject: [PATCH 10/18] charge point: added public method to notify csms when external limit is cleared Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- doc/ocpp_201_status.md | 4 ++-- include/ocpp/v201/charge_point.hpp | 9 +++++++++ include/ocpp/v201/smart_charging.hpp | 6 ++---- lib/ocpp/v201/charge_point.cpp | 16 ++++++++++++++++ lib/ocpp/v201/smart_charging.cpp | 3 +-- .../v201/mocks/smart_charging_handler_mock.hpp | 3 +-- tests/lib/ocpp/v201/test_charge_point.cpp | 17 +++++++++++++++++ .../ocpp/v201/test_smart_charging_handler.cpp | 15 ++++++--------- 8 files changed, 54 insertions(+), 19 deletions(-) diff --git a/doc/ocpp_201_status.md b/doc/ocpp_201_status.md index d69e4e4c0..0164c1ad3 100644 --- a/doc/ocpp_201_status.md +++ b/doc/ocpp_201_status.md @@ -1400,8 +1400,8 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir | ID | Status | Remark | |-----------|--------|--------| | K13.FR.01 | | | -| K13.FR.02 | | | -| K13.FR.03 | | | +| K13.FR.02 | ✅ | | +| K13.FR.03 | ✅ | | ## SmartCharging - External Charging Limit with Local Controller diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index a9414ff74..9c8d03027 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -259,6 +259,13 @@ class ChargePointInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) = 0; + /// \brief Notifies the ChargePoint that an external limit has been cleared. + /// This shall send a ClearedChargingLimitRequest when called. + // This may send TransactionEventRequest if the \p percentage_delta is greater than our LimitChangeSignificance. + /// \param percentage_delta the percent changed from the existing limits + /// \param source the source of the external limit + virtual void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) = 0; + /// \brief Data transfer mechanism initiated by charger /// \param vendorId /// \param messageId @@ -832,6 +839,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) override; + + void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) override; std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 186710354..51d6671cf 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -118,8 +118,7 @@ class SmartChargingHandlerInterface { std::optional evse_id) const = 0; virtual std::pair> - handle_external_limits_cleared(const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const = 0; + handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -198,8 +197,7 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { std::optional evse_id) const override; virtual std::pair> - handle_external_limits_cleared(const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const override; + handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const override; protected: /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 6d17ea482..6964e6267 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1025,6 +1025,22 @@ void ChargePoint::on_external_limits_changed(const std::variantsmart_charging_handler->handle_external_limit_cleared(percentage_delta, source); + + auto [cleared_charging_limit_request, transaction_event_request] = request; + + ocpp::Call call(cleared_charging_limit_request, + this->message_queue->createMessageId()); + this->send(call); + + if (transaction_event_request.has_value()) { + ocpp::Call call(transaction_event_request.value(), + this->message_queue->createMessageId()); + this->send(call); + } +} + bool ChargePoint::send(CallError call_error) { this->message_queue->push(call_error); return true; diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 81a4657ce..0589b9e84 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -671,8 +671,7 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant> -SmartChargingHandler::handle_external_limits_cleared(const std::variant& limit, - double percentage_delta, ChargingLimitSourceEnum source) const { +SmartChargingHandler::handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const { // K13.FR.02 ClearedChargingLimitRequest cleared_charging_limit_request = {}; cleared_charging_limit_request.chargingLimitSource = source; diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index fad285c02..51e7e3f48 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -37,8 +37,7 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { std::optional evse_id), (const, override)); MOCK_METHOD((std::pair>), - handle_external_limits_cleared, - (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source), + handle_external_limit_cleared, (double percentage_delta, ChargingLimitSourceEnum source), (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index fb2398d35..455535183 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -965,4 +965,21 @@ TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { charge_point->on_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); } +TEST_F(ChargepointTestFixtureV201, K13_OnExternalLimitsCleared_CallsHandler) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + ConstantChargingLimit limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + EXPECT_CALL(*smart_charging_handler, handle_external_limit_cleared(deltaChanged, source)); + + charge_point->on_external_limit_cleared(deltaChanged, source); +} + } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 4de1258a7..a5f709c7d 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1907,10 +1907,9 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limits_cleared(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source); - auto cleared_charging_limit_request = resp.first; - auto transaction_event_request = resp.second; + auto [cleared_charging_limit_request, transaction_event_request] = resp; ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); @@ -1929,10 +1928,9 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_cleared_charging_limit(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source); - auto cleared_charging_limit_request = resp.first; - auto transaction_event_request = resp.second; + auto [cleared_charging_limit_request, transaction_event_request] = resp; ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); @@ -1952,10 +1950,9 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_cleared_charging_limit(new_limit, deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source); - auto cleared_charging_limit_request = resp.first; - auto transaction_event_request = resp.second; + auto [cleared_charging_limit_request, transaction_event_request] = resp; ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); ASSERT_THAT(transaction_event_request.has_value(), testing::IsTrue()); From 33437bd0be5579dda43f7ed9df1e6e14104b6866 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:07:40 +0000 Subject: [PATCH 11/18] smart charging: updated transaction even with additional attributes but some details are still needed. Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- lib/ocpp/v201/smart_charging.cpp | 5 +++++ tests/lib/ocpp/v201/test_smart_charging_handler.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 0589b9e84..de6faae11 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -684,7 +684,12 @@ SmartChargingHandler::handle_external_limit_cleared(double percentage_delta, Cha // K13.FR.03 if (percentage_delta > limit_change_significance) { transaction_event_request = TransactionEventRequest{}; + transaction_event_request->eventType = TransactionEventEnum::Updated; + transaction_event_request->timestamp = ocpp::DateTime(); transaction_event_request->triggerReason = TriggerReasonEnum::ChargingRateChanged; + // TODO: there are transaction specific attributes in this type. + // It is unclear how transactions are used when a external constraint is cleared. + // This will need to be updated based on further discussion. } auto requests = std::make_pair(cleared_charging_limit_request, transaction_event_request); diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index a5f709c7d..4e9eaa3fb 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1956,6 +1956,7 @@ TEST_F( ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); ASSERT_THAT(transaction_event_request.has_value(), testing::IsTrue()); + ASSERT_THAT(transaction_event_request.value().eventType, TransactionEventEnum::Updated); ASSERT_THAT(transaction_event_request.value().triggerReason, TriggerReasonEnum::ChargingRateChanged); } From 8a9854a088247b95ac8210267539ab31e67aeadc Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:59:10 +0000 Subject: [PATCH 12/18] updated: using vector to pass back multiple TransactionEventRequest. Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/smart_charging.hpp | 4 ++-- lib/ocpp/v201/charge_point.cpp | 11 ++++++----- lib/ocpp/v201/smart_charging.cpp | 15 ++++++++------- .../v201/mocks/smart_charging_handler_mock.hpp | 2 +- .../ocpp/v201/test_smart_charging_handler.cpp | 17 +++++++++-------- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 51d6671cf..2a4a07447 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -117,7 +117,7 @@ class SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const = 0; - virtual std::pair> + virtual std::pair> handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const = 0; }; @@ -196,7 +196,7 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const override; - virtual std::pair> + virtual std::pair> handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const override; protected: diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 6964e6267..f0fc6adef 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1028,16 +1028,17 @@ void ChargePoint::on_external_limits_changed(const std::variantsmart_charging_handler->handle_external_limit_cleared(percentage_delta, source); - auto [cleared_charging_limit_request, transaction_event_request] = request; + auto [cleared_charging_limit_request, transaction_event_requests] = request; ocpp::Call call(cleared_charging_limit_request, this->message_queue->createMessageId()); this->send(call); - if (transaction_event_request.has_value()) { - ocpp::Call call(transaction_event_request.value(), - this->message_queue->createMessageId()); - this->send(call); + if (transaction_event_requests.size() > 0) { + for (auto transaction_event_request : transaction_event_requests) { + ocpp::Call call(transaction_event_request, this->message_queue->createMessageId()); + this->send(call); + } } } diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index de6faae11..64d46e702 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -670,29 +670,30 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant> +std::pair> SmartChargingHandler::handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const { // K13.FR.02 ClearedChargingLimitRequest cleared_charging_limit_request = {}; cleared_charging_limit_request.chargingLimitSource = source; - std::optional transaction_event_request = {}; + std::vector transaction_event_requests = {}; const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; const float limit_change_significance = this->device_model->get_value(limit_change_cv); // K13.FR.03 if (percentage_delta > limit_change_significance) { - transaction_event_request = TransactionEventRequest{}; - transaction_event_request->eventType = TransactionEventEnum::Updated; - transaction_event_request->timestamp = ocpp::DateTime(); - transaction_event_request->triggerReason = TriggerReasonEnum::ChargingRateChanged; + auto tmp = TransactionEventRequest{}; + tmp.eventType = TransactionEventEnum::Updated; + tmp.timestamp = ocpp::DateTime(); + tmp.triggerReason = TriggerReasonEnum::ChargingRateChanged; // TODO: there are transaction specific attributes in this type. // It is unclear how transactions are used when a external constraint is cleared. // This will need to be updated based on further discussion. + transaction_event_requests.push_back(tmp); } - auto requests = std::make_pair(cleared_charging_limit_request, transaction_event_request); + auto requests = std::make_pair(cleared_charging_limit_request, transaction_event_requests); return requests; } diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 51e7e3f48..e987fb273 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -36,7 +36,7 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id), (const, override)); - MOCK_METHOD((std::pair>), + MOCK_METHOD((std::pair>), handle_external_limit_cleared, (double percentage_delta, ChargingLimitSourceEnum source), (const, override)); }; diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 4e9eaa3fb..9c2ad96d8 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1909,10 +1909,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, auto resp = handler.handle_external_limit_cleared(deltaChanged, source); - auto [cleared_charging_limit_request, transaction_event_request] = resp; + auto [cleared_charging_limit_request, transaction_event_requests] = resp; ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); + ASSERT_THAT(transaction_event_requests.size(), testing::Eq(0)); } TEST_F(SmartChargingHandlerTestFixtureV201, @@ -1930,10 +1930,10 @@ TEST_F(SmartChargingHandlerTestFixtureV201, auto resp = handler.handle_external_limit_cleared(deltaChanged, source); - auto [cleared_charging_limit_request, transaction_event_request] = resp; + auto [cleared_charging_limit_request, transaction_event_requests] = resp; ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(transaction_event_request.has_value(), testing::IsFalse()); + ASSERT_THAT(transaction_event_requests.size(), testing::Eq(0)); } TEST_F( @@ -1952,12 +1952,13 @@ TEST_F( auto resp = handler.handle_external_limit_cleared(deltaChanged, source); - auto [cleared_charging_limit_request, transaction_event_request] = resp; + auto [cleared_charging_limit_request, transaction_event_requests] = resp; ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(transaction_event_request.has_value(), testing::IsTrue()); - ASSERT_THAT(transaction_event_request.value().eventType, TransactionEventEnum::Updated); - ASSERT_THAT(transaction_event_request.value().triggerReason, TriggerReasonEnum::ChargingRateChanged); + + ASSERT_THAT(transaction_event_requests.size(), testing::Eq(1)); + ASSERT_THAT(transaction_event_requests.at(0).eventType, TransactionEventEnum::Updated); + ASSERT_THAT(transaction_event_requests.at(0).triggerReason, TriggerReasonEnum::ChargingRateChanged); } } // namespace ocpp::v201 From 2f2267fb09f9c5e944da8fe7c06b344e2cf827bd Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:43:08 +0000 Subject: [PATCH 13/18] updated: added optional evse_id to on_handle method Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/charge_point.hpp | 9 ++++++--- lib/ocpp/v201/charge_point.cpp | 3 ++- tests/lib/ocpp/v201/test_charge_point.cpp | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 9c8d03027..a963b044e 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -262,9 +262,11 @@ class ChargePointInterface { /// \brief Notifies the ChargePoint that an external limit has been cleared. /// This shall send a ClearedChargingLimitRequest when called. // This may send TransactionEventRequest if the \p percentage_delta is greater than our LimitChangeSignificance. + /// \param evse_id if provided checks for transactions on the provided evse /// \param percentage_delta the percent changed from the existing limits /// \param source the source of the external limit - virtual void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) = 0; + virtual void on_external_limit_cleared(std::optional evse_id, double percentage_delta, + ChargingLimitSourceEnum source) = 0; /// \brief Data transfer mechanism initiated by charger /// \param vendorId @@ -839,8 +841,9 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void on_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) override; - - void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) override; + + void on_external_limit_cleared(std::optional evse_id, double percentage_delta, + ChargingLimitSourceEnum source) override; std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index f0fc6adef..c74f6ba6a 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1025,7 +1025,8 @@ void ChargePoint::on_external_limits_changed(const std::variant evse_id, double percentage_delta, + ChargingLimitSourceEnum source) { auto request = this->smart_charging_handler->handle_external_limit_cleared(percentage_delta, source); auto [cleared_charging_limit_request, transaction_event_requests] = request; diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 455535183..1c88425fd 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include static const int DEFAULT_EVSE_ID = 1; @@ -979,7 +980,7 @@ TEST_F(ChargepointTestFixtureV201, K13_OnExternalLimitsCleared_CallsHandler) { EXPECT_CALL(*smart_charging_handler, handle_external_limit_cleared(deltaChanged, source)); - charge_point->on_external_limit_cleared(deltaChanged, source); + charge_point->on_external_limit_cleared(std::nullopt, deltaChanged, source); } } // namespace ocpp::v201 From 103876632c04a689c1637f748be4b83c103643d2 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:53:53 +0000 Subject: [PATCH 14/18] updated: added optional evse_id to handler and passed Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/smart_charging.hpp | 8 +++++--- lib/ocpp/v201/charge_point.cpp | 2 +- lib/ocpp/v201/smart_charging.cpp | 3 ++- tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp | 3 ++- tests/lib/ocpp/v201/test_charge_point.cpp | 4 +++- tests/lib/ocpp/v201/test_smart_charging_handler.cpp | 6 +++--- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index 2a4a07447..ee49495af 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -118,7 +118,8 @@ class SmartChargingHandlerInterface { std::optional evse_id) const = 0; virtual std::pair> - handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const = 0; + handle_external_limit_cleared(std::optional evse_id, double percentage_delta, + ChargingLimitSourceEnum source) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -188,7 +189,7 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { std::optional charging_rate_unit) override; /// - /// \brief Determines whether or not we should notify the CSMS of a change to our limits + /// \brief Determines whether or not we should notify the CSMS of a cleared external limit /// based on \p percentage_delta and builds the notification. /// std::optional @@ -197,7 +198,8 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { std::optional evse_id) const override; virtual std::pair> - handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const override; + handle_external_limit_cleared(std::optional evse_id, double percentage_delta, + ChargingLimitSourceEnum source) const override; protected: /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index c74f6ba6a..4022a331e 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1027,7 +1027,7 @@ void ChargePoint::on_external_limits_changed(const std::variant evse_id, double percentage_delta, ChargingLimitSourceEnum source) { - auto request = this->smart_charging_handler->handle_external_limit_cleared(percentage_delta, source); + auto request = this->smart_charging_handler->handle_external_limit_cleared(evse_id, percentage_delta, source); auto [cleared_charging_limit_request, transaction_event_requests] = request; diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 64d46e702..ddbf4ed2a 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -671,7 +671,8 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant> -SmartChargingHandler::handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source) const { +SmartChargingHandler::handle_external_limit_cleared(std::optional evse_id, double percentage_delta, + ChargingLimitSourceEnum source) const { // K13.FR.02 ClearedChargingLimitRequest cleared_charging_limit_request = {}; cleared_charging_limit_request.chargingLimitSource = source; diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index e987fb273..84356c6bb 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -37,7 +37,8 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { std::optional evse_id), (const, override)); MOCK_METHOD((std::pair>), - handle_external_limit_cleared, (double percentage_delta, ChargingLimitSourceEnum source), + handle_external_limit_cleared, + (std::optional evse_id, double percentage_delta, ChargingLimitSourceEnum source), (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 1c88425fd..ebb063cb0 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -975,10 +975,12 @@ TEST_F(ChargepointTestFixtureV201, K13_OnExternalLimitsCleared_CallsHandler) { .limit = 100.0, .charging_rate_unit = ChargingRateUnitEnum::A, }; + + std::optional evse_id; double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - EXPECT_CALL(*smart_charging_handler, handle_external_limit_cleared(deltaChanged, source)); + EXPECT_CALL(*smart_charging_handler, handle_external_limit_cleared(evse_id, deltaChanged, source)); charge_point->on_external_limit_cleared(std::nullopt, deltaChanged, source); } diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 9c2ad96d8..098434e7c 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1907,7 +1907,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limit_cleared(deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(std::nullopt, deltaChanged, source); auto [cleared_charging_limit_request, transaction_event_requests] = resp; @@ -1928,7 +1928,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limit_cleared(deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(std::nullopt, deltaChanged, source); auto [cleared_charging_limit_request, transaction_event_requests] = resp; @@ -1950,7 +1950,7 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limit_cleared(deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(std::nullopt, deltaChanged, source); auto [cleared_charging_limit_request, transaction_event_requests] = resp; From 025de7a681614cd3e49eb9a08e37097d501379c6 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Mon, 7 Oct 2024 17:29:33 +0000 Subject: [PATCH 15/18] updated: check for open transaction on an evse Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/charge_point.hpp | 10 +- include/ocpp/v201/smart_charging.hpp | 13 +- lib/ocpp/v201/charge_point.cpp | 26 +-- lib/ocpp/v201/smart_charging.cpp | 81 +++++++--- .../mocks/smart_charging_handler_mock.hpp | 4 +- tests/lib/ocpp/v201/test_charge_point.cpp | 4 +- .../ocpp/v201/test_smart_charging_handler.cpp | 148 +++++++++++++++--- 7 files changed, 224 insertions(+), 62 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index a963b044e..f76bdf4c2 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -262,11 +262,11 @@ class ChargePointInterface { /// \brief Notifies the ChargePoint that an external limit has been cleared. /// This shall send a ClearedChargingLimitRequest when called. // This may send TransactionEventRequest if the \p percentage_delta is greater than our LimitChangeSignificance. - /// \param evse_id if provided checks for transactions on the provided evse /// \param percentage_delta the percent changed from the existing limits /// \param source the source of the external limit - virtual void on_external_limit_cleared(std::optional evse_id, double percentage_delta, - ChargingLimitSourceEnum source) = 0; + /// \param evse_id if provided checks for transactions on the provided evse + virtual void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) = 0; /// \brief Data transfer mechanism initiated by charger /// \param vendorId @@ -842,8 +842,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) override; - void on_external_limit_cleared(std::optional evse_id, double percentage_delta, - ChargingLimitSourceEnum source) override; + void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) override; std::optional data_transfer_req(const CiString<255>& vendorId, const std::optional>& messageId, diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index ee49495af..dd612690f 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -117,9 +117,9 @@ class SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const = 0; - virtual std::pair> - handle_external_limit_cleared(std::optional evse_id, double percentage_delta, - ChargingLimitSourceEnum source) const = 0; + virtual std::optional>> + handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) const = 0; }; /// \brief This class handles and maintains incoming ChargingProfiles and contains the logic @@ -197,9 +197,9 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const override; - virtual std::pair> - handle_external_limit_cleared(std::optional evse_id, double percentage_delta, - ChargingLimitSourceEnum source) const override; + virtual std::optional>> + handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) const override; protected: /// @@ -254,6 +254,7 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { std::vector get_valid_profiles_for_evse(int32_t evse_id); void conform_validity_periods(ChargingProfile& profile) const; CurrentPhaseType get_current_phase_type(const std::optional evse_opt) const; + TransactionEventRequest create_transaction_event_request(std::unique_ptr& tx) const; }; } // namespace ocpp::v201 diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 4022a331e..1ecd11b9b 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1025,20 +1025,24 @@ void ChargePoint::on_external_limits_changed(const std::variant evse_id, double percentage_delta, - ChargingLimitSourceEnum source) { - auto request = this->smart_charging_handler->handle_external_limit_cleared(evse_id, percentage_delta, source); +void ChargePoint::on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) { + auto request = this->smart_charging_handler->handle_external_limit_cleared(percentage_delta, source, evse_id); - auto [cleared_charging_limit_request, transaction_event_requests] = request; + if (request.has_value()) { + + auto [cleared_charging_limit_request, transaction_event_requests] = request.value(); - ocpp::Call call(cleared_charging_limit_request, - this->message_queue->createMessageId()); - this->send(call); + ocpp::Call call(cleared_charging_limit_request, + this->message_queue->createMessageId()); + this->send(call); - if (transaction_event_requests.size() > 0) { - for (auto transaction_event_request : transaction_event_requests) { - ocpp::Call call(transaction_event_request, this->message_queue->createMessageId()); - this->send(call); + if (transaction_event_requests.size() > 0) { + for (auto transaction_event_request : transaction_event_requests) { + ocpp::Call call(transaction_event_request, + this->message_queue->createMessageId()); + this->send(call); + } } } } diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index ddbf4ed2a..4bbcd6852 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -12,9 +12,11 @@ #include "ocpp/v201/messages/ClearedChargingLimit.hpp" #include "ocpp/v201/messages/NotifyChargingLimit.hpp" #include "ocpp/v201/messages/SetChargingProfile.hpp" +#include "ocpp/v201/messages/TransactionEvent.hpp" #include "ocpp/v201/ocpp_enums.hpp" #include "ocpp/v201/ocpp_types.hpp" #include "ocpp/v201/profile.hpp" +#include "ocpp/v201/transaction.hpp" #include "ocpp/v201/utils.hpp" #include #include @@ -670,33 +672,76 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant> -SmartChargingHandler::handle_external_limit_cleared(std::optional evse_id, double percentage_delta, - ChargingLimitSourceEnum source) const { - // K13.FR.02 - ClearedChargingLimitRequest cleared_charging_limit_request = {}; - cleared_charging_limit_request.chargingLimitSource = source; +std::optional>> +SmartChargingHandler::handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, + std::optional evse_id) const { + bool has_transaction = false; + + std::pair> pair; std::vector transaction_event_requests = {}; const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; const float limit_change_significance = this->device_model->get_value(limit_change_cv); - // K13.FR.03 - if (percentage_delta > limit_change_significance) { - auto tmp = TransactionEventRequest{}; - tmp.eventType = TransactionEventEnum::Updated; - tmp.timestamp = ocpp::DateTime(); - tmp.triggerReason = TriggerReasonEnum::ChargingRateChanged; - // TODO: there are transaction specific attributes in this type. - // It is unclear how transactions are used when a external constraint is cleared. - // This will need to be updated based on further discussion. - transaction_event_requests.push_back(tmp); + if (evse_id.has_value()) { + auto evse = &this->evse_manager.get_evse(evse_id.value()); + if (evse->has_active_transaction()) { + has_transaction = true; + // K13.FR.03 + if (percentage_delta > limit_change_significance) { + auto& tx = evse->get_transaction(); + transaction_event_requests.push_back(this->create_transaction_event_request(tx)); + } + } + } else { + for (auto& evse : this->evse_manager) { + if (evse.has_active_transaction()) { + has_transaction = true; + + // K13.FR.03 + if (percentage_delta > limit_change_significance) { + + auto& tx = evse.get_transaction(); + transaction_event_requests.push_back(this->create_transaction_event_request(tx)); + } + } + } } - auto requests = std::make_pair(cleared_charging_limit_request, transaction_event_requests); + std::optional>> request; + + if (has_transaction) { + // K13.FR.02 + ClearedChargingLimitRequest cleared_charging_limit_request = {}; + + if (evse_id.has_value()) { + cleared_charging_limit_request.evseId = evse_id.value(); + } + + // There is not restriction on this source in the spec. + // K12.FR04 requires it not to be CSO. Not enforced here. + cleared_charging_limit_request.chargingLimitSource = source; + pair.first = cleared_charging_limit_request; + + pair.second = transaction_event_requests; + request.emplace(pair); + } + + return request; +} + +TransactionEventRequest +SmartChargingHandler::create_transaction_event_request(std::unique_ptr& tx) const { + auto tmp = TransactionEventRequest{}; + tmp.eventType = TransactionEventEnum::Updated; + tmp.timestamp = ocpp::DateTime(); + tmp.triggerReason = TriggerReasonEnum::ChargingRateChanged; + + tmp.seqNo = tx->get_seq_no(); + tmp.transactionInfo = tx->get_transaction(); - return requests; + return tmp; } } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index 84356c6bb..f51ba0273 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -36,9 +36,9 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id), (const, override)); - MOCK_METHOD((std::pair>), + MOCK_METHOD((std::optional>>), handle_external_limit_cleared, - (std::optional evse_id, double percentage_delta, ChargingLimitSourceEnum source), + (double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id), (const, override)); }; } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index ebb063cb0..43f308c3c 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -980,9 +980,9 @@ TEST_F(ChargepointTestFixtureV201, K13_OnExternalLimitsCleared_CallsHandler) { double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - EXPECT_CALL(*smart_charging_handler, handle_external_limit_cleared(evse_id, deltaChanged, source)); + EXPECT_CALL(*smart_charging_handler, handle_external_limit_cleared(deltaChanged, source, evse_id)); - charge_point->on_external_limit_cleared(std::nullopt, deltaChanged, source); + charge_point->on_external_limit_cleared(deltaChanged, source, std::nullopt); } } // namespace ocpp::v201 diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 098434e7c..915cf1689 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1895,7 +1895,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12_HandleExternalLimitsChanged_Requ } TEST_F(SmartChargingHandlerTestFixtureV201, - K13FR02_HandleClearedChargingLimitRequest_ReturnsClearedChargingLimitRequest) { + K13FR01_HandleClearedChargingLimitRequest_NoTransactionForEvseId_NoRequestCreated) { const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.5", "test"); @@ -1907,16 +1907,63 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limit_cleared(std::nullopt, deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, DEFAULT_EVSE_ID); - auto [cleared_charging_limit_request, transaction_event_requests] = resp; - - ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(transaction_event_requests.size(), testing::Eq(0)); + ASSERT_THAT(resp.has_value(), testing::IsFalse()); } TEST_F(SmartChargingHandlerTestFixtureV201, - K13FR02_HandleClearedChargingLimitRequest_LimitChangeSignificanceEqual_ReturnsClearedChargingLimitRequest) { + K13FR01_HandleClearedChargingLimitRequest_NoTransactionExists_NoRequestCreated) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, std::nullopt); + ASSERT_THAT(resp.has_value(), testing::IsFalse()); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K13FR02_HandleClearedChargingLimitRequest_TransactionForEvseId_UnderLimitChangeSignificance_OnlyClearedChargingLimitRequest) { + + std::string transaction_id = uuid(); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID, transaction_id); + + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.5", + "test"); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, DEFAULT_EVSE_ID); + + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + auto [f, s] = resp.value(); + ASSERT_THAT(f.evseId, testing::Eq(DEFAULT_EVSE_ID)); + ASSERT_THAT(f.chargingLimitSource, testing::Eq(source)); + + ASSERT_THAT(s.size(), testing::Eq(0)); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K13FR02_HandleClearedChargingLimitRequest_TransactionForEvseId_LimitChangeSignificanceEqual_OnlyClearedChargingLimitRequest) { + + std::string transaction_id = uuid(); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID, transaction_id); + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.2", "test"); @@ -1928,17 +1975,52 @@ TEST_F(SmartChargingHandlerTestFixtureV201, double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limit_cleared(std::nullopt, deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, DEFAULT_EVSE_ID); + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + auto [f, s] = resp.value(); + ASSERT_THAT(f.evseId, testing::Eq(DEFAULT_EVSE_ID)); + ASSERT_THAT(f.chargingLimitSource, testing::Eq(source)); + + ASSERT_THAT(s.size(), testing::Eq(0)); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K13FR03_HandleClearedChargingLimitRequest_HasTransaction_LimitChangeSignificanceExceeded_BothClearedChargingLimitRequestAndTransactionEventRequest) { - auto [cleared_charging_limit_request, transaction_event_requests] = resp; + std::string transaction_id = uuid(); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID, transaction_id); + + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); - ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(transaction_event_requests.size(), testing::Eq(0)); + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, DEFAULT_EVSE_ID); + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + auto [f, s] = resp.value(); + ASSERT_THAT(f.evseId, testing::Eq(DEFAULT_EVSE_ID)); + ASSERT_THAT(f.chargingLimitSource, testing::Eq(source)); + + ASSERT_THAT(s.size(), testing::Eq(1)); + ASSERT_THAT(s.at(0).eventType, testing::Eq(TransactionEventEnum::Updated)); + ASSERT_THAT(s.at(0).triggerReason, testing::Eq(TriggerReasonEnum::ChargingRateChanged)); + ASSERT_THAT(s.at(0).transactionInfo.transactionId, testing::Eq(CiString<36>(transaction_id))); } TEST_F( SmartChargingHandlerTestFixtureV201, - K13FR02_HandleClearedChargingLimitRequest_LimitChangeSignificanceExceeded_ReturnsClearedChargingLimitRequestAndTransactionEventRequest) { + K13FR03_HandleClearedChargingLimitRequest_NoEvseId_TransactionExists_LimitChangeSignificanceExceeded_BothClearedChargingLimitRequestAndSingleTransactionEventRequest) { + + std::string transaction_id = uuid(); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID, transaction_id); + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); @@ -1950,15 +2032,45 @@ TEST_F( double deltaChanged = 0.2; auto source = ChargingLimitSourceEnum::Other; - auto resp = handler.handle_external_limit_cleared(std::nullopt, deltaChanged, source); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, std::nullopt); + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + auto [f, s] = resp.value(); + ASSERT_THAT(f.evseId.has_value(), testing::IsFalse()); + ASSERT_THAT(f.chargingLimitSource, testing::Eq(source)); + + ASSERT_THAT(s.size(), testing::Eq(1)); + ASSERT_THAT(s.at(0).eventType, testing::Eq(TransactionEventEnum::Updated)); + ASSERT_THAT(s.at(0).triggerReason, testing::Eq(TriggerReasonEnum::ChargingRateChanged)); + ASSERT_THAT(s.at(0).transactionInfo.transactionId, testing::Eq(CiString<36>(transaction_id))); +} + +TEST_F( + SmartChargingHandlerTestFixtureV201, + K13FR03_HandleClearedChargingLimitRequest_NoEvseId_TransactionsExist_LimitChangeSignificanceExceeded_BothClearedChargingLimitRequestAndMultipleTransactionEventRequest) { + + std::string transaction_id_a = uuid(); + std::string transaction_id_b = uuid(); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID, transaction_id_a); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID + 1, transaction_id_b); + + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); - auto [cleared_charging_limit_request, transaction_event_requests] = resp; + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; - ASSERT_THAT(cleared_charging_limit_request.chargingLimitSource, testing::Eq(source)); + auto resp = handler.handle_external_limit_cleared(deltaChanged, source, std::nullopt); + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + auto [f, s] = resp.value(); + ASSERT_THAT(f.evseId.has_value(), testing::IsFalse()); + ASSERT_THAT(f.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(transaction_event_requests.size(), testing::Eq(1)); - ASSERT_THAT(transaction_event_requests.at(0).eventType, TransactionEventEnum::Updated); - ASSERT_THAT(transaction_event_requests.at(0).triggerReason, TriggerReasonEnum::ChargingRateChanged); + ASSERT_THAT(s.size(), testing::Eq(2)); } } // namespace ocpp::v201 From f0b374653dc12b0705cae4c01827d02320931f21 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:50:10 +0000 Subject: [PATCH 16/18] updated: moved duplicated code to method Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- include/ocpp/v201/smart_charging.hpp | 3 ++ lib/ocpp/v201/smart_charging.cpp | 53 +++++++++++++++------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index dd612690f..ce23f8099 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -255,6 +255,9 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { void conform_validity_periods(ChargingProfile& profile) const; CurrentPhaseType get_current_phase_type(const std::optional evse_opt) const; TransactionEventRequest create_transaction_event_request(std::unique_ptr& tx) const; + bool process_evses_with_active_transactions(const bool limit_change_significance_exceeded, + std::vector& transaction_event_requests, + std::optional evse_id) const; }; } // namespace ocpp::v201 diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index 4bbcd6852..f65492035 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -676,38 +676,16 @@ std::optional evse_id) const { - bool has_transaction = false; - std::pair> pair; std::vector transaction_event_requests = {}; const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; const float limit_change_significance = this->device_model->get_value(limit_change_cv); - if (evse_id.has_value()) { - auto evse = &this->evse_manager.get_evse(evse_id.value()); - if (evse->has_active_transaction()) { - has_transaction = true; - // K13.FR.03 - if (percentage_delta > limit_change_significance) { - auto& tx = evse->get_transaction(); - transaction_event_requests.push_back(this->create_transaction_event_request(tx)); - } - } - } else { - for (auto& evse : this->evse_manager) { - if (evse.has_active_transaction()) { - has_transaction = true; - - // K13.FR.03 - if (percentage_delta > limit_change_significance) { + const bool limit_change_significance_exceeded = percentage_delta > limit_change_significance; - auto& tx = evse.get_transaction(); - transaction_event_requests.push_back(this->create_transaction_event_request(tx)); - } - } - } - } + bool has_transaction = this->process_evses_with_active_transactions(limit_change_significance_exceeded, + transaction_event_requests, evse_id); std::optional>> request; @@ -744,4 +722,29 @@ SmartChargingHandler::create_transaction_event_request(std::unique_ptr& transaction_event_requests, + std::optional evse_id) const { + bool has_transaction = false; + if (evse_id.has_value()) { + auto evse = &this->evse_manager.get_evse(evse_id.value()); + if (evse->has_active_transaction()) { + has_transaction = true; + // K13.FR.03 + if (limit_change_significance_exceeded) { + auto& tx = evse->get_transaction(); + transaction_event_requests.push_back(this->create_transaction_event_request(tx)); + } + } + } else { + for (auto& evse : this->evse_manager) { + has_transaction = (process_evses_with_active_transactions(limit_change_significance_exceeded, + transaction_event_requests, evse.get_id()) || + has_transaction); + } + } + + return has_transaction; +} + } // namespace ocpp::v201 From 075ab82ccd70e5209f7e7905fbaf17a342d5ced9 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:49:03 +0000 Subject: [PATCH 17/18] updated: incorrect test fixture name Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- tests/lib/ocpp/v201/test_charge_point.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib/ocpp/v201/test_charge_point.cpp b/tests/lib/ocpp/v201/test_charge_point.cpp index 43f308c3c..018bf56d6 100644 --- a/tests/lib/ocpp/v201/test_charge_point.cpp +++ b/tests/lib/ocpp/v201/test_charge_point.cpp @@ -945,7 +945,7 @@ TEST_F(ChargePointFunctionalityTestFixtureV201, K02FR05_TransactionEnds_WillDele TriggerReasonEnum::StopAuthorized, {}, {}, ChargingStateEnum::EVConnected); } -TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { +TEST_F(ChargePointFunctionalityTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); @@ -966,7 +966,7 @@ TEST_F(ChargepointTestFixtureV201, K12_OnExternalLimitsChanged_CallsHandler) { charge_point->on_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); } -TEST_F(ChargepointTestFixtureV201, K13_OnExternalLimitsCleared_CallsHandler) { +TEST_F(ChargePointFunctionalityTestFixtureV201, K13_OnExternalLimitsCleared_CallsHandler) { const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); From 719772e133c0588ae4fd2bf296689210581ac615 Mon Sep 17 00:00:00 2001 From: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:30:11 +0000 Subject: [PATCH 18/18] added: logic for K11FR04 to existing handle_external_limits_changed Signed-off-by: Coury Richards <146002925+couryrr-afs@users.noreply.github.com> --- doc/ocpp_201_status.md | 6 +- include/ocpp/v201/smart_charging.hpp | 12 ++- lib/ocpp/v201/charge_point.cpp | 13 ++- lib/ocpp/v201/smart_charging.cpp | 31 +++++--- .../mocks/smart_charging_handler_mock.hpp | 3 +- .../ocpp/v201/test_smart_charging_handler.cpp | 79 ++++++++++++++++--- 6 files changed, 115 insertions(+), 29 deletions(-) diff --git a/doc/ocpp_201_status.md b/doc/ocpp_201_status.md index 0164c1ad3..f3c3c8980 100644 --- a/doc/ocpp_201_status.md +++ b/doc/ocpp_201_status.md @@ -1266,7 +1266,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir | K01.FR.40 | ✅ | `Absolute`/`Recurring` profiles without `startSchedule` fields are rejected. | | K01.FR.41 | ✅ | `Relative` profiles with `startSchedule` fields are rejected. | | K01.FR.42 | ⛽️ | | -| K01.FR.43 | | Open question to OCA - https://oca.causewaynow.com/wg/OCA-TWG/mail/thread/4254 | +| K01.FR.43 | | Open question to OCA - | | K01.FR.44 | ✅ | We reject invalid profiles instead of modifying and accepting them. | | K01.FR.45 | ✅ | We reject invalid profiles instead of modifying and accepting them. | | K01.FR.46 | ⛽️ | K08 | @@ -1381,7 +1381,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir | K11.FR.01 | | | | K11.FR.02 | | | | K11.FR.03 | | | -| K11.FR.04 | | | +| K11.FR.04 | ✅ | | | K11.FR.05 | | | | K11.FR.06 | | | @@ -1392,7 +1392,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir | K12.FR.01 | | | | K12.FR.02 | ✅ | | | K12.FR.03 | ✅ | | -| K12.FR.04 | ✅ | | +| K12.FR.04 | ✅ | The spec does not define what we should do when the source given is CSO. The system currently throws and exception. | | K12.FR.05 | | | ## SmartCharging - Reset / Release External Charging Limit diff --git a/include/ocpp/v201/smart_charging.hpp b/include/ocpp/v201/smart_charging.hpp index ce23f8099..001d1c47d 100644 --- a/include/ocpp/v201/smart_charging.hpp +++ b/include/ocpp/v201/smart_charging.hpp @@ -112,7 +112,7 @@ class SmartChargingHandlerInterface { const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit) = 0; - virtual std::optional + virtual std::optional>> handle_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const = 0; @@ -189,15 +189,19 @@ class SmartChargingHandler : public SmartChargingHandlerInterface { std::optional charging_rate_unit) override; /// - /// \brief Determines whether or not we should notify the CSMS of a cleared external limit + /// \brief Determines whether or not we should notify the CSMS of a changed external limit /// based on \p percentage_delta and builds the notification. /// - std::optional + std::optional>> handle_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const override; - virtual std::optional>> + /// + /// \brief Determines whether or not we should notify the CSMS of a cleared external limit + /// based on \p percentage_delta and builds the notification. + /// + std::optional>> handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const override; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 1ecd11b9b..f451aaba8 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1020,8 +1020,19 @@ void ChargePoint::on_external_limits_changed(const std::variantsmart_charging_handler->handle_external_limits_changed(limit, percentage_delta, source, evse_id); if (request.has_value()) { - ocpp::Call call(request.value(), this->message_queue->createMessageId()); + auto [cleared_charging_limit_request, transaction_event_requests] = request.value(); + + ocpp::Call call(cleared_charging_limit_request, + this->message_queue->createMessageId()); this->send(call); + + if (transaction_event_requests.size() > 0) { + for (auto transaction_event_request : transaction_event_requests) { + ocpp::Call call(transaction_event_request, + this->message_queue->createMessageId()); + this->send(call); + } + } } } diff --git a/lib/ocpp/v201/smart_charging.cpp b/lib/ocpp/v201/smart_charging.cpp index f65492035..7ddd49414 100644 --- a/lib/ocpp/v201/smart_charging.cpp +++ b/lib/ocpp/v201/smart_charging.cpp @@ -636,7 +636,7 @@ ChargingSchedule create_schedule_from_limit(const ConstantChargingLimit limit) { }; } -std::optional +std::optional>> SmartChargingHandler::handle_external_limits_changed(const std::variant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id) const { @@ -647,7 +647,8 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant request = {}; + NotifyChargingLimitRequest notify_charging_limit_request = {}; + std::vector transaction_event_requests = {}; const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; const float limit_change_significance = this->device_model->get_value(limit_change_cv); @@ -656,19 +657,31 @@ SmartChargingHandler::handle_external_limits_changed(const std::variant notify_with_schedules = this->device_model->get_optional_value(notify_charging_limit_cv); - if (percentage_delta > limit_change_significance) { - request = NotifyChargingLimitRequest{}; - request->evseId = evse_id; - request->chargingLimit = {.chargingLimitSource = source}; + std::optional>> request = {}; + std::pair> pair; + + const bool limit_change_significance_exceeded = percentage_delta > limit_change_significance; + + if (limit_change_significance_exceeded) { + notify_charging_limit_request = NotifyChargingLimitRequest{}; + notify_charging_limit_request.evseId = evse_id; + notify_charging_limit_request.chargingLimit = {.chargingLimitSource = source}; if (notify_with_schedules.has_value() && notify_with_schedules.value()) { if (const auto* limit_c = std::get_if(&limit)) { - request->chargingSchedule = {{create_schedule_from_limit(*limit_c)}}; + notify_charging_limit_request.chargingSchedule = {{create_schedule_from_limit(*limit_c)}}; } else if (const auto* limit_s = std::get_if(&limit)) { - request->chargingSchedule = {{*limit_s}}; + notify_charging_limit_request.chargingSchedule = {{*limit_s}}; } } - } + pair.first = notify_charging_limit_request; + // K11.FR.04 + this->process_evses_with_active_transactions(limit_change_significance_exceeded, transaction_event_requests, + evse_id); + + pair.second = transaction_event_requests; + request.emplace(pair); + } return request; } diff --git a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp index f51ba0273..b33cf1be6 100644 --- a/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp +++ b/tests/lib/ocpp/v201/mocks/smart_charging_handler_mock.hpp @@ -32,7 +32,8 @@ class SmartChargingHandlerMock : public SmartChargingHandlerInterface { (std::vector & valid_profiles, const ocpp::DateTime& start_time, const ocpp::DateTime& end_time, const int32_t evse_id, std::optional charging_rate_unit)); - MOCK_METHOD(std::optional, handle_external_limits_changed, + MOCK_METHOD((std::optional>>), + handle_external_limits_changed, (const ChargingLimitVariant& limit, double percentage_delta, ChargingLimitSourceEnum source, std::optional evse_id), (const, override)); diff --git a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp index 915cf1689..afd04cf86 100644 --- a/tests/lib/ocpp/v201/test_smart_charging_handler.cpp +++ b/tests/lib/ocpp/v201/test_smart_charging_handler.cpp @@ -1683,6 +1683,49 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K05FR02_RequestStartTransactionReque ASSERT_THAT(sut, testing::Eq(ProfileValidationResultEnum::RequestStartTransactionNonTxProfile)); } +TEST_F(SmartChargingHandlerTestFixtureV201, K11FR04_HandleChangedChargingLimitRequest_NoTransactionExists) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, std::nullopt); + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + + auto [notify_charging_limit_request, transaction_event_requests] = resp.value(); + ASSERT_THAT(transaction_event_requests.size(), testing::Eq(0)); +} + +TEST_F(SmartChargingHandlerTestFixtureV201, K11FR04_HandleChangedChargingLimitRequest_OneTransactionExists) { + const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; + device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", + "test"); + + std::string transaction_id = uuid(); + this->evse_manager->open_transaction(DEFAULT_EVSE_ID, transaction_id); + + ConstantChargingLimit new_limit = { + .limit = 100.0, + .charging_rate_unit = ChargingRateUnitEnum::A, + }; + + double deltaChanged = 0.2; + auto source = ChargingLimitSourceEnum::Other; + + auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, std::nullopt); + ASSERT_THAT(resp.has_value(), testing::IsTrue()); + + auto [notify_charging_limit_request, transaction_event_requests] = resp.value(); + ASSERT_THAT(transaction_event_requests.size(), testing::Eq(1)); +} + TEST_F(SmartChargingHandlerTestFixtureV201, K12FR02_HandleExternalLimitsChanged_LimitChangeSignificanceNotMet_ReturnNone) { const auto& limit_change_cv = ControllerComponentVariables::LimitChangeSignificance; @@ -1764,8 +1807,10 @@ TEST_F( auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingSchedule.value(), testing::Contains(charging_schedule)); + auto [notify_charging_limit_request, s] = resp.value(); + + ASSERT_THAT(notify_charging_limit_request.chargingSchedule.has_value(), testing::IsTrue()); + ASSERT_THAT(notify_charging_limit_request.chargingSchedule.value(), testing::Contains(charging_schedule)); } TEST_F( @@ -1791,8 +1836,11 @@ TEST_F( auto resp = handler.handle_external_limits_changed(charging_schedule, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingSchedule.value(), testing::Contains(charging_schedule)); + + auto [notify_charging_limit_request, s] = resp.value(); + + ASSERT_THAT(notify_charging_limit_request.chargingSchedule.has_value(), testing::IsTrue()); + ASSERT_THAT(notify_charging_limit_request.chargingSchedule.value(), testing::Contains(charging_schedule)); } TEST_F( @@ -1812,7 +1860,9 @@ TEST_F( auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); + auto [notify_charging_limit_request, s] = resp.value(); + + ASSERT_THAT(notify_charging_limit_request.chargingSchedule.has_value(), testing::IsFalse()); } TEST_F( @@ -1835,7 +1885,9 @@ TEST_F( auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingSchedule.has_value(), testing::IsFalse()); + auto [notify_charging_limit_request, s] = resp.value(); + + ASSERT_THAT(notify_charging_limit_request.chargingSchedule.has_value(), testing::IsFalse()); } TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_NotificationIncludesSource) { @@ -1853,7 +1905,9 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, DEFAULT_EVSE_ID); ASSERT_THAT(resp.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); + auto [notify_charging_limit_request, s] = resp.value(); + + ASSERT_THAT(notify_charging_limit_request.chargingLimit.chargingLimitSource, testing::Eq(source)); } TEST_F(SmartChargingHandlerTestFixtureV201, K12FR04_HandleExternalLimitsChanged_ThrowsIfSourceIsCSO) { @@ -1877,7 +1931,7 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12_HandleExternalLimitsChanged_Requ device_model->set_value(limit_change_cv.component, limit_change_cv.variable.value(), AttributeEnum::Actual, "0.1", "test"); - auto evse_id = 12; + auto evse_id = 2; ConstantChargingLimit new_limit = { .limit = 100.0, @@ -1889,9 +1943,12 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K12_HandleExternalLimitsChanged_Requ auto resp = handler.handle_external_limits_changed(new_limit, deltaChanged, source, evse_id); ASSERT_THAT(resp.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->chargingLimit.chargingLimitSource, testing::Eq(source)); - ASSERT_THAT(resp->evseId.has_value(), testing::IsTrue()); - ASSERT_THAT(resp->evseId.value(), testing::Eq(evse_id)); + + auto [notify_charging_limit_request, s] = resp.value(); + + ASSERT_THAT(notify_charging_limit_request.chargingLimit.chargingLimitSource, testing::Eq(source)); + ASSERT_THAT(notify_charging_limit_request.evseId.has_value(), testing::IsTrue()); + ASSERT_THAT(notify_charging_limit_request.evseId.value(), testing::Eq(evse_id)); } TEST_F(SmartChargingHandlerTestFixtureV201,