Merge branch 'rolling' into master

This commit is contained in:
CaCO3
2023-02-28 22:01:05 +01:00
committed by GitHub
60 changed files with 9626 additions and 1658 deletions

View File

@@ -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);
}
}

View File

@@ -228,7 +228,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
if (chunksize > 0){
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
fclose(fd);
ESP_LOGE(TAG, "File sending failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
return ESP_FAIL;
}
}
@@ -267,7 +267,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len);
ESP_LOGD(TAG, "Entrypath: %s", entrypath);
if (stat(entrypath, &entry_stat) == -1) {
ESP_LOGE(TAG, "Failed to stat %s: %s", entrytype, entry->d_name);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to stat " + string(entrytype) + ": " + string(entry->d_name));
continue;
}
@@ -357,7 +357,7 @@ static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file)
fd = fopen(currentfilename.c_str(), "r");
if (!fd) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(currentfilename) +"!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + currentfilename + "!");
/* Respond with 404 Error */
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, get404());
return ESP_FAIL;
@@ -373,7 +373,7 @@ static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file)
/* Adapted from https://www.geeksforgeeks.org/implement-your-own-tail-read-last-n-lines-of-a-huge-file/ */
if (fseek(fd, 0, SEEK_END)) {
ESP_LOGE(TAG, "Failed to get to end of file!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to get to end of file!");
return ESP_FAIL;
}
else {
@@ -381,7 +381,7 @@ static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file)
ESP_LOGI(TAG, "File contains %ld bytes", pos);
if (fseek(fd, pos - std::min((long)LOGFILE_LAST_PART_BYTES, pos), SEEK_SET)) { // Go LOGFILE_LAST_PART_BYTES bytes back from EOF
ESP_LOGE(TAG, "Failed to go back %ld bytes within the file!", std::min((long)LOGFILE_LAST_PART_BYTES, pos));
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to go back " + to_string(std::min((long)LOGFILE_LAST_PART_BYTES, pos)) + " bytes within the file!");
return ESP_FAIL;
}
}
@@ -404,7 +404,7 @@ static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file)
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
fclose(fd);
ESP_LOGE(TAG, "File sending failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
/* Abort sending file */
httpd_resp_sendstr_chunk(req, NULL);
/* Respond with 500 Internal Server Error */
@@ -443,7 +443,7 @@ static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file)
fd = fopen(currentfilename.c_str(), "r");
if (!fd) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(currentfilename.c_str()) +"!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + currentfilename + "!");
/* Respond with 404 Error */
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, get404());
return ESP_FAIL;
@@ -459,7 +459,7 @@ static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file)
/* Adapted from https://www.geeksforgeeks.org/implement-your-own-tail-read-last-n-lines-of-a-huge-file/ */
if (fseek(fd, 0, SEEK_END)) {
ESP_LOGE(TAG, "Failed to get to end of file!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to get to end of file!");
return ESP_FAIL;
}
else {
@@ -467,7 +467,7 @@ static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file)
ESP_LOGI(TAG, "File contains %ld bytes", pos);
if (fseek(fd, pos - std::min((long)LOGFILE_LAST_PART_BYTES, pos), SEEK_SET)) { // Go LOGFILE_LAST_PART_BYTES bytes back from EOF
ESP_LOGE(TAG, "Failed to go back %ld bytes within the file!", std::min((long)LOGFILE_LAST_PART_BYTES, pos));
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to go back " + to_string(std::min((long)LOGFILE_LAST_PART_BYTES, pos)) + " bytes within the file!");
return ESP_FAIL;
}
}
@@ -490,7 +490,7 @@ static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file)
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
fclose(fd);
ESP_LOGE(TAG, "File sending failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
/* Abort sending file */
httpd_resp_sendstr_chunk(req, NULL);
/* Respond with 500 Internal Server Error */
@@ -530,7 +530,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
if (!filename) {
ESP_LOGE(TAG, "Filename is too long");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Filename is too long");
/* Respond with 414 Error */
httpd_resp_send_err(req, HTTPD_414_URI_TOO_LONG, "Filename too long");
return ESP_FAIL;
@@ -571,7 +571,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
fd = fopen(filepath, "r");
if (!fd) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filepath) +"!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filepath) + "!");
/* Respond with 404 Error */
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, get404());
return ESP_FAIL;
@@ -592,7 +592,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
fclose(fd);
ESP_LOGE(TAG, "File sending failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
/* Abort sending file */
httpd_resp_sendstr_chunk(req, NULL);
/* Respond with 500 Internal Server Error */
@@ -634,14 +634,14 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
/* Filename cannot have a trailing '/' */
if (filename[strlen(filename) - 1] == '/') {
ESP_LOGE(TAG, "Invalid filename: %s", filename);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Invalid filename: " + string(filename));
/* Respond with 400 Bad Request */
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid filename");
return ESP_FAIL;
}
if (stat(filepath, &file_stat) == 0) {
ESP_LOGE(TAG, "File already exists: %s", filepath);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File already exists: " + string(filepath));
/* Respond with 400 Bad Request */
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File already exists");
return ESP_FAIL;
@@ -649,7 +649,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
/* File cannot be larger than a limit */
if (req->content_len > MAX_FILE_SIZE) {
ESP_LOGE(TAG, "File too large: %d bytes", req->content_len);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File too large: " + to_string(req->content_len) + " bytes");
/* Respond with 400 Bad Request */
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
"File size must be less than "
@@ -661,7 +661,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
fd = fopen(filepath, "w");
if (!fd) {
ESP_LOGE(TAG, "Failed to create file: %s", filepath);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create file: " + string(filepath));
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to create file");
return ESP_FAIL;
@@ -692,7 +692,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
fclose(fd);
unlink(filepath);
ESP_LOGE(TAG, "File reception failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File reception failed!");
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file");
return ESP_FAIL;
@@ -705,7 +705,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
fclose(fd);
unlink(filepath);
ESP_LOGE(TAG, "File write failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File write failed!");
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to write file to storage");
return ESP_FAIL;
@@ -780,7 +780,7 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK)
{
ESP_LOGD(TAG, "task is found: %s", _valuechar);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "task is found: " + string(_valuechar));
_task = std::string(_valuechar);
}
}
@@ -826,26 +826,26 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
/* Filename cannot have a trailing '/' */
if (filename[strlen(filename) - 1] == '/') {
ESP_LOGE(TAG, "Invalid filename: %s", filename);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Invalid filename: " + string(filename));
/* Respond with 400 Bad Request */
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid filename");
return ESP_FAIL;
}
if (strcmp(filename, "wlan.ini") == 0) {
ESP_LOGE(TAG, "Trying to delete protected file : %s", filename);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to delete protected file : " + string(filename));
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Not allowed to delete wlan.ini");
return ESP_FAIL;
}
if (stat(filepath, &file_stat) == -1) {
ESP_LOGE(TAG, "File does not exist: %s", filename);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File does not exist: " + string(filename));
/* Respond with 400 Bad Request */
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Deleting file: %s", filename);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Deleting file: " + string(filename));
/* Delete file */
unlink(filepath);
@@ -887,7 +887,7 @@ void delete_all_in_directory(std::string _directory)
std::string filename;
if (!dir) {
ESP_LOGE(TAG, "Failed to stat dir: %s", _directory.c_str());
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to stat dir: " + _directory);
return;
}
@@ -896,7 +896,7 @@ void delete_all_in_directory(std::string _directory)
if (!(entry->d_type == DT_DIR)){
if (strcmp("wlan.ini", entry->d_name) != 0){ // auf wlan.ini soll nicht zugegriffen werden !!!
filename = _directory + "/" + std::string(entry->d_name);
ESP_LOGI(TAG, "Deleting file: %s", filename.c_str());
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Deleting file: " + filename);
/* Delete file */
unlink(filename.c_str());
}
@@ -930,7 +930,7 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
// Get and print information about each file in the archive.
int numberoffiles = (int)mz_zip_reader_get_num_files(&zip_archive);
ESP_LOGI(TAG, "Numbers of files to be extracted: %d", numberoffiles);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Numbers of files to be extracted: " + to_string(numberoffiles));
sort_iter = 0;
{
@@ -953,7 +953,7 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
p = mz_zip_reader_extract_file_to_heap(&zip_archive, archive_filename, &uncomp_size, 0);
if (!p)
{
ESP_LOGE(TAG, "mz_zip_reader_extract_file_to_heap() failed on file %s", archive_filename);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "mz_zip_reader_extract_file_to_heap() failed on file " + string(archive_filename));
mz_zip_reader_end(&zip_archive);
return ret;
}
@@ -1015,21 +1015,22 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
else
{
isokay = false;
ESP_LOGD(TAG, "ERROR in writting extracted file (function fwrite) extracted file \"%s\", size %u", archive_filename, (uint)uncomp_size);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ERROR in writting extracted file (function fwrite) extracted file \"" +
string(archive_filename) + "\", size " + to_string(uncomp_size));
}
DeleteFile(zw);
if (!isokay)
ESP_LOGE(TAG, "ERROR in fwrite \"%s\", size %u", archive_filename, (uint)uncomp_size);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ERROR in fwrite \"" + string(archive_filename) + "\", size " + to_string(uncomp_size));
isokay = isokay && RenameFile(filename_zw, zw);
if (!isokay)
ESP_LOGE(TAG, "ERROR in Rename \"%s\" to \"%s\"", filename_zw.c_str(), zw.c_str());
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ERROR in Rename \"" + filename_zw + "\" to \"" + zw);
if (isokay)
ESP_LOGI(TAG, "Successfully extracted file \"%s\", size %u", archive_filename, (uint)uncomp_size);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully extracted file \"" + string(archive_filename) + "\", size " + to_string(uncomp_size));
else
{
ESP_LOGE(TAG, "ERROR in extracting file \"%s\", size %u", archive_filename, (uint)uncomp_size);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ERROR in extracting file \"" + string(archive_filename) + "\", size " + to_string(uncomp_size));
ret = "ERROR";
}
mz_free(p);
@@ -1063,7 +1064,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
status = mz_zip_reader_init_file(&zip_archive, _in_zip_file.c_str(), 0);
if (!status)
{
ESP_LOGD(TAG, "mz_zip_reader_init_file() failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "mz_zip_reader_init_file() failed!");
return;
}
@@ -1075,7 +1076,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
status = mz_zip_reader_init_file(&zip_archive, _in_zip_file.c_str(), sort_iter ? MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY : 0);
if (!status)
{
ESP_LOGD(TAG, "mz_zip_reader_init_file() failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "mz_zip_reader_init_file() failed!");
return;
}
@@ -1089,7 +1090,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
p = mz_zip_reader_extract_file_to_heap(&zip_archive, archive_filename, &uncomp_size, 0);
if (!p)
{
ESP_LOGD(TAG, "mz_zip_reader_extract_file_to_heap() failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "mz_zip_reader_extract_file_to_heap() failed!");
mz_zip_reader_end(&zip_archive);
return;
}
@@ -1125,19 +1126,19 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
/* Validate file storage base path */
if (!base_path) {
// if (!base_path || strcmp(base_path, "/spiffs") != 0) {
ESP_LOGE(TAG, "File server base_path not set");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File server base_path not set");
// return ESP_ERR_INVALID_ARG;
}
if (server_data) {
ESP_LOGE(TAG, "File server already started");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File server already started");
// return ESP_ERR_INVALID_STATE;
}
/* Allocate memory for server data */
server_data = (file_server_data *) calloc(1, sizeof(struct file_server_data));
if (!server_data) {
ESP_LOGE(TAG, "Failed to allocate memory for server data");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to allocate memory for server data");
// return ESP_ERR_NO_MEM;
}
strlcpy(server_data->base_path, base_path,

View File

@@ -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*/
@@ -56,9 +57,9 @@ bool initial_setup = false;
static void infinite_loop(void)
{
int i = 0;
ESP_LOGI(TAG, "When a new firmware is available on the server, press the reset button to download it");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "When a new firmware is available on the server, press the reset button to download it");
while(1) {
ESP_LOGI(TAG, "Waiting for a new firmware... %d", ++i);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Waiting for a new firmware... (" + to_string(++i) + ")");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
@@ -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,13 @@ 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");
}
}
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);
@@ -148,10 +151,10 @@ static bool ota_update_task(std::string fn)
const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();
if (configured != running) {
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
configured->address, running->address);
ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
if (configured != running) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Configured OTA boot partition at offset " + to_string(configured->address) +
", but running from offset " + to_string(running->address));
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
}
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
running->type, running->subtype, running->address);
@@ -179,7 +182,7 @@ static bool ota_update_task(std::string fn)
while (data_read > 0) {
if (data_read < 0) {
ESP_LOGE(TAG, "Error: SSL data read error");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Error: SSL data read error");
return false;
} else if (data_read > 0) {
if (image_header_was_checked == false) {
@@ -203,16 +206,17 @@ static bool ota_update_task(std::string fn)
// check current version with last invalid partition
if (last_invalid_app != NULL) {
if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAG, "New version is the same as invalid version.");
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "New version is the same as invalid version");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Previously, there was an attempt to launch the firmware with " +
string(invalid_app_info.version) + " version, but it failed");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "The firmware has been rolled back to the previous version");
infinite_loop();
}
}
/*
if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Current running version is the same as a new. We will not continue the update");
infinite_loop();
}
*/
@@ -220,12 +224,12 @@ static bool ota_update_task(std::string fn)
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_ota_begin failed (" + string(esp_err_to_name(err)) + ")");
return false;
}
ESP_LOGI(TAG, "esp_ota_begin succeeded");
} else {
ESP_LOGE(TAG, "received package is not fit len");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "received package is not fit len");
return false;
}
}
@@ -241,7 +245,7 @@ static bool ota_update_task(std::string fn)
// * `errno` to check for underlying transport connectivity closure if any
//
if (errno == ECONNRESET || errno == ENOTCONN) {
ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection closed, errno = " + to_string(errno));
break;
}
}
@@ -254,15 +258,15 @@ static bool ota_update_task(std::string fn)
err = esp_ota_end(update_handle);
if (err != ESP_OK) {
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Image validation failed, image is corrupted");
}
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_ota_end failed (" + string(esp_err_to_name(err)) + ")!");
return false;
}
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "esp_ota_set_boot_partition failed (" + string(esp_err_to_name(err)) + ")!");
}
// ESP_LOGI(TAG, "Prepare to restart system!");
@@ -329,7 +333,7 @@ void CheckOTAUpdate(void)
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
esp_ota_mark_app_valid_cancel_rollback();
} else {
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version...");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Diagnostics failed! Start rollback to the previous version...");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
@@ -353,7 +357,7 @@ void CheckOTAUpdate(void)
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
esp_ota_mark_app_valid_cancel_rollback();
} else {
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version...");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Diagnostics failed! Start rollback to the previous version...");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
@@ -445,7 +449,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
if ((filetype == "ZIP") || (filetype == "BIN"))
{
FILE *pfile;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update for reboot.");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update for reboot");
pfile = fopen("/sdcard/update.txt", "w");
fwrite(fn.c_str(), fn.length(), 1, pfile);
fclose(pfile);
@@ -522,7 +526,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
}
else
{
ESP_LOGD(TAG, "File does not exist: %s", fn.c_str());
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File does not exist: " + fn);
}
/* Respond with an empty chunk to signal HTTP response completion */
std::string zw = "file deleted\n";
@@ -537,7 +541,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
httpd_resp_send_chunk(req, NULL, 0);
ESP_LOGE(TAG, "ota without parameter - should not be the case!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ota without parameter - should not be the case!");
/*
const char* resp_str;
@@ -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);
@@ -600,20 +607,20 @@ void task_reboot(void *KillAutoFlow)
vTaskDelay(5000 / portTICK_PERIOD_MS);
hard_restart(); // Reset type: System reset (Triggered by watchdog), if esp_restart stalls (WDT needs to be activated)
ESP_LOGE(TAG, "Reboot failed!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Reboot failed!");
vTaskDelete(NULL); //Delete this task if it comes to this point
}
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);
if( xReturned != pdPASS )
{
ESP_LOGE(TAG, "task_reboot not created -> force reboot without killing flow");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "task_reboot not created -> force reboot without killing flow");
task_reboot((void*) false);
}
vTaskDelay(10000 / portTICK_PERIOD_MS); // Prevent serving web client fetch response until system is shuting down
@@ -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);
@@ -641,7 +650,7 @@ esp_err_t handler_reboot(httpd_req_t *req)
#endif
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot");
ESP_LOGI(TAG, "!!! System will restart within 5 sec!!!");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "!!! System will restart within 5 sec!!!");
std::string response =
"<html><head><script>"

View File

@@ -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";
@@ -195,6 +196,7 @@ void ClassFlowControll::SetInitialParameter(void)
disabled = false;
aktRunNr = 0;
aktstatus = "Flow task not yet created";
aktstatusWithTime = aktstatus;
}
@@ -272,6 +274,8 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
void ClassFlowControll::InitFlow(std::string config)
{
aktstatus = "Initialization";
aktstatusWithTime = aktstatus;
//#ifdef ENABLE_MQTT
//MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization", false); // Right now, not possible -> MQTT Service is going to be started later
//#endif //ENABLE_MQTT
@@ -318,6 +322,12 @@ void ClassFlowControll::InitFlow(std::string config)
}
std::string* ClassFlowControll::getActStatusWithTime()
{
return &aktstatusWithTime;
}
std::string* ClassFlowControll::getActStatus()
{
return &aktstatus;
@@ -327,6 +337,7 @@ std::string* ClassFlowControll::getActStatus()
void ClassFlowControll::setActStatus(std::string _aktstatus)
{
aktstatus = _aktstatus;
aktstatusWithTime = aktstatus;
}
@@ -338,10 +349,10 @@ void ClassFlowControll::doFlowTakeImageOnly(string time)
{
if (FlowControll[i]->name() == "ClassFlowTakeImage") {
zw_time = getCurrentTimeString("%H:%M:%S");
std::string flowStatus = TranslateAktstatus(FlowControll[i]->name());
aktstatus = flowStatus + " (" + zw_time + ")";
aktstatus = TranslateAktstatus(FlowControll[i]->name());
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
#ifdef ENABLE_MQTT
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, false);
#endif //ENABLE_MQTT
FlowControll[i]->doFlow(time);
@@ -371,11 +382,11 @@ bool ClassFlowControll::doFlow(string time)
for (int i = 0; i < FlowControll.size(); ++i)
{
zw_time = getCurrentTimeString("%H:%M:%S");
std::string flowStatus = TranslateAktstatus(FlowControll[i]->name());
aktstatus = flowStatus + " (" + zw_time + ")";
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatus);
aktstatus = TranslateAktstatus(FlowControll[i]->name());
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatusWithTime);
#ifdef ENABLE_MQTT
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, false);
#endif //ENABLE_MQTT
#ifdef DEBUG_DETAIL_ON
@@ -405,11 +416,11 @@ bool ClassFlowControll::doFlow(string time)
}
zw_time = getCurrentTimeString("%H:%M:%S");
std::string flowStatus = "Flow finished";
aktstatus = flowStatus + " (" + zw_time + ")";
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatus);
aktstatus = "Flow finished";
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatusWithTime);
#ifdef ENABLE_MQTT
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, false);
#endif //ENABLE_MQTT
return result;
@@ -589,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))
{
@@ -597,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))
{
@@ -616,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();
}
}

View File

@@ -37,6 +37,7 @@ protected:
float AutoInterval;
bool SetupModeActive;
void SetInitialParameter(void);
std::string aktstatusWithTime;
std::string aktstatus;
int aktRunNr;
@@ -71,6 +72,7 @@ public:
bool isAutoStart(long &_interval);
std::string* getActStatusWithTime();
std::string* getActStatus();
void setActStatus(std::string _aktstatus);

View File

@@ -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,12 +32,12 @@ void ClassFlowMQTT::SetInitialParameter(void)
topicError = "";
topicRate = "";
topicTimeStamp = "";
maintopic = hostname;
maintopic = wlan_config.hostname;
topicUptime = "";
topicFreeMem = "";
clientname = "AIOTED-" + getMac();
clientname = wlan_config.hostname;
OldValue = "";
flowpostprocessing = NULL;
@@ -165,7 +166,6 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
if (((toUpper(splitted[0]) == "TOPIC") || (toUpper(splitted[0]) == "MAINTOPIC")) && (splitted.size() > 1))
{
maintopic = splitted[1];
mqttServer_setMainTopic(maintopic);
}
}
@@ -174,6 +174,8 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
* How ever we need the interval parameter from the ClassFlowControll, but that only gets started later.
* To work around this, we delay the start and trigger it from ClassFlowControll::ReadParameter() */
mqttServer_setMainTopic(maintopic);
return true;
}
@@ -209,6 +211,7 @@ bool ClassFlowMQTT::Start(float AutoInterval)
bool ClassFlowMQTT::doFlow(string zwtime)
{
bool success;
std::string result;
std::string resulterror = "";
std::string resultraw = "";
@@ -220,7 +223,7 @@ bool ClassFlowMQTT::doFlow(string zwtime)
string zw = "";
string namenumber = "";
publishSystemData();
success = publishSystemData();
if (flowpostprocessing && getMQTTisConnected())
{
@@ -246,13 +249,13 @@ bool ClassFlowMQTT::doFlow(string zwtime)
if (result.length() > 0)
MQTTPublish(namenumber + "value", result, SetRetainFlag);
success |= MQTTPublish(namenumber + "value", result, SetRetainFlag);
if (resulterror.length() > 0)
MQTTPublish(namenumber + "error", resulterror, SetRetainFlag);
success |= MQTTPublish(namenumber + "error", resulterror, SetRetainFlag);
if (resultrate.length() > 0) {
MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag);
success |= MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag);
std::string resultRatePerTimeUnit;
if (getTimeUnit() == "h") { // Need conversion to be per hour
@@ -261,22 +264,22 @@ bool ClassFlowMQTT::doFlow(string zwtime)
else { // Keep per minute
resultRatePerTimeUnit = resultrate;
}
MQTTPublish(namenumber + "rate_per_time_unit", resultRatePerTimeUnit, SetRetainFlag);
success |= MQTTPublish(namenumber + "rate_per_time_unit", resultRatePerTimeUnit, SetRetainFlag);
}
if (resultchangabs.length() > 0) {
MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); // Legacy API
MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, SetRetainFlag);
success |= MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); // Legacy API
success |= MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, SetRetainFlag);
}
if (resultraw.length() > 0)
MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag);
success |= MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag);
if (resulttimestamp.length() > 0)
MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag);
success |= MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag);
std::string json = flowpostprocessing->getJsonFromNumber(i, "\n");
MQTTPublish(namenumber + "json", json, SetRetainFlag);
success |= MQTTPublish(namenumber + "json", json, SetRetainFlag);
}
}
@@ -294,10 +297,14 @@ bool ClassFlowMQTT::doFlow(string zwtime)
// result = result + "\t" + zw;
// }
// }
// MQTTPublish(topic, result, SetRetainFlag);
// success |= MQTTPublish(topic, result, SetRetainFlag);
// }
OldValue = result;
if (!success) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more MQTT topics failed to be published!");
}
return true;
}

View File

@@ -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;
}
@@ -963,3 +963,34 @@ std::string UrlDecode(const std::string& value)
return result;
}
bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
return replaceString(s, toReplace, replaceWith, true);
}
bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt) {
std::size_t pos = s.find(toReplace);
if (pos == std::string::npos) { // Not found
return false;
}
std::string old = s;
s.replace(pos, toReplace.length(), replaceWith);
if (logIt) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line '" + old + "' to '" + s + "'");
}
return true;
}
bool isInString(std::string& s, std::string const& toFind) {
std::size_t pos = s.find(toFind);
if (pos == std::string::npos) { // Not found
return false;
}
return true;
}

View File

@@ -76,6 +76,8 @@ enum SystemStatusFlag_t { // One bit per error
SYSTEM_STATUS_PSRAM_BAD = 1 << 0, // 1, Critical Error
SYSTEM_STATUS_HEAP_TOO_SMALL = 1 << 1, // 2, Critical Error
SYSTEM_STATUS_CAM_BAD = 1 << 2, // 4, Critical Error
SYSTEM_STATUS_SDCARD_CHECK_BAD = 1 << 3, // 8, Critical Error
SYSTEM_STATUS_FOLDER_CHECK_BAD = 1 << 4, // 16, Critical Error
// Second Byte
SYSTEM_STATUS_CAM_FB_BAD = 1 << (0+8), // 8, Flow still might work
@@ -95,4 +97,8 @@ const char* get404(void);
std::string UrlDecode(const std::string& value);
bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith);
bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt);
bool isInString(std::string& s, std::string const& toFind);
#endif //HELPER_H

View File

@@ -0,0 +1,166 @@
#include "sdcard_check.h"
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/stat.h>
#include "esp_rom_crc.h"
#include "ClassLogFile.h"
static const char *TAG = "SDCARD";
int SDCardCheckRW(void)
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Basic R/W check started...");
FILE* pFile = NULL;
int iCRCMessage = 0;
pFile = fopen("/sdcard/sdcheck.txt","w");
if (pFile == NULL) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E1) No able to open file to write");
return -1;
}
else {
std::string sMessage = "This message is used for a SD-Card basic check!";
iCRCMessage = esp_rom_crc16_le(0, (uint8_t*)sMessage.c_str(), sMessage.length());
if (fwrite(sMessage.c_str(), sMessage.length(), 1, pFile) == 0 ) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E2) Not able to write file");
fclose(pFile);
unlink("/sdcard/sdcheck.txt");
return -2;
}
fclose(pFile);
}
pFile = fopen("/sdcard/sdcheck.txt","r");
if (pFile == NULL) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E3) Not able to open file to read back");
unlink("/sdcard/sdcheck.txt");
return -3;
}
else {
char cReadBuf[50];
if (fgets(cReadBuf, sizeof(cReadBuf), pFile) == 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E4) Not able to read file back");
fclose(pFile);
unlink("/sdcard/sdcheck.txt");
return -4;
}
else {
if (esp_rom_crc16_le(0, (uint8_t*)cReadBuf, strlen(cReadBuf)) != iCRCMessage) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E5) Read back, but wrong CRC");
fclose(pFile);
unlink("/sdcard/sdcheck.txt");
return -5;
}
}
fclose(pFile);
}
if (unlink("/sdcard/sdcheck.txt") != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E6) Unable to delete the file");
return -6;
}
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Basic R/W check successful");
return 0;
}
bool SDCardCheckFolderFilePresence()
{
struct stat sb;
bool bRetval = true;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Folder/file presence check started...");
/* check if folder exists: config */
if (stat("/sdcard/config", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /config not found");
bRetval = false;
}
/* check if folder exists: html */
if (stat("/sdcard/html", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /html not found");
bRetval = false;
}
/* check if folder exists: firmware */
if (stat("/sdcard/firmware", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /firmware not found");
bRetval = false;
}
/* check if folder exists: img_tmp */
if (stat("/sdcard/img_tmp", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /img_tmp not found");
bRetval = false;
}
/* check if folder exists: log */
if (stat("/sdcard/log", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /log not found");
bRetval = false;
}
/* check if folder exists: demo */
if (stat("/sdcard/demo", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /demo not found");
bRetval = false;
}
/* check if file exists: wlan.ini */
if (stat("/sdcard/wlan.ini", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /wlan.ini not found");
bRetval = false;
}
/* check if file exists: config.ini */
if (stat("/sdcard/config/config.ini", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /config/config.ini not found");
bRetval = false;
}
/* check if file exists: index.html */
if (stat("/sdcard/html/index.html", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/index.html not found");
bRetval = false;
}
/* check if file exists: ota.html */
if (stat("/sdcard/html/ota_page.html", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/ota.html not found");
bRetval = false;
}
/* check if file exists: log.html */
if (stat("/sdcard/html/log.html", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/log.html not found");
bRetval = false;
}
/* check if file exists: common.js */
if (stat("/sdcard/html/common.js", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/common.js not found");
bRetval = false;
}
/* check if file exists: gethost.js */
if (stat("/sdcard/html/gethost.js", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/gethost.js not found");
bRetval = false;
}
/* check if file exists: version.txt */
if (stat("/sdcard/html/version.txt", &sb) != 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/version.txt not found");
bRetval = false;
}
if (bRetval)
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Folder/file presence check successful");
return bRetval;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#ifndef COMPONENTS_HELPER_SDCARD_CHECK_H
#define COMPONENTS_HELPER_SDCARD_CHECK_H
#include "../../include/defines.h"
int SDCardCheckRW(void);
bool SDCardCheckFolderFilePresence(void);
#endif /* COMPONENTS_HELPER_SDCARD_CHECK_H */

View File

@@ -0,0 +1,148 @@
#include "statusled.h"
#include <sys/types.h>
#include <sys/stat.h>
#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<2; ) // Default: repeat 2 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
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -35,7 +35,7 @@ public:
void CloseLogFileAppendHandle();
void CreateLogDirectories();
bool CreateLogDirectories();
void RemoveOldLogFile();
void RemoveOldDataLog();

View File

@@ -14,6 +14,7 @@ std::map<std::string, std::function<void()>>* connectFunktionMap = NULL;
std::map<std::string, std::function<bool(std::string, char*, int)>>* 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;
@@ -313,8 +326,7 @@ bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len) {
void MQTTconnected(){
if (mqtt_connected) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
MQTTPublish(lwt_topic, lwt_connected, true); // Publish "connected" to maintopic/connection
if (connectFunktionMap != NULL) {
for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
it->second();

View File

@@ -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"
@@ -46,7 +47,7 @@ void mqttServer_setMeterType(std::string _meterType, std::string _valueUnit, std
rateUnit = _rateUnit;
}
void sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
std::string name, std::string icon, std::string unit, std::string deviceClass, std::string stateClass, std::string entityCategory) {
std::string version = std::string(libfive_git_version());
@@ -130,26 +131,29 @@ void sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
"}" +
"}";
MQTTPublish(topicFull, payload, true);
return MQTTPublish(topicFull, payload, true);
}
void MQTThomeassistantDiscovery() {
if (!getMQTTisConnected())
return;
bool MQTThomeassistantDiscovery() {
bool allSendsSuccessed = false;
if (!getMQTTisConnected()) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Unable to send Homeassistant Discovery Topics, we are not connected to the MQTT broker!");
return false;
}
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "MQTT - Sending Homeassistant Discovery Topics (Meter Type: " + meterType + ", Value Unit: " + valueUnit + " , Rate Unit: " + rateUnit + ")...");
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "clock-time-eight-outline", "s", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "MAC", "MAC Address", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "hostname", "Hostname", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "freeMem", "Free Memory", "memory", "B", "", "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "CPUtemp", "CPU Temperature", "thermometer", "°C", "temperature", "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "interval", "Interval", "clock-time-eight-outline", "min", "" , "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "IP", "IP", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "status", "Status", "list-status", "", "", "", "diagnostic");
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "clock-time-eight-outline", "s", "", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "MAC", "MAC Address", "network-outline", "", "", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "hostname", "Hostname", "network-outline", "", "", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "freeMem", "Free Memory", "memory", "B", "", "measurement", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "CPUtemp", "CPU Temperature", "thermometer", "°C", "temperature", "measurement", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "interval", "Interval", "clock-time-eight-outline", "min", "" , "measurement", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "IP", "IP", "network-outline", "", "", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "status", "Status", "list-status", "", "", "", "diagnostic");
for (int i = 0; i < (*NUMBERS).size(); ++i) {
@@ -158,76 +162,126 @@ void MQTThomeassistantDiscovery() {
group = "";
}
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, "total_increasing", "");
sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", valueUnit, "", "total_increasing", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "error", "Error", "alert-circle-outline", "", "", "", "diagnostic");
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, "total_increasing", "");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", "", "", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "error", "Error", "alert-circle-outline", "", "", "", "diagnostic");
/* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitalization_round */
// sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", ""); // Legacy, always Unit per Minute
sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, "", "", "");
sendHomeAssistantDiscoveryTopic(group, "rate_per_digitalization_round", "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "", "measurement", ""); // correctly the Unit is Uint/Interval!
sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "json", "JSON", "code-json", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "problem", "Problem", "alert-outline", "", "problem", "", ""); // Special binary sensor which is based on error topic
// allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", ""); // Legacy, always Unit per Minute
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, "", "", "");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_digitalization_round", "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "", "measurement", ""); // correctly the Unit is Uint/Interval!
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "json", "JSON", "code-json", "", "", "", "diagnostic");
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "problem", "Problem", "alert-outline", "", "problem", "", ""); // Special binary sensor which is based on error topic
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all Homeassistant Discovery MQTT topics");
return allSendsSuccessed;
}
void publishSystemData() {
if (!getMQTTisConnected())
return;
bool publishSystemData() {
bool allSendsSuccessed = false;
if (!getMQTTisConnected()) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Unable to send System Topics, we are not connected to the MQTT broker!");
return false;
}
char tmp_char[50];
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing system MQTT topics...");
allSendsSuccessed |= MQTTPublish(maintopic + "/" + std::string(LWT_TOPIC), LWT_CONNECTED, retainFlag); // Publish "connected" to maintopic/connection
sprintf(tmp_char, "%ld", (long)getUpTime());
MQTTPublish(maintopic + "/" + "uptime", std::string(tmp_char), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "uptime", std::string(tmp_char), retainFlag);
sprintf(tmp_char, "%lu", (long) getESPHeapSize());
MQTTPublish(maintopic + "/" + "freeMem", std::string(tmp_char), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "freeMem", std::string(tmp_char), retainFlag);
sprintf(tmp_char, "%d", get_WIFI_RSSI());
MQTTPublish(maintopic + "/" + "wifiRSSI", std::string(tmp_char), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "wifiRSSI", std::string(tmp_char), retainFlag);
sprintf(tmp_char, "%d", (int)temperatureRead());
MQTTPublish(maintopic + "/" + "CPUtemp", std::string(tmp_char), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "CPUtemp", std::string(tmp_char), retainFlag);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all System MQTT topics");
return allSendsSuccessed;
}
void publishStaticData() {
if (!getMQTTisConnected())
return;
bool publishStaticData() {
bool allSendsSuccessed = false;
if (!getMQTTisConnected()) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Unable to send Static Topics, we are not connected to the MQTT broker!");
return false;
}
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);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "MAC", getMac(), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, retainFlag);
std::stringstream stream;
stream << std::fixed << std::setprecision(1) << roundInterval; // minutes
MQTTPublish(maintopic + "/" + "interval", stream.str(), retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "interval", stream.str(), retainFlag);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all Static MQTT topics");
return allSendsSuccessed;
}
esp_err_t sendDiscovery_and_static_Topics(httpd_req_t *req) {
bool success = false;
if (HomeassistantDiscovery) {
MQTThomeassistantDiscovery();
success = MQTThomeassistantDiscovery();
}
publishStaticData();
success |= publishStaticData();
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));
return ESP_OK;
if (success) {
char msg[] = "MQTT Homeassistant Discovery and Static Topics sent!";
httpd_resp_send(req, msg, strlen(msg));
return ESP_OK;
}
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more MQTT topics failed to be published!");
char msg[] = "Failed to send MQTT topics!";
httpd_resp_send(req, msg, strlen(msg));
return ESP_FAIL;
}
}
void GotConnected(std::string maintopic, bool retainFlag) {
if (HomeassistantDiscovery) {
MQTThomeassistantDiscovery();
static bool initialStaticOrHomeassistantDiscoveryTopicsGotSent = false;
bool success = false;
/* Only send Homeassistant Discovery and Static topics on the first time connecting */
if (!initialStaticOrHomeassistantDiscoveryTopicsGotSent) {
if (HomeassistantDiscovery) {
success = MQTThomeassistantDiscovery();
}
success |= publishStaticData();
if (success) {
/* Sending of all Homeassistant Discovery and Static Topics was successfull.
* Will no no longer send it on a re-connect!
* (But it is still possible to trigger sending through the REST API). */
initialStaticOrHomeassistantDiscoveryTopicsGotSent = true;
}
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more static or Homeassistant Discovery MQTT topics failed to be published! Will try again on the next round.");
}
}
publishStaticData();
publishSystemData();
/* The System Data changes at runtime, therefore we always send it after a re-connect */
success |= publishSystemData();
if (!success) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "One or more MQTT topics failed to be published!");
}
}
void register_server_mqtt_uri(httpd_handle_t server) {
@@ -236,7 +290,7 @@ void register_server_mqtt_uri(httpd_handle_t server) {
uri.uri = "/mqtt_publish_discovery";
uri.handler = sendDiscovery_and_static_Topics;
uri.user_ctx = (void*) "MQTT Discovery and Static Topics sent";
uri.user_ctx = (void*) "";
httpd_register_uri_handler(server, &uri);
}

View File

@@ -16,7 +16,7 @@ std::string mqttServer_getMainTopic();
void register_server_mqtt_uri(httpd_handle_t server);
void publishSystemData();
bool publishSystemData();
std::string getTimeUnit(void);
void GotConnected(std::string maintopic, bool SetRetainFlag);

View File

@@ -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;
@@ -370,64 +378,109 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
return ESP_OK;
}
zw = tfliteflow.getReadout(_rawValue, _noerror);
if (zw.length() > 0)
httpd_resp_sendstr_chunk(req, zw.c_str());
std::string *status = tfliteflow.getActStatus();
string query = std::string(_query);
// ESP_LOGD(TAG, "Query: %s, query.c_str());
if (query.find("full") != std::string::npos)
{
string txt;
txt = "<body style=\"font-family: arial\">";
if ((countRounds <= 1) && (*status != std::string("Flow finished"))) { // First round not completed yet
txt += "<h3>Please wait for the first round to complete!</h3><h3>Current state: " + *status + "</h3>\n";
}
else {
txt += "<h3>Value</h3>";
}
httpd_resp_sendstr_chunk(req, txt.c_str());
}
zw = tfliteflow.getReadout(_rawValue, _noerror);
if (zw.length() > 0)
httpd_resp_sendstr_chunk(req, zw.c_str());
if (query.find("full") != std::string::npos)
{
string txt, zw;
txt = "<p>Aligned Image: <p><img src=\"/img_tmp/alg_roi.jpg\"> <p>\n";
txt = txt + "Digital Counter: <p> ";
httpd_resp_sendstr_chunk(req, txt.c_str());
std::vector<HTMLInfo*> htmlinfodig;
htmlinfodig = tfliteflow.GetAllDigital();
for (int i = 0; i < htmlinfodig.size(); ++i)
{
if (tfliteflow.GetTypeDigital() == Digital)
if ((countRounds <= 1) && (*status != std::string("Flow finished"))) { // First round not completed yet
// Nothing to do
}
else {
/* Digital ROIs */
txt = "<body style=\"font-family: arial\">";
txt += "<h3>Recognized Digit ROIs (previous round)</h3>\n";
txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
std::vector<HTMLInfo*> htmlinfodig;
htmlinfodig = tfliteflow.GetAllDigital();
for (int i = 0; i < htmlinfodig.size(); ++i)
{
if (htmlinfodig[i]->val == 10)
zw = "NaN";
else
zw = to_string((int) htmlinfodig[i]->val);
if (tfliteflow.GetTypeDigital() == Digital)
{
if (htmlinfodig[i]->val == 10)
zw = "NaN";
else
zw = to_string((int) htmlinfodig[i]->val);
txt = "<img src=\"/img_tmp/" + htmlinfodig[i]->filename + "\"> " + zw;
txt += "<td style=\"width: 100px\"><h4>" + zw + "</h4><p><img src=\"/img_tmp/" + htmlinfodig[i]->filename + "\"></p></td>\n";
}
else
{
std::stringstream stream;
stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val;
zw = stream.str();
txt += "<td style=\"width: 100px\"><h4>" + zw + "</h4><p><img src=\"/img_tmp/" + htmlinfodig[i]->filename + "\"></p></td>\n";
}
delete htmlinfodig[i];
}
else
htmlinfodig.clear();
txt += "</tr></table>\n";
httpd_resp_sendstr_chunk(req, txt.c_str());
/* Analog ROIs */
txt = "<h3>Recognized Analog ROIs (previous round)</h3>\n";
txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
std::vector<HTMLInfo*> htmlinfoana;
htmlinfoana = tfliteflow.GetAllAnalog();
for (int i = 0; i < htmlinfoana.size(); ++i)
{
std::stringstream stream;
stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val;
stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val;
zw = stream.str();
txt = "<img src=\"/img_tmp/" + htmlinfodig[i]->filename + "\"> " + zw;
txt += "<td style=\"width: 150px;\"><h4>" + zw + "</h4><p><img src=\"/img_tmp/" + htmlinfoana[i]->filename + "\"></p></td>\n";
delete htmlinfoana[i];
}
htmlinfoana.clear();
txt += "</tr>\n</table>\n";
httpd_resp_sendstr_chunk(req, txt.c_str());
/* Full Image
* Only show it after the image got taken and aligned */
txt = "<h3>Aligned Image (current round)</h3>\n";
if ((*status == std::string("Initialization")) ||
(*status == std::string("Initialization (delayed)")) ||
(*status == std::string("Take Image"))) {
txt += "<p>Current state: " + *status + "</p>\n";
}
else {
txt += "<img src=\"/img_tmp/alg_roi.jpg\">\n";
}
httpd_resp_sendstr_chunk(req, txt.c_str());
delete htmlinfodig[i];
}
htmlinfodig.clear();
txt = " <p> Analog Meter: <p> ";
httpd_resp_sendstr_chunk(req, txt.c_str());
std::vector<HTMLInfo*> htmlinfoana;
htmlinfoana = tfliteflow.GetAllAnalog();
for (int i = 0; i < htmlinfoana.size(); ++i)
{
std::stringstream stream;
stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val;
zw = stream.str();
txt = "<img src=\"/img_tmp/" + htmlinfoana[i]->filename + "\"> " + zw;
httpd_resp_sendstr_chunk(req, txt.c_str());
delete htmlinfoana[i];
}
htmlinfoana.clear();
}
/* Respond with an empty chunk to signal HTTP response completion */
@@ -664,7 +717,7 @@ esp_err_t handler_statusflow(httpd_req_t *req)
ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
#endif
string* zw = tfliteflow.getActStatus();
string* zw = tfliteflow.getActStatusWithTime();
resp_str = zw->c_str();
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
@@ -807,21 +860,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();
@@ -861,16 +908,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)

View File

@@ -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);

View File

@@ -1,12 +1,24 @@
#include "connect_wlan.h"
#include <string.h>
#include <stdlib.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <iostream>
#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 <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include "ClassLogFile.h"
#include "read_wlanini.h"
#include "Helper.h"
#include "statusled.h"
//////////////////////
#include <string.h>
#include <stdlib.h>
#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();
}

View File

@@ -5,18 +5,11 @@
#include <string>
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

View File

@@ -11,9 +11,14 @@
#include <iostream>
#include <string.h>
#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<string> ZerlegeZeileWLAN(std::string input, std::string _delimiter = "")
{
@@ -40,207 +45,189 @@ std::vector<string> 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<string> 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<string> splitted;
std::vector<string> neuesfile;
bool found = false;
std::vector<string> 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<string> splitted;
std::vector<string> neuesfile;
bool found = false;
std::vector<string> 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

View File

@@ -5,8 +5,20 @@
#include <string>
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);

View File

@@ -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

View File

@@ -40,7 +40,10 @@
#ifdef ENABLE_MQTT
#include "server_mqtt.h"
#endif //ENABLE_MQTT
//#include "Helper.h"
#include "Helper.h"
#include "statusled.h"
#include "sdcard_check.h"
#include "../../include/defines.h"
//#include "server_GPIO.h"
@@ -83,16 +86,12 @@ extern std::string getFwVersion(void);
extern std::string getHTMLversion(void);
extern std::string getHTMLcommit(void);
std::vector<std::string> 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);
//bool replace_all(std::string& s, std::string const& toReplace, std::string const& replaceWith);
bool isInString(std::string& s, std::string const& toFind);
void migrateConfiguration(void);
static const char *TAG = "MAIN";
bool Init_NVS_SDCard()
{
esp_err_t ret = nvs_flash_init();
@@ -100,9 +99,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 +108,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 +132,324 @@ 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 log directories (if not already existing)
// ********************************************
LogFile.CreateLogDirectories(); // mandatory for logging + image saving
// ********************************************
// 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, "=================================================");
// SD card: basic R/W check
// ********************************************
int iSDCardStatus = SDCardCheckRW();
if (iSDCardStatus < 0) {
if (iSDCardStatus <= -1 && iSDCardStatus >= -2) { // write error
StatusLED(SDCARD_CHECK, 1, true);
}
else if (iSDCardStatus <= -3 && iSDCardStatus >= -5) { // read error
StatusLED(SDCARD_CHECK, 2, true);
}
else if (iSDCardStatus == -6) { // delete error
StatusLED(SDCARD_CHECK, 3, true);
}
setSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD); // reduced web interface going to be loaded
}
// Migrate parameter in config.ini to new naming (firmware 15.0 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: Create further mandatory directories (if not already existing)
// Correct creation of these folders will be checked with function "SDCardCheckFolderFilePresence"
// ********************************************
MakeDir("/sdcard/firmware"); // mandatory for OTA firmware update
MakeDir("/sdcard/img_tmp"); // mandatory for setting up alignment marks
MakeDir("/sdcard/demo"); // mandatory for demo mode
// 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 card empty; function does not exit anymore until reboot
// ********************************************
#ifdef ENABLE_SOFTAP
CheckStartAPMode();
#endif
// SD card: Check presence of some mandatory folders / files
// ********************************************
if (!SDCardCheckFolderFilePresence()) {
StatusLED(SDCARD_CHECK, 4, true);
setSystemStatusFlag(SYSTEM_STATUS_FOLDER_CHECK_BAD); // reduced web interface going to be loaded
}
// 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 +466,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");
isSetSystemStatusFlag(SYSTEM_STATUS_NTP_BAD)) {
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. Loading reduced web interface...");
}
}
@@ -435,7 +508,7 @@ void migrateConfiguration(void) {
if (configLines[i].find("[") != std::string::npos) { // Start of new section
section = configLines[i];
replace(section, ";", "", false); // Remove possible semicolon (just for the string comparison)
replaceString(section, ";", "", false); // Remove possible semicolon (just for the string comparison)
//ESP_LOGI(TAG, "New section: %s", section.c_str());
}
@@ -450,79 +523,79 @@ void migrateConfiguration(void) {
* - Only one whitespace before/after the equal sign
*/
if (section == "[MakeImage]") {
migrated = migrated | replace(configLines[i], "[MakeImage]", "[TakeImage]"); // Rename the section itself
migrated = migrated | replaceString(configLines[i], "[MakeImage]", "[TakeImage]"); // Rename the section itself
}
if (section == "[MakeImage]" || section == "[TakeImage]") {
migrated = migrated | replace(configLines[i], "LogImageLocation", "RawImagesLocation");
migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "RawImagesLocation");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
migrated = migrated | replace(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";Demo", "Demo"); // Enable it
migrated = migrated | replaceString(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";Demo", "Demo"); // Enable it
migrated = migrated | replace(configLines[i], ";FixedExposure = true", ";FixedExposure = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";FixedExposure", "FixedExposure"); // Enable it
migrated = migrated | replaceString(configLines[i], ";FixedExposure = true", ";FixedExposure = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";FixedExposure", "FixedExposure"); // Enable it
}
if (section == "[Alignment]") {
migrated = migrated | replace(configLines[i], ";InitialMirror = true", ";InitialMirror = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";InitialMirror", "InitialMirror"); // Enable it
migrated = migrated | replaceString(configLines[i], ";InitialMirror = true", ";InitialMirror = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";InitialMirror", "InitialMirror"); // Enable it
migrated = migrated | replace(configLines[i], ";FlipImageSize = true", ";FlipImageSize = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";FlipImageSize", "FlipImageSize"); // Enable it
migrated = migrated | replaceString(configLines[i], ";FlipImageSize = true", ";FlipImageSize = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";FlipImageSize", "FlipImageSize"); // Enable it
}
if (section == "[Digits]") {
migrated = migrated | replace(configLines[i], "LogImageLocation", "ROIImagesLocation");
migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
}
if (section == "[Analog]") {
migrated = migrated | replace(configLines[i], "LogImageLocation", "ROIImagesLocation");
migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
migrated = migrated | replace(configLines[i], "ExtendedResolution", ";UNUSED_PARAMETER"); // This parameter is no longer used
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
migrated = migrated | replaceString(configLines[i], "ExtendedResolution", ";UNUSED_PARAMETER"); // This parameter is no longer used
}
if (section == "[PostProcessing]") {
migrated = migrated | replace(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
migrated = migrated | replaceString(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
/* AllowNegativeRates has a <NUMBER> as prefix! */
if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) { // It is the parameter "AllowNegativeRates" and it is commented out
migrated = migrated | replace(configLines[i], "true", "false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";", ""); // Enable it
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
/* IgnoreLeadingNaN has a <NUMBER> as prefix! */
if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) { // It is the parameter "IgnoreLeadingNaN" and it is commented out
migrated = migrated | replace(configLines[i], "true", "false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";", ""); // Enable it
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
/* ExtendedResolution has a <NUMBER> as prefix! */
if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) { // It is the parameter "ExtendedResolution" and it is commented out
migrated = migrated | replace(configLines[i], "true", "false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";", ""); // Enable it
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
migrated = migrated | replace(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
migrated = migrated | replaceString(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
migrated = migrated | replace(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
}
if (section == "[MQTT]") {
migrated = migrated | replace(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
migrated = migrated | replace(configLines[i], ";RetainMessages = true", ";RetainMessages = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
migrated = migrated | replaceString(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
migrated = migrated | replaceString(configLines[i], ";RetainMessages = true", ";RetainMessages = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
migrated = migrated | replace(configLines[i], ";HomeassistantDiscovery = true", ";HomeassistantDiscovery = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery = true", ";HomeassistantDiscovery = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
if (configLines[i].rfind("Topic", 0) != std::string::npos) // only if string starts with "Topic" (Was the naming in very old version)
{
migrated = migrated | replace(configLines[i], "Topic", "MainTopic");
migrated = migrated | replaceString(configLines[i], "Topic", "MainTopic");
}
}
@@ -535,34 +608,34 @@ void migrateConfiguration(void) {
}
if (section == "[DataLogging]") {
migrated = migrated | replace(configLines[i], "DataLogRetentionInDays", "DataFilesRetention");
migrated = migrated | replaceString(configLines[i], "DataLogRetentionInDays", "DataFilesRetention");
/* DataLogActive is true by default! */
migrated = migrated | replace(configLines[i], ";DataLogActive = false", ";DataLogActive = true"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
migrated = migrated | replaceString(configLines[i], ";DataLogActive = false", ";DataLogActive = true"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
}
if (section == "[AutoTimer]") {
migrated = migrated | replace(configLines[i], "Intervall", "Interval");
migrated = migrated | replace(configLines[i], ";AutoStart = true", ";AutoStart = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";AutoStart", "AutoStart"); // Enable it
migrated = migrated | replaceString(configLines[i], "Intervall", "Interval");
migrated = migrated | replaceString(configLines[i], ";AutoStart = true", ";AutoStart = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";AutoStart", "AutoStart"); // Enable it
}
if (section == "[Debug]") {
migrated = migrated | replace(configLines[i], "Logfile ", "LogLevel "); // Whitespace needed so it does not match `LogfileRetentionInDays`
migrated = migrated | replaceString(configLines[i], "Logfile ", "LogLevel "); // Whitespace needed so it does not match `LogfileRetentionInDays`
/* LogLevel (resp. LogFile) was originally a boolean, but we switched it to an int
* For both cases (true/false), we set it to level 2 (WARNING) */
migrated = migrated | replace(configLines[i], "LogLevel = true", "LogLevel = 2");
migrated = migrated | replace(configLines[i], "LogLevel = false", "LogLevel = 2");
migrated = migrated | replace(configLines[i], "LogfileRetentionInDays", "LogfilesRetention");
migrated = migrated | replaceString(configLines[i], "LogLevel = true", "LogLevel = 2");
migrated = migrated | replaceString(configLines[i], "LogLevel = false", "LogLevel = 2");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "LogfilesRetention");
}
if (section == "[System]") {
migrated = migrated | replace(configLines[i], "RSSIThreashold", "RSSIThreshold");
migrated = migrated | replace(configLines[i], "AutoAdjustSummertime", ";UNUSED_PARAMETER"); // This parameter is no longer used
migrated = migrated | replaceString(configLines[i], "RSSIThreashold", "RSSIThreshold");
migrated = migrated | replaceString(configLines[i], "AutoAdjustSummertime", ";UNUSED_PARAMETER"); // This parameter is no longer used
migrated = migrated | replace(configLines[i], ";SetupMode = true", ";SetupMode = false"); // Set it to its default value
migrated = migrated | replace(configLines[i], ";SetupMode", "SetupMode"); // Enable it
migrated = migrated | replaceString(configLines[i], ";SetupMode = true", ";SetupMode = false"); // Set it to its default value
migrated = migrated | replaceString(configLines[i], ";SetupMode", "SetupMode"); // Enable it
}
}
@@ -623,33 +696,3 @@ std::vector<std::string> splitString(const std::string& str) {
return found;
}*/
bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
return replace(s, toReplace, replaceWith, true);
}
bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt) {
std::size_t pos = s.find(toReplace);
if (pos == std::string::npos) { // Not found
return false;
}
std::string old = s;
s.replace(pos, toReplace.length(), replaceWith);
if (logIt) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line '" + old + "' to '" + s + "'");
}
return true;
}
bool isInString(std::string& s, std::string const& toFind) {
std::size_t pos = s.find(toFind);
if (pos == std::string::npos) { // Not found
return false;
}
return true;
}

View File

@@ -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;
}
@@ -214,7 +215,10 @@ esp_err_t hello_main_handler(httpd_req_t *req)
if (filetosend == "/sdcard/html/index.html") {
if (isSetSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD) || // Initialization failed with crritical errors!
isSetSystemStatusFlag(SYSTEM_STATUS_CAM_BAD)) {
isSetSystemStatusFlag(SYSTEM_STATUS_CAM_BAD) ||
isSetSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD) ||
isSetSystemStatusFlag(SYSTEM_STATUS_FOLDER_CHECK_BAD))
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "We have a critical error, not serving main page!");
char buf[20];
@@ -227,13 +231,13 @@ esp_err_t hello_main_handler(httpd_req_t *req)
}
}
message += "<br>Please check <a href=\"https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes\" target=_blank>jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes</a> for more information!";
message += "<br>Please check logs with log viewer and/or <a href=\"https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes\" target=_blank>jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes</a> for more information!";
message += "<br><br><button onclick=\"window.location.href='/reboot';\">Reboot</button>";
message += "&nbsp;<button onclick=\"window.open('/ota_page.html');\">OTA Update</button>";
message += "&nbsp;<button onclick=\"window.open('/log.html');\">Log Viewer</button>";
message += "&nbsp;<button onclick=\"window.open('/info.html');\">Show System Info</button>";
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, message.c_str());
return ESP_FAIL;
httpd_resp_send(req, message.c_str(), message.length());
return ESP_OK;
}
else if (isSetupModusActive()) {
ESP_LOGD(TAG, "System is in setup mode --> index.html --> setup.html");

View File

@@ -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 = "</tr><tr><td> Hostname</td><td><input type=\"text\" name=\"hostname\" id=\"hostname\"></td><td></td>";
// message += "</tr><tr><td>Fixed IP</td><td><input type=\"text\" name=\"ip\" id=\"ip\"></td><td>Leave emtpy if set by router</td></tr>";
// message += "<tr><td>gateway</td><td><input type=\"text\" name=\"gateway\" id=\"gateway\"></td><td>Leave emtpy if set by router</td></tr>";
// message += "<tr><td>netmask</td><td><input type=\"text\" name=\"netmask\" id=\"netmask\"></td><td>Leave emtpy if set by router</td>";
// message += "</tr><tr><td>DNS</td><td><input type=\"text\" name=\"dns\" id=\"dns\"></td><td>Leave emtpy if set by router</td></tr>";
// message += "<tr><td>RSSI Threshold</td><td><input type=\"number\" name=\"name\" id=\"threshold\" min=\"-100\" max=\"0\" step=\"1\" value = \"0\"></td><td>WLAN 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)</td></tr>";
// message += "</tr><tr><td>Fixed IP</td><td><input type=\"text\" name=\"ip\" id=\"ip\"></td><td>Leave emtpy if set by router (DHCP)</td></tr>";
// message += "<tr><td>Gateway</td><td><input type=\"text\" name=\"gateway\" id=\"gateway\"></td><td>Leave emtpy if set by router (DHCP)</td></tr>";
// message += "<tr><td>Netmask</td><td><input type=\"text\" name=\"netmask\" id=\"netmask\"></td><td>Leave emtpy if set by router (DHCP)</td>";
// message += "</tr><tr><td>DNS</td><td><input type=\"text\" name=\"dns\" id=\"dns\"></td><td>Leave emtpy if set by router (DHCP)</td></tr>";
// message += "<tr><td>RSSI Threshold</td><td><input type=\"number\" name=\"name\" id=\"threshold\" min=\"-100\" max=\"0\" step=\"1\" value = \"0\"></td><td>WLAN 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)</td></tr>";
// httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str()));
message = "<button class=\"button\" type=\"button\" onclick=\"wr()\">Write wlan.ini</button>";
message += "<script language=\"JavaScript\">async function wr(){";
message += "api = \"/config?\"+\"ssid=\"+document.getElementById(\"ssid\").value+\"&pwd=\"+document.getElementById(\"password\").value;";
// message += "api = \"/config?\"+\"ssid=\"+document.getElementById(\"ssid\").value+\"&pwd=\"+document.getElementById(\"password\").value+\"&hn=\"+document.getElementById(\"hostname\").value+\"&ip=\"+document.getElementById(\"ip\").value+\"&gw=\"+document.getElementById(\"gateway\").value+\"&nm=\"+document.getElementById(\"netmask\").value+\"&dns=\"+document.getElementById(\"dns\").value+\"&rssi=\"+document.getElementById(\"threshold\").value;";
// message += "api = \"/config?\"+\"ssid=\"+document.getElementById(\"ssid\").value+\"&pwd=\"+document.getElementById(\"password\").value+\"&hn=\"+document.getElementById(\"hostname\").value+\"&ip=\"+document.getElementById(\"ip\").value+\"&gw=\"+document.getElementById(\"gateway\").value+\"&nm=\"+document.getElementById(\"netmask\").value+\"&dns=\"+document.getElementById(\"dns\").value+\"&rssithreshold=\"+document.getElementById(\"threshold\").value;";
message += "fetch(api);await new Promise(resolve => setTimeout(resolve, 1000));location.reload();}</script>";
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

View File

@@ -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