diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index e1f04091..13dd7ab3 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -7,6 +7,7 @@ #include "esp_log.h" #include "Helper.h" +#include "statusled.h" #include "CImageBasis.h" #include "server_ota.h" @@ -557,15 +558,17 @@ void CCamera::LightOnOff(bool status) void CCamera::LEDOnOff(bool status) { - // Init the GPIO - gpio_pad_select_gpio(BLINK_GPIO); - /* Set the GPIO as a push/pull output */ - gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); + if (xHandle_task_StatusLED == NULL) { + // Init the GPIO + gpio_pad_select_gpio(BLINK_GPIO); + /* Set the GPIO as a push/pull output */ + gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); - if (!status) - gpio_set_level(BLINK_GPIO, 1); - else - gpio_set_level(BLINK_GPIO, 0); + if (!status) + gpio_set_level(BLINK_GPIO, 1); + else + gpio_set_level(BLINK_GPIO, 0); + } } diff --git a/code/components/jomjol_fileserver_ota/server_ota.cpp b/code/components/jomjol_fileserver_ota/server_ota.cpp index bea0a4ad..5c668b29 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.cpp +++ b/code/components/jomjol_fileserver_ota/server_ota.cpp @@ -39,6 +39,7 @@ #include "ClassLogFile.h" #include "Helper.h" +#include "statusled.h" #include "../../include/defines.h" /*an ota data write buffer ready to write to the flash*/ @@ -66,6 +67,8 @@ static void infinite_loop(void) void task_do_Update_ZIP(void *pvParameter) { + StatusLED(AP_OR_OTA, 1, true); // Signaling an OTA update + std::string filetype = toUpper(getFileType(_file_name_update)); LogFile.WriteToFile(ESP_LOG_INFO, TAG, "File: " + _file_name_update + " Filetype: " + filetype); @@ -87,13 +90,13 @@ void task_do_Update_ZIP(void *pvParameter) ota_update_task(retfirmware); } - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update."); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update"); doRebootOTA(); } else if (filetype == "BIN") { LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Do firmware update - file: " + _file_name_update); ota_update_task(_file_name_update); - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update."); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update"); doRebootOTA(); } else @@ -108,7 +111,7 @@ void CheckUpdate() FILE *pfile; if ((pfile = fopen("/sdcard/update.txt", "r")) == NULL) { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "No update triggered."); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "No pending update"); return; } @@ -120,13 +123,14 @@ void CheckUpdate() std::string _szw = std::string(zw); if (_szw == "init") { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Inital Setup triggered."); - initial_setup = true; } + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Inital setup triggered"); + initial_setup = true; + } } fclose(pfile); DeleteFile("/sdcard/update.txt"); // Prevent Boot Loop!!! - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update during boot triggered - Update File: " + _file_name_update); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Start update process (" + _file_name_update + ")"); xTaskCreate(&task_do_Update_ZIP, "task_do_Update_ZIP", configMINIMAL_STACK_SIZE * 35, NULL, tskIDLE_PRIORITY+1, NULL); @@ -586,6 +590,9 @@ void task_reboot(void *KillAutoFlow) KillTFliteTasks(); // Kill autoflow task if executed in extra task, if not don't kill parent task } + Camera.LightOnOff(false); + StatusLEDOff(); + /* Stop service tasks */ #ifdef ENABLE_MQTT MQTTdestroy_client(true); @@ -607,7 +614,7 @@ void task_reboot(void *KillAutoFlow) void doReboot() { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reboot triggered by Software (5s)."); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reboot triggered by Software (5s)"); LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reboot in 5sec"); BaseType_t xReturned = xTaskCreate(&task_reboot, "task_reboot", configMINIMAL_STACK_SIZE * 3, (void*) true, 10, NULL); @@ -624,6 +631,8 @@ void doRebootOTA() { LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reboot in 5sec"); + Camera.LightOnOff(false); + StatusLEDOff(); esp_camera_deinit(); vTaskDelay(5000 / portTICK_PERIOD_MS); diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp index 145fe8b0..f493a0e8 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp @@ -25,6 +25,7 @@ extern "C" { #endif //ENABLE_MQTT #include "server_help.h" +#include "server_tflite.h" #include "../../include/defines.h" static const char* TAG = "CTRL"; @@ -599,6 +600,10 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph) { LogFile.setLogLevel(ESP_LOG_DEBUG); } + + /* If system reboot was not triggered by user and reboot was caused by execption -> keep log level to DEBUG */ + if (!getIsPlannedReboot() && (esp_reset_reason() == ESP_RST_PANIC)) + LogFile.setLogLevel(ESP_LOG_DEBUG); } if ((toUpper(splitted[0]) == "LOGFILESRETENTION") && (splitted.size() > 1)) { @@ -607,18 +612,21 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph) /* TimeServer and TimeZone got already read from the config, see setupTime () */ + #ifdef WLAN_USE_MESH_ROAMING if ((toUpper(splitted[0]) == "RSSITHRESHOLD") && (splitted.size() > 1)) { - if (ChangeRSSIThreshold(WLAN_CONFIG_FILE, atoi(splitted[1].c_str()))) + int RSSIThresholdTMP = atoi(splitted[1].c_str()); + RSSIThresholdTMP = min(0, max(-100, RSSIThresholdTMP)); // Verify input limits (-100 - 0) + + if (ChangeRSSIThreshold(WLAN_CONFIG_FILE, RSSIThresholdTMP)) { // reboot necessary so that the new wlan.ini is also used !!! fclose(pfile); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Rebooting to activate new RSSITHRESHOLD ..."); - esp_restart(); - hard_restart(); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Rebooting to activate new RSSITHRESHOLD ..."); doReboot(); } } + #endif if ((toUpper(splitted[0]) == "HOSTNAME") && (splitted.size() > 1)) { @@ -626,9 +634,7 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph) { // reboot necessary so that the new wlan.ini is also used !!! fclose(pfile); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Rebooting to activate new HOSTNAME..."); - esp_restart(); - hard_restart(); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Rebooting to activate new HOSTNAME..."); doReboot(); } } diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp index cb5d53f5..e85e3152 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp @@ -5,6 +5,7 @@ #include "ClassFlowMQTT.h" #include "Helper.h" #include "connect_wlan.h" +#include "read_wlanini.h" #include "ClassLogFile.h" #include "time_sntp.h" @@ -31,7 +32,7 @@ void ClassFlowMQTT::SetInitialParameter(void) topicError = ""; topicRate = ""; topicTimeStamp = ""; - maintopic = hostname; + maintopic = wlan_config.hostname; topicUptime = ""; topicFreeMem = ""; diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index b6151b2a..77dade32 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/code/components/jomjol_helper/Helper.cpp @@ -258,7 +258,7 @@ bool MakeDir(std::string path) break; default: - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create folder: " + path); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create folder: " + path + " (errno: " + std::to_string(errno) + ")"); bSuccess = false; break; } diff --git a/code/components/jomjol_helper/statusled.cpp b/code/components/jomjol_helper/statusled.cpp new file mode 100644 index 00000000..158e5f62 --- /dev/null +++ b/code/components/jomjol_helper/statusled.cpp @@ -0,0 +1,148 @@ +#include "statusled.h" + +#include +#include +#include "driver/gpio.h" + +#include "ClassLogFile.h" +#include "../../include/defines.h" + + +static const char* TAG = "STATUSLED"; + +TaskHandle_t xHandle_task_StatusLED = NULL; +struct StatusLEDData StatusLEDData = {}; + + +void task_StatusLED(void *pvParameter) +{ + //ESP_LOGD(TAG, "task_StatusLED - create"); + while (StatusLEDData.bProcessingRequest) + { + //ESP_LOGD(TAG, "task_StatusLED - start"); + struct StatusLEDData StatusLEDDataInt = StatusLEDData; + + gpio_pad_select_gpio(BLINK_GPIO); // Init the GPIO + gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); // Set the GPIO as a push/pull output + gpio_set_level(BLINK_GPIO, 1);// LED off + + for (int i=0; i<3; ) // Default: repeat 3 times + { + if (!StatusLEDDataInt.bInfinite) + ++i; + + for (int j = 0; j < StatusLEDDataInt.iSourceBlinkCnt; ++j) + { + gpio_set_level(BLINK_GPIO, 0); + vTaskDelay(StatusLEDDataInt.iBlinkTime / portTICK_PERIOD_MS); + gpio_set_level(BLINK_GPIO, 1); + vTaskDelay(StatusLEDDataInt.iBlinkTime / portTICK_PERIOD_MS); + } + + vTaskDelay(500 / portTICK_PERIOD_MS); // Delay between module code and error code + + for (int j = 0; j < StatusLEDDataInt.iCodeBlinkCnt; ++j) + { + gpio_set_level(BLINK_GPIO, 0); + vTaskDelay(StatusLEDDataInt.iBlinkTime / portTICK_PERIOD_MS); + gpio_set_level(BLINK_GPIO, 1); + vTaskDelay(StatusLEDDataInt.iBlinkTime / portTICK_PERIOD_MS); + } + vTaskDelay(1500 / portTICK_PERIOD_MS); // Delay to signal new round + } + + StatusLEDData.bProcessingRequest = false; + //ESP_LOGD(TAG, "task_StatusLED - done/wait"); + vTaskDelay(10000 / portTICK_PERIOD_MS); // Wait for an upcoming request otherwise continue and delete task to save memory + } + //ESP_LOGD(TAG, "task_StatusLED - delete"); + xHandle_task_StatusLED = NULL; + vTaskDelete(NULL); // Delete this task due to no request +} + + +void StatusLED(StatusLedSource _eSource, int _iCode, bool _bInfinite) +{ + //ESP_LOGD(TAG, "StatusLED - start"); + + if (_eSource == WLAN_CONN) { + StatusLEDData.iSourceBlinkCnt = WLAN_CONN; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == WLAN_INIT) { + StatusLEDData.iSourceBlinkCnt = WLAN_INIT; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == SDCARD_INIT) { + StatusLEDData.iSourceBlinkCnt = SDCARD_INIT; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == SDCARD_CHECK) { + StatusLEDData.iSourceBlinkCnt = SDCARD_CHECK; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == CAM_INIT) { + StatusLEDData.iSourceBlinkCnt = CAM_INIT; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == PSRAM_INIT) { + StatusLEDData.iSourceBlinkCnt = PSRAM_INIT; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == TIME_CHECK) { + StatusLEDData.iSourceBlinkCnt = TIME_CHECK; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 250; + StatusLEDData.bInfinite = _bInfinite; + } + else if (_eSource == AP_OR_OTA) { + StatusLEDData.iSourceBlinkCnt = AP_OR_OTA; + StatusLEDData.iCodeBlinkCnt = _iCode; + StatusLEDData.iBlinkTime = 350; + StatusLEDData.bInfinite = _bInfinite; + } + + if (xHandle_task_StatusLED && !StatusLEDData.bProcessingRequest) { + StatusLEDData.bProcessingRequest = true; + BaseType_t xReturned = xTaskAbortDelay(xHandle_task_StatusLED); // Reuse still running status LED task + /*if (xReturned == pdPASS) + ESP_LOGD(TAG, "task_StatusLED - abort waiting delay");*/ + } + else if (xHandle_task_StatusLED == NULL) { + StatusLEDData.bProcessingRequest = true; + BaseType_t xReturned = xTaskCreate(&task_StatusLED, "task_StatusLED", 1280, NULL, tskIDLE_PRIORITY+1, &xHandle_task_StatusLED); + if(xReturned != pdPASS) + { + xHandle_task_StatusLED = NULL; + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "task_StatusLED failed to create"); + LogFile.WriteHeapInfo("task_StatusLED failed"); + } + } + else { + ESP_LOGD(TAG, "task_StatusLED still processing, request skipped"); // Requests with high frequency could be skipped, but LED is only helpful for static states + } + //ESP_LOGD(TAG, "StatusLED - done"); +} + + +void StatusLEDOff(void) +{ + if (xHandle_task_StatusLED) + vTaskDelete(xHandle_task_StatusLED); // Delete task for StatusLED to force stop of blinking + + gpio_pad_select_gpio(BLINK_GPIO); // Init the GPIO + gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); // Set the GPIO as a push/pull output + gpio_set_level(BLINK_GPIO, 1);// LED off +} \ No newline at end of file diff --git a/code/components/jomjol_helper/statusled.h b/code/components/jomjol_helper/statusled.h new file mode 100644 index 00000000..e4ea2d0c --- /dev/null +++ b/code/components/jomjol_helper/statusled.h @@ -0,0 +1,34 @@ +#pragma once + +#ifndef STATUSLED_H +#define STATUSLED_H + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + + +extern TaskHandle_t xHandle_task_StatusLED; + +enum StatusLedSource { + WLAN_CONN = 1, + WLAN_INIT = 2, + SDCARD_INIT = 3, + SDCARD_CHECK = 4, + CAM_INIT = 5, + PSRAM_INIT = 6, + TIME_CHECK = 7, + AP_OR_OTA = 8 +}; + +struct StatusLEDData { + int iSourceBlinkCnt = 1; + int iCodeBlinkCnt = 1; + int iBlinkTime = 250; + bool bInfinite = false; + bool bProcessingRequest = false; +}; + +void StatusLED(StatusLedSource _eSource, int _iCode, bool _bInfinite); +void StatusLEDOff(void); + +#endif //STATUSLED_H \ No newline at end of file diff --git a/code/components/jomjol_logfile/ClassLogFile.cpp b/code/components/jomjol_logfile/ClassLogFile.cpp index e92ddbd5..d702ecc7 100644 --- a/code/components/jomjol_logfile/ClassLogFile.cpp +++ b/code/components/jomjol_logfile/ClassLogFile.cpp @@ -78,11 +78,11 @@ void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::s } -void ClassLogFile::setLogLevel(esp_log_level_t _logLevel){ - loglevel = _logLevel; - +void ClassLogFile::setLogLevel(esp_log_level_t _logLevel) +{ std::string levelText; + // Print log level to log file switch(_logLevel) { case ESP_LOG_WARN: levelText = "WARNING"; @@ -95,13 +95,16 @@ void ClassLogFile::setLogLevel(esp_log_level_t _logLevel){ case ESP_LOG_DEBUG: levelText = "DEBUG"; break; + case ESP_LOG_ERROR: default: levelText = "ERROR"; break; } + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Set log level to " + levelText); - ESP_LOGI(TAG, "Log Level set to %s", levelText.c_str()); + // set new log level + loglevel = _logLevel; /* LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Test"); @@ -386,14 +389,17 @@ void ClassLogFile::RemoveOldDataLog() } -void ClassLogFile::CreateLogDirectories() +bool ClassLogFile::CreateLogDirectories() { - MakeDir("/sdcard/log"); - MakeDir("/sdcard/log/data"); - MakeDir("/sdcard/log/analog"); - MakeDir("/sdcard/log/digit"); - MakeDir("/sdcard/log/message"); - MakeDir("/sdcard/log/source"); + bool bRetval = false; + bRetval = MakeDir("/sdcard/log"); + bRetval = MakeDir("/sdcard/log/data"); + bRetval = MakeDir("/sdcard/log/analog"); + bRetval = MakeDir("/sdcard/log/digit"); + bRetval = MakeDir("/sdcard/log/message"); + bRetval = MakeDir("/sdcard/log/source"); + + return bRetval; } diff --git a/code/components/jomjol_logfile/ClassLogFile.h b/code/components/jomjol_logfile/ClassLogFile.h index b21e8a66..b3ade1cd 100644 --- a/code/components/jomjol_logfile/ClassLogFile.h +++ b/code/components/jomjol_logfile/ClassLogFile.h @@ -35,7 +35,7 @@ public: void CloseLogFileAppendHandle(); - void CreateLogDirectories(); + bool CreateLogDirectories(); void RemoveOldLogFile(); void RemoveOldDataLog(); diff --git a/code/components/jomjol_mqtt/interface_mqtt.cpp b/code/components/jomjol_mqtt/interface_mqtt.cpp index 0118b873..fc1f328a 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.cpp +++ b/code/components/jomjol_mqtt/interface_mqtt.cpp @@ -14,6 +14,7 @@ std::map>* connectFunktionMap = NULL; std::map>* subscribeFunktionMap = NULL; int failedOnRound = -1; +int MQTTReconnectCnt = 0; esp_mqtt_event_id_t esp_mqtt_ID = MQTT_EVENT_ANY; // ESP_EVENT_ANY_ID @@ -89,29 +90,39 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { std::string topic = ""; switch (event->event_id) { case MQTT_EVENT_BEFORE_CONNECT: - ESP_LOGD(TAG, "MQTT_EVENT_BEFORE_CONNECT"); mqtt_initialized = true; break; + case MQTT_EVENT_CONNECTED: - ESP_LOGD(TAG, "MQTT_EVENT_CONNECTED"); + MQTTReconnectCnt = 0; mqtt_initialized = true; mqtt_connected = true; MQTTconnected(); break; + case MQTT_EVENT_DISCONNECTED: - ESP_LOGD(TAG, "MQTT_EVENT_DISCONNECTED"); - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Disconnected from broker"); mqtt_connected = false; + MQTTReconnectCnt++; + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected, trying to reconnect"); + + if (MQTTReconnectCnt >= 5) { + MQTTReconnectCnt = 0; + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Disconnected, multiple reconnect attempts failed, still retrying..."); + } break; + case MQTT_EVENT_SUBSCRIBED: ESP_LOGD(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); break; + case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGD(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); break; + case MQTT_EVENT_PUBLISHED: ESP_LOGD(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); break; + case MQTT_EVENT_DATA: ESP_LOGD(TAG, "MQTT_EVENT_DATA"); ESP_LOGD(TAG, "TOPIC=%.*s", event->topic_len, event->topic); @@ -126,6 +137,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { ESP_LOGW(TAG, "no handler available\r\n"); } break; + case MQTT_EVENT_ERROR: #ifdef DEBUG_DETAIL_ON ESP_LOGD(TAG, "MQTT_EVENT_ERROR - esp_mqtt_error_codes:"); @@ -136,8 +148,9 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { ESP_LOGD(TAG, "esp_tls_stack_err:%d", event->error_handle->esp_tls_stack_err); ESP_LOGD(TAG, "esp_tls_cert_verify_flags:%d", event->error_handle->esp_tls_cert_verify_flags); #endif - mqtt_connected = false; + //mqtt_connected = false; break; + default: ESP_LOGD(TAG, "Other event id:%d", event->event_id); break; diff --git a/code/components/jomjol_mqtt/server_mqtt.cpp b/code/components/jomjol_mqtt/server_mqtt.cpp index a10ebce6..7a34a68c 100644 --- a/code/components/jomjol_mqtt/server_mqtt.cpp +++ b/code/components/jomjol_mqtt/server_mqtt.cpp @@ -7,6 +7,7 @@ #include "esp_log.h" #include "ClassLogFile.h" #include "connect_wlan.h" +#include "read_wlanini.h" #include "server_mqtt.h" #include "interface_mqtt.h" #include "time_sntp.h" @@ -201,7 +202,7 @@ void publishStaticData() { LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing static MQTT topics..."); MQTTPublish(maintopic + "/" + "MAC", getMac(), retainFlag); MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), retainFlag); - MQTTPublish(maintopic + "/" + "hostname", hostname, retainFlag); + MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, retainFlag); std::stringstream stream; stream << std::fixed << std::setprecision(1) << roundInterval; // minutes diff --git a/code/components/jomjol_tfliteclass/server_tflite.cpp b/code/components/jomjol_tfliteclass/server_tflite.cpp index f4c00227..f937a68d 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.cpp +++ b/code/components/jomjol_tfliteclass/server_tflite.cpp @@ -10,6 +10,7 @@ #include "../../include/defines.h" #include "Helper.h" +#include "statusled.h" #include "esp_camera.h" #include "time_sntp.h" @@ -21,8 +22,11 @@ #include "server_GPIO.h" #include "server_file.h" + +#include "read_wlanini.h" #include "connect_wlan.h" + ClassFlowControll tfliteflow; TaskHandle_t xHandletask_autodoFlow = NULL; @@ -44,20 +48,24 @@ static const char *TAG = "TFLITE SERVER"; void CheckIsPlannedReboot() { FILE *pfile; - if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Not a planned reboot."); + if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) { + //LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Initial boot or not a planned reboot"); isPlannedReboot = false; } - else - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot."); + else { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot"); DeleteFile("/sdcard/reboot.txt"); // Prevent Boot Loop!!! isPlannedReboot = true; } } +bool getIsPlannedReboot() +{ + return isPlannedReboot; +} + + int getCountFlowRounds() { return countRounds; @@ -837,21 +845,15 @@ void task_autodoFlow(void *pvParameter) bTaskAutoFlowCreated = true; - if (!isPlannedReboot) + if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC)) { - if (esp_reset_reason() == ESP_RST_PANIC) { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Restarted due to an Exception/panic! Postponing first round start by 5 minutes to allow for an OTA Update or to fetch the log!"); - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Setting logfile level to DEBUG until the next reboot!"); - LogFile.setLogLevel(ESP_LOG_DEBUG); - tfliteflow.setActStatus("Initialization (delayed)"); - //#ifdef ENABLE_MQTT - //MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later - //#endif //ENABLE_MQTT - vTaskDelay(60*5000 / portTICK_RATE_MS); // Wait 5 minutes to give time to do an OTA Update or fetch the log - } + tfliteflow.setActStatus("Initialization (delayed)"); + //#ifdef ENABLE_MQTT + //MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later + //#endif //ENABLE_MQTT + vTaskDelay(60*5000 / portTICK_PERIOD_MS); // Wait 5 minutes to give time to do an OTA update or fetch the log } - ESP_LOGD(TAG, "task_autodoFlow: start"); doInit(); @@ -891,16 +893,22 @@ void task_autodoFlow(void *pvParameter) LogFile.RemoveOldLogFile(); LogFile.RemoveOldDataLog(); } + + //Round finished -> Logfile + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) + + " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)"); //CPU Temp -> Logfile LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C"); // WIFI Signal Strength (RSSI) -> Logfile LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm"); - - //Round finished -> Logfile - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) + - " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)"); + + // Check if time is synchronized (if NTP is configured) + if (getUseNtp() && !getTimeIsSet()) { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time server is configured, but time is not yet set. Check configuration"); + StatusLED(TIME_CHECK, 1, false); + } fr_delta_ms = (esp_timer_get_time() - fr_start) / 1000; if (auto_interval > fr_delta_ms) diff --git a/code/components/jomjol_tfliteclass/server_tflite.h b/code/components/jomjol_tfliteclass/server_tflite.h index d857946e..91aa1075 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.h +++ b/code/components/jomjol_tfliteclass/server_tflite.h @@ -21,6 +21,7 @@ bool isSetupModusActive(); int getCountFlowRounds(); void CheckIsPlannedReboot(); +bool getIsPlannedReboot(); esp_err_t GetJPG(std::string _filename, httpd_req_t *req); esp_err_t GetRawJPG(httpd_req_t *req); diff --git a/code/components/jomjol_wlan/connect_wlan.cpp b/code/components/jomjol_wlan/connect_wlan.cpp index eee58d5f..414f4e48 100644 --- a/code/components/jomjol_wlan/connect_wlan.cpp +++ b/code/components/jomjol_wlan/connect_wlan.cpp @@ -1,12 +1,24 @@ #include "connect_wlan.h" #include +#include +#include +#include +#include +#include + #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" + #include "driver/gpio.h" #include "esp_system.h" #include "esp_wifi.h" +#include "esp_wnm.h" +#include "esp_rrm.h" +#include "esp_mbo.h" +#include "esp_mac.h" +#include "esp_netif.h" #include "esp_event.h" #include "esp_log.h" #include "nvs_flash.h" @@ -17,56 +29,20 @@ #include "interface_mqtt.h" #endif //ENABLE_MQTT -#include -#include -#include -#include -#include +#include "ClassLogFile.h" +#include "read_wlanini.h" +#include "Helper.h" +#include "statusled.h" -////////////////////// -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include "esp_wifi.h" -#include "esp_wnm.h" -#include "esp_rrm.h" -#include "esp_mbo.h" -#include "esp_event.h" -#include "esp_log.h" -#include "esp_mac.h" -#include "nvs_flash.h" -#include "esp_netif.h" - - -///////////////////// #include "../../include/defines.h" -/* FreeRTOS event group to signal when we are connected*/ -static EventGroupHandle_t s_wifi_event_group; - static const char *TAG = "WIFI"; -static int s_retry_num = 0; + bool WIFIConnected = false; +int WIFIReconnectCnt = 0; -/////////////////////////////////////////////////////////// - -int BlinkDauer; -int BlinkAnzahl; -bool BlinkOff; -bool BlinkIsRunning = false; - -std::string hostname = ""; -std::string std_hostname = "watermeter"; -std::string ipadress = ""; -std::string ssid = ""; -int RSSIThreshold; - -///////////////////////////////// -///////////////////////////////// #ifdef WLAN_USE_MESH_ROAMING @@ -301,97 +277,87 @@ static void esp_bss_rssi_low_handler(void* arg, esp_event_base_t event_base, std::string* getIPAddress() { - return &ipadress; + return &wlan_config.ipaddress; } std::string* getSSID() { - return &ssid; + return &wlan_config.ssid; } -void task_doBlink(void *pvParameter) +static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { - ESP_LOGI("BLINK", "Flash - start"); - while (BlinkIsRunning) - { -// ESP_LOGI("BLINK", "Blinken - wait"); - vTaskDelay(100 / portTICK_PERIOD_MS); - } - - BlinkIsRunning = true; - - // Init the GPIO - gpio_pad_select_gpio(BLINK_GPIO); - /* Set the GPIO as a push/pull output */ - gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); - - for (int i = 0; i < BlinkAnzahl; ++i) - { - if (BlinkAnzahl > 1) - { - gpio_set_level(BLINK_GPIO, 1); - vTaskDelay(BlinkDauer / portTICK_PERIOD_MS); - } - gpio_set_level(BLINK_GPIO, 0); - vTaskDelay(BlinkDauer / portTICK_PERIOD_MS); - } - - if (BlinkOff) - gpio_set_level(BLINK_GPIO, 1); - - ESP_LOGI("BLINK", "Flash - done"); - BlinkIsRunning = false; - - vTaskDelete(NULL); //Delete this task if it exits from the loop above -} - - -void LEDBlinkTask(int _dauer, int _anz, bool _off) -{ - BlinkDauer = _dauer; - BlinkAnzahl = _anz; - BlinkOff = _off; - - xTaskCreate(&task_doBlink, "task_doBlink", 4 * 1024, NULL, tskIDLE_PRIORITY+1, NULL); -} -///////////////////////////////////////////////////////// - - -static void event_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { WIFIConnected = false; - LEDBlinkTask(200, 1, true); esp_wifi_connect(); - } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - WIFIConnected = false; -// if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { - esp_wifi_connect(); - s_retry_num++; - ESP_LOGI(TAG, "retrying connection to the AP"); -// } else { -// xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); -// } - ESP_LOGI(TAG,"connection to the AP failed"); - } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); - ipadress = std::string(ip4addr_ntoa((const ip4_addr*) &event->ip_info.ip)); - s_retry_num = 0; - xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); - LEDBlinkTask(1000, 5, true); + } + + else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + /* Disconnect reason: https://github.com/espressif/esp-idf/blob/d825753387c1a64463779bbd2369e177e5d59a79/components/esp_wifi/include/esp_wifi_types.h */ + wifi_event_sta_disconnected_t *disconn = (wifi_event_sta_disconnected_t *)event_data; + if (disconn->reason == WIFI_REASON_ROAMING) { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected (" + std::to_string(disconn->reason) + ", Roaming)"); + // --> no reconnect neccessary, it should automatically reconnect to new AP + } + else { + WIFIConnected = false; + if (disconn->reason == WIFI_REASON_NO_AP_FOUND) { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected (" + std::to_string(disconn->reason) + ", No AP)"); + StatusLED(WLAN_CONN, 1, false); + } + else if (disconn->reason == WIFI_REASON_AUTH_EXPIRE || + disconn->reason == WIFI_REASON_AUTH_FAIL || + disconn->reason == WIFI_REASON_NOT_AUTHED || + disconn->reason == WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT || + disconn->reason == WIFI_REASON_HANDSHAKE_TIMEOUT) { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected (" + std::to_string(disconn->reason) + ", Auth fail)"); + StatusLED(WLAN_CONN, 2, false); + } + else if (disconn->reason == WIFI_REASON_BEACON_TIMEOUT) { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected (" + std::to_string(disconn->reason) + ", Timeout)"); + StatusLED(WLAN_CONN, 3, false); + } + else { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected (" + std::to_string(disconn->reason) + ")"); + StatusLED(WLAN_CONN, 4, false); + } + WIFIReconnectCnt++; + esp_wifi_connect(); // Try to connect again + } + if (WIFIReconnectCnt >= 10) { + WIFIReconnectCnt = 0; + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Disconnected, multiple reconnect attempts failed (" + + std::to_string(disconn->reason) + "), still retrying..."); + } + } + + else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to: " + wlan_config.ssid + ", RSSI: " + + std::to_string(get_WIFI_RSSI())); + } + + else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { WIFIConnected = true; - #ifdef ENABLE_MQTT + WIFIReconnectCnt = 0; + + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + wlan_config.ipaddress = std::string(ip4addr_ntoa((const ip4_addr*) &event->ip_info.ip)); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Got IP: " + wlan_config.ipaddress); + + #ifdef ENABLE_MQTT if (getMQTTisEnabled()) { vTaskDelay(5000 / portTICK_PERIOD_MS); MQTT_Init(); // Init when WIFI is getting connected } - #endif //ENABLE_MQTT - } + #endif //ENABLE_MQTT + } } @@ -403,148 +369,148 @@ void strinttoip4(const char *ip, int &a, int &b, int &c, int &d) { } -void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname, const char *_ipadr, const char *_gw, const char *_netmask, const char *_dns, int _rssithreshold) +esp_err_t wifi_init_sta(void) { - RSSI_Threshold = _rssithreshold; - s_wifi_event_group = xEventGroupCreate(); + esp_err_t retval = esp_netif_init(); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_netif_init: Error: " + std::to_string(retval)); + return retval; + } - ESP_ERROR_CHECK(esp_netif_init()); - - ESP_ERROR_CHECK(esp_event_loop_create_default()); + retval = esp_event_loop_create_default(); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_event_loop_create_default: Error: " + std::to_string(retval)); + return retval; + } + esp_netif_t *my_sta = esp_netif_create_default_wifi_sta(); - if ((_ipadr != NULL) && (_gw != NULL) && (_netmask != NULL)) + if (!wlan_config.ipaddress.empty() && !wlan_config.gateway.empty() && !wlan_config.netmask.empty()) { - - ESP_LOGI(TAG, "set IP %s, GW %s, Netmask %s manual", _ipadr, _gw, _netmask); - esp_netif_dhcpc_stop(my_sta); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Manual interface config -> IP: " + wlan_config.ipaddress + ", Gateway: " + + std::string(wlan_config.gateway) + ", Netmask: " + std::string(wlan_config.netmask)); + esp_netif_dhcpc_stop(my_sta); // Stop DHCP service esp_netif_ip_info_t ip_info; int a, b, c, d; - strinttoip4(_ipadr, a, b, c, d); - IP4_ADDR(&ip_info.ip, a, b, c, d); - strinttoip4(_gw, a, b, c, d); - IP4_ADDR(&ip_info.gw, a, b, c, d); - strinttoip4(_netmask, a, b, c, d); - IP4_ADDR(&ip_info.netmask, a, b, c, d); + strinttoip4(wlan_config.ipaddress.c_str(), a, b, c, d); + IP4_ADDR(&ip_info.ip, a, b, c, d); // Set static IP address - esp_netif_set_ip_info(my_sta, &ip_info); + strinttoip4(wlan_config.gateway.c_str(), a, b, c, d); + IP4_ADDR(&ip_info.gw, a, b, c, d); // Set gateway + + strinttoip4(wlan_config.netmask.c_str(), a, b, c, d); + IP4_ADDR(&ip_info.netmask, a, b, c, d); // Set netmask + + esp_netif_set_ip_info(my_sta, &ip_info); // Set static IP configuration } + else { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Automatic interface config --> Use DHCP service"); + } - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + retval = esp_wifi_init(&cfg); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_wifi_init: Error: " + std::to_string(retval)); + return retval; + } - if ((_ipadr != NULL) && (_gw != NULL) && (_netmask != NULL)) + if (!wlan_config.ipaddress.empty() && !wlan_config.gateway.empty() && !wlan_config.netmask.empty()) { - if (_dns == NULL) - _dns = _gw; - - ESP_LOGI(TAG, "set DNS manual"); + if (wlan_config.dns.empty()) { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "No DNS server, use gateway"); + wlan_config.dns = wlan_config.gateway; + } + else { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Manual interface config -> DNS: " + wlan_config.dns); + } + esp_netif_dns_info_t dns_info; ip4_addr_t ip; - ip.addr = esp_ip4addr_aton(_dns); + ip.addr = esp_ip4addr_aton(wlan_config.dns.c_str()); ip_addr_set_ip4_u32(&dns_info.ip, ip.addr); - ESP_ERROR_CHECK(esp_netif_set_dns_info(my_sta, ESP_NETIF_DNS_MAIN, &dns_info)); - } - esp_event_handler_instance_t instance_any_id; - esp_event_handler_instance_t instance_got_ip; - esp_event_handler_instance_t instance_bss_rssi_low; - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - ESP_EVENT_ANY_ID, - &event_handler, - NULL, - &instance_any_id)); - ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, - IP_EVENT_STA_GOT_IP, - &event_handler, - NULL, - &instance_got_ip)); + retval = esp_netif_set_dns_info(my_sta, ESP_NETIF_DNS_MAIN, &dns_info); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_netif_set_dns_info: Error: " + std::to_string(retval)); + return retval; + } + } + + retval = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, + &event_handler, NULL, NULL); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_event_handler_instance_register - WIFI_ANY: Error: " + std::to_string(retval)); + return retval; + } + + retval = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, + &event_handler, NULL, NULL); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_event_handler_instance_register - GOT_IP: Error: " + std::to_string(retval)); + return retval; + } #ifdef WLAN_USE_MESH_ROAMING - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - WIFI_EVENT_STA_BSS_RSSI_LOW, - &esp_bss_rssi_low_handler, - NULL, - &instance_bss_rssi_low)); + retval = esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_BSS_RSSI_LOW, + &esp_bss_rssi_low_handler, NULL, NULL); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_event_handler_instance_register - BSS_RSSI_LOW: Error: " + std::to_string(retval)); + return retval; + } #endif wifi_config_t wifi_config = { }; - strcpy((char*)wifi_config.sta.ssid, (const char*)_ssid); - strcpy((char*)wifi_config.sta.password, (const char*)_password); + strcpy((char*)wifi_config.sta.ssid, (const char*)wlan_config.ssid.c_str()); + strcpy((char*)wifi_config.sta.password, (const char*)wlan_config.password.c_str()); - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); - ESP_ERROR_CHECK(esp_wifi_start() ); + retval = esp_wifi_set_mode(WIFI_MODE_STA); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_wifi_set_mode: Error: " + std::to_string(retval)); + return retval; + } - if (_hostname != NULL) + retval = esp_wifi_set_config(WIFI_IF_STA, &wifi_config); + if (retval != ESP_OK) { + if (retval == ESP_ERR_WIFI_PASSWORD) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_wifi_set_config: SSID password invalid! Error: " + std::to_string(retval)); + } + else { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_wifi_set_config: Error: " + std::to_string(retval)); + } + return retval; + } + + retval = esp_wifi_start(); + if (retval != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_wifi_start: Error: " + std::to_string(retval)); + return retval; + } + + if (!wlan_config.hostname.empty()) { - esp_err_t ret = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA , _hostname); - hostname = std::string(_hostname); - if(ret != ESP_OK ){ - ESP_LOGE(TAG,"Failed to set hostname: %d",ret); + retval = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA , wlan_config.hostname.c_str()); + if(retval != ESP_OK ) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to set hostname! Error: " + std::to_string(retval)); } else { - ESP_LOGI(TAG,"Set hostname to: %s", _hostname); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Set hostname to: " + wlan_config.hostname); } - } - ESP_LOGI(TAG, "wifi_init_sta finished."); - - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum - * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - - /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually - * happened. */ - if (bits & WIFI_CONNECTED_BIT) { - #ifdef __HIDE_PASSWORD - ESP_LOGI(TAG, "Connected with AP: %s, password: XXXXXXX", _ssid); - #else - ESP_LOGI(TAG, "Connected with AP: %s, password: %s", _ssid, _password); - #endif - } else if (bits & WIFI_FAIL_BIT) { - #ifdef __HIDE_PASSWORD - ESP_LOGI(TAG, "Failed to connect with AP: %s, password: XXXXXXXX", _ssid); - #else - ESP_LOGI(TAG, "Failed to connect with AP: %s, password: %s", _ssid, _password); - #endif - } else { - ESP_LOGE(TAG, "UNEXPECTED EVENT"); - } - ssid = std::string(_ssid); - - - /* The event will not be processed after unregister */ -// ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip)); -// ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); -// vEventGroupDelete(s_wifi_event_group); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Init successful"); + return ESP_OK; } int get_WIFI_RSSI() { - wifi_ap_record_t ap; - esp_wifi_sta_get_ap_info(&ap); - return ap.rssi; -} - - -void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname) -{ - wifi_init_sta(_ssid, _password, _hostname, NULL, NULL, NULL, NULL, 0); -} - - -void wifi_init_sta(const char *_ssid, const char *_password) -{ - wifi_init_sta(_ssid, _password, NULL, NULL, NULL, NULL, NULL, 0); + wifi_ap_record_t ap; + if (esp_wifi_sta_get_ap_info(&ap) == ESP_OK) + return ap.rssi; + else + return -127; // Return -127 if no info available e.g. not connected } @@ -556,14 +522,13 @@ bool getWIFIisConnected() void WIFIDestroy() { - esp_wifi_disconnect(); - esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler); esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler); #ifdef WLAN_USE_MESH_ROAMING esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_BSS_RSSI_LOW, esp_bss_rssi_low_handler); #endif - + + esp_wifi_disconnect(); esp_wifi_stop(); esp_wifi_deinit(); } diff --git a/code/components/jomjol_wlan/connect_wlan.h b/code/components/jomjol_wlan/connect_wlan.h index b0c8bc38..c5374f8f 100644 --- a/code/components/jomjol_wlan/connect_wlan.h +++ b/code/components/jomjol_wlan/connect_wlan.h @@ -5,18 +5,11 @@ #include -void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname, const char *_ipadr, const char *_gw, const char *_netmask, const char *_dns, int _rssithreshold); -void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname); -void wifi_init_sta(const char *_ssid, const char *_password); - +int wifi_init_sta(void); std::string* getIPAddress(); std::string* getSSID(); int get_WIFI_RSSI(); bool getWIFIisConnected(); void WIFIDestroy(); -extern std::string hostname; -extern std::string std_hostname; -extern int RSSIThreshold; - #endif //CONNECT_WLAN_H \ No newline at end of file diff --git a/code/components/jomjol_wlan/read_wlanini.cpp b/code/components/jomjol_wlan/read_wlanini.cpp index 0cb21adf..1e489460 100644 --- a/code/components/jomjol_wlan/read_wlanini.cpp +++ b/code/components/jomjol_wlan/read_wlanini.cpp @@ -11,9 +11,14 @@ #include #include #include "esp_log.h" +#include "ClassLogFile.h" #include "../../include/defines.h" -static const char *TAG = "WLAN.INI"; +static const char *TAG = "WLANINI"; + + +struct wlan_config wlan_config = {}; + std::vector ZerlegeZeileWLAN(std::string input, std::string _delimiter = "") { @@ -40,207 +45,189 @@ std::vector ZerlegeZeileWLAN(std::string input, std::string _delimiter = } - -bool LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_hostname, char *&_ipadr, char *&_gw, char *&_netmask, char *&_dns, int &_rssithreshold) +int LoadWlanFromFile(std::string fn) { - std::string ssid = ""; - std::string passphrase = ""; - std::string ipaddress = ""; - std::string gw = ""; - std::string netmask = ""; - std::string dns = ""; - int rssithreshold = 0; - std::string line = ""; + std::string tmp = ""; std::vector splitted; - hostname = std_hostname; - FILE* pFile; fn = FormatFileName(fn); + FILE* pFile = fopen(fn.c_str(), "r"); + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to open file (read). Device init aborted!"); + return -1; + } - pFile = fopen(fn.c_str(), "r"); - if (!pFile) - return false; + ESP_LOGD(TAG, "LoadWlanFromFile: wlan.ini opened"); - ESP_LOGD(TAG, "file loaded"); - - if (pFile == NULL) - return false; - - char zw[1024]; - fgets(zw, 1024, pFile); - line = std::string(zw); + char zw[256]; + if (fgets(zw, sizeof(zw), pFile) == NULL) { + line = ""; + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "file opened, but empty or content not readable. Device init aborted!"); + fclose(pFile); + return -1; + } + else { + line = std::string(zw); + } while ((line.size() > 0) || !(feof(pFile))) { -// ESP_LOGD(TAG, "%s", line.c_str()); - splitted = ZerlegeZeileWLAN(line, "="); - splitted[0] = trim(splitted[0], " "); + //ESP_LOGD(TAG, "line: %s", line.c_str()); + if (line[0] != ';') { // Skip lines which starts with ';' - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HOSTNAME")){ - hostname = trim(splitted[1]); - if ((hostname[0] == '"') && (hostname[hostname.length()-1] == '"')){ - hostname = hostname.substr(1, hostname.length()-2); + splitted = ZerlegeZeileWLAN(line, "="); + splitted[0] = trim(splitted[0], " "); + + if ((splitted.size() > 1) && (toUpper(splitted[0]) == "SSID")){ + tmp = trim(splitted[1]); + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.ssid = tmp; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "SSID: " + wlan_config.ssid); } + + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "PASSWORD")){ + tmp = splitted[1]; + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.password = tmp; + #ifndef __HIDE_PASSWORD + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Password: " + wlan_config.password); + #else + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Password: XXXXXXXX"); + #endif + } + + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HOSTNAME")){ + tmp = trim(splitted[1]); + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.hostname = tmp; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Hostname: " + wlan_config.hostname); + } + + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "IP")){ + tmp = splitted[1]; + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.ipaddress = tmp; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "IP-Address: " + wlan_config.ipaddress); + } + + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "GATEWAY")){ + tmp = splitted[1]; + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.gateway = tmp; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Gateway: " + wlan_config.gateway); + } + + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "NETMASK")){ + tmp = splitted[1]; + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.netmask = tmp; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Netmask: " + wlan_config.netmask); + } + + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "DNS")){ + tmp = splitted[1]; + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.dns = tmp; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "DNS: " + wlan_config.dns); + } + #ifdef WLAN_USE_MESH_ROAMING + else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHRESHOLD")) { + tmp = trim(splitted[1]); + if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){ + tmp = tmp.substr(1, tmp.length()-2); + } + wlan_config.rssi_threshold = atoi(tmp.c_str()); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "RSSIThreshold: " + std::to_string(wlan_config.rssi_threshold)); + } + #endif } - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "SSID")){ - ssid = trim(splitted[1]); - if ((ssid[0] == '"') && (ssid[ssid.length()-1] == '"')){ - ssid = ssid.substr(1, ssid.length()-2); - } - } - - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHRESHOLD")){ - string _s = trim(splitted[1]); - if ((_s[0] == '"') && (_s[_s.length()-1] == '"')){ - _s = _s.substr(1, ssid.length()-2); - } - rssithreshold = atoi(_s.c_str()); - } - - - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "PASSWORD")){ - passphrase = splitted[1]; - if ((passphrase[0] == '"') && (passphrase[passphrase.length()-1] == '"')){ - passphrase = passphrase.substr(1, passphrase.length()-2); - } - } - - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "IP")){ - ipaddress = splitted[1]; - if ((ipaddress[0] == '"') && (ipaddress[ipaddress.length()-1] == '"')){ - ipaddress = ipaddress.substr(1, ipaddress.length()-2); - } - } - - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "GATEWAY")){ - gw = splitted[1]; - if ((gw[0] == '"') && (gw[gw.length()-1] == '"')){ - gw = gw.substr(1, gw.length()-2); - } - } - - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "NETMASK")){ - netmask = splitted[1]; - if ((netmask[0] == '"') && (netmask[netmask.length()-1] == '"')){ - netmask = netmask.substr(1, netmask.length()-2); - } - } - - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "DNS")){ - dns = splitted[1]; - if ((dns[0] == '"') && (dns[dns.length()-1] == '"')){ - dns = dns.substr(1, dns.length()-2); - } - } - - - if (fgets(zw, 1024, pFile) == NULL) - { + /* read next line */ + if (fgets(zw, sizeof(zw), pFile) == NULL) { line = ""; } - else - { + else { line = std::string(zw); } } - fclose(pFile); - // Check if Hostname was empty in .ini if yes set to std_hostname - if(hostname.length() == 0){ - hostname = std_hostname; + /* Check if SSID is empty (mandatory parameter) */ + if (wlan_config.ssid.empty()) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SSID empty. Device init aborted!"); + return -2; } - _hostname = new char[hostname.length() + 1]; - strcpy(_hostname, hostname.c_str()); - - _ssid = new char[ssid.length() + 1]; - strcpy(_ssid, ssid.c_str()); - - _password = new char[passphrase.length() + 1]; - strcpy(_password, passphrase.c_str()); - - if (ipaddress.length() > 0) - { - _ipadr = new char[ipaddress.length() + 1]; - strcpy(_ipadr, ipaddress.c_str()); + /* Check if password is empty (mandatory parameter) */ + if (wlan_config.password.empty()) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Password empty. Device init aborted!"); + return -2; } - else - _ipadr = NULL; - if (gw.length() > 0) - { - _gw = new char[gw.length() + 1]; - strcpy(_gw, gw.c_str()); - } - else - _gw = NULL; - - if (netmask.length() > 0) - { - _netmask = new char[netmask.length() + 1]; - strcpy(_netmask, netmask.c_str()); - } - else - _netmask = NULL; - - if (dns.length() > 0) - { - _dns = new char[dns.length() + 1]; - strcpy(_dns, dns.c_str()); - } - else - _dns = NULL; - - _rssithreshold = rssithreshold; - RSSIThreshold = rssithreshold; - return true; + return 0; } - - bool ChangeHostName(std::string fn, std::string _newhostname) { - if (_newhostname == hostname) + if (_newhostname == wlan_config.hostname) return false; - string line = ""; + std::string line = ""; std::vector splitted; - + std::vector neuesfile; bool found = false; - std::vector neuesfile; + FILE* pFile = NULL; - FILE* pFile; fn = FormatFileName(fn); pFile = fopen(fn.c_str(), "r"); - - ESP_LOGD(TAG, "file loaded\n"); - - if (pFile == NULL) + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ChangeHostName: Unable to open file wlan.ini (read)"); return false; + } - char zw[1024]; - fgets(zw, 1024, pFile); - line = std::string(zw); + ESP_LOGD(TAG, "ChangeHostName: wlan.ini opened"); + + char zw[256]; + if (fgets(zw, sizeof(zw), pFile) == NULL) { + line = ""; + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ChangeHostName: File opened, but empty or content not readable"); + return false; + } + else { + line = std::string(zw); + } while ((line.size() > 0) || !(feof(pFile))) { - ESP_LOGD(TAG, "%s", line.c_str()); + //ESP_LOGD(TAG, "ChangeHostName: line: %s", line.c_str()); splitted = ZerlegeZeileWLAN(line, "="); splitted[0] = trim(splitted[0], " "); - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HOSTNAME")){ + if ((splitted.size() > 1) && ((toUpper(splitted[0]) == "HOSTNAME") || (toUpper(splitted[0]) == ";HOSTNAME"))){ line = "hostname = \"" + _newhostname + "\"\n"; found = true; } neuesfile.push_back(line); - if (fgets(zw, 1024, pFile) == NULL) + if (fgets(zw, sizeof(zw), pFile) == NULL) { line = ""; } @@ -252,52 +239,64 @@ bool ChangeHostName(std::string fn, std::string _newhostname) if (!found) { - line = "\nhostname = \"" + _newhostname + "\"\n"; + line = "\n;++++++++++++++++++++++++++++++++++\n"; + line += "; Hostname: Name of device in network\n"; + line += "; This parameter can be configured via WebUI configuration\n"; + line += "; Default: \"watermeter\", if nothing is configured\n\n"; + line = "hostname = \"" + _newhostname + "\"\n"; neuesfile.push_back(line); } - fclose(pFile); pFile = fopen(fn.c_str(), "w+"); + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ChangeHostName: Unable to open file wlan.ini (write)"); + return false; + } for (int i = 0; i < neuesfile.size(); ++i) { - ESP_LOGD(TAG, "%s", neuesfile[i].c_str()); + //ESP_LOGD(TAG, "%s", neuesfile[i].c_str()); fputs(neuesfile[i].c_str(), pFile); } - fclose(pFile); - ESP_LOGD(TAG, "*** Hostname update done ***"); + ESP_LOGD(TAG, "ChangeHostName done"); return true; } - +#ifdef WLAN_USE_MESH_ROAMING bool ChangeRSSIThreshold(std::string fn, int _newrssithreshold) { - if (RSSIThreshold == _newrssithreshold) + if (wlan_config.rssi_threshold == _newrssithreshold) return false; - string line = ""; + std::string line = ""; std::vector splitted; - + std::vector neuesfile; bool found = false; - std::vector neuesfile; + FILE* pFile = NULL; - FILE* pFile; fn = FormatFileName(fn); pFile = fopen(fn.c_str(), "r"); - - ESP_LOGD(TAG, "file loaded\n"); - - if (pFile == NULL) + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ChangeRSSIThreshold: Unable to open file wlan.ini (read)"); return false; + } - char zw[1024]; - fgets(zw, 1024, pFile); - line = std::string(zw); + ESP_LOGD(TAG, "ChangeRSSIThreshold: wlan.ini opened"); + + char zw[256]; + if (fgets(zw, sizeof(zw), pFile) == NULL) { + line = ""; + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ChangeRSSIThreshold: File opened, but empty or content not readable"); + return false; + } + else { + line = std::string(zw); + } while ((line.size() > 0) || !(feof(pFile))) { @@ -305,43 +304,68 @@ bool ChangeRSSIThreshold(std::string fn, int _newrssithreshold) splitted = ZerlegeZeileWLAN(line, "="); splitted[0] = trim(splitted[0], " "); - if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHRESHOLD")){ + /* Workaround to eliminate line with typo "RSSIThreashold" or "rssi" if existing */ + if (((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHREASHOLD")) || + ((splitted.size() > 1) && (toUpper(splitted[0]) == ";RSSITHREASHOLD")) || + ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSI")) || + ((splitted.size() > 1) && (toUpper(splitted[0]) == ";RSSI"))) { + if (fgets(zw, sizeof(zw), pFile) == NULL) { + line = ""; + } + else { + line = std::string(zw); + } + continue; + } + + if ((splitted.size() > 1) && ((toUpper(splitted[0]) == "RSSITHRESHOLD") || (toUpper(splitted[0]) == ";RSSITHRESHOLD"))) { line = "RSSIThreshold = " + to_string(_newrssithreshold) + "\n"; found = true; } - + neuesfile.push_back(line); - - if (fgets(zw, 1024, pFile) == NULL) - { + + if (fgets(zw, sizeof(zw), pFile) == NULL) { line = ""; } - else - { + else { line = std::string(zw); } } if (!found) { - line = "RSSIThreshold = " + to_string(_newrssithreshold) + "\n"; + line = "\n;++++++++++++++++++++++++++++++++++\n"; + line += "; WIFI Roaming:\n"; + line += "; Network assisted roaming protocol is activated by default\n"; + line += "; AP / mesh system needs to support roaming protocol 802.11k/v\n"; + line += ";\n"; + line += "; Optional feature (usually not neccessary):\n"; + line += "; RSSI Threshold for client requested roaming query (RSSI < RSSIThreshold)\n"; + line += "; Note: This parameter can be configured via WebUI configuration\n"; + line += "; Default: 0 = Disable client requested roaming query\n\n"; + line += "RSSIThreshold = " + to_string(_newrssithreshold) + "\n"; neuesfile.push_back(line); } fclose(pFile); pFile = fopen(fn.c_str(), "w+"); + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ChangeRSSIThreshold: Unable to open file wlan.ini (write)"); + return false; + } for (int i = 0; i < neuesfile.size(); ++i) { - ESP_LOGD(TAG, "%s", neuesfile[i].c_str()); + //ESP_LOGD(TAG, "%s", neuesfile[i].c_str()); fputs(neuesfile[i].c_str(), pFile); } fclose(pFile); - ESP_LOGD(TAG, "*** RSSIThreshold update done ***"); + ESP_LOGD(TAG, "ChangeRSSIThreshold done"); return true; } - +#endif diff --git a/code/components/jomjol_wlan/read_wlanini.h b/code/components/jomjol_wlan/read_wlanini.h index 8f2121ed..6a31490f 100644 --- a/code/components/jomjol_wlan/read_wlanini.h +++ b/code/components/jomjol_wlan/read_wlanini.h @@ -5,8 +5,20 @@ #include -bool LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_hostname, char *&_ipadr, char *&_gw, char *&_netmask, char *&_dns, int &_rssithreshold); +struct wlan_config { + std::string ssid = ""; + std::string password = ""; + std::string hostname = "watermeter"; // Default: watermeter + std::string ipaddress = ""; + std::string gateway = ""; + std::string netmask = ""; + std::string dns = ""; + int rssi_threshold = 0; // Default: 0 -> ROAMING disabled +}; +extern struct wlan_config wlan_config; + +int LoadWlanFromFile(std::string fn); bool ChangeHostName(std::string fn, std::string _newhostname); bool ChangeRSSIThreshold(std::string fn, int _newrssithreshold); diff --git a/code/include/defines.h b/code/include/defines.h index 4fd8a4e1..0da3c8d4 100644 --- a/code/include/defines.h +++ b/code/include/defines.h @@ -62,7 +62,7 @@ #define FLASH_GPIO GPIO_NUM_4 #define BLINK_GPIO GPIO_NUM_33 - //ClassFlowMQTT + interface_mqtt + connect_wlan + main + //interface_mqtt + read_wlanini #define __HIDE_PASSWORD //ClassControllCamera @@ -164,12 +164,7 @@ //connect_wlan #define WLAN_USE_MESH_ROAMING #define WLAN_WIFI_RSSI_THRESHOLD -50 - #define EXAMPLE_ESP_MAXIMUM_RETRY 1000 - /* The event group allows multiple bits for each event, but we only care about two events: - * - we are connected to the AP with an IP - * - we failed to connect after the maximum amount of retries */ - #define WIFI_CONNECTED_BIT BIT0 - #define WIFI_FAIL_BIT BIT1 + //ClassFlowCNNGeneral #define Analog_error 3 diff --git a/code/main/main.cpp b/code/main/main.cpp index a5794ba6..622b2ad8 100644 --- a/code/main/main.cpp +++ b/code/main/main.cpp @@ -40,7 +40,9 @@ #ifdef ENABLE_MQTT #include "server_mqtt.h" #endif //ENABLE_MQTT -//#include "Helper.h" +#include "Helper.h" +#include "statusled.h" + #include "../../include/defines.h" //#include "server_GPIO.h" @@ -83,7 +85,6 @@ extern std::string getFwVersion(void); extern std::string getHTMLversion(void); extern std::string getHTMLcommit(void); - std::vector splitString(const std::string& str); bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith); bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt); @@ -93,6 +94,7 @@ void migrateConfiguration(void); static const char *TAG = "MAIN"; + bool Init_NVS_SDCard() { esp_err_t ret = nvs_flash_init(); @@ -100,9 +102,8 @@ bool Init_NVS_SDCard() ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } -//////////////////////////////////////////////// - ESP_LOGI(TAG, "Using SDMMC peripheral"); + ESP_LOGD(TAG, "Using SDMMC peripheral"); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); // This initializes the slot without card detect (CD) and write protect (WP) signals. @@ -110,20 +111,19 @@ bool Init_NVS_SDCard() sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); // To use 1-line SD mode, uncomment the following line: - -#ifdef __SD_USE_ONE_LINE_MODE__ - slot_config.width = 1; -#endif + #ifdef __SD_USE_ONE_LINE_MODE__ + slot_config.width = 1; + #endif // GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups. // Internal pull-ups are not sufficient. However, enabling internal pull-ups // does make a difference some boards, so we do that here. gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes -#ifndef __SD_USE_ONE_LINE_MODE__ - gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only - gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only -#endif + #ifndef __SD_USE_ONE_LINE_MODE__ + gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only + gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only + #endif gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes // Options for mounting the filesystem. @@ -135,246 +135,308 @@ bool Init_NVS_SDCard() .allocation_unit_size = 16 * 1024 }; + sdmmc_card_t* card; // Use settings defined above to initialize SD card and mount FAT filesystem. // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function. // Please check its source code and implement error recovery when developing // production applications. - sdmmc_card_t* card; ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card); if (ret != ESP_OK) { if (ret == ESP_FAIL) { - ESP_LOGE(TAG, "Failed to mount filesystem. " - "If you want the card to be formatted, set format_if_mount_failed = true."); - } else { - ESP_LOGE(TAG, "Failed to initialize the card (%s). " - "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); + ESP_LOGE(TAG, "Failed to mount FAT filesystem on SD card. Check SD card filesystem (only FAT supported) or try another card"); + StatusLED(SDCARD_INIT, 1, true); + } + else if (ret == 263) { // Error code: 0x107 --> usually: SD not found + ESP_LOGE(TAG, "SD card init failed. Check if SD card is properly inserted into SD card slot or try another card"); + StatusLED(SDCARD_INIT, 2, true); + } + else { + ESP_LOGE(TAG, "SD card init failed. Check error code or try another card"); + StatusLED(SDCARD_INIT, 3, true); } return false; } - sdmmc_card_print_info(stdout, card); + //sdmmc_card_print_info(stdout, card); // With activated CONFIG_NEWLIB_NANO_FORMAT --> capacity not printed correctly anymore SaveSDCardInfo(card); return true; } -void task_MainInitError_blink(void *pvParameter) -{ - gpio_pad_select_gpio(BLINK_GPIO); - gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); - - - TickType_t xDelay; - xDelay = 100 / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "SD-Card could not be inialized - STOP THE PROGRAMM HERE"); - - while (1) - { - gpio_set_level(BLINK_GPIO, 1); - vTaskDelay( xDelay ); - gpio_set_level(BLINK_GPIO, 0); - vTaskDelay( xDelay ); - - } - vTaskDelete(NULL); //Delete this task if it exits from the loop above -} - extern "C" void app_main(void) { - -//#ifdef CONFIG_HEAP_TRACING_STANDALONE -#if defined HEAP_TRACING_MAIN_WIFI || defined HEAP_TRACING_MAIN_START - //register a buffer to record the memory trace - ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) ); -#endif - + //#ifdef CONFIG_HEAP_TRACING_STANDALONE + #if defined HEAP_TRACING_MAIN_WIFI || defined HEAP_TRACING_MAIN_START + //register a buffer to record the memory trace + ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) ); + #endif + TickType_t xDelay; - -#ifdef DISABLE_BROWNOUT_DETECTOR - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector -#endif - + + #ifdef DISABLE_BROWNOUT_DETECTOR + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector + #endif - ESP_LOGI(TAG, "\n\n\n\n\n"); // Add mark on log to see when it restarted - + #ifdef HEAP_TRACING_MAIN_START + ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); + #endif + + // ******************************************** + // Highlight start of app_main + // ******************************************** + ESP_LOGI(TAG, "\n\n\n\n================ Start app_main ================="); + + // Init camera + // ******************************************** PowerResetCamera(); esp_err_t camStatus = Camera.InitCam(); Camera.LightOnOff(false); - xDelay = 2000 / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay); - vTaskDelay( xDelay ); + xDelay = 2000 / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS); + vTaskDelay( xDelay ); + + // Init SD card + // ******************************************** if (!Init_NVS_SDCard()) { - xTaskCreate(&task_MainInitError_blink, "task_MainInitError_blink", configMINIMAL_STACK_SIZE * 64, NULL, tskIDLE_PRIORITY+1, NULL); - return; // No way to continue without SD-Card! + ESP_LOGE(TAG, "Device init aborted!"); + return; // No way to continue without working SD card! } + // SD card: Create directories (if not already existing) + // ******************************************** + bool bDirStatus = LogFile.CreateLogDirectories(); // needed for logging + image saving + bDirStatus = MakeDir("/sdcard/firmware"); // needed for firmware update + bDirStatus = MakeDir("/sdcard/img_tmp"); // needed for setting up alignment marks + bDirStatus = MakeDir("/sdcard/demo"); // needed for demo mode + if (!bDirStatus) { + StatusLED(SDCARD_CHECK, 1, false); + } + + // ******************************************** + // Highlight start of logfile logging + // Default Log Level: INFO -> Everything which needs to be logged during boot should be have level INFO, WARN OR ERROR + // ******************************************** + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Start ======================"); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); + + // Migrate parameter in config.ini to new naming (firmware 14.1 and newer) + // ******************************************** migrateConfiguration(); - setupTime(); + // Init time (as early as possible, but SD card needs to be initialized) + // ******************************************** + setupTime(); // NTP time service: Status of time synchronization will be checked after every round (server_tflite.cpp) - string versionFormated = getFwVersion() + ", Date/Time: " + std::string(BUILD_TIME) + \ + // SD card: basic RW check + // ******************************************** + // TODO + + // Check for updates + // ******************************************** + CheckOTAUpdate(); + CheckUpdate(); + + // Start SoftAP for initial remote setup + // Note: Start AP if no wlan.ini and/or config.ini available, e.g. SD empty; function does not exit anymore until reboot + // ******************************************** + #ifdef ENABLE_SOFTAP + CheckStartAPMode(); + #endif + + // SD card: Check folder structure + // ******************************************** + // TODO + + // Check version information + // ******************************************** + std::string versionFormated = getFwVersion() + ", Date/Time: " + std::string(BUILD_TIME) + \ ", Web UI: " + getHTMLversion(); if (std::string(GIT_TAG) != "") { // We are on a tag, add it as prefix - string versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated; + versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated; } - - LogFile.CreateLogDirectories(); - MakeDir("/sdcard/demo"); // needed for demo mode - - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Startup ===================="); - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated); - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason()); - -#ifdef DEBUG_ENABLE_SYSINFO - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 ) - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device Info : " + get_device_info() ); - ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str()); - #endif -#endif //DEBUG_ENABLE_SYSINFO - -#ifdef USE_HIMEM_IF_AVAILABLE - #ifdef DEBUG_HIMEM_MEMORY_CHECK - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Himem mem check : " + himem_memory_check() ); - ESP_LOGD(TAG, "Himem mem check %s", himem_memory_check().c_str()); - #endif -#endif - - CheckIsPlannedReboot(); - CheckOTAUpdate(); - CheckUpdate(); - #ifdef ENABLE_SOFTAP - CheckStartAPMode(); // if no wlan.ini and/or config.ini --> AP ist startet and this function does not exit anymore until reboot - #endif - -#ifdef HEAP_TRACING_MAIN_WIFI - ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); -#endif - - char *ssid = NULL, *passwd = NULL, *hostname = NULL, *ip = NULL, *gateway = NULL, *netmask = NULL, *dns = NULL; int rssithreshold = 0; - LoadWlanFromFile(WLAN_CONFIG_FILE, ssid, passwd, hostname, ip, gateway, netmask, dns, rssithreshold); - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "WLAN-Settings - RSSI-Threshold: " + to_string(rssithreshold)); - - if (ssid != NULL && passwd != NULL) -#ifdef __HIDE_PASSWORD - ESP_LOGD(TAG, "WLan: %s, XXXXXX", ssid); -#else - ESP_LOGD(TAG, "WLan: %s, %s", ssid, passwd); -#endif - - else - ESP_LOGD(TAG, "No SSID and PASSWORD set!!!"); - - if (hostname != NULL) - ESP_LOGD(TAG, "Hostname: %s", hostname); - else - ESP_LOGD(TAG, "Hostname not set"); - - if (ip != NULL && gateway != NULL && netmask != NULL) - ESP_LOGD(TAG, "Fixed IP: %s, Gateway %s, Netmask %s", ip, gateway, netmask); - if (dns != NULL) - ESP_LOGD(TAG, "DNS IP: %s", dns); - - - wifi_init_sta(ssid, passwd, hostname, ip, gateway, netmask, dns, rssithreshold); - - - xDelay = 2000 / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay); - vTaskDelay( xDelay ); - -#ifdef HEAP_TRACING_MAIN_WIFI - ESP_ERROR_CHECK( heap_trace_stop() ); - heap_trace_dump(); -#endif - -#ifdef HEAP_TRACING_MAIN_START - ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); -#endif - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================== Main Started ================="); - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); + if (getHTMLcommit().substr(0, 7) == "?") + LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Failed to read file html/version.txt to parse Web UI version")); + if (getHTMLcommit().substr(0, 7) != std::string(GIT_REV).substr(0, 7)) { // Compare the first 7 characters of both hashes - LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Web UI version (") + getHTMLcommit() + ") does not match firmware version (" + std::string(GIT_REV) + ") !"); - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Please make sure to setup the SD-Card properly (check the documentation) or re-install using the AI-on-the-edge-device__update__*.zip!"); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Web UI version (" + getHTMLcommit() + ") does not match firmware version (" + std::string(GIT_REV) + ")"); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Recommendation: Repeat installation using AI-on-the-edge-device__update__*.zip"); } - std::string zw = getCurrentTimeString("%Y%m%d-%H%M%S"); - ESP_LOGD(TAG, "time %s", zw.c_str()); + // Check reboot reason + // ******************************************** + CheckIsPlannedReboot(); + if (!getIsPlannedReboot() && (esp_reset_reason() == ESP_RST_PANIC)) { // If system reboot was not triggered by user and reboot was caused by execption + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reset reason: " + getResetReason()); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Device was rebooted due to a software exception! Log level is set to DEBUG until the next reboot. " + "Flow init is delayed by 5 minutes to check the logs or do an OTA update"); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Keep device running until crash occurs again and check logs after device is up again"); + LogFile.setLogLevel(ESP_LOG_DEBUG); + } + else { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason()); + } + + #ifdef HEAP_TRACING_MAIN_START + ESP_ERROR_CHECK( heap_trace_stop() ); + heap_trace_dump(); + #endif -#ifdef HEAP_TRACING_MAIN_START - ESP_ERROR_CHECK( heap_trace_stop() ); - heap_trace_dump(); -#endif + #ifdef HEAP_TRACING_MAIN_WIFI + ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); + #endif - /* Check if PSRAM can be initalized */ - esp_err_t ret; - ret = esp_spiram_init(); - if (ret == ESP_FAIL) { // Failed to init PSRAM, most likely not available or broken - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize PSRAM (" + std::to_string(ret) + ")!"); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Either your device misses the PSRAM chip or it is broken!"); - setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD); - } - else { // PSRAM init ok - /* Check if PSRAM provides at least 4 MB */ - size_t psram_size = esp_spiram_get_size(); - // size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0 - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "The device has " + std::to_string(psram_size/1024/1024) + " MBytes of PSRAM"); - if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "At least 4 MBytes are required!"); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Does the device really have a 4 Mbytes PSRAM?"); - setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD); + // Read WLAN parameter and start WIFI + // ******************************************** + int iWLANStatus = LoadWlanFromFile(WLAN_CONFIG_FILE); + if (iWLANStatus == 0) { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "WLAN config loaded, init WIFI..."); + if (wifi_init_sta() != ESP_OK) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "WIFI init failed. Device init aborted!"); + StatusLED(WLAN_INIT, 3, true); + return; } } - - /* Check available Heap memory */ - size_t _hsize = getESPHeapSize(); - if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available) - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Not enough Heap memory available. Expected around 4 MBytes, but only " + std::to_string(_hsize) + " Bytes are available! That is not enough for this firmware!"); - setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL); - } else { // Heap memory is ok - if (camStatus != ESP_OK) { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Failed to initialize camera module, retrying..."); - - PowerResetCamera(); - esp_err_t camStatus = Camera.InitCam(); - Camera.LightOnOff(false); - xDelay = 2000 / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay); - vTaskDelay( xDelay ); - - if (camStatus != ESP_OK) { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize camera module!"); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Check that your camera module is working and connected properly!"); - setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD); - } - } else { // Test Camera - if (!Camera.testCamera()) { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialized!"); - /* Easiest would be to simply restart here and try again, - how ever there seem to be systems where it fails at startup but still work corectly later. - Therefore we treat it still as successed! */ - setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD); - } - else { - Camera.LightOnOff(false); - } - } + else if (iWLANStatus == -1) { // wlan.ini not available, potentially empty or content not readable + StatusLED(WLAN_INIT, 1, true); + return; // No way to continue without reading the wlan.ini + } + else if (iWLANStatus == -2) { // SSID or password not configured + StatusLED(WLAN_INIT, 2, true); + return; // No way to continue with empty SSID or password! } xDelay = 2000 / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay*10); + ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS); + vTaskDelay( xDelay ); + + // Set log level for wifi component to WARN level (default: INFO; only relevant for serial console) + // ******************************************** + esp_log_level_set("wifi", ESP_LOG_WARN); + + #ifdef HEAP_TRACING_MAIN_WIFI + ESP_ERROR_CHECK( heap_trace_stop() ); + heap_trace_dump(); + #endif + + #ifdef DEBUG_ENABLE_SYSINFO + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 ) + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device Info : " + get_device_info() ); + ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str()); + #endif + #endif //DEBUG_ENABLE_SYSINFO + + #ifdef USE_HIMEM_IF_AVAILABLE + #ifdef DEBUG_HIMEM_MEMORY_CHECK + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Himem mem check : " + himem_memory_check() ); + ESP_LOGD(TAG, "Himem mem check %s", himem_memory_check().c_str()); + #endif + #endif + + // Init external PSRAM + // ******************************************** + esp_err_t PSRAMStatus = esp_spiram_init(); + if (PSRAMStatus != ESP_OK) { // ESP_FAIL -> Failed to init PSRAM + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM init failed (" + std::to_string(PSRAMStatus) + ")! PSRAM not found or defective"); + setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD); + StatusLED(PSRAM_INIT, 1, true); + } + else { // ESP_OK -> PSRAM init OK --> continue to check PSRAM size + size_t psram_size = esp_spiram_get_size(); // size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0 + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "PSRAM size: " + std::to_string(psram_size) + " byte (" + std::to_string(psram_size/1024/1024) + + "MB / " + std::to_string(psram_size/1024/1024*8) + "MBit)"); + + // Check PSRAM size + // ******************************************** + if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes (32Mbit) + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM size >= 4MB (32Mbit) is mandatory to run this application"); + setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD); + StatusLED(PSRAM_INIT, 2, true); + } + else { // PSRAM size OK --> continue to check heap size + size_t _hsize = getESPHeapSize(); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Total heap: " + std::to_string(_hsize) + " byte"); + + // Check heap memory + // ******************************************** + if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available) + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Total heap >= 4000000 byte is mandatory to run this application"); + setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL); + StatusLED(PSRAM_INIT, 3, true); + } + else { // HEAP size OK --> continue to check camera init + // Check camera init + // ******************************************** + if (camStatus != ESP_OK) { // Camera init failed, retry to init + char camStatusHex[33]; + sprintf(camStatusHex,"0x%02x", camStatus); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Camera init failed (" + std::string(camStatusHex) + "), retrying..."); + + PowerResetCamera(); + camStatus = Camera.InitCam(); + Camera.LightOnOff(false); + + xDelay = 2000 / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS); + vTaskDelay( xDelay ); + + if (camStatus != ESP_OK) { // Camera init failed again + sprintf(camStatusHex,"0x%02x", camStatus); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera init failed (" + std::string(camStatusHex) + + ")! Check camera module and/or proper electrical connection"); + setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD); + StatusLED(CAM_INIT, 1, true); + } + } + else { // ESP_OK -> Camera init OK --> continue to perform camera framebuffer check + // Camera framebuffer check + // ******************************************** + if (!Camera.testCamera()) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera framebuffer check failed"); + // Easiest would be to simply restart here and try again, + // how ever there seem to be systems where it fails at startup but still work correctly later. + // Therefore we treat it still as successed! */ + setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD); + StatusLED(CAM_INIT, 2, false); + } + Camera.LightOnOff(false); // make sure flashlight is off before start of flow + + // Print camera infos + // ******************************************** + char caminfo[50]; + sensor_t * s = esp_camera_sensor_get(); + sprintf(caminfo, "PID: 0x%02x, VER: 0x%02x, MIDL: 0x%02x, MIDH: 0x%02x", s->id.PID, s->id.VER, s->id.MIDH, s->id.MIDL); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Camera info: " + std::string(caminfo)); + } + } + } + } + + // Print Device info + // ******************************************** + esp_chip_info_t chipInfo; + esp_chip_info(&chipInfo); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device info: CPU frequency: " + std::to_string(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) + + "Mhz, CPU cores: " + std::to_string(chipInfo.cores) + + ", Chip revision: " + std::to_string(chipInfo.revision)); + + // Print SD-Card info + // ******************************************** + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "SD card info: Name: " + getSDCardName() + ", Capacity: " + + getSDCardCapacity() + "MB, Free: " + getSDCardFreePartitionSpace() + "MB"); + + xDelay = 2000 / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS); vTaskDelay( xDelay ); + // Start webserver + register handler + // ******************************************** ESP_LOGD(TAG, "starting servers"); server = start_webserver(); @@ -391,25 +453,23 @@ extern "C" void app_main(void) ESP_LOGD(TAG, "Before reg server main"); register_server_main_uri(server, "/sdcard"); - - /* Testing */ + // Only for testing purpose //setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD); //setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD); - /* Main Init has successed or only an error which allows to continue operation */ + // Check main init + start TFlite task + // ******************************************** if (getSystemStatus() == 0) { // No error flag is set - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Initialization completed successfully!"); - ESP_LOGD(TAG, "Before do autostart"); + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Initialization completed successfully! Starting flow task ..."); TFliteDoAutoStart(); } else if (isSetSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD) || // Non critical errors occured, we try to continue... isSetSystemStatusFlag(SYSTEM_STATUS_NTP_BAD)) { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Initialization completed with errors, but trying to continue..."); - ESP_LOGD(TAG, "Before do autostart"); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Initialization completed with errors! Starting flow task ..."); TFliteDoAutoStart(); } - else { // Any other error is critical and makes running the flow impossible. - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Initialization failed. Not starting flows!"); + else { // Any other error is critical and makes running the flow impossible. Init is going to abort. + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Initialization failed. Flow task start aborted!"); } } diff --git a/code/main/server_main.cpp b/code/main/server_main.cpp index e99fd370..54b51985 100644 --- a/code/main/server_main.cpp +++ b/code/main/server_main.cpp @@ -8,6 +8,7 @@ #include "time_sntp.h" #include "connect_wlan.h" +#include "read_wlanini.h" #include "version.h" @@ -83,7 +84,7 @@ esp_err_t info_get_handler(httpd_req_t *req) else if (_task.compare("Hostname") == 0) { std::string zw; - zw = std::string(hostname); + zw = std::string(wlan_config.hostname); httpd_resp_sendstr(req, zw.c_str()); return ESP_OK; } diff --git a/code/main/softAP.cpp b/code/main/softAP.cpp index 6c7aaa04..62eec287 100644 --- a/code/main/softAP.cpp +++ b/code/main/softAP.cpp @@ -27,6 +27,7 @@ #include "server_help.h" #include "defines.h" #include "Helper.h" +#include "statusled.h" #include "server_ota.h" #include "lwip/err.h" @@ -40,22 +41,24 @@ bool isConfigINI = false; bool isWlanINI = false; -static const char *TAG = "wifi softAP"; +static const char *TAG = "WIFI AP"; + static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_id == WIFI_EVENT_AP_STACONNECTED) { wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; - ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", + ESP_LOGI(TAG, "station " MACSTR " join, AID=%d", MAC2STR(event->mac), event->aid); } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; - ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", + ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d", MAC2STR(event->mac), event->aid); } } + void wifi_init_softAP(void) { ESP_ERROR_CHECK(esp_netif_init()); @@ -87,7 +90,7 @@ void wifi_init_softAP(void) ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); - ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d", + ESP_LOGI(TAG, "started with SSID \"%s\", password: \"%s\", channel: %d. Connect to AP and open http://192.168.4.1", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL); } @@ -136,18 +139,18 @@ void SendHTTPResponse(httpd_req_t *req) httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str())); // message = " Hostname"; -// message += "Fixed IPLeave emtpy if set by router"; -// message += "gatewayLeave emtpy if set by router"; -// message += "netmaskLeave emtpy if set by router"; -// message += "DNSLeave emtpy if set by router"; -// message += "RSSI ThresholdWLAN Mesh Parameter: Threshold for RSSI value to check for start switching access point in a mesh system.Possible values: -100 to 0, 0 = disabled - Value will be transfered to wlan.ini at next startup)"; +// message += "Fixed IPLeave emtpy if set by router (DHCP)"; +// message += "GatewayLeave emtpy if set by router (DHCP)"; +// message += "NetmaskLeave emtpy if set by router (DHCP)"; +// message += "DNSLeave emtpy if set by router (DHCP)"; +// message += "RSSI ThresholdWLAN Mesh Parameter: Threshold for RSSI value to check for start switching access point in a mesh system (if actual RSSI is lower). Possible values: -100 to 0, 0 = disabled - Value will be transfered to wlan.ini at next startup)"; // httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str())); message = ""; message += ""; httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str())); return; @@ -164,8 +167,6 @@ void SendHTTPResponse(httpd_req_t *req) } - - esp_err_t test_handler(httpd_req_t *req) { SendHTTPResponse(req); @@ -182,7 +183,7 @@ esp_err_t reboot_handlerAP(httpd_req_t *req) LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update."); doRebootOTA(); return ESP_OK; -}; +} esp_err_t config_ini_handler(httpd_req_t *req) @@ -201,9 +202,10 @@ esp_err_t config_ini_handler(httpd_req_t *req) std::string hn = ""; // hostname std::string ip = ""; std::string gw = ""; // gateway - std::string nm = ""; // nm + std::string nm = ""; // netmask std::string dns = ""; - std::string rssi = ""; + std::string rssithreshold = ""; //rssi threshold for WIFI roaming + std::string text = ""; if (httpd_req_get_url_query_str(req, _query, 400) == ESP_OK) @@ -258,77 +260,106 @@ esp_err_t config_ini_handler(httpd_req_t *req) dns = UrlDecode(std::string(_valuechar)); } - if (httpd_query_key_value(_query, "rssi", _valuechar, 30) == ESP_OK) + if (httpd_query_key_value(_query, "rssithreshold", _valuechar, 30) == ESP_OK) { - ESP_LOGD(TAG, "rssi is found: %s", _valuechar); - rssi = UrlDecode(std::string(_valuechar)); + ESP_LOGD(TAG, "rssithreshold is found: %s", _valuechar); + rssithreshold = UrlDecode(std::string(_valuechar)); } - }; + } FILE* configfilehandle = fopen(WLAN_CONFIG_FILE, "w"); + + text = ";++++++++++++++++++++++++++++++++++\n"; + text += "; AI on the edge - WLAN configuration\n"; + text += "; ssid: Name of WLAN network (mandatory), e.g. \"WLAN-SSID\"\n"; + text += "; password: Password of WLAN network (mandatory), e.g. \"PASSWORD\"\n\n"; + fputs(text.c_str(), configfilehandle); if (ssid.length()) ssid = "ssid = \"" + ssid + "\"\n"; else - ssid = ";ssid = \"\"\n"; - + ssid = "ssid = \"\"\n"; fputs(ssid.c_str(), configfilehandle); if (pwd.length()) pwd = "password = \"" + pwd + "\"\n"; else - pwd = ";password = \"\"\n"; + pwd = "password = \"\"\n"; fputs(pwd.c_str(), configfilehandle); + text = "\n;++++++++++++++++++++++++++++++++++\n"; + text += "; Hostname: Name of device in network\n"; + text += "; This parameter can be configured via WebUI configuration\n"; + text += "; Default: \"watermeter\", if nothing is configured\n\n"; + fputs(text.c_str(), configfilehandle); + if (hn.length()) hn = "hostname = \"" + hn + "\"\n"; else - hn = ";hostname = \"\"\n"; + hn = ";hostname = \"watermeter\"\n"; fputs(hn.c_str(), configfilehandle); + text = "\n;++++++++++++++++++++++++++++++++++\n"; + text += "; Fixed IP: If you like to use fixed IP instead of DHCP (default), the following\n"; + text += "; parameters needs to be configured: ip, gateway, netmask are mandatory, dns optional\n\n"; + fputs(text.c_str(), configfilehandle); + if (ip.length()) ip = "ip = \"" + ip + "\"\n"; else - ip = ";ip = \"\"\n"; + ip = ";ip = \"xxx.xxx.xxx.xxx\"\n"; fputs(ip.c_str(), configfilehandle); if (gw.length()) gw = "gateway = \"" + gw + "\"\n"; else - gw = ";gateway = \"\"\n"; + gw = ";gateway = \"xxx.xxx.xxx.xxx\"\n"; fputs(gw.c_str(), configfilehandle); if (nm.length()) nm = "netmask = \"" + nm + "\"\n"; else - nm = ";netmask = \"\"\n"; + nm = ";netmask = \"xxx.xxx.xxx.xxx\"\n"; fputs(nm.c_str(), configfilehandle); + text = "\n;++++++++++++++++++++++++++++++++++\n"; + text += "; DNS server (optional, if no DNS is configured, gateway address will be used)\n\n"; + fputs(text.c_str(), configfilehandle); + if (dns.length()) dns = "dns = \"" + dns + "\"\n"; else - dns = ";dns = \"\"\n"; + dns = ";dns = \"xxx.xxx.xxx.xxx\"\n"; fputs(dns.c_str(), configfilehandle); - if (rssi.length()) - rssi = "RSSIThreshold = \"" + rssi + "\"\n"; + text = "\n;++++++++++++++++++++++++++++++++++\n"; + text += "; WIFI Roaming:\n"; + text += "; Network assisted roaming protocol is activated by default\n"; + text += "; AP / mesh system needs to support roaming protocol 802.11k/v\n"; + text += ";\n"; + text += "; Optional feature (usually not neccessary):\n"; + text += "; RSSI Threshold for client requested roaming query (RSSI < RSSIThreshold)\n"; + text += "; Note: This parameter can be configured via WebUI configuration\n"; + text += "; Default: 0 = Disable client requested roaming query\n\n"; + fputs(text.c_str(), configfilehandle); + + if (rssithreshold.length()) + rssithreshold = "RSSIThreshold = " + rssithreshold + "\n"; else - rssi = ";rssi = \"\"\n"; - fputs(rssi.c_str(), configfilehandle); + rssithreshold = "RSSIThreshold = 0\n"; + fputs(rssithreshold.c_str(), configfilehandle); fflush(configfilehandle); fclose(configfilehandle); std::string zw = "ota without parameter - should not be the case!"; httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), strlen(zw.c_str())); - httpd_resp_send_chunk(req, NULL, 0); - - ESP_LOGE(TAG, "end config.ini"); + httpd_resp_send(req, zw.c_str(), zw.length()); + ESP_LOGD(TAG, "end config.ini"); return ESP_OK; -}; +} esp_err_t upload_post_handlerAP(httpd_req_t *req) @@ -470,21 +501,28 @@ httpd_handle_t start_webserverAP(void) return NULL; } + void CheckStartAPMode() { isConfigINI = FileExists(CONFIG_FILE); isWlanINI = FileExists(WLAN_CONFIG_FILE); - if (!isConfigINI or !isWlanINI) + if (!isConfigINI) + ESP_LOGW(TAG, "config.ini not found!"); + + if (!isWlanINI) + ESP_LOGW(TAG, "wlan.ini not found!"); + + if (!isConfigINI || !isWlanINI) { + ESP_LOGI(TAG, "Starting access point for remote configuration"); + StatusLED(AP_OR_OTA, 2, true); wifi_init_softAP(); start_webserverAP(); while(1) { // wait until reboot within task_do_Update_ZIP vTaskDelay(1000 / portTICK_PERIOD_MS); } } - - } #endif //#ifdef ENABLE_SOFTAP diff --git a/code/sdkconfig.defaults b/code/sdkconfig.defaults index a524df65..978a4b48 100644 --- a/code/sdkconfig.defaults +++ b/code/sdkconfig.defaults @@ -133,6 +133,8 @@ CONFIG_GC032A_SUPPORT=n CONFIG_GC0308_SUPPORT=n CONFIG_BF3005_SUPPORT=n +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4864 + #only necessary for task analysis (include/defines -> TASK_ANALYSIS_ON) #set in [env:esp32cam-dev-task-analysis] #CONFIG_FREERTOS_USE_TRACE_FACILITY=1 diff --git a/sd-card/html/edit_config_param.html b/sd-card/html/edit_config_param.html index 0082dbe3..2798db16 100644 --- a/sd-card/html/edit_config_param.html +++ b/sd-card/html/edit_config_param.html @@ -1959,7 +1959,7 @@ function ReadParameterAll() ReadParameter(param, "System", "TimeZone", true); ReadParameter(param, "System", "Hostname", true); - ReadParameter(param, "System", "TimeServer", true); + ReadParameter(param, "System", "TimeServer", true); ReadParameter(param, "System", "RSSIThreshold", true); var sel = document.getElementById("Numbers_value1"); diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index 34c1b056..55332573 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -283,7 +283,7 @@ function ParseConfig() { aktline++; } - // Make the downward compatiblity + // Make the downward compatiblity with DataLogging if (category["DataLogging"]["found"] == false) { category["DataLogging"]["found"] = true; @@ -315,8 +315,16 @@ function ParseConfig() { param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; } + // Downward compatiblity: Create RSSIThreshold if not available + if (param["System"]["RSSIThreshold"]["found"] == false) + { + param["System"]["RSSIThreshold"]["found"] = true; + param["System"]["RSSIThreshold"]["enabled"] = false; + param["System"]["RSSIThreshold"]["value1"] = "0"; + } } + function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _checkRegExList = null){ param[_cat][_param] = new Object(); param[_cat][_param]["found"] = false; diff --git a/sd-card/wlan.ini b/sd-card/wlan.ini index 60073814..a1ba7454 100644 --- a/sd-card/wlan.ini +++ b/sd-card/wlan.ini @@ -1,12 +1,38 @@ -ssid = "SSID" -password = "PASSWORD" -hostname = "watermeter" -;hostname is optional +;++++++++++++++++++++++++++++++++++ +; AI on the edge - WLAN configuration +;++++++++++++++++++++++++++++++++++ +; ssid: Name of WLAN network (mandatory), e.g. "WLAN-SSID" +; password: Password of WLAN network (mandatory), e.g. "PASSWORD" -;if you want to use a fixed IP you need to specify the following 3 parameters (ip, gateway, netmask) with IP4-Addresses "123.456.789.012" -;ip = "IP4-ADDRESS" -;gateway = "IP4-ADDRESS" -;netmask = "255.255.255.0" +ssid = "" +password = "" -;in some cases you want to specify the DNS server as well (especially, if it is not identical to the gateway - this is optional for a fixed IP -;dns = "IP4-ADDRESS" \ No newline at end of file +;++++++++++++++++++++++++++++++++++ +; hostname: Name of device in network, e.g "watermeter" +; This parameter can be configured via WebUI configuration +; Default: "watermeter", if nothing is configured +;hostname = "watermeter" + +;++++++++++++++++++++++++++++++++++ +; Fixed IP: If you like to use fixed IP instead of DHCP (default), the following +; parameters needs to be configured: ip, gateway, netmask are mandatory, dns optional + +;ip = "xxx.xxx.xxx.xxx" +;gateway = "xxx.xxx.xxx.xxx" +;netmask = "xxx.xxx.xxx.xxx" + +; DNS server (optional, if no DNS is configured, gateway address will be used) + +;dns = "xxx.xxx.xxx.xxx" + +;++++++++++++++++++++++++++++++++++ +; WIFI Roaming: +; Network assisted roaming protocol is activated by default +; AP / mesh system needs to support roaming protocol 802.11k/v +; +; Optional feature (usually not neccessary): +; RSSI Threshold for client requested roaming query (RSSI < RSSIThreshold) +; Note: This parameter can be configured via WebUI configuration +; Default: 0 = Disable client requested roaming query + +RSSIThreshold = 0