diff --git a/CHANGELOG.md b/CHANGELOG.md index 4868681..5b417fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## Unreleased ### Added -- Mongoose v7.13 support ([#11](https://github.com/matth-x/MicroOcppMongoose/pull/11) +- Mongoose v7.13 support ([#11](https://github.com/matth-x/MicroOcppMongoose/pull/11)) +- OCPP 2.0.1 BasicAuthPassword integration ([#13](https://github.com/matth-x/MicroOcppMongoose/pull/13)) ### Fixed - AuthorizationKey hex conversion ([#12](https://github.com/matth-x/MicroOcppMongoose/pull/12)) diff --git a/src/MicroOcppMongooseClient.cpp b/src/MicroOcppMongooseClient.cpp index 2a0e1fe..9b10019 100644 --- a/src/MicroOcppMongooseClient.cpp +++ b/src/MicroOcppMongooseClient.cpp @@ -6,6 +6,10 @@ #include #include +#if MO_ENABLE_V201 +#include +#endif + #define DEBUG_MSG_INTERVAL 5000UL #define WS_UNRESPONSIVE_THRESHOLD_MS 15000UL @@ -68,16 +72,32 @@ MOcppMongooseClient::MOcppMongooseClient(struct mg_mgr *mgr, MO_DBG_WARN("auth_key_factory too long - will be cropped"); auth_key_factory_len = MO_AUTHKEY_LEN_MAX; } - char auth_key_hex [2 * MO_AUTHKEY_LEN_MAX + 1]; - auth_key_hex[0] = '\0'; - if (auth_key_factory) { - for (size_t i = 0; i < auth_key_factory_len; i++) { - snprintf(auth_key_hex + 2 * i, 3, "%02X", auth_key_factory[i]); + +#if MO_ENABLE_V201 + if (protocolVersion.major == 2) { + websocketSettings = makeVariableContainerVolatile(MO_WSCONN_FN_V201, true); + auto variable = websocketSettings->createVariable(Variable::InternalDataType::String, Variable::AttributeType::Actual); + variable->setComponentId("SecurityCtrlr"); + variable->setName("BasicAuthPassword"); + char basicAuthPassword [MO_AUTHKEY_LEN_MAX + 1]; + snprintf(basicAuthPassword, sizeof(basicAuthPassword), "%.*s", (int)auth_key_factory_len, auth_key_factory ? (const char*)auth_key_factory : ""); + variable->setString(basicAuthPassword); + websocketSettings->add(std::move(variable)); + basicAuthPasswordString = websocketSettings->getVariable("SecurityCtrlr", "BasicAuthPassword"); + } else +#endif + { + char auth_key_hex [2 * MO_AUTHKEY_LEN_MAX + 1]; + auth_key_hex[0] = '\0'; + if (auth_key_factory) { + for (size_t i = 0; i < auth_key_factory_len; i++) { + snprintf(auth_key_hex + 2 * i, 3, "%02X", auth_key_factory[i]); + } } + setting_auth_key_hex_str = declareConfiguration( + "AuthorizationKey", auth_key_hex, MO_WSCONN_FN, readonly, true); + registerConfigurationValidator("AuthorizationKey", validateAuthorizationKeyHex); } - setting_auth_key_hex_str = declareConfiguration( - "AuthorizationKey", auth_key_hex, MO_WSCONN_FN, readonly, true); - registerConfigurationValidator("AuthorizationKey", validateAuthorizationKeyHex); ws_ping_interval_int = declareConfiguration( "WebSocketPingInterval", 5, MO_WSCONN_FN); @@ -378,15 +398,26 @@ void MOcppMongooseClient::setAuthKey(const unsigned char *auth_key, size_t len) return; } - char auth_key_hex [2 * MO_AUTHKEY_LEN_MAX + 1]; - auth_key_hex[0] = '\0'; - for (size_t i = 0; i < len; i++) { - snprintf(auth_key_hex + 2 * i, 3, "%02X", auth_key[i]); - } - if (setting_auth_key_hex_str) { - setting_auth_key_hex_str->setString(auth_key_hex); - configuration_save(); +#if MO_ENABLE_V201 + if (protocolVersion.major == 2) { + char basicAuthPassword [MO_AUTHKEY_LEN_MAX + 1]; + snprintf(basicAuthPassword, sizeof(basicAuthPassword), "%.*s", (int)len, auth_key ? (const char*)auth_key : ""); + if (basicAuthPasswordString) { + basicAuthPasswordString->setString(basicAuthPassword); + } + } else +#endif + { + char auth_key_hex [2 * MO_AUTHKEY_LEN_MAX + 1]; + auth_key_hex[0] = '\0'; + for (size_t i = 0; i < len; i++) { + snprintf(auth_key_hex + 2 * i, 3, "%02X", auth_key[i]); + } + if (setting_auth_key_hex_str) { + setting_auth_key_hex_str->setString(auth_key_hex); + configuration_save(); + } } } @@ -409,19 +440,29 @@ void MOcppMongooseClient::reloadConfigs() { cb_id = setting_cb_id_str->getString(); } - if (setting_auth_key_hex_str) { - auto auth_key_hex = setting_auth_key_hex_str->getString(); - - #if MO_MG_VERSION_614 - cs_from_hex((char*)auth_key, auth_key_hex, strlen(auth_key_hex)); - #elif MO_MG_USE_VERSION <= MO_MG_V713 - mg_unhex(auth_key_hex, strlen(auth_key_hex), auth_key); - #else - mg_str_to_num(mg_str(auth_key_hex), 16, auth_key, MO_AUTHKEY_LEN_MAX); - #endif +#if MO_ENABLE_V201 + if (protocolVersion.major == 2) { + if (basicAuthPasswordString) { + snprintf((char*)auth_key, sizeof(auth_key), "%s", basicAuthPasswordString->getString()); + auth_key_len = strlen((char*)auth_key); + } + } else +#endif + { + if (setting_auth_key_hex_str) { + auto auth_key_hex = setting_auth_key_hex_str->getString(); + + #if MO_MG_VERSION_614 + cs_from_hex((char*)auth_key, auth_key_hex, strlen(auth_key_hex)); + #elif MO_MG_USE_VERSION <= MO_MG_V713 + mg_unhex(auth_key_hex, strlen(auth_key_hex), auth_key); + #else + mg_str_to_num(mg_str(auth_key_hex), 16, auth_key, MO_AUTHKEY_LEN_MAX); + #endif - auth_key_len = strlen(setting_auth_key_hex_str->getString()) / 2; - auth_key[auth_key_len] = '\0'; //need null-termination as long as deprecated `const char *getAuthKey()` exists + auth_key_len = strlen(setting_auth_key_hex_str->getString()) / 2; + auth_key[auth_key_len] = '\0'; //need null-termination as long as deprecated `const char *getAuthKey()` exists + } } /* @@ -480,6 +521,12 @@ unsigned long MOcppMongooseClient::getLastConnected() { return last_connection_established; } +#if MO_ENABLE_V201 +std::shared_ptr MOcppMongooseClient::getVariableContainer() { + return websocketSettings; +} +#endif + #if MO_MG_USE_VERSION == MO_MG_V614 void ws_cb(struct mg_connection *nc, int ev, void *ev_data, void *user_data) { diff --git a/src/MicroOcppMongooseClient.h b/src/MicroOcppMongooseClient.h index 1160230..149b3d3 100644 --- a/src/MicroOcppMongooseClient.h +++ b/src/MicroOcppMongooseClient.h @@ -19,15 +19,25 @@ #ifndef MO_WSCONN_FN #define MO_WSCONN_FN (MO_FILENAME_PREFIX "ws-conn.jsn") +#define MO_WSCONN_FN_V201 (MO_FILENAME_PREFIX "ws-conn-v201.jsn") #endif +#if MO_ENABLE_V201 +#define MO_AUTHKEY_LEN_MAX 40 //BasicAuthPassword length +#else #define MO_AUTHKEY_LEN_MAX 20 //AuthKey in Bytes. Hex value has double length +#endif namespace MicroOcpp { class FilesystemAdapter; class Configuration; +#if MO_ENABLE_V201 +class Variable; +class VariableContainer; +#endif + class MOcppMongooseClient : public MicroOcpp::Connection { private: struct mg_mgr *mgr {nullptr}; @@ -35,7 +45,7 @@ class MOcppMongooseClient : public MicroOcpp::Connection { std::string backend_url; std::string cb_id; std::string url; //url = backend_url + '/' + cb_id - unsigned char auth_key [MO_AUTHKEY_LEN_MAX + 1]; //AuthKey in bytes encoding ("FF01" = {0xFF, 0x01}) + unsigned char auth_key [MO_AUTHKEY_LEN_MAX + 1]; //OCPP 2.0.1: BasicAuthPassword. OCPP 1.6: AuthKey in bytes encoding ("FF01" = {0xFF, 0x01}). Both versions append a terminating '\0' size_t auth_key_len; const char *ca_cert; //zero-copy. The host system must ensure that this pointer remains valid during the lifetime of this class std::shared_ptr setting_backend_url_str; @@ -47,6 +57,10 @@ class MOcppMongooseClient : public MicroOcpp::Connection { std::shared_ptr stale_timeout_int; //inactivity period after which the connection will be closed std::shared_ptr ws_ping_interval_int; //heartbeat intervall in s. 0 sets hb off unsigned long last_hb {0}; +#if MO_ENABLE_V201 + std::shared_ptr websocketSettings; + Variable *basicAuthPasswordString = nullptr; +#endif bool connection_established {false}; unsigned long last_connection_established {-1UL / 2UL}; bool connection_closing {false}; @@ -115,6 +129,12 @@ class MOcppMongooseClient : public MicroOcpp::Connection { void updateRcvTimer(); unsigned long getLastRecv(); //get time of last successful receive in millis unsigned long getLastConnected(); //get time of last connection establish + +#if MO_ENABLE_V201 + //WS client creates and manages its own Variables. This getter function is a temporary solution, in future + //the WS client will be initialized with a Context reference for registering the Variables directly + std::shared_ptr getVariableContainer(); +#endif }; }