Skip to content

Commit

Permalink
Add query interval settings for Nuki Lock component, Fix alt connect …
Browse files Browse the repository at this point in the history
…mode
  • Loading branch information
AzonInc committed Feb 6, 2025
1 parent be53778 commit c143507
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .github/test-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ lock:
security_pin: 1234
alternative_connect_mode: true
pairing_as_app: false
query_interval_config: 3600s
query_interval_auth_data: 7200s

on_pairing_mode_on_action:
- lambda: ESP_LOGI("nuki_lock", "Pairing mode turned on");
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ lock:
# Optional: Advanced Settings
alternative_connect_mode: true
pairing_as_app: false
query_interval_config: 3600s
query_interval_auth_data: 7200s

# Optional: Binary Sensors
is_connected:
name: "Nuki Connected"
Expand Down Expand Up @@ -135,6 +138,34 @@ After running ESPHome (`esphome run <yamlfile.yaml>`), follow these steps to pai
Your Nuki Smartlock is now connected and ready to use!


## Settings

These settings allow you to customize the behavior of the Nuki Lock component to improve the performance and reliability.
They can be configured in your ESPHome YAML file:

- **pairing_mode_timeout**: The duration (in seconds) for which the pairing mode will be active. Default is `300s`.
- **event**: The event name used for the Nuki Lock component. Default is `nuki`.
- **security_pin**: The Nuki security PIN required for certain operations.
- **alternative_connect_mode**: Enable the alternative connection mode. Disable it if you encounter any issues. Default is `true`.
- **pairing_as_app**: Specify if the pairing should be done as an app (not recommended). Default is `false`.
- **query_interval_config**: The interval (in seconds) at which the configuration will be queried. Default is `3600s`.
- **query_interval_auth_data**: The interval (in seconds) at which the authentication data will be queried. Default is `7200s`.



## Settings

The following settings allow you to customize the behavior of the Nuki Lock component, optimizing its performance and reliability. You can configure these in your ESPHome YAML file:

- **`security_pin`**: The Nuki security PIN required for performing specific operations.
- **`pairing_mode_timeout`**: Specifies how long (in seconds) the pairing mode remains active. Default: `300s`.
- **`event`**: Defines the event name used by the Nuki Lock component. Default: `nuki`.
- **`alternative_connect_mode`**: Enables an alternative connection mode to improve compatibility. If you experience issues, consider disabling this. Default: `true`.
- **`pairing_as_app`**: Determines if pairing should be done as an app. This is not recommended for most setups. Default: `false`.
- **`query_interval_config`**: Sets the interval (in seconds) for querying the configuration. Default: `3600s`.
- **`query_interval_auth_data`**: Sets the interval (in seconds) for querying authentication data. Default: `7200s`.


## Supported Services
### Unlatch
To unlatch doors without a handle, call the `open` service in Home Assistant:
Expand Down
20 changes: 16 additions & 4 deletions components/nuki_lock/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@
CONF_PAIRING_AS_APP = "pairing_as_app"
CONF_SECURITY_PIN = "security_pin"
CONF_ALT_CONNECT_MODE = "alternative_connect_mode"
CONF_QUERY_INTERVAL_CONFIG = "query_interval_config"
CONF_QUERY_INTERVAL_AUTH_DATA = "query_interval_auth_data"
CONF_EVENT = "event"

CONF_SET_PAIRING_MODE = "pairing_mode"
Expand Down Expand Up @@ -392,6 +394,8 @@ def _validate(config):
cv.Optional(CONF_PAIRING_MODE_TIMEOUT, default="300s"): cv.positive_time_period_seconds,
cv.Optional(CONF_EVENT, default="nuki"): cv.string,
cv.Optional(CONF_SECURITY_PIN): cv.uint16_t,
cv.Optional(CONF_QUERY_INTERVAL_CONFIG, default="3600s"): cv.positive_time_period_seconds,
cv.Optional(CONF_QUERY_INTERVAL_AUTH_DATA, default="3600s"): cv.positive_time_period_seconds,
cv.Optional(CONF_ON_PAIRING_MODE_ON): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PairingModeOnTrigger),
Expand Down Expand Up @@ -431,6 +435,18 @@ async def to_code(config):

if CONF_PAIRING_AS_APP in config:
cg.add(var.set_pairing_as_app(config[CONF_PAIRING_AS_APP]))

if config[CONF_ALT_CONNECT_MODE]:
cg.add_define("NUKI_ALT_CONNECT")

if CONF_ALT_CONNECT_MODE in config:
cg.add(var.set_alt_connect_mode(config[CONF_ALT_CONNECT_MODE]))

if CONF_QUERY_INTERVAL_CONFIG in config:
cg.add(var.set_query_interval_config(config[CONF_QUERY_INTERVAL_CONFIG]))

if CONF_QUERY_INTERVAL_AUTH_DATA in config:
cg.add(var.set_query_interval_auth_data(config[CONF_QUERY_INTERVAL_AUTH_DATA]))

# Binary Sensor
if is_connected := config.get(CONF_IS_CONNECTED_BINARY_SENSOR):
Expand Down Expand Up @@ -674,10 +690,6 @@ async def to_code(config):
cg.add_define("NUKI_MUTEX_RECURSIVE")
cg.add_define("NUKI_NO_WDT_RESET")

if CONF_ALT_CONNECT_MODE in config and config[CONF_ALT_CONNECT_MODE]:
cg.add_define("NUKI_ALT_CONNECT")


# Remove Build flags
cg.add_platformio_option(
"build_unflags",
Expand Down
31 changes: 22 additions & 9 deletions components/nuki_lock/nuki_lock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ void NukiLockComponent::update_config() {
if (conf_req_result == Nuki::CmdResult::Success) {
ESP_LOGD(TAG, "requestConfig has resulted in %s (%d)", str, conf_req_result);

keypad_paired_ = config.hasKeypad;
keypad_paired_ = config.hasKeypad || config.hasKeypadV2;

#ifdef USE_SWITCH
if (this->auto_unlatch_enabled_switch_ != nullptr) {
Expand Down Expand Up @@ -973,11 +973,11 @@ void NukiLockComponent::setup() {
}
);

this->scanner_.initialize("ESPHomeNuki");
this->scanner_.setScanDuration(10);
this->scanner_.initialize("ESPHomeNuki", true, 40, 40);
this->scanner_.setScanDuration(0);

this->nuki_lock_.registerBleScanner(&this->scanner_);
this->nuki_lock_.initialize();
this->nuki_lock_.initialize(this->alt_connect_mode_);
this->nuki_lock_.setConnectTimeout(BLE_CONNECT_TIMEOUT_SEC);
this->nuki_lock_.setConnectRetries(BLE_CONNECT_TIMEOUT_RETRIES);

Expand Down Expand Up @@ -1030,12 +1030,12 @@ void NukiLockComponent::setup_intervals(bool setup) {
this->cancel_interval("update_auth_data");

if(setup) {
this->set_interval("update_config", CONFIG_UPDATE_INTERVAL_SEC * 1000, [this]() {
this->set_interval("update_config", this->query_interval_config_ * 1000, [this]() {
this->config_update_ = true;
this->advanced_config_update_ = true;
});

this->set_interval("update_auth_data", AUTH_DATA_UPDATE_INTERVAL_SEC * 1000, [this]() {
this->set_interval("update_auth_data", this->query_interval_auth_data_ * 1000, [this]() {
this->auth_data_update_ = true;
});
}
Expand Down Expand Up @@ -1329,6 +1329,19 @@ void NukiLockComponent::print_keypad_entries() {
void NukiLockComponent::dump_config() {
ESP_LOGCONFIG(TAG, "NUKI LOCK:");

if (strcmp(this->event_, "esphome.none") != 0) {
ESP_LOGCONFIG(TAG, " Event: %s", this->event_);
} else {
ESP_LOGCONFIG(TAG, " Event: Disabled");
}

ESP_LOGCONFIG(TAG, " Pairing Identity: %s",this->pairing_as_app_ ? "App" : "Bridge");
ESP_LOGCONFIG(TAG, " Alternative Connect Mode: %s",YESNO(this->alt_connect_mode_));

ESP_LOGCONFIG(TAG, " Pairing mode timeout: %us", this->pairing_mode_timeout_);
ESP_LOGCONFIG(TAG, " Configuration query interval: %us", this->query_interval_config_);
ESP_LOGCONFIG(TAG, " Auth Data query interval: %us", this->query_interval_auth_data_);

LOG_LOCK(TAG, "Nuki Lock", this);
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(TAG, "Is Connected", this->is_connected_binary_sensor_);
Expand Down Expand Up @@ -1491,7 +1504,7 @@ void NukiLockComponent::set_config_select(const char* config, const char* value)
this->config_update_ = !is_advanced;
this->advanced_config_update_ = is_advanced;
} else {
ESP_LOGW(TAG, "Saving setting failed: %s", config);
ESP_LOGE(TAG, "Saving setting %s failed (result %d)", config, cmd_result);
}
}
#endif
Expand Down Expand Up @@ -1572,7 +1585,7 @@ void NukiLockComponent::set_config_switch(const char* config, bool value) {
this->config_update_ = !is_advanced;
this->advanced_config_update_ = is_advanced;
} else {
ESP_LOGW(TAG, "Saving setting failed: %s", config);
ESP_LOGE(TAG, "Saving setting %s failed (result %d)", config, cmd_result);
}
}
#endif
Expand Down Expand Up @@ -1601,7 +1614,7 @@ void NukiLockComponent::set_config_number(const char* config, float value) {
this->config_update_ = !is_advanced;
this->advanced_config_update_ = is_advanced;
} else {
ESP_LOGW(TAG, "Saving setting failed: %s", config);
ESP_LOGE(TAG, "Saving setting %s failed (result %d)", config, cmd_result);
}
}
#endif
Expand Down
11 changes: 8 additions & 3 deletions components/nuki_lock/nuki_lock.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ class NukiLockComponent : public lock::Lock, public PollingComponent, public Nuk
static const uint32_t COOLDOWN_COMMANDS_MILLIS = 1000;
static const uint32_t COOLDOWN_COMMANDS_EXTENDED_MILLIS = 3000;

static const uint8_t CONFIG_UPDATE_INTERVAL_SEC = 60;
static const uint8_t AUTH_DATA_UPDATE_INTERVAL_SEC = 120;
static const uint8_t MAX_AUTH_DATA_ENTRIES = 10;
static const uint8_t MAX_EVENT_LOG_ENTRIES = 3;

Expand All @@ -126,8 +124,11 @@ class NukiLockComponent : public lock::Lock, public PollingComponent, public Nuk
void notify(Nuki::EventType event_type) override;
float get_setup_priority() const override { return setup_priority::HARDWARE - 1.0f; }

void set_alt_connect_mode(bool alt_connect_mode) { this->alt_connect_mode_ = alt_connect_mode; }
void set_pairing_as_app(bool pairing_as_app) { this->pairing_as_app_ = pairing_as_app; }
void set_pairing_mode_timeout(uint16_t pairing_mode_timeout) { this->pairing_mode_timeout_ = pairing_mode_timeout; }
void set_query_interval_config(uint16_t query_interval_config) { this->query_interval_config_ = query_interval_config; }
void set_query_interval_auth_data(uint16_t query_interval_auth_data) { this->query_interval_auth_data_ = query_interval_auth_data; }
void set_event(const char *event) {
this->event_ = event;
if(strcmp(event, "esphome.none") != 0) {
Expand Down Expand Up @@ -221,9 +222,13 @@ class NukiLockComponent : public lock::Lock, public PollingComponent, public Nuk
const char* event_;
bool send_events_ = false;

bool alt_connect_mode_ = false;

uint16_t query_interval_auth_data_ = 0;
uint16_t query_interval_config_ = 0;

uint16_t pairing_mode_timeout_ = 0;
bool pairing_mode_ = false;
uint32_t pairing_mode_timer_ = 0;

uint32_t last_rolling_log_id = 0;

Expand Down

0 comments on commit c143507

Please sign in to comment.