diff --git a/src/Config.h b/src/Config.h index ac9014d..48f590a 100644 --- a/src/Config.h +++ b/src/Config.h @@ -5,7 +5,7 @@ #define NUKI_HUB_VERSION "9.07" #define NUKI_HUB_VERSION_INT (uint32_t)907 #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2024-12-31" +#define NUKI_HUB_DATE "2025-01-02" #define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json" diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index edcbfe6..8da820d 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -6,6 +6,8 @@ #include #include "Config.h" #include "hal/wdt_hal.h" +#include +#include "esp_sntp.h" NukiOpenerWrapper* nukiOpenerInst; Preferences* nukiOpenerPreferences = nullptr; @@ -55,7 +57,7 @@ void NukiOpenerWrapper::initialize() _nukiOpener.setDebugHexData(_preferences->getBool(preference_debug_hex_data, false)); _nukiOpener.setDebugCommand(_preferences->getBool(preference_debug_command, false)); _nukiOpener.registerLogger(Log); - + _nukiOpener.initialize(_preferences->getBool(preference_connect_mode, true)); _nukiOpener.registerBleScanner(_bleScanner); _nukiOpener.setEventHandler(this); @@ -317,6 +319,11 @@ void NukiOpenerWrapper::update() _waitKeypadUpdateTs = 0; updateKeypad(true); } + if(_preferences->getBool(preference_update_time, false) && ts > (120 * 1000) && ts > _nextTimeUpdateTs) + { + _nextTimeUpdateTs = ts + (12 * 60 * 60 * 1000); + updateTime(); + } if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs) { _waitTimeControlUpdateTs = 0; @@ -4154,3 +4161,39 @@ void NukiOpenerWrapper::updateGpioOutputs() } } } + +void NukiOpenerWrapper::updateTime() +{ + if(!isPinValid()) + { + Log->println(F("No valid PIN set")); + return; + } + + time_t now; + tm tm; + time(&now); + localtime_r(&now, &tm); + + if (int(tm.tm_year + 1900) < int(2025)) + { + Log->println(F("NTP Time not valid, not updating Nuki device")); + return; + } + + Nuki::TimeValue nukiTime; + nukiTime.year = tm.tm_year + 1900; + nukiTime.month = tm.tm_mon + 1; + nukiTime.day = tm.tm_mday; + nukiTime.hour = tm.tm_hour; + nukiTime.minute = tm.tm_min; + nukiTime.second = tm.tm_sec; + + Nuki::CmdResult cmdResult = _nukiOpener.updateTime(nukiTime); + + char resultStr[15] = {0}; + NukiOpener::cmdResultToString(cmdResult, resultStr); + + Log->print(F("Opener time update result: ")); + Log->println(resultStr); +} \ No newline at end of file diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h index a57fc3d..8c7a4fb 100644 --- a/src/NukiOpenerWrapper.h +++ b/src/NukiOpenerWrapper.h @@ -68,6 +68,7 @@ private: void updateTimeControl(bool retrieved); void updateAuth(bool retrieved); void postponeBleWatchdog(); + void updateTime(); void updateGpioOutputs(); @@ -147,6 +148,7 @@ private: int64_t _waitKeypadUpdateTs = 0; int64_t _waitTimeControlUpdateTs = 0; int64_t _waitAuthUpdateTs = 0; + int64_t _nextTimeUpdateTs = 0; int64_t _nextKeypadUpdateTs = 0; int64_t _nextPairTs = 0; int64_t _nextRssiTs = 0; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 3556a45..3ab67ce 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -6,6 +6,8 @@ #include #include "Config.h" #include "hal/wdt_hal.h" +#include +#include "esp_sntp.h" NukiWrapper* nukiInst = nullptr; @@ -19,6 +21,7 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, _gpio(gpio), _preferences(preferences) { + Log->print("Device id lock: "); Log->println(_deviceId->get()); @@ -368,6 +371,11 @@ void NukiWrapper::update() _nextKeypadUpdateTs = ts + _intervalKeypad * 1000; updateKeypad(false); } + if(_preferences->getBool(preference_update_time, false) && ts > (120 * 1000) && ts > _nextTimeUpdateTs) + { + _nextTimeUpdateTs = ts + (12 * 60 * 60 * 1000); + updateTime(); + } } if(_clearAuthData) { @@ -4195,3 +4203,39 @@ void NukiWrapper::updateGpioOutputs() } } } + +void NukiWrapper::updateTime() +{ + if(!isPinValid()) + { + Log->println(F("No valid PIN set")); + return; + } + + time_t now; + tm tm; + time(&now); + localtime_r(&now, &tm); + + if (int(tm.tm_year + 1900) < int(2025)) + { + Log->println(F("NTP Time not valid, not updating Nuki device")); + return; + } + + Nuki::TimeValue nukiTime; + nukiTime.year = tm.tm_year + 1900; + nukiTime.month = tm.tm_mon + 1; + nukiTime.day = tm.tm_mday; + nukiTime.hour = tm.tm_hour; + nukiTime.minute = tm.tm_min; + nukiTime.second = tm.tm_sec; + + Nuki::CmdResult cmdResult = _nukiLock.updateTime(nukiTime); + + char resultStr[15] = {0}; + NukiLock::cmdResultToString(cmdResult, resultStr); + + Log->print(F("Lock time update result: ")); + Log->println(resultStr); +} \ No newline at end of file diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h index 116c4a7..820a062 100644 --- a/src/NukiWrapper.h +++ b/src/NukiWrapper.h @@ -73,6 +73,7 @@ private: void updateTimeControl(bool retrieved); void updateAuth(bool retrieved); void postponeBleWatchdog(); + void updateTime(); void updateGpioOutputs(); @@ -153,6 +154,7 @@ private: int64_t _waitKeypadUpdateTs = 0; int64_t _waitTimeControlUpdateTs = 0; int64_t _waitAuthUpdateTs = 0; + int64_t _nextTimeUpdateTs = 0; int64_t _nextKeypadUpdateTs = 0; int64_t _nextRssiTs = 0; int64_t _lastRssi = 0; diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index e172907..f2c744a 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -68,6 +68,7 @@ #define preference_debug_command (char*)"dbgCommand" #define preference_connect_mode (char*)"nukiConnMode" #define preference_http_auth_type (char*)"httpdAuthType" +#define preference_update_time (char*)"updateTime" // CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT #define preference_find_best_rssi (char*)"nwbestrssi" @@ -369,7 +370,7 @@ private: preference_started_before, preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates, preference_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status, - preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, + preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_update_time, preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type, @@ -398,7 +399,7 @@ private: std::vector _boolPrefs = { preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode, - preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, + preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_update_time, preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, preference_show_secrets, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled, preference_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled, preference_mqtt_hass_enabled, preference_retain_gpio, diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 789b9f5..94b84e9 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -1676,6 +1676,16 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } } #endif + else if(key == "UPTIME") + { + if(_preferences->getBool(preference_update_time, false) != (value == "1")) + { + _preferences->putBool(preference_update_time, (value == "1")); + Log->print(F("Setting changed: ")); + Log->println(key); + configChanged = true; + } + } else if(key == "NWHW") { if(_preferences->getInt(preference_network_hardware, 0) != value.toInt()) @@ -4360,7 +4370,7 @@ esp_err_t WebCfgServer::buildNukiConfigHtml(PsychicRequest *request, PsychicResp } 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, ""); - + printCheckBox(&response, "UPTIME", "Update Nuki Hub and Lock/Opener time using NTP", _preferences->getBool(preference_update_time, false), ""); response.print(""); response.print("
"); response.print(""); diff --git a/src/main.cpp b/src/main.cpp index 430ca33..2961335 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,8 @@ #include "RestartReason.h" #include "EspMillis.h" #include "NimBLEDevice.h" +#include +#include "esp_sntp.h" /* #ifdef DEBUG_NUKIHUB @@ -249,7 +251,6 @@ void nukiTask(void *pvParameters) { int64_t nukiLoopTs = 0; bool whiteListed = false; - while(true) { if(disableNetwork || wifiConnected) @@ -437,7 +438,6 @@ void otaTask(void *pvParameter) vTaskDelay(1000 / portTICK_PERIOD_MS); } } - Log->println("Firmware upgrade failed, restarting"); esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL)); restartEsp(RestartReason::OTAAborted); @@ -480,6 +480,10 @@ void setupTasks(bool ota) } } +void cbSyncTime(struct timeval *tv) { + Log->println(F("NTP time synched")); +} + void setup() { //Set Log level to error for all TAGS @@ -804,6 +808,13 @@ void setup() #endif */ } + + if(preferences->getBool(preference_update_time, false)) + { + sntp_set_sync_interval(12 * 60 * 60 * 1000UL); + sntp_set_time_sync_notification_cb(cbSyncTime); + configTime(0, 0, "pool.ntp.org"); + } #endif if(doOta)