diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index ca5caaf06..776449c90 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -133,6 +133,24 @@ class ChargePoint : ocpp::ChargingStationBase { int network_configuration_priority; bool disable_automatic_websocket_reconnects; + // store the connector status + struct EvseConnectorPair { + int32_t evse_id; + int32_t connector_id; + + // Define a comparison operator for the struct + bool operator<(const EvseConnectorPair& other) const { + // Compare based on name, then age + if (evse_id != other.evse_id) { + return evse_id < other.evse_id; + } + return connector_id < other.connector_id; + } + }; + + std::map conn_state_per_evse; + std::chrono::time_point time_disconnected; + /// \brief Used when an 'OnIdle' reset is requested, to perform the reset after the charging has stopped. bool reset_scheduled; /// \brief If `reset_scheduled` is true and the reset is for a specific evse id, it will be stored in this member. diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index a90256b48..39dac3c50 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -470,6 +470,35 @@ void ChargePoint::init_websocket() { this->websocket->register_connected_callback([this](const int security_profile) { this->message_queue->resume(); this->websocket_connection_status = WebsocketConnectionStatusEnum::Connected; + + if (this->registration_status == RegistrationStatusEnum::Accepted) { + // handle offline threshold + // Get the current time point using steady_clock + std::chrono::steady_clock::duration offline_duration = std::chrono::steady_clock::now() - time_disconnected; + + // B04.FR.01 + // If offline period exceeds offline threshold then send the status notification for all connectors + if (offline_duration > std::chrono::seconds(this->device_model->get_value( + ControllerComponentVariables::OfflineThreshold))) { + EVLOG_debug << "offline for more than offline threshold "; + for (auto const& [evse_id, evse] : this->evses) { + evse->trigger_status_notification_callbacks(); + } + } else { + // B04.FR.02 + // If offline period doesn't exceed offline threshold then send the status notification for all + // connectors that changed state + EVLOG_debug << "offline for less than offline threshold "; + for (auto const& [evse_id, evse] : this->evses) { + int number_of_connectors = evse->get_number_of_connectors(); + for (int connector_id = 1; connector_id <= number_of_connectors; connector_id++) { + if (conn_state_per_evse[{evse_id, connector_id}] != evse->get_state(connector_id)) { + evse->trigger_status_notification_callback(connector_id); + } + } + } + } + } }); this->websocket->register_closed_callback( @@ -480,6 +509,25 @@ void ChargePoint::init_websocket() { this->websocket_connection_status = WebsocketConnectionStatusEnum::Disconnected; this->message_queue->pause(); + // check if offline threshold has been defined + if (this->device_model->get_value(ControllerComponentVariables::OfflineThreshold) != 0) { + // get the status of all the connectors + for (auto const& [evse_id, evse] : this->evses) { + int number_of_connectors = evse->get_number_of_connectors(); + EvseConnectorPair conn_states_struct_key; + EVLOG_debug << "evseId: " << evse_id << " numConn: " << number_of_connectors; + for (int connector_id = 1; connector_id <= number_of_connectors; connector_id++) { + conn_states_struct_key.evse_id = evse_id; + conn_states_struct_key.connector_id = connector_id; + conn_state_per_evse[conn_states_struct_key] = evse->get_state(connector_id); + EVLOG_debug << "conn_id: " << conn_states_struct_key.connector_id + << " State: " << conn_state_per_evse[conn_states_struct_key]; + } + } + // Get the current time point using steady_clock + time_disconnected = std::chrono::steady_clock::now(); + } + if (!this->disable_automatic_websocket_reconnects) { this->websocket_timer.timeout( [this, reason]() {