Sync time to the lock automatically

This commit is contained in:
2024-06-10 22:19:33 +02:00
parent a06d6f74c1
commit 9d6fa7f4e4
5 changed files with 99 additions and 3 deletions
+13 -2
View File
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
import esphome.const as c
from esphome.components import lock, binary_sensor, text_sensor, sensor, button
from esphome.components import lock, binary_sensor, text_sensor, sensor, button, time
AUTO_LOAD = ["binary_sensor", "text_sensor", "sensor", "button"]
@@ -32,6 +32,7 @@ CONF_REQUEST_BATTERY_REPORTS = "request_battery_reports"
CONF_RESTART_AFTER_BEACON_LATENCY = "restart_after_beacon_latency"
CONF_REQUEST_STATE = "request_state"
CONF_UNPAIR = "unpair"
CONF_TIME_SOURCE = "time_source"
nuki_lock_ns = cg.esphome_ns.namespace("nuki_lock")
NukiLockComponent = nuki_lock_ns.class_("NukiLockComponent", lock.Lock, cg.PollingComponent)
@@ -184,6 +185,7 @@ CONFIG_SCHEMA = lock.LOCK_SCHEMA.extend({
unit_of_measurement=c.UNIT_AMPERE,
device_class=c.DEVICE_CLASS_CURRENT,
accuracy_decimals=3,
# DEFAULT DISABLE. A few others, too.
),
# Configuration.
@@ -203,8 +205,11 @@ CONFIG_SCHEMA = lock.LOCK_SCHEMA.extend({
entity_category=c.ENTITY_CATEGORY_CONFIG,
icon="mdi:close",
),
}).extend(cv.polling_component_schema("30min"))
# Time autoupdate.
cv.Optional(c.CONF_PIN): cv.positive_int,
cv.Optional(CONF_TIME_SOURCE): cv.use_id(time.RealTimeClock),
}).extend(cv.polling_component_schema("30min"))
async def to_code(config):
var = cg.new_Pvariable(config[c.CONF_ID])
@@ -269,3 +274,9 @@ async def to_code(config):
if CONF_RESTART_AFTER_BEACON_LATENCY in config:
cg.add(var.set_restart_after_beacon_latency(config[CONF_RESTART_AFTER_BEACON_LATENCY]))
if c.CONF_PIN in config:
cg.add(var.set_pin(config[c.CONF_PIN]))
if CONF_TIME_SOURCE in config:
cg.add(var.set_time_source(await cg.get_variable(config[CONF_TIME_SOURCE])))
+59
View File
@@ -231,6 +231,49 @@ bool NukiLockComponent::update_key_turner_state_() {
return true;
}
bool NukiLockComponent::update_lock_time_() {
if (time_source_ == nullptr) {
ESP_LOGE(TAG, "updating lock time failed: time source not set");
return false;
}
Nuki::CmdResult result = nuki_lock_->verifySecurityPin();
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "verifying security pin for lock time update failed: %s",
Adapt::cmd_result_to_string(result).c_str());
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
return false;
}
ESPTime now = time_source_->utcnow();
if (!now.is_valid()) {
ESP_LOGE(TAG, "updating lock time failed: time source is invalid");
return false;
}
Nuki::TimeValue tv = {
.year = now.year,
.month = now.month,
.day = now.day_of_month,
.hour = now.hour,
.minute = now.minute,
.second = now.second,
};
ESP_LOGI(TAG, "Setting lock time: %.4d-%.2d-%.2d %.2d:%.2d:%.2d", tv.year,
tv.month, tv.day, tv.hour, tv.minute, tv.second);
result = nuki_lock_->updateTime(tv);
if (result != Nuki::CmdResult::Success) {
ESP_LOGE(TAG, "updating lock time failed: %s",
Adapt::cmd_result_to_string(result).c_str());
error_text_sensor_->publish_state(
Adapt::error_to_string(nuki_lock_->getLastError()));
return false;
}
return true;
}
bool NukiLockComponent::update_battery_report_() {
NukiLock::BatteryReport batteryReport;
Nuki::CmdResult result =
@@ -304,6 +347,10 @@ void NukiLockComponent::setup() {
nuki_lock_->initialize();
nuki_lock_->setEventHandler(this);
if (pin_set_) {
nuki_lock_->saveSecurityPincode(pin_);
}
bool paired = nuki_lock_->isPairedWithLock();
paired_binary_sensor_->publish_initial_state(paired);
error_text_sensor_->publish_state("No error");
@@ -387,6 +434,10 @@ void NukiLockComponent::ble_loop_() {
void NukiLockComponent::update() {
bool paired = nuki_lock_->isPairedWithLock();
if (paired) {
if (time_source_ != nullptr) {
// Update time first, then request the state so we get updated time.
update_lock_time_();
}
update_key_turner_state_();
if (request_battery_reports_) {
update_battery_report_();
@@ -477,6 +528,14 @@ void NukiLockComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Restart after beacon latency: %dms",
restart_after_beacon_latency_);
if (time_source_ != nullptr) {
ESP_LOGCONFIG(TAG, " Time source: set");
}
if (pin_set_) {
ESP_LOGCONFIG(
TAG, " Pin: " ESPHOME_LOG_SECRET_BEGIN "%d" ESPHOME_LOG_SECRET_END,
pin_);
}
}
} // namespace nuki_lock
+15 -1
View File
@@ -8,7 +8,9 @@
#include "esphome/components/lock/lock.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/text_sensor/text_sensor.h"
#include "esphome/components/time/real_time_clock.h"
#include "esphome/core/component.h"
#include "esphome/core/time.h"
namespace esphome {
namespace nuki_lock {
@@ -22,7 +24,8 @@ class NukiLockComponent : public lock::Lock,
last_passive_update_millis_(0),
restart_after_beacon_latency_(0),
update_scheduled_(false),
request_battery_reports_(false){};
request_battery_reports_(false),
pin_set_(false){};
// Component.
void setup() override;
@@ -81,6 +84,13 @@ class NukiLockComponent : public lock::Lock,
restart_after_beacon_latency_ = value;
}
void set_pin(unsigned long value) {
pin_ = value;
pin_set_ = true;
}
void set_time_source(time::RealTimeClock *value) { time_source_ = value; }
// RequestStateButton.
void schedule_update();
@@ -95,11 +105,15 @@ class NukiLockComponent : public lock::Lock,
private:
bool update_key_turner_state_();
bool update_battery_report_();
bool update_lock_time_();
void ble_loop_();
void send_action_(NukiLock::LockAction action);
NukiLock::NukiLock *nuki_lock_;
BleScanner::Scanner scanner_;
time::RealTimeClock *time_source_{nullptr};
uint16_t pin_;
bool pin_set_;
unsigned long last_passive_update_millis_;
unsigned long restart_after_beacon_latency_;