From 327038119eb74d8a9455402a9ced24efab854dda Mon Sep 17 00:00:00 2001 From: technyon Date: Sat, 4 Feb 2023 17:31:59 +0100 Subject: [PATCH 01/36] Rename W5500 classes --- CMakeLists.txt | 4 ++-- ...ntSyncEthernet.cpp => ClientSyncW5500.cpp} | 20 +++++++++---------- ...ClientSyncEthernet.h => ClientSyncW5500.h} | 4 ++-- networkDevices/W5500Device.h | 4 ++-- networkDevices/espMqttClientEthernet.cpp | 8 -------- networkDevices/espMqttClientW5500.cpp | 8 ++++++++ ...tClientEthernet.h => espMqttClientW5500.h} | 8 ++++---- 7 files changed, 28 insertions(+), 28 deletions(-) rename networkDevices/{ClientSyncEthernet.cpp => ClientSyncW5500.cpp} (76%) rename networkDevices/{ClientSyncEthernet.h => ClientSyncW5500.h} (89%) delete mode 100644 networkDevices/espMqttClientEthernet.cpp create mode 100644 networkDevices/espMqttClientW5500.cpp rename networkDevices/{espMqttClientEthernet.h => espMqttClientW5500.h} (53%) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc1d2e7..ea0462c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,8 @@ file(GLOB SRCFILES networkDevices/NetworkDevice.h networkDevices/WifiDevice.cpp networkDevices/W5500Device.cpp - networkDevices/ClientSyncEthernet.cpp - networkDevices/espMqttClientEthernet.cpp + networkDevices/ClientSyncW5500.cpp + networkDevices/espMqttClientW5500.cpp NukiWrapper.cpp NukiOpenerWrapper.cpp MqttTopics.h diff --git a/networkDevices/ClientSyncEthernet.cpp b/networkDevices/ClientSyncW5500.cpp similarity index 76% rename from networkDevices/ClientSyncEthernet.cpp rename to networkDevices/ClientSyncW5500.cpp index 513c8f8..b6f764c 100644 --- a/networkDevices/ClientSyncEthernet.cpp +++ b/networkDevices/ClientSyncW5500.cpp @@ -8,17 +8,17 @@ the LICENSE file. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) -#include "ClientSyncEthernet.h" +#include "ClientSyncW5500.h" #include // socket options namespace espMqttClientInternals { - ClientSyncEthernet::ClientSyncEthernet() + ClientSyncW5500::ClientSyncW5500() : client() { // empty } - bool ClientSyncEthernet::connect(IPAddress ip, uint16_t port) { + bool ClientSyncW5500::connect(IPAddress ip, uint16_t port) { bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool if (ret) { #if defined(ARDUINO_ARCH_ESP8266) @@ -34,7 +34,7 @@ namespace espMqttClientInternals { return ret; } - bool ClientSyncEthernet::connect(const char* host, uint16_t port) { + bool ClientSyncW5500::connect(const char* host, uint16_t port) { bool ret = client.connect(host, port); // implicit conversion of return code int --> bool if (ret) { #if defined(ARDUINO_ARCH_ESP8266) @@ -50,27 +50,27 @@ namespace espMqttClientInternals { return ret; } - size_t ClientSyncEthernet::write(const uint8_t* buf, size_t size) { + size_t ClientSyncW5500::write(const uint8_t* buf, size_t size) { return client.write(buf, size); } - int ClientSyncEthernet::available() { + int ClientSyncW5500::available() { return client.available(); } - int ClientSyncEthernet::read(uint8_t* buf, size_t size) { + int ClientSyncW5500::read(uint8_t* buf, size_t size) { return client.read(buf, size); } - void ClientSyncEthernet::stop() { + void ClientSyncW5500::stop() { client.stop(); } - bool ClientSyncEthernet::connected() { + bool ClientSyncW5500::connected() { return client.connected(); } - bool ClientSyncEthernet::disconnected() { + bool ClientSyncW5500::disconnected() { return !client.connected(); } diff --git a/networkDevices/ClientSyncEthernet.h b/networkDevices/ClientSyncW5500.h similarity index 89% rename from networkDevices/ClientSyncEthernet.h rename to networkDevices/ClientSyncW5500.h index 69df7ea..64f5b8d 100644 --- a/networkDevices/ClientSyncEthernet.h +++ b/networkDevices/ClientSyncW5500.h @@ -7,9 +7,9 @@ namespace espMqttClientInternals { - class ClientSyncEthernet : public Transport { + class ClientSyncW5500 : public Transport { public: - ClientSyncEthernet(); + ClientSyncW5500(); bool connect(IPAddress ip, uint16_t port) override; bool connect(const char* host, uint16_t port) override; size_t write(const uint8_t* buf, size_t size) override; diff --git a/networkDevices/W5500Device.h b/networkDevices/W5500Device.h index a86fb06..7128af4 100644 --- a/networkDevices/W5500Device.h +++ b/networkDevices/W5500Device.h @@ -2,7 +2,7 @@ #include "NetworkDevice.h" #include "espMqttClient.h" -#include "espMqttClientEthernet.h" +#include "espMqttClientW5500.h" #include #include @@ -61,7 +61,7 @@ private: void resetDevice(); void initializeMacAddress(byte* mac); - espMqttClientEthernet _mqttClient; + espMqttClientW5500 _mqttClient; Preferences* _preferences = nullptr; int _maintainResult = 0; diff --git a/networkDevices/espMqttClientEthernet.cpp b/networkDevices/espMqttClientEthernet.cpp deleted file mode 100644 index 4e7c826..0000000 --- a/networkDevices/espMqttClientEthernet.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "espMqttClientEthernet.h" - -espMqttClientEthernet::espMqttClientEthernet(uint8_t priority, uint8_t core) -: MqttClientSetup(true, priority, core), - _client() -{ - _transport = &_client; -} diff --git a/networkDevices/espMqttClientW5500.cpp b/networkDevices/espMqttClientW5500.cpp new file mode 100644 index 0000000..445cb71 --- /dev/null +++ b/networkDevices/espMqttClientW5500.cpp @@ -0,0 +1,8 @@ +#include "espMqttClientW5500.h" + +espMqttClientW5500::espMqttClientW5500(uint8_t priority, uint8_t core) +: MqttClientSetup(true, priority, core), + _client() +{ + _transport = &_client; +} diff --git a/networkDevices/espMqttClientEthernet.h b/networkDevices/espMqttClientW5500.h similarity index 53% rename from networkDevices/espMqttClientEthernet.h rename to networkDevices/espMqttClientW5500.h index d2d6b7e..f880ed7 100644 --- a/networkDevices/espMqttClientEthernet.h +++ b/networkDevices/espMqttClientW5500.h @@ -1,19 +1,19 @@ #pragma once #include "MqttClientSetup.h" -#include "ClientSyncEthernet.h" +#include "ClientSyncW5500.h" -class espMqttClientEthernet : public MqttClientSetup { +class espMqttClientW5500 : public MqttClientSetup { public: #if defined(ARDUINO_ARCH_ESP32) - explicit espMqttClientEthernet(uint8_t priority = 1, uint8_t core = 1); + explicit espMqttClientW5500(uint8_t priority = 1, uint8_t core = 1); #else espMqttClient(); #endif protected: #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - espMqttClientInternals::ClientSyncEthernet _client; + espMqttClientInternals::ClientSyncW5500 _client; #elif defined(__linux__) espMqttClientInternals::ClientPosix _client; #endif From 2094595e78f5658aa34a23120fa6b3d108036dc4 Mon Sep 17 00:00:00 2001 From: technyon Date: Sun, 5 Feb 2023 12:11:10 +0100 Subject: [PATCH 02/36] add /info endpoint to publish preference content --- NukiOpenerWrapper.cpp | 5 ++ NukiOpenerWrapper.h | 1 + NukiWrapper.cpp | 5 ++ NukiWrapper.h | 1 + PreferencesKeys.h | 111 ++++++++++++++++++++++++++++++++++++++++++ WebCfgServer.cpp | 26 +++++++++- WebCfgServer.h | 1 + 7 files changed, 149 insertions(+), 1 deletion(-) diff --git a/NukiOpenerWrapper.cpp b/NukiOpenerWrapper.cpp index 7ba2685..aa82aa7 100644 --- a/NukiOpenerWrapper.cpp +++ b/NukiOpenerWrapper.cpp @@ -205,6 +205,11 @@ void NukiOpenerWrapper::update() memcpy(&_lastKeyTurnerState, &_keyTurnerState, sizeof(NukiOpener::OpenerState)); } +bool NukiOpenerWrapper::isPinSet() +{ + return _nukiOpener.getSecurityPincode() != 0; +} + void NukiOpenerWrapper::setPin(const uint16_t pin) { _nukiOpener.saveSecurityPincode(pin); diff --git a/NukiOpenerWrapper.h b/NukiOpenerWrapper.h index 152d9cf..8290624 100644 --- a/NukiOpenerWrapper.h +++ b/NukiOpenerWrapper.h @@ -15,6 +15,7 @@ public: void initialize(); void update(); + bool isPinSet(); void setPin(const uint16_t pin); void unpair(); diff --git a/NukiWrapper.cpp b/NukiWrapper.cpp index 7c72a76..805bf13 100644 --- a/NukiWrapper.cpp +++ b/NukiWrapper.cpp @@ -251,6 +251,11 @@ void NukiWrapper::unlatch() _nextLockAction = NukiLock::LockAction::Unlatch; } +bool NukiWrapper::isPinSet() +{ + return _nukiLock.getSecurityPincode() != 0; +} + void NukiWrapper::setPin(const uint16_t pin) { _nukiLock.saveSecurityPincode(pin); diff --git a/NukiWrapper.h b/NukiWrapper.h index 6a6e758..6b03b30 100644 --- a/NukiWrapper.h +++ b/NukiWrapper.h @@ -19,6 +19,7 @@ public: void unlock(); void unlatch(); + bool isPinSet(); void setPin(const uint16_t pin); void unpair(); diff --git a/PreferencesKeys.h b/PreferencesKeys.h index 806bf44..5a4b3bd 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -1,5 +1,7 @@ #pragma once +#include + #define preference_started_before "run" #define preference_deviceId "deviceId" #define preference_mqtt_broker "mqttbroker" @@ -41,5 +43,114 @@ #define preference_has_mac_byte_1 "macb1" #define preference_has_mac_byte_2 "macb2" +class DebugPreferences +{ +private: + std::vector _keys = + { + preference_started_before, preference_deviceId, preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_lock_enabled, preference_mqtt_lock_path, preference_opener_enabled, preference_mqtt_opener_path, preference_max_keypad_code_count, preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_network_hardware, preference_network_hardware_gpio, preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, preference_restart_timer, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, preference_register_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata, preference_gpio_locking_enabled, preference_presence_detection_timeout, preference_has_mac_saved, preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2, + }; + std::vector _redact = + { + preference_mqtt_user, preference_mqtt_password, + preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, + preference_cred_user, preference_cred_password, + }; + std::vector _boolPrefs = + { + preference_started_before, preference_mqtt_log_enabled, preference_lock_enabled, preference_opener_enabled, + preference_restart_on_disconnect, preference_keypad_control_enabled, preference_register_as_app, + preference_publish_authdata, preference_gpio_locking_enabled, preference_has_mac_saved, + }; + const bool isRedacted(const char* key) const + { + return std::find(_redact.begin(), _redact.end(), key) != _redact.end(); + } + const String redact(const String s) const + { + return s == "" ? "" : "***"; + } + const String redact(const int i) const + { + return i == 0 ? "" : "***"; + } + const String redact(const uint i) const + { + return i == 0 ? "" : "***"; + } + const void appendPreferenceInt(Preferences *preferences, String& s, const char* description, const char* key) + { + s.concat(description); + s.concat(": "); + s.concat(isRedacted(key) ? redact(preferences->getInt(key)) : String(preferences->getInt(key))); + s.concat("\n"); + } + const void appendPreferenceUInt(Preferences *preferences, String& s, const char* description, const char* key) + { + s.concat(description); + s.concat(": "); + s.concat(isRedacted(key) ? redact(preferences->getUInt(key)) : String(preferences->getUInt(key))); + s.concat("\n"); + } + const void appendPreferenceBool(Preferences *preferences, String& s, const char* description, const char* key) + { + s.concat(description); + s.concat(": "); + s.concat(preferences->getBool(key) ? "true" : "false"); + s.concat("\n"); + } + const void appendPreferenceString(Preferences *preferences, String& s, const char* description, const char* key) + { + s.concat(description); + s.concat(": "); + s.concat(isRedacted(key) ? redact(preferences->getString(key)) : preferences->getString(key)); + s.concat("\n"); + } + + const void appendPreference(Preferences *preferences, String& s, const char* key) + { + if(std::find(_boolPrefs.begin(), _boolPrefs.end(), key) != _boolPrefs.end()) + { + appendPreferenceBool(preferences, s, key, key); + return; + } + + switch(preferences->getType(key)) + { + case PT_I8: + case PT_I16: + case PT_I32: + case PT_I64: + appendPreferenceInt(preferences, s, key, key); + break; + case PT_U8: + case PT_U16: + case PT_U32: + case PT_U64: + appendPreferenceUInt(preferences, s, key, key); + break; + case PT_STR: + appendPreferenceString(preferences, s, key, key); + break; + default: + appendPreferenceString(preferences, s, key, key); + break; + } + } + +public: + const String preferencesToString(Preferences *preferences) + { + String s = ""; + + for(const auto& key : _keys) + { + appendPreference(preferences, s, key); + } + + return s; + } + +}; diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index c6ba8d1..7b6ad63 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -159,6 +159,14 @@ void WebCfgServer::initialize() handleOtaUpload(); }); + _server.on("/info", [&]() { + if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) { + return _server.requestAuthentication(); + } + String response = ""; + buildInfoHtml(response); + _server.send(200, "text/html", response); + }); _server.begin(); @@ -698,6 +706,22 @@ void WebCfgServer::buildConfigureWifiHtml(String &response) response.concat(""); } +void WebCfgServer::buildInfoHtml(String &response) +{ + DebugPreferences debugPreferences; + + buildHtmlHeader(response); + response.concat("

Info

");
+    response.concat(debugPreferences.preferencesToString(_preferences));
+
+    response.concat("Lock PIN set: ");
+    response.concat(_nuki->isPinSet() ? "Yes\n" : "No\n");
+    response.concat("Opener PIN set: ");
+    response.concat(_nukiOpener->isPinSet() ? "Yes\n" : "No\n");
+
+    response.concat("
"); +} + void WebCfgServer::processUnpair(bool opener) { String response = ""; @@ -981,4 +1005,4 @@ const std::vector> WebCfgServer::getNetworkGpioOptions } return options; -} \ No newline at end of file +} diff --git a/WebCfgServer.h b/WebCfgServer.h index cf1be2b..4736519 100644 --- a/WebCfgServer.h +++ b/WebCfgServer.h @@ -37,6 +37,7 @@ private: void buildNukiConfigHtml(String& response); void buildConfirmHtml(String& response, const String &message, uint32_t redirectDelay = 5); void buildConfigureWifiHtml(String& response); + void buildInfoHtml(String& response); void sendCss(); void sendFavicon(); void processUnpair(bool opener); From 4dd1a9e516afb4e68c0d3a2ce361d05de551d6e4 Mon Sep 17 00:00:00 2001 From: technyon Date: Sun, 5 Feb 2023 12:23:24 +0100 Subject: [PATCH 03/36] show length restrictions on some input fields --- WebCfgServer.cpp | 38 +++++++++++++++++++++++++++----------- WebCfgServer.h | 4 ++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index 7b6ad63..9c3ebcb 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -519,8 +519,8 @@ void WebCfgServer::buildCredHtml(String &response) response.concat("
"); response.concat("

Credentials

"); response.concat(""); - printInputField(response, "CREDUSER", "User (# to clear)", _preferences->getString(preference_cred_user).c_str(), 30); - printInputField(response, "CREDPASS", "Password (max 30 characters)", "*", 30, true); + printInputField(response, "CREDUSER", "User (# to clear)", _preferences->getString(preference_cred_user).c_str(), 30, false, true); + printInputField(response, "CREDPASS", "Password", "*", 30, true, true); printInputField(response, "CREDPASSRE", "Retype password", "*", 30, true); response.concat("
"); response.concat("
"); @@ -610,16 +610,16 @@ void WebCfgServer::buildMqttConfigHtml(String &response) printInputField(response, "HOSTNAME", "Host name", _preferences->getString(preference_hostname).c_str(), 100); printInputField(response, "MQTTSERVER", "MQTT Broker", _preferences->getString(preference_mqtt_broker).c_str(), 100); printInputField(response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5); - printInputField(response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30); - printInputField(response, "MQTTPASS", "MQTT Password", "*", 30, true); + 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); response.concat("
"); response.concat("

Advanced MQTT and Network Configuration

"); response.concat(""); printInputField(response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30); - printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, _network->encryptionSupported()); - printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, _network->encryptionSupported()); - printTextarea(response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, _network->encryptionSupported()); + printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, _network->encryptionSupported(), true); + printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, _network->encryptionSupported(), true); + printTextarea(response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, _network->encryptionSupported(), true); printDropDown(response, "NWHW", "Network hardware", String(_preferences->getInt(preference_network_hardware)), getNetworkDetectionOptions()); printDropDown(response, "NWHWDT", "Network hardware detection", String(_preferences->getInt(preference_network_hardware_gpio)), getNetworkGpioOptions()); printInputField(response, "RSSI", "RSSI Publish interval (seconds; -1 to disable)", _preferences->getInt(preference_rssi_publish_interval), 6); @@ -775,8 +775,9 @@ void WebCfgServer::printInputField(String& response, const char *token, const char *description, const char *value, - const size_t maxLength, - const bool isPassword) + const size_t& maxLength, + const bool& isPassword, + const bool& showLengthRestriction) { char maxLengthStr[20]; @@ -784,6 +785,14 @@ void WebCfgServer::printInputField(String& response, response.concat("
"); response.concat(description); + + if(showLengthRestriction) + { + response.concat(" (Max. "); + response.concat(maxLength); + response.concat(" characters)"); + } + response.concat(""); response.concat(""); response.concat(description); + if(showLengthRestriction) + { + response.concat(" (Max. "); + response.concat(maxLength); + response.concat(" characters)"); + } response.concat(""); response.concat("