From 9d7cd00d2dcdf4d58d4f0628c1be687a3781be17 Mon Sep 17 00:00:00 2001 From: iranl Date: Sat, 4 Jan 2025 21:24:12 +0100 Subject: [PATCH 1/6] -Implement BLE retry after failed hybrid lockaction --- src/NukiWrapper.cpp | 7 +++++-- src/WebCfgServer.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 3ab67ce..8d82ac4 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -1091,8 +1091,11 @@ LockActionResult NukiWrapper::onLockActionReceived(const char *value) { if(_preferences->getBool(preference_official_hybrid_actions, false)) { - _nukiOfficial->setOffCommandExecutedTs(espMillis() + 2000); - _offCommand = action; + if(_preferences->getBool(preference_official_hybrid_retry, false)) + { + _nukiOfficial->setOffCommandExecutedTs(espMillis() + 2000); + _offCommand = action; + } _network->publishOffAction((int)action); } else diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 1746de4..370ee28 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -4042,7 +4042,7 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request, PsychicResp printCheckBox(&response, "OFFHYBRID", "Enable hybrid official MQTT and Nuki Hub setup", _preferences->getBool(preference_official_hybrid_enabled), ""); printCheckBox(&response, "HYBRIDACT", "Enable sending actions through official MQTT", _preferences->getBool(preference_official_hybrid_actions), ""); printInputField(&response, "HYBRIDTIMER", "Time between status updates when official MQTT is offline (seconds)", _preferences->getInt(preference_query_interval_hybrid_lockstate), 5, ""); - // printCheckBox(&response, "HYBRIDRETRY", "Retry command sent using official MQTT over BLE if failed", _preferences->getBool(preference_official_hybrid_retry), ""); // NOT IMPLEMENTED (YET?) + printCheckBox(&response, "HYBRIDRETRY", "Retry command sent using official MQTT over BLE if failed", _preferences->getBool(preference_official_hybrid_retry), ""); response.print(""); response.print("* If no encryption is configured for the MQTT broker, leave empty.

"); response.print("
"); From 4c8f9c65b1495d0d93e4b97c97f992e691486490 Mon Sep 17 00:00:00 2001 From: iranl Date: Sat, 4 Jan 2025 22:01:23 +0100 Subject: [PATCH 2/6] Auth Name and Context --- lib/nuki_ble | 2 +- src/Config.h | 2 +- src/MqttTopics.h | 1 + src/NukiNetworkLock.cpp | 26 ++++++++------ src/NukiNetworkLock.h | 1 + src/NukiNetworkOpener.cpp | 9 ++--- src/NukiOfficial.cpp | 72 +++++++++++++++++++++++++++++++++++---- src/NukiOfficial.h | 3 +- src/PreferencesKeys.h | 2 +- 9 files changed, 89 insertions(+), 29 deletions(-) diff --git a/lib/nuki_ble b/lib/nuki_ble index 84865a9..ebcd364 160000 --- a/lib/nuki_ble +++ b/lib/nuki_ble @@ -1 +1 @@ -Subproject commit 84865a9eedcdb9971a1414ea9338ad6ded13a028 +Subproject commit ebcd364046b0a0bc44dc6ef9e96c2a352f086167 diff --git a/src/Config.h b/src/Config.h index 4eb4a51..37f5d96 100644 --- a/src/Config.h +++ b/src/Config.h @@ -5,7 +5,7 @@ #define NUKI_HUB_VERSION "9.07" #define NUKI_HUB_VERSION_INT (uint32_t)907 #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2025-01-04" +#define NUKI_HUB_DATE "2025-01-05" #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/MqttTopics.h b/src/MqttTopics.h index 040d65a..ef8f5de 100644 --- a/src/MqttTopics.h +++ b/src/MqttTopics.h @@ -12,6 +12,7 @@ #define mqtt_topic_lock_binary_ring (char*)"/binaryRing" #define mqtt_topic_lock_trigger (char*)"/trigger" #define mqtt_topic_lock_last_lock_action (char*)"/lastLockAction" +#define mqtt_topic_lock_lock_action_context (char*)"/lockActionContext" #define mqtt_topic_lock_log (char*)"/log" #define mqtt_topic_lock_log_latest (char*)"/shortLog" #define mqtt_topic_lock_log_rolling (char*)"/rollingLog" diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp index 1e091e2..5347f40 100644 --- a/src/NukiNetworkLock.cpp +++ b/src/NukiNetworkLock.cpp @@ -142,12 +142,6 @@ void NukiNetworkLock::initialize() { _network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last); } -/* - _network->addReconnectedCallback([&]() - { - _reconnected = true; - }); -*/ } void NukiNetworkLock::update() @@ -496,7 +490,7 @@ void NukiNetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyT } json["auth_id"] = getAuthId(); - json["auth_name"] = _authName; + json["auth_name"] = getAuthName(); serializeJson(json, _buffer, _bufferSize); _nukiPublisher->publishString(mqtt_topic_lock_json, _buffer, true); @@ -697,10 +691,10 @@ void NukiNetworkLock::publishAuthorizationInfo(const std::listpublishString(mqtt_topic_lock_log, _buffer, true); } - if(authIndex > 0) + if(authIndex > 0 || (_nukiOfficial->getOffConnected() && _nukiOfficial->hasAuthId())) { _nukiPublisher->publishUInt(mqtt_topic_lock_auth_id, getAuthId(), true); - _nukiPublisher->publishString(mqtt_topic_lock_auth_name, _authName, true); + _nukiPublisher->publishString(mqtt_topic_lock_auth_name, getAuthName(), true); } } @@ -911,6 +905,7 @@ void NukiNetworkLock::publishKeypad(const std::list& entr } jsonEntry["enabled"] = entry.enabled; jsonEntry["name"] = entry.name; + _authEntries[jsonEntry["codeId"]] = jsonEntry["name"].as(); char createdDT[20]; sprintf(createdDT, "%04d-%02d-%02d %02d:%02d:%02d", entry.dateCreatedYear, entry.dateCreatedMonth, entry.dateCreatedDay, entry.dateCreatedHour, entry.dateCreatedMin, entry.dateCreatedSec); jsonEntry["dateCreated"] = createdDT; @@ -1276,7 +1271,7 @@ void NukiNetworkLock::publishAuth(const std::list& auto jsonEntry = json.add(); jsonEntry["authId"] = entry.authId; - jsonEntry["idType"] = entry.idType; //CONSIDER INT TO STRING + jsonEntry["idType"] = entry.idType; jsonEntry["enabled"] = entry.enabled; jsonEntry["name"] = entry.name; _authEntries[jsonEntry["authId"]] = jsonEntry["name"].as(); @@ -1627,9 +1622,18 @@ void NukiNetworkLock::fobActionToString(const int fobact, char* str) const uint32_t NukiNetworkLock::getAuthId() const { - if(_nukiOfficial->hasAuthId()) + if(_nukiOfficial->getOffConnected() && _nukiOfficial->hasAuthId()) { return _nukiOfficial->getAuthId(); } return _authId; } + +const char* NukiNetworkLock::getAuthName() +{ + if(_nukiOfficial->getOffConnected() && _nukiOfficial->hasAuthId()) + { + return _authEntries[getAuthId()].c_str(); + } + return _authName; +} \ No newline at end of file diff --git a/src/NukiNetworkLock.h b/src/NukiNetworkLock.h index 2c84b42..96a136a 100644 --- a/src/NukiNetworkLock.h +++ b/src/NukiNetworkLock.h @@ -59,6 +59,7 @@ public: void setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad); const uint32_t getAuthId() const; + const char* getAuthName(); int mqttConnectionState(); uint8_t queryCommands(); diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp index c44f492..b13a39d 100644 --- a/src/NukiNetworkOpener.cpp +++ b/src/NukiNetworkOpener.cpp @@ -116,12 +116,6 @@ void NukiNetworkOpener::initialize() { _network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last); } -/* - _network->addReconnectedCallback([&]() - { - _reconnected = true; - }); -*/ } void NukiNetworkOpener::update() @@ -886,6 +880,7 @@ void NukiNetworkOpener::publishKeypad(const std::list& en } jsonEntry["enabled"] = entry.enabled; jsonEntry["name"] = entry.name; + _authEntries[jsonEntry["codeId"]] = jsonEntry["name"].as(); char createdDT[20]; sprintf(createdDT, "%04d-%02d-%02d %02d:%02d:%02d", entry.dateCreatedYear, entry.dateCreatedMonth, entry.dateCreatedDay, entry.dateCreatedHour, entry.dateCreatedMin, entry.dateCreatedSec); jsonEntry["dateCreated"] = createdDT; @@ -1218,7 +1213,7 @@ void NukiNetworkOpener::publishAuth(const std::list(); jsonEntry["authId"] = entry.authId; - jsonEntry["idType"] = entry.idType; //CONSIDER INT TO STRING + jsonEntry["idType"] = entry.idType; jsonEntry["enabled"] = entry.enabled; jsonEntry["name"] = entry.name; _authEntries[jsonEntry["authId"]] = jsonEntry["name"].as(); diff --git a/src/NukiOfficial.cpp b/src/NukiOfficial.cpp index d1bd966..469aded 100644 --- a/src/NukiOfficial.cpp +++ b/src/NukiOfficial.cpp @@ -6,7 +6,6 @@ #include #include - NukiOfficial::NukiOfficial(Preferences *preferences) { offEnabled = preferences->getBool(preference_official_hybrid_enabled, false); @@ -197,6 +196,7 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value } else if(strcmp(topic, mqtt_topic_official_lockActionEvent) == 0) { + clearAuthId(); clearOffCommandExecutedTs(); offLockActionEvent = (char*)value; String LockActionEvent = offLockActionEvent; @@ -210,7 +210,7 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value offTrigger = atoi(LockActionEvent.substring(ind1 + 1, ind2 + 1).c_str()); offAuthId = atoi(LockActionEvent.substring(ind2 + 1, ind3 + 1).c_str()); offCodeId = atoi(LockActionEvent.substring(ind3 + 1, ind4 + 1).c_str()); -// offContext = atoi(LockActionEvent.substring(ind4 + 1, ind5 + 1).c_str()); + offContext = atoi(LockActionEvent.substring(ind4 + 1, ind5 + 1).c_str()); memset(&str, 0, sizeof(str)); lockactionToString((NukiLock::LockAction)offLockAction, str); @@ -225,17 +225,69 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value if(offCodeId > 0) { _authId = offCodeId; + + switch(offContext) + { + case 0: + _publisher->publishString(mqtt_topic_lock_lock_action_context, "keypadBackKey", true); + break; + case 1: + _publisher->publishString(mqtt_topic_lock_lock_action_context, "keypadCode", true); + break; + case 2: + _publisher->publishString(mqtt_topic_lock_lock_action_context, "keypadFingerprint", true); + break; + default: + _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); + break; + } } else { _authId = offAuthId; + + switch(offTrigger) + { + case 0: + if (offContext == 1) + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, "autoUnlock", true); + } + else + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); + } + break; + case 2: + if (offContext > 0) + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, String("button") + String(offContext) + "press", true); + } + else + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); + } + break; + case 3: + if (offContext > 0) + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, String("fob") + String(offContext) + "press", true); + } + else + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); + } + break; + default: + _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); + break; + } } _hasAuthId = true; - - /* - _network->_authName = RETRIEVE FROM VECTOR AFTER AUTHORIZATION ENTRIES ARE IMPLEMENTED; - _offContext = BASE ON CONTEXT OF TRIGGER AND PUBLISH TO MQTT; - */ + } + else + { + _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); } } @@ -285,6 +337,7 @@ const bool NukiOfficial::hasAuthId() const void NukiOfficial::clearAuthId() { _hasAuthId = false; + _authId = 0; } const bool NukiOfficial::getOffConnected() const @@ -317,6 +370,11 @@ const uint8_t NukiOfficial::getOffTrigger() const return offTrigger; } +const uint8_t NukiOfficial::getOffContext() const +{ + return offContext; +} + const int64_t NukiOfficial::getOffCommandExecutedTs() const { return offCommandExecutedTs; diff --git a/src/NukiOfficial.h b/src/NukiOfficial.h index 17383c3..1d8c048 100644 --- a/src/NukiOfficial.h +++ b/src/NukiOfficial.h @@ -34,6 +34,7 @@ public: const uint8_t getOffState() const; const uint8_t getOffLockAction() const; const uint8_t getOffTrigger() const; + const uint8_t getOffContext() const; const std::vector getOffTopics() const; const int64_t getOffCommandExecutedTs() const; @@ -69,7 +70,7 @@ private: uint8_t offTrigger = 0; uint32_t offAuthId = 0; uint32_t offCodeId = 0; - //uint8_t offContext = 0; + uint8_t offContext = 0; bool offEnabled = false; }; diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index 2996690..cfb50d6 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -83,7 +83,7 @@ #define preference_authlog_max_entries (char*)"authmaxentry" #define preference_keypad_max_entries (char*)"kpmaxentry" #define preference_timecontrol_max_entries (char*)"tcmaxentry" -#define preference_register_as_app (char*)"regAsApp" // true = register as hub; false = register as app +#define preference_register_as_app (char*)"regAsApp" #define preference_register_opener_as_app (char*)"regOpnAsApp" #define preference_acl (char*)"aclLckOpn" #define preference_conf_lock_basic_acl (char*)"confLckBasAcl" From 00c96831cdf9110e8dab84d08c86ec2fa91c827c Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 5 Jan 2025 11:00:15 +0100 Subject: [PATCH 3/6] Add device type and update time setting to info page --- src/WebCfgServer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 370ee28..c971866 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -4763,6 +4763,8 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse* buildHtmlHeader(&response); response.print("

System Information

");
     response.print("------------ NUKI HUB ------------");
+    response.print("\nDevice: ");
+    response.print(NUKI_HUB_HW);
     response.print("\nVersion: ");
     response.print(NUKI_HUB_VERSION);
     response.print("\nBuild: ");
@@ -4827,6 +4829,8 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse*
     response.print(_preferences->getString(preference_latest_version, ""));
     response.print("\nAllow update from MQTT: ");
     response.print(_preferences->getBool(preference_update_from_mqtt, false) ? "Yes" : "No");
+    response.print("\nUpdate NukiHub and Nuki devices time using NTP: ");
+    response.print(_preferences->getBool(preference_update_time, false) ? "Yes" : "No");
     response.print("\nWeb configurator username: ");
     response.print(_preferences->getString(preference_cred_user, "").length() > 0 ? "***" : "Not set");
     response.print("\nWeb configurator password: ");

From 850f7fcc8a3b33a928e197d895f9aca4ccad24b2 Mon Sep 17 00:00:00 2001
From: iranl 
Date: Sun, 5 Jan 2025 11:48:24 +0100
Subject: [PATCH 4/6] Clear MQTT topics on boot

---
 src/NukiNetwork.cpp       |  3 +++
 src/NukiNetworkLock.cpp   | 20 ++++++++++++++++----
 src/NukiNetworkOpener.cpp | 19 +++++++++++++++----
 3 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp
index dbbb7c3..4fc2ae1 100644
--- a/src/NukiNetwork.cpp
+++ b/src/NukiNetwork.cpp
@@ -757,6 +757,9 @@ bool NukiNetwork::reconnect()
 
                 initTopic(_maintenancePathPrefix, mqtt_topic_reset, "0");
                 subscribe(_maintenancePathPrefix, mqtt_topic_reset);
+                initTopic(_maintenancePathPrefix, mqtt_topic_freeheap, "");
+                initTopic(_maintenancePathPrefix, mqtt_topic_log, "");
+                initTopic(_maintenancePathPrefix, mqtt_topic_wifi_rssi, "");
 
                 if(_preferences->getBool(preference_update_from_mqtt, false))
                 {
diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp
index 5347f40..6229d6a 100644
--- a/src/NukiNetworkLock.cpp
+++ b/src/NukiNetworkLock.cpp
@@ -51,6 +51,7 @@ void NukiNetworkLock::initialize()
     _network->initTopic(_mqttPath, mqtt_topic_config_action, "--");
     _network->subscribe(_mqttPath, mqtt_topic_config_action);
 
+    _network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
     _network->initTopic(_mqttPath, mqtt_topic_query_config, "0");
     _network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0");
     _network->initTopic(_mqttPath, mqtt_topic_query_battery, "0");
@@ -58,6 +59,21 @@ void NukiNetworkLock::initialize()
     _network->subscribe(_mqttPath, mqtt_topic_query_lockstate);
     _network->subscribe(_mqttPath, mqtt_topic_query_battery);
 
+    _network->initTopic(_mqttPath, mqtt_topic_auth_action, "--");
+    _network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
+    _network->initTopic(_mqttPath, mqtt_topic_keypad_json_action, "--");
+    _network->initTopic(_mqttPath, mqtt_topic_lock_retry, "0");
+
+    _network->removeTopic(_mqttPath, mqtt_topic_hybrid_state);
+    _network->removeTopic(_mqttPath, mqtt_topic_config_action_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_keypad_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_keypad_json_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_timecontrol_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_auth_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_query_lockstate_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_lock_completionStatus);
+    _network->removeTopic(_mqttPath, mqtt_topic_lock_action_command_result);
+
     if(_disableNonJSON)
     {
         _network->removeTopic(_mqttPath, mqtt_topic_keypad_command_action);
@@ -110,21 +126,17 @@ void NukiNetworkLock::initialize()
             _network->subscribe(_mqttPath, mqtt_topic_keypad_command_enabled);
         }
 
-        _network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
-        _network->initTopic(_mqttPath, mqtt_topic_keypad_json_action, "--");
         _network->subscribe(_mqttPath, mqtt_topic_query_keypad);
         _network->subscribe(_mqttPath, mqtt_topic_keypad_json_action);
     }
 
     if(_preferences->getBool(preference_timecontrol_control_enabled))
     {
-        _network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
         _network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
     }
 
     if(_preferences->getBool(preference_auth_control_enabled))
     {
-        _network->initTopic(_mqttPath, mqtt_topic_auth_action, "--");
         _network->subscribe(_mqttPath, mqtt_topic_auth_action);
     }
 
diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp
index b13a39d..01cbff3 100644
--- a/src/NukiNetworkOpener.cpp
+++ b/src/NukiNetworkOpener.cpp
@@ -39,6 +39,7 @@ void NukiNetworkOpener::initialize()
     _network->initTopic(_mqttPath, mqtt_topic_config_action, "--");
     _network->subscribe(_mqttPath, mqtt_topic_config_action);
 
+    _network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
     _network->initTopic(_mqttPath, mqtt_topic_query_config, "0");
     _network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0");
     _network->initTopic(_mqttPath, mqtt_topic_query_battery, "0");
@@ -47,6 +48,20 @@ void NukiNetworkOpener::initialize()
     _network->subscribe(_mqttPath, mqtt_topic_query_config);
     _network->subscribe(_mqttPath, mqtt_topic_query_lockstate);
     _network->subscribe(_mqttPath, mqtt_topic_query_battery);
+    
+    _network->initTopic(_mqttPath, mqtt_topic_keypad_json_action, "--");
+    _network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
+    _network->initTopic(_mqttPath, mqtt_topic_auth_action, "--");
+    _network->initTopic(_mqttPath, mqtt_topic_lock_retry, "0");
+
+    _network->removeTopic(_mqttPath, mqtt_topic_config_action_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_keypad_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_keypad_json_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_timecontrol_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_auth_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_query_lockstate_command_result);
+    _network->removeTopic(_mqttPath, mqtt_topic_lock_completionStatus);
+    _network->removeTopic(_mqttPath, mqtt_topic_lock_action_command_result);
 
     if(_disableNonJSON)
     {
@@ -94,21 +109,17 @@ void NukiNetworkOpener::initialize()
             _network->subscribe(_mqttPath, mqtt_topic_keypad_command_enabled);
         }
 
-        _network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
-        _network->initTopic(_mqttPath, mqtt_topic_keypad_json_action, "--");
         _network->subscribe(_mqttPath, mqtt_topic_query_keypad);
         _network->subscribe(_mqttPath, mqtt_topic_keypad_json_action);
     }
 
     if(_preferences->getBool(preference_timecontrol_control_enabled, false))
     {
-        _network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
         _network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
     }
 
     if(_preferences->getBool(preference_auth_control_enabled))
     {
-        _network->initTopic(_mqttPath, mqtt_topic_auth_action, "--");
         _network->subscribe(_mqttPath, mqtt_topic_auth_action);
     }
 

From dbb58caf977ac73f5b8ac27d14fc495b0d24c702 Mon Sep 17 00:00:00 2001
From: iranl 
Date: Sun, 5 Jan 2025 12:50:20 +0100
Subject: [PATCH 5/6] Reboot lock on Hybrid failure and logging fix

---
 README.md                              |   2 +
 src/Gpio.cpp                           |  14 +-
 src/NukiNetwork.cpp                    |  95 ++++-----
 src/NukiNetwork.h                      |   1 +
 src/NukiNetworkLock.cpp                |  26 ++-
 src/NukiNetworkLock.h                  |   5 +-
 src/NukiNetworkOpener.cpp              |   6 +-
 src/NukiOfficial.cpp                   |  20 +-
 src/NukiOpenerWrapper.cpp              | 118 ++++++------
 src/NukiWrapper.cpp                    | 124 ++++++------
 src/NukiWrapper.h                      |   2 +-
 src/PreferencesKeys.h                  |   7 +-
 src/WebCfgServer.cpp                   | 255 +++++++++++++------------
 src/main.cpp                           |  28 +--
 src/networkDevices/EthernetDevice.cpp  |  14 +-
 src/networkDevices/IPConfiguration.cpp |  12 +-
 src/networkDevices/NetworkDevice.cpp   |   6 +-
 src/networkDevices/WifiDevice.cpp      |   6 +-
 src/util/NetworkUtil.cpp               |   2 +-
 19 files changed, 400 insertions(+), 343 deletions(-)

diff --git a/README.md b/README.md
index dbf0341..6b73fb4 100644
--- a/README.md
+++ b/README.md
@@ -244,6 +244,8 @@ In a browser navigate to the IP address assigned to the ESP32.
 - Enable hybrid official MQTT and Nuki Hub setup: Enable to combine the official MQTT over Thread/Wi-Fi with BLE. Improves speed of state changes. Needs the official MQTT to be setup first. Also requires Nuki Hub to be paired as app and unregistered as a bridge using the Nuki app. See [hybrid mode](/HYBRID.md)
 - Enable sending actions through official MQTT: Enable to sent lock actions through the official MQTT topics (e.g. over Thread/Wi-Fi) instead of using BLE. Needs "Enable hybrid official MQTT and Nuki Hub setup" to be enabled. See [hybrid mode](/HYBRID.md)
 - Time between status updates when official MQTT is offline (seconds): Set to a positive integer to set the maximum amount of seconds between actively querying the Nuki lock for the current lock state when the official MQTT is offline, default 600.
+- Retry command sent using official MQTT over BLE if failed: Enable to publish lock commands over BLE if NukiHub fails to use Hybrid mode to execute the command over MQTT
+- Reboot Nuki lock on official MQTT failure: Enable to reboot the Nuki Lock if official MQTT over WiFi/Thread is offline for more than 180 seconds
 
 ### Nuki Configuration
 
diff --git a/src/Gpio.cpp b/src/Gpio.cpp
index 8bf9f9e..3c109c6 100644
--- a/src/Gpio.cpp
+++ b/src/Gpio.cpp
@@ -216,7 +216,7 @@ void Gpio::loadPinConfiguration()
     {
         PinEntry entry;
         entry.pin = serialized[i * 2];
-        Log->print(F("Pin "));
+        Log->print(("Pin "));
         Log->println(entry.pin);
 
         if(std::find(disabledPins.begin(), disabledPins.end(), entry.pin) == disabledPins.end())
@@ -227,14 +227,14 @@ void Gpio::loadPinConfiguration()
             }
             entry.role = (PinRole) serialized[(i * 2 + 1)];
             Log->println("Not found in Ethernet disabled pins");
-            Log->print(F("Role: "));
+            Log->print(("Role: "));
             Log->println(getRoleDescription(entry.role));
         }
         else
         {
             entry.role = PinRole::Ethernet;
             Log->println("Found in Ethernet disabled pins");
-            Log->print(F("Role: "));
+            Log->print(("Role: "));
             Log->println(getRoleDescription(entry.role));
         }
         if(entry.role != PinRole::Disabled)
@@ -331,7 +331,7 @@ const  std::vector Gpio::getDisabledPins() const
         break;
     }
 
-    Log->print(F("GPIO Ethernet disabled pins:"));
+    Log->print(("GPIO Ethernet disabled pins:"));
     for_each_n(disabledPins.begin(), disabledPins.size(),
                [](int x)
     {
@@ -354,7 +354,7 @@ void Gpio::savePinConfiguration(const std::vector &pinConfiguration)
     for(int i=0; i < len; i++)
     {
         const auto& entry = pinConfiguration[i];
-        Log->print(F("Pin "));
+        Log->print(("Pin "));
         Log->println(entry.pin);
 
         if(std::find(disabledPins.begin(), disabledPins.end(), entry.pin) != disabledPins.end())
@@ -362,7 +362,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(F("Role: "));
+            Log->print(("Role: "));
             Log->println(getRoleDescription(PinRole::Ethernet));
 
         }
@@ -373,7 +373,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(F("Role: "));
+                Log->print(("Role: "));
                 Log->println(getRoleDescription(entry.role));
             }
         }
diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp
index 4fc2ae1..317aff8 100644
--- a/src/NukiNetwork.cpp
+++ b/src/NukiNetwork.cpp
@@ -72,7 +72,7 @@ void NukiNetwork::setupDevice()
 {
     _ipConfiguration = new IPConfiguration(_preferences);
     int hardwareDetect = _preferences->getInt(preference_network_hardware, 0);
-    Log->print(F("Hardware detect: "));
+    Log->print(("Hardware detect: "));
     Log->println(hardwareDetect);
 
     _firstBootAfterDeviceChange = _preferences->getBool(preference_ntw_reconfigure, false);
@@ -100,13 +100,13 @@ void NukiNetwork::setupDevice()
 #ifndef CONFIG_IDF_TARGET_ESP32H2
         if(!_firstBootAfterDeviceChange)
         {
-            Log->println(F("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(F("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);
@@ -130,7 +130,7 @@ void NukiNetwork::setupDevice()
 
     _device = NetworkDeviceInstantiator::Create(_networkDeviceType, _hostname, _preferences, _ipConfiguration);
 
-    Log->print(F("Network device: "));
+    Log->print(("Network device: "));
     Log->println(_device->deviceName());
 
 #ifndef NUKI_HUB_UPDATER
@@ -194,6 +194,15 @@ bool NukiNetwork::isConnected()
     return _device->isConnected();
 }
 
+bool NukiNetwork::mqttConnected()
+{
+    #ifndef NUKI_HUB_UPDATER
+    return _device->mqttConnected();
+    #else
+    return false;
+    #endif
+}
+
 bool NukiNetwork::wifiConnected()
 {
     if(_networkDeviceType != NetworkDeviceType::WiFi)
@@ -220,7 +229,7 @@ void NukiNetwork::initialize()
     strcpy(_hostnameArr, _hostname.c_str());
     _device->initialize();
 
-    Log->print(F("Host name: "));
+    Log->print(("Host name: "));
     Log->println(_hostname);
 }
 
@@ -270,7 +279,7 @@ void NukiNetwork::initialize()
         strcpy(_hostnameArr, _hostname.c_str());
         _device->initialize();
 
-        Log->print(F("Host name: "));
+        Log->print(("Host name: "));
         Log->println(_hostname);
 
         String brokerAddr = _preferences->getString(preference_mqtt_broker);
@@ -297,9 +306,9 @@ void NukiNetwork::initialize()
             }
         }
 
-        Log->print(F("MQTT Broker: "));
+        Log->print(("MQTT Broker: "));
         Log->print(_mqttBrokerAddr);
-        Log->print(F(":"));
+        Log->print((":"));
         Log->println(_mqttPort);
 
         _device->mqttSetClientId(_hostnameArr);
@@ -311,7 +320,7 @@ void NukiNetwork::initialize()
 
         if(rebGpio)
         {
-            Log->println(F("Rebuild MQTT GPIO structure"));
+            Log->println(("Rebuild MQTT GPIO structure"));
         }
         for (const auto &pinEntry: _gpio->pinConfiguration())
         {
@@ -413,7 +422,7 @@ bool NukiNetwork::update()
     if(_logIp && _device->isConnected() && !_device->localIP().equals("0.0.0.0"))
     {
         _logIp = false;
-        Log->print(F("IP: "));
+        Log->print(("IP: "));
         Log->println(_device->localIP());
         _firstDisconnected = true;
     }
@@ -576,9 +585,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(F("GPIO "));
+            Log->print(("GPIO "));
             Log->print(pin);
-            Log->print(F(" (Input) --> "));
+            Log->print((" (Input) --> "));
             Log->println(pinState);
         }
     }
@@ -598,31 +607,31 @@ void NukiNetwork::onMqttDisconnect(const espMqttClientTypes::DisconnectReason &r
     switch(reason)
     {
     case espMqttClientTypes::DisconnectReason::USER_OK:
-        Log->println(F("USER_OK"));
+        Log->println(("USER_OK"));
         break;
     case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
-        Log->println(F("MQTT_UNACCEPTABLE_PROTOCOL_VERSION"));
+        Log->println(("MQTT_UNACCEPTABLE_PROTOCOL_VERSION"));
         break;
     case espMqttClientTypes::DisconnectReason::MQTT_IDENTIFIER_REJECTED:
-        Log->println(F("MQTT_IDENTIFIER_REJECTED"));
+        Log->println(("MQTT_IDENTIFIER_REJECTED"));
         break;
     case espMqttClientTypes::DisconnectReason::MQTT_SERVER_UNAVAILABLE:
-        Log->println(F("MQTT_SERVER_UNAVAILABLE"));
+        Log->println(("MQTT_SERVER_UNAVAILABLE"));
         break;
     case espMqttClientTypes::DisconnectReason::MQTT_MALFORMED_CREDENTIALS:
-        Log->println(F("MQTT_MALFORMED_CREDENTIALS"));
+        Log->println(("MQTT_MALFORMED_CREDENTIALS"));
         break;
     case espMqttClientTypes::DisconnectReason::MQTT_NOT_AUTHORIZED:
-        Log->println(F("MQTT_NOT_AUTHORIZED"));
+        Log->println(("MQTT_NOT_AUTHORIZED"));
         break;
     case espMqttClientTypes::DisconnectReason::TLS_BAD_FINGERPRINT:
-        Log->println(F("TLS_BAD_FINGERPRINT"));
+        Log->println(("TLS_BAD_FINGERPRINT"));
         break;
     case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED:
-        Log->println(F("TCP_DISCONNECTED"));
+        Log->println(("TCP_DISCONNECTED"));
         break;
     default:
-        Log->println(F("Unknown"));
+        Log->println(("Unknown"));
         break;
     }
 }
@@ -635,7 +644,7 @@ bool NukiNetwork::reconnect()
     {
         if(strcmp(_mqttBrokerAddr, "") == 0)
         {
-            Log->println(F("MQTT Broker not configured, aborting connection attempt."));
+            Log->println(("MQTT Broker not configured, aborting connection attempt."));
             _nextReconnect = espMillis() + 5000;
             
             if(_device->isConnected())
@@ -645,17 +654,17 @@ bool NukiNetwork::reconnect()
             return false;
         }
 
-        Log->println(F("Attempting MQTT connection"));
+        Log->println(("Attempting MQTT connection"));
 
         _connectReplyReceived = false;
 
         if(strlen(_mqttUser) == 0)
         {
-            Log->println(F("MQTT: Connecting without credentials"));
+            Log->println(("MQTT: Connecting without credentials"));
         }
         else
         {
-            Log->print(F("MQTT: Connecting with user: "));
+            Log->print(("MQTT: Connecting with user: "));
             Log->println(_mqttUser);
             _device->mqttSetCredentials(_mqttUser, _mqttPass);
         }
@@ -678,7 +687,7 @@ bool NukiNetwork::reconnect()
 
         if (_device->mqttConnected())
         {
-            Log->println(F("MQTT connected"));
+            Log->println(("MQTT connected"));
             _mqttConnectedTs = millis();
             _mqttConnectionState = 1;
             delay(100);
@@ -793,7 +802,7 @@ bool NukiNetwork::reconnect()
         }
         else
         {
-            Log->print(F("MQTT connect failed"));
+            Log->print(("MQTT connect failed"));
             _mqttConnectionState = 0;
             _nextReconnect = espMillis() + 5000;
             //_device->mqttDisconnect(true);
@@ -912,14 +921,14 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
 
     if(comparePrefixedPath(topic, mqtt_topic_reset) && strcmp(data, "1") == 0 && !mqttRecentlyConnected())
     {
-        Log->println(F("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))
     {
-        Log->println(F("Update requested via MQTT."));
+        Log->println(("Update requested via MQTT."));
 
         bool otaManifestSuccess = false;
         JsonDocument doc;
@@ -960,13 +969,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(F("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(F("Updating to latest release version."));
+                    Log->println(("Updating to latest release version."));
                     delay(200);
                     restartEsp(RestartReason::OTAReboot);
                 }
@@ -975,13 +984,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(F("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(F("Updating to latest beta version."));
+                    Log->println(("Updating to latest beta version."));
                     delay(200);
                     restartEsp(RestartReason::OTAReboot);
                 }
@@ -990,13 +999,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(F("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(F("Updating to latest developmemt version."));
+                    Log->println(("Updating to latest developmemt version."));
                     delay(200);
                     restartEsp(RestartReason::OTAReboot);
                 }
@@ -1005,13 +1014,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(F("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(F("Updating to latest release version."));
+                    Log->println(("Updating to latest release version."));
                     delay(200);
                     restartEsp(RestartReason::OTAReboot);
                 }
@@ -1019,7 +1028,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
         }
         else
         {
-            Log->println(F("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))
@@ -1036,7 +1045,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
             {
                 return;
             }
-            Log->println(F("Webserver enabled, restarting."));
+            Log->println(("Webserver enabled, restarting."));
             _preferences->putBool(preference_webserver_enabled, true);
 
         }
@@ -1046,7 +1055,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
             {
                 return;
             }
-            Log->println(F("Webserver disabled, restarting."));
+            Log->println(("Webserver disabled, restarting."));
             _preferences->putBool(preference_webserver_enabled, false);
         }
 
@@ -1076,9 +1085,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(F("GPIO "));
+            Log->print(("GPIO "));
             Log->print(pin);
-            Log->print(F(" (Output) --> "));
+            Log->print((" (Output) --> "));
             Log->println(pinState);
             digitalWrite(pin, pinState);
         }
@@ -1180,7 +1189,7 @@ void NukiNetwork::removeTopic(const String& mqttPath, const String& mqttTopic)
     publish(path.c_str(), "", true);
 
 #ifdef DEBUG_NUKIHUB
-    Log->print(F("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 e0a5f07..3f68481 100644
--- a/src/NukiNetwork.h
+++ b/src/NukiNetwork.h
@@ -28,6 +28,7 @@ public:
     void scan(bool passive = false, bool async = true);
     bool isApOpen();
     bool isConnected();
+    bool mqttConnected();
     bool wifiConnected();
     void clearWifiFallback();
 
diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp
index 6229d6a..503f704 100644
--- a/src/NukiNetworkLock.cpp
+++ b/src/NukiNetworkLock.cpp
@@ -45,6 +45,7 @@ void NukiNetworkLock::initialize()
 
     _haEnabled = _preferences->getString(preference_mqtt_hass_discovery, "") != "";
     _disableNonJSON = _preferences->getBool(preference_disable_non_json, false);
+    _hybridRebootOnDisconnect = _preferences->getBool(preference_hybrid_reboot_on_disconnect, false);
 
     _network->initTopic(_mqttPath, mqtt_topic_lock_action, "--");
     _network->subscribe(_mqttPath, mqtt_topic_lock_action);
@@ -156,12 +157,33 @@ void NukiNetworkLock::initialize()
     }
 }
 
-void NukiNetworkLock::update()
+bool NukiNetworkLock::update()
 {
+    bool ret = false;
+    
     if(_nukiOfficial->hasOffStateToPublish())
     {
         publishState(_nukiOfficial->getOffStateToPublish());
     }
+
+    if(_hybridRebootOnDisconnect && _network->mqttConnected())
+    {
+        int64_t ts = espMillis();
+
+        if(_offConnected && !_nukiOfficial->getOffConnected())
+        {
+            _offLastConnected = ts;
+        }
+        else if(!_offConnected && _offLastConnected > 0 && _offLastConnected < (ts - (180 * 1000)))
+        {
+            _offLastConnected = 0;
+            ret = true;
+        }
+
+        _offConnected = _nukiOfficial->getOffConnected();
+    }
+    
+    return ret;
 }
 
 void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
@@ -214,7 +236,7 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
             return;
         }
 
-        Log->print(F("Lock action received: "));
+        Log->print(("Lock action received: "));
         Log->println(data);
         LockActionResult lockActionResult = LockActionResult::Failed;
         if(_lockActionReceivedCallback != NULL)
diff --git a/src/NukiNetworkLock.h b/src/NukiNetworkLock.h
index 96a136a..37a45b8 100644
--- a/src/NukiNetworkLock.h
+++ b/src/NukiNetworkLock.h
@@ -23,7 +23,7 @@ public:
     virtual ~NukiNetworkLock();
 
     void initialize();
-    void update();
+    bool update();
 
     void publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState);
     void publishState(NukiLock::LockState lockState);
@@ -88,6 +88,8 @@ private:
     bool _firstTunerStatePublish = true;
     bool _haEnabled = false;
     bool _disableNonJSON = false;
+    bool _offConnected = false;
+    bool _hybridRebootOnDisconnect = false;
 
     String _keypadCommandName = "";
     String _keypadCommandCode = "";
@@ -96,6 +98,7 @@ private:
     uint8_t _queryCommands = 0;
     uint32_t _lastRollingLog = 0;
     uint32_t _authId = 0;
+    int64_t _offLastConnected = 0;
 
     char _nukiName[33];
     char _authName[33];
diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp
index 01cbff3..e22272b 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(F("Opener action received: "));
+        Log->print(("Opener action received: "));
         Log->println(data);
         LockActionResult lockActionResult = LockActionResult::Failed;
         if(_lockActionReceivedCallback != NULL)
@@ -660,12 +660,12 @@ void NukiNetworkOpener::publishAuthorizationInfo(const std::listprintln(F("Nuki opener: Ring detected (Locked)"));
+                    Log->println(("Nuki opener: Ring detected (Locked)"));
                     publishRing(true);
                 }
                 else
                 {
-                    Log->println(F("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 469aded..7628dd7 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(F("Topic: "));
+    Log->print(("Topic: "));
     Log->println(topic);
-    Log->print(F("Value: "));
+    Log->print(("Value: "));
     Log->println(value);
 
     if(strcmp(topic, mqtt_topic_official_connected) == 0)
     {
-        Log->print(F("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(F("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(F("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(F("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(F("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(F("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(F("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(F("Battery level: "));
+        Log->print(("Battery level: "));
         Log->println(offChargeState);
 
         if(!_disableNonJSON)
diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp
index 8da820d..8d52089 100644
--- a/src/NukiOpenerWrapper.cpp
+++ b/src/NukiOpenerWrapper.cpp
@@ -62,7 +62,7 @@ void NukiOpenerWrapper::initialize()
     _nukiOpener.registerBleScanner(_bleScanner);
     _nukiOpener.setEventHandler(this);
     _nukiOpener.setConnectTimeout(3);
-    _nukiOpener.setDisconnectTimeout(5000);
+    _nukiOpener.setDisconnectTimeout(2000);
 
     _hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
     readSettings();
@@ -174,11 +174,11 @@ void NukiOpenerWrapper::readSettings()
         _preferences->putInt(preference_restart_ble_beacon_lost, _restartBeaconTimeout);
     }
 
-    Log->print(F("Opener state interval: "));
+    Log->print(("Opener state interval: "));
     Log->print(_intervalLockstate);
-    Log->print(F(" | Battery interval: "));
+    Log->print((" | Battery interval: "));
     Log->print(_intervalBattery);
-    Log->print(F(" | Publish auth data: "));
+    Log->print((" | Publish auth data: "));
     Log->println(_publishAuthData ? "yes" : "no");
 
     if(!_publishAuthData)
@@ -195,7 +195,7 @@ void NukiOpenerWrapper::update()
     wdt_hal_write_protect_enable(&rtc_wdt_ctx);
     if(!_paired)
     {
-        Log->println(F("Nuki opener start pairing"));
+        Log->println(("Nuki opener start pairing"));
         _network->publishBleAddress("");
 
         Nuki::AuthorizationIdType idType = _preferences->getBool(preference_register_opener_as_app) ?
@@ -204,7 +204,7 @@ void NukiOpenerWrapper::update()
 
         if(_nukiOpener.pairNuki(idType) == NukiOpener::PairingResult::Success)
         {
-            Log->println(F("Nuki opener paired"));
+            Log->println(("Nuki opener paired"));
             _paired = true;
             _network->publishBleAddress(_nukiOpener.getBleAddress().toString());
         }
@@ -247,14 +247,14 @@ void NukiOpenerWrapper::update()
 
             _network->publishCommandResult(resultStr);
 
-            Log->print(F("Opener action result: "));
+            Log->print(("Opener action result: "));
             Log->println(resultStr);
 
             if(cmdResult != Nuki::CmdResult::Success)
             {
-                Log->print(F("Opener: Last command failed, retrying after "));
+                Log->print(("Opener: Last command failed, retrying after "));
                 Log->print(_retryDelay);
-                Log->print(F(" milliseconds. Retry "));
+                Log->print((" milliseconds. Retry "));
                 Log->print(retryCount + 1);
                 Log->print(" of ");
                 Log->println(_nrOfRetries);
@@ -274,7 +274,7 @@ void NukiOpenerWrapper::update()
             _network->publishRetry("--");
             retryCount = 0;
             _statusUpdated = true;
-            Log->println(F("Opener: updating status after action"));
+            Log->println(("Opener: updating status after action"));
             _statusUpdatedTs = ts;
             if(_intervalLockstate > 10)
             {
@@ -283,7 +283,7 @@ void NukiOpenerWrapper::update()
         }
         else
         {
-            Log->println(F("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;
@@ -452,7 +452,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
 
     while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1)
     {
-        Log->print(F("Result (attempt "));
+        Log->print(("Result (attempt "));
         Log->print(retryCount + 1);
         Log->print("): ");
         result =_nukiOpener.requestOpenerState(&_keyTurnerState);
@@ -471,7 +471,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
         postponeBleWatchdog();
         if(_retryLockstateCount < _nrOfRetries + 1)
         {
-            Log->print(F("Query opener state retrying in "));
+            Log->print(("Query opener state retrying in "));
             Log->print(_retryDelay);
             Log->println("ms");
             _nextLockStateUpdateTs = espMillis() + _retryDelay;
@@ -493,7 +493,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
             _lastKeyTurnerState.lockState == NukiOpener::LockState::Locked &&
             _lastKeyTurnerState.nukiState == _keyTurnerState.nukiState)
     {
-        Log->println(F("Nuki opener: Ring detected (Locked)"));
+        Log->println(("Nuki opener: Ring detected (Locked)"));
         _network->publishRing(true);
     }
     else
@@ -503,15 +503,15 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
                 _keyTurnerState.lockState == NukiOpener::LockState::Open &&
                 _keyTurnerState.trigger == NukiOpener::Trigger::Manual)
         {
-            Log->println(F("Nuki opener: Ring detected (Open)"));
+            Log->println(("Nuki opener: Ring detected (Open)"));
             _network->publishRing(false);
         }
 
         if(_publishAuthData)
         {
-            Log->println(F("Publishing auth data"));
+            Log->println(("Publishing auth data"));
             updateAuthData(false);
-            Log->println(F("Done publishing auth data"));
+            Log->println(("Done publishing auth data"));
         }
 
         updateGpioOutputs();
@@ -520,12 +520,12 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
         if((_keyTurnerState.lockState == NukiOpener::LockState::Open || _keyTurnerState.lockState == NukiOpener::LockState::Opening) && espMillis() < _statusUpdatedTs + 10000)
         {
             updateStatus = true;
-            Log->println(F("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(F("Continuous Mode"));
+            Log->println(("Continuous Mode"));
         }
 
         char lockStateStr[20];
@@ -534,7 +534,7 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
     }
 
     postponeBleWatchdog();
-    Log->println(F("Done querying opener state"));
+    Log->println(("Done querying opener state"));
     return updateStatus;
 }
 
@@ -545,7 +545,7 @@ void NukiOpenerWrapper::updateBatteryState()
 
     while(retryCount < _nrOfRetries + 1)
     {
-        Log->print(F("Querying opener battery state: "));
+        Log->print(("Querying opener battery state: "));
         result = _nukiOpener.requestBatteryReport(&_batteryReport);
         delay(250);
         if(result != Nuki::CmdResult::Success)
@@ -564,7 +564,7 @@ void NukiOpenerWrapper::updateBatteryState()
         _network->publishBatteryReport(_batteryReport);
     }
     postponeBleWatchdog();
-    Log->println(F("Done querying opener battery state"));
+    Log->println(("Done querying opener battery state"));
 }
 
 void NukiOpenerWrapper::updateConfig()
@@ -579,7 +579,7 @@ void NukiOpenerWrapper::updateConfig()
         {
             char uidString[20];
             itoa(_nukiConfig.nukiId, uidString, 16);
-            Log->print(F("Saving Opener Nuki ID to preferences ("));
+            Log->print(("Saving Opener Nuki ID to preferences ("));
             Log->print(_nukiConfig.nukiId);
             Log->print(" / ");
             Log->print(uidString);
@@ -612,7 +612,7 @@ void NukiOpenerWrapper::updateConfig()
             {
                 Nuki::CmdResult result = (Nuki::CmdResult)-1;
                 int retryCount = 0;
-                Log->println(F("Nuki opener PIN is set"));
+                Log->println(("Nuki opener PIN is set"));
 
                 while(retryCount < _nrOfRetries + 1)
                 {
@@ -630,7 +630,7 @@ void NukiOpenerWrapper::updateConfig()
 
                 if(result != Nuki::CmdResult::Success)
                 {
-                    Log->println(F("Nuki opener PIN is invalid"));
+                    Log->println(("Nuki opener PIN is invalid"));
                     if(pinStatus != 2)
                     {
                         _preferences->putInt(preference_opener_pin_status, 2);
@@ -638,7 +638,7 @@ void NukiOpenerWrapper::updateConfig()
                 }
                 else
                 {
-                    Log->println(F("Nuki opener PIN is valid"));
+                    Log->println(("Nuki opener PIN is valid"));
                     if(pinStatus != 1)
                     {
                         _preferences->putInt(preference_opener_pin_status, 1);
@@ -647,7 +647,7 @@ void NukiOpenerWrapper::updateConfig()
             }
             else
             {
-                Log->println(F("Nuki opener PIN is not set"));
+                Log->println(("Nuki opener PIN is not set"));
                 if(pinStatus != 0)
                 {
                     _preferences->putInt(preference_opener_pin_status, 0);
@@ -656,13 +656,13 @@ void NukiOpenerWrapper::updateConfig()
         }
         else
         {
-            Log->println(F("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(F("Invalid/Unexpected opener config received, Config is not valid"));
+        Log->println(("Invalid/Unexpected opener config received, Config is not valid"));
         expectedConfig = false;
     }
 
@@ -679,7 +679,7 @@ void NukiOpenerWrapper::updateConfig()
         }
         else
         {
-            Log->println(F("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;
         }
     }
@@ -687,12 +687,12 @@ void NukiOpenerWrapper::updateConfig()
     if(expectedConfig && _nukiConfigValid && _nukiAdvancedConfigValid)
     {
         _retryConfigCount = 0;
-        Log->println(F("Done retrieving opener config and advanced config"));
+        Log->println(("Done retrieving opener config and advanced config"));
     }
     else
     {
         ++_retryConfigCount;
-        Log->println(F("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;
     }
@@ -702,7 +702,7 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
 {
     if(!isPinValid())
     {
-        Log->println(F("No valid PIN set"));
+        Log->println(("No valid PIN set"));
         return;
     }
 
@@ -713,7 +713,7 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
 
         while(retryCount < _nrOfRetries + 1)
         {
-            Log->print(F("Retrieve log entries: "));
+            Log->print(("Retrieve log entries: "));
             result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
 
             if(result != Nuki::CmdResult::Success)
@@ -767,7 +767,7 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
             return a.index < b.index;
         });
 
-        Log->print(F("Log size: "));
+        Log->print(("Log size: "));
         Log->println(log.size());
 
         if(log.size() > 0)
@@ -788,7 +788,7 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
 
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Opener PIN set"));
+        Log->println(("No valid Nuki Opener PIN set"));
         return;
     }
 
@@ -799,7 +799,7 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
 
         while(retryCount < _nrOfRetries + 1)
         {
-            Log->print(F("Querying opener keypad: "));
+            Log->print(("Querying opener keypad: "));
             result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
 
             if(result != Nuki::CmdResult::Success)
@@ -823,7 +823,7 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
         std::list entries;
         _nukiOpener.getKeypadEntries(&entries);
 
-        Log->print(F("Opener keypad codes: "));
+        Log->print(("Opener keypad codes: "));
         Log->println(entries.size());
 
         entries.sort([](const NukiOpener::KeypadEntry& a, const NukiOpener::KeypadEntry& b)
@@ -868,7 +868,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
 
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Opener PIN set"));
+        Log->println(("No valid Nuki Opener PIN set"));
         return;
     }
 
@@ -879,7 +879,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
 
         while(retryCount < _nrOfRetries + 1)
         {
-            Log->print(F("Querying opener timecontrol: "));
+            Log->print(("Querying opener timecontrol: "));
             result = _nukiOpener.retrieveTimeControlEntries();
 
             if(result != Nuki::CmdResult::Success)
@@ -903,7 +903,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
         std::list timeControlEntries;
         _nukiOpener.getTimeControlEntries(&timeControlEntries);
 
-        Log->print(F("Opener timecontrol entries: "));
+        Log->print(("Opener timecontrol entries: "));
         Log->println(timeControlEntries.size());
 
         timeControlEntries.sort([](const NukiOpener::TimeControlEntry& a, const NukiOpener::TimeControlEntry& b)
@@ -940,7 +940,7 @@ void NukiOpenerWrapper::updateAuth(bool retrieved)
 {
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Lock PIN set"));
+        Log->println(("No valid Nuki Lock PIN set"));
         return;
     }
 
@@ -956,7 +956,7 @@ void NukiOpenerWrapper::updateAuth(bool retrieved)
 
         while(retryCount < _nrOfRetries)
         {
-            Log->print(F("Querying opener authorization: "));
+            Log->print(("Querying opener authorization: "));
             result = _nukiOpener.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH));
             delay(250);
             if(result != Nuki::CmdResult::Success)
@@ -980,7 +980,7 @@ void NukiOpenerWrapper::updateAuth(bool retrieved)
         std::list authEntries;
         _nukiOpener.getAuthorizationEntries(&authEntries);
 
-        Log->print(F("Opener authorization entries: "));
+        Log->print(("Opener authorization entries: "));
         Log->println(authEntries.size());
 
         authEntries.sort([](const NukiOpener::AuthorizationEntry& a, const NukiOpener::AuthorizationEntry& b)
@@ -2731,7 +2731,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
             {
                 auto it1 = std::find(_keypadCodeIds.begin(), _keypadCodeIds.end(), codeId);
                 int index = it1 - _keypadCodeIds.begin();
-                Log->print(F("Check keypad code: "));
+                Log->print(("Check keypad code: "));
 
                 if(code == _keypadCodes[index])
                 {
@@ -2770,7 +2770,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
                     if(idExists)
                     {
                         result = _nukiOpener.deleteKeypadEntry(codeId);
-                        Log->print(F("Delete keypad code: "));
+                        Log->print(("Delete keypad code: "));
                         Log->println((int)result);
                     }
                     else
@@ -2977,7 +2977,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
                         }
 
                         result = _nukiOpener.addKeypadEntry(entry);
-                        Log->print(F("Add keypad code: "));
+                        Log->print(("Add keypad code: "));
                         Log->println((int)result);
                     }
                     else if (strcmp(action, "update") == 0)
@@ -3143,7 +3143,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
                         }
 
                         result = _nukiOpener.updateKeypadEntry(entry);
-                        Log->print(F("Update keypad code: "));
+                        Log->print(("Update keypad code: "));
                         Log->println((int)result);
                     }
                 }
@@ -3270,7 +3270,7 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
                 if(idExists)
                 {
                     result = _nukiOpener.removeTimeControlEntry(entryId);
-                    Log->print(F("Delete timecontrol: "));
+                    Log->print(("Delete timecontrol: "));
                     Log->println((int)result);
                 }
                 else
@@ -3349,7 +3349,7 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
 
                     entry.lockAction = timeControlLockAction;
                     result = _nukiOpener.addTimeControlEntry(entry);
-                    Log->print(F("Add timecontrol: "));
+                    Log->print(("Add timecontrol: "));
                     Log->println((int)result);
                 }
                 else if (strcmp(action, "update") == 0)
@@ -3426,7 +3426,7 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
 
                     entry.lockAction = timeControlLockAction;
                     result = _nukiOpener.updateTimeControlEntry(entry);
-                    Log->print(F("Update timecontrol: "));
+                    Log->print(("Update timecontrol: "));
                     Log->println((int)result);
                 }
             }
@@ -3580,7 +3580,7 @@ void NukiOpenerWrapper::onAuthCommandReceived(const char *value)
                 if(idExists)
                 {
                     result = _nukiOpener.deleteAuthorizationEntry(authId);
-                    Log->print(F("Delete authorization: "));
+                    Log->print(("Delete authorization: "));
                     Log->println((int)result);
                 }
                 else
@@ -3799,7 +3799,7 @@ void NukiOpenerWrapper::onAuthCommandReceived(const char *value)
                     }
 
                     result = _nukiOpener.addAuthorizationEntry(entry);
-                    Log->print(F("Add authorization: "));
+                    Log->print(("Add authorization: "));
                     Log->println((int)result);
                 }
                 else if (strcmp(action, "update") == 0)
@@ -3964,7 +3964,7 @@ void NukiOpenerWrapper::onAuthCommandReceived(const char *value)
                     }
 
                     result = _nukiOpener.updateAuthorizationEntry(entry);
-                    Log->print(F("Update authorization: "));
+                    Log->print(("Update authorization: "));
                     Log->println((int)result);
                 }
             }
@@ -4077,7 +4077,7 @@ void NukiOpenerWrapper::readConfig()
 
     char resultStr[20];
     NukiOpener::cmdResultToString(result, resultStr);
-    Log->print(F("Opener config result: "));
+    Log->print(("Opener config result: "));
     Log->print(resultStr);
     Log->print("(");
     Log->print(result);
@@ -4107,7 +4107,7 @@ void NukiOpenerWrapper::readAdvancedConfig()
 
     char resultStr[20];
     NukiOpener::cmdResultToString(result, resultStr);
-    Log->print(F("Opener advanced config result: "));
+    Log->print(("Opener advanced config result: "));
     Log->println(resultStr);
     postponeBleWatchdog();
 }
@@ -4166,7 +4166,7 @@ void NukiOpenerWrapper::updateTime()
 {
     if(!isPinValid())
     {
-        Log->println(F("No valid PIN set"));
+        Log->println(("No valid PIN set"));
         return;
     }
 
@@ -4177,7 +4177,7 @@ void NukiOpenerWrapper::updateTime()
 
     if (int(tm.tm_year + 1900) < int(2025))
     {
-        Log->println(F("NTP Time not valid, not updating Nuki device"));
+        Log->println(("NTP Time not valid, not updating Nuki device"));
         return;
     }
 
@@ -4194,6 +4194,6 @@ void NukiOpenerWrapper::updateTime()
     char resultStr[15] = {0};
     NukiOpener::cmdResultToString(cmdResult, resultStr);
 
-    Log->print(F("Opener time update result: "));
+    Log->print(("Opener time update result: "));
     Log->println(resultStr);
 }
\ No newline at end of file
diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp
index 8d82ac4..18b054b 100644
--- a/src/NukiWrapper.cpp
+++ b/src/NukiWrapper.cpp
@@ -64,7 +64,7 @@ void NukiWrapper::initialize()
     _nukiLock.registerBleScanner(_bleScanner);
     _nukiLock.setEventHandler(this);
     _nukiLock.setConnectTimeout(3);
-    _nukiLock.setDisconnectTimeout(5000);
+    _nukiLock.setDisconnectTimeout(2000);
 
     _hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
     readSettings();
@@ -183,11 +183,11 @@ void NukiWrapper::readSettings()
         _preferences->putInt(preference_restart_ble_beacon_lost, _restartBeaconTimeout);
     }
 
-    Log->print(F("Lock state interval: "));
+    Log->print(("Lock state interval: "));
     Log->print(_intervalLockstate);
-    Log->print(F(" | Battery interval: "));
+    Log->print((" | Battery interval: "));
     Log->print(_intervalBattery);
-    Log->print(F(" | Publish auth data: "));
+    Log->print((" | Publish auth data: "));
     Log->println(_publishAuthData ? "yes" : "no");
 
     if(!_publishAuthData)
@@ -196,7 +196,7 @@ void NukiWrapper::readSettings()
     }
 }
 
-void NukiWrapper::update()
+void NukiWrapper::update(bool reboot)
 {
     wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
     wdt_hal_write_protect_disable(&rtc_wdt_ctx);
@@ -204,8 +204,8 @@ void NukiWrapper::update()
     wdt_hal_write_protect_enable(&rtc_wdt_ctx);
     if(!_paired)
     {
-        Log->println(F("Nuki lock start pairing"));
-        _preferences->getBool(preference_register_as_app) ? Log->println(F("Pairing as app")) : Log->println(F("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) ?
@@ -214,7 +214,7 @@ void NukiWrapper::update()
 
         if(_nukiLock.pairNuki(idType) == Nuki::PairingResult::Success)
         {
-            Log->println(F("Nuki paired"));
+            Log->println(("Nuki paired"));
             _paired = true;
             _network->publishBleAddress(_nukiLock.getBleAddress().toString());
         }
@@ -261,14 +261,14 @@ void NukiWrapper::update()
             NukiLock::cmdResultToString(cmdResult, resultStr);
             _network->publishCommandResult(resultStr);
 
-            Log->print(F("Lock action result: "));
+            Log->print(("Lock action result: "));
             Log->println(resultStr);
 
             if(cmdResult != Nuki::CmdResult::Success)
             {
-                Log->print(F("Lock: Last command failed, retrying after "));
+                Log->print(("Lock: Last command failed, retrying after "));
                 Log->print(_retryDelay);
-                Log->print(F(" milliseconds. Retry "));
+                Log->print((" milliseconds. Retry "));
                 Log->print(retryCount + 1);
                 Log->print(" of ");
                 Log->println(_nrOfRetries);
@@ -291,7 +291,7 @@ void NukiWrapper::update()
             {
                 _statusUpdated = true;
             }
-            Log->println(F("Lock: updating status after action"));
+            Log->println(("Lock: updating status after action"));
             _statusUpdatedTs = ts;
             if(_intervalLockstate > 10)
             {
@@ -300,7 +300,7 @@ void NukiWrapper::update()
         }
         else
         {
-            Log->println(F("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;
@@ -387,6 +387,10 @@ void NukiWrapper::update()
         {
             _invalidCount--;
         }
+        if(reboot && isPinValid())
+        {
+            Nuki::CmdResult cmdResult = _nukiLock.requestReboot();
+        }
     }
 
     memcpy(&_lastKeyTurnerState, &_keyTurnerState, sizeof(NukiLock::KeyTurnerState));
@@ -458,13 +462,13 @@ bool NukiWrapper::updateKeyTurnerState()
     Nuki::CmdResult result = (Nuki::CmdResult)-1;
     int retryCount = 0;
 
-    Log->println(F("Querying lock state"));
+    Log->println(("Querying lock state"));
 
     while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1)
     {
-        Log->print(F("Result (attempt "));
+        Log->print(("Result (attempt "));
         Log->print(retryCount + 1);
-        Log->print(F("): "));
+        Log->print(("): "));
         result =_nukiLock.requestKeyTurnerState(&_keyTurnerState);
         ++retryCount;
     }
@@ -481,7 +485,7 @@ bool NukiWrapper::updateKeyTurnerState()
         postponeBleWatchdog();
         if(_retryLockstateCount < _nrOfRetries + 1)
         {
-            Log->print(F("Query lock state retrying in "));
+            Log->print(("Query lock state retrying in "));
             Log->print(_retryDelay);
             Log->println("ms");
             _nextLockStateUpdateTs = espMillis() + _retryDelay;
@@ -506,9 +510,9 @@ bool NukiWrapper::updateKeyTurnerState()
     {
         if(_publishAuthData && (lockState == NukiLock::LockState::Locked || lockState == NukiLock::LockState::Unlocked))
         {
-            Log->println(F("Publishing auth data"));
+            Log->println(("Publishing auth data"));
             updateAuthData(false);
-            Log->println(F("Done publishing auth data"));
+            Log->println(("Done publishing auth data"));
         }
 
         updateGpioOutputs();
@@ -516,7 +520,7 @@ bool NukiWrapper::updateKeyTurnerState()
     else if(!_nukiOfficial->getOffConnected() && espMillis() < _statusUpdatedTs + 10000)
     {
         updateStatus = true;
-        Log->println(F("Lock: Keep updating status on intermediate lock state"));
+        Log->println(("Lock: Keep updating status on intermediate lock state"));
     }
 
     _network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
@@ -526,7 +530,7 @@ bool NukiWrapper::updateKeyTurnerState()
     Log->println(lockStateStr);
 
     postponeBleWatchdog();
-    Log->println(F("Done querying lock state"));
+    Log->println(("Done querying lock state"));
     return updateStatus;
 }
 
@@ -539,7 +543,7 @@ void NukiWrapper::updateBatteryState()
 
     while(retryCount < _nrOfRetries + 1)
     {
-        Log->print(F("Result (attempt "));
+        Log->print(("Result (attempt "));
         Log->print(retryCount + 1);
         Log->print("): ");
         result = _nukiLock.requestBatteryReport(&_batteryReport);
@@ -560,7 +564,7 @@ void NukiWrapper::updateBatteryState()
         _network->publishBatteryReport(_batteryReport);
     }
     postponeBleWatchdog();
-    Log->println(F("Done querying lock battery state"));
+    Log->println(("Done querying lock battery state"));
 }
 
 void NukiWrapper::updateConfig()
@@ -575,7 +579,7 @@ void NukiWrapper::updateConfig()
         {
             char uidString[20];
             itoa(_nukiConfig.nukiId, uidString, 16);
-            Log->print(F("Saving Lock Nuki ID to preferences ("));
+            Log->print(("Saving Lock Nuki ID to preferences ("));
             Log->print(_nukiConfig.nukiId);
             Log->print(" / ");
             Log->print(uidString);
@@ -607,7 +611,7 @@ void NukiWrapper::updateConfig()
             {
                 Nuki::CmdResult result = (Nuki::CmdResult)-1;
                 int retryCount = 0;
-                Log->println(F("Nuki Lock PIN is set"));
+                Log->println(("Nuki Lock PIN is set"));
 
                 while(retryCount < _nrOfRetries + 1)
                 {
@@ -624,7 +628,7 @@ void NukiWrapper::updateConfig()
 
                 if(result != Nuki::CmdResult::Success)
                 {
-                    Log->println(F("Nuki Lock PIN is invalid"));
+                    Log->println(("Nuki Lock PIN is invalid"));
                     if(pinStatus != 2)
                     {
                         _preferences->putInt(preference_lock_pin_status, 2);
@@ -632,7 +636,7 @@ void NukiWrapper::updateConfig()
                 }
                 else
                 {
-                    Log->println(F("Nuki Lock PIN is valid"));
+                    Log->println(("Nuki Lock PIN is valid"));
                     if(pinStatus != 1)
                     {
                         _preferences->putInt(preference_lock_pin_status, 1);
@@ -641,7 +645,7 @@ void NukiWrapper::updateConfig()
             }
             else
             {
-                Log->println(F("Nuki Lock PIN is not set"));
+                Log->println(("Nuki Lock PIN is not set"));
                 if(pinStatus != 0)
                 {
                     _preferences->putInt(preference_lock_pin_status, 0);
@@ -650,13 +654,13 @@ void NukiWrapper::updateConfig()
         }
         else
         {
-            Log->println(F("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(F("Invalid/Unexpected lock config received, Config is not valid"));
+        Log->println(("Invalid/Unexpected lock config received, Config is not valid"));
         expectedConfig = false;
     }
 
@@ -673,7 +677,7 @@ void NukiWrapper::updateConfig()
         }
         else
         {
-            Log->println(F("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;
         }
     }
@@ -681,12 +685,12 @@ void NukiWrapper::updateConfig()
     if(expectedConfig && _nukiConfigValid && _nukiAdvancedConfigValid)
     {
         _retryConfigCount = 0;
-        Log->println(F("Done retrieving lock config and advanced config"));
+        Log->println(("Done retrieving lock config and advanced config"));
     }
     else
     {
         ++_retryConfigCount;
-        Log->println(F("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;
     }
@@ -696,7 +700,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
 {
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Lock PIN set"));
+        Log->println(("No valid Nuki Lock PIN set"));
         return;
     }
 
@@ -707,7 +711,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
 
         while(retryCount < _nrOfRetries + 1)
         {
-            Log->print(F("Retrieve log entries: "));
+            Log->print(("Retrieve log entries: "));
             result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
             if(result != Nuki::CmdResult::Success)
             {
@@ -759,7 +763,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
             return a.index < b.index;
         });
 
-        Log->print(F("Log size: "));
+        Log->print(("Log size: "));
         Log->println(log.size());
 
         if(log.size() > 0)
@@ -780,7 +784,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
 
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Lock PIN set"));
+        Log->println(("No valid Nuki Lock PIN set"));
         return;
     }
 
@@ -791,7 +795,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
 
         while(retryCount < _nrOfRetries + 1)
         {
-            Log->print(F("Querying lock keypad: "));
+            Log->print(("Querying lock keypad: "));
             result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
             if(result != Nuki::CmdResult::Success)
             {
@@ -814,7 +818,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
         std::list entries;
         _nukiLock.getKeypadEntries(&entries);
 
-        Log->print(F("Lock keypad codes: "));
+        Log->print(("Lock keypad codes: "));
         Log->println(entries.size());
 
         entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b)
@@ -859,7 +863,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
 
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Lock PIN set"));
+        Log->println(("No valid Nuki Lock PIN set"));
         return;
     }
 
@@ -870,7 +874,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
 
         while(retryCount < _nrOfRetries + 1)
         {
-            Log->print(F("Querying lock timecontrol: "));
+            Log->print(("Querying lock timecontrol: "));
             result = _nukiLock.retrieveTimeControlEntries();
             if(result != Nuki::CmdResult::Success)
             {
@@ -893,7 +897,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
         std::list timeControlEntries;
         _nukiLock.getTimeControlEntries(&timeControlEntries);
 
-        Log->print(F("Lock timecontrol entries: "));
+        Log->print(("Lock timecontrol entries: "));
         Log->println(timeControlEntries.size());
 
         timeControlEntries.sort([](const NukiLock::TimeControlEntry& a, const NukiLock::TimeControlEntry& b)
@@ -930,7 +934,7 @@ void NukiWrapper::updateAuth(bool retrieved)
 {
     if(!isPinValid())
     {
-        Log->println(F("No valid Nuki Lock PIN set"));
+        Log->println(("No valid Nuki Lock PIN set"));
         return;
     }
 
@@ -946,7 +950,7 @@ void NukiWrapper::updateAuth(bool retrieved)
 
         while(retryCount < _nrOfRetries)
         {
-            Log->print(F("Querying lock authorization: "));
+            Log->print(("Querying lock authorization: "));
             result = _nukiLock.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH));
             delay(250);
             if(result != Nuki::CmdResult::Success)
@@ -970,7 +974,7 @@ void NukiWrapper::updateAuth(bool retrieved)
         std::list authEntries;
         _nukiLock.getAuthorizationEntries(&authEntries);
 
-        Log->print(F("Lock authorization entries: "));
+        Log->print(("Lock authorization entries: "));
         Log->println(authEntries.size());
 
         authEntries.sort([](const NukiLock::AuthorizationEntry& a, const NukiLock::AuthorizationEntry& b)
@@ -2760,7 +2764,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
             {
                 auto it1 = std::find(_keypadCodeIds.begin(), _keypadCodeIds.end(), codeId);
                 int index = it1 - _keypadCodeIds.begin();
-                Log->print(F("Check keypad code: "));
+                Log->print(("Check keypad code: "));
 
                 if(code == _keypadCodes[index])
                 {
@@ -2800,7 +2804,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
                     if(idExists)
                     {
                         result = _nukiLock.deleteKeypadEntry(codeId);
-                        Log->print(F("Delete keypad code: "));
+                        Log->print(("Delete keypad code: "));
                         Log->println((int)result);
                     }
                     else
@@ -3007,7 +3011,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
                         }
 
                         result = _nukiLock.addKeypadEntry(entry);
-                        Log->print(F("Add keypad code: "));
+                        Log->print(("Add keypad code: "));
                         Log->println((int)result);
                     }
                     else if (strcmp(action, "update") == 0)
@@ -3173,7 +3177,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
                         }
 
                         result = _nukiLock.updateKeypadEntry(entry);
-                        Log->print(F("Update keypad code: "));
+                        Log->print(("Update keypad code: "));
                         Log->println((int)result);
                     }
                 }
@@ -3300,7 +3304,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
                 if(idExists)
                 {
                     result = _nukiLock.removeTimeControlEntry(entryId);
-                    Log->print(F("Delete timecontrol: "));
+                    Log->print(("Delete timecontrol: "));
                     Log->println((int)result);
                 }
                 else
@@ -3380,7 +3384,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
                     entry.lockAction = timeControlLockAction;
 
                     result = _nukiLock.addTimeControlEntry(entry);
-                    Log->print(F("Add timecontrol: "));
+                    Log->print(("Add timecontrol: "));
                     Log->println((int)result);
                 }
                 else if (strcmp(action, "update") == 0)
@@ -3458,7 +3462,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
                     entry.lockAction = timeControlLockAction;
 
                     result = _nukiLock.updateTimeControlEntry(entry);
-                    Log->print(F("Update timecontrol: "));
+                    Log->print(("Update timecontrol: "));
                     Log->println((int)result);
                 }
             }
@@ -3613,7 +3617,7 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
                 {
                     result = _nukiLock.deleteAuthorizationEntry(authId);
                     delay(250);
-                    Log->print(F("Delete authorization: "));
+                    Log->print(("Delete authorization: "));
                     Log->println((int)result);
                 }
                 else
@@ -3833,7 +3837,7 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
 
                     result = _nukiLock.addAuthorizationEntry(entry);
                     delay(250);
-                    Log->print(F("Add authorization: "));
+                    Log->print(("Add authorization: "));
                     Log->println((int)result);
                 }
                 else if (strcmp(action, "update") == 0)
@@ -3999,7 +4003,7 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
 
                     result = _nukiLock.updateAuthorizationEntry(entry);
                     delay(250);
-                    Log->print(F("Update authorization: "));
+                    Log->print(("Update authorization: "));
                     Log->println((int)result);
                 }
             }
@@ -4103,7 +4107,7 @@ void NukiWrapper::readConfig()
 
         char resultStr[20];
         NukiLock::cmdResultToString(result, resultStr);
-        Log->print(F("Lock config result: "));
+        Log->print(("Lock config result: "));
         Log->println(resultStr);
 
         if(result != Nuki::CmdResult::Success)
@@ -4131,7 +4135,7 @@ void NukiWrapper::readAdvancedConfig()
 
         char resultStr[20];
         NukiLock::cmdResultToString(result, resultStr);
-        Log->print(F("Lock advanced config result: "));
+        Log->print(("Lock advanced config result: "));
         Log->println(resultStr);
 
         if(result != Nuki::CmdResult::Success)
@@ -4211,7 +4215,7 @@ void NukiWrapper::updateTime()
 {
     if(!isPinValid())
     {
-        Log->println(F("No valid PIN set"));
+        Log->println(("No valid PIN set"));
         return;
     }
     
@@ -4222,7 +4226,7 @@ void NukiWrapper::updateTime()
     
     if (int(tm.tm_year + 1900) < int(2025))
     {
-        Log->println(F("NTP Time not valid, not updating Nuki device"));
+        Log->println(("NTP Time not valid, not updating Nuki device"));
         return;
     }
     
@@ -4239,6 +4243,6 @@ void NukiWrapper::updateTime()
     char resultStr[15] = {0};
     NukiLock::cmdResultToString(cmdResult, resultStr);
 
-    Log->print(F("Lock time update result: "));
+    Log->print(("Lock time update result: "));
     Log->println(resultStr);
 }
\ No newline at end of file
diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h
index 820a062..40f52a5 100644
--- a/src/NukiWrapper.h
+++ b/src/NukiWrapper.h
@@ -19,7 +19,7 @@ public:
 
     void initialize();
     void readSettings();
-    void update();
+    void update(bool reboot = false);
 
     void lock();
     void unlock();
diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h
index cfb50d6..decc236 100644
--- a/src/PreferencesKeys.h
+++ b/src/PreferencesKeys.h
@@ -124,6 +124,7 @@
 #define preference_lock_force_keypad (char*)"lckForceKp"
 #define preference_opener_force_id (char*)"opForceId"
 #define preference_opener_force_keypad (char*)"opForceKp"
+#define preference_hybrid_reboot_on_disconnect (char*)"hybridRbtLck"
 
 //NOT USER CHANGABLE
 #define preference_updater_version (char*)"updVer"
@@ -185,6 +186,7 @@ inline void initPreferences(Preferences* preferences)
         preferences->putBool(preference_official_hybrid_enabled, false);
         preferences->putBool(preference_official_hybrid_actions, false);
         preferences->putBool(preference_official_hybrid_retry, false);
+        preferences->putBool(preference_hybrid_reboot_on_disconnect, false);
         preferences->putBool(preference_disable_non_json, false);
         preferences->putBool(preference_update_from_mqtt, false);
         preferences->putBool(preference_ip_dhcp_enabled, true);
@@ -472,7 +474,7 @@ private:
         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_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type,
-        preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
+        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,
         preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled,
         preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_info_enabled,
@@ -505,7 +507,8 @@ private:
         preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_webserial_enabled, preference_hass_device_discovery,
         preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_http_auth_type,
         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_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
     };
     std::vector _bytePrefs =
     {
diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp
index c971866..fc5c778 100644
--- a/src/WebCfgServer.cpp
+++ b/src/WebCfgServer.cpp
@@ -441,7 +441,7 @@ void WebCfgServer::initialize()
             {
                 processGpioArgs(request, resp);
                 esp_err_t res = buildConfirmHtml(request, resp, "Saving GPIO configuration. Restarting.", 3, true);
-                Log->println(F("Restarting"));
+                Log->println(("Restarting"));
                 waitAndProcess(true, 1000);
                 restartEsp(RestartReason::GpioConfigurationUpdated);
                 return res;
@@ -571,7 +571,7 @@ esp_err_t WebCfgServer::buildSSIDListHtml(PsychicRequest *request, PsychicRespon
 
     for (int i = 0; i < _ssidList.size(); i++)
     {
-        response.print("" + _ssidList[i] + String(F(" (")) + String(_rssiList[i]) + String(F(" %)")) + "");
+        response.print("" + _ssidList[i] + String((" (")) + String(_rssiList[i]) + String((" %)")) + "");
     }
     return response.endSend();
 }
@@ -626,7 +626,7 @@ esp_err_t WebCfgServer::buildWifiConnectHtml(PsychicRequest *request, PsychicRes
     createSsidList();
     for (int i = 0; i < _ssidList.size(); i++)
     {
-        response.print("" + _ssidList[i] + String(F(" (")) + String(_rssiList[i]) + String(F(" %)")) + "");
+        response.print("" + _ssidList[i] + String((" (")) + String(_rssiList[i]) + String((" %)")) + "");
     }
     response.print("");
     response.print("
"); @@ -1139,7 +1139,7 @@ esp_err_t WebCfgServer::handleOtaUpload(PsychicRequest *request, const String& f return(ESP_FAIL); } } - Log->print(F("Progress: 100%")); + Log->print(("Progress: 100%")); Log->println(); Log->print("handleFileUpload Total Size: "); Log->println(index+len); @@ -1642,7 +1642,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_broker, "") != value) { _preferences->putString(preference_mqtt_broker, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1652,7 +1652,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1668,7 +1668,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_user, "") != value) { _preferences->putString(preference_mqtt_user, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1681,7 +1681,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_password, "") != value) { _preferences->putString(preference_mqtt_password, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1692,7 +1692,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1725,7 +1725,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S Serial.println("Failed to delete /mqtt_ssl.ca"); } } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1758,7 +1758,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S Serial.println("Failed to delete /mqtt_ssl.crt"); } } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1791,7 +1791,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S Serial.println("Failed to delete /mqtt_ssl.key"); } } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1825,7 +1825,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S Serial.println("Failed to delete /http_ssl.crt"); } } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1858,7 +1858,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S Serial.println("Failed to delete /http_ssl.key"); } } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1869,7 +1869,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1887,7 +1887,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } } _preferences->putInt(preference_network_hardware, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1898,7 +1898,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_phy, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1909,7 +1909,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_addr, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1920,7 +1920,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_irq, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1931,7 +1931,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_rst, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1942,7 +1942,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_cs, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1953,7 +1953,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_sck, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1964,7 +1964,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_miso, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1975,7 +1975,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_mosi, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1986,7 +1986,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_pwr, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -1997,7 +1997,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_mdio, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2008,7 +2008,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_mdc, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2019,7 +2019,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { networkReconfigure = true; _preferences->putInt(preference_network_custom_clk, value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2029,7 +2029,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_network_wifi_fallback_disabled, false) != (value == "1")) { _preferences->putBool(preference_network_wifi_fallback_disabled, (value == "1")); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2039,7 +2039,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2050,7 +2050,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _network->disableHASS(); _preferences->putBool(preference_hass_device_discovery, (value == "1")); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2061,7 +2061,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _network->disableHASS(); _preferences->putBool(preference_mqtt_hass_enabled, (value == "1")); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2072,7 +2072,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _network->disableHASS(); _preferences->putString(preference_mqtt_hass_discovery, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2082,7 +2082,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2092,7 +2092,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2102,7 +2102,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_hostname, "") != value) { _preferences->putString(preference_hostname, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2112,7 +2112,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2122,7 +2122,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2132,7 +2132,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2142,7 +2142,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2152,7 +2152,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2162,7 +2162,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2172,7 +2172,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2182,7 +2182,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2196,7 +2196,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _preferences->putBool(preference_register_as_app, true); } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2210,7 +2210,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { _preferences->putBool(preference_register_as_app, true); } - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2220,7 +2220,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2230,7 +2230,17 @@ 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(F("Setting changed: ")); + Log->print(("Setting changed: ")); + Log->println(key); + //configChanged = true; + } + } + else if(key == "HYBRIDREBOOT") + { + 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->println(key); //configChanged = true; } @@ -2240,7 +2250,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2250,7 +2260,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2260,7 +2270,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_address, "") != value) { _preferences->putString(preference_ip_address, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2270,7 +2280,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_subnet, "") != value) { _preferences->putString(preference_ip_subnet, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2280,7 +2290,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_ip_gateway, "") != value) { _preferences->putString(preference_ip_gateway, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2290,7 +2300,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2300,7 +2310,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2310,7 +2320,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2320,7 +2330,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2330,7 +2340,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2340,7 +2350,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2350,7 +2360,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2362,7 +2372,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2373,7 +2383,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2385,7 +2395,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2398,7 +2408,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2411,7 +2421,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2424,7 +2434,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2437,7 +2447,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2450,7 +2460,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2463,7 +2473,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2474,7 +2484,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2484,7 +2494,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2494,7 +2504,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2504,7 +2514,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2514,7 +2524,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2524,7 +2534,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2534,7 +2544,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2544,7 +2554,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2554,7 +2564,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2564,7 +2574,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2574,7 +2584,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); } } @@ -2583,7 +2593,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); } } @@ -2592,7 +2602,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); } } @@ -2601,7 +2611,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); } } @@ -2610,7 +2620,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); } } @@ -2623,7 +2633,7 @@ 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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2633,7 +2643,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_keypad_info_enabled, false) != (value == "1")) { _preferences->putBool(preference_keypad_info_enabled, (value == "1")); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2643,7 +2653,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2653,7 +2663,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2663,7 +2673,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2673,7 +2683,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2683,7 +2693,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2693,7 +2703,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2703,7 +2713,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2713,7 +2723,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2723,7 +2733,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2733,7 +2743,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -2743,7 +2753,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -2753,7 +2763,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getBool(preference_http_auth_type, false) != (value == "1")) { _preferences->putBool(preference_http_auth_type, (value == "1")); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3127,7 +3137,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -3137,7 +3147,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); //configChanged = true; } @@ -3147,7 +3157,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3157,7 +3167,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3167,7 +3177,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3183,7 +3193,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_user, "") != value) { _preferences->putString(preference_cred_user, value); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3203,7 +3213,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Lock PIN cleared"; _nuki->setPin(0xffff); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3213,7 +3223,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Lock PIN saved"; _nuki->setPin(value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3225,7 +3235,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Opener PIN cleared"; _nukiOpener->setPin(0xffff); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3235,7 +3245,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S { message = "Nuki Opener PIN saved"; _nukiOpener->setPin(value.toInt()); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println(key); configChanged = true; } @@ -3300,7 +3310,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(manPairLck) { - Log->println(F("Changing lock pairing")); + Log->println(("Changing lock pairing")); Preferences nukiBlePref; nukiBlePref.begin("NukiHub", false); nukiBlePref.putBytes("bleAddress", currentBleAddress, 6); @@ -3308,14 +3318,14 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S nukiBlePref.putBytes("authorizationId", authorizationId, 4); nukiBlePref.putBytes("securityPinCode", pincode, 2); nukiBlePref.end(); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("Lock pairing data"); configChanged = true; } if(manPairOpn) { - Log->println(F("Changing opener pairing")); + Log->println(("Changing opener pairing")); Preferences nukiBlePref; nukiBlePref.begin("NukiHubopener", false); nukiBlePref.putBytes("bleAddress", currentBleAddressOpn, 6); @@ -3323,7 +3333,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S nukiBlePref.putBytes("authorizationId", authorizationIdOpn, 4); nukiBlePref.putBytes("securityPinCode", pincode, 2); nukiBlePref.end(); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("Opener pairing data"); configChanged = true; } @@ -3333,7 +3343,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_password, "") != pass1) { _preferences->putString(preference_cred_password, pass1); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("CREDPASS"); configChanged = true; } @@ -3344,14 +3354,14 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_mqtt_user, "") != "") { _preferences->putString(preference_mqtt_user, ""); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("MQTTUSER"); configChanged = true; } if(_preferences->getString(preference_mqtt_password, "") != "") { _preferences->putString(preference_mqtt_password, ""); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("MQTTPASS"); configChanged = true; } @@ -3362,14 +3372,14 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(_preferences->getString(preference_cred_user, "") != "") { _preferences->putString(preference_cred_user, ""); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("CREDUSER"); configChanged = true; } if(_preferences->getString(preference_cred_password, "") != "") { _preferences->putString(preference_cred_password, ""); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("CREDPASS"); configChanged = true; } @@ -3393,7 +3403,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S if(curAclPrefs[i] != aclPrefs[i]) { _preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs)); - Log->print(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("ACLPREFS"); //configChanged = true; break; @@ -3404,7 +3414,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("ACLCONFBASICLOCK"); //configChanged = true; break; @@ -3415,7 +3425,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("ACLCONFADVANCEDLOCK"); //configChanged = true; break; @@ -3427,7 +3437,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("ACLCONFBASICOPENER"); //configChanged = true; break; @@ -3438,7 +3448,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(F("Setting changed: ")); + Log->print(("Setting changed: ")); Log->println("ACLCONFADVANCEDOPENER"); //configChanged = true; break; @@ -4043,6 +4053,7 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request, PsychicResp printCheckBox(&response, "HYBRIDACT", "Enable sending actions through official MQTT", _preferences->getBool(preference_official_hybrid_actions), ""); printInputField(&response, "HYBRIDTIMER", "Time between status updates when official MQTT is offline (seconds)", _preferences->getInt(preference_query_interval_hybrid_lockstate), 5, ""); printCheckBox(&response, "HYBRIDRETRY", "Retry command sent using official MQTT over BLE if failed", _preferences->getBool(preference_official_hybrid_retry), ""); + printCheckBox(&response, "HYBRIDREBOOT", "Reboot Nuki lock on official MQTT failure", _preferences->getBool(preference_hybrid_reboot_on_disconnect, false), ""); response.print(""); response.print("* If no encryption is configured for the MQTT broker, leave empty.

"); response.print("
"); diff --git a/src/main.cpp b/src/main.cpp index 82a0db3..43a39cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,6 +54,7 @@ Gpio* gpio = nullptr; bool lockEnabled = false; bool openerEnabled = false; bool wifiConnected = false; +bool rebootLock = false; TaskHandle_t nukiTaskHandle = nullptr; @@ -162,9 +163,9 @@ void setReroute() uint8_t checkPartition() { const esp_partition_t* running_partition = esp_ota_get_running_partition(); - Log->print(F("Partition size: ")); + Log->print(("Partition size: ")); Log->println(running_partition->size); - Log->print(F("Partition subtype: ")); + Log->print(("Partition subtype: ")); Log->println(running_partition->subtype); if(running_partition->size == 1966080) @@ -197,7 +198,7 @@ void networkTask(void *pvParameters) if(bootloopCounter > 0) { bootloopCounter = (int8_t)0; - Log->println(F("Bootloop counter reset")); + Log->println(("Bootloop counter reset")); } } @@ -217,7 +218,7 @@ void networkTask(void *pvParameters) if(connected && lockEnabled) { - networkLock->update(); + rebootLock = networkLock->update(); } if(connected && openerEnabled) @@ -293,7 +294,8 @@ void nukiTask(void *pvParameters) if(lockEnabled) { - nuki->update(); + nuki->update(rebootLock); + rebootLock = false; } if(openerEnabled) { @@ -330,12 +332,12 @@ void bootloopDetection() esp_reset_reason() == esp_reset_reason_t::ESP_RST_WDT) { bootloopCounter++; - Log->print(F("Bootloop counter incremented: ")); + Log->print(("Bootloop counter incremented: ")); Log->println(bootloopCounter); if(bootloopCounter == 10) { - Log->print(F("Bootloop detected.")); + Log->print(("Bootloop detected.")); preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE); preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE); @@ -431,7 +433,7 @@ void otaTask(void *pvParameter) { .http_config = &config, }; - Log->print(F("Attempting to download update from ")); + Log->print(("Attempting to download update from ")); Log->println(config.url); int retryMax = 3; @@ -503,7 +505,7 @@ void setupTasks(bool ota) } void cbSyncTime(struct timeval *tv) { - Log->println(F("NTP time synched")); + Log->println(("NTP time synched")); } void setup() @@ -549,9 +551,9 @@ void setup() } #ifdef NUKI_HUB_UPDATER - Log->print(F("Nuki Hub OTA version ")); + Log->print(("Nuki Hub OTA version ")); Log->println(NUKI_HUB_VERSION); - Log->print(F("Nuki Hub OTA build ")); + Log->print(("Nuki Hub OTA build ")); Log->println(); if(preferences->getString(preference_updater_version, "") != NUKI_HUB_VERSION) @@ -653,9 +655,9 @@ void setup() bootloopDetection(); } - Log->print(F("Nuki Hub version ")); + Log->print(("Nuki Hub version ")); Log->println(NUKI_HUB_VERSION); - Log->print(F("Nuki Hub build ")); + Log->print(("Nuki Hub build ")); Log->println(NUKI_HUB_BUILD); uint32_t devIdOpener = preferences->getUInt(preference_device_id_opener); diff --git a/src/networkDevices/EthernetDevice.cpp b/src/networkDevices/EthernetDevice.cpp index c1163f9..8be245f 100644 --- a/src/networkDevices/EthernetDevice.cpp +++ b/src/networkDevices/EthernetDevice.cpp @@ -72,7 +72,7 @@ void EthernetDevice::initialize() if(ethCriticalFailure) { ethCriticalFailure = false; - Log->println(F("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(F("Init Ethernet")); + Log->println(("Init Ethernet")); if(_useSpi) { - Log->println(F("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(F("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(F("Ethernet hardware Initialized")); + Log->println(("Ethernet hardware Initialized")); wifiFallback = false; if(_useSpi && !_ipConfiguration->dhcpEnabled()) @@ -133,7 +133,7 @@ void EthernetDevice::initialize() } else { - Log->println(F("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(F("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 fadcfb6..3dc5423 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(F("IP configuration: ")); + Log->print(("IP configuration: ")); if(dhcpEnabled()) { - Log->println(F("DHCP")); + Log->println(("DHCP")); } else { - Log->print(F("IP address: ")); + Log->print(("IP address: ")); Log->print(ipAddress()); - Log->print(F(", Subnet: ")); + Log->print((", Subnet: ")); Log->print(subnet()); - Log->print(F(", Gateway: ")); + Log->print((", Gateway: ")); Log->print(defaultGateway()); - Log->print(F(", DNS: ")); + Log->print((", DNS: ")); Log->println(dnsServer()); } } diff --git a/src/networkDevices/NetworkDevice.cpp b/src/networkDevices/NetworkDevice.cpp index feaf87a..ebd70b0 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(F("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(F("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(F("MQTT without TLS.")); + Log->println(("MQTT without TLS.")); _mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO); } diff --git a/src/networkDevices/WifiDevice.cpp b/src/networkDevices/WifiDevice.cpp index f27eee9..5b1c68e 100644 --- a/src/networkDevices/WifiDevice.cpp +++ b/src/networkDevices/WifiDevice.cpp @@ -110,7 +110,7 @@ bool WifiDevice::connect() if (ssid == WiFi.SSID(i)) { Log->println(String("Saved SSID ") + ssid + String(" found with RSSI: ") + - String(WiFi.RSSI(i)) + String(F("(")) + + String(WiFi.RSSI(i)) + String(("(")) + String(constrain((100.0 + WiFi.RSSI(i)) * 2, 0, 100)) + String(" %) and BSSID: ") + WiFi.BSSIDstr(i) + String(" and channel: ") + String(WiFi.channel(i))); @@ -136,7 +136,7 @@ bool WifiDevice::connect() else { Log->println(String("Trying to connect to SSID ") + ssid + String(" found with RSSI: ") + - String(WiFi.RSSI(bestConnection)) + String(F("(")) + + String(WiFi.RSSI(bestConnection)) + String(("(")) + String(constrain((100.0 + WiFi.RSSI(bestConnection)) * 2, 0, 100)) + String(" %) and BSSID: ") + WiFi.BSSIDstr(bestConnection) + String(" and channel: ") + String(WiFi.channel(bestConnection))); @@ -253,7 +253,7 @@ void WifiDevice::onWifiEvent(const WiFiEvent_t &event, const WiFiEventInfo_t &in for (int i = 0; i < _foundNetworks; i++) { Log->println(String("SSID ") + WiFi.SSID(i) + String(" found with RSSI: ") + - String(WiFi.RSSI(i)) + String(F("(")) + + String(WiFi.RSSI(i)) + String(("(")) + String(constrain((100.0 + WiFi.RSSI(i)) * 2, 0, 100)) + String(" %) and BSSID: ") + WiFi.BSSIDstr(i) + String(" and channel: ") + String(WiFi.channel(i))); diff --git a/src/util/NetworkUtil.cpp b/src/util/NetworkUtil.cpp index 1dc057d..463898d 100644 --- a/src/util/NetworkUtil.cpp +++ b/src/util/NetworkUtil.cpp @@ -47,7 +47,7 @@ NetworkDeviceType NetworkUtil::GetDeviceTypeFromPreference(int hardwareDetect, i } break; default: - Log->println(F("Unknown hardware selected, falling back to Wi-Fi.")); + Log->println(("Unknown hardware selected, falling back to Wi-Fi.")); return NetworkDeviceType::WiFi; break; } From fdef9984a21631329f650e694e1278573196fec5 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 5 Jan 2025 20:26:19 +0100 Subject: [PATCH 6/6] Keypad improvements --- lib/nuki_ble | 2 +- src/NukiOpenerWrapper.cpp | 10 +++++----- src/NukiWrapper.cpp | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/nuki_ble b/lib/nuki_ble index ebcd364..8798980 160000 --- a/lib/nuki_ble +++ b/lib/nuki_ble @@ -1 +1 @@ -Subproject commit ebcd364046b0a0bc44dc6ef9e96c2a352f086167 +Subproject commit 87989807674b5935ec654e3fecd028706da0188e diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index 8d52089..37840a8 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -336,7 +336,7 @@ void NukiOpenerWrapper::update() } if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && !_hassSetupCompleted) { - _network->setupHASS(2, _nukiConfig.nukiId, (char*)_nukiConfig.name, _firmwareVersion.c_str(), _hardwareVersion.c_str(), false, _hasKeypad); + _network->setupHASS(2, _nukiConfig.nukiId, (char*)_nukiConfig.name, _firmwareVersion.c_str(), _hardwareVersion.c_str(), false, hasKeypad()); _hassSetupCompleted = true; } if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs)) @@ -350,7 +350,7 @@ void NukiOpenerWrapper::update() _lastRssi = rssi; } } - if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0)) + if(hasKeypad() && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0)) { _nextKeypadUpdateTs = ts + _intervalKeypad * 1000; updateKeypad(false); @@ -2469,7 +2469,7 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint return; } - if(!_hasKeypad) + if(!hasKeypad()) { if(_nukiConfigValid) { @@ -2609,7 +2609,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value) return; } - if(!_hasKeypad) + if(!hasKeypad()) { if(_nukiConfigValid) { @@ -4013,7 +4013,7 @@ const bool NukiOpenerWrapper::isPaired() const const bool NukiOpenerWrapper::hasKeypad() const { - return _forceKeypad || _hasKeypad; + return (_forceKeypad || _hasKeypad); } const BLEAddress NukiOpenerWrapper::getBleAddress() const diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 18b054b..cf8f193 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -351,7 +351,7 @@ void NukiWrapper::update(bool reboot) } if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && !_hassSetupCompleted) { - _network->setupHASS(1, _nukiConfig.nukiId, (char*)_nukiConfig.name, _firmwareVersion.c_str(), _hardwareVersion.c_str(), hasDoorSensor(), _hasKeypad); + _network->setupHASS(1, _nukiConfig.nukiId, (char*)_nukiConfig.name, _firmwareVersion.c_str(), _hardwareVersion.c_str(), hasDoorSensor(), hasKeypad()); _hassSetupCompleted = true; } if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs)) @@ -365,7 +365,7 @@ void NukiWrapper::update(bool reboot) _lastRssi = rssi; } } - if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0)) + if(hasKeypad() && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0)) { Log->println("Updating Lock keypad based on timer or query"); _nextKeypadUpdateTs = ts + _intervalKeypad * 1000; @@ -2502,7 +2502,7 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c return; } - if(!_hasKeypad) + if(!hasKeypad()) { if(_nukiConfigValid) { @@ -2642,7 +2642,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value) return; } - if(!_hasKeypad) + if(!hasKeypad()) { if(_nukiConfigValid) { @@ -4052,7 +4052,7 @@ const bool NukiWrapper::isPaired() const const bool NukiWrapper::hasKeypad() const { - return _forceKeypad || _hasKeypad; + return (_forceKeypad || _hasKeypad); } void NukiWrapper::notify(Nuki::EventType eventType) @@ -4153,10 +4153,10 @@ void NukiWrapper::readAdvancedConfig() bool NukiWrapper::hasDoorSensor() const { - return _forceDoorsensor || + return (_forceDoorsensor || _keyTurnerState.doorSensorState == Nuki::DoorSensorState::DoorClosed || _keyTurnerState.doorSensorState == Nuki::DoorSensorState::DoorOpened || - _keyTurnerState.doorSensorState == Nuki::DoorSensorState::Calibrating; + _keyTurnerState.doorSensorState == Nuki::DoorSensorState::Calibrating); } const BLEAddress NukiWrapper::getBleAddress() const