├── .ci └── build-kit │ ├── docker │ └── Dockerfile │ └── scripts │ ├── build_docs.sh │ ├── compile.sh │ ├── install.sh │ ├── run_coverage.sh │ └── run_unit_tests.sh ├── .clang-format ├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── pull_request_template.md └── workflows │ └── build_and_test.yaml ├── .gitignore ├── 3rd_party └── websocketpp_utils │ ├── base64.hpp │ └── uri.hpp ├── CMakeLists.txt ├── LICENSE ├── README.md ├── THIRD_PARTY.md ├── config ├── CollectMigrationFiles.cmake ├── logging.ini ├── v16 │ ├── CMakeLists.txt │ ├── config-docker-tls.json │ ├── config-docker.json │ ├── config-full.json │ ├── config.json │ ├── core_migrations │ │ ├── 1_up-initial.sql │ │ ├── 2_down-offline-transaction.sql │ │ ├── 2_up-offline-transaction.sql │ │ ├── 3_down-persist-normal-messages.sql │ │ ├── 3_up-persist-normal-messages.sql │ │ ├── 4_down-drop-ocsp-request.sql │ │ └── 4_up-drop-ocsp-request.sql │ ├── profile_schemas │ │ ├── Config.json │ │ ├── Core.json │ │ ├── CostAndPrice.json │ │ ├── Custom.json │ │ ├── FirmwareManagement.json │ │ ├── Internal.json │ │ ├── LocalAuthListManagement.json │ │ ├── PnC.json │ │ ├── Reservation.json │ │ ├── Security.json │ │ └── SmartCharging.json │ └── user_config │ │ └── .gitignore └── v2 │ ├── CMakeLists.txt │ ├── component_config │ ├── custom │ │ ├── Connector_1_1.json │ │ ├── Connector_2_1.json │ │ ├── EVSE_1.json │ │ └── EVSE_2.json │ └── standardized │ │ ├── AlignedDataCtrlr.json │ │ ├── AuthCacheCtrlr.json │ │ ├── AuthCtrlr.json │ │ ├── ChargingStation.json │ │ ├── ChargingStatusIndicator.json │ │ ├── ClockCtrlr.json │ │ ├── CustomizationCtrlr.json │ │ ├── DeviceDataCtrlr.json │ │ ├── DisplayMessageCtrlr.json │ │ ├── ISO15118Ctrlr.json │ │ ├── InternalCtrlr.json │ │ ├── LocalAuthListCtrlr.json │ │ ├── MonitoringCtrlr.json │ │ ├── OCPPCommCtrlr.json │ │ ├── ReservationCtrlr.json │ │ ├── SampledDataCtrlr.json │ │ ├── SecurityCtrlr.json │ │ ├── SmartChargingCtrlr.json │ │ ├── TariffCostCtrlr.json │ │ └── TxCtrlr.json │ ├── core_migrations │ ├── 1_up-initial.sql │ ├── 2_down-auth_cache_management.sql │ ├── 2_up-auth_cache_management.sql │ ├── 3_down-persist-normal-messages.sql │ ├── 3_up-persist-normal-messages.sql │ ├── 4_down-transactions_db.sql │ ├── 4_up-transactions_db.sql │ ├── 5_down-charging_profiles_db.sql │ ├── 5_up-charging_profiles_db.sql │ ├── 6_down-charging_profiles_source_tx_id.sql │ └── 6_up-charging_profiles_source_tx_id.sql │ └── device_model_migrations │ ├── 1_up-initial.sql │ ├── 2_down-variable_source.sql │ ├── 2_up-variable_source.sql │ ├── 3_down-variable_required.sql │ └── 3_up-variable_required.sql ├── dependencies.yaml ├── doc ├── common │ ├── build-with-fetchcontent │ │ ├── CMakeLists.txt │ │ └── README.md │ ├── california_pricing_requirements.md │ ├── database_exception_handling.md │ ├── database_migrations.md │ ├── getting_started.md │ └── smart_charging_profiles.md ├── message_dispatching.md ├── networkconnectivity │ └── README.md ├── v16 │ ├── getting_started.md │ └── state_chart_1_6.drawio └── v2 │ ├── getting_started.md │ ├── ocpp_201_device_model_initialization.md │ ├── ocpp_201_monitors.md │ ├── ocpp_201_monitors_periodic_flowchart.puml │ ├── ocpp_201_monitors_trigger_flowchart.puml │ ├── ocpp_201_smart_charging_in_depth.md │ ├── ocpp_2x_status.md │ └── resumeInterruptedTransactions │ ├── resumeInterruptedTransactions.png │ └── resumeInterruptedTransactions.puml ├── include └── ocpp │ ├── common │ ├── aligned_timer.hpp │ ├── call_types.hpp │ ├── charging_station_base.hpp │ ├── cistring.hpp │ ├── constants.hpp │ ├── custom_iterators.hpp │ ├── database │ │ └── database_handler_common.hpp │ ├── evse_security.hpp │ ├── evse_security_impl.hpp │ ├── message_dispatcher.hpp │ ├── message_queue.hpp │ ├── ocpp_logging.hpp │ ├── safe_queue.hpp │ ├── schemas.hpp │ ├── string.hpp │ ├── support_older_cpp_versions.hpp │ ├── types.hpp │ ├── utils.hpp │ └── websocket │ │ ├── websocket.hpp │ │ ├── websocket_base.hpp │ │ ├── websocket_libwebsockets.hpp │ │ └── websocket_uri.hpp │ ├── v16 │ ├── charge_point.hpp │ ├── charge_point_configuration.hpp │ ├── charge_point_impl.hpp │ ├── charge_point_state_machine.hpp │ ├── connector.hpp │ ├── database_handler.hpp │ ├── message_dispatcher.hpp │ ├── messages │ │ ├── Authorize.hpp │ │ ├── BootNotification.hpp │ │ ├── CancelReservation.hpp │ │ ├── CertificateSigned.hpp │ │ ├── ChangeAvailability.hpp │ │ ├── ChangeConfiguration.hpp │ │ ├── ClearCache.hpp │ │ ├── ClearChargingProfile.hpp │ │ ├── DataTransfer.hpp │ │ ├── DeleteCertificate.hpp │ │ ├── DiagnosticsStatusNotification.hpp │ │ ├── ExtendedTriggerMessage.hpp │ │ ├── FirmwareStatusNotification.hpp │ │ ├── GetCompositeSchedule.hpp │ │ ├── GetConfiguration.hpp │ │ ├── GetDiagnostics.hpp │ │ ├── GetInstalledCertificateIds.hpp │ │ ├── GetLocalListVersion.hpp │ │ ├── GetLog.hpp │ │ ├── Heartbeat.hpp │ │ ├── InstallCertificate.hpp │ │ ├── LogStatusNotification.hpp │ │ ├── MeterValues.hpp │ │ ├── RemoteStartTransaction.hpp │ │ ├── RemoteStopTransaction.hpp │ │ ├── ReserveNow.hpp │ │ ├── Reset.hpp │ │ ├── SecurityEventNotification.hpp │ │ ├── SendLocalList.hpp │ │ ├── SetChargingProfile.hpp │ │ ├── SignCertificate.hpp │ │ ├── SignedFirmwareStatusNotification.hpp │ │ ├── SignedUpdateFirmware.hpp │ │ ├── StartTransaction.hpp │ │ ├── StatusNotification.hpp │ │ ├── StopTransaction.hpp │ │ ├── TriggerMessage.hpp │ │ ├── UnlockConnector.hpp │ │ └── UpdateFirmware.hpp │ ├── ocpp_enums.hpp │ ├── ocpp_types.hpp │ ├── profile.hpp │ ├── smart_charging.hpp │ ├── transaction.hpp │ ├── types.hpp │ └── utils.hpp │ ├── v2 │ ├── average_meter_values.hpp │ ├── charge_point.hpp │ ├── charge_point_callbacks.hpp │ ├── comparators.hpp │ ├── component_state_manager.hpp │ ├── connectivity_manager.hpp │ ├── connector.hpp │ ├── constants.hpp │ ├── ctrlr_component_variables.hpp │ ├── database_handler.hpp │ ├── device_model.hpp │ ├── device_model_storage_interface.hpp │ ├── device_model_storage_sqlite.hpp │ ├── enums.hpp │ ├── evse.hpp │ ├── evse_manager.hpp │ ├── functional_blocks │ │ ├── authorization.hpp │ │ ├── availability.hpp │ │ ├── data_transfer.hpp │ │ ├── diagnostics.hpp │ │ ├── display_message.hpp │ │ ├── firmware_update.hpp │ │ ├── functional_block_context.hpp │ │ ├── meter_values.hpp │ │ ├── provisioning.hpp │ │ ├── remote_transaction_control.hpp │ │ ├── reservation.hpp │ │ ├── security.hpp │ │ ├── smart_charging.hpp │ │ ├── tariff_and_cost.hpp │ │ └── transaction.hpp │ ├── init_device_model_db.hpp │ ├── message_dispatcher.hpp │ ├── message_handler.hpp │ ├── messages │ │ ├── Authorize.hpp │ │ ├── BootNotification.hpp │ │ ├── CancelReservation.hpp │ │ ├── CertificateSigned.hpp │ │ ├── ChangeAvailability.hpp │ │ ├── ClearCache.hpp │ │ ├── ClearChargingProfile.hpp │ │ ├── ClearDisplayMessage.hpp │ │ ├── ClearVariableMonitoring.hpp │ │ ├── ClearedChargingLimit.hpp │ │ ├── CostUpdated.hpp │ │ ├── CustomerInformation.hpp │ │ ├── DataTransfer.hpp │ │ ├── DeleteCertificate.hpp │ │ ├── FirmwareStatusNotification.hpp │ │ ├── Get15118EVCertificate.hpp │ │ ├── GetBaseReport.hpp │ │ ├── GetCertificateStatus.hpp │ │ ├── GetChargingProfiles.hpp │ │ ├── GetCompositeSchedule.hpp │ │ ├── GetDisplayMessages.hpp │ │ ├── GetInstalledCertificateIds.hpp │ │ ├── GetLocalListVersion.hpp │ │ ├── GetLog.hpp │ │ ├── GetMonitoringReport.hpp │ │ ├── GetReport.hpp │ │ ├── GetTransactionStatus.hpp │ │ ├── GetVariables.hpp │ │ ├── Heartbeat.hpp │ │ ├── InstallCertificate.hpp │ │ ├── LogStatusNotification.hpp │ │ ├── MeterValues.hpp │ │ ├── NotifyChargingLimit.hpp │ │ ├── NotifyCustomerInformation.hpp │ │ ├── NotifyDisplayMessages.hpp │ │ ├── NotifyEVChargingNeeds.hpp │ │ ├── NotifyEVChargingSchedule.hpp │ │ ├── NotifyEvent.hpp │ │ ├── NotifyMonitoringReport.hpp │ │ ├── NotifyReport.hpp │ │ ├── PublishFirmware.hpp │ │ ├── PublishFirmwareStatusNotification.hpp │ │ ├── ReportChargingProfiles.hpp │ │ ├── RequestStartTransaction.hpp │ │ ├── RequestStopTransaction.hpp │ │ ├── ReservationStatusUpdate.hpp │ │ ├── ReserveNow.hpp │ │ ├── Reset.hpp │ │ ├── SecurityEventNotification.hpp │ │ ├── SendLocalList.hpp │ │ ├── SetChargingProfile.hpp │ │ ├── SetDisplayMessage.hpp │ │ ├── SetMonitoringBase.hpp │ │ ├── SetMonitoringLevel.hpp │ │ ├── SetNetworkProfile.hpp │ │ ├── SetVariableMonitoring.hpp │ │ ├── SetVariables.hpp │ │ ├── SignCertificate.hpp │ │ ├── StatusNotification.hpp │ │ ├── TransactionEvent.hpp │ │ ├── TriggerMessage.hpp │ │ ├── UnlockConnector.hpp │ │ ├── UnpublishFirmware.hpp │ │ └── UpdateFirmware.hpp │ ├── monitoring_updater.hpp │ ├── notify_report_requests_splitter.hpp │ ├── ocpp_enums.hpp │ ├── ocpp_types.hpp │ ├── ocsp_updater.hpp │ ├── profile.hpp │ ├── transaction.hpp │ ├── types.hpp │ └── utils.hpp │ └── v21 │ └── messages │ ├── AFRRSignal.hpp │ ├── AdjustPeriodicEventStream.hpp │ ├── BatterySwap.hpp │ ├── ChangeTransactionTariff.hpp │ ├── ClearDERControl.hpp │ ├── ClearTariffs.hpp │ ├── ClosePeriodicEventStream.hpp │ ├── GetCertificateChainStatus.hpp │ ├── GetDERControl.hpp │ ├── GetPeriodicEventStream.hpp │ ├── GetTariffs.hpp │ ├── NotifyAllowedEnergyTransfer.hpp │ ├── NotifyCRL.hpp │ ├── NotifyDERAlarm.hpp │ ├── NotifyDERStartStop.hpp │ ├── NotifyPeriodicEventStream.hpp │ ├── NotifyPriorityCharging.hpp │ ├── NotifyQRCodeScanned.hpp │ ├── NotifySettlement.hpp │ ├── NotifyWebPaymentStarted.hpp │ ├── OpenPeriodicEventStream.hpp │ ├── PullDynamicScheduleUpdate.hpp │ ├── ReportDERControl.hpp │ ├── RequestBatterySwap.hpp │ ├── SetDERControl.hpp │ ├── SetDefaultTariff.hpp │ ├── UpdateDynamicSchedule.hpp │ ├── UsePriorityCharging.hpp │ └── VatNumberValidation.hpp ├── lib ├── CMakeLists.txt └── ocpp │ ├── common │ ├── call_types.cpp │ ├── charging_station_base.cpp │ ├── database │ │ └── database_handler_common.cpp │ ├── evse_security.cpp │ ├── evse_security_impl.cpp │ ├── ocpp_logging.cpp │ ├── schemas.cpp │ ├── types.cpp │ ├── utils.cpp │ └── websocket │ │ ├── CMakeLists.txt │ │ ├── websocket.cpp │ │ ├── websocket_base.cpp │ │ ├── websocket_libwebsockets.cpp │ │ └── websocket_uri.cpp │ ├── v16 │ ├── charge_point.cpp │ ├── charge_point_configuration.cpp │ ├── charge_point_impl.cpp │ ├── charge_point_state_machine.cpp │ ├── database_handler.cpp │ ├── message_dispatcher.cpp │ ├── message_queue.cpp │ ├── messages │ │ ├── Authorize.cpp │ │ ├── BootNotification.cpp │ │ ├── CMakeLists.txt │ │ ├── CancelReservation.cpp │ │ ├── CertificateSigned.cpp │ │ ├── ChangeAvailability.cpp │ │ ├── ChangeConfiguration.cpp │ │ ├── ClearCache.cpp │ │ ├── ClearChargingProfile.cpp │ │ ├── DataTransfer.cpp │ │ ├── DeleteCertificate.cpp │ │ ├── DiagnosticsStatusNotification.cpp │ │ ├── ExtendedTriggerMessage.cpp │ │ ├── FirmwareStatusNotification.cpp │ │ ├── GetCompositeSchedule.cpp │ │ ├── GetConfiguration.cpp │ │ ├── GetDiagnostics.cpp │ │ ├── GetInstalledCertificateIds.cpp │ │ ├── GetLocalListVersion.cpp │ │ ├── GetLog.cpp │ │ ├── Heartbeat.cpp │ │ ├── InstallCertificate.cpp │ │ ├── LogStatusNotification.cpp │ │ ├── MeterValues.cpp │ │ ├── RemoteStartTransaction.cpp │ │ ├── RemoteStopTransaction.cpp │ │ ├── ReserveNow.cpp │ │ ├── Reset.cpp │ │ ├── SecurityEventNotification.cpp │ │ ├── SendLocalList.cpp │ │ ├── SetChargingProfile.cpp │ │ ├── SignCertificate.cpp │ │ ├── SignedFirmwareStatusNotification.cpp │ │ ├── SignedUpdateFirmware.cpp │ │ ├── StartTransaction.cpp │ │ ├── StatusNotification.cpp │ │ ├── StopTransaction.cpp │ │ ├── TriggerMessage.cpp │ │ ├── UnlockConnector.cpp │ │ └── UpdateFirmware.cpp │ ├── ocpp_enums.cpp │ ├── ocpp_types.cpp │ ├── profile.cpp │ ├── smart_charging.cpp │ ├── transaction.cpp │ ├── types.cpp │ └── utils.cpp │ ├── v2 │ ├── average_meter_values.cpp │ ├── charge_point.cpp │ ├── charge_point_callbacks.cpp │ ├── component_state_manager.cpp │ ├── connectivity_manager.cpp │ ├── connector.cpp │ ├── ctrlr_component_variables.cpp │ ├── database_handler.cpp │ ├── device_model.cpp │ ├── device_model_storage_sqlite.cpp │ ├── enums.cpp │ ├── evse.cpp │ ├── evse_manager.cpp │ ├── functional_blocks │ │ ├── authorization.cpp │ │ ├── availability.cpp │ │ ├── data_transfer.cpp │ │ ├── diagnostics.cpp │ │ ├── display_message.cpp │ │ ├── firmware_update.cpp │ │ ├── meter_values.cpp │ │ ├── provisioning.cpp │ │ ├── remote_transaction_control.cpp │ │ ├── reservation.cpp │ │ ├── security.cpp │ │ ├── smart_charging.cpp │ │ ├── tariff_and_cost.cpp │ │ └── transaction.cpp │ ├── init_device_model_db.cpp │ ├── message_dispatcher.cpp │ ├── message_queue.cpp │ ├── messages │ │ ├── Authorize.cpp │ │ ├── BootNotification.cpp │ │ ├── CMakeLists.txt │ │ ├── CancelReservation.cpp │ │ ├── CertificateSigned.cpp │ │ ├── ChangeAvailability.cpp │ │ ├── ClearCache.cpp │ │ ├── ClearChargingProfile.cpp │ │ ├── ClearDisplayMessage.cpp │ │ ├── ClearVariableMonitoring.cpp │ │ ├── ClearedChargingLimit.cpp │ │ ├── CostUpdated.cpp │ │ ├── CustomerInformation.cpp │ │ ├── DataTransfer.cpp │ │ ├── DeleteCertificate.cpp │ │ ├── FirmwareStatusNotification.cpp │ │ ├── Get15118EVCertificate.cpp │ │ ├── GetBaseReport.cpp │ │ ├── GetCertificateStatus.cpp │ │ ├── GetChargingProfiles.cpp │ │ ├── GetCompositeSchedule.cpp │ │ ├── GetDisplayMessages.cpp │ │ ├── GetInstalledCertificateIds.cpp │ │ ├── GetLocalListVersion.cpp │ │ ├── GetLog.cpp │ │ ├── GetMonitoringReport.cpp │ │ ├── GetReport.cpp │ │ ├── GetTransactionStatus.cpp │ │ ├── GetVariables.cpp │ │ ├── Heartbeat.cpp │ │ ├── InstallCertificate.cpp │ │ ├── LogStatusNotification.cpp │ │ ├── MeterValues.cpp │ │ ├── NotifyChargingLimit.cpp │ │ ├── NotifyCustomerInformation.cpp │ │ ├── NotifyDisplayMessages.cpp │ │ ├── NotifyEVChargingNeeds.cpp │ │ ├── NotifyEVChargingSchedule.cpp │ │ ├── NotifyEvent.cpp │ │ ├── NotifyMonitoringReport.cpp │ │ ├── NotifyReport.cpp │ │ ├── PublishFirmware.cpp │ │ ├── PublishFirmwareStatusNotification.cpp │ │ ├── ReportChargingProfiles.cpp │ │ ├── RequestStartTransaction.cpp │ │ ├── RequestStopTransaction.cpp │ │ ├── ReservationStatusUpdate.cpp │ │ ├── ReserveNow.cpp │ │ ├── Reset.cpp │ │ ├── SecurityEventNotification.cpp │ │ ├── SendLocalList.cpp │ │ ├── SetChargingProfile.cpp │ │ ├── SetDisplayMessage.cpp │ │ ├── SetMonitoringBase.cpp │ │ ├── SetMonitoringLevel.cpp │ │ ├── SetNetworkProfile.cpp │ │ ├── SetVariableMonitoring.cpp │ │ ├── SetVariables.cpp │ │ ├── SignCertificate.cpp │ │ ├── StatusNotification.cpp │ │ ├── TransactionEvent.cpp │ │ ├── TriggerMessage.cpp │ │ ├── UnlockConnector.cpp │ │ ├── UnpublishFirmware.cpp │ │ └── UpdateFirmware.cpp │ ├── monitoring_updater.cpp │ ├── notify_report_requests_splitter.cpp │ ├── ocpp_enums.cpp │ ├── ocpp_types.cpp │ ├── ocsp_updater.cpp │ ├── profile.cpp │ ├── transaction.cpp │ ├── types.cpp │ └── utils.cpp │ └── v21 │ └── messages │ ├── AFRRSignal.cpp │ ├── AdjustPeriodicEventStream.cpp │ ├── BatterySwap.cpp │ ├── CMakeLists.txt │ ├── ChangeTransactionTariff.cpp │ ├── ClearDERControl.cpp │ ├── ClearTariffs.cpp │ ├── ClosePeriodicEventStream.cpp │ ├── GetCertificateChainStatus.cpp │ ├── GetDERControl.cpp │ ├── GetPeriodicEventStream.cpp │ ├── GetTariffs.cpp │ ├── NotifyAllowedEnergyTransfer.cpp │ ├── NotifyCRL.cpp │ ├── NotifyDERAlarm.cpp │ ├── NotifyDERStartStop.cpp │ ├── NotifyPeriodicEventStream.cpp │ ├── NotifyPriorityCharging.cpp │ ├── NotifyQRCodeScanned.cpp │ ├── NotifySettlement.cpp │ ├── NotifyWebPaymentStarted.cpp │ ├── OpenPeriodicEventStream.cpp │ ├── PullDynamicScheduleUpdate.cpp │ ├── ReportDERControl.cpp │ ├── RequestBatterySwap.cpp │ ├── SetDERControl.cpp │ ├── SetDefaultTariff.cpp │ ├── UpdateDynamicSchedule.cpp │ ├── UsePriorityCharging.cpp │ └── VatNumberValidation.cpp ├── run-docker-tls.sh ├── run-docker.sh ├── src ├── CMakeLists.txt ├── charge_point.cpp └── code_generator │ ├── README.md │ └── common │ ├── generate_cpp.py │ ├── generate_everest_types.py │ ├── templates │ ├── everest_type.yaml.jinja │ ├── message.cpp.jinja │ ├── message.hpp.jinja │ ├── messages.cmakelists.txt.jinja │ ├── ocpp_enums.cpp.jinja │ ├── ocpp_enums.hpp.jinja │ ├── ocpp_types.cpp.jinja │ └── ocpp_types.hpp.jinja │ └── utils.py └── tests ├── CMakeLists.txt ├── config ├── v16 │ └── resources │ │ ├── config.json │ │ └── user_config.json └── v2 │ ├── pytest.ini │ ├── resources │ └── component_config │ │ ├── custom │ │ ├── Connector_1_1.json │ │ ├── Connector_2_1.json │ │ ├── EVSE_1.json │ │ └── EVSE_2.json │ │ └── standardized │ │ └── UnitTestCtrlr.json │ ├── resources_changed │ └── component_config │ │ ├── custom │ │ ├── Connector_1_1.json │ │ ├── Connector_2_2.json │ │ ├── EVSE_1.json │ │ ├── EVSE_2.json │ │ └── EVSE_3.json │ │ └── standardized │ │ └── UnitTestCtrlr.json │ └── resources_wrong │ ├── component_config_required_no_value │ ├── custom │ │ ├── Connector_1_1.json │ │ └── EVSE_1.json │ └── standardized │ │ └── UnitTestCtrlr.json │ └── component_config_wrong_value_type │ ├── custom │ ├── Connector_1_1.json │ └── EVSE_1.json │ └── standardized │ └── UnitTestCtrlr.json ├── lib └── ocpp │ ├── common │ ├── CMakeLists.txt │ ├── database_testing_utils.hpp │ ├── evse_security_mock.hpp │ ├── smart_charging_matchers.hpp │ ├── test_database_migration_files.cpp │ ├── test_database_migration_files.hpp │ ├── test_message_queue.cpp │ ├── test_websocket_uri.cpp │ └── utils_tests.cpp │ ├── v16 │ ├── CMakeLists.txt │ ├── database_handler_mock.hpp │ ├── database_stub.hpp │ ├── database_tests.cpp │ ├── json │ │ ├── Absolute_301.json │ │ ├── ChargingStationMaxProfile_24_Ampere.json │ │ ├── ChargingStationMaxProfile_401.json │ │ ├── Recurring_Daily_301.json │ │ ├── Recurring_Daily_302_phase_limit.json │ │ ├── Relative_302_phase_limit.json │ │ ├── Relative_303.json │ │ ├── TXDefaultProfile_25_Watt.json │ │ ├── TxDefaultProfile_01.json │ │ ├── TxDefaultProfile_100.json │ │ ├── TxDefaultProfile_2kw_17-20.json │ │ ├── TxDefaultProfile_401.json │ │ ├── TxDefaultProfile_402.json │ │ ├── TxDefaultProfile_Absolute_Daily_2kw_1080.json │ │ ├── TxDefaultProfile_no_chargingRateUnit.json │ │ ├── TxProfile_02.json │ │ ├── TxProfile_03_Absolute.json │ │ └── TxProfile_grid.json │ ├── profile_testsA.cpp │ ├── profile_testsB.cpp │ ├── profile_testsC.cpp │ ├── profile_tests_common.cpp │ ├── profile_tests_common.hpp │ ├── test_charge_point_state_machine.cpp │ ├── test_composite_schedule.cpp │ ├── test_config_validation.cpp │ ├── test_database_migration_files.cpp │ ├── test_message_queue.cpp │ └── test_smart_charging_handler.cpp │ └── v2 │ ├── CMakeLists.txt │ ├── comparators.cpp │ ├── comparators.hpp │ ├── device_model_test_helper.cpp │ ├── device_model_test_helper.hpp │ ├── functional_blocks │ ├── CMakeLists.txt │ ├── test_authorization.cpp │ ├── test_availability.cpp │ ├── test_data_transfer.cpp │ ├── test_reservation.cpp │ ├── test_security.cpp │ └── test_smart_charging.cpp │ ├── json │ ├── OCCT_TC_K_41_CS │ │ ├── 0 │ │ │ └── id1-ChargingStationMaxProfile.json │ │ ├── 1 │ │ │ ├── id2-TxDefaultProfile.json │ │ │ └── id2-TxProfile.json │ │ └── README.md │ ├── README.md │ ├── baseline │ │ ├── README.md │ │ ├── TxProfile_1.json │ │ └── TxProfile_100.json │ ├── case_one │ │ ├── README.md │ │ ├── TxProfile_1.json │ │ └── TxProfile_100.json │ ├── external │ │ ├── 0 │ │ │ ├── ChargingStationExternalConstraintProfile_grid_hourly.json │ │ │ └── ChargingStationMaxProfile_2000.json │ │ ├── 1 │ │ │ └── TXProfile_2001.json │ │ └── README.md │ ├── grid │ │ ├── README.md │ │ └── TxProfile_grid_hourly.json │ ├── layered │ │ ├── README.md │ │ ├── TXProfile_single.json │ │ └── TxProfile_grid_hourly.json │ ├── layered_recurring │ │ ├── README.md │ │ ├── TXProfile_single.json │ │ └── TxProfile_grid_hourly.json │ ├── max │ │ ├── 0 │ │ │ └── ChargingStationMaxProfile_grid_hourly.json │ │ ├── 1 │ │ │ ├── TXProfile_2000.json │ │ │ └── TXProfile_2001.json │ │ └── README.md │ ├── no_gap │ │ ├── TxDefaultProfile_401.json │ │ └── TxDefaultProfile_402.json │ ├── relative │ │ ├── README.md │ │ ├── TxProfile_grid_hourly.json │ │ └── TxProfile_relative.json │ └── singles │ │ ├── Absolute_301.json │ │ ├── Absolute_NoDuration_301.json │ │ ├── ChargingStationMaxProfile_24_Ampere.json │ │ ├── ChargingStationMaxProfile_401.json │ │ ├── ProfileA.json │ │ ├── README.md │ │ ├── Recurring_Daily_301.json │ │ ├── Recurring_Daily_302_phase_limit.json │ │ ├── Recurring_Daily_NoDuration_301.json │ │ ├── Recurring_Weekly_301.json │ │ ├── Recurring_Weekly_NoDuration_301.json │ │ ├── Relative_301.json │ │ ├── Relative_302_phase_limit.json │ │ ├── Relative_303.json │ │ ├── Relative_MultipleChargingSchedules.json │ │ ├── Relative_NoDuration_301.json │ │ ├── TXDefaultProfile_25_Watt.json │ │ ├── TXProfile_Absolute_Start18-04.json │ │ └── TxProfile_CONCERNING_overlapping_periods.json │ ├── mocks │ ├── component_state_manager_mock.hpp │ ├── connectivity_manager_mock.hpp │ ├── database_handler_fake.hpp │ ├── database_handler_mock.hpp │ ├── device_model_storage_interface_mock.hpp │ ├── evse_manager_fake.hpp │ ├── evse_mock.hpp │ ├── message_dispatcher_mock.hpp │ ├── ocsp_updater_mock.hpp │ └── smart_charging_mock.hpp │ ├── smart_charging_test_utils.cpp │ ├── smart_charging_test_utils.hpp │ ├── stubs │ └── timer │ │ ├── everest │ │ └── timer.hpp │ │ ├── timer_stub.cpp │ │ └── timer_stub.hpp │ ├── test_charge_point.cpp │ ├── test_component_state_manager.cpp │ ├── test_composite_schedule.cpp │ ├── test_database_handler.cpp │ ├── test_database_migration_files.cpp │ ├── test_device_model.cpp │ ├── test_device_model_storage_sqlite.cpp │ ├── test_init_device_model_db.cpp │ ├── test_message_queue.cpp │ ├── test_notify_report_requests_splitter.cpp │ ├── test_ocsp_updater.cpp │ ├── test_profile.cpp │ └── utils_tests.cpp ├── libocpp-unittests.cmake └── resources ├── unittest_device_model.db └── unittest_device_model_missing_required.db /.ci/build-kit/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | ARG BASE_IMAGE_TAG=latest 3 | FROM ghcr.io/everest/everest-ci/build-kit-base:${BASE_IMAGE_TAG} 4 | -------------------------------------------------------------------------------- /.ci/build-kit/scripts/build_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cmake \ 4 | -B "$EXT_MOUNT/build" \ 5 | -S "$EXT_MOUNT/source" \ 6 | -G Ninja \ 7 | -DBUILD_TESTING=ON \ 8 | -DLIBOCPP16_BUILD_EXAMPLES=ON \ 9 | -DCMAKE_BUILD_TYPE=Debug \ 10 | -DCMAKE_INSTALL_PREFIX="$EXT_MOUNT/dist" \ 11 | -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 12 | 13 | retVal=$? 14 | if [ $retVal -ne 0 ]; then 15 | echo "Configuring failed with return code $retVal" 16 | exit $retVal 17 | fi 18 | 19 | ninja -C "$EXT_MOUNT/build" doxygen-ocpp 20 | retVal=$? 21 | if [ $retVal -ne 0 ]; then 22 | echo "Building docs failed with return code $retVal" 23 | exit $retVal 24 | fi 25 | 26 | cp -r "$EXT_MOUNT/build/dist/docs/html" "$EXT_MOUNT/doxygen-docs" 27 | retVal=$? 28 | if [ $retVal -ne 0 ]; then 29 | echo "Copying docs failed with return code $retVal" 30 | exit $retVal 31 | fi 32 | -------------------------------------------------------------------------------- /.ci/build-kit/scripts/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cmake \ 4 | -B "$EXT_MOUNT/build" \ 5 | -S "$EXT_MOUNT/source" \ 6 | -G Ninja \ 7 | -DBUILD_TESTING=ON \ 8 | -DLIBOCPP16_BUILD_EXAMPLES=ON \ 9 | -DCMAKE_BUILD_TYPE=Debug \ 10 | -DCMAKE_INSTALL_PREFIX="$EXT_MOUNT/dist" \ 11 | -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 12 | 13 | retVal=$? 14 | if [ $retVal -ne 0 ]; then 15 | echo "Configuring failed with return code $retVal" 16 | exit $retVal 17 | fi 18 | 19 | ninja -C "$EXT_MOUNT/build" 20 | retVal=$? 21 | if [ $retVal -ne 0 ]; then 22 | echo "Compiling failed with return code $retVal" 23 | exit $retVal 24 | fi 25 | -------------------------------------------------------------------------------- /.ci/build-kit/scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ninja -C "$EXT_MOUNT/build" install 4 | retVal=$? 5 | 6 | if [ $retVal -ne 0 ]; then 7 | echo "Installation failed with return code $retVal" 8 | exit $retVal 9 | fi 10 | -------------------------------------------------------------------------------- /.ci/build-kit/scripts/run_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ninja \ 4 | -C "$EXT_MOUNT/build" \ 5 | ocpp_gcovr_coverage 6 | retValHTML=$? 7 | 8 | ninja \ 9 | -C "$EXT_MOUNT/build" \ 10 | ocpp_gcovr_coverage_xml 11 | retValXML=$? 12 | 13 | # Copy the generated coverage report and xml to the mounted directory in any case 14 | cp -R "$EXT_MOUNT/build/ocpp_gcovr_coverage" "$EXT_MOUNT/gcovr-coverage" 15 | cp "$EXT_MOUNT/build/ocpp_gcovr_coverage_xml.xml" "$EXT_MOUNT/gcovr-coverage-xml.xml" 16 | 17 | if [ $retValHTML -ne 0 ]; then 18 | echo "Coverage HTML report failed with return code $retValHTML" 19 | exit $retValHTML 20 | fi 21 | 22 | if [ $retValXML -ne 0 ]; then 23 | echo "Coverage XML report failed with return code $retValXML" 24 | exit $retValXML 25 | fi 26 | -------------------------------------------------------------------------------- /.ci/build-kit/scripts/run_unit_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ninja -C "$EXT_MOUNT/build" test 4 | retVal=$? 5 | 6 | # Copy the LastTest.log file to the mounted directory in any case 7 | cp "$EXT_MOUNT/build/Testing/Temporary/LastTest.log" "$EXT_MOUNT/ctest-report" 8 | 9 | if [ $retVal -ne 0 ]; then 10 | echo "Unit tests failed with return code $retVal" 11 | exit $retVal 12 | fi 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.json] 2 | indent_style = space 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @pietfried @hikinggrass @marcemmers @mlitre 2 | 3 | /config/v16/ @pietfried @hikinggrass @mlitre 4 | /include/ocpp/v16/ @pietfried @hikinggrass @mlitre 5 | /lib/ocpp/v16/ @pietfried @hikinggrass @mlitre 6 | 7 | /.github/ @pietfried @hikinggrass @mlitre 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Thanks for taking the time to fill out this bug report! 3 | 4 | body: 5 | - type: dropdown 6 | id: affected-ocpp-version 7 | attributes: 8 | label: OCPP Version 9 | description: Which OCPP is affected? Mark multiple if applicable. 10 | options: 11 | - OCPP1.6 12 | - OCPP2.0.1 13 | - OCPP2.1 14 | multiple: true 15 | validations: 16 | required: true 17 | 18 | - type: textarea 19 | id: description 20 | attributes: 21 | label: Describe the bug 22 | description: A clear and concise description of what the bug is. If applicable, add screenshots or logfiles to help explain your problem. 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: reproduction 28 | attributes: 29 | label: To Reproduce 30 | description: | 31 | If applicable describe the steps to and additional information to reproduce the behavior like message communication between CSMS, used configuration(s), compile options and your system information 32 | 33 | - type: textarea 34 | id: other 35 | attributes: 36 | label: Anything else? 37 | placeholder: Add any other context about the bug report here. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Thanks for taking the time to fill out this feature request! 3 | 4 | body: 5 | - type: dropdown 6 | id: affected-ocpp-version 7 | attributes: 8 | label: OCPP Version 9 | description: For which OCPP do you suggest this feature? Mark multiple if applicable. 10 | options: 11 | - OCPP1.6 12 | - OCPP2.0.1 13 | - OCPP2.1 14 | multiple: true 15 | validations: 16 | required: true 17 | 18 | - type: textarea 19 | id: description 20 | attributes: 21 | label: Describe the problem 22 | description: What problem is your feature request targeting and why is it a problem? Please describe. 23 | placeholder: | 24 | A clear and concise description of what the problem is. 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | id: solution 30 | attributes: 31 | label: Describe your solution 32 | description: Describe the solution you'd like 33 | placeholder: | 34 | A clear and concise description of what you want to happen. 35 | 36 | - type: textarea 37 | id: other 38 | attributes: 39 | label: Additional context 40 | placeholder: Add any other context about the feature request here. 41 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Describe your changes 2 | 3 | ## Issue ticket number and link 4 | 5 | ## Checklist before requesting a review 6 | - [ ] I have performed a self-review of my code 7 | - [ ] I have made corresponding changes to the documentation 8 | - [ ] If OCPP 2.0.1 or OCPP2.1: I have updated the [OCPP 2.x status document](https://github.com/EVerest/libocpp/tree/main/doc/ocpp_2x_status.md) 9 | - [ ] I read the [contribution documentation](https://github.com/EVerest/EVerest/blob/main/CONTRIBUTING.md) and made sure that my changes meet its requirements 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | !.gitignore 3 | *vscode 4 | .cache/ 5 | workspace.yaml 6 | CMakeLists.txt.user 7 | __pycache__ 8 | !doc/build-with-fetchcontent 9 | /dist 10 | -------------------------------------------------------------------------------- /THIRD_PARTY.md: -------------------------------------------------------------------------------- 1 | _Use this file to list out any third-party dependencies used by this project. You may choose to point to a Gemfile or other language specific packaging file for details._ 2 | -------------------------------------------------------------------------------- /config/logging.ini: -------------------------------------------------------------------------------- 1 | # for documentation on this file format see: 2 | # https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter 3 | 4 | [Core] 5 | DisableLogging=false 6 | Filter="%Severity% >= INFO" 7 | 8 | [Sinks.Console] 9 | Destination=Console 10 | # Filter="%Target% contains \"MySink1\"" 11 | Format="%TimeStamp% \033[1;32m%Process%\033[0m [\033[1;32m%ProcessID%\033[0m] [%Severity%] {\033[1;34m%ThreadID%\033[0m} \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%" 12 | Asynchronous=false 13 | AutoFlush=true 14 | SeverityStringColorDebug="\033[1;30m" 15 | SeverityStringColorInfo="\033[1;37m" 16 | SeverityStringColorWarning="\033[1;33m" 17 | SeverityStringColorError="\033[1;31m" 18 | SeverityStringColorCritical="\033[1;35m" 19 | -------------------------------------------------------------------------------- /config/v16/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(OCPP1_6_PROFILE_SCHEMAS_DIR "profile_schemas/") 2 | set(USER_CONFIG_FILE "user_config/user_config.json") 3 | set(CERTS_DIR "../certs/") 4 | 5 | # find all migration files, store only the filenames by showing relative to the folder 6 | set(MIGRATION_FILES_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/core_migrations") 7 | 8 | include(../CollectMigrationFiles.cmake) 9 | 10 | collect_migration_files( 11 | LOCATION ${MIGRATION_FILES_LOCATION} 12 | INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP/core_migrations 13 | ) 14 | 15 | set(OCPP1_6_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) 16 | set(MIGRATION_FILE_VERSION_V16 ${TARGET_MIGRATION_FILE_VERSION} PARENT_SCOPE) 17 | set(MIGRATION_FILES_SOURCE_DIR_V16 ${MIGRATION_FILES_LOCATION} PARENT_SCOPE) 18 | 19 | 20 | list(APPEND OCPP1_6_PROFILE_SCHEMAS 21 | Config.json 22 | Core.json 23 | FirmwareManagement.json 24 | Internal.json 25 | LocalAuthListManagement.json 26 | Reservation.json 27 | SmartCharging.json 28 | Security.json 29 | PnC.json 30 | CostAndPrice.json 31 | ) 32 | 33 | list(TRANSFORM OCPP1_6_PROFILE_SCHEMAS 34 | PREPEND ${OCPP1_6_PROFILE_SCHEMAS_DIR}) 35 | 36 | install( 37 | FILES ${OCPP1_6_PROFILE_SCHEMAS} 38 | DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP/profile_schemas 39 | ) 40 | 41 | list(APPEND CONFIGS 42 | config.json 43 | config-docker.json 44 | config-full.json 45 | config-docker-tls.json 46 | ../logging.ini 47 | ) 48 | 49 | install( 50 | FILES ${CONFIGS} 51 | DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP 52 | ) 53 | 54 | if(EXISTS ${USER_CONFIG_FILE}) 55 | install( 56 | FILES ${USER_CONFIG_FILE} 57 | DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP) 58 | endif() 59 | -------------------------------------------------------------------------------- /config/v16/config-docker-tls.json: -------------------------------------------------------------------------------- 1 | { 2 | "Internal": { 3 | "ChargePointId": "cp001", 4 | "CentralSystemURI": "127.0.0.1:8443/steve/websocket/CentralSystemService/", 5 | "ChargeBoxSerialNumber": "cp001", 6 | "ChargePointModel": "Yeti", 7 | "ChargePointVendor": "Pionix", 8 | "FirmwareVersion": "0.1" 9 | }, 10 | "Core": { 11 | "AuthorizeRemoteTxRequests": false, 12 | "ClockAlignedDataInterval": 900, 13 | "ConnectionTimeOut": 10, 14 | "ConnectorPhaseRotation": "0.RST,1.RST", 15 | "GetConfigurationMaxKeys": 100, 16 | "HeartbeatInterval": 86400, 17 | "LocalAuthorizeOffline": false, 18 | "LocalPreAuthorize": false, 19 | "MeterValuesAlignedData": "Energy.Active.Import.Register", 20 | "MeterValuesSampledData": "Energy.Active.Import.Register", 21 | "MeterValueSampleInterval": 0, 22 | "NumberOfConnectors": 1, 23 | "ResetRetries": 1, 24 | "StopTransactionOnInvalidId": true, 25 | "StopTxnAlignedData": "Energy.Active.Import.Register", 26 | "StopTxnSampledData": "Energy.Active.Import.Register", 27 | "SupportedFeatureProfiles": "Core,FirmwareManagement,Reservation,RemoteTrigger,LocalAuthListManagement,SmartCharging", 28 | "TransactionMessageAttempts": 1, 29 | "TransactionMessageRetryInterval": 10, 30 | "UnlockConnectorOnEVSideDisconnect": true 31 | }, 32 | "FirmwareManagement": { 33 | "SupportedFileTransferProtocols": "FTP" 34 | }, 35 | "Security": { 36 | "AuthorizationKey": "AABBCCDDEEFFGGHH", 37 | "SecurityProfile": 2 38 | }, 39 | "LocalAuthListManagement": { 40 | "LocalAuthListEnabled": true, 41 | "LocalAuthListMaxLength": 42, 42 | "SendLocalListMaxLength": 42 43 | }, 44 | "SmartCharging": { 45 | "ChargeProfileMaxStackLevel": 42, 46 | "ChargingScheduleAllowedChargingRateUnit": "Current", 47 | "ChargingScheduleMaxPeriods": 42, 48 | "MaxChargingProfilesInstalled": 42 49 | }, 50 | "PnC": { 51 | "ISO15118PnCEnabled": true, 52 | "ContractValidationOffline": true 53 | }, 54 | "Custom": { 55 | "ExampleConfigurationKey": "example" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /config/v16/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Internal": { 3 | "ChargePointId": "cp001", 4 | "CentralSystemURI": "127.0.0.1:8180/steve/websocket/CentralSystemService/", 5 | "ChargeBoxSerialNumber": "cp001", 6 | "ChargePointModel": "Yeti", 7 | "ChargePointVendor": "Pionix", 8 | "FirmwareVersion": "0.1", 9 | "LogMessagesFormat": [] 10 | }, 11 | "Core": { 12 | "AuthorizeRemoteTxRequests": false, 13 | "ClockAlignedDataInterval": 900, 14 | "ConnectionTimeOut": 10, 15 | "ConnectorPhaseRotation": "0.RST,1.RST", 16 | "GetConfigurationMaxKeys": 100, 17 | "HeartbeatInterval": 86400, 18 | "LocalAuthorizeOffline": false, 19 | "LocalPreAuthorize": false, 20 | "MeterValuesAlignedData": "Energy.Active.Import.Register", 21 | "MeterValuesSampledData": "Energy.Active.Import.Register", 22 | "MeterValueSampleInterval": 0, 23 | "NumberOfConnectors": 1, 24 | "ResetRetries": 1, 25 | "StopTransactionOnEVSideDisconnect": true, 26 | "StopTransactionOnInvalidId": true, 27 | "StopTxnAlignedData": "Energy.Active.Import.Register", 28 | "StopTxnSampledData": "Energy.Active.Import.Register", 29 | "SupportedFeatureProfiles": "Core,FirmwareManagement,RemoteTrigger,Reservation,LocalAuthListManagement,SmartCharging", 30 | "TransactionMessageAttempts": 1, 31 | "TransactionMessageRetryInterval": 10, 32 | "UnlockConnectorOnEVSideDisconnect": true 33 | }, 34 | "FirmwareManagement": { 35 | "SupportedFileTransferProtocols": "FTP" 36 | }, 37 | "LocalAuthListManagement": { 38 | "LocalAuthListEnabled": true, 39 | "LocalAuthListMaxLength": 42, 40 | "SendLocalListMaxLength": 42 41 | }, 42 | "SmartCharging": { 43 | "ChargeProfileMaxStackLevel": 42, 44 | "ChargingScheduleAllowedChargingRateUnit": "Current", 45 | "ChargingScheduleMaxPeriods": 42, 46 | "MaxChargingProfilesInstalled": 42 47 | }, 48 | "Security": { 49 | "SecurityProfile": 0 50 | }, 51 | "PnC": { 52 | "ISO15118PnCEnabled": true, 53 | "ContractValidationOffline": true 54 | }, 55 | "CostAndPrice": { 56 | "CustomDisplayCostAndPrice": false 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /config/v16/core_migrations/1_up-initial.sql: -------------------------------------------------------------------------------- 1 | PRAGMA foreign_keys = ON; 2 | CREATE TABLE CONNECTORS ( 3 | ID INT PRIMARY KEY NOT NULL, 4 | AVAILABILITY TEXT 5 | ); 6 | CREATE TABLE AUTH_CACHE ( 7 | ID_TAG TEXT PRIMARY KEY NOT NULL, 8 | AUTH_STATUS TEXT NOT NULL, 9 | EXPIRY_DATE TEXT, 10 | PARENT_ID_TAG TEXT 11 | ); 12 | CREATE TABLE AUTH_LIST_VERSION ( 13 | ID INT PRIMARY KEY NOT NULL, 14 | VERSION INT 15 | ); 16 | CREATE TABLE AUTH_LIST ( 17 | ID_TAG TEXT PRIMARY KEY NOT NULL, 18 | AUTH_STATUS TEXT NOT NULL, 19 | EXPIRY_DATE TEXT, 20 | PARENT_ID_TAG TEXT 21 | ); 22 | CREATE TABLE TRANSACTIONS ( 23 | ID INT PRIMARY KEY NOT NULL, 24 | TRANSACTION_ID INT, 25 | CONNECTOR INT NOT NULL, 26 | ID_TAG_START TEXT NOT NULL, 27 | TIME_START TEXT NOT NULL, 28 | METER_START INT NOT NULL, 29 | CSMS_ACK INT NOT NULL, 30 | METER_LAST INT NOT NULL, 31 | METER_LAST_TIME TEXT NOT NULL, 32 | LAST_UPDATE TEXT NOT NULL, 33 | RESERVATION_ID INT, 34 | PARENT_ID_TAG TEXT, 35 | ID_TAG_END TEXT, 36 | TIME_END TEXT, 37 | METER_STOP INT, 38 | STOP_REASON TEXT, 39 | FOREIGN KEY(CONNECTOR) REFERENCES CONNECTORS(ID) 40 | ); 41 | INSERT 42 | OR IGNORE INTO AUTH_LIST_VERSION (ID, VERSION) 43 | VALUES (0, 0); 44 | 45 | CREATE TABLE CHARGING_PROFILES ( 46 | ID INT PRIMARY KEY NOT NULL, 47 | CONNECTOR_ID INT NOT NULL, 48 | PROFILE TEXT NOT NULL 49 | ); 50 | 51 | CREATE TABLE OCSP_REQUEST ( 52 | LAST_UPDATE TEXT PRIMARY KEY NOT NULL 53 | ); 54 | 55 | CREATE TABLE TRANSACTION_QUEUE( 56 | UNIQUE_ID TEXT PRIMARY KEY NOT NULL, 57 | MESSAGE TEXT NOT NULL, 58 | MESSAGE_TYPE TEXT NOT NULL, 59 | MESSAGE_ATTEMPTS INT NOT NULL, 60 | MESSAGE_TIMESTAMP TEXT NOT NULL 61 | ); 62 | -------------------------------------------------------------------------------- /config/v16/core_migrations/2_down-offline-transaction.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE TRANSACTIONS DROP COLUMN START_TRANSACTION_MESSAGE_ID; 2 | ALTER TABLE TRANSACTIONS DROP COLUMN STOP_TRANSACTION_MESSAGE_ID; -------------------------------------------------------------------------------- /config/v16/core_migrations/2_up-offline-transaction.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE TRANSACTIONS ADD COLUMN START_TRANSACTION_MESSAGE_ID TEXT NOT NULL DEFAULT ""; 2 | ALTER TABLE TRANSACTIONS ADD COLUMN STOP_TRANSACTION_MESSAGE_ID TEXT; 3 | UPDATE TRANSACTIONS SET CSMS_ACK = 1; -------------------------------------------------------------------------------- /config/v16/core_migrations/3_down-persist-normal-messages.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE NORMAL_QUEUE; 2 | -------------------------------------------------------------------------------- /config/v16/core_migrations/3_up-persist-normal-messages.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE NORMAL_QUEUE( 2 | UNIQUE_ID TEXT PRIMARY KEY NOT NULL, 3 | MESSAGE TEXT NOT NULL, 4 | MESSAGE_TYPE TEXT NOT NULL, 5 | MESSAGE_ATTEMPTS INT NOT NULL, 6 | MESSAGE_TIMESTAMP TEXT NOT NULL 7 | ); 8 | -------------------------------------------------------------------------------- /config/v16/core_migrations/4_down-drop-ocsp-request.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE OCSP_REQUEST ( 2 | LAST_UPDATE TEXT PRIMARY KEY NOT NULL 3 | ); 4 | -------------------------------------------------------------------------------- /config/v16/core_migrations/4_up-drop-ocsp-request.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE OCSP_REQUEST; 2 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/Config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for OCPP 1.6 config", 4 | "type": "object", 5 | "required": [ 6 | "Internal", 7 | "Core", 8 | "Security" 9 | ], 10 | "properties": { 11 | "Internal": { 12 | "type": "object", 13 | "$ref": "Internal.json" 14 | }, 15 | "Core": { 16 | "type": "object", 17 | "$ref": "Core.json" 18 | }, 19 | "LocalAuthListManagement": { 20 | "type": "object", 21 | "$ref": "LocalAuthListManagement.json" 22 | }, 23 | "SmartCharging": { 24 | "type": "object", 25 | "$ref": "SmartCharging.json" 26 | }, 27 | "FirmwareManagement": { 28 | "type": "object", 29 | "$ref": "FirmwareManagement.json" 30 | }, 31 | "Reservation": { 32 | "type": "object", 33 | "$ref": "Reservation.json" 34 | }, 35 | "Security": { 36 | "type": "object", 37 | "$ref": "Security.json" 38 | }, 39 | "PnC": { 40 | "type": "object", 41 | "$ref": "PnC.json" 42 | }, 43 | "CostAndPrice": { 44 | "type": "object", 45 | "$ref": "CostAndPrice.json" 46 | } 47 | }, 48 | "additionalProperties": false 49 | } 50 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/Custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for Custom configuration keys", 4 | "$comment": "This is just an example schema and can be modified according to custom requirements", 5 | "type": "object", 6 | "required": [], 7 | "properties": {} 8 | } 9 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/FirmwareManagement.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for Firmware Management Profile config", 4 | "type": "object", 5 | "required": [], 6 | "properties": { 7 | "SupportedFileTransferProtocols": { 8 | "type": "string", 9 | "readOnly": true 10 | } 11 | }, 12 | "additionalProperties": false 13 | } 14 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/LocalAuthListManagement.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for Local Auth List Management Profile config", 4 | "type": "object", 5 | "required": [ 6 | "LocalAuthListEnabled", 7 | "LocalAuthListMaxLength", 8 | "SendLocalListMaxLength" 9 | ], 10 | "properties": { 11 | "LocalAuthListEnabled": { 12 | "type": "boolean", 13 | "readOnly": false 14 | }, 15 | "LocalAuthListMaxLength": { 16 | "type": "integer", 17 | "readOnly": true, 18 | "minimum": 0 19 | }, 20 | "SendLocalListMaxLength": { 21 | "type": "integer", 22 | "readOnly": true, 23 | "minimum": 0 24 | } 25 | }, 26 | "additionalProperties": false 27 | } 28 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/PnC.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for ISO15118 PnC extension", 4 | "type": "object", 5 | "required": ["ISO15118PnCEnabled", "ContractValidationOffline"], 6 | "properties": { 7 | "ISO15118PnCEnabled": { 8 | "type": "boolean", 9 | "description": "If this variable set to true, then the Charge Point supports ISO 15118 plug and charge messages via the DataTransfer mechanism as described in this application note.", 10 | "readOnly": false 11 | }, 12 | "CentralContractValidationAllowed": { 13 | "type": "boolean", 14 | "description": "If this variable exists and has the value true, then the Charge Point can provide a contract certificate that it cannot validate to the Central System for validation as part of the Authorize.req.", 15 | "readOnly": false 16 | }, 17 | "CertificateSignedMaxChainSize": { 18 | "type": "integer", 19 | "description": "This configuration key can be used to limit the size of the 'certificateChain' field from the CertificateSigned.req PDU", 20 | "maximum": 10000, 21 | "minimum": 0, 22 | "readOnly": true 23 | }, 24 | "CertSigningWaitMinimum": { 25 | "type": "integer", 26 | "description": "This configuration key defines how long the Charge Point has to wait (in seconds) before generating another CSR, in the case the Central System accepts the SignCertificate.req, but never returns the signed certificate back.", 27 | "minimum": 0, 28 | "readOnly": false 29 | }, 30 | "CertSigningRepeatTimes": { 31 | "type": "integer", 32 | "description": "This configuration key can be used to configure the amount of times the Charge Point SHALL double the previous back-off time", 33 | "minimum": 0, 34 | "readOnly": false 35 | }, 36 | "CertificateStoreMaxLength": { 37 | "type": "integer", 38 | "description": "Maximum number of Root/CA certificates that can be installed in the Charge Point.", 39 | "minimum": 1, 40 | "readOnly": true 41 | }, 42 | "ContractValidationOffline": { 43 | "type": "boolean", 44 | "description": "If this variable is true, then the Charge Point will try to validate a contract certificate when it is offline.", 45 | "readOnly": false 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/Reservation.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for Reservation Profile config", 4 | "type": "object", 5 | "required": [], 6 | "properties": { 7 | "ReserveConnectorZeroSupported": { 8 | "type": "boolean", 9 | "readOnly": true 10 | } 11 | }, 12 | "additionalProperties": false 13 | } 14 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/Security.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for Security Profile config", 4 | "type": "object", 5 | "required": [ 6 | "SecurityProfile" 7 | ], 8 | "properties": { 9 | "AdditionalRootCertificateCheck": { 10 | "type": "boolean", 11 | "description": "When set to true, only one certificate (plus a temporarily fallback certificate) of certificateType CentralSystemRootCertificate is allowed to be installed at a time", 12 | "readOnly": true 13 | }, 14 | "AuthorizationKey": { 15 | "type": "string", 16 | "description": "The basic authentication password is used for HTTP Basic Authentication", 17 | "minLength": 8, 18 | "readOnly": false 19 | }, 20 | "CertificateSignedMaxChainSize": { 21 | "type": "integer", 22 | "description": "This configuration key can be used to limit the size of the 'certificateChain' field from the CertificateSigned.req PDU.", 23 | "maximum": 10000, 24 | "readOnly": true 25 | }, 26 | "CertificateStoreMaxLength": { 27 | "type": "integer", 28 | "description": "Maximum number of Root/CA certificates that can be installed in the Charge Point.", 29 | "minimum": 0, 30 | "readOnly": true 31 | }, 32 | "CpoName": { 33 | "type": "string", 34 | "description": "This configuration key contains CPO name (or an organization trusted by the CPO) as used in the Charge Point Certificate.", 35 | "readOnly": false 36 | }, 37 | "SecurityProfile": { 38 | "type": "integer", 39 | "default": 0, 40 | "minimum": 0, 41 | "maximum": 3, 42 | "description": "This configuration key is used to set the security profile used by the Charge Point", 43 | "readOnly": false 44 | }, 45 | "DisableSecurityEventNotifications": { 46 | "type": "boolean", 47 | "description": "When set to true, no SecurityEventNotification.req messages will be sent by the Charge Point", 48 | "readOnly": false, 49 | "default": false 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /config/v16/profile_schemas/SmartCharging.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Json schema for Smart Charging Profile config", 4 | "type": "object", 5 | "required": [ 6 | "ChargeProfileMaxStackLevel", 7 | "ChargingScheduleAllowedChargingRateUnit", 8 | "ChargingScheduleMaxPeriods", 9 | "MaxChargingProfilesInstalled" 10 | ], 11 | "properties": { 12 | "ChargeProfileMaxStackLevel": { 13 | "type": "integer", 14 | "readOnly": true, 15 | "minimum": 0 16 | }, 17 | "ChargingScheduleAllowedChargingRateUnit": { 18 | "type": "string", 19 | "readOnly": true, 20 | "default": "Current,Power" 21 | }, 22 | "ChargingScheduleMaxPeriods": { 23 | "type": "integer", 24 | "readOnly": true, 25 | "minimum": 0, 26 | "default": 1440 27 | }, 28 | "ConnectorSwitch3to1PhaseSupported": { 29 | "type": "boolean", 30 | "readOnly": true 31 | }, 32 | "MaxChargingProfilesInstalled": { 33 | "type": "integer", 34 | "readOnly": true, 35 | "minimum": 0, 36 | "default": 500 37 | } 38 | }, 39 | "additionalProperties": false 40 | } 41 | -------------------------------------------------------------------------------- /config/v16/user_config/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !README.md 4 | -------------------------------------------------------------------------------- /config/v2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # find all migration files, store only the filenames by showing relative to the folder 2 | set(MIGRATION_FILES_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/core_migrations") 3 | set(MIGRATION_FILES_DEVICE_MODEL_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/device_model_migrations") 4 | 5 | include(../CollectMigrationFiles.cmake) 6 | 7 | collect_migration_files( 8 | LOCATION ${MIGRATION_FILES_LOCATION} 9 | INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP201/core_migrations 10 | ) 11 | 12 | set(MIGRATION_FILE_VERSION_V2 ${TARGET_MIGRATION_FILE_VERSION} PARENT_SCOPE) 13 | 14 | collect_migration_files( 15 | LOCATION ${MIGRATION_FILES_DEVICE_MODEL_LOCATION} 16 | INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP201/device_model_migrations 17 | ) 18 | 19 | set(MIGRATION_DEVICE_MODEL_FILE_VERSION_V2 ${TARGET_MIGRATION_FILE_VERSION} PARENT_SCOPE) 20 | set(MIGRATION_FILES_SOURCE_DIR_V2 ${MIGRATION_FILES_LOCATION} PARENT_SCOPE) 21 | set(MIGRATION_FILES_DEVICE_MODEL_SOURCE_DIR_V2 ${MIGRATION_FILES_DEVICE_MODEL_LOCATION} PARENT_SCOPE) 22 | 23 | option(LIBOCPP_INSTALL_DEVICE_MODEL_DATABASE "Install device model database for OCPP2.0.1 and OCPP2.1" ON) 24 | 25 | list(APPEND CONFIGS 26 | ../logging.ini 27 | ) 28 | 29 | install( 30 | FILES ${CONFIGS} 31 | DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP201 32 | ) 33 | 34 | if (LIBOCPP_INSTALL_DEVICE_MODEL_DATABASE) 35 | 36 | if (NOT LIBOCPP_COMPONENT_CONFIG_PATH) 37 | set(LIBOCPP_COMPONENT_CONFIG_PATH "${CMAKE_CURRENT_SOURCE_DIR}/component_config") 38 | endif() 39 | 40 | 41 | message(STATUS "Using ocpp v2 component config file path: ${LIBOCPP_COMPONENT_CONFIG_PATH}") 42 | 43 | install(DIRECTORY ${LIBOCPP_COMPONENT_CONFIG_PATH} DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/OCPP201) 44 | endif() 45 | -------------------------------------------------------------------------------- /config/v2/component_config/standardized/ChargingStatusIndicator.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for Charging Status Indicator", 4 | "type": "object", 5 | "name": "ChargingStatusIndicator", 6 | "properties": { 7 | "ChargingStatusIndicatorActive": { 8 | "variable_name": "Active", 9 | "characteristics": { 10 | "supportsMonitoring": true, 11 | "dataType": "boolean" 12 | }, 13 | "attributes": [ 14 | { 15 | "type": "Actual", 16 | "mutability": "ReadWrite", 17 | "value": false 18 | } 19 | ], 20 | "description": "Lighted", 21 | "type": "boolean" 22 | }, 23 | "ChargingStatusIndicatorColor": { 24 | "variable_name": "Color", 25 | "characteristics": { 26 | "supportsMonitoring": true, 27 | "dataType": "string" 28 | }, 29 | "attributes": [ 30 | { 31 | "type": "Actual", 32 | "mutability": "ReadWrite", 33 | "value": "FFFF00" 34 | } 35 | ], 36 | "description": "Displayed color", 37 | "type": "string" 38 | } 39 | }, 40 | "required": [ 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /config/v2/component_config/standardized/CustomizationCtrlr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for CustomizationCtrlr", 4 | "name": "CustomizationCtrlr", 5 | "type": "object", 6 | "properties": { 7 | "": { 8 | "variable_name": "Enabled", 9 | "characteristics": { 10 | "supportsMonitoring": true, 11 | "dataType": "boolean" 12 | }, 13 | "attributes": [ 14 | { 15 | "type": "Actual", 16 | "mutability": "ReadWrite" 17 | } 18 | ], 19 | "type": "boolean" 20 | }, 21 | "CustomImplementationEnabled": { 22 | "variable_name": "CustomImplementationEnabled", 23 | "characteristics": { 24 | "supportsMonitoring": true, 25 | "dataType": "boolean" 26 | }, 27 | "attributes": [ 28 | { 29 | "type": "Actual", 30 | "mutability": "ReadWrite" 31 | } 32 | ], 33 | "description": "Custom implementation has been enabled.", 34 | "type": "boolean" 35 | }, 36 | "CustomImplementationCaliforniaPricingEnabled": { 37 | "variable_name": "CustomImplementationEnabled", 38 | "instance": "org.openchargealliance.costmsg", 39 | "characteristics": { 40 | "supportsMonitoring": true, 41 | "dataType": "boolean" 42 | }, 43 | "attributes": [ 44 | { 45 | "type": "Actual", 46 | "mutability": "ReadWrite" 47 | } 48 | ], 49 | "description": "Custom implementation org.openchargealliance.costmsg (California Pricing) has been enabled.", 50 | "type": "boolean" 51 | }, 52 | "CustomImplementationMultiLanguageEnabled": { 53 | "variable_name": "CustomImplementationEnabled", 54 | "instance": "org.openchargealliance.multilanguage", 55 | "characteristics": { 56 | "supportsMonitoring": true, 57 | "dataType": "boolean" 58 | }, 59 | "attributes": [ 60 | { 61 | "type": "Actual", 62 | "mutability": "ReadWrite" 63 | } 64 | ], 65 | "description": "Custom implementation org.openchargealliance.multilanguage has been enabled.", 66 | "type": "boolean" 67 | } 68 | }, 69 | "required": [] 70 | } 71 | -------------------------------------------------------------------------------- /config/v2/component_config/standardized/ReservationCtrlr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for ReservationCtrlr", 4 | "name": "ReservationCtrlr", 5 | "type": "object", 6 | "properties": { 7 | "ReservationCtrlrAvailable": { 8 | "variable_name": "Available", 9 | "characteristics": { 10 | "supportsMonitoring": true, 11 | "dataType": "boolean" 12 | }, 13 | "attributes": [ 14 | { 15 | "type": "Actual", 16 | "mutability": "ReadOnly" 17 | } 18 | ], 19 | "description": "Whether reservation is supported.", 20 | "default": true, 21 | "type": "boolean" 22 | }, 23 | "ReservationCtrlrEnabled": { 24 | "variable_name": "Enabled", 25 | "characteristics": { 26 | "supportsMonitoring": true, 27 | "dataType": "boolean" 28 | }, 29 | "attributes": [ 30 | { 31 | "type": "Actual", 32 | "mutability": "ReadWrite" 33 | } 34 | ], 35 | "description": "Whether reservation is enabled.", 36 | "default": true, 37 | "type": "boolean" 38 | }, 39 | "ReservationCtrlrNonEvseSpecific": { 40 | "variable_name": "NonEvseSpecific", 41 | "characteristics": { 42 | "supportsMonitoring": true, 43 | "dataType": "boolean" 44 | }, 45 | "attributes": [ 46 | { 47 | "type": "Actual", 48 | "mutability": "ReadOnly", 49 | "value": true 50 | } 51 | ], 52 | "description": "If this configuration variable is present and set to true: Charging Station supports Reservation where EVSE id is not specified.", 53 | "type": "boolean" 54 | } 55 | }, 56 | "required": [] 57 | } 58 | -------------------------------------------------------------------------------- /config/v2/core_migrations/2_down-auth_cache_management.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE AUTH_CACHE DROP COLUMN LAST_USED; 2 | ALTER TABLE AUTH_CACHE DROP COLUMN EXPIRY_DATE; -------------------------------------------------------------------------------- /config/v2/core_migrations/2_up-auth_cache_management.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE AUTH_CACHE ADD COLUMN LAST_USED INT64 NOT NULL DEFAULT 0; 2 | ALTER TABLE AUTH_CACHE ADD COLUMN EXPIRY_DATE INT64; -------------------------------------------------------------------------------- /config/v2/core_migrations/3_down-persist-normal-messages.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE NORMAL_QUEUE; 2 | -------------------------------------------------------------------------------- /config/v2/core_migrations/3_up-persist-normal-messages.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE NORMAL_QUEUE( 2 | UNIQUE_ID TEXT PRIMARY KEY NOT NULL, 3 | MESSAGE TEXT NOT NULL, 4 | MESSAGE_TYPE TEXT NOT NULL, 5 | MESSAGE_ATTEMPTS INT NOT NULL, 6 | MESSAGE_TIMESTAMP TEXT NOT NULL 7 | ); 8 | -------------------------------------------------------------------------------- /config/v2/core_migrations/4_down-transactions_db.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE TRANSACTIONS; -------------------------------------------------------------------------------- /config/v2/core_migrations/4_up-transactions_db.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE TRANSACTIONS ( 2 | TRANSACTION_ID TEXT NOT NULL UNIQUE, 3 | EVSE_ID INT NOT NULL UNIQUE, 4 | CONNECTOR_ID INT NOT NULL, 5 | TIME_START INT64 NOT NULL, 6 | SEQ_NO INT NOT NULL, 7 | CHARGING_STATE TEXT NOT NULL, 8 | ID_TAG_SENT INT NOT NULL 9 | ); 10 | -------------------------------------------------------------------------------- /config/v2/core_migrations/5_down-charging_profiles_db.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE CHARGING_PROFILES; 2 | -------------------------------------------------------------------------------- /config/v2/core_migrations/5_up-charging_profiles_db.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE CHARGING_PROFILES ( 2 | ID INT PRIMARY KEY NOT NULL, 3 | EVSE_ID INT NOT NULL, 4 | STACK_LEVEL INT NOT NULL, 5 | CHARGING_PROFILE_PURPOSE TEXT NOT NULL, 6 | PROFILE TEXT NOT NULL 7 | ); 8 | -------------------------------------------------------------------------------- /config/v2/core_migrations/6_down-charging_profiles_source_tx_id.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE CHARGING_PROFILES DROP COLUMN CHARGING_LIMIT_SOURCE; 2 | ALTER TABLE CHARGING_PROFILES DROP COLUMN TRANSACTION_ID; -------------------------------------------------------------------------------- /config/v2/core_migrations/6_up-charging_profiles_source_tx_id.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE CHARGING_PROFILES ADD COLUMN CHARGING_LIMIT_SOURCE TEXT NOT NULL DEFAULT 'CSO'; 2 | ALTER TABLE CHARGING_PROFILES ADD COLUMN TRANSACTION_ID TEXT; -------------------------------------------------------------------------------- /config/v2/device_model_migrations/2_down-variable_source.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE VARIABLE 2 | DROP COLUMN SOURCE; 3 | -------------------------------------------------------------------------------- /config/v2/device_model_migrations/2_up-variable_source.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE VARIABLE 2 | ADD COLUMN SOURCE TEXT; 3 | -------------------------------------------------------------------------------- /config/v2/device_model_migrations/3_down-variable_required.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE VARIABLE 2 | ADD REQUIRED INTEGER DEFAULT FALSE; 3 | -------------------------------------------------------------------------------- /config/v2/device_model_migrations/3_up-variable_required.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE VARIABLE 2 | DROP COLUMN REQUIRED; 3 | -------------------------------------------------------------------------------- /dependencies.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | nlohmann_json: 3 | git: https://github.com/nlohmann/json 4 | git_tag: v3.11.2 5 | options: ["JSON_BuildTests OFF", "JSON_MultipleHeaders ON"] 6 | nlohmann_json_schema_validator: 7 | git: https://github.com/pboettch/json-schema-validator 8 | git_tag: 2.3.0 9 | options: 10 | [ 11 | "JSON_VALIDATOR_INSTALL OFF", 12 | "JSON_VALIDATOR_BUILD_TESTS OFF", 13 | "JSON_VALIDATOR_BUILD_EXAMPLES OFF", 14 | "JSON_VALIDATOR_BUILD_SHARED_LIBS ON", 15 | ] 16 | liblog: 17 | git: https://github.com/EVerest/liblog.git 18 | git_tag: v0.2.2 19 | options: ["BUILD_EXAMPLES OFF"] 20 | libtimer: 21 | git: https://github.com/EVerest/libtimer.git 22 | git_tag: v0.1.2 23 | options: ["BUILD_EXAMPLES OFF"] 24 | date: 25 | git: https://github.com/HowardHinnant/date.git 26 | git_tag: v3.0.1 27 | options: ["BUILD_TZ_LIB ON", "HAS_REMOTE_API 0", "USE_AUTOLOAD 0", "USE_SYSTEM_TZ_DB ON"] 28 | libevse-security: 29 | git: https://github.com/EVerest/libevse-security.git 30 | git_tag: 3b1231392c9f93e1a1375e4691cb20b83cc63a9b 31 | libwebsockets: 32 | git: https://github.com/warmcat/libwebsockets.git 33 | git_tag: v4.3.3 34 | options: 35 | - CMAKE_POLICY_DEFAULT_CMP0077 NEW 36 | - LWS_ROLE_RAW_FILE OFF 37 | - LWS_UNIX_SOCK OFF 38 | - LWS_WITH_SYS_STATE OFF 39 | - LWS_WITH_SYS_SMD OFF 40 | - LWS_WITH_UPNG OFF 41 | - LWS_WITH_JPEG OFF 42 | - LWS_WITH_DLO OFF 43 | - LWS_WITH_SECURE_STREAMS OFF 44 | - LWS_WITH_STATIC OFF 45 | - LWS_WITH_LHP OFF 46 | - LWS_WITH_LEJP_CONF OFF 47 | - LWS_WITH_MINIMAL_EXAMPLES OFF 48 | - LWS_WITH_CACHE_NSCOOKIEJAR OFF 49 | - LWS_WITHOUT_TESTAPPS ON 50 | - LWS_WITHOUT_TEST_SERVER ON 51 | - LWS_WITHOUT_TEST_SERVER_EXTPOLL ON 52 | - LWS_WITHOUT_TEST_PING ON 53 | - LWS_WITHOUT_TEST_CLIENT ON 54 | - LWS_INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} 55 | gtest: 56 | # GoogleTest now follows the Abseil Live at Head philosophy. We recommend updating to the latest commit in the main branch as often as possible. 57 | git: https://github.com/google/googletest.git 58 | git_tag: release-1.12.1 59 | cmake_condition: "LIBOCPP_BUILD_TESTING" 60 | everest-sqlite: 61 | git: https://github.com/EVerest/everest-sqlite.git 62 | git_tag: v0.1.1 63 | -------------------------------------------------------------------------------- /doc/common/build-with-fetchcontent/README.md: -------------------------------------------------------------------------------- 1 | # Building with FetchContent instead of EDM 2 | 3 | In this directory you can find a [CMakeLists.txt](CMakeLists.txt) that serves as an example how to build libocpp with FetchContent instead of EDM. 4 | -------------------------------------------------------------------------------- /doc/common/database_exception_handling.md: -------------------------------------------------------------------------------- 1 | # Exception Handling of Database Operations 2 | 3 | OCPP versions 1.6 and 2.0.1 contain several requirements for the persistent storage and retrieval of data. This library leverages SQLite to fulfill these persistent storage requirements. The DatabaseHandler classes manage all related database operations, including CREATE, SELECT, INSERT, UPDATE, and DELETE commands. 4 | 5 | ## Exception Design Considerations 6 | 7 | The primary design decision in the development of DatabaseHandler classes is to allow exceptions to propagate to higher level logic rather than catching them internally. By propagating exceptions of database operations, it is ensured the consumer application is fully aware of any issues that occur during database operations. This transparency allows higher-level logic to make informed decisions based on the specific errors encountered. Different higher level logic may require different strategies for error handling based on their specific requirements. Propagating exceptions gives developers the flexibility to implement custom handling procedures that best fit the application’s needs. 8 | 9 | SQLite does not natively support exceptions as it is written in C. The DatabaseHandler classes check the return codes of SQLite function calls, and if an operation fails (i.e., the return code is not SQLITE_OK, SQLITE_DONE, SQLITE_ROW, etc.), an exception is thrown. This way, all database-related errors are converted into C++ exceptions, which are then propagated up to the caller. 10 | 11 | ## Implementation Strategy 12 | 13 | The public functions of the DatabaseHandler classes are designed to throw exceptions when SQL operations fail to execute as expected Error Handling. Consumer code should implement try-catch blocks around calls to DatabaseHandler functions. This handling should be tailored to the requirements of the OCPP specification and improve the stability of the application, whether it involves the logging errors, retrying operations or other logic. 14 | -------------------------------------------------------------------------------- /doc/common/database_migrations.md: -------------------------------------------------------------------------------- 1 | # Database migrations 2 | 3 | The migrations support has been moved to [everest-sqlite](https://github.com/EVerest/everest-sqlite). Please see its [documentation for the migration support](https://github.com/EVerest/everest-sqlite/blob/main/docs/migrations.md). 4 | -------------------------------------------------------------------------------- /doc/common/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Requirements 4 | 5 | For Debian GNU/Linux 11 you will need the following dependencies: 6 | 7 | ```bash 8 | sudo apt install build-essential cmake python3-pip libboost-all-dev libsqlite3-dev libssl-dev 9 | ``` 10 | 11 | OpenSSL version 3.0 or above is required. 12 | 13 | Clone this repository. 14 | 15 | ```bash 16 | git clone https://github.com/EVerest/libocpp 17 | ``` 18 | 19 | In the libocpp folder create a folder named build and cd into it. 20 | Execute cmake and then make: 21 | 22 | ```bash 23 | mkdir build && cd build 24 | cmake .. 25 | make -j$(nproc) 26 | ``` 27 | 28 | ## Unit testing 29 | 30 | GTest is required for building the test cases target. 31 | To build the target and run the tests you can reference the script `.ci/build-kit/install_and_test.sh`. 32 | The script allows the GitHub Actions runner to execute. 33 | 34 | Local testing: 35 | 36 | ```bash 37 | mkdir build 38 | cmake -B build -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="./dist" 39 | cd build 40 | make -j$(nproc) install 41 | ``` 42 | 43 | Run any required tests from build/tests. 44 | 45 | ## Clarifications for directory structures, namespaces and OCPP versions 46 | 47 | This repository contains multiple subdirectories and namespaces named v16, v2 and v21. 48 | 49 | * The v16 directories contain files for configuring and implementing OCPP 1.6. 50 | * The v2 directories include files for both OCPP2.0.1 and OCPP2.1, as OCPP 2.1 51 | is fully backward compatible with OCPP 2.0.1. 52 | * The v21 directories include files only for OCPP2.1. 53 | 54 | ## Get Started with OCPP1.6 55 | 56 | Please see the [Getting Started documentation for OCPP1.6](../v16/getting_started.md). 57 | 58 | ## Get Started with OCPP2.0.1 59 | 60 | Please see the [Getting Started documentation for OCPP2.0.1](../v2/getting_started.md). 61 | 62 | ## Building the doxygen documentation 63 | 64 | ```bash 65 | cmake -S . -B build 66 | cmake --build build --target doxygen-ocpp 67 | ``` 68 | 69 | You will find the generated doxygen documentation at: 70 | `build/dist/docs/html/index.html` 71 | 72 | The main reference for the integration of libocpp for OCPP1.6 is the ocpp::v16::ChargePoint class defined in `v16/charge_point.hpp` , for OCPP2.0.1 and OCPP2.1 that is the ocpp::v2::ChargePoint class defined in `v2/charge_point.hpp` . 73 | -------------------------------------------------------------------------------- /doc/message_dispatching.md: -------------------------------------------------------------------------------- 1 | # Message Dispatching Class Diagram 2 | 3 | ```mermaid 4 | classDiagram 5 | class MessageDispatcherInterface { 6 | +dispatch_call(const json& call, bool triggered = false) 7 | +dispatch_call_async(const json& call, bool triggered = false): std::future~EnhancedMessage~T~~ 8 | +dispatch_call_result(const json& call_result) 9 | +dispatch_call_error(const json& call_error) 10 | } 11 | 12 | class v16_MessageDispatcher { 13 | - MessageQueue& message_queue 14 | - ChargePointConfiguration& configuration 15 | - RegistrationStatus& registration_status 16 | } 17 | 18 | class v2_MessageDispatcher { 19 | - MessageQueue& message_queue 20 | - DeviceModel& device_model 21 | - ConnectivityManager& connectivity_manager 22 | - RegistrationStatusEnum& registration_status 23 | } 24 | 25 | class v2_MessageHandlerInterface { 26 | +handle_message(EnhancedMessage~v2_MessageType~ message) 27 | } 28 | 29 | class v16_MessageHandlerInterface { 30 | +handle_message(EnhancedMessage~v16_MessageType~ message) 31 | } 32 | 33 | class v2_DataTransferInterface { 34 | +data_transfer_req(request: DataTransferRequest): std::optional~DataTransferResponse~ 35 | +handle_data_transfer_req(call: Call~DataTransferRequest~) 36 | } 37 | 38 | class v2_DataTransfer { 39 | -MessageDispatcherInterface &message_dispatcher 40 | -std::optional~function~ data_transfer_callback 41 | } 42 | 43 | class v2_ChargePoint { 44 | std::unique_ptr~MessageDispatcherInterface~ message_dispatcher 45 | std::unique_ptr~v2_DataTransferInterface~ data_transfer 46 | } 47 | 48 | class v16_ChargePoint { 49 | std::unique_ptr~MessageDispatcherInterface~ message_dispatcher 50 | } 51 | 52 | MessageDispatcherInterface <|-- v16_MessageDispatcher 53 | MessageDispatcherInterface <|-- v2_MessageDispatcher 54 | v2_DataTransferInterface <|-- v2_DataTransfer 55 | v2_MessageHandlerInterface <|-- v2_DataTransferInterface 56 | MessageDispatcherInterface *-- v2_DataTransfer 57 | MessageDispatcherInterface *-- v2_ChargePoint 58 | v2_DataTransferInterface *-- v2_ChargePoint 59 | MessageDispatcherInterface *-- v16_ChargePoint 60 | ``` 61 | -------------------------------------------------------------------------------- /doc/v2/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting Started with OCPP2.0.1 2 | 3 | ## Integrate this library with your Charging Station Implementation for OCPP2.0.1 4 | 5 | OCPP is a protocol that affects, controls and monitors many areas of a charging station's operation. 6 | 7 | If you want to integrate this library with your charging station implementation, you have to register a couple of **callbacks** and integrate **event handlers**. This is necessary for the library to interact with your charging station according to the requirements of OCPP. 8 | 9 | Libocpp needs registered **callbacks** in order to execute control commands defined within OCPP (e.g ResetRequest or RemoteStartTransactionRequest) 10 | 11 | The implementation must call **event handlers** of libocpp so that the library can track the state of the charging station and trigger OCPP messages accordingly (e.g. MeterValuesRequest , StatusNotificationRequest) 12 | 13 | Your reference within libocpp to interact is a single instance to the class ocpp::v2::ChargePoint defined in `v2/charge_point.hpp` for OCPP 2.0.1. 14 | -------------------------------------------------------------------------------- /doc/v2/ocpp_201_monitors_periodic_flowchart.puml: -------------------------------------------------------------------------------- 1 | @startuml Periodic Monitors 2 | 3 | start 4 | :DB Monitor Config Setup; 5 | :DB Monitor Initialization; 6 | if (Monitoring Enabled?) then (yes) 7 | :Query Config\nProcess Time; 8 | :Enable Monitor\nProcessor; 9 | repeat 10 | :Verify Periodic\nMonitors; 11 | if(Periodic Monitor\nTime Elapsed?) then (yes) 12 | if(Online?) then (yes) 13 | if(Active Monitoring Severity\n> Monitor Severity?) then (yes) 14 | :Queue \nPeriodic Monitor; 15 | else (no) 16 | :Discard Monitor; 17 | endif 18 | else (no) 19 | if(Offline Monitoring Severity\n> Monitor Severity?) then (yes) 20 | :Queue \nPeriodic Monitor; 21 | else (no) 22 | :Discard Monitor; 23 | endif 24 | endif 25 | else(no) 26 | :Update Monitor\nElapsed Time; 27 | endif 28 | :Verify Triggered\nMonitors\n(see trigger flowchart); 29 | :Queue Triggered\nMonitors; 30 | :Send Queued\nMonitors to CSMS; 31 | repeat while (Each N Seconds) 32 | else (no) 33 | :Do Nothing; 34 | endif 35 | stop 36 | 37 | @enduml -------------------------------------------------------------------------------- /doc/v2/ocpp_201_monitors_trigger_flowchart.puml: -------------------------------------------------------------------------------- 1 | @startuml Periodic Monitors 2 | 3 | start 4 | :DB Monitor Config Setup; 5 | :DB Monitor Initialization; 6 | if (Monitoring Enabled?) then (yes) 7 | :Inject Device\nModel Listener; 8 | :Enable Monitor\nProcessor; 9 | repeat 10 | :Verify Variable\nMonitors; 11 | if(Variable Monitor\nTriggered?) then (yes) 12 | if(Online?) then (yes) 13 | if(Active Monitoring Severity\n> Monitor Severity?) then (yes) 14 | :Queue Monitor; 15 | else (no) 16 | :Discard Monitor; 17 | endif 18 | else (no) 19 | if(Offline Monitoring Severity\n> Monitor Severity?) then (yes) 20 | :Queue Monitor; 21 | else (no) 22 | :Discard Monitor; 23 | endif 24 | endif 25 | else(no) 26 | :Do Nothing; 27 | endif 28 | :Process Queued\nMonitors; 29 | repeat while (DB Variable Updated) 30 | else (no) 31 | :Do Nothing; 32 | endif 33 | stop 34 | 35 | @enduml -------------------------------------------------------------------------------- /doc/v2/resumeInterruptedTransactions/resumeInterruptedTransactions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EVerest/libocpp/7c9d31e94a1d3e86ee76a8d034997c7a02743223/doc/v2/resumeInterruptedTransactions/resumeInterruptedTransactions.png -------------------------------------------------------------------------------- /include/ocpp/common/charging_station_base.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | #ifndef OCPP_COMMON_CHARGE_POINT_HPP 4 | #define OCPP_COMMON_CHARGE_POINT_HPP 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace ocpp { 14 | 15 | /// \brief Common base class for OCPP1.6 and OCPP2.0.1 charging stations 16 | class ChargingStationBase { 17 | 18 | protected: 19 | std::shared_ptr evse_security; 20 | std::shared_ptr logging; 21 | 22 | boost::shared_ptr> work; 23 | boost::asio::io_context io_context; 24 | std::thread io_context_thread; 25 | 26 | public: 27 | /// \brief Constructor for ChargingStationBase 28 | /// \param evse_security Pointer to evse_security that manages security related operations; if nullptr 29 | /// security_configuration must be set 30 | /// \param security_configuration specifies the file paths that are required to set up the internal evse_security 31 | /// implementation 32 | explicit ChargingStationBase(const std::shared_ptr evse_security, 33 | const std::optional security_configuration = std::nullopt); 34 | virtual ~ChargingStationBase(); 35 | }; 36 | 37 | } // namespace ocpp 38 | 39 | #endif // OCPP_COMMON 40 | -------------------------------------------------------------------------------- /include/ocpp/common/constants.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ocpp { 11 | 12 | // Time 13 | constexpr std::int32_t DAYS_PER_WEEK = 7; 14 | constexpr std::int32_t HOURS_PER_DAY = 24; 15 | constexpr std::int32_t SECONDS_PER_HOUR = 3600; 16 | constexpr std::int32_t SECONDS_PER_DAY = 86400; 17 | 18 | constexpr float DEFAULT_LIMIT_AMPS = 48.0; 19 | constexpr float DEFAULT_LIMIT_WATTS = 33120.0; 20 | constexpr std::int32_t DEFAULT_AND_MAX_NUMBER_PHASES = 3; 21 | constexpr float LOW_VOLTAGE = 230; 22 | 23 | constexpr float NO_LIMIT_SPECIFIED = -1.0; 24 | constexpr std::int32_t NO_START_PERIOD = -1; 25 | constexpr std::int32_t EVSEID_NOT_SET = -1; 26 | 27 | constexpr std::chrono::seconds DEFAULT_WAIT_FOR_FUTURE_TIMEOUT = std::chrono::seconds(60); 28 | 29 | const std::string VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL = "internal"; 30 | const std::string VARIABLE_ATTRIBUTE_VALUE_SOURCE_CSMS = "csms"; 31 | 32 | } // namespace ocpp 33 | -------------------------------------------------------------------------------- /include/ocpp/common/message_dispatcher.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace ocpp { 9 | 10 | /// \brief Interface for dispatching OCPP messages that shall be send over the websocket. This interface defines 11 | /// dispatching of Call, CallResult and CallError messages. 12 | /// \tparam T Type specifies the OCPP protocol version 13 | template class MessageDispatcherInterface { 14 | 15 | public: 16 | virtual ~MessageDispatcherInterface(){}; 17 | 18 | /// \brief Dispatches a Call message. 19 | /// \param call the OCPP Call message. 20 | /// \param triggered indicates if the call was triggered by a TriggerMessage. Default is false. 21 | virtual void dispatch_call(const json& call, bool triggered = false) = 0; 22 | 23 | /// \brief Dispatches a Call message asynchronously. 24 | /// \param call the OCPP Call message. 25 | /// \param triggered indicates if the call was triggered by a TriggerMessage. Default is false. 26 | /// \return std::future> Future object containing the enhanced message 27 | /// result of type T. 28 | virtual std::future> dispatch_call_async(const json& call, bool triggered = false) = 0; 29 | 30 | /// \brief Dispatches a CallResult message. 31 | /// \param call_result the OCPP CallResult message. 32 | virtual void dispatch_call_result(const json& call_result) = 0; 33 | 34 | /// \brief Dispatches a CallError message. 35 | /// \param call_result the OCPP CallError message. 36 | virtual void dispatch_call_error(const json& call_error) = 0; 37 | }; 38 | 39 | } // namespace ocpp 40 | -------------------------------------------------------------------------------- /include/ocpp/common/schemas.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | #ifndef OCPP_COMMON_SCHEMAS_HPP 4 | #define OCPP_COMMON_SCHEMAS_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using json = nlohmann::json; 17 | using json_uri = nlohmann::json_uri; 18 | using json_validator = nlohmann::json_schema::json_validator; 19 | 20 | namespace ocpp { 21 | 22 | /// \brief Contains the json schema validation for the libocpp config 23 | class Schemas { 24 | private: 25 | json schema; 26 | std::shared_ptr validator; 27 | fs::path schemas_path; 28 | std::set available_schemas_paths; 29 | const static std::vector profiles; 30 | const static std::regex date_time_regex; 31 | 32 | /// \brief Loads the root schema "Config.json" from the schemas path 33 | void load_root_schema(); 34 | 35 | /// \brief A custom json schema loader that loads \p schema files relative to the provided \p uri 36 | void loader(const json_uri& uri, json& schema); 37 | 38 | public: 39 | /// \brief Creates a new Schemas object looking for the root schema file in relation to the provided \p main_dir 40 | explicit Schemas(fs::path schemas_path); 41 | /// \brief Creates a new Schemas object using the supplied JSON schema 42 | explicit Schemas(const json& schema_in); 43 | /// \brief Creates a new Schemas object using the supplied JSON schema 44 | explicit Schemas(json&& schema_in); 45 | 46 | /// \brief Provides the config schema 47 | /// \returns the config schema as as json object 48 | json get_schema(); 49 | 50 | /// \brief Provides the config schema validator 51 | /// \returns a json_validator for the config 52 | std::shared_ptr get_validator(); 53 | 54 | /// \brief Provides a format checker for the given \p format and \p value 55 | static void format_checker(const std::string& format, const std::string& value); 56 | }; 57 | } // namespace ocpp 58 | 59 | #endif // OCPP_COMMON_SCHEMAS_HPP 60 | -------------------------------------------------------------------------------- /include/ocpp/common/support_older_cpp_versions.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #ifndef OCPP_COMMON_SUPPORT_OLDER_CPP_VERSIONS_HPP_ 5 | #define OCPP_COMMON_SUPPORT_OLDER_CPP_VERSIONS_HPP_ 6 | 7 | #ifndef LIBOCPP_USE_BOOST_FILESYSTEM 8 | #include 9 | #else 10 | #include 11 | #endif 12 | 13 | #ifndef LIBOCPP_USE_BOOST_FILESYSTEM 14 | namespace fs = std::filesystem; 15 | namespace fsstd = std; 16 | #else 17 | namespace fs = boost::filesystem; 18 | namespace fsstd = boost::filesystem; 19 | #endif 20 | 21 | #endif /* OCPP_COMMON_SUPPORT_OLDER_CPP_VERSIONS_HPP_ */ 22 | -------------------------------------------------------------------------------- /include/ocpp/common/utils.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | #ifndef OCPP_COMMON_UTILS_HPP 4 | #define OCPP_COMMON_UTILS_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ocpp { 11 | 12 | /// \brief Case insensitive compare for a case insensitive (Ci)String 13 | bool iequals(const std::string& lhs, const std::string rhs); 14 | 15 | bool is_integer(const std::string& value); 16 | std::tuple is_positive_integer(const std::string& value); 17 | bool is_decimal_number(const std::string& value); 18 | 19 | bool is_rfc3339_datetime(const std::string& value); 20 | bool is_boolean(const std::string& value); 21 | 22 | /// 23 | /// \brief Split string on a given character. 24 | /// \param string_to_split The string to split. 25 | /// \param c The character to split the string on. 26 | /// \param trim True if all strings must be trimmed as well. Defaults to 'false'. 27 | /// \return A vector with the string 'segments'. 28 | /// 29 | std::vector split_string(const std::string& string_to_split, const char c, const bool trim = false); 30 | 31 | /// 32 | /// \brief Trim string, removing leading and trailing white spaces. 33 | /// \param string_to_trim The string to trim. 34 | /// \return The trimmed string. 35 | /// 36 | std::string trim_string(const std::string& string_to_trim); 37 | 38 | } // namespace ocpp 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/ocpp/v16/connector.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #ifndef OCPP_V16_CONNECTOR_HPP 5 | #define OCPP_V16_CONNECTOR_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace ocpp { 12 | namespace v16 { 13 | 14 | struct Connector { 15 | int32_t id; 16 | std::optional measurement; 17 | double max_current_offered = 0; 18 | double max_power_offered = 0; 19 | std::shared_ptr transaction = nullptr; 20 | std::map stack_level_tx_default_profiles_map; 21 | std::map stack_level_tx_profiles_map; 22 | std::optional> trigger_metervalue_on_status; 23 | std::optional trigger_metervalue_on_power_kw; 24 | std::optional trigger_metervalue_on_energy_kwh; 25 | std::unique_ptr trigger_metervalue_at_time_timer; 26 | std::optional previous_status; 27 | std::optional last_triggered_metervalue_power_kw; 28 | 29 | explicit Connector(const int id) : id(id) { 30 | } 31 | ~Connector() = default; 32 | Connector& operator=(const Connector&) = delete; 33 | Connector(const Connector&) = delete; 34 | }; 35 | 36 | } // namespace v16 37 | } // namespace ocpp 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/ocpp/v16/message_dispatcher.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace ocpp { 10 | namespace v16 { 11 | 12 | class MessageDispatcher : public MessageDispatcherInterface { 13 | 14 | public: 15 | MessageDispatcher(ocpp::MessageQueue& message_queue, ChargePointConfiguration& configuration, 16 | std::atomic& registration_status) : 17 | message_queue(message_queue), configuration(configuration), registration_status(registration_status){}; 18 | void dispatch_call(const json& call, bool triggered = false) override; 19 | std::future> dispatch_call_async(const json& call, bool triggered) override; 20 | void dispatch_call_result(const json& call_result) override; 21 | void dispatch_call_error(const json& call_error) override; 22 | 23 | private: 24 | ocpp::MessageQueue& message_queue; 25 | ChargePointConfiguration& configuration; 26 | std::atomic& registration_status; 27 | }; 28 | 29 | } // namespace v16 30 | } // namespace ocpp 31 | -------------------------------------------------------------------------------- /include/ocpp/v16/messages/Heartbeat.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #ifndef OCPP_V16_HEARTBEAT_HPP 6 | #define OCPP_V16_HEARTBEAT_HPP 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace ocpp { 13 | namespace v16 { 14 | 15 | /// \brief Contains a OCPP Heartbeat message 16 | struct HeartbeatRequest : public ocpp::Message { 17 | 18 | /// \brief Provides the type of this Heartbeat message as a human readable string 19 | /// \returns the message type as a human readable string 20 | std::string get_type() const override; 21 | }; 22 | 23 | /// \brief Conversion from a given HeartbeatRequest \p k to a given json object \p j 24 | void to_json(json& j, const HeartbeatRequest& k); 25 | 26 | /// \brief Conversion from a given json object \p j to a given HeartbeatRequest \p k 27 | void from_json(const json& j, HeartbeatRequest& k); 28 | 29 | /// \brief Writes the string representation of the given HeartbeatRequest \p k to the given output stream \p os 30 | /// \returns an output stream with the HeartbeatRequest written to 31 | std::ostream& operator<<(std::ostream& os, const HeartbeatRequest& k); 32 | 33 | /// \brief Contains a OCPP HeartbeatResponse message 34 | struct HeartbeatResponse : public ocpp::Message { 35 | ocpp::DateTime currentTime; 36 | 37 | /// \brief Provides the type of this HeartbeatResponse message as a human readable string 38 | /// \returns the message type as a human readable string 39 | std::string get_type() const override; 40 | }; 41 | 42 | /// \brief Conversion from a given HeartbeatResponse \p k to a given json object \p j 43 | void to_json(json& j, const HeartbeatResponse& k); 44 | 45 | /// \brief Conversion from a given json object \p j to a given HeartbeatResponse \p k 46 | void from_json(const json& j, HeartbeatResponse& k); 47 | 48 | /// \brief Writes the string representation of the given HeartbeatResponse \p k to the given output stream \p os 49 | /// \returns an output stream with the HeartbeatResponse written to 50 | std::ostream& operator<<(std::ostream& os, const HeartbeatResponse& k); 51 | 52 | } // namespace v16 53 | } // namespace ocpp 54 | 55 | #endif // OCPP_V16_HEARTBEAT_HPP 56 | -------------------------------------------------------------------------------- /include/ocpp/v16/messages/Reset.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #ifndef OCPP_V16_RESET_HPP 6 | #define OCPP_V16_RESET_HPP 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace ocpp { 14 | namespace v16 { 15 | 16 | /// \brief Contains a OCPP Reset message 17 | struct ResetRequest : public ocpp::Message { 18 | ResetType type; 19 | 20 | /// \brief Provides the type of this Reset message as a human readable string 21 | /// \returns the message type as a human readable string 22 | std::string get_type() const override; 23 | }; 24 | 25 | /// \brief Conversion from a given ResetRequest \p k to a given json object \p j 26 | void to_json(json& j, const ResetRequest& k); 27 | 28 | /// \brief Conversion from a given json object \p j to a given ResetRequest \p k 29 | void from_json(const json& j, ResetRequest& k); 30 | 31 | /// \brief Writes the string representation of the given ResetRequest \p k to the given output stream \p os 32 | /// \returns an output stream with the ResetRequest written to 33 | std::ostream& operator<<(std::ostream& os, const ResetRequest& k); 34 | 35 | /// \brief Contains a OCPP ResetResponse message 36 | struct ResetResponse : public ocpp::Message { 37 | ResetStatus status; 38 | 39 | /// \brief Provides the type of this ResetResponse message as a human readable string 40 | /// \returns the message type as a human readable string 41 | std::string get_type() const override; 42 | }; 43 | 44 | /// \brief Conversion from a given ResetResponse \p k to a given json object \p j 45 | void to_json(json& j, const ResetResponse& k); 46 | 47 | /// \brief Conversion from a given json object \p j to a given ResetResponse \p k 48 | void from_json(const json& j, ResetResponse& k); 49 | 50 | /// \brief Writes the string representation of the given ResetResponse \p k to the given output stream \p os 51 | /// \returns an output stream with the ResetResponse written to 52 | std::ostream& operator<<(std::ostream& os, const ResetResponse& k); 53 | 54 | } // namespace v16 55 | } // namespace ocpp 56 | 57 | #endif // OCPP_V16_RESET_HPP 58 | -------------------------------------------------------------------------------- /include/ocpp/v16/utils.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | #ifndef V16_UTILS_HPP 4 | #define V16_UTILS_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace ocpp { 12 | namespace v16 { 13 | namespace utils { 14 | 15 | size_t get_message_size(const ocpp::Call& call); 16 | 17 | /// \brief Drops every second entry from transactionData as long as the message size of the \p call is greater than the 18 | /// \p max_message_size 19 | void drop_transaction_data(size_t max_message_size, ocpp::Call& call); 20 | 21 | /// \brief Determines if a given \p security_event is critical as defined in the OCPP 1.6 security whitepaper 22 | bool is_critical(const std::string& security_event); 23 | 24 | } // namespace utils 25 | } // namespace v16 26 | } // namespace ocpp 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/ocpp/v2/average_meter_values.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | namespace ocpp { 15 | namespace v2 { 16 | class AverageMeterValues { 17 | 18 | public: 19 | AverageMeterValues(); 20 | /// @brief Set the meter values into the local object for processing 21 | /// @param meter_value MeterValue 22 | void set_values(const MeterValue& meter_value); 23 | /// @brief retrive the processed values 24 | /// @return MeterValue type 25 | MeterValue retrieve_processed_values(); 26 | /// @brief Manually clear the local object meter values 27 | void clear_values(); 28 | 29 | private: 30 | struct MeterValueCalc { 31 | double sum; 32 | int num_elements; 33 | }; 34 | struct MeterValueMeasurands { 35 | MeasurandEnum measurand; 36 | std::optional phase; // measurand may or may not have a phase field 37 | std::optional location; // measurand may or may not have location field 38 | 39 | // Define a comparison operator for the struct 40 | bool operator<(const MeterValueMeasurands& other) const { 41 | // Using tie here to compare the two lexicographically instead of writing it all out 42 | return std::tie(measurand, location, phase) < std::tie(other.measurand, other.location, other.phase); 43 | } 44 | }; 45 | 46 | MeterValue averaged_meter_values; 47 | std::mutex avg_meter_value_mutex; 48 | std::map aligned_meter_values; 49 | bool is_avg_meas(const SampledValue& sample); 50 | void average_meter_value(); 51 | }; 52 | } // namespace v2 53 | 54 | } // namespace ocpp -------------------------------------------------------------------------------- /include/ocpp/v2/constants.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace ocpp { 9 | namespace v2 { 10 | 11 | /// \brief OCPP 2.0.1 defines this as 5600 but it can be set to a higher value, which we do here, if it's reported via 12 | /// the device model, which we do as well 13 | /// 17000 is the minimum value from OCPP 2.1 14 | constexpr std::size_t ISO15118_GET_EV_CERTIFICATE_EXI_RESPONSE_SIZE = 17000; 15 | 16 | } // namespace v2 17 | } // namespace ocpp 18 | -------------------------------------------------------------------------------- /include/ocpp/v2/enums.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // Manually added enums for OCPP, for the auto-generated ones see 'ocpp_enums.hpp' 4 | 5 | #ifndef OCPP_V2_ENUMS_HPP 6 | #define OCPP_V2_ENUMS_HPP 7 | 8 | #include 9 | 10 | namespace ocpp { 11 | namespace v2 { 12 | 13 | enum class VariableMonitorType { 14 | HardWiredMonitor, 15 | PreconfiguredMonitor, 16 | CustomMonitor, 17 | }; 18 | 19 | namespace conversions { 20 | /// \brief Converts the given std::string \p s to VariableMonitorType 21 | /// \returns a VariableMonitorType from a string representation 22 | VariableMonitorType string_to_variable_monitor_type(const std::string& s); 23 | } // namespace conversions 24 | 25 | namespace MonitoringLevelSeverity { 26 | constexpr int32_t Danger = 0; 27 | constexpr int32_t HardwareFailure = 1; 28 | constexpr int32_t SystemFailure = 2; 29 | constexpr int32_t Critical = 3; 30 | constexpr int32_t Error = 4; 31 | constexpr int32_t Alert = 5; 32 | constexpr int32_t Warning = 6; 33 | constexpr int32_t Notice = 7; 34 | constexpr int32_t Informational = 8; 35 | constexpr int32_t Debug = 9; 36 | 37 | constexpr int32_t MIN = Danger; 38 | constexpr int32_t MAX = Debug; 39 | } // namespace MonitoringLevelSeverity 40 | 41 | } // namespace v2 42 | } // namespace ocpp 43 | 44 | #endif // OCPP_V2_ENUMS_HPP 45 | -------------------------------------------------------------------------------- /include/ocpp/v2/functional_blocks/functional_block_context.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace ocpp { 10 | class EvseSecurity; 11 | 12 | namespace v2 { 13 | class DeviceModel; 14 | class ConnectivityManagerInterface; 15 | class EvseManagerInterface; 16 | class DatabaseHandlerInterface; 17 | class ComponentStateManagerInterface; 18 | 19 | /// \brief Context / requirements for the functional blocks. 20 | /// 21 | /// All functional blocks will get this context. The references and pointers in this struct are used by all or most 22 | /// functional blocks. 23 | struct FunctionalBlockContext { 24 | MessageDispatcherInterface& message_dispatcher; 25 | DeviceModel& device_model; 26 | ConnectivityManagerInterface& connectivity_manager; 27 | EvseManagerInterface& evse_manager; 28 | DatabaseHandlerInterface& database_handler; 29 | EvseSecurity& evse_security; 30 | ComponentStateManagerInterface& component_state_manager; 31 | 32 | FunctionalBlockContext(MessageDispatcherInterface& message_dispatcher, DeviceModel& device_model, 33 | ConnectivityManagerInterface& connectivity_manager, EvseManagerInterface& evse_manager, 34 | DatabaseHandlerInterface& database_handler, EvseSecurity& evse_security, 35 | ComponentStateManagerInterface& component_state_manager) : 36 | message_dispatcher(message_dispatcher), 37 | device_model(device_model), 38 | connectivity_manager(connectivity_manager), 39 | evse_manager(evse_manager), 40 | database_handler(database_handler), 41 | evse_security(evse_security), 42 | component_state_manager(component_state_manager) { 43 | } 44 | }; 45 | } // namespace v2 46 | } // namespace ocpp 47 | -------------------------------------------------------------------------------- /include/ocpp/v2/message_dispatcher.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ocpp { 11 | namespace v2 { 12 | 13 | class MessageDispatcher : public MessageDispatcherInterface { 14 | 15 | public: 16 | MessageDispatcher(ocpp::MessageQueue& message_queue, DeviceModel& device_model, 17 | std::atomic& registration_status) : 18 | message_queue(message_queue), device_model(device_model), registration_status(registration_status){}; 19 | void dispatch_call(const json& call, bool triggered = false) override; 20 | std::future> dispatch_call_async(const json& call, bool triggered) override; 21 | void dispatch_call_result(const json& call_result) override; 22 | void dispatch_call_error(const json& call_error) override; 23 | 24 | private: 25 | ocpp::MessageQueue& message_queue; 26 | DeviceModel& device_model; 27 | std::atomic& registration_status; 28 | }; 29 | 30 | } // namespace v2 31 | } // namespace ocpp 32 | -------------------------------------------------------------------------------- /include/ocpp/v2/message_handler.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace ocpp { 9 | namespace v2 { 10 | 11 | /// \brief Interface for handling OCPP2.0.1 CALL messages from the CSMS. Classes implementing a functional block shall 12 | /// extend this interface. 13 | class MessageHandlerInterface { 14 | 15 | public: 16 | virtual ~MessageHandlerInterface() { 17 | } 18 | /// \brief Handles the given \p message from the CSMS. This includes dispatching a CALLRESULT as a response to the 19 | /// incoming \p message . 20 | /// @param message 21 | virtual void handle_message(const EnhancedMessage& message) = 0; 22 | }; 23 | 24 | class MessageTypeNotImplementedException : public std::exception { 25 | private: 26 | std::string message; 27 | 28 | public: 29 | MessageTypeNotImplementedException(MessageType message_type) : 30 | message("Message is not implemented: " + conversions::messagetype_to_string(message_type)) { 31 | } 32 | 33 | const char* what() const noexcept override { 34 | return message.c_str(); 35 | } 36 | }; 37 | 38 | } // namespace v2 39 | } // namespace ocpp -------------------------------------------------------------------------------- /include/ocpp/v2/transaction.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | #ifndef OCPP_V2_TRANSACTION_HANDLER_HPP 4 | #define OCPP_V2_TRANSACTION_HANDLER_HPP 5 | 6 | #include 7 | #include 8 | 9 | namespace ocpp { 10 | 11 | namespace v2 { 12 | 13 | class DatabaseHandler; 14 | 15 | /// \brief Struct that enhances the OCPP Transaction by some meta data and functionality 16 | struct EnhancedTransaction : public Transaction { 17 | explicit EnhancedTransaction(DatabaseHandler& database_handler, bool database_enabled) : 18 | database_handler{database_handler}, database_enabled{database_enabled} { 19 | } 20 | 21 | bool id_token_sent = false; 22 | int32_t connector_id = 0; 23 | int32_t seq_no = 0; 24 | std::optional active_energy_import_start_value; 25 | DateTime start_time; 26 | bool check_max_active_import_energy = false; 27 | 28 | ClockAlignedTimer sampled_tx_updated_meter_values_timer; 29 | ClockAlignedTimer sampled_tx_ended_meter_values_timer; 30 | ClockAlignedTimer aligned_tx_updated_meter_values_timer; 31 | ClockAlignedTimer aligned_tx_ended_meter_values_timer; 32 | 33 | /// @brief Get the current sequence number of the transaction message. 34 | /// @details This method also increments the sequence number. 35 | /// @return int32_t seq number 36 | int32_t get_seq_no(); 37 | Transaction get_transaction(); 38 | 39 | /// @brief Update the charging state of the transaction. 40 | /// @details Also update the charging state in the database 41 | /// @param charging_state 42 | void update_charging_state(const ChargingStateEnum charging_state); 43 | 44 | void set_id_token_sent(); 45 | 46 | private: 47 | DatabaseHandler& database_handler; 48 | bool database_enabled; 49 | }; 50 | } // namespace v2 51 | 52 | } // namespace ocpp 53 | 54 | #endif // OCPP_V2_TRANSACTION_HANDLER_HPP 55 | -------------------------------------------------------------------------------- /include/ocpp/v21/messages/NotifyPeriodicEventStream.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #ifndef OCPP_V21_NOTIFYPERIODICEVENTSTREAM_HPP 6 | #define OCPP_V21_NOTIFYPERIODICEVENTSTREAM_HPP 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | using namespace ocpp::v2; 13 | #include 14 | 15 | namespace ocpp { 16 | namespace v21 { 17 | 18 | /// \brief Contains a OCPP NotifyPeriodicEventStream message 19 | struct NotifyPeriodicEventStream : public ocpp::Message { 20 | std::vector data; 21 | int32_t id; 22 | int32_t pending; 23 | ocpp::DateTime basetime; 24 | std::optional customData; 25 | 26 | /// \brief Provides the type of this NotifyPeriodicEventStream message as a human readable string 27 | /// \returns the message type as a human readable string 28 | std::string get_type() const override; 29 | }; 30 | 31 | /// \brief Conversion from a given NotifyPeriodicEventStream \p k to a given json object \p j 32 | void to_json(json& j, const NotifyPeriodicEventStream& k); 33 | 34 | /// \brief Conversion from a given json object \p j to a given NotifyPeriodicEventStream \p k 35 | void from_json(const json& j, NotifyPeriodicEventStream& k); 36 | 37 | /// \brief Writes the string representation of the given NotifyPeriodicEventStream \p k to the given output stream \p os 38 | /// \returns an output stream with the NotifyPeriodicEventStream written to 39 | std::ostream& operator<<(std::ostream& os, const NotifyPeriodicEventStream& k); 40 | 41 | } // namespace v21 42 | } // namespace ocpp 43 | 44 | #endif // OCPP_V21_NOTIFYPERIODICEVENTSTREAM_HPP 45 | -------------------------------------------------------------------------------- /lib/ocpp/common/call_types.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ocpp { 11 | 12 | MessageId create_message_id() { 13 | static boost::uuids::random_generator uuid_generator; 14 | boost::uuids::uuid uuid = uuid_generator(); 15 | std::stringstream s; 16 | s << uuid; 17 | return MessageId(s.str()); 18 | } 19 | 20 | bool operator<(const MessageId& lhs, const MessageId& rhs) { 21 | return lhs.get() < rhs.get(); 22 | } 23 | 24 | void to_json(json& j, const MessageId& k) { 25 | j = json(k.get()); 26 | } 27 | 28 | void from_json(const json& j, MessageId& k) { 29 | k.set(j); 30 | } 31 | 32 | } // namespace ocpp 33 | -------------------------------------------------------------------------------- /lib/ocpp/common/charging_station_base.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | #include 6 | 7 | namespace ocpp { 8 | ChargingStationBase::ChargingStationBase(const std::shared_ptr evse_security, 9 | const std::optional security_configuration) { 10 | 11 | if (evse_security != nullptr) { 12 | this->evse_security = evse_security; 13 | } else { 14 | if (!security_configuration.has_value()) { 15 | throw std::runtime_error("No implementation of EvseSecurity interface and no SecurityConfiguration " 16 | "provided to chargepoint constructor. One of options must be set"); 17 | } 18 | this->evse_security = std::make_shared(security_configuration.value()); 19 | } 20 | this->work = boost::make_shared>( 21 | boost::asio::make_work_guard(this->io_context)); 22 | this->io_context_thread = std::thread([this]() { this->io_context.run(); }); 23 | } 24 | 25 | ChargingStationBase::~ChargingStationBase() { 26 | work->get_executor().context().stop(); 27 | io_context.stop(); 28 | io_context_thread.join(); 29 | } 30 | 31 | } // namespace ocpp 32 | -------------------------------------------------------------------------------- /lib/ocpp/common/websocket/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | target_sources(ocpp 3 | PRIVATE 4 | websocket_base.cpp 5 | websocket_uri.cpp 6 | websocket.cpp 7 | websocket_libwebsockets.cpp 8 | ) 9 | -------------------------------------------------------------------------------- /lib/ocpp/v16/message_queue.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace ocpp { 9 | 10 | template <> 11 | ControlMessage::ControlMessage(const json& message, const bool stall_until_accepted) : 12 | message(message.get()), 13 | messageType(v16::conversions::string_to_messagetype(message.at(CALL_ACTION))), 14 | message_attempts(0), 15 | initial_unique_id(message[MESSAGE_ID]), 16 | stall_until_accepted(stall_until_accepted) { 17 | } 18 | 19 | bool is_transaction_message(const ocpp::v16::MessageType message_type) { 20 | return (message_type == v16::MessageType::StartTransaction) || 21 | (message_type == v16::MessageType::StopTransaction) || (message_type == v16::MessageType::MeterValues) || 22 | (message_type == v16::MessageType::SecurityEventNotification); 23 | } 24 | 25 | bool is_start_transaction_message(const ocpp::v16::MessageType message_type) { 26 | return message_type == v16::MessageType::StartTransaction; 27 | } 28 | 29 | bool is_boot_notification_message(const ocpp::v16::MessageType message_type) { 30 | return message_type == ocpp::v16::MessageType::BootNotification; 31 | } 32 | 33 | template <> bool ControlMessage::is_transaction_update_message() const { 34 | return (this->messageType == v16::MessageType::MeterValues); 35 | } 36 | 37 | template <> v16::MessageType MessageQueue::string_to_messagetype(const std::string& s) { 38 | return v16::conversions::string_to_messagetype(s); 39 | } 40 | 41 | template <> std::string MessageQueue::messagetype_to_string(v16::MessageType m) { 42 | return v16::conversions::messagetype_to_string(m); 43 | } 44 | 45 | } // namespace ocpp 46 | -------------------------------------------------------------------------------- /lib/ocpp/v16/messages/Authorize.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using json = nlohmann::json; 12 | 13 | namespace ocpp { 14 | namespace v16 { 15 | 16 | std::string AuthorizeRequest::get_type() const { 17 | return "Authorize"; 18 | } 19 | 20 | void to_json(json& j, const AuthorizeRequest& k) { 21 | // the required parts of the message 22 | j = json{ 23 | {"idTag", k.idTag}, 24 | }; 25 | // the optional parts of the message 26 | } 27 | 28 | void from_json(const json& j, AuthorizeRequest& k) { 29 | // the required parts of the message 30 | k.idTag = j.at("idTag"); 31 | 32 | // the optional parts of the message 33 | } 34 | 35 | /// \brief Writes the string representation of the given AuthorizeRequest \p k to the given output stream \p os 36 | /// \returns an output stream with the AuthorizeRequest written to 37 | std::ostream& operator<<(std::ostream& os, const AuthorizeRequest& k) { 38 | os << json(k).dump(4); 39 | return os; 40 | } 41 | 42 | std::string AuthorizeResponse::get_type() const { 43 | return "AuthorizeResponse"; 44 | } 45 | 46 | void to_json(json& j, const AuthorizeResponse& k) { 47 | // the required parts of the message 48 | j = json{ 49 | {"idTagInfo", k.idTagInfo}, 50 | }; 51 | // the optional parts of the message 52 | } 53 | 54 | void from_json(const json& j, AuthorizeResponse& k) { 55 | // the required parts of the message 56 | k.idTagInfo = j.at("idTagInfo"); 57 | 58 | // the optional parts of the message 59 | } 60 | 61 | /// \brief Writes the string representation of the given AuthorizeResponse \p k to the given output stream \p os 62 | /// \returns an output stream with the AuthorizeResponse written to 63 | std::ostream& operator<<(std::ostream& os, const AuthorizeResponse& k) { 64 | os << json(k).dump(4); 65 | return os; 66 | } 67 | 68 | } // namespace v16 69 | } // namespace ocpp 70 | -------------------------------------------------------------------------------- /lib/ocpp/v16/messages/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | target_sources(ocpp 3 | PRIVATE 4 | Authorize.cpp 5 | BootNotification.cpp 6 | CancelReservation.cpp 7 | CertificateSigned.cpp 8 | ChangeAvailability.cpp 9 | ChangeConfiguration.cpp 10 | ClearCache.cpp 11 | ClearChargingProfile.cpp 12 | DataTransfer.cpp 13 | DeleteCertificate.cpp 14 | DiagnosticsStatusNotification.cpp 15 | ExtendedTriggerMessage.cpp 16 | FirmwareStatusNotification.cpp 17 | GetCompositeSchedule.cpp 18 | GetConfiguration.cpp 19 | GetDiagnostics.cpp 20 | GetInstalledCertificateIds.cpp 21 | GetLocalListVersion.cpp 22 | GetLog.cpp 23 | Heartbeat.cpp 24 | InstallCertificate.cpp 25 | LogStatusNotification.cpp 26 | MeterValues.cpp 27 | RemoteStartTransaction.cpp 28 | RemoteStopTransaction.cpp 29 | ReserveNow.cpp 30 | Reset.cpp 31 | SecurityEventNotification.cpp 32 | SendLocalList.cpp 33 | SetChargingProfile.cpp 34 | SignCertificate.cpp 35 | SignedFirmwareStatusNotification.cpp 36 | SignedUpdateFirmware.cpp 37 | StartTransaction.cpp 38 | StatusNotification.cpp 39 | StopTransaction.cpp 40 | TriggerMessage.cpp 41 | UnlockConnector.cpp 42 | UpdateFirmware.cpp 43 | ) 44 | -------------------------------------------------------------------------------- /lib/ocpp/v16/messages/Heartbeat.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using json = nlohmann::json; 11 | 12 | namespace ocpp { 13 | namespace v16 { 14 | 15 | std::string HeartbeatRequest::get_type() const { 16 | return "Heartbeat"; 17 | } 18 | 19 | void to_json(json& j, const HeartbeatRequest& k) { 20 | // the required parts of the message 21 | j = json({}, true); 22 | // the optional parts of the message 23 | (void)k; // no elements to unpack, silence unused parameter warning 24 | } 25 | 26 | void from_json(const json& j, HeartbeatRequest& k) { 27 | // the required parts of the message 28 | 29 | // the optional parts of the message 30 | // no elements to unpack, silence unused parameter warning 31 | (void)j; 32 | (void)k; 33 | } 34 | 35 | /// \brief Writes the string representation of the given HeartbeatRequest \p k to the given output stream \p os 36 | /// \returns an output stream with the HeartbeatRequest written to 37 | std::ostream& operator<<(std::ostream& os, const HeartbeatRequest& k) { 38 | os << json(k).dump(4); 39 | return os; 40 | } 41 | 42 | std::string HeartbeatResponse::get_type() const { 43 | return "HeartbeatResponse"; 44 | } 45 | 46 | void to_json(json& j, const HeartbeatResponse& k) { 47 | // the required parts of the message 48 | j = json{ 49 | {"currentTime", k.currentTime.to_rfc3339()}, 50 | }; 51 | // the optional parts of the message 52 | } 53 | 54 | void from_json(const json& j, HeartbeatResponse& k) { 55 | // the required parts of the message 56 | k.currentTime = ocpp::DateTime(std::string(j.at("currentTime"))); 57 | 58 | // the optional parts of the message 59 | } 60 | 61 | /// \brief Writes the string representation of the given HeartbeatResponse \p k to the given output stream \p os 62 | /// \returns an output stream with the HeartbeatResponse written to 63 | std::ostream& operator<<(std::ostream& os, const HeartbeatResponse& k) { 64 | os << json(k).dump(4); 65 | return os; 66 | } 67 | 68 | } // namespace v16 69 | } // namespace ocpp 70 | -------------------------------------------------------------------------------- /lib/ocpp/v16/messages/Reset.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using json = nlohmann::json; 11 | 12 | namespace ocpp { 13 | namespace v16 { 14 | 15 | std::string ResetRequest::get_type() const { 16 | return "Reset"; 17 | } 18 | 19 | void to_json(json& j, const ResetRequest& k) { 20 | // the required parts of the message 21 | j = json{ 22 | {"type", conversions::reset_type_to_string(k.type)}, 23 | }; 24 | // the optional parts of the message 25 | } 26 | 27 | void from_json(const json& j, ResetRequest& k) { 28 | // the required parts of the message 29 | k.type = conversions::string_to_reset_type(j.at("type")); 30 | 31 | // the optional parts of the message 32 | } 33 | 34 | /// \brief Writes the string representation of the given ResetRequest \p k to the given output stream \p os 35 | /// \returns an output stream with the ResetRequest written to 36 | std::ostream& operator<<(std::ostream& os, const ResetRequest& k) { 37 | os << json(k).dump(4); 38 | return os; 39 | } 40 | 41 | std::string ResetResponse::get_type() const { 42 | return "ResetResponse"; 43 | } 44 | 45 | void to_json(json& j, const ResetResponse& k) { 46 | // the required parts of the message 47 | j = json{ 48 | {"status", conversions::reset_status_to_string(k.status)}, 49 | }; 50 | // the optional parts of the message 51 | } 52 | 53 | void from_json(const json& j, ResetResponse& k) { 54 | // the required parts of the message 55 | k.status = conversions::string_to_reset_status(j.at("status")); 56 | 57 | // the optional parts of the message 58 | } 59 | 60 | /// \brief Writes the string representation of the given ResetResponse \p k to the given output stream \p os 61 | /// \returns an output stream with the ResetResponse written to 62 | std::ostream& operator<<(std::ostream& os, const ResetResponse& k) { 63 | os << json(k).dump(4); 64 | return os; 65 | } 66 | 67 | } // namespace v16 68 | } // namespace ocpp 69 | -------------------------------------------------------------------------------- /lib/ocpp/v16/messages/SignCertificate.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using json = nlohmann::json; 11 | 12 | namespace ocpp { 13 | namespace v16 { 14 | 15 | std::string SignCertificateRequest::get_type() const { 16 | return "SignCertificate"; 17 | } 18 | 19 | void to_json(json& j, const SignCertificateRequest& k) { 20 | // the required parts of the message 21 | j = json{ 22 | {"csr", k.csr}, 23 | }; 24 | // the optional parts of the message 25 | } 26 | 27 | void from_json(const json& j, SignCertificateRequest& k) { 28 | // the required parts of the message 29 | k.csr = j.at("csr"); 30 | 31 | // the optional parts of the message 32 | } 33 | 34 | /// \brief Writes the string representation of the given SignCertificateRequest \p k to the given output stream \p os 35 | /// \returns an output stream with the SignCertificateRequest written to 36 | std::ostream& operator<<(std::ostream& os, const SignCertificateRequest& k) { 37 | os << json(k).dump(4); 38 | return os; 39 | } 40 | 41 | std::string SignCertificateResponse::get_type() const { 42 | return "SignCertificateResponse"; 43 | } 44 | 45 | void to_json(json& j, const SignCertificateResponse& k) { 46 | // the required parts of the message 47 | j = json{ 48 | {"status", conversions::generic_status_enum_type_to_string(k.status)}, 49 | }; 50 | // the optional parts of the message 51 | } 52 | 53 | void from_json(const json& j, SignCertificateResponse& k) { 54 | // the required parts of the message 55 | k.status = conversions::string_to_generic_status_enum_type(j.at("status")); 56 | 57 | // the optional parts of the message 58 | } 59 | 60 | /// \brief Writes the string representation of the given SignCertificateResponse \p k to the given output stream \p os 61 | /// \returns an output stream with the SignCertificateResponse written to 62 | std::ostream& operator<<(std::ostream& os, const SignCertificateResponse& k) { 63 | os << json(k).dump(4); 64 | return os; 65 | } 66 | 67 | } // namespace v16 68 | } // namespace ocpp 69 | -------------------------------------------------------------------------------- /lib/ocpp/v16/messages/UnlockConnector.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using json = nlohmann::json; 11 | 12 | namespace ocpp { 13 | namespace v16 { 14 | 15 | std::string UnlockConnectorRequest::get_type() const { 16 | return "UnlockConnector"; 17 | } 18 | 19 | void to_json(json& j, const UnlockConnectorRequest& k) { 20 | // the required parts of the message 21 | j = json{ 22 | {"connectorId", k.connectorId}, 23 | }; 24 | // the optional parts of the message 25 | } 26 | 27 | void from_json(const json& j, UnlockConnectorRequest& k) { 28 | // the required parts of the message 29 | k.connectorId = j.at("connectorId"); 30 | 31 | // the optional parts of the message 32 | } 33 | 34 | /// \brief Writes the string representation of the given UnlockConnectorRequest \p k to the given output stream \p os 35 | /// \returns an output stream with the UnlockConnectorRequest written to 36 | std::ostream& operator<<(std::ostream& os, const UnlockConnectorRequest& k) { 37 | os << json(k).dump(4); 38 | return os; 39 | } 40 | 41 | std::string UnlockConnectorResponse::get_type() const { 42 | return "UnlockConnectorResponse"; 43 | } 44 | 45 | void to_json(json& j, const UnlockConnectorResponse& k) { 46 | // the required parts of the message 47 | j = json{ 48 | {"status", conversions::unlock_status_to_string(k.status)}, 49 | }; 50 | // the optional parts of the message 51 | } 52 | 53 | void from_json(const json& j, UnlockConnectorResponse& k) { 54 | // the required parts of the message 55 | k.status = conversions::string_to_unlock_status(j.at("status")); 56 | 57 | // the optional parts of the message 58 | } 59 | 60 | /// \brief Writes the string representation of the given UnlockConnectorResponse \p k to the given output stream \p os 61 | /// \returns an output stream with the UnlockConnectorResponse written to 62 | std::ostream& operator<<(std::ostream& os, const UnlockConnectorResponse& k) { 63 | os << json(k).dump(4); 64 | return os; 65 | } 66 | 67 | } // namespace v16 68 | } // namespace ocpp 69 | -------------------------------------------------------------------------------- /lib/ocpp/v16/utils.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | #include 6 | 7 | namespace ocpp { 8 | namespace v16 { 9 | namespace utils { 10 | 11 | size_t get_message_size(const ocpp::Call& call) { 12 | return json(call).at(CALL_PAYLOAD).dump().length(); 13 | } 14 | 15 | void drop_transaction_data(size_t max_message_size, ocpp::Call& call) { 16 | auto& transaction_data = call.msg.transactionData.value(); 17 | while (get_message_size(call) > max_message_size && transaction_data.size() > 2) { 18 | for (size_t i = 1; i < transaction_data.size() - 1; i = i + 2) { 19 | transaction_data.erase(transaction_data.begin() + i); 20 | } 21 | } 22 | } 23 | 24 | bool is_critical(const std::string& security_event) { 25 | if (security_event == ocpp::security_events::FIRMWARE_UPDATED) { 26 | return true; 27 | } else if (security_event == ocpp::security_events::SETTINGSYSTEMTIME) { 28 | return true; 29 | } else if (security_event == ocpp::security_events::STARTUP_OF_THE_DEVICE) { 30 | return true; 31 | } else if (security_event == ocpp::security_events::RESET_OR_REBOOT) { 32 | return true; 33 | } else if (security_event == ocpp::security_events::SECURITYLOGWASCLEARED) { 34 | return true; 35 | } else if (security_event == ocpp::security_events::MEMORYEXHAUSTION) { 36 | return true; 37 | } else if (security_event == ocpp::security_events::TAMPERDETECTIONACTIVATED) { 38 | return true; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | } // namespace utils 45 | } // namespace v16 46 | } // namespace ocpp 47 | -------------------------------------------------------------------------------- /lib/ocpp/v2/enums.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace ocpp::v2 { 9 | 10 | namespace conversions { 11 | /// \brief Converts the given std::string \p s to VariableMonitorType 12 | /// \returns a VariableMonitorType from a string representation 13 | VariableMonitorType string_to_variable_monitor_type(const std::string& s) { 14 | if (s == "HardWiredMonitor") { 15 | return VariableMonitorType::HardWiredMonitor; 16 | } 17 | if (s == "PreconfiguredMonitor") { 18 | return VariableMonitorType::PreconfiguredMonitor; 19 | } 20 | if (s == "CustomMonitor") { 21 | return VariableMonitorType::CustomMonitor; 22 | } 23 | 24 | throw std::out_of_range("Provided string " + s + " could not be converted to enum of type VariableMonitorType"); 25 | } 26 | 27 | } // namespace conversions 28 | 29 | } // namespace ocpp::v2 30 | -------------------------------------------------------------------------------- /lib/ocpp/v2/message_queue.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace ocpp { 9 | 10 | bool is_transaction_message(const ocpp::v2::MessageType message_type) { 11 | return (message_type == v2::MessageType::TransactionEvent) || 12 | (message_type == v2::MessageType::SecurityEventNotification); 13 | } 14 | 15 | bool is_start_transaction_message(const ocpp::v2::MessageType message_type) { 16 | return false; 17 | } 18 | 19 | bool is_boot_notification_message(const ocpp::v2::MessageType message_type) { 20 | return message_type == ocpp::v2::MessageType::BootNotification; 21 | } 22 | 23 | template <> bool ControlMessage::is_transaction_update_message() const { 24 | if (this->messageType == v2::MessageType::TransactionEvent) { 25 | return v2::TransactionEventRequest{this->message.at(CALL_PAYLOAD)}.eventType == 26 | v2::TransactionEventEnum::Updated; 27 | } 28 | return false; 29 | } 30 | 31 | template <> 32 | ControlMessage::ControlMessage(const json& message, const bool stall_until_accepted) : 33 | message(message.get()), 34 | messageType(v2::conversions::string_to_messagetype(message.at(CALL_ACTION))), 35 | message_attempts(0), 36 | initial_unique_id(message[MESSAGE_ID]), 37 | stall_until_accepted(stall_until_accepted) { 38 | } 39 | 40 | template <> v2::MessageType MessageQueue::string_to_messagetype(const std::string& s) { 41 | return v2::conversions::string_to_messagetype(s); 42 | } 43 | 44 | template <> std::string MessageQueue::messagetype_to_string(const v2::MessageType m) { 45 | return v2::conversions::messagetype_to_string(m); 46 | } 47 | 48 | } // namespace ocpp 49 | -------------------------------------------------------------------------------- /lib/ocpp/v2/messages/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | target_sources(ocpp 3 | PRIVATE 4 | Authorize.cpp 5 | BootNotification.cpp 6 | CancelReservation.cpp 7 | CertificateSigned.cpp 8 | ChangeAvailability.cpp 9 | ClearCache.cpp 10 | ClearChargingProfile.cpp 11 | ClearDisplayMessage.cpp 12 | ClearVariableMonitoring.cpp 13 | ClearedChargingLimit.cpp 14 | CostUpdated.cpp 15 | CustomerInformation.cpp 16 | DataTransfer.cpp 17 | DeleteCertificate.cpp 18 | FirmwareStatusNotification.cpp 19 | Get15118EVCertificate.cpp 20 | GetBaseReport.cpp 21 | GetCertificateStatus.cpp 22 | GetChargingProfiles.cpp 23 | GetCompositeSchedule.cpp 24 | GetDisplayMessages.cpp 25 | GetInstalledCertificateIds.cpp 26 | GetLocalListVersion.cpp 27 | GetLog.cpp 28 | GetMonitoringReport.cpp 29 | GetReport.cpp 30 | GetTransactionStatus.cpp 31 | GetVariables.cpp 32 | Heartbeat.cpp 33 | InstallCertificate.cpp 34 | LogStatusNotification.cpp 35 | MeterValues.cpp 36 | NotifyChargingLimit.cpp 37 | NotifyCustomerInformation.cpp 38 | NotifyDisplayMessages.cpp 39 | NotifyEVChargingNeeds.cpp 40 | NotifyEVChargingSchedule.cpp 41 | NotifyEvent.cpp 42 | NotifyMonitoringReport.cpp 43 | NotifyReport.cpp 44 | PublishFirmware.cpp 45 | PublishFirmwareStatusNotification.cpp 46 | ReportChargingProfiles.cpp 47 | RequestStartTransaction.cpp 48 | RequestStopTransaction.cpp 49 | ReservationStatusUpdate.cpp 50 | ReserveNow.cpp 51 | Reset.cpp 52 | SecurityEventNotification.cpp 53 | SendLocalList.cpp 54 | SetChargingProfile.cpp 55 | SetDisplayMessage.cpp 56 | SetMonitoringBase.cpp 57 | SetMonitoringLevel.cpp 58 | SetNetworkProfile.cpp 59 | SetVariableMonitoring.cpp 60 | SetVariables.cpp 61 | SignCertificate.cpp 62 | StatusNotification.cpp 63 | TransactionEvent.cpp 64 | TriggerMessage.cpp 65 | UnlockConnector.cpp 66 | UnpublishFirmware.cpp 67 | UpdateFirmware.cpp 68 | ) 69 | -------------------------------------------------------------------------------- /lib/ocpp/v2/transaction.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | #include 6 | 7 | using QueryExecutionException = everest::db::QueryExecutionException; 8 | 9 | namespace ocpp { 10 | 11 | namespace v2 { 12 | 13 | Transaction EnhancedTransaction::get_transaction() { 14 | Transaction transaction; 15 | transaction.transactionId = this->transactionId; 16 | transaction.chargingState = this->chargingState; 17 | transaction.timeSpentCharging = this->timeSpentCharging; 18 | transaction.stoppedReason = this->stoppedReason; 19 | transaction.remoteStartId = this->remoteStartId; 20 | return transaction; 21 | } 22 | 23 | int32_t EnhancedTransaction::get_seq_no() { 24 | this->seq_no += 1; 25 | if (this->database_enabled) { 26 | try { 27 | this->database_handler.transaction_update_seq_no(this->transactionId, this->seq_no); 28 | } catch (const QueryExecutionException& e) { 29 | EVLOG_error << "Can't update transaction: " << e.what(); 30 | } 31 | } 32 | return this->seq_no - 1; 33 | } 34 | 35 | void EnhancedTransaction::update_charging_state(const ChargingStateEnum charging_state) { 36 | this->chargingState = charging_state; 37 | if (this->database_enabled) { 38 | try { 39 | this->database_handler.transaction_update_charging_state(this->transactionId, charging_state); 40 | } catch (const QueryExecutionException& e) { 41 | EVLOG_error << "Can't update transaction: " << e.what(); 42 | } 43 | } 44 | } 45 | 46 | void EnhancedTransaction::set_id_token_sent() { 47 | this->id_token_sent = true; 48 | if (this->database_enabled) { 49 | try { 50 | this->database_handler.transaction_update_id_token_sent(this->transactionId, this->id_token_sent); 51 | } catch (const QueryExecutionException& e) { 52 | EVLOG_error << "Can't update transaction: " << e.what(); 53 | } 54 | } 55 | } 56 | 57 | } // namespace v2 58 | 59 | } // namespace ocpp 60 | -------------------------------------------------------------------------------- /lib/ocpp/v21/messages/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | target_sources(ocpp 3 | PRIVATE 4 | AFRRSignal.cpp 5 | AdjustPeriodicEventStream.cpp 6 | BatterySwap.cpp 7 | ChangeTransactionTariff.cpp 8 | ClearDERControl.cpp 9 | ClearTariffs.cpp 10 | ClosePeriodicEventStream.cpp 11 | GetCertificateChainStatus.cpp 12 | GetDERControl.cpp 13 | GetPeriodicEventStream.cpp 14 | GetTariffs.cpp 15 | NotifyAllowedEnergyTransfer.cpp 16 | NotifyDERAlarm.cpp 17 | NotifyDERStartStop.cpp 18 | NotifyPeriodicEventStream.cpp 19 | NotifyPriorityCharging.cpp 20 | NotifySettlement.cpp 21 | NotifyWebPaymentStarted.cpp 22 | OpenPeriodicEventStream.cpp 23 | PullDynamicScheduleUpdate.cpp 24 | ReportDERControl.cpp 25 | RequestBatterySwap.cpp 26 | SetDERControl.cpp 27 | SetDefaultTariff.cpp 28 | UpdateDynamicSchedule.cpp 29 | UsePriorityCharging.cpp 30 | VatNumberValidation.cpp 31 | ) 32 | -------------------------------------------------------------------------------- /lib/ocpp/v21/messages/NotifyPeriodicEventStream.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest 3 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using json = nlohmann::json; 12 | 13 | namespace ocpp { 14 | namespace v21 { 15 | 16 | std::string NotifyPeriodicEventStream::get_type() const { 17 | return "NotifyPeriodicEventStream"; 18 | } 19 | 20 | void to_json(json& j, const NotifyPeriodicEventStream& k) { 21 | // the required parts of the message 22 | j = json{ 23 | {"data", k.data}, 24 | {"id", k.id}, 25 | {"pending", k.pending}, 26 | {"basetime", k.basetime.to_rfc3339()}, 27 | }; 28 | // the optional parts of the message 29 | if (k.customData) { 30 | j["customData"] = k.customData.value(); 31 | } 32 | } 33 | 34 | void from_json(const json& j, NotifyPeriodicEventStream& k) { 35 | // the required parts of the message 36 | for (auto val : j.at("data")) { 37 | k.data.push_back(val); 38 | } 39 | k.id = j.at("id"); 40 | k.pending = j.at("pending"); 41 | k.basetime = ocpp::DateTime(std::string(j.at("basetime"))); 42 | 43 | // the optional parts of the message 44 | if (j.contains("customData")) { 45 | k.customData.emplace(j.at("customData")); 46 | } 47 | } 48 | 49 | /// \brief Writes the string representation of the given NotifyPeriodicEventStream \p k to the given output stream \p os 50 | /// \returns an output stream with the NotifyPeriodicEventStream written to 51 | std::ostream& operator<<(std::ostream& os, const NotifyPeriodicEventStream& k) { 52 | os << json(k).dump(4); 53 | return os; 54 | } 55 | 56 | } // namespace v21 57 | } // namespace ocpp 58 | -------------------------------------------------------------------------------- /run-docker-tls.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## 3 | ## SPDX-License-Identifier: Apache-2.0 4 | ## Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 5 | ## 6 | ./dist/bin/charge_point \ 7 | --maindir ./dist/ocpp \ 8 | --conf config-docker-tls.json 9 | -------------------------------------------------------------------------------- /run-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## 3 | ## SPDX-License-Identifier: Apache-2.0 4 | ## Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 5 | ## 6 | ./dist/bin/charge_point \ 7 | --maindir ./dist/ocpp \ 8 | --conf config-docker.json 9 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(charge_point charge_point.cpp) 2 | 3 | target_link_libraries(charge_point 4 | PRIVATE 5 | Boost::thread 6 | Boost::program_options 7 | nlohmann_json::nlohmann_json 8 | nlohmann_json_schema_validator 9 | ocpp 10 | OpenSSL::SSL 11 | OpenSSL::Crypto 12 | SQLite::SQLite3 13 | ) 14 | 15 | install(TARGETS charge_point 16 | RUNTIME) 17 | set_property(TARGET ocpp PROPERTY POSITION_INDEPENDENT_CODE ON) 18 | -------------------------------------------------------------------------------- /src/code_generator/README.md: -------------------------------------------------------------------------------- 1 | # Libocpp Code Generators 2 | In this directory a collection of code generators for various purposes are located. 3 | 4 | ## C++ Code generator for v16 and v2 5 | The script [generate_cpp.py](common/generate_cpp.py) can be used to generate datatypes, enums, and messages for v16 and v2. 6 | 7 | ```bash 8 | python3 generate_cpp.py --schemas --out --version 9 | ``` 10 | 11 | e.g. 12 | 13 | ```bash 14 | python3 generate_cpp.py --schemas ~/ocpp-schemas/v16/ --out ~/checkout/everest-workspace/libocpp --version v16 15 | ``` 16 | 17 | ```bash 18 | python3 generate_cpp.py --schemas ~/ocpp-schemas/v2/ --out ~/checkout/everest-workspace/libocpp --version v2 19 | ``` 20 | 21 | ```bash 22 | python3 generate_cpp.py --schemas ~/ocpp-schemas/v21/ --out ~/checkout/everest-workspace/libocpp --version v21 23 | ``` 24 | 25 | ## YAML code generator for EVerest types 26 | 27 | The script [generate_everest_types.py](common/generate_cpp.py) can be used to generate EVerest YAML type definitions using OCPP2.0.1 and OCPP2.1 JSON schemas. 28 | 29 | ```bash 30 | python3 generate_everest_types.py --schemas --out --types 31 | ``` 32 | 33 | e.g. 34 | 35 | ```bash 36 | python3 generate_everest_types.py --schemas ~/ocpp-schemas/v21/ --out ocpp.yaml --types ChargingNeedsType,ChargingScheduleType 37 | ``` 38 | -------------------------------------------------------------------------------- /src/code_generator/common/templates/everest_type.yaml.jinja: -------------------------------------------------------------------------------- 1 | description: Autogenerated types based on OCPP JSON schemas 2 | types: 3 | {% for enum in enums %} 4 | {{ enum.name }}: 5 | description: >- 6 | {{ enum.description }} 7 | type: string 8 | enum: 9 | {% for value in enum.values %} 10 | - "{{ value }}" 11 | {% endfor %} 12 | {% endfor %} 13 | {% for type in types %} 14 | {{ type.name }}: 15 | description: >- 16 | {{ type.description }} 17 | type: object 18 | required: 19 | {% if type.properties|selectattr('required', 'true')|list %} 20 | {% for property in type.properties if property.required %} 21 | - {{ property.name | snake_case }} 22 | {% endfor %} 23 | {% else %} 24 | [] 25 | {% endif %} 26 | properties: 27 | {% for property in type.properties %} 28 | {% if property.name != "customData" %} 29 | {{ property.name | snake_case }}: 30 | description: >- 31 | {{ property.description }} 32 | type: {{ property.type }} 33 | {% if property.type == "object" or property.enum %} 34 | $ref: /ocpp#/{{ property.ref }} 35 | {% endif %} 36 | {% if property.type == "array" %} 37 | items: 38 | type: {{ property.item.type }} 39 | {% if property.item.ref != None %} 40 | $ref: /ocpp#/{{ property.item.ref }} 41 | {% endif %} 42 | {% if property.item.min_items != None %} 43 | minItems: {{ property.item.min_items }} 44 | {% endif %} 45 | {% if property.item.max_items != None %} 46 | maxItems: {{ property.item.max_items }} 47 | {% endif %} 48 | {% endif %} 49 | {% endif %} 50 | {% endfor %} 51 | {% endfor %} 52 | -------------------------------------------------------------------------------- /src/code_generator/common/templates/messages.cmakelists.txt.jinja: -------------------------------------------------------------------------------- 1 | 2 | target_sources(ocpp 3 | PRIVATE 4 | {% for message in messages %} 5 | {{message}}.cpp 6 | {% endfor %} 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /src/code_generator/common/templates/ocpp_enums.cpp.jinja: -------------------------------------------------------------------------------- 1 | {% if first %} 2 | // SPDX-License-Identifier: Apache-2.0 3 | // Copyright 2020 - {{year}} Pionix GmbH and Contributors to EVerest 4 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace ocpp { 13 | namespace {{namespace}} { 14 | {% endif %} 15 | {%- if enum_types|length %} 16 | {%- for enum_type in enum_types %} 17 | 18 | // from: {{action.class_name}} 19 | namespace conversions { 20 | std::string {{ enum_type.name | snake_case }}_to_string({{ enum_type.name }} e) { 21 | switch (e) { 22 | {% for enum in enum_type.enums %} 23 | case {{ enum_type.name }}::{{ enum.replace('.', '_').replace('-', '_') }}: return "{{enum}}"; 24 | {% endfor %} 25 | } 26 | 27 | throw EnumToStringException{e, "{{ enum_type.name }}"}; 28 | } 29 | 30 | {{ enum_type.name }} string_to_{{ enum_type.name | snake_case }}(const std::string& s) { 31 | {% for enum in enum_type.enums %} 32 | if(s == "{{enum}}") { 33 | return {{ enum_type.name }}::{{ enum.replace('.', '_').replace('-', '_') }}; 34 | } 35 | {% endfor %} 36 | 37 | throw StringToEnumException{s, "{{ enum_type.name }}"}; 38 | } 39 | } 40 | 41 | std::ostream& operator<<(std::ostream& os, const {{ enum_type.name }}& {{ enum_type.name | snake_case }}) { 42 | os << conversions::{{ enum_type.name | snake_case }}_to_string({{ enum_type.name | snake_case }}); 43 | return os; 44 | } 45 | 46 | {% endfor %} 47 | {%- endif %} 48 | {% if last %} 49 | } // namespace {{namespace}} 50 | } // namespace ocpp 51 | 52 | {% endif %} 53 | -------------------------------------------------------------------------------- /src/code_generator/common/templates/ocpp_enums.hpp.jinja: -------------------------------------------------------------------------------- 1 | {% if first %} 2 | // SPDX-License-Identifier: Apache-2.0 3 | // Copyright 2020 - {{year}} Pionix GmbH and Contributors to EVerest 4 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 5 | 6 | #ifndef OCPP_{{namespace | upper}}_OCPP_ENUMS_HPP 7 | #define OCPP_{{namespace | upper}}_OCPP_ENUMS_HPP 8 | 9 | #include 10 | #include 11 | 12 | namespace ocpp { 13 | namespace {{namespace}} { 14 | {% endif %} 15 | {%- if enum_types|length %} 16 | {%- for enum_type in enum_types %} 17 | 18 | // from: {{action.class_name}} 19 | enum class {{ enum_type.name }} 20 | { 21 | {% for enum in enum_type.enums %} 22 | {{ enum.replace('.', '_').replace('-', '_') }}, 23 | {% endfor %} 24 | }; 25 | 26 | namespace conversions { 27 | /// \brief Converts the given {{ enum_type.name }} \p e to human readable string 28 | /// \returns a string representation of the {{ enum_type.name }} 29 | std::string {{ enum_type.name | snake_case }}_to_string({{ enum_type.name }} e); 30 | 31 | /// \brief Converts the given std::string \p s to {{ enum_type.name }} 32 | /// \returns a {{ enum_type.name }} from a string representation 33 | {{ enum_type.name }} string_to_{{ enum_type.name | snake_case }}(const std::string& s); 34 | } 35 | 36 | /// \brief Writes the string representation of the given {{ enum_type.name }} \p {{ enum_type.name | snake_case }} to the given output stream \p os 37 | /// \returns an output stream with the {{ enum_type.name }} written to 38 | std::ostream& operator<<(std::ostream& os, const {{ enum_type.name }}& {{ enum_type.name | snake_case }}); 39 | {% endfor %} 40 | {%- endif %} 41 | {% if last %} 42 | 43 | } // namespace {{namespace}} 44 | } // namespace ocpp 45 | 46 | #endif // OCPP_{{namespace | upper}}_OCPP_ENUMS_HPP 47 | {% endif %} 48 | -------------------------------------------------------------------------------- /src/code_generator/common/templates/ocpp_types.hpp.jinja: -------------------------------------------------------------------------------- 1 | {% if first %} 2 | // SPDX-License-Identifier: Apache-2.0 3 | // Copyright 2020 - {{year}} Pionix GmbH and Contributors to EVerest 4 | // This code is generated using the generator in 'src/code_generator/common`, please do not edit manually 5 | 6 | #ifndef OCPP_{{namespace | upper}}_OCPP_TYPES_HPP 7 | #define OCPP_{{namespace | upper}}_OCPP_TYPES_HPP 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | {% if namespace == "v16" %} 16 | #include 17 | {% endif %} 18 | #include 19 | 20 | namespace ocpp { 21 | namespace {{namespace}} { 22 | {% endif %} 23 | {%- if parsed_types|length %} 24 | {%- for type in parsed_types %} 25 | {% if not type.name.endswith('Request') and not type.name.endswith('Response') %} 26 | 27 | {% if type.name == "CustomData" and namespace == "v2" %} 28 | using CustomData = nlohmann::json; 29 | {% else %} 30 | struct {{type.name}} { 31 | {% for property in type.properties %} 32 | {{ 'std::optional<' if not property.required -}} 33 | {{ property.type -}} 34 | {{ '>' if not property.required -}} 35 | {{ ' ' + property.name + ';' }} 36 | {% endfor %} 37 | }; 38 | {% endif %} 39 | {% if not (type.name == "CustomData" and namespace == "v2") %} 40 | /// \brief Conversion from a given {{ type.name }} \p k to a given json object \p j 41 | void to_json(json& j, const {{ type.name }}& k); 42 | 43 | /// \brief Conversion from a given json object \p j to a given {{ type.name }} \p k 44 | void from_json(const json& j, {{ type.name }}& k); 45 | 46 | /// \brief Writes the string representation of the given {{ type.name }} \p k to the given output stream \p os 47 | /// \returns an output stream with the {{ type.name }} written to 48 | std::ostream& operator<<(std::ostream& os, const {{ type.name }}& k); 49 | 50 | {% endif %} 51 | {% endif %} 52 | {% endfor %} 53 | {%- endif %} 54 | {% if last %} 55 | } // namespace {{namespace}} 56 | } // namespace ocpp 57 | 58 | #endif // OCPP_{{namespace | upper}}_OCPP_TYPES_HPP 59 | {% endif %} 60 | -------------------------------------------------------------------------------- /src/code_generator/common/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest 5 | # 6 | 7 | def snake_case(word: str) -> str: 8 | """Convert capital case to snake case. 9 | Only alphanumerical characters are allowed. Only inserts camelcase 10 | between a consecutive lower and upper alphabetical character and 11 | lowers first letter. 12 | """ 13 | 14 | # special handling for soc 15 | word = word.replace('SoC', 'Soc') 16 | 17 | out = '' 18 | if len(word) == 0: 19 | return out 20 | cur_char: str = '' 21 | for i, character in enumerate(word): 22 | if i == 0: 23 | cur_char = character 24 | if not cur_char.isalnum(): 25 | raise Exception('Non legal character in: ' + word) 26 | out += cur_char.lower() 27 | continue 28 | last_char: str = cur_char 29 | cur_char = character 30 | if (last_char.islower() and last_char.isalpha() and 31 | cur_char.isupper() and cur_char.isalpha): 32 | out += '_' 33 | if not cur_char.isalnum(): 34 | out += '_' 35 | else: 36 | out += cur_char.lower() 37 | 38 | return out 39 | -------------------------------------------------------------------------------- /tests/config/v16/resources/user_config.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/config/v2/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | pythonpath=../../../config/v2 -------------------------------------------------------------------------------- /tests/config/v2/resources/component_config/standardized/UnitTestCtrlr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for UnitTestCtrlr", 4 | "name": "UnitTestCtrlr", 5 | "type": "object", 6 | "evse_id": 2, 7 | "connector_id": 3, 8 | "properties": { 9 | "UnitTestPropertyA": { 10 | "variable_name": "UnitTestPropertyAName", 11 | "source": "OCPP", 12 | "characteristics": { 13 | "supportsMonitoring": true, 14 | "dataType": "boolean" 15 | }, 16 | "attributes": [ 17 | { 18 | "type": "Actual", 19 | "mutability": "ReadWrite" 20 | } 21 | ], 22 | "default": true, 23 | "type": "boolean" 24 | }, 25 | "UnitTestPropertyB": { 26 | "variable_name": "UnitTestPropertyBName", 27 | "characteristics": { 28 | "supportsMonitoring": false, 29 | "dataType": "string" 30 | }, 31 | "attributes": [ 32 | { 33 | "type": "Actual", 34 | "mutability": "ReadOnly", 35 | "value": "test_value" 36 | } 37 | ], 38 | "type": "string" 39 | }, 40 | "UnitTestPropertyC": { 41 | "variable_name": "UnitTestPropertyCName", 42 | "characteristics": { 43 | "supportsMonitoring": false, 44 | "dataType": "integer" 45 | }, 46 | "attributes": [ 47 | { 48 | "type": "Actual", 49 | "mutability": "ReadOnly" 50 | } 51 | ], 52 | "type": "integer" 53 | } 54 | }, 55 | "required": [ 56 | "UnitTestPropertyA" 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /tests/config/v2/resources_changed/component_config/custom/Connector_2_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for Connector", 4 | "type": "object", 5 | "name": "Connector", 6 | "evse_id": 2, 7 | "connector_id": 2, 8 | "properties": { 9 | "ConnectorAvailabilityState": { 10 | "variable_name": "AvailabilityState", 11 | "characteristics": { 12 | "supportsMonitoring": true, 13 | "dataType": "OptionList", 14 | "valuesList": "Available,Unavailable" 15 | }, 16 | "attributes": [ 17 | { 18 | "type": "Actual" 19 | } 20 | ], 21 | "description": "This variable reports current availability state for the Connector. Optional, because already reported in StatusNotification.", 22 | "type": "string" 23 | }, 24 | "ConnectorAvailable": { 25 | "variable_name": "Available", 26 | "characteristics": { 27 | "supportsMonitoring": true, 28 | "dataType": "boolean" 29 | }, 30 | "attributes": [ 31 | { 32 | "type": "Actual", 33 | "mutability": "ReadOnly" 34 | } 35 | ], 36 | "description": "Component exists", 37 | "type": "boolean", 38 | "default": false 39 | } 40 | }, 41 | "required": [ 42 | "ConnectorAvailable" 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /tests/config/v2/resources_changed/component_config/standardized/UnitTestCtrlr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for UnitTestCtrlr", 4 | "name": "UnitTestCtrlr", 5 | "type": "object", 6 | "evse_id": 2, 7 | "connector_id": 3, 8 | "properties": { 9 | "UnitTestPropertyA": { 10 | "variable_name": "UnitTestPropertyAName", 11 | "characteristics": { 12 | "supportsMonitoring": true, 13 | "dataType": "string" 14 | }, 15 | "attributes": [ 16 | { 17 | "type": "Actual", 18 | "mutability": "ReadWrite" 19 | } 20 | ], 21 | "default": "1", 22 | "type": "string" 23 | }, 24 | "UnitTestPropertyB": { 25 | "variable_name": "UnitTestPropertyBName", 26 | "characteristics": { 27 | "supportsMonitoring": false, 28 | "dataType": "string" 29 | }, 30 | "attributes": [ 31 | { 32 | "type": "Actual", 33 | "mutability": "ReadOnly" 34 | } 35 | ], 36 | "type": "string" 37 | } 38 | }, 39 | "required": [ 40 | "UnitTestPropertyA" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /tests/config/v2/resources_wrong/component_config_required_no_value/standardized/UnitTestCtrlr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for UnitTestCtrlr", 4 | "name": "UnitTestCtrlr", 5 | "type": "object", 6 | "evse_id": 2, 7 | "connector_id": 3, 8 | "properties": { 9 | "UnitTestPropertyA": { 10 | "variable_name": "UnitTestPropertyAName", 11 | "characteristics": { 12 | "supportsMonitoring": true, 13 | "dataType": "boolean" 14 | }, 15 | "attributes": [ 16 | { 17 | "type": "Actual", 18 | "mutability": "ReadWrite" 19 | } 20 | ], 21 | "type": "boolean" 22 | }, 23 | "UnitTestPropertyB": { 24 | "variable_name": "UnitTestPropertyBName", 25 | "characteristics": { 26 | "supportsMonitoring": false, 27 | "dataType": "string" 28 | }, 29 | "attributes": [ 30 | { 31 | "type": "Actual", 32 | "mutability": "ReadOnly", 33 | "value": "test_value" 34 | } 35 | ], 36 | "type": "string" 37 | }, 38 | "UnitTestPropertyC": { 39 | "variable_name": "UnitTestPropertyCName", 40 | "characteristics": { 41 | "supportsMonitoring": false, 42 | "dataType": "integer" 43 | }, 44 | "attributes": [ 45 | { 46 | "type": "Target", 47 | "mutability": "ReadOnly" 48 | } 49 | ], 50 | "type": "integer", 51 | "default": 42 52 | }, 53 | "UnitTestPropertyD": { 54 | "variable_name": "UnitTestPropertyDName", 55 | "characteristics": { 56 | "supportsMonitoring": false, 57 | "dataType": "integer" 58 | }, 59 | "attributes": [ 60 | { 61 | "type": "Actual", 62 | "mutability": "ReadOnly" 63 | } 64 | ], 65 | "type": "integer", 66 | "default": 42 67 | } 68 | }, 69 | "required": [ 70 | "UnitTestPropertyA", 71 | "UnitTestPropertyB", 72 | "UnitTestPropertyC", 73 | "UnitTestPropertyD" 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /tests/config/v2/resources_wrong/component_config_wrong_value_type/standardized/UnitTestCtrlr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "description": "Schema for UnitTestCtrlr", 4 | "name": "UnitTestCtrlr", 5 | "type": "object", 6 | "evse_id": 2, 7 | "connector_id": 3, 8 | "properties": { 9 | "UnitTestPropertyA": { 10 | "variable_name": "UnitTestPropertyAName", 11 | "characteristics": { 12 | "supportsMonitoring": true, 13 | "dataType": "boolean" 14 | }, 15 | "attributes": [ 16 | { 17 | "type": "Actual", 18 | "mutability": "ReadWrite", 19 | "value": 42 20 | } 21 | ], 22 | "type": "boolean" 23 | }, 24 | "UnitTestPropertyB": { 25 | "variable_name": "UnitTestPropertyBName", 26 | "characteristics": { 27 | "supportsMonitoring": false, 28 | "dataType": "decimal" 29 | }, 30 | "attributes": [ 31 | { 32 | "type": "Actual", 33 | "mutability": "ReadOnly", 34 | "value": "test_value" 35 | } 36 | ], 37 | "type": "number", 38 | "default": "test" 39 | }, 40 | "UnitTestPropertyC": { 41 | "variable_name": "UnitTestPropertyCName", 42 | "characteristics": { 43 | "supportsMonitoring": false, 44 | "dataType": "integer" 45 | }, 46 | "attributes": [ 47 | { 48 | "type": "Actual", 49 | "mutability": "ReadOnly" 50 | } 51 | ], 52 | "type": "integer", 53 | "default": "true" 54 | } 55 | }, 56 | "required": [ 57 | "UnitTestPropertyA" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /tests/lib/ocpp/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(libocpp_unit_tests PRIVATE 2 | test_database_migration_files.cpp 3 | test_message_queue.cpp 4 | test_websocket_uri.cpp 5 | ) 6 | 7 | 8 | set(TEST_UTILS_SOURCES ${LIBOCPP_LIB_PATH}/ocpp/common/utils.cpp) 9 | 10 | target_sources(libocpp_utils_tests PRIVATE ${TEST_UTILS_SOURCES}) 11 | -------------------------------------------------------------------------------- /tests/lib/ocpp/common/database_testing_utils.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std::string_literals; 11 | 12 | class DatabaseTestingUtils : public ::testing::Test { 13 | 14 | protected: 15 | std::unique_ptr database; 16 | 17 | public: 18 | DatabaseTestingUtils() : database(std::make_unique("file::memory:?cache=shared")) { 19 | EXPECT_TRUE(this->database->open_connection()); 20 | } 21 | 22 | void ExpectUserVersion(uint32_t expected_version) { 23 | auto statement = this->database->new_statement("PRAGMA user_version"); 24 | 25 | EXPECT_EQ(statement->step(), SQLITE_ROW); 26 | EXPECT_EQ(statement->column_int(0), expected_version); 27 | } 28 | 29 | void SetUserVersion(uint32_t user_version) { 30 | EXPECT_TRUE(this->database->execute_statement("PRAGMA user_version = "s + std::to_string(user_version))); 31 | } 32 | 33 | bool DoesTableExist(std::string_view table) { 34 | const std::string statement = "SELECT name FROM sqlite_master WHERE type='table' AND name=@table_name"; 35 | 36 | std::unique_ptr table_exists_statement = 37 | this->database->new_statement(statement); 38 | table_exists_statement->bind_text("@table_name", std::string(table), 39 | everest::db::sqlite::SQLiteString::Transient); 40 | const int status = table_exists_statement->step(); 41 | const int number_of_rows = table_exists_statement->get_number_of_rows(); 42 | return status != SQLITE_ERROR && number_of_rows == 1; 43 | } 44 | 45 | bool DoesColumnExist(std::string_view table, std::string_view column) { 46 | return this->database->execute_statement("SELECT "s + column.data() + " FROM " + table.data() + " LIMIT 1;"); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /tests/lib/ocpp/common/smart_charging_matchers.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | MATCHER_P2(PeriodEquals, start, limit, 9 | "Period start " + testing::DescribeMatcher(start, negation) + " and limit " + 10 | testing::DescribeMatcher(limit, negation)) { 11 | return ExplainMatchResult(start, arg.startPeriod, result_listener) && 12 | ExplainMatchResult(limit, arg.limit, result_listener); 13 | } 14 | 15 | MATCHER_P3(PeriodEqualsWithPhases, start, limit, phases, 16 | "Period start " + testing::DescribeMatcher(start, negation) + " and limit " + 17 | testing::DescribeMatcher(limit, negation) + " and phases " + 18 | testing::DescribeMatcher>(phases, negation)) { 19 | return ExplainMatchResult(start, arg.startPeriod, result_listener) && 20 | ExplainMatchResult(limit, arg.limit, result_listener) && 21 | ExplainMatchResult(phases, arg.numberPhases, result_listener); 22 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/common/test_database_migration_files.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #include "test_database_migration_files.hpp" 5 | 6 | TEST_P(DatabaseMigrationFilesTest, ApplyMigrationFilesStepByStep) { 7 | everest::db::sqlite::SchemaUpdater updater{this->database.get()}; 8 | 9 | for (uint32_t i = 1; i <= this->max_version; i++) { 10 | EXPECT_TRUE(updater.apply_migration_files(this->migration_files_path, i)); 11 | this->ExpectUserVersion(i); 12 | } 13 | 14 | for (uint32_t i = this->max_version; i > 0; i--) { 15 | EXPECT_TRUE(updater.apply_migration_files(this->migration_files_path, i)); 16 | this->ExpectUserVersion(i); 17 | } 18 | } 19 | 20 | TEST_P(DatabaseMigrationFilesTest, ApplyMigrationFilesAtOnce) { 21 | everest::db::sqlite::SchemaUpdater updater{this->database.get()}; 22 | 23 | EXPECT_TRUE(updater.apply_migration_files(this->migration_files_path, this->max_version)); 24 | this->ExpectUserVersion(this->max_version); 25 | 26 | EXPECT_TRUE(updater.apply_migration_files(this->migration_files_path, 1)); 27 | this->ExpectUserVersion(1); 28 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/common/test_database_migration_files.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include "database_testing_utils.hpp" 7 | #include 8 | 9 | class DatabaseMigrationFilesTest : public DatabaseTestingUtils, 10 | public ::testing::WithParamInterface> { 11 | 12 | protected: 13 | const std::filesystem::path migration_files_path; 14 | const uint32_t max_version; 15 | 16 | public: 17 | DatabaseMigrationFilesTest() : 18 | DatabaseTestingUtils(), 19 | migration_files_path(std::get(GetParam())), 20 | max_version(std::get(GetParam())) { 21 | EXPECT_TRUE(this->database->open_connection()); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /tests/lib/ocpp/common/test_websocket_uri.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | #include 4 | #include 5 | 6 | #include "ocpp/common/websocket/websocket_uri.hpp" 7 | 8 | using namespace ocpp; 9 | 10 | TEST(WebsocketUriTest, EmptyStrings) { 11 | EXPECT_THROW(Uri::parse_and_validate("", "cp0001", 1), std::invalid_argument); 12 | EXPECT_THROW(Uri::parse_and_validate("ws://test.uri.com", "", 1), std::invalid_argument); 13 | } 14 | 15 | TEST(WebsocketUriTest, UriInvalid) { 16 | EXPECT_THROW(Uri::parse_and_validate("://invalid", "cp0001", 1), std::invalid_argument); 17 | EXPECT_THROW(Uri::parse_and_validate("ws:test.uri.com", "cp0001", 1), std::invalid_argument); 18 | } 19 | 20 | TEST(WebsocketUriTest, InvalidSecurityLevel) { 21 | EXPECT_THROW(Uri::parse_and_validate("wss://test.uri.com", "cp0001", 4), std::invalid_argument); 22 | } 23 | 24 | TEST(WebsocketUriTest, SecurityLevelMismatch) { 25 | EXPECT_THROW(Uri::parse_and_validate("wss://test.uri.com", "cp0001", 0), std::invalid_argument); 26 | EXPECT_THROW(Uri::parse_and_validate("wss://test.uri.com", "cp0001", 1), std::invalid_argument); 27 | EXPECT_THROW(Uri::parse_and_validate("ws://test.uri.com", "cp0001", 2), std::invalid_argument); 28 | EXPECT_THROW(Uri::parse_and_validate("ws://test.uri.com", "cp0001", 3), std::invalid_argument); 29 | } 30 | 31 | TEST(WebsocketUriTest, AppendingIdentity) { 32 | EXPECT_EQ(Uri::parse_and_validate("ws://test.uri.com/path", "cp0001", 1).string(), "ws://test.uri.com/path/cp0001"); 33 | EXPECT_EQ(Uri::parse_and_validate("ws://test.uri.com/path/", "cp0001", 1).string(), 34 | "ws://test.uri.com/path/cp0001"); 35 | EXPECT_EQ(Uri::parse_and_validate("ws://test.uri.com/path/cp0001", "cp0001", 1).string(), 36 | "ws://test.uri.com/path/cp0001"); 37 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_include_directories(libocpp_unit_tests PUBLIC 2 | ${CMAKE_CURRENT_SOURCE_DIR} 3 | ) 4 | 5 | target_sources(libocpp_unit_tests PRIVATE 6 | profile_tests_common.cpp 7 | profile_testsA.cpp 8 | profile_testsB.cpp 9 | profile_testsC.cpp 10 | test_database_migration_files.cpp 11 | test_smart_charging_handler.cpp 12 | database_tests.cpp 13 | test_message_queue.cpp 14 | test_charge_point_state_machine.cpp 15 | test_composite_schedule.cpp 16 | test_config_validation.cpp 17 | ) 18 | 19 | # Copy the json files used for testing to the destination directory 20 | file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/json DESTINATION ${TEST_PROFILES_LOCATION_V16}) 21 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/database_handler_mock.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | #ifndef OCPP_DATABASE_HANDLE_MOCK_H 4 | #define OCPP_DATABASE_HANDLE_MOCK_H 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace ocpp { 12 | 13 | class DatabaseHandlerMock : public v16::DatabaseHandler { 14 | public: 15 | DatabaseHandlerMock(std::unique_ptr database, 16 | const fs::path& init_script_path) : 17 | DatabaseHandler(std::move(database), init_script_path, 2){}; 18 | MOCK_METHOD(void, insert_or_update_charging_profile, (const int, const v16::ChargingProfile&), (override)); 19 | MOCK_METHOD(void, delete_charging_profile, (const int profile_id), (override)); 20 | }; 21 | 22 | } // namespace ocpp 23 | 24 | #endif // DATABASE_HANDLE_MOCK_H -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/Absolute_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 301, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "A", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 32.0, 10 | "startPeriod": 0 11 | }, 12 | { 13 | "limit": 31.0, 14 | "startPeriod": 1800 15 | }, 16 | { 17 | "limit": 30.0, 18 | "startPeriod": 2700 19 | } 20 | ], 21 | "duration": 3600, 22 | "startSchedule": "2024-01-01T12:02:00Z" 23 | }, 24 | "stackLevel": 5, 25 | "validFrom": "2024-01-01T12:00:00Z", 26 | "validTo": "2024-01-01T14:00:00Z" 27 | } 28 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/ChargingStationMaxProfile_24_Ampere.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 24, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "ChargePointMaxProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 16.0, 11 | "numberPhases": 1, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 16.0, 16 | "numberPhases": 3, 17 | "startPeriod": 3600 18 | }, 19 | { 20 | "limit": 10.0, 21 | "numberPhases": 1, 22 | "startPeriod": 7200 23 | }, 24 | { 25 | "limit": 10.0, 26 | "numberPhases": 3, 27 | "startPeriod": 10800 28 | } 29 | ], 30 | "duration": 86400, 31 | "minChargingRate": 0.0, 32 | "startSchedule": "2024-01-17T00:00:00.000Z" 33 | }, 34 | "recurrencyKind": "Daily", 35 | "stackLevel": 0 36 | } 37 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/ChargingStationMaxProfile_401.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 24, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "ChargePointMaxProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "A", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 24.0, 10 | "numberPhases": 1, 11 | "startPeriod": 0 12 | }, 13 | { 14 | "limit": 28.0, 15 | "numberPhases": 1, 16 | "startPeriod": 900 17 | }, 18 | { 19 | "limit": 30.0, 20 | "numberPhases": 1, 21 | "startPeriod": 1800 22 | }, 23 | { 24 | "limit": 32.0, 25 | "numberPhases": 1, 26 | "startPeriod": 2700 27 | } 28 | ], 29 | "duration": 86400, 30 | "minChargingRate": 0.0, 31 | "startSchedule": "2024-01-17T08:00:00.000Z" 32 | }, 33 | "recurrencyKind": "Daily", 34 | "stackLevel": 0 35 | } 36 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/Recurring_Daily_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 301, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 16.0, 11 | "startPeriod": 0 12 | }, 13 | { 14 | "limit": 15.0, 15 | "startPeriod": 1800 16 | }, 17 | { 18 | "limit": 14.0, 19 | "startPeriod": 2700 20 | } 21 | ], 22 | "duration": 3600, 23 | "startSchedule": "2024-01-01T08:00:00Z" 24 | }, 25 | "recurrencyKind": "Daily", 26 | "stackLevel": 5, 27 | "validFrom": "2024-01-01T12:00:00Z", 28 | "validTo": "2024-02-01T12:00:00Z" 29 | } 30 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/Recurring_Daily_302_phase_limit.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 302, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 16.0, 11 | "numberPhases": 1, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 15.0, 16 | "numberPhases": 1, 17 | "startPeriod": 1800 18 | }, 19 | { 20 | "limit": 14.0, 21 | "numberPhases": 3, 22 | "startPeriod": 2700 23 | } 24 | ], 25 | "duration": 3600, 26 | "startSchedule": "2024-01-01T08:00:00Z" 27 | }, 28 | "recurrencyKind": "Daily", 29 | "stackLevel": 5, 30 | "validFrom": "2024-01-01T12:00:00Z", 31 | "validTo": "2024-02-01T12:00:00Z" 32 | } 33 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/Relative_302_phase_limit.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 302, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 16.0, 11 | "numberPhases": 3, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 15.0, 16 | "numberPhases": 1, 17 | "startPeriod": 1800 18 | }, 19 | { 20 | "limit": 14.0, 21 | "numberPhases": 3, 22 | "startPeriod": 2700 23 | } 24 | ], 25 | "duration": 3600 26 | }, 27 | "stackLevel": 5, 28 | "validFrom": "2024-01-01T12:00:00Z", 29 | "validTo": "2025-01-01T14:00:00Z" 30 | } 31 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/Relative_303.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 301, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "A", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 16.0, 10 | "startPeriod": 0 11 | }, 12 | { 13 | "limit": 15.0, 14 | "startPeriod": 1800 15 | }, 16 | { 17 | "limit": 14.0, 18 | "startPeriod": 2700 19 | } 20 | ], 21 | "duration": 3600 22 | }, 23 | "stackLevel": 5, 24 | "validFrom": "2024-01-01T12:00:00Z", 25 | "validTo": "2025-01-01T14:00:00Z" 26 | } 27 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TXDefaultProfile_25_Watt.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 25, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "W", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 12420.0, 11 | "startPeriod": 0 12 | }, 13 | { 14 | "limit": 8280.0, 15 | "startPeriod": 300 16 | }, 17 | { 18 | "limit": 6210.0, 19 | "startPeriod": 600 20 | }, 21 | { 22 | "limit": 4140.0, 23 | "startPeriod": 900 24 | }, 25 | { 26 | "limit": 2070.0, 27 | "startPeriod": 1200 28 | } 29 | ], 30 | "duration": 3600, 31 | "minChargingRate": 0.0 32 | }, 33 | "stackLevel": 0 34 | } 35 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_01.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 1, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "W", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 2000.0, 10 | "numberPhases": 1, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 1080, 15 | "minChargingRate": 0.0, 16 | "startSchedule": "2024-01-17T18:00:00.000Z" 17 | }, 18 | "recurrencyKind": "Daily", 19 | "stackLevel": 1 20 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_100.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 100, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "W", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 11000.0, 10 | "numberPhases": 3, 11 | "startPeriod": 0 12 | }, 13 | { 14 | "limit": 6000.0, 15 | "numberPhases": 3, 16 | "startPeriod": 28800 17 | }, 18 | { 19 | "limit": 12000.0, 20 | "numberPhases": 3, 21 | "startPeriod": 72000 22 | } 23 | ], 24 | "duration": 86400, 25 | "minChargingRate": 0.0, 26 | "startSchedule": "2023-01-17T17:00:00.000Z" 27 | }, 28 | "recurrencyKind": "Daily", 29 | "stackLevel": 0 30 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_2kw_17-20.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 10, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "W", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 2000.0, 10 | "numberPhases": 1, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 1080, 15 | "minChargingRate": 0.0, 16 | "startSchedule": "2024-01-17T17:00:00.000Z" 17 | }, 18 | "recurrencyKind": "Daily", 19 | "stackLevel": 1 20 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_401.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 401, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 16.0, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 300, 15 | "startSchedule": "2024-01-01T08:00:00Z" 16 | }, 17 | "recurrencyKind": "Daily", 18 | "stackLevel": 5 19 | } 20 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_402.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 402, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "id": 0, 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 12.0, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 300, 15 | "startSchedule": "2024-01-01T08:05:00Z" 16 | }, 17 | "recurrencyKind": "Daily", 18 | "stackLevel": 5 19 | } 20 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_Absolute_Daily_2kw_1080.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 11, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "W", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 2000.0, 10 | "numberPhases": 1, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 1080, 15 | "minChargingRate": 0.0, 16 | "startSchedule": "2024-01-17T17:00:00.000Z" 17 | }, 18 | "recurrencyKind": "Daily", 19 | "stackLevel": 1 20 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxDefaultProfile_no_chargingRateUnit.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 1, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": { 6 | "chargingSchedulePeriod": [ 7 | { 8 | "limit": 2000.0, 9 | "numberPhases": 1, 10 | "startPeriod": 0 11 | } 12 | ], 13 | "duration": 1080, 14 | "minChargingRate": 0.0, 15 | "startSchedule": "2024-01-17T17:00:00.000Z" 16 | }, 17 | "recurrencyKind": "Daily", 18 | "stackLevel": 1 19 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxProfile_02.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 2, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "W", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 2000.0, 10 | "numberPhases": 1, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 1080, 15 | "minChargingRate": 0.0, 16 | "startSchedule": "2024-01-17T18:04:00.000Z" 17 | }, 18 | "recurrencyKind": "Daily", 19 | "stackLevel": 2 20 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v16/json/TxProfile_03_Absolute.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileId": 3, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": { 6 | "chargingRateUnit": "W", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 2000.0, 10 | "numberPhases": 1, 11 | "startPeriod": 0 12 | } 13 | ], 14 | "duration": 1080, 15 | "minChargingRate": 0.0, 16 | "startSchedule": "2024-01-17T18:04:00.000Z" 17 | }, 18 | "recurrencyKind": "Daily", 19 | "stackLevel": 2 20 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_include_directories(libocpp_unit_tests PUBLIC 2 | mocks 3 | ${CMAKE_CURRENT_SOURCE_DIR}) 4 | 5 | target_sources(libocpp_unit_tests PRIVATE 6 | device_model_test_helper.cpp 7 | smart_charging_test_utils.cpp 8 | test_charge_point.cpp 9 | test_database_handler.cpp 10 | test_database_migration_files.cpp 11 | test_device_model_storage_sqlite.cpp 12 | test_notify_report_requests_splitter.cpp 13 | test_ocsp_updater.cpp 14 | test_component_state_manager.cpp 15 | test_database_handler.cpp 16 | test_device_model.cpp 17 | test_init_device_model_db.cpp 18 | comparators.cpp 19 | test_message_queue.cpp 20 | test_composite_schedule.cpp 21 | test_profile.cpp 22 | ) 23 | 24 | # Copy the json files used for testing to the destination directory 25 | file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/json DESTINATION ${TEST_PROFILES_LOCATION_V2}) 26 | 27 | set(LIBOCPP_TESTS_V2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 28 | 29 | add_subdirectory(functional_blocks) 30 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/comparators.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | 6 | namespace testing::internal { 7 | 8 | bool operator==(const ::ocpp::CertificateHashDataType& a, const ::ocpp::CertificateHashDataType& b) { 9 | return a.serialNumber == b.serialNumber && a.issuerKeyHash == b.issuerKeyHash && 10 | a.issuerNameHash == b.issuerNameHash && a.hashAlgorithm == b.hashAlgorithm; 11 | } 12 | bool operator==(const ::ocpp::v2::GetCertificateStatusRequest& a, const ::ocpp::v2::GetCertificateStatusRequest& b) { 13 | return a.ocspRequestData.serialNumber == b.ocspRequestData.serialNumber && 14 | a.ocspRequestData.issuerKeyHash == b.ocspRequestData.issuerKeyHash && 15 | a.ocspRequestData.issuerNameHash == b.ocspRequestData.issuerNameHash && 16 | a.ocspRequestData.hashAlgorithm == b.ocspRequestData.hashAlgorithm && 17 | a.ocspRequestData.responderURL == b.ocspRequestData.responderURL; 18 | } 19 | 20 | } // namespace testing::internal 21 | 22 | namespace ocpp::v2 { 23 | 24 | bool operator==(const ChargingProfile& a, const ChargingProfile& b) { 25 | return a.chargingProfileKind == b.chargingProfileKind && a.chargingProfilePurpose == b.chargingProfilePurpose && 26 | a.id == b.id && a.stackLevel == b.stackLevel; 27 | } 28 | } // namespace ocpp::v2 -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/comparators.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #ifndef TESTS_OCPP_COMPARATORS_H 5 | #define TESTS_OCPP_COMPARATORS_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace testing::internal { 12 | 13 | bool operator==(const ::ocpp::CertificateHashDataType& a, const ::ocpp::CertificateHashDataType& b); 14 | bool operator==(const ::ocpp::v2::GetCertificateStatusRequest& a, const ::ocpp::v2::GetCertificateStatusRequest& b); 15 | 16 | } // namespace testing::internal 17 | 18 | namespace ocpp::v2 { 19 | 20 | bool operator==(const ChargingProfile& a, const ChargingProfile& b); 21 | 22 | } // namespace ocpp::v2 23 | 24 | #endif // TESTS_OCPP_COMPARATORS_H 25 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/OCCT_TC_K_41_CS/0/id1-ChargingStationMaxProfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "ChargingStationMaxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 10.000000, 11 | "numberPhases": 3, 12 | "startPeriod": 0 13 | } 14 | ], 15 | "duration": 86404, 16 | "id": 1, 17 | "startSchedule": "2024-08-21T12:24:36Z" 18 | } 19 | ], 20 | "stackLevel": 0 21 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/OCCT_TC_K_41_CS/1/id2-TxDefaultProfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "chargingRateUnit": "A", 8 | "chargingSchedulePeriod": [ 9 | { 10 | "limit": 6.000000, 11 | "numberPhases": 3, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 10.000000, 16 | "numberPhases": 3, 17 | "startPeriod": 60 18 | }, 19 | { 20 | "limit": 8.000000, 21 | "numberPhases": 3, 22 | "startPeriod": 120 23 | }, 24 | { 25 | "limit": 15.000000, 26 | "numberPhases": 3, 27 | "startPeriod": 180 28 | }, 29 | { 30 | "limit": 8.000000, 31 | "numberPhases": 3, 32 | "startPeriod": 260 33 | } 34 | ], 35 | "duration": 304, 36 | "id": 1, 37 | "startSchedule": "2024-08-21T12:24:36Z" 38 | } 39 | ], 40 | "stackLevel": 0, 41 | "validFrom": "2024-08-21T12:24:36Z", 42 | "validTo": "2024-08-21T12:31:25Z" 43 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/OCCT_TC_K_41_CS/1/id2-TxProfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "chargingProfileKind": "Absolute", 3 | "chargingProfilePurpose": "TxProfile", 4 | "chargingSchedule": [ 5 | { 6 | "chargingRateUnit": "A", 7 | "chargingSchedulePeriod": [ 8 | { 9 | "limit": 8.000000, 10 | "numberPhases": 3, 11 | "startPeriod": 0 12 | }, 13 | { 14 | "limit": 11.000000, 15 | "numberPhases": 3, 16 | "startPeriod": 50 17 | }, 18 | { 19 | "limit": 16.000000, 20 | "numberPhases": 3, 21 | "startPeriod": 140 22 | }, 23 | { 24 | "limit": 6.000000, 25 | "numberPhases": 3, 26 | "startPeriod": 200 27 | }, 28 | { 29 | "limit": 12.000000, 30 | "numberPhases": 3, 31 | "startPeriod": 240 32 | } 33 | ], 34 | "duration": 264, 35 | "id": 1, 36 | "startSchedule": "2024-08-21T12:24:36Z" 37 | } 38 | ], 39 | "id": 2, 40 | "stackLevel": 0, 41 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 42 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/OCCT_TC_K_41_CS/README.md: -------------------------------------------------------------------------------- 1 | # OCCT K08 Test Case #TC_K_41_CS 2 | 3 | This Composite Schedule test scenario is based on the OCTT integration test 4 | suite TC_K_41_CS test. It is compromised of three Profiles: 5 | 6 | - Absolute ChargingStationMaxProfile with a duration of 86404 and one 7 | chargingSchedulePeriod. 8 | - Absolute TxDefaultProfile with a duration of 304 and 5 periods. 9 | - Absolute TxProfile with a duration of 264 and 5 periods. 10 | 11 | All have a stackLevel of 0. 12 | 13 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Sample Smart Charging Profiles for Testing 3 | 4 | A collection of JSON Profile files used for testing different Smart Charging 5 | scenarios. 6 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/baseline/README.md: -------------------------------------------------------------------------------- 1 | # Baseline Profiles 2 | 3 | Profiles created to use as a baseline for testing Composite Schedule scenarios. 4 | The goal was to use actual Profiles from the standard as a baseline for Unit 5 | and Integration Testing via tools such as 6 | [Appenzell](https://github.com/US-JOET/appenzell). 7 | 8 | ## Profiles 9 | 10 | `TxProfile_100.json` is based on the example profile on page 240 of the 11 | `OCPP-2.0.1_part2_specification_edition2` document. The only substantial change 12 | has been to change the 3rd `ChargingSchedulePeriod` limit to 12,000 so that it 13 | can be more easily differentiated from the first period with a limit of 11,000. 14 | Since it has a Stack Level of 0, any profile with a higher one will take 15 | precedence. 16 | 17 | `TxProfile_1.json` is based on the example profile on page 241 of the 18 | `OCPP-2.0.1_part2_specification_edition2` document. With a Stack Level of 1, 19 | any overlapping `ChargingSchedulePeriods` will take precedence. 20 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/baseline/TxProfile_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "chargingProfilePurpose": "TxProfile", 4 | "chargingProfileKind": "Recurring", 5 | "recurrencyKind": "Daily", 6 | "chargingSchedule": [ 7 | { 8 | "id": 0, 9 | "chargingRateUnit": "W", 10 | "chargingSchedulePeriod": [ 11 | { 12 | "limit": 2000.0, 13 | "numberPhases": 1, 14 | "startPeriod": 0 15 | } 16 | ], 17 | "duration": 1080, 18 | "minChargingRate": 0.0, 19 | "startSchedule": "2024-01-17T18:00:00.000Z" 20 | } 21 | ], 22 | "stackLevel": 1, 23 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 24 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/baseline/TxProfile_100.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 100, 3 | "stackLevel": 0, 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingProfileKind": "Recurring", 6 | "recurrencyKind": "Daily", 7 | "chargingSchedule": [ 8 | { 9 | "id": 1, 10 | "chargingRateUnit": "W", 11 | "chargingSchedulePeriod": [ 12 | { 13 | "limit": 11000.0, 14 | "numberPhases": 3, 15 | "startPeriod": 0 16 | }, 17 | { 18 | "limit": 6000.0, 19 | "numberPhases": 3, 20 | "startPeriod": 28800 21 | }, 22 | { 23 | "limit": 12000.0, 24 | "numberPhases": 3, 25 | "startPeriod": 72000 26 | } 27 | ], 28 | "duration": 86400, 29 | "minChargingRate": 0.0, 30 | "startSchedule": "2023-01-17T17:00:00.000Z" 31 | } 32 | ], 33 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 34 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/case_one/README.md: -------------------------------------------------------------------------------- 1 | # Case One 2 | 3 | Case one is a variation of the baseline scenario but with `TxProfile_1.json` 4 | being `Absolute` instead of `Recurring`. It was designed to track down a 5 | potential defect that was being tracked in the earlier version of the code. 6 | See [Issue #609](https://github.com/EVerest/libocpp/issues/609). 7 | 8 | The following tests are designed to isolate the issue: 9 | 10 | * K08_CalculateCompositeSchedule_DemoCaseOne_17th 11 | * K08_CalculateCompositeSchedule_DemoCaseOne_19th 12 | 13 | In the first the time window matches both profiles, while in the second it 14 | only matches the `Recurring` profile. 15 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/case_one/TxProfile_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 1080, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T18:00:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 1, 22 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 23 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/case_one/TxProfile_100.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 100, 3 | "stackLevel": 0, 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingProfileKind": "Recurring", 6 | "recurrencyKind": "Daily", 7 | "chargingSchedule": [ 8 | { 9 | "id": 1, 10 | "chargingRateUnit": "W", 11 | "chargingSchedulePeriod": [ 12 | { 13 | "limit": 11000.0, 14 | "numberPhases": 1, 15 | "startPeriod": 0 16 | }, 17 | { 18 | "limit": 6000.0, 19 | "numberPhases": 1, 20 | "startPeriod": 28800 21 | }, 22 | { 23 | "limit": 12000.0, 24 | "numberPhases": 1, 25 | "startPeriod": 72000 26 | } 27 | ], 28 | "duration": 86400, 29 | "minChargingRate": 0.0, 30 | "startSchedule": "2023-01-17T17:00:00.000Z" 31 | } 32 | ], 33 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 34 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/external/0/ChargingStationMaxProfile_2000.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2000, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "ChargingStationMaxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 3600, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T00:00:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 0 22 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/external/1/TXProfile_2001.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2001, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 10.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 3600, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T23:00:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 1, 22 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 23 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/external/README.md: -------------------------------------------------------------------------------- 1 | # External 2 | 3 | This scenario layers TxProfiles on top of a ChargingStationExternalConstraints that has limits for all 24 hours. 4 | 5 | Used by: 6 | 7 | * `K08_CalculateCompositeSchedule_ExternalOverridesHigherLimits` 8 | * `K08_CalculateCompositeSchedule_ExternalOverridenByLowerLimits` 9 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/grid/README.md: -------------------------------------------------------------------------------- 1 | # Grid Profile 2 | 3 | This is a foundational Profile designed to act as a sort of temporal grid paper 4 | for testing out different Profile combinations. Each charging schedule period 5 | is exactly 1 hour apart, with the limit increasing by 1 every hour. Since it 6 | has a Stack Level of 0, any Profile with a higher Stack Level will take 7 | precidence over it. 8 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/layered/README.md: -------------------------------------------------------------------------------- 1 | # Layered 2 | 3 | This scenario layers an Absolute Profile on top of the Grid Profile in order to 4 | provide opportunities to test how absolute Profiles handle different time 5 | windows. 6 | 7 | Used by: 8 | 9 | * `K08_CalculateCompositeSchedule_LayeredTest_SameStartTime` 10 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/layered/TXProfile_single.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2000, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 1080, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T18:04:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 1, 22 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 23 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/layered_recurring/README.md: -------------------------------------------------------------------------------- 1 | # Layered Recurring 2 | 3 | This scenario matches Layered except now the higher Profile is recurring. 4 | 5 | Used by: 6 | 7 | * `K08_CalculateCompositeSchedule_LayeredRecurringTest_PreviousStartTime` 8 | * `K08_CalculateCompositeSchedule_LayeredRecurringTest_FutureStartTime` 9 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/layered_recurring/TXProfile_single.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2000, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 1080, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T18:04:00.000Z" 19 | } 20 | ], 21 | "recurrencyKind": "Daily", 22 | "stackLevel": 1, 23 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 24 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/max/1/TXProfile_2000.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2000, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 3600, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T00:00:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 0, 22 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 23 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/max/1/TXProfile_2001.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2001, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 10.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 3600, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T23:00:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 1, 22 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 23 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/max/README.md: -------------------------------------------------------------------------------- 1 | # Max 2 | 3 | This scenario layers TxProfiles on top of a ChargingStationMaxProfile that has 4 | limits for all 24 hours. 5 | 6 | Used by: 7 | 8 | * `K08_CalculateCompositesSchedule_MaxOverridesHigherLimits` 9 | * `K08_CalculateCompositeSchedule_MaxOverridenByLowerLimits` 10 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/no_gap/TxDefaultProfile_401.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 401, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 16.0, 12 | "startPeriod": 0 13 | } 14 | ], 15 | "duration": 300, 16 | "startSchedule": "2024-01-01T08:00:00Z" 17 | } 18 | ], 19 | "recurrencyKind": "Daily", 20 | "stackLevel": 5 21 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/no_gap/TxDefaultProfile_402.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 402, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 12.0, 12 | "startPeriod": 0 13 | } 14 | ], 15 | "duration": 300, 16 | "startSchedule": "2024-01-01T08:05:00Z" 17 | } 18 | ], 19 | "recurrencyKind": "Daily", 20 | "stackLevel": 5 21 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/relative/README.md: -------------------------------------------------------------------------------- 1 | # Layered Relative 2 | 3 | This scenario matches Layered except now the higher Profile is Relative. 4 | 5 | Used by: 6 | 7 | * `K08_CalculateCompositeSchedule_RelativeProfile_minutia` 8 | * `K08_CalculateCompositeSchedule_RelativeProfile_e2e` 9 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/relative/TxProfile_relative.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 66, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 3601, 17 | "minChargingRate": 0.0 18 | } 19 | ], 20 | "stackLevel": 1, 21 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 22 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Absolute_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "duration": 3600, 24 | "startSchedule": "2024-01-01T12:02:00Z" 25 | } 26 | ], 27 | "stackLevel": 5, 28 | "validFrom": "2024-01-01T12:00:00Z", 29 | "validTo": "2024-01-01T14:00:00Z" 30 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Absolute_NoDuration_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "startSchedule": "2024-01-01T12:02:00Z" 24 | } 25 | ], 26 | "stackLevel": 5, 27 | "validFrom": "2024-01-01T12:00:00Z", 28 | "validTo": "2024-01-01T14:00:00Z" 29 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/ChargingStationMaxProfile_24_Ampere.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 24, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "ChargingStationMaxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 16.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | }, 15 | { 16 | "limit": 16.0, 17 | "numberPhases": 3, 18 | "startPeriod": 3600 19 | }, 20 | { 21 | "limit": 10.0, 22 | "numberPhases": 1, 23 | "startPeriod": 7200 24 | }, 25 | { 26 | "limit": 10.0, 27 | "numberPhases": 3, 28 | "startPeriod": 10800 29 | } 30 | ], 31 | "duration": 86400, 32 | "minChargingRate": 0.0, 33 | "startSchedule": "2024-01-17T00:00:00.000Z" 34 | } 35 | ], 36 | "recurrencyKind": "Daily", 37 | "stackLevel": 0 38 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/ChargingStationMaxProfile_401.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 24, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "ChargingStationMaxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 24.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | }, 15 | { 16 | "limit": 28.0, 17 | "numberPhases": 1, 18 | "startPeriod": 900 19 | }, 20 | { 21 | "limit": 30.0, 22 | "numberPhases": 1, 23 | "startPeriod": 1800 24 | }, 25 | { 26 | "limit": 32.0, 27 | "numberPhases": 1, 28 | "startPeriod": 2700 29 | } 30 | ], 31 | "duration": 86400, 32 | "minChargingRate": 0.0, 33 | "startSchedule": "2024-01-17T08:00:00.000Z" 34 | } 35 | ], 36 | "recurrencyKind": "Daily", 37 | "stackLevel": 0 38 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/ProfileA.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 6000 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 12000 21 | } 22 | ], 23 | "duration": 3600, 24 | "startSchedule": "2024-01-01T12:02:00Z" 25 | } 26 | ], 27 | "stackLevel": 5, 28 | "validFrom": "2024-01-01T12:00:00Z", 29 | "validTo": "2024-01-01T14:00:00Z", 30 | "transactionId": "g1522902-1170-416f-8e43-9e3bce28fab7" 31 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/README.md: -------------------------------------------------------------------------------- 1 | # Profiles for tests only requiring a single one 2 | 3 | The following Profiles are all serialized JSON versions of ones instantiated 4 | directly in the original `tests/lib/ocpp/v16/profile_testsA.cpp` OCPP 1.6 5 | versions of the tests. 6 | 7 | * singles/Absolute_301.json 8 | * singles/Absolute_NoDuration_301.json 9 | * singles/Relative_301.json 10 | * singles/Relative_NoDuration_301.json 11 | * singles/Recurring_Daily_301.json 12 | * singles/Recurring_Daily_NoDuration_301.json 13 | * singles/Recurring_Weekly_301.json 14 | * singles/Recurring_Weekly_NoDuration_301.json 15 | 16 | The goal is to clearly isolate out each profile, and simplify as much as 17 | possible the writing of the tests by leveraging 18 | [GoogleTests's parameter based testing feature](https://google.github.io/googletest/reference/testing.html#TEST_P), 19 | greatly reducing the amount of boiler plate needed for the tests. 20 | 21 | * singles/TXProfile_Absolute_Start18-04.json 22 | 23 | This profile is used for a specific test scenario where any actual Profile 24 | ChargingSchedulePeriod happens after the time window of the request. 25 | 26 | * singles/TxProfile_CONCERNING_overlapping_periods.json 27 | 28 | This is a Profile created with a vector of `ChargingSchedulePeriods` that is 29 | longer in duraction for a single day, but is recurring daily so that they 30 | will start to overlap after 24 hours. The idea is to create a Profile to test 31 | this sort of edge case. Right now there aren't any tests using it. 32 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Recurring_Daily_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 16.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 15.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 14.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "duration": 3600, 24 | "startSchedule": "2024-01-01T08:00:00Z" 25 | } 26 | ], 27 | "recurrencyKind": "Daily", 28 | "stackLevel": 5, 29 | "validFrom": "2024-01-01T12:00:00Z", 30 | "validTo": "2024-02-01T12:00:00Z" 31 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Recurring_Daily_302_phase_limit.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 302, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 16.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | }, 15 | { 16 | "limit": 15.0, 17 | "numberPhases": 1, 18 | "startPeriod": 1800 19 | }, 20 | { 21 | "limit": 14.0, 22 | "numberPhases": 3, 23 | "startPeriod": 2700 24 | } 25 | ], 26 | "duration": 3600, 27 | "startSchedule": "2024-01-01T08:00:00Z" 28 | } 29 | ], 30 | "recurrencyKind": "Daily", 31 | "stackLevel": 5, 32 | "validFrom": "2024-01-01T12:00:00Z", 33 | "validTo": "2024-02-01T12:00:00Z" 34 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Recurring_Daily_NoDuration_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "startSchedule": "2024-01-01T08:00:00Z" 24 | } 25 | ], 26 | "recurrencyKind": "Daily", 27 | "stackLevel": 5, 28 | "validFrom": "2024-01-01T12:00:00Z", 29 | "validTo": "2024-02-01T12:00:00Z" 30 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Recurring_Weekly_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "duration": 3600, 24 | "startSchedule": "2024-01-03T16:00:00Z" 25 | } 26 | ], 27 | "recurrencyKind": "Weekly", 28 | "stackLevel": 5, 29 | "validFrom": "2024-01-01T12:00:00Z", 30 | "validTo": "2024-02-01T12:00:00Z" 31 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Recurring_Weekly_NoDuration_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Recurring", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "startSchedule": "2024-01-03T16:00:00Z" 24 | } 25 | ], 26 | "recurrencyKind": "Weekly", 27 | "stackLevel": 5, 28 | "validFrom": "2024-01-01T12:00:00Z", 29 | "validTo": "2024-02-01T12:00:00Z" 30 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Relative_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "duration": 3600 24 | } 25 | ], 26 | "stackLevel": 5, 27 | "validFrom": "2024-01-01T12:00:00Z", 28 | "validTo": "2024-01-01T14:00:00Z" 29 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Relative_302_phase_limit.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 302, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 16.0, 12 | "numberPhases": 3, 13 | "startPeriod": 0 14 | }, 15 | { 16 | "limit": 15.0, 17 | "numberPhases": 1, 18 | "startPeriod": 1800 19 | }, 20 | { 21 | "limit": 14.0, 22 | "numberPhases": 3, 23 | "startPeriod": 2700 24 | } 25 | ], 26 | "duration": 3600 27 | } 28 | ], 29 | "stackLevel": 5, 30 | "validFrom": "2024-01-01T12:00:00Z", 31 | "validTo": "2025-01-01T14:00:00Z" 32 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Relative_303.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 16.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 15.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 14.0, 20 | "startPeriod": 2700 21 | } 22 | ], 23 | "duration": 3600 24 | } 25 | ], 26 | "stackLevel": 5, 27 | "validFrom": "2024-01-01T12:00:00Z", 28 | "validTo": "2025-01-01T14:00:00Z" 29 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Relative_MultipleChargingSchedules.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 66, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 11.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | }, 15 | { 16 | "limit": 12.0, 17 | "numberPhases": 1, 18 | "startPeriod": 10 19 | } 20 | ], 21 | "duration": 19, 22 | "minChargingRate": 0.0 23 | }, 24 | { 25 | "id": 1, 26 | "chargingRateUnit": "W", 27 | "chargingSchedulePeriod": [ 28 | { 29 | "limit": 31.0, 30 | "numberPhases": 1, 31 | "startPeriod": 0 32 | }, 33 | { 34 | "limit": 31.0, 35 | "numberPhases": 1, 36 | "startPeriod": 8 37 | } 38 | ], 39 | "duration": 37, 40 | "minChargingRate": 0.0 41 | }, 42 | { 43 | "id": 2, 44 | "chargingRateUnit": "W", 45 | "chargingSchedulePeriod": [ 46 | { 47 | "limit": 71.0, 48 | "numberPhases": 1, 49 | "startPeriod": 0 50 | } 51 | ], 52 | "duration": 79, 53 | "minChargingRate": 0.0 54 | } 55 | ], 56 | "stackLevel": 1, 57 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 58 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/Relative_NoDuration_301.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 301, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "A", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 32.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 31.0, 16 | "startPeriod": 1800 17 | }, 18 | { 19 | "limit": 30.0, 20 | "startPeriod": 2700 21 | } 22 | ] 23 | } 24 | ], 25 | "stackLevel": 5, 26 | "validFrom": "2024-01-01T12:00:00Z", 27 | "validTo": "2024-01-01T14:00:00Z" 28 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/TXDefaultProfile_25_Watt.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 25, 3 | "chargingProfileKind": "Relative", 4 | "chargingProfilePurpose": "TxDefaultProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 12420.0, 12 | "startPeriod": 0 13 | }, 14 | { 15 | "limit": 8280.0, 16 | "startPeriod": 300 17 | }, 18 | { 19 | "limit": 6210.0, 20 | "startPeriod": 600 21 | }, 22 | { 23 | "limit": 4140.0, 24 | "startPeriod": 900 25 | }, 26 | { 27 | "limit": 2070.0, 28 | "startPeriod": 1200 29 | } 30 | ], 31 | "duration": 3600, 32 | "minChargingRate": 0.0 33 | } 34 | ], 35 | "stackLevel": 0 36 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/TXProfile_Absolute_Start18-04.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 2000, 3 | "chargingProfileKind": "Absolute", 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingSchedule": [ 6 | { 7 | "id": 0, 8 | "chargingRateUnit": "W", 9 | "chargingSchedulePeriod": [ 10 | { 11 | "limit": 2000.0, 12 | "numberPhases": 1, 13 | "startPeriod": 0 14 | } 15 | ], 16 | "duration": 1080, 17 | "minChargingRate": 0.0, 18 | "startSchedule": "2024-01-17T18:04:00.000Z" 19 | } 20 | ], 21 | "stackLevel": 1, 22 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 23 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/json/singles/TxProfile_CONCERNING_overlapping_periods.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 100, 3 | "stackLevel": 0, 4 | "chargingProfilePurpose": "TxProfile", 5 | "chargingProfileKind": "Recurring", 6 | "recurrencyKind": "Daily", 7 | "chargingSchedule": [ 8 | { 9 | "id": 1, 10 | "chargingRateUnit": "W", 11 | "chargingSchedulePeriod": [ 12 | { 13 | "limit": 11000.0, 14 | "numberPhases": 3, 15 | "startPeriod": 0 16 | }, 17 | { 18 | "limit": 6000.0, 19 | "numberPhases": 3, 20 | "startPeriod": 28800 21 | }, 22 | { 23 | "limit": 12000.0, 24 | "numberPhases": 3, 25 | "startPeriod": 72100 26 | }, 27 | { 28 | "limit": 12005.0, 29 | "numberPhases": 3, 30 | "startPeriod": 73010 31 | }, 32 | { 33 | "limit": 12010.0, 34 | "numberPhases": 3, 35 | "startPeriod": 74020 36 | } 37 | ], 38 | "duration": 86400, 39 | "minChargingRate": 0.0, 40 | "startSchedule": "2023-01-17T17:00:00.000Z" 41 | } 42 | ], 43 | "transactionId": "f1522902-1170-416f-8e43-9e3bce28fde7" 44 | } -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/mocks/connectivity_manager_mock.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include "gmock/gmock.h" 7 | 8 | #include 9 | 10 | namespace ocpp::v2 { 11 | class ConnectivityManagerMock : public ConnectivityManagerInterface { 12 | public: 13 | MOCK_METHOD(void, set_websocket_authorization_key, (const std::string& authorization_key)); 14 | MOCK_METHOD(void, set_websocket_connection_options, (const WebsocketConnectionOptions& connection_options)); 15 | MOCK_METHOD(void, set_websocket_connection_options_without_reconnect, ()); 16 | MOCK_METHOD(void, set_websocket_connected_callback, (WebsocketConnectionCallback callback)); 17 | MOCK_METHOD(void, set_websocket_disconnected_callback, (WebsocketConnectionCallback callback)); 18 | MOCK_METHOD(void, set_websocket_connection_failed_callback, (WebsocketConnectionFailedCallback callback)); 19 | MOCK_METHOD(void, set_configure_network_connection_profile_callback, 20 | (ConfigureNetworkConnectionProfileCallback callback)); 21 | MOCK_METHOD(std::optional, get_network_connection_profile, 22 | (const int32_t configuration_slot), (const)); 23 | MOCK_METHOD(std::optional, get_priority_from_configuration_slot, (const int configuration_slot), (const)); 24 | MOCK_METHOD(const std::vector&, get_network_connection_slots, (), (const)); 25 | MOCK_METHOD(bool, is_websocket_connected, ()); 26 | MOCK_METHOD(void, connect, (std::optional network_profile_slot)); 27 | MOCK_METHOD(void, disconnect, ()); 28 | MOCK_METHOD(bool, send_to_websocket, (const std::string& message)); 29 | MOCK_METHOD(void, on_network_disconnected, (OCPPInterfaceEnum ocpp_interface)); 30 | MOCK_METHOD(void, on_charging_station_certificate_changed, ()); 31 | MOCK_METHOD(void, confirm_successful_connection, ()); 32 | }; 33 | } // namespace ocpp::v2 34 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/mocks/database_handler_fake.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include "database_handler_mock.hpp" 7 | #include 8 | 9 | namespace ocpp::v2 { 10 | class DatabaseHandlerFake : public DatabaseHandlerMock { 11 | DatabaseHandler handler; 12 | 13 | public: 14 | DatabaseHandlerFake(std::unique_ptr database, 15 | const fs::path& sql_migration_files_path) : 16 | handler(std::move(database), sql_migration_files_path) { 17 | 18 | // Add more wrappers here as needed 19 | ON_CALL(*this, new_statement).WillByDefault([this](const std::string& sql) { 20 | return handler.new_statement(sql); 21 | }); 22 | } 23 | 24 | void open_connection() { 25 | this->handler.open_connection(); 26 | } 27 | }; 28 | } // namespace ocpp::v2 -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/mocks/device_model_storage_interface_mock.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | #include "ocpp/v2/device_model_storage_interface.hpp" 9 | 10 | namespace ocpp::v2 { 11 | class DeviceModelStorageMock : public DeviceModelStorageInterface { 12 | public: 13 | MOCK_METHOD(DeviceModelMap, get_device_model, ()); 14 | MOCK_METHOD(std::optional, get_variable_attribute, 15 | (const Component&, const Variable&, const AttributeEnum&)); 16 | MOCK_METHOD(std::vector, get_variable_attributes, 17 | (const Component&, const Variable&, const std::optional&)); 18 | MOCK_METHOD(SetVariableStatusEnum, set_variable_attribute_value, 19 | (const Component&, const Variable&, const AttributeEnum&, const std::string&, const std::string&)); 20 | MOCK_METHOD(std::optional, set_monitoring_data, 21 | (const SetMonitoringData&, const VariableMonitorType)); 22 | MOCK_METHOD(std::vector, get_monitoring_data, 23 | (const std::vector&, const Component&, const Variable&)); 24 | MOCK_METHOD(ClearMonitoringStatusEnum, clear_variable_monitor, (int, bool)); 25 | MOCK_METHOD(int32_t, clear_custom_variable_monitors, ()); 26 | MOCK_METHOD(void, check_integrity, ()); 27 | MOCK_METHOD(bool, update_monitoring_reference, (int32_t monitor_id, const std::string& reference_value), 28 | (override)); 29 | }; 30 | } // namespace ocpp::v2 31 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/mocks/message_dispatcher_mock.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include "gmock/gmock.h" 7 | 8 | #include 9 | 10 | using namespace ocpp::v2; 11 | 12 | class MockMessageDispatcher : public ocpp::MessageDispatcherInterface { 13 | public: 14 | MOCK_METHOD(void, dispatch_call, (const json& call, bool triggered), (override)); 15 | MOCK_METHOD(std::future>, dispatch_call_async, 16 | (const json& call, bool triggered), (override)); 17 | MOCK_METHOD(void, dispatch_call_result, (const json& call_result), (override)); 18 | MOCK_METHOD(void, dispatch_call_error, (const json& call_error), (override)); 19 | }; 20 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/mocks/ocsp_updater_mock.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include "gmock/gmock.h" 7 | 8 | #include 9 | 10 | namespace ocpp::v2 { 11 | class OcspUpdaterMock : public OcspUpdaterInterface { 12 | public: 13 | virtual ~OcspUpdaterMock() { 14 | } 15 | MOCK_METHOD(void, start, ()); 16 | MOCK_METHOD(void, stop, ()); 17 | MOCK_METHOD(void, trigger_ocsp_cache_update, ()); 18 | }; 19 | } // namespace ocpp::v2 20 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/mocks/smart_charging_mock.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include "gmock/gmock.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace ocpp::v2 { 12 | class SmartChargingMock : public SmartChargingInterface { 13 | public: 14 | MOCK_METHOD(void, handle_message, (const ocpp::EnhancedMessage& message)); 15 | MOCK_METHOD(std::vector, get_all_composite_schedules, 16 | (const int32_t duration, const ChargingRateUnitEnum& unit)); 17 | MOCK_METHOD(void, delete_transaction_tx_profiles, (const std::string& transaction_id)); 18 | MOCK_METHOD(SetChargingProfileResponse, conform_validate_and_add_profile, 19 | (ChargingProfile & profile, int32_t evse_id, CiString<20> charging_limit_source, 20 | AddChargingProfileSource source_of_request)); 21 | MOCK_METHOD(ProfileValidationResultEnum, conform_and_validate_profile, 22 | (ChargingProfile & profile, int32_t evse_id, AddChargingProfileSource source_of_request)); 23 | }; 24 | } // namespace ocpp::v2 25 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/stubs/timer/timer_stub.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | #include 6 | 7 | #include "timer_stub.hpp" 8 | 9 | static uint32_t stop_called_count; 10 | static uint32_t timeout_called_count; 11 | static uint32_t interval_called_count; 12 | static uint32_t at_called_count; 13 | static std::function callback; 14 | 15 | void timer_stub_stop_called(uint32_t called_count) { 16 | stop_called_count += called_count; 17 | } 18 | 19 | void timer_stub_timeout_called(uint32_t called_count) { 20 | timeout_called_count += called_count; 21 | } 22 | 23 | void timer_stub_interval_called(uint32_t called_count) { 24 | interval_called_count += called_count; 25 | } 26 | 27 | void timer_stub_at_called(uint32_t called_count) { 28 | at_called_count += called_count; 29 | } 30 | 31 | void timer_stub_set_callback(std::function callback_func) { 32 | callback = callback_func; 33 | } 34 | 35 | void timer_stub_reset_stop_called_count() { 36 | stop_called_count = 0; 37 | } 38 | 39 | void timer_stub_reset_timeout_called_count() { 40 | timeout_called_count = 0; 41 | } 42 | 43 | void timer_stub_reset_interval_called_count() { 44 | interval_called_count = 0; 45 | } 46 | 47 | void timer_stub_reset_at_called_count() { 48 | at_called_count = 0; 49 | } 50 | 51 | void timer_stub_reset_callback() { 52 | callback = nullptr; 53 | } 54 | 55 | uint32_t timer_stub_get_stop_called_count() { 56 | return stop_called_count; 57 | } 58 | 59 | uint32_t timer_stub_get_timeout_called_count() { 60 | return timeout_called_count; 61 | } 62 | 63 | uint32_t timer_stub_get_interval_called_count() { 64 | return interval_called_count; 65 | } 66 | 67 | uint32_t timer_stub_get_at_called_count() { 68 | return at_called_count; 69 | } 70 | 71 | std::function timer_stub_get_callback() { 72 | return callback; 73 | } 74 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/stubs/timer/timer_stub.hpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright Pionix GmbH and Contributors to EVerest 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | void timer_stub_stop_called(uint32_t called_count); 10 | void timer_stub_timeout_called(uint32_t called_count); 11 | void timer_stub_interval_called(uint32_t called_count); 12 | void timer_stub_at_called(uint32_t called_count); 13 | void timer_stub_set_callback(std::function callback_func); 14 | 15 | void timer_stub_reset_stop_called_count(); 16 | void timer_stub_reset_timeout_called_count(); 17 | void timer_stub_reset_interval_called_count(); 18 | void timer_stub_reset_at_called_count(); 19 | void timer_stub_reset_callback(); 20 | 21 | uint32_t timer_stub_get_stop_called_count(); 22 | uint32_t timer_stub_get_timeout_called_count(); 23 | uint32_t timer_stub_get_interval_called_count(); 24 | uint32_t timer_stub_get_at_called_count(); 25 | std::function timer_stub_get_callback(); 26 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/test_device_model_storage_sqlite.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace ocpp { 14 | namespace v2 { 15 | 16 | class DeviceModelStorageSQLiteTest : public ::testing::Test { 17 | protected: 18 | const std::string DATABASE_PATH = "file::memory:?cache=shared"; 19 | const std::string MIGRATION_FILES_PATH = "./resources/v2/device_model_migration_files"; 20 | const std::string CONFIGS_PATH = "./resources/config/v2/component_config"; 21 | DeviceModelTestHelper device_model_test_helper; 22 | 23 | public: 24 | DeviceModelStorageSQLiteTest() : device_model_test_helper(DATABASE_PATH, MIGRATION_FILES_PATH, CONFIGS_PATH) { 25 | } 26 | }; 27 | 28 | /// \brief Tests check_integrity does not raise error for valid database 29 | TEST_F(DeviceModelStorageSQLiteTest, test_check_integrity_valid) { 30 | DeviceModelStorageSqlite dm(DATABASE_PATH, "", "", false); 31 | 32 | EXPECT_NO_THROW(dm.check_integrity()); 33 | } 34 | 35 | /// \brief Tests check_integrity raises exception for invalid database 36 | TEST_F(DeviceModelStorageSQLiteTest, test_check_integrity_invalid) { 37 | 38 | device_model_test_helper.remove_variable_from_db("DisplayMessageCtrlr", std::nullopt, std::nullopt, std::nullopt, 39 | "NumberOfDisplayMessages", std::nullopt); 40 | 41 | DeviceModelStorageSqlite dm(DATABASE_PATH, "", "", false); 42 | 43 | EXPECT_NO_THROW(dm.check_integrity()); 44 | } 45 | 46 | } // namespace v2 47 | } // namespace ocpp 48 | -------------------------------------------------------------------------------- /tests/lib/ocpp/v2/test_message_queue.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace ocpp { 10 | 11 | namespace v2 { 12 | 13 | class ControlMessageV2Test : public ::testing::Test { 14 | 15 | protected: 16 | }; 17 | 18 | TEST_F(ControlMessageV2Test, test_is_transactional) { 19 | 20 | EXPECT_TRUE(is_transaction_message((ControlMessage{ 21 | Call{ 22 | v2::TransactionEventRequest{}}}.messageType))); 23 | 24 | EXPECT_TRUE(!is_transaction_message( 25 | ControlMessage{Call{v2::AuthorizeRequest{}}}.messageType)); 26 | } 27 | 28 | TEST_F(ControlMessageV2Test, test_is_transactional_update) { 29 | 30 | v2::TransactionEventRequest transaction_event_request{}; 31 | transaction_event_request.eventType = v2::TransactionEventEnum::Updated; 32 | 33 | EXPECT_TRUE((ControlMessage{Call{transaction_event_request}} 34 | .is_transaction_update_message())); 35 | 36 | transaction_event_request.eventType = v2::TransactionEventEnum::Started; 37 | EXPECT_TRUE(!(ControlMessage{Call{transaction_event_request}} 38 | .is_transaction_update_message())); 39 | 40 | transaction_event_request.eventType = v2::TransactionEventEnum::Ended; 41 | EXPECT_TRUE(!(ControlMessage{Call{transaction_event_request}} 42 | .is_transaction_update_message())); 43 | 44 | EXPECT_TRUE(!(ControlMessage{Call{v2::AuthorizeRequest{}}} 45 | .is_transaction_update_message())); 46 | } 47 | 48 | } // namespace v2 49 | } // namespace ocpp 50 | -------------------------------------------------------------------------------- /tests/resources/unittest_device_model.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EVerest/libocpp/7c9d31e94a1d3e86ee76a8d034997c7a02743223/tests/resources/unittest_device_model.db -------------------------------------------------------------------------------- /tests/resources/unittest_device_model_missing_required.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EVerest/libocpp/7c9d31e94a1d3e86ee76a8d034997c7a02743223/tests/resources/unittest_device_model_missing_required.db --------------------------------------------------------------------------------