From 62742549a79d2fc7742f32bc0a7028b75fcb4535 Mon Sep 17 00:00:00 2001 From: iranl Date: Sat, 2 Nov 2024 21:54:06 +0100 Subject: [PATCH 1/4] Enable/Disable HA Discovery using a checkbox --- README.md | 3 ++- src/NukiNetwork.cpp | 6 ++++++ src/PreferencesKeys.h | 5 +++-- src/WebCfgServer.cpp | 44 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e251f85..a0202a0 100644 --- a/README.md +++ b/README.md @@ -203,10 +203,11 @@ In a browser navigate to the IP address assigned to the ESP32. - MQTT User: If using authentication on the MQTT broker set to a username with read/write rights on the MQTT broker, set to # to clear - MQTT Password : If using authentication on the MQTT broker set to the password belonging to a username with read/write rights on the MQTT broker, set to # to clear - MQTT NukiHub Path: Set to the preferred MQTT root topic for NukiHub, defaults to "nukihub". Make sure this topic is unique when using multiple ESP32 NukiHub devices +- Enable Home Assistant auto discovery: Enable Home Assistant MQTT auto discovery. Will automatically create entities in Home Assistant for NukiHub and connected Nuki Lock and/or Opener when enabled. #### Advanced MQTT Configuration -- Home Assistant discovery topic: Set to the Home Assistant auto discovery topic, leave empty to disable auto discovery. Usually "homeassistant" unless you manually changed this setting on the Home Assistant side. +- Home Assistant discovery topic: Set to the Home Assistant auto discovery topic. Usually "homeassistant" unless you manually changed this setting on the Home Assistant side. - Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode (Opener only): By default the lock entity in Home Assistant will enable Ring-to-Open (RTO) when unlocking and disable RTO when locking. By enabling this setting this behaviour will change and now unlocking will enable Continuous Mode and locking will disable Continuous Mode, for more information see the "[Home Assistant Discovery](#home-assistant-discovery-optional)" section of this README. - MQTT SSL CA Certificate: Optionally set to the CA SSL certificate of the MQTT broker, see the "[MQTT Encryption](#mqtt-encryption-optional)" section of this README. - MQTT SSL Client Certificate: Optionally set to the Client SSL certificate of the MQTT broker, see the "[MQTT Encryption](#mqtt-encryption-optional)" section of this README. diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp index 9ae5d7a..88c7b08 100644 --- a/src/NukiNetwork.cpp +++ b/src/NukiNetwork.cpp @@ -61,6 +61,12 @@ NukiNetwork::NukiNetwork(Preferences *preferences) { _mqttConnectionStateTopic[i] = connectionStateTopic.charAt(i); } + + if(_preferences->getString(preference_mqtt_hass_discovery, "") != "" && !_preferences->getBool(preference_mqtt_hass_enabled, false)) + { + _preferences->putBool(preference_mqtt_hass_enabled, true); + } + #endif setupDevice(); diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index b01a959..8390e0f 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -46,6 +46,7 @@ #define preference_cred_user (char*)"crdusr" #define preference_cred_password (char*)"crdpass" #define preference_gpio_configuration (char*)"gpiocfg" +#define preference_mqtt_hass_enabled (char*)"hassena" #define preference_mqtt_hass_discovery (char*)"hassdiscovery" #define preference_webserver_enabled (char*)"websrvena" #define preference_update_from_mqtt (char*)"updMqtt" @@ -293,7 +294,7 @@ private: preference_network_custom_rst, preference_network_custom_cs, preference_network_custom_sck, preference_network_custom_miso, preference_network_custom_mosi, preference_network_custom_pwr, preference_network_custom_mdio, preference_ntw_reconfigure, preference_lock_max_auth_entry_count, preference_opener_max_auth_entry_count, preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries, preference_wifi_ssid, preference_wifi_pass, - preference_keypad_check_code_enabled, preference_disable_network_not_connected + preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_mqtt_hass_enabled }; std::vector _redact = { @@ -306,7 +307,7 @@ private: preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, 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_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled, preference_mqtt_hass_enabled, preference_official_hybrid_actions, preference_official_hybrid_retry, preference_conf_info_enabled, preference_disable_non_json, preference_update_from_mqtt, preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_webserial_enabled, preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 7bbaa7f..a94ce81 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -1726,6 +1726,33 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message) //configChanged = true; } } + else if(key == "ENHADISC") + { + if(_preferences->getBool(preference_mqtt_hass_enabled, false) != (value == "1")) + { + if(!_preferences->getBool(preference_mqtt_hass_enabled, false)) + { + if (_nuki != nullptr) + { + _nuki->disableHASS(); + } + if (_nukiOpener != nullptr) + { + _nukiOpener->disableHASS(); + } + + _preferences->putString(preference_mqtt_hass_discovery, ""); + } + else if(_preferences->getString(preference_mqtt_hass_discovery, "") == "") + { + _preferences->putString(preference_mqtt_hass_discovery, "homeassistant"); + } + _preferences->putBool(preference_mqtt_hass_enabled, (value == "1")); + Log->print(F("Setting changed: ")); + Log->println(key); + configChanged = true; + } + } else if(key == "HASSDISCOVERY") { if(_preferences->getString(preference_mqtt_hass_discovery, "") != value) @@ -1739,6 +1766,16 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message) _nukiOpener->disableHASS(); } _preferences->putString(preference_mqtt_hass_discovery, value); + + if(value != "" && !_preferences->getBool(preference_mqtt_hass_enabled, false)) + { + _preferences->putBool(preference_mqtt_hass_enabled, true); + } + else if(value == "" && _preferences->getBool(preference_mqtt_hass_enabled, false)) + { + _preferences->putBool(preference_mqtt_hass_enabled, false); + } + Log->print(F("Setting changed: ")); Log->println(key); configChanged = true; @@ -3507,11 +3544,12 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request) printInputField(&response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30, "", false, true); printInputField(&response, "MQTTPASS", "MQTT Password", "*", 30, "", true, true); printInputField(&response, "MQTTPATH", "MQTT NukiHub Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180, ""); + printCheckBox(&response, "ENHADISC", "Enable Home Assistant auto discovery", _preferences->getBool(preference_mqtt_hass_enabled), ""); response.print("
"); response.print("

Advanced MQTT Configuration

"); response.print(""); - printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, ""); + printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (usually \"homeassistant\")", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, ""); if(_preferences->getBool(preference_opener_enabled, false)) { printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), ""); @@ -3547,7 +3585,7 @@ esp_err_t WebCfgServer::buildAdvancedConfigHtml(PsychicRequest *request) response.print(""); - printCheckBox(&response, "DISNTWNOCON", "Disable Network if not connected within 60s", _preferences->getBool(preference_disable_network_not_connected, false), ""); + printCheckBox(&response, "DISNTWNOCON", "Disable Network if not connected within 60s", _preferences->getBool(preference_disable_network_not_connected, false), ""); printCheckBox(&response, "WEBLOG", "Enable WebSerial logging", _preferences->getBool(preference_webserial_enabled), ""); 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, ""); @@ -3721,7 +3759,7 @@ esp_err_t WebCfgServer::buildAccLvlHtml(PsychicRequest *request) printCheckBox(&response, "KPPER", "Publish a topic per keypad entry and create HA sensor", _preferences->getBool(preference_keypad_topic_per_entry), ""); printCheckBox(&response, "KPCODE", "Also publish keypad codes (Disadvised for security reasons)", _preferences->getBool(preference_keypad_publish_code, false), ""); printCheckBox(&response, "KPENA", "Add, modify and delete keypad codes", _preferences->getBool(preference_keypad_control_enabled), ""); - printCheckBox(&response, "KPCHECK", "Allow checking if keypad codes are valid (Disadvised for security reasons)", _preferences->getBool(preference_keypad_check_code_enabled, false), ""); + printCheckBox(&response, "KPCHECK", "Allow checking if keypad codes are valid (Disadvised for security reasons)", _preferences->getBool(preference_keypad_check_code_enabled, false), ""); } printCheckBox(&response, "TCPUB", "Publish time control entries information", _preferences->getBool(preference_timecontrol_info_enabled), ""); printCheckBox(&response, "TCPER", "Publish a topic per time control entry and create HA sensor", _preferences->getBool(preference_timecontrol_topic_per_entry), ""); From be646bc6a8259ee027151c381adddc410174b415 Mon Sep 17 00:00:00 2001 From: iranl Date: Sat, 2 Nov 2024 23:54:03 +0100 Subject: [PATCH 2/4] Update main.cpp --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 4fb617f..ded388c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,7 @@ bool wifiConnected = false; TaskHandle_t nukiTaskHandle = nullptr; -int64_t restartTs = ((2^64) - (5 * 1000 * 60000)) / 1000; +int64_t restartTs = (pow(2,64) - (5 * 1000 * 60000)) / 1000; #else #include "../../src/WebCfgServer.h" From 7ea04e6366c97d04ce68c9fff7903e6cf1f96905 Mon Sep 17 00:00:00 2001 From: iranl Date: Mon, 4 Nov 2024 21:14:53 +0100 Subject: [PATCH 3/4] Fix Ring detection --- src/Config.h | 2 +- src/NukiNetwork.cpp | 1 + src/NukiNetworkOpener.cpp | 21 +++++++++++++++++++-- src/NukiOpenerWrapper.cpp | 16 +++++++++------- src/NukiOpenerWrapper.h | 2 +- src/NukiWrapper.cpp | 8 ++++---- src/NukiWrapper.h | 2 +- src/WebCfgServer.cpp | 24 +++++------------------- 8 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/Config.h b/src/Config.h index d032352..7ef96ef 100644 --- a/src/Config.h +++ b/src/Config.h @@ -4,7 +4,7 @@ #define NUKI_HUB_VERSION "9.02" #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2024-11-03" +#define NUKI_HUB_DATE "2024-11-04" #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/NukiNetwork.cpp b/src/NukiNetwork.cpp index 88c7b08..5755cf6 100644 --- a/src/NukiNetwork.cpp +++ b/src/NukiNetwork.cpp @@ -2700,6 +2700,7 @@ void NukiNetwork::publishHASSConfigAdditionalOpenerEntities(char *deviceType, co json = createHassJson(uidString, "_ring_event", "Ring", name, baseTopic, String("~") + mqtt_topic_lock_ring, deviceType, "doorbell", "", "", "", {{(char*)"val_tpl", (char*)"{ \"event_type\": \"{{ value }}\" }"}}); json["event_types"][0] = "ring"; json["event_types"][1] = "ringlocked"; + json["event_types"][2] = "standby"; serializeJson(json, _buffer, _bufferSize); String path = createHassTopicPath("event", "ring", uidString); _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer); diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp index b1e2692..3dbf265 100644 --- a/src/NukiNetworkOpener.cpp +++ b/src/NukiNetworkOpener.cpp @@ -43,6 +43,7 @@ void NukiNetworkOpener::initialize() _network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0"); _network->initTopic(_mqttPath, mqtt_topic_query_battery, "0"); _network->initTopic(_mqttPath, mqtt_topic_lock_binary_ring, "standby"); + _network->initTopic(_mqttPath, mqtt_topic_lock_ring, "standby"); _network->subscribe(_mqttPath, mqtt_topic_query_config); _network->subscribe(_mqttPath, mqtt_topic_query_lockstate); _network->subscribe(_mqttPath, mqtt_topic_query_battery); @@ -128,6 +129,7 @@ void NukiNetworkOpener::update() { _resetRingStateTs = 0; publishString(mqtt_topic_lock_binary_ring, "standby", true); + publishString(mqtt_topic_lock_ring, "standby", true); } } @@ -647,10 +649,25 @@ void NukiNetworkOpener::publishAuthorizationInfo(const std::list _lastRollingLog) { - _lastRollingLog = log.index; serializeJson(entry, _buffer, _bufferSize); publishString(mqtt_topic_lock_log_rolling, _buffer, true); publishInt(mqtt_topic_lock_log_rolling_last, log.index, true); + + if(log.loggingType == NukiOpener::LoggingType::DoorbellRecognition && _lastRollingLog > 0) + { + if((log.data[0] & 3) == 0) + { + Log->println(F("Nuki opener: Ring detected (Locked)")); + publishRing(true); + } + else + { + Log->println(F("Nuki opener: Ring detected (Open)")); + publishRing(false); + } + } + + _lastRollingLog = log.index; } } @@ -658,7 +675,7 @@ void NukiNetworkOpener::publishAuthorizationInfo(const std::list= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0) { - _statusUpdated = false; - _nextLockStateUpdateTs = ts + _intervalLockstate * 1000; updateKeyTurnerState(); + _nextLockStateUpdateTs = ts + _intervalLockstate * 1000; + _statusUpdated = false; _network->publishStatusUpdated(_statusUpdated); } if(_network->mqttConnectionState() == 2) @@ -448,7 +448,8 @@ void NukiOpenerWrapper::updateKeyTurnerState() } _retryLockstateCount = 0; - if(_statusUpdated && + if((!isPinValid() || !_publishAuthData) && + _statusUpdated && _keyTurnerState.lockState == NukiOpener::LockState::Locked && _lastKeyTurnerState.lockState == NukiOpener::LockState::Locked && _lastKeyTurnerState.nukiState == _keyTurnerState.nukiState) @@ -458,7 +459,8 @@ void NukiOpenerWrapper::updateKeyTurnerState() } else { - if(_keyTurnerState.lockState != _lastKeyTurnerState.lockState && + if((!isPinValid() || !_publishAuthData) && + _keyTurnerState.lockState != _lastKeyTurnerState.lockState && _keyTurnerState.lockState == NukiOpener::LockState::Open && _keyTurnerState.trigger == NukiOpener::Trigger::Manual) { @@ -3882,14 +3884,14 @@ void NukiOpenerWrapper::notify(Nuki::EventType eventType) { if(eventType == Nuki::EventType::KeyTurnerStatusReset) { - _newSignal = false; + _newSignal = 0; Log->println("KeyTurnerStatusReset"); } else if(eventType == Nuki::EventType::KeyTurnerStatusUpdated) { - if(!_statusUpdated && !_newSignal) + if(!_statusUpdated && _newSignal < 5) { - _newSignal = true; + _newSignal++; Log->println("KeyTurnerStatusUpdated"); _statusUpdated = true; _statusUpdatedTs = espMillis(); diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h index 177efa9..f0c892f 100644 --- a/src/NukiOpenerWrapper.h +++ b/src/NukiOpenerWrapper.h @@ -135,7 +135,7 @@ private: bool _paired = false; bool _statusUpdated = false; - bool _newSignal = false; + int _newSignal = 0; bool _hasKeypad = false; bool _keypadEnabled = false; uint _maxKeypadCodeCount = 0; diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp index e2ca06b..49aba9a 100644 --- a/src/NukiWrapper.cpp +++ b/src/NukiWrapper.cpp @@ -362,9 +362,9 @@ void NukiWrapper::update() if(_nukiOfficial->getStatusUpdated() || _statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0) { Log->println("Updating Lock state based on status, timer or query"); + updateKeyTurnerState(); _statusUpdated = false; _nextLockStateUpdateTs = ts + _intervalLockstate * 1000; - updateKeyTurnerState(); _network->publishStatusUpdated(_statusUpdated); } if(_network->mqttConnectionState() == 2) @@ -4000,14 +4000,14 @@ void NukiWrapper::notify(Nuki::EventType eventType) { if(eventType == Nuki::EventType::KeyTurnerStatusReset) { - _newSignal = false; + _newSignal = 0; Log->println("KeyTurnerStatusReset"); } else if(eventType == Nuki::EventType::KeyTurnerStatusUpdated) { - if(!_statusUpdated && !_newSignal) + if(!_statusUpdated && _newSignal < 5) { - _newSignal = true; + _newSignal++; Log->println("KeyTurnerStatusUpdated"); _statusUpdated = true; _statusUpdatedTs = espMillis(); diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h index 890f7b4..2358e02 100644 --- a/src/NukiWrapper.h +++ b/src/NukiWrapper.h @@ -134,7 +134,7 @@ private: bool _pairedAsApp = false; bool _paired = false; bool _statusUpdated = false; - bool _newSignal = false; + int _newSignal = 0; bool _hasKeypad = false; bool _keypadEnabled = false; uint _maxKeypadCodeCount = 0; diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 9d6f3eb..790d387 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -1737,12 +1737,6 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message) { _nukiOpener->disableHASS(); } - - _preferences->putString(preference_mqtt_hass_discovery, ""); - } - else if(_preferences->getString(preference_mqtt_hass_discovery, "") == "") - { - _preferences->putString(preference_mqtt_hass_discovery, "homeassistant"); } _preferences->putBool(preference_mqtt_hass_enabled, (value == "1")); Log->print(F("Setting changed: ")); @@ -1763,16 +1757,6 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message) _nukiOpener->disableHASS(); } _preferences->putString(preference_mqtt_hass_discovery, value); - - if(value != "" && !_preferences->getBool(preference_mqtt_hass_enabled, false)) - { - _preferences->putBool(preference_mqtt_hass_enabled, true); - } - else if(value == "" && _preferences->getBool(preference_mqtt_hass_enabled, false)) - { - _preferences->putBool(preference_mqtt_hass_enabled, false); - } - Log->print(F("Setting changed: ")); Log->println(key); configChanged = true; @@ -3541,12 +3525,12 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request) printInputField(&response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30, "", false, true); printInputField(&response, "MQTTPASS", "MQTT Password", "*", 30, "", true, true); printInputField(&response, "MQTTPATH", "MQTT NukiHub Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180, ""); - printCheckBox(&response, "ENHADISC", "Enable Home Assistant auto discovery", _preferences->getBool(preference_mqtt_hass_enabled), ""); + printCheckBox(&response, "ENHADISC", "Enable Home Assistant auto discovery", _preferences->getBool(preference_mqtt_hass_enabled), "chkHass"); response.print("
Current bootloop prevention state"); response.print(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled"); response.print("

"); response.print("

Advanced MQTT Configuration

"); response.print(""); - printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (usually \"homeassistant\")", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, ""); + printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (usually \"homeassistant\")", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, "class=\"chkHass\""); if(_preferences->getBool(preference_opener_enabled, false)) { printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), ""); @@ -3566,7 +3550,9 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request) response.print("* If no encryption is configured for the MQTT broker, leave empty.

"); response.print("
"); response.print(""); - response.print(""); + response.print(""); + response.print(""); + response.print(""); return response.endSend(); } From 7632a8cbcc5d621d9672e7dd4662228a956a4851 Mon Sep 17 00:00:00 2001 From: iranl Date: Mon, 4 Nov 2024 21:32:57 +0100 Subject: [PATCH 4/4] HTTP, MQTT and PSRAM fixes --- boards/nuki-esp32dev.json | 37 ++++++++++++++++++++++++ platformio.ini | 2 +- src/NukiNetwork.cpp | 9 ++++-- src/NukiNetwork.h | 1 + src/WebCfgServer.cpp | 60 +++++++++++++++++++++++++-------------- updater/platformio.ini | 2 +- 6 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 boards/nuki-esp32dev.json diff --git a/boards/nuki-esp32dev.json b/boards/nuki-esp32dev.json new file mode 100644 index 0000000..5b04731 --- /dev/null +++ b/boards/nuki-esp32dev.json @@ -0,0 +1,37 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue", + "f_cpu": "240000000L", + "f_flash": "40000000L", + "flash_mode": "dio", + "mcu": "esp32", + "variant": "esp32" + }, + "connectivity": [ + "wifi", + "bluetooth", + "ethernet", + "can" + ], + "debug": { + "openocd_board": "esp-wroom-32.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif ESP32 Dev Module", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://en.wikipedia.org/wiki/ESP32", + "vendor": "AI Thinker" +} diff --git a/platformio.ini b/platformio.ini index fd5dd54..1785ee6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -69,7 +69,7 @@ monitor_filters = time [env:esp32] -board = esp32dev +board = nuki-esp32dev board_build.cmake_extra_args = -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.defaults.esp32" extra_scripts = diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp index 5755cf6..d15dad6 100644 --- a/src/NukiNetwork.cpp +++ b/src/NukiNetwork.cpp @@ -461,8 +461,13 @@ bool NukiNetwork::update() if(_lastMaintenanceTs == 0 || (ts - _lastMaintenanceTs) > 30000) { - publishULong(_maintenancePathPrefix, mqtt_topic_uptime, ts / 1000 / 60, true); - publishString(_maintenancePathPrefix, mqtt_topic_mqtt_connection_state, "online", true); + int64_t curUptime = ts / 1000 / 60; + if(curUptime > _publishedUpTime) + { + publishULong(_maintenancePathPrefix, mqtt_topic_uptime, curUptime, true); + _publishedUpTime = curUptime; + } + //publishString(_maintenancePathPrefix, mqtt_topic_mqtt_connection_state, "online", true); if(_lastMaintenanceTs == 0) { diff --git a/src/NukiNetwork.h b/src/NukiNetwork.h index 517d670..a867311 100644 --- a/src/NukiNetwork.h +++ b/src/NukiNetwork.h @@ -155,6 +155,7 @@ private: bool _connectReplyReceived = false; bool _firstDisconnected = true; + int64_t _publishedUpTime = 0; int64_t _nextReconnect = 0; char _mqttBrokerAddr[101] = {0}; char _mqttUser[31] = {0}; diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 790d387..61255a7 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -292,14 +292,31 @@ void WebCfgServer::initialize() { return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); } - if(_allowRestartToPortal) + String value = ""; + if(request->hasParam("CONFIRMTOKEN")) { - esp_err_t res = buildConfirmHtml(request, "Restarting. Connect to ESP access point (\"NukiHub\" with password \"NukiHubESP32\") to reconfigure Wi-Fi.", 0); - waitAndProcess(false, 1000); - _network->reconfigureDevice(); - return res; + const PsychicWebParameter* p = request->getParam("CONFIRMTOKEN"); + if(p->value() != "") + { + value = p->value(); + } } - return(ESP_OK); + else + { + return buildConfirmHtml(request, "No confirm code set.", 3, true); + } + if(value != _confirmCode) + { + return request->redirect("/"); + } + if(!_allowRestartToPortal) + { + return buildConfirmHtml(request, "Can't reset WiFi when network device is Ethernet", 3, true); + } + esp_err_t res = buildConfirmHtml(request, "Restarting. Connect to ESP access point (\"NukiHub\" with password \"NukiHubESP32\") to reconfigure Wi-Fi.", 0); + waitAndProcess(false, 1000); + _network->reconfigureDevice(); + return res; }); #endif _psychicServer->on("/unpairlock", HTTP_POST, [&](PsychicRequest *request) @@ -3363,37 +3380,37 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request) printParameter(&response, "Nuki Opener PIN status", openerState.c_str(), "", "openerPin"); } } - printParameter(&response, "Firmware", NUKI_HUB_VERSION, "/info", "firmware"); + printParameter(&response, "Firmware", NUKI_HUB_VERSION, "/info?", "firmware"); if(_preferences->getBool(preference_check_updates)) { - printParameter(&response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota", "ota"); + printParameter(&response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota?", "ota"); } response.print("

"); response.print("