Hosted update
This commit is contained in:
@@ -410,7 +410,7 @@ Note that the following options can break Nuki Hub and cause bootloops that will
|
|||||||
- Char buffer size (min 4096, max 65536): Set the character buffer size, needs to be enlarged to support large amounts of auth/keypad/timecontrol/authorization entries. Default 4096.
|
- Char buffer size (min 4096, max 65536): Set the character buffer size, needs to be enlarged to support large amounts of auth/keypad/timecontrol/authorization entries. Default 4096.
|
||||||
- Task size Network (min 12288, max 65536): Set the Network task stack size, needs to be enlarged to support large amounts of auth/keypad/timecontrol/authorization entries. Default 12288.
|
- Task size Network (min 12288, max 65536): Set the Network task stack size, needs to be enlarged to support large amounts of auth/keypad/timecontrol/authorization entries. Default 12288.
|
||||||
- Task size Nuki (min 8192, max 65536): Set the Nuki task stack size. Default 8192.
|
- Task size Nuki (min 8192, max 65536): Set the Nuki task stack size. Default 8192.
|
||||||
- BLE General timeout in ms (min 3000, max 65536): General timeout for communication with Nuki devices, default 3000ms. Mainly used when retrieving Nuki keypad authorizations
|
- BLE General timeout in ms (min 3000, max 65536): General timeout for communication with Nuki devices, default 10000ms. Mainly used when retrieving Nuki keypad authorizations
|
||||||
- BLE Command timeout in ms (min 3000, max 65536): Command timeout for communication with Nuki devices, default 3000ms.
|
- BLE Command timeout in ms (min 3000, max 65536): Command timeout for communication with Nuki devices, default 3000ms.
|
||||||
- Max auth log entries (min 1, max 100): The maximum amount of log entries that will be requested from the lock/opener, default 5.
|
- Max auth log entries (min 1, max 100): The maximum amount of log entries that will be requested from the lock/opener, default 5.
|
||||||
- Max keypad entries (min 1, max 200): The maximum amount of keypad codes that will be requested from the lock/opener, default 10.
|
- Max keypad entries (min 1, max 200): The maximum amount of keypad codes that will be requested from the lock/opener, default 10.
|
||||||
|
|||||||
29
apply_patches.py
Normal file
29
apply_patches.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from os.path import join, isfile
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
FRAMEWORK_DIR = env.PioPlatform().get_package_dir("framework-arduinoespressif32")
|
||||||
|
patchflag_path = join(FRAMEWORK_DIR, ".hosted-patching-done")
|
||||||
|
|
||||||
|
# patch file only if we didn't do it before
|
||||||
|
if not isfile(join(FRAMEWORK_DIR, ".hosted-patching-done")):
|
||||||
|
original_file = join(FRAMEWORK_DIR, "cores", "esp32", "esp32-hal-hosted.c")
|
||||||
|
patched_file = join("resources", "esp32-hal-hosted.c.patch")
|
||||||
|
|
||||||
|
assert isfile(original_file) and isfile(patched_file)
|
||||||
|
|
||||||
|
env.Execute("patch %s %s" % (original_file, patched_file))
|
||||||
|
# env.Execute("touch " + patchflag_path)
|
||||||
|
|
||||||
|
original_file = join(FRAMEWORK_DIR, "cores", "esp32", "esp32-hal-hosted.h")
|
||||||
|
patched_file = join("resources", "esp32-hal-hosted.h.patch")
|
||||||
|
|
||||||
|
assert isfile(original_file) and isfile(patched_file)
|
||||||
|
|
||||||
|
env.Execute("patch %s %s" % (original_file, patched_file))
|
||||||
|
|
||||||
|
def _touch(path):
|
||||||
|
with open(path, "w") as fp:
|
||||||
|
fp.write("")
|
||||||
|
|
||||||
|
env.Execute(lambda *args, **kwargs: _touch(patchflag_path))
|
||||||
Submodule lib/nuki_ble updated: b04185e0f2...b70c93e120
@@ -13,7 +13,7 @@ default_envs = esp32
|
|||||||
boards_dir = boards
|
boards_dir = boards
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.33/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.34/platform-espressif32.zip
|
||||||
platform_packages =
|
platform_packages =
|
||||||
framework = arduino, espidf
|
framework = arduino, espidf
|
||||||
build_type = release
|
build_type = release
|
||||||
@@ -188,6 +188,10 @@ build_flags =
|
|||||||
extends = env:esp32
|
extends = env:esp32
|
||||||
board_build.embed_txtfiles =
|
board_build.embed_txtfiles =
|
||||||
board = esp32-p4
|
board = esp32-p4
|
||||||
|
extra_scripts =
|
||||||
|
pre:pio_package_pre.py
|
||||||
|
#pre:apply_patches.py
|
||||||
|
post:pio_package_post.py
|
||||||
board_build.cmake_extra_args =
|
board_build.cmake_extra_args =
|
||||||
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.ramoptimize.defaults;sdkconfig.defaults.esp32-p4"
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release.defaults;sdkconfig.ramoptimize.defaults;sdkconfig.defaults.esp32-p4"
|
||||||
custom_component_remove =
|
custom_component_remove =
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
#define NUKI_HUB_VERSION "9.14"
|
#define NUKI_HUB_VERSION "9.14"
|
||||||
#define NUKI_HUB_VERSION_INT (uint32_t)914
|
#define NUKI_HUB_VERSION_INT (uint32_t)914
|
||||||
#define NUKI_HUB_BUILD "unknownbuildnr"
|
#define NUKI_HUB_BUILD "unknownbuildnr"
|
||||||
#define NUKI_HUB_DATE "2025-10-17"
|
#define NUKI_HUB_DATE "2025-11-23"
|
||||||
#define NUKI_HUB_DATE "2025-10-17"
|
#define NUKI_HUB_DATE "2025-11-23"
|
||||||
|
|
||||||
#define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest"
|
#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"
|
#define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json"
|
||||||
@@ -249,3 +249,7 @@
|
|||||||
|
|
||||||
#define NETWORK_TASK_SIZE 12288
|
#define NETWORK_TASK_SIZE 12288
|
||||||
#define HTTPD_TASK_SIZE 8192
|
#define HTTPD_TASK_SIZE 8192
|
||||||
|
|
||||||
|
#ifndef CHUNK_SIZE
|
||||||
|
#define CHUNK_SIZE 1400
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ void NukiOpenerWrapper::initialize()
|
|||||||
_nukiOpener.setEventHandler(this);
|
_nukiOpener.setEventHandler(this);
|
||||||
_nukiOpener.setConnectTimeout(2);
|
_nukiOpener.setConnectTimeout(2);
|
||||||
_nukiOpener.setDisconnectTimeout(2000);
|
_nukiOpener.setDisconnectTimeout(2000);
|
||||||
_nukiOpener.setGeneralTimeout(_preferences->getInt(preference_ble_general_timeout, 3000));
|
_nukiOpener.setGeneralTimeout(_preferences->getInt(preference_ble_general_timeout, 10000));
|
||||||
_nukiOpener.setCommandTimeout(_preferences->getInt(preference_ble_command_timeout, 3000));
|
_nukiOpener.setCommandTimeout(_preferences->getInt(preference_ble_command_timeout, 3000));
|
||||||
|
|
||||||
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
|
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ void NukiWrapper::initialize()
|
|||||||
_nukiLock.setEventHandler(this);
|
_nukiLock.setEventHandler(this);
|
||||||
_nukiLock.setConnectTimeout(2);
|
_nukiLock.setConnectTimeout(2);
|
||||||
_nukiLock.setDisconnectTimeout(2000);
|
_nukiLock.setDisconnectTimeout(2000);
|
||||||
_nukiLock.setGeneralTimeout(_preferences->getInt(preference_ble_general_timeout, 3000));
|
_nukiLock.setGeneralTimeout(_preferences->getInt(preference_ble_general_timeout, 10000));
|
||||||
_nukiLock.setCommandTimeout(_preferences->getInt(preference_ble_command_timeout, 3000));
|
_nukiLock.setCommandTimeout(_preferences->getInt(preference_ble_command_timeout, 3000));
|
||||||
|
|
||||||
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
|
_hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#define preference_ota_main_url (char*)"otaMainUrl"
|
#define preference_ota_main_url (char*)"otaMainUrl"
|
||||||
#define preference_ota_updater_url (char*)"otaUpdUrl"
|
#define preference_ota_updater_url (char*)"otaUpdUrl"
|
||||||
#define preference_buffer_size (char*)"buffsize"
|
#define preference_buffer_size (char*)"buffsize"
|
||||||
|
#define preference_force_hosted_update (char*)"frcHstdUpd"
|
||||||
|
|
||||||
// CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT
|
// CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT
|
||||||
#define preference_find_best_rssi (char*)"nwbestrssi"
|
#define preference_find_best_rssi (char*)"nwbestrssi"
|
||||||
@@ -262,12 +263,13 @@ inline void initPreferences(Preferences* preferences)
|
|||||||
preferences->putBool(preference_cred_bypass_boot_btn_enabled, false);
|
preferences->putBool(preference_cred_bypass_boot_btn_enabled, false);
|
||||||
preferences->putBool(preference_publish_config, false);
|
preferences->putBool(preference_publish_config, false);
|
||||||
preferences->putBool(preference_config_from_mqtt, false);
|
preferences->putBool(preference_config_from_mqtt, false);
|
||||||
|
preferences->putBool(preference_force_hosted_update, false);
|
||||||
|
|
||||||
preferences->putInt(preference_mqtt_broker_port, 1883);
|
preferences->putInt(preference_mqtt_broker_port, 1883);
|
||||||
preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
|
preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
|
||||||
preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
|
preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
|
||||||
preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
|
preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
|
||||||
preferences->putInt(preference_ble_general_timeout, 3000);
|
preferences->putInt(preference_ble_general_timeout, 10000);
|
||||||
preferences->putInt(preference_ble_command_timeout, 3000);
|
preferences->putInt(preference_ble_command_timeout, 3000);
|
||||||
preferences->putInt(preference_authlog_max_entries, MAX_AUTHLOG);
|
preferences->putInt(preference_authlog_max_entries, MAX_AUTHLOG);
|
||||||
preferences->putInt(preference_keypad_max_entries, MAX_KEYPAD);
|
preferences->putInt(preference_keypad_max_entries, MAX_KEYPAD);
|
||||||
@@ -561,7 +563,7 @@ private:
|
|||||||
preference_cred_session_lifetime, preference_cred_session_lifetime_remember, preference_cred_session_lifetime_duo, preference_cred_session_lifetime_duo_remember,
|
preference_cred_session_lifetime, preference_cred_session_lifetime_remember, preference_cred_session_lifetime_duo, preference_cred_session_lifetime_duo_remember,
|
||||||
preference_cred_duo_approval, preference_cred_bypass_boot_btn_enabled, preference_cred_bypass_gpio_high, preference_cred_bypass_gpio_low, preference_publish_config,
|
preference_cred_duo_approval, preference_cred_bypass_boot_btn_enabled, preference_cred_bypass_gpio_high, preference_cred_bypass_gpio_low, preference_publish_config,
|
||||||
preference_config_from_mqtt, preference_totp_secret, preference_cred_session_lifetime_totp, preference_cred_session_lifetime_totp_remember, preference_bypass_secret,
|
preference_config_from_mqtt, preference_totp_secret, preference_cred_session_lifetime_totp, preference_cred_session_lifetime_totp_remember, preference_bypass_secret,
|
||||||
preference_admin_secret, preference_ble_general_timeout, preference_ble_command_timeout
|
preference_admin_secret, preference_ble_general_timeout, preference_ble_command_timeout, preference_force_hosted_update
|
||||||
};
|
};
|
||||||
std::vector<char*> _redact =
|
std::vector<char*> _redact =
|
||||||
{
|
{
|
||||||
@@ -582,7 +584,7 @@ private:
|
|||||||
preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command,
|
preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command,
|
||||||
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_mqtt_ssl_enabled,
|
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_mqtt_ssl_enabled,
|
||||||
preference_hybrid_reboot_on_disconnect, preference_lock_gemini_enabled, preference_enable_debug_mode, preference_cred_duo_enabled, preference_cred_duo_approval,
|
preference_hybrid_reboot_on_disconnect, preference_lock_gemini_enabled, preference_enable_debug_mode, preference_cred_duo_enabled, preference_cred_duo_approval,
|
||||||
preference_publish_config, preference_config_from_mqtt
|
preference_publish_config, preference_config_from_mqtt, preference_force_hosted_update
|
||||||
};
|
};
|
||||||
std::vector<char*> _bytePrefs =
|
std::vector<char*> _bytePrefs =
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,20 @@ extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_
|
|||||||
extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end");
|
extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end");
|
||||||
extern bool timeSynced;
|
extern bool timeSynced;
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
#include "esp_hosted.h"
|
||||||
|
static esp_hosted_coprocessor_fwver_t slave_version_struct = {
|
||||||
|
.major1 = 0,
|
||||||
|
.minor1 = 0,
|
||||||
|
.patch1 = 0
|
||||||
|
};
|
||||||
|
static esp_hosted_coprocessor_fwver_t host_version_struct = {
|
||||||
|
.major1 = ESP_HOSTED_VERSION_MAJOR_1,
|
||||||
|
.minor1 = ESP_HOSTED_VERSION_MINOR_1,
|
||||||
|
.patch1 = ESP_HOSTED_VERSION_PATCH_1
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NUKI_HUB_UPDATER
|
#ifndef NUKI_HUB_UPDATER
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include <NetworkClientSecure.h>
|
#include <NetworkClientSecure.h>
|
||||||
@@ -3573,6 +3587,16 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
|
|||||||
restartServicesNoReconnect = true;
|
restartServicesNoReconnect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(key == "FRCHSTUPD")
|
||||||
|
{
|
||||||
|
if(_preferences->getBool(preference_force_hosted_update, false) != (value == "1"))
|
||||||
|
{
|
||||||
|
_preferences->putBool(preference_force_hosted_update, (value == "1"));
|
||||||
|
Log->print("Setting changed: ");
|
||||||
|
Log->println(key);
|
||||||
|
configChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(key == "CHECKUPDATE")
|
else if(key == "CHECKUPDATE")
|
||||||
{
|
{
|
||||||
if(_preferences->getBool(preference_check_updates, false) != (value == "1"))
|
if(_preferences->getBool(preference_check_updates, false) != (value == "1"))
|
||||||
@@ -3817,7 +3841,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
|
|||||||
{
|
{
|
||||||
if(value.toInt() > 2999 && value.toInt() < 65537)
|
if(value.toInt() > 2999 && value.toInt() < 65537)
|
||||||
{
|
{
|
||||||
if(_preferences->getInt(preference_ble_general_timeout, 3000) != value.toInt())
|
if(_preferences->getInt(preference_ble_general_timeout, 10000) != value.toInt())
|
||||||
{
|
{
|
||||||
_preferences->putInt(preference_ble_general_timeout, value.toInt());
|
_preferences->putInt(preference_ble_general_timeout, value.toInt());
|
||||||
Log->print("Setting changed: ");
|
Log->print("Setting changed: ");
|
||||||
@@ -5749,14 +5773,15 @@ esp_err_t WebCfgServer::buildAdvancedConfigHtml(PsychicRequest *request, Psychic
|
|||||||
response.print(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled");
|
response.print(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled");
|
||||||
response.print("</td></tr>");
|
response.print("</td></tr>");
|
||||||
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, "WEBLOG", "Enable WebSerial logging", _preferences->getBool(preference_force_hosted_update, false), "");
|
||||||
|
printCheckBox(&response, "FRCHSTUPD", "Force slave Hosted update on next boot", _preferences->getBool(preference_webserial_enabled), "");
|
||||||
printCheckBox(&response, "BTLPRST", "Enable Bootloop prevention (Try to reset these settings to default on bootloop)", true, "");
|
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 65536)", _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE), 6, "");
|
printInputField(&response, "BUFFSIZE", "Char buffer size (min 4096, max 65536)", _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE), 6, "");
|
||||||
response.print("<tr><td>Advised minimum char buffer size based on current settings</td><td id=\"mincharbuffer\"></td>");
|
response.print("<tr><td>Advised minimum char buffer size based on current settings</td><td id=\"mincharbuffer\"></td>");
|
||||||
printInputField(&response, "TSKNTWK", "Task size Network (min 12288, max 65536)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6, "");
|
printInputField(&response, "TSKNTWK", "Task size Network (min 12288, max 65536)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6, "");
|
||||||
response.print("<tr><td>Advised minimum network task size based on current settings</td><td id=\"minnetworktask\"></td>");
|
response.print("<tr><td>Advised minimum network task size based on current settings</td><td id=\"minnetworktask\"></td>");
|
||||||
printInputField(&response, "TSKNUKI", "Task size Nuki (min 8192, max 65536)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6, "");
|
printInputField(&response, "TSKNUKI", "Task size Nuki (min 8192, max 65536)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6, "");
|
||||||
printInputField(&response, "BLEGENTIMEOUT", "BLE General timeout in ms (min 3000, max 65536)", _preferences->getInt(preference_ble_general_timeout, 3000), 6, "");
|
printInputField(&response, "BLEGENTIMEOUT", "BLE General timeout in ms (min 10000, max 65536)", _preferences->getInt(preference_ble_general_timeout, 10000), 6, "");
|
||||||
printInputField(&response, "BLECMDTIMEOUT", "BLE Command timeout in ms (min 3000, max 65536)", _preferences->getInt(preference_ble_command_timeout, 3000), 6, "");
|
printInputField(&response, "BLECMDTIMEOUT", "BLE Command timeout in ms (min 3000, max 65536)", _preferences->getInt(preference_ble_command_timeout, 3000), 6, "");
|
||||||
printInputField(&response, "ALMAX", "Max auth log entries (min 1, max 100)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3, "id=\"inputmaxauthlog\"");
|
printInputField(&response, "ALMAX", "Max auth log entries (min 1, max 100)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3, "id=\"inputmaxauthlog\"");
|
||||||
printInputField(&response, "KPMAX", "Max keypad entries (min 1, max 200)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3, "id=\"inputmaxkeypad\"");
|
printInputField(&response, "KPMAX", "Max keypad entries (min 1, max 200)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3, "id=\"inputmaxkeypad\"");
|
||||||
@@ -6263,6 +6288,11 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse*
|
|||||||
response.print(_preferences->getString(preference_updater_build, ""));
|
response.print(_preferences->getString(preference_updater_build, ""));
|
||||||
response.print("\nUpdater build date: ");
|
response.print("\nUpdater build date: ");
|
||||||
response.print(_preferences->getString(preference_updater_date, ""));
|
response.print(_preferences->getString(preference_updater_date, ""));
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
response.printf("\nHost hosted firmware version: %u.%u.%u", host_version_struct.major1, host_version_struct.minor1, host_version_struct.patch1);
|
||||||
|
esp_hosted_get_coprocessor_fwversion(&slave_version_struct);
|
||||||
|
response.printf("\nSlave hosted firmware version: %u.%u.%u", slave_version_struct.major1, slave_version_struct.minor1, slave_version_struct.patch1);
|
||||||
|
#endif
|
||||||
response.print("\nUptime (min): ");
|
response.print("\nUptime (min): ");
|
||||||
response.print(espMillis() / 1000 / 60);
|
response.print(espMillis() / 1000 / 60);
|
||||||
response.print("\nConfig version: ");
|
response.print("\nConfig version: ");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ dependencies:
|
|||||||
espressif/libsodium: "^1.0.20~2"
|
espressif/libsodium: "^1.0.20~2"
|
||||||
|
|
||||||
espressif/esp_hosted:
|
espressif/esp_hosted:
|
||||||
version: "2.6.0"
|
version: "2.6.6"
|
||||||
rules:
|
rules:
|
||||||
- if: "target in [esp32p4]"
|
- if: "target in [esp32p4]"
|
||||||
|
|
||||||
|
|||||||
444
src/main.cpp
444
src/main.cpp
@@ -28,6 +28,12 @@ bool nuki_hub_https_server_enabled = false;
|
|||||||
#include "esp_psram.h"
|
#include "esp_psram.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
#include "esp_hosted.h"
|
||||||
|
#include "esp_hosted_ota.h"
|
||||||
|
#include "esp_hosted_api_types.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NUKI_HUB_UPDATER
|
#ifndef NUKI_HUB_UPDATER
|
||||||
#include "SerialReader.h"
|
#include "SerialReader.h"
|
||||||
#include "NukiWrapper.h"
|
#include "NukiWrapper.h"
|
||||||
@@ -114,8 +120,10 @@ bool lockStarted = false;
|
|||||||
bool openerStarted = false;
|
bool openerStarted = false;
|
||||||
bool bleScannerStarted = false;
|
bool bleScannerStarted = false;
|
||||||
bool webSerialEnabled = false;
|
bool webSerialEnabled = false;
|
||||||
|
bool forceHostedUpdate = false;
|
||||||
uint8_t partitionType = -1;
|
uint8_t partitionType = -1;
|
||||||
|
|
||||||
|
uint8_t http_err = 0;
|
||||||
int lastHTTPeventId = -1;
|
int lastHTTPeventId = -1;
|
||||||
bool doOta = false;
|
bool doOta = false;
|
||||||
bool restartReason_isValid;
|
bool restartReason_isValid;
|
||||||
@@ -124,6 +132,339 @@ RestartReason currentRestartReason = RestartReason::NotApplicable;
|
|||||||
TaskHandle_t otaTaskHandle = nullptr;
|
TaskHandle_t otaTaskHandle = nullptr;
|
||||||
TaskHandle_t networkTaskHandle = nullptr;
|
TaskHandle_t networkTaskHandle = nullptr;
|
||||||
|
|
||||||
|
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
||||||
|
{
|
||||||
|
if (lastHTTPeventId != int(evt->event_id))
|
||||||
|
{
|
||||||
|
Log->println("");
|
||||||
|
switch (evt->event_id)
|
||||||
|
{
|
||||||
|
case HTTP_EVENT_ERROR:
|
||||||
|
Log->println("HTTP_EVENT_ERROR");
|
||||||
|
http_err = 1;
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_CONNECTED:
|
||||||
|
Log->println("HTTP_EVENT_ON_CONNECTED");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_HEADER_SENT:
|
||||||
|
Log->println("HTTP_EVENT_HEADER_SENT");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_HEADER:
|
||||||
|
Log->printf("HTTPS_EVENT_ON_HEADER: %s=%s\n", evt->header_key, evt->header_value);
|
||||||
|
if (strcmp(evt->header_key, "Content-Length") == 0) {
|
||||||
|
Log->printf("Content-Length: %s bytes\n", evt->header_value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_DATA:
|
||||||
|
Log->println("HTTP_EVENT_ON_DATA");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_FINISH:
|
||||||
|
Log->println("HTTP_EVENT_ON_FINISH");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_DISCONNECTED:
|
||||||
|
Log->println("HTTP_EVENT_DISCONNECTED");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_REDIRECT:
|
||||||
|
Log->println("HTTP_EVENT_REDIRECT");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log->print(".");
|
||||||
|
}
|
||||||
|
lastHTTPeventId = int(evt->event_id);
|
||||||
|
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||||
|
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_feed(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
static esp_err_t parse_image_header_from_buffer(const uint8_t* buffer, size_t buffer_size, size_t* firmware_size, char* app_version_str, size_t version_str_len)
|
||||||
|
{
|
||||||
|
esp_image_header_t image_header;
|
||||||
|
esp_image_segment_header_t segment_header;
|
||||||
|
esp_app_desc_t app_desc;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t total_size = 0;
|
||||||
|
|
||||||
|
/* Check if buffer has enough data for image header */
|
||||||
|
if (buffer_size < sizeof(image_header)) {
|
||||||
|
Log->println("Buffer too small for image header verification");
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read image header from buffer */
|
||||||
|
memcpy(&image_header, buffer + offset, sizeof(image_header));
|
||||||
|
|
||||||
|
/* Validate magic number */
|
||||||
|
if (image_header.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||||
|
Log->printf("Invalid image magic: 0x%" PRIx8 "\n", image_header.magic);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log->printf("Image header: magic=0x%" PRIx8 ", segment_count=%" PRIu8 ", hash_appended=%" PRIu8 "\n", image_header.magic, image_header.segment_count, image_header.hash_appended);
|
||||||
|
|
||||||
|
/* Calculate total size by reading all segments */
|
||||||
|
offset = sizeof(image_header);
|
||||||
|
total_size = sizeof(image_header);
|
||||||
|
|
||||||
|
for (int i = 0; i < image_header.segment_count; i++) {
|
||||||
|
/* Check if buffer has enough data for segment header */
|
||||||
|
if (buffer_size < offset + sizeof(segment_header)) {
|
||||||
|
Log->println("Buffer too small to read all segment headers, using partial verification");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read segment header from buffer */
|
||||||
|
memcpy(&segment_header, buffer + offset, sizeof(segment_header));
|
||||||
|
|
||||||
|
Log->printf("Segment %d: data_len=%" PRIu32 ", load_addr=0x%" PRIx32 "\n", i, segment_header.data_len, segment_header.load_addr);
|
||||||
|
|
||||||
|
/* Add segment header size + data size */
|
||||||
|
total_size += sizeof(segment_header) + segment_header.data_len;
|
||||||
|
offset += sizeof(segment_header) + segment_header.data_len;
|
||||||
|
|
||||||
|
/* Read app description from the first segment */
|
||||||
|
if (i == 0) {
|
||||||
|
size_t app_desc_offset = sizeof(image_header) + sizeof(segment_header);
|
||||||
|
if (buffer_size >= app_desc_offset + sizeof(app_desc)) {
|
||||||
|
memcpy(&app_desc, buffer + app_desc_offset, sizeof(app_desc));
|
||||||
|
strncpy(app_version_str, app_desc.version, version_str_len - 1);
|
||||||
|
app_version_str[version_str_len - 1] = '\0';
|
||||||
|
Log->printf("Found app description: version='%s', project_name='%s'\n", app_desc.version, app_desc.project_name);
|
||||||
|
} else {
|
||||||
|
Log->println("Buffer too small to read app description");
|
||||||
|
strncpy(app_version_str, "unknown", version_str_len - 1);
|
||||||
|
app_version_str[version_str_len - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add padding to align to 16 bytes */
|
||||||
|
size_t padding = (16 - (total_size % 16)) % 16;
|
||||||
|
if (padding > 0) {
|
||||||
|
Log->printf("Adding %u bytes of padding for alignment\n", (unsigned int)padding);
|
||||||
|
total_size += padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the checksum byte (always present) */
|
||||||
|
total_size += 1;
|
||||||
|
Log->println("Added 1 byte for checksum");
|
||||||
|
|
||||||
|
/* Add SHA256 hash if appended */
|
||||||
|
bool has_hash = (image_header.hash_appended == 1);
|
||||||
|
if (has_hash) {
|
||||||
|
total_size += 32; // SHA256 hash is 32 bytes
|
||||||
|
Log->println("Added 32 bytes for SHA256 hash (hash_appended=1)");
|
||||||
|
} else {
|
||||||
|
Log->println("No SHA256 hash appended (hash_appended=0)");
|
||||||
|
}
|
||||||
|
|
||||||
|
*firmware_size = total_size;
|
||||||
|
Log->printf("Total image size: %u bytes\n", (unsigned int)*firmware_size);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ota_https_perform(const char* image_url)
|
||||||
|
{
|
||||||
|
uint8_t *ota_chunk = NULL;
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
int data_read = 0;
|
||||||
|
int ota_failed = 0;
|
||||||
|
|
||||||
|
if ((image_url == NULL) || (image_url[0] == '\0')) {
|
||||||
|
Log->println("Invalid image URL");
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate HTTPS URL
|
||||||
|
if (strncmp(image_url, "https://", 8) != 0) {
|
||||||
|
Log->println("URL must use HTTPS protocol");
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log->printf("Starting HTTPS OTA from URL: %s\n", image_url);
|
||||||
|
|
||||||
|
esp_http_client_config_t config = {
|
||||||
|
.url = image_url,
|
||||||
|
.timeout_ms = 30000,
|
||||||
|
.event_handler = _http_event_handler,
|
||||||
|
.transport_type = HTTP_TRANSPORT_OVER_SSL, // Force HTTPS
|
||||||
|
.buffer_size = 8192, // Larger buffer for SSL
|
||||||
|
.buffer_size_tx = 4096, // Increased TX buffer
|
||||||
|
.skip_cert_common_name_check = false, // Always validate CN in production
|
||||||
|
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||||
|
.keep_alive_enable = true,
|
||||||
|
.keep_alive_idle = 5,
|
||||||
|
.keep_alive_interval = 5,
|
||||||
|
.keep_alive_count = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||||
|
if (client == NULL) {
|
||||||
|
Log->println("Failed to initialize HTTPS client");
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open connection */
|
||||||
|
Log->println("Opening HTTPS connection...");
|
||||||
|
if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
|
||||||
|
Log->printf("Failed to open HTTPS connection: %s\n", esp_err_to_name(err));
|
||||||
|
Log->println("Common causes:");
|
||||||
|
Log->println(" - Certificate CN doesn't match server IP");
|
||||||
|
Log->println(" - Server not running or unreachable");
|
||||||
|
Log->println(" - WiFi connection issues");
|
||||||
|
Log->println(" - Firewall blocking port 443");
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (http_err) {
|
||||||
|
Log->println("Exiting OTA, due to http failure");
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
http_err = 0;
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch headers */
|
||||||
|
Log->println("Fetching HTTPS headers...");
|
||||||
|
int64_t content_length = esp_http_client_fetch_headers(client);
|
||||||
|
|
||||||
|
int http_status = esp_http_client_get_status_code(client);
|
||||||
|
if (http_status != 200) {
|
||||||
|
Log->printf("HTTPS request failed with status: %d\n", http_status);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_length <= 0) {
|
||||||
|
Log->println("HTTP client fetch headers failed");
|
||||||
|
Log->printf("HTTP GET Status = %d, content_length = %" PRId64 "\n", esp_http_client_get_status_code(client), esp_http_client_get_content_length(client));
|
||||||
|
esp_http_client_close(client);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log->printf("HTTP GET Status = %d, content_length = %" PRId64 "\n", esp_http_client_get_status_code(client), esp_http_client_get_content_length(client));
|
||||||
|
|
||||||
|
/* Begin OTA */
|
||||||
|
Log->println("Preparing OTA");
|
||||||
|
if ((err = esp_hosted_slave_ota_begin()) != ESP_OK) {
|
||||||
|
Log->printf("esp_hosted_slave_ota_begin failed: %s\n", esp_err_to_name(err));
|
||||||
|
Log->printf("esp_ota_begin failed, error=%s\n", esp_err_to_name(err));
|
||||||
|
esp_http_client_close(client);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ota_chunk = (uint8_t*)calloc(1, CHUNK_SIZE);
|
||||||
|
if (!ota_chunk) {
|
||||||
|
Log->println("Failed to allocate OTA chunk memory");
|
||||||
|
esp_http_client_close(client);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log->println("Starting OTA data transfer over HTTPS");
|
||||||
|
|
||||||
|
/* Read and write OTA data */
|
||||||
|
bool header_verified = false;
|
||||||
|
int chunk_count = 0;
|
||||||
|
|
||||||
|
while ((data_read = esp_http_client_read(client, (char*)ota_chunk, CHUNK_SIZE)) > 0) {
|
||||||
|
Log->printf("Read image length %d\n", data_read);
|
||||||
|
|
||||||
|
/* Verify image header from the first chunk */
|
||||||
|
if (!header_verified && chunk_count == 0) {
|
||||||
|
size_t firmware_size;
|
||||||
|
char app_version[32];
|
||||||
|
|
||||||
|
Log->printf("Verifying image header from first chunk (%d bytes)\n", data_read);
|
||||||
|
if ((err = parse_image_header_from_buffer(ota_chunk, data_read, &firmware_size, app_version, sizeof(app_version))) != ESP_OK) {
|
||||||
|
Log->printf("Image header verification failed: %s\n", esp_err_to_name(err));
|
||||||
|
ota_failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log->printf("Image verified - Size: %u bytes, Version: %s\n", (unsigned int)firmware_size, app_version);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OTA_VERSION_CHECK_SLAVEFW_SLAVE
|
||||||
|
/* Get current running slave firmware version and compare */
|
||||||
|
esp_hosted_coprocessor_fwver_t current_slave_version = {0};
|
||||||
|
esp_err_t version_ret = esp_hosted_get_coprocessor_fwversion(¤t_slave_version);
|
||||||
|
|
||||||
|
if (version_ret == ESP_OK) {
|
||||||
|
char current_version_str[32];
|
||||||
|
snprintf(current_version_str, sizeof(current_version_str), "%" PRIu32 ".%" PRIu32 ".%" PRIu32,
|
||||||
|
current_slave_version.major1, current_slave_version.minor1, current_slave_version.patch1);
|
||||||
|
|
||||||
|
Log->printf("Current slave firmware version: %s\n", current_version_str);
|
||||||
|
Log->printf("New slave firmware version: %s\n", app_version);
|
||||||
|
|
||||||
|
if (strcmp(app_version, current_version_str) == 0) {
|
||||||
|
Log->printf("Current slave firmware version (%s) is the same as new version (%s). Skipping OTA.\n", current_version_str, app_version);
|
||||||
|
/* Cleanup and return success */
|
||||||
|
free(ota_chunk);
|
||||||
|
esp_http_client_close(client);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_NOT_REQUIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log->printf("Version differs - proceeding with OTA from %s to %s\n", current_version_str, app_version);
|
||||||
|
} else {
|
||||||
|
Log->printf("Could not get current slave firmware version (error: %s), proceeding with OTA\n", esp_err_to_name(version_ret));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Log->printf("Version check disabled - proceeding with OTA (new firmware version: %s)\n", app_version);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
header_verified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = esp_hosted_slave_ota_write(ota_chunk, data_read)) != ESP_OK) {
|
||||||
|
Log->printf("esp_hosted_slave_ota_write failed: %s\n", esp_err_to_name(err));
|
||||||
|
ota_failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup resources */
|
||||||
|
free(ota_chunk);
|
||||||
|
esp_http_client_close(client);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
|
||||||
|
/* Check for read errors */
|
||||||
|
if (data_read < 0) {
|
||||||
|
Log->println("Error: HTTPS data read error");
|
||||||
|
ota_failed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End OTA */
|
||||||
|
if ((err = esp_hosted_slave_ota_end()) != ESP_OK) {
|
||||||
|
Log->printf("esp_ota_end failed, error=%s\n", esp_err_to_name(err));
|
||||||
|
esp_http_client_close(client);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final result */
|
||||||
|
if (ota_failed) {
|
||||||
|
Log->println("********* Slave OTA Failed *******************");
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_FAILED;
|
||||||
|
} else {
|
||||||
|
Log->println("********* Slave OTA Complete *******************");
|
||||||
|
return ESP_HOSTED_SLAVE_OTA_COMPLETED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ssize_t write_fn(void* cookie, const char* buf, ssize_t size)
|
ssize_t write_fn(void* cookie, const char* buf, ssize_t size)
|
||||||
{
|
{
|
||||||
Log->write((uint8_t *)buf, (size_t)size);
|
Log->write((uint8_t *)buf, (size_t)size);
|
||||||
@@ -474,6 +815,13 @@ void restartServices(bool reconnect)
|
|||||||
Log->println("Deinit BLE device");
|
Log->println("Deinit BLE device");
|
||||||
BLEDevice::deinit(false);
|
BLEDevice::deinit(false);
|
||||||
Log->println("Deinit BLE device done");
|
Log->println("Deinit BLE device done");
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
if (hostedIsBLEActive())
|
||||||
|
{
|
||||||
|
hostedDeinitBLE();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (esp_task_wdt_status(NULL) == ESP_OK)
|
if (esp_task_wdt_status(NULL) == ESP_OK)
|
||||||
@@ -545,6 +893,10 @@ void restartServices(bool reconnect)
|
|||||||
Log->println("Starting web server done");
|
Log->println("Starting web server done");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
hostedInitBLE();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -584,6 +936,37 @@ void networkTask(void *pvParameters)
|
|||||||
|
|
||||||
if(connected && reroute)
|
if(connected && reroute)
|
||||||
{
|
{
|
||||||
|
#if !defined(NUKI_HUB_UPDATER) && (defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED))
|
||||||
|
//if (hostedHasUpdate() || forceHostedUpdate)
|
||||||
|
if (forceHostedUpdate)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
forceHostedUpdate = false;
|
||||||
|
preferences->putBool(preference_force_hosted_update, false);
|
||||||
|
|
||||||
|
Log->printf("Update URL: %s", hostedGetUpdateURL());
|
||||||
|
ret = ota_https_perform(hostedGetUpdateURL());
|
||||||
|
//ret = ota_https_perform("https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/hosted/network_adapter.bin");
|
||||||
|
|
||||||
|
if (ret == ESP_HOSTED_SLAVE_OTA_COMPLETED) {
|
||||||
|
Log->printf("Hosted OTA completed successfully");
|
||||||
|
ret = esp_hosted_slave_ota_activate();
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
Log->printf("Hosted Slave will reboot with new firmware");
|
||||||
|
Log->printf("********* Restarting host to avoid sync issues **********************");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
|
esp_restart();
|
||||||
|
} else {
|
||||||
|
Log->printf("Failed to activate Hosted OTA: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
} else if (ret == ESP_HOSTED_SLAVE_OTA_NOT_REQUIRED) {
|
||||||
|
Log->printf("Hosted OTA not required");
|
||||||
|
} else {
|
||||||
|
Log->printf("Hosted OTA failed: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(preferences->getBool(preference_update_time, false))
|
if(preferences->getBool(preference_update_time, false))
|
||||||
{
|
{
|
||||||
esp_netif_sntp_start();
|
esp_netif_sntp_start();
|
||||||
@@ -873,6 +1256,7 @@ void bootloopDetection()
|
|||||||
{
|
{
|
||||||
uint64_t cmp = IS_VALID_DETECT;
|
uint64_t cmp = IS_VALID_DETECT;
|
||||||
bool bootloopIsValid = (bootloopValidDetect == cmp);
|
bool bootloopIsValid = (bootloopValidDetect == cmp);
|
||||||
|
Log->print("Bootloop counter valid: ");
|
||||||
Log->println(bootloopIsValid);
|
Log->println(bootloopIsValid);
|
||||||
|
|
||||||
if(!bootloopIsValid)
|
if(!bootloopIsValid)
|
||||||
@@ -891,10 +1275,11 @@ void bootloopDetection()
|
|||||||
Log->print("Bootloop counter incremented: ");
|
Log->print("Bootloop counter incremented: ");
|
||||||
Log->println(bootloopCounter);
|
Log->println(bootloopCounter);
|
||||||
|
|
||||||
if(bootloopCounter == 10)
|
if(bootloopCounter == 10 && preferences->getBool(preference_enable_bootloop_reset, false))
|
||||||
{
|
{
|
||||||
Log->print("Bootloop detected.");
|
Log->print("Bootloop detected.");
|
||||||
|
|
||||||
|
preferences->putInt(preference_network_hardware, 15);
|
||||||
preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
|
preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
|
||||||
preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
|
preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
|
||||||
preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
|
preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
|
||||||
@@ -908,52 +1293,6 @@ void bootloopDetection()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
|
||||||
{
|
|
||||||
if (lastHTTPeventId != int(evt->event_id))
|
|
||||||
{
|
|
||||||
Log->println("");
|
|
||||||
switch (evt->event_id)
|
|
||||||
{
|
|
||||||
case HTTP_EVENT_ERROR:
|
|
||||||
Log->println("HTTP_EVENT_ERROR");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_ON_CONNECTED:
|
|
||||||
Log->print("HTTP_EVENT_ON_CONNECTED");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_HEADER_SENT:
|
|
||||||
Log->print("HTTP_EVENT_HEADER_SENT");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_ON_HEADER:
|
|
||||||
Log->print("HTTP_EVENT_ON_HEADER");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_ON_DATA:
|
|
||||||
Log->print("HTTP_EVENT_ON_DATA");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_ON_FINISH:
|
|
||||||
Log->println("HTTP_EVENT_ON_FINISH");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_DISCONNECTED:
|
|
||||||
Log->println("HTTP_EVENT_DISCONNECTED");
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_REDIRECT:
|
|
||||||
Log->print("HTTP_EVENT_REDIRECT");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log->print(".");
|
|
||||||
}
|
|
||||||
lastHTTPeventId = int(evt->event_id);
|
|
||||||
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
|
||||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
|
||||||
wdt_hal_feed(&rtc_wdt_ctx);
|
|
||||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void otaTask(void *pvParameter)
|
void otaTask(void *pvParameter)
|
||||||
{
|
{
|
||||||
esp_task_wdt_add(NULL);
|
esp_task_wdt_add(NULL);
|
||||||
@@ -1032,6 +1371,8 @@ void otaTask(void *pvParameter)
|
|||||||
restartEsp(RestartReason::OTAAborted);
|
restartEsp(RestartReason::OTAAborted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setupTasks(bool ota)
|
void setupTasks(bool ota)
|
||||||
{
|
{
|
||||||
// configMAX_PRIORITIES is 25
|
// configMAX_PRIORITIES is 25
|
||||||
@@ -1205,6 +1546,8 @@ void setup()
|
|||||||
logCoreDump();
|
logCoreDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceHostedUpdate = preferences->getBool(preference_force_hosted_update, false);
|
||||||
|
|
||||||
if (SPIFFS.begin(true))
|
if (SPIFFS.begin(true))
|
||||||
{
|
{
|
||||||
listDir(SPIFFS, "/", 1);
|
listDir(SPIFFS, "/", 1);
|
||||||
@@ -1346,10 +1689,11 @@ void setup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(preferences->getBool(preference_enable_bootloop_reset, false))
|
|
||||||
{
|
|
||||||
bootloopDetection();
|
bootloopDetection();
|
||||||
}
|
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
hostedInitBLE();
|
||||||
|
#endif
|
||||||
|
|
||||||
Log->print("Nuki Hub version ");
|
Log->print("Nuki Hub version ");
|
||||||
Log->println(NUKI_HUB_VERSION);
|
Log->println(NUKI_HUB_VERSION);
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ const String WifiDevice::deviceName() const
|
|||||||
|
|
||||||
void WifiDevice::initialize()
|
void WifiDevice::initialize()
|
||||||
{
|
{
|
||||||
if (_hostname != "fakep4forhosted")
|
|
||||||
{
|
|
||||||
ssid = _preferences->getString(preference_wifi_ssid, "");
|
ssid = _preferences->getString(preference_wifi_ssid, "");
|
||||||
ssid.trim();
|
ssid.trim();
|
||||||
pass = _preferences->getString(preference_wifi_pass, "");
|
pass = _preferences->getString(preference_wifi_pass, "");
|
||||||
@@ -54,26 +52,6 @@ void WifiDevice::initialize()
|
|||||||
_openAP = true;
|
_openAP = true;
|
||||||
scan(false, true);
|
scan(false, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WiFi.disconnect(true);
|
|
||||||
WiFi.mode(WIFI_STA);
|
|
||||||
WiFi.disconnect();
|
|
||||||
|
|
||||||
int loop = 0;
|
|
||||||
while (!_wifiClientStarted && loop < 50)
|
|
||||||
{
|
|
||||||
if (esp_task_wdt_status(NULL) == ESP_OK)
|
|
||||||
{
|
|
||||||
esp_task_wdt_reset();
|
|
||||||
}
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
loop++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log->println("Dummy WiFi device for Hosted on P4 done");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,6 @@
|
|||||||
NetworkDevice *NetworkDeviceInstantiator::Create(NetworkDeviceType networkDeviceType, String hostname, Preferences *preferences, IPConfiguration *ipConfiguration)
|
NetworkDevice *NetworkDeviceInstantiator::Create(NetworkDeviceType networkDeviceType, String hostname, Preferences *preferences, IPConfiguration *ipConfiguration)
|
||||||
{
|
{
|
||||||
NetworkDevice* device = nullptr;
|
NetworkDevice* device = nullptr;
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
|
||||||
bool fakedevice = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (networkDeviceType)
|
switch (networkDeviceType)
|
||||||
{
|
{
|
||||||
@@ -183,10 +180,13 @@ NetworkDevice *NetworkDeviceInstantiator::Create(NetworkDeviceType networkDevice
|
|||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
if (!hostedIsWiFiActive())
|
||||||
|
{
|
||||||
|
hostedInitWiFi();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
device = new WifiDevice(hostname, preferences, ipConfiguration);
|
device = new WifiDevice(hostname, preferences, ipConfiguration);
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
|
||||||
fakedevice = false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -216,16 +216,22 @@ NetworkDevice *NetworkDeviceInstantiator::Create(NetworkDeviceType networkDevice
|
|||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
||||||
case NetworkDeviceType::WiFi:
|
case NetworkDeviceType::WiFi:
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
if (!hostedIsWiFiActive())
|
||||||
|
{
|
||||||
|
hostedInitWiFi();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
device = new WifiDevice(hostname, preferences, ipConfiguration);
|
device = new WifiDevice(hostname, preferences, ipConfiguration);
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
|
||||||
fakedevice = false;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE) || defined(CONFIG_ESP_WIFI_REMOTE_ENABLED)
|
||||||
|
if (!hostedIsWiFiActive())
|
||||||
|
{
|
||||||
|
hostedInitWiFi();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
device = new WifiDevice(hostname, preferences, ipConfiguration);
|
device = new WifiDevice(hostname, preferences, ipConfiguration);
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
|
||||||
fakedevice = false;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
default:
|
default:
|
||||||
@@ -242,17 +248,5 @@ NetworkDevice *NetworkDeviceInstantiator::Create(NetworkDeviceType networkDevice
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
|
||||||
if (fakedevice)
|
|
||||||
{
|
|
||||||
Log->println("Create dummy WiFi device for Hosted on P4");
|
|
||||||
NetworkDevice* device2 = nullptr;
|
|
||||||
device2 = new WifiDevice("fakep4forhosted", preferences, ipConfiguration);
|
|
||||||
device2->initialize();
|
|
||||||
delete device2;
|
|
||||||
device2 = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|||||||
29
updater/apply_patches.py
Normal file
29
updater/apply_patches.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from os.path import join, isfile
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
FRAMEWORK_DIR = env.PioPlatform().get_package_dir("framework-arduinoespressif32")
|
||||||
|
patchflag_path = join(FRAMEWORK_DIR, ".hosted-patching-done")
|
||||||
|
|
||||||
|
# patch file only if we didn't do it before
|
||||||
|
if not isfile(join(FRAMEWORK_DIR, ".hosted-patching-done")):
|
||||||
|
original_file = join(FRAMEWORK_DIR, "cores", "esp32", "esp32-hal-hosted.c")
|
||||||
|
patched_file = join("resources", "esp32-hal-hosted.c.patch")
|
||||||
|
|
||||||
|
assert isfile(original_file) and isfile(patched_file)
|
||||||
|
|
||||||
|
env.Execute("patch %s %s" % (original_file, patched_file))
|
||||||
|
# env.Execute("touch " + patchflag_path)
|
||||||
|
|
||||||
|
original_file = join(FRAMEWORK_DIR, "cores", "esp32", "esp32-hal-hosted.h")
|
||||||
|
patched_file = join("resources", "esp32-hal-hosted.h.patch")
|
||||||
|
|
||||||
|
assert isfile(original_file) and isfile(patched_file)
|
||||||
|
|
||||||
|
env.Execute("patch %s %s" % (original_file, patched_file))
|
||||||
|
|
||||||
|
def _touch(path):
|
||||||
|
with open(path, "w") as fp:
|
||||||
|
fp.write("")
|
||||||
|
|
||||||
|
env.Execute(lambda *args, **kwargs: _touch(patchflag_path))
|
||||||
@@ -13,7 +13,7 @@ default_envs = updater_esp32
|
|||||||
boards_dir = ../boards
|
boards_dir = ../boards
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.33/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.34/platform-espressif32.zip
|
||||||
platform_packages =
|
platform_packages =
|
||||||
framework = arduino, espidf
|
framework = arduino, espidf
|
||||||
build_type = release
|
build_type = release
|
||||||
@@ -149,6 +149,10 @@ board_build.cmake_extra_args =
|
|||||||
extends = env:updater_esp32
|
extends = env:updater_esp32
|
||||||
board_build.embed_txtfiles =
|
board_build.embed_txtfiles =
|
||||||
board = esp32-p4
|
board = esp32-p4
|
||||||
|
extra_scripts =
|
||||||
|
pre:pio_package_pre.py
|
||||||
|
#pre:apply_patches.py
|
||||||
|
post:pio_package_post.py
|
||||||
board_build.cmake_extra_args =
|
board_build.cmake_extra_args =
|
||||||
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32-p4"
|
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32-p4"
|
||||||
custom_component_remove =
|
custom_component_remove =
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ dependencies:
|
|||||||
idf: ">=5.5"
|
idf: ">=5.5"
|
||||||
|
|
||||||
espressif/esp_hosted:
|
espressif/esp_hosted:
|
||||||
version: "*"
|
version: "2.6.6"
|
||||||
#override_path: "../../resources/espressif__esp_hosted"
|
#override_path: "../../resources/espressif__esp_hosted"
|
||||||
rules:
|
rules:
|
||||||
- if: "target in [esp32p4]"
|
- if: "target in [esp32p4]"
|
||||||
|
|||||||
Reference in New Issue
Block a user