From d2ee7d1222c5a05248208556f071b5812d7d46ce Mon Sep 17 00:00:00 2001 From: tobimai Date: Sat, 27 Jun 2026 14:27:07 +0200 Subject: [PATCH] in between commit --- src/global_data/defines.h | 1 + src/global_data/global_data.h | 2 + src/main.cpp | 55 ++++++++++++++++---- src/networking/networking.cpp | 97 ++++++++++++++++++++++++++--------- src/networking/networking.h | 12 ++++- src/networking/webserver.cpp | 10 +++- src/tools/ota.cpp | 25 +++++---- src/tools/ota.h | 8 ++- 8 files changed, 160 insertions(+), 50 deletions(-) diff --git a/src/global_data/defines.h b/src/global_data/defines.h index e4365b2..ab295bc 100644 --- a/src/global_data/defines.h +++ b/src/global_data/defines.h @@ -3,6 +3,7 @@ #define ssid_key "ssid" #define wifi_password_key "wifi_password" +#define hostname_key "hostname" #define level_sensor_range_key "sensor_range" #define water_level_min_key "water_level_min" #define water_level_max_key "water_level_max" diff --git a/src/global_data/global_data.h b/src/global_data/global_data.h index de04a83..d53e8db 100644 --- a/src/global_data/global_data.h +++ b/src/global_data/global_data.h @@ -88,6 +88,7 @@ typedef struct { DeviceTelemetry telemetryData; /**< Latest telemetry data */ OTAStatus otaStatus; /**< Latest OTA status */ ActiveErrors activeErrors; /**< Latest active errors */ + Version spiffs_version; /**< Current SPIFFS version */ } CurrentState; // Enum to represent different types of data that can be sent between tasks @@ -113,6 +114,7 @@ typedef struct { float water_volume; /**< Total volume of the tank in liters */ char ssid[33]; /**< WiFi SSID (max 32 chars + null terminator) */ char wifi_password[65]; /**< WiFi password (max 64 chars + null terminator) */ + char hostname[33]; /**< Device hostname (max 32 chars + null terminator) */ } PreferencesData; // Union to hold different types of data diff --git a/src/main.cpp b/src/main.cpp index de79fce..5100835 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,13 +39,14 @@ Version current_spiffs_version; // Variable to store the current state of the system CurrentState current_state = { - {-999.0f, -999.0f, -999.0f}, - {-999.0f, -999.0f, -999.0f}, + {-999.0f, -999.0f, -999.0f}, // waterData + {-999.0f, -999.0f, -999.0f}, // sensorData {"0.0.0.0", false, -999.0f, "UNKNOWN"}, // wifiData {"0.0.0.0", false, -999.0f, "UNKNOWN"}, // ethernetData - {-999.0f, -999, -999.0f}, - {false, {0, 0, 0}, {0, 0, 0}, -999, "UNKNOWN"}, - {false, false, false, false, false, false} + {-999.0f, -999, -999.0f}, // telemetryData + {false, {0, 0, 0}, {0, 0, 0}, -999, "UNKNOWN"}, // otaStatus + {false, false, false, false, false, false}, // activeErrors + {0, 0, 0} // spiffs_version }; #define FORMAT_LITTLEFS_IF_FAILED true @@ -62,6 +63,9 @@ QueueHandle_t prefsForWebserverQueue = xQueueCreate(2, sizeof(DataMessage)); // Queue for sending preferences from main to sensor task QueueHandle_t prefsForSensorQueue = xQueueCreate(2, sizeof(DataMessage)); +// Queue for sending preferences from main to networking tasks +QueueHandle_t prefsForNetworkingQueue = xQueueCreate(2, sizeof(DataMessage)); + void setup() { Logger.registerSerial(MYLOG, ELOG_LEVEL_DEBUG, "Serial"); @@ -69,8 +73,8 @@ void setup() prefs.begin("waterlevel", false); Serial.begin(115200); - // Read initial preferences and send to webserver and sensor - if (prefsForWebserverQueue != NULL || prefsForSensorQueue != NULL) { + // Read initial preferences and send to webserver, sensor, and networking + if (prefsForWebserverQueue != NULL || prefsForSensorQueue != NULL || prefsForNetworkingQueue != NULL) { DataMessage prefsMessage; prefsMessage.type = DATA_TYPE_PREFERENCES; prefsMessage.data.preferencesData.level_sensor_range = prefs.getFloat(level_sensor_range_key, 200); @@ -81,6 +85,8 @@ void setup() prefsMessage.data.preferencesData.ssid[sizeof(prefsMessage.data.preferencesData.ssid) - 1] = '\0'; strncpy(prefsMessage.data.preferencesData.wifi_password, prefs.getString(wifi_password_key, "").c_str(), sizeof(prefsMessage.data.preferencesData.wifi_password) - 1); prefsMessage.data.preferencesData.wifi_password[sizeof(prefsMessage.data.preferencesData.wifi_password) - 1] = '\0'; + strncpy(prefsMessage.data.preferencesData.hostname, prefs.getString(hostname_key, "").c_str(), sizeof(prefsMessage.data.preferencesData.hostname) - 1); + prefsMessage.data.preferencesData.hostname[sizeof(prefsMessage.data.preferencesData.hostname) - 1] = '\0'; // Send to webserver if (prefsForWebserverQueue != NULL) { @@ -99,6 +105,15 @@ void setup() LOG(ELOG_LEVEL_DEBUG, "Sent initial preferences to sensor"); } } + + // Send to networking tasks + if (prefsForNetworkingQueue != NULL) { + if (xQueueSend(prefsForNetworkingQueue, &prefsMessage, 100 / portTICK_PERIOD_MS) != pdTRUE) { + LOG(ELOG_LEVEL_ERROR, "Failed to send initial preferences to networking queue"); + } else { + LOG(ELOG_LEVEL_DEBUG, "Sent initial preferences to networking"); + } + } } LOG(ELOG_LEVEL_DEBUG, "Beginning LittleFS"); @@ -112,6 +127,7 @@ void setup() } else { String version = file.readStringUntil('\n'); current_spiffs_version = parseVersion(version.c_str()); + current_state.spiffs_version = current_spiffs_version; LOG(ELOG_LEVEL_DEBUG, "Current LittleFS Version: %d.%d.%d", current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch); } LOG(ELOG_LEVEL_DEBUG, "LittleFS initialized"); @@ -121,8 +137,13 @@ void setup() if (dataQueue == NULL) { LOG(ELOG_LEVEL_ERROR, "Failed to create data queue"); } else { - xTaskCreate(ethernet_task, "EthernetTask", 1024 * 4, dataQueue, 1, NULL); - xTaskCreate(wifi_task, "WiFiTask", 1024 * 4, dataQueue, 1, NULL); + // Create networking queues struct (shared by wifi and ethernet tasks) + NetworkingQueues networkingQueues = { + .dataQueue = dataQueue, + .prefsQueue = prefsForNetworkingQueue + }; + xTaskCreate(ethernet_task, "EthernetTask", 1024 * 4, &networkingQueues, 1, NULL); + xTaskCreate(wifi_task, "WiFiTask", 1024 * 4, &networkingQueues, 1, NULL); // Create sensor queues struct SensorQueues sensorQueues = { .dataQueue = dataQueue, @@ -132,7 +153,12 @@ void setup() xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 1024 * 2, dataQueue, 1, NULL); xTaskCreate(display_task, "DisplayTask", 1024 * 2, NULL, 1, NULL); xTaskCreate(get_time_task, "GetTimeTask", 1024 * 2, NULL, 1, NULL); - xTaskCreate(check_update_task, "CheckUpdateTask", 1024 * 6, dataQueue, 1, NULL); + // Create check update task args with spiffs_version + CheckUpdateTaskArgs checkUpdateArgs = { + .dataQueue = dataQueue, + .spiffs_version = current_spiffs_version + }; + xTaskCreate(check_update_task, "CheckUpdateTask", 1024 * 6, &checkUpdateArgs, 1, NULL); // Create webserver queues struct WebserverQueues webserverQueues = { .stateQueue = stateForWebserverQueue, @@ -214,7 +240,14 @@ void loop() LOG(ELOG_LEVEL_ERROR, "Failed to forward preferences to sensor queue"); } } - LOG(ELOG_LEVEL_DEBUG, "Stored preferences and forwarded to tasks"); + + // Forward to networking tasks so they can update their local copy + if (prefsForNetworkingQueue != NULL) { + if (xQueueSend(prefsForNetworkingQueue, &dataMessage, 100 / portTICK_PERIOD_MS) != pdTRUE) { + LOG(ELOG_LEVEL_ERROR, "Failed to forward preferences to networking queue"); + } + } + LOG(ELOG_LEVEL_DEBUG, "Stored preferences and forwarded to all tasks"); break; default: LOG(ELOG_LEVEL_ERROR, "Unknown data type received"); diff --git a/src/networking/networking.cpp b/src/networking/networking.cpp index 7a71247..0adcac4 100644 --- a/src/networking/networking.cpp +++ b/src/networking/networking.cpp @@ -1,10 +1,10 @@ #include #include #include "../global_data/defines.h" -#include #include "../global_data/global_data.h" #include #include "freertos/queue.h" +#include "networking.h" #define ETH_PHY_TYPE ETH_PHY_LAN8720 #define ETH_PHY_ADDR 0 @@ -22,7 +22,13 @@ uint8_t failed_connection_attempts = 0; NetworkData wifi_data; NetworkData ethernet_data; -extern Preferences prefs; +// Local preference storage +static char local_hostname[33] = ""; +static char local_ssid[33] = ""; +static char local_wifi_password[65] = ""; + +// Queue handle for receiving preference updates +static QueueHandle_t g_prefsQueue = NULL; // Defines the type of connection for which the hostname should be created enum HostnameType { @@ -32,33 +38,60 @@ enum HostnameType { }; const char * get_hostname(HostnameType host_type) { - String default_hostname = "Waterlevel-" + String(mac_address, HEX); - String hostname = prefs.getString("hostname", default_hostname); + String hostname_str = String(local_hostname); + if (hostname_str.length() == 0) { + hostname_str = "Waterlevel-" + String(mac_address, HEX); + } + + static char hostname_buffer[64]; switch (host_type) { case Wireless: - return (hostname + "-wl").c_str(); + snprintf(hostname_buffer, sizeof(hostname_buffer), "%s-wl", hostname_str.c_str()); + break; case Ethernet: - return (hostname + "-eth").c_str(); + snprintf(hostname_buffer, sizeof(hostname_buffer), "%s-eth", hostname_str.c_str()); + break; default: - return hostname.c_str(); + snprintf(hostname_buffer, sizeof(hostname_buffer), "%s", hostname_str.c_str()); + break; } + return hostname_buffer; } void wifi_task(void* parameter) { - // Extract the queue handle from the task parameters - QueueHandle_t dataQueue = (QueueHandle_t)parameter; - if (dataQueue == NULL) { - LOG(ELOG_LEVEL_ERROR, "Data queue is NULL"); + // Extract the queue handles from the task parameters + NetworkingQueues* queues = (NetworkingQueues*)parameter; + if (queues == NULL || queues->dataQueue == NULL) { + LOG(ELOG_LEVEL_ERROR, "Queue parameters are NULL"); vTaskDelete(NULL); return; } + // Store queue handles + QueueHandle_t dataQueue = queues->dataQueue; + g_prefsQueue = queues->prefsQueue; + LOG(ELOG_LEVEL_DEBUG, "Starting WiFi Task"); WiFi.setHostname(get_hostname(Wireless)); while (true) { - if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5) { + // Check for preference updates first + DataMessage prefsMessage; + if (g_prefsQueue != NULL && xQueueReceive(g_prefsQueue, &prefsMessage, 0) == pdTRUE) { + if (prefsMessage.type == DATA_TYPE_PREFERENCES) { + // Update local preference values + strncpy(local_ssid, prefsMessage.data.preferencesData.ssid, sizeof(local_ssid) - 1); + local_ssid[sizeof(local_ssid) - 1] = '\0'; + strncpy(local_wifi_password, prefsMessage.data.preferencesData.wifi_password, sizeof(local_wifi_password) - 1); + local_wifi_password[sizeof(local_wifi_password) - 1] = '\0'; + strncpy(local_hostname, prefsMessage.data.preferencesData.hostname, sizeof(local_hostname) - 1); + local_hostname[sizeof(local_hostname) - 1] = '\0'; + LOG(ELOG_LEVEL_DEBUG, "Updated networking preferences: ssid=%s, hostname=%s", local_ssid, local_hostname); + } + } + + if (local_ssid[0] == '\0' || failed_connection_attempts > 5) { wifi_data.link = false; if (failed_connection_attempts > 5) { LOG(ELOG_LEVEL_WARNING, "Failed to connect to currently saved SSID, starting SoftAP"); @@ -71,14 +104,14 @@ void wifi_task(void* parameter) LOG(ELOG_LEVEL_DEBUG, "Waiting for SSID now..."); - String old_ssid = prefs.getString(ssid_key, "xxx"); - while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid) { + String old_ssid = String(local_ssid); + while (local_ssid[0] == '\0' || String(local_ssid) == old_ssid) { delay(5000); } failed_connection_attempts = 0; } else { - if (WiFi.isConnected() && WiFi.SSID() == prefs.getString(ssid_key, "")) { + if (WiFi.isConnected() && WiFi.SSID() == String(local_ssid)) { failed_connection_attempts = 0; wifi_data.rssi = WiFi.RSSI(); wifi_data.link = true; @@ -97,14 +130,12 @@ void wifi_task(void* parameter) LOG(ELOG_LEVEL_ERROR, "Failed to send WiFi data to queue"); } - LOG(ELOG_LEVEL_DEBUG, "WIFI connected; RSSI: %F, IP Address, %s, SSID: %s", float(WiFi.RSSI()), WiFi.localIP().toString(), prefs.getString(ssid_key, "NOSSID")); + LOG(ELOG_LEVEL_DEBUG, "WIFI connected; RSSI: %F, IP Address, %s, SSID: %s", float(WiFi.RSSI()), WiFi.localIP().toString(), local_ssid); delay(1000 * 60); } else { - String ssid = prefs.getString(ssid_key, ""); - String password = prefs.getString(wifi_password_key, ""); - LOG(ELOG_LEVEL_DEBUG, "Connecting to %s...", ssid); + LOG(ELOG_LEVEL_DEBUG, "Connecting to %s...", local_ssid); WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); + WiFi.begin(local_ssid, local_wifi_password); failed_connection_attempts++; LOG(ELOG_LEVEL_WARNING, "Failed to connect, retrying..."); delay(5000); @@ -115,18 +146,35 @@ void wifi_task(void* parameter) void ethernet_task(void* parameter) { - // Extract the queue handle from the task parameters - QueueHandle_t dataQueue = (QueueHandle_t)parameter; - if (dataQueue == NULL) { - LOG(ELOG_LEVEL_ERROR, "Data queue is NULL"); + // Extract the queue handles from the task parameters + NetworkingQueues* queues = (NetworkingQueues*)parameter; + if (queues == NULL || queues->dataQueue == NULL) { + LOG(ELOG_LEVEL_ERROR, "Queue parameters are NULL"); vTaskDelete(NULL); return; } + // Store queue handles + QueueHandle_t dataQueue = queues->dataQueue; + g_prefsQueue = queues->prefsQueue; + LOG(ELOG_LEVEL_DEBUG, "Starting Ethernet Task"); ETH.begin(); ETH.setHostname(get_hostname(Ethernet)); while (true) { + // Check for preference updates first + DataMessage prefsMessage; + if (g_prefsQueue != NULL && xQueueReceive(g_prefsQueue, &prefsMessage, 0) == pdTRUE) { + if (prefsMessage.type == DATA_TYPE_PREFERENCES) { + // Update local preference values + strncpy(local_hostname, prefsMessage.data.preferencesData.hostname, sizeof(local_hostname) - 1); + local_hostname[sizeof(local_hostname) - 1] = '\0'; + // Update hostname on Ethernet interface + ETH.setHostname(get_hostname(Ethernet)); + LOG(ELOG_LEVEL_DEBUG, "Updated networking preferences: hostname=%s", local_hostname); + } + } + ethernet_data.link = ETH.linkUp(); ethernet_data.rssi = ETH.linkSpeed(); strncpy(ethernet_data.ip_address, ETH.localIP().toString().c_str(), sizeof(ethernet_data.ip_address) - 1); @@ -146,6 +194,7 @@ void ethernet_task(void* parameter) if (ETH.linkUp() && !ETH.isDefault() && ETH.localIP().toString() != "0.0.0.0") { LOG(ELOG_LEVEL_DEBUG, "Ethernet is up, setting to default"); + ETH.setHostname(get_hostname(Ethernet)); ETH.setDefault(); } diff --git a/src/networking/networking.h b/src/networking/networking.h index 1bcd3dc..1db8126 100644 --- a/src/networking/networking.h +++ b/src/networking/networking.h @@ -1,2 +1,10 @@ -void wifi_task(void*); -void ethernet_task(void*); \ No newline at end of file +#include + +// Structure to hold queue handles for networking tasks +typedef struct { + QueueHandle_t dataQueue; + QueueHandle_t prefsQueue; +} NetworkingQueues; + +void wifi_task(void* parameter); +void ethernet_task(void* parameter); \ No newline at end of file diff --git a/src/networking/webserver.cpp b/src/networking/webserver.cpp index f367743..d79ea71 100644 --- a/src/networking/webserver.cpp +++ b/src/networking/webserver.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "tools/log.h" #include "AsyncJson.h" #include @@ -43,6 +42,9 @@ float local_water_volume = 10000.0f; char local_ssid[33] = ""; char local_wifi_password[65] = ""; +// Local SPIFFS version storage +static Version local_spiffs_version = {0, 0, 0}; + ReadersWriterLock waterDataLock; ReadersWriterLock sensorDataLock; ReadersWriterLock networkDataLock; @@ -191,7 +193,8 @@ void setup_api_endpoints(){ } static TaskArgs_t args = { - .ota_status = local_ota_status + .ota_status = local_ota_status, + .spiffs_version = local_spiffs_version }; xTaskCreate(run_ota_update_task, "RunOTAUpdate", 1024 * 8, (void *)&args, 1, NULL); @@ -456,6 +459,9 @@ void webserver_task(void *pvParameters) { rwLockAcquireWrite(&otaStatusLock); local_ota_status = currentState.otaStatus; rwLockReleaseWrite(&otaStatusLock); + + // Update local SPIFFS version + local_spiffs_version = currentState.spiffs_version; } } } \ No newline at end of file diff --git a/src/tools/ota.cpp b/src/tools/ota.cpp index fe220e6..7cb0dfb 100644 --- a/src/tools/ota.cpp +++ b/src/tools/ota.cpp @@ -2,7 +2,6 @@ #include "ota.h" #include #include "../global_data/defines.h" -#include #include #include #include @@ -14,8 +13,6 @@ #define BOARD_VARIANT "INA233REV2" #endif -extern Version current_spiffs_version; - // OTA Callbacks void update_started() { LOG(ELOG_LEVEL_DEBUG, "OTA Update started"); @@ -36,8 +33,16 @@ void update_error(int err) { } void check_update_task(void* parameter) { - // Extract the queue handle from the task parameters - QueueHandle_t dataQueue = (QueueHandle_t)parameter; + // Extract the queue handle and spiffs_version from the task parameters + CheckUpdateTaskArgs* args = (CheckUpdateTaskArgs*)parameter; + if (args == NULL || args->dataQueue == NULL) { + LOG(ELOG_LEVEL_ERROR, "Invalid parameters for check_update_task"); + vTaskDelete(NULL); + return; + } + + QueueHandle_t dataQueue = args->dataQueue; + Version spiffs_version = args->spiffs_version; OTAStatus ota_status; LOG(ELOG_LEVEL_DEBUG, "Starting check Update Task"); @@ -51,7 +56,7 @@ void check_update_task(void* parameter) { // Check if internet connection exists before running update, the web client seems to fail otherwise if (check_for_internet_connection()) { LOG(ELOG_LEVEL_DEBUG, "Ping sucessful, starting update checks"); - check_and_update_littleFS(littlefs_ota); + check_and_update_littleFS(littlefs_ota, spiffs_version); check_for_new_version(ota, &ota_status); } else { LOG(ELOG_LEVEL_WARNING, "Server did not respond to ping, waiting..."); @@ -70,15 +75,15 @@ void check_update_task(void* parameter) { } } -void check_and_update_littleFS(OTA littlefs) { +void check_and_update_littleFS(OTA littlefs, Version current_spiffs_version_param) { Firmware latest_fs_version = littlefs.getLatestVersionOnServer(); - LOG(ELOG_LEVEL_DEBUG, "Required SPIFFS Version: %d.%d.%d; Current SPIFFS version: %d.%d.%d; Server SPIFFS Version: %d.%d.%d", REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch, current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch, latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch); + LOG(ELOG_LEVEL_DEBUG, "Required SPIFFS Version: %d.%d.%d; Current SPIFFS version: %d.%d.%d; Server SPIFFS Version: %d.%d.%d", REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch, current_spiffs_version_param.major, current_spiffs_version_param.minor, current_spiffs_version_param.patch, latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch); if (latest_fs_version.valid) { // If we need new version and the server has a new version - if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION) && isVersionNewer(current_spiffs_version, latest_fs_version.version)) { + if (isVersionNewer(current_spiffs_version_param, REQUIRED_SPIFFS_VERSION) && isVersionNewer(current_spiffs_version_param, latest_fs_version.version)) { LOG(ELOG_LEVEL_DEBUG, "New SPIFFS version, running update now"); run_ota_spiffs_update(latest_fs_version.url, update_started, update_finished, update_progress, update_error); @@ -87,7 +92,7 @@ void check_and_update_littleFS(OTA littlefs) { LOG(ELOG_LEVEL_DEBUG, "New SPIFFS version available: %d.%d.%d, current version: %d.%d.%d but not necessary to update", latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch, REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch); // If we need a new version but server has no new version - } else if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION)) { + } else if (isVersionNewer(current_spiffs_version_param, REQUIRED_SPIFFS_VERSION)) { LOG(ELOG_LEVEL_ERROR, "New LittleFS Version is needed, but not found on server"); // Catch case for the rest diff --git a/src/tools/ota.h b/src/tools/ota.h index a1563bc..33fe48c 100644 --- a/src/tools/ota.h +++ b/src/tools/ota.h @@ -15,13 +15,19 @@ void update_error(int err); // OTA Update functions void check_update_task(void* parameter); void run_ota_update_task(void* parameter); -void check_and_update_littleFS(OTA littlefs); +void check_and_update_littleFS(OTA littlefs, Version current_spiffs_version); void check_for_new_version(OTA ota, OTAStatus *status); bool check_for_internet_connection(); // OTA Handler task void ota_handler_task(void *pvParameters); +// Struct for check_update_task parameters +typedef struct { + QueueHandle_t dataQueue; + Version spiffs_version; +} CheckUpdateTaskArgs; + typedef struct { OTAStatus ota_status; Version spiffs_version;