From a8236671201930bca96e49e542b7c9950e950878 Mon Sep 17 00:00:00 2001 From: iranl Date: Mon, 20 May 2024 20:24:02 +0200 Subject: [PATCH 1/4] Update Tasks --- src/MqttTopics.h | 2 ++ src/NetworkLock.cpp | 34 ++++++++++++++++++++++++++++++++-- src/PreferencesKeys.h | 5 +++-- src/WebCfgServer.cpp | 8 ++++++-- src/main.cpp | 26 ++++++++++++++++++-------- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/MqttTopics.h b/src/MqttTopics.h index f52dbbd..d1493e3 100644 --- a/src/MqttTopics.h +++ b/src/MqttTopics.h @@ -70,6 +70,8 @@ #define mqtt_topic_info_nuki_hub_ip "/info/nukiHubIp" #define mqtt_topic_reset "/maintenance/reset" +#define mqtt_topic_webserver_state "/maintenance/webserver/state" +#define mqtt_topic_webserver_action "/maintenance/webserver/enable" #define mqtt_topic_uptime "/maintenance/uptime" #define mqtt_topic_wifi_rssi "/maintenance/wifiRssi" #define mqtt_topic_log "/maintenance/log" diff --git a/src/NetworkLock.cpp b/src/NetworkLock.cpp index 95e7397..f68b2bb 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -53,6 +53,10 @@ void NetworkLock::initialize() _network->subscribe(_mqttPath, mqtt_topic_reset); _network->initTopic(_mqttPath, mqtt_topic_reset, "0"); + _network->subscribe(_mqttPath, mqtt_topic_webserver_action); + _network->initTopic(_mqttPath, mqtt_topic_webserver_action, "--"); + _network->initTopic(_mqttPath, mqtt_topic_webserver_state, _preferences->getBool(preference_webserver_enabled, true) ? 1 : 0); + _network->initTopic(_mqttPath, mqtt_topic_query_config, "0"); _network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0"); _network->initTopic(_mqttPath, mqtt_topic_query_battery, "0"); @@ -102,6 +106,32 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns restartEsp(RestartReason::RequestedViaMqtt); } + if(comparePrefixedPath(topic, mqtt_topic_webserver_action)) + { + if(strcmp(value, "") == 0 || + strcmp(value, "--") == 0) return; + + publishString(mqtt_topic_webserver_action, "--"); + + if(strcmp(value, "1") == 0) + { + if(_preferences->getBool(preference_webserver_enabled)) return; + Log->println(F("Webserver enabled, restarting.")); + _preferences->putBool(preference_webserver_enabled, true); + + } + else if (strcmp(value, "0") == 0) + { + if(!_preferences->getBool(preference_webserver_enabled)) return; + Log->println(F("Webserver disabled, restarting.")); + _preferences->putBool(preference_webserver_enabled, false); + } + + _network->clearWifiFallback(); + delay(200); + restartEsp(RestartReason::RequestedViaMqtt); + } + if(comparePrefixedPath(topic, mqtt_topic_lock_action)) { if(strcmp(value, "") == 0 || @@ -199,7 +229,7 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns if(comparePrefixedPath(topic, mqtt_topic_config_action)) { if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return; - + if(_configUpdateReceivedCallback != NULL) { _configUpdateReceivedCallback(value); @@ -265,7 +295,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne } json["trigger"] = str; - + char curTime[20]; sprintf(curTime, "%04d-%02d-%02d %02d:%02d:%02d", keyTurnerState.currentTimeYear, keyTurnerState.currentTimeMonth, keyTurnerState.currentTimeDay, keyTurnerState.currentTimeHour, keyTurnerState.currentTimeMinute, keyTurnerState.currentTimeSecond); json["currentTime"] = curTime; diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index 7f706d8..8ad13be 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -13,6 +13,7 @@ #define preference_mqtt_user (char*)"mqttuser" #define preference_mqtt_password (char*)"mqttpass" #define preference_mqtt_log_enabled (char*)"mqttlog" +#define preference_webserver_enabled (char*)"websrvena" #define preference_lock_enabled (char*)"lockena" #define preference_lock_pin_status (char*)"lockpin" #define preference_mqtt_lock_path (char*)"mqttpath" @@ -77,7 +78,7 @@ class DebugPreferences private: std::vector _keys = { - 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_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_mqtt_opener_path, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, @@ -104,7 +105,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_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, + preference_webserver_enabled, preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_ip_dhcp_enabled, preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled }; diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 8d9ad38..fd28b68 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -1765,8 +1765,12 @@ void WebCfgServer::buildInfoHtml(String &response) response.concat(uxTaskGetStackHighWaterMark(networkTaskHandle)); response.concat(", nuki: "); response.concat(uxTaskGetStackHighWaterMark(nukiTaskHandle)); - response.concat(", pd: "); - response.concat(uxTaskGetStackHighWaterMark(presenceDetectionTaskHandle)); + + if(_preferences->getInt(preference_presence_detection_timeout) >= 0) + { + response.concat(", pd: "); + response.concat(uxTaskGetStackHighWaterMark(presenceDetectionTaskHandle)); + } response.concat("\n"); _gpio->getConfigurationText(response, _gpio->pinConfiguration()); diff --git a/src/main.cpp b/src/main.cpp index e3f158f..87e3ddd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -114,7 +114,11 @@ void setupTasks() xTaskCreatePinnedToCore(networkTask, "ntw", 12288, NULL, 3, &networkTaskHandle, 1); xTaskCreatePinnedToCore(nukiTask, "nuki", 8192, NULL, 2, &nukiTaskHandle, 1); - xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", 1024, NULL, 5, &presenceDetectionTaskHandle, 1); + + if(preferences->getInt(preference_presence_detection_timeout) >= 0) + { + xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", 1024, NULL, 5, &presenceDetectionTaskHandle, 1); + } } void initEthServer(const NetworkDeviceType device) @@ -316,16 +320,22 @@ void setup() nukiOpener->initialize(); } - webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi); - webCfgServer->initialize(); - - presenceDetection = new PresenceDetection(preferences, bleScanner, network, CharBuffer::get(), CHAR_BUFFER_SIZE); - presenceDetection->initialize(); - + if(preferences->getBool(preference_webserver_enabled, true)) + { + webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi); + webCfgServer->initialize(); + } + + if(preferences->getInt(preference_presence_detection_timeout) >= 0) + { + presenceDetection = new PresenceDetection(preferences, bleScanner, network, CharBuffer::get(), CHAR_BUFFER_SIZE); + presenceDetection->initialize(); + } + setupTasks(); } void loop() { - delay(60000); + vTaskDelete(NULL); } \ No newline at end of file From 699d9a148ab76157dcc64d0d2c5f723719df315f Mon Sep 17 00:00:00 2001 From: iranl Date: Wed, 22 May 2024 21:10:15 +0200 Subject: [PATCH 2/4] Update Tasks --- src/NetworkLock.cpp | 18 +++------ src/NetworkOpener.cpp | 38 ------------------- src/NetworkOpener.h | 1 - src/NukiOpenerWrapper.cpp | 23 ++++++++++-- src/NukiWrapper.cpp | 23 ++++++++++-- src/PreferencesKeys.h | 22 ++++++----- src/WebCfgServer.cpp | 78 ++++++++++++++++++++++++++++++++++----- src/WebCfgServer.h | 1 + src/main.cpp | 18 +++++---- 9 files changed, 138 insertions(+), 84 deletions(-) diff --git a/src/NetworkLock.cpp b/src/NetworkLock.cpp index 0d126db..9cc26aa 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -55,7 +55,7 @@ void NetworkLock::initialize() _network->subscribe(_mqttPath, mqtt_topic_webserver_action); _network->initTopic(_mqttPath, mqtt_topic_webserver_action, "--"); - _network->initTopic(_mqttPath, mqtt_topic_webserver_state, _preferences->getBool(preference_webserver_enabled, true) ? 1 : 0); + _network->initTopic(_mqttPath, mqtt_topic_webserver_state, (_preferences->getBool(preference_webserver_enabled, true) ? "1" : "0")); _network->initTopic(_mqttPath, mqtt_topic_query_config, "0"); _network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0"); @@ -111,22 +111,21 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return; - publishString(mqtt_topic_webserver_action, "--"); - if(strcmp(value, "1") == 0) { - if(_preferences->getBool(preference_webserver_enabled)) return; + if(_preferences->getBool(preference_webserver_enabled, true)) return; Log->println(F("Webserver enabled, restarting.")); _preferences->putBool(preference_webserver_enabled, true); } else if (strcmp(value, "0") == 0) { - if(!_preferences->getBool(preference_webserver_enabled)) return; + if(!_preferences->getBool(preference_webserver_enabled, true)) return; Log->println(F("Webserver disabled, restarting.")); _preferences->putBool(preference_webserver_enabled, false); } + publishString(mqtt_topic_webserver_action, "--"); _network->clearWifiFallback(); delay(200); restartEsp(RestartReason::RequestedViaMqtt); @@ -410,15 +409,8 @@ void NetworkLock::publishAuthorizationInfo(const std::list& JsonDocument json; - int i = 5; for(const auto& log : logEntries) { - if(i <= 0) - { - break; - } - --i; - memset(authName, 0, sizeof(authName)); authName[0] = '\0'; @@ -468,6 +460,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list& memset(str, 0, sizeof(str)); NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[3]; break; case NukiLock::LoggingType::KeypadAction: memset(str, 0, sizeof(str)); @@ -477,6 +470,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list& memset(str, 0, sizeof(str)); NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[2]; break; case NukiLock::LoggingType::DoorSensor: memset(str, 0, sizeof(str)); diff --git a/src/NetworkOpener.cpp b/src/NetworkOpener.cpp index 574d646..3b5ad69 100644 --- a/src/NetworkOpener.cpp +++ b/src/NetworkOpener.cpp @@ -378,15 +378,8 @@ void NetworkOpener::publishAuthorizationInfo(const std::listgetInt(preference_authlog_max_entries, 5), 1, false); Log->print(F("Retrieve log entries: ")); Log->println(result); if(result != Nuki::CmdResult::Success) @@ -493,11 +493,16 @@ void NukiOpenerWrapper::updateAuthData() return; } - delay(100); + delay(_preferences->getInt(preference_authlog_max_entries, 5) * 30); std::list log; _nukiOpener.getLogEntries(&log); + if(log.size() > _preferences->getInt(preference_authlog_max_entries, 5)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, 5)); + } + Log->print(F("Log size: ")); Log->println(log.size()); @@ -513,7 +518,7 @@ void NukiOpenerWrapper::updateKeypad() if(!_preferences->getBool(preference_keypad_info_enabled)) return; Log->print(F("Querying opener keypad: ")); - Nuki::CmdResult result = _nukiOpener.retrieveKeypadEntries(0, 0xffff); + Nuki::CmdResult result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, 10)); printCommandResult(result); if(result == Nuki::CmdResult::Success) { @@ -525,6 +530,11 @@ void NukiOpenerWrapper::updateKeypad() entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b) { return a.codeId < b.codeId; }); + if(entries.size() > _preferences->getInt(preference_keypad_max_entries, 10)) + { + entries.resize(_preferences->getInt(preference_keypad_max_entries, 10)); + } + uint keypadCount = entries.size(); if(keypadCount > _maxKeypadCodeCount) { @@ -572,6 +582,11 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved) timeControlEntries.sort([](const NukiOpener::TimeControlEntry& a, const NukiOpener::TimeControlEntry& b) { return a.entryId < b.entryId; }); + if(timeControlEntries.size() > _preferences->getInt(preference_timecontrol_max_entries, 10)) + { + timeControlEntries.resize(_preferences->getInt(preference_timecontrol_max_entries, 10)); + } + _network->publishTimeControl(timeControlEntries); _timeControlIds.clear(); @@ -1706,7 +1721,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value) auto it = std::find(_keypadCodeIds.begin(), _keypadCodeIds.end(), codeId); entry.code = _keypadCodes[(it - _keypadCodeIds.begin())]; } - + entry.enabled = enabled == 0 ? 0 : 1; entry.timeLimited = timeLimited == 1 ? 1 : 0; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 65533db..14f739b 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -466,7 +466,7 @@ void NukiWrapper::updateAuthData() return; } - Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, 5, 1, false); + Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, 5), 1, false); Log->print(F("Retrieve log entries: ")); Log->println(result); if(result != Nuki::CmdResult::Success) @@ -474,10 +474,15 @@ void NukiWrapper::updateAuthData() return; } - delay(100); + delay(_preferences->getInt(preference_authlog_max_entries, 5) * 30); std::list log; _nukiLock.getLogEntries(&log); + + if(log.size() > _preferences->getInt(preference_authlog_max_entries, 5)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, 5)); + } Log->print(F("Log size: ")); Log->println(log.size()); @@ -494,7 +499,7 @@ void NukiWrapper::updateKeypad() if(!_preferences->getBool(preference_keypad_info_enabled)) return; Log->print(F("Querying lock keypad: ")); - Nuki::CmdResult result = _nukiLock.retrieveKeypadEntries(0, 0xffff); + Nuki::CmdResult result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, 10)); printCommandResult(result); if(result == Nuki::CmdResult::Success) { @@ -505,6 +510,11 @@ void NukiWrapper::updateKeypad() Log->println(entries.size()); entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b) { return a.codeId < b.codeId; }); + + if(entries.size() > _preferences->getInt(preference_keypad_max_entries, 10)) + { + entries.resize(_preferences->getInt(preference_keypad_max_entries, 10)); + } uint keypadCount = entries.size(); if(keypadCount > _maxKeypadCodeCount) @@ -552,7 +562,12 @@ void NukiWrapper::updateTimeControl(bool retrieved) Log->println(timeControlEntries.size()); timeControlEntries.sort([](const NukiLock::TimeControlEntry& a, const NukiLock::TimeControlEntry& b) { return a.entryId < b.entryId; }); - + + if(timeControlEntries.size() > _preferences->getInt(preference_timecontrol_max_entries, 10)) + { + timeControlEntries.resize(_preferences->getInt(preference_timecontrol_max_entries, 10)); + } + _network->publishTimeControl(timeControlEntries); _timeControlIds.clear(); diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index 8ad13be..cea02b4 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -72,6 +72,12 @@ #define preference_has_mac_byte_1 (char*)"macb1" #define preference_has_mac_byte_2 (char*)"macb2" #define preference_latest_version (char*)"latest" +#define preference_task_size_network (char*)"tsksznetw" +#define preference_task_size_nuki (char*)"tsksznuki" +#define preference_task_size_pd (char*)"tskszpd" +#define preference_authlog_max_entries (char*)"authmaxentry" +#define preference_keypad_max_entries (char*)"kpmaxentry" +#define preference_timecontrol_max_entries (char*)"tcmaxentry" class DebugPreferences { @@ -83,17 +89,15 @@ private: preference_opener_continuous_mode, preference_mqtt_opener_path, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, - preference_network_hardware, preference_network_wifi_fallback_disabled, preference_rssi_publish_interval, - preference_hostname, preference_network_timeout, preference_restart_on_disconnect, - preference_restart_ble_beacon_lost, preference_query_interval_lockstate, - preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, - preference_keypad_control_enabled, preference_keypad_info_enabled, preference_acl, - preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, + preference_network_hardware, preference_network_wifi_fallback_disabled, preference_rssi_publish_interval, preference_hostname, + preference_network_timeout, preference_restart_on_disconnect, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, + preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, + preference_keypad_info_enabled, preference_acl, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl, preference_conf_opener_advanced_acl, - preference_access_level, preference_register_as_app, preference_command_nr_of_retries, - preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata, - preference_publish_debug_info, preference_presence_detection_timeout, + preference_access_level, preference_register_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user, + preference_cred_password, preference_publish_authdata, preference_publish_debug_info, preference_presence_detection_timeout, 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_task_size_pd, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries }; std::vector _redact = { diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index dcfd1c4..90a0499 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -78,6 +78,14 @@ void WebCfgServer::initialize() buildAccLvlHtml(response); _server.send(200, "text/html", response); }); + _server.on("/advanced", [&]() { + if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) { + return _server.requestAuthentication(); + } + String response = ""; + buildAdvancedConfigHtml(response); + _server.send(200, "text/html", response); + }); _server.on("/cred", [&]() { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) { return _server.requestAuthentication(); @@ -465,6 +473,36 @@ bool WebCfgServer::processArgs(String& message) _preferences->putInt(preference_restart_ble_beacon_lost, value.toInt()); configChanged = true; } + else if(key == "TSKNTWK") + { + _preferences->putInt(preference_task_size_network, value.toInt()); + configChanged = true; + } + else if(key == "TSKNUKI") + { + _preferences->putInt(preference_task_size_nuki, value.toInt()); + configChanged = true; + } + else if(key == "TSKPD") + { + _preferences->putInt(preference_task_size_pd, value.toInt()); + configChanged = true; + } + else if(key == "ALMAX") + { + _preferences->putInt(preference_authlog_max_entries, value.toInt()); + configChanged = true; + } + else if(key == "KPMAX") + { + _preferences->putInt(preference_keypad_max_entries, value.toInt()); + configChanged = true; + } + else if(key == "TCMAX") + { + _preferences->putInt(preference_timecontrol_max_entries, value.toInt()); + configChanged = true; + } else if(key == "ACLLVLCHANGED") { aclLvlChanged = true; @@ -488,7 +526,7 @@ bool WebCfgServer::processArgs(String& message) { _preferences->putBool(preference_timecontrol_control_enabled, (value == "1")); configChanged = true; - } + } else if(key == "PUBAUTH") { _preferences->putBool(preference_publish_authdata, (value == "1")); @@ -1071,23 +1109,25 @@ void WebCfgServer::buildHtml(String& response) if(_preferences->getBool(preference_check_updates)) printParameter(response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota"); response.concat("
"); - response.concat(""); if(_allowRestartToPortal) { - response.concat(""); } @@ -1257,6 +1297,26 @@ void WebCfgServer::buildMqttConfigHtml(String &response) response.concat(""); } +void WebCfgServer::buildAdvancedConfigHtml(String &response) +{ + buildHtmlHeader(response); + response.concat(""); + response.concat("

Advanced Configuration

"); + response.concat("

Warning: Changing these settings can lead to bootloops that might require you to erase the ESP32 and reflash nukihub using USB/serial

"); + response.concat("

MQTT and Network Configuration

"); + response.concat("
MQTT and Network Configuration
"); buildNavigationButton(response, "Edit", "/mqttconfig", _brokerConfigured ? "" : "(!) Please configure MQTT broker"); - response.concat("

Nuki Configuration

"); + response.concat("
Nuki Configuration
"); buildNavigationButton(response, "Edit", "/nukicfg"); - response.concat("

Access Level Configuration

"); + response.concat("
Access Level Configuration
"); buildNavigationButton(response, "Edit", "/acclvl"); - response.concat("

Credentials

"); + response.concat("
Credentials
"); buildNavigationButton(response, "Edit", "/cred", _pinsConfigured ? "" : "(!) Please configure PIN"); - response.concat("

GPIO Configuration

"); + response.concat("
GPIO Configuration
"); buildNavigationButton(response, "Edit", "/gpiocfg"); - response.concat("

Firmware update

"); + response.concat("
Firmware update
"); buildNavigationButton(response, "Open", "/ota"); + response.concat("
Advanced Configuration
"); + buildNavigationButton(response, "Edit", "/advanced"); response.concat("

Wi-Fi

"); + response.concat("
Wi-Fi
"); buildNavigationButton(response, "Restart and configure Wi-Fi", "/wifi"); response.concat("
"); + printInputField(response, "TSKNTWK", "Task size Network", _preferences->getInt(preference_task_size_network, 12288), 6); + printInputField(response, "TSKNUKI", "Task size Nuki", _preferences->getInt(preference_task_size_nuki, 8192), 6); + printInputField(response, "TSKPD", "Task size Presence Detection", _preferences->getInt(preference_task_size_pd, 1024), 6); + printInputField(response, "ALMAX", "Max auth log entries", _preferences->getInt(preference_authlog_max_entries, 5), 3); + printInputField(response, "KPMAX", "Max keypad entries", _preferences->getInt(preference_keypad_max_entries, 10), 3); + printInputField(response, "TCMAX", "Max timecontrol entries", _preferences->getInt(preference_timecontrol_max_entries, 10), 3); + response.concat("
"); + + response.concat("
"); + response.concat(""); + response.concat(""); +} + void WebCfgServer::buildAccLvlHtml(String &response) { buildHtmlHeader(response); @@ -1765,7 +1825,7 @@ void WebCfgServer::buildInfoHtml(String &response) response.concat(uxTaskGetStackHighWaterMark(networkTaskHandle)); response.concat(", nuki: "); response.concat(uxTaskGetStackHighWaterMark(nukiTaskHandle)); - + if(_preferences->getInt(preference_presence_detection_timeout) >= 0) { response.concat(", pd: "); diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h index 48a16e8..6d3deac 100644 --- a/src/WebCfgServer.h +++ b/src/WebCfgServer.h @@ -42,6 +42,7 @@ private: void buildOtaHtml(String& response, bool errored); void buildOtaCompletedHtml(String& response); void buildMqttConfigHtml(String& response); + void buildAdvancedConfigHtml(String& response); void buildNukiConfigHtml(String& response); void buildGpioConfigHtml(String& response); void buildConfirmHtml(String& response, const String &message, uint32_t redirectDelay = 5); diff --git a/src/main.cpp b/src/main.cpp index 87e3ddd..c35785d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,7 +52,11 @@ void networkTask(void *pvParameters) { networkOpener->update(); } - webCfgServer->update(); + + if(preferences->getBool(preference_webserver_enabled, true)) + { + webCfgServer->update(); + } // millis() is about to overflow. Restart device to prevent problems with overflow if(millis() > restartTs) @@ -112,12 +116,12 @@ void setupTasks() { // configMAX_PRIORITIES is 25 - xTaskCreatePinnedToCore(networkTask, "ntw", 12288, NULL, 3, &networkTaskHandle, 1); - xTaskCreatePinnedToCore(nukiTask, "nuki", 8192, NULL, 2, &nukiTaskHandle, 1); - + xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, 12288), NULL, 3, &networkTaskHandle, 1); + xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, 8192), NULL, 2, &nukiTaskHandle, 1); + if(preferences->getInt(preference_presence_detection_timeout) >= 0) { - xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", 1024, NULL, 5, &presenceDetectionTaskHandle, 1); + xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", preferences->getInt(preference_task_size_pd, 1024), NULL, 5, &presenceDetectionTaskHandle, 1); } } @@ -325,13 +329,13 @@ void setup() webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi); webCfgServer->initialize(); } - + if(preferences->getInt(preference_presence_detection_timeout) >= 0) { presenceDetection = new PresenceDetection(preferences, bleScanner, network, CharBuffer::get(), CHAR_BUFFER_SIZE); presenceDetection->initialize(); } - + setupTasks(); } From acad87b3083dea28531790779f292f395650ab46 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 26 May 2024 19:25:45 +0200 Subject: [PATCH 3/4] Update Tasks --- src/CharBuffer.cpp | 4 +- src/CharBuffer.h | 4 +- src/Config.h | 8 ++ src/Network.cpp | 8 +- src/NetworkLock.cpp | 132 ++++++++++++++-------------- src/NetworkLock.h | 2 +- src/NetworkOpener.cpp | 178 ++++++++++++++++++++------------------ src/NetworkOpener.h | 2 +- src/NukiOpenerWrapper.cpp | 94 ++++++++++++-------- src/NukiOpenerWrapper.h | 8 +- src/NukiWrapper.cpp | 112 +++++++++++++++--------- src/NukiWrapper.h | 8 +- src/PreferencesKeys.h | 9 +- src/WebCfgServer.cpp | 75 ++++++++++++---- src/main.cpp | 37 ++++++-- 15 files changed, 416 insertions(+), 265 deletions(-) diff --git a/src/CharBuffer.cpp b/src/CharBuffer.cpp index 62b47b7..70b3595 100644 --- a/src/CharBuffer.cpp +++ b/src/CharBuffer.cpp @@ -1,8 +1,8 @@ #include "CharBuffer.h" -void CharBuffer::initialize() +void CharBuffer::initialize(char16_t buffer_size) { - _buffer = new char[CHAR_BUFFER_SIZE]; + _buffer = new char[buffer_size]; } char *CharBuffer::get() diff --git a/src/CharBuffer.h b/src/CharBuffer.h index 4abaf87..9c5745d 100644 --- a/src/CharBuffer.h +++ b/src/CharBuffer.h @@ -1,11 +1,9 @@ #pragma once -#define CHAR_BUFFER_SIZE 4096 - class CharBuffer { public: - static void initialize(); + static void initialize(char16_t buffer_size); static char* get(); private: diff --git a/src/Config.h b/src/Config.h index d26d6eb..a854dbb 100644 --- a/src/Config.h +++ b/src/Config.h @@ -23,3 +23,11 @@ #define MQTT_CLEAN_SESSIONS false #define GPIO_DEBOUNCE_TIME 200 + +#define CHAR_BUFFER_SIZE 4096 +#define NETWORK_TASK_SIZE 12288 +#define NUKI_TASK_SIZE 8192 +#define PD_TASK_SIZE 1024 +#define MAX_AUTHLOG 5 +#define MAX_KEYPAD 10 +#define MAX_TIMECONTROL 10 \ No newline at end of file diff --git a/src/Network.cpp b/src/Network.cpp index 8155d0f..ad5c138 100644 --- a/src/Network.cpp +++ b/src/Network.cpp @@ -264,7 +264,13 @@ void Network::initialize() bool Network::update() { unsigned long ts = millis(); - + + if(ts > 120000 && ts < 125000 && _preferences->getInt(preference_bootloop_counter, 0) > 0) + { + _preferences->putInt(preference_bootloop_counter, 0); + Log->println(F("Bootloop counter reset")); + } + _device->update(); if(!_mqttEnabled) diff --git a/src/NetworkLock.cpp b/src/NetworkLock.cpp index 9cc26aa..7ce3ddd 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -401,7 +401,7 @@ void NetworkLock::publishState(NukiLock::LockState lockState) } } -void NetworkLock::publishAuthorizationInfo(const std::list& logEntries) +void NetworkLock::publishAuthorizationInfo(const std::list& logEntries, bool latest) { char str[50]; char authName[33]; @@ -430,77 +430,83 @@ void NetworkLock::publishAuthorizationInfo(const std::list& } } - auto entry = json.add(); - - entry["index"] = log.index; - entry["authorizationId"] = log.authId; - entry["authorizationName"] = authName; - entry["timeYear"] = log.timeStampYear; - entry["timeMonth"] = log.timeStampMonth; - entry["timeDay"] = log.timeStampDay; - entry["timeHour"] = log.timeStampHour; - entry["timeMinute"] = log.timeStampMinute; - entry["timeSecond"] = log.timeStampSecond; - - memset(str, 0, sizeof(str)); - loggingTypeToString(log.loggingType, str); - entry["type"] = str; - - switch(log.loggingType) + if(!latest) { - case NukiLock::LoggingType::LockAction: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - entry["action"] = str; + auto entry = json.add(); - memset(str, 0, sizeof(str)); - NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str); - entry["trigger"] = str; + entry["index"] = log.index; + entry["authorizationId"] = log.authId; + entry["authorizationName"] = authName; + entry["timeYear"] = log.timeStampYear; + entry["timeMonth"] = log.timeStampMonth; + entry["timeDay"] = log.timeStampDay; + entry["timeHour"] = log.timeStampHour; + entry["timeMinute"] = log.timeStampMinute; + entry["timeSecond"] = log.timeStampSecond; - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); - entry["completionStatus"] = str; - entry["completionStatusVal"] = log.data[3]; - break; - case NukiLock::LoggingType::KeypadAction: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - entry["action"] = str; + memset(str, 0, sizeof(str)); + loggingTypeToString(log.loggingType, str); + entry["type"] = str; - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - entry["completionStatusVal"] = log.data[2]; - break; - case NukiLock::LoggingType::DoorSensor: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + switch(log.loggingType) + { + case NukiLock::LoggingType::LockAction: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + entry["action"] = str; - switch(log.data[0]) - { - case 0: - entry["action"] = "DoorOpened"; - break; - case 1: - entry["action"] = "DoorClosed"; - break; - case 2: - entry["action"] = "SensorJammed"; - break; - default: - entry["action"] = "Unknown"; - break; - } + memset(str, 0, sizeof(str)); + NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str); + entry["trigger"] = str; - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - break; + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); + entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[3]; + break; + case NukiLock::LoggingType::KeypadAction: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + entry["action"] = str; + + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[2]; + break; + case NukiLock::LoggingType::DoorSensor: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + + switch(log.data[0]) + { + case 0: + entry["action"] = "DoorOpened"; + break; + case 1: + entry["action"] = "DoorClosed"; + break; + case 2: + entry["action"] = "SensorJammed"; + break; + default: + entry["action"] = "Unknown"; + break; + } + + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + break; + } } } - serializeJson(json, _buffer, _bufferSize); - publishString(mqtt_topic_lock_log, _buffer); + if(!latest) + { + serializeJson(json, _buffer, _bufferSize); + publishString(mqtt_topic_lock_log, _buffer); + } if(authFound) { diff --git a/src/NetworkLock.h b/src/NetworkLock.h index e6c3104..67e812f 100644 --- a/src/NetworkLock.h +++ b/src/NetworkLock.h @@ -24,7 +24,7 @@ public: void publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState); void publishState(NukiLock::LockState lockState); - void publishAuthorizationInfo(const std::list& logEntries); + void publishAuthorizationInfo(const std::list& logEntries, bool latest); void clearAuthorizationInfo(); void publishCommandResult(const char* resultStr); void publishLockstateCommandResult(const char* resultStr); diff --git a/src/NetworkOpener.cpp b/src/NetworkOpener.cpp index 3b5ad69..8cdd1d3 100644 --- a/src/NetworkOpener.cpp +++ b/src/NetworkOpener.cpp @@ -370,7 +370,7 @@ void NetworkOpener::publishState(NukiOpener::OpenerState lockState) } } -void NetworkOpener::publishAuthorizationInfo(const std::list& logEntries) +void NetworkOpener::publishAuthorizationInfo(const std::list& logEntries, bool latest) { char str[50]; char authName[33]; @@ -399,101 +399,107 @@ void NetworkOpener::publishAuthorizationInfo(const std::list(); - - entry["index"] = log.index; - entry["authorizationId"] = log.authId; - entry["authorizationName"] = _authName; - entry["timeYear"] = log.timeStampYear; - entry["timeMonth"] = log.timeStampMonth; - entry["timeDay"] = log.timeStampDay; - entry["timeHour"] = log.timeStampHour; - entry["timeMinute"] = log.timeStampMinute; - entry["timeSecond"] = log.timeStampSecond; - - memset(str, 0, sizeof(str)); - loggingTypeToString(log.loggingType, str); - entry["type"] = str; - - switch(log.loggingType) + if(!latest) { - case NukiOpener::LoggingType::LockAction: - memset(str, 0, sizeof(str)); - NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); - entry["action"] = str; + auto entry = json.add(); - memset(str, 0, sizeof(str)); - NukiOpener::triggerToString((NukiOpener::Trigger)log.data[1], str); - entry["trigger"] = str; + entry["index"] = log.index; + entry["authorizationId"] = log.authId; + entry["authorizationName"] = _authName; + entry["timeYear"] = log.timeStampYear; + entry["timeMonth"] = log.timeStampMonth; + entry["timeDay"] = log.timeStampDay; + entry["timeHour"] = log.timeStampHour; + entry["timeMinute"] = log.timeStampMinute; + entry["timeSecond"] = log.timeStampSecond; - memset(str, 0, sizeof(str)); - NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[3], str); - entry["completionStatus"] = str; - break; - case NukiOpener::LoggingType::KeypadAction: - memset(str, 0, sizeof(str)); - NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); - entry["action"] = str; + memset(str, 0, sizeof(str)); + loggingTypeToString(log.loggingType, str); + entry["type"] = str; - memset(str, 0, sizeof(str)); - NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - break; - case NukiOpener::LoggingType::DoorbellRecognition: - switch(log.data[0] & 3) - { - case 0: - entry["mode"] = "None"; - break; - case 1: - entry["mode"] = "RTO"; - break; - case 2: - entry["mode"] = "CM"; - break; - default: - entry["mode"] = "Unknown"; - break; - } + switch(log.loggingType) + { + case NukiOpener::LoggingType::LockAction: + memset(str, 0, sizeof(str)); + NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); + entry["action"] = str; - switch(log.data[1]) - { - case 0: - entry["source"] = "Doorbell"; - break; - case 1: - entry["source"] = "Timecontrol"; - break; - case 2: - entry["source"] = "App"; - break; - case 3: - entry["source"] = "Button"; - break; - case 4: - entry["source"] = "Fob"; - break; - case 5: - entry["source"] = "Bridge"; - break; - case 6: - entry["source"] = "Keypad"; - break; - default: - entry["source"] = "Unknown"; - break; } + memset(str, 0, sizeof(str)); + NukiOpener::triggerToString((NukiOpener::Trigger)log.data[1], str); + entry["trigger"] = str; - entry["geofence"] = log.data[2] == 1 ? "active" : "inactive"; - entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive"; - entry["completionStatus"] = str; + memset(str, 0, sizeof(str)); + NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[3], str); + entry["completionStatus"] = str; + break; + case NukiOpener::LoggingType::KeypadAction: + memset(str, 0, sizeof(str)); + NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); + entry["action"] = str; - break; + memset(str, 0, sizeof(str)); + NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + break; + case NukiOpener::LoggingType::DoorbellRecognition: + switch(log.data[0] & 3) + { + case 0: + entry["mode"] = "None"; + break; + case 1: + entry["mode"] = "RTO"; + break; + case 2: + entry["mode"] = "CM"; + break; + default: + entry["mode"] = "Unknown"; + break; + } + + switch(log.data[1]) + { + case 0: + entry["source"] = "Doorbell"; + break; + case 1: + entry["source"] = "Timecontrol"; + break; + case 2: + entry["source"] = "App"; + break; + case 3: + entry["source"] = "Button"; + break; + case 4: + entry["source"] = "Fob"; + break; + case 5: + entry["source"] = "Bridge"; + break; + case 6: + entry["source"] = "Keypad"; + break; + default: + entry["source"] = "Unknown"; + break; } + + entry["geofence"] = log.data[2] == 1 ? "active" : "inactive"; + entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive"; + entry["completionStatus"] = str; + + break; + } } } - serializeJson(json, _buffer, _bufferSize); - publishString(mqtt_topic_lock_log, _buffer); - + if(!latest) + { + serializeJson(json, _buffer, _bufferSize); + publishString(mqtt_topic_lock_log, _buffer); + } + if(authFound) { publishUInt(mqtt_topic_lock_auth_id, _authId); diff --git a/src/NetworkOpener.h b/src/NetworkOpener.h index 1ec614c..6ba3ff3 100644 --- a/src/NetworkOpener.h +++ b/src/NetworkOpener.h @@ -21,7 +21,7 @@ public: void publishKeyTurnerState(const NukiOpener::OpenerState& keyTurnerState, const NukiOpener::OpenerState& lastKeyTurnerState); void publishRing(const bool locked); void publishState(NukiOpener::OpenerState lockState); - void publishAuthorizationInfo(const std::list& logEntries); + void publishAuthorizationInfo(const std::list& logEntries, bool latest); void clearAuthorizationInfo(); void publishCommandResult(const char* resultStr); void publishLockstateCommandResult(const char* resultStr); diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index c067a46..2884844 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -5,6 +5,7 @@ #include "Logger.h" #include "RestartReason.h" #include +#include "Config.h" NukiOpenerWrapper* nukiOpenerInst; Preferences* nukiOpenerPreferences = nullptr; @@ -173,9 +174,19 @@ void NukiOpenerWrapper::update() setupHASS(); } } - if(_nextTimeControlUpdateTs != 0 && ts > _nextTimeControlUpdateTs) + if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs) { - _nextTimeControlUpdateTs = 0; + _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()) @@ -197,7 +208,7 @@ void NukiOpenerWrapper::update() if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0)) { _nextKeypadUpdateTs = ts + _intervalKeypad * 1000; - updateKeypad(); + updateKeypad(false); } if(_nextLockAction != (NukiOpener::LockAction)0xff && ts > _nextRetryTs) @@ -379,7 +390,7 @@ void NukiOpenerWrapper::updateKeyTurnerState() if(_publishAuthData) { Log->println(F("Publishing auth data")); - updateAuthData(); + updateAuthData(false); Log->println(F("Done publishing auth data")); } @@ -477,7 +488,7 @@ void NukiOpenerWrapper::updateConfig() } } -void NukiOpenerWrapper::updateAuthData() +void NukiOpenerWrapper::updateAuthData(bool retrieved) { if(!isPinValid()) { @@ -485,40 +496,53 @@ void NukiOpenerWrapper::updateAuthData() return; } - Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, 5), 1, false); - Log->print(F("Retrieve log entries: ")); - Log->println(result); - if(result != Nuki::CmdResult::Success) + if(!retrieved) { - return; + Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, 3, 1, false); + Log->print(F("Retrieve log entries: ")); + Log->println(result); + printCommandResult(result); + if(result == Nuki::CmdResult::Success) + { + Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); + if(result == Nuki::CmdResult::Success) + { + _waitAuthLogUpdateTs = millis() + 5000; + } + delay(150); + + std::list log; + _nukiOpener.getLogEntries(&log); + _network->publishAuthorizationInfo(log, true); + } } - - delay(_preferences->getInt(preference_authlog_max_entries, 5) * 30); - - std::list log; - _nukiOpener.getLogEntries(&log); - - if(log.size() > _preferences->getInt(preference_authlog_max_entries, 5)) + else { - log.resize(_preferences->getInt(preference_authlog_max_entries, 5)); - } + std::list log; + _nukiOpener.getLogEntries(&log); - Log->print(F("Log size: ")); - Log->println(log.size()); + if(log.size() > _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG)); + } - if(log.size() > 0) - { - _network->publishAuthorizationInfo(log); + Log->print(F("Log size: ")); + Log->println(log.size()); + + if(log.size() > 0) + { + _network->publishAuthorizationInfo(log, false); + } } postponeBleWatchdog(); } -void NukiOpenerWrapper::updateKeypad() +void NukiOpenerWrapper::updateKeypad(bool retrieved) { if(!_preferences->getBool(preference_keypad_info_enabled)) return; Log->print(F("Querying opener keypad: ")); - Nuki::CmdResult result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, 10)); + Nuki::CmdResult result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)); printCommandResult(result); if(result == Nuki::CmdResult::Success) { @@ -530,9 +554,9 @@ void NukiOpenerWrapper::updateKeypad() entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b) { return a.codeId < b.codeId; }); - if(entries.size() > _preferences->getInt(preference_keypad_max_entries, 10)) + if(entries.size() > _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)) { - entries.resize(_preferences->getInt(preference_keypad_max_entries, 10)); + entries.resize(_preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)); } uint keypadCount = entries.size(); @@ -569,7 +593,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved) printCommandResult(result); if(result == Nuki::CmdResult::Success) { - _nextTimeControlUpdateTs = millis() + 5000; + _waitTimeControlUpdateTs = millis() + 5000; } } else @@ -582,9 +606,9 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved) timeControlEntries.sort([](const NukiOpener::TimeControlEntry& a, const NukiOpener::TimeControlEntry& b) { return a.entryId < b.entryId; }); - if(timeControlEntries.size() > _preferences->getInt(preference_timecontrol_max_entries, 10)) + if(timeControlEntries.size() > _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL)) { - timeControlEntries.resize(_preferences->getInt(preference_timecontrol_max_entries, 10)); + timeControlEntries.resize(_preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL)); } _network->publishTimeControl(timeControlEntries); @@ -1372,7 +1396,7 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint entry.code = codeInt; result = _nukiOpener.addKeypadEntry(entry); Log->print("Add keypad code: "); Log->println((int)result); - updateKeypad(); + updateKeypad(false); } else if(strcmp(command, "delete") == 0) { @@ -1383,7 +1407,7 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint } result = _nukiOpener.deleteKeypadEntry(id); Log->print("Delete keypad code: "); Log->println((int)result); - updateKeypad(); + updateKeypad(false); } else if(strcmp(command, "update") == 0) { @@ -1417,7 +1441,7 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint entry.enabled = enabled == 0 ? 0 : 1; result = _nukiOpener.updateKeypadEntry(entry); Log->print("Update keypad code: "); Log->println((int)result); - updateKeypad(); + updateKeypad(false); } else if(command == "--") { @@ -1770,7 +1794,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value) return; } - updateKeypad(); + updateKeypad(false); if((int)result != -1) { diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h index ea91605..6b2cf31 100644 --- a/src/NukiOpenerWrapper.h +++ b/src/NukiOpenerWrapper.h @@ -61,8 +61,8 @@ private: void updateKeyTurnerState(); void updateBatteryState(); void updateConfig(); - void updateAuthData(); - void updateKeypad(); + void updateAuthData(bool retrieved); + void updateKeypad(bool retrieved); void updateTimeControl(bool retrieved); void postponeBleWatchdog(); @@ -132,7 +132,9 @@ private: unsigned long _nextLockStateUpdateTs = 0; unsigned long _nextBatteryReportTs = 0; unsigned long _nextConfigUpdateTs = 0; - unsigned long _nextTimeControlUpdateTs = 0; + unsigned long _waitAuthLogUpdateTs = 0; + unsigned long _waitKeypadUpdateTs = 0; + unsigned long _waitTimeControlUpdateTs = 0; unsigned long _nextKeypadUpdateTs = 0; unsigned long _nextPairTs = 0; long _nextRssiTs = 0; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 14f739b..80c3021 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -5,6 +5,7 @@ #include "Logger.h" #include "RestartReason.h" #include +#include "Config.h" NukiWrapper* nukiInst; Preferences* nukiLockPreferences = nullptr; @@ -192,9 +193,19 @@ void NukiWrapper::update() setupHASS(); } } - if(_nextTimeControlUpdateTs != 0 && ts > _nextTimeControlUpdateTs) + if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs) { - _nextTimeControlUpdateTs = 0; + _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()) @@ -216,7 +227,7 @@ void NukiWrapper::update() if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0)) { _nextKeypadUpdateTs = ts + _intervalKeypad * 1000; - updateKeypad(); + updateKeypad(false); } if(_nextLockAction != (NukiLock::LockAction)0xff && ts > _nextRetryTs) @@ -353,7 +364,7 @@ void NukiWrapper::updateKeyTurnerState() if(_publishAuthData) { Log->println(F("Publishing auth data")); - updateAuthData(); + updateAuthData(false); Log->println(F("Done publishing auth data")); } @@ -458,7 +469,7 @@ void NukiWrapper::updateConfig() } } -void NukiWrapper::updateAuthData() +void NukiWrapper::updateAuthData(bool retrieved) { if(!isPinValid()) { @@ -466,42 +477,63 @@ void NukiWrapper::updateAuthData() return; } - Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, 5), 1, false); - Log->print(F("Retrieve log entries: ")); - Log->println(result); - if(result != Nuki::CmdResult::Success) + if(!retrieved) { - return; + Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, 3, 1, false); + Log->print(F("Retrieve log entries: ")); + Log->println(result); + printCommandResult(result); + if(result == Nuki::CmdResult::Success) + { + Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); + if(result == Nuki::CmdResult::Success) + { + _waitAuthLogUpdateTs = millis() + 5000; + } + delay(150); + + std::list log; + _nukiLock.getLogEntries(&log); + _network->publishAuthorizationInfo(log, true); + } } + else + { + std::list log; + _nukiLock.getLogEntries(&log); + + if(log.size() > _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG)); + } - delay(_preferences->getInt(preference_authlog_max_entries, 5) * 30); + Log->print(F("Log size: ")); + Log->println(log.size()); - std::list log; - _nukiLock.getLogEntries(&log); + if(log.size() > 0) + { + _network->publishAuthorizationInfo(log, false); + } + } - if(log.size() > _preferences->getInt(preference_authlog_max_entries, 5)) - { - log.resize(_preferences->getInt(preference_authlog_max_entries, 5)); - } - - Log->print(F("Log size: ")); - Log->println(log.size()); - - if(log.size() > 0) - { - _network->publishAuthorizationInfo(log); - } postponeBleWatchdog(); } -void NukiWrapper::updateKeypad() +void NukiWrapper::updateKeypad(bool retrieved) { if(!_preferences->getBool(preference_keypad_info_enabled)) return; - - Log->print(F("Querying lock keypad: ")); - Nuki::CmdResult result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, 10)); - printCommandResult(result); - if(result == Nuki::CmdResult::Success) + + if(!retrieved) + { + Log->print(F("Querying lock keypad: ")); + Nuki::CmdResult result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)); + printCommandResult(result); + if(result == Nuki::CmdResult::Success) + { + _waitKeypadUpdateTs = millis() + 5000; + } + } + else { std::list entries; _nukiLock.getKeypadEntries(&entries); @@ -511,9 +543,9 @@ void NukiWrapper::updateKeypad() entries.sort([](const NukiLock::KeypadEntry& a, const NukiLock::KeypadEntry& b) { return a.codeId < b.codeId; }); - if(entries.size() > _preferences->getInt(preference_keypad_max_entries, 10)) + if(entries.size() > _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)) { - entries.resize(_preferences->getInt(preference_keypad_max_entries, 10)); + entries.resize(_preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD)); } uint keypadCount = entries.size(); @@ -550,7 +582,7 @@ void NukiWrapper::updateTimeControl(bool retrieved) printCommandResult(result); if(result == Nuki::CmdResult::Success) { - _nextTimeControlUpdateTs = millis() + 5000; + _waitTimeControlUpdateTs = millis() + 5000; } } else @@ -563,9 +595,9 @@ void NukiWrapper::updateTimeControl(bool retrieved) timeControlEntries.sort([](const NukiLock::TimeControlEntry& a, const NukiLock::TimeControlEntry& b) { return a.entryId < b.entryId; }); - if(timeControlEntries.size() > _preferences->getInt(preference_timecontrol_max_entries, 10)) + if(timeControlEntries.size() > _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL)) { - timeControlEntries.resize(_preferences->getInt(preference_timecontrol_max_entries, 10)); + timeControlEntries.resize(_preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL)); } _network->publishTimeControl(timeControlEntries); @@ -1358,7 +1390,7 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c entry.code = codeInt; result = _nukiLock.addKeypadEntry(entry); Log->print("Add keypad code: "); Log->println((int)result); - updateKeypad(); + updateKeypad(false); } else if(strcmp(command, "delete") == 0) { @@ -1369,7 +1401,7 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c } result = _nukiLock.deleteKeypadEntry(id); Log->print("Delete keypad code: "); Log->println((int)result); - updateKeypad(); + updateKeypad(false); } else if(strcmp(command, "update") == 0) { @@ -1403,7 +1435,7 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c entry.enabled = enabled == 0 ? 0 : 1; result = _nukiLock.updateKeypadEntry(entry); Log->print("Update keypad code: "); Log->println((int)result); - updateKeypad(); + updateKeypad(false); } else if(command == "--") { @@ -1756,7 +1788,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value) return; } - updateKeypad(); + updateKeypad(false); if((int)result != -1) { diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h index a1dbe3a..b24b679 100644 --- a/src/NukiWrapper.h +++ b/src/NukiWrapper.h @@ -59,8 +59,8 @@ private: void updateKeyTurnerState(); void updateBatteryState(); void updateConfig(); - void updateAuthData(); - void updateKeypad(); + void updateAuthData(bool retrieved); + void updateKeypad(bool retrieved); void updateTimeControl(bool retrieved); void postponeBleWatchdog(); @@ -127,7 +127,9 @@ private: unsigned long _nextLockStateUpdateTs = 0; unsigned long _nextBatteryReportTs = 0; unsigned long _nextConfigUpdateTs = 0; - unsigned long _nextTimeControlUpdateTs = 0; + unsigned long _waitAuthLogUpdateTs = 0; + unsigned long _waitKeypadUpdateTs = 0; + unsigned long _waitTimeControlUpdateTs = 0; unsigned long _nextKeypadUpdateTs = 0; unsigned long _nextRssiTs = 0; unsigned long _lastRssi = 0; diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index cea02b4..25cf03e 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -78,6 +78,9 @@ #define preference_authlog_max_entries (char*)"authmaxentry" #define preference_keypad_max_entries (char*)"kpmaxentry" #define preference_timecontrol_max_entries (char*)"tcmaxentry" +#define preference_bootloop_counter (char*)"btlpcounter" +#define preference_enable_bootloop_reset (char*)"enabtlprst" +#define preference_buffer_size (char*)"buffsize" class DebugPreferences { @@ -87,8 +90,8 @@ 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_mqtt_opener_path, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, - preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, - preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, + 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_network_wifi_fallback_disabled, preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, @@ -109,7 +112,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_webserver_enabled, preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, + preference_enable_bootloop_reset, preference_webserver_enabled, preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_ip_dhcp_enabled, preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled }; diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 90a0499..f9af511 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -475,32 +475,63 @@ bool WebCfgServer::processArgs(String& message) } else if(key == "TSKNTWK") { + if(value.toInt() > 12287 && value.toInt() < 32769) + { _preferences->putInt(preference_task_size_network, value.toInt()); configChanged = true; + } } else if(key == "TSKNUKI") { - _preferences->putInt(preference_task_size_nuki, value.toInt()); - configChanged = true; + if(value.toInt() > 8191 && value.toInt() < 32769) + { + _preferences->putInt(preference_task_size_nuki, value.toInt()); + configChanged = true; + } } else if(key == "TSKPD") { - _preferences->putInt(preference_task_size_pd, value.toInt()); - configChanged = true; + if(value.toInt() > 1023 && value.toInt() < 4049) + { + _preferences->putInt(preference_task_size_pd, value.toInt()); + configChanged = true; + } } else if(key == "ALMAX") { - _preferences->putInt(preference_authlog_max_entries, value.toInt()); - configChanged = true; + if(value.toInt() > 0 && value.toInt() < 51) + { + _preferences->putInt(preference_authlog_max_entries, value.toInt()); + configChanged = true; + } } else if(key == "KPMAX") { - _preferences->putInt(preference_keypad_max_entries, value.toInt()); - configChanged = true; + if(value.toInt() > 0 && value.toInt() < 101) + { + _preferences->putInt(preference_keypad_max_entries, value.toInt()); + configChanged = true; + } } else if(key == "TCMAX") { - _preferences->putInt(preference_timecontrol_max_entries, value.toInt()); + if(value.toInt() > 0 && value.toInt() < 51) + { + _preferences->putInt(preference_timecontrol_max_entries, value.toInt()); + configChanged = true; + } + } + else if(key == "BUFFSIZE") + { + if(value.toInt() > 4095 && value.toInt() < 32769) + { + _preferences->putInt(preference_buffer_size, value.toInt()); + configChanged = true; + } + } + else if(key == "BTLPRST") + { + _preferences->putBool(preference_enable_bootloop_reset, (value == "1")); configChanged = true; } else if(key == "ACLLVLCHANGED") @@ -1121,8 +1152,13 @@ void WebCfgServer::buildHtml(String& response) buildNavigationButton(response, "Edit", "/gpiocfg"); response.concat("
Firmware update
"); buildNavigationButton(response, "Open", "/ota"); - response.concat("
Advanced Configuration
"); - buildNavigationButton(response, "Edit", "/advanced"); + + if(_preferences->getBool(preference_publish_debug_info, false)) + { + response.concat("
Advanced Configuration
"); + buildNavigationButton(response, "Edit", "/advanced"); + } + response.concat(""); if(_allowRestartToPortal) @@ -1304,12 +1340,17 @@ void WebCfgServer::buildAdvancedConfigHtml(String &response) response.concat("

Advanced Configuration

"); response.concat("

Warning: Changing these settings can lead to bootloops that might require you to erase the ESP32 and reflash nukihub using USB/serial

"); response.concat(""); - printInputField(response, "TSKNTWK", "Task size Network", _preferences->getInt(preference_task_size_network, 12288), 6); - printInputField(response, "TSKNUKI", "Task size Nuki", _preferences->getInt(preference_task_size_nuki, 8192), 6); - printInputField(response, "TSKPD", "Task size Presence Detection", _preferences->getInt(preference_task_size_pd, 1024), 6); - printInputField(response, "ALMAX", "Max auth log entries", _preferences->getInt(preference_authlog_max_entries, 5), 3); - printInputField(response, "KPMAX", "Max keypad entries", _preferences->getInt(preference_keypad_max_entries, 10), 3); - printInputField(response, "TCMAX", "Max timecontrol entries", _preferences->getInt(preference_timecontrol_max_entries, 10), 3); + response.concat(""); + printCheckBox(response, "BTLPRST", "Enable Bootloop prevention (Try to reset these settings to default on bootloop)", true, ""); + printInputField(response, "BUFFSIZE", "Char buffer size (min 4096, max 32768)", _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE), 6); + printInputField(response, "TSKNTWK", "Task size Network (min 12288, max 32768)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6); + printInputField(response, "TSKNUKI", "Task size Nuki (min 8192, max 32768)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6); + printInputField(response, "TSKPD", "Task size Presence Detection (min 1024, max 4048)", _preferences->getInt(preference_task_size_pd, PD_TASK_SIZE), 6); + printInputField(response, "ALMAX", "Max auth log entries (min 1, max 50)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3); + printInputField(response, "KPMAX", "Max keypad entries (min 1, max 100)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3); + printInputField(response, "TCMAX", "Max timecontrol entries (min 1, max 50)", _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL), 3); response.concat("
Current bootloop prevention state"); + response.concat(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled"); + response.concat("
"); response.concat("
"); diff --git a/src/main.cpp b/src/main.cpp index c35785d..c810f5d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -116,12 +116,12 @@ void setupTasks() { // configMAX_PRIORITIES is 25 - xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, 12288), NULL, 3, &networkTaskHandle, 1); - xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, 8192), NULL, 2, &nukiTaskHandle, 1); + xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1); + xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 1); if(preferences->getInt(preference_presence_detection_timeout) >= 0) { - xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", preferences->getInt(preference_task_size_pd, 1024), NULL, 5, &presenceDetectionTaskHandle, 1); + xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", preferences->getInt(preference_task_size_pd, PD_TASK_SIZE), NULL, 5, &presenceDetectionTaskHandle, 1); } } @@ -265,6 +265,27 @@ void setup() initializeRestartReason(); + if(preferences->getBool(preference_enable_bootloop_reset, false) && + (esp_reset_reason() == esp_reset_reason_t::ESP_RST_PANIC || + esp_reset_reason() == esp_reset_reason_t::ESP_RST_INT_WDT || + esp_reset_reason() == esp_reset_reason_t::ESP_RST_TASK_WDT || + esp_reset_reason() == esp_reset_reason_t::ESP_RST_WDT)) + { + preferences->putInt(preference_bootloop_counter, preferences->getInt(preference_bootloop_counter, 0) + 1); + Log->println(F("Bootloop counter incremented")); + + if(preferences->getInt(preference_bootloop_counter) == 10) + { + preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE); + preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE); + preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE); + preferences->putInt(preference_task_size_pd, PD_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_bootloop_counter, 0); + } + } uint32_t devIdOpener = preferences->getUInt(preference_device_id_opener); @@ -275,8 +296,10 @@ void setup() { deviceIdOpener->assignId(deviceIdLock->get()); } + + char16_t buffer_size = preferences->getInt(preference_buffer_size, 4096); - CharBuffer::initialize(); + CharBuffer::initialize(buffer_size); if(preferences->getInt(preference_restart_timer) != 0) { @@ -292,15 +315,15 @@ void setup() openerEnabled = preferences->getBool(preference_opener_enabled); const String mqttLockPath = preferences->getString(preference_mqtt_lock_path); - network = new Network(preferences, gpio, mqttLockPath, CharBuffer::get(), CHAR_BUFFER_SIZE); + network = new Network(preferences, gpio, mqttLockPath, CharBuffer::get(), buffer_size); network->initialize(); - networkLock = new NetworkLock(network, preferences, CharBuffer::get(), CHAR_BUFFER_SIZE); + networkLock = new NetworkLock(network, preferences, CharBuffer::get(), buffer_size); networkLock->initialize(); if(openerEnabled) { - networkOpener = new NetworkOpener(network, preferences, CharBuffer::get(), CHAR_BUFFER_SIZE); + networkOpener = new NetworkOpener(network, preferences, CharBuffer::get(), buffer_size); networkOpener->initialize(); } From 72289336ad984195dce7f022997785367ab09df7 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 26 May 2024 21:45:54 +0200 Subject: [PATCH 4/4] Auth log --- README.md | 1 + src/MqttTopics.h | 1 + src/NetworkLock.cpp | 132 ++++++++++++++-------------- src/NetworkOpener.cpp | 176 +++++++++++++++++++------------------- src/NukiOpenerWrapper.cpp | 24 ++++-- src/NukiWrapper.cpp | 22 +++-- 6 files changed, 181 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index d9ad064..aa62953 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ In a browser navigate to the IP address assigned to the ESP32. - lock/trigger: The trigger of the last action: autoLock, automatic, button, manual, system. - lock/lastLockAction: Reports the last lock action as a string. Possible values are: Unlock, Lock, Unlatch, LockNgo, LockNgoUnlatch, FullLock, FobAction1, FobAction2, FobAction3, Unknown. - lock/log: If "Publish auth data" is enabled in the web interface, this topic will be filled with the log of authorization data. +- lock/shortLog: If "Publish auth data" is enabled in the web interface, this topic will be filled with the 3 most recent entries in the log of authorization data, updates faster than lock/log. - lock/completionStatus: Status of the last action as reported by Nuki Lock: success, motorBlocked, canceled, tooRecent, busy, lowMotorVoltage, clutchFailure, motorPowerFailure, incompleteFailure, invalidCode, otherError, unknown. - lock/authorizationId: If enabled in the web interface, this node returns the authorization id of the last lock action. - lock/authorizationName: If enabled in the web interface, this node returns the authorization name of the last lock action. diff --git a/src/MqttTopics.h b/src/MqttTopics.h index bb38f22..af639a2 100644 --- a/src/MqttTopics.h +++ b/src/MqttTopics.h @@ -12,6 +12,7 @@ #define mqtt_topic_lock_trigger "/lock/trigger" #define mqtt_topic_lock_last_lock_action "/lock/lastLockAction" #define mqtt_topic_lock_log "/lock/log" +#define mqtt_topic_lock_log_latest "/lock/shortLog" #define mqtt_topic_lock_auth_id "/lock/authorizationId" #define mqtt_topic_lock_auth_name "/lock/authorizationName" #define mqtt_topic_lock_completionStatus "/lock/completionStatus" diff --git a/src/NetworkLock.cpp b/src/NetworkLock.cpp index 2f79b7a..2b43924 100644 --- a/src/NetworkLock.cpp +++ b/src/NetworkLock.cpp @@ -429,83 +429,79 @@ void NetworkLock::publishAuthorizationInfo(const std::list& } } - if(!latest) + auto entry = json.add(); + + entry["index"] = log.index; + entry["authorizationId"] = log.authId; + entry["authorizationName"] = authName; + entry["timeYear"] = log.timeStampYear; + entry["timeMonth"] = log.timeStampMonth; + entry["timeDay"] = log.timeStampDay; + entry["timeHour"] = log.timeStampHour; + entry["timeMinute"] = log.timeStampMinute; + entry["timeSecond"] = log.timeStampSecond; + + memset(str, 0, sizeof(str)); + loggingTypeToString(log.loggingType, str); + entry["type"] = str; + + switch(log.loggingType) { - auto entry = json.add(); + case NukiLock::LoggingType::LockAction: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + entry["action"] = str; - entry["index"] = log.index; - entry["authorizationId"] = log.authId; - entry["authorizationName"] = authName; - entry["timeYear"] = log.timeStampYear; - entry["timeMonth"] = log.timeStampMonth; - entry["timeDay"] = log.timeStampDay; - entry["timeHour"] = log.timeStampHour; - entry["timeMinute"] = log.timeStampMinute; - entry["timeSecond"] = log.timeStampSecond; + memset(str, 0, sizeof(str)); + NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str); + entry["trigger"] = str; - memset(str, 0, sizeof(str)); - loggingTypeToString(log.loggingType, str); - entry["type"] = str; + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); + entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[3]; + break; + case NukiLock::LoggingType::KeypadAction: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); + entry["action"] = str; - switch(log.loggingType) - { - case NukiLock::LoggingType::LockAction: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - entry["action"] = str; + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + entry["completionStatusVal"] = log.data[2]; + break; + case NukiLock::LoggingType::DoorSensor: + memset(str, 0, sizeof(str)); + NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - memset(str, 0, sizeof(str)); - NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str); - entry["trigger"] = str; + switch(log.data[0]) + { + case 0: + entry["action"] = "DoorOpened"; + break; + case 1: + entry["action"] = "DoorClosed"; + break; + case 2: + entry["action"] = "SensorJammed"; + break; + default: + entry["action"] = "Unknown"; + break; + } - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str); - entry["completionStatus"] = str; - entry["completionStatusVal"] = log.data[3]; - break; - case NukiLock::LoggingType::KeypadAction: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - entry["action"] = str; - - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - entry["completionStatusVal"] = log.data[2]; - break; - case NukiLock::LoggingType::DoorSensor: - memset(str, 0, sizeof(str)); - NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str); - - switch(log.data[0]) - { - case 0: - entry["action"] = "DoorOpened"; - break; - case 1: - entry["action"] = "DoorClosed"; - break; - case 2: - entry["action"] = "SensorJammed"; - break; - default: - entry["action"] = "Unknown"; - break; - } - - memset(str, 0, sizeof(str)); - NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - break; - } + memset(str, 0, sizeof(str)); + NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + break; } } - if(!latest) - { - serializeJson(json, _buffer, _bufferSize); - publishString(mqtt_topic_lock_log, _buffer); - } + serializeJson(json, _buffer, _bufferSize); + + if(latest) publishString(mqtt_topic_lock_log_latest, _buffer); + else publishString(mqtt_topic_lock_log, _buffer); if(authFound) { diff --git a/src/NetworkOpener.cpp b/src/NetworkOpener.cpp index 370fe10..deb4642 100644 --- a/src/NetworkOpener.cpp +++ b/src/NetworkOpener.cpp @@ -398,106 +398,102 @@ void NetworkOpener::publishAuthorizationInfo(const std::list(); + + entry["index"] = log.index; + entry["authorizationId"] = log.authId; + entry["authorizationName"] = _authName; + entry["timeYear"] = log.timeStampYear; + entry["timeMonth"] = log.timeStampMonth; + entry["timeDay"] = log.timeStampDay; + entry["timeHour"] = log.timeStampHour; + entry["timeMinute"] = log.timeStampMinute; + entry["timeSecond"] = log.timeStampSecond; + + memset(str, 0, sizeof(str)); + loggingTypeToString(log.loggingType, str); + entry["type"] = str; + + switch(log.loggingType) { - auto entry = json.add(); + case NukiOpener::LoggingType::LockAction: + memset(str, 0, sizeof(str)); + NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); + entry["action"] = str; - entry["index"] = log.index; - entry["authorizationId"] = log.authId; - entry["authorizationName"] = _authName; - entry["timeYear"] = log.timeStampYear; - entry["timeMonth"] = log.timeStampMonth; - entry["timeDay"] = log.timeStampDay; - entry["timeHour"] = log.timeStampHour; - entry["timeMinute"] = log.timeStampMinute; - entry["timeSecond"] = log.timeStampSecond; + memset(str, 0, sizeof(str)); + NukiOpener::triggerToString((NukiOpener::Trigger)log.data[1], str); + entry["trigger"] = str; - memset(str, 0, sizeof(str)); - loggingTypeToString(log.loggingType, str); - entry["type"] = str; + memset(str, 0, sizeof(str)); + NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[3], str); + entry["completionStatus"] = str; + break; + case NukiOpener::LoggingType::KeypadAction: + memset(str, 0, sizeof(str)); + NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); + entry["action"] = str; - switch(log.loggingType) - { - case NukiOpener::LoggingType::LockAction: - memset(str, 0, sizeof(str)); - NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); - entry["action"] = str; + memset(str, 0, sizeof(str)); + NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str); + entry["completionStatus"] = str; + break; + case NukiOpener::LoggingType::DoorbellRecognition: + switch(log.data[0] & 3) + { + case 0: + entry["mode"] = "None"; + break; + case 1: + entry["mode"] = "RTO"; + break; + case 2: + entry["mode"] = "CM"; + break; + default: + entry["mode"] = "Unknown"; + break; + } - memset(str, 0, sizeof(str)); - NukiOpener::triggerToString((NukiOpener::Trigger)log.data[1], str); - entry["trigger"] = str; + switch(log.data[1]) + { + case 0: + entry["source"] = "Doorbell"; + break; + case 1: + entry["source"] = "Timecontrol"; + break; + case 2: + entry["source"] = "App"; + break; + case 3: + entry["source"] = "Button"; + break; + case 4: + entry["source"] = "Fob"; + break; + case 5: + entry["source"] = "Bridge"; + break; + case 6: + entry["source"] = "Keypad"; + break; + default: + entry["source"] = "Unknown"; + break; } - memset(str, 0, sizeof(str)); - NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[3], str); - entry["completionStatus"] = str; - break; - case NukiOpener::LoggingType::KeypadAction: - memset(str, 0, sizeof(str)); - NukiOpener::lockactionToString((NukiOpener::LockAction)log.data[0], str); - entry["action"] = str; + entry["geofence"] = log.data[2] == 1 ? "active" : "inactive"; + entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive"; + entry["completionStatus"] = str; - memset(str, 0, sizeof(str)); - NukiOpener::completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str); - entry["completionStatus"] = str; - break; - case NukiOpener::LoggingType::DoorbellRecognition: - switch(log.data[0] & 3) - { - case 0: - entry["mode"] = "None"; - break; - case 1: - entry["mode"] = "RTO"; - break; - case 2: - entry["mode"] = "CM"; - break; - default: - entry["mode"] = "Unknown"; - break; - } - - switch(log.data[1]) - { - case 0: - entry["source"] = "Doorbell"; - break; - case 1: - entry["source"] = "Timecontrol"; - break; - case 2: - entry["source"] = "App"; - break; - case 3: - entry["source"] = "Button"; - break; - case 4: - entry["source"] = "Fob"; - break; - case 5: - entry["source"] = "Bridge"; - break; - case 6: - entry["source"] = "Keypad"; - break; - default: - entry["source"] = "Unknown"; - break; } - - entry["geofence"] = log.data[2] == 1 ? "active" : "inactive"; - entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive"; - entry["completionStatus"] = str; - - break; - } + break; } } - if(!latest) - { - serializeJson(json, _buffer, _bufferSize); - publishString(mqtt_topic_lock_log, _buffer); - } + serializeJson(json, _buffer, _bufferSize); + + if(latest) publishString(mqtt_topic_lock_log_latest, _buffer); + else publishString(mqtt_topic_lock_log, _buffer); if(authFound) { diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp index d99ab88..648108e 100644 --- a/src/NukiOpenerWrapper.cpp +++ b/src/NukiOpenerWrapper.cpp @@ -499,22 +499,28 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved) if(!retrieved) { - Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, 3, 1, false); + delay(250); + Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); Log->print(F("Retrieve log entries: ")); Log->println(result); printCommandResult(result); if(result == Nuki::CmdResult::Success) { - Nuki::CmdResult result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); - if(result == Nuki::CmdResult::Success) - { - _waitAuthLogUpdateTs = millis() + 5000; - } - delay(150); + _waitAuthLogUpdateTs = millis() + 5000; + delay(100); std::list log; _nukiOpener.getLogEntries(&log); - _network->publishAuthorizationInfo(log, true); + + if(log.size() > _preferences->getInt(preference_authlog_max_entries, 3)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, 3)); + } + + if(log.size() > 0) + { + _network->publishAuthorizationInfo(log, true); + } } } else @@ -1734,7 +1740,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value) _network->publishKeypadJsonCommandResult("noExistingCodeIdSet"); return; } - + NukiOpener::UpdatedKeypadEntry entry; memset(&entry, 0, sizeof(entry)); entry.codeId = codeId; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index 87f5b5d..e923680 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -480,22 +480,28 @@ void NukiWrapper::updateAuthData(bool retrieved) if(!retrieved) { - Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, 3, 1, false); + delay(250); + Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); Log->print(F("Retrieve log entries: ")); Log->println(result); printCommandResult(result); if(result == Nuki::CmdResult::Success) { - Nuki::CmdResult result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false); - if(result == Nuki::CmdResult::Success) - { - _waitAuthLogUpdateTs = millis() + 5000; - } - delay(150); + _waitAuthLogUpdateTs = millis() + 5000; + delay(100); std::list log; _nukiLock.getLogEntries(&log); - _network->publishAuthorizationInfo(log, true); + + if(log.size() > _preferences->getInt(preference_authlog_max_entries, 3)) + { + log.resize(_preferences->getInt(preference_authlog_max_entries, 3)); + } + + if(log.size() > 0) + { + _network->publishAuthorizationInfo(log, true); + } } } else