Restart BLE controller

This commit is contained in:
iranl
2025-06-15 21:13:45 +02:00
parent b60bbf032f
commit f8b68ff2fa
14 changed files with 384 additions and 114 deletions

View File

@@ -0,0 +1,31 @@
{
"build": {
"core": "esp32",
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32c5",
"variant": "esp32c5"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32c5.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-C5 (>=8MB QD, QUAD OR NO PSRAM)",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32c5/esp32-c5-devkitc-1/user_guide.html",
"vendor": "Espressif"
}

View File

@@ -20,6 +20,16 @@ Scanner::Scanner(int reservedSubscribers) {
subscribers.reserve(reservedSubscribers); subscribers.reserve(reservedSubscribers);
} }
Scanner::~Scanner() {
Serial.println("Destroying scanner");
bleScan->stop();
Serial.println("bleScan stopped");
bleScan->clearResults();
Serial.println("bleScan results cleared");
bleScan = nullptr;
Serial.println("bleScan nulled");
}
void Scanner::initialize(const std::string& deviceName, const bool wantDuplicates, const uint16_t interval, const uint16_t window) { void Scanner::initialize(const std::string& deviceName, const bool wantDuplicates, const uint16_t interval, const uint16_t window) {
if (!BLEDevice::isInitialized()) { if (!BLEDevice::isInitialized()) {
if (wantDuplicates) { if (wantDuplicates) {

View File

@@ -25,7 +25,7 @@ namespace BleScanner {
class Scanner : public Publisher, BLEAdvertisedDeviceCallbacks { class Scanner : public Publisher, BLEAdvertisedDeviceCallbacks {
public: public:
Scanner(int reservedSubscribers = 10); Scanner(int reservedSubscribers = 10);
~Scanner() = default; ~Scanner();
static Scanner& instance() { static Scanner& instance() {
static Scanner* scanner = new Scanner(); // only initialized once on first call static Scanner* scanner = new Scanner(); // only initialized once on first call

1
partitions_c5dbg.csv Normal file
View File

@@ -0,0 +1 @@
# Espressif ESP32 Partition Table
1 # Espressif ESP32 Partition Table # Name Type SubType Offset Size Flags nvs data nvs 0x9000 0x5000 otadata data ota 0xe000 0x2000 app0 app ota_0 0x10000 0x500000 app1 app ota_1 0x510000 0x150000 spiffs data spiffs 0x660000 0x40000 coredump data coredump 0x6A0000 0x10000

View File

@@ -179,9 +179,11 @@ build_flags =
[env:esp32-c5_dbg] [env:esp32-c5_dbg]
extends = env:esp32-c5 extends = env:esp32-c5
board_build.partitions = partitions_c5dbg.csv
board = nuki-esp32-c5dbg
custom_build = debug custom_build = debug
board_build.cmake_extra_args = board_build.cmake_extra_args =
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.defaults.esp32-c5;sdkconfig.singlecore.defaults" -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.debug.defaults;sdkconfig.defaults.esp32-c5;sdkconfig.defaults.esp32-c5dbg;sdkconfig.singlecore.defaults"
build_flags = build_flags =
${env.build_flags} ${env.build_flags}
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG

View File

@@ -2,4 +2,5 @@ CONFIG_SPIRAM=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT=y CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT=y
CONFIG_ESPTOOLPY_NO_STUB=n
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=50768 CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=50768

View File

@@ -0,0 +1,4 @@
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG=y
CONFIG_BT_NIMBLE_LOG_LEVEL=4
CONFIG_NIMBLE_CPP_LOG_LEVEL=4

View File

@@ -5,7 +5,7 @@
#define NUKI_HUB_VERSION "9.11" #define NUKI_HUB_VERSION "9.11"
#define NUKI_HUB_VERSION_INT (uint32_t)911 #define NUKI_HUB_VERSION_INT (uint32_t)911
#define NUKI_HUB_BUILD "unknownbuildnr" #define NUKI_HUB_BUILD "unknownbuildnr"
#define NUKI_HUB_DATE "2025-06-10" #define NUKI_HUB_DATE "2025-06-15"
#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"

View File

@@ -1142,7 +1142,9 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
{ {
duoResult = _importExport->checkDuoApprove(); duoResult = _importExport->checkDuoApprove();
delay(2000); delay(2000);
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_reset(); esp_task_wdt_reset();
#endif
} }
} }

View File

@@ -214,6 +214,16 @@ void NukiOpenerWrapper::readSettings()
} }
} }
uint8_t NukiOpenerWrapper::restartController()
{
return _restartController;
}
bool NukiOpenerWrapper::hasConnected()
{
return _hasConnected;
}
void NukiOpenerWrapper::update() void NukiOpenerWrapper::update()
{ {
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
@@ -254,9 +264,9 @@ void NukiOpenerWrapper::update()
{ {
Log->print("No BLE beacon received from the opener for "); Log->print("No BLE beacon received from the opener for ");
Log->print((ts - lastReceivedBeaconTs) / 1000); Log->print((ts - lastReceivedBeaconTs) / 1000);
Log->println(" seconds, restarting device."); Log->println(" seconds, signalling to restart BLE controller.");
delay(200); delay(200);
restartEsp(RestartReason::BLEBeaconWatchdog); _restartController = 2;
} }
_nukiOpener.updateConnectionState(); _nukiOpener.updateConnectionState();
@@ -501,6 +511,11 @@ bool NukiOpenerWrapper::updateKeyTurnerState()
_network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState); _network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
return false; return false;
} }
else if (!_hasConnected)
{
_hasConnected = true;
}
_retryLockstateCount = 0; _retryLockstateCount = 0;
const NukiOpener::LockState& lockState = _keyTurnerState.lockState; const NukiOpener::LockState& lockState = _keyTurnerState.lockState;
@@ -4067,8 +4082,8 @@ void NukiOpenerWrapper::notify(Nuki::EventType eventType)
} }
else if(eventType == Nuki::EventType::BLE_ERROR_ON_DISCONNECT) else if(eventType == Nuki::EventType::BLE_ERROR_ON_DISCONNECT)
{ {
Log->println("Error in disconnecting BLE client, rebooting"); Log->println("Error in disconnecting BLE client, signalling to restart BLE controller");
restartEsp(RestartReason::BLEError); _restartController = 1;
} }
} }

View File

@@ -25,6 +25,7 @@ public:
void deactivateRTO(); void deactivateRTO();
void deactivateCM(); void deactivateCM();
bool hasConnected();
bool isPinValid(); bool isPinValid();
void setPin(const uint16_t pin); void setPin(const uint16_t pin);
uint16_t getPin(); uint16_t getPin();
@@ -36,6 +37,7 @@ public:
const bool isPaired() const; const bool isPaired() const;
const bool hasKeypad() const; const bool hasKeypad() const;
const BLEAddress getBleAddress() const; const BLEAddress getBleAddress() const;
uint8_t restartController();
std::string firmwareVersion() const; std::string firmwareVersion() const;
std::string hardwareVersion() const; std::string hardwareVersion() const;
@@ -135,9 +137,11 @@ private:
bool _forceKeypad = false; bool _forceKeypad = false;
bool _keypadEnabled = false; bool _keypadEnabled = false;
bool _forceId = false; bool _forceId = false;
bool _hasConnected = false;
uint _maxKeypadCodeCount = 0; uint _maxKeypadCodeCount = 0;
uint _maxTimeControlEntryCount = 0; uint _maxTimeControlEntryCount = 0;
uint _maxAuthEntryCount = 0; uint _maxAuthEntryCount = 0;
uint8_t _restartController = 0;
int _rssiPublishInterval = 0; int _rssiPublishInterval = 0;
int64_t _statusUpdatedTs = 0; int64_t _statusUpdatedTs = 0;
int64_t _nextLockStateUpdateTs = 0; int64_t _nextLockStateUpdateTs = 0;

View File

@@ -229,6 +229,16 @@ void NukiWrapper::readSettings()
} }
} }
uint8_t NukiWrapper::restartController()
{
return _restartController;
}
bool NukiWrapper::hasConnected()
{
return _hasConnected;
}
void NukiWrapper::update(bool reboot) void NukiWrapper::update(bool reboot)
{ {
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
@@ -270,9 +280,9 @@ void NukiWrapper::update(bool reboot)
{ {
Log->print("No BLE beacon received from the lock for "); Log->print("No BLE beacon received from the lock for ");
Log->print((ts - lastReceivedBeaconTs) / 1000); Log->print((ts - lastReceivedBeaconTs) / 1000);
Log->println(" seconds, restarting device."); Log->println(" seconds, signalling to restart BLE controller.");
delay(200); delay(200);
restartEsp(RestartReason::BLEBeaconWatchdog); _restartController = 2;
} }
_nukiLock.updateConnectionState(); _nukiLock.updateConnectionState();
@@ -535,6 +545,10 @@ bool NukiWrapper::updateKeyTurnerState()
_network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState); _network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
return false; return false;
} }
else if (!_hasConnected)
{
_hasConnected = true;
}
_retryLockstateCount = 0; _retryLockstateCount = 0;
@@ -4320,8 +4334,8 @@ void NukiWrapper::notify(Nuki::EventType eventType)
} }
else if(eventType == Nuki::EventType::BLE_ERROR_ON_DISCONNECT) else if(eventType == Nuki::EventType::BLE_ERROR_ON_DISCONNECT)
{ {
Log->println("Error in disconnecting BLE client, rebooting"); Log->println("Error in disconnecting BLE client, signalling to restart BLE controller");
restartEsp(RestartReason::BLEError); _restartController = 1;
} }
} }
} }

View File

@@ -27,6 +27,7 @@ public:
void lockngo(); void lockngo();
void lockngounlatch(); void lockngounlatch();
bool hasConnected();
bool isPinValid(); bool isPinValid();
void setPin(const uint16_t pin); void setPin(const uint16_t pin);
void setUltraPin(const uint32_t pin); void setUltraPin(const uint32_t pin);
@@ -42,6 +43,7 @@ public:
bool hasDoorSensor() const; bool hasDoorSensor() const;
bool offConnected(); bool offConnected();
const BLEAddress getBleAddress() const; const BLEAddress getBleAddress() const;
uint8_t restartController();
std::string firmwareVersion() const; std::string firmwareVersion() const;
std::string hardwareVersion() const; std::string hardwareVersion() const;
@@ -142,9 +144,11 @@ private:
bool _forceId = false; bool _forceId = false;
bool _isUltra = false; bool _isUltra = false;
bool _isDebugging = false; bool _isDebugging = false;
bool _hasConnected = false;
uint _maxKeypadCodeCount = 0; uint _maxKeypadCodeCount = 0;
uint _maxTimeControlEntryCount = 0; uint _maxTimeControlEntryCount = 0;
uint _maxAuthEntryCount = 0; uint _maxAuthEntryCount = 0;
uint8_t _restartController = 0;
int _nrOfRetries = 0; int _nrOfRetries = 0;
int _retryDelay = 0; int _retryDelay = 0;
int _retryConfigCount = 0; int _retryConfigCount = 0;

View File

@@ -53,10 +53,14 @@ NukiDeviceId* deviceIdOpener = nullptr;
Gpio* gpio = nullptr; Gpio* gpio = nullptr;
SerialReader* serialReader = nullptr; SerialReader* serialReader = nullptr;
bool bleDone = false;
bool lockEnabled = false; bool lockEnabled = false;
bool openerEnabled = false; bool openerEnabled = false;
bool wifiConnected = false; bool wifiConnected = false;
bool rebootLock = false; bool rebootLock = false;
uint8_t lockRestartControllerCount = 0;
uint8_t openerRestartControllerCount = 0;
char16_t buffer_size = CHAR_BUFFER_SIZE;
TaskHandle_t nukiTaskHandle = nullptr; TaskHandle_t nukiTaskHandle = nullptr;
@@ -78,6 +82,7 @@ int64_t restartTs = 10 * 60 * 1000;
char log_print_buffer[1024]; char log_print_buffer[1024];
PsychicHttpServer* psychicServer = nullptr; PsychicHttpServer* psychicServer = nullptr;
PsychicHttpServer* psychicServerRedirect = nullptr;
PsychicHttpsServer* psychicSSLServer = nullptr; PsychicHttpsServer* psychicSSLServer = nullptr;
NukiNetwork* network = nullptr; NukiNetwork* network = nullptr;
WebCfgServer* webCfgServer = nullptr; WebCfgServer* webCfgServer = nullptr;
@@ -95,10 +100,12 @@ RTC_NOINIT_ATTR bool forceEnableWebServer;
RTC_NOINIT_ATTR bool disableNetwork; RTC_NOINIT_ATTR bool disableNetwork;
RTC_NOINIT_ATTR bool wifiFallback; RTC_NOINIT_ATTR bool wifiFallback;
RTC_NOINIT_ATTR bool ethCriticalFailure; RTC_NOINIT_ATTR bool ethCriticalFailure;
bool coredumpPrinted = true; bool coredumpPrinted = true;
bool timeSynced = false; bool timeSynced = false;
bool webStarted = false; bool webStarted = false;
bool webSSLStarted = false; bool webSSLStarted = false;
uint8_t partitionType = -1;
int lastHTTPeventId = -1; int lastHTTPeventId = -1;
bool doOta = false; bool doOta = false;
@@ -176,11 +183,15 @@ uint8_t checkPartition()
Log->print("Partition subtype: "); Log->print("Partition subtype: ");
Log->println(running_partition->subtype); Log->println(running_partition->subtype);
#if !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32P4)
if(running_partition->size == 1966080) if(running_partition->size == 1966080)
{ {
return 0; //OLD PARTITION TABLE return 0; //OLD PARTITION TABLE
} }
else if(running_partition->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) #endif
if(running_partition->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0)
{ {
return 1; //NEW PARTITION TABLE, RUNNING MAIN APP return 1; //NEW PARTITION TABLE, RUNNING MAIN APP
} }
@@ -307,7 +318,7 @@ void networkTask(void *pvParameters)
if(espMillis() > restartTs) if(espMillis() > restartTs)
{ {
uint8_t partitionType = checkPartition(); partitionType = checkPartition();
if(partitionType!=1) if(partitionType!=1)
{ {
@@ -316,11 +327,202 @@ void networkTask(void *pvParameters)
restartEsp(RestartReason::RestartTimer); restartEsp(RestartReason::RestartTimer);
} }
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_reset(); esp_task_wdt_reset();
#endif
} }
} }
#ifndef NUKI_HUB_UPDATER #ifndef NUKI_HUB_UPDATER
void startWebServer()
{
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
bool failed = false;
if (esp_psram_get_size() <= 0) {
Log->println("Not running on PSRAM enabled device");
failed = true;
}
else
{
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
failed = true;
}
else
{
File file = SPIFFS.open("/http_ssl.crt");
if (!file || file.isDirectory()) {
failed = true;
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';
File file2 = SPIFFS.open("/http_ssl.key");
if (!file2 || file2.isDirectory()) {
failed = true;
Log->println("http_ssl.key not found");
}
else
{
Log->println("Reading http_ssl.key");
size_t filesize2 = file2.size();
char key[filesize2 + 1];
file2.read((uint8_t *)key, sizeof(key));
file2.close();
key[filesize2] = '\0';
psychicServerRedirect = new PsychicHttpServer();
psychicServerRedirect->config.ctrl_port = 20424;
psychicServerRedirect->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
String url = "https://" + request->host() + request->url();
if (preferences->getString(preference_https_fqdn, "") != "")
{
url = "https://" + preferences->getString(preference_https_fqdn) + request->url();
}
response->setCode(301);
response->addHeader("Cache-Control", "no-cache");
return response->redirect(url.c_str());
});
psychicServerRedirect->begin();
psychicSSLServer = new PsychicHttpsServer;
psychicSSLServer->ssl_config.httpd.max_open_sockets = 8;
psychicSSLServer->setCertificate(cert, key);
psychicSSLServer->config.stack_size = HTTPD_TASK_SIZE;
webCfgServerSSL = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicSSLServer, importExport);
webCfgServerSSL->initialize();
psychicSSLServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
return response->redirect("/");
});
psychicSSLServer->begin();
webSSLStarted = true;
}
}
}
}
if (failed)
{
#endif
psychicServer = new PsychicHttpServer;
psychicServer->config.stack_size = HTTPD_TASK_SIZE;
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer, importExport);
webCfgServer->initialize();
psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
return response->redirect("/");
});
psychicServer->begin();
webStarted = true;
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
}
#endif
}
void restartBle()
{
bleDone = false;
if(webSSLStarted)
{
Log->println("Reset Psychic SSL server");
psychicSSLServer->reset();
Log->println("Reset Psychic SSL server done");
Log->println("Deleting Psychic SSL server");
delete psychicSSLServer;
psychicSSLServer = nullptr;
Log->println("Deleting Psychic SSL server done");
}
if(webStarted)
{
Log->println("Reset Psychic server");
psychicServer->reset();
Log->println("Reset Psychic server done");
Log->println("Deleting Psychic server");
delete psychicServer;
psychicServer = nullptr;
Log->println("Deleting Psychic server done");
}
if(webStarted || webSSLStarted)
{
Log->println("Deleting webCfgServer");
delete webCfgServer;
webCfgServer = nullptr;
Log->println("Deleting webCfgServer done");
}
if(lockEnabled)
{
Log->println("Deleting nuki");
delete nuki;
nuki = nullptr;
Log->println("Deleting nuki done");
}
if(openerEnabled)
{
Log->println("Deleting nukiOpener");
delete nukiOpener;
nukiOpener = nullptr;
Log->println("Deleting nukiOpener done");
}
Log->println("Destroying scanner from main");
delete bleScanner;
Log->println("Scanner deleted");
bleScanner = nullptr;
Log->println("Scanner nulled from main");
if (BLEDevice::isInitialized()) {
Log->println("Deinit BLE device");
BLEDevice::deinit(false);
Log->println("Deinit BLE device done");
}
delay(2000);
Log->println("Restarting BLE Scanner");
bleScanner = new BleScanner::Scanner();
bleScanner->initialize("NukiHub", true, 40, 40);
bleScanner->setScanDuration(0);
Log->println("Restarting BLE Scanner done");
if(lockEnabled)
{
Log->println("Restarting Nuki lock");
nuki = new NukiWrapper("NukiHub", deviceIdLock, bleScanner, networkLock, nukiOfficial, gpio, preferences, CharBuffer::get(), buffer_size);
nuki->initialize();
Log->println("Restarting Nuki lock done");
}
if(openerEnabled)
{
Log->println("Restarting Nuki opener");
nukiOpener = new NukiOpenerWrapper("NukiHub", deviceIdOpener, bleScanner, networkOpener, gpio, preferences, CharBuffer::get(), buffer_size);
nukiOpener->initialize();
Log->println("Restarting Nuki opener done");
}
bleDone = true;
if(webStarted || webSSLStarted)
{
Log->println("Restarting web server");
startWebServer();
Log->println("Restarting web server done");
}
}
void nukiTask(void *pvParameters) void nukiTask(void *pvParameters)
{ {
if (preferences->getBool(preference_mqtt_ssl_enabled, false)) if (preferences->getBool(preference_mqtt_ssl_enabled, false))
@@ -340,7 +542,7 @@ void nukiTask(void *pvParameters)
bool whiteListed = false; bool whiteListed = false;
while(true) while(true)
{ {
if(disableNetwork || wifiConnected) if((disableNetwork || wifiConnected) && bleDone)
{ {
bleScanner->update(); bleScanner->update();
delay(20); delay(20);
@@ -366,12 +568,68 @@ void nukiTask(void *pvParameters)
if(lockEnabled) if(lockEnabled)
{ {
nuki->update(rebootLock); if (nuki->restartController() > 0)
rebootLock = false; {
if (lockRestartControllerCount > 3)
{
if (nuki->restartController() == 1)
{
restartEsp(RestartReason::BLEError);
}
else if (nuki->restartController() == 2)
{
restartEsp(RestartReason::BLEBeaconWatchdog);
}
}
else
{
lockRestartControllerCount += 1;
restartBle();
continue;
}
}
else
{
if (lockRestartControllerCount > 0 && nuki->hasConnected())
{
lockRestartControllerCount = 0;
}
nuki->update(rebootLock);
rebootLock = false;
}
} }
if(openerEnabled) if(openerEnabled)
{ {
nukiOpener->update(); if (nukiOpener->restartController() > 0)
{
if (openerRestartControllerCount > 3)
{
if (nukiOpener->restartController() == 1)
{
restartEsp(RestartReason::BLEError);
}
else if (nukiOpener->restartController() == 2)
{
restartEsp(RestartReason::BLEBeaconWatchdog);
}
}
else
{
openerRestartControllerCount += 1;
restartBle();
continue;
}
}
else
{
if (openerRestartControllerCount > 0 && nukiOpener->hasConnected())
{
openerRestartControllerCount = 0;
}
nukiOpener->update();
}
} }
} }
@@ -380,8 +638,9 @@ void nukiTask(void *pvParameters)
Log->println("nukiTask is running"); Log->println("nukiTask is running");
nukiLoopTs = espMillis(); nukiLoopTs = espMillis();
} }
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_reset(); esp_task_wdt_reset();
#endif
} }
} }
@@ -472,7 +731,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt)
void otaTask(void *pvParameter) void otaTask(void *pvParameter)
{ {
uint8_t partitionType = checkPartition(); partitionType = checkPartition();
String updateUrl; String updateUrl;
if(partitionType==1) if(partitionType==1)
@@ -525,7 +784,9 @@ void otaTask(void *pvParameter)
{ {
Log->println("Firmware upgrade failed, retrying in 5 seconds"); Log->println("Firmware upgrade failed, retrying in 5 seconds");
retryCount++; retryCount++;
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_reset(); esp_task_wdt_reset();
#endif
delay(5000); delay(5000);
continue; continue;
} }
@@ -542,6 +803,7 @@ void otaTask(void *pvParameter)
void setupTasks(bool ota) void setupTasks(bool ota)
{ {
// configMAX_PRIORITIES is 25 // configMAX_PRIORITIES is 25
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_config_t twdt_config = esp_task_wdt_config_t twdt_config =
{ {
.timeout_ms = 300000, .timeout_ms = 300000,
@@ -549,6 +811,7 @@ void setupTasks(bool ota)
.trigger_panic = true, .trigger_panic = true,
}; };
esp_task_wdt_reconfigure(&twdt_config); esp_task_wdt_reconfigure(&twdt_config);
#endif
esp_chip_info_t info; esp_chip_info_t info;
esp_chip_info(&info); esp_chip_info(&info);
@@ -559,20 +822,26 @@ void setupTasks(bool ota)
if(ota) if(ota)
{ {
xTaskCreatePinnedToCore(otaTask, "ota", 8192, NULL, 2, &otaTaskHandle, (espCores > 1) ? 1 : 0); xTaskCreatePinnedToCore(otaTask, "ota", 8192, NULL, 2, &otaTaskHandle, (espCores > 1) ? 1 : 0);
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_add(otaTaskHandle); esp_task_wdt_add(otaTaskHandle);
#endif
} }
else else
{ {
if(!disableNetwork) if(!disableNetwork)
{ {
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, (espCores > 1) ? 1 : 0); xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, (espCores > 1) ? 1 : 0);
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_add(networkTaskHandle); esp_task_wdt_add(networkTaskHandle);
#endif
} }
#ifndef NUKI_HUB_UPDATER #ifndef NUKI_HUB_UPDATER
if(!network->isApOpen() && (lockEnabled || openerEnabled)) if(!network->isApOpen() && (lockEnabled || openerEnabled))
{ {
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 0); xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 0);
#if !defined(CONFIG_IDF_TARGET_ESP32C5)
esp_task_wdt_add(nukiTaskHandle); esp_task_wdt_add(nukiTaskHandle);
#endif
} }
#endif #endif
} }
@@ -678,7 +947,7 @@ void setup()
Serial.begin(115200); Serial.begin(115200);
Log = &Serial; Log = &Serial;
#ifndef NUKI_HUB_UPDATER #if !defined(NUKI_HUB_UPDATER) && !defined(CONFIG_IDF_TARGET_ESP32C5)
// //
stdout = funopen(NULL, NULL, &write_fn, NULL, NULL); stdout = funopen(NULL, NULL, &write_fn, NULL, NULL);
static char linebuf[1024]; static char linebuf[1024];
@@ -705,7 +974,7 @@ void setup()
listDir(SPIFFS, "/", 1); listDir(SPIFFS, "/", 1);
} }
uint8_t partitionType = checkPartition(); partitionType = checkPartition();
//default disableNetwork RTC_ATTR to false on power-on //default disableNetwork RTC_ATTR to false on power-on
if(espRunning != 1) if(espRunning != 1)
@@ -861,7 +1130,7 @@ void setup()
deviceIdOpener->assignId(deviceIdLock->get()); deviceIdOpener->assignId(deviceIdLock->get());
} }
char16_t buffer_size = preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE); buffer_size = preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE);
CharBuffer::initialize(buffer_size); CharBuffer::initialize(buffer_size);
gpio = new Gpio(preferences); gpio = new Gpio(preferences);
@@ -928,100 +1197,13 @@ void setup()
nukiOpener->initialize(); nukiOpener->initialize();
} }
bleDone = true;
if(!doOta && !disableNetwork && (forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true) || preferences->getBool(preference_webserial_enabled, false))) if(!doOta && !disableNetwork && (forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true) || preferences->getBool(preference_webserial_enabled, false)))
{ {
if(forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true)) if(forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true))
{ {
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED startWebServer();
bool failed = false;
if (esp_psram_get_size() <= 0) {
Log->println("Not running on PSRAM enabled device");
failed = true;
}
else
{
if (!SPIFFS.begin(true)) {
Log->println("SPIFFS Mount Failed");
failed = true;
}
else
{
File file = SPIFFS.open("/http_ssl.crt");
if (!file || file.isDirectory()) {
failed = true;
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';
File file2 = SPIFFS.open("/http_ssl.key");
if (!file2 || file2.isDirectory()) {
failed = true;
Log->println("http_ssl.key not found");
}
else
{
Log->println("Reading http_ssl.key");
size_t filesize2 = file2.size();
char key[filesize2 + 1];
file2.read((uint8_t *)key, sizeof(key));
file2.close();
key[filesize2] = '\0';
psychicServer = new PsychicHttpServer();
psychicServer->config.ctrl_port = 20424;
psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
String url = "https://" + request->host() + request->url();
if (preferences->getString(preference_https_fqdn, "") != "")
{
url = "https://" + preferences->getString(preference_https_fqdn) + request->url();
}
response->setCode(301);
response->addHeader("Cache-Control", "no-cache");
return response->redirect(url.c_str());
});
psychicServer->begin();
psychicSSLServer = new PsychicHttpsServer;
psychicSSLServer->ssl_config.httpd.max_open_sockets = 8;
psychicSSLServer->setCertificate(cert, key);
psychicSSLServer->config.stack_size = HTTPD_TASK_SIZE;
webCfgServerSSL = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicSSLServer, importExport);
webCfgServerSSL->initialize();
psychicSSLServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
return response->redirect("/");
});
psychicSSLServer->begin();
webSSLStarted = true;
}
}
}
}
if (failed)
{
#endif
psychicServer = new PsychicHttpServer;
psychicServer->config.stack_size = HTTPD_TASK_SIZE;
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer, importExport);
webCfgServer->initialize();
psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
return response->redirect("/");
});
psychicServer->begin();
webStarted = true;
#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
}
#endif
} }
/* /*
#ifdef DEBUG_NUKIHUB #ifdef DEBUG_NUKIHUB