Skip to content

Commit

Permalink
Added a time sync callback that can be used to sync system time (#202)
Browse files Browse the repository at this point in the history
* Added a time sync callback that can be used to sync system time

Signed-off-by: Marc Emmers <[email protected]>

clang-format

Signed-off-by: Kai-Uwe Hermann <[email protected]>

Add time_sync_callback to callbacks valid check

Signed-off-by: Marc Emmers <[email protected]>

Fix incorrect time of flight calculation

Signed-off-by: Marc Emmers <[email protected]>

Fix wrong call type used and use monotonic timer so time of flight never becomes negative

Signed-off-by: Marc Emmers <[email protected]>

* Check the TimeSource before updating the time based on heartbeats and boot notification

Signed-off-by: Marc Emmers <[email protected]>

---------

Signed-off-by: Marc Emmers <[email protected]>
Co-authored-by: Patrick van Bennekom <[email protected]>
Co-authored-by: Marc Emmers <[email protected]>
  • Loading branch information
3 people authored Oct 10, 2023
1 parent 314baaa commit 4769c49
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 3 deletions.
2 changes: 1 addition & 1 deletion config/v201/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@
"TimeSource": {
"variable_name": "TimeSource",
"attributes": {
"Actual": ""
"Actual": "Heartbeat"
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions include/ocpp/v201/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ struct Callbacks {
validate_network_profile_callback;
std::optional<std::function<bool(const NetworkConnectionProfile& network_connection_profile)>>
configure_network_connection_profile_callback;
std::optional<std::function<void(const ocpp::DateTime& currentTime)>> time_sync_callback;
};

/// \brief Class implements OCPP2.0.1 Charging Station
Expand Down Expand Up @@ -123,6 +124,9 @@ class ChargePoint : ocpp::ChargingStationBase {
Everest::SteadyTimer boot_notification_timer;
Everest::SteadyTimer aligned_meter_values_timer;

// time keeping
std::chrono::time_point<std::chrono::steady_clock> heartbeat_request_time;

// states
RegistrationStatusEnum registration_status;
WebsocketConnectionStatusEnum websocket_connection_status;
Expand Down Expand Up @@ -301,6 +305,7 @@ class ChargePoint : ocpp::ChargingStationBase {

// Functional Block G: Availability
void handle_change_availability_req(Call<ChangeAvailabilityRequest> call);
void handle_heartbeat_response(CallResult<HeartbeatResponse> call);

// Functional Block L: Firmware management
void handle_firmware_update_req(Call<UpdateFirmwareRequest> call);
Expand Down
26 changes: 24 additions & 2 deletions lib/ocpp/v201/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ bool Callbacks::all_callbacks_valid() const {
(!this->validate_network_profile_callback.has_value() or
this->validate_network_profile_callback.value() != nullptr) and
(!this->configure_network_connection_profile_callback.has_value() or
this->configure_network_connection_profile_callback.value() != nullptr);
this->configure_network_connection_profile_callback.value() != nullptr) and
(!this->time_sync_callback.has_value() or this->time_sync_callback.value() != nullptr);
}

ChargePoint::ChargePoint(const std::map<int32_t, int32_t>& evse_connector_structure,
Expand Down Expand Up @@ -675,6 +676,9 @@ void ChargePoint::handle_message(const EnhancedMessage<v201::MessageType>& messa
case MessageType::TriggerMessage:
this->handle_trigger_message(json_message);
break;
case MessageType::HeartbeatResponse:
this->handle_heartbeat_response(json_message);
break;
case MessageType::SendLocalList:
this->handle_send_local_authorization_list_req(json_message);
break;
Expand Down Expand Up @@ -1154,6 +1158,7 @@ void ChargePoint::status_notification_req(const int32_t evse_id, const int32_t c
void ChargePoint::heartbeat_req() {
HeartbeatRequest req;

heartbeat_request_time = std::chrono::steady_clock::now();
ocpp::Call<HeartbeatRequest> call(req, this->message_queue->createMessageId());
this->send<HeartbeatRequest>(call);
}
Expand Down Expand Up @@ -1267,7 +1272,12 @@ void ChargePoint::handle_boot_notification_response(CallResult<BootNotificationR
this->heartbeat_timer.interval([this]() { this->heartbeat_req(); }, std::chrono::seconds(msg.interval));
}
this->update_aligned_data_interval();

// B01.FR.06 Only use boot timestamp if TimeSource contains Heartbeat
if (this->callbacks.time_sync_callback.has_value() &&
this->device_model->get_value<std::string>(ControllerComponentVariables::TimeSource).find("Heartbeat") !=
std::string::npos) {
this->callbacks.time_sync_callback.value()(msg.currentTime);
}
for (auto const& [evse_id, evse] : this->evses) {
evse->trigger_status_notification_callbacks();
}
Expand Down Expand Up @@ -1926,6 +1936,18 @@ void ChargePoint::handle_change_availability_req(Call<ChangeAvailabilityRequest>
}
}

void ChargePoint::handle_heartbeat_response(CallResult<HeartbeatResponse> call) {
if (this->callbacks.time_sync_callback.has_value() &&
this->device_model->get_value<std::string>(ControllerComponentVariables::TimeSource).find("Heartbeat") !=
std::string::npos) {
// the received currentTime was the time the CSMS received the heartbeat request
// to get a system time as accurate as possible keep the time-of-flight into account
auto timeOfFlight = (std::chrono::steady_clock::now() - this->heartbeat_request_time) / 2;
ocpp::DateTime currentTimeCompensated(call.msg.currentTime.to_time_point() + timeOfFlight);
this->callbacks.time_sync_callback.value()(currentTimeCompensated);
}
}

void ChargePoint::handle_firmware_update_req(Call<UpdateFirmwareRequest> call) {
EVLOG_debug << "Received UpdateFirmwareRequest: " << call.msg << "\nwith messageId: " << call.uniqueId;
UpdateFirmwareResponse response = callbacks.update_firmware_request_callback(call.msg);
Expand Down

0 comments on commit 4769c49

Please sign in to comment.