Refactor retry handling (#702)

* add NukiRetryHandler

* apply retry wrapper to opener wrapper

* apply retry wrapper to all opener communication

* apply retry wrapper to all lock communication

* remove commented out code

* replace millis() with espMillis() in wrapper classes
This commit is contained in:
Jan-Ole Schümann
2025-10-05 21:12:29 +07:00
committed by GitHub
parent 778d73cd58
commit e05ff0fdd0
9 changed files with 214 additions and 329 deletions

View File

@@ -48,6 +48,7 @@ set(SRCFILES
../lib/BleScanner/src/BleScanner.cpp ../lib/BleScanner/src/BleScanner.cpp
../lib/MqttLogger/src/MqttLogger.cpp ../lib/MqttLogger/src/MqttLogger.cpp
../src/util/NetworkUtil.cpp ../src/util/NetworkUtil.cpp
../src/util/NukiRetryHandler.cpp
../src/enums/NetworkDeviceType.h ../src/enums/NetworkDeviceType.h
../src/util/NetworkDeviceInstantiator.cpp ../src/util/NetworkDeviceInstantiator.cpp
../src/HomeAssistantDiscovery.cpp ../src/HomeAssistantDiscovery.cpp

View File

@@ -5,8 +5,8 @@
#define NUKI_HUB_VERSION "9.13" #define NUKI_HUB_VERSION "9.13"
#define NUKI_HUB_VERSION_INT (uint32_t)913 #define NUKI_HUB_VERSION_INT (uint32_t)913
#define NUKI_HUB_BUILD "unknownbuildnr" #define NUKI_HUB_BUILD "unknownbuildnr"
#define NUKI_HUB_DATE "2025-10-02" #define NUKI_HUB_DATE "2025-10-05"
#define NUKI_HUB_DATE "2025-10-02" #define NUKI_HUB_DATE "2025-10-05"
#define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" #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" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json"

View File

@@ -806,7 +806,7 @@ bool NukiNetwork::reconnect(bool force)
if (_device->mqttConnected()) if (_device->mqttConnected())
{ {
Log->println("MQTT connected"); Log->println("MQTT connected");
_mqttConnectedTs = millis(); _mqttConnectedTs = espMillis();
_mqttConnectionState = 1; _mqttConnectionState = 1;
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {

View File

@@ -75,6 +75,9 @@ void NukiOpenerWrapper::initialize()
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false); _hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
readSettings(); readSettings();
#ifndef NUKI_HUB_UPDATER
_nukiRetryHandler = new NukiRetryHandler("Opener", _gpio, _gpio->getPinsWithRole(PinRole::OutputHighBluetoothCommError), _nrOfRetries, _retryDelay);
#endif
} }
void NukiOpenerWrapper::readSettings() void NukiOpenerWrapper::readSettings()
@@ -287,44 +290,35 @@ void NukiOpenerWrapper::update()
if(_nextLockAction != (NukiOpener::LockAction)0xff) if(_nextLockAction != (NukiOpener::LockAction)0xff)
{ {
int retryCount = 0; int retryCount = 0;
Nuki::CmdResult cmdResult = (Nuki::CmdResult)-1;
while(retryCount < _nrOfRetries + 1 && cmdResult != Nuki::CmdResult::Success) Nuki::CmdResult result = _nukiRetryHandler->retryComm([&]()
{ {
Nuki::CmdResult cmdResult;
cmdResult = _nukiOpener.lockAction(_nextLockAction, 0, 0); cmdResult = _nukiOpener.lockAction(_nextLockAction, 0, 0);
char resultStr[15] = {0}; char resultStr[15] = {0};
NukiOpener::cmdResultToString(cmdResult, resultStr); NukiLock::cmdResultToString(cmdResult, resultStr);
_network->publishCommandResult(resultStr); _network->publishCommandResult(resultStr);
Log->print("Opener action result: "); Log->print("Opener lock action result: ");
Log->println(resultStr); Log->println(resultStr);
if(cmdResult != Nuki::CmdResult::Success) if(cmdResult != Nuki::CmdResult::Success)
{ {
setCommErrorPins(HIGH);
Log->print("Opener: Last command failed, retrying after ");
Log->print(_retryDelay);
Log->print(" milliseconds. Retry ");
Log->print(retryCount + 1);
Log->print(" of ");
Log->println(_nrOfRetries);
_network->publishRetry(std::to_string(retryCount + 1)); _network->publishRetry(std::to_string(retryCount + 1));
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(_retryDelay / portTICK_PERIOD_MS);
++retryCount; ++retryCount;
} }
postponeBleWatchdog(); postponeBleWatchdog();
}
setCommErrorPins(LOW);
if(cmdResult == Nuki::CmdResult::Success) return cmdResult;
});
if(result == Nuki::CmdResult::Success)
{ {
_nextLockAction = (NukiOpener::LockAction) 0xff; _nextLockAction = (NukiOpener::LockAction) 0xff;
_network->publishRetry("--"); _network->publishRetry("--");
@@ -509,16 +503,12 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
{ {
bool updateStatus = false; bool updateStatus = false;
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0; Log->println("Querying opener state");
while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
Log->print("Result (attempt "); return _nukiOpener.requestOpenerState(&_keyTurnerState);
Log->print(retryCount + 1); });
Log->print("): ");
result =_nukiOpener.requestOpenerState(&_keyTurnerState);
++retryCount;
}
char resultStr[15]; char resultStr[15];
memset(&resultStr, 0, sizeof(resultStr)); memset(&resultStr, 0, sizeof(resultStr));
@@ -621,28 +611,18 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
void NukiOpenerWrapper::updateBatteryState() void NukiOpenerWrapper::updateBatteryState()
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1)
{
Log->print("Querying opener battery state: "); Log->print("Querying opener battery state: ");
result = _nukiOpener.requestBatteryReport(&_batteryReport);
result = _nukiRetryHandler->retryComm([&]()
{
Nuki::CmdResult cmdResult = _nukiOpener.requestBatteryReport(&_batteryReport);
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(250 / portTICK_PERIOD_MS); return cmdResult;
if(result != Nuki::CmdResult::Success) });
{
++retryCount;
}
else
{
break;
}
}
NukiOpenerHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
{ {
_network->publishBatteryReport(_batteryReport); _network->publishBatteryReport(_batteryReport);
@@ -693,21 +673,11 @@ void NukiOpenerWrapper::updateConfig()
const int pinStatus = _preferences->getInt(preference_opener_pin_status, (int)NukiPinState::NotConfigured); const int pinStatus = _preferences->getInt(preference_opener_pin_status, (int)NukiPinState::NotConfigured);
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
result = _nukiOpener.verifySecurityPin(); return _nukiOpener.verifySecurityPin();
});
if(result != Nuki::CmdResult::Success)
{
++retryCount;
}
else
{
break;
}
}
if(result != Nuki::CmdResult::Success) if(result != Nuki::CmdResult::Success)
{ {
@@ -781,22 +751,11 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
if(!retrieved) if(!retrieved)
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
Log->print("Retrieve log entries: "); return _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); });
if(result != Nuki::CmdResult::Success)
{
++retryCount;
}
else
{
break;
}
}
Log->println(result); Log->println(result);
NukiOpenerHelper::printCommandResult(result); NukiOpenerHelper::printCommandResult(result);
@@ -871,22 +830,11 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
if(!retrieved) if(!retrieved)
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
Log->print("Querying opener keypad: "); return _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)); });
if(result != Nuki::CmdResult::Success)
{
++retryCount;
}
else
{
break;
}
}
NukiOpenerHelper::printCommandResult(result); NukiOpenerHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
@@ -951,24 +899,13 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
if(!retrieved) if(!retrieved)
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1)
{
Log->print("Querying opener timecontrol: "); Log->print("Querying opener timecontrol: ");
result = _nukiOpener.retrieveTimeControlEntries();
if(result != Nuki::CmdResult::Success) result = _nukiRetryHandler->retryComm([&]()
{ {
++retryCount; return _nukiOpener.retrieveTimeControlEntries();
} });
else
{
break;
}
}
NukiOpenerHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
{ {
_waitTimeControlUpdateTs = espMillis() + 5000; _waitTimeControlUpdateTs = espMillis() + 5000;
@@ -1028,31 +965,21 @@ void NukiOpenerWrapper::updateAuth(bool retrieved)
if(!retrieved) if(!retrieved)
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries)
{
Log->print("Querying opener authorization: "); Log->print("Querying opener authorization: ");
result = _nukiOpener.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH));
result = _nukiRetryHandler->retryComm([&]()
{
Nuki::CmdResult cmdResult = _nukiOpener.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH));
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(250 / portTICK_PERIOD_MS); return cmdResult;
if(result != Nuki::CmdResult::Success) });
{
++retryCount;
}
else
{
break;
}
}
NukiOpenerHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
{ {
_waitAuthUpdateTs = millis() + 5000; _waitAuthUpdateTs = espMillis() + 5000;
} }
} }
else else
@@ -3687,23 +3614,13 @@ void NukiOpenerWrapper::notify(Nuki::EventType eventType)
void NukiOpenerWrapper::readConfig() void NukiOpenerWrapper::readConfig()
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
result = _nukiOpener.requestConfig(&_nukiConfig); return _nukiOpener.requestConfig(&_nukiConfig);
});
_nukiConfigValid = result == Nuki::CmdResult::Success; _nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid)
{
++retryCount;
}
else
{
break;
}
}
char resultStr[20]; char resultStr[20];
NukiOpener::cmdResultToString(result, resultStr); NukiOpener::cmdResultToString(result, resultStr);
Log->print("Opener config result: "); Log->print("Opener config result: ");
@@ -3717,23 +3634,13 @@ void NukiOpenerWrapper::readConfig()
void NukiOpenerWrapper::readAdvancedConfig() void NukiOpenerWrapper::readAdvancedConfig()
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
result = _nukiOpener.requestAdvancedConfig(&_nukiAdvancedConfig); return _nukiOpener.requestAdvancedConfig(&_nukiAdvancedConfig);
});
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success; _nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiAdvancedConfigValid)
{
++retryCount;
}
else
{
break;
}
}
char resultStr[20]; char resultStr[20];
NukiOpener::cmdResultToString(result, resultStr); NukiOpener::cmdResultToString(result, resultStr);
Log->print("Opener advanced config result: "); Log->print("Opener advanced config result: ");
@@ -3819,7 +3726,10 @@ void NukiOpenerWrapper::updateTime()
nukiTime.minute = tm.tm_min; nukiTime.minute = tm.tm_min;
nukiTime.second = tm.tm_sec; nukiTime.second = tm.tm_sec;
Nuki::CmdResult cmdResult = _nukiOpener.updateTime(nukiTime); Nuki::CmdResult cmdResult = _nukiRetryHandler->retryComm([&]()
{
return _nukiOpener.updateTime(nukiTime);
});
char resultStr[15] = {0}; char resultStr[15] = {0};
NukiOpener::cmdResultToString(cmdResult, resultStr); NukiOpener::cmdResultToString(cmdResult, resultStr);

View File

@@ -7,6 +7,7 @@
#include "BleScanner.h" #include "BleScanner.h"
#include "Gpio.h" #include "Gpio.h"
#include "NukiDeviceId.h" #include "NukiDeviceId.h"
#include "util/NukiRetryHandler.h"
class NukiOpenerWrapper : public NukiOpener::SmartlockEventHandler class NukiOpenerWrapper : public NukiOpener::SmartlockEventHandler
{ {
@@ -85,6 +86,7 @@ private:
NukiNetworkOpener* _network = nullptr; NukiNetworkOpener* _network = nullptr;
Preferences* _preferences = nullptr; Preferences* _preferences = nullptr;
Gpio* _gpio = nullptr; Gpio* _gpio = nullptr;
NukiRetryHandler* _nukiRetryHandler = nullptr;
std::vector<uint8_t> _pinsCommError; std::vector<uint8_t> _pinsCommError;

View File

@@ -10,6 +10,7 @@
#include <time.h> #include <time.h>
#include "esp_sntp.h" #include "esp_sntp.h"
#include "util/NukiHelper.h" #include "util/NukiHelper.h"
#include "util/NukiRetryHandler.h"
NukiWrapper* nukiInst = nullptr; NukiWrapper* nukiInst = nullptr;
@@ -46,9 +47,6 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId,
network->setAuthCommandReceivedCallback(nukiInst->onAuthCommandReceivedCallback); network->setAuthCommandReceivedCallback(nukiInst->onAuthCommandReceivedCallback);
_gpio->addCallback(NukiWrapper::gpioActionCallback); _gpio->addCallback(NukiWrapper::gpioActionCallback);
#ifndef NUKI_HUB_UPDATER
_pinsCommError = _gpio->getPinsWithRole(PinRole::OutputHighBluetoothCommError);
#endif
} }
@@ -80,6 +78,10 @@ void NukiWrapper::initialize()
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false); _hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
readSettings(); readSettings();
#ifndef NUKI_HUB_UPDATER
_nukiRetryHandler = new NukiRetryHandler("Lock", _gpio, _gpio->getPinsWithRole(PinRole::OutputHighBluetoothCommError), _nrOfRetries, _retryDelay);
#endif
} }
void NukiWrapper::readSettings() void NukiWrapper::readSettings()
@@ -307,10 +309,10 @@ void NukiWrapper::update(bool reboot)
if(_nextLockAction != (NukiLock::LockAction)0xff) if(_nextLockAction != (NukiLock::LockAction)0xff)
{ {
int retryCount = 0; int retryCount = 0;
Nuki::CmdResult cmdResult;
while(retryCount < _nrOfRetries + 1 && cmdResult != Nuki::CmdResult::Success) Nuki::CmdResult result = _nukiRetryHandler->retryComm([&]()
{ {
Nuki::CmdResult cmdResult;
cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0); cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0);
char resultStr[15] = {0}; char resultStr[15] = {0};
NukiLock::cmdResultToString(cmdResult, resultStr); NukiLock::cmdResultToString(cmdResult, resultStr);
@@ -321,29 +323,21 @@ void NukiWrapper::update(bool reboot)
if(cmdResult != Nuki::CmdResult::Success) if(cmdResult != Nuki::CmdResult::Success)
{ {
setCommErrorPins(HIGH);
Log->print("Lock: Last command failed, retrying after ");
Log->print(_retryDelay);
Log->print(" milliseconds. Retry ");
Log->print(retryCount + 1);
Log->print(" of ");
Log->println(_nrOfRetries);
_network->publishRetry(std::to_string(retryCount + 1)); _network->publishRetry(std::to_string(retryCount + 1));
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(_retryDelay / portTICK_PERIOD_MS);
++retryCount; ++retryCount;
} }
postponeBleWatchdog(); postponeBleWatchdog();
}
setCommErrorPins(LOW);
if(cmdResult == Nuki::CmdResult::Success) return cmdResult;
});
if(result == Nuki::CmdResult::Success)
{ {
_nextLockAction = (NukiLock::LockAction) 0xff; _nextLockAction = (NukiLock::LockAction) 0xff;
_network->publishRetry("--"); _network->publishRetry("--");
@@ -544,14 +538,10 @@ bool NukiWrapper::updateKeyTurnerState()
Log->println("Querying lock state"); Log->println("Querying lock state");
while(result != Nuki::CmdResult::Success && retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
Log->print("Result (attempt "); return _nukiLock.requestKeyTurnerState(&_keyTurnerState);
Log->print(retryCount + 1); });
Log->print("): ");
result =_nukiLock.requestKeyTurnerState(&_keyTurnerState);
++retryCount;
}
char resultStr[15]; char resultStr[15];
memset(&resultStr, 0, sizeof(resultStr)); memset(&resultStr, 0, sizeof(resultStr));
@@ -636,24 +626,11 @@ void NukiWrapper::updateBatteryState()
Log->println("Querying lock battery state"); Log->println("Querying lock battery state");
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
Log->print("Result (attempt "); return _nukiLock.requestBatteryReport(&_batteryReport);
Log->print(retryCount + 1); });
Log->print("): ");
result = _nukiLock.requestBatteryReport(&_batteryReport);
if(result != Nuki::CmdResult::Success)
{
++retryCount;
}
else
{
break;
}
}
NukiHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
{ {
_network->publishBatteryReport(_batteryReport); _network->publishBatteryReport(_batteryReport);
@@ -703,20 +680,11 @@ void NukiWrapper::updateConfig()
const int pinStatus = _preferences->getInt(preference_lock_pin_status, (int)NukiPinState::NotConfigured); const int pinStatus = _preferences->getInt(preference_lock_pin_status, (int)NukiPinState::NotConfigured);
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
result = _nukiLock.verifySecurityPin(); return _nukiLock.verifySecurityPin();
if(result != Nuki::CmdResult::Success) });
{
++retryCount;
}
else
{
break;
}
}
if(result != Nuki::CmdResult::Success) if(result != Nuki::CmdResult::Success)
{ {
@@ -946,20 +914,12 @@ void NukiWrapper::updateAuthData(bool retrieved)
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0; int retryCount = 0;
Log->print("Retrieving log entries: ");
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
Log->print("Retrieve log entries: "); return _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); });
if(result != Nuki::CmdResult::Success)
{
++retryCount;
}
else
{
break;
}
}
NukiHelper::printCommandResult(result); NukiHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
@@ -1034,22 +994,13 @@ void NukiWrapper::updateKeypad(bool retrieved)
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0; int retryCount = 0;
while(retryCount < _nrOfRetries + 1)
{
Log->print("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)
{
++retryCount;
}
else
{
break;
}
}
NukiHelper::printCommandResult(result); result = _nukiRetryHandler->retryComm([&]()
{
return _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
});
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
{ {
_waitKeypadUpdateTs = espMillis() + 5000; _waitKeypadUpdateTs = espMillis() + 5000;
@@ -1110,23 +1061,14 @@ void NukiWrapper::updateTimeControl(bool retrieved)
} }
if(!retrieved) if(!retrieved)
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1)
{ {
Log->print("Querying lock timecontrol: "); Log->print("Querying lock timecontrol: ");
result = _nukiLock.retrieveTimeControlEntries(); Nuki::CmdResult result = (Nuki::CmdResult)-1;
if(result != Nuki::CmdResult::Success)
result = _nukiRetryHandler->retryComm([&]()
{ {
++retryCount; return _nukiLock.retrieveTimeControlEntries();
} });
else
{
break;
}
}
NukiHelper::printCommandResult(result); NukiHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
@@ -1186,33 +1128,24 @@ void NukiWrapper::updateAuth(bool retrieved)
} }
if(!retrieved) if(!retrieved)
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries)
{ {
Log->print("Querying lock authorization: "); Log->print("Querying lock authorization: ");
result = _nukiLock.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH)); Nuki::CmdResult result = (Nuki::CmdResult)-1;
result = _nukiRetryHandler->retryComm([&]()
{
Nuki::CmdResult cmdResult = _nukiLock.retrieveAuthorizationEntries(0, _preferences->getInt(preference_auth_max_entries, MAX_AUTH));
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(250 / portTICK_PERIOD_MS); return cmdResult;
if(result != Nuki::CmdResult::Success) });
{
++retryCount;
}
else
{
break;
}
}
NukiHelper::printCommandResult(result); NukiHelper::printCommandResult(result);
if(result == Nuki::CmdResult::Success) if(result == Nuki::CmdResult::Success)
{ {
_waitAuthUpdateTs = millis() + 5000; _waitAuthUpdateTs = espMillis() + 5000;
} }
} }
else else
@@ -4074,33 +4007,22 @@ void NukiWrapper::notify(Nuki::EventType eventType)
void NukiWrapper::readConfig() void NukiWrapper::readConfig()
{ {
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
result = _nukiLock.requestConfig(&_nukiConfig); Nuki::CmdResult cmdResult = _nukiLock.requestConfig(&_nukiConfig);
_nukiConfigValid = result == Nuki::CmdResult::Success;
char resultStr[20];
NukiLock::cmdResultToString(result, resultStr);
Log->print("Lock config result: ");
Log->println(resultStr);
if(result != Nuki::CmdResult::Success) if(result != Nuki::CmdResult::Success)
{ {
++retryCount;
Log->println("Failed to retrieve lock config, retrying in 1s");
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
else
{
break;
}
} }
return cmdResult;
});
_nukiConfigValid = result == Nuki::CmdResult::Success;
} }
void NukiWrapper::readAdvancedConfig() void NukiWrapper::readAdvancedConfig()
@@ -4108,31 +4030,19 @@ void NukiWrapper::readAdvancedConfig()
Nuki::CmdResult result = (Nuki::CmdResult)-1; Nuki::CmdResult result = (Nuki::CmdResult)-1;
int retryCount = 0; int retryCount = 0;
while(retryCount < _nrOfRetries + 1) result = _nukiRetryHandler->retryComm([&]()
{ {
result = _nukiLock.requestAdvancedConfig(&_nukiAdvancedConfig); Nuki::CmdResult cmdResult = _nukiLock.requestAdvancedConfig(&_nukiAdvancedConfig);
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
char resultStr[20];
NukiLock::cmdResultToString(result, resultStr);
Log->print("Lock advanced config result: ");
Log->println(resultStr);
if(result != Nuki::CmdResult::Success) if(result != Nuki::CmdResult::Success)
{ {
++retryCount;
Log->println("Failed to retrieve lock advanced config, retrying in 1s");
if (esp_task_wdt_status(NULL) == ESP_OK) if (esp_task_wdt_status(NULL) == ESP_OK)
{ {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
else
{
break;
}
} }
return cmdResult;
});
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
} }
bool NukiWrapper::hasDoorSensor() const bool NukiWrapper::hasDoorSensor() const
@@ -4158,14 +4068,6 @@ const std::string NukiWrapper::hardwareVersion() const
return _hardwareVersion; return _hardwareVersion;
} }
void NukiWrapper::setCommErrorPins(const uint8_t& value)
{
for (uint8_t pin : _pinsCommError)
{
_gpio->setPinOutput(pin, value);
}
}
void NukiWrapper::disableWatchdog() void NukiWrapper::disableWatchdog()
{ {
_restartBeaconTimeout = -1; _restartBeaconTimeout = -1;
@@ -4223,11 +4125,8 @@ void NukiWrapper::updateTime()
nukiTime.minute = tm.tm_min; nukiTime.minute = tm.tm_min;
nukiTime.second = tm.tm_sec; nukiTime.second = tm.tm_sec;
Nuki::CmdResult cmdResult = _nukiLock.updateTime(nukiTime); Nuki::CmdResult cmdResult = _nukiRetryHandler->retryComm([&]()
{
char resultStr[15] = {0}; return _nukiLock.updateTime(nukiTime);
NukiLock::cmdResultToString(cmdResult, resultStr); });
Log->print("Lock time update result: ");
Log->println(resultStr);
} }

View File

@@ -10,6 +10,7 @@
#include "NukiDeviceId.h" #include "NukiDeviceId.h"
#include "NukiOfficial.h" #include "NukiOfficial.h"
#include "EspMillis.h" #include "EspMillis.h"
#include "util/NukiRetryHandler.h"
class NukiWrapper : public Nuki::SmartlockEventHandler class NukiWrapper : public Nuki::SmartlockEventHandler
{ {
@@ -48,7 +49,6 @@ public:
const std::string firmwareVersion() const; const std::string firmwareVersion() const;
const std::string hardwareVersion() const; const std::string hardwareVersion() const;
void setCommErrorPins(const uint8_t& value);
void notify(Nuki::EventType eventType) override; void notify(Nuki::EventType eventType) override;
@@ -93,8 +93,7 @@ private:
NukiNetworkLock* _network = nullptr; NukiNetworkLock* _network = nullptr;
NukiOfficial* _nukiOfficial = nullptr; NukiOfficial* _nukiOfficial = nullptr;
Gpio* _gpio = nullptr; Gpio* _gpio = nullptr;
NukiRetryHandler* _nukiRetryHandler = nullptr;
std::vector<uint8_t> _pinsCommError;
Preferences* _preferences; Preferences* _preferences;
int _intervalLockstate = 0; // seconds int _intervalLockstate = 0; // seconds

View File

@@ -0,0 +1,52 @@
#include "NukiRetryHandler.h"
#include "Logger.h"
NukiRetryHandler::NukiRetryHandler(std::string reference, Gpio* gpio, std::vector<uint8_t> pinsCommError, int nrOfRetries, int retryDelay)
: _reference(reference),
_gpio(gpio),
_pinsCommError(pinsCommError),
_nrOfRetries(nrOfRetries),
_retryDelay(retryDelay)
{
}
const Nuki::CmdResult NukiRetryHandler::retryComm(std::function<Nuki::CmdResult()> func)
{
Nuki::CmdResult cmdResult = Nuki::CmdResult::Error;
int retryCount = 0;
while(retryCount < _nrOfRetries + 1 && cmdResult != Nuki::CmdResult::Success)
{
cmdResult = func();
if (cmdResult != Nuki::CmdResult::Success)
{
setCommErrorPins(HIGH);
++retryCount;
Log->print(_reference.c_str());
Log->print(": Last command failed, retrying after ");
Log->print(_retryDelay);
Log->print(" milliseconds. Retry ");
Log->print(retryCount);
Log->print(" of ");
Log->println(_nrOfRetries);
vTaskDelay(_retryDelay / portTICK_PERIOD_MS);
}
}
setCommErrorPins(LOW);
return cmdResult;
}
void NukiRetryHandler::setCommErrorPins(const uint8_t& value)
{
for (uint8_t pin : _pinsCommError)
{
_gpio->setPinOutput(pin, value);
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <functional>
#include "NukiDataTypes.h"
#include "NukiPublisher.h"
class NukiRetryHandler
{
public:
NukiRetryHandler(std::string reference, Gpio* gpio, std::vector<uint8_t> pinsCommError, int nrOfRetries, int retryDelay);
const Nuki::CmdResult retryComm(std::function<Nuki::CmdResult ()> func);
private:
void setCommErrorPins(const uint8_t& value);
std::string _reference;
Gpio* _gpio = nullptr;
int _nrOfRetries = 0;
int _retryDelay = 0;
std::vector<uint8_t> _pinsCommError;
};