diff --git a/README.md b/README.md
index eac85c4..2cddf21 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ Feel free to join us on Discord: https://discord.gg/9nPq85bP4p
Supported ESP32 devices:
- Nuki Hub is compiled against all ESP32 models with Wi-Fi and Bluetooh Low Energy (BLE) which are supported by ESP-IDF 5.1.4 and Arduino Core 3.0.1.
- Tested stable builds are provided for the ESP32, ESP32-S3 and ESP32-C3.
-- Support for the ESP32-C6 is ***HIGHLY*** experimental. Expect frequent crashes, especially when running Nuki Hub paired as an app (when not using in Hybrid mode). Pairing is also not supported yet and needs to be done manually on the /advanced page of the web configurator.
-- The ESP32-Solo1 is not supported by ESP-IDF 5.1 and as such can't be build using Arduino Core 3 and ESP-IDF 5.1. Untested build against Arduino Core 2.0.14 and ESP-IDF 4.4 are provided.
+- Support for the ESP32-C6 is experimental. There could be more frequent crashes than on other ESP32 devices and connections with the Nuki device could be slower than on other ESP32 devices.
+- The ESP32-Solo1 is not supported by ESP-IDF 5.1 and as such can't be build using Arduino Core 3 and ESP-IDF 5.1. Untested builds against Arduino Core 2.0.14 and ESP-IDF 4.4 are provided.
Not supported ESP32 devices:
- The ESP32-S2 has no BLE and as such can't run Nuki Hub.
@@ -165,7 +165,7 @@ In a browser navigate to the IP address assigned to the ESP32.
- Lock: Nuki Bridge is running alongside Nuki Hub: Enable to allow Nuki Hub to co-exist with a Nuki Bridge by registering Nuki Hub as an (smartphone) app instead of a bridge. Changing this setting will require re-pairing. Enabling this setting is strongly discouraged as described in the "[Pairing with a Nuki Lock or Opener](#pairing-with-a-nuki-lock-or-opener)" section of this README, ***unless when used in [Hybrid mode](/HYBRID.md) (Official MQTT / Nuki Hub co-existance)***
- Opener: Nuki Bridge is running alongside Nuki Hub: Enable to allow Nuki Hub to co-exist with a Nuki Bridge by registering Nuki Hub as an (smartphone) app instead of a bridge. Changing this setting will require re-pairing. Enabling this setting is strongly discouraged as described in the "[Pairing with a Nuki Lock or Opener](#pairing-with-a-nuki-lock-or-opener)" section of this README
- Restart if bluetooth beacons not received: Set to a positive integer to restart the Nuki Hub after the set amount of seconds has passed without receiving a bluetooth beacon from the Nuki device, set to -1 to disable, default 60. Because the bluetooth stack of the ESP32 can silently fail it is not recommended to disable this setting.
-
+- BLE transmit power in dB: Set to a integer between -12 and 9 to set the Bluetooth transmit power, default 9.
### Access Level Configuration
#### Nuki General Access Control
diff --git a/lib/BleScanner/src/BleScanner.cpp b/lib/BleScanner/src/BleScanner.cpp
index 4ad6ab7..ff4eca4 100644
--- a/lib/BleScanner/src/BleScanner.cpp
+++ b/lib/BleScanner/src/BleScanner.cpp
@@ -30,6 +30,7 @@ void Scanner::initialize(const std::string& deviceName, const bool wantDuplicate
}
BLEDevice::init(deviceName);
}
+
bleScan = BLEDevice::getScan();
#ifndef BLESCANNER_USE_LATEST_NIMBLE
@@ -98,4 +99,9 @@ void Scanner::onResult(NimBLEAdvertisedDevice* advertisedDevice) {
}
}
+void Scanner::whitelist(BLEAddress bleAddress) {
+ BLEDevice::whiteListAdd(bleAddress);
+ bleScan->setFilterPolicy(BLE_HCI_SCAN_FILT_USE_WL);
+}
+
} // namespace BleScanner
\ No newline at end of file
diff --git a/lib/BleScanner/src/BleScanner.h b/lib/BleScanner/src/BleScanner.h
index c7b0bcb..4942bc0 100644
--- a/lib/BleScanner/src/BleScanner.h
+++ b/lib/BleScanner/src/BleScanner.h
@@ -84,6 +84,14 @@ class Scanner : public Publisher, BLEAdvertisedDeviceCallbacks {
* @param advertisedDevice
*/
void onResult(NimBLEAdvertisedDevice* advertisedDevice) override;
+
+ /**
+ * @brief Whitelist a specific BLE Address
+ *
+ * @param whiteListBleAddress
+ */
+ void whitelist(BLEAddress bleAddress);
+
private:
uint32_t scanDuration = 0; //default indefinite scanning time
diff --git a/lib/esp-nimble-cpp/src/NimBLEClient.cpp b/lib/esp-nimble-cpp/src/NimBLEClient.cpp
index b524a2d..a0a0131 100644
--- a/lib/esp-nimble-cpp/src/NimBLEClient.cpp
+++ b/lib/esp-nimble-cpp/src/NimBLEClient.cpp
@@ -295,8 +295,6 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
if(isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response");
disconnect();
- NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
- ble_gap_conn_cancel();
} else {
// workaround; if the controller doesn't cancel the connection
// at the timeout, cancel it here.
diff --git a/platformio.ini b/platformio.ini
index 86581a8..a19c296 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -13,7 +13,7 @@ default_envs = esp32dev
boards_dir = boards
[env]
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.11/platform-espressif32.zip
+platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.07.11/platform-espressif32.zip
platform_packages =
framework = arduino, espidf
build_type = release
@@ -25,13 +25,13 @@ build_unflags =
-Werror=all
-Wall
build_flags =
- -fexceptions
- -DTLS_CA_MAX_SIZE=2200
- -DTLS_CERT_MAX_SIZE=1500
- -DTLS_KEY_MAX_SIZE=1800
- -DESP_PLATFORM
- -DESP32
- -DARDUINO_ARCH_ESP32
+ -fexceptions
+ -DTLS_CA_MAX_SIZE=2200
+ -DTLS_CERT_MAX_SIZE=1500
+ -DTLS_KEY_MAX_SIZE=1800
+ -DESP_PLATFORM
+ -DESP32
+ -DARDUINO_ARCH_ESP32
-DCONFIG_BTDM_BLE_SCAN_DUPL=y
-DCONFIG_ASYNC_TCP_MAX_ACK_TIME=3000
-DCONFIG_ASYNC_TCP_PRIORITY=10
@@ -63,14 +63,15 @@ extra_scripts =
pre:pio_package_pre.py
post:pio_package.py
build_flags =
- ${env.build_flags}
+ ${env.build_flags}
+ -DNUKI_ALT_CONNECT
-DBLESCANNER_USE_LATEST_NIMBLE
-DNUKI_USE_LATEST_NIMBLE
-DNUKI_NO_WDT_RESET
-DNUKI_MUTEX_RECURSIVE
-DNUKI_64BIT_TIME
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=0
[env:esp32-c3]
@@ -93,11 +94,12 @@ extra_scripts =
pre:pio_package_pre.py
post:pio_package.py
build_flags =
- ${env.build_flags}
- -DFRAMEWORK_ARDUINO_SOLO1
+ ${env.build_flags}
+ -DFRAMEWORK_ARDUINO_SOLO1
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=0
+ -DNUKI_ALT_CONNECT
-DNUKI_64BIT_TIME
lib_deps =
BleScanner=symlink://lib/BleScanner
@@ -111,99 +113,104 @@ lib_ignore =
extends = env:esp32dev
custom_build = debug
build_flags =
- ${env.build_flags}
+ ${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=0
+ -DNUKI_ALT_CONNECT
-DBLESCANNER_USE_LATEST_NIMBLE
-DNUKI_USE_LATEST_NIMBLE
-DNUKI_NO_WDT_RESET
-DNUKI_MUTEX_RECURSIVE
-DNUKI_64BIT_TIME
-DDEBUG_NUKIHUB
- -DDEBUG_SENSE_NUKI
- -DDEBUG_NUKI_COMMAND
- -DDEBUG_NUKI_CONNECT
- -DDEBUG_NUKI_COMMUNICATION
- ;-DDEBUG_NUKI_HEX_DATA
- -DDEBUG_NUKI_READABLE_DATA
+ -DDEBUG_SENSE_NUKI
+ -DDEBUG_NUKI_COMMAND
+ -DDEBUG_NUKI_CONNECT
+ -DDEBUG_NUKI_COMMUNICATION
+ ;-DDEBUG_NUKI_HEX_DATA
+ -DDEBUG_NUKI_READABLE_DATA
[env:esp32-c3_dbg]
extends = env:esp32-c3
custom_build = debug
build_flags =
- ${env.build_flags}
+ ${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=0
+ -DNUKI_ALT_CONNECT
-DBLESCANNER_USE_LATEST_NIMBLE
-DNUKI_USE_LATEST_NIMBLE
-DNUKI_NO_WDT_RESET
-DNUKI_MUTEX_RECURSIVE
-DNUKI_64BIT_TIME
-DDEBUG_NUKIHUB
- -DDEBUG_SENSE_NUKI
- -DDEBUG_NUKI_COMMAND
- -DDEBUG_NUKI_CONNECT
- -DDEBUG_NUKI_COMMUNICATION
- ;-DDEBUG_NUKI_HEX_DATA
- -DDEBUG_NUKI_READABLE_DATA
+ -DDEBUG_SENSE_NUKI
+ -DDEBUG_NUKI_COMMAND
+ -DDEBUG_NUKI_CONNECT
+ -DDEBUG_NUKI_COMMUNICATION
+ ;-DDEBUG_NUKI_HEX_DATA
+ -DDEBUG_NUKI_READABLE_DATA
[env:esp32-c6_dbg]
extends = env:esp32-c6
custom_build = debug
build_flags =
- ${env.build_flags}
+ ${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=0
+ -DNUKI_ALT_CONNECT
-DBLESCANNER_USE_LATEST_NIMBLE
-DNUKI_USE_LATEST_NIMBLE
-DNUKI_NO_WDT_RESET
-DNUKI_MUTEX_RECURSIVE
-DNUKI_64BIT_TIME
-DDEBUG_NUKIHUB
- -DDEBUG_SENSE_NUKI
- -DDEBUG_NUKI_COMMAND
- -DDEBUG_NUKI_CONNECT
- -DDEBUG_NUKI_COMMUNICATION
- ;-DDEBUG_NUKI_HEX_DATA
- -DDEBUG_NUKI_READABLE_DATA
+ -DDEBUG_SENSE_NUKI
+ -DDEBUG_NUKI_COMMAND
+ -DDEBUG_NUKI_CONNECT
+ -DDEBUG_NUKI_COMMUNICATION
+ ;-DDEBUG_NUKI_HEX_DATA
+ -DDEBUG_NUKI_READABLE_DATA
[env:esp32-s3_dbg]
extends = env:esp32-s3
custom_build = debug
build_flags =
- ${env.build_flags}
+ ${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=0
+ -DNUKI_ALT_CONNECT
-DBLESCANNER_USE_LATEST_NIMBLE
-DNUKI_USE_LATEST_NIMBLE
-DNUKI_NO_WDT_RESET
-DNUKI_MUTEX_RECURSIVE
-DNUKI_64BIT_TIME
-DDEBUG_NUKIHUB
- -DDEBUG_SENSE_NUKI
- -DDEBUG_NUKI_COMMAND
- -DDEBUG_NUKI_CONNECT
- -DDEBUG_NUKI_COMMUNICATION
- ;-DDEBUG_NUKI_HEX_DATA
- -DDEBUG_NUKI_READABLE_DATA
+ -DDEBUG_SENSE_NUKI
+ -DDEBUG_NUKI_COMMAND
+ -DDEBUG_NUKI_CONNECT
+ -DDEBUG_NUKI_COMMUNICATION
+ ;-DDEBUG_NUKI_HEX_DATA
+ -DDEBUG_NUKI_READABLE_DATA
[env:esp32solo1_dbg]
extends = env:esp32solo1
custom_build = debug
build_flags =
- ${env.build_flags}
+ ${env.build_flags}
-DFRAMEWORK_ARDUINO_SOLO1
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
- -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0
+ -DNUKI_ALT_CONNECT
-DNUKI_64BIT_TIME
-DDEBUG_NUKIHUB
- -DDEBUG_SENSE_NUKI
- -DDEBUG_NUKI_COMMAND
- -DDEBUG_NUKI_CONNECT
- -DDEBUG_NUKI_COMMUNICATION
- ;-DDEBUG_NUKI_HEX_DATA
- -DDEBUG_NUKI_READABLE_DATA
\ No newline at end of file
+ -DDEBUG_SENSE_NUKI
+ -DDEBUG_NUKI_COMMAND
+ -DDEBUG_NUKI_CONNECT
+ -DDEBUG_NUKI_COMMUNICATION
+ ;-DDEBUG_NUKI_HEX_DATA
+ -DDEBUG_NUKI_READABLE_DATA
\ No newline at end of file
diff --git a/sdkconfig.defaults b/sdkconfig.defaults
index 4e3f25b..c09044d 100644
--- a/sdkconfig.defaults
+++ b/sdkconfig.defaults
@@ -14,6 +14,10 @@ CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y
CONFIG_BT_NIMBLE_LOG_LEVEL=0
+CONFIG_BT_NIMBLE_MAX_CONNECTIONS=8
+CONFIG_BT_NIMBLE_MAX_BONDS=8
+CONFIG_BT_NIMBLE_NVS_PERSIST=y
+CONFIG_BT_NIMBLE_GATT_MAX_PROCS=8
CONFIG_NIMBLE_PINNED_TO_CORE_0=y
CONFIG_NIMBLE_PINNED_TO_CORE=0
CONFIG_NIMBLE_TASK_STACK_SIZE=8192
@@ -37,6 +41,7 @@ CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=30
CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=8
+CONFIG_BTDM_CTRL_MODEM_SLEEP=n
CONFIG_NIMBLE_HS_FLOW_CTRL=y
CONFIG_NIMBLE_HS_FLOW_CTRL_ITVL=1000
CONFIG_NIMBLE_HS_FLOW_CTRL_THRESH=2
@@ -44,8 +49,9 @@ CONFIG_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT=y
CONFIG_NIMBLE_RPA_TIMEOUT=900
CONFIG_NIMBLE_CRYPTO_STACK_MBEDTLS=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
-CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN=3
-CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=3
+CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN=8
+CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=8
+CONFIG_BT_ACL_CONNECTIONS=8
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
@@ -64,4 +70,5 @@ CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n
CONFIG_IEEE802154_ENABLED=n
CONFIG_ARDUINO_SELECTIVE_COMPILATION=y
CONFIG_ARDUINO_SELECTIVE_HTTPClient=n
-CONFIG_ARDUINO_SELECTIVE_WebServer=n
\ No newline at end of file
+CONFIG_ARDUINO_SELECTIVE_WebServer=n
+CONFIG_HEAP_TASK_TRACKING=n
\ No newline at end of file
diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp
index bf8c61d..069bdcb 100644
--- a/src/NukiNetworkLock.cpp
+++ b/src/NukiNetworkLock.cpp
@@ -113,7 +113,7 @@ void NukiNetworkLock::initialize()
//_network->removeTopic(_mqttPath, mqtt_topic_presence);
}
- if(!_preferences->getBool(preference_conf_info_enabled, false))
+ if(!_preferences->getBool(preference_conf_info_enabled, true))
{
_network->removeTopic(_mqttPath, mqtt_topic_config_basic_json);
_network->removeTopic(_mqttPath, mqtt_topic_config_advanced_json);
diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp
index 2a0c047..433f094 100644
--- a/src/NukiNetworkOpener.cpp
+++ b/src/NukiNetworkOpener.cpp
@@ -69,7 +69,7 @@ void NukiNetworkOpener::initialize()
//_network->removeTopic(_mqttPath, mqtt_topic_presence);
}
- if(!_preferences->getBool(preference_conf_info_enabled, false))
+ if(!_preferences->getBool(preference_conf_info_enabled, true))
{
_network->removeTopic(_mqttPath, mqtt_topic_config_basic_json);
_network->removeTopic(_mqttPath, mqtt_topic_config_advanced_json);
@@ -156,7 +156,7 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
strcmp(value, "denied") == 0 ||
strcmp(value, "error") == 0) return;
- Log->print(F("Lock action received: "));
+ Log->print(F("Opener action received: "));
Log->println(value);
LockActionResult lockActionResult = LockActionResult::Failed;
if(_lockActionReceivedCallback != NULL)
diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp
index da9d644..651f2d0 100644
--- a/src/NukiOpenerWrapper.cpp
+++ b/src/NukiOpenerWrapper.cpp
@@ -24,10 +24,10 @@ NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId
nukiOpenerInst = this;
- memset(&_lastKeyTurnerState, sizeof(NukiLock::KeyTurnerState), 0);
- memset(&_lastBatteryReport, sizeof(NukiLock::BatteryReport), 0);
- memset(&_batteryReport, sizeof(NukiLock::BatteryReport), 0);
- memset(&_keyTurnerState, sizeof(NukiLock::KeyTurnerState), 0);
+ memset(&_lastKeyTurnerState, sizeof(NukiOpener::OpenerState), 0);
+ memset(&_lastBatteryReport, sizeof(NukiOpener::BatteryReport), 0);
+ memset(&_batteryReport, sizeof(NukiOpener::BatteryReport), 0);
+ memset(&_keyTurnerState, sizeof(NukiOpener::OpenerState), 0);
_keyTurnerState.lockState = NukiOpener::LockState::Undefined;
network->setLockActionReceivedCallback(nukiOpenerInst->onLockActionReceivedCallback);
@@ -48,6 +48,19 @@ NukiOpenerWrapper::~NukiOpenerWrapper()
void NukiOpenerWrapper::initialize()
{
_nukiOpener.initialize();
+
+ esp_power_level_t powerLevel;
+
+ if(_preferences->getInt(preference_ble_tx_power, 9) >= 9) powerLevel = ESP_PWR_LVL_P9;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= 6) powerLevel = ESP_PWR_LVL_P6;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= 3) powerLevel = ESP_PWR_LVL_P6;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= 0) powerLevel = ESP_PWR_LVL_P3;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -3) powerLevel = ESP_PWR_LVL_N3;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -6) powerLevel = ESP_PWR_LVL_N6;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -9) powerLevel = ESP_PWR_LVL_N9;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -12) powerLevel = ESP_PWR_LVL_N12;
+
+ _nukiOpener.setPower(powerLevel);
_nukiOpener.registerBleScanner(_bleScanner);
_intervalLockstate = _preferences->getInt(preference_query_interval_lockstate);
@@ -103,9 +116,10 @@ void NukiOpenerWrapper::initialize()
}
_nukiOpener.setEventHandler(this);
+ _nukiOpener.setConnectTimeout(3);
_nukiOpener.setDisconnectTimeout(5000);
- Log->print(F("Lock state interval: "));
+ Log->print(F("Opener state interval: "));
Log->print(_intervalLockstate);
Log->print(F(" | Battery interval: "));
Log->print(_intervalBattery);
@@ -219,33 +233,23 @@ void NukiOpenerWrapper::update()
updateKeypad(false);
}
- if(_nextLockAction != (NukiOpener::LockAction)0xff && ts > _nextRetryTs)
+ if(_nextLockAction != (NukiOpener::LockAction)0xff)
{
- Nuki::CmdResult cmdResult = _nukiOpener.lockAction(_nextLockAction, 0, 0);
- delay(250);
+ _retryCount = 0;
+ Nuki::CmdResult cmdResult;
- char resultStr[15] = {0};
- NukiOpener::cmdResultToString(cmdResult, resultStr);
-
- _network->publishCommandResult(resultStr);
-
- Log->print(F("Lock action result: "));
- Log->println(resultStr);
-
- if(cmdResult == Nuki::CmdResult::Success)
+ while(_retryCount < _nrOfRetries + 1 && cmdResult != Nuki::CmdResult::Success)
{
- _retryCount = 0;
- _nextLockAction = (NukiOpener::LockAction) 0xff;
- _network->publishRetry("--");
+ cmdResult = _nukiOpener.lockAction(_nextLockAction, 0, 0);
+ char resultStr[15] = {0};
+ NukiOpener::cmdResultToString(cmdResult, resultStr);
- if(_intervalLockstate > 10)
- {
- _nextLockStateUpdateTs = ts + 10 * 1000;
- }
- }
- else
- {
- if(_retryCount < _nrOfRetries)
+ _network->publishCommandResult(resultStr);
+
+ Log->print(F("Opener action result: "));
+ Log->println(resultStr);
+
+ if(cmdResult != Nuki::CmdResult::Success)
{
Log->print(F("Opener: Last command failed, retrying after "));
Log->print(_retryDelay);
@@ -256,20 +260,27 @@ void NukiOpenerWrapper::update()
_network->publishRetry(std::to_string(_retryCount + 1));
- _nextRetryTs = (esp_timer_get_time() / 1000) + _retryDelay;
+ delay(_retryDelay);
++_retryCount;
}
- else
- {
- Log->println(F("Opener: Maximum number of retries exceeded, aborting."));
- _network->publishRetry("failed");
- _retryCount = 0;
- _nextRetryTs = 0;
- _nextLockAction = (NukiOpener::LockAction) 0xff;
- }
+ postponeBleWatchdog();
+ }
+
+ if(cmdResult == Nuki::CmdResult::Success)
+ {
+ _nextLockAction = (NukiOpener::LockAction) 0xff;
+ _network->publishRetry("--");
+ _retryCount = 0;
+ if(_intervalLockstate > 10) _nextLockStateUpdateTs = ts + 10 * 1000;
+ }
+ else
+ {
+ Log->println(F("Opener: Maximum number of retries exceeded, aborting."));
+ _network->publishRetry("failed");
+ _retryCount = 0;
+ _nextLockAction = (NukiOpener::LockAction) 0xff;
}
- postponeBleWatchdog();
}
if(_clearAuthData)
@@ -349,7 +360,7 @@ void NukiOpenerWrapper::updateKeyTurnerState()
{
Log->print(F("Querying opener state: "));
result =_nukiOpener.requestOpenerState(&_keyTurnerState);
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -459,7 +470,7 @@ void NukiOpenerWrapper::updateConfig()
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2 > 0;
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
- if(_preferences->getBool(preference_conf_info_enabled, false)) _network->publishConfig(_nukiConfig);
+ if(_preferences->getBool(preference_conf_info_enabled, true)) _network->publishConfig(_nukiConfig);
_retryConfigCount = 0;
if(_preferences->getBool(preference_timecontrol_info_enabled)) updateTimeControl(false);
@@ -473,7 +484,7 @@ void NukiOpenerWrapper::updateConfig()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiOpener.verifySecurityPin();
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -513,7 +524,7 @@ void NukiOpenerWrapper::updateConfig()
}
if(_nukiAdvancedConfigValid && _preferences->getUInt(preference_nuki_id_opener, 0) == _nukiConfig.nukiId)
{
- if(_preferences->getBool(preference_conf_info_enabled, false)) _network->publishAdvancedConfig(_nukiAdvancedConfig);
+ if(_preferences->getBool(preference_conf_info_enabled, true)) _network->publishAdvancedConfig(_nukiAdvancedConfig);
_retryConfigCount = 0;
}
else
@@ -538,7 +549,6 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
if(!retrieved)
{
- delay(250);
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
@@ -546,7 +556,7 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
{
Log->print(F("Retrieve log entries: "));
result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -604,6 +614,12 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
{
if(!_preferences->getBool(preference_keypad_info_enabled)) return;
+ if(!isPinValid())
+ {
+ Log->println(F("No valid Nuki Opener PIN set"));
+ return;
+ }
+
if(!retrieved)
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
@@ -613,7 +629,7 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
{
Log->print(F("Querying opener keypad: "));
result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -631,7 +647,7 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
std::list entries;
_nukiOpener.getKeypadEntries(&entries);
- Log->print(F("Lock keypad codes: "));
+ Log->print(F("Opener keypad codes: "));
Log->println(entries.size());
entries.sort([](const NukiOpener::KeypadEntry& a, const NukiOpener::KeypadEntry& b) { return a.codeId < b.codeId; });
@@ -665,6 +681,12 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
{
if(!_preferences->getBool(preference_timecontrol_info_enabled)) return;
+ if(!isPinValid())
+ {
+ Log->println(F("No valid Nuki Opener PIN set"));
+ return;
+ }
+
if(!retrieved)
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
@@ -674,7 +696,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
{
Log->print(F("Querying opener time control: "));
result = _nukiOpener.retrieveTimeControlEntries();
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -1509,7 +1531,6 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
result = _nukiOpener.addKeypadEntry(entry);
- delay(250);
Log->print("Add keypad code: ");
Log->println((int)result);
updateKeypad(false);
@@ -1523,7 +1544,6 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
}
result = _nukiOpener.deleteKeypadEntry(id);
- delay(250);
Log->print("Delete keypad code: ");
Log->println((int)result);
updateKeypad(false);
@@ -1559,8 +1579,7 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
entry.code = codeInt;
entry.enabled = enabled == 0 ? 0 : 1;
result = _nukiOpener.updateKeypadEntry(entry);
- delay(250);
- Log->print("Update keypad code: ");
+ Log->print("Update keypad code: ");
Log->println((int)result);
updateKeypad(false);
}
@@ -1677,7 +1696,6 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
if(idExists)
{
result = _nukiOpener.deleteKeypadEntry(codeId);
- delay(250);
Log->print(F("Delete keypad code: "));
Log->println((int)result);
}
@@ -1864,7 +1882,6 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
}
result = _nukiOpener.addKeypadEntry(entry);
- delay(250);
Log->print(F("Add keypad code: "));
Log->println((int)result);
}
@@ -1883,11 +1900,11 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
}
Nuki::CmdResult resultKp = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
- delay(250);
bool foundExisting = false;
if(resultKp == Nuki::CmdResult::Success)
{
+ delay(250);
std::list entries;
_nukiOpener.getKeypadEntries(&entries);
@@ -2012,7 +2029,6 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
}
result = _nukiOpener.updateKeypadEntry(entry);
- delay(250);
Log->print(F("Update keypad code: "));
Log->println((int)result);
}
@@ -2119,7 +2135,6 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
if(idExists)
{
result = _nukiOpener.removeTimeControlEntry(entryId);
- delay(250);
Log->print(F("Delete time control: "));
Log->println((int)result);
}
@@ -2178,7 +2193,6 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
entry.lockAction = timeControlLockAction;
result = _nukiOpener.addTimeControlEntry(entry);
- delay(250);
Log->print(F("Add time control: "));
Log->println((int)result);
}
@@ -2191,11 +2205,11 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
}
Nuki::CmdResult resultTc = _nukiOpener.retrieveTimeControlEntries();
- delay(250);
bool foundExisting = false;
if(resultTc == Nuki::CmdResult::Success)
{
+ delay(250);
std::list timeControlEntries;
_nukiOpener.getTimeControlEntries(&timeControlEntries);
@@ -2241,7 +2255,6 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
entry.lockAction = timeControlLockAction;
result = _nukiOpener.updateTimeControlEntry(entry);
- delay(250);
Log->print(F("Update time control: "));
Log->println((int)result);
}
@@ -2318,7 +2331,6 @@ void NukiOpenerWrapper::readConfig()
while(_retryCount < _nrOfRetries + 1)
{
Nuki::CmdResult result = _nukiOpener.requestConfig(&_nukiConfig);
- delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid) {
@@ -2329,6 +2341,7 @@ void NukiOpenerWrapper::readConfig()
char resultStr[20];
NukiOpener::cmdResultToString(result, resultStr);
+ Log->print(F("Opener config result: "));
Log->println(resultStr);
postponeBleWatchdog();
}
@@ -2341,7 +2354,6 @@ void NukiOpenerWrapper::readAdvancedConfig()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiOpener.requestAdvancedConfig(&_nukiAdvancedConfig);
- delay(250);
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiAdvancedConfigValid) {
@@ -2352,6 +2364,7 @@ void NukiOpenerWrapper::readAdvancedConfig()
char resultStr[20];
NukiOpener::cmdResultToString(result, resultStr);
+ Log->print(F("Opener advanced config result: "));
Log->println(resultStr);
postponeBleWatchdog();
}
@@ -2383,7 +2396,6 @@ void NukiOpenerWrapper::disableHASS()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiOpener.requestConfig(&_nukiConfig);
- delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid) {
diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp
index e470001..b8d9136 100644
--- a/src/NukiWrapper.cpp
+++ b/src/NukiWrapper.cpp
@@ -51,8 +51,20 @@ NukiWrapper::~NukiWrapper()
void NukiWrapper::initialize(const bool& firstStart)
{
-
_nukiLock.initialize();
+
+ esp_power_level_t powerLevel;
+
+ if(_preferences->getInt(preference_ble_tx_power, 9) >= 9) powerLevel = ESP_PWR_LVL_P9;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= 6) powerLevel = ESP_PWR_LVL_P6;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= 3) powerLevel = ESP_PWR_LVL_P6;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= 0) powerLevel = ESP_PWR_LVL_P3;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -3) powerLevel = ESP_PWR_LVL_N3;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -6) powerLevel = ESP_PWR_LVL_N6;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -9) powerLevel = ESP_PWR_LVL_N9;
+ else if(_preferences->getInt(preference_ble_tx_power, 9) >= -12) powerLevel = ESP_PWR_LVL_N12;
+
+ _nukiLock.setPower(powerLevel);
_nukiLock.registerBleScanner(_bleScanner);
_intervalLockstate = _preferences->getInt(preference_query_interval_lockstate);
@@ -75,7 +87,7 @@ void NukiWrapper::initialize(const bool& firstStart)
Log->println("First start, setting preference defaults");
_preferences->putBool(preference_network_wifi_fallback_disabled, false);
_preferences->putBool(preference_find_best_rssi, false);
- _preferences->putBool(preference_check_updates, true);
+ _preferences->putBool(preference_check_updates, true);
_preferences->putBool(preference_opener_continuous_mode, false);
_preferences->putBool(preference_network_wifi_fallback_disabled, false);
_preferences->putBool(preference_official_hybrid, false);
@@ -83,7 +95,7 @@ void NukiWrapper::initialize(const bool& firstStart)
_preferences->putBool(preference_official_hybrid_retry, false);
_preferences->putBool(preference_disable_non_json, false);
_preferences->putBool(preference_update_from_mqtt, false);
- _preferences->putBool(preference_ip_dhcp_enabled, true);
+ _preferences->putBool(preference_ip_dhcp_enabled, true);
_preferences->putBool(preference_enable_bootloop_reset, false);
_preferences->putBool(preference_show_secrets, false);
@@ -105,7 +117,7 @@ void NukiWrapper::initialize(const bool& firstStart)
_preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
_preferences->putInt(preference_authlog_max_entries, MAX_AUTHLOG);
_preferences->putInt(preference_keypad_max_entries, MAX_KEYPAD);
- _preferences->putInt(preference_timecontrol_max_entries, MAX_TIMECONTROL);
+ _preferences->putInt(preference_timecontrol_max_entries, MAX_TIMECONTROL);
_preferences->putInt(preference_query_interval_hybrid_lockstate, 600);
_preferences->putInt(preference_rssi_publish_interval, 60);
_preferences->putInt(preference_network_timeout, 60);
@@ -171,8 +183,9 @@ void NukiWrapper::initialize(const bool& firstStart)
_restartBeaconTimeout = -1;
_preferences->putInt(preference_restart_ble_beacon_lost, _restartBeaconTimeout);
}
-
+
_nukiLock.setEventHandler(this);
+ _nukiLock.setConnectTimeout(3);
_nukiLock.setDisconnectTimeout(5000);
Log->print(F("Lock state interval: "));
@@ -232,99 +245,28 @@ void NukiWrapper::update()
_nukiLock.updateConnectionState();
- if(_statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
- {
- Log->println("Updating Lock state based on timer or query");
- _statusUpdated = false;
- _nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
- updateKeyTurnerState();
- _network->publishStatusUpdated(_statusUpdated);
- }
if(networkInst->_offCommandExecutedTs>0 && ts >= networkInst->_offCommandExecutedTs)
{
nukiInst->_nextLockAction = networkInst->_offCommand;
networkInst->_offCommandExecutedTs = 0;
}
- if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0)
+ if(_nextLockAction != (NukiLock::LockAction)0xff)
{
- Log->println("Updating Lock battery state based on timer or query");
- _nextBatteryReportTs = ts + _intervalBattery * 1000;
- updateBatteryState();
- }
- if(_nextConfigUpdateTs == 0 || ts > _nextConfigUpdateTs || (queryCommands & QUERY_COMMAND_CONFIG) > 0)
- {
- Log->println("Updating Lock config based on timer or query");
- _nextConfigUpdateTs = ts + _intervalConfig * 1000;
- updateConfig();
- if(_hassEnabled && !_hassSetupCompleted)
+ _retryCount = 0;
+ Nuki::CmdResult cmdResult;
+
+ while(_retryCount < _nrOfRetries + 1 && cmdResult != Nuki::CmdResult::Success)
{
- setupHASS();
- }
- }
- if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs)
- {
- _waitAuthLogUpdateTs = 0;
- updateAuthData(true);
- }
- if(_waitKeypadUpdateTs != 0 && ts > _waitKeypadUpdateTs)
- {
- _waitKeypadUpdateTs = 0;
- updateKeypad(true);
- }
- if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs)
- {
- _waitTimeControlUpdateTs = 0;
- updateTimeControl(true);
- }
- if(_hassEnabled && _configRead && _network->reconnected())
- {
- setupHASS();
- }
- if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
- {
- _nextRssiTs = ts + _rssiPublishInterval;
+ cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0);
+ char resultStr[15] = {0};
+ NukiLock::cmdResultToString(cmdResult, resultStr);
- int rssi = _nukiLock.getRssi();
- if(rssi != _lastRssi)
- {
- _network->publishRssi(rssi);
- _lastRssi = rssi;
- }
- }
+ _network->publishCommandResult(resultStr);
- 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;
- updateKeypad(false);
- }
+ Log->print(F("Lock action result: "));
+ Log->println(resultStr);
- if(_nextLockAction != (NukiLock::LockAction)0xff && ts > _nextRetryTs)
- {
- Nuki::CmdResult cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0);
-
- char resultStr[15] = {0};
- NukiLock::cmdResultToString(cmdResult, resultStr);
-
- _network->publishCommandResult(resultStr);
-
- Log->print(F("Lock action result: "));
- Log->println(resultStr);
-
- if(cmdResult == Nuki::CmdResult::Success)
- {
- _retryCount = 0;
- _nextLockAction = (NukiLock::LockAction) 0xff;
- _network->publishRetry("--");
-
- if(_intervalLockstate > 10)
- {
- _nextLockStateUpdateTs = ts + 10 * 1000;
- }
- }
- else
- {
- if(_retryCount < _nrOfRetries)
+ if(cmdResult != Nuki::CmdResult::Success)
{
Log->print(F("Lock: Last command failed, retrying after "));
Log->print(_retryDelay);
@@ -335,22 +277,93 @@ void NukiWrapper::update()
_network->publishRetry(std::to_string(_retryCount + 1));
- _nextRetryTs = (esp_timer_get_time() / 1000) + _retryDelay;
+ delay(_retryDelay);
++_retryCount;
}
- else
+ postponeBleWatchdog();
+ }
+
+ if(cmdResult == Nuki::CmdResult::Success)
+ {
+ _nextLockAction = (NukiLock::LockAction) 0xff;
+ _network->publishRetry("--");
+ _retryCount = 0;
+ if(!_network->_offConnected) _statusUpdated = true; Log->println(F("Lock: updating status after action"));
+ _statusUpdatedTs = ts;
+ if(_intervalLockstate > 10) _nextLockStateUpdateTs = ts + 10 * 1000;
+ }
+ else
+ {
+ Log->println(F("Lock: Maximum number of retries exceeded, aborting."));
+ _network->publishRetry("failed");
+ _retryCount = 0;
+ _nextLockAction = (NukiLock::LockAction) 0xff;
+ }
+ }
+ if(_statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
+ {
+ Log->println("Updating Lock state based on status, timer or query");
+ _statusUpdated = false;
+ _nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
+ updateKeyTurnerState();
+ _network->publishStatusUpdated(_statusUpdated);
+ }
+ if(!_statusUpdated)
+ {
+ if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0)
+ {
+ Log->println("Updating Lock battery state based on timer or query");
+ _nextBatteryReportTs = ts + _intervalBattery * 1000;
+ updateBatteryState();
+ }
+ if(_nextConfigUpdateTs == 0 || ts > _nextConfigUpdateTs || (queryCommands & QUERY_COMMAND_CONFIG) > 0)
+ {
+ Log->println("Updating Lock config based on timer or query");
+ _nextConfigUpdateTs = ts + _intervalConfig * 1000;
+ updateConfig();
+ if(_hassEnabled && !_hassSetupCompleted)
{
- Log->println(F("Lock: Maximum number of retries exceeded, aborting."));
- _network->publishRetry("failed");
- _retryCount = 0;
- _nextRetryTs = 0;
- _nextLockAction = (NukiLock::LockAction) 0xff;
+ setupHASS();
}
}
- postponeBleWatchdog();
- }
+ if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs)
+ {
+ _waitAuthLogUpdateTs = 0;
+ updateAuthData(true);
+ }
+ if(_waitKeypadUpdateTs != 0 && ts > _waitKeypadUpdateTs)
+ {
+ _waitKeypadUpdateTs = 0;
+ updateKeypad(true);
+ }
+ if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs)
+ {
+ _waitTimeControlUpdateTs = 0;
+ updateTimeControl(true);
+ }
+ if(_hassEnabled && _configRead && _network->reconnected())
+ {
+ setupHASS();
+ }
+ if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
+ {
+ _nextRssiTs = ts + _rssiPublishInterval;
+ int rssi = _nukiLock.getRssi();
+ if(rssi != _lastRssi)
+ {
+ _network->publishRssi(rssi);
+ _lastRssi = rssi;
+ }
+ }
+ 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;
+ updateKeypad(false);
+ }
+ }
if(_clearAuthData)
{
Log->println("Clearing Lock auth data");
@@ -417,7 +430,7 @@ void NukiWrapper::updateKeyTurnerState()
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
-
+
Log->println("Querying lock state");
while(_retryCount < _nrOfRetries + 1)
@@ -426,7 +439,6 @@ void NukiWrapper::updateKeyTurnerState()
Log->print(_retryCount + 1);
Log->print("): ");
result =_nukiLock.requestKeyTurnerState(&_keyTurnerState);
- delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
@@ -455,19 +467,36 @@ void NukiWrapper::updateKeyTurnerState()
}
_retryLockstateCount = 0;
+
+ const NukiLock::LockState& lockState = _keyTurnerState.lockState;
- if(_publishAuthData)
+ if(lockState != _lastKeyTurnerState.lockState) _statusUpdatedTs = esp_timer_get_time() / 1000;
+
+ if(lockState == NukiLock::LockState::Locked ||
+ lockState == NukiLock::LockState::Unlocked ||
+ lockState == NukiLock::LockState::Calibration ||
+ lockState == NukiLock::LockState::BootRun ||
+ lockState == NukiLock::LockState::MotorBlocked)
{
- Log->println(F("Publishing auth data"));
- updateAuthData(false);
- Log->println(F("Done publishing auth data"));
- }
+ if(_publishAuthData && (lockState == NukiLock::LockState::Locked || lockState == NukiLock::LockState::Unlocked))
+ {
+ Log->println(F("Publishing auth data"));
+ updateAuthData(false);
+ Log->println(F("Done publishing auth data"));
+ }
+ updateGpioOutputs();
+ }
+ else if(!_network->_offConnected && (esp_timer_get_time() / 1000) < _statusUpdatedTs + 10000)
+ {
+ _statusUpdated = true;
+ Log->println(F("Lock: Keep updating status on intermediate lock state"));
+ }
+
_network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
- updateGpioOutputs();
char lockStateStr[20];
- lockstateToString(_keyTurnerState.lockState, lockStateStr);
+ lockstateToString(lockState, lockStateStr);
Log->println(lockStateStr);
postponeBleWatchdog();
@@ -478,7 +507,7 @@ void NukiWrapper::updateBatteryState()
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
-
+
Log->println("Querying lock battery state");
while(_retryCount < _nrOfRetries + 1)
@@ -487,7 +516,7 @@ void NukiWrapper::updateBatteryState()
Log->print(_retryCount + 1);
Log->print("): ");
result = _nukiLock.requestBatteryReport(&_batteryReport);
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -519,7 +548,7 @@ void NukiWrapper::updateConfig()
Log->print(F("Saving Nuki ID to preferences ("));
Log->print(_nukiConfig.nukiId);
Log->print(" / ");
- Log->print(uidString);
+ Log->print(uidString);
Log->println(")");
_preferences->putUInt(preference_nuki_id_lock, _nukiConfig.nukiId);
}
@@ -544,7 +573,7 @@ void NukiWrapper::updateConfig()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiLock.verifySecurityPin();
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -554,7 +583,7 @@ void NukiWrapper::updateConfig()
if(result != Nuki::CmdResult::Success)
{
Log->println(F("Nuki Lock PIN is invalid"));
- if(pinStatus != 2) {
+ if(pinStatus != 2) {
_preferences->putInt(preference_lock_pin_status, 2);
}
}
@@ -615,7 +644,6 @@ void NukiWrapper::updateAuthData(bool retrieved)
if(!retrieved)
{
- delay(250);
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
@@ -623,7 +651,7 @@ void NukiWrapper::updateAuthData(bool retrieved)
{
Log->print(F("Retrieve log entries: "));
result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -680,6 +708,12 @@ void NukiWrapper::updateKeypad(bool retrieved)
{
if(!_preferences->getBool(preference_keypad_info_enabled)) return;
+ if(!isPinValid())
+ {
+ Log->println(F("No valid Nuki Lock PIN set"));
+ return;
+ }
+
if(!retrieved)
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
@@ -689,7 +723,7 @@ void NukiWrapper::updateKeypad(bool retrieved)
{
Log->print(F("Querying lock keypad: "));
result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -741,6 +775,12 @@ void NukiWrapper::updateTimeControl(bool retrieved)
{
if(!_preferences->getBool(preference_timecontrol_info_enabled)) return;
+ if(!isPinValid())
+ {
+ Log->println(F("No valid Nuki Lock PIN set"));
+ return;
+ }
+
if(!retrieved)
{
Nuki::CmdResult result = (Nuki::CmdResult)-1;
@@ -750,7 +790,7 @@ void NukiWrapper::updateTimeControl(bool retrieved)
{
Log->print(F("Querying lock time control: "));
result = _nukiLock.retrieveTimeControlEntries();
- delay(250);
+
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -986,6 +1026,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
{
_network->_offState = atoi(value);
_statusUpdated = true;
+ Log->println(F("Lock: Updating status on Hybrid state change"));
_network->publishStatusUpdated(_statusUpdated);
NukiLock::lockstateToString((NukiLock::LockState)_network->_offState, str);
_network->publishString(mqtt_topic_lock_state, str, true);
@@ -1002,6 +1043,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
{
_network->_offDoorsensorState = atoi(value);
_statusUpdated = true;
+ Log->println(F("Lock: Updating status on Hybrid door sensor state change"));
_network->publishStatusUpdated(_statusUpdated);
NukiLock::doorSensorStateToString((NukiLock::DoorSensorState)_network->_offDoorsensorState, str);
@@ -1350,7 +1392,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
else jsonResult[basicKeys[i]] = "invalidValue";
}
- delay(250);
if(!cmdResult == Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -1635,7 +1676,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
else jsonResult[advancedKeys[j]] = "invalidValue";
}
- delay(250);
if(!cmdResult == Nuki::CmdResult::Success) {
++_retryCount;
}
@@ -1794,8 +1834,8 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
result = _nukiLock.addKeypadEntry(entry);
- delay(250);
- Log->print("Add keypad code: "); Log->println((int)result);
+ Log->print("Add keypad code: ");
+ Log->println((int)result);
updateKeypad(false);
}
else if(strcmp(command, "delete") == 0)
@@ -1807,8 +1847,8 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
}
result = _nukiLock.deleteKeypadEntry(id);
- delay(250);
- Log->print("Delete keypad code: "); Log->println((int)result);
+ Log->print("Delete keypad code: ");
+ Log->println((int)result);
updateKeypad(false);
}
else if(strcmp(command, "update") == 0)
@@ -1842,8 +1882,8 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
entry.code = codeInt;
entry.enabled = enabled == 0 ? 0 : 1;
result = _nukiLock.updateKeypadEntry(entry);
- delay(250);
- Log->print("Update keypad code: "); Log->println((int)result);
+ Log->print("Update keypad code: ");
+ Log->println((int)result);
updateKeypad(false);
}
else if(strcmp(command, "--") == 0)
@@ -1959,7 +1999,6 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
if(idExists)
{
result = _nukiLock.deleteKeypadEntry(codeId);
- delay(250);
Log->print(F("Delete keypad code: "));
Log->println((int)result);
}
@@ -2146,7 +2185,6 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
}
result = _nukiLock.addKeypadEntry(entry);
- delay(250);
Log->print(F("Add keypad code: "));
Log->println((int)result);
}
@@ -2165,11 +2203,11 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
}
Nuki::CmdResult resultKp = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
- delay(250);
bool foundExisting = false;
if(resultKp == Nuki::CmdResult::Success)
{
+ delay(250);
std::list entries;
_nukiLock.getKeypadEntries(&entries);
@@ -2294,7 +2332,6 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
}
result = _nukiLock.updateKeypadEntry(entry);
- delay(250);
Log->print(F("Update keypad code: "));
Log->println((int)result);
}
@@ -2401,7 +2438,6 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
if(idExists)
{
result = _nukiLock.removeTimeControlEntry(entryId);
- delay(250);
Log->print(F("Delete time control: "));
Log->println((int)result);
}
@@ -2461,7 +2497,6 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
entry.lockAction = timeControlLockAction;
result = _nukiLock.addTimeControlEntry(entry);
- delay(250);
Log->print(F("Add time control: "));
Log->println((int)result);
}
@@ -2474,11 +2509,11 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
}
Nuki::CmdResult resultTc = _nukiLock.retrieveTimeControlEntries();
- delay(250);
bool foundExisting = false;
if(resultTc == Nuki::CmdResult::Success)
{
+ delay(250);
std::list timeControlEntries;
_nukiLock.getTimeControlEntries(&timeControlEntries);
@@ -2525,7 +2560,6 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
entry.lockAction = timeControlLockAction;
result = _nukiLock.updateTimeControlEntry(entry);
- delay(250);
Log->print(F("Update time control: "));
Log->println((int)result);
}
@@ -2590,6 +2624,7 @@ void NukiWrapper::notify(Nuki::EventType eventType)
{
Log->println("KeyTurnerStatusUpdated");
_statusUpdated = true;
+ _statusUpdatedTs = esp_timer_get_time() / 1000;
_network->publishStatusUpdated(_statusUpdated);
}
}
@@ -2604,11 +2639,8 @@ void NukiWrapper::readConfig()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiLock.requestConfig(&_nukiConfig);
- delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
- Log->print(F("Config valid: "));
- Log->println(_nukiConfigValid);
if(!_nukiConfigValid) {
++_retryCount;
Log->println("Retrying in 1s");
@@ -2618,6 +2650,7 @@ void NukiWrapper::readConfig()
char resultStr[20];
NukiLock::cmdResultToString(result, resultStr);
+ Log->print(F("Lock config result: "));
Log->println(resultStr);
}
@@ -2629,7 +2662,6 @@ void NukiWrapper::readAdvancedConfig()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiLock.requestAdvancedConfig(&_nukiAdvancedConfig);
- delay(250);
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiAdvancedConfigValid) {
@@ -2640,6 +2672,7 @@ void NukiWrapper::readAdvancedConfig()
char resultStr[20];
NukiLock::cmdResultToString(result, resultStr);
+ Log->print(F("Lock advanced config result: "));
Log->println(resultStr);
}
@@ -2675,7 +2708,6 @@ void NukiWrapper::disableHASS()
while(_retryCount < _nrOfRetries + 1)
{
result = _nukiLock.requestConfig(&_nukiConfig);
- delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid) {
diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h
index 6ebcaf2..5f09cfe 100644
--- a/src/NukiWrapper.h
+++ b/src/NukiWrapper.h
@@ -127,6 +127,7 @@ private:
int _retryConfigCount = 0;
int _retryLockstateCount = 0;
int _rssiPublishInterval = 0;
+ int64_t _statusUpdatedTs = 0;
int64_t _nextRetryTs = 0;
int64_t _nextLockStateUpdateTs = 0;
int64_t _nextHybridLockStateUpdateTs = 0;
diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h
index 39ad41e..d593280 100644
--- a/src/PreferencesKeys.h
+++ b/src/PreferencesKeys.h
@@ -97,6 +97,7 @@
#define preference_ota_updater_url (char*)"otaUpdUrl"
#define preference_update_from_mqtt (char*)"updMqtt"
#define preference_show_secrets (char*)"showSecr"
+#define preference_ble_tx_power (char*)"bleTxPwr"
#define preference_recon_netw_on_mqtt_discon (char*)"recNtwMqttDis"
inline bool initPreferences(Preferences* preferences)
@@ -250,7 +251,7 @@ private:
preference_official_hybrid, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry, preference_has_mac_saved,
preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2, preference_latest_version, preference_task_size_network, preference_task_size_nuki,
preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries, preference_update_from_mqtt, preference_show_secrets,
- preference_recon_netw_on_mqtt_discon
+ preference_ble_tx_power, preference_recon_netw_on_mqtt_discon
};
std::vector _redact =
{
@@ -280,7 +281,8 @@ private:
preference_rssi_publish_interval, preference_network_timeout, preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_command_nr_of_retries,
preference_command_retry_delay, preference_presence_detection_timeout, preference_query_interval_hybrid_lockstate, preference_latest_version,
- preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries
+ preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries,
+ preference_ble_tx_power
};
std::vector _charPrefs =
{
diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp
index 7362c85..157186c 100644
--- a/src/WebCfgServer.cpp
+++ b/src/WebCfgServer.cpp
@@ -766,7 +766,7 @@ void WebCfgServer::sendSettings()
}
}
- if(pairing && _preferences->getBool(preference_show_secrets))
+ if(pairing)
{
if(_nuki != nullptr)
{
@@ -1119,6 +1119,14 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putInt(preference_command_retry_delay, value.toInt());
configChanged = true;
}
+ else if(key == "TXPWR")
+ {
+ if(value.toInt() >= -12 && value.toInt() <= 9)
+ {
+ _preferences->putInt(preference_ble_tx_power, value.toInt());
+ configChanged = true;
+ }
+ }
#if PRESENCE_DETECTION_ENABLED
else if(key == "PRDTMO")
{
@@ -2530,6 +2538,8 @@ void WebCfgServer::buildNukiConfigHtml(String &response)
printInputField(response, "PRDTMO", "Presence detection timeout (seconds; -1 to disable)", _preferences->getInt(preference_presence_detection_timeout), 10, "");
#endif
printInputField(response, "RSBC", "Restart if bluetooth beacons not received (seconds; -1 to disable)", _preferences->getInt(preference_restart_ble_beacon_lost), 10, "");
+ printInputField(response, "TXPWR", "BLE transmit power in dB (minimum -12, maximum 9)", _preferences->getInt(preference_ble_tx_power, 9), 10, "");
+
response.concat("");
response.concat("
");
response.concat("");
diff --git a/src/main.cpp b/src/main.cpp
index 15e6e16..02756d1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -74,14 +74,19 @@ TaskHandle_t networkTaskHandle = nullptr;
void networkTask(void *pvParameters)
{
int64_t networkLoopTs = 0;
-
+ bool secrets = preferences->getBool(preference_show_secrets);
+
while(true)
{
int64_t ts = (esp_timer_get_time() / 1000);
- if(ts > 120000 && ts < 125000 && bootloopCounter > 0)
+ if(ts > 120000 && ts < 125000)
{
- bootloopCounter = (int8_t)0;
- Log->println(F("Bootloop counter reset"));
+ if(secrets) preferences->putBool(preference_show_secrets, false);
+ if(bootloopCounter > 0)
+ {
+ bootloopCounter = (int8_t)0;
+ Log->println(F("Bootloop counter reset"));
+ }
}
bool connected = network->update();
@@ -99,13 +104,13 @@ void networkTask(void *pvParameters)
#else
webCfgServer->update();
#endif
-
+
if((esp_timer_get_time() / 1000) - networkLoopTs > 120000)
{
Log->println("networkTask is running");
networkLoopTs = esp_timer_get_time() / 1000;
}
-
+
esp_task_wdt_reset();
delay(100);
@@ -116,7 +121,8 @@ void networkTask(void *pvParameters)
void nukiTask(void *pvParameters)
{
int64_t nukiLoopTs = 0;
-
+ bool whiteListed = false;
+
while(true)
{
bleScanner->update();
@@ -128,6 +134,20 @@ void nukiTask(void *pvParameters)
{
delay(5000);
}
+ #ifndef PRESENCE_DETECTION_ENABLED
+ else if (!whiteListed)
+ {
+ whiteListed = true;
+ if(lockEnabled)
+ {
+ bleScanner->whitelist(nuki->getBleAddress());
+ }
+ if(openerEnabled)
+ {
+ bleScanner->whitelist(nukiOpener->getBleAddress());
+ }
+ }
+ #endif
if(lockEnabled)
{
@@ -137,13 +157,13 @@ void nukiTask(void *pvParameters)
{
nukiOpener->update();
}
-
+
if((esp_timer_get_time() / 1000) - nukiLoopTs > 120000)
{
Log->println("nukiTask is running");
nukiLoopTs = esp_timer_get_time() / 1000;
}
-
+
esp_task_wdt_reset();
}
}
@@ -274,7 +294,7 @@ void otaTask(void *pvParameter)
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
-
+
esp_task_wdt_reset();
}
#endif
@@ -282,7 +302,7 @@ void otaTask(void *pvParameter)
void setupTasks(bool ota)
{
// configMAX_PRIORITIES is 25
-
+
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))
esp_task_wdt_init(300, true);
#else
@@ -313,7 +333,7 @@ void setupTasks(bool ota)
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1);
esp_task_wdt_add(networkTaskHandle);
#ifndef NUKI_HUB_UPDATER
- xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 1);
+ xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 0);
esp_task_wdt_add(nukiTaskHandle);
#endif
}
@@ -349,7 +369,7 @@ void setup()
uint8_t partitionType = checkPartition();
initializeRestartReason();
-
+
#ifndef NUKI_HUB_UPDATER
if(preferences->getBool(preference_enable_bootloop_reset, false))
{
@@ -393,7 +413,7 @@ void setup()
// Scan interval and window according to Nuki recommendations:
// https://developer.nuki.io/t/bluetooth-specification-questions/1109/27
bleScanner->initialize("NukiHub", true, 40, 40);
- bleScanner->setScanDuration(10);
+ bleScanner->setScanDuration(0);
#if PRESENCE_DETECTION_ENABLED
if(preferences->getInt(preference_presence_detection_timeout) >= 0)
diff --git a/updater/platformio.ini b/updater/platformio.ini
index 9e81029..afdaa1c 100644
--- a/updater/platformio.ini
+++ b/updater/platformio.ini
@@ -13,7 +13,7 @@ default_envs = updater_esp32dev
boards_dir = ../boards
[env]
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.11/platform-espressif32.zip
+platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.07.11/platform-espressif32.zip
platform_packages =
framework = arduino, espidf
build_type = release