From 24bbe22e872ce8f0e1c02c202eb351e8398e7def Mon Sep 17 00:00:00 2001 From: iranl Date: Fri, 31 Jan 2025 20:21:26 +0100 Subject: [PATCH] Import/Export config over MQTT --- README.md | 56 +- src/Config.h | 2 +- src/Gpio.cpp | 14 +- src/ImportExport.cpp | 1005 +++++++++++++++++++++ src/ImportExport.h | 45 + src/MqttTopics.h | 5 + src/NukiNetwork.cpp | 276 +++++- src/NukiNetwork.h | 6 +- src/NukiNetworkLock.cpp | 2 +- src/NukiNetworkOpener.cpp | 6 +- src/NukiOfficial.cpp | 20 +- src/NukiOpenerWrapper.cpp | 149 ++-- src/NukiOpenerWrapper.h | 6 +- src/NukiWrapper.cpp | 143 ++- src/NukiWrapper.h | 6 +- src/PreferencesKeys.h | 14 +- src/WebCfgServer.cpp | 1101 +++++------------------- src/WebCfgServer.h | 23 +- src/main.cpp | 77 +- src/networkDevices/EthernetDevice.cpp | 14 +- src/networkDevices/IPConfiguration.cpp | 12 +- src/networkDevices/NetworkDevice.cpp | 11 +- src/networkDevices/NetworkDevice.h | 1 + src/util/NetworkUtil.cpp | 2 +- updater/src/CMakeLists.txt | 2 + 25 files changed, 1792 insertions(+), 1206 deletions(-) create mode 100644 src/ImportExport.cpp create mode 100644 src/ImportExport.h diff --git a/README.md b/README.md index 66798f5..88d5b32 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Devices ranked best-to-worst: - ESP32 without PSRAM - ......
(Devices below will not support more Nuki Hub functions) -- ...... +- ...... - ESP32-C6 - ESP32-solo1 - ESP32-C3 @@ -292,7 +292,9 @@ In a browser navigate to the IP address assigned to the ESP32. ### Access Level Configuration #### Nuki General Access Control -- Publish Nuki configuration information: Enable to publish information about the configuration of the connected Nuki device(s) through MQTT. +- Publish Nuki Hub configuration information: Publish Nuki Hub settings over MQTT, see "[Import and Export Nuki Hub settings over MQTT](#import-and-export-nuki-hub-settings-over-mqtt)" +- Modify Nuki Hub configuration over MQTT: Allow changing Nuki Hub settings using MQTT, see "[Import and Export Nuki Hub settings over MQTT](#import-and-export-nuki-hub-settings-over-mqtt)" +- Publish Nuki configuration information: Enable to publish information about the configuration of the connected Nuki device(s) through MQTT. Note: All of the following requires the Nuki security code / PIN to be set, see "[Nuki Lock PIN / Nuki Opener PIN](#nuki-lock-pin--nuki-opener-pin)" @@ -463,6 +465,9 @@ Note that the following options can break Nuki Hub and cause bootloops that will - [lock/opener/]configuration/commandResult: Result of the last configuration change action as JSON data. See the "[Changing Nuki Lock/Opener Configuration](#changing-nuki-lockopener-configuration)" section of this README for possible values - [lock/opener/]configuration/basicJson: The current basic configuration of the Nuki Lock/Opener as JSON data. See [Nuki Smart Lock API](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--set-config) and [Nuki Opener API](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--set-config) for available settings. Please note: Longitude and Latitude of the Lock/Opener are not published to MQTT by design. These values can still be changed though. - [lock/opener/]configuration/advancedJson: The current advanced configuration of the Nuki Lock/Opener as JSON data. See [Nuki Smart Lock API](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--advanced-config) and [Nuki Opener API](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--advanced-config) for available settings. +- configuration/action: Allows importing and exporting configuration settings of Nuki Hub using a JSON formatted value. After receiving the action, the value is set to "--", see "[Import and Export Nuki Hub settings over MQTT](#import-and-export-nuki-hub-settings-over-mqtt)" +- configuration/commandResult: Result of the last Nuki Hub configuration import action as JSON data, see "[Import and Export Nuki Hub settings over MQTT](#import-and-export-nuki-hub-settings-over-mqtt)" +- configuration/json: Topic where you can export Nuki Hub configuration as JSON data to, see "[Import and Export Nuki Hub settings over MQTT](#import-and-export-nuki-hub-settings-over-mqtt)" ### Query @@ -512,8 +517,51 @@ Note that the following options can break Nuki Hub and cause bootloops that will - maintenance/wifiRssi: The Wi-Fi signal strength of the Wi-Fi Access Point as measured by the ESP32 and expressed by the RSSI Value in dBm. - maintenance/log: If "Enable MQTT logging" is enabled in the web interface, this topic will be filled with debug log information. - maintenance/freeHeap: Only available when debug mode is enabled. Set to the current size of free heap memory in bytes. -- maintenance/restartReasonNukiHub: Set to the last reason Nuki Hub was restarted. See [RestartReason.h](/RestartReason.h) for possible values -- maintenance/restartReasonNukiEsp: Set to the last reason the ESP was restarted. See [RestartReason.h](/RestartReason.h) for possible values +- maintenance/restartReasonNukiHub: Set to the last reason Nuki Hub was restarted. See [RestartReason.h](/src/RestartReason.h) for possible values +- maintenance/restartReasonNukiEsp: Set to the last reason the ESP was restarted. See [RestartReason.h](/src/RestartReason.h) for possible values + +## Import and Export Nuki Hub settings over MQTT + +Consider this when deciding if you want to enable the following functionality: + +- Any application/actor that has read access to `nukihub/configuration/action` and `nukihub/configuration/json` can view your changes and exports. +- If you have not enabled the setting to require MFA when changing settings any application/actor that has write access to `nukihub/configuration/action` can change Nuki Hub settings (including pairing data and credentials) + +### Export Nuki Hub settings over MQTT + +To allow Nuki Hub to export configuration over MQTT first enable "Publish Nuki Hub configuration information" in "Access Level Configuration" and save the configuration. +You can export Nuki Hub settings in JSON format by sending the following JSON values to the `nukihub/configuration/action` topic: +- Export Nuki Hub settings without redacted settings and without pairing settings: `{"exportNH": 0}` + +NOTE: The following settings can only be exported if you have setup a secure MQTT connection (MQTT over SSL) + +- Export Nuki Hub settings with redacted settings and without pairing settings: `{"exportNH": 0, "redacted": 1}` +- Export Nuki Hub settings without redacted settings and with pairing settings: `{"exportNH": 0, "pairing": 1}` +- Export Nuki Hub settings with redacted settings and pairing settings: `{"exportNH": 0, "redacted": 1, "pairing": 1}` +- Export Nuki Hub MQTTS certificates and key: `{"exportMQTTS": 0}` +- Export Nuki Hub HTTPS certificate and key: `{"exportHTTPS": 0}` + +The exported values will be available in the `nukihub/configuration/json` topic in JSON format. +A general explanation of the exported values can be found in the [PreferencesKeys.h](/src/PreferencesKeys.h) file + +If you set the value of `exportNH`/`exportMQTTS`/`exportHTTPS` to an integer value > 0 the `nukihub/configuration/json` will be cleared after the given amount of seconds (e.g. `{"exportMQTTS": 30}` will clear the JSON topic after 30 seconds) + +If you have enabled `Require Duo Push authentication for all sensitive Nuki Hub operations (changing/exporting settings)` you will first need to approve the Duo Push before the settings will be exported. + +### Import/Change Nuki Hub settings over MQTT + +To allow Nuki Hub to import/change configuration over MQTT first enable "Modify Nuki Hub configuration over MQTT" in "Access Level Configuration" and save the configuration. +You can import Nuki Hub settings in JSON format by sending the desired JSON values to be changed to the `nukihub/configuration/action` topic. +The expected values and format is the same as the JSON files/values that can be exported over MQTT or through the Web Configurator. + +The result of the import will be available in the `nukihub/configuration/commandResult` topic in JSON format. +After the import is complete the ESP32 will reboot. + +If you have enabled `Require Duo Push authentication for all sensitive Nuki Hub operations (changing/exporting settings)` you will first need to approve the Duo Push before the settings will be changed/imported. + +Note: When importing settings using MQTT there are less/no checks on the values entered. These checks are only available when changing settings through the WebConfigurator. +Consider testing your configuration values by changing them in the Web Configurator before trying to use MQTT to change configuration. +A general explanation of the values that can be imported can be found in the [PreferencesKeys.h](/src/PreferencesKeys.h) file ## Changing Nuki Lock/Opener Configuration diff --git a/src/Config.h b/src/Config.h index f868828..c7e4c00 100644 --- a/src/Config.h +++ b/src/Config.h @@ -5,7 +5,7 @@ #define NUKI_HUB_VERSION "9.09" #define NUKI_HUB_VERSION_INT (uint32_t)909 #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2025-01-28" +#define NUKI_HUB_DATE "2025-02-04" #define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json" diff --git a/src/Gpio.cpp b/src/Gpio.cpp index 9490ca0..b3cd5f1 100644 --- a/src/Gpio.cpp +++ b/src/Gpio.cpp @@ -223,7 +223,7 @@ void Gpio::loadPinConfiguration() { PinEntry entry; entry.pin = serialized[i * 2]; - Log->print(("Pin ")); + Log->print("Pin "); Log->println(entry.pin); if(std::find(disabledPins.begin(), disabledPins.end(), entry.pin) == disabledPins.end()) @@ -234,14 +234,14 @@ void Gpio::loadPinConfiguration() } entry.role = (PinRole) serialized[(i * 2 + 1)]; Log->println("Not found in Ethernet disabled pins"); - Log->print(("Role: ")); + Log->print("Role: "); Log->println(getRoleDescription(entry.role)); } else { entry.role = PinRole::Ethernet; Log->println("Found in Ethernet disabled pins"); - Log->print(("Role: ")); + Log->print("Role: "); Log->println(getRoleDescription(entry.role)); } if(entry.role != PinRole::Disabled) @@ -359,7 +359,7 @@ const std::vector Gpio::getDisabledPins() const break; } - Log->print(("GPIO Boot button and Ethernet disabled pins:")); + Log->print("GPIO Boot button and Ethernet disabled pins:"); for_each_n(disabledPins.begin(), disabledPins.size(), [](int x) { @@ -382,7 +382,7 @@ void Gpio::savePinConfiguration(const std::vector &pinConfiguration) for(int i=0; i < len; i++) { const auto& entry = pinConfiguration[i]; - Log->print(("Pin ")); + Log->print("Pin "); Log->println(entry.pin); if(std::find(disabledPins.begin(), disabledPins.end(), entry.pin) != disabledPins.end()) @@ -390,7 +390,7 @@ void Gpio::savePinConfiguration(const std::vector &pinConfiguration) serialized[i * 2] = entry.pin; serialized[i * 2 + 1] = (int8_t)PinRole::Ethernet; Log->println("Found in Ethernet disabled pins"); - Log->print(("Role: ")); + Log->print("Role: "); Log->println(getRoleDescription(PinRole::Ethernet)); } @@ -401,7 +401,7 @@ void Gpio::savePinConfiguration(const std::vector &pinConfiguration) serialized[i * 2] = entry.pin; serialized[i * 2 + 1] = (int8_t) entry.role; Log->println("Not found in Ethernet disabled pins"); - Log->print(("Role: ")); + Log->print("Role: "); Log->println(getRoleDescription(entry.role)); } } diff --git a/src/ImportExport.cpp b/src/ImportExport.cpp new file mode 100644 index 0000000..452411c --- /dev/null +++ b/src/ImportExport.cpp @@ -0,0 +1,1005 @@ +#include "ImportExport.h" +#include "SPIFFS.h" +#include "Logger.h" +#include "PreferencesKeys.h" +#include + +ImportExport::ImportExport(Preferences *preferences) + : _preferences(preferences) +{ + readSettings(); +} + +void ImportExport::readSettings() +{ + if (_preferences->getBool(preference_cred_duo_enabled, false)) + { + _duoEnabled = true; + _duoHost = _preferences->getString(preference_cred_duo_host, ""); + _duoIkey = _preferences->getString(preference_cred_duo_ikey, ""); + _duoSkey = _preferences->getString(preference_cred_duo_skey, ""); + _duoUser = _preferences->getString(preference_cred_duo_user, ""); + + if (_duoHost == "" || _duoIkey == "" || _duoSkey == "" || _duoUser == "" || !_preferences->getBool(preference_update_time, false)) + { + _duoEnabled = false; + } + else if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false) || _preferences->getInt(preference_cred_bypass_gpio_high, -1) > -1 || _preferences->getInt(preference_cred_bypass_gpio_low, -1) > -1) + { + if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false)) + { + _bypassGPIO = true; + } + _bypassGPIOHigh = _preferences->getInt(preference_cred_bypass_gpio_high, -1); + _bypassGPIOLow = _preferences->getInt(preference_cred_bypass_gpio_low, -1); + } + } +} + +bool ImportExport::getDuoEnabled() +{ + return _duoEnabled; +} + +bool ImportExport::getBypassGPIOEnabled() +{ + return _bypassGPIO; +} + +int ImportExport::getBypassGPIOHigh() +{ + return _bypassGPIOHigh; +} +int ImportExport::getBypassGPIOLow() +{ + return _bypassGPIOLow; +} + +bool ImportExport::startDuoAuth(char* pushType) +{ + int64_t timeout = esp_timer_get_time() - (30 * 1000 * 1000L); + if(!_duoActiveRequest || timeout > _duoRequestTS) + { + const char* duo_host = _duoHost.c_str(); + const char* duo_ikey = _duoIkey.c_str(); + const char* duo_skey = _duoSkey.c_str(); + const char* duo_user = _duoUser.c_str(); + + DuoAuthLib duoAuth; + bool duoRequestResult; + duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo); + duoAuth.setPushType(pushType); + duoRequestResult = duoAuth.pushAuth((char*)duo_user, true); + + if(duoRequestResult == true) + { + _duoTransactionId = duoAuth.getAuthTxId(); + _duoActiveRequest = true; + _duoRequestTS = esp_timer_get_time(); + Log->println("Duo MFA Auth sent"); + return true; + } + else + { + Log->println("Failed Duo MFA Auth"); + return false; + } + } + return true; +} + +void ImportExport::setDuoCheckIP(String duoCheckIP) +{ + _duoCheckIP = duoCheckIP; +} + +void ImportExport::setDuoCheckId(String duoCheckId) +{ + _duoCheckId = duoCheckId; +} + +void ImportExport::saveSessions() +{ + if(_preferences->getBool(preference_update_time, false)) + { + if (!SPIFFS.begin(true)) + { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file; + file = SPIFFS.open("/duosessions.json", "w"); + serializeJson(_duoSessions, file); + file.close(); + } + } +} + +int ImportExport::checkDuoAuth(PsychicRequest *request) +{ + const char* duo_host = _duoHost.c_str(); + const char* duo_ikey = _duoIkey.c_str(); + const char* duo_skey = _duoSkey.c_str(); + const char* duo_user = _duoUser.c_str(); + + if (request->hasParam("id")) { + const PsychicWebParameter* p = request->getParam("id"); + String cookie2 = p->value(); + DuoAuthLib duoAuth; + if(_duoActiveRequest && _duoCheckIP == request->client()->localIP().toString() && cookie2 == _duoCheckId) + { + duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo); + + Log->println("Checking Duo Push Status..."); + duoAuth.authStatus(_duoTransactionId); + + if(duoAuth.pushWaiting()) + { + Log->println("Duo Push Waiting..."); + return 2; + } + else + { + if (duoAuth.authSuccessful()) + { + Log->println("Successful Duo MFA Auth"); + _duoActiveRequest = false; + _duoTransactionId = ""; + _duoCheckIP = ""; + _duoCheckId = ""; + int64_t durationLength = 60*60*_preferences->getInt(preference_cred_session_lifetime_duo_remember, 720); + + if (!_sessionsOpts[request->client()->localIP().toString()]) + { + durationLength = _preferences->getInt(preference_cred_session_lifetime_duo, 3600); + } + struct timeval time; + gettimeofday(&time, NULL); + int64_t time_us = (int64_t)time.tv_sec * 1000000L + (int64_t)time.tv_usec; + _duoSessions[cookie2] = time_us + (durationLength*1000000L); + saveSessions(); + if (_preferences->getBool(preference_mfa_reconfigure, false)) + { + _preferences->putBool(preference_mfa_reconfigure, false); + } + return 1; + } + else + { + Log->println("Failed Duo MFA Auth"); + _duoActiveRequest = false; + _duoTransactionId = ""; + _duoCheckIP = ""; + _duoCheckId = ""; + if (_preferences->getBool(preference_mfa_reconfigure, false)) + { + _preferences->putBool(preference_cred_duo_enabled, false); + _duoEnabled = false; + _preferences->putBool(preference_mfa_reconfigure, false); + } + return 0; + } + } + } + } + return 0; +} + +int ImportExport::checkDuoApprove() +{ + const char* duo_host = _duoHost.c_str(); + const char* duo_ikey = _duoIkey.c_str(); + const char* duo_skey = _duoSkey.c_str(); + const char* duo_user = _duoUser.c_str(); + + DuoAuthLib duoAuth; + if(_duoActiveRequest) + { + duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo); + + Log->println("Checking Duo Push Status..."); + duoAuth.authStatus(_duoTransactionId); + + if(duoAuth.pushWaiting()) + { + Log->println("Duo Push Waiting..."); + return 2; + } + else + { + if (duoAuth.authSuccessful()) + { + Log->println("Successful Duo MFA Auth"); + _duoActiveRequest = false; + _duoTransactionId = ""; + _duoCheckIP = ""; + _duoCheckId = ""; + return 1; + } + else + { + Log->println("Failed Duo MFA Auth"); + _duoActiveRequest = false; + _duoTransactionId = ""; + _duoCheckIP = ""; + _duoCheckId = ""; + return 0; + } + } + } + return 0; +} + +void ImportExport::exportHttpsJson(JsonDocument &json) +{ + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/http_ssl.crt"); + if (!file || file.isDirectory()) { + Log->println("http_ssl.crt not found"); + } + else + { + Log->println("Reading http_ssl.crt"); + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); + file.close(); + cert[filesize] = '\0'; + json["http_ssl.crt"] = cert; + } + } + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/http_ssl.key"); + if (!file || file.isDirectory()) { + Log->println("http_ssl.key not found"); + } + else + { + Log->println("Reading http_ssl.key"); + size_t filesize = file.size(); + char key[filesize + 1]; + + file.read((uint8_t *)key, sizeof(key)); + file.close(); + key[filesize] = '\0'; + json["http_ssl.key"] = key; + } + } +} + +void ImportExport::exportMqttsJson(JsonDocument &json) +{ + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.ca"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.ca not found"); + } + else + { + Log->println("Reading mqtt_ssl.ca"); + size_t filesize = file.size(); + char ca[filesize + 1]; + + file.read((uint8_t *)ca, sizeof(ca)); + file.close(); + ca[filesize] = '\0'; + json["mqtt_ssl.ca"] = ca; + } + } + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.crt"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.crt not found"); + } + else + { + Log->println("Reading mqtt_ssl.crt"); + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); + file.close(); + cert[filesize] = '\0'; + json["mqtt_ssl.crt"] = cert; + } + } + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.key"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.key not found"); + } + else + { + Log->println("Reading mqtt_ssl.key"); + size_t filesize = file.size(); + char key[filesize + 1]; + + file.read((uint8_t *)key, sizeof(key)); + file.close(); + key[filesize] = '\0'; + json["mqtt_ssl.key"] = key; + } + } +} + +void ImportExport::exportNukiHubJson(JsonDocument &json, bool redacted, bool pairing, bool nuki, bool nukiOpener) +{ + DebugPreferences debugPreferences; + + const std::vector keysPrefs = debugPreferences.getPreferencesKeys(); + const std::vector boolPrefs = debugPreferences.getPreferencesBoolKeys(); + const std::vector redactedPrefs = debugPreferences.getPreferencesRedactedKeys(); + const std::vector bytePrefs = debugPreferences.getPreferencesByteKeys(); + + for(const auto& key : keysPrefs) + { + if(strcmp(key, preference_show_secrets) == 0) + { + continue; + } + if(strcmp(key, preference_latest_version) == 0) + { + continue; + } + if(!redacted) if(std::find(redactedPrefs.begin(), redactedPrefs.end(), key) != redactedPrefs.end()) + { + continue; + } + if(!_preferences->isKey(key)) + { + json[key] = ""; + } + else if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end()) + { + json[key] = _preferences->getBool(key) ? "1" : "0"; + } + else + { + switch(_preferences->getType(key)) + { + case PT_I8: + json[key] = String(_preferences->getChar(key)); + break; + case PT_I16: + json[key] = String(_preferences->getShort(key)); + break; + case PT_I32: + json[key] = String(_preferences->getInt(key)); + break; + case PT_I64: + json[key] = String(_preferences->getLong64(key)); + break; + case PT_U8: + json[key] = String(_preferences->getUChar(key)); + break; + case PT_U16: + json[key] = String(_preferences->getUShort(key)); + break; + case PT_U32: + json[key] = String(_preferences->getUInt(key)); + break; + case PT_U64: + json[key] = String(_preferences->getULong64(key)); + break; + case PT_STR: + json[key] = _preferences->getString(key); + break; + default: + json[key] = _preferences->getString(key); + break; + } + } + } + + if(pairing) + { + if(nuki) + { + unsigned char currentBleAddress[6]; + unsigned char authorizationId[4] = {0x00}; + unsigned char secretKeyK[32] = {0x00}; + uint16_t storedPincode = 0000; + uint32_t storedUltraPincode = 000000; + bool isUltra = false; + Preferences nukiBlePref; + nukiBlePref.begin("NukiHub", false); + nukiBlePref.getBytes("bleAddress", currentBleAddress, 6); + nukiBlePref.getBytes("secretKeyK", secretKeyK, 32); + nukiBlePref.getBytes("authorizationId", authorizationId, 4); + nukiBlePref.getBytes("securityPinCode", &storedPincode, 2); + nukiBlePref.getBytes("ultraPinCode", &storedUltraPincode, 4); + isUltra = nukiBlePref.getBool("isUltra", false); + nukiBlePref.end(); + char text[255]; + text[0] = '\0'; + for(int i = 0 ; i < 6 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", currentBleAddress[i]); + } + json["bleAddressLock"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 32 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", secretKeyK[i]); + } + json["secretKeyKLock"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 4 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", authorizationId[i]); + } + json["authorizationIdLock"] = text; + memset(text, 0, sizeof(text)); + json["securityPinCodeLock"] = storedPincode; + json["ultraPinCodeLock"] = storedUltraPincode; + json["isUltra"] = isUltra ? "1" : "0"; + } + if(nukiOpener) + { + unsigned char currentBleAddressOpn[6]; + unsigned char authorizationIdOpn[4] = {0x00}; + unsigned char secretKeyKOpn[32] = {0x00}; + uint16_t storedPincodeOpn = 0000; + Preferences nukiBlePref; + nukiBlePref.begin("NukiHubopener", false); + nukiBlePref.getBytes("bleAddress", currentBleAddressOpn, 6); + nukiBlePref.getBytes("secretKeyK", secretKeyKOpn, 32); + nukiBlePref.getBytes("authorizationId", authorizationIdOpn, 4); + nukiBlePref.getBytes("securityPinCode", &storedPincodeOpn, 2); + nukiBlePref.end(); + char text[255]; + text[0] = '\0'; + for(int i = 0 ; i < 6 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", currentBleAddressOpn[i]); + } + json["bleAddressOpener"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 32 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", secretKeyKOpn[i]); + } + json["secretKeyKOpener"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 4 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", authorizationIdOpn[i]); + } + json["authorizationIdOpener"] = text; + memset(text, 0, sizeof(text)); + json["securityPinCodeOpener"] = storedPincodeOpn; + } + } + + for(const auto& key : bytePrefs) + { + size_t storedLength = _preferences->getBytesLength(key); + if(storedLength == 0) + { + continue; + } + uint8_t serialized[storedLength]; + memset(serialized, 0, sizeof(serialized)); + size_t size = _preferences->getBytes(key, serialized, sizeof(serialized)); + if(size == 0) + { + continue; + } + char text[255]; + text[0] = '\0'; + for(int i = 0 ; i < size ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", serialized[i]); + } + json[key] = text; + memset(text, 0, sizeof(text)); + } +} + +JsonDocument ImportExport::importJson(JsonDocument &doc) +{ + JsonDocument json; + unsigned char currentBleAddress[6]; + unsigned char authorizationId[4] = {0x00}; + unsigned char secretKeyK[32] = {0x00}; + unsigned char currentBleAddressOpn[6]; + unsigned char authorizationIdOpn[4] = {0x00}; + unsigned char secretKeyKOpn[32] = {0x00}; + + DebugPreferences debugPreferences; + + const std::vector keysPrefs = debugPreferences.getPreferencesKeys(); + const std::vector boolPrefs = debugPreferences.getPreferencesBoolKeys(); + const std::vector bytePrefs = debugPreferences.getPreferencesByteKeys(); + const std::vector intPrefs = debugPreferences.getPreferencesIntKeys(); + const std::vector uintPrefs = debugPreferences.getPreferencesUIntKeys(); + const std::vector uint64Prefs = debugPreferences.getPreferencesUInt64Keys(); + + for(const auto& key : keysPrefs) + { + if(doc[key].isNull()) + { + continue; + } + if(strcmp(key, preference_show_secrets) == 0) + { + continue; + } + if(strcmp(key, preference_latest_version) == 0) + { + continue; + } + if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end()) + { + if (doc[key].as().length() > 0) + { + _preferences->putBool(key, (doc[key].as() == "1" ? true : false)); + json[key] = "changed"; + } + else + { + json[key] = "removed"; + _preferences->remove(key); + } + continue; + } + if(std::find(intPrefs.begin(), intPrefs.end(), key) != intPrefs.end()) + { + if (doc[key].as().length() > 0) + { + json[key] = "changed"; + _preferences->putInt(key, doc[key].as()); + } + else + { + json[key] = "removed"; + _preferences->remove(key); + } + continue; + } + if(std::find(uintPrefs.begin(), uintPrefs.end(), key) != uintPrefs.end()) + { + if (doc[key].as().length() > 0) + { + json[key] = "changed"; + _preferences->putUInt(key, doc[key].as()); + } + else + { + json[key] = "removed"; + _preferences->remove(key); + } + continue; + } + if(std::find(uint64Prefs.begin(), uint64Prefs.end(), key) != uint64Prefs.end()) + { + if (doc[key].as().length() > 0) + { + json[key] = "changed"; + _preferences->putULong64(key, doc[key].as()); + } + else + { + json[key] = "removed"; + _preferences->remove(key); + } + continue; + } + if (doc[key].as().length() > 0) + { + json[key] = "changed"; + _preferences->putString(key, doc[key].as()); + } + else + { + json[key] = "removed"; + _preferences->remove(key); + } + } + + for(const auto& key : bytePrefs) + { + if(!doc[key].isNull() && doc[key].is()) + { + String value = doc[key].as(); + unsigned char tmpchar[32]; + for(int i=0; iputBytes(key, (byte*)(&tmpchar), (value.length() / 2)); + memset(tmpchar, 0, sizeof(tmpchar)); + } + } + + Preferences nukiBlePref; + nukiBlePref.begin("NukiHub", false); + + if(!doc["bleAddressLock"].isNull()) + { + if (doc["bleAddressLock"].as().length() == 12) + { + String value = doc["bleAddressLock"].as(); + for(int i=0; i().length() == 64) + { + String value = doc["secretKeyKLock"].as(); + for(int i=0; i().length() == 8) + { + String value = doc["authorizationIdLock"].as(); + for(int i=0; i().length() >0) + { + json["isUltra"] = "changed"; + nukiBlePref.putBool("isUltra", (doc["isUltra"].as() == "1" ? true : false)); + } + } + if(!doc["securityPinCodeLock"].isNull()) + { + if(doc["securityPinCodeLock"].as().length() > 0) + { + json["securityPinCodeLock"] = "changed"; + nukiBlePref.putBytes("securityPinCode", (byte*)(doc["securityPinCodeLock"].as()), 2); + //_nuki->setPin(doc["securityPinCodeLock"].as()); + } + else + { + json["securityPinCodeLock"] = "removed"; + unsigned char pincode[2] = {0x00}; + nukiBlePref.putBytes("securityPinCode", pincode, 2); + //_nuki->setPin(0xffff); + } + } + if(!doc["ultraPinCodeLock"].isNull()) + { + if(doc["ultraPinCodeLock"].as().length() > 0) + { + json["ultraPinCodeLock"] = "changed"; + nukiBlePref.putBytes("ultraPinCode", (byte*)(doc["ultraPinCodeLock"].as()), 4); + //_nuki->setUltraPin(doc["ultraPinCodeLock"].as()); + _preferences->putInt(preference_lock_gemini_pin, doc["ultraPinCodeLock"].as()); + } + else + { + json["ultraPinCodeLock"] = "removed"; + unsigned char ultraPincode[4] = {0x00}; + nukiBlePref.putBytes("ultraPinCode", ultraPincode, 4); + _preferences->putInt(preference_lock_gemini_pin, 0); + } + } + nukiBlePref.end(); + nukiBlePref.begin("NukiHubopener", false); + if(!doc["bleAddressOpener"].isNull()) + { + if (doc["bleAddressOpener"].as().length() == 12) + { + String value = doc["bleAddressOpener"].as(); + for(int i=0; i().length() == 64) + { + String value = doc["secretKeyKOpener"].as(); + for(int i=0; i().length() == 8) + { + String value = doc["authorizationIdOpener"].as(); + for(int i=0; i().length() > 0) + { + json["securityPinCodeOpener"] = "changed"; + nukiBlePref.putBytes("securityPinCode", (byte*)(doc["securityPinCodeOpener"].as()), 2); + //_nukiOpener->setPin(doc["securityPinCodeOpener"].as()); + } + else + { + json["securityPinCodeOpener"] = "removed"; + unsigned char pincode[2] = {0x00}; + nukiBlePref.putBytes("securityPinCode", pincode, 2); + //_nukiOpener->setPin(0xffff); + } + } + nukiBlePref.end(); + if(!doc["mqtt_ssl.ca"].isNull()) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + json["mqtt_ssl.ca"] = "error"; + } + else + { + if(doc["mqtt_ssl.ca"].as().length() > 0) + { + File file = SPIFFS.open("/mqtt_ssl.ca", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.ca for writing"); + json["mqtt_ssl.ca"] = "error"; + } + else + { + if (!file.print(doc["mqtt_ssl.ca"].as())) + { + Log->println("Failed to write /mqtt_ssl.ca"); + json["mqtt_ssl.crt"] = "error"; + } + else + { + json["mqtt_ssl.ca"] = "changed"; + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/mqtt_ssl.ca")) { + Log->println("Failed to delete /mqtt_ssl.ca"); + json["mqtt_ssl.crt"] = "error"; + } + else + { + json["mqtt_ssl.ca"] = "removed"; + } + } + } + } + if(!doc["mqtt_ssl.crt"].isNull()) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + json["mqtt_ssl.crt"] = "error"; + } + else + { + if(doc["mqtt_ssl.crt"].as().length() > 0) + { + File file = SPIFFS.open("/mqtt_ssl.crt", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.crt for writing"); + json["mqtt_ssl.crt"] = "error"; + } + else + { + if (!file.print(doc["mqtt_ssl.crt"].as())) + { + Log->println("Failed to write /mqtt_ssl.crt"); + json["mqtt_ssl.crt"] = "error"; + } + else + { + json["mqtt_ssl.crt"] = "changed"; + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/mqtt_ssl.crt")) { + Log->println("Failed to delete /mqtt_ssl.crt"); + json["mqtt_ssl.crt"] = "error"; + } + else + { + json["mqtt_ssl.crt"] = "removed"; + } + } + } + } + if(!doc["mqtt_ssl.key"].isNull()) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + json["mqtt_ssl.key"] = "error"; + } + else + { + if(doc["mqtt_ssl.key"].as().length() > 0) + { + File file = SPIFFS.open("/mqtt_ssl.key", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.key for writing"); + json["mqtt_ssl.key"] = "error"; + } + else + { + if (!file.print(doc["mqtt_ssl.key"].as())) + { + Log->println("Failed to write /mqtt_ssl.key"); + json["mqtt_ssl.key"] = "error"; + } + else + { + json["mqtt_ssl.key"] = "changed"; + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/mqtt_ssl.key")) { + Log->println("Failed to delete /mqtt_ssl.key"); + } + else + { + json["mqtt_ssl.key"] = "removed"; + } + } + } + } + if(!doc["http_ssl.crt"].isNull()) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + json["http_ssl.crt"] = "error"; + } + else + { + if(doc["http_ssl.crt"].as().length() > 0) + { + File file = SPIFFS.open("/http_ssl.crt", FILE_WRITE); + if (!file) { + Log->println("Failed to open /http_ssl.crt for writing"); + json["http_ssl.crt"] = "error"; + } + else + { + if (!file.print(doc["http_ssl.crt"].as())) + { + Log->println("Failed to write /http_ssl.crt"); + json["http_ssl.crt"] = "error"; + } + else + { + json["http_ssl.crt"] = "changed"; + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/http_ssl.crt")) { + Log->println("Failed to delete /http_ssl.crt"); + json["http_ssl.crt"] = "error"; + } + else + { + json["http_ssl.crt"] = "removed"; + } + } + } + } + if(!doc["http_ssl.key"].isNull()) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + json["http_ssl.key"] = "error"; + } + else + { + if(doc["http_ssl.key"].as().length() > 0) + { + File file = SPIFFS.open("/http_ssl.key", FILE_WRITE); + if (!file) { + Log->println("Failed to open /http_ssl.key for writing"); + json["http_ssl.key"] = "error"; + } + else + { + if (!file.print(doc["http_ssl.key"].as())) + { + Log->println("Failed to write /http_ssl.key"); + json["http_ssl.key"] = "error"; + } + else + { + json["http_ssl.key"] = "changed"; + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/http_ssl.key")) { + Log->println("Failed to delete /http_ssl.key"); + json["http_ssl.key"] = "error"; + } + else + { + json["http_ssl.key"] = "removed"; + } + } + } + } + + return json; +} \ No newline at end of file diff --git a/src/ImportExport.h b/src/ImportExport.h new file mode 100644 index 0000000..263983c --- /dev/null +++ b/src/ImportExport.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include "ArduinoJson.h" +#include + +class ImportExport +{ +public: + explicit ImportExport(Preferences* preferences); + void exportHttpsJson(JsonDocument &json); + void exportMqttsJson(JsonDocument &json); + void exportNukiHubJson(JsonDocument &json, bool redacted = false, bool pairing = false, bool nuki = false, bool nukiOpener = false); + JsonDocument importJson(JsonDocument &doc); + int checkDuoAuth(PsychicRequest *request); + int checkDuoApprove(); + bool startDuoAuth(char* pushType = (char*)""); + bool getDuoEnabled(); + bool getBypassGPIOEnabled(); + int getBypassGPIOHigh(); + int getBypassGPIOLow(); + void readSettings(); + void setDuoCheckIP(String duoCheckIP); + void setDuoCheckId(String duoCheckId); + JsonDocument _duoSessions; + JsonDocument _sessionsOpts; +private: + void saveSessions(); + Preferences* _preferences; + struct tm timeinfo; + bool _duoActiveRequest; + bool _duoEnabled = false; + bool _bypassGPIO = false; + int _bypassGPIOHigh = -1; + int _bypassGPIOLow = -1; + int64_t _duoRequestTS = 0; + String _duoTransactionId; + String _duoHost; + String _duoSkey; + String _duoIkey; + String _duoUser; + String _duoCheckId; + String _duoCheckIP; +}; + diff --git a/src/MqttTopics.h b/src/MqttTopics.h index 8b84d18..1866839 100644 --- a/src/MqttTopics.h +++ b/src/MqttTopics.h @@ -113,6 +113,11 @@ #define mqtt_topic_restart_reason_esp (char*)"/maintenance/restartReasonNukiEsp" #define mqtt_topic_mqtt_connection_state (char*)"/maintenance/mqttConnectionState" #define mqtt_topic_network_device (char*)"/maintenance/networkDevice" + +#define mqtt_topic_nuki_hub_config_action (char*)"/configuration/action" +#define mqtt_topic_nuki_hub_config_action_command_result (char*)"/configuration/commandResult" +#define mqtt_topic_nuki_hub_config_json (char*)"/configuration/json" + #define mqtt_topic_hybrid_state (char*)"/hybridConnected" #define mqtt_topic_gpio_prefix (char*)"/gpio" diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp index ec656a1..26bbe0f 100644 --- a/src/NukiNetwork.cpp +++ b/src/NukiNetwork.cpp @@ -14,6 +14,7 @@ NukiNetwork* NukiNetwork::_inst = nullptr; +extern bool timeSynced; extern bool wifiFallback; extern bool disableNetwork; extern bool forceEnableWebServer; @@ -21,11 +22,12 @@ extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_ extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end"); #ifndef NUKI_HUB_UPDATER -NukiNetwork::NukiNetwork(Preferences *preferences, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize) +NukiNetwork::NukiNetwork(Preferences *preferences, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize, ImportExport* importExport) : _preferences(preferences), _gpio(gpio), _buffer(buffer), - _bufferSize(bufferSize) + _bufferSize(bufferSize), + _importExport(importExport) #else NukiNetwork::NukiNetwork(Preferences *preferences) : _preferences(preferences) @@ -66,7 +68,7 @@ void NukiNetwork::setupDevice() { _ipConfiguration = new IPConfiguration(_preferences); int hardwareDetect = _preferences->getInt(preference_network_hardware, 0); - Log->print(("Hardware detect: ")); + Log->print("Hardware detect: "); Log->println(hardwareDetect); _firstBootAfterDeviceChange = _preferences->getBool(preference_ntw_reconfigure, false); @@ -94,13 +96,13 @@ void NukiNetwork::setupDevice() #ifndef CONFIG_IDF_TARGET_ESP32H2 if(!_firstBootAfterDeviceChange) { - Log->println(("Failed to connect to network. Wi-Fi fallback is disabled, rebooting.")); + Log->println("Failed to connect to network. Wi-Fi fallback is disabled, rebooting."); wifiFallback = false; sleep(5); restartEsp(RestartReason::NetworkDeviceCriticalFailureNoWifiFallback); } - Log->println(("Switching to Wi-Fi device as fallback.")); + Log->println("Switching to Wi-Fi device as fallback."); _networkDeviceType = NetworkDeviceType::WiFi; #else int custEth = _preferences->getInt(preference_network_custom_phy, 0); @@ -124,7 +126,7 @@ void NukiNetwork::setupDevice() _device = NetworkDeviceInstantiator::Create(_networkDeviceType, _hostname, _preferences, _ipConfiguration); - Log->print(("Network device: ")); + Log->print("Network device: "); Log->println(_device->deviceName()); #ifndef NUKI_HUB_UPDATER @@ -223,7 +225,7 @@ void NukiNetwork::initialize() strcpy(_hostnameArr, _hostname.c_str()); _device->initialize(); - Log->print(("Host name: ")); + Log->print("Host name: "); Log->println(_hostname); } @@ -273,7 +275,7 @@ void NukiNetwork::initialize() strcpy(_hostnameArr, _hostname.c_str()); _device->initialize(); - Log->print(("Host name: ")); + Log->print("Host name: "); Log->println(_hostname); String brokerAddr = _preferences->getString(preference_mqtt_broker); @@ -300,9 +302,9 @@ void NukiNetwork::initialize() } } - Log->print(("MQTT Broker: ")); + Log->print("MQTT Broker: "); Log->print(_mqttBrokerAddr); - Log->print((":")); + Log->print(":"); Log->println(_mqttPort); _device->mqttSetClientId(_hostnameArr); @@ -314,7 +316,7 @@ void NukiNetwork::initialize() if(rebGpio) { - Log->println(("Rebuild MQTT GPIO structure")); + Log->println("Rebuild MQTT GPIO structure"); } for (const auto &pinEntry: _gpio->pinConfiguration()) { @@ -412,7 +414,7 @@ bool NukiNetwork::update() if(_logIp && _device->isConnected() && !_device->localIP().equals("0.0.0.0")) { _logIp = false; - Log->print(("IP: ")); + Log->print("IP: "); Log->println(_device->localIP()); _firstDisconnected = true; } @@ -470,6 +472,12 @@ bool NukiNetwork::update() _lastRssi = rssi; } } + + if(_overwriteNukiHubConfigTS > 0 && espMillis() > _overwriteNukiHubConfigTS) + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_json, "--", true); + _overwriteNukiHubConfigTS = -1; + } if(_lastMaintenanceTs == 0 || (ts - _lastMaintenanceTs) > 30000) { @@ -575,9 +583,9 @@ bool NukiNetwork::update() buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pin)).c_str(), mqtt_topic_gpio_state}); publishInt(_lockPath.c_str(), gpioPath, pinState, _retainGpio); - Log->print(("GPIO ")); + Log->print("GPIO "); Log->print(pin); - Log->print((" (Input) --> ")); + Log->print(" (Input) --> "); Log->println(pinState); } } @@ -597,31 +605,31 @@ void NukiNetwork::onMqttDisconnect(const espMqttClientTypes::DisconnectReason &r switch(reason) { case espMqttClientTypes::DisconnectReason::USER_OK: - Log->println(("USER_OK")); + Log->println("USER_OK"); break; case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION: - Log->println(("MQTT_UNACCEPTABLE_PROTOCOL_VERSION")); + Log->println("MQTT_UNACCEPTABLE_PROTOCOL_VERSION"); break; case espMqttClientTypes::DisconnectReason::MQTT_IDENTIFIER_REJECTED: - Log->println(("MQTT_IDENTIFIER_REJECTED")); + Log->println("MQTT_IDENTIFIER_REJECTED"); break; case espMqttClientTypes::DisconnectReason::MQTT_SERVER_UNAVAILABLE: - Log->println(("MQTT_SERVER_UNAVAILABLE")); + Log->println("MQTT_SERVER_UNAVAILABLE"); break; case espMqttClientTypes::DisconnectReason::MQTT_MALFORMED_CREDENTIALS: - Log->println(("MQTT_MALFORMED_CREDENTIALS")); + Log->println("MQTT_MALFORMED_CREDENTIALS"); break; case espMqttClientTypes::DisconnectReason::MQTT_NOT_AUTHORIZED: - Log->println(("MQTT_NOT_AUTHORIZED")); + Log->println("MQTT_NOT_AUTHORIZED"); break; case espMqttClientTypes::DisconnectReason::TLS_BAD_FINGERPRINT: - Log->println(("TLS_BAD_FINGERPRINT")); + Log->println("TLS_BAD_FINGERPRINT"); break; case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED: - Log->println(("TCP_DISCONNECTED")); + Log->println("TCP_DISCONNECTED"); break; default: - Log->println(("Unknown")); + Log->println("Unknown"); break; } } @@ -634,7 +642,7 @@ bool NukiNetwork::reconnect() { if(strcmp(_mqttBrokerAddr, "") == 0) { - Log->println(("MQTT Broker not configured, aborting connection attempt.")); + Log->println("MQTT Broker not configured, aborting connection attempt."); _nextReconnect = espMillis() + 5000; if(_device->isConnected()) @@ -644,17 +652,17 @@ bool NukiNetwork::reconnect() return false; } - Log->println(("Attempting MQTT connection")); + Log->println("Attempting MQTT connection"); _connectReplyReceived = false; if(strlen(_mqttUser) == 0) { - Log->println(("MQTT: Connecting without credentials")); + Log->println("MQTT: Connecting without credentials"); } else { - Log->print(("MQTT: Connecting with user: ")); + Log->print("MQTT: Connecting with user: "); Log->println(_mqttUser); _device->mqttSetCredentials(_mqttUser, _mqttPass); } @@ -677,7 +685,7 @@ bool NukiNetwork::reconnect() if (_device->mqttConnected()) { - Log->println(("MQTT connected")); + Log->println("MQTT connected"); _mqttConnectedTs = millis(); _mqttConnectionState = 1; delay(100); @@ -766,6 +774,18 @@ bool NukiNetwork::reconnect() subscribe(_maintenancePathPrefix, mqtt_topic_update); } + if(_preferences->getBool(preference_publish_config, false)) + { + initTopic(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_json, "--"); + } + + if(_preferences->getBool(preference_config_from_mqtt, false) || _preferences->getBool(preference_publish_config, false)) + { + initTopic(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action, "--"); + subscribe(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action); + initTopic(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "--"); + } + initTopic(_maintenancePathPrefix, mqtt_topic_webserver_action, "--"); subscribe(_maintenancePathPrefix, mqtt_topic_webserver_action); initTopic(_maintenancePathPrefix, mqtt_topic_webserver_state, (_preferences->getBool(preference_webserver_enabled, true) || forceEnableWebServer ? "1" : "0")); @@ -792,7 +812,7 @@ bool NukiNetwork::reconnect() } else { - Log->print(("MQTT connect failed")); + Log->print("MQTT connect failed"); _mqttConnectionState = 0; _nextReconnect = espMillis() + 5000; //_device->mqttDisconnect(true); @@ -911,14 +931,14 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns if(comparePrefixedPath(topic, mqtt_topic_reset) && strcmp(data, "1") == 0 && !mqttRecentlyConnected()) { - Log->println(("Restart requested via MQTT.")); + Log->println("Restart requested via MQTT."); clearWifiFallback(); delay(200); restartEsp(RestartReason::RequestedViaMqtt); } else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(data, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false) && !mqttRecentlyConnected()) { - Log->println(("Update requested via MQTT.")); + Log->println("Update requested via MQTT."); bool otaManifestSuccess = false; JsonDocument doc; @@ -959,13 +979,13 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns { if(strcmp(NUKI_HUB_VERSION, doc["release"]["fullversion"].as()) == 0 && strcmp(NUKI_HUB_BUILD, doc["release"]["build"].as()) == 0 && strcmp(NUKI_HUB_DATE, doc["release"]["time"].as()) == 0) { - Log->println(("Nuki Hub is already on the latest release version, OTA update aborted.")); + Log->println("Nuki Hub is already on the latest release version, OTA update aborted."); } else { _preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL); _preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL); - Log->println(("Updating to latest release version.")); + Log->println("Updating to latest release version."); delay(200); restartEsp(RestartReason::OTAReboot); } @@ -974,13 +994,13 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns { if(strcmp(NUKI_HUB_VERSION, doc["beta"]["fullversion"].as()) == 0 && strcmp(NUKI_HUB_BUILD, doc["beta"]["build"].as()) == 0 && strcmp(NUKI_HUB_DATE, doc["beta"]["time"].as()) == 0) { - Log->println(("Nuki Hub is already on the latest beta version, OTA update aborted.")); + Log->println("Nuki Hub is already on the latest beta version, OTA update aborted."); } else { _preferences->putString(preference_ota_updater_url, GITHUB_BETA_UPDATER_BINARY_URL); _preferences->putString(preference_ota_main_url, GITHUB_BETA_RELEASE_BINARY_URL); - Log->println(("Updating to latest beta version.")); + Log->println("Updating to latest beta version."); delay(200); restartEsp(RestartReason::OTAReboot); } @@ -989,13 +1009,13 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns { if(strcmp(NUKI_HUB_VERSION, doc["master"]["fullversion"].as()) == 0 && strcmp(NUKI_HUB_BUILD, doc["master"]["build"].as()) == 0 && strcmp(NUKI_HUB_DATE, doc["master"]["time"].as()) == 0) { - Log->println(("Nuki Hub is already on the latest development version, OTA update aborted.")); + Log->println("Nuki Hub is already on the latest development version, OTA update aborted."); } else { _preferences->putString(preference_ota_updater_url, GITHUB_MASTER_UPDATER_BINARY_URL); _preferences->putString(preference_ota_main_url, GITHUB_MASTER_RELEASE_BINARY_URL); - Log->println(("Updating to latest developmemt version.")); + Log->println("Updating to latest developmemt version."); delay(200); restartEsp(RestartReason::OTAReboot); } @@ -1004,13 +1024,13 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns { if(strcmp(NUKI_HUB_VERSION, doc["release"]["fullversion"].as()) == 0 && strcmp(NUKI_HUB_BUILD, doc["release"]["build"].as()) == 0 && strcmp(NUKI_HUB_DATE, doc["release"]["time"].as()) == 0) { - Log->println(("Nuki Hub is already on the latest release version, OTA update aborted.")); + Log->println("Nuki Hub is already on the latest release version, OTA update aborted."); } else { _preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL); _preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL); - Log->println(("Updating to latest release version.")); + Log->println("Updating to latest release version."); delay(200); restartEsp(RestartReason::OTAReboot); } @@ -1018,7 +1038,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns } else { - Log->println(("Failed to retrieve OTA manifest, OTA update aborted.")); + Log->println("Failed to retrieve OTA manifest, OTA update aborted."); } } else if(comparePrefixedPath(topic, mqtt_topic_webserver_action) && !mqttRecentlyConnected()) @@ -1035,7 +1055,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns { return; } - Log->println(("Webserver enabled, restarting.")); + Log->println("Webserver enabled, restarting."); _preferences->putBool(preference_webserver_enabled, true); } else if (strcmp(data, "0") == 0) @@ -1044,20 +1064,184 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns { return; } - Log->println(("Webserver disabled, restarting.")); + Log->println("Webserver disabled, restarting."); _preferences->putBool(preference_webserver_enabled, false); } clearWifiFallback(); delay(200); restartEsp(RestartReason::ReconfigureWebServer); } + else if(comparePrefixedPath(topic, mqtt_topic_nuki_hub_config_action) && !mqttRecentlyConnected()) + { + if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) + { + return; + } + else + { + Log->println("JSON config update received"); + JsonDocument doc; + + DeserializationError error = deserializeJson(doc, data); + if (error) + { + Log->println("Invalid JSON for import/export"); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"jsonInvalid\"}", false); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action, "--", true); + } + else + { + if(_preferences->getBool(preference_cred_duo_approval, false)) + { + if (!timeSynced) + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"duoTimeNotSynced\"}", false); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action, "--", true); + return; + } + else if (_importExport->startDuoAuth((char*)"Approve Nuki Hub setting change")) + { + int duoResult = 2; + + while (duoResult == 2) + { + duoResult = _importExport->checkDuoApprove(); + delay(2000); + esp_task_wdt_reset(); + } + + if (duoResult != 1) + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"duoApprovalFailed\"}", false); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action, "--", true); + return; + } + } + } + + if(!doc["exportHTTPS"].isNull() && _device->isEncrypted()) + { + if(_preferences->getBool(preference_publish_config, false)) + { + if(_device->isEncrypted()) + { + JsonDocument json; + _importExport->exportHttpsJson(json); + serializeJson(json, _buffer, _bufferSize); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_json, _buffer, false); + + if (doc["exportHTTPS"].as() > 0) + { + _overwriteNukiHubConfigTS = espMillis() + (doc["exportHTTPS"].as() * 1000); + } + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEncrypted\"}", false); + } + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEnabled\"}", false); + } + } + else if(!doc["exportMQTTS"].isNull()) + { + if(_preferences->getBool(preference_publish_config, false)) + { + if(_device->isEncrypted()) + { + JsonDocument json; + _importExport->exportMqttsJson(json); + serializeJson(json, _buffer, _bufferSize); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_json, _buffer, false); + + if (doc["exportMQTTS"].as() > 0) + { + _overwriteNukiHubConfigTS = espMillis() + (doc["exportMQTTS"].as() * 1000); + } + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEncrypted\"}", false); + } + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEnabled\"}", false); + } + } + else if(!doc["exportNH"].isNull()) + { + if(_preferences->getBool(preference_publish_config, false)) + { + bool redacted = false; + if(!doc["redacted"].isNull()) + { + if(_device->isEncrypted()) + { + redacted = true; + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEncrypted\"}", false); + } + } + bool pairing = false; + if(!doc["pairing"].isNull()) + { + if(_device->isEncrypted()) + { + pairing = true; + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEncrypted\"}", false); + } + } + JsonDocument json; + _importExport->exportNukiHubJson(json, redacted, pairing, _preferences->getBool(preference_lock_enabled, true), _preferences->getBool(preference_opener_enabled, false)); + serializeJson(json, _buffer, _bufferSize); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_json, _buffer, false); + + if (doc["exportNH"].as() > 0) + { + _overwriteNukiHubConfigTS = espMillis() + (doc["exportNH"].as() * 1000); + } + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttExportNotEnabled\"}", false); + } + } + else + { + if(_preferences->getBool(preference_config_from_mqtt, false)) + { + JsonDocument json; + json = _importExport->importJson(doc); + serializeJson(json, _buffer, _bufferSize); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_json, _buffer, false); + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action, "--", true); + delay(200); + restartEsp(RestartReason::ConfigurationUpdated); + } + else + { + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action_command_result, "{\"error\": \"mqttImportNotEnabled\"}", false); + } + } + publishString(_maintenancePathPrefix, mqtt_topic_nuki_hub_config_action, "--", true); + } + } + } } void NukiNetwork::parseGpioTopics(const espMqttClientTypes::MessageProperties &properties, const char *topic, const uint8_t *payload, size_t& len, size_t& index, size_t& total) { char gpioPath[250]; buildMqttPath(gpioPath, {_lockPath.c_str(), mqtt_topic_gpio_prefix, mqtt_topic_gpio_pin}); -// /nuki_t/gpio/pin_17/state + size_t gpioLen = strlen(gpioPath); if(strncmp(gpioPath, topic, gpioLen) == 0) { @@ -1073,9 +1257,9 @@ void NukiNetwork::parseGpioTopics(const espMqttClientTypes::MessageProperties &p if(_gpio->getPinRole(pin) == PinRole::GeneralOutput) { const uint8_t pinState = strcmp((const char*)payload, "1") == 0 ? HIGH : LOW; - Log->print(("GPIO ")); + Log->print("GPIO "); Log->print(pin); - Log->print((" (Output) --> ")); + Log->print(" (Output) --> "); Log->println(pinState); digitalWrite(pin, pinState); } @@ -1177,7 +1361,7 @@ void NukiNetwork::removeTopic(const String& mqttPath, const String& mqttTopic) publish(path.c_str(), "", true); #ifdef DEBUG_NUKIHUB - Log->print(("Removing MQTT topic: ")); + Log->print("Removing MQTT topic: "); Log->println(path.c_str()); #endif } diff --git a/src/NukiNetwork.h b/src/NukiNetwork.h index 3f68481..860c279 100644 --- a/src/NukiNetwork.h +++ b/src/NukiNetwork.h @@ -16,6 +16,7 @@ #include #include "NukiConstants.h" #include "HomeAssistantDiscovery.h" +#include "ImportExport.h" #endif class NukiNetwork @@ -42,7 +43,7 @@ public: #ifdef NUKI_HUB_UPDATER explicit NukiNetwork(Preferences* preferences); #else - explicit NukiNetwork(Preferences* preferences, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize); + explicit NukiNetwork(Preferences* preferences, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize, ImportExport* importExport); void registerMqttReceiver(MqttReceiver* receiver); void disableAutoRestarts(); // disable on OTA start @@ -128,13 +129,14 @@ private: String _lockPath; HomeAssistantDiscovery* _hadiscovery = nullptr; - + ImportExport* _importExport; Gpio* _gpio; int _mqttConnectionState = 0; int _mqttConnectCounter = 0; int _mqttPort = 1883; long _mqttConnectedTs = -1; + long _overwriteNukiHubConfigTS = -1; bool _connectReplyReceived = false; bool _firstDisconnected = true; diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp index 4a79b01..b7189c4 100644 --- a/src/NukiNetworkLock.cpp +++ b/src/NukiNetworkLock.cpp @@ -237,7 +237,7 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const return; } - Log->print(("Lock action received: ")); + Log->print("Lock action received: "); Log->println(data); LockActionResult lockActionResult = LockActionResult::Failed; if(_lockActionReceivedCallback != NULL) diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp index 7031720..8574ebd 100644 --- a/src/NukiNetworkOpener.cpp +++ b/src/NukiNetworkOpener.cpp @@ -175,7 +175,7 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con return; } - Log->print(("Opener action received: ")); + Log->print("Opener action received: "); Log->println(data); LockActionResult lockActionResult = LockActionResult::Failed; if(_lockActionReceivedCallback != NULL) @@ -667,12 +667,12 @@ void NukiNetworkOpener::publishAuthorizationInfo(const std::listprintln(("Nuki opener: Ring detected (Locked)")); + Log->println("Nuki opener: Ring detected (Locked)"); publishRing(true); } else { - Log->println(("Nuki opener: Ring detected (Open)")); + Log->println("Nuki opener: Ring detected (Open)"); publishRing(false); } } diff --git a/src/NukiOfficial.cpp b/src/NukiOfficial.cpp index 7628dd7..c692972 100644 --- a/src/NukiOfficial.cpp +++ b/src/NukiOfficial.cpp @@ -86,14 +86,14 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value memset(&str, 0, sizeof(str)); Log->println("Official Nuki change received"); - Log->print(("Topic: ")); + Log->print("Topic: "); Log->println(topic); - Log->print(("Value: ")); + Log->print("Value: "); Log->println(value); if(strcmp(topic, mqtt_topic_official_connected) == 0) { - Log->print(("Connected: ")); + Log->print("Connected: "); Log->println((strcmp(value, "true") == 0 ? 1 : 0)); offConnected = (strcmp(value, "true") == 0 ? 1 : 0); _publisher->publishBool(mqtt_topic_hybrid_state, offConnected, true); @@ -102,12 +102,12 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value { offState = atoi(value); _statusUpdated = true; - Log->println(("Lock: Updating status on Hybrid state change")); + Log->println("Lock: Updating status on Hybrid state change"); _publisher->publishBool(mqtt_topic_hybrid_state, offConnected, true); NukiLock::lockstateToString((NukiLock::LockState)offState, str); _publisher->publishString(mqtt_topic_lock_state, str, true); - Log->print(("Lockstate: ")); + Log->print("Lockstate: "); Log->println(str); _offStateToPublish = (NukiLock::LockState)offState; @@ -117,11 +117,11 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value { offDoorsensorState = atoi(value); _statusUpdated = true; - Log->println(("Lock: Updating status on Hybrid door sensor state change")); + Log->println("Lock: Updating status on Hybrid door sensor state change"); _publisher->publishBool(mqtt_topic_lock_status_updated, _statusUpdated, true); NukiLock::doorSensorStateToString((NukiLock::DoorSensorState)offDoorsensorState, str); - Log->print(("Doorsensor state: ")); + Log->print("Doorsensor state: "); Log->println(str); _publisher->publishString(mqtt_topic_lock_door_sensor_state, str, true); @@ -130,7 +130,7 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value { offCritical = (strcmp(value, "true") == 0 ? 1 : 0); - Log->print(("Battery critical: ")); + Log->print("Battery critical: "); Log->println(offCritical); if(!_disableNonJSON) @@ -143,7 +143,7 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value { offCharging = (strcmp(value, "true") == 0 ? 1 : 0); - Log->print(("Battery charging: ")); + Log->print("Battery charging: "); Log->println(offCharging); if(!_disableNonJSON) @@ -156,7 +156,7 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value { offChargeState = atoi(value); - Log->print(("Battery level: ")); + Log->print("Battery level: "); Log->println(offChargeState); if(!_disableNonJSON) diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index 0538b5b..a75ce08 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -12,14 +12,16 @@ NukiOpenerWrapper* nukiOpenerInst; Preferences* nukiOpenerPreferences = nullptr; -NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkOpener* network, Gpio* gpio, Preferences* preferences) +NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkOpener* network, Gpio* gpio, Preferences* preferences, char* buffer, size_t bufferSize) : _deviceName(deviceName), _deviceId(deviceId), _nukiOpener(deviceName, _deviceId->get()), _bleScanner(scanner), _network(network), _gpio(gpio), - _preferences(preferences) + _preferences(preferences), + _buffer(buffer), + _bufferSize(bufferSize) { Log->print("Device id opener: "); Log->println(_deviceId->get()); @@ -81,7 +83,7 @@ void NukiOpenerWrapper::readSettings() #else if(pwrLvl >= 20) { - powerLevel = ESP_PWR_LVL_P20; + powerLevel = ESP_PWR_LVL_P20; } else if(pwrLvl >= 18) { @@ -197,11 +199,11 @@ void NukiOpenerWrapper::readSettings() _preferences->putInt(preference_restart_ble_beacon_lost, _restartBeaconTimeout); } - Log->print(("Opener state interval: ")); + Log->print("Opener state interval: "); Log->print(_intervalLockstate); - Log->print((" | Battery interval: ")); + Log->print(" | Battery interval: "); Log->print(_intervalBattery); - Log->print((" | Publish auth data: ")); + Log->print(" | Publish auth data: "); Log->println(_publishAuthData ? "yes" : "no"); if(!_publishAuthData) @@ -218,7 +220,7 @@ void NukiOpenerWrapper::update() wdt_hal_write_protect_enable(&rtc_wdt_ctx); if(!_paired) { - Log->println(("Nuki opener start pairing")); + Log->println("Nuki opener start pairing"); _network->publishBleAddress(""); Nuki::AuthorizationIdType idType = _preferences->getBool(preference_register_opener_as_app) ? @@ -227,7 +229,7 @@ void NukiOpenerWrapper::update() if(_nukiOpener.pairNuki(idType) == NukiOpener::PairingResult::Success) { - Log->println(("Nuki opener paired")); + Log->println("Nuki opener paired"); _paired = true; _network->publishBleAddress(_nukiOpener.getBleAddress().toString()); } @@ -270,14 +272,14 @@ void NukiOpenerWrapper::update() _network->publishCommandResult(resultStr); - Log->print(("Opener action result: ")); + Log->print("Opener action result: "); Log->println(resultStr); if(cmdResult != Nuki::CmdResult::Success) { - Log->print(("Opener: Last command failed, retrying after ")); + Log->print("Opener: Last command failed, retrying after "); Log->print(_retryDelay); - Log->print((" milliseconds. Retry ")); + Log->print(" milliseconds. Retry "); Log->print(retryCount + 1); Log->print(" of "); Log->println(_nrOfRetries); @@ -297,7 +299,7 @@ void NukiOpenerWrapper::update() _network->publishRetry("--"); retryCount = 0; _statusUpdated = true; - Log->println(("Opener: updating status after action")); + Log->println("Opener: updating status after action"); _statusUpdatedTs = ts; if(_intervalLockstate > 10) { @@ -306,7 +308,7 @@ void NukiOpenerWrapper::update() } else { - Log->println(("Opener: Maximum number of retries exceeded, aborting.")); + Log->println("Opener: Maximum number of retries exceeded, aborting."); _network->publishRetry("failed"); retryCount = 0; _nextLockAction = (NukiOpener::LockAction) 0xff; @@ -432,11 +434,6 @@ void NukiOpenerWrapper::deactivateCM() _nextLockAction = NukiOpener::LockAction::DeactivateCM; } -bool NukiOpenerWrapper::isPinSet() -{ - return _nukiOpener.getSecurityPincode() != 0; -} - bool NukiOpenerWrapper::isPinValid() { return _preferences->getInt(preference_opener_pin_status, 4) == 1; @@ -475,7 +472,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState() while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1) { - Log->print(("Result (attempt ")); + Log->print("Result (attempt "); Log->print(retryCount + 1); Log->print("): "); result =_nukiOpener.requestOpenerState(&_keyTurnerState); @@ -494,7 +491,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState() postponeBleWatchdog(); if(_retryLockstateCount < _nrOfRetries + 1) { - Log->print(("Query opener state retrying in ")); + Log->print("Query opener state retrying in "); Log->print(_retryDelay); Log->println("ms"); _nextLockStateUpdateTs = espMillis() + _retryDelay; @@ -517,7 +514,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState() _lastKeyTurnerState.lockState == NukiOpener::LockState::Locked && _lastKeyTurnerState.nukiState == _keyTurnerState.nukiState) { - Log->println(("Nuki opener: Ring detected (Locked)")); + Log->println("Nuki opener: Ring detected (Locked)"); _network->publishRing(true); } else @@ -527,17 +524,17 @@ bool NukiOpenerWrapper::updateKeyTurnerState() _keyTurnerState.lockState == NukiOpener::LockState::Open && _keyTurnerState.trigger == NukiOpener::Trigger::Manual) { - Log->println(("Nuki opener: Ring detected (Open)")); + Log->println("Nuki opener: Ring detected (Open)"); _network->publishRing(false); } if(_publishAuthData) { - Log->println(("Publishing auth data")); + Log->println("Publishing auth data"); updateAuthData(false); - Log->println(("Done publishing auth data")); + Log->println("Done publishing auth data"); } - + if(_keyTurnerState.lockState == NukiOpener::LockState::Undefined) { if (_nextLockStateUpdateTs > espMillis() + 60000) @@ -552,12 +549,12 @@ bool NukiOpenerWrapper::updateKeyTurnerState() if((_keyTurnerState.lockState == NukiOpener::LockState::Open || _keyTurnerState.lockState == NukiOpener::LockState::Opening) && espMillis() < _statusUpdatedTs + 10000) { updateStatus = true; - Log->println(("Opener: Keep updating status on intermediate lock state")); + Log->println("Opener: Keep updating status on intermediate lock state"); } if(_keyTurnerState.nukiState == NukiOpener::State::ContinuousMode) { - Log->println(("Continuous Mode")); + Log->println("Continuous Mode"); } char lockStateStr[20]; @@ -566,7 +563,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState() } postponeBleWatchdog(); - Log->println(("Done querying opener state")); + Log->println("Done querying opener state"); return updateStatus; } @@ -577,7 +574,7 @@ void NukiOpenerWrapper::updateBatteryState() while(retryCount < _nrOfRetries + 1) { - Log->print(("Querying opener battery state: ")); + Log->print("Querying opener battery state: "); result = _nukiOpener.requestBatteryReport(&_batteryReport); delay(250); if(result != Nuki::CmdResult::Success) @@ -596,7 +593,7 @@ void NukiOpenerWrapper::updateBatteryState() _network->publishBatteryReport(_batteryReport); } postponeBleWatchdog(); - Log->println(("Done querying opener battery state")); + Log->println("Done querying opener battery state"); } void NukiOpenerWrapper::updateConfig() @@ -611,7 +608,7 @@ void NukiOpenerWrapper::updateConfig() { char uidString[20]; itoa(_nukiConfig.nukiId, uidString, 16); - Log->print(("Saving Opener Nuki ID to preferences (")); + Log->print("Saving Opener Nuki ID to preferences ("); Log->print(_nukiConfig.nukiId); Log->print(" / "); Log->print(uidString); @@ -640,61 +637,49 @@ void NukiOpenerWrapper::updateConfig() const int pinStatus = _preferences->getInt(preference_opener_pin_status, 4); - if(isPinSet()) + Nuki::CmdResult result = (Nuki::CmdResult)-1; + int retryCount = 0; + + while(retryCount < _nrOfRetries + 1) { - Nuki::CmdResult result = (Nuki::CmdResult)-1; - int retryCount = 0; - Log->println(("Nuki opener PIN is set")); - - while(retryCount < _nrOfRetries + 1) - { - result = _nukiOpener.verifySecurityPin(); - - if(result != Nuki::CmdResult::Success) - { - ++retryCount; - } - else - { - break; - } - } + result = _nukiOpener.verifySecurityPin(); if(result != Nuki::CmdResult::Success) { - Log->println(("Nuki opener PIN is invalid")); - if(pinStatus != 2) - { - _preferences->putInt(preference_opener_pin_status, 2); - } + ++retryCount; } else { - Log->println(("Nuki opener PIN is valid")); - if(pinStatus != 1) - { - _preferences->putInt(preference_opener_pin_status, 1); - } + break; + } + } + + if(result != Nuki::CmdResult::Success) + { + Log->println("Nuki opener PIN is invalid or not set"); + if(pinStatus != 2) + { + _preferences->putInt(preference_opener_pin_status, 2); } } else { - Log->println(("Nuki opener PIN is not set")); - if(pinStatus != 0) + Log->println("Nuki opener PIN is valid"); + if(pinStatus != 1) { - _preferences->putInt(preference_opener_pin_status, 0); + _preferences->putInt(preference_opener_pin_status, 1); } } } else { - Log->println(("Invalid/Unexpected opener config received, ID does not matched saved ID")); + Log->println("Invalid/Unexpected opener config received, ID does not matched saved ID"); expectedConfig = false; } } else { - Log->println(("Invalid/Unexpected opener config received, Config is not valid")); + Log->println("Invalid/Unexpected opener config received, Config is not valid"); expectedConfig = false; } @@ -711,7 +696,7 @@ void NukiOpenerWrapper::updateConfig() } else { - Log->println(("Invalid/Unexpected opener advanced config received, Advanced config is not valid")); + Log->println("Invalid/Unexpected opener advanced config received, Advanced config is not valid"); expectedConfig = false; } } @@ -719,12 +704,12 @@ void NukiOpenerWrapper::updateConfig() if(expectedConfig && _nukiConfigValid && _nukiAdvancedConfigValid) { _retryConfigCount = 0; - Log->println(("Done retrieving opener config and advanced config")); + Log->println("Done retrieving opener config and advanced config"); } else { ++_retryConfigCount; - Log->println(("Invalid/Unexpected opener config and/or advanced config received, retrying in 10 seconds")); + Log->println("Invalid/Unexpected opener config and/or advanced config received, retrying in 10 seconds"); int64_t ts = espMillis(); _nextConfigUpdateTs = ts + 10000; } @@ -734,7 +719,7 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved) { if(!isPinValid()) { - Log->println(("No valid PIN set")); + Log->println("No valid PIN set"); return; } @@ -820,7 +805,7 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved) if(!isPinValid()) { - Log->println(("No valid Nuki Opener PIN set")); + Log->println("No valid Nuki Opener PIN set"); return; } @@ -900,7 +885,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved) if(!isPinValid()) { - Log->println(("No valid Nuki Opener PIN set")); + Log->println("No valid Nuki Opener PIN set"); return; } @@ -972,7 +957,7 @@ void NukiOpenerWrapper::updateAuth(bool retrieved) { if(!isPinValid()) { - Log->println(("No valid Nuki Lock PIN set")); + Log->println("No valid Nuki Lock PIN set"); return; } @@ -1558,23 +1543,21 @@ Nuki::BatteryType NukiOpenerWrapper::batteryTypeToEnum(const char* str) void NukiOpenerWrapper::onConfigUpdateReceived(const char *value) { - JsonDocument jsonResult; - char _resbuf[2048]; if(!_nukiConfigValid) { jsonResult["general"] = "configNotReady"; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } if(!isPinValid()) { jsonResult["general"] = "noValidPinSet"; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } @@ -1584,8 +1567,8 @@ void NukiOpenerWrapper::onConfigUpdateReceived(const char *value) if(jsonError) { jsonResult["general"] = "invalidJson"; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } @@ -2437,8 +2420,8 @@ void NukiOpenerWrapper::onConfigUpdateReceived(const char *value) _nextConfigUpdateTs = espMillis() + 300; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } @@ -4198,7 +4181,7 @@ void NukiOpenerWrapper::updateTime() { if(!isPinValid()) { - Log->println(("No valid PIN set")); + Log->println("No valid PIN set"); return; } @@ -4209,7 +4192,7 @@ void NukiOpenerWrapper::updateTime() if (int(tm.tm_year + 1900) < int(2025)) { - Log->println(("NTP Time not valid, not updating Nuki device")); + Log->println("NTP Time not valid, not updating Nuki device"); return; } diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h index 8c7a4fb..f3caec9 100644 --- a/src/NukiOpenerWrapper.h +++ b/src/NukiOpenerWrapper.h @@ -11,7 +11,7 @@ class NukiOpenerWrapper : public NukiOpener::SmartlockEventHandler { public: - NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkOpener* network, Gpio* gpio, Preferences* preferences); + NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkOpener* network, Gpio* gpio, Preferences* preferences, char* buffer, size_t bufferSize); virtual ~NukiOpenerWrapper(); void initialize(); @@ -25,7 +25,6 @@ public: void deactivateRTO(); void deactivateCM(); - bool isPinSet(); bool isPinValid(); void setPin(const uint16_t pin); uint16_t getPin(); @@ -159,4 +158,7 @@ private: std::string _firmwareVersion = ""; std::string _hardwareVersion = ""; NukiOpener::LockAction _nextLockAction = (NukiOpener::LockAction)0xff; + + char* _buffer; + const size_t _bufferSize; }; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index b056e86..a5e4e28 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -11,7 +11,7 @@ NukiWrapper* nukiInst = nullptr; -NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, NukiOfficial* nukiOfficial, Gpio* gpio, Preferences* preferences) +NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, NukiOfficial* nukiOfficial, Gpio* gpio, Preferences* preferences, char* buffer, size_t bufferSize) : _deviceName(deviceName), _deviceId(deviceId), _bleScanner(scanner), @@ -19,7 +19,9 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, _network(network), _nukiOfficial(nukiOfficial), _gpio(gpio), - _preferences(preferences) + _preferences(preferences), + _buffer(buffer), + _bufferSize(bufferSize) { Log->print("Device id lock: "); @@ -233,8 +235,8 @@ void NukiWrapper::update(bool reboot) wdt_hal_write_protect_enable(&rtc_wdt_ctx); if(!_paired) { - Log->println(("Nuki lock start pairing")); - _preferences->getBool(preference_register_as_app) ? Log->println(("Pairing as app")) : Log->println(("Pairing as bridge")); + Log->println("Nuki lock start pairing"); + _preferences->getBool(preference_register_as_app) ? Log->println("Pairing as app") : Log->println("Pairing as bridge"); _network->publishBleAddress(""); Nuki::AuthorizationIdType idType = _preferences->getBool(preference_register_as_app) ? @@ -243,7 +245,7 @@ void NukiWrapper::update(bool reboot) if(_nukiLock.pairNuki(idType) == Nuki::PairingResult::Success) { - Log->println(("Nuki paired")); + Log->println("Nuki paired"); _paired = true; _network->publishBleAddress(_nukiLock.getBleAddress().toString()); } @@ -295,9 +297,9 @@ void NukiWrapper::update(bool reboot) if(cmdResult != Nuki::CmdResult::Success) { - Log->print(("Lock: Last command failed, retrying after ")); + Log->print("Lock: Last command failed, retrying after "); Log->print(_retryDelay); - Log->print((" milliseconds. Retry ")); + Log->print(" milliseconds. Retry "); Log->print(retryCount + 1); Log->print(" of "); Log->println(_nrOfRetries); @@ -320,7 +322,7 @@ void NukiWrapper::update(bool reboot) { _statusUpdated = true; } - Log->println(("Lock: updating status after action")); + Log->println("Lock: updating status after action"); _statusUpdatedTs = ts; if(_intervalLockstate > 10) { @@ -329,7 +331,7 @@ void NukiWrapper::update(bool reboot) } else { - Log->println(("Lock: Maximum number of retries exceeded, aborting.")); + Log->println("Lock: Maximum number of retries exceeded, aborting."); _network->publishRetry("failed"); retryCount = 0; _nextLockAction = (NukiLock::LockAction) 0xff; @@ -450,18 +452,6 @@ void NukiWrapper::lockngounlatch() _nextLockAction = NukiLock::LockAction::LockNgoUnlatch; } -bool NukiWrapper::isPinSet() -{ - if (_isUltra) - { - return _nukiLock.getUltraPincode() != 0; - } - else - { - return _nukiLock.getSecurityPincode() != 0; - } -} - bool NukiWrapper::isPinValid() { return _preferences->getInt(preference_lock_pin_status, 4) == 1; @@ -508,11 +498,11 @@ bool NukiWrapper::updateKeyTurnerState() Nuki::CmdResult result = (Nuki::CmdResult)-1; int retryCount = 0; - Log->println(("Querying lock state")); + Log->println("Querying lock state"); while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1) { - Log->print(("Result (attempt ")); + Log->print("Result (attempt "); Log->print(retryCount + 1); Log->print(("): ")); result =_nukiLock.requestKeyTurnerState(&_keyTurnerState); @@ -531,7 +521,7 @@ bool NukiWrapper::updateKeyTurnerState() postponeBleWatchdog(); if(_retryLockstateCount < _nrOfRetries + 1) { - Log->print(("Query lock state retrying in ")); + Log->print("Query lock state retrying in "); Log->print(_retryDelay); Log->println("ms"); _nextLockStateUpdateTs = espMillis() + _retryDelay; @@ -557,9 +547,9 @@ bool NukiWrapper::updateKeyTurnerState() { if(_publishAuthData && (lockState == NukiLock::LockState::Locked || lockState == NukiLock::LockState::Unlocked)) { - Log->println(("Publishing auth data")); + Log->println("Publishing auth data"); updateAuthData(false); - Log->println(("Done publishing auth data")); + Log->println("Done publishing auth data"); } updateGpioOutputs(); @@ -567,7 +557,7 @@ bool NukiWrapper::updateKeyTurnerState() else if(!_nukiOfficial->getOffConnected() && espMillis() < _statusUpdatedTs + 10000) { updateStatus = true; - Log->println(("Lock: Keep updating status on intermediate lock state")); + Log->println("Lock: Keep updating status on intermediate lock state"); } else if(lockState == NukiLock::LockState::Undefined) { @@ -583,7 +573,7 @@ bool NukiWrapper::updateKeyTurnerState() Log->println(lockStateStr); postponeBleWatchdog(); - Log->println(("Done querying lock state")); + Log->println("Done querying lock state"); return updateStatus; } @@ -617,7 +607,7 @@ void NukiWrapper::updateBatteryState() _network->publishBatteryReport(_batteryReport); } postponeBleWatchdog(); - Log->println(("Done querying lock battery state")); + Log->println("Done querying lock battery state"); } void NukiWrapper::updateConfig() @@ -632,7 +622,7 @@ void NukiWrapper::updateConfig() { char uidString[20]; itoa(_nukiConfig.nukiId, uidString, 16); - Log->print(("Saving Lock Nuki ID to preferences (")); + Log->print("Saving Lock Nuki ID to preferences ("); Log->print(_nukiConfig.nukiId); Log->print(" / "); Log->print(uidString); @@ -660,60 +650,48 @@ void NukiWrapper::updateConfig() const int pinStatus = _preferences->getInt(preference_lock_pin_status, 4); - if(isPinSet()) + Nuki::CmdResult result = (Nuki::CmdResult)-1; + int retryCount = 0; + + while(retryCount < _nrOfRetries + 1) { - Nuki::CmdResult result = (Nuki::CmdResult)-1; - int retryCount = 0; - Log->println(("Nuki Lock PIN is set")); - - while(retryCount < _nrOfRetries + 1) - { - result = _nukiLock.verifySecurityPin(); - if(result != Nuki::CmdResult::Success) - { - ++retryCount; - } - else - { - break; - } - } - + result = _nukiLock.verifySecurityPin(); if(result != Nuki::CmdResult::Success) { - Log->println(("Nuki Lock PIN is invalid")); - if(pinStatus != 2) - { - _preferences->putInt(preference_lock_pin_status, 2); - } + ++retryCount; } else { - Log->println(("Nuki Lock PIN is valid")); - if(pinStatus != 1) - { - _preferences->putInt(preference_lock_pin_status, 1); - } + break; + } + } + + if(result != Nuki::CmdResult::Success) + { + Log->println("Nuki Lock PIN is invalid or not set"); + if(pinStatus != 2) + { + _preferences->putInt(preference_lock_pin_status, 2); } } else { - Log->println(("Nuki Lock PIN is not set")); - if(pinStatus != 0) + Log->println("Nuki Lock PIN is valid"); + if(pinStatus != 1) { - _preferences->putInt(preference_lock_pin_status, 0); + _preferences->putInt(preference_lock_pin_status, 1); } } } else { - Log->println(("Invalid/Unexpected lock config received, ID does not matched saved ID")); + Log->println("Invalid/Unexpected lock config received, ID does not matched saved ID"); expectedConfig = false; } } else { - Log->println(("Invalid/Unexpected lock config received, Config is not valid")); + Log->println("Invalid/Unexpected lock config received, Config is not valid"); expectedConfig = false; } @@ -730,7 +708,7 @@ void NukiWrapper::updateConfig() } else { - Log->println(("Invalid/Unexpected lock advanced config received, Advanced config is not valid")); + Log->println("Invalid/Unexpected lock advanced config received, Advanced config is not valid"); expectedConfig = false; } } @@ -738,12 +716,12 @@ void NukiWrapper::updateConfig() if(expectedConfig && _nukiConfigValid && _nukiAdvancedConfigValid) { _retryConfigCount = 0; - Log->println(("Done retrieving lock config and advanced config")); + Log->println("Done retrieving lock config and advanced config"); } else { ++_retryConfigCount; - Log->println(("Invalid/Unexpected lock config and/or advanced config received, retrying in 10 seconds")); + Log->println("Invalid/Unexpected lock config and/or advanced config received, retrying in 10 seconds"); int64_t ts = espMillis(); _nextConfigUpdateTs = ts + 10000; } @@ -753,7 +731,7 @@ void NukiWrapper::updateAuthData(bool retrieved) { if(!isPinValid()) { - Log->println(("No valid Nuki Lock PIN set")); + Log->println("No valid Nuki Lock PIN set"); return; } @@ -837,7 +815,7 @@ void NukiWrapper::updateKeypad(bool retrieved) if(!isPinValid()) { - Log->println(("No valid Nuki Lock PIN set")); + Log->println("No valid Nuki Lock PIN set"); return; } @@ -916,7 +894,7 @@ void NukiWrapper::updateTimeControl(bool retrieved) if(!isPinValid()) { - Log->println(("No valid Nuki Lock PIN set")); + Log->println("No valid Nuki Lock PIN set"); return; } @@ -987,7 +965,7 @@ void NukiWrapper::updateAuth(bool retrieved) { if(!isPinValid()) { - Log->println(("No valid Nuki Lock PIN set")); + Log->println("No valid Nuki Lock PIN set"); return; } @@ -1495,21 +1473,20 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value) void NukiWrapper::onConfigUpdateReceived(const char *value) { JsonDocument jsonResult; - char _resbuf[2048]; if(!_nukiConfigValid) { jsonResult["general"] = "configNotReady"; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } if(!isPinValid()) { jsonResult["general"] = "noValidPinSet"; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } @@ -1519,15 +1496,11 @@ void NukiWrapper::onConfigUpdateReceived(const char *value) if(jsonError) { jsonResult["general"] = "invalidJson"; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } - Log->println(value); - serializeJson(json, _resbuf, sizeof(_resbuf)); - Log->println(_resbuf); - Nuki::CmdResult cmdResult; const char *basicKeys[16] = {"name", "latitude", "longitude", "autoUnlatch", "pairingEnabled", "buttonEnabled", "ledEnabled", "ledBrightness", "timeZoneOffset", "dstMode", "fobAction1", "fobAction2", "fobAction3", "singleLock", "advertisingMode", "timeZone"}; const char *advancedKeys[25] = {"unlockedPositionOffsetDegrees", "lockedPositionOffsetDegrees", "singleLockedPositionOffsetDegrees", "unlockedToLockedTransitionOffsetDegrees", "lockNgoTimeout", "singleButtonPressAction", "doubleButtonPressAction", "detachedCylinder", "batteryType", "automaticBatteryTypeDetection", "unlatchDuration", "autoLockTimeOut", "autoUnLockDisabled", "nightModeEnabled", "nightModeStartTime", "nightModeEndTime", "nightModeAutoLockEnabled", "nightModeAutoUnlockDisabled", "nightModeImmediateLockOnStart", "autoLockEnabled", "immediateAutoLockEnabled", "autoUpdateEnabled", "rebootNuki", "motorSpeed", "enableSlowSpeedDuringNightMode"}; @@ -2500,8 +2473,8 @@ void NukiWrapper::onConfigUpdateReceived(const char *value) _nextConfigUpdateTs = espMillis() + 300; - serializeJson(jsonResult, _resbuf, sizeof(_resbuf)); - _network->publishConfigCommandResult(_resbuf); + serializeJson(jsonResult, _buffer, _bufferSize); + _network->publishConfigCommandResult(_buffer); return; } @@ -4325,7 +4298,7 @@ void NukiWrapper::updateTime() { if(!isPinValid()) { - Log->println(("No valid PIN set")); + Log->println("No valid PIN set"); return; } @@ -4336,7 +4309,7 @@ void NukiWrapper::updateTime() if (int(tm.tm_year + 1900) < int(2025)) { - Log->println(("NTP Time not valid, not updating Nuki device")); + Log->println("NTP Time not valid, not updating Nuki device"); return; } diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h index 7dbe709..76ddbd8 100644 --- a/src/NukiWrapper.h +++ b/src/NukiWrapper.h @@ -14,7 +14,7 @@ class NukiWrapper : public Nuki::SmartlockEventHandler { public: - NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, NukiOfficial* nukiOfficial, Gpio* gpio, Preferences* preferences); + NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, NukiOfficial* nukiOfficial, Gpio* gpio, Preferences* preferences, char* buffer, size_t bufferSize); virtual ~NukiWrapper(); void initialize(); @@ -27,7 +27,6 @@ public: void lockngo(); void lockngounlatch(); - bool isPinSet(); bool isPinValid(); void setPin(const uint16_t pin); void setUltraPin(const uint32_t pin); @@ -168,4 +167,7 @@ private: std::string _firmwareVersion = ""; std::string _hardwareVersion = ""; volatile NukiLock::LockAction _nextLockAction = (NukiLock::LockAction)0xff; + + char* _buffer; + const size_t _bufferSize; }; diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index 1aea27a..5b02550 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -91,6 +91,8 @@ #define preference_cred_bypass_boot_btn_enabled (char*)"bypassBtBtn" #define preference_cred_bypass_gpio_high (char*)"bypassHigh" #define preference_cred_bypass_gpio_low (char*)"bypassLow" +#define preference_publish_config (char*)"nhPubConfig" +#define preference_config_from_mqtt (char*)"nhCntrlEnabled" // CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT #define preference_find_best_rssi (char*)"nwbestrssi" @@ -241,6 +243,8 @@ inline void initPreferences(Preferences* preferences) preferences->putBool(preference_cred_duo_enabled, false); preferences->putBool(preference_cred_duo_approval, false); preferences->putBool(preference_cred_bypass_boot_btn_enabled, false); + preferences->putBool(preference_publish_config, false); + preferences->putBool(preference_config_from_mqtt, false); preferences->putInt(preference_mqtt_broker_port, 1883); preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE); @@ -504,8 +508,8 @@ private: preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates, preference_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status, preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_update_time, preference_time_server, - preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt, - preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address, + preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, + preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type, preference_lock_gemini_pin, preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, preference_hybrid_reboot_on_disconnect, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, @@ -525,7 +529,8 @@ private: preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_nukihub_id, preference_cred_duo_host, preference_cred_duo_ikey, preference_cred_duo_skey, preference_cred_duo_user, preference_cred_duo_enabled, preference_https_fqdn, preference_bypass_proxy, preference_cred_session_lifetime, preference_cred_session_lifetime_remember, preference_cred_session_lifetime_duo, preference_cred_session_lifetime_duo_remember, - preference_cred_duo_approval, preference_cred_bypass_boot_btn_enabled, preference_cred_bypass_gpio_high, preference_cred_bypass_gpio_low + preference_cred_duo_approval, preference_cred_bypass_boot_btn_enabled, preference_cred_bypass_gpio_high, preference_cred_bypass_gpio_low, preference_publish_config, + preference_config_from_mqtt }; std::vector _redact = { @@ -544,7 +549,8 @@ private: preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_cred_bypass_boot_btn_enabled, preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command, preference_connect_mode, preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_mqtt_ssl_enabled, - preference_hybrid_reboot_on_disconnect, preference_lock_gemini_enabled, preference_enable_debug_mode, preference_cred_duo_enabled, preference_cred_duo_approval + preference_hybrid_reboot_on_disconnect, preference_lock_gemini_enabled, preference_enable_debug_mode, preference_cred_duo_enabled, preference_cred_duo_approval, + preference_publish_config, preference_config_from_mqtt }; std::vector _bytePrefs = { diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 4b81414..85d9f47 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -15,7 +15,6 @@ #include #endif #include -#include #include "driver/gpio.h" extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_bundle_start"); @@ -27,7 +26,7 @@ extern bool timeSynced; #include #include "ArduinoJson.h" -WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer) +WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer, ImportExport* importExport) : _nuki(nuki), _nukiOpener(nukiOpener), _network(network), @@ -35,14 +34,16 @@ WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Nuk _preferences(preferences), _allowRestartToPortal(allowRestartToPortal), _partitionType(partitionType), - _psychicServer(psychicServer) + _psychicServer(psychicServer), + _importExport(importExport) #else -WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer) +WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer, ImportExport* importExport) : _network(network), _preferences(preferences), _allowRestartToPortal(allowRestartToPortal), _partitionType(partitionType), - _psychicServer(psychicServer) + _psychicServer(psychicServer), + _importExport(importExport) #endif { _hostname = _preferences->getString(preference_hostname, ""); @@ -50,28 +51,10 @@ WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool str = _preferences->getString(preference_cred_user, ""); _isSSL = (psychicServer->getPort() == 443); - if (_preferences->getBool(preference_cred_duo_enabled, false)) - { - _duoEnabled = true; - _duoHost = _preferences->getString(preference_cred_duo_host, ""); - _duoIkey = _preferences->getString(preference_cred_duo_ikey, ""); - _duoSkey = _preferences->getString(preference_cred_duo_skey, ""); - _duoUser = _preferences->getString(preference_cred_duo_user, ""); - - if (_duoHost == "" || _duoIkey == "" || _duoSkey == "" || _duoUser == "" || !_preferences->getBool(preference_update_time, false)) - { - _duoEnabled = false; - } - else if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false) || _preferences->getInt(preference_cred_bypass_gpio_high, -1) > -1 || _preferences->getInt(preference_cred_bypass_gpio_low, -1) > -1) - { - if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false)) - { - _bypassGPIO = true; - } - _bypassGPIOHigh = _preferences->getInt(preference_cred_bypass_gpio_high, -1); - _bypassGPIOLow = _preferences->getInt(preference_cred_bypass_gpio_low, -1); - } - } + _duoEnabled = _importExport->getDuoEnabled(); + _bypassGPIO = _importExport->getBypassGPIOEnabled(); + _bypassGPIOHigh = _importExport->getBypassGPIOHigh(); + _bypassGPIOLow = _importExport->getBypassGPIOLow(); if(str.length() > 0) { @@ -98,17 +81,6 @@ WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool _confirmCode = generateConfirmCode(); #ifndef NUKI_HUB_UPDATER - _pinsConfigured = true; - - if(_nuki != nullptr && !_nuki->isPinSet()) - { - _pinsConfigured = false; - } - if(_nukiOpener != nullptr && !_nukiOpener->isPinSet()) - { - _pinsConfigured = false; - } - _brokerConfigured = _preferences->getString(preference_mqtt_broker).length() > 0 && _preferences->getInt(preference_mqtt_broker_port) > 0; #endif } @@ -126,13 +98,13 @@ bool WebCfgServer::isAuthenticated(PsychicRequest *request, bool duo) { String cookie = request->getCookie(cookieKey.c_str()); - if ((!duo && _httpSessions[cookie].is()) || (duo && _duoSessions[cookie].is())) + if ((!duo && _httpSessions[cookie].is()) || (duo && _importExport->_duoSessions[cookie].is())) { struct timeval time; gettimeofday(&time, NULL); int64_t time_us = (int64_t)time.tv_sec * 1000000L + (int64_t)time.tv_usec; - if ((!duo && _httpSessions[cookie].as() > time_us) || (duo && _duoSessions[cookie].as() > time_us)) + if ((!duo && _httpSessions[cookie].as() > time_us) || (duo && _importExport->_duoSessions[cookie].as() > time_us)) { return true; } @@ -183,7 +155,7 @@ esp_err_t WebCfgServer::logoutSession(PsychicRequest *request, PsychicResponse* if (request->hasCookie("duoId")) { String cookie2 = request->getCookie("duoId"); - _duoSessions.remove(cookie2); + _importExport->_duoSessions.remove(cookie2); saveSessions(true); } else @@ -215,12 +187,13 @@ void WebCfgServer::saveSessions(bool duo) else { file = SPIFFS.open("/duosessions.json", "w"); - serializeJson(_duoSessions, file); + serializeJson(_importExport->_duoSessions, file); } file.close(); } } } + void WebCfgServer::loadSessions(bool duo) { if(_preferences->getBool(preference_update_time, false)) @@ -254,7 +227,7 @@ void WebCfgServer::loadSessions(bool duo) } else { - deserializeJson(_duoSessions, file); + deserializeJson(_importExport->_duoSessions, file); } } file.close(); @@ -271,13 +244,13 @@ void WebCfgServer::clearSessions() else { _httpSessions.clear(); - _duoSessions.clear(); + _importExport->_duoSessions.clear(); File file; file = SPIFFS.open("/sessions.json", "w"); serializeJson(_httpSessions, file); file.close(); file = SPIFFS.open("/duosessions.json", "w"); - serializeJson(_duoSessions, file); + serializeJson(_importExport->_duoSessions, file); file.close(); } } @@ -366,154 +339,6 @@ int WebCfgServer::doAuthentication(PsychicRequest *request) return 4; } -bool WebCfgServer::startDuoAuth(char* pushType) -{ - int64_t timeout = esp_timer_get_time() - (30 * 1000 * 1000L); - if(!_duoActiveRequest || timeout > _duoRequestTS) - { - const char* duo_host = _duoHost.c_str(); - const char* duo_ikey = _duoIkey.c_str(); - const char* duo_skey = _duoSkey.c_str(); - const char* duo_user = _duoUser.c_str(); - - DuoAuthLib duoAuth; - bool duoRequestResult; - duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo); - duoAuth.setPushType(pushType); - duoRequestResult = duoAuth.pushAuth((char*)duo_user, true); - - if(duoRequestResult == true) - { - _duoTransactionId = duoAuth.getAuthTxId(); - _duoActiveRequest = true; - _duoRequestTS = esp_timer_get_time(); - Log->println("Duo MFA Auth sent"); - return true; - } - else - { - Log->println("Failed Duo MFA Auth"); - return false; - } - } - return true; -} - -int WebCfgServer::checkDuoAuth(PsychicRequest *request) -{ - const char* duo_host = _duoHost.c_str(); - const char* duo_ikey = _duoIkey.c_str(); - const char* duo_skey = _duoSkey.c_str(); - const char* duo_user = _duoUser.c_str(); - - if (request->hasParam("id")) { - const PsychicWebParameter* p = request->getParam("id"); - String cookie2 = p->value(); - DuoAuthLib duoAuth; - if(_duoActiveRequest && _duoCheckIP == request->client()->localIP().toString() && cookie2 == _duoCheckId) - { - duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo); - - Log->println("Checking Duo Push Status..."); - duoAuth.authStatus(_duoTransactionId); - - if(duoAuth.pushWaiting()) - { - Log->println("Duo Push Waiting..."); - return 2; - } - else - { - if (duoAuth.authSuccessful()) - { - Log->println("Successful Duo MFA Auth"); - _duoActiveRequest = false; - _duoTransactionId = ""; - _duoCheckIP = ""; - _duoCheckId = ""; - int64_t durationLength = 60*60*_preferences->getInt(preference_cred_session_lifetime_duo_remember, 720); - - if (!_sessionsOpts[request->client()->localIP().toString()]) - { - durationLength = _preferences->getInt(preference_cred_session_lifetime_duo, 3600); - } - struct timeval time; - gettimeofday(&time, NULL); - int64_t time_us = (int64_t)time.tv_sec * 1000000L + (int64_t)time.tv_usec; - _duoSessions[cookie2] = time_us + (durationLength*1000000L); - saveSessions(true); - if (_preferences->getBool(preference_mfa_reconfigure, false)) - { - _preferences->putBool(preference_mfa_reconfigure, false); - } - return 1; - } - else - { - Log->println("Failed Duo MFA Auth"); - _duoActiveRequest = false; - _duoTransactionId = ""; - _duoCheckIP = ""; - _duoCheckId = ""; - if (_preferences->getBool(preference_mfa_reconfigure, false)) - { - _preferences->putBool(preference_cred_duo_enabled, false); - _duoEnabled = false; - _preferences->putBool(preference_mfa_reconfigure, false); - } - return 0; - } - } - } - } - return 0; -} - -int WebCfgServer::checkDuoApprove() -{ - const char* duo_host = _duoHost.c_str(); - const char* duo_ikey = _duoIkey.c_str(); - const char* duo_skey = _duoSkey.c_str(); - const char* duo_user = _duoUser.c_str(); - - DuoAuthLib duoAuth; - if(_duoActiveRequest) - { - duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo); - - Log->println("Checking Duo Push Status..."); - duoAuth.authStatus(_duoTransactionId); - - if(duoAuth.pushWaiting()) - { - Log->println("Duo Push Waiting..."); - return 2; - } - else - { - if (duoAuth.authSuccessful()) - { - Log->println("Successful Duo MFA Auth"); - _duoActiveRequest = false; - _duoTransactionId = ""; - _duoCheckIP = ""; - _duoCheckId = ""; - return 1; - } - else - { - Log->println("Failed Duo MFA Auth"); - _duoActiveRequest = false; - _duoTransactionId = ""; - _duoCheckIP = ""; - _duoCheckId = ""; - return 0; - } - } - } - return 0; -} - void WebCfgServer::initialize() { //_psychicServer->onOpen([&](PsychicClient* client) { Log->printf("[http] connection #%u connected from %s\n", client->socket(), client->localIP().toString().c_str()); }); @@ -741,13 +566,13 @@ void WebCfgServer::initialize() { return buildConfirmHtml(request, resp, "NTP time not synced yet, Duo not available, please wait for NTP to sync", 3, true); } - else if (startDuoAuth((char*)"Approve Nuki Hub export")) + else if (_importExport->startDuoAuth((char*)"Approve Nuki Hub export")) { int duoResult = 2; while (duoResult == 2) { - duoResult = checkDuoApprove(); + duoResult = _importExport->checkDuoApprove(); delay(2000); esp_task_wdt_reset(); } @@ -958,13 +783,13 @@ void WebCfgServer::initialize() { return buildConfirmHtml(request, resp, "NTP time not synced yet, Duo not available, please wait for NTP to sync", 3, true); } - else if (startDuoAuth((char*)"Approve Nuki Hub setting change")) + else if (_importExport->startDuoAuth((char*)"Approve Nuki Hub setting change")) { int duoResult = 2; while (duoResult == 2) { - duoResult = checkDuoApprove(); + duoResult = _importExport->checkDuoApprove(); delay(2000); esp_task_wdt_reset(); } @@ -1015,7 +840,7 @@ void WebCfgServer::initialize() { processGpioArgs(request, resp); esp_err_t res = buildConfirmHtml(request, resp, "Saving GPIO configuration. Restarting.", 3, true); - Log->println(("Restarting")); + Log->println("Restarting"); waitAndProcess(true, 1000); restartEsp(RestartReason::GpioConfigurationUpdated); return res; @@ -1790,7 +1615,7 @@ esp_err_t WebCfgServer::handleOtaUpload(PsychicRequest *request, const String& f return(ESP_FAIL); } } - Log->print(("Progress: 100%")); + Log->print("Progress: 100%"); Log->println(); Log->print("handleFileUpload Total Size: "); Log->println(index+len); @@ -1924,7 +1749,7 @@ esp_err_t WebCfgServer::buildLoginHtml(PsychicRequest *request, PsychicResponse* esp_err_t WebCfgServer::buildDuoCheckHtml(PsychicRequest *request, PsychicResponse* resp) { char valueStr[2]; - itoa(checkDuoAuth(request), valueStr, 10); + itoa(_importExport->checkDuoAuth(request), valueStr, 10); resp->setCode(200); resp->setContentType("text/plain"); resp->setContent(valueStr); @@ -1945,16 +1770,16 @@ esp_err_t WebCfgServer::buildCoredumpHtml(PsychicRequest *request, PsychicRespon Log->println("coredump.hex not found"); } else - { + { PsychicFileResponse response(resp, file, "coredump.hex"); String name = "coredump.txt"; char buf[26 + name.length()]; snprintf(buf, sizeof(buf), "attachment; filename=\"%s\"", name.c_str()); response.addHeader("Content-Disposition", buf); - return response.send(); + return response.send(); } } - + resp->setCode(302); resp->addHeader("Cache-Control", "no-cache"); return resp->redirect("/"); @@ -1966,8 +1791,8 @@ esp_err_t WebCfgServer::buildDuoHtml(PsychicRequest *request, PsychicResponse* r { return buildConfirmHtml(request, resp, "NTP time not synced yet, Duo not available, please wait for NTP to sync", 3, true); } - - bool duo = startDuoAuth((char*)"Approve Nuki Hub login"); + + bool duo = _importExport->startDuoAuth((char*)"Approve Nuki Hub login"); if (!duo) { @@ -1984,7 +1809,7 @@ esp_err_t WebCfgServer::buildDuoHtml(PsychicRequest *request, PsychicResponse* r int64_t durationLength = 60*60*_preferences->getInt(preference_cred_session_lifetime_duo_remember, 720); - if (!_sessionsOpts[request->client()->localIP().toString()]) + if (!_importExport->_sessionsOpts[request->client()->localIP().toString()]) { durationLength = _preferences->getInt(preference_cred_session_lifetime_duo, 3600); } @@ -1998,13 +1823,13 @@ esp_err_t WebCfgServer::buildDuoHtml(PsychicRequest *request, PsychicResponse* r response.setCookie("duoId", buffer, durationLength, "Secure; HttpOnly"); } - _duoCheckIP = request->client()->localIP().toString(); - _duoCheckId = buffer; + _importExport->setDuoCheckIP(request->client()->localIP().toString()); + _importExport->setDuoCheckId(buffer); response.beginSend(); response.print(""); response.print(""); - response.print((String)""); + response.print((String)""); response.print("

Nuki Hub login

"); response.print("
Duo Push sent

"); response.print("Please confirm login in the Duo app

"); @@ -2035,7 +1860,7 @@ bool WebCfgServer::processLogin(PsychicRequest *request, PsychicResponse* resp) durationLength = _preferences->getInt(preference_cred_session_lifetime, 3600); } - _sessionsOpts[request->client()->localIP().toString()] = request->hasParam("remember"); + _importExport->_sessionsOpts[request->client()->localIP().toString()] = request->hasParam("remember"); if (!_isSSL) { @@ -2072,118 +1897,12 @@ esp_err_t WebCfgServer::sendSettings(PsychicRequest *request, PsychicResponse* r if(p->value() == "https") { name = "nuki_hub_http_ssl.json"; - if (!SPIFFS.begin(true)) { - Log->println("SPIFFS Mount Failed"); - } - else - { - File file = SPIFFS.open("/http_ssl.crt"); - if (!file || file.isDirectory()) { - Log->println("http_ssl.crt not found"); - } - else - { - Log->println("Reading http_ssl.crt"); - size_t filesize = file.size(); - char cert[filesize + 1]; - - file.read((uint8_t *)cert, sizeof(cert)); - file.close(); - cert[filesize] = '\0'; - json["http_ssl.crt"] = cert; - } - } - - if (!SPIFFS.begin(true)) { - Log->println("SPIFFS Mount Failed"); - } - else - { - File file = SPIFFS.open("/http_ssl.key"); - if (!file || file.isDirectory()) { - Log->println("http_ssl.key not found"); - } - else - { - Log->println("Reading http_ssl.key"); - size_t filesize = file.size(); - char key[filesize + 1]; - - file.read((uint8_t *)key, sizeof(key)); - file.close(); - key[filesize] = '\0'; - json["http_ssl.key"] = key; - } - } + _importExport->exportHttpsJson(json); } else { name = "nuki_hub_mqtt_ssl.json"; - if (!SPIFFS.begin(true)) { - Log->println("SPIFFS Mount Failed"); - } - else - { - File file = SPIFFS.open("/mqtt_ssl.ca"); - if (!file || file.isDirectory()) { - Log->println("mqtt_ssl.ca not found"); - } - else - { - Log->println("Reading mqtt_ssl.ca"); - size_t filesize = file.size(); - char ca[filesize + 1]; - - file.read((uint8_t *)ca, sizeof(ca)); - file.close(); - ca[filesize] = '\0'; - json["mqtt_ssl.ca"] = ca; - } - } - - if (!SPIFFS.begin(true)) { - Log->println("SPIFFS Mount Failed"); - } - else - { - File file = SPIFFS.open("/mqtt_ssl.crt"); - if (!file || file.isDirectory()) { - Log->println("mqtt_ssl.crt not found"); - } - else - { - Log->println("Reading mqtt_ssl.crt"); - size_t filesize = file.size(); - char cert[filesize + 1]; - - file.read((uint8_t *)cert, sizeof(cert)); - file.close(); - cert[filesize] = '\0'; - json["mqtt_ssl.crt"] = cert; - } - } - - if (!SPIFFS.begin(true)) { - Log->println("SPIFFS Mount Failed"); - } - else - { - File file = SPIFFS.open("/mqtt_ssl.key"); - if (!file || file.isDirectory()) { - Log->println("mqtt_ssl.key not found"); - } - else - { - Log->println("Reading mqtt_ssl.key"); - size_t filesize = file.size(); - char key[filesize + 1]; - - file.read((uint8_t *)key, sizeof(key)); - file.close(); - key[filesize] = '\0'; - json["mqtt_ssl.key"] = key; - } - } + _importExport->exportMqttsJson(json); } } else @@ -2208,188 +1927,7 @@ esp_err_t WebCfgServer::sendSettings(PsychicRequest *request, PsychicResponse* r pairing = true; } } - - DebugPreferences debugPreferences; - - const std::vector keysPrefs = debugPreferences.getPreferencesKeys(); - const std::vector boolPrefs = debugPreferences.getPreferencesBoolKeys(); - const std::vector redactedPrefs = debugPreferences.getPreferencesRedactedKeys(); - const std::vector bytePrefs = debugPreferences.getPreferencesByteKeys(); - - for(const auto& key : keysPrefs) - { - if(strcmp(key, preference_show_secrets) == 0) - { - continue; - } - if(strcmp(key, preference_latest_version) == 0) - { - continue; - } - if(!redacted) if(std::find(redactedPrefs.begin(), redactedPrefs.end(), key) != redactedPrefs.end()) - { - continue; - } - if(!_preferences->isKey(key)) - { - json[key] = ""; - } - else if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end()) - { - json[key] = _preferences->getBool(key) ? "1" : "0"; - } - else - { - switch(_preferences->getType(key)) - { - case PT_I8: - json[key] = String(_preferences->getChar(key)); - break; - case PT_I16: - json[key] = String(_preferences->getShort(key)); - break; - case PT_I32: - json[key] = String(_preferences->getInt(key)); - break; - case PT_I64: - json[key] = String(_preferences->getLong64(key)); - break; - case PT_U8: - json[key] = String(_preferences->getUChar(key)); - break; - case PT_U16: - json[key] = String(_preferences->getUShort(key)); - break; - case PT_U32: - json[key] = String(_preferences->getUInt(key)); - break; - case PT_U64: - json[key] = String(_preferences->getULong64(key)); - break; - case PT_STR: - json[key] = _preferences->getString(key); - break; - default: - json[key] = _preferences->getString(key); - break; - } - } - } - - if(pairing) - { - if(_nuki != nullptr) - { - unsigned char currentBleAddress[6]; - unsigned char authorizationId[4] = {0x00}; - unsigned char secretKeyK[32] = {0x00}; - uint16_t storedPincode = 0000; - uint32_t storedUltraPincode = 000000; - bool isUltra = false; - Preferences nukiBlePref; - nukiBlePref.begin("NukiHub", false); - nukiBlePref.getBytes("bleAddress", currentBleAddress, 6); - nukiBlePref.getBytes("secretKeyK", secretKeyK, 32); - nukiBlePref.getBytes("authorizationId", authorizationId, 4); - nukiBlePref.getBytes("securityPinCode", &storedPincode, 2); - nukiBlePref.getBytes("ultraPinCode", &storedUltraPincode, 4); - isUltra = nukiBlePref.getBool("isUltra", false); - nukiBlePref.end(); - char text[255]; - text[0] = '\0'; - for(int i = 0 ; i < 6 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", currentBleAddress[i]); - } - json["bleAddressLock"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 32 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", secretKeyK[i]); - } - json["secretKeyKLock"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 4 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", authorizationId[i]); - } - json["authorizationIdLock"] = text; - memset(text, 0, sizeof(text)); - json["securityPinCodeLock"] = storedPincode; - json["ultraPinCodeLock"] = storedUltraPincode; - json["isUltra"] = isUltra ? "1" : "0"; - } - if(_nukiOpener != nullptr) - { - unsigned char currentBleAddressOpn[6]; - unsigned char authorizationIdOpn[4] = {0x00}; - unsigned char secretKeyKOpn[32] = {0x00}; - uint16_t storedPincodeOpn = 0000; - Preferences nukiBlePref; - nukiBlePref.begin("NukiHubopener", false); - nukiBlePref.getBytes("bleAddress", currentBleAddressOpn, 6); - nukiBlePref.getBytes("secretKeyK", secretKeyKOpn, 32); - nukiBlePref.getBytes("authorizationId", authorizationIdOpn, 4); - nukiBlePref.getBytes("securityPinCode", &storedPincodeOpn, 2); - nukiBlePref.end(); - char text[255]; - text[0] = '\0'; - for(int i = 0 ; i < 6 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", currentBleAddressOpn[i]); - } - json["bleAddressOpener"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 32 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", secretKeyKOpn[i]); - } - json["secretKeyKOpener"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 4 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", authorizationIdOpn[i]); - } - json["authorizationIdOpener"] = text; - memset(text, 0, sizeof(text)); - json["securityPinCodeOpener"] = storedPincodeOpn; - } - } - - for(const auto& key : bytePrefs) - { - size_t storedLength = _preferences->getBytesLength(key); - if(storedLength == 0) - { - continue; - } - uint8_t serialized[storedLength]; - memset(serialized, 0, sizeof(serialized)); - size_t size = _preferences->getBytes(key, serialized, sizeof(serialized)); - if(size == 0) - { - continue; - } - char text[255]; - text[0] = '\0'; - for(int i = 0 ; i < size ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", serialized[i]); - } - json[key] = text; - memset(text, 0, sizeof(text)); - } + _importExport->exportNukiHubJson(json, redacted, pairing, (_nuki != nullptr), (_nukiOpener != nullptr)); } serializeJsonPretty(json, jsonPretty); @@ -2454,7 +1992,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_broker, "") != value) { _preferences->putString(preference_mqtt_broker, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2464,7 +2002,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_mqtt_broker_port, 0) != value.toInt()) { _preferences->putInt(preference_mqtt_broker_port, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2480,7 +2018,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_user, "") != value) { _preferences->putString(preference_mqtt_user, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2493,7 +2031,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_password, "") != value) { _preferences->putString(preference_mqtt_password, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2504,7 +2042,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_lock_path, "") != value) { _preferences->putString(preference_mqtt_lock_path, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2536,10 +2074,10 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S else { if (!SPIFFS.remove("/mqtt_ssl.ca")) { - Serial.println("Failed to delete /mqtt_ssl.ca"); + Log->println("Failed to delete /mqtt_ssl.ca"); } } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2572,10 +2110,10 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S else { if (!SPIFFS.remove("/mqtt_ssl.crt")) { - Serial.println("Failed to delete /mqtt_ssl.crt"); + Log->println("Failed to delete /mqtt_ssl.crt"); } } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2608,10 +2146,10 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S else { if (!SPIFFS.remove("/mqtt_ssl.key")) { - Serial.println("Failed to delete /mqtt_ssl.key"); + Log->println("Failed to delete /mqtt_ssl.key"); } } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2645,10 +2183,10 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S else { if (!SPIFFS.remove("/http_ssl.crt")) { - Serial.println("Failed to delete /http_ssl.crt"); + Log->println("Failed to delete /http_ssl.crt"); } } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2681,10 +2219,10 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S else { if (!SPIFFS.remove("/http_ssl.key")) { - Serial.println("Failed to delete /http_ssl.key"); + Log->println("Failed to delete /http_ssl.key"); } } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2696,7 +2234,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_update_time, false) != (value == "1")) { _preferences->putBool(preference_update_time, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2706,7 +2244,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_time_server, "pool.ntp.org") != value) { _preferences->putString(preference_time_server, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2724,7 +2262,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } } _preferences->putInt(preference_network_hardware, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2735,7 +2273,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_phy, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2746,7 +2284,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_addr, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2757,7 +2295,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_irq, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2768,7 +2306,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_rst, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2779,7 +2317,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_cs, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2790,7 +2328,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_sck, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2801,7 +2339,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_miso, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2812,7 +2350,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_mosi, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2823,7 +2361,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_pwr, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2834,7 +2372,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_mdio, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2845,7 +2383,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_mdc, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2856,7 +2394,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_clk, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2866,7 +2404,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_rssi_publish_interval, 60) != value.toInt()) { _preferences->putInt(preference_rssi_publish_interval, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -2876,7 +2414,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_https_fqdn, "") != value) { _preferences->putString(preference_https_fqdn, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2888,7 +2426,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_duo_host, "") != value) { _preferences->putString(preference_cred_duo_host, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -2903,7 +2441,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_duo_ikey, "") != value) { _preferences->putString(preference_cred_duo_ikey, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -2918,7 +2456,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_duo_skey, "") != value) { _preferences->putString(preference_cred_duo_skey, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -2933,7 +2471,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_duo_user, "") != value) { _preferences->putString(preference_cred_duo_user, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -2949,7 +2487,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if (value == "1") { _preferences->putBool(preference_update_time, true); } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -2961,7 +2499,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false) != (value == "1")) { _preferences->putBool(preference_cred_bypass_boot_btn_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2971,7 +2509,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_cred_bypass_gpio_high, -1) != value.toInt()) { _preferences->putInt(preference_cred_bypass_gpio_high, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2981,7 +2519,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_cred_bypass_gpio_low, -1) != value.toInt()) { _preferences->putInt(preference_cred_bypass_gpio_low, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -2991,7 +2529,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_cred_duo_approval, false) != (value == "1")) { _preferences->putBool(preference_cred_duo_approval, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3001,7 +2539,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_cred_session_lifetime, 3600) != value.toInt()) { _preferences->putInt(preference_cred_session_lifetime, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -3012,7 +2550,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_cred_session_lifetime_remember, 720) != value.toInt()) { _preferences->putInt(preference_cred_session_lifetime_remember, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -3023,7 +2561,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_cred_session_lifetime_duo, 3600) != value.toInt()) { _preferences->putInt(preference_cred_session_lifetime_duo, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -3034,7 +2572,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_cred_session_lifetime_duo_remember, 720) != value.toInt()) { _preferences->putInt(preference_cred_session_lifetime_duo_remember, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -3046,7 +2584,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _network->disableHASS(); _preferences->putBool(preference_hass_device_discovery, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3057,7 +2595,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _network->disableHASS(); _preferences->putBool(preference_mqtt_hass_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3068,7 +2606,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _network->disableHASS(); _preferences->putString(preference_mqtt_hass_discovery, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3078,7 +2616,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_opener_continuous_mode, false) != (value == "1")) { _preferences->putBool(preference_opener_continuous_mode, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3088,7 +2626,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_hass_cu_url, "") != value) { _preferences->putString(preference_mqtt_hass_cu_url, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3098,7 +2636,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_hostname, "") != value) { _preferences->putString(preference_hostname, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3108,7 +2646,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_network_timeout, 60) != value.toInt()) { _preferences->putInt(preference_network_timeout, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3118,7 +2656,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_find_best_rssi, false) != (value == "1")) { _preferences->putBool(preference_find_best_rssi, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3128,7 +2666,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_restart_on_disconnect, false) != (value == "1")) { _preferences->putBool(preference_restart_on_disconnect, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3138,7 +2676,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_mqtt_log_enabled, false) != (value == "1")) { _preferences->putBool(preference_mqtt_log_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3148,7 +2686,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_mqtt_ssl_enabled, false) != (value == "1")) { _preferences->putBool(preference_mqtt_ssl_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3158,7 +2696,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_webserial_enabled, false) != (value == "1")) { _preferences->putBool(preference_webserial_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3168,7 +2706,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_check_updates, false) != (value == "1")) { _preferences->putBool(preference_check_updates, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3178,7 +2716,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_update_from_mqtt, false) != (value == "1")) { _preferences->putBool(preference_update_from_mqtt, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3192,7 +2730,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _preferences->putBool(preference_register_as_app, true); } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3206,7 +2744,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _preferences->putBool(preference_register_as_app, true); } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3216,7 +2754,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_query_interval_hybrid_lockstate, 600) != value.toInt()) { _preferences->putInt(preference_query_interval_hybrid_lockstate, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3226,7 +2764,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_official_hybrid_retry, false) != (value == "1")) { _preferences->putBool(preference_official_hybrid_retry, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3236,7 +2774,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_hybrid_reboot_on_disconnect, false) != (value == "1")) { _preferences->putBool(preference_hybrid_reboot_on_disconnect, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3246,7 +2784,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_disable_non_json, false) != (value == "1")) { _preferences->putBool(preference_disable_non_json, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3256,7 +2794,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_ip_dhcp_enabled, true) != (value == "1")) { _preferences->putBool(preference_ip_dhcp_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3266,7 +2804,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_address, "") != value) { _preferences->putString(preference_ip_address, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3276,7 +2814,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_subnet, "") != value) { _preferences->putString(preference_ip_subnet, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3286,7 +2824,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_gateway, "") != value) { _preferences->putString(preference_ip_gateway, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3296,7 +2834,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_dns_server, "") != value) { _preferences->putString(preference_ip_dns_server, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3306,7 +2844,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_query_interval_lockstate, 1800) != value.toInt()) { _preferences->putInt(preference_query_interval_lockstate, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3316,7 +2854,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_query_interval_configuration, 3600) != value.toInt()) { _preferences->putInt(preference_query_interval_configuration, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3326,7 +2864,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_query_interval_battery, 1800) != value.toInt()) { _preferences->putInt(preference_query_interval_battery, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3336,7 +2874,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_query_interval_keypad, 1800) != value.toInt()) { _preferences->putInt(preference_query_interval_keypad, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3346,7 +2884,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_command_nr_of_retries, 3) != value.toInt()) { _preferences->putInt(preference_command_nr_of_retries, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3356,7 +2894,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_command_retry_delay, 100) != value.toInt()) { _preferences->putInt(preference_command_retry_delay, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3372,7 +2910,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_ble_tx_power, 9) != value.toInt()) { _preferences->putInt(preference_ble_tx_power, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3383,7 +2921,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_restart_ble_beacon_lost, 60) != value.toInt()) { _preferences->putInt(preference_restart_ble_beacon_lost, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3395,7 +2933,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE) != value.toInt()) { _preferences->putInt(preference_task_size_network, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3408,7 +2946,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE) != value.toInt()) { _preferences->putInt(preference_task_size_nuki, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3421,7 +2959,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG) != value.toInt()) { _preferences->putInt(preference_authlog_max_entries, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3434,7 +2972,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD) != value.toInt()) { _preferences->putInt(preference_keypad_max_entries, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3447,7 +2985,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL) != value.toInt()) { _preferences->putInt(preference_timecontrol_max_entries, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3460,7 +2998,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_auth_max_entries, MAX_AUTH) != value.toInt()) { _preferences->putInt(preference_auth_max_entries, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3473,7 +3011,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE) != value.toInt()) { _preferences->putInt(preference_buffer_size, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3484,7 +3022,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_enable_bootloop_reset, false) != (value == "1")) { _preferences->putBool(preference_enable_bootloop_reset, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3494,7 +3032,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_disable_network_not_connected, false) != (value == "1")) { _preferences->putBool(preference_disable_network_not_connected, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3504,7 +3042,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ota_updater_url, "") != value) { _preferences->putString(preference_ota_updater_url, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3514,7 +3052,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ota_main_url, "") != value) { _preferences->putString(preference_ota_main_url, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3524,7 +3062,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_show_secrets, false) != (value == "1")) { _preferences->putBool(preference_show_secrets, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3534,7 +3072,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_debug_connect, false) != (value == "1")) { _preferences->putBool(preference_debug_connect, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3544,7 +3082,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_debug_communication, false) != (value == "1")) { _preferences->putBool(preference_debug_communication, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3554,7 +3092,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_publish_debug_info, false) != (value == "1")) { _preferences->putBool(preference_publish_debug_info, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3564,7 +3102,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_debug_readable_data, false) != (value == "1")) { _preferences->putBool(preference_debug_readable_data, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3574,7 +3112,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_debug_hex_data, false) != (value == "1")) { _preferences->putBool(preference_debug_hex_data, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3584,7 +3122,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_debug_command, false) != (value == "1")) { _preferences->putBool(preference_debug_command, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3594,7 +3132,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_lock_force_id, false) != (value == "1")) { _preferences->putBool(preference_lock_force_id, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); } } @@ -3603,7 +3141,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_lock_force_keypad, false) != (value == "1")) { _preferences->putBool(preference_lock_force_keypad, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); } } @@ -3612,7 +3150,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_lock_force_doorsensor, false) != (value == "1")) { _preferences->putBool(preference_lock_force_doorsensor, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); } } @@ -3621,7 +3159,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_opener_force_id, false) != (value == "1")) { _preferences->putBool(preference_opener_force_id, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); } } @@ -3630,7 +3168,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_opener_force_keypad, false) != (value == "1")) { _preferences->putBool(preference_opener_force_keypad, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); } } @@ -3643,17 +3181,45 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_conf_info_enabled, true) != (value == "1")) { _preferences->putBool(preference_conf_info_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } } + else if(key == "CONFNHPUB") + { + if(_preferences->getBool(preference_publish_config, false) != (value == "1")) + { + if(_preferences->getBool(preference_config_from_mqtt, false) && _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE) < 8192) + { + _preferences->putInt(preference_buffer_size, 8192); + } + _preferences->putBool(preference_publish_config, (value == "1")); + Log->print("Setting changed: "); + Log->println(key); + configChanged = true; + } + } + else if(key == "CONFNHCTRL") + { + if(_preferences->getBool(preference_config_from_mqtt, false) != (value == "1")) + { + if(_preferences->getBool(preference_config_from_mqtt, false) && _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE) < 8192) + { + _preferences->putInt(preference_buffer_size, 8192); + } + _preferences->putBool(preference_config_from_mqtt, (value == "1")); + Log->print("Setting changed: "); + Log->println(key); + configChanged = true; + } + } else if(key == "KPPUB") { if(_preferences->getBool(preference_keypad_info_enabled, false) != (value == "1")) { _preferences->putBool(preference_keypad_info_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3663,7 +3229,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_keypad_publish_code, false) != (value == "1")) { _preferences->putBool(preference_keypad_publish_code, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3673,7 +3239,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_keypad_check_code_enabled, false) != (value == "1")) { _preferences->putBool(preference_keypad_check_code_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3683,7 +3249,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_keypad_control_enabled, false) != (value == "1")) { _preferences->putBool(preference_keypad_control_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3693,7 +3259,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_timecontrol_info_enabled, false) != (value == "1")) { _preferences->putBool(preference_timecontrol_info_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3703,7 +3269,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_auth_info_enabled, false) != (value == "1")) { _preferences->putBool(preference_auth_info_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3713,7 +3279,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_keypad_topic_per_entry, false) != (value == "1")) { _preferences->putBool(preference_keypad_topic_per_entry, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3723,7 +3289,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_timecontrol_topic_per_entry, false) != (value == "1")) { _preferences->putBool(preference_timecontrol_topic_per_entry, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3733,7 +3299,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_timecontrol_control_enabled, false) != (value == "1")) { _preferences->putBool(preference_timecontrol_control_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3743,7 +3309,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_auth_topic_per_entry, false) != (value == "1")) { _preferences->putBool(preference_auth_topic_per_entry, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3753,7 +3319,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_auth_control_enabled, false) != (value == "1")) { _preferences->putBool(preference_auth_control_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -3763,7 +3329,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_publish_authdata, false) != (value == "1")) { _preferences->putBool(preference_publish_authdata, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -3773,7 +3339,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getInt(preference_http_auth_type, 0) != value.toInt()) { _preferences->putInt(preference_http_auth_type, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -3786,7 +3352,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_bypass_proxy, "") != value) { _preferences->putString(preference_bypass_proxy, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -4170,7 +3736,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_register_as_app, false) != (value == "1")) { _preferences->putBool(preference_register_as_app, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -4180,7 +3746,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_register_opener_as_app, false) != (value == "1")) { _preferences->putBool(preference_register_opener_as_app, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); //configChanged = true; } @@ -4190,7 +3756,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_lock_enabled, true) != (value == "1")) { _preferences->putBool(preference_lock_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4207,7 +3773,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S _preferences->putBool(preference_official_hybrid_enabled, true); _preferences->putBool(preference_official_hybrid_actions, true); } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4217,7 +3783,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_opener_enabled, false) != (value == "1")) { _preferences->putBool(preference_opener_enabled, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4227,7 +3793,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_connect_mode, true) != (value == "1")) { _preferences->putBool(preference_connect_mode, (value == "1")); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4243,7 +3809,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_user, "") != value) { _preferences->putString(preference_cred_user, value); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; clearSession = true; @@ -4273,7 +3839,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S message = "Nuki Lock PIN cleared"; _nuki->setPin(0xffff); } - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4286,7 +3852,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S message = "Nuki Lock Ultra PIN saved"; _nuki->setUltraPin(value.toInt()); _preferences->putInt(preference_lock_gemini_pin, value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4297,7 +3863,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Lock PIN saved"; _nuki->setPin(value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4310,7 +3876,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Opener PIN cleared"; _nukiOpener->setPin(0xffff); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4320,7 +3886,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Opener PIN saved"; _nukiOpener->setPin(value.toInt()); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println(key); configChanged = true; } @@ -4389,7 +3955,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(manPairLck) { - Log->println(("Changing lock pairing")); + Log->println("Changing lock pairing"); Preferences nukiBlePref; nukiBlePref.begin("NukiHub", false); nukiBlePref.putBytes("bleAddress", currentBleAddress, 6); @@ -4400,14 +3966,14 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S nukiBlePref.putBool("isUltra", isUltra); nukiBlePref.end(); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("Lock pairing data"); configChanged = true; } if(manPairOpn) { - Log->println(("Changing opener pairing")); + Log->println("Changing opener pairing"); Preferences nukiBlePref; nukiBlePref.begin("NukiHubopener", false); nukiBlePref.putBytes("bleAddress", currentBleAddressOpn, 6); @@ -4415,7 +3981,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S nukiBlePref.putBytes("authorizationId", authorizationIdOpn, 4); nukiBlePref.putBytes("securityPinCode", pincode, 2); nukiBlePref.end(); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("Opener pairing data"); configChanged = true; } @@ -4425,7 +3991,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_password, "") != pass1) { _preferences->putString(preference_cred_password, pass1); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("CREDPASS"); configChanged = true; clearSession = true; @@ -4437,14 +4003,14 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_user, "") != "") { _preferences->putString(preference_mqtt_user, ""); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("MQTTUSER"); configChanged = true; } if(_preferences->getString(preference_mqtt_password, "") != "") { _preferences->putString(preference_mqtt_password, ""); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("MQTTPASS"); configChanged = true; } @@ -4455,7 +4021,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_user, "") != "") { _preferences->putString(preference_cred_user, ""); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("CREDUSER"); configChanged = true; clearSession = true; @@ -4463,7 +4029,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_password, "") != "") { _preferences->putString(preference_cred_password, ""); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("CREDPASS"); configChanged = true; clearSession = true; @@ -4488,7 +4054,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(curAclPrefs[i] != aclPrefs[i]) { _preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs)); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("ACLPREFS"); //configChanged = true; break; @@ -4499,7 +4065,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(curBasicLockConfigAclPrefs[i] != basicLockConfigAclPrefs[i]) { _preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs)); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("ACLCONFBASICLOCK"); //configChanged = true; break; @@ -4510,7 +4076,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(curAdvancedLockConfigAclPrefs[i] != advancedLockConfigAclPrefs[i]) { _preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs)); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("ACLCONFADVANCEDLOCK"); //configChanged = true; break; @@ -4522,7 +4088,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(curBasicOpenerConfigAclPrefs[i] != basicOpenerConfigAclPrefs[i]) { _preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs)); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("ACLCONFBASICOPENER"); //configChanged = true; break; @@ -4533,7 +4099,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(curAdvancedOpenerConfigAclPrefs[i] != advancedOpenerConfigAclPrefs[i]) { _preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs)); - Log->print(("Setting changed: ")); + Log->print("Setting changed: "); Log->println("ACLCONFADVANCEDOPENER"); //configChanged = true; break; @@ -4548,24 +4114,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(newMFA) { _preferences->putBool(preference_mfa_reconfigure, true); - - if (_preferences->getBool(preference_cred_duo_enabled, false)) - { - _duoEnabled = true; - _duoHost = _preferences->getString(preference_cred_duo_host, ""); - _duoIkey = _preferences->getString(preference_cred_duo_ikey, ""); - _duoSkey = _preferences->getString(preference_cred_duo_skey, ""); - _duoUser = _preferences->getString(preference_cred_duo_user, ""); - - if (_duoHost == "" || _duoIkey == "" || _duoSkey == "" || _duoUser == "" || !_preferences->getBool(preference_update_time, false)) - { - _duoEnabled = false; - } - } - else - { - _duoEnabled = false; - } + _importExport->readSettings(); } if(configChanged) { @@ -4593,13 +4142,6 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S bool WebCfgServer::processImport(PsychicRequest *request, PsychicResponse* resp, String& message) { bool configChanged = false; - unsigned char currentBleAddress[6]; - unsigned char authorizationId[4] = {0x00}; - unsigned char secretKeyK[32] = {0x00}; - unsigned char currentBleAddressOpn[6]; - unsigned char authorizationIdOpn[4] = {0x00}; - unsigned char secretKeyKOpn[32] = {0x00}; - int params = request->params(); for(int index = 0; index < params; index++) @@ -4617,222 +4159,7 @@ bool WebCfgServer::processImport(PsychicRequest *request, PsychicResponse* resp, return configChanged; } - DebugPreferences debugPreferences; - - const std::vector keysPrefs = debugPreferences.getPreferencesKeys(); - const std::vector boolPrefs = debugPreferences.getPreferencesBoolKeys(); - const std::vector bytePrefs = debugPreferences.getPreferencesByteKeys(); - const std::vector intPrefs = debugPreferences.getPreferencesIntKeys(); - const std::vector uintPrefs = debugPreferences.getPreferencesUIntKeys(); - const std::vector uint64Prefs = debugPreferences.getPreferencesUInt64Keys(); - - for(const auto& key : keysPrefs) - { - if(doc[key].isNull()) - { - continue; - } - if(strcmp(key, preference_show_secrets) == 0) - { - continue; - } - if(strcmp(key, preference_latest_version) == 0) - { - continue; - } - if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end()) - { - if (doc[key].as().length() > 0) - { - _preferences->putBool(key, (doc[key].as() == "1" ? true : false)); - } - else - { - _preferences->remove(key); - } - continue; - } - if(std::find(intPrefs.begin(), intPrefs.end(), key) != intPrefs.end()) - { - if (doc[key].as().length() > 0) - { - _preferences->putInt(key, doc[key].as()); - } - else - { - _preferences->remove(key); - } - continue; - } - if(std::find(uintPrefs.begin(), uintPrefs.end(), key) != uintPrefs.end()) - { - if (doc[key].as().length() > 0) - { - _preferences->putUInt(key, doc[key].as()); - } - else - { - _preferences->remove(key); - } - continue; - } - if(std::find(uint64Prefs.begin(), uint64Prefs.end(), key) != uint64Prefs.end()) - { - if (doc[key].as().length() > 0) - { - _preferences->putULong64(key, doc[key].as()); - } - else - { - _preferences->remove(key); - } - continue; - } - if (doc[key].as().length() > 0) - { - _preferences->putString(key, doc[key].as()); - } - else - { - _preferences->remove(key); - } - } - - for(const auto& key : bytePrefs) - { - if(!doc[key].isNull() && doc[key].is()) - { - String value = doc[key].as(); - unsigned char tmpchar[32]; - for(int i=0; iputBytes(key, (byte*)(&tmpchar), (value.length() / 2)); - memset(tmpchar, 0, sizeof(tmpchar)); - } - } - - Preferences nukiBlePref; - nukiBlePref.begin("NukiHub", false); - - if(!doc["bleAddressLock"].isNull()) - { - if (doc["bleAddressLock"].as().length() == 12) - { - String value = doc["bleAddressLock"].as(); - for(int i=0; i().length() == 64) - { - String value = doc["secretKeyKLock"].as(); - for(int i=0; i().length() == 8) - { - String value = doc["authorizationIdLock"].as(); - for(int i=0; i().length() >0) - { - nukiBlePref.putBool("isUltra", (doc["isUltra"].as() == "1" ? true : false)); - } - } - nukiBlePref.end(); - if(!doc["securityPinCodeLock"].isNull() && _nuki != nullptr) - { - if(doc["securityPinCodeLock"].as().length() > 0) - { - _nuki->setPin(doc["securityPinCodeLock"].as()); - } - else - { - _nuki->setPin(0xffff); - } - } - if(!doc["ultraPinCodeLock"].isNull() && _nuki != nullptr) - { - if(doc["ultraPinCodeLock"].as().length() > 0) - { - _nuki->setUltraPin(doc["ultraPinCodeLock"].as()); - _preferences->putInt(preference_lock_gemini_pin, doc["ultraPinCodeLock"].as()); - } - else - { - _nuki->setUltraPin(0xffffffff); - _preferences->putInt(preference_lock_gemini_pin, 0); - } - } - nukiBlePref.begin("NukiHubopener", false); - if(!doc["bleAddressOpener"].isNull()) - { - if (doc["bleAddressOpener"].as().length() == 12) - { - String value = doc["bleAddressOpener"].as(); - for(int i=0; i().length() == 64) - { - String value = doc["secretKeyKOpener"].as(); - for(int i=0; i().length() == 8) - { - String value = doc["authorizationIdOpener"].as(); - for(int i=0; i().length() > 0) - { - _nukiOpener->setPin(doc["securityPinCodeOpener"].as()); - } - else - { - _nukiOpener->setPin(0xffff); - } - } + _importExport->importJson(doc); configChanged = true; } @@ -5006,13 +4333,13 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request, PsychicResponse* resp printParameter(&response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/get?page=ota", "ota"); } response.print("
"); - + response.print("
    "); buildNavigationMenuEntry(&response, "Network Configuration", "/get?page=ntwconfig"); buildNavigationMenuEntry(&response, "MQTT Configuration", "/get?page=mqttconfig", _brokerConfigured ? "" : "Please configure MQTT broker"); buildNavigationMenuEntry(&response, "Nuki Configuration", "/get?page=nukicfg"); buildNavigationMenuEntry(&response, "Access Level Configuration", "/get?page=acclvl"); - buildNavigationMenuEntry(&response, "Credentials", "/get?page=cred", _pinsConfigured ? "" : "Please configure PIN"); + buildNavigationMenuEntry(&response, "Credentials", "/get?page=cred"); buildNavigationMenuEntry(&response, "GPIO Configuration", "/get?page=gpiocfg"); buildNavigationMenuEntry(&response, "Firmware update", "/get?page=ota"); buildNavigationMenuEntry(&response, "Import/Export Configuration", "/get?page=impexpcfg"); @@ -5625,7 +4952,7 @@ String WebCfgServer::pinStateToString(uint8_t value) case 1: return String("PIN valid"); case 2: - return String("PIN set but invalid"); + return String("PIN invalid or not set"); default: return String("Unknown"); } @@ -5645,6 +4972,8 @@ esp_err_t WebCfgServer::buildAccLvlHtml(PsychicRequest *request, PsychicResponse response.print(""); response.print("

    Nuki General Access Control

    "); response.print(""); + printCheckBox(&response, "CONFNHPUB", "Publish Nuki Hub configuration information", _preferences->getBool(preference_publish_config, false), ""); + printCheckBox(&response, "CONFNHCTRL", "Modify Nuki Hub configuration over MQTT", _preferences->getBool(preference_config_from_mqtt, false), ""); printCheckBox(&response, "CONFPUB", "Publish Nuki configuration information", _preferences->getBool(preference_conf_info_enabled, true), ""); if((_nuki != nullptr && _nuki->hasKeypad()) || (_nukiOpener != nullptr && _nukiOpener->hasKeypad())) diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h index d93ce78..bba0e17 100644 --- a/src/WebCfgServer.h +++ b/src/WebCfgServer.h @@ -13,6 +13,7 @@ #include "NukiNetworkLock.h" #include "NukiOpenerWrapper.h" #include "Gpio.h" +#include "ImportExport.h" extern TaskHandle_t nukiTaskHandle; @@ -30,6 +31,7 @@ enum class TokenType #else #include "NukiNetwork.h" +#include "ImportExport.h" #endif extern TaskHandle_t networkTaskHandle; @@ -38,9 +40,9 @@ class WebCfgServer { public: #ifndef NUKI_HUB_UPDATER - WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer); + WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer, ImportExport* importExport); #else - WebCfgServer(NukiNetwork* network, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer); + WebCfgServer(NukiNetwork* network, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer, ImportExport* importExport); #endif ~WebCfgServer() = default; @@ -91,7 +93,6 @@ private: NukiWrapper* _nuki = nullptr; NukiOpenerWrapper* _nukiOpener = nullptr; Gpio* _gpio = nullptr; - bool _pinsConfigured = false; bool _brokerConfigured = false; bool _rebootRequired = false; #endif @@ -101,9 +102,6 @@ private: String generateConfirmCode(); String _confirmCode = "----"; - int checkDuoAuth(PsychicRequest *request); - int checkDuoApprove(); - bool startDuoAuth(char* pushType = (char*)""); void saveSessions(bool duo = false); void loadSessions(bool duo = false); void clearSessions(); @@ -136,6 +134,7 @@ private: PsychicHttpServer* _psychicServer = nullptr; NukiNetwork* _network = nullptr; Preferences* _preferences = nullptr; + ImportExport* _importExport; char _credUser[31] = {0}; char _credPassword[31] = {0}; @@ -145,20 +144,8 @@ private: size_t _otaContentLen = 0; String _hostname; JsonDocument _httpSessions; - JsonDocument _duoSessions; - JsonDocument _sessionsOpts; - struct tm timeinfo; - bool _duoActiveRequest; bool _duoEnabled = false; bool _bypassGPIO = false; int _bypassGPIOHigh = -1; int _bypassGPIOLow = -1; - int64_t _duoRequestTS = 0; - String _duoTransactionId; - String _duoHost; - String _duoSkey; - String _duoIkey; - String _duoUser; - String _duoCheckId; - String _duoCheckIP; }; diff --git a/src/main.cpp b/src/main.cpp index 9da9be3..142450f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,6 +31,7 @@ #include "RestartReason.h" #include "EspMillis.h" #include "NimBLEDevice.h" +#include "ImportExport.h" /* #ifdef DEBUG_NUKIHUB @@ -65,6 +66,7 @@ int64_t restartTs = (pow(2,63) - (5 * 1000 * 60000)) / 1000; #include "../../src/RestartReason.h" #include "../../src/NukiNetwork.h" #include "../../src/EspMillis.h" +#include "../../src/ImportExport.h" int64_t restartTs = 10 * 60 * 1000; @@ -78,6 +80,7 @@ NukiNetwork* network = nullptr; WebCfgServer* webCfgServer = nullptr; WebCfgServer* webCfgServerSSL = nullptr; Preferences* preferences = nullptr; +ImportExport* importExport = nullptr; RTC_NOINIT_ATTR int espRunning; RTC_NOINIT_ATTR int restartReason; @@ -163,9 +166,9 @@ void setReroute() uint8_t checkPartition() { const esp_partition_t* running_partition = esp_ota_get_running_partition(); - Log->print(("Partition size: ")); + Log->print("Partition size: "); Log->println(running_partition->size); - Log->print(("Partition subtype: ")); + Log->print("Partition subtype: "); Log->println(running_partition->subtype); if(running_partition->size == 1966080) @@ -203,7 +206,7 @@ void networkTask(void *pvParameters) if(bootloopCounter > 0) { bootloopCounter = (int8_t)0; - Log->println(("Bootloop counter reset")); + Log->println("Bootloop counter reset"); } } @@ -339,12 +342,12 @@ void bootloopDetection() esp_reset_reason() == esp_reset_reason_t::ESP_RST_WDT) { bootloopCounter++; - Log->print(("Bootloop counter incremented: ")); + Log->print("Bootloop counter incremented: "); Log->println(bootloopCounter); if(bootloopCounter == 10) { - Log->print(("Bootloop detected.")); + Log->print("Bootloop detected."); preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE); preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE); @@ -440,7 +443,7 @@ void otaTask(void *pvParameter) { .http_config = &config, }; - Log->print(("Attempting to download update from ")); + Log->print("Attempting to download update from "); Log->println(config.url); int retryMax = 3; @@ -649,9 +652,9 @@ void setup() } #ifdef NUKI_HUB_UPDATER - Log->print(("Nuki Hub OTA version ")); + Log->print("Nuki Hub OTA version "); Log->println(NUKI_HUB_VERSION); - Log->print(("Nuki Hub OTA build ")); + Log->print("Nuki Hub OTA build "); Log->println(); if(preferences->getString(preference_updater_version, "") != NUKI_HUB_VERSION) @@ -666,6 +669,8 @@ void setup() { preferences->putString(preference_updater_date, NUKI_HUB_DATE); } + + importExport = new ImportExport(preferences); network = new NukiNetwork(preferences); network->initialize(); @@ -735,7 +740,7 @@ void setup() psychicSSLServer->ssl_config.httpd.max_open_sockets = 8; psychicSSLServer->setCertificate(cert, key); psychicSSLServer->config.stack_size = HTTPD_TASK_SIZE; - webCfgServerSSL = new WebCfgServer(network, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicSSLServer); + webCfgServerSSL = new WebCfgServer(network, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicSSLServer, importExport); webCfgServerSSL->initialize(); psychicSSLServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) { return response->redirect("/"); @@ -751,7 +756,7 @@ void setup() #endif psychicServer = new PsychicHttpServer; psychicServer->config.stack_size = HTTPD_TASK_SIZE; - webCfgServer = new WebCfgServer(network, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer); + webCfgServer = new WebCfgServer(network, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer, importExport); webCfgServer->initialize(); psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) { return response->redirect("/"); @@ -767,9 +772,9 @@ void setup() bootloopDetection(); } - Log->print(("Nuki Hub version ")); + Log->print("Nuki Hub version "); Log->println(NUKI_HUB_VERSION); - Log->print(("Nuki Hub build ")); + Log->print("Nuki Hub build "); Log->println(NUKI_HUB_BUILD); uint32_t devIdOpener = preferences->getUInt(preference_device_id_opener); @@ -791,8 +796,10 @@ void setup() Log->print(gpioDesc.c_str()); const String mqttLockPath = preferences->getString(preference_mqtt_lock_path); + + importExport = new ImportExport(preferences); - network = new NukiNetwork(preferences, gpio, mqttLockPath, CharBuffer::get(), buffer_size); + network = new NukiNetwork(preferences, gpio, mqttLockPath, CharBuffer::get(), buffer_size, importExport); network->initialize(); lockEnabled = preferences->getBool(preference_lock_enabled); @@ -826,7 +833,7 @@ void setup() networkLock->initialize(); } - nuki = new NukiWrapper("NukiHub", deviceIdLock, bleScanner, networkLock, nukiOfficial, gpio, preferences); + nuki = new NukiWrapper("NukiHub", deviceIdLock, bleScanner, networkLock, nukiOfficial, gpio, preferences, CharBuffer::get(), buffer_size); nuki->initialize(); } @@ -840,7 +847,7 @@ void setup() networkOpener->initialize(); } - nukiOpener = new NukiOpenerWrapper("NukiHub", deviceIdOpener, bleScanner, networkOpener, gpio, preferences); + nukiOpener = new NukiOpenerWrapper("NukiHub", deviceIdOpener, bleScanner, networkOpener, gpio, preferences, CharBuffer::get(), buffer_size); nukiOpener->initialize(); } @@ -911,7 +918,7 @@ void setup() psychicSSLServer->ssl_config.httpd.max_open_sockets = 8; psychicSSLServer->setCertificate(cert, key); psychicSSLServer->config.stack_size = HTTPD_TASK_SIZE; - webCfgServerSSL = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicSSLServer); + webCfgServerSSL = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicSSLServer, importExport); webCfgServerSSL->initialize(); psychicSSLServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) { return response->redirect("/"); @@ -927,7 +934,7 @@ void setup() #endif psychicServer = new PsychicHttpServer; psychicServer->config.stack_size = HTTPD_TASK_SIZE; - webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer); + webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer, importExport); webCfgServer->initialize(); psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) { return response->redirect("/"); @@ -949,27 +956,27 @@ void setup() } #endif */ - - String timeserver = preferences->getString(preference_time_server, "pool.ntp.org"); - esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeserver.c_str()); - config.start = false; - config.server_from_dhcp = true; - config.renew_servers_after_new_IP = true; - config.index_of_first_server = 1; - - if (network->networkDeviceType() == NetworkDeviceType::WiFi) - { - config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; - } - else - { - config.ip_event_to_renew = IP_EVENT_ETH_GOT_IP; - } - config.sync_cb = cbSyncTime; - esp_netif_sntp_init(&config); } #endif + String timeserver = preferences->getString(preference_time_server, "pool.ntp.org"); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeserver.c_str()); + config.start = false; + config.server_from_dhcp = true; + config.renew_servers_after_new_IP = true; + config.index_of_first_server = 1; + + if (network->networkDeviceType() == NetworkDeviceType::WiFi) + { + config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; + } + else + { + config.ip_event_to_renew = IP_EVENT_ETH_GOT_IP; + } + config.sync_cb = cbSyncTime; + esp_netif_sntp_init(&config); + if(doOta) { setupTasks(true); diff --git a/src/networkDevices/EthernetDevice.cpp b/src/networkDevices/EthernetDevice.cpp index 8be245f..f3ef974 100644 --- a/src/networkDevices/EthernetDevice.cpp +++ b/src/networkDevices/EthernetDevice.cpp @@ -72,7 +72,7 @@ void EthernetDevice::initialize() if(ethCriticalFailure) { ethCriticalFailure = false; - Log->println(("Failed to initialize ethernet hardware")); + Log->println("Failed to initialize ethernet hardware"); Log->println("Network device has a critical failure, enable fallback to Wi-Fi and reboot."); wifiFallback = true; delay(200); @@ -80,11 +80,11 @@ void EthernetDevice::initialize() return; } - Log->println(("Init Ethernet")); + Log->println("Init Ethernet"); if(_useSpi) { - Log->println(("Use SPI")); + Log->println("Use SPI"); ethCriticalFailure = true; SPI.begin(_spi_sck, _spi_miso, _spi_mosi); _hardwareInitialized = ETH.begin(_type, _phy_addr, _cs, _irq, _rst, SPI); @@ -93,7 +93,7 @@ void EthernetDevice::initialize() #ifdef CONFIG_IDF_TARGET_ESP32 else { - Log->println(("Use RMII")); + Log->println("Use RMII"); // Workaround for failing RMII initialization with pioarduino 3.1.0 // Revoke all GPIO's some of them set by init PSRAM in IDF @@ -118,7 +118,7 @@ void EthernetDevice::initialize() if(_hardwareInitialized) { - Log->println(("Ethernet hardware Initialized")); + Log->println("Ethernet hardware Initialized"); wifiFallback = false; if(_useSpi && !_ipConfiguration->dhcpEnabled()) @@ -133,7 +133,7 @@ void EthernetDevice::initialize() } else { - Log->println(("Failed to initialize ethernet hardware")); + Log->println("Failed to initialize ethernet hardware"); Log->println("Network device has a critical failure, enable fallback to Wi-Fi and reboot."); wifiFallback = true; delay(200); @@ -150,7 +150,7 @@ void EthernetDevice::update() { if(_ipConfiguration->ipAddress() != ETH.localIP()) { - Log->println(("ETH Set static IP")); + Log->println("ETH Set static IP"); ETH.config(_ipConfiguration->ipAddress(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet(), _ipConfiguration->dnsServer()); _checkIpTs = espMillis() + 5000; return; diff --git a/src/networkDevices/IPConfiguration.cpp b/src/networkDevices/IPConfiguration.cpp index 3dc5423..9dc9df0 100644 --- a/src/networkDevices/IPConfiguration.cpp +++ b/src/networkDevices/IPConfiguration.cpp @@ -16,20 +16,20 @@ IPConfiguration::IPConfiguration(Preferences *preferences) _gateway.fromString(_preferences->getString(preference_ip_gateway, "")); _dnsServer.fromString(_preferences->getString(preference_ip_dns_server, "")); - Log->print(("IP configuration: ")); + Log->print("IP configuration: "); if(dhcpEnabled()) { - Log->println(("DHCP")); + Log->println("DHCP"); } else { - Log->print(("IP address: ")); + Log->print("IP address: "); Log->print(ipAddress()); - Log->print((", Subnet: ")); + Log->print(", Subnet: "); Log->print(subnet()); - Log->print((", Gateway: ")); + Log->print(", Gateway: "); Log->print(defaultGateway()); - Log->print((", DNS: ")); + Log->print(", DNS: "); Log->println(dnsServer()); } } diff --git a/src/networkDevices/NetworkDevice.cpp b/src/networkDevices/NetworkDevice.cpp index ebd70b0..b921d71 100644 --- a/src/networkDevices/NetworkDevice.cpp +++ b/src/networkDevices/NetworkDevice.cpp @@ -32,7 +32,7 @@ void NetworkDevice::init() if(ca_cert.length() > 1) { _useEncryption = true; - Log->println(("MQTT over TLS.")); + Log->println("MQTT over TLS."); _mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO); _mqttClientSecure->setCACert(caDest); @@ -57,7 +57,7 @@ void NetworkDevice::init() if(cert.length() > 1 && key.length() > 1) { - Log->println(("MQTT with client certificate.")); + Log->println("MQTT with client certificate."); _mqttClientSecure->setCertificate(certDest); _mqttClientSecure->setPrivateKey(keyDest); } @@ -69,7 +69,7 @@ void NetworkDevice::init() if (!_useEncryption) { - Log->println(("MQTT without TLS.")); + Log->println("MQTT without TLS."); _mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO); } @@ -251,6 +251,11 @@ void NetworkDevice::mqttDisable() _mqttEnabled = false; } +bool NetworkDevice::isEncrypted() +{ + return _useEncryption; +} + MqttClient *NetworkDevice::getMqttClient() const { if (_useEncryption) diff --git a/src/networkDevices/NetworkDevice.h b/src/networkDevices/NetworkDevice.h index d2d19a3..667bf64 100644 --- a/src/networkDevices/NetworkDevice.h +++ b/src/networkDevices/NetworkDevice.h @@ -29,6 +29,7 @@ public: virtual String BSSIDstr() = 0; #ifndef NUKI_HUB_UPDATER + virtual bool isEncrypted(); virtual bool mqttConnect(); virtual bool mqttDisconnect(bool force); virtual void mqttDisable(); diff --git a/src/util/NetworkUtil.cpp b/src/util/NetworkUtil.cpp index eef08af..50308a5 100644 --- a/src/util/NetworkUtil.cpp +++ b/src/util/NetworkUtil.cpp @@ -50,7 +50,7 @@ NetworkDeviceType NetworkUtil::GetDeviceTypeFromPreference(int hardwareDetect, i return NetworkDeviceType::LilyGO_T_ETH_ELite; break; default: - Log->println(("Unknown hardware selected, falling back to Wi-Fi.")); + Log->println("Unknown hardware selected, falling back to Wi-Fi."); return NetworkDeviceType::WiFi; break; } diff --git a/updater/src/CMakeLists.txt b/updater/src/CMakeLists.txt index b418139..d317a2b 100644 --- a/updater/src/CMakeLists.txt +++ b/updater/src/CMakeLists.txt @@ -6,10 +6,12 @@ list(APPEND app_sources ../../src/PreferencesKeys.h) list(APPEND app_sources ../../src/RestartReason.h) list(APPEND app_sources ../../src/WebCfgServer.h) list(APPEND app_sources ../../src/WebCfgServerConstants.h) +list(APPEND app_sources ../../src/ImportExport.h) list(APPEND app_sources ../../src/Logger.cpp) list(APPEND app_sources ../../src/NukiNetwork.cpp) list(APPEND app_sources ../../src/WebCfgServer.cpp) +list(APPEND app_sources ../../src/ImportExport.cpp) list(APPEND app_sources ../../src/enums/NetworkDeviceType.h) list(APPEND app_sources ../../src/networkDevices/EthernetDevice.h)
    SettingEnabled