Skip to content

Commit

Permalink
SmartChargingHandler: Add validation for TxProfiles
Browse files Browse the repository at this point in the history
Creates a skeleton for SmartChargingHandler and adds a method
to validate TxProfiles and TxProfiles only. This method
ensures that a given profile (assumed to be TxProfile) fits all of
the functional requirements specific to TxProfiles per K01.

The function, `validate_tx_profile ()`, takes a profile and an
EVSE, and returns a variant of `ProfileValidationResultEnum`.
This enum allows us to have detailed responses for the different types
of invalid profiles, and eventually will let us log *why* a profile
is invalid if the general validation fails.

Part of the prerequisites for #361

Co-authored-by: Gianfranco Berardi <[email protected]>
Signed-off-by: Christopher Davis <[email protected]>
  • Loading branch information
christopher-davis-afs and gberardi-pillar committed Feb 27, 2024
1 parent d9536ad commit ce6b167
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 1 deletion.
48 changes: 48 additions & 0 deletions include/ocpp/v201/smart_charging.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest

#ifndef OCPP_V201_SMART_CHARGING_HPP
#define OCPP_V201_SMART_CHARGING_HPP

#include "ocpp/v201/enums.hpp"
#include <limits>

#include <ocpp/v201/database_handler.hpp>
#include <ocpp/v201/evse.hpp>
#include <ocpp/v201/ocpp_types.hpp>
#include <ocpp/v201/transaction.hpp>

namespace ocpp::v201 {

enum class ProfileValidationResultEnum {
Valid,
TxProfileMissingTransactionId,
TxProfileEvseIdNotGreaterThanZero,
TxProfileTransactionNotOnEvse,
TxProfileEvseHasNoActiveTransaction,
TxProfileConflictingStackLevel
};

/// \brief This class handles and maintains incoming ChargingProfiles and contains the logic
/// to calculate the composite schedules
class SmartChargingHandler {
private:
std::shared_ptr<ocpp::v201::DatabaseHandler> database_handler;
// cppcheck-suppress unusedStructMember
std::vector<ChargingProfile> charging_profiles;

public:
explicit SmartChargingHandler(std::shared_ptr<DatabaseHandler> database_handler);

///
/// \brief validates the given \p profile according to the specification
///
ProfileValidationResultEnum validate_tx_profile(const ChargingProfile& profile, Evse& evse) const;

/// \brief Adds a given \p profile to our stored list of profiles
void add_profile(ChargingProfile& profile);
};

} // namespace ocpp::v201

#endif // OCPP_V201_SMART_CHARGING_HPP
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ target_sources(ocpp
ocpp/v16/types.cpp
ocpp/v201/average_meter_values.cpp
ocpp/v201/charge_point.cpp
ocpp/v201/smart_charging.cpp
ocpp/v201/connector.cpp
ocpp/v201/ctrlr_component_variables.cpp
ocpp/v201/database_handler.cpp
Expand Down
53 changes: 53 additions & 0 deletions lib/ocpp/v201/smart_charging.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest

#include "ocpp/common/types.hpp"
#include "ocpp/v201/enums.hpp"
#include "ocpp/v201/ocpp_types.hpp"
#include "ocpp/v201/transaction.hpp"
#include <memory>
#include <ocpp/v201/smart_charging.hpp>

using namespace std::chrono;

namespace ocpp::v201 {

SmartChargingHandler::SmartChargingHandler(std::shared_ptr<DatabaseHandler> database_handler) :
database_handler(database_handler) {
}

ProfileValidationResultEnum SmartChargingHandler::validate_tx_profile(const ChargingProfile& profile,
Evse& evse) const {
if (!profile.transactionId.has_value()) {
return ProfileValidationResultEnum::TxProfileMissingTransactionId;
}

int32_t evseId = evse.get_evse_info().id;
if (evseId <= 0) {
return ProfileValidationResultEnum::TxProfileEvseIdNotGreaterThanZero;
}

if (!evse.has_active_transaction()) {
return ProfileValidationResultEnum::TxProfileEvseHasNoActiveTransaction;
}

auto& transaction = evse.get_transaction();
if (transaction->transactionId != profile.transactionId.value()) {
return ProfileValidationResultEnum::TxProfileTransactionNotOnEvse;
}

auto conflicts_with = [&profile](const ChargingProfile& candidate) {
return candidate.transactionId == profile.transactionId && candidate.stackLevel == profile.stackLevel;
};
if (std::any_of(charging_profiles.begin(), charging_profiles.end(), conflicts_with)) {
return ProfileValidationResultEnum::TxProfileConflictingStackLevel;
}

return ProfileValidationResultEnum::Valid;
}

void SmartChargingHandler::add_profile(ChargingProfile& profile) {
charging_profiles.push_back(profile);
}

} // namespace ocpp::v201
4 changes: 3 additions & 1 deletion tests/lib/ocpp/v201/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
target_include_directories(libocpp_unit_tests PUBLIC mocks)

target_sources(libocpp_unit_tests PRIVATE
test_device_model_storage_sqlite.cpp
test_notify_report_requests_splitter.cpp
test_ocsp_updater.cpp
test_component_state_manager.cpp
test_device_model.cpp)
test_device_model.cpp
test_smart_charging_handler.cpp)
44 changes: 44 additions & 0 deletions tests/lib/ocpp/v201/mocks/component_state_manager_mock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <gmock/gmock.h>

#include "ocpp/v201/component_state_manager.hpp"

namespace ocpp::v201 {
class ComponentStateManagerMock : public ComponentStateManagerInterface {
MOCK_METHOD(void, set_cs_effective_availability_changed_callback,
(const std::function<void(const OperationalStatusEnum new_status)>& callback));

MOCK_METHOD(void, set_evse_effective_availability_changed_callback,
(const std::function<void(const int32_t evse_id, const OperationalStatusEnum new_status)>& callback));

MOCK_METHOD(void, set_connector_effective_availability_changed_callback,
(const std::function<void(const int32_t evse_id, const int32_t connector_id,
const OperationalStatusEnum new_status)>& callback));

MOCK_METHOD(OperationalStatusEnum, get_cs_individual_operational_status, ());
MOCK_METHOD(OperationalStatusEnum, get_evse_individual_operational_status, (int32_t evse_id));
MOCK_METHOD(OperationalStatusEnum, get_connector_individual_operational_status,
(int32_t evse_id, int32_t connector_id));
MOCK_METHOD(OperationalStatusEnum, get_cs_persisted_operational_status, ());
MOCK_METHOD(OperationalStatusEnum, get_evse_persisted_operational_status, (int32_t evse_id));
MOCK_METHOD(OperationalStatusEnum, get_connector_persisted_operational_status,
(int32_t evse_id, int32_t connector_id));
MOCK_METHOD(void, set_cs_individual_operational_status, (OperationalStatusEnum new_status, bool persist));
MOCK_METHOD(void, set_evse_individual_operational_status,
(int32_t evse_id, OperationalStatusEnum new_status, bool persist));
MOCK_METHOD(void, set_connector_individual_operational_status,
(int32_t evse_id, int32_t connector_id, OperationalStatusEnum new_status, bool persist));
MOCK_METHOD(OperationalStatusEnum, get_evse_effective_operational_status, (int32_t evse_id));
MOCK_METHOD(OperationalStatusEnum, get_connector_effective_operational_status,
(int32_t evse_id, int32_t connector_id));
MOCK_METHOD(ConnectorStatusEnum, get_connector_effective_status, (int32_t evse_id, int32_t connector_id));
MOCK_METHOD(void, set_connector_occupied, (int32_t evse_id, int32_t connector_id, bool is_occupied));
MOCK_METHOD(void, set_connector_reserved, (int32_t evse_id, int32_t connector_id, bool is_reserved));
MOCK_METHOD(void, set_connector_faulted, (int32_t evse_id, int32_t connector_id, bool is_faulted));
MOCK_METHOD(void, set_connector_unavailable, (int32_t evse_id, int32_t connector_id, bool is_unavailable));
MOCK_METHOD(void, trigger_all_effective_availability_changed_callbacks, ());
MOCK_METHOD(void, send_status_notification_all_connectors, ());
MOCK_METHOD(void, send_status_notification_changed_connectors, ());
MOCK_METHOD(void, send_status_notification_single_connector, (int32_t evse_id, int32_t connector_id));
};

} // namespace ocpp::v201
17 changes: 17 additions & 0 deletions tests/lib/ocpp/v201/mocks/device_model_storage_mock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <gmock/gmock.h>

#include "ocpp/v201/device_model_storage.hpp"

namespace ocpp::v201 {
class DeviceModelStorageMock : public DeviceModelStorage {
public:
MOCK_METHOD(DeviceModelMap, get_device_model, ());
MOCK_METHOD(std::optional<VariableAttribute>, get_variable_attribute,
(const Component&, const Variable&, const AttributeEnum&));
MOCK_METHOD(std::vector<VariableAttribute>, get_variable_attributes,
(const Component&, const Variable&, const std::optional<AttributeEnum>&));
MOCK_METHOD(bool, set_variable_attribute_value,
(const Component&, const Variable&, const AttributeEnum&, const std::string&));
MOCK_METHOD(void, check_integrity, ());
};
} // namespace ocpp::v201
Loading

0 comments on commit ce6b167

Please sign in to comment.