├── examples └── ESP-IDF │ ├── components │ ├── ArduinoJson │ │ └── .gitkeep │ ├── ArduinoOcpp │ │ └── .gitkeep │ ├── mongoose │ │ └── .gitkeep │ ├── ArduinoOcppMongoose │ │ └── .gitkeep │ └── README.md │ ├── main │ ├── CMakeLists.txt │ ├── component.mk │ └── Kconfig.projbuild │ ├── Makefile │ ├── partitions.csv │ ├── CMakeLists.txt │ └── README.md ├── docs ├── img │ └── favicon.ico ├── stylesheets │ └── extra.css └── index.md ├── tests ├── catch2 │ └── catchMain.cpp ├── helpers │ ├── testHelper.h │ └── testHelper.cpp ├── ocppEngineLifecycle.cpp ├── benchmarks │ └── firmware_size │ │ ├── platformio.ini │ │ └── main.cpp └── Security.cpp ├── .gitignore ├── library.properties ├── src └── MicroOcpp │ ├── Model │ ├── Transactions │ │ ├── TransactionDefs.h │ │ └── TransactionDeserialize.h │ ├── Diagnostics │ │ └── DiagnosticsStatus.h │ ├── FirmwareManagement │ │ └── FirmwareStatus.h │ ├── Reset │ │ └── ResetDefs.h │ ├── Availability │ │ ├── ChangeAvailabilityStatus.h │ │ └── AvailabilityService.h │ ├── ConnectorBase │ │ ├── ConnectorsCommon.h │ │ ├── EvseId.h │ │ ├── ChargePointStatus.h │ │ ├── UnlockConnectorResult.h │ │ └── ChargePointErrorData.h │ ├── Heartbeat │ │ ├── HeartbeatService.h │ │ └── HeartbeatService.cpp │ ├── Metering │ │ ├── ReadingContext.h │ │ ├── MeteringService.h │ │ ├── MeterStore.h │ │ ├── SampledValue.cpp │ │ ├── MeterValue.h │ │ └── ReadingContext.cpp │ ├── RemoteControl │ │ ├── RemoteControlDefs.h │ │ └── RemoteControlService.h │ ├── Certificates │ │ ├── CertificateService.h │ │ ├── CertificateService.cpp │ │ ├── Certificate_c.h │ │ ├── CertificateMbedTLS.h │ │ └── Certificate_c.cpp │ ├── Authorization │ │ ├── IdToken.h │ │ ├── AuthorizationList.h │ │ ├── AuthorizationService.h │ │ └── AuthorizationData.h │ ├── Reservation │ │ ├── ReservationService.h │ │ └── Reservation.h │ └── Variables │ │ └── VariableContainer.h │ ├── Core │ ├── UuidUtils.h │ ├── ConfigurationContainerFlash.h │ ├── RequestCallbacks.h │ ├── OperationRegistry.h │ ├── Operation.cpp │ ├── FilesystemUtils.h │ ├── FtpMbedTLS.h │ ├── Context.h │ ├── OcppError.h │ ├── UuidUtils.cpp │ ├── Context.cpp │ ├── ConfigurationOptions.h │ ├── Configuration.h │ ├── ConfigurationKeyValue.h │ ├── ConfigurationContainer.h │ ├── ConfigurationContainer.cpp │ ├── Operation.h │ ├── FilesystemAdapter.h │ └── OperationRegistry.cpp │ ├── Operations │ ├── CiStrings.h │ ├── ClearCache.h │ ├── Heartbeat.h │ ├── DataTransfer.h │ ├── ClearChargingProfile.h │ ├── GetLocalListVersion.h │ ├── RemoteStopTransaction.h │ ├── TriggerMessage.h │ ├── UpdateFirmware.h │ ├── ChangeConfiguration.h │ ├── FirmwareStatusNotification.h │ ├── GetConfiguration.h │ ├── GetDiagnostics.h │ ├── DiagnosticsStatusNotification.h │ ├── ReserveNow.h │ ├── CancelReservation.h │ ├── DeleteCertificate.h │ ├── InstallCertificate.h │ ├── SendLocalList.h │ ├── GetBaseReport.h │ ├── SetChargingProfile.h │ ├── StartTransaction.h │ ├── NotifyReport.h │ ├── TransactionEvent.h │ ├── RequestStopTransaction.h │ ├── GetCompositeSchedule.h │ ├── RemoteStartTransaction.h │ ├── SecurityEventNotification.h │ ├── GetInstalledCertificateIds.h │ ├── BootNotification.h │ ├── RequestStartTransaction.h │ ├── GetLocalListVersion.cpp │ ├── StopTransaction.h │ ├── CancelReservation.cpp │ ├── ClearCache.cpp │ ├── Reset.h │ ├── MeterValues.h │ ├── DiagnosticsStatusNotification.cpp │ ├── DataTransfer.cpp │ ├── GetVariables.h │ ├── RemoteStopTransaction.cpp │ ├── SetVariables.h │ ├── SecurityEventNotification.cpp │ ├── Authorize.h │ ├── UpdateFirmware.cpp │ ├── ChangeAvailability.h │ ├── RequestStopTransaction.cpp │ ├── FirmwareStatusNotification.cpp │ ├── StatusNotification.h │ ├── Heartbeat.cpp │ ├── GetDiagnostics.cpp │ ├── UnlockConnector.h │ ├── CustomOperation.h │ ├── SendLocalList.cpp │ ├── RequestStartTransaction.cpp │ ├── GetBaseReport.cpp │ ├── GetCompositeSchedule.cpp │ ├── InstallCertificate.cpp │ ├── ClearChargingProfile.cpp │ ├── CustomOperation.cpp │ └── MeterValues.cpp │ ├── Version.h │ ├── Debug.cpp │ └── Debug.h ├── .github └── workflows │ ├── platformless.yml │ ├── pio.yml │ ├── esp-idf.yml │ └── tests.yml ├── LICENSE ├── platformio.ini ├── mkdocs.yml ├── SConscript.py └── library.json /examples/ESP-IDF/components/ArduinoJson/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/ESP-IDF/components/ArduinoOcpp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/ESP-IDF/components/mongoose/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/ESP-IDF/components/ArduinoOcppMongoose/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matth-x/MicroOcpp/HEAD/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --md-primary-fg-color: #2984C7; 3 | } 4 | -------------------------------------------------------------------------------- /examples/ESP-IDF/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "main.c" 2 | INCLUDE_DIRS ".") 3 | -------------------------------------------------------------------------------- /tests/catch2/catchMain.cpp: -------------------------------------------------------------------------------- 1 | 2 | //use the main function provided by catch2 3 | #define CATCH_CONFIG_MAIN 4 | 5 | //include the catch2 library 6 | #include "./catch.hpp" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode 3 | build 4 | lib 5 | mo_store 6 | src/ArduinoJson* 7 | src/main.cpp 8 | tests/helpers/ArduinoJson* 9 | coverage.info 10 | docs/assets 11 | -------------------------------------------------------------------------------- /examples/ESP-IDF/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := mo_example 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=MicroOcpp 2 | version=1.2.0 3 | author=Matthias Akstaller 4 | maintainer=Matthias Akstaller 5 | sentence=OCPP 1.6 Client for microcontrollers 6 | paragraph= 7 | category=Communication 8 | url=https://github.com/matth-x/MicroOcpp/ 9 | architectures=* 10 | depends=ArduinoJson, WebSockets 11 | -------------------------------------------------------------------------------- /tests/helpers/testHelper.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_TESTHELPER_H 6 | #define MO_TESTHELPER_H 7 | 8 | #define UNIT_MEM_TAG "UnitTests" 9 | 10 | extern unsigned long mtime; 11 | unsigned long custom_timer_cb(); 12 | 13 | void loop(); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /examples/ESP-IDF/partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, , 0x4000, 3 | otadata, data, ota, , 0x2000, 4 | phy_init, data, phy, , 0x1000, 5 | ota_0, app, ota_0, , 0x190000, 6 | ota_1, app, ota_1, , 0x190000, 7 | mo, data, spiffs, , 0xD0000, -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Transactions/TransactionDefs.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_TRANSACTIONDEFS_H 6 | #define MO_TRANSACTIONDEFS_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #define MO_TXID_LEN_MAX 36 13 | 14 | #endif //MO_ENABLE_V201 15 | #endif 16 | -------------------------------------------------------------------------------- /examples/ESP-IDF/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /examples/ESP-IDF/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following five lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | project(mo_example) 7 | 8 | idf_build_set_property(COMPILE_OPTIONS -DMO_TRAFFIC_OUT APPEND) 9 | idf_build_set_property(COMPILE_OPTIONS -DMO_FILENAME_PREFIX="/mo_store/" APPEND) 10 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/UuidUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef MO_UUIDUTILS_H 2 | #define MO_UUIDUTILS_H 3 | 4 | #include 5 | namespace MicroOcpp { 6 | 7 | // Generates a UUID (Universally Unique Identifier) and writes it into a given buffer 8 | // Returns false if the generation failed 9 | // The buffer must be at least 37 bytes long (36 characters + zero termination) 10 | bool generateUUID(char *uuidBuffer, size_t len); 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Diagnostics/DiagnosticsStatus.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_DIAGNOSTICS_STATUS 6 | #define MO_DIAGNOSTICS_STATUS 7 | 8 | namespace MicroOcpp { 9 | namespace Ocpp16 { 10 | 11 | enum class DiagnosticsStatus { 12 | Idle, 13 | Uploaded, 14 | UploadFailed, 15 | Uploading 16 | }; 17 | 18 | } 19 | } //end namespace MicroOcpp 20 | #endif 21 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/FirmwareManagement/FirmwareStatus.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_FIRMWARE_STATUS 6 | #define MO_FIRMWARE_STATUS 7 | 8 | namespace MicroOcpp { 9 | namespace Ocpp16 { 10 | 11 | enum class FirmwareStatus { 12 | Downloaded, 13 | DownloadFailed, 14 | Downloading, 15 | Idle, 16 | InstallationFailed, 17 | Installing, 18 | Installed 19 | }; 20 | 21 | } 22 | } //end namespace MicroOcpp 23 | #endif 24 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Reset/ResetDefs.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_RESETDEFS_H 6 | #define MO_RESETDEFS_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | typedef enum ResetType { 13 | ResetType_Immediate, 14 | ResetType_OnIdle 15 | } ResetType; 16 | 17 | typedef enum ResetStatus { 18 | ResetStatus_Accepted, 19 | ResetStatus_Rejected, 20 | ResetStatus_Scheduled 21 | } ResetStatus; 22 | 23 | #endif //MO_ENABLE_V201 24 | #endif 25 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Transactions/TransactionDeserialize.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_TRANSACTIONDESERIALIZE_H 6 | #define MO_TRANSACTIONDESERIALIZE_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | bool serializeTransaction(Transaction& tx, JsonDoc& out); 16 | bool deserializeTransaction(Transaction& tx, JsonObject in); 17 | 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/ESP-IDF/components/README.md: -------------------------------------------------------------------------------- 1 | ## Components folder structure 2 | 3 | The ESP-IDF integration requires at least the following components: 4 | 5 | - [MicroOcpp](https://github.com/matth-x/MicroOcpp) 6 | - [Mongoose (ESP-IDF integration)](https://github.com/cesanta/mongoose-esp-idf) 7 | - [Mongoose adapter for MicroOcpp](https://github.com/matth-x/MicroOcppMongoose) 8 | - [ArduinoJson (v6.21)](https://github.com/bblanchon/ArduinoJson) 9 | 10 | This example only provides the folder structure. You need to clone every project into it in order to run the example. 11 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Availability/ChangeAvailabilityStatus.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CHANGEAVAILABILITYSTATUS_H 6 | #define MO_CHANGEAVAILABILITYSTATUS_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | enum class ChangeAvailabilityStatus : uint8_t { 17 | Accepted, 18 | Rejected, 19 | Scheduled 20 | }; 21 | 22 | } //namespace MicroOcpp 23 | 24 | #endif //MO_ENABLE_V201 25 | #endif 26 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/ConfigurationContainerFlash.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CONFIGURATIONCONTAINERFLASH_H 6 | #define MO_CONFIGURATIONCONTAINERFLASH_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | std::unique_ptr makeConfigurationContainerFlash(std::shared_ptr filesystem, const char *filename, bool accessible); 14 | 15 | } //end namespace MicroOcpp 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/CiStrings.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | /* 6 | * A collection of the fixed-length string types in the OCPP specification 7 | */ 8 | 9 | #ifndef MO_CI_STRINGS_H 10 | #define MO_CI_STRINGS_H 11 | 12 | #define CiString20TypeLen 20 13 | #define CiString25TypeLen 25 14 | #define CiString50TypeLen 50 15 | #define CiString255TypeLen 255 16 | #define CiString500TypeLen 500 17 | 18 | //specified by OCPP 19 | #define IDTAG_LEN_MAX CiString20TypeLen 20 | #define CONF_KEYLEN_MAX CiString50TypeLen 21 | 22 | //not specified by OCPP 23 | #define REASON_LEN_MAX 15 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/ConnectorBase/ConnectorsCommon.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CHARGECONTROLCOMMON_H 6 | #define MO_CHARGECONTROLCOMMON_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | class Context; 14 | 15 | class ConnectorsCommon : public MemoryManaged { 16 | private: 17 | Context& context; 18 | public: 19 | ConnectorsCommon(Context& context, unsigned int numConnectors, std::shared_ptr filesystem); 20 | 21 | void loop(); 22 | }; 23 | 24 | } //end namespace MicroOcpp 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Heartbeat/HeartbeatService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_HEARTBEATSERVICE_H 6 | #define MO_HEARTBEATSERVICE_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class Context; 16 | 17 | class HeartbeatService : public MemoryManaged { 18 | private: 19 | Context& context; 20 | 21 | unsigned long lastHeartbeat; 22 | std::shared_ptr heartbeatIntervalInt; 23 | 24 | public: 25 | HeartbeatService(Context& context); 26 | 27 | void loop(); 28 | }; 29 | 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /tests/ocppEngineLifecycle.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include "./helpers/testHelper.h" 9 | 10 | TEST_CASE( "Context lifecycle" ) { 11 | printf("\nRun %s\n", "Context lifecycle"); 12 | 13 | //initialize Context with dummy socket 14 | MicroOcpp::LoopbackConnection loopback; 15 | mocpp_initialize(loopback); 16 | 17 | SECTION("OCPP is initialized"){ 18 | REQUIRE( getOcppContext() ); 19 | } 20 | 21 | mocpp_deinitialize(); 22 | 23 | SECTION("OCPP is deinitialized"){ 24 | REQUIRE( !( getOcppContext() ) ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | MicroOCPP is an OCPP client which runs on microcontrollers and enables EVSEs to participate in OCPP charging networks. As a software library, it can be added to the firmware of the EVSE and will become a new part of it. If the EVSE has already an internet controller, then most likely, no extra hardware is required. 2 | 3 | [Technical introduction](intro-tech) 4 | 5 | [Migrating to v1.0](migration) 6 | 7 | [Modules](modules) 8 | 9 | [Development tools and basic prerequisites](prerequisites) 10 | 11 | [Security whitepaper](security) 12 | 13 | 14 | 15 | *Documentation WIP. See the [GitHub Readme](https://github.com/matth-x/MicroOcpp) or the [API description](https://github.com/matth-x/MicroOcpp/blob/main/src/MicroOcpp.h) as reference.* 16 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Metering/ReadingContext.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_READINGCONTEXT_H 6 | #define MO_READINGCONTEXT_H 7 | 8 | typedef enum { 9 | ReadingContext_UNDEFINED, 10 | ReadingContext_InterruptionBegin, 11 | ReadingContext_InterruptionEnd, 12 | ReadingContext_Other, 13 | ReadingContext_SampleClock, 14 | ReadingContext_SamplePeriodic, 15 | ReadingContext_TransactionBegin, 16 | ReadingContext_TransactionEnd, 17 | ReadingContext_Trigger 18 | } ReadingContext; 19 | 20 | #ifdef __cplusplus 21 | 22 | namespace MicroOcpp { 23 | const char *serializeReadingContext(ReadingContext context); 24 | ReadingContext deserializeReadingContext(const char *serialized); 25 | } 26 | 27 | #endif 28 | #endif 29 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ClearCache.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CLEARCACHE_H 6 | #define MO_CLEARCACHE_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | namespace Ocpp16 { 13 | 14 | class ClearCache : public Operation, public MemoryManaged { 15 | private: 16 | std::shared_ptr filesystem; 17 | bool success = true; 18 | public: 19 | ClearCache(std::shared_ptr filesystem); 20 | 21 | const char* getOperationType() override; 22 | 23 | void processReq(JsonObject payload) override; 24 | 25 | std::unique_ptr createConf() override; 26 | }; 27 | 28 | } //end namespace Ocpp16 29 | } //end namespace MicroOcpp 30 | #endif 31 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/Heartbeat.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_HEARTBEAT_H 6 | #define MO_HEARTBEAT_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | class Model; 13 | 14 | namespace Ocpp16 { 15 | 16 | class Heartbeat : public Operation, public MemoryManaged { 17 | private: 18 | Model& model; 19 | public: 20 | Heartbeat(Model& model); 21 | 22 | const char* getOperationType() override; 23 | 24 | std::unique_ptr createReq() override; 25 | 26 | void processConf(JsonObject payload) override; 27 | 28 | void processReq(JsonObject payload) override; 29 | 30 | std::unique_ptr createConf() override; 31 | }; 32 | 33 | } //end namespace Ocpp16 34 | } //end namespace MicroOcpp 35 | #endif 36 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/ConnectorBase/EvseId.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_EVSEID_H 6 | #define MO_EVSEID_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | // number of EVSE IDs (including 0). Defaults to MO_NUMCONNECTORS if defined, otherwise to 2 13 | #ifndef MO_NUM_EVSEID 14 | #if defined(MO_NUMCONNECTORS) 15 | #define MO_NUM_EVSEID MO_NUMCONNECTORS 16 | #else 17 | #define MO_NUM_EVSEID 2 18 | #endif 19 | #endif // MO_NUM_EVSEID 20 | 21 | namespace MicroOcpp { 22 | 23 | // EVSEType (2.23) 24 | struct EvseId { 25 | int id; 26 | int connectorId = -1; //optional 27 | 28 | EvseId(int id) : id(id) { } 29 | EvseId(int id, int connectorId) : id(id), connectorId(connectorId) { } 30 | }; 31 | 32 | } 33 | 34 | #endif // MO_ENABLE_V201 35 | #endif 36 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/DataTransfer.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_DATATRANSFER_H 6 | #define MO_DATATRANSFER_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | namespace Ocpp16 { 12 | 13 | class DataTransfer : public Operation, public MemoryManaged { 14 | private: 15 | String msg; 16 | public: 17 | DataTransfer(); 18 | DataTransfer(const String &msg); 19 | 20 | const char* getOperationType() override; 21 | 22 | std::unique_ptr createReq() override; 23 | 24 | void processConf(JsonObject payload) override; 25 | 26 | void processReq(JsonObject payload) override; 27 | 28 | std::unique_ptr createConf() override; 29 | 30 | }; 31 | 32 | } //end namespace Ocpp16 33 | } //end namespace MicroOcpp 34 | #endif 35 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ClearChargingProfile.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CLEARCHARGINGPROFILE_H 6 | #define MO_CLEARCHARGINGPROFILE_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | class SmartChargingService; 13 | 14 | namespace Ocpp16 { 15 | 16 | class ClearChargingProfile : public Operation, public MemoryManaged { 17 | private: 18 | SmartChargingService& scService; 19 | bool matchingProfilesFound = false; 20 | public: 21 | ClearChargingProfile(SmartChargingService& scService); 22 | 23 | const char* getOperationType() override; 24 | 25 | void processReq(JsonObject payload) override; 26 | 27 | std::unique_ptr createConf() override; 28 | 29 | }; 30 | 31 | } //end namespace Ocpp16 32 | } //end namespace MicroOcpp 33 | #endif 34 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetLocalListVersion.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETLOCALLISTVERSION_H 6 | #define MO_GETLOCALLISTVERSION_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_LOCAL_AUTH 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class Model; 17 | 18 | namespace Ocpp16 { 19 | 20 | class GetLocalListVersion : public Operation, public MemoryManaged { 21 | private: 22 | Model& model; 23 | public: 24 | GetLocalListVersion(Model& model); 25 | 26 | const char* getOperationType() override; 27 | 28 | void processReq(JsonObject payload) override; 29 | 30 | std::unique_ptr createConf() override; 31 | }; 32 | 33 | } //end namespace Ocpp16 34 | } //end namespace MicroOcpp 35 | 36 | #endif //MO_ENABLE_LOCAL_AUTH 37 | #endif 38 | -------------------------------------------------------------------------------- /tests/helpers/testHelper.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | using namespace MicroOcpp; 12 | 13 | unsigned long mtime = 10000; 14 | unsigned long custom_timer_cb() { 15 | return mtime; 16 | } 17 | 18 | void loop() { 19 | for (int i = 0; i < 30; i++) { 20 | mtime += 100; 21 | mocpp_loop(); 22 | } 23 | } 24 | 25 | class TestRunListener : public Catch::TestEventListenerBase { 26 | public: 27 | using Catch::TestEventListenerBase::TestEventListenerBase; 28 | 29 | void testRunEnded( Catch::TestRunStats const& testRunStats ) override { 30 | MO_MEM_PRINT_STATS(); 31 | MO_MEM_DEINIT(); 32 | } 33 | }; 34 | 35 | CATCH_REGISTER_LISTENER(TestRunListener) 36 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RemoteStopTransaction.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_REMOTESTOPTRANSACTION_H 6 | #define MO_REMOTESTOPTRANSACTION_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | class Model; 13 | 14 | namespace Ocpp16 { 15 | 16 | class RemoteStopTransaction : public Operation, public MemoryManaged { 17 | private: 18 | Model& model; 19 | bool accepted = false; 20 | 21 | const char *errorCode = nullptr; 22 | public: 23 | RemoteStopTransaction(Model& model); 24 | 25 | const char* getOperationType() override; 26 | 27 | void processReq(JsonObject payload) override; 28 | 29 | std::unique_ptr createConf() override; 30 | 31 | const char *getErrorCode() override {return errorCode;} 32 | }; 33 | 34 | } //end namespace Ocpp16 35 | } //end namespace MicroOcpp 36 | #endif 37 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/ConnectorBase/ChargePointStatus.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CHARGEPOINTSTATUS_H 6 | #define MO_CHARGEPOINTSTATUS_H 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | typedef enum ChargePointStatus { 15 | ChargePointStatus_UNDEFINED, //internal use only - no OCPP standard value 16 | ChargePointStatus_Available, 17 | ChargePointStatus_Preparing, 18 | ChargePointStatus_Charging, 19 | ChargePointStatus_SuspendedEVSE, 20 | ChargePointStatus_SuspendedEV, 21 | ChargePointStatus_Finishing, 22 | ChargePointStatus_Reserved, 23 | ChargePointStatus_Unavailable, 24 | ChargePointStatus_Faulted 25 | 26 | #if MO_ENABLE_V201 27 | ,ChargePointStatus_Occupied 28 | #endif 29 | 30 | } ChargePointStatus; 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/TriggerMessage.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_TRIGGERMESSAGE_H 6 | #define MO_TRIGGERMESSAGE_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | class Context; 14 | 15 | namespace Ocpp16 { 16 | 17 | class TriggerMessage : public Operation, public MemoryManaged { 18 | private: 19 | Context& context; 20 | const char *statusMessage = nullptr; 21 | 22 | const char *errorCode = nullptr; 23 | public: 24 | TriggerMessage(Context& context); 25 | 26 | const char* getOperationType() override; 27 | 28 | void processReq(JsonObject payload) override; 29 | 30 | std::unique_ptr createConf() override; 31 | 32 | const char *getErrorCode() override {return errorCode;} 33 | }; 34 | 35 | } //end namespace Ocpp16 36 | } //end namespace MicroOcpp 37 | #endif 38 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/UpdateFirmware.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_UPDATEFIRMWARE_H 6 | #define MO_UPDATEFIRMWARE_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | class FirmwareService; 14 | 15 | namespace Ocpp16 { 16 | 17 | class UpdateFirmware : public Operation, public MemoryManaged { 18 | private: 19 | FirmwareService& fwService; 20 | 21 | const char *errorCode = nullptr; 22 | public: 23 | UpdateFirmware(FirmwareService& fwService); 24 | 25 | const char* getOperationType() override {return "UpdateFirmware";} 26 | 27 | void processReq(JsonObject payload) override; 28 | 29 | std::unique_ptr createConf() override; 30 | 31 | const char *getErrorCode() override {return errorCode;} 32 | }; 33 | 34 | } //end namespace Ocpp16 35 | } //end namespace MicroOcpp 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ChangeConfiguration.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CHANGECONFIGURATION_H 6 | #define MO_CHANGECONFIGURATION_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | namespace Ocpp16 { 12 | 13 | class ChangeConfiguration : public Operation, public MemoryManaged { 14 | private: 15 | bool reject = false; 16 | bool rebootRequired = false; 17 | bool readOnly = false; 18 | bool notSupported = false; 19 | 20 | const char *errorCode = nullptr; 21 | public: 22 | ChangeConfiguration(); 23 | 24 | const char* getOperationType() override; 25 | 26 | void processReq(JsonObject payload) override; 27 | 28 | std::unique_ptr createConf() override; 29 | 30 | const char *getErrorCode() override {return errorCode;} 31 | 32 | }; 33 | 34 | } //end namespace Ocpp16 35 | } //end namespace MicroOcpp 36 | #endif 37 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/RemoteControl/RemoteControlDefs.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_UNLOCKCONNECTOR_H 6 | #define MO_UNLOCKCONNECTOR_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | 14 | #include 15 | 16 | typedef enum { 17 | RequestStartStopStatus_Accepted, 18 | RequestStartStopStatus_Rejected 19 | } RequestStartStopStatus; 20 | 21 | #if MO_ENABLE_CONNECTOR_LOCK 22 | 23 | typedef enum { 24 | UnlockStatus_Unlocked, 25 | UnlockStatus_UnlockFailed, 26 | UnlockStatus_OngoingAuthorizedTransaction, 27 | UnlockStatus_UnknownConnector, 28 | UnlockStatus_PENDING // unlock action not finished yet, result still unknown (MO will check again later) 29 | } UnlockStatus; 30 | 31 | #endif // MO_ENABLE_CONNECTOR_LOCK 32 | 33 | #endif // MO_ENABLE_V201 34 | #endif // MO_UNLOCKCONNECTOR_H 35 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/RequestCallbacks.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_REQUESTCALLBACKS_H 6 | #define MO_REQUESTCALLBACKS_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | using OnReceiveConfListener = std::function; 14 | using OnReceiveReqListener = std::function; 15 | using OnSendConfListener = std::function; 16 | using OnTimeoutListener = std::function; 17 | using OnReceiveErrorListener = std::function; //will be called if OCPP communication partner returns error code 18 | using OnAbortListener = std::function; //will be called whenever the engine will stop trying to execute the operation normallythere is a timeout or error (onAbort = onTimeout || onReceiveError) 19 | 20 | } //end namespace MicroOcpp 21 | #endif 22 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/FirmwareStatusNotification.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #include 8 | 9 | #ifndef MO_FIRMWARESTATUSNOTIFICATION_H 10 | #define MO_FIRMWARESTATUSNOTIFICATION_H 11 | 12 | namespace MicroOcpp { 13 | namespace Ocpp16 { 14 | 15 | class FirmwareStatusNotification : public Operation, public MemoryManaged { 16 | private: 17 | FirmwareStatus status = FirmwareStatus::Idle; 18 | static const char *cstrFromFwStatus(FirmwareStatus status); 19 | public: 20 | FirmwareStatusNotification(FirmwareStatus status); 21 | 22 | const char* getOperationType() override {return "FirmwareStatusNotification"; } 23 | 24 | std::unique_ptr createReq() override; 25 | 26 | void processConf(JsonObject payload) override; 27 | 28 | }; 29 | 30 | } //end namespace Ocpp16 31 | } //end namespace MicroOcpp 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetConfiguration.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETCONFIGURATION_H 6 | #define MO_GETCONFIGURATION_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | namespace Ocpp16 { 13 | 14 | class GetConfiguration : public Operation, public MemoryManaged { 15 | private: 16 | Vector keys; 17 | 18 | const char *errorCode {nullptr}; 19 | const char *errorDescription = ""; 20 | public: 21 | GetConfiguration(); 22 | 23 | const char* getOperationType() override; 24 | 25 | void processReq(JsonObject payload) override; 26 | 27 | std::unique_ptr createConf() override; 28 | 29 | const char *getErrorCode() override {return errorCode;} 30 | const char *getErrorDescription() override {return errorDescription;} 31 | 32 | }; 33 | 34 | } //end namespace Ocpp16 35 | } //end namespace MicroOcpp 36 | #endif 37 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetDiagnostics.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETDIAGNOSTICS_H 6 | #define MO_GETDIAGNOSTICS_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | class DiagnosticsService; 14 | 15 | namespace Ocpp16 { 16 | 17 | class GetDiagnostics : public Operation, public MemoryManaged { 18 | private: 19 | DiagnosticsService& diagService; 20 | String fileName; 21 | 22 | const char *errorCode = nullptr; 23 | public: 24 | GetDiagnostics(DiagnosticsService& diagService); 25 | 26 | const char* getOperationType() override {return "GetDiagnostics";} 27 | 28 | void processReq(JsonObject payload) override; 29 | 30 | std::unique_ptr createConf() override; 31 | 32 | const char *getErrorCode() override {return errorCode;} 33 | }; 34 | 35 | } //end namespace Ocpp16 36 | } //end namespace MicroOcpp 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/DiagnosticsStatusNotification.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | 8 | #ifndef MO_DIAGNOSTICSSTATUSNOTIFICATION_H 9 | #define MO_DIAGNOSTICSSTATUSNOTIFICATION_H 10 | 11 | namespace MicroOcpp { 12 | namespace Ocpp16 { 13 | 14 | class DiagnosticsStatusNotification : public Operation, public MemoryManaged { 15 | private: 16 | DiagnosticsStatus status = DiagnosticsStatus::Idle; 17 | static const char *cstrFromStatus(DiagnosticsStatus status); 18 | public: 19 | DiagnosticsStatusNotification(DiagnosticsStatus status); 20 | 21 | const char* getOperationType() override {return "DiagnosticsStatusNotification"; } 22 | 23 | std::unique_ptr createReq() override; 24 | 25 | void processConf(JsonObject payload) override; 26 | 27 | }; 28 | 29 | } //end namespace Ocpp16 30 | } //end namespace MicroOcpp 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ReserveNow.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_RESERVENOW_H 6 | #define MO_RESERVENOW_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_RESERVATION 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class Model; 17 | 18 | namespace Ocpp16 { 19 | 20 | class ReserveNow : public Operation, public MemoryManaged { 21 | private: 22 | Model& model; 23 | const char *errorCode = nullptr; 24 | const char *reservationStatus = nullptr; 25 | public: 26 | ReserveNow(Model& model); 27 | 28 | ~ReserveNow(); 29 | 30 | const char* getOperationType() override; 31 | 32 | void processReq(JsonObject payload) override; 33 | 34 | std::unique_ptr createConf() override; 35 | 36 | const char *getErrorCode() override {return errorCode;} 37 | }; 38 | 39 | } //end namespace Ocpp16 40 | } //end namespace MicroOcpp 41 | 42 | #endif //MO_ENABLE_RESERVATION 43 | #endif 44 | -------------------------------------------------------------------------------- /.github/workflows/platformless.yml: -------------------------------------------------------------------------------- 1 | # matth-x/MicroOcpp 2 | # Copyright Matthias Akstaller 2019 - 2024 3 | # MIT License 4 | 5 | name: Default Compilation 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | pull_request: 13 | 14 | jobs: 15 | 16 | compile-platform: 17 | name: Compile (no linking) 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Check out repository code 21 | uses: actions/checkout@v3 22 | - name: Get gcc compiler 23 | run: | 24 | sudo apt update 25 | sudo apt install build-essential 26 | sudo apt -y install gcc-9 g++-9 27 | g++ --version 28 | echo "g++ version must be 9.4.0" 29 | - name: Get ArduinoJson 30 | run: wget -Uri https://github.com/bblanchon/ArduinoJson/releases/download/v6.19.4/ArduinoJson-v6.19.4.h -O ./src/ArduinoJson.h 31 | - name: Compile 32 | run: g++ -c -std=c++11 -I ./src $(find ./src -type f -iregex ".*\.cpp") -DMO_PLATFORM=MO_PLATFORM_NONE -Wall -Wextra -Wno-unused-parameter -Wno-redundant-move -Werror 33 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/CancelReservation.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CANCELRESERVATION_H 6 | #define MO_CANCELRESERVATION_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_RESERVATION 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class ReservationService; 17 | 18 | namespace Ocpp16 { 19 | 20 | class CancelReservation : public Operation, public MemoryManaged { 21 | private: 22 | ReservationService& reservationService; 23 | bool found = false; 24 | const char *errorCode = nullptr; 25 | public: 26 | CancelReservation(ReservationService& reservationService); 27 | 28 | const char* getOperationType() override; 29 | 30 | void processReq(JsonObject payload) override; 31 | 32 | std::unique_ptr createConf() override; 33 | 34 | const char *getErrorCode() override {return errorCode;} 35 | }; 36 | 37 | } //end namespace Ocpp16 38 | } //end namespace MicroOcpp 39 | 40 | #endif //MO_ENABLE_RESERVATION 41 | #endif 42 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Certificates/CertificateService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | /* 6 | * Functional Block M: ISO 15118 Certificate Management 7 | * 8 | * Implementation of UC: 9 | * - M03 10 | * - M04 11 | * - M05 12 | */ 13 | 14 | #ifndef MO_CERTIFICATESERVICE_H 15 | #define MO_CERTIFICATESERVICE_H 16 | 17 | #include 18 | 19 | #if MO_ENABLE_CERT_MGMT 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | namespace MicroOcpp { 28 | 29 | class Context; 30 | 31 | class CertificateService : public MemoryManaged { 32 | private: 33 | Context& context; 34 | std::unique_ptr certStore; 35 | public: 36 | CertificateService(Context& context); 37 | 38 | void setCertificateStore(std::unique_ptr certStore); 39 | CertificateStore *getCertificateStore(); 40 | }; 41 | 42 | } 43 | 44 | #endif //MO_ENABLE_CERT_MGMT 45 | #endif 46 | -------------------------------------------------------------------------------- /tests/benchmarks/firmware_size/platformio.ini: -------------------------------------------------------------------------------- 1 | ; matth-x/MicroOcpp 2 | ; Copyright Matthias Akstaller 2019 - 2024 3 | ; MIT License 4 | 5 | [common] 6 | platform = espressif32@6.8.1 7 | board = esp-wrover-kit 8 | framework = arduino 9 | lib_deps = 10 | bblanchon/ArduinoJson@6.20.1 11 | build_flags= 12 | -D MO_DBG_LEVEL=MO_DL_NONE ; don't take debug messages into account 13 | -D MO_CUSTOM_WS 14 | 15 | [env:v16] 16 | platform = ${common.platform} 17 | board = ${common.board} 18 | framework = ${common.framework} 19 | lib_deps = ${common.lib_deps} 20 | build_flags = 21 | ${common.build_flags} 22 | -D MO_ENABLE_MBEDTLS=1 23 | -D MO_ENABLE_CERT_MGMT=1 24 | -D MO_ENABLE_RESERVATION=1 25 | -D MO_ENABLE_LOCAL_AUTH=1 26 | -D MO_REPORT_NOERROR=1 27 | -D MO_ENABLE_CONNECTOR_LOCK=1 28 | 29 | [env:v201] 30 | platform = ${common.platform} 31 | board = ${common.board} 32 | framework = ${common.framework} 33 | lib_deps = ${common.lib_deps} 34 | build_flags = 35 | ${common.build_flags} 36 | -D MO_ENABLE_V201=1 37 | -D MO_ENABLE_MBEDTLS=1 38 | -D MO_ENABLE_CERT_MGMT=1 39 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/DeleteCertificate.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_DELETECERTIFICATE_H 6 | #define MO_DELETECERTIFICATE_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_CERT_MGMT 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class CertificateService; 17 | 18 | namespace Ocpp201 { 19 | 20 | class DeleteCertificate : public Operation, public MemoryManaged { 21 | private: 22 | CertificateService& certService; 23 | const char *status = nullptr; 24 | const char *errorCode = nullptr; 25 | public: 26 | DeleteCertificate(CertificateService& certService); 27 | 28 | const char* getOperationType() override {return "DeleteCertificate";} 29 | 30 | void processReq(JsonObject payload) override; 31 | 32 | std::unique_ptr createConf() override; 33 | 34 | const char *getErrorCode() override {return errorCode;} 35 | }; 36 | 37 | } //end namespace Ocpp201 38 | } //end namespace MicroOcpp 39 | 40 | #endif //MO_ENABLE_CERT_MGMT 41 | #endif 42 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/InstallCertificate.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_INSTALLCERTIFICATE_H 6 | #define MO_INSTALLCERTIFICATE_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_CERT_MGMT 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class CertificateService; 17 | 18 | namespace Ocpp201 { 19 | 20 | class InstallCertificate : public Operation, public MemoryManaged { 21 | private: 22 | CertificateService& certService; 23 | const char *status = nullptr; 24 | const char *errorCode = nullptr; 25 | public: 26 | InstallCertificate(CertificateService& certService); 27 | 28 | const char* getOperationType() override {return "InstallCertificate";} 29 | 30 | void processReq(JsonObject payload) override; 31 | 32 | std::unique_ptr createConf() override; 33 | 34 | const char *getErrorCode() override {return errorCode;} 35 | }; 36 | 37 | } //end namespace Ocpp201 38 | } //end namespace MicroOcpp 39 | 40 | #endif //MO_ENABLE_CERT_MGMT 41 | #endif 42 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/SendLocalList.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_SENDLOCALLIST_H 6 | #define MO_SENDLOCALLIST_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_LOCAL_AUTH 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class AuthorizationService; 17 | 18 | namespace Ocpp16 { 19 | 20 | class SendLocalList : public Operation, public MemoryManaged { 21 | private: 22 | AuthorizationService& authService; 23 | const char *errorCode = nullptr; 24 | bool updateFailure = true; 25 | bool versionMismatch = false; 26 | public: 27 | SendLocalList(AuthorizationService& authService); 28 | 29 | ~SendLocalList(); 30 | 31 | const char* getOperationType() override; 32 | 33 | void processReq(JsonObject payload) override; 34 | 35 | std::unique_ptr createConf() override; 36 | 37 | const char *getErrorCode() override {return errorCode;} 38 | }; 39 | 40 | } //end namespace Ocpp16 41 | } //end namespace MicroOcpp 42 | 43 | #endif //MO_ENABLE_LOCAL_AUTH 44 | #endif 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 - 2024 Matthias Akstaller 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/ConnectorBase/UnlockConnectorResult.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_UNLOCKCONNECTORRESULT_H 6 | #define MO_UNLOCKCONNECTORRESULT_H 7 | 8 | #include 9 | 10 | // Connector-lock related behavior (i.e. if UnlockConnectorOnEVSideDisconnect is RW; enable HW binding for UnlockConnector) 11 | #ifndef MO_ENABLE_CONNECTOR_LOCK 12 | #define MO_ENABLE_CONNECTOR_LOCK 0 13 | #endif 14 | 15 | #if MO_ENABLE_CONNECTOR_LOCK 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif // __cplusplus 20 | 21 | #ifndef MO_UNLOCK_TIMEOUT 22 | #define MO_UNLOCK_TIMEOUT 10000 // if Result is Pending, wait at most this period (in ms) until sending UnlockFailed 23 | #endif 24 | 25 | typedef enum { 26 | UnlockConnectorResult_UnlockFailed, 27 | UnlockConnectorResult_Unlocked, 28 | UnlockConnectorResult_Pending // unlock action not finished yet, result still unknown (MO will check again later) 29 | } UnlockConnectorResult; 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif // __cplusplus 34 | 35 | #endif // MO_ENABLE_CONNECTOR_LOCK 36 | #endif // MO_UNLOCKCONNECTORRESULT_H 37 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetBaseReport.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETBASEREPORT_H 6 | #define MO_GETBASEREPORT_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | class VariableService; 19 | 20 | namespace Ocpp201 { 21 | 22 | class GetBaseReport : public Operation, public MemoryManaged { 23 | private: 24 | VariableService& variableService; 25 | 26 | GenericDeviceModelStatus status; 27 | 28 | const char *errorCode = nullptr; 29 | public: 30 | GetBaseReport(VariableService& variableService); 31 | 32 | const char* getOperationType() override; 33 | 34 | void processReq(JsonObject payload) override; 35 | 36 | std::unique_ptr createConf() override; 37 | 38 | const char *getErrorCode() override {return errorCode;} 39 | 40 | }; 41 | 42 | } //namespace Ocpp201 43 | } //namespace MicroOcpp 44 | 45 | #endif //MO_ENABLE_V201 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/SetChargingProfile.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_SETCHARGINGPROFILE_H 6 | #define MO_SETCHARGINGPROFILE_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | class Model; 13 | class SmartChargingService; 14 | 15 | namespace Ocpp16 { 16 | 17 | class SetChargingProfile : public Operation, public MemoryManaged { 18 | private: 19 | Model& model; 20 | SmartChargingService& scService; 21 | 22 | bool accepted = false; 23 | const char *errorCode = nullptr; 24 | const char *errorDescription = ""; 25 | public: 26 | SetChargingProfile(Model& model, SmartChargingService& scService); 27 | 28 | ~SetChargingProfile(); 29 | 30 | const char* getOperationType() override; 31 | 32 | void processReq(JsonObject payload) override; 33 | 34 | std::unique_ptr createConf() override; 35 | 36 | const char *getErrorCode() override {return errorCode;} 37 | const char *getErrorDescription() override {return errorDescription;} 38 | }; 39 | 40 | } //end namespace Ocpp16 41 | } //end namespace MicroOcpp 42 | #endif 43 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/StartTransaction.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_STARTTRANSACTION_H 6 | #define MO_STARTTRANSACTION_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class Model; 16 | class Transaction; 17 | 18 | namespace Ocpp16 { 19 | 20 | class StartTransaction : public Operation, public MemoryManaged { 21 | private: 22 | Model& model; 23 | std::shared_ptr transaction; 24 | public: 25 | 26 | StartTransaction(Model& model, std::shared_ptr transaction); 27 | 28 | ~StartTransaction(); 29 | 30 | const char* getOperationType() override; 31 | 32 | std::unique_ptr createReq() override; 33 | 34 | void processConf(JsonObject payload) override; 35 | 36 | void processReq(JsonObject payload) override; 37 | 38 | std::unique_ptr createConf() override; 39 | }; 40 | 41 | } //end namespace Ocpp16 42 | } //end namespace MicroOcpp 43 | #endif 44 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/NotifyReport.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_TRANSACTIONEVENT_H 6 | #define MO_TRANSACTIONEVENT_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | class Model; 19 | class Variable; 20 | 21 | namespace Ocpp201 { 22 | 23 | class NotifyReport : public Operation, public MemoryManaged { 24 | private: 25 | Model& model; 26 | 27 | int requestId; 28 | Timestamp generatedAt; 29 | bool tbc; 30 | int seqNo; 31 | Vector reportData; 32 | public: 33 | 34 | NotifyReport(Model& model, int requestId, const Timestamp& generatedAt, bool tbc, int seqNo, const Vector& reportData); 35 | 36 | const char* getOperationType() override; 37 | 38 | std::unique_ptr createReq() override; 39 | 40 | void processConf(JsonObject payload) override; 41 | }; 42 | 43 | } //end namespace Ocpp201 44 | } //end namespace MicroOcpp 45 | #endif // MO_ENABLE_V201 46 | #endif 47 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/ConnectorBase/ChargePointErrorData.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CHARGEPOINTERRORCODE_H 6 | #define MO_CHARGEPOINTERRORCODE_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | struct ErrorData { 13 | bool isError = false; //if any error information is set 14 | bool isFaulted = false; //if this is a severe error and the EVSE should go into the faulted state 15 | uint8_t severity = 1; //severity: don't send less severe errors during highly severe error condition 16 | const char *errorCode = nullptr; //see ChargePointErrorCode (p. 76/77) for possible values 17 | const char *info = nullptr; //Additional free format information related to the error 18 | const char *vendorId = nullptr; //vendor-specific implementation identifier 19 | const char *vendorErrorCode = nullptr; //vendor-specific error code 20 | 21 | ErrorData() = default; 22 | 23 | ErrorData(const char *errorCode = nullptr) : errorCode(errorCode) { 24 | if (errorCode) { 25 | isError = true; 26 | isFaulted = true; 27 | } 28 | } 29 | }; 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/TransactionEvent.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_TRANSACTIONEVENT_H 6 | #define MO_TRANSACTIONEVENT_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class Model; 17 | 18 | namespace Ocpp201 { 19 | 20 | class TransactionEventData; 21 | 22 | class TransactionEvent : public Operation, public MemoryManaged { 23 | private: 24 | Model& model; 25 | TransactionEventData *txEvent; 26 | 27 | const char *errorCode = nullptr; 28 | public: 29 | 30 | TransactionEvent(Model& model, TransactionEventData *txEvent); 31 | 32 | const char* getOperationType() override; 33 | 34 | std::unique_ptr createReq() override; 35 | 36 | void processConf(JsonObject payload) override; 37 | 38 | const char *getErrorCode() override {return errorCode;} 39 | 40 | void processReq(JsonObject payload) override; 41 | 42 | std::unique_ptr createConf() override; 43 | }; 44 | 45 | } //end namespace Ocpp201 46 | } //end namespace MicroOcpp 47 | #endif // MO_ENABLE_V201 48 | #endif 49 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RequestStopTransaction.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_REQUESTSTOPTRANSACTION_H 6 | #define MO_REQUESTSTOPTRANSACTION_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | class RemoteControlService; 19 | 20 | namespace Ocpp201 { 21 | 22 | class RequestStopTransaction : public Operation, public MemoryManaged { 23 | private: 24 | RemoteControlService& rcService; 25 | 26 | RequestStartStopStatus status; 27 | 28 | const char *errorCode = nullptr; 29 | public: 30 | RequestStopTransaction(RemoteControlService& rcService); 31 | 32 | const char* getOperationType() override; 33 | 34 | void processReq(JsonObject payload) override; 35 | 36 | std::unique_ptr createConf() override; 37 | 38 | const char *getErrorCode() override {return errorCode;} 39 | 40 | }; 41 | 42 | } //namespace Ocpp201 43 | } //namespace MicroOcpp 44 | 45 | #endif //MO_ENABLE_V201 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetCompositeSchedule.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETCOMPOSITESCHEDULE_H 6 | #define MO_GETCOMPOSITESCHEDULE_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace MicroOcpp { 13 | 14 | class Model; 15 | 16 | namespace Ocpp16 { 17 | 18 | class GetCompositeSchedule : public Operation, public MemoryManaged { 19 | private: 20 | Model& model; 21 | SmartChargingService& scService; 22 | int connectorId = -1; 23 | int duration = -1; 24 | ChargingRateUnitType_Optional chargingRateUnit = ChargingRateUnitType_Optional::None; 25 | 26 | const char *errorCode {nullptr}; 27 | public: 28 | GetCompositeSchedule(Model& model, SmartChargingService& scService); 29 | 30 | const char* getOperationType() override; 31 | 32 | void processReq(JsonObject payload) override; 33 | 34 | std::unique_ptr createConf() override; 35 | 36 | const char *getErrorCode() override {return errorCode;} 37 | }; 38 | 39 | } //end namespace Ocpp16 40 | } //end namespace MicroOcpp 41 | #endif 42 | -------------------------------------------------------------------------------- /examples/ESP-IDF/main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Example Configuration" 2 | 3 | config ESP_WIFI_SSID 4 | string "WiFi SSID" 5 | default "myssid" 6 | help 7 | SSID (network name) for the example to connect to. 8 | 9 | config ESP_WIFI_PASSWORD 10 | string "WiFi Password" 11 | default "mypassword" 12 | help 13 | WiFi password (WPA or WPA2) for the example to use. 14 | 15 | config ESP_MAXIMUM_RETRY 16 | int "Maximum retry" 17 | default 5 18 | help 19 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. 20 | 21 | config MO_OCPP_BACKEND 22 | string "OCPP backend URL" 23 | default "ws://echo.websocket.events/" 24 | help 25 | URL of the OCPP backend 26 | 27 | config MO_CHARGEBOXID 28 | string "ChargeBoxId" 29 | default "" 30 | help 31 | ChargeBoxId as it appears in the WebSocket connection URL 32 | 33 | config MO_AUTHORIZATIONKEY 34 | string "Authorization Key" 35 | default "" 36 | help 37 | Passphrase for connecting to the OCPP server 38 | endmenu 39 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RemoteStartTransaction.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_REMOTESTARTTRANSACTION_H 6 | #define MO_REMOTESTARTTRANSACTION_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | class Model; 14 | class ChargingProfile; 15 | 16 | namespace Ocpp16 { 17 | 18 | class RemoteStartTransaction : public Operation, public MemoryManaged { 19 | private: 20 | Model& model; 21 | 22 | bool accepted = false; 23 | 24 | const char *errorCode {nullptr}; 25 | const char *errorDescription = ""; 26 | public: 27 | RemoteStartTransaction(Model& model); 28 | 29 | const char* getOperationType() override; 30 | 31 | std::unique_ptr createReq() override; 32 | 33 | void processConf(JsonObject payload) override; 34 | 35 | void processReq(JsonObject payload) override; 36 | 37 | std::unique_ptr createConf() override; 38 | 39 | const char *getErrorCode() override {return errorCode;} 40 | const char *getErrorDescription() override {return errorDescription;} 41 | }; 42 | 43 | } //end namespace Ocpp16 44 | } //end namespace MicroOcpp 45 | #endif 46 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/SecurityEventNotification.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_SECURITYEVENTNOTIFICATION_H 6 | #define MO_SECURITYEVENTNOTIFICATION_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | namespace Ocpp201 { 19 | 20 | class SecurityEventNotification : public Operation, public MemoryManaged { 21 | private: 22 | String type; 23 | Timestamp timestamp; 24 | 25 | const char *errorCode = nullptr; 26 | public: 27 | SecurityEventNotification(const char *type, const Timestamp& timestamp); 28 | 29 | const char* getOperationType() override; 30 | 31 | std::unique_ptr createReq() override; 32 | 33 | void processConf(JsonObject payload) override; 34 | 35 | const char *getErrorCode() override {return errorCode;} 36 | 37 | void processReq(JsonObject payload) override; 38 | 39 | std::unique_ptr createConf() override; 40 | 41 | }; 42 | 43 | } //namespace Ocpp201 44 | } //namespace MicroOcpp 45 | 46 | #endif //MO_ENABLE_V201 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetInstalledCertificateIds.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETINSTALLEDCERTIFICATEIDS_H 6 | #define MO_GETINSTALLEDCERTIFICATEIDS_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_CERT_MGMT 11 | 12 | #include 13 | #include 14 | 15 | namespace MicroOcpp { 16 | 17 | class CertificateService; 18 | 19 | namespace Ocpp201 { 20 | 21 | class GetInstalledCertificateIds : public Operation, public MemoryManaged { 22 | private: 23 | CertificateService& certService; 24 | Vector certificateHashDataChain; 25 | const char *status = nullptr; 26 | const char *errorCode = nullptr; 27 | public: 28 | GetInstalledCertificateIds(CertificateService& certService); 29 | 30 | const char* getOperationType() override {return "GetInstalledCertificateIds";} 31 | 32 | void processReq(JsonObject payload) override; 33 | 34 | std::unique_ptr createConf() override; 35 | 36 | const char *getErrorCode() override {return errorCode;} 37 | }; 38 | 39 | } //end namespace Ocpp201 40 | } //end namespace MicroOcpp 41 | 42 | #endif //MO_ENABLE_CERT_MGMT 43 | #endif 44 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; matth-x/MicroOcpp 2 | ; Copyright Matthias Akstaller 2019 - 2024 3 | ; MIT License 4 | 5 | [platformio] 6 | default_envs = esp32-development-board 7 | 8 | [common] 9 | framework = arduino 10 | lib_deps = 11 | bblanchon/ArduinoJson@6.20.1 12 | links2004/WebSockets@2.4.1 13 | monitor_speed = 115200 14 | 15 | [env:nodemcuv2] 16 | platform = espressif8266@2.6.3 17 | board = nodemcuv2 18 | framework = ${common.framework} 19 | lib_deps = ${common.lib_deps} 20 | monitor_speed = ${common.monitor_speed} 21 | build_flags = 22 | -D MO_DBG_LEVEL=MO_DL_INFO ; flood the serial monitor with information about the internal state 23 | -DMO_TRAFFIC_OUT ; print the OCPP communication to the serial monitor 24 | -D ARDUINOJSON_ENABLE_STD_STRING=1 25 | 26 | [env:esp32-development-board] 27 | platform = espressif32@6.0.1 28 | board = esp-wrover-kit 29 | framework = ${common.framework} 30 | lib_deps = ${common.lib_deps} 31 | monitor_speed = ${common.monitor_speed} 32 | build_flags = 33 | -D MO_DBG_LEVEL=MO_DL_INFO ; flood the serial monitor with information about the internal state 34 | -DMO_TRAFFIC_OUT ; print the OCPP communication to the serial monitor 35 | board_build.partitions = min_spiffs.csv 36 | upload_speed = 921600 37 | monitor_filters = 38 | esp32_exception_decoder 39 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/OperationRegistry.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_OPERATIONREGISTRY_H 6 | #define MO_OPERATIONREGISTRY_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class Operation; 16 | class Request; 17 | 18 | struct OperationCreator { 19 | const char *operationType {nullptr}; 20 | std::function creator {nullptr}; 21 | OnReceiveReqListener onRequest {nullptr}; 22 | OnSendConfListener onResponse {nullptr}; 23 | }; 24 | 25 | class OperationRegistry { 26 | private: 27 | Vector registry; 28 | OperationCreator *findCreator(const char *operationType); 29 | 30 | public: 31 | OperationRegistry(); 32 | 33 | void registerOperation(const char *operationType, std::function creator); 34 | void setOnRequest(const char *operationType, OnReceiveReqListener onRequest); 35 | void setOnResponse(const char *operationType, OnSendConfListener onResponse); 36 | 37 | std::unique_ptr deserializeOperation(const char *operationType); 38 | 39 | void debugPrint(); 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/Operation.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #include 8 | 9 | using namespace MicroOcpp; 10 | 11 | Operation::Operation() {} 12 | 13 | Operation::~Operation() {} 14 | 15 | const char* Operation::getOperationType(){ 16 | MO_DBG_ERR("Unsupported operation: getOperationType() is not implemented"); 17 | return "CustomOperation"; 18 | } 19 | 20 | std::unique_ptr Operation::createReq() { 21 | MO_DBG_ERR("Unsupported operation: createReq() is not implemented"); 22 | return createEmptyDocument(); 23 | } 24 | 25 | void Operation::processConf(JsonObject payload) { 26 | MO_DBG_ERR("Unsupported operation: processConf() is not implemented"); 27 | } 28 | 29 | void Operation::processReq(JsonObject payload) { 30 | MO_DBG_ERR("Unsupported operation: processReq() is not implemented"); 31 | } 32 | 33 | std::unique_ptr Operation::createConf() { 34 | MO_DBG_ERR("Unsupported operation: createConf() is not implemented"); 35 | return createEmptyDocument(); 36 | } 37 | 38 | std::unique_ptr MicroOcpp::createEmptyDocument() { 39 | auto emptyDoc = makeJsonDoc("EmptyJsonDoc", 0); 40 | emptyDoc->to(); 41 | return emptyDoc; 42 | } 43 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Authorization/IdToken.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_IDTOKEN_H 6 | #define MO_IDTOKEN_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | 14 | #include 15 | 16 | #define MO_IDTOKEN_LEN_MAX 36 17 | 18 | namespace MicroOcpp { 19 | 20 | // IdTokenType (2.28) 21 | class IdToken : public MemoryManaged { 22 | public: 23 | 24 | // IdTokenEnumType (3.43) 25 | enum class Type : uint8_t { 26 | Central, 27 | eMAID, 28 | ISO14443, 29 | ISO15693, 30 | KeyCode, 31 | Local, 32 | MacAddress, 33 | NoAuthorization, 34 | UNDEFINED 35 | }; 36 | 37 | private: 38 | char idToken [MO_IDTOKEN_LEN_MAX + 1]; 39 | Type type = Type::UNDEFINED; 40 | public: 41 | IdToken(const char *token = nullptr, Type type = Type::ISO14443, const char *memoryTag = nullptr); 42 | 43 | IdToken(const IdToken& other, const char *memoryTag = nullptr); 44 | 45 | bool parseCstr(const char *token, const char *typeCstr); 46 | 47 | const char *get() const; 48 | const char *getTypeCstr() const; 49 | 50 | bool equals(const IdToken& other); 51 | }; 52 | 53 | } // namespace MicroOcpp 54 | 55 | #endif // MO_ENABLE_V201 56 | #endif 57 | -------------------------------------------------------------------------------- /.github/workflows/pio.yml: -------------------------------------------------------------------------------- 1 | # matth-x/MicroOcpp 2 | # Copyright Matthias Akstaller 2019 - 2024 3 | # MIT License 4 | 5 | name: PlatformIO CI 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | pull_request: 13 | 14 | jobs: 15 | build: 16 | 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | example: [examples/ESP/main.cpp, examples/ESP-TLS/main.cpp] 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Cache pip 25 | uses: actions/cache@v4 26 | with: 27 | path: ~/.cache/pip 28 | key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} 29 | restore-keys: | 30 | ${{ runner.os }}-pip- 31 | - name: Cache PlatformIO 32 | uses: actions/cache@v4 33 | with: 34 | path: ~/.platformio 35 | key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} 36 | - name: Set up Python 37 | uses: actions/setup-python@v4 38 | - name: Install PlatformIO 39 | run: | 40 | python -m pip install --upgrade pip 41 | pip install --upgrade platformio 42 | - name: Install library dependencies 43 | run: pio pkg install 44 | - name: Run PlatformIO 45 | run: pio ci --lib="." --project-conf=platformio.ini ${{ matrix.dashboard-extra }} 46 | env: 47 | PLATFORMIO_CI_SRC: ${{ matrix.example }} 48 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/FilesystemUtils.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_FILESYSTEMUTILS_H 6 | #define MO_FILESYSTEMUTILS_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class ArduinoJsonFileAdapter { 16 | private: 17 | FileAdapter *file; 18 | public: 19 | ArduinoJsonFileAdapter(FileAdapter *file) : file(file) { } 20 | 21 | size_t readBytes(char *buf, size_t len) { 22 | return file->read(buf, len); 23 | } 24 | 25 | int read() { 26 | return file->read(); 27 | } 28 | 29 | size_t write(const uint8_t *buf, size_t len) { 30 | return file->write((const char*) buf, len); 31 | } 32 | 33 | size_t write(uint8_t c) { 34 | return file->write((const char*) &c, 1); 35 | } 36 | }; 37 | 38 | namespace FilesystemUtils { 39 | 40 | std::unique_ptr loadJson(std::shared_ptr filesystem, const char *fn, const char *memoryTag = nullptr); 41 | bool storeJson(std::shared_ptr filesystem, const char *fn, const JsonDoc& doc); 42 | 43 | bool remove_if(std::shared_ptr filesystem, std::function pred); 44 | 45 | } 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: MicroOCPP docs 2 | 3 | theme: 4 | name: material 5 | features: 6 | - announce.dismiss 7 | - content.action.edit 8 | - content.action.view 9 | - content.code.annotate 10 | - content.code.copy 11 | # - content.tabs.link 12 | - content.tooltips 13 | # - header.autohide 14 | # - navigation.expand 15 | - navigation.footer 16 | - navigation.indexes 17 | # - navigation.instant 18 | # - navigation.prune 19 | - navigation.sections 20 | - navigation.tabs 21 | # - navigation.tabs.sticky 22 | - navigation.top 23 | - navigation.tracking 24 | - search.highlight 25 | - search.share 26 | - search.suggest 27 | - toc.follow 28 | # - toc.integrate 29 | palette: 30 | - scheme: default 31 | primary: custom 32 | accent: custom 33 | toggle: 34 | icon: material/brightness-7 35 | name: Switch to dark mode 36 | - scheme: slate 37 | primary: custom 38 | accent: custom 39 | toggle: 40 | icon: material/brightness-4 41 | name: Switch to light mode 42 | font: 43 | text: Roboto 44 | code: Roboto Mono 45 | favicon: img/favicon.ico 46 | icon: 47 | logo: logo 48 | 49 | extra_css: 50 | - stylesheets/extra.css 51 | 52 | plugins: 53 | - search 54 | - table-reader: 55 | data_path: "docs/assets/tables" 56 | -------------------------------------------------------------------------------- /src/MicroOcpp/Version.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_VERSION_H 6 | #define MO_VERSION_H 7 | 8 | /* 9 | * Version specification of MicroOcpp library (not related with the OCPP version) 10 | */ 11 | #define MO_VERSION "1.2.0" 12 | 13 | /* 14 | * Enable OCPP 2.0.1 support. If enabled, library can be initialized with both v1.6 and v2.0.1. The choice 15 | * of the protocol is done dynamically during initialization 16 | */ 17 | #ifndef MO_ENABLE_V201 18 | #define MO_ENABLE_V201 0 19 | #endif 20 | 21 | #ifdef __cplusplus 22 | 23 | namespace MicroOcpp { 24 | 25 | /* 26 | * OCPP version type, defined in Model 27 | */ 28 | struct ProtocolVersion { 29 | const int major, minor, patch; 30 | ProtocolVersion(int major = 1, int minor = 6, int patch = 0) : major(major), minor(minor), patch(patch) { } 31 | }; 32 | 33 | } 34 | 35 | #endif //__cplusplus 36 | 37 | // Certificate Management (UCs M03 - M05). Works with OCPP 1.6 and 2.0.1 38 | #ifndef MO_ENABLE_CERT_MGMT 39 | #define MO_ENABLE_CERT_MGMT MO_ENABLE_V201 40 | #endif 41 | 42 | // Reservations 43 | #ifndef MO_ENABLE_RESERVATION 44 | #define MO_ENABLE_RESERVATION 1 45 | #endif 46 | 47 | // Local Authorization, i.e. feature profile LocalAuthListManagement 48 | #ifndef MO_ENABLE_LOCAL_AUTH 49 | #define MO_ENABLE_LOCAL_AUTH 1 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/BootNotification.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_BOOTNOTIFICATION_H 6 | #define MO_BOOTNOTIFICATION_H 7 | 8 | #include 9 | #include 10 | 11 | #define CP_MODEL_LEN_MAX CiString20TypeLen 12 | #define CP_SERIALNUMBER_LEN_MAX CiString25TypeLen 13 | #define CP_VENDOR_LEN_MAX CiString20TypeLen 14 | #define FW_VERSION_LEN_MAX CiString50TypeLen 15 | 16 | namespace MicroOcpp { 17 | 18 | class Model; 19 | 20 | namespace Ocpp16 { 21 | 22 | class BootNotification : public Operation, public MemoryManaged { 23 | private: 24 | Model& model; 25 | std::unique_ptr credentials; 26 | const char *errorCode = nullptr; 27 | public: 28 | BootNotification(Model& model, std::unique_ptr payload); 29 | 30 | ~BootNotification() = default; 31 | 32 | const char* getOperationType() override; 33 | 34 | std::unique_ptr createReq() override; 35 | 36 | void processConf(JsonObject payload) override; 37 | 38 | void processReq(JsonObject payload) override; 39 | 40 | std::unique_ptr createConf() override; 41 | 42 | const char *getErrorCode() override {return errorCode;} 43 | }; 44 | 45 | } //end namespace Ocpp16 46 | } //end namespace MicroOcpp 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/FtpMbedTLS.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_FTP_MBEDTLS_H 6 | #define MO_FTP_MBEDTLS_H 7 | 8 | /* 9 | * Built-in FTP client (depends on MbedTLS) 10 | * 11 | * Moved from https://github.com/matth-x/MicroFtp 12 | * 13 | * Currently, the compatibility with the following FTP servers has been tested: 14 | * 15 | * | Server | FTP | FTPS | 16 | * | --------------------------------------------------------------------- | --- | ---- | 17 | * | [vsftp](https://security.appspot.com/vsftpd.html) | | x | 18 | * | [Rebex](https://www.rebex.net/) | x | x | 19 | * | [Windows Server 2022](https://www.microsoft.com/en-us/windows-server) | x | x | 20 | * | [SFTPGo](https://github.com/drakkan/sftpgo) | x | | 21 | * 22 | */ 23 | 24 | #include 25 | 26 | #if MO_ENABLE_MBEDTLS 27 | 28 | #include 29 | 30 | #include 31 | 32 | namespace MicroOcpp { 33 | 34 | std::unique_ptr makeFtpClientMbedTLS(bool tls_only = false, const char *client_cert = nullptr, const char *client_key = nullptr); 35 | 36 | } //namespace MicroOcpp 37 | 38 | #endif //MO_ENABLE_MBEDTLS 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RequestStartTransaction.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_REQUESTSTARTTRANSACTION_H 6 | #define MO_REQUESTSTARTTRANSACTION_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace MicroOcpp { 18 | 19 | class RemoteControlService; 20 | 21 | namespace Ocpp201 { 22 | 23 | class RequestStartTransaction : public Operation, public MemoryManaged { 24 | private: 25 | RemoteControlService& rcService; 26 | 27 | RequestStartStopStatus status; 28 | std::shared_ptr transaction; 29 | char transactionId [MO_TXID_LEN_MAX + 1] = {'\0'}; 30 | 31 | const char *errorCode = nullptr; 32 | public: 33 | RequestStartTransaction(RemoteControlService& rcService); 34 | 35 | const char* getOperationType() override; 36 | 37 | void processReq(JsonObject payload) override; 38 | 39 | std::unique_ptr createConf() override; 40 | 41 | const char *getErrorCode() override {return errorCode;} 42 | 43 | }; 44 | 45 | } //namespace Ocpp201 46 | } //namespace MicroOcpp 47 | 48 | #endif //MO_ENABLE_V201 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /SConscript.py: -------------------------------------------------------------------------------- 1 | # matth-x/MicroOcpp 2 | # Copyright Matthias Akstaller 2019 - 2024 3 | # MIT License 4 | 5 | # NOTE: This SConscript is still WIP. It has thankfully been contributed from a project using SCons, 6 | # not necessarily considering full reusability in other projects though. 7 | # Use this file as a starting point for writing your own SCons integration. And as always, any 8 | # contributions are highly welcome! 9 | 10 | Import("env") 11 | 12 | import os, pathlib 13 | 14 | def getAllDirs(root_dir): 15 | dir_list = [] 16 | for root, subfolders, files in os.walk(root_dir.abspath): 17 | dir_list.append(Dir(root)) 18 | return dir_list 19 | 20 | SOURCE_DIR = Dir(".").srcnode().Dir("src") 21 | 22 | source_dirs = getAllDirs(SOURCE_DIR) 23 | 24 | source_files = [] 25 | 26 | for folder in source_dirs: 27 | source_files += folder.glob("*.c") 28 | source_files += folder.glob("*.cpp") 29 | 30 | compiled_objects = [] 31 | for source_file in source_files: 32 | obj = env.Object( 33 | target = pathlib.Path(source_file.path).stem 34 | + ".o", 35 | source=source_file, 36 | ) 37 | compiled_objects.append(obj) 38 | 39 | libmicroocpp = env.StaticLibrary( 40 | target='libmicroocpp', 41 | source=sorted(compiled_objects) 42 | ) 43 | 44 | exports = { 45 | 'library': libmicroocpp, 46 | 'CPPPATH': SOURCE_DIR 47 | } 48 | 49 | Return("exports") 50 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/Context.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CONTEXT_H 6 | #define MO_CONTEXT_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace MicroOcpp { 18 | 19 | class Connection; 20 | class FilesystemAdapter; 21 | 22 | class Context : public MemoryManaged { 23 | private: 24 | Connection& connection; 25 | OperationRegistry operationRegistry; 26 | Model model; 27 | RequestQueue reqQueue; 28 | 29 | std::unique_ptr ftpClient; 30 | 31 | public: 32 | Context(Connection& connection, std::shared_ptr filesystem, uint16_t bootNr, ProtocolVersion version); 33 | ~Context(); 34 | 35 | void loop(); 36 | 37 | void initiateRequest(std::unique_ptr op); 38 | 39 | Model& getModel(); 40 | 41 | OperationRegistry& getOperationRegistry(); 42 | 43 | const ProtocolVersion& getVersion(); 44 | 45 | Connection& getConnection(); 46 | 47 | RequestQueue& getRequestQueue(); 48 | 49 | void setFtpClient(std::unique_ptr ftpClient); 50 | FtpClient *getFtpClient(); 51 | }; 52 | 53 | } //end namespace MicroOcpp 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Authorization/AuthorizationList.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_AUTHORIZATIONLIST_H 6 | #define MO_AUTHORIZATIONLIST_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_LOCAL_AUTH 11 | 12 | #include 13 | #include 14 | 15 | #ifndef MO_LocalAuthListMaxLength 16 | #define MO_LocalAuthListMaxLength 48 17 | #endif 18 | 19 | #ifndef MO_SendLocalListMaxLength 20 | #define MO_SendLocalListMaxLength MO_LocalAuthListMaxLength 21 | #endif 22 | 23 | namespace MicroOcpp { 24 | 25 | class AuthorizationList : public MemoryManaged { 26 | private: 27 | int listVersion = 0; 28 | Vector localAuthorizationList; //sorted list 29 | public: 30 | AuthorizationList(); 31 | ~AuthorizationList(); 32 | 33 | AuthorizationData *get(const char *idTag); 34 | 35 | bool readJson(JsonArray localAuthorizationList, int listVersion, bool differential = false, bool compact = false); //compact: if true, then use compact non-ocpp representation 36 | void clear(); 37 | 38 | size_t getJsonCapacity(); 39 | void writeJson(JsonArray authListOut, bool compact = false); 40 | 41 | int getListVersion() {return listVersion;} 42 | size_t size(); //used in unit tests 43 | 44 | }; 45 | 46 | } 47 | 48 | #endif //MO_ENABLE_LOCAL_AUTH 49 | #endif 50 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Certificates/CertificateService.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_CERT_MGMT 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace MicroOcpp; 15 | 16 | CertificateService::CertificateService(Context& context) 17 | : MemoryManaged("v201.Certificates.CertificateService"), context(context) { 18 | 19 | context.getOperationRegistry().registerOperation("DeleteCertificate", [this] () { 20 | return new Ocpp201::DeleteCertificate(*this);}); 21 | context.getOperationRegistry().registerOperation("GetInstalledCertificateIds", [this] () { 22 | return new Ocpp201::GetInstalledCertificateIds(*this);}); 23 | context.getOperationRegistry().registerOperation("InstallCertificate", [this] () { 24 | return new Ocpp201::InstallCertificate(*this);}); 25 | } 26 | 27 | void CertificateService::setCertificateStore(std::unique_ptr certStore) { 28 | this->certStore = std::move(certStore); 29 | } 30 | 31 | CertificateStore *CertificateService::getCertificateStore() { 32 | return certStore.get(); 33 | } 34 | 35 | #endif //MO_ENABLE_CERT_MGMT 36 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetLocalListVersion.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_LOCAL_AUTH 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using MicroOcpp::Ocpp16::GetLocalListVersion; 15 | using MicroOcpp::JsonDoc; 16 | 17 | GetLocalListVersion::GetLocalListVersion(Model& model) : MemoryManaged("v16.Operation.", "GetLocalListVersion"), model(model) { 18 | 19 | } 20 | 21 | const char* GetLocalListVersion::getOperationType(){ 22 | return "GetLocalListVersion"; 23 | } 24 | 25 | void GetLocalListVersion::processReq(JsonObject payload) { 26 | //empty payload 27 | } 28 | 29 | std::unique_ptr GetLocalListVersion::createConf(){ 30 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 31 | JsonObject payload = doc->to(); 32 | 33 | auto authService = model.getAuthorizationService(); 34 | if (authService && authService->localAuthListEnabled()) { 35 | payload["listVersion"] = authService->getLocalListVersion(); 36 | } else { 37 | //TC_042_1_CS Get Local List Version (not supported) 38 | payload["listVersion"] = -1; 39 | } 40 | return doc; 41 | } 42 | 43 | #endif //MO_ENABLE_LOCAL_AUTH 44 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/OcppError.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_OCPPERROR_H 6 | #define MO_OCPPERROR_H 7 | 8 | #include 9 | #include 10 | 11 | namespace MicroOcpp { 12 | 13 | class NotImplemented : public Operation, public MemoryManaged { 14 | public: 15 | NotImplemented() : MemoryManaged("v16.CallError.", "NotImplemented") { } 16 | 17 | const char *getErrorCode() override { 18 | return "NotImplemented"; 19 | } 20 | }; 21 | 22 | class MsgBufferExceeded : public Operation, public MemoryManaged { 23 | private: 24 | size_t maxCapacity; 25 | size_t msgLen; 26 | public: 27 | MsgBufferExceeded(size_t maxCapacity, size_t msgLen) : MemoryManaged("v16.CallError.", "GenericError"), maxCapacity(maxCapacity), msgLen(msgLen) { } 28 | const char *getErrorCode() override { 29 | return "GenericError"; 30 | } 31 | const char *getErrorDescription() override { 32 | return "JSON too long or too many fields. Cannot deserialize"; 33 | } 34 | std::unique_ptr getErrorDetails() override { 35 | auto errDoc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(2)); 36 | JsonObject err = errDoc->to(); 37 | err["max_capacity"] = maxCapacity; 38 | err["msg_length"] = msgLen; 39 | return errDoc; 40 | } 41 | }; 42 | 43 | } //end namespace MicroOcpp 44 | #endif 45 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/StopTransaction.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_STOPTRANSACTION_H 6 | #define MO_STOPTRANSACTION_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class Model; 16 | 17 | class SampledValue; 18 | class MeterValue; 19 | 20 | class Transaction; 21 | 22 | namespace Ocpp16 { 23 | 24 | class StopTransaction : public Operation, public MemoryManaged { 25 | private: 26 | Model& model; 27 | std::shared_ptr transaction; 28 | Vector> transactionData; 29 | public: 30 | 31 | StopTransaction(Model& model, std::shared_ptr transaction); 32 | 33 | StopTransaction(Model& model, std::shared_ptr transaction, Vector> transactionData); 34 | 35 | const char* getOperationType() override; 36 | 37 | std::unique_ptr createReq() override; 38 | 39 | void processConf(JsonObject payload) override; 40 | 41 | bool processErr(const char *code, const char *description, JsonObject details) override; 42 | 43 | void processReq(JsonObject payload) override; 44 | 45 | std::unique_ptr createConf() override; 46 | }; 47 | 48 | } //end namespace Ocpp16 49 | } //end namespace MicroOcpp 50 | #endif 51 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/CancelReservation.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_RESERVATION 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using MicroOcpp::Ocpp16::CancelReservation; 14 | using MicroOcpp::JsonDoc; 15 | 16 | CancelReservation::CancelReservation(ReservationService& reservationService) : MemoryManaged("v16.Operation.", "CancelReservation"), reservationService(reservationService) { 17 | 18 | } 19 | 20 | const char* CancelReservation::getOperationType() { 21 | return "CancelReservation"; 22 | } 23 | 24 | void CancelReservation::processReq(JsonObject payload) { 25 | if (!payload.containsKey("reservationId")) { 26 | errorCode = "FormationViolation"; 27 | return; 28 | } 29 | 30 | if (auto reservation = reservationService.getReservationById(payload["reservationId"])) { 31 | found = true; 32 | reservation->clear(); 33 | } 34 | } 35 | 36 | std::unique_ptr CancelReservation::createConf(){ 37 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 38 | JsonObject payload = doc->to(); 39 | if (found) { 40 | payload["status"] = "Accepted"; 41 | } else { 42 | payload["status"] = "Rejected"; 43 | } 44 | return doc; 45 | } 46 | 47 | #endif //MO_ENABLE_RESERVATION 48 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Authorization/AuthorizationService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_AUTHORIZATIONSERVICE_H 6 | #define MO_AUTHORIZATIONSERVICE_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_LOCAL_AUTH 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace MicroOcpp { 18 | 19 | class Context; 20 | 21 | class AuthorizationService : public MemoryManaged { 22 | private: 23 | Context& context; 24 | std::shared_ptr filesystem; 25 | AuthorizationList localAuthorizationList; 26 | 27 | std::shared_ptr localAuthListEnabledBool; 28 | 29 | public: 30 | AuthorizationService(Context& context, std::shared_ptr filesystem); 31 | ~AuthorizationService(); 32 | 33 | bool loadLists(); 34 | 35 | AuthorizationData *getLocalAuthorization(const char *idTag); 36 | 37 | int getLocalListVersion(); 38 | bool localAuthListEnabled() const; 39 | size_t getLocalListSize(); //number of entries in current localAuthList; used in unit tests 40 | 41 | bool updateLocalList(JsonArray localAuthorizationListJson, int listVersion, bool differential); 42 | 43 | void notifyAuthorization(const char *idTag, JsonObject idTagInfo); 44 | }; 45 | 46 | } 47 | 48 | #endif //MO_ENABLE_LOCAL_AUTH 49 | #endif 50 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ClearCache.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using MicroOcpp::Ocpp16::ClearCache; 10 | using MicroOcpp::JsonDoc; 11 | 12 | ClearCache::ClearCache(std::shared_ptr filesystem) : MemoryManaged("v16.Operation.", "ClearCache"), filesystem(filesystem) { 13 | 14 | } 15 | 16 | const char* ClearCache::getOperationType(){ 17 | return "ClearCache"; 18 | } 19 | 20 | void ClearCache::processReq(JsonObject payload) { 21 | MO_DBG_WARN("Clear transaction log (Authorization Cache not supported)"); 22 | 23 | if (!filesystem) { 24 | //no persistency - nothing to do 25 | return; 26 | } 27 | 28 | success = FilesystemUtils::remove_if(filesystem, [] (const char *fname) -> bool { 29 | return !strncmp(fname, "sd", strlen("sd")) || 30 | !strncmp(fname, "tx", strlen("tx")) || 31 | !strncmp(fname, "op", strlen("op")); 32 | }); 33 | } 34 | 35 | std::unique_ptr ClearCache::createConf(){ 36 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 37 | JsonObject payload = doc->to(); 38 | if (success) { 39 | payload["status"] = "Accepted"; //"Accepted", because the intended postcondition is true 40 | } else { 41 | payload["status"] = "Rejected"; 42 | } 43 | return doc; 44 | } 45 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/Reset.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef RESET_H 6 | #define RESET_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace MicroOcpp { 13 | 14 | class Model; 15 | 16 | namespace Ocpp16 { 17 | 18 | class Reset : public Operation, public MemoryManaged { 19 | private: 20 | Model& model; 21 | bool resetAccepted {false}; 22 | public: 23 | Reset(Model& model); 24 | 25 | const char* getOperationType() override; 26 | 27 | void processReq(JsonObject payload) override; 28 | 29 | std::unique_ptr createConf() override; 30 | }; 31 | 32 | } //end namespace Ocpp16 33 | } //end namespace MicroOcpp 34 | 35 | #if MO_ENABLE_V201 36 | 37 | namespace MicroOcpp { 38 | namespace Ocpp201 { 39 | 40 | class ResetService; 41 | 42 | class Reset : public Operation, public MemoryManaged { 43 | private: 44 | ResetService& resetService; 45 | ResetStatus status; 46 | const char *errorCode = nullptr; 47 | public: 48 | Reset(ResetService& resetService); 49 | 50 | const char* getOperationType() override; 51 | 52 | void processReq(JsonObject payload) override; 53 | 54 | std::unique_ptr createConf() override; 55 | 56 | const char *getErrorCode() override {return errorCode;} 57 | }; 58 | 59 | } //end namespace Ocpp201 60 | } //end namespace MicroOcpp 61 | 62 | #endif //MO_ENABLE_V201 63 | #endif 64 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Heartbeat/HeartbeatService.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace MicroOcpp; 13 | 14 | HeartbeatService::HeartbeatService(Context& context) : MemoryManaged("v16.Heartbeat.HeartbeatService"), context(context) { 15 | heartbeatIntervalInt = declareConfiguration("HeartbeatInterval", 86400); 16 | registerConfigurationValidator("HeartbeatInterval", VALIDATE_UNSIGNED_INT); 17 | lastHeartbeat = mocpp_tick_ms(); 18 | 19 | //Register message handler for TriggerMessage operation 20 | context.getOperationRegistry().registerOperation("Heartbeat", [&context] () { 21 | return new Ocpp16::Heartbeat(context.getModel());}); 22 | } 23 | 24 | void HeartbeatService::loop() { 25 | unsigned long hbInterval = heartbeatIntervalInt->getInt(); 26 | hbInterval *= 1000UL; //conversion s -> ms 27 | unsigned long now = mocpp_tick_ms(); 28 | 29 | if (now - lastHeartbeat >= hbInterval) { 30 | lastHeartbeat = now; 31 | 32 | auto heartbeat = makeRequest(new Ocpp16::Heartbeat(context.getModel())); 33 | // Heartbeats can not deviate more than 4s from the configured interval 34 | heartbeat->setTimeout(std::min(4000UL, hbInterval)); 35 | context.initiateRequest(std::move(heartbeat)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/esp-idf.yml: -------------------------------------------------------------------------------- 1 | # matth-x/MicroOcpp 2 | # Copyright Matthias Akstaller 2019 - 2024 3 | # MIT License 4 | 5 | name: ESP-IDF CI 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | pull_request: 13 | 14 | jobs: 15 | build: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout ESP-IDF example folder structure 21 | uses: actions/checkout@v3 22 | with: 23 | sparse-checkout: examples/ESP-IDF 24 | - name: Clean sumodules folders template 25 | run: rm -r ./examples/ESP-IDF/components/* 26 | - name: Checkout main repo 27 | uses: actions/checkout@v3 28 | with: 29 | path: examples/ESP-IDF/components/MicroOcpp 30 | - name: Checkout Mongoose 31 | uses: actions/checkout@v3 32 | with: 33 | repository: cesanta/mongoose-esp-idf 34 | path: examples/ESP-IDF/components/mongoose 35 | submodules: 'recursive' 36 | - name: Checkout Mongoose WS adapter 37 | uses: actions/checkout@v3 38 | with: 39 | repository: matth-x/MicroOcppMongoose 40 | ref: v1.2.0 41 | path: examples/ESP-IDF/components/MicroOcppMongoose 42 | - name: Checkout ArduinoJson 43 | uses: actions/checkout@v3 44 | with: 45 | repository: bblanchon/ArduinoJson 46 | ref: 3e1be980d93e47b2a0073efeeb9a9396fd7a83be 47 | path: examples/ESP-IDF/components/ArduinoJson 48 | - name: esp-idf build 49 | uses: espressif/esp-idf-ci-action@v1 50 | with: 51 | esp_idf_version: v4.4 52 | target: esp32 53 | path: './examples/ESP-IDF' 54 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/MeterValues.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_METERVALUES_H 6 | #define MO_METERVALUES_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace MicroOcpp { 13 | 14 | class Model; 15 | class MeterValue; 16 | class Transaction; 17 | 18 | namespace Ocpp16 { 19 | 20 | class MeterValues : public Operation, public MemoryManaged { 21 | private: 22 | Model& model; //for adjusting the timestamp if MeterValue has been created before BootNotification 23 | MeterValue *meterValue = nullptr; 24 | std::unique_ptr meterValueOwnership; 25 | 26 | unsigned int connectorId = 0; 27 | 28 | std::shared_ptr transaction; 29 | 30 | public: 31 | MeterValues(Model& model, MeterValue *meterValue, unsigned int connectorId, std::shared_ptr transaction = nullptr); 32 | MeterValues(Model& model, std::unique_ptr meterValue, unsigned int connectorId, std::shared_ptr transaction = nullptr); 33 | 34 | MeterValues(Model& model); //for debugging only. Make this for the server pendant 35 | 36 | ~MeterValues(); 37 | 38 | const char* getOperationType() override; 39 | 40 | std::unique_ptr createReq() override; 41 | 42 | void processConf(JsonObject payload) override; 43 | 44 | void processReq(JsonObject payload) override; 45 | 46 | std::unique_ptr createConf() override; 47 | }; 48 | 49 | } //end namespace Ocpp16 50 | } //end namespace MicroOcpp 51 | #endif 52 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/UuidUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace MicroOcpp { 7 | 8 | #define UUID_STR_LEN 36 9 | 10 | bool generateUUID(char *uuidBuffer, size_t len) { 11 | if (len < UUID_STR_LEN + 1) 12 | { 13 | return false; 14 | } 15 | 16 | uint32_t ar[4]; 17 | for (uint8_t i = 0; i < 4; i++) { 18 | ar[i] = mocpp_rng(); 19 | } 20 | 21 | // Conforming to RFC 4122 Specification 22 | // - byte 7: four most significant bits ==> 0100 --> always 4 23 | // - byte 9: two most significant bits ==> 10 --> always {8, 9, A, B}. 24 | // 25 | // patch bits for version 1 and variant 4 here 26 | ar[1] &= 0xFFF0FFFF; // remove 4 bits. 27 | ar[1] |= 0x00040000; // variant 4 28 | ar[2] &= 0xFFFFFFF3; // remove 2 bits 29 | ar[2] |= 0x00000008; // version 1 30 | 31 | // loop through the random 16 byte array 32 | for (uint8_t i = 0, j = 0; i < 16; i++) { 33 | // multiples of 4 between 8 and 20 get a -. 34 | // note we are processing 2 digits in one loop. 35 | if ((i & 0x1) == 0) { 36 | if ((4 <= i) && (i <= 10)) { 37 | uuidBuffer[j++] = '-'; 38 | } 39 | } 40 | 41 | // encode the byte as two hex characters 42 | uint8_t nr = i / 4; 43 | uint8_t xx = ar[nr]; 44 | uint8_t ch = xx & 0x0F; 45 | uuidBuffer[j++] = (ch < 10)? '0' + ch : ('a' - 10) + ch; 46 | 47 | ch = (xx >> 4) & 0x0F; 48 | ar[nr] >>= 8; 49 | uuidBuffer[j++] = (ch < 10)? '0' + ch : ('a' - 10) + ch; 50 | } 51 | 52 | uuidBuffer[UUID_STR_LEN] = 0; 53 | return true; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/DiagnosticsStatusNotification.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::DiagnosticsStatusNotification; 11 | using MicroOcpp::JsonDoc; 12 | 13 | DiagnosticsStatusNotification::DiagnosticsStatusNotification(DiagnosticsStatus status) : MemoryManaged("v16.Operation.", "DiagnosticsStatusNotification"), status(status) { 14 | 15 | } 16 | 17 | const char *DiagnosticsStatusNotification::cstrFromStatus(DiagnosticsStatus status) { 18 | switch (status) { 19 | case (DiagnosticsStatus::Idle): 20 | return "Idle"; 21 | break; 22 | case (DiagnosticsStatus::Uploaded): 23 | return "Uploaded"; 24 | break; 25 | case (DiagnosticsStatus::UploadFailed): 26 | return "UploadFailed"; 27 | break; 28 | case (DiagnosticsStatus::Uploading): 29 | return "Uploading"; 30 | break; 31 | } 32 | return nullptr; //cannot be reached 33 | } 34 | 35 | std::unique_ptr DiagnosticsStatusNotification::createReq() { 36 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 37 | JsonObject payload = doc->to(); 38 | payload["status"] = cstrFromStatus(status); 39 | return doc; 40 | } 41 | 42 | void DiagnosticsStatusNotification::processConf(JsonObject payload){ 43 | // no payload, nothing to do 44 | } 45 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/Context.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | using namespace MicroOcpp; 13 | 14 | Context::Context(Connection& connection, std::shared_ptr filesystem, uint16_t bootNr, ProtocolVersion version) 15 | : MemoryManaged("Context"), connection(connection), model{version, bootNr}, reqQueue{connection, operationRegistry} { 16 | 17 | } 18 | 19 | Context::~Context() { 20 | 21 | } 22 | 23 | void Context::loop() { 24 | connection.loop(); 25 | reqQueue.loop(); 26 | model.loop(); 27 | } 28 | 29 | void Context::initiateRequest(std::unique_ptr op) { 30 | if (!op) { 31 | MO_DBG_ERR("invalid arg"); 32 | return; 33 | } 34 | reqQueue.sendRequest(std::move(op)); 35 | } 36 | 37 | Model& Context::getModel() { 38 | return model; 39 | } 40 | 41 | OperationRegistry& Context::getOperationRegistry() { 42 | return operationRegistry; 43 | } 44 | 45 | const ProtocolVersion& Context::getVersion() { 46 | return model.getVersion(); 47 | } 48 | 49 | Connection& Context::getConnection() { 50 | return connection; 51 | } 52 | 53 | RequestQueue& Context::getRequestQueue() { 54 | return reqQueue; 55 | } 56 | 57 | void Context::setFtpClient(std::unique_ptr ftpClient) { 58 | this->ftpClient = std::move(ftpClient); 59 | } 60 | 61 | FtpClient *Context::getFtpClient() { 62 | return ftpClient.get(); 63 | } 64 | -------------------------------------------------------------------------------- /src/MicroOcpp/Debug.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #include 8 | 9 | const char *level_label [] = { 10 | "", //MO_DL_NONE 0x00 11 | "ERROR", //MO_DL_ERROR 0x01 12 | "warning", //MO_DL_WARN 0x02 13 | "info", //MO_DL_INFO 0x03 14 | "debug", //MO_DL_DEBUG 0x04 15 | "verbose" //MO_DL_VERBOSE 0x05 16 | }; 17 | 18 | #if MO_DBG_FORMAT == MO_DF_MINIMAL 19 | void mo_dbg_print_prefix(int level, const char *fn, int line) { 20 | (void)0; 21 | } 22 | 23 | #elif MO_DBG_FORMAT == MO_DF_COMPACT 24 | void mo_dbg_print_prefix(int level, const char *fn, int line) { 25 | size_t l = strlen(fn); 26 | size_t r = l; 27 | while (l > 0 && fn[l-1] != '/' && fn[l-1] != '\\') { 28 | l--; 29 | if (fn[l] == '.') r = l; 30 | } 31 | MO_CONSOLE_PRINTF("%.*s:%i ", (int) (r - l), fn + l, line); 32 | } 33 | 34 | #elif MO_DBG_FORMAT == MO_DF_FILE_LINE 35 | void mo_dbg_print_prefix(int level, const char *fn, int line) { 36 | size_t l = strlen(fn); 37 | while (l > 0 && fn[l-1] != '/' && fn[l-1] != '\\') { 38 | l--; 39 | } 40 | MO_CONSOLE_PRINTF("[MO] %s (%s:%i): ", level_label[level], fn + l, line); 41 | } 42 | 43 | #elif MO_DBG_FORMAT == MO_DF_FULL 44 | void mo_dbg_print_prefix(int level, const char *fn, int line) { 45 | MO_CONSOLE_PRINTF("[MO] %s (%s:%i): ", level_label[level], fn, line); 46 | } 47 | 48 | #else 49 | #error invalid MO_DBG_FORMAT definition 50 | #endif 51 | 52 | void mo_dbg_print_suffix() { 53 | MO_CONSOLE_PRINTF("\n"); 54 | } 55 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/DataTransfer.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | 8 | using MicroOcpp::Ocpp16::DataTransfer; 9 | using MicroOcpp::JsonDoc; 10 | 11 | DataTransfer::DataTransfer() : MemoryManaged("v16.Operation.", "DataTransfer") { 12 | 13 | } 14 | 15 | DataTransfer::DataTransfer(const String &msg) : MemoryManaged("v16.Operation.", "DataTransfer"), msg{makeString(getMemoryTag(), msg.c_str())} { 16 | 17 | } 18 | 19 | const char* DataTransfer::getOperationType(){ 20 | return "DataTransfer"; 21 | } 22 | 23 | std::unique_ptr DataTransfer::createReq() { 24 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(2) + (msg.length() + 1)); 25 | JsonObject payload = doc->to(); 26 | payload["vendorId"] = "CustomVendor"; 27 | payload["data"] = msg; 28 | return doc; 29 | } 30 | 31 | void DataTransfer::processConf(JsonObject payload){ 32 | const char *status = payload["status"] | "Invalid"; 33 | 34 | if (!strcmp(status, "Accepted")) { 35 | MO_DBG_DEBUG("Request has been accepted"); 36 | } else { 37 | MO_DBG_INFO("Request has been denied"); 38 | } 39 | } 40 | 41 | void DataTransfer::processReq(JsonObject payload) { 42 | // Do nothing - we're just required to reject these DataTransfer requests 43 | } 44 | 45 | std::unique_ptr DataTransfer::createConf(){ 46 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 47 | JsonObject payload = doc->to(); 48 | payload["status"] = "Rejected"; 49 | return doc; 50 | } 51 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/ConfigurationOptions.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CONFIGURATIONOPTIONS_H 6 | #define MO_CONFIGURATIONOPTIONS_H 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | struct OCPP_FilesystemOpt { 15 | bool use; 16 | bool mount; 17 | bool formatFsOnFail; 18 | }; 19 | 20 | #ifdef __cplusplus 21 | } 22 | 23 | namespace MicroOcpp { 24 | 25 | class FilesystemOpt{ 26 | private: 27 | bool use = false; 28 | bool mount = false; 29 | bool formatFsOnFail = false; 30 | public: 31 | enum Mode : uint8_t {Deactivate, Use, Use_Mount, Use_Mount_FormatOnFail}; 32 | 33 | FilesystemOpt() = default; 34 | FilesystemOpt(Mode mode) { 35 | switch (mode) { 36 | case (FilesystemOpt::Use_Mount_FormatOnFail): 37 | formatFsOnFail = true; 38 | //fallthrough 39 | case (FilesystemOpt::Use_Mount): 40 | mount = true; 41 | //fallthrough 42 | case (FilesystemOpt::Use): 43 | use = true; 44 | break; 45 | default: 46 | break; 47 | } 48 | } 49 | FilesystemOpt(struct OCPP_FilesystemOpt fsopt) { 50 | this->use = fsopt.use; 51 | this->mount = fsopt.mount; 52 | this->formatFsOnFail = fsopt.formatFsOnFail; 53 | } 54 | 55 | bool accessAllowed() {return use;} 56 | bool mustMount() {return mount;} 57 | bool formatOnFail() {return formatFsOnFail;} 58 | }; 59 | 60 | } //end namespace MicroOcpp 61 | 62 | #endif //__cplusplus 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetVariables.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_GETVARIABLES_H 6 | #define MO_GETVARIABLES_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | class VariableService; 19 | 20 | namespace Ocpp201 { 21 | 22 | // GetVariableDataType (2.25) and 23 | // GetVariableResultType (2.26) 24 | struct GetVariableData { 25 | // GetVariableDataType 26 | Variable::AttributeType attributeType = Variable::AttributeType::Actual; 27 | String componentName; 28 | int componentEvseId = -1; 29 | int componentEvseConnectorId = -1; 30 | String variableName; 31 | 32 | // GetVariableResultType 33 | GetVariableStatus attributeStatus; 34 | Variable *variable = nullptr; 35 | 36 | GetVariableData(const char *memory_tag = nullptr); 37 | }; 38 | 39 | class GetVariables : public Operation, public MemoryManaged { 40 | private: 41 | VariableService& variableService; 42 | Vector queries; 43 | 44 | const char *errorCode = nullptr; 45 | public: 46 | GetVariables(VariableService& variableService); 47 | 48 | const char* getOperationType() override; 49 | 50 | void processReq(JsonObject payload) override; 51 | 52 | std::unique_ptr createConf() override; 53 | 54 | const char *getErrorCode() override {return errorCode;} 55 | 56 | }; 57 | 58 | } //namespace Ocpp201 59 | } //namespace MicroOcpp 60 | 61 | #endif //MO_ENABLE_V201 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RemoteStopTransaction.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::RemoteStopTransaction; 11 | using MicroOcpp::JsonDoc; 12 | 13 | RemoteStopTransaction::RemoteStopTransaction(Model& model) : MemoryManaged("v16.Operation.", "RemoteStopTransaction"), model(model) { 14 | 15 | } 16 | 17 | const char* RemoteStopTransaction::getOperationType(){ 18 | return "RemoteStopTransaction"; 19 | } 20 | 21 | void RemoteStopTransaction::processReq(JsonObject payload) { 22 | 23 | if (!payload.containsKey("transactionId")) { 24 | errorCode = "FormationViolation"; 25 | } 26 | int transactionId = payload["transactionId"]; 27 | 28 | for (unsigned int cId = 0; cId < model.getNumConnectors(); cId++) { 29 | auto connector = model.getConnector(cId); 30 | if (connector->getTransaction() && 31 | connector->getTransaction()->getTransactionId() == transactionId) { 32 | connector->endTransaction(nullptr, "Remote"); 33 | accepted = true; 34 | } 35 | } 36 | } 37 | 38 | std::unique_ptr RemoteStopTransaction::createConf(){ 39 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 40 | JsonObject payload = doc->to(); 41 | if (accepted){ 42 | payload["status"] = "Accepted"; 43 | } else { 44 | payload["status"] = "Rejected"; 45 | } 46 | return doc; 47 | } 48 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/SetVariables.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_SETVARIABLES_H 6 | #define MO_SETVARIABLES_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | class VariableService; 19 | 20 | namespace Ocpp201 { 21 | 22 | // SetVariableDataType (2.44) and 23 | // SetVariableResultType (2.45) 24 | struct SetVariableData { 25 | // SetVariableDataType 26 | Variable::AttributeType attributeType = Variable::AttributeType::Actual; 27 | const char *attributeValue; // will become invalid after processReq 28 | String componentName; 29 | int componentEvseId = -1; 30 | int componentEvseConnectorId = -1; 31 | String variableName; 32 | 33 | // SetVariableResultType 34 | SetVariableStatus attributeStatus; 35 | 36 | SetVariableData(const char *memory_tag = nullptr); 37 | }; 38 | 39 | class SetVariables : public Operation, public MemoryManaged { 40 | private: 41 | VariableService& variableService; 42 | Vector queries; 43 | 44 | const char *errorCode = nullptr; 45 | public: 46 | SetVariables(VariableService& variableService); 47 | 48 | const char* getOperationType() override; 49 | 50 | void processReq(JsonObject payload) override; 51 | 52 | std::unique_ptr createConf() override; 53 | 54 | const char *getErrorCode() override {return errorCode;} 55 | 56 | }; 57 | 58 | } //namespace Ocpp201 59 | } //namespace MicroOcpp 60 | 61 | #endif //MO_ENABLE_V201 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /tests/Security.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_V201 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "./helpers/testHelper.h" 20 | 21 | #define BASE_TIME "2023-01-01T00:00:00.000Z" 22 | 23 | using namespace MicroOcpp; 24 | 25 | 26 | TEST_CASE( "Security" ) { 27 | printf("\nRun %s\n", "Security"); 28 | 29 | mocpp_set_timer(custom_timer_cb); 30 | 31 | //initialize Context with dummy socket 32 | LoopbackConnection loopback; 33 | auto filesystem = makeDefaultFilesystemAdapter(FilesystemOpt::Use_Mount_FormatOnFail); 34 | mocpp_initialize(loopback, 35 | ChargerCredentials(), 36 | filesystem, 37 | false, 38 | ProtocolVersion(2,0,1)); 39 | 40 | SECTION("Manual SecurityEventNotification") { 41 | 42 | loop(); 43 | 44 | MO_MEM_RESET(); 45 | 46 | getOcppContext()->initiateRequest(makeRequest(new Ocpp201::SecurityEventNotification( 47 | "ReconfigurationOfSecurityParameters", 48 | getOcppContext()->getModel().getClock().now()))); 49 | 50 | loop(); 51 | 52 | MO_MEM_PRINT_STATS(); 53 | } 54 | 55 | mocpp_deinitialize(); 56 | } 57 | 58 | #endif // MO_ENABLE_V201 59 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/Configuration.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CONFIGURATION_H 6 | #define MO_CONFIGURATION_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #define CONFIGURATION_FN (MO_FILENAME_PREFIX "ocpp-config.jsn") 16 | #define CONFIGURATION_VOLATILE "/volatile" 17 | #define MO_KEYVALUE_FN (MO_FILENAME_PREFIX "client-state.jsn") 18 | 19 | namespace MicroOcpp { 20 | 21 | template 22 | std::shared_ptr declareConfiguration(const char *key, T factoryDefault, const char *filename = CONFIGURATION_FN, bool readonly = false, bool rebootRequired = false, bool accessible = true); 23 | 24 | std::function *getConfigurationValidator(const char *key); 25 | void registerConfigurationValidator(const char *key, std::function validator); 26 | 27 | void addConfigurationContainer(std::shared_ptr container); 28 | 29 | Configuration *getConfigurationPublic(const char *key); 30 | Vector getConfigurationContainersPublic(); 31 | 32 | bool configuration_init(std::shared_ptr filesytem); 33 | void configuration_deinit(); 34 | 35 | bool configuration_load(const char *filename = nullptr); 36 | 37 | bool configuration_save(); 38 | 39 | bool configuration_clean_unused(); //remove configs which haven't been accessed 40 | 41 | //default implementation for common validator 42 | bool VALIDATE_UNSIGNED_INT(const char*); 43 | 44 | } //end namespace MicroOcpp 45 | #endif 46 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/SecurityEventNotification.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_V201 8 | 9 | #include 10 | #include 11 | 12 | using MicroOcpp::Ocpp201::SecurityEventNotification; 13 | using MicroOcpp::JsonDoc; 14 | 15 | SecurityEventNotification::SecurityEventNotification(const char *type, const Timestamp& timestamp) : MemoryManaged("v201.Operation.", "SecurityEventNotification"), type(makeString(getMemoryTag(), type ? type : "")), timestamp(timestamp) { 16 | 17 | } 18 | 19 | const char* SecurityEventNotification::getOperationType(){ 20 | return "SecurityEventNotification"; 21 | } 22 | 23 | std::unique_ptr SecurityEventNotification::createReq() { 24 | 25 | auto doc = makeJsonDoc(getMemoryTag(), 26 | JSON_OBJECT_SIZE(2) + 27 | JSONDATE_LENGTH + 1); 28 | 29 | JsonObject payload = doc->to(); 30 | 31 | payload["type"] = type.c_str(); 32 | 33 | char timestampStr [JSONDATE_LENGTH + 1]; 34 | timestamp.toJsonString(timestampStr, sizeof(timestampStr)); 35 | payload["timestamp"] = timestampStr; 36 | 37 | return doc; 38 | } 39 | 40 | void SecurityEventNotification::processConf(JsonObject) { 41 | //empty payload 42 | } 43 | 44 | void SecurityEventNotification::processReq(JsonObject payload) { 45 | /** 46 | * Ignore Contents of this Req-message, because this is for debug purposes only 47 | */ 48 | } 49 | 50 | std::unique_ptr SecurityEventNotification::createConf() { 51 | return createEmptyDocument(); 52 | } 53 | 54 | #endif // MO_ENABLE_V201 55 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/Authorize.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef AUTHORIZE_H 6 | #define AUTHORIZE_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace MicroOcpp { 13 | 14 | class Model; 15 | 16 | namespace Ocpp16 { 17 | 18 | class Authorize : public Operation, public MemoryManaged { 19 | private: 20 | Model& model; 21 | char idTag [IDTAG_LEN_MAX + 1] = {'\0'}; 22 | public: 23 | Authorize(Model& model, const char *idTag); 24 | 25 | const char* getOperationType() override; 26 | 27 | std::unique_ptr createReq() override; 28 | 29 | void processConf(JsonObject payload) override; 30 | 31 | void processReq(JsonObject payload) override; 32 | 33 | std::unique_ptr createConf() override; 34 | 35 | }; 36 | 37 | } //end namespace Ocpp16 38 | } //end namespace MicroOcpp 39 | 40 | #if MO_ENABLE_V201 41 | 42 | #include 43 | 44 | namespace MicroOcpp { 45 | namespace Ocpp201 { 46 | 47 | class Authorize : public Operation, public MemoryManaged { 48 | private: 49 | Model& model; 50 | IdToken idToken; 51 | public: 52 | Authorize(Model& model, const IdToken& idToken); 53 | 54 | const char* getOperationType() override; 55 | 56 | std::unique_ptr createReq() override; 57 | 58 | void processConf(JsonObject payload) override; 59 | 60 | void processReq(JsonObject payload) override; 61 | 62 | std::unique_ptr createConf() override; 63 | 64 | }; 65 | 66 | } //end namespace Ocpp201 67 | } //end namespace MicroOcpp 68 | 69 | #endif //MO_ENABLE_V201 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/UpdateFirmware.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::UpdateFirmware; 11 | using MicroOcpp::JsonDoc; 12 | 13 | UpdateFirmware::UpdateFirmware(FirmwareService& fwService) : MemoryManaged("v16.Operation.", "UpdateFirmware"), fwService(fwService) { 14 | 15 | } 16 | 17 | void UpdateFirmware::processReq(JsonObject payload) { 18 | 19 | const char *location = payload["location"] | ""; 20 | //check location URL. Maybe introduce Same-Origin-Policy? 21 | if (!*location) { 22 | errorCode = "FormationViolation"; 23 | return; 24 | } 25 | 26 | int retries = payload["retries"] | 1; 27 | int retryInterval = payload["retryInterval"] | 180; 28 | if (retries < 0 || retryInterval < 0) { 29 | errorCode = "PropertyConstraintViolation"; 30 | return; 31 | } 32 | 33 | //check the integrity of retrieveDate 34 | if (!payload.containsKey("retrieveDate")) { 35 | errorCode = "FormationViolation"; 36 | return; 37 | } 38 | 39 | Timestamp retrieveDate; 40 | if (!retrieveDate.setTime(payload["retrieveDate"] | "Invalid")) { 41 | errorCode = "PropertyConstraintViolation"; 42 | MO_DBG_WARN("bad time format"); 43 | return; 44 | } 45 | 46 | fwService.scheduleFirmwareUpdate(location, retrieveDate, (unsigned int) retries, (unsigned int) retryInterval); 47 | } 48 | 49 | std::unique_ptr UpdateFirmware::createConf(){ 50 | return createEmptyDocument(); 51 | } 52 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Reservation/ReservationService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_RESERVATIONSERVICE_H 6 | #define MO_RESERVATIONSERVICE_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_RESERVATION 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace MicroOcpp { 18 | 19 | class Context; 20 | 21 | class ReservationService : public MemoryManaged { 22 | private: 23 | Context& context; 24 | 25 | const int maxReservations; // = number of physical connectors 26 | Vector> reservations; 27 | 28 | std::shared_ptr reserveConnectorZeroSupportedBool; 29 | 30 | public: 31 | ReservationService(Context& context, unsigned int numConnectors); 32 | 33 | void loop(); 34 | 35 | Reservation *getReservation(unsigned int connectorId); //by connectorId 36 | Reservation *getReservation(const char *idTag, const char *parentIdTag = nullptr); //by idTag 37 | 38 | /* 39 | * Get prevailing reservation for a charging session authorized by idTag/parentIdTag at connectorId. 40 | * returns nullptr if there is no reservation in question 41 | * returns a reservation if applicable. Caller must check if idTag/parentIdTag match before starting a transaction 42 | */ 43 | Reservation *getReservation(unsigned int connectorId, const char *idTag, const char *parentIdtag = nullptr); 44 | 45 | Reservation *getReservationById(int reservationId); 46 | 47 | bool updateReservation(int reservationId, unsigned int connectorId, Timestamp expiryDate, const char *idTag, const char *parentIdTag = nullptr); 48 | }; 49 | 50 | } 51 | 52 | #endif //MO_ENABLE_RESERVATION 53 | #endif 54 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Certificates/Certificate_c.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CERTIFICATE_C_H 6 | #define MO_CERTIFICATE_C_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_CERT_MGMT 11 | 12 | #include 13 | 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | typedef struct ocpp_cert_chain_hash { 21 | void *user_data; //set this at your choice. MO passes it back to the functions below 22 | 23 | enum GetCertificateIdType certType; 24 | ocpp_cert_hash certHashData; 25 | //ocpp_cert_hash *childCertificateHashData; 26 | 27 | struct ocpp_cert_chain_hash *next; //link to next list element if result of getCertificateIds 28 | 29 | void (*invalidate)(void *user_data); //free resources here. Guaranteed to be called 30 | } ocpp_cert_chain_hash; 31 | 32 | typedef struct ocpp_cert_store { 33 | void *user_data; //set this at your choice. MO passes it back to the functions below 34 | 35 | enum GetInstalledCertificateStatus (*getCertificateIds)(void *user_data, const enum GetCertificateIdType certType [], size_t certTypeLen, ocpp_cert_chain_hash **out); 36 | enum DeleteCertificateStatus (*deleteCertificate)(void *user_data, const ocpp_cert_hash *hash); 37 | enum InstallCertificateStatus (*installCertificate)(void *user_data, enum InstallCertificateType certType, const char *cert); 38 | } ocpp_cert_store; 39 | 40 | #ifdef __cplusplus 41 | } //extern "C" 42 | 43 | #include 44 | 45 | namespace MicroOcpp { 46 | 47 | std::unique_ptr makeCertificateStoreCwrapper(ocpp_cert_store *certstore); 48 | 49 | } //namespace MicroOcpp 50 | 51 | #endif //__cplusplus 52 | 53 | #endif //MO_ENABLE_CERT_MGMT 54 | #endif 55 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ChangeAvailability.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CHANGEAVAILABILITY_H 6 | #define MO_CHANGEAVAILABILITY_H 7 | 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | class Model; 13 | 14 | namespace Ocpp16 { 15 | 16 | class ChangeAvailability : public Operation, public MemoryManaged { 17 | private: 18 | Model& model; 19 | bool scheduled = false; 20 | bool accepted = false; 21 | 22 | const char *errorCode {nullptr}; 23 | public: 24 | ChangeAvailability(Model& model); 25 | 26 | const char* getOperationType() override; 27 | 28 | void processReq(JsonObject payload) override; 29 | 30 | std::unique_ptr createConf() override; 31 | 32 | const char *getErrorCode() override {return errorCode;} 33 | }; 34 | 35 | } //end namespace Ocpp16 36 | } //end namespace MicroOcpp 37 | 38 | #if MO_ENABLE_V201 39 | 40 | #include 41 | #include 42 | 43 | namespace MicroOcpp { 44 | 45 | class AvailabilityService; 46 | 47 | namespace Ocpp201 { 48 | 49 | class ChangeAvailability : public Operation, public MemoryManaged { 50 | private: 51 | AvailabilityService& availabilityService; 52 | ChangeAvailabilityStatus status = ChangeAvailabilityStatus::Rejected; 53 | 54 | const char *errorCode {nullptr}; 55 | public: 56 | ChangeAvailability(AvailabilityService& availabilityService); 57 | 58 | const char* getOperationType() override; 59 | 60 | void processReq(JsonObject payload) override; 61 | 62 | std::unique_ptr createConf() override; 63 | 64 | const char *getErrorCode() override {return errorCode;} 65 | }; 66 | 67 | } //end namespace Ocpp201 68 | } //end namespace MicroOcpp 69 | 70 | #endif //MO_ENABLE_V201 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Metering/MeteringService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_METERINGSERVICE_H 6 | #define MO_METERINGSERVICE_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace MicroOcpp { 17 | 18 | class Context; 19 | class Request; 20 | class FilesystemAdapter; 21 | 22 | class MeteringService : public MemoryManaged { 23 | private: 24 | Context& context; 25 | MeterStore meterStore; 26 | 27 | Vector> connectors; 28 | public: 29 | MeteringService(Context& context, int numConnectors, std::shared_ptr filesystem); 30 | 31 | void loop(); 32 | 33 | void addMeterValueSampler(int connectorId, std::unique_ptr meterValueSampler); 34 | 35 | std::unique_ptr readTxEnergyMeter(int connectorId, ReadingContext reason); 36 | 37 | std::unique_ptr takeTriggeredMeterValues(int connectorId); //snapshot of all meters now 38 | 39 | void beginTxMeterData(Transaction *transaction); 40 | 41 | std::shared_ptr endTxMeterData(Transaction *transaction); //use return value to keep data in cache 42 | 43 | void abortTxMeterData(unsigned int connectorId); //call this to free resources if txMeterData record is not ended normally. Does not remove files 44 | 45 | std::shared_ptr getStopTxMeterData(Transaction *transaction); //prefer endTxMeterData when possible 46 | 47 | bool removeTxMeterData(unsigned int connectorId, unsigned int txNr); 48 | 49 | int getNumConnectors() {return connectors.size();} 50 | }; 51 | 52 | } //end namespace MicroOcpp 53 | #endif 54 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RequestStopTransaction.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_V201 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using MicroOcpp::Ocpp201::RequestStopTransaction; 14 | using MicroOcpp::JsonDoc; 15 | 16 | RequestStopTransaction::RequestStopTransaction(RemoteControlService& rcService) : MemoryManaged("v201.Operation.", "RequestStopTransaction"), rcService(rcService) { 17 | 18 | } 19 | 20 | const char* RequestStopTransaction::getOperationType(){ 21 | return "RequestStopTransaction"; 22 | } 23 | 24 | void RequestStopTransaction::processReq(JsonObject payload) { 25 | 26 | if (!payload.containsKey("transactionId") || 27 | !payload["transactionId"].is() || 28 | strlen(payload["transactionId"].as()) > MO_TXID_LEN_MAX) { 29 | errorCode = "FormationViolation"; 30 | return; 31 | } 32 | 33 | status = rcService.requestStopTransaction(payload["transactionId"].as()); 34 | } 35 | 36 | std::unique_ptr RequestStopTransaction::createConf(){ 37 | 38 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 39 | JsonObject payload = doc->to(); 40 | 41 | const char *statusCstr = ""; 42 | 43 | switch (status) { 44 | case RequestStartStopStatus_Accepted: 45 | statusCstr = "Accepted"; 46 | break; 47 | case RequestStartStopStatus_Rejected: 48 | statusCstr = "Rejected"; 49 | break; 50 | default: 51 | MO_DBG_ERR("internal error"); 52 | break; 53 | } 54 | 55 | payload["status"] = statusCstr; 56 | 57 | return doc; 58 | } 59 | 60 | #endif // MO_ENABLE_V201 61 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/FirmwareStatusNotification.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::FirmwareStatusNotification; 11 | using MicroOcpp::JsonDoc; 12 | 13 | FirmwareStatusNotification::FirmwareStatusNotification(FirmwareStatus status) : MemoryManaged("v16.Operation.", "FirmwareStatusNotification"), status{status} { 14 | 15 | } 16 | 17 | const char *FirmwareStatusNotification::cstrFromFwStatus(FirmwareStatus status) { 18 | switch (status) { 19 | case (FirmwareStatus::Downloaded): 20 | return "Downloaded"; 21 | break; 22 | case (FirmwareStatus::DownloadFailed): 23 | return "DownloadFailed"; 24 | break; 25 | case (FirmwareStatus::Downloading): 26 | return "Downloading"; 27 | break; 28 | case (FirmwareStatus::Idle): 29 | return "Idle"; 30 | break; 31 | case (FirmwareStatus::InstallationFailed): 32 | return "InstallationFailed"; 33 | break; 34 | case (FirmwareStatus::Installing): 35 | return "Installing"; 36 | break; 37 | case (FirmwareStatus::Installed): 38 | return "Installed"; 39 | break; 40 | } 41 | return NULL; //cannot be reached 42 | } 43 | 44 | std::unique_ptr FirmwareStatusNotification::createReq() { 45 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 46 | JsonObject payload = doc->to(); 47 | payload["status"] = cstrFromFwStatus(status); 48 | return doc; 49 | } 50 | 51 | void FirmwareStatusNotification::processConf(JsonObject payload){ 52 | // no payload, nothing to do 53 | } 54 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Certificates/CertificateMbedTLS.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CERTIFICATE_MBEDTLS_H 6 | #define MO_CERTIFICATE_MBEDTLS_H 7 | 8 | /* 9 | * Built-in implementation of the Certificate interface for MbedTLS 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #ifndef MO_ENABLE_CERT_STORE_MBEDTLS 16 | #define MO_ENABLE_CERT_STORE_MBEDTLS MO_ENABLE_MBEDTLS 17 | #endif 18 | 19 | #if MO_ENABLE_CERT_MGMT && MO_ENABLE_CERT_STORE_MBEDTLS 20 | 21 | /* 22 | * Provide certificate interpreter to facilitate cert store in C. A full implementation is only available for C++ 23 | */ 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | bool ocpp_get_cert_hash(const unsigned char *cert, size_t len, enum HashAlgorithmType hashAlg, ocpp_cert_hash *out); 31 | 32 | #ifdef __cplusplus 33 | } //extern "C" 34 | 35 | #include 36 | 37 | #include 38 | 39 | #ifndef MO_CERT_FN_PREFIX 40 | #define MO_CERT_FN_PREFIX "cert-" 41 | #endif 42 | 43 | #ifndef MO_CERT_FN_SUFFIX 44 | #define MO_CERT_FN_SUFFIX ".pem" 45 | #endif 46 | 47 | #ifndef MO_CERT_FN_CSMS_ROOT 48 | #define MO_CERT_FN_CSMS_ROOT "csms" 49 | #endif 50 | 51 | #ifndef MO_CERT_FN_MANUFACTURER_ROOT 52 | #define MO_CERT_FN_MANUFACTURER_ROOT "mfact" 53 | #endif 54 | 55 | #ifndef MO_CERT_STORE_SIZE 56 | #define MO_CERT_STORE_SIZE 3 //max number of certs per certificate type (e.g. CSMS root CA, Manufacturer root CA) 57 | #endif 58 | 59 | namespace MicroOcpp { 60 | 61 | std::unique_ptr makeCertificateStoreMbedTLS(std::shared_ptr filesystem); 62 | 63 | bool printCertFn(const char *certType, size_t index, char *buf, size_t bufsize); 64 | 65 | } //namespace MicroOcpp 66 | 67 | #endif //def __cplusplus 68 | #endif //MO_ENABLE_CERT_MGMT && MO_ENABLE_CERT_STORE_MBEDTLS 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/RemoteControl/RemoteControlService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_REMOTECONTROLSERVICE_H 6 | #define MO_REMOTECONTROLSERVICE_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_V201 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace MicroOcpp { 18 | 19 | class Context; 20 | class Variable; 21 | 22 | class RemoteControlServiceEvse : public MemoryManaged { 23 | private: 24 | Context& context; 25 | const unsigned int evseId; 26 | 27 | #if MO_ENABLE_CONNECTOR_LOCK 28 | UnlockConnectorResult (*onUnlockConnector)(unsigned int evseId, void *user) = nullptr; 29 | void *onUnlockConnectorUserData = nullptr; 30 | #endif 31 | 32 | public: 33 | RemoteControlServiceEvse(Context& context, unsigned int evseId); 34 | 35 | #if MO_ENABLE_CONNECTOR_LOCK 36 | void setOnUnlockConnector(UnlockConnectorResult (*onUnlockConnector)(unsigned int evseId, void *userData), void *userData); 37 | 38 | UnlockStatus unlockConnector(); 39 | #endif 40 | 41 | }; 42 | 43 | class RemoteControlService : public MemoryManaged { 44 | private: 45 | Context& context; 46 | RemoteControlServiceEvse* evses [MO_NUM_EVSEID] = {nullptr}; 47 | 48 | Variable *authorizeRemoteStart = nullptr; 49 | 50 | public: 51 | RemoteControlService(Context& context, size_t numEvses); 52 | ~RemoteControlService(); 53 | 54 | RemoteControlServiceEvse *getEvse(unsigned int evseId); 55 | 56 | RequestStartStopStatus requestStartTransaction(unsigned int evseId, unsigned int remoteStartId, IdToken idToken, char *transactionIdOut, size_t transactionIdBufSize); //ChargingProfile, GroupIdToken not supported yet 57 | 58 | RequestStartStopStatus requestStopTransaction(const char *transactionId); 59 | }; 60 | 61 | } // namespace MicroOcpp 62 | 63 | #endif // MO_ENABLE_V201 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MicroOcpp", 3 | "version": "1.2.0", 4 | "description": "OCPP 1.6 / 2.0.1 Client for microcontrollers", 5 | "keywords": "OCPP, 1.6, OCPP 1.6, OCPP 2.0.1, Smart Energy, Smart Charging, client, ESP8266, ESP32, Arduino, esp-idf, EVSE, Charge Point", 6 | "repository": 7 | { 8 | "type": "git", 9 | "url": "https://github.com/matth-x/MicroOcpp/" 10 | }, 11 | "authors": 12 | [ 13 | { 14 | "name": "Matthias Akstaller", 15 | "url": "https://www.micro-ocpp.com", 16 | "maintainer": true 17 | } 18 | ], 19 | "license": "MIT", 20 | "homepage": "https://www.micro-ocpp.com", 21 | "dependencies": [ 22 | { 23 | "owner": "bblanchon", 24 | "name": "ArduinoJson", 25 | "version": "6.20.1" 26 | }, 27 | { 28 | "owner": "links2004", 29 | "name": "WebSockets", 30 | "version": "2.4.1" 31 | } 32 | ], 33 | "frameworks": "arduino,espidf", 34 | "platforms": "espressif8266, espressif32", 35 | 36 | "export": { 37 | "include": 38 | [ 39 | "docs/*", 40 | "examples/*", 41 | "src/*", 42 | "CHANGELOG.md", 43 | "CMakeLists.txt", 44 | "library.json", 45 | "library.properties", 46 | "LICENSE", 47 | "mkdocs.yml", 48 | "platformio.ini", 49 | "README.md" 50 | ] 51 | }, 52 | 53 | "examples": [ 54 | { 55 | "name": "Basic OCPP connection", 56 | "base": "examples/ESP", 57 | "files": [ 58 | "main.cpp" 59 | ] 60 | }, 61 | { 62 | "name": "OCPP Security Profile 2", 63 | "base": "examples/ESP-TLS", 64 | "files": [ 65 | "main.cpp" 66 | ] 67 | }, 68 | { 69 | "name": "ESP-IDF integration", 70 | "base": "examples/ESP-IDF", 71 | "files": [ 72 | "main/main.c" 73 | ] 74 | } 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/StatusNotification.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef STATUSNOTIFICATION_H 6 | #define STATUSNOTIFICATION_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | const char *cstrFromOcppEveState(ChargePointStatus state); 17 | 18 | namespace Ocpp16 { 19 | 20 | class StatusNotification : public Operation, public MemoryManaged { 21 | private: 22 | int connectorId = 1; 23 | ChargePointStatus currentStatus = ChargePointStatus_UNDEFINED; 24 | Timestamp timestamp; 25 | ErrorData errorData; 26 | public: 27 | StatusNotification(int connectorId, ChargePointStatus currentStatus, const Timestamp ×tamp, ErrorData errorData = nullptr); 28 | 29 | const char* getOperationType() override; 30 | 31 | std::unique_ptr createReq() override; 32 | 33 | void processConf(JsonObject payload) override; 34 | 35 | void processReq(JsonObject payload) override; 36 | 37 | std::unique_ptr createConf() override; 38 | 39 | int getConnectorId() { 40 | return connectorId; 41 | } 42 | }; 43 | 44 | } // namespace Ocpp16 45 | } // namespace MicroOcpp 46 | 47 | #if MO_ENABLE_V201 48 | 49 | #include 50 | 51 | namespace MicroOcpp { 52 | namespace Ocpp201 { 53 | 54 | class StatusNotification : public Operation, public MemoryManaged { 55 | private: 56 | EvseId evseId; 57 | Timestamp timestamp; 58 | ChargePointStatus currentStatus = ChargePointStatus_UNDEFINED; 59 | public: 60 | StatusNotification(EvseId evseId, ChargePointStatus currentStatus, const Timestamp ×tamp); 61 | 62 | const char* getOperationType() override; 63 | 64 | std::unique_ptr createReq() override; 65 | 66 | void processConf(JsonObject payload) override; 67 | }; 68 | 69 | } // namespace Ocpp201 70 | } // namespace MicroOcpp 71 | 72 | #endif //MO_ENABLE_V201 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Metering/MeterStore.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_METERSTORE_H 6 | #define MO_METERSTORE_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class TransactionMeterData : public MemoryManaged { 16 | private: 17 | const unsigned int connectorId; //assignment to Transaction object 18 | const unsigned int txNr; //assignment to Transaction object 19 | 20 | unsigned int mvCount = 0; //nr of saved meter values, including gaps 21 | bool finalized = false; //if true, this is read-only 22 | 23 | std::shared_ptr filesystem; 24 | 25 | Vector> txData; 26 | 27 | public: 28 | TransactionMeterData(unsigned int connectorId, unsigned int txNr, std::shared_ptr filesystem); 29 | 30 | bool addTxData(std::unique_ptr mv); 31 | 32 | Vector> retrieveStopTxData(); //will invalidate internal cache 33 | 34 | bool restore(MeterValueBuilder& mvBuilder); //load record from memory; true if record found, false if nothing loaded 35 | 36 | unsigned int getConnectorId() {return connectorId;} 37 | unsigned int getTxNr() {return txNr;} 38 | unsigned int getPathsCount() {return mvCount;} //size of spanned path indexes 39 | void finalize() {finalized = true;} 40 | bool isFinalized() {return finalized;} 41 | }; 42 | 43 | class MeterStore : public MemoryManaged { 44 | private: 45 | std::shared_ptr filesystem; 46 | 47 | Vector> txMeterData; 48 | 49 | public: 50 | MeterStore() = delete; 51 | MeterStore(MeterStore&) = delete; 52 | MeterStore(std::shared_ptr filesystem); 53 | 54 | std::shared_ptr getTxMeterData(MeterValueBuilder& mvBuilder, Transaction *transaction); 55 | 56 | bool remove(unsigned int connectorId, unsigned int txNr); 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Metering/SampledValue.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef MO_SAMPLEDVALUE_FLOAT_FORMAT 10 | #define MO_SAMPLEDVALUE_FLOAT_FORMAT "%.2f" 11 | #endif 12 | 13 | using namespace MicroOcpp; 14 | 15 | int32_t SampledValueDeSerializer::deserialize(const char *str) { 16 | return strtol(str, nullptr, 10); 17 | } 18 | 19 | MicroOcpp::String SampledValueDeSerializer::serialize(int32_t& val) { 20 | char str [12] = {'\0'}; 21 | snprintf(str, 12, "%" PRId32, val); 22 | return makeString("v16.Metering.SampledValueDeSerializer", str); 23 | } 24 | 25 | MicroOcpp::String SampledValueDeSerializer::serialize(float& val) { 26 | char str [20]; 27 | str[0] = '\0'; 28 | snprintf(str, 20, MO_SAMPLEDVALUE_FLOAT_FORMAT, val); 29 | return makeString("v16.Metering.SampledValueDeSerializer", str); 30 | } 31 | 32 | std::unique_ptr SampledValue::toJson() { 33 | auto value = serializeValue(); 34 | if (value.empty()) { 35 | return nullptr; 36 | } 37 | size_t capacity = 0; 38 | capacity += JSON_OBJECT_SIZE(8); 39 | capacity += value.length() + 1; 40 | auto result = makeJsonDoc("v16.Metering.SampledValue", capacity); 41 | auto payload = result->to(); 42 | payload["value"] = value; 43 | auto context_cstr = serializeReadingContext(context); 44 | if (context_cstr) 45 | payload["context"] = context_cstr; 46 | if (*properties.getFormat()) 47 | payload["format"] = properties.getFormat(); 48 | if (*properties.getMeasurand()) 49 | payload["measurand"] = properties.getMeasurand(); 50 | if (*properties.getPhase()) 51 | payload["phase"] = properties.getPhase(); 52 | if (*properties.getLocation()) 53 | payload["location"] = properties.getLocation(); 54 | if (*properties.getUnit()) 55 | payload["unit"] = properties.getUnit(); 56 | return result; 57 | } 58 | 59 | ReadingContext SampledValue::getReadingContext() { 60 | return context; 61 | } 62 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Metering/MeterValue.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_METERVALUE_H 6 | #define MO_METERVALUE_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace MicroOcpp { 16 | 17 | class MeterValue : public MemoryManaged { 18 | private: 19 | Timestamp timestamp; 20 | Vector> sampledValue; 21 | 22 | int txNr = -1; 23 | unsigned int opNr = 1; 24 | unsigned int attemptNr = 0; 25 | unsigned long attemptTime = 0; 26 | public: 27 | MeterValue(const Timestamp& timestamp); 28 | MeterValue(const MeterValue& other) = delete; 29 | 30 | void addSampledValue(std::unique_ptr sample); 31 | 32 | std::unique_ptr toJson(); 33 | 34 | const Timestamp& getTimestamp(); 35 | void setTimestamp(Timestamp timestamp); 36 | 37 | ReadingContext getReadingContext(); 38 | 39 | void setTxNr(unsigned int txNr); 40 | int getTxNr(); 41 | 42 | void setOpNr(unsigned int opNr); 43 | unsigned int getOpNr(); 44 | 45 | void advanceAttemptNr(); 46 | unsigned int getAttemptNr(); 47 | 48 | unsigned long getAttemptTime(); 49 | void setAttemptTime(unsigned long timestamp); 50 | }; 51 | 52 | class MeterValueBuilder : public MemoryManaged { 53 | private: 54 | const Vector> &samplers; 55 | std::shared_ptr selectString; 56 | Vector select_mask; 57 | unsigned int select_n {0}; 58 | decltype(selectString->getValueRevision()) select_observe; 59 | 60 | void updateObservedSamplers(); 61 | public: 62 | MeterValueBuilder(const Vector> &samplers, 63 | std::shared_ptr samplersSelectStr); 64 | 65 | std::unique_ptr takeSample(const Timestamp& timestamp, const ReadingContext& context); 66 | 67 | std::unique_ptr deserializeSample(const JsonObject mvJson); 68 | }; 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Variables/VariableContainer.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | /* 6 | * Implementation of the UCs B05 - B06 7 | */ 8 | 9 | #ifndef MO_VARIABLECONTAINER_H 10 | #define MO_VARIABLECONTAINER_H 11 | 12 | #include 13 | 14 | #if MO_ENABLE_V201 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | namespace MicroOcpp { 23 | 24 | class VariableContainer { 25 | public: 26 | ~VariableContainer(); 27 | virtual size_t size() = 0; 28 | virtual Variable *getVariable(size_t i) = 0; 29 | virtual Variable *getVariable(const ComponentId& component, const char *variableName) = 0; 30 | 31 | virtual bool commit(); 32 | }; 33 | 34 | class VariableContainerNonOwning : public VariableContainer, public MemoryManaged { 35 | private: 36 | Vector variables; 37 | public: 38 | VariableContainerNonOwning(); 39 | 40 | size_t size() override; 41 | Variable *getVariable(size_t i) override; 42 | Variable *getVariable(const ComponentId& component, const char *variableName) override; 43 | 44 | bool add(Variable *variable); 45 | }; 46 | 47 | class VariableContainerOwning : public VariableContainer, public MemoryManaged { 48 | private: 49 | Vector> variables; 50 | std::shared_ptr filesystem; 51 | char *filename = nullptr; 52 | 53 | uint16_t trackWriteCount = 0; 54 | bool checkWriteCountUpdated(); 55 | 56 | bool loaded = false; 57 | 58 | public: 59 | VariableContainerOwning(); 60 | ~VariableContainerOwning(); 61 | 62 | size_t size() override; 63 | Variable *getVariable(size_t i) override; 64 | Variable *getVariable(const ComponentId& component, const char *variableName) override; 65 | 66 | bool add(std::unique_ptr variable); 67 | 68 | bool enablePersistency(std::shared_ptr filesystem, const char *filename); 69 | bool load(); //load variables from flash 70 | bool commit() override; 71 | }; 72 | 73 | } //end namespace MicroOcpp 74 | 75 | #endif //MO_ENABLE_V201 76 | #endif 77 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/Heartbeat.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::Heartbeat; 11 | using MicroOcpp::JsonDoc; 12 | 13 | Heartbeat::Heartbeat(Model& model) : MemoryManaged("v16.Operation.", "Heartbeat"), model(model) { 14 | 15 | } 16 | 17 | const char* Heartbeat::getOperationType(){ 18 | return "Heartbeat"; 19 | } 20 | 21 | std::unique_ptr Heartbeat::createReq() { 22 | return createEmptyDocument(); 23 | } 24 | 25 | void Heartbeat::processConf(JsonObject payload) { 26 | 27 | const char* currentTime = payload["currentTime"] | "Invalid"; 28 | if (strcmp(currentTime, "Invalid")) { 29 | if (model.getClock().setTime(currentTime)) { 30 | //success 31 | MO_DBG_DEBUG("Request has been accepted"); 32 | } else { 33 | MO_DBG_WARN("Could not read time string. Expect format like 2020-02-01T20:53:32.486Z"); 34 | } 35 | } else { 36 | MO_DBG_WARN("Missing field currentTime. Expect format like 2020-02-01T20:53:32.486Z"); 37 | } 38 | } 39 | 40 | void Heartbeat::processReq(JsonObject payload) { 41 | 42 | /** 43 | * Ignore Contents of this Req-message, because this is for debug purposes only 44 | */ 45 | 46 | } 47 | 48 | std::unique_ptr Heartbeat::createConf(){ 49 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1) + (JSONDATE_LENGTH + 1)); 50 | JsonObject payload = doc->to(); 51 | 52 | //safety mechanism; in some test setups the library could have to answer Heartbeats without valid system time 53 | Timestamp ocppTimeReference = Timestamp(2019,10,0,11,59,55); 54 | Timestamp ocppSelect = ocppTimeReference; 55 | auto& ocppNow = model.getClock().now(); 56 | if (ocppNow > ocppTimeReference) { 57 | //time has already been set 58 | ocppSelect = ocppNow; 59 | } 60 | 61 | char ocppNowJson [JSONDATE_LENGTH + 1] = {'\0'}; 62 | ocppSelect.toJsonString(ocppNowJson, JSONDATE_LENGTH + 1); 63 | payload["currentTime"] = ocppNowJson; 64 | 65 | return doc; 66 | } 67 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetDiagnostics.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::GetDiagnostics; 11 | using MicroOcpp::JsonDoc; 12 | 13 | GetDiagnostics::GetDiagnostics(DiagnosticsService& diagService) : MemoryManaged("v16.Operation.", "GetDiagnostics"), diagService(diagService), fileName(makeString(getMemoryTag())) { 14 | 15 | } 16 | 17 | void GetDiagnostics::processReq(JsonObject payload) { 18 | 19 | const char *location = payload["location"] | ""; 20 | //check location URL. Maybe introduce Same-Origin-Policy? 21 | if (!*location) { 22 | errorCode = "FormationViolation"; 23 | return; 24 | } 25 | 26 | int retries = payload["retries"] | 1; 27 | int retryInterval = payload["retryInterval"] | 180; 28 | if (retries < 0 || retryInterval < 0) { 29 | errorCode = "PropertyConstraintViolation"; 30 | return; 31 | } 32 | 33 | Timestamp startTime; 34 | if (payload.containsKey("startTime")) { 35 | if (!startTime.setTime(payload["startTime"] | "Invalid")) { 36 | errorCode = "PropertyConstraintViolation"; 37 | MO_DBG_WARN("bad time format"); 38 | return; 39 | } 40 | } 41 | 42 | Timestamp stopTime; 43 | if (payload.containsKey("stopTime")) { 44 | if (!stopTime.setTime(payload["stopTime"] | "Invalid")) { 45 | errorCode = "PropertyConstraintViolation"; 46 | MO_DBG_WARN("bad time format"); 47 | return; 48 | } 49 | } 50 | 51 | fileName = diagService.requestDiagnosticsUpload(location, (unsigned int) retries, (unsigned int) retryInterval, startTime, stopTime); 52 | } 53 | 54 | std::unique_ptr GetDiagnostics::createConf(){ 55 | if (fileName.empty()) { 56 | return createEmptyDocument(); 57 | } else { 58 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 59 | JsonObject payload = doc->to(); 60 | payload["fileName"] = fileName.c_str(); 61 | return doc; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/UnlockConnector.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef UNLOCKCONNECTOR_H 6 | #define UNLOCKCONNECTOR_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | class Model; 17 | 18 | namespace Ocpp16 { 19 | 20 | class UnlockConnector : public Operation, public MemoryManaged { 21 | private: 22 | Model& model; 23 | 24 | #if MO_ENABLE_CONNECTOR_LOCK 25 | std::function unlockConnector; 26 | UnlockConnectorResult cbUnlockResult; 27 | unsigned long timerStart = 0; //for timeout 28 | #endif //MO_ENABLE_CONNECTOR_LOCK 29 | 30 | const char *errorCode = nullptr; 31 | public: 32 | UnlockConnector(Model& model); 33 | 34 | const char* getOperationType() override; 35 | 36 | void processReq(JsonObject payload) override; 37 | 38 | std::unique_ptr createConf() override; 39 | 40 | const char *getErrorCode() override {return errorCode;} 41 | }; 42 | 43 | } //end namespace Ocpp16 44 | } //end namespace MicroOcpp 45 | 46 | #if MO_ENABLE_V201 47 | #if MO_ENABLE_CONNECTOR_LOCK 48 | 49 | #include 50 | 51 | namespace MicroOcpp { 52 | 53 | class RemoteControlService; 54 | class RemoteControlServiceEvse; 55 | 56 | namespace Ocpp201 { 57 | 58 | class UnlockConnector : public Operation, public MemoryManaged { 59 | private: 60 | RemoteControlService& rcService; 61 | RemoteControlServiceEvse *rcEvse = nullptr; 62 | 63 | UnlockStatus status; 64 | unsigned long timerStart = 0; //for timeout 65 | 66 | const char *errorCode = nullptr; 67 | public: 68 | UnlockConnector(RemoteControlService& rcService); 69 | 70 | const char* getOperationType() override; 71 | 72 | void processReq(JsonObject payload) override; 73 | 74 | std::unique_ptr createConf() override; 75 | 76 | const char *getErrorCode() override {return errorCode;} 77 | }; 78 | 79 | } //end namespace Ocpp201 80 | } //end namespace MicroOcpp 81 | 82 | #endif //MO_ENABLE_CONNECTOR_LOCK 83 | #endif //MO_ENABLE_V201 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # matth-x/MicroOcpp 2 | # Copyright Matthias Akstaller 2019 - 2024 3 | # MIT License 4 | 5 | name: Unit tests 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | pull_request: 13 | 14 | jobs: 15 | 16 | compile-and-run: 17 | name: Automated Tests 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Check out repository code 21 | uses: actions/checkout@v3 22 | - name: Check out MbedTLS 23 | uses: actions/checkout@v3 24 | with: 25 | repository: Mbed-TLS/mbedtls 26 | ref: v2.28.10 27 | path: lib/mbedtls 28 | - name: Get build tools 29 | run: | 30 | sudo apt update 31 | sudo apt install build-essential cmake lcov valgrind 32 | sudo apt -y install gcc-9 g++-9 33 | g++ --version 34 | echo "g++ version must be 9.4.0" 35 | - name: Get ArduinoJson 36 | run: wget -Uri https://github.com/bblanchon/ArduinoJson/releases/download/v6.21.3/ArduinoJson-v6.21.3.h -O ./src/ArduinoJson.h 37 | - name: Generate CMake build files 38 | run: cmake -S . -B ./build -DMO_BUILD_UNIT_MBEDTLS=True 39 | - name: Compile 40 | run: cmake --build ./build -j 32 --target mo_unit_tests 41 | - name: Configure FS 42 | run: mkdir mo_store 43 | - name: Run tests (valgrind) 44 | run: valgrind --error-exitcode=1 --leak-check=full ./build/mo_unit_tests --abort 45 | - name: Generate CMake build files (AddressSanitizer, UndefinedBehaviorSanitizer) 46 | run: | 47 | rm -r ./build 48 | cmake -S . -B ./build -DCMAKE_CXX_FLAGS="-fsanitize=address -fsanitize=undefined" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address -fsanitize=undefined" -DMO_BUILD_UNIT_MBEDTLS=True 49 | - name: Compile (ASan, UBSan) 50 | run: cmake --build ./build -j 32 --target mo_unit_tests 51 | - name: Run tests (ASan, UBSan) 52 | run: ./build/mo_unit_tests --abort 53 | - name: Create coverage report 54 | run: | 55 | lcov --directory . --capture --output-file coverage.info --ignore-errors mismatch 56 | lcov --remove coverage.info '/usr/*' '*/tests/*' '*/ArduinoJson.h' --output-file coverage.info 57 | lcov --list coverage.info 58 | - name: Upload coverage reports to Codecov 59 | uses: codecov/codecov-action@v3 60 | env: 61 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 62 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/ConfigurationKeyValue.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef CONFIGURATIONKEYVALUE_H 6 | #define CONFIGURATIONKEYVALUE_H 7 | 8 | #include 9 | #include 10 | 11 | #define MO_CONFIG_MAX_VALSTRSIZE 128 12 | 13 | #ifndef MO_CONFIG_EXT_PREFIX 14 | #define MO_CONFIG_EXT_PREFIX "Cst_" 15 | #endif 16 | 17 | #ifndef MO_CONFIG_TYPECHECK 18 | #define MO_CONFIG_TYPECHECK 1 //enable this for debugging 19 | #endif 20 | 21 | namespace MicroOcpp { 22 | 23 | using revision_t = uint16_t; 24 | 25 | enum class TConfig : uint8_t { 26 | Int, 27 | Bool, 28 | String 29 | }; 30 | 31 | template 32 | TConfig convertType(); 33 | 34 | class Configuration { 35 | protected: 36 | revision_t value_revision = 0; //write access counter; used to check if this config has been changed 37 | private: 38 | bool rebootRequired = false; 39 | 40 | enum class Mutability : uint8_t { 41 | ReadWrite, 42 | ReadOnly, 43 | WriteOnly, 44 | None 45 | }; 46 | Mutability mutability = Mutability::ReadWrite; 47 | 48 | public: 49 | virtual ~Configuration(); 50 | 51 | virtual bool setKey(const char *key) = 0; 52 | virtual const char *getKey() = 0; 53 | 54 | virtual void setInt(int); 55 | virtual void setBool(bool); 56 | virtual bool setString(const char*); 57 | 58 | virtual int getInt(); 59 | virtual bool getBool(); 60 | virtual const char *getString(); //always returns c-string (empty if undefined) 61 | 62 | virtual TConfig getType() = 0; 63 | 64 | virtual revision_t getValueRevision(); 65 | 66 | void setRebootRequired(); 67 | bool isRebootRequired(); 68 | 69 | void setReadOnly(); 70 | bool isReadOnly(); 71 | bool isReadable(); 72 | 73 | void setWriteOnly(); 74 | }; 75 | 76 | /* 77 | * Default implementations of the Configuration interface. 78 | * 79 | * How to use custom implementations: for each OCPP config, pass a config instance to the OCPP lib 80 | * before its initialization stage. Then the library won't create new config objects but 81 | */ 82 | std::unique_ptr makeConfiguration(TConfig type, const char *key); 83 | 84 | const char *serializeTConfig(TConfig type); 85 | bool deserializeTConfig(const char *serialized, TConfig& out); 86 | 87 | } //end namespace MicroOcpp 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Authorization/AuthorizationData.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_AUTHORIZATIONDATA_H 6 | #define MO_AUTHORIZATIONDATA_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_LOCAL_AUTH 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace MicroOcpp { 19 | 20 | enum class AuthorizationStatus : uint8_t { 21 | Accepted, 22 | Blocked, 23 | Expired, 24 | Invalid, 25 | ConcurrentTx, 26 | UNDEFINED //not part of OCPP 1.6 27 | }; 28 | 29 | #define AUTHDATA_KEY_IDTAG(COMPACT) (COMPACT ? "it" : "idTag") 30 | #define AUTHDATA_KEY_IDTAGINFO "idTagInfo" 31 | #define AUTHDATA_KEY_EXPIRYDATE(COMPACT) (COMPACT ? "ed" : "expiryDate") 32 | #define AUTHDATA_KEY_PARENTIDTAG(COMPACT) (COMPACT ? "pi" : "parentIdTag") 33 | #define AUTHDATA_KEY_STATUS(COMPACT) (COMPACT ? "st" : "status") 34 | 35 | #define AUTHORIZATIONSTATUS_LEN_MAX (sizeof("ConcurrentTx") - 1) //max length of serialized AuthStatus 36 | 37 | const char *serializeAuthorizationStatus(AuthorizationStatus status); 38 | AuthorizationStatus deserializeAuthorizationStatus(const char *cstr); 39 | 40 | class AuthorizationData : public MemoryManaged { 41 | private: 42 | //data structure optimized for memory consumption 43 | 44 | char *parentIdTag = nullptr; 45 | std::unique_ptr expiryDate; 46 | 47 | char idTag [IDTAG_LEN_MAX + 1] = {'\0'}; 48 | 49 | AuthorizationStatus status = AuthorizationStatus::UNDEFINED; 50 | public: 51 | AuthorizationData(); 52 | AuthorizationData(AuthorizationData&& other); 53 | ~AuthorizationData(); 54 | 55 | AuthorizationData& operator=(AuthorizationData&& other); 56 | 57 | void readJson(JsonObject entry, bool compact = false); //compact: compressed representation for flash storage 58 | 59 | size_t getJsonCapacity() const; 60 | void writeJson(JsonObject& entry, bool compact = false); //compact: compressed representation for flash storage 61 | 62 | const char *getIdTag() const; 63 | Timestamp *getExpiryDate() const; 64 | const char *getParentIdTag() const; 65 | AuthorizationStatus getAuthorizationStatus() const; 66 | 67 | void reset(); 68 | }; 69 | 70 | } 71 | 72 | #endif //MO_ENABLE_LOCAL_AUTH 73 | #endif 74 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Metering/ReadingContext.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace MicroOcpp { 11 | 12 | const char *serializeReadingContext(ReadingContext context) { 13 | switch (context) { 14 | case (ReadingContext_InterruptionBegin): 15 | return "Interruption.Begin"; 16 | case (ReadingContext_InterruptionEnd): 17 | return "Interruption.End"; 18 | case (ReadingContext_Other): 19 | return "Other"; 20 | case (ReadingContext_SampleClock): 21 | return "Sample.Clock"; 22 | case (ReadingContext_SamplePeriodic): 23 | return "Sample.Periodic"; 24 | case (ReadingContext_TransactionBegin): 25 | return "Transaction.Begin"; 26 | case (ReadingContext_TransactionEnd): 27 | return "Transaction.End"; 28 | case (ReadingContext_Trigger): 29 | return "Trigger"; 30 | default: 31 | MO_DBG_ERR("ReadingContext not specified"); 32 | /* fall through */ 33 | case (ReadingContext_UNDEFINED): 34 | return ""; 35 | } 36 | } 37 | ReadingContext deserializeReadingContext(const char *context) { 38 | if (!context) { 39 | MO_DBG_ERR("Invalid argument"); 40 | return ReadingContext_UNDEFINED; 41 | } 42 | 43 | if (!strcmp(context, "Sample.Periodic")) { 44 | return ReadingContext_SamplePeriodic; 45 | } else if (!strcmp(context, "Sample.Clock")) { 46 | return ReadingContext_SampleClock; 47 | } else if (!strcmp(context, "Transaction.Begin")) { 48 | return ReadingContext_TransactionBegin; 49 | } else if (!strcmp(context, "Transaction.End")) { 50 | return ReadingContext_TransactionEnd; 51 | } else if (!strcmp(context, "Other")) { 52 | return ReadingContext_Other; 53 | } else if (!strcmp(context, "Interruption.Begin")) { 54 | return ReadingContext_InterruptionBegin; 55 | } else if (!strcmp(context, "Interruption.End")) { 56 | return ReadingContext_InterruptionEnd; 57 | } else if (!strcmp(context, "Trigger")) { 58 | return ReadingContext_Trigger; 59 | } 60 | 61 | MO_DBG_ERR("ReadingContext not specified %.10s", context); 62 | return ReadingContext_UNDEFINED; 63 | } 64 | 65 | } //namespace MicroOcpp 66 | -------------------------------------------------------------------------------- /examples/ESP-IDF/README.md: -------------------------------------------------------------------------------- 1 | # ESP-IDF integration example 2 | 3 | To run MicroOcpp on the ESP-IDF platform, please take this example as the starting point. It is widely based on the [Wi-Fi Station Example](https://github.com/espressif/esp-idf/tree/release/v4.4/examples/wifi/getting_started/station) of Espressif. This example works with the ESP-IDF version `4.4`. For a general guide how to setup and use the ESP-IDF, please refer to the documentation of Espressif. 4 | 5 | ## Setup guide 6 | 7 | ### Dependencies 8 | 9 | Please clone the following repositories into the respective components-directories: 10 | 11 | - [MicroOcpp](https://github.com/matth-x/MicroOcpp) into `components/MicroOcpp` 12 | - [Mongoose (ESP-IDF integration)](https://github.com/cesanta/mongoose-esp-idf) into `components/mongoose` 13 | - [Mongoose adapter for MicroOcpp](https://github.com/matth-x/MicroOcppMongoose) into `components/MicroOcppMongoose` 14 | - [ArduinoJson (v6.21)](https://github.com/bblanchon/ArduinoJson) into `components/ArduinoJson` 15 | 16 | For setup, the following commands could come handy (change to the root directory of the ESP-IDF project first): 17 | 18 | ``` 19 | rm components/mongoose/.gitkeep 20 | rm components/MicroOcpp/.gitkeep 21 | rm components/MicroOcppMongoose/.gitkeep 22 | rm components/ArduinoJson/.gitkeep 23 | git clone https://github.com/matth-x/MicroOcpp components/MicroOcpp 24 | git clone --recurse-submodules https://github.com/cesanta/mongoose-esp-idf.git components/mongoose 25 | git clone https://github.com/matth-x/MicroOcppMongoose components/MicroOcppMongoose 26 | git clone https://github.com/bblanchon/ArduinoJson components/ArduinoJson 27 | cd components/ArduinoJson 28 | git checkout 3e1be980d93e47b2a0073efeeb9a9396fd7a83be 29 | ``` 30 | 31 | The setup is done if the following include statements work: 32 | 33 | ```cpp 34 | #include 35 | #include 36 | #include 37 | #include 38 | ``` 39 | 40 | ### Configure the project 41 | 42 | Open the project configuration menu (`idf.py menuconfig`). 43 | 44 | In the `Example Configuration` menu: 45 | 46 | * Set the Wi-Fi configuration. 47 | * Set `WiFi SSID`. 48 | * Set `WiFi Password`. 49 | * Set `OCPP backend URL`. (e.g. `ws://ocpp.example.com/steve/websocket/CentralSystemService`) 50 | * Set `ChargeBoxId`. (e.g. `my-charger` - last part of the WebSocket URL 51 | * Set `AuthorizationKey`, or leave empty if not necessary 52 | 53 | Optional: If you need, change the other options according to your requirements. 54 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/CustomOperation.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CUSTOMOPERATION_H 6 | #define MO_CUSTOMOPERATION_H 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace MicroOcpp { 13 | 14 | namespace Ocpp16 { 15 | 16 | class CustomOperation : public Operation, public MemoryManaged { 17 | private: 18 | String operationType; 19 | std::function ()> fn_createReq; 20 | std::function fn_processConf; 21 | std::function fn_processErr; //optional 22 | std::function fn_processReq; 23 | std::function ()> fn_createConf; 24 | std::function fn_getErrorCode; //optional 25 | std::function fn_getErrorDescription; //optional 26 | std::function ()> fn_getErrorDetails; //optional 27 | public: 28 | 29 | //for operations initiated at this device 30 | CustomOperation(const char *operationType, 31 | std::function ()> fn_createReq, 32 | std::function fn_processConf, 33 | std::function fn_processErr = nullptr); 34 | 35 | //for operations receied from remote 36 | CustomOperation(const char *operationType, 37 | std::function fn_processReq, 38 | std::function ()> fn_createConf, 39 | std::function fn_getErrorCode = nullptr, 40 | std::function fn_getErrorDescription = nullptr, 41 | std::function ()> fn_getErrorDetails = nullptr); 42 | 43 | ~CustomOperation(); 44 | 45 | const char* getOperationType() override; 46 | 47 | std::unique_ptr createReq() override; 48 | 49 | void processConf(JsonObject payload) override; 50 | 51 | bool processErr(const char *code, const char *description, JsonObject details) override; 52 | 53 | void processReq(JsonObject payload) override; 54 | 55 | std::unique_ptr createConf() override; 56 | const char *getErrorCode() override; 57 | const char *getErrorDescription() override; 58 | std::unique_ptr getErrorDetails() override; 59 | }; 60 | 61 | } //end namespace Ocpp16 62 | } //end namespace MicroOcpp 63 | #endif 64 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/ConfigurationContainer.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_CONFIGURATIONCONTAINER_H 6 | #define MO_CONFIGURATIONCONTAINER_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace MicroOcpp { 14 | 15 | class ConfigurationContainer { 16 | private: 17 | const char *filename; 18 | bool accessible; 19 | public: 20 | ConfigurationContainer(const char *filename, bool accessible) : filename(filename), accessible(accessible) { } 21 | 22 | virtual ~ConfigurationContainer(); 23 | 24 | const char *getFilename() {return filename;} 25 | bool isAccessible() {return accessible;} 26 | 27 | virtual bool load() = 0; //called at the end of mocpp_intialize, to load the configurations with the stored value 28 | virtual bool save() = 0; 29 | 30 | virtual std::shared_ptr createConfiguration(TConfig type, const char *key) = 0; 31 | virtual void remove(Configuration *config) = 0; 32 | 33 | virtual size_t size() = 0; 34 | virtual Configuration *getConfiguration(size_t i) = 0; 35 | virtual std::shared_ptr getConfiguration(const char *key) = 0; 36 | 37 | virtual void loadStaticKey(Configuration& config, const char *key) { } //possible optimization: can replace internal key with passed static key 38 | 39 | virtual void removeUnused() { } //remove configs which haven't been accessed (optional and only if known) 40 | }; 41 | 42 | class ConfigurationContainerVolatile : public ConfigurationContainer, public MemoryManaged { 43 | private: 44 | Vector> configurations; 45 | public: 46 | ConfigurationContainerVolatile(const char *filename, bool accessible); 47 | 48 | //ConfigurationContainer definitions 49 | bool load() override; 50 | bool save() override; 51 | std::shared_ptr createConfiguration(TConfig type, const char *key) override; 52 | void remove(Configuration *config) override; 53 | size_t size() override; 54 | Configuration *getConfiguration(size_t i) override; 55 | std::shared_ptr getConfiguration(const char *key) override; 56 | 57 | //add custom Configuration object 58 | void add(std::shared_ptr c); 59 | }; 60 | 61 | std::unique_ptr makeConfigurationContainerVolatile(const char *filename, bool accessible); 62 | 63 | } //end namespace MicroOcpp 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/SendLocalList.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_LOCAL_AUTH 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using MicroOcpp::Ocpp16::SendLocalList; 14 | using MicroOcpp::JsonDoc; 15 | 16 | SendLocalList::SendLocalList(AuthorizationService& authService) : MemoryManaged("v16.Operation.", "SendLocalList"), authService(authService) { 17 | 18 | } 19 | 20 | SendLocalList::~SendLocalList() { 21 | 22 | } 23 | 24 | const char* SendLocalList::getOperationType(){ 25 | return "SendLocalList"; 26 | } 27 | 28 | void SendLocalList::processReq(JsonObject payload) { 29 | 30 | //TC_043_1_CS Send Local Authorization List - NotSupported 31 | if (!authService.localAuthListEnabled()) { 32 | errorCode = "NotSupported"; 33 | return; 34 | } 35 | 36 | if (!payload.containsKey("listVersion") || !payload.containsKey("updateType")) { 37 | errorCode = "FormationViolation"; 38 | return; 39 | } 40 | 41 | if (payload.containsKey("localAuthorizationList") && !payload["localAuthorizationList"].is()) { 42 | errorCode = "FormationViolation"; 43 | return; 44 | } 45 | 46 | JsonArray localAuthorizationList = payload["localAuthorizationList"]; 47 | 48 | if (localAuthorizationList.size() > MO_SendLocalListMaxLength) { 49 | errorCode = "OccurenceConstraintViolation"; 50 | return; 51 | } 52 | 53 | bool differential = !strcmp("Differential", payload["updateType"] | "Invalid"); //updateType Differential or Full 54 | 55 | int listVersion = payload["listVersion"]; 56 | 57 | if (differential && authService.getLocalListVersion() >= listVersion) { 58 | versionMismatch = true; 59 | return; 60 | } 61 | 62 | updateFailure = !authService.updateLocalList(localAuthorizationList, listVersion, differential); 63 | } 64 | 65 | std::unique_ptr SendLocalList::createConf(){ 66 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 67 | JsonObject payload = doc->to(); 68 | 69 | if (versionMismatch) { 70 | payload["status"] = "VersionMismatch"; 71 | } else if (updateFailure) { 72 | payload["status"] = "Failed"; 73 | } else { 74 | payload["status"] = "Accepted"; 75 | } 76 | 77 | return doc; 78 | } 79 | 80 | #endif //MO_ENABLE_LOCAL_AUTH 81 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Reservation/Reservation.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_RESERVATION_H 6 | #define MO_RESERVATION_H 7 | 8 | #include 9 | 10 | #if MO_ENABLE_RESERVATION 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #ifndef RESERVATION_FN 17 | #define RESERVATION_FN (MO_FILENAME_PREFIX "reservations.jsn") 18 | #endif 19 | 20 | #define MO_RESERVATION_CID_KEY "cid_" 21 | #define MO_RESERVATION_EXPDATE_KEY "expdt_" 22 | #define MO_RESERVATION_IDTAG_KEY "idt_" 23 | #define MO_RESERVATION_RESID_KEY "rsvid_" 24 | #define MO_RESERVATION_PARENTID_KEY "pidt_" 25 | 26 | namespace MicroOcpp { 27 | 28 | class Model; 29 | 30 | class Reservation : public MemoryManaged { 31 | private: 32 | Model& model; 33 | const unsigned int slot; 34 | 35 | std::shared_ptr connectorIdInt; 36 | char connectorIdKey [sizeof(MO_RESERVATION_CID_KEY "xxx") + 1]; //"xxx" = placeholder for digits 37 | std::shared_ptr expiryDateRawString; 38 | char expiryDateRawKey [sizeof(MO_RESERVATION_EXPDATE_KEY "xxx") + 1]; 39 | 40 | Timestamp expiryDate = MIN_TIME; 41 | std::shared_ptr idTagString; 42 | char idTagKey [sizeof(MO_RESERVATION_IDTAG_KEY "xxx") + 1]; 43 | std::shared_ptr reservationIdInt; 44 | char reservationIdKey [sizeof(MO_RESERVATION_RESID_KEY "xxx") + 1]; 45 | std::shared_ptr parentIdTagString; 46 | char parentIdTagKey [sizeof(MO_RESERVATION_PARENTID_KEY "xxx") + 1]; 47 | 48 | public: 49 | Reservation(Model& model, unsigned int slot); 50 | Reservation(const Reservation&) = delete; 51 | Reservation(Reservation&&) = delete; 52 | Reservation& operator=(const Reservation&) = delete; 53 | 54 | ~Reservation(); 55 | 56 | bool isActive(); //if this object contains a valid, unexpired reservation 57 | 58 | bool matches(unsigned int connectorId); 59 | bool matches(const char *idTag, const char *parentIdTag = nullptr); //idTag == parentIdTag == nullptr -> return True 60 | 61 | int getConnectorId(); 62 | Timestamp& getExpiryDate(); 63 | const char *getIdTag(); 64 | int getReservationId(); 65 | const char *getParentIdTag(); 66 | 67 | void update(int reservationId, unsigned int connectorId, Timestamp expiryDate, const char *idTag, const char *parentIdTag = nullptr); 68 | void clear(); 69 | }; 70 | 71 | } 72 | 73 | #endif //MO_ENABLE_RESERVATION 74 | #endif 75 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/RequestStartTransaction.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_V201 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using MicroOcpp::Ocpp201::RequestStartTransaction; 14 | using MicroOcpp::JsonDoc; 15 | 16 | RequestStartTransaction::RequestStartTransaction(RemoteControlService& rcService) : MemoryManaged("v201.Operation.", "RequestStartTransaction"), rcService(rcService) { 17 | 18 | } 19 | 20 | const char* RequestStartTransaction::getOperationType(){ 21 | return "RequestStartTransaction"; 22 | } 23 | 24 | void RequestStartTransaction::processReq(JsonObject payload) { 25 | 26 | int evseId = payload["evseId"] | 0; 27 | if (evseId < 0 || evseId >= MO_NUM_EVSEID) { 28 | errorCode = "PropertyConstraintViolation"; 29 | return; 30 | } 31 | 32 | int remoteStartId = payload["remoteStartId"] | 0; 33 | if (remoteStartId < 0) { 34 | errorCode = "PropertyConstraintViolation"; 35 | MO_DBG_ERR("IDs must be >= 0"); 36 | return; 37 | } 38 | 39 | IdToken idToken; 40 | if (!idToken.parseCstr(payload["idToken"]["idToken"] | (const char*)nullptr, payload["idToken"]["type"] | (const char*)nullptr)) { //parseCstr rejects nullptr as argument 41 | MO_DBG_ERR("could not parse idToken"); 42 | errorCode = "FormationViolation"; 43 | return; 44 | } 45 | 46 | status = rcService.requestStartTransaction(evseId, remoteStartId, idToken, transactionId, sizeof(transactionId)); 47 | } 48 | 49 | std::unique_ptr RequestStartTransaction::createConf(){ 50 | 51 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(2)); 52 | JsonObject payload = doc->to(); 53 | 54 | const char *statusCstr = ""; 55 | 56 | switch (status) { 57 | case RequestStartStopStatus_Accepted: 58 | statusCstr = "Accepted"; 59 | break; 60 | case RequestStartStopStatus_Rejected: 61 | statusCstr = "Rejected"; 62 | break; 63 | default: 64 | MO_DBG_ERR("internal error"); 65 | break; 66 | } 67 | 68 | payload["status"] = statusCstr; 69 | 70 | if (transaction) { 71 | payload["transactionId"] = (const char*)transaction->transactionId; //force zero-copy mode 72 | } 73 | 74 | return doc; 75 | } 76 | 77 | #endif // MO_ENABLE_V201 78 | -------------------------------------------------------------------------------- /tests/benchmarks/firmware_size/main.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | MicroOcpp::LoopbackConnection g_loopback; 11 | 12 | void setup() { 13 | 14 | ocpp_deinitialize(); 15 | 16 | #if MO_ENABLE_V201 17 | mocpp_initialize(g_loopback, ChargerCredentials::v201(),MicroOcpp::makeDefaultFilesystemAdapter(MicroOcpp::FilesystemOpt::Use_Mount_FormatOnFail),true,MicroOcpp::ProtocolVersion(2,0,1)); 18 | #else 19 | mocpp_initialize(g_loopback, ChargerCredentials()); 20 | #endif 21 | 22 | ocpp_beginTransaction(""); 23 | ocpp_beginTransaction_authorized("",""); 24 | ocpp_endTransaction("",""); 25 | ocpp_endTransaction_authorized("",""); 26 | ocpp_isTransactionActive(); 27 | ocpp_isTransactionRunning(); 28 | ocpp_getTransactionIdTag(); 29 | ocpp_getTransaction(); 30 | ocpp_ocppPermitsCharge(); 31 | ocpp_getChargePointStatus(); 32 | ocpp_setConnectorPluggedInput([] () {return false;}); 33 | ocpp_setEnergyMeterInput([] () {return 0;}); 34 | ocpp_setPowerMeterInput([] () {return 0.f;}); 35 | ocpp_setSmartChargingPowerOutput([] (float) {}); 36 | ocpp_setSmartChargingCurrentOutput([] (float) {}); 37 | ocpp_setSmartChargingOutput([] (float,float,int) {}); 38 | ocpp_setEvReadyInput([] () {return false;}); 39 | ocpp_setEvseReadyInput([] () {return false;}); 40 | ocpp_addErrorCodeInput([] () {return (const char*)nullptr;}); 41 | addErrorDataInput([] () {return MicroOcpp::ErrorData("");}); 42 | ocpp_addMeterValueInputFloat([] () {return 0.f;},"","","",""); 43 | ocpp_setOccupiedInput([] () {return false;}); 44 | ocpp_setStartTxReadyInput([] () {return false;}); 45 | ocpp_setStopTxReadyInput([] () {return false;}); 46 | ocpp_setTxNotificationOutput([] (OCPP_Transaction*, TxNotification) {}); 47 | 48 | #if MO_ENABLE_CONNECTOR_LOCK 49 | ocpp_setOnUnlockConnectorInOut([] () {return UnlockConnectorResult_UnlockFailed;}); 50 | #endif 51 | 52 | isOperative(); 53 | setOnResetNotify([] (bool) {return false;}); 54 | setOnResetExecute([] (bool) {return false;}); 55 | getFirmwareService()->getFirmwareStatus(); 56 | getDiagnosticsService()->getDiagnosticsStatus(); 57 | 58 | #if MO_ENABLE_CERT_MGMT 59 | setCertificateStore(nullptr); 60 | #endif 61 | 62 | getOcppContext(); 63 | 64 | } 65 | 66 | void loop() { 67 | mocpp_loop(); 68 | } 69 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetBaseReport.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_V201 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using MicroOcpp::Ocpp201::GetBaseReport; 14 | using MicroOcpp::JsonDoc; 15 | 16 | GetBaseReport::GetBaseReport(VariableService& variableService) : MemoryManaged("v201.Operation.", "GetBaseReport"), variableService(variableService) { 17 | 18 | } 19 | 20 | const char* GetBaseReport::getOperationType(){ 21 | return "GetBaseReport"; 22 | } 23 | 24 | void GetBaseReport::processReq(JsonObject payload) { 25 | 26 | int requestId = payload["requestId"] | -1; 27 | if (requestId < 0) { 28 | errorCode = "FormationViolation"; 29 | MO_DBG_ERR("invalid requestId"); 30 | return; 31 | } 32 | 33 | ReportBase reportBase; 34 | 35 | const char *reportBaseCstr = payload["reportBase"] | ""; 36 | if (!strcmp(reportBaseCstr, "ConfigurationInventory")) { 37 | reportBase = ReportBase_ConfigurationInventory; 38 | } else if (!strcmp(reportBaseCstr, "FullInventory")) { 39 | reportBase = ReportBase_FullInventory; 40 | } else if (!strcmp(reportBaseCstr, "SummaryInventory")) { 41 | reportBase = ReportBase_SummaryInventory; 42 | } else { 43 | errorCode = "FormationViolation"; 44 | MO_DBG_ERR("invalid reportBase"); 45 | return; 46 | } 47 | 48 | status = variableService.getBaseReport(requestId, reportBase); 49 | } 50 | 51 | std::unique_ptr GetBaseReport::createConf(){ 52 | 53 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 54 | JsonObject payload = doc->to(); 55 | 56 | const char *statusCstr = ""; 57 | 58 | switch (status) { 59 | case GenericDeviceModelStatus_Accepted: 60 | statusCstr = "Accepted"; 61 | break; 62 | case GenericDeviceModelStatus_Rejected: 63 | statusCstr = "Rejected"; 64 | break; 65 | case GenericDeviceModelStatus_NotSupported: 66 | statusCstr = "NotSupported"; 67 | break; 68 | case GenericDeviceModelStatus_EmptyResultSet: 69 | statusCstr = "EmptyResultSet"; 70 | break; 71 | default: 72 | MO_DBG_ERR("internal error"); 73 | break; 74 | } 75 | 76 | payload["status"] = statusCstr; 77 | 78 | return doc; 79 | } 80 | 81 | #endif // MO_ENABLE_V201 82 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/ConfigurationContainer.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #include 8 | 9 | using namespace MicroOcpp; 10 | 11 | ConfigurationContainer::~ConfigurationContainer() { 12 | 13 | } 14 | 15 | ConfigurationContainerVolatile::ConfigurationContainerVolatile(const char *filename, bool accessible) : 16 | ConfigurationContainer(filename, accessible), MemoryManaged("v16.Configuration.ContainerVoltaile.", filename), configurations(makeVector>(getMemoryTag())) { 17 | 18 | } 19 | 20 | bool ConfigurationContainerVolatile::load() { 21 | return true; 22 | } 23 | 24 | bool ConfigurationContainerVolatile::save() { 25 | return true; 26 | } 27 | 28 | std::shared_ptr ConfigurationContainerVolatile::createConfiguration(TConfig type, const char *key) { 29 | auto res = std::shared_ptr(makeConfiguration(type, key).release(), std::default_delete(), makeAllocator("v16.Configuration.", key)); 30 | if (!res) { 31 | //allocation failure - OOM 32 | MO_DBG_ERR("OOM"); 33 | return nullptr; 34 | } 35 | configurations.push_back(res); 36 | return res; 37 | } 38 | 39 | void ConfigurationContainerVolatile::remove(Configuration *config) { 40 | for (auto entry = configurations.begin(); entry != configurations.end();) { 41 | if (entry->get() == config) { 42 | entry = configurations.erase(entry); 43 | } else { 44 | entry++; 45 | } 46 | } 47 | } 48 | 49 | size_t ConfigurationContainerVolatile::size() { 50 | return configurations.size(); 51 | } 52 | 53 | Configuration *ConfigurationContainerVolatile::getConfiguration(size_t i) { 54 | return configurations[i].get(); 55 | } 56 | 57 | std::shared_ptr ConfigurationContainerVolatile::getConfiguration(const char *key) { 58 | for (auto& entry : configurations) { 59 | if (entry->getKey() && !strcmp(entry->getKey(), key)) { 60 | return entry; 61 | } 62 | } 63 | return nullptr; 64 | } 65 | 66 | void ConfigurationContainerVolatile::add(std::shared_ptr c) { 67 | configurations.push_back(std::move(c)); 68 | } 69 | 70 | namespace MicroOcpp { 71 | 72 | std::unique_ptr makeConfigurationContainerVolatile(const char *filename, bool accessible) { 73 | return std::unique_ptr(new ConfigurationContainerVolatile(filename, accessible)); 74 | } 75 | 76 | } //end namespace MicroOcpp 77 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Availability/AvailabilityService.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | /* 6 | * Implementation of the UCs G01, G03, G04. 7 | * 8 | * G02 (Heartbeat) is implemented in the HeartbeatService 9 | */ 10 | 11 | #ifndef MO_AVAILABILITYSERVICE_H 12 | #define MO_AVAILABILITYSERVICE_H 13 | 14 | #include 15 | 16 | #if MO_ENABLE_V201 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifndef MO_INOPERATIVE_REQUESTERS_MAX 26 | #define MO_INOPERATIVE_REQUESTERS_MAX 3 27 | #endif 28 | 29 | #ifndef MO_FAULTED_REQUESTERS_MAX 30 | #define MO_FAULTED_REQUESTERS_MAX 3 31 | #endif 32 | 33 | namespace MicroOcpp { 34 | 35 | class Context; 36 | class AvailabilityService; 37 | 38 | class AvailabilityServiceEvse : public MemoryManaged { 39 | private: 40 | Context& context; 41 | AvailabilityService& availabilityService; 42 | const unsigned int evseId; 43 | 44 | std::function connectorPluggedInput; 45 | std::function occupiedInput; //instead of Available, go into Occupied 46 | 47 | void *unavailableRequesters [MO_INOPERATIVE_REQUESTERS_MAX] = {nullptr}; 48 | void *faultedRequesters [MO_FAULTED_REQUESTERS_MAX] = {nullptr}; 49 | 50 | ChargePointStatus reportedStatus = ChargePointStatus_UNDEFINED; 51 | public: 52 | AvailabilityServiceEvse(Context& context, AvailabilityService& availabilityService, unsigned int evseId); 53 | 54 | void loop(); 55 | 56 | void setConnectorPluggedInput(std::function connectorPluggedInput); 57 | void setOccupiedInput(std::function occupiedInput); 58 | 59 | ChargePointStatus getStatus(); 60 | 61 | void setUnavailable(void *requesterId); 62 | void setAvailable(void *requesterId); 63 | 64 | ChangeAvailabilityStatus changeAvailability(bool operative); 65 | 66 | void setFaulted(void *requesterId); 67 | void resetFaulted(void *requesterId); 68 | 69 | bool isAvailable(); 70 | bool isFaulted(); 71 | }; 72 | 73 | class AvailabilityService : public MemoryManaged { 74 | private: 75 | Context& context; 76 | 77 | AvailabilityServiceEvse* evses [MO_NUM_EVSEID] = {nullptr}; 78 | 79 | public: 80 | AvailabilityService(Context& context, size_t numEvses); 81 | ~AvailabilityService(); 82 | 83 | void loop(); 84 | 85 | AvailabilityServiceEvse *getEvse(unsigned int evseId); 86 | }; 87 | 88 | } // namespace MicroOcpp 89 | 90 | #endif // MO_ENABLE_V201 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/Operation.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | /** 6 | * This framework considers OCPP operations to be a combination of two things: first, ensure that the message reaches its 7 | * destination properly (the "Remote procedure call" header, e.g. message Id). Second, transmit the application data 8 | * as specified in the OCPP 1.6 document. 9 | * 10 | * The remote procedure call (RPC) part is implemented by the class Request. The application data part is implemented by 11 | * the respective Operation subclasses, e.g. BootNotification, StartTransaction, ect. 12 | * 13 | * The resulting structure is that the RPC header (=instance of Request) holds a reference to the payload 14 | * message creator (=instance of BootNotification, StartTransaction, ...). Both objects working together give the complete 15 | * OCPP operation. 16 | */ 17 | 18 | #ifndef MO_OPERATION_H 19 | #define MO_OPERATION_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace MicroOcpp { 26 | 27 | std::unique_ptr createEmptyDocument(); 28 | 29 | class Operation { 30 | public: 31 | Operation(); 32 | 33 | virtual ~Operation(); 34 | 35 | virtual const char* getOperationType(); 36 | 37 | /** 38 | * Create the payload for the respective OCPP message 39 | * 40 | * For instance operation Authorize: creates Authorize.req(idTag) 41 | * 42 | * This function is usually called multiple times by the Arduino loop(). On first call, the request is initially sent. In the 43 | * succeeding calls, the implementers decide to either recreate the request, or do nothing as the operation is still pending. 44 | */ 45 | virtual std::unique_ptr createReq(); 46 | 47 | 48 | virtual void processConf(JsonObject payload); 49 | 50 | /* 51 | * returns if the operation must be aborted 52 | */ 53 | virtual bool processErr(const char *code, const char *description, JsonObject details) { return true;} 54 | 55 | /** 56 | * Processes the request in the JSON document. 57 | */ 58 | virtual void processReq(JsonObject payload); 59 | 60 | /** 61 | * After successfully processing a request sent by the communication counterpart, this function creates the payload for a confirmation 62 | * message. 63 | */ 64 | virtual std::unique_ptr createConf(); 65 | 66 | virtual const char *getErrorCode() {return nullptr;} //nullptr means no error 67 | virtual const char *getErrorDescription() {return "";} 68 | virtual std::unique_ptr getErrorDetails() {return createEmptyDocument();} 69 | }; 70 | 71 | } //end namespace MicroOcpp 72 | #endif 73 | -------------------------------------------------------------------------------- /src/MicroOcpp/Model/Certificates/Certificate_c.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_CERT_MGMT 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | namespace MicroOcpp { 15 | 16 | /* 17 | * C++ wrapper for the C-style certificate interface 18 | */ 19 | class CertificateStoreC : public CertificateStore, public MemoryManaged { 20 | private: 21 | ocpp_cert_store *certstore = nullptr; 22 | public: 23 | CertificateStoreC(ocpp_cert_store *certstore) : MemoryManaged("v201.Certificates.CertificateStoreC"), certstore(certstore) { 24 | 25 | } 26 | 27 | ~CertificateStoreC() = default; 28 | 29 | GetInstalledCertificateStatus getCertificateIds(const Vector& certificateType, Vector& out) override { 30 | out.clear(); 31 | 32 | ocpp_cert_chain_hash *cch; 33 | 34 | auto ret = certstore->getCertificateIds(certstore->user_data, &certificateType[0], certificateType.size(), &cch); 35 | if (ret == GetInstalledCertificateStatus_NotFound || !cch) { 36 | return GetInstalledCertificateStatus_NotFound; 37 | } 38 | 39 | bool err = false; 40 | 41 | for (ocpp_cert_chain_hash *it = cch; it && !err; it = it->next) { 42 | out.emplace_back(); 43 | auto &chd_el = out.back(); 44 | chd_el.certificateType = it->certType; 45 | memcpy(&chd_el.certificateHashData, &it->certHashData, sizeof(ocpp_cert_hash)); 46 | } 47 | 48 | while (cch) { 49 | ocpp_cert_chain_hash *el = cch; 50 | cch = cch->next; 51 | el->invalidate(el); 52 | } 53 | 54 | if (err) { 55 | out.clear(); 56 | } 57 | 58 | return out.empty() ? 59 | GetInstalledCertificateStatus_NotFound : 60 | GetInstalledCertificateStatus_Accepted; 61 | } 62 | 63 | DeleteCertificateStatus deleteCertificate(const CertificateHash& hash) override { 64 | return certstore->deleteCertificate(certstore->user_data, &hash); 65 | } 66 | 67 | InstallCertificateStatus installCertificate(InstallCertificateType certificateType, const char *certificate) override { 68 | return certstore->installCertificate(certstore->user_data, certificateType, certificate); 69 | } 70 | }; 71 | 72 | std::unique_ptr makeCertificateStoreCwrapper(ocpp_cert_store *certstore) { 73 | return std::unique_ptr(new CertificateStoreC(certstore)); 74 | } 75 | 76 | } //namespace MicroOcpp 77 | #endif //MO_ENABLE_CERT_MGMT 78 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/GetCompositeSchedule.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using MicroOcpp::Ocpp16::GetCompositeSchedule; 11 | using MicroOcpp::JsonDoc; 12 | 13 | GetCompositeSchedule::GetCompositeSchedule(Model& model, SmartChargingService& scService) : MemoryManaged("v16.Operation.", "GetCompositeSchedule"), model(model), scService(scService) { 14 | 15 | } 16 | 17 | const char* GetCompositeSchedule::getOperationType() { 18 | return "GetCompositeSchedule"; 19 | } 20 | 21 | void GetCompositeSchedule::processReq(JsonObject payload) { 22 | 23 | connectorId = payload["connectorId"] | -1; 24 | duration = payload["duration"] | 0; 25 | 26 | if (connectorId < 0 || !payload.containsKey("duration")) { 27 | errorCode = "FormationViolation"; 28 | return; 29 | } 30 | 31 | if ((unsigned int) connectorId >= model.getNumConnectors()) { 32 | errorCode = "PropertyConstraintViolation"; 33 | } 34 | 35 | const char *unitStr = payload["chargingRateUnit"] | "_Undefined"; 36 | 37 | if (unitStr[0] == 'A' || unitStr[0] == 'a') { 38 | chargingRateUnit = ChargingRateUnitType_Optional::Amp; 39 | } else if (unitStr[0] == 'W' || unitStr[0] == 'w') { 40 | chargingRateUnit = ChargingRateUnitType_Optional::Watt; 41 | } 42 | } 43 | 44 | std::unique_ptr GetCompositeSchedule::createConf(){ 45 | 46 | bool success = false; 47 | 48 | auto chargingSchedule = scService.getCompositeSchedule((unsigned int) connectorId, duration, chargingRateUnit); 49 | JsonDoc chargingScheduleDoc {0}; 50 | 51 | if (chargingSchedule) { 52 | success = chargingSchedule->toJson(chargingScheduleDoc); 53 | } 54 | 55 | char scheduleStart_str [JSONDATE_LENGTH + 1] = {'\0'}; 56 | 57 | if (success && chargingSchedule) { 58 | success = chargingSchedule->startSchedule.toJsonString(scheduleStart_str, JSONDATE_LENGTH + 1); 59 | } 60 | 61 | if (success && chargingSchedule) { 62 | auto doc = makeJsonDoc(getMemoryTag(), 63 | JSON_OBJECT_SIZE(4) + 64 | chargingScheduleDoc.memoryUsage()); 65 | JsonObject payload = doc->to(); 66 | payload["status"] = "Accepted"; 67 | payload["connectorId"] = connectorId; 68 | payload["scheduleStart"] = scheduleStart_str; 69 | payload["chargingSchedule"] = chargingScheduleDoc; 70 | return doc; 71 | } else { 72 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 73 | JsonObject payload = doc->to(); 74 | payload["status"] = "Rejected"; 75 | return doc; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/FilesystemAdapter.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_FILESYSTEMADAPTER_H 6 | #define MO_FILESYSTEMADAPTER_H 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #define DISABLE_FS 0 15 | #define ARDUINO_LITTLEFS 1 16 | #define ARDUINO_SPIFFS 2 17 | #define ESPIDF_SPIFFS 3 18 | #define POSIX_FILEAPI 4 19 | 20 | // choose FileAPI if not given by build flag; assume usage with Arduino if no build flags are present 21 | #ifndef MO_USE_FILEAPI 22 | #if MO_PLATFORM == MO_PLATFORM_ARDUINO 23 | #if defined(ESP32) 24 | #define MO_USE_FILEAPI ARDUINO_LITTLEFS 25 | #else 26 | #define MO_USE_FILEAPI ARDUINO_SPIFFS 27 | #endif 28 | #elif MO_PLATFORM == MO_PLATFORM_ESPIDF 29 | #define MO_USE_FILEAPI ESPIDF_SPIFFS 30 | #elif MO_PLATFORM == MO_PLATFORM_UNIX 31 | #define MO_USE_FILEAPI POSIX_FILEAPI 32 | #else 33 | #define MO_USE_FILEAPI DISABLE_FS 34 | #endif //switch-case MO_PLATFORM 35 | #endif //ndef MO_USE_FILEAPI 36 | 37 | #ifndef MO_FILENAME_PREFIX 38 | #if MO_USE_FILEAPI == ESPIDF_SPIFFS 39 | #define MO_FILENAME_PREFIX "/mo_store/" 40 | #else 41 | #define MO_FILENAME_PREFIX "/" 42 | #endif 43 | #endif 44 | 45 | // set default max path size parameters 46 | #ifndef MO_MAX_PATH_SIZE 47 | #if MO_USE_FILEAPI == POSIX_FILEAPI 48 | #define MO_MAX_PATH_SIZE 128 49 | #else 50 | #define MO_MAX_PATH_SIZE 30 51 | #endif 52 | #endif 53 | 54 | #ifndef MO_ENABLE_FILE_INDEX 55 | #define MO_ENABLE_FILE_INDEX 0 56 | #endif 57 | 58 | namespace MicroOcpp { 59 | 60 | class FileAdapter { 61 | public: 62 | virtual ~FileAdapter() = default; 63 | virtual size_t read(char *buf, size_t len) = 0; 64 | virtual size_t write(const char *buf, size_t len) = 0; 65 | virtual size_t seek(size_t offset) = 0; 66 | 67 | virtual int read() = 0; 68 | }; 69 | 70 | class FilesystemAdapter { 71 | public: 72 | virtual ~FilesystemAdapter() = default; 73 | virtual int stat(const char *path, size_t *size) = 0; 74 | virtual std::unique_ptr open(const char *fn, const char *mode) = 0; 75 | virtual bool remove(const char *fn) = 0; 76 | virtual int ftw_root(std::function fn) = 0; //enumerate the files in the mo_store root folder 77 | }; 78 | 79 | /* 80 | * Platform specific implementation. Currently supported: 81 | * - Arduino LittleFs 82 | * - Arduino SPIFFS 83 | * - ESP-IDF SPIFFS 84 | * - POSIX-like API (tested on Ubuntu 20.04) 85 | * 86 | * You can add support for other file systems by passing a custom adapter to mocpp_initialize(...) 87 | * 88 | * Returns null if platform is not supported or Filesystem is disabled 89 | */ 90 | std::shared_ptr makeDefaultFilesystemAdapter(FilesystemOpt config); 91 | 92 | } //end namespace MicroOcpp 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/MicroOcpp/Core/OperationRegistry.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace MicroOcpp; 13 | 14 | OperationRegistry::OperationRegistry() : registry(makeVector("OperationRegistry")) { 15 | 16 | } 17 | 18 | OperationCreator *OperationRegistry::findCreator(const char *operationType) { 19 | for (auto it = registry.begin(); it != registry.end(); ++it) { 20 | if (!strcmp(it->operationType, operationType)) { 21 | return &*it; 22 | } 23 | } 24 | return nullptr; 25 | } 26 | 27 | void OperationRegistry::registerOperation(const char *operationType, std::function creator) { 28 | registry.erase(std::remove_if(registry.begin(), registry.end(), 29 | [operationType] (const OperationCreator& el) { 30 | return !strcmp(operationType, el.operationType); 31 | }), 32 | registry.end()); 33 | 34 | OperationCreator entry; 35 | entry.operationType = operationType; 36 | entry.creator = creator; 37 | 38 | registry.push_back(entry); 39 | 40 | MO_DBG_DEBUG("registered operation %s", operationType); 41 | } 42 | 43 | void OperationRegistry::setOnRequest(const char *operationType, OnReceiveReqListener onRequest) { 44 | if (auto entry = findCreator(operationType)) { 45 | entry->onRequest = onRequest; 46 | } else { 47 | MO_DBG_ERR("%s not registered", operationType); 48 | } 49 | } 50 | 51 | void OperationRegistry::setOnResponse(const char *operationType, OnSendConfListener onResponse) { 52 | if (auto entry = findCreator(operationType)) { 53 | entry->onResponse = onResponse; 54 | } else { 55 | MO_DBG_ERR("%s not registered", operationType); 56 | } 57 | } 58 | 59 | std::unique_ptr OperationRegistry::deserializeOperation(const char *operationType) { 60 | 61 | if (auto entry = findCreator(operationType)) { 62 | auto payload = entry->creator(); 63 | if (payload) { 64 | auto result = std::unique_ptr(new Request( 65 | std::unique_ptr(payload))); 66 | result->setOnReceiveReqListener(entry->onRequest); 67 | result->setOnSendConfListener(entry->onResponse); 68 | return result; 69 | } 70 | } 71 | 72 | return std::unique_ptr(new Request( 73 | std::unique_ptr(new NotImplemented()))); 74 | } 75 | 76 | void OperationRegistry::debugPrint() { 77 | for (auto& creator : registry) { 78 | MO_CONSOLE_PRINTF("[OCPP] > %s\n", creator.operationType); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/InstallCertificate.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | #if MO_ENABLE_CERT_MGMT 8 | 9 | #include 10 | #include 11 | 12 | using MicroOcpp::Ocpp201::InstallCertificate; 13 | using MicroOcpp::JsonDoc; 14 | 15 | InstallCertificate::InstallCertificate(CertificateService& certService) : MemoryManaged("v201.Operation.", "InstallCertificate"), certService(certService) { 16 | 17 | } 18 | 19 | void InstallCertificate::processReq(JsonObject payload) { 20 | 21 | if (!payload.containsKey("certificateType") || 22 | !payload.containsKey("certificate")) { 23 | errorCode = "FormationViolation"; 24 | return; 25 | } 26 | 27 | InstallCertificateType certificateType; 28 | 29 | const char *certificateTypeCstr = payload["certificateType"] | "_Invalid"; 30 | 31 | if (!strcmp(certificateTypeCstr, "V2GRootCertificate")) { 32 | certificateType = InstallCertificateType_V2GRootCertificate; 33 | } else if (!strcmp(certificateTypeCstr, "MORootCertificate")) { 34 | certificateType = InstallCertificateType_MORootCertificate; 35 | } else if (!strcmp(certificateTypeCstr, "CSMSRootCertificate")) { 36 | certificateType = InstallCertificateType_CSMSRootCertificate; 37 | } else if (!strcmp(certificateTypeCstr, "ManufacturerRootCertificate")) { 38 | certificateType = InstallCertificateType_ManufacturerRootCertificate; 39 | } else { 40 | errorCode = "FormationViolation"; 41 | return; 42 | } 43 | 44 | if (!payload["certificate"].is()) { 45 | errorCode = "FormationViolation"; 46 | return; 47 | } 48 | 49 | const char *certificate = payload["certificate"]; 50 | 51 | auto certStore = certService.getCertificateStore(); 52 | if (!certStore) { 53 | errorCode = "NotSupported"; 54 | return; 55 | } 56 | 57 | auto status = certStore->installCertificate(certificateType, certificate); 58 | 59 | switch (status) { 60 | case InstallCertificateStatus_Accepted: 61 | this->status = "Accepted"; 62 | break; 63 | case InstallCertificateStatus_Rejected: 64 | this->status = "Rejected"; 65 | break; 66 | case InstallCertificateStatus_Failed: 67 | this->status = "Failed"; 68 | break; 69 | default: 70 | MO_DBG_ERR("internal error"); 71 | errorCode = "InternalError"; 72 | return; 73 | } 74 | 75 | //operation executed successfully 76 | } 77 | 78 | std::unique_ptr InstallCertificate::createConf(){ 79 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 80 | JsonObject payload = doc->to(); 81 | payload["status"] = status; 82 | return doc; 83 | } 84 | 85 | #endif //MO_ENABLE_CERT_MGMT 86 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/ClearChargingProfile.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | using MicroOcpp::Ocpp16::ClearChargingProfile; 12 | using MicroOcpp::JsonDoc; 13 | 14 | ClearChargingProfile::ClearChargingProfile(SmartChargingService& scService) : MemoryManaged("v16.Operation.", "ClearChargingProfile"), scService(scService) { 15 | 16 | } 17 | 18 | const char* ClearChargingProfile::getOperationType(){ 19 | return "ClearChargingProfile"; 20 | } 21 | 22 | void ClearChargingProfile::processReq(JsonObject payload) { 23 | 24 | std::function filter = [payload] 25 | (int chargingProfileId, int connectorId, ChargingProfilePurposeType chargingProfilePurpose, int stackLevel) { 26 | 27 | if (payload.containsKey("id")) { 28 | if (chargingProfileId == (payload["id"] | -1)) { 29 | return true; 30 | } else { 31 | return false; 32 | } 33 | } 34 | 35 | if (payload.containsKey("connectorId")) { 36 | if (connectorId != (payload["connectorId"] | -1)) { 37 | return false; 38 | } 39 | } 40 | 41 | if (payload.containsKey("chargingProfilePurpose")) { 42 | switch (chargingProfilePurpose) { 43 | case ChargingProfilePurposeType::ChargePointMaxProfile: 44 | if (strcmp(payload["chargingProfilePurpose"] | "INVALID", "ChargePointMaxProfile")) { 45 | return false; 46 | } 47 | break; 48 | case ChargingProfilePurposeType::TxDefaultProfile: 49 | if (strcmp(payload["chargingProfilePurpose"] | "INVALID", "TxDefaultProfile")) { 50 | return false; 51 | } 52 | break; 53 | case ChargingProfilePurposeType::TxProfile: 54 | if (strcmp(payload["chargingProfilePurpose"] | "INVALID", "TxProfile")) { 55 | return false; 56 | } 57 | break; 58 | } 59 | } 60 | 61 | if (payload.containsKey("stackLevel")) { 62 | if (stackLevel != (payload["stackLevel"] | -1)) { 63 | return false; 64 | } 65 | } 66 | 67 | return true; 68 | }; 69 | 70 | matchingProfilesFound = scService.clearChargingProfile(filter); 71 | } 72 | 73 | std::unique_ptr ClearChargingProfile::createConf(){ 74 | auto doc = makeJsonDoc(getMemoryTag(), JSON_OBJECT_SIZE(1)); 75 | JsonObject payload = doc->to(); 76 | if (matchingProfilesFound) 77 | payload["status"] = "Accepted"; 78 | else 79 | payload["status"] = "Unknown"; 80 | 81 | return doc; 82 | } 83 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/CustomOperation.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | 7 | using MicroOcpp::Ocpp16::CustomOperation; 8 | using MicroOcpp::JsonDoc; 9 | 10 | CustomOperation::CustomOperation(const char *operationType, 11 | std::function ()> fn_createReq, 12 | std::function fn_processConf, 13 | std::function fn_processErr) : 14 | MemoryManaged("Operation.Custom.", operationType), 15 | operationType{makeString(getMemoryTag(), operationType)}, 16 | fn_createReq{fn_createReq}, 17 | fn_processConf{fn_processConf}, 18 | fn_processErr{fn_processErr} { 19 | 20 | } 21 | 22 | CustomOperation::CustomOperation(const char *operationType, 23 | std::function fn_processReq, 24 | std::function ()> fn_createConf, 25 | std::function fn_getErrorCode, 26 | std::function fn_getErrorDescription, 27 | std::function ()> fn_getErrorDetails) : 28 | MemoryManaged("Operation.Custom.", operationType), 29 | operationType{makeString(getMemoryTag(), operationType)}, 30 | fn_processReq{fn_processReq}, 31 | fn_createConf{fn_createConf}, 32 | fn_getErrorCode{fn_getErrorCode}, 33 | fn_getErrorDescription{fn_getErrorDescription}, 34 | fn_getErrorDetails{fn_getErrorDetails} { 35 | 36 | } 37 | 38 | CustomOperation::~CustomOperation() { 39 | 40 | } 41 | 42 | const char* CustomOperation::getOperationType() { 43 | return operationType.c_str(); 44 | } 45 | 46 | std::unique_ptr CustomOperation::createReq() { 47 | return fn_createReq(); 48 | } 49 | 50 | void CustomOperation::processConf(JsonObject payload) { 51 | return fn_processConf(payload); 52 | } 53 | 54 | bool CustomOperation::processErr(const char *code, const char *description, JsonObject details) { 55 | if (fn_processErr) { 56 | return fn_processErr(code, description, details); 57 | } 58 | return true; 59 | } 60 | 61 | void CustomOperation::processReq(JsonObject payload) { 62 | return fn_processReq(payload); 63 | } 64 | 65 | std::unique_ptr CustomOperation::createConf() { 66 | return fn_createConf(); 67 | } 68 | 69 | const char *CustomOperation::getErrorCode() { 70 | if (fn_getErrorCode) { 71 | return fn_getErrorCode(); 72 | } else { 73 | return nullptr; 74 | } 75 | } 76 | 77 | const char *CustomOperation::getErrorDescription() { 78 | if (fn_getErrorDescription) { 79 | return fn_getErrorDescription(); 80 | } else { 81 | return ""; 82 | } 83 | } 84 | 85 | std::unique_ptr CustomOperation::getErrorDetails() { 86 | if (fn_getErrorDetails) { 87 | return fn_getErrorDetails(); 88 | } else { 89 | return createEmptyDocument(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/MicroOcpp/Debug.h: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #ifndef MO_DEBUG_H 6 | #define MO_DEBUG_H 7 | 8 | #include 9 | 10 | #define MO_DL_NONE 0x00 //suppress all output to the console 11 | #define MO_DL_ERROR 0x01 //report failures 12 | #define MO_DL_WARN 0x02 //report observed or assumed inconsistent state 13 | #define MO_DL_INFO 0x03 //inform about internal state changes 14 | #define MO_DL_DEBUG 0x04 //relevant info for debugging 15 | #define MO_DL_VERBOSE 0x05 //all output 16 | 17 | #ifndef MO_DBG_LEVEL 18 | #define MO_DBG_LEVEL MO_DL_INFO //default 19 | #endif 20 | 21 | //MbedTLS debug level documented in mbedtls/debug.h: 22 | #ifndef MO_DBG_LEVEL_MBEDTLS 23 | #define MO_DBG_LEVEL_MBEDTLS 1 24 | #endif 25 | 26 | #define MO_DF_MINIMAL 0x00 //don't reveal origin of a debug message 27 | #define MO_DF_COMPACT 0x01 //print module by file name and line number 28 | #define MO_DF_FILE_LINE 0x02 //print file and line number 29 | #define MO_DF_FULL 0x03 //print path and file and line numbr 30 | 31 | #ifndef MO_DBG_FORMAT 32 | #define MO_DBG_FORMAT MO_DF_FILE_LINE //default 33 | #endif 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | void mo_dbg_print_prefix(int level, const char *fn, int line); 40 | void mo_dbg_print_suffix(); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #define MO_DBG(level, X) \ 47 | do { \ 48 | mo_dbg_print_prefix(level, __FILE__, __LINE__); \ 49 | MO_CONSOLE_PRINTF X; \ 50 | mo_dbg_print_suffix(); \ 51 | } while (0) 52 | 53 | #if MO_DBG_LEVEL >= MO_DL_ERROR 54 | #define MO_DBG_ERR(...) MO_DBG(MO_DL_ERROR,(__VA_ARGS__)) 55 | #else 56 | #define MO_DBG_ERR(...) ((void)0) 57 | #endif 58 | 59 | #if MO_DBG_LEVEL >= MO_DL_WARN 60 | #define MO_DBG_WARN(...) MO_DBG(MO_DL_WARN,(__VA_ARGS__)) 61 | #else 62 | #define MO_DBG_WARN(...) ((void)0) 63 | #endif 64 | 65 | #if MO_DBG_LEVEL >= MO_DL_INFO 66 | #define MO_DBG_INFO(...) MO_DBG(MO_DL_INFO,(__VA_ARGS__)) 67 | #else 68 | #define MO_DBG_INFO(...) ((void)0) 69 | #endif 70 | 71 | #if MO_DBG_LEVEL >= MO_DL_DEBUG 72 | #define MO_DBG_DEBUG(...) MO_DBG(MO_DL_DEBUG,(__VA_ARGS__)) 73 | #else 74 | #define MO_DBG_DEBUG(...) ((void)0) 75 | #endif 76 | 77 | #if MO_DBG_LEVEL >= MO_DL_VERBOSE 78 | #define MO_DBG_VERBOSE(...) MO_DBG(MO_DL_VERBOSE,(__VA_ARGS__)) 79 | #else 80 | #define MO_DBG_VERBOSE(...) ((void)0) 81 | #endif 82 | 83 | #ifdef MO_TRAFFIC_OUT 84 | 85 | #define MO_DBG_TRAFFIC_OUT(...) \ 86 | do { \ 87 | MO_CONSOLE_PRINTF("[MO] Send: %s",__VA_ARGS__); \ 88 | MO_CONSOLE_PRINTF("\n"); \ 89 | } while (0) 90 | 91 | #define MO_DBG_TRAFFIC_IN(...) \ 92 | do { \ 93 | MO_CONSOLE_PRINTF("[MO] Recv: %.*s",__VA_ARGS__); \ 94 | MO_CONSOLE_PRINTF("\n"); \ 95 | } while (0) 96 | 97 | #else 98 | #define MO_DBG_TRAFFIC_OUT(...) ((void)0) 99 | #define MO_DBG_TRAFFIC_IN(...) ((void)0) 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /src/MicroOcpp/Operations/MeterValues.cpp: -------------------------------------------------------------------------------- 1 | // matth-x/MicroOcpp 2 | // Copyright Matthias Akstaller 2019 - 2024 3 | // MIT License 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using MicroOcpp::Ocpp16::MeterValues; 12 | using MicroOcpp::JsonDoc; 13 | 14 | //can only be used for echo server debugging 15 | MeterValues::MeterValues(Model& model) : MemoryManaged("v16.Operation.", "MeterValues"), model(model) { 16 | 17 | } 18 | 19 | MeterValues::MeterValues(Model& model, MeterValue *meterValue, unsigned int connectorId, std::shared_ptr transaction) 20 | : MemoryManaged("v16.Operation.", "MeterValues"), model(model), meterValue{meterValue}, connectorId{connectorId}, transaction{transaction} { 21 | 22 | } 23 | 24 | MeterValues::MeterValues(Model& model, std::unique_ptr meterValue, unsigned int connectorId, std::shared_ptr transaction) 25 | : MeterValues(model, meterValue.get(), connectorId, transaction) { 26 | this->meterValueOwnership = std::move(meterValue); 27 | } 28 | 29 | MeterValues::~MeterValues(){ 30 | 31 | } 32 | 33 | const char* MeterValues::getOperationType(){ 34 | return "MeterValues"; 35 | } 36 | 37 | std::unique_ptr MeterValues::createReq() { 38 | 39 | size_t capacity = 0; 40 | 41 | std::unique_ptr meterValueJson; 42 | 43 | if (meterValue) { 44 | 45 | if (meterValue->getTimestamp() < MIN_TIME) { 46 | MO_DBG_DEBUG("adjust preboot MeterValue timestamp"); 47 | Timestamp adjusted = model.getClock().adjustPrebootTimestamp(meterValue->getTimestamp()); 48 | meterValue->setTimestamp(adjusted); 49 | } 50 | 51 | meterValueJson = meterValue->toJson(); 52 | if (meterValueJson) { 53 | capacity += meterValueJson->capacity(); 54 | } else { 55 | MO_DBG_ERR("Energy meter reading not convertible to JSON"); 56 | } 57 | } 58 | 59 | capacity += JSON_OBJECT_SIZE(3); 60 | capacity += JSON_ARRAY_SIZE(1); 61 | 62 | auto doc = makeJsonDoc(getMemoryTag(), capacity); 63 | auto payload = doc->to(); 64 | payload["connectorId"] = connectorId; 65 | 66 | if (transaction && transaction->getTransactionId() > 0) { //add txId if MVs are assigned to a tx with txId 67 | payload["transactionId"] = transaction->getTransactionId(); 68 | } 69 | 70 | auto meterValueArray = payload.createNestedArray("meterValue"); 71 | if (meterValueJson) { 72 | meterValueArray.add(*meterValueJson); 73 | } 74 | 75 | return doc; 76 | } 77 | 78 | void MeterValues::processConf(JsonObject payload) { 79 | MO_DBG_DEBUG("Request has been confirmed"); 80 | } 81 | 82 | 83 | void MeterValues::processReq(JsonObject payload) { 84 | 85 | /** 86 | * Ignore Contents of this Req-message, because this is for debug purposes only 87 | */ 88 | 89 | } 90 | 91 | std::unique_ptr MeterValues::createConf(){ 92 | return createEmptyDocument(); 93 | } 94 | --------------------------------------------------------------------------------