Merge pull request #591 from iranl/spiffs

Memory optimizations, MQTT SPIFFS and SPIFFS Import/Export
This commit is contained in:
iranl
2025-01-03 16:46:24 +01:00
committed by GitHub
9 changed files with 835 additions and 334 deletions

View File

@@ -32,9 +32,6 @@ build_unflags =
-Wall
build_flags =
-fexceptions
-DTLS_CA_MAX_SIZE=2200
-DTLS_CERT_MAX_SIZE=2200
-DTLS_KEY_MAX_SIZE=2200
-DESP_PLATFORM
-DESP32
-DARDUINO_ARCH_ESP32
@@ -85,7 +82,7 @@ build_flags =
extends = env:esp32
board = esp32-c3-devkitc-02
board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.singlecore.defaults"
[env:esp32-s3]
extends = env:esp32
@@ -103,14 +100,14 @@ board_build.cmake_extra_args =
extends = env:esp32
board = esp32-c6-devkitm-1
board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.singlecore.defaults"
[env:esp32-h2]
extends = env:esp32
board = esp32-h2-devkitm-1
board_build.cmake_extra_args =
-DNUKI_TARGET_H2=y
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.singlecore.defaults"
lib_ignore =
BLE
BluetoothSerial
@@ -125,7 +122,7 @@ lib_ignore =
extends = env:esp32
board = nuki-esp32solo1
board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.defaults.esp32-solo1"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.singlecore.defaults;sdkconfig.defaults.esp32-solo1"
[env:esp32_dbg]
extends = env:esp32
@@ -143,7 +140,7 @@ build_flags =
extends = env:esp32-c3
custom_build = debug
board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.singlecore.defaults"
build_flags =
${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
@@ -155,7 +152,7 @@ build_flags =
extends = env:esp32-c6
custom_build = debug
board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.singlecore.defaults"
build_flags =
${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
@@ -168,7 +165,7 @@ extends = env:esp32-h2
custom_build = debug
board_build.cmake_extra_args =
-DNUKI_TARGET_H2=y
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.singlecore.defaults"
build_flags =
${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
@@ -204,7 +201,7 @@ build_flags =
extends = env:esp32-solo1
custom_build = debug
board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.defaults.esp32-solo1"
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.singlecore.defaults;sdkconfig.defaults.esp32-solo1"
build_flags =
${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG

View File

@@ -14,7 +14,7 @@ CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y
CONFIG_BT_NIMBLE_LOG_LEVEL=0
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=8
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4
CONFIG_BT_NIMBLE_MAX_BONDS=8
CONFIG_BT_NIMBLE_NVS_PERSIST=y
CONFIG_BT_NIMBLE_GATT_MAX_PROCS=8
@@ -22,7 +22,7 @@ CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y
CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
CONFIG_BT_NIMBLE_ROLE_CENTRAL=y
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y
CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=n
CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y
CONFIG_BT_NIMBLE_ROLE_OBSERVER=y
CONFIG_BT_NIMBLE_SM_LEGACY=y
@@ -46,9 +46,11 @@ CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH=2
CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT=y
CONFIG_BT_NIMBLE_RPA_TIMEOUT=900
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=y
CONFIG_BTDM_CTRL_BLE_MAX_CONN=8
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=8
CONFIG_BT_ACL_CONNECTIONS=8
CONFIG_BTDM_CTRL_BLE_MAX_CONN=4
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=4
CONFIG_BT_CTRL_BLE_MAX_ACT=4
CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=4
CONFIG_BT_ACL_CONNECTIONS=4
CONFIG_BTDM_CTRLR_BR_EDR_MAX_ACL_CONN_EFF=0
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
@@ -108,4 +110,12 @@ CONFIG_BOOTLOADER_WDT_TIME_MS=120000
CONFIG_LWIP_MAX_SOCKETS=24
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1024
CONFIG_ARDUINO_LOOP_STACK_SIZE=12288
CONFIG_ARDUINO_LOOP_STACK_SIZE=12288
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4
CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM=4
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=8
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=8
CONFIG_ESP_WIFI_RX_BA_WIN=6
CONFIG_ESP_WIFI_IRAM_OPT=n
CONFIG_ESP_WIFI_RX_IRAM_OPT=n
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y

View File

@@ -0,0 +1,3 @@
CONFIG_MBEDTLS_IRAM_8BIT_MEM_ALLOC=y
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT=y
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1

View File

@@ -5,7 +5,7 @@
#define NUKI_HUB_VERSION "9.07"
#define NUKI_HUB_VERSION_INT (uint32_t)907
#define NUKI_HUB_BUILD "unknownbuildnr"
#define NUKI_HUB_DATE "2025-01-02"
#define NUKI_HUB_DATE "2025-01-03"
#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"

View File

@@ -3,6 +3,9 @@
#include <vector>
#include "Config.h"
#include "Logger.h"
#include "FS.h"
#include "SPIFFS.h"
#include "RestartReason.h"
#ifndef CONFIG_IDF_TARGET_ESP32H2
#include <WiFi.h>
@@ -69,6 +72,7 @@
#define preference_connect_mode (char*)"nukiConnMode"
#define preference_http_auth_type (char*)"httpdAuthType"
#define preference_update_time (char*)"updateTime"
#define preference_mqtt_ssl_enabled (char*)"mqttSSLena"
// CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT
#define preference_find_best_rssi (char*)"nwbestrssi"
@@ -199,6 +203,7 @@ inline void initPreferences(Preferences* preferences)
preferences->putBool(preference_publish_authdata, false);
preferences->putBool(preference_register_as_app, false);
preferences->putBool(preference_register_opener_as_app, false);
preferences->putBool(preference_mqtt_ssl_enabled, false);
preferences->putInt(preference_mqtt_broker_port, 1883);
preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
@@ -226,7 +231,6 @@ inline void initPreferences(Preferences* preferences)
preferences->putBool(preference_connect_mode, true);
preferences->putBool(preference_http_auth_type, false);
preferences->putBool(preference_retain_gpio, false);
#ifndef CONFIG_IDF_TARGET_ESP32H2
WiFi.begin();
@@ -236,6 +240,7 @@ inline void initPreferences(Preferences* preferences)
else
{
int lastConfigVer = preferences->getInt(preference_config_version);
bool rebootOnMigrate = false;
Log->print("Last config version: ");
Log->println(lastConfigVer);
@@ -357,7 +362,100 @@ inline void initPreferences(Preferences* preferences)
Log->println("Migration 9.02");
preferences->putBool(preference_reset_mqtt_topics, true);
}
if (lastConfigVer < 907)
{
Log->println("Migration 9.07");
char ca[2200] = {0};
char cert[2200] = {0};
char key[2200] = {0};
size_t caLength = preferences->getString(preference_mqtt_ca, ca, 2200);
size_t crtLength = preferences->getString(preference_mqtt_crt, cert, 2200);
size_t keyLength = preferences->getString(preference_mqtt_key, key, 2200);
if (caLength > 1)
{
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.ca", FILE_WRITE);
if (!file) {
Log->println("Failed to open /mqtt_ssl.ca for writing");
}
else
{
if (!file.print(ca))
{
Log->println("Failed to write /mqtt_ssl.ca");
}
file.close();
}
}
rebootOnMigrate = true;
preferences->putBool(preference_mqtt_ssl_enabled, true);
preferences->putString(preference_mqtt_ca, "");
}
if (crtLength > 1)
{
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.crt", FILE_WRITE);
if (!file) {
Log->println("Failed to open /mqtt_ssl.crt for writing");
}
else
{
if (!file.print(cert))
{
Log->println("Failed to write /mqtt_ssl.crt");
}
file.close();
}
}
rebootOnMigrate = true;
preferences->putString(preference_mqtt_crt, "");
}
if (keyLength > 1)
{
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.key", FILE_WRITE);
if (!file) {
Log->println("Failed to open /mqtt_ssl.key for writing");
}
else
{
if (!file.print(key))
{
Log->println("Failed to write /mqtt_ssl.key");
}
file.close();
}
}
rebootOnMigrate = true;
preferences->putString(preference_mqtt_key, "");
}
}
preferences->putInt(preference_config_version, NUKI_HUB_VERSION_INT);
if (rebootOnMigrate)
{
restartEsp(RestartReason::OTACompleted);
}
}
#endif
}
@@ -367,29 +465,29 @@ class DebugPreferences
private:
std::vector<char*> _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_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status,
preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_update_time,
preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt,
preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address,
preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type,
preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled,
preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_info_enabled,
preference_register_as_app, preference_register_opener_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user,
preference_cred_password, preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info,
preference_official_hybrid_enabled, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry,
preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries,
preference_update_from_mqtt, preference_show_secrets, preference_ble_tx_power, preference_webserial_enabled, preference_find_best_rssi,
preference_network_custom_mdc, preference_network_custom_clk, preference_network_custom_phy, preference_network_custom_addr, preference_network_custom_irq,
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_mqtt_hass_enabled, preference_hass_device_discovery, preference_retain_gpio,
preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command, preference_connect_mode,
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_nukihub_id
preference_started_before, preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener,
preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates,
preference_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status,
preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_update_time,
preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt,
preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address,
preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type,
preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled,
preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_info_enabled,
preference_register_as_app, preference_register_opener_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user,
preference_cred_password, preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info, preference_mqtt_ssl_enabled,
preference_official_hybrid_enabled, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry,
preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries,
preference_update_from_mqtt, preference_show_secrets, preference_ble_tx_power, preference_webserial_enabled, preference_find_best_rssi,
preference_network_custom_mdc, preference_network_custom_clk, preference_network_custom_phy, preference_network_custom_addr, preference_network_custom_irq,
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_mqtt_hass_enabled, preference_hass_device_discovery, preference_retain_gpio,
preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command, preference_connect_mode,
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_nukihub_id
};
std::vector<char*> _redact =
{
@@ -398,34 +496,34 @@ private:
};
std::vector<char*> _boolPrefs =
{
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_update_time,
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, preference_show_secrets,
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled,
preference_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled, preference_mqtt_hass_enabled, preference_retain_gpio,
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_hass_device_discovery,
preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_http_auth_type,
preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command, preference_connect_mode,
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_update_time,
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, preference_show_secrets,
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled,
preference_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled, preference_mqtt_hass_enabled, preference_retain_gpio,
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_hass_device_discovery,
preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_http_auth_type,
preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command, preference_connect_mode,
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_mqtt_ssl_enabled
};
std::vector<char*> _bytePrefs =
{
preference_acl, preference_conf_info_enabled, preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl,
preference_conf_opener_advanced_acl, preference_gpio_configuration
preference_acl, preference_conf_info_enabled, preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl,
preference_conf_opener_advanced_acl, preference_gpio_configuration
};
std::vector<char*> _intPrefs =
{
preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, preference_mqtt_broker_port,
preference_lock_pin_status, preference_opener_pin_status, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count,
preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_buffer_size, preference_network_hardware,
preference_rssi_publish_interval, preference_network_timeout, preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_command_nr_of_retries,
preference_command_retry_delay, preference_query_interval_hybrid_lockstate,
preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries,
preference_ble_tx_power, preference_network_custom_mdc, preference_network_custom_clk, preference_network_custom_phy, preference_network_custom_addr,
preference_network_custom_irq, 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_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, preference_mqtt_broker_port,
preference_lock_pin_status, preference_opener_pin_status, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count,
preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_buffer_size, preference_network_hardware,
preference_rssi_publish_interval, preference_network_timeout, preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_command_nr_of_retries,
preference_command_retry_delay, preference_query_interval_hybrid_lockstate,
preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries,
preference_ble_tx_power, preference_network_custom_mdc, preference_network_custom_clk, preference_network_custom_phy, preference_network_custom_addr,
preference_network_custom_irq, 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
};
public:
const std::vector<char*> getPreferencesKeys()

View File

@@ -4,10 +4,10 @@
#include "Logger.h"
#include "RestartReason.h"
#include <esp_task_wdt.h>
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
#include "esp_psram.h"
#include "FS.h"
#include "SPIFFS.h"
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
#include "esp_psram.h"
#endif
#ifndef CONFIG_IDF_TARGET_ESP32H2
#include <esp_wifi.h>
@@ -112,20 +112,10 @@ void WebCfgServer::initialize()
});
_psychicServer->on("/style.css", HTTP_GET, [&](PsychicRequest *request, PsychicResponse* resp)
{
if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword))
{
return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in.");
}
return sendCss(request, resp);
});
_psychicServer->on("/favicon.ico", HTTP_GET, [&](PsychicRequest *request, PsychicResponse* resp)
{
if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword))
{
return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in.");
}
return sendFavicon(request, resp);
});
@@ -1269,206 +1259,335 @@ void WebCfgServer::printInputField(PsychicStreamResponse *response,
#ifndef NUKI_HUB_UPDATER
esp_err_t WebCfgServer::sendSettings(PsychicRequest *request, PsychicResponse* resp)
{
bool redacted = false;
bool pairing = false;
if(request->hasParam("redacted"))
{
const PsychicWebParameter* p = request->getParam("redacted");
if(p->value() == "1")
{
redacted = true;
}
}
if(request->hasParam("pairing"))
{
const PsychicWebParameter* p = request->getParam("pairing");
if(p->value() == "1")
{
pairing = true;
}
}
JsonDocument json;
String jsonPretty;
String name;
DebugPreferences debugPreferences;
const std::vector<char*> keysPrefs = debugPreferences.getPreferencesKeys();
const std::vector<char*> boolPrefs = debugPreferences.getPreferencesBoolKeys();
const std::vector<char*> redactedPrefs = debugPreferences.getPreferencesRedactedKeys();
const std::vector<char*> bytePrefs = debugPreferences.getPreferencesByteKeys();
for(const auto& key : keysPrefs)
if(request->hasParam("type"))
{
if(strcmp(key, preference_show_secrets) == 0)
name = "nuki_hub_http_ssl.json";
const PsychicWebParameter* p = request->getParam("type");
if(p->value() == "https")
{
continue;
}
if(strcmp(key, preference_latest_version) == 0)
{
continue;
}
if(!redacted) if(std::find(redactedPrefs.begin(), redactedPrefs.end(), key) != redactedPrefs.end())
{
continue;
name = "nuki_hub_http_ssl.json";
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/http_ssl.crt");
if (!file || file.isDirectory()) {
Log->println("http_ssl.crt not found");
}
else
{
Log->println("Reading http_ssl.crt");
size_t filesize = file.size();
char cert[filesize + 1];
file.read((uint8_t *)cert, sizeof(cert));
file.close();
cert[filesize] = '\0';
json["http_ssl.crt"] = cert;
}
}
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/http_ssl.key");
if (!file || file.isDirectory()) {
Log->println("http_ssl.key not found");
}
else
{
Log->println("Reading http_ssl.key");
size_t filesize = file.size();
char key[filesize + 1];
file.read((uint8_t *)key, sizeof(key));
file.close();
key[filesize] = '\0';
json["http_ssl.key"] = key;
}
}
if(!_preferences->isKey(key))
{
json[key] = "";
}
else if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end())
{
json[key] = _preferences->getBool(key) ? "1" : "0";
}
else
{
switch(_preferences->getType(key))
name = "nuki_hub_mqtt_ssl.json";
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
case PT_I8:
json[key] = String(_preferences->getChar(key));
break;
case PT_I16:
json[key] = String(_preferences->getShort(key));
break;
case PT_I32:
json[key] = String(_preferences->getInt(key));
break;
case PT_I64:
json[key] = String(_preferences->getLong64(key));
break;
case PT_U8:
json[key] = String(_preferences->getUChar(key));
break;
case PT_U16:
json[key] = String(_preferences->getUShort(key));
break;
case PT_U32:
json[key] = String(_preferences->getUInt(key));
break;
case PT_U64:
json[key] = String(_preferences->getULong64(key));
break;
case PT_STR:
json[key] = _preferences->getString(key);
break;
default:
json[key] = _preferences->getString(key);
break;
File file = SPIFFS.open("/mqtt_ssl.ca");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.ca not found");
}
else
{
Log->println("Reading mqtt_ssl.ca");
size_t filesize = file.size();
char ca[filesize + 1];
file.read((uint8_t *)ca, sizeof(ca));
file.close();
ca[filesize] = '\0';
json["mqtt_ssl.ca"] = ca;
}
}
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.crt");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.crt not found");
}
else
{
Log->println("Reading mqtt_ssl.crt");
size_t filesize = file.size();
char cert[filesize + 1];
file.read((uint8_t *)cert, sizeof(cert));
file.close();
cert[filesize] = '\0';
json["mqtt_ssl.crt"] = cert;
}
}
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.key");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.key not found");
}
else
{
Log->println("Reading mqtt_ssl.key");
size_t filesize = file.size();
char key[filesize + 1];
file.read((uint8_t *)key, sizeof(key));
file.close();
key[filesize] = '\0';
json["mqtt_ssl.key"] = key;
}
}
}
}
if(pairing)
else
{
if(_nuki != nullptr)
name = "nuki_hub_settings.json";
bool redacted = false;
bool pairing = false;
if(request->hasParam("redacted"))
{
unsigned char currentBleAddress[6];
unsigned char authorizationId[4] = {0x00};
unsigned char secretKeyK[32] = {0x00};
uint16_t storedPincode = 0000;
Preferences nukiBlePref;
nukiBlePref.begin("NukiHub", false);
nukiBlePref.getBytes("bleAddress", currentBleAddress, 6);
nukiBlePref.getBytes("secretKeyK", secretKeyK, 32);
nukiBlePref.getBytes("authorizationId", authorizationId, 4);
nukiBlePref.getBytes("securityPinCode", &storedPincode, 2);
nukiBlePref.end();
const PsychicWebParameter* p = request->getParam("redacted");
if(p->value() == "1")
{
redacted = true;
}
}
if(request->hasParam("pairing"))
{
const PsychicWebParameter* p = request->getParam("pairing");
if(p->value() == "1")
{
pairing = true;
}
}
DebugPreferences debugPreferences;
const std::vector<char*> keysPrefs = debugPreferences.getPreferencesKeys();
const std::vector<char*> boolPrefs = debugPreferences.getPreferencesBoolKeys();
const std::vector<char*> redactedPrefs = debugPreferences.getPreferencesRedactedKeys();
const std::vector<char*> bytePrefs = debugPreferences.getPreferencesByteKeys();
for(const auto& key : keysPrefs)
{
if(strcmp(key, preference_show_secrets) == 0)
{
continue;
}
if(strcmp(key, preference_latest_version) == 0)
{
continue;
}
if(!redacted) if(std::find(redactedPrefs.begin(), redactedPrefs.end(), key) != redactedPrefs.end())
{
continue;
}
if(!_preferences->isKey(key))
{
json[key] = "";
}
else if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end())
{
json[key] = _preferences->getBool(key) ? "1" : "0";
}
else
{
switch(_preferences->getType(key))
{
case PT_I8:
json[key] = String(_preferences->getChar(key));
break;
case PT_I16:
json[key] = String(_preferences->getShort(key));
break;
case PT_I32:
json[key] = String(_preferences->getInt(key));
break;
case PT_I64:
json[key] = String(_preferences->getLong64(key));
break;
case PT_U8:
json[key] = String(_preferences->getUChar(key));
break;
case PT_U16:
json[key] = String(_preferences->getUShort(key));
break;
case PT_U32:
json[key] = String(_preferences->getUInt(key));
break;
case PT_U64:
json[key] = String(_preferences->getULong64(key));
break;
case PT_STR:
json[key] = _preferences->getString(key);
break;
default:
json[key] = _preferences->getString(key);
break;
}
}
}
if(pairing)
{
if(_nuki != nullptr)
{
unsigned char currentBleAddress[6];
unsigned char authorizationId[4] = {0x00};
unsigned char secretKeyK[32] = {0x00};
uint16_t storedPincode = 0000;
Preferences nukiBlePref;
nukiBlePref.begin("NukiHub", false);
nukiBlePref.getBytes("bleAddress", currentBleAddress, 6);
nukiBlePref.getBytes("secretKeyK", secretKeyK, 32);
nukiBlePref.getBytes("authorizationId", authorizationId, 4);
nukiBlePref.getBytes("securityPinCode", &storedPincode, 2);
nukiBlePref.end();
char text[255];
text[0] = '\0';
for(int i = 0 ; i < 6 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", currentBleAddress[i]);
}
json["bleAddressLock"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 32 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", secretKeyK[i]);
}
json["secretKeyKLock"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 4 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", authorizationId[i]);
}
json["authorizationIdLock"] = text;
memset(text, 0, sizeof(text));
json["securityPinCodeLock"] = storedPincode;
}
if(_nukiOpener != nullptr)
{
unsigned char currentBleAddressOpn[6];
unsigned char authorizationIdOpn[4] = {0x00};
unsigned char secretKeyKOpn[32] = {0x00};
uint16_t storedPincodeOpn = 0000;
Preferences nukiBlePref;
nukiBlePref.begin("NukiHubopener", false);
nukiBlePref.getBytes("bleAddress", currentBleAddressOpn, 6);
nukiBlePref.getBytes("secretKeyK", secretKeyKOpn, 32);
nukiBlePref.getBytes("authorizationId", authorizationIdOpn, 4);
nukiBlePref.getBytes("securityPinCode", &storedPincodeOpn, 2);
nukiBlePref.end();
char text[255];
text[0] = '\0';
for(int i = 0 ; i < 6 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", currentBleAddressOpn[i]);
}
json["bleAddressOpener"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 32 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", secretKeyKOpn[i]);
}
json["secretKeyKOpener"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 4 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", authorizationIdOpn[i]);
}
json["authorizationIdOpener"] = text;
memset(text, 0, sizeof(text));
json["securityPinCodeOpener"] = storedPincodeOpn;
}
}
for(const auto& key : bytePrefs)
{
size_t storedLength = _preferences->getBytesLength(key);
if(storedLength == 0)
{
continue;
}
uint8_t serialized[storedLength];
memset(serialized, 0, sizeof(serialized));
size_t size = _preferences->getBytes(key, serialized, sizeof(serialized));
if(size == 0)
{
continue;
}
char text[255];
text[0] = '\0';
for(int i = 0 ; i < 6 ; i++)
for(int i = 0 ; i < size ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", currentBleAddress[i]);
sprintf(&(text[offset]), "%02x", serialized[i]);
}
json["bleAddressLock"] = text;
json[key] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 32 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", secretKeyK[i]);
}
json["secretKeyKLock"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 4 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", authorizationId[i]);
}
json["authorizationIdLock"] = text;
memset(text, 0, sizeof(text));
json["securityPinCodeLock"] = storedPincode;
}
if(_nukiOpener != nullptr)
{
unsigned char currentBleAddressOpn[6];
unsigned char authorizationIdOpn[4] = {0x00};
unsigned char secretKeyKOpn[32] = {0x00};
uint16_t storedPincodeOpn = 0000;
Preferences nukiBlePref;
nukiBlePref.begin("NukiHubopener", false);
nukiBlePref.getBytes("bleAddress", currentBleAddressOpn, 6);
nukiBlePref.getBytes("secretKeyK", secretKeyKOpn, 32);
nukiBlePref.getBytes("authorizationId", authorizationIdOpn, 4);
nukiBlePref.getBytes("securityPinCode", &storedPincodeOpn, 2);
nukiBlePref.end();
char text[255];
text[0] = '\0';
for(int i = 0 ; i < 6 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", currentBleAddressOpn[i]);
}
json["bleAddressOpener"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 32 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", secretKeyKOpn[i]);
}
json["secretKeyKOpener"] = text;
memset(text, 0, sizeof(text));
text[0] = '\0';
for(int i = 0 ; i < 4 ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", authorizationIdOpn[i]);
}
json["authorizationIdOpener"] = text;
memset(text, 0, sizeof(text));
json["securityPinCodeOpener"] = storedPincodeOpn;
}
}
for(const auto& key : bytePrefs)
{
size_t storedLength = _preferences->getBytesLength(key);
if(storedLength == 0)
{
continue;
}
uint8_t serialized[storedLength];
memset(serialized, 0, sizeof(serialized));
size_t size = _preferences->getBytes(key, serialized, sizeof(serialized));
if(size == 0)
{
continue;
}
char text[255];
text[0] = '\0';
for(int i = 0 ; i < size ; i++)
{
size_t offset = strlen(text);
sprintf(&(text[offset]), "%02x", serialized[i]);
}
json[key] = text;
memset(text, 0, sizeof(text));
}
serializeJsonPretty(json, jsonPretty);
char buf[26 + name.length()];
snprintf(buf, sizeof(buf), "attachment; filename=\"%s\"", name.c_str());
resp->addHeader("Content-Disposition", buf);
resp->setCode(200);
resp->setContentType("application/json");
resp->setContent(jsonPretty.c_str());
@@ -1580,9 +1699,32 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
}
else if(key == "MQTTCA")
{
if(_preferences->getString(preference_mqtt_ca, "") != value)
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
_preferences->putString(preference_mqtt_ca, value);
if(value != "")
{
File file = SPIFFS.open("/mqtt_ssl.ca", FILE_WRITE);
if (!file) {
Log->println("Failed to open /mqtt_ssl.ca for writing");
}
else
{
if (!file.print(value))
{
Log->println("Failed to write /mqtt_ssl.ca");
}
file.close();
}
}
else
{
if (!SPIFFS.remove("/mqtt_ssl.ca")) {
Serial.println("Failed to delete /mqtt_ssl.ca");
}
}
Log->print(F("Setting changed: "));
Log->println(key);
configChanged = true;
@@ -1590,9 +1732,32 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
}
else if(key == "MQTTCRT")
{
if(_preferences->getString(preference_mqtt_crt, "") != value)
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
_preferences->putString(preference_mqtt_crt, value);
if(value != "")
{
File file = SPIFFS.open("/mqtt_ssl.crt", FILE_WRITE);
if (!file) {
Log->println("Failed to open /mqtt_ssl.crt for writing");
}
else
{
if (!file.print(value))
{
Log->println("Failed to write /mqtt_ssl.crt");
}
file.close();
}
}
else
{
if (!SPIFFS.remove("/mqtt_ssl.crt")) {
Serial.println("Failed to delete /mqtt_ssl.crt");
}
}
Log->print(F("Setting changed: "));
Log->println(key);
configChanged = true;
@@ -1600,9 +1765,32 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
}
else if(key == "MQTTKEY")
{
if(_preferences->getString(preference_mqtt_key, "") != value)
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
_preferences->putString(preference_mqtt_key, value);
if(value != "")
{
File file = SPIFFS.open("/mqtt_ssl.key", FILE_WRITE);
if (!file) {
Log->println("Failed to open /mqtt_ssl.key for writing");
}
else
{
if (!file.print(value))
{
Log->println("Failed to write /mqtt_ssl.key");
}
file.close();
}
}
else
{
if (!SPIFFS.remove("/mqtt_ssl.key")) {
Serial.println("Failed to delete /mqtt_ssl.key");
}
}
Log->print(F("Setting changed: "));
Log->println(key);
configChanged = true;
@@ -1959,6 +2147,16 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
configChanged = true;
}
}
else if(key == "MQTTSENA")
{
if(_preferences->getBool(preference_mqtt_ssl_enabled, false) != (value == "1"))
{
_preferences->putBool(preference_mqtt_ssl_enabled, (value == "1"));
Log->print(F("Setting changed: "));
Log->println(key);
configChanged = true;
}
}
else if(key == "WEBLOG")
{
if(_preferences->getBool(preference_webserial_enabled, false) != (value == "1"))
@@ -3541,6 +3739,13 @@ esp_err_t WebCfgServer::buildImportExportHtml(PsychicRequest *request, PsychicRe
response.print("<button title=\"Basic export\" onclick=\" window.open('/get?page=export', '_self'); return false;\">Basic export</button>");
response.print("<br><br><button title=\"Export with redacted settings\" onclick=\" window.open('/get?page=export&redacted=1'); return false;\">Export with redacted settings</button>");
response.print("<br><br><button title=\"Export with redacted settings and pairing data\" onclick=\" window.open('/get?page=export&redacted=1&pairing=1'); return false;\">Export with redacted settings and pairing data</button>");
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
if(esp_psram_get_size() > 0)
{
response.print("<br><br><button title=\"Export HTTP SSL certificate and key\" onclick=\" window.open('/get?page=export&type=https'); return false;\">Export HTTP SSL certificate and key</button>");
}
#endif
response.print("<br><br><button title=\"Export MQTT SSL CA, client certificate and client key\" onclick=\" window.open('/get?page=export&type=mqtts'); return false;\">Export MQTT SSL CA, client certificate and client key</button>");
response.print("</div></body></html>");
return response.endSend();
}
@@ -3783,7 +3988,7 @@ esp_err_t WebCfgServer::buildNetworkConfigHtml(PsychicRequest *request, PsychicR
if(esp_psram_get_size() > 0)
{
response.print("<tr><td>Set HTTP SSL Certificate</td><td><button title=\"Set HTTP SSL Certificate\" onclick=\" window.open('/get?page=httpcrtconfig', '_self'); return false;\">Change</button></td></tr>");
response.print("<tr><td>Set HTTP SSL Key</td><td><button title=\"Set MQTT SSL Key\" onclick=\" window.open('/get?page=httpkeyconfig', '_self'); return false;\">Change</button></td></tr>");
response.print("<tr><td>Set HTTP SSL Key</td><td><button title=\"Set HTTP SSL Key\" onclick=\" window.open('/get?page=httpkeyconfig', '_self'); return false;\">Change</button></td></tr>");
}
#endif
response.print("</table>");
@@ -3826,6 +4031,7 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request, PsychicResp
{
printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), "");
}
printCheckBox(&response, "MQTTSENA", "Enable MQTT SSL", _preferences->getBool(preference_mqtt_ssl_enabled, false), "");
response.print("<tr><td>Set MQTT SSL CA Certificate</td><td><button title=\"Set MQTT SSL CA Certificate\" onclick=\" window.open('/get?page=mqttcaconfig', '_self'); return false;\">Change</button></td></tr>");
response.print("<tr><td>Set MQTT SSL Client Certificate</td><td><button title=\"Set MQTT Client Certificate\" onclick=\" window.open('/get?page=mqttcrtconfig', '_self'); return false;\">Change</button></td></tr>");
response.print("<tr><td>Set MQTT SSL Client Key</td><td><button title=\"Set MQTT SSL Client Key\" onclick=\" window.open('/get?page=mqttkeyconfig', '_self'); return false;\">Change</button></td></tr>");
@@ -3860,15 +4066,102 @@ esp_err_t WebCfgServer::buildMqttSSLConfigHtml(PsychicRequest *request, PsychicR
if (type == 0)
{
printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, true, true);
bool found = false;
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.ca");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.ca not found");
}
else
{
Log->println("Reading mqtt_ssl.ca");
size_t filesize = file.size();
char ca[filesize + 1];
file.read((uint8_t *)ca, sizeof(ca));
file.close();
ca[filesize] = '\0';
printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", ca, 2200, true, true);
found = true;
}
}
if (!found)
{
printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", "", 2200, true, true);
}
}
else if (type == 1)
{
printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, true, true);
bool found = false;
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.crt");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.crt not found");
}
else
{
Log->println("Reading mqtt_ssl.crt");
size_t filesize = file.size();
char cert[filesize + 1];
file.read((uint8_t *)cert, sizeof(cert));
file.close();
cert[filesize] = '\0';
printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", cert, 2200, true, true);
found = true;
}
}
if (!found)
{
printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", "", 2200, true, true);
}
}
else
{
printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, true, true);
bool found = false;
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.key");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.key not found");
}
else
{
Log->println("Reading mqtt_ssl.key");
size_t filesize = file.size();
char key[filesize + 1];
file.read((uint8_t *)key, sizeof(key));
file.close();
key[filesize] = '\0';
printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", key, 2200, true, true);
found = true;
}
}
if (!found)
{
printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", "", 2200, true, true);
}
}
response.print("</table>");
response.print("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
@@ -3891,8 +4184,8 @@ esp_err_t WebCfgServer::buildHttpSSLConfigHtml(PsychicRequest *request, PsychicR
if (type == 1)
{
char cert[4400] = {0};
bool found = false;
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
@@ -3906,21 +4199,27 @@ esp_err_t WebCfgServer::buildHttpSSLConfigHtml(PsychicRequest *request, PsychicR
else
{
Log->println("Reading http_ssl.crt");
uint32_t i = 0;
while(file.available()){
cert[i] = file.read();
i++;
}
size_t filesize = file.size();
char cert[filesize + 1];
file.read((uint8_t *)cert, sizeof(cert));
file.close();
cert[filesize] = '\0';
printTextarea(&response, "HTTPCRT", "HTTP SSL Certificate (*, optional)", cert, 4400, true, true);
found = true;
}
}
#endif
printTextarea(&response, "HTTPCRT", "HTTP SSL Certificate (*, optional)", cert, 4400, true, true);
if (!found)
{
printTextarea(&response, "HTTPCRT", "HTTP SSL Certificate (*, optional)", "", 4400, true, true);
}
}
else
{
char key[2200] = {0};
bool found = false;
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
@@ -3934,16 +4233,22 @@ esp_err_t WebCfgServer::buildHttpSSLConfigHtml(PsychicRequest *request, PsychicR
else
{
Log->println("Reading http_ssl.key");
uint32_t i = 0;
while(file.available()){
key[i] = file.read();
i++;
}
size_t filesize = file.size();
char key[filesize + 1];
file.read((uint8_t *)key, sizeof(key));
file.close();
key[filesize] = '\0';
printTextarea(&response, "HTTPKEY", "HTTP SSL Key (*, optional)", key, 2200, true, true);
found = true;
}
}
#endif
printTextarea(&response, "HTTPKEY", "HTTP SSL Key (*, optional)", key, 2200, true, true);
if (!found)
{
printTextarea(&response, "HTTPKEY", "HTTP SSL Key (*, optional)", "", 2200, true, true);
}
}
response.print("</table>");
response.print("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
@@ -4528,10 +4833,29 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse*
response.print(_preferences->getString(preference_cred_password, "").length() > 0 ? "***" : "Not set");
response.print("\nWeb configurator enabled: ");
response.print(_preferences->getBool(preference_webserver_enabled, true) ? "Yes" : "No");
//response.print("\nHTTP SSL CRT: ");
//response.print(_preferences->getString(preference_http_crt, "").length() > 0 ? "***" : "Not set");
//response.print("\nHTTP SSL Key: ");
//response.print(_preferences->getString(preference_http_key, "").length() > 0 ? "***" : "Not set");
response.print("\nHTTP SSL: ");
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
if(esp_psram_get_size() > 0)
{
if (!SPIFFS.begin(true)) {
response.print("Disabled");
}
else
{
File file = SPIFFS.open("/http_ssl.crt");
File file2 = SPIFFS.open("/http_ssl.key");
response.print((!file || file.isDirectory() || !file2 || file2.isDirectory()) ? "Disabled" : "Enabled");
file.close();
file2.close();
}
}
else
{
response.print("Disabled");
}
#else
response.print("Disabled");
#endif
response.print("\nPublish debug information enabled: ");
response.print(_preferences->getBool(preference_publish_debug_info, false) ? "Yes" : "No");
response.print("\nMQTT log enabled: ");
@@ -4628,12 +4952,38 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse*
response.print(_preferences->getString(preference_mqtt_password, "").length() > 0 ? "***" : "Not set");
response.print("\nMQTT base topic: ");
response.print(_preferences->getString(preference_mqtt_lock_path, ""));
response.print("\nMQTT SSL CA: ");
response.print(_preferences->getString(preference_mqtt_ca, "").length() > 0 ? "***" : "Not set");
response.print("\nMQTT SSL CRT: ");
response.print(_preferences->getString(preference_mqtt_crt, "").length() > 0 ? "***" : "Not set");
response.print("\nMQTT SSL Key: ");
response.print(_preferences->getString(preference_mqtt_key, "").length() > 0 ? "***" : "Not set");
response.print("\nMQTT SSL: ");
if(_preferences->getBool(preference_mqtt_ssl_enabled, false))
{
if (!SPIFFS.begin(true)) {
response.print("Disabled");
}
else
{
File file = SPIFFS.open("/mqtt_ssl.ca");
if (!file || file.isDirectory()) {
response.print("Disabled");
}
else
{
response.print("Enabled");
response.print("\nMQTT SSL CA: ***");
File file2 = SPIFFS.open("/mqtt_ssl.crt");
File file3 = SPIFFS.open("/mqtt_ssl.key");
response.print("\nMQTT SSL CRT: ");
response.print((!file2 || file2.isDirectory()) ? "Not set" : "***");
response.print("\nMQTT SSL Key: ");
response.print((!file3 || file3.isDirectory()) ? "Not set" : "***");
file2.close();
file3.close();
}
file.close();
}
}
else
{
response.print("Disabled");
}
response.print("\n\n------------ BLUETOOTH ------------");
response.print("\nBluetooth TX power (dB): ");
response.print(_preferences->getInt(preference_ble_tx_power, 9));

View File

@@ -249,6 +249,19 @@ void networkTask(void *pvParameters)
#ifndef NUKI_HUB_UPDATER
void nukiTask(void *pvParameters)
{
if (preferences->getBool(preference_mqtt_ssl_enabled, false))
{
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
if (esp_psram_get_size() <= 0)
{
Log->println("Waiting 20 seconds to start BLE because of MQTT SSL");
delay(20000);
}
#else
Log->println("Waiting 20 seconds to start BLE because of MQTT SSL");
delay(20000);
#endif
}
int64_t nukiLoopTs = 0;
bool whiteListed = false;
while(true)
@@ -572,15 +585,13 @@ void setup()
}
else
{
char cert[4400] = {0};
Log->println("Reading http_ssl.crt");
uint32_t i = 0;
while(file.available()){
cert[i] = file.read();
i++;
}
size_t filesize = file.size();
char cert[filesize + 1];
file.read((uint8_t *)cert, sizeof(cert));
file.close();
cert[filesize] = '\0';
File file2 = SPIFFS.open("/http_ssl.key");
if (!file2 || file2.isDirectory()) {
@@ -589,15 +600,13 @@ void setup()
}
else
{
char key[2200] = {0};
Log->println("Reading http_ssl.key");
i = 0;
while(file2.available()){
key[i] = file2.read();
i++;
}
size_t filesize2 = file2.size();
char key[filesize2 + 1];
file2.read((uint8_t *)key, sizeof(key));
file2.close();
key[filesize2] = '\0';
psychicSSLServer = new PsychicHttpsServer;
psychicSSLServer->ssl_config.httpd.max_open_sockets = 8;
@@ -738,15 +747,13 @@ void setup()
}
else
{
char cert[4400] = {0};
Log->println("Reading http_ssl.crt");
uint32_t i = 0;
while(file.available()){
cert[i] = file.read();
i++;
}
size_t filesize = file.size();
char cert[filesize + 1];
file.read((uint8_t *)cert, sizeof(cert));
file.close();
cert[filesize] = '\0';
File file2 = SPIFFS.open("/http_ssl.key");
if (!file2 || file2.isDirectory()) {
@@ -755,15 +762,13 @@ void setup()
}
else
{
char key[2200] = {0};
Log->println("Reading http_ssl.key");
i = 0;
while(file2.available()){
key[i] = file2.read();
i++;
}
size_t filesize2 = file2.size();
char key[filesize2 + 1];
file2.read((uint8_t *)key, sizeof(key));
file2.close();
key[filesize2] = '\0';
psychicSSLServer = new PsychicHttpsServer;
psychicSSLServer->ssl_config.httpd.max_open_sockets = 8;

View File

@@ -3,30 +3,71 @@
#include "../Logger.h"
#ifndef NUKI_HUB_UPDATER
#include "FS.h"
#include "SPIFFS.h"
#include "../MqttTopics.h"
#include "PreferencesKeys.h"
void NetworkDevice::init()
{
size_t caLength = _preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
size_t crtLength = _preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE);
size_t keyLength = _preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE);
_useEncryption = caLength > 1; // length is 1 when empty
if(_useEncryption)
{
Log->println(F("MQTT over TLS."));
_mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
_mqttClientSecure->setCACert(_ca);
if(crtLength > 1 && keyLength > 1) // length is 1 when empty
if(_preferences->getBool(preference_mqtt_ssl_enabled, false)) {
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
}
else
{
Log->println(F("MQTT with client certificate."));
_mqttClientSecure->setCertificate(_cert);
_mqttClientSecure->setPrivateKey(_key);
File file = SPIFFS.open("/mqtt_ssl.ca");
if (!file || file.isDirectory()) {
Log->println("mqtt_ssl.ca not found");
}
else
{
Log->println("Reading mqtt_ssl.ca");
String ca_cert = file.readString();
file.close();
char* caDest;
caDest = (char *)malloc(sizeof(char) * (ca_cert.length()+1));
strcpy(caDest, ca_cert.c_str());
if(ca_cert.length() > 1)
{
_useEncryption = true;
Log->println(F("MQTT over TLS."));
_mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
_mqttClientSecure->setCACert(caDest);
File file2 = SPIFFS.open("/mqtt_ssl.crt");
File file3 = SPIFFS.open("/mqtt_ssl.key");
if (!file2 || file2.isDirectory() || !file3 || file3.isDirectory()) {
Log->println("mqtt_ssl.crt or mqtt_ssl.key not found");
}
else
{
String cert = file2.readString();
file2.close();
char* certDest;
certDest = (char *)malloc(sizeof(char) * (cert.length()+1));
strcpy(certDest, cert.c_str());
String key = file3.readString();
file3.close();
char* keyDest;
keyDest = (char *)malloc(sizeof(char) * (key.length()+1));
strcpy(keyDest, key.c_str());
if(cert.length() > 1 && key.length() > 1)
{
Log->println(F("MQTT with client certificate."));
_mqttClientSecure->setCertificate(certDest);
_mqttClientSecure->setPrivateKey(keyDest);
}
}
}
}
}
}
else
if (!_useEncryption)
{
Log->println(F("MQTT without TLS."));
_mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);

View File

@@ -64,9 +64,6 @@ protected:
bool _useEncryption = false;
bool _mqttEnabled = true;
char* _path;
char _ca[TLS_CA_MAX_SIZE] = {0};
char _cert[TLS_CERT_MAX_SIZE] = {0};
char _key[TLS_KEY_MAX_SIZE] = {0};
#endif
const String _hostname;