Skip to content

Commit

Permalink
refactor: move component operative state management into a separate c…
Browse files Browse the repository at this point in the history
…lass

Signed-off-by: Valentin Dimov <[email protected]>
  • Loading branch information
valentin-dimov committed Dec 14, 2023
1 parent a5d5766 commit d1e02ac
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 251 deletions.
19 changes: 12 additions & 7 deletions include/ocpp/v201/charge_point.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest

#pragma once

#include <future>
#include <set>

Expand Down Expand Up @@ -54,6 +56,8 @@
#include <ocpp/v201/messages/UnlockConnector.hpp>
#include <ocpp/v201/messages/UpdateFirmware.hpp>

#include "component_state_manager.hpp"

namespace ocpp {
namespace v201 {

Expand Down Expand Up @@ -201,9 +205,8 @@ class ChargePoint : ocpp::ChargingStationBase {
int network_configuration_priority;
bool disable_automatic_websocket_reconnects;

/// \brief The availability status of the whole CS, set externally by the CSMS via ChangeAvailability requests.
/// It can also be set internally by the user of libocpp (e.g. to turn the CS inoperative for internal reasons)
OperationalStatusEnum operative_status;
/// \brief Component responsible for maintaining and persisting the operational status of CS, EVSEs, and connectors.
std::shared_ptr<ComponentStateManager> component_state_manager;

// store the connector status
struct EvseConnectorPair {
Expand Down Expand Up @@ -487,10 +490,10 @@ class ChargePoint : ocpp::ChargingStationBase {
};
};

/// \brief Checks if all connectors are effectively unavailable.
/// \brief Checks if all connectors are effectively inoperative.
/// If this is the case, calls the all_connectors_unavailable_callback
/// This is used e.g. to allow firmware updates once all transactions have finished
void notify_user_if_all_connectors_unavailable();
void notify_user_if_all_connectors_inoperative();

public:
/// \brief Construct a new ChargePoint object
Expand Down Expand Up @@ -667,9 +670,11 @@ class ChargePoint : ocpp::ChargingStationBase {
/// \param connector_id: The ID of the connector, empty if an EVSE or the CS is addressed
/// \param new_status: The new operative status to switch to
/// \param persist: True if the updated state should be persisted in the database
/// \param is_boot True if the call is due to recomputing the effective statuses on boot
void set_operative_status(std::optional<int32_t> evse_id, std::optional<int32_t> connector_id,
OperationalStatusEnum new_status, bool persist, bool is_boot);
std::optional<OperationalStatusEnum> new_status, bool persist);

/// \brief Explicitly trigger the change_effective_availability_callback for each component (done on boot)
void trigger_change_effective_availability_callback();

/// \brief Delay draining the message queue after reconnecting, so the CSMS can perform post-reconnect checks first
/// \param delay The delay period (seconds)
Expand Down
57 changes: 57 additions & 0 deletions include/ocpp/v201/component_state_manager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest

#pragma once

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

namespace ocpp::v201 {

struct FullConnectorStatus {
OperationalStatusEnum individual_operational_status;
bool faulted;

Check notice on line 13 in include/ocpp/v201/component_state_manager.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/component_state_manager.hpp#L13

struct member 'FullConnectorStatus::faulted' is never used.
bool reserved;

Check notice on line 14 in include/ocpp/v201/component_state_manager.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/component_state_manager.hpp#L14

struct member 'FullConnectorStatus::reserved' is never used.
bool occupied;

Check notice on line 15 in include/ocpp/v201/component_state_manager.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/component_state_manager.hpp#L15

struct member 'FullConnectorStatus::occupied' is never used.

ConnectorStatusEnum to_effective_status();
};

class ComponentStateManager {
private:
std::shared_ptr<DatabaseHandler> database;

OperationalStatusEnum cs_individual_status;
std::vector<std::pair<OperationalStatusEnum, std::vector<FullConnectorStatus>>>
evse_and_connector_individual_statuses;

Check notice on line 26 in include/ocpp/v201/component_state_manager.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/component_state_manager.hpp#L26

class member 'ComponentStateManager::evse_and_connector_individual_statuses' is never used.

void check_evse_id(int32_t evse_id);
void check_evse_and_connector_id(int32_t evse_id, int32_t connector_id);

public:
explicit ComponentStateManager(const std::map<int32_t, int32_t>& evse_connector_structure,
std::shared_ptr<DatabaseHandler> db_handler);

OperationalStatusEnum get_cs_individual_operational_status();
OperationalStatusEnum get_evse_individual_operational_status(int32_t evse_id);
OperationalStatusEnum get_connector_individual_operational_status(int32_t evse_id, int32_t connector_id);

OperationalStatusEnum get_cs_persisted_operational_status();
OperationalStatusEnum get_evse_persisted_operational_status(int32_t evse_id);
OperationalStatusEnum get_connector_persisted_operational_status(int32_t evse_id, int32_t connector_id);

void set_cs_individual_operational_status(OperationalStatusEnum new_status, bool persist);
void set_evse_individual_operational_status(int32_t evse_id, OperationalStatusEnum new_status, bool persist);
void set_connector_individual_operational_status(int32_t evse_id, int32_t connector_id,
OperationalStatusEnum new_status,bool persist);

OperationalStatusEnum get_evse_effective_operational_status(int32_t evse_id);
OperationalStatusEnum get_connector_effective_operational_status(int32_t evse_id, int32_t connector_id);
ConnectorStatusEnum get_connector_effective_status(int32_t evse_id, int32_t connector_id);

void set_connector_occupied(int32_t evse_id, int32_t connector_id, bool is_occupied);
void set_connector_reserved(int32_t evse_id, int32_t connector_id, bool is_reserved);
void set_connector_faulted(int32_t evse_id, int32_t connector_id, bool is_faulted);
};

} // namespace ocpp::v201
59 changes: 20 additions & 39 deletions include/ocpp/v201/connector.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest

#pragma once

#include <functional>
#include <mutex>

#include "database_handler.hpp"
#include <ocpp/v201/enums.hpp>
#include <optional>
#include "component_state_manager.hpp"

namespace ocpp {
namespace v201 {
Expand Down Expand Up @@ -34,69 +37,47 @@ class Connector {
int32_t evse_id;

Check notice on line 37 in include/ocpp/v201/connector.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/connector.hpp#L37

class member 'Connector::evse_id' is never used.
/// \brief ID of the connector itself (>0)
int32_t connector_id;
/// \brief The libocpp internal database
std::shared_ptr<DatabaseHandler> database_handler;

/// \brief Protects all fields describing the state (or effective state) of the connector
std::recursive_mutex state_mutex;
/// \brief Matches the connector's operative status setting, as set by the CSMS or libocpp commands.
/// Note: this might not match the actual state of the connector, e.g. because the EVSE or CS is inoperative.
OperationalStatusEnum operational;
/// \brief True if a reservation is active on this connector
bool reserved;
/// \brief True if the connector is occupied (an EV is plugged in)
bool plugged_in;
/// \brief True if an error is active on this connector (e.g. an electrical fault)
bool faulted;
/// \brief The actual status of the connector, depending on the enabled, reserved, plugged_in, and faulted booleans
/// as well as the effective status (Operative/Inoperative) of the EVSE and CS.
ConnectorStatusEnum effective_status;

/// \brief Component responsible for maintaining and persisting the operational status of CS, EVSEs, and connectors.
std::shared_ptr<ComponentStateManager> component_state_manager;

/// \brief Sends a status update to the CSMS about a change in effective status of this connector.
std::function<void(const ConnectorStatusEnum& status)> status_notification_callback;

/// \brief Callback to execute an effective status change (e.g. actually enabling/disabling connectors)
std::function<void(const OperationalStatusEnum new_status)> change_effective_availability_callback;

/// \brief Determines the current effective state of the connector
/// \param evse_status: The effective state of the EVSE
/// \return ConnectorStatusEnum
ConnectorStatusEnum determine_effective_status(OperationalStatusEnum evse_status);

/// \brief Updates the connector's effective status and publishes a status update if it changed
void set_effective_status(ConnectorStatusEnum new_effective_status);

public:
/// \brief Construct a new Connector object
/// \param evse_id id of the EVSE the connector is ap art of
/// \param connector_id id of the connector
/// \param database_handler a reference to the internal libocpp database handler
/// \param status_notification_callback callback executed to send a status notification for the connector
/// \param change_effective_availability_callback callback to change the effective operative state of the connector
Connector(const int32_t evse_id, const int32_t connector_id, std::shared_ptr<DatabaseHandler> database_handler,
OperationalStatusEnum evse_effective_status,
Connector(const int32_t evse_id, const int32_t connector_id,
std::shared_ptr<ComponentStateManager> component_state_manager,
const std::function<void(const ConnectorStatusEnum& status)>& status_notification_callback,
const std::function<void(const OperationalStatusEnum new_status)> change_effective_availability_callback);

/// \brief Get the effective state of the connector
/// \return ConnectorStatusEnum
ConnectorStatusEnum get_effective_status();

/// \brief Get the operative status of the connector (NOT the same as the effective status!)
OperationalStatusEnum get_operative_status();
/// \brief Gets the effective Operative/Inoperative status of this connector
OperationalStatusEnum get_effective_operational_status();
/// \brief Gets the effective Available/Unavailable/Faulted/Reserved/Occupied status of this connector
ConnectorStatusEnum get_effective_connector_status();

/// \brief Adjust the state of the connector according to the \p event that was submitted.
/// \param event
/// \param evse_status: The effective state of the EVSE
void submit_event(ConnectorEvent event, OperationalStatusEnum evse_status);
void submit_event(ConnectorEvent event);

/// \brief Explicitly causes a StatusNotification callback with the current effective status to be sent.
void trigger_status_notification_callback();

/// \brief Switches the operative status of the connector and recomputes its effective status
/// \param new_status: The operative status to switch to, empty if we only want to recompute the effective status
/// \param evse_status: The effective status of the EVSE
/// \param persist: True if the updated operative status setting should be persisted
/// \param is_boot True if the call is due to recomputing the effective statuses on boot
void set_operative_status(std::optional<OperationalStatusEnum> new_status, OperationalStatusEnum evse_status,
bool persist, bool is_boot);
void set_operative_status(std::optional<OperationalStatusEnum> new_status, bool persist);

/// \brief Explicitly trigger the change_effective_availability_callback for each component (done on boot)
void trigger_change_effective_availability_callback();
};

} // namespace v201
Expand Down
35 changes: 14 additions & 21 deletions include/ocpp/v201/evse.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest

#pragma once

#include <functional>
#include <map>
#include <memory>
Expand All @@ -11,6 +13,7 @@
#include <ocpp/v201/device_model.hpp>
#include <ocpp/v201/ocpp_types.hpp>
#include <ocpp/v201/transaction.hpp>
#include <ocpp/v201/component_state_manager.hpp>

namespace ocpp {
namespace v201 {
Expand Down Expand Up @@ -49,16 +52,8 @@ class Evse {
AverageMeterValues aligned_data_updated;
AverageMeterValues aligned_data_tx_end;

/// \brief The operational status setting of the EVSE, as set by the CSMS and libocpp commands.
/// Note that this might not match the actual state of the EVSE, e.g. if the CS is inoperative.
OperationalStatusEnum operative_status;
/// \brief The actual state of the EVSE, dependent on both the operative status and the CS's operative status.
OperationalStatusEnum effective_status;

/// \brief Determine the new effective state of the EVSE
/// \param cs_status: The effective state of the charging station
/// \return ConnectorStatusEnum
OperationalStatusEnum determine_effective_status(OperationalStatusEnum cs_status);
/// \brief Component responsible for maintaining and persisting the operational status of CS, EVSEs, and connectors.
std::shared_ptr<ComponentStateManager> component_state_manager;

public:
/// \brief Construct a new Evse object
Expand All @@ -69,7 +64,8 @@ class Evse {
/// \param pause_charging_callback that is called when the charging should be paused due to max energy on
/// invalid id being exceeded
Evse(const int32_t evse_id, const int32_t number_of_connectors, DeviceModel& device_model,
std::shared_ptr<DatabaseHandler> database_handler, OperationalStatusEnum cs_effective_status,
std::shared_ptr<DatabaseHandler> database_handler,
std::shared_ptr<ComponentStateManager> component_state_manager,
const std::function<void(const int32_t connector_id, const ConnectorStatusEnum& status)>&
status_notification_callback,
const std::function<void(const MeterValue& meter_value, const Transaction& transaction, const int32_t seq_no,
Expand Down Expand Up @@ -139,7 +135,7 @@ class Evse {
/// \p connector_id
/// \param connector_id id of the connector of the evse
/// \param event
void submit_event(const int32_t connector_id, ConnectorEvent event, OperationalStatusEnum cs_status);
void submit_event(const int32_t connector_id, ConnectorEvent event);

/// \brief Triggers status notification callback for all connectors of the evse
void trigger_status_notification_callbacks();
Expand All @@ -163,21 +159,18 @@ class Evse {
/// @brief Clear the idle meter values for this evse
void clear_idle_meter_values();

/// \brief Get the operative status of the EVSE or one of its connectors (NOT the same as the effective status!)
/// \param connector_id The ID of the connector, empty if the EVSE itself is addressed
OperationalStatusEnum get_operative_status(std::optional<int32_t> connector_id);

/// \brief check if all connectors are effectively Inoperative.
bool all_connectors_inoperative();
/// \brief Gets the effective Operative/Inoperative status of this EVSE
OperationalStatusEnum get_effective_operational_status();

/// \brief Switches the operative status of the EVSE or a connector and recomputes effective statuses
/// \param connector_id The ID of the connector, empty if the EVSE itself is addressed
/// \param new_status The operative status to switch to, empty if we only want to recompute the effective status
/// \param cs_status The effective status of the charging station
/// \param persist True the updated operative state should be persisted
/// \param is_boot True if the call is due to recomputing the effective statuses on boot
void set_operative_status(std::optional<int32_t> connector_id, std::optional<OperationalStatusEnum> new_status,
OperationalStatusEnum cs_status, bool persist, bool is_boot);
bool persist);

/// \brief Explicitly trigger the change_effective_availability_callback for each component (done on boot)
void trigger_change_effective_availability_callback();
};

} // namespace v201
Expand Down
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ target_sources(ocpp
ocpp/v201/transaction.cpp
ocpp/v201/types.cpp
ocpp/v201/utils.cpp
ocpp/v201/component_state_manager.cpp
)

add_subdirectory(ocpp/common/websocket)
Expand Down
Loading

0 comments on commit d1e02ac

Please sign in to comment.