diff --git a/lib/fetchOTA/fetchOTA.cpp b/lib/fetchOTA/fetchOTA.cpp index 5381a80..fed3703 100644 --- a/lib/fetchOTA/fetchOTA.cpp +++ b/lib/fetchOTA/fetchOTA.cpp @@ -13,6 +13,7 @@ OTA::OTA(String server_url, Version currentVersion, String currentDeviceConfigur _serverUrl = server_url; _currentVersion = currentVersion; _current_device_configuration = currentDeviceConfiguration; + _current_device_configuration.toLowerCase(); } @@ -42,6 +43,7 @@ Firmware OTA::getLatestVersionOnServer() { for (JsonObject config : doc["Configurations"].as()) { if (config.containsKey("Version") && config.containsKey("URL") && config.containsKey("Config")) { String deviceConfig = config["Config"].as(); + deviceConfig.toLowerCase(); if (deviceConfig == _current_device_configuration) { configs.push_back(Configuration{ parseVersion(config["Version"]), @@ -107,7 +109,6 @@ void run_ota_update(String url, std::function callback_started, std::fu Log.error("URL is not valid: \n%s", url.c_str()); } - switch (ret) { case HTTP_UPDATE_FAILED: Log.error("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); @@ -123,6 +124,45 @@ void run_ota_update(String url, std::function callback_started, std::fu } } +void run_ota_spiffs_update(String url, std::function callback_started, std::function callback_finished, std::function callback_progress, std::function callback_error) { + Log.verbose("Starting OTA SPIFFS upgrade"); + HTTPUpdate httpUpdate; + httpUpdate.onStart(callback_started); + httpUpdate.onEnd(callback_finished); + httpUpdate.onProgress(callback_progress); + httpUpdate.onError(callback_error); + Log.verbose("Defined callbacks, Starting update now"); + + t_httpUpdate_return ret; + + if (url.startsWith("https")) { + Log.verbose("HTTPS URL"); + WiFiClientSecure client; + client.setInsecure(); + ret = httpUpdate.updateSpiffs(client, url); + } else if (url.startsWith("http")) { + Log.verbose("HTTP URL"); + WiFiClient client; + ret = httpUpdate.updateSpiffs(client, url); + } else { + Log.error("URL is not valid: \n%s", url.c_str()); + } + + switch (ret) { + case HTTP_UPDATE_FAILED: + Log.error("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); + break; + + case HTTP_UPDATE_NO_UPDATES: + Log.error("HTTP_UPDATE_NO_UPDATES"); + break; + + case HTTP_UPDATE_OK: + Log.verbose("SPIFFS Update done"); + break; + } +} + #endif \ No newline at end of file diff --git a/lib/fetchOTA/fetchOTA.h b/lib/fetchOTA/fetchOTA.h index 5920ebf..6fc2c50 100644 --- a/lib/fetchOTA/fetchOTA.h +++ b/lib/fetchOTA/fetchOTA.h @@ -27,5 +27,6 @@ class OTA { }; void run_ota_update(String url, std::function callback_started, std::function callback_finished, std::function callback_progress, std::function callback_error); +void run_ota_spiffs_update(String url, std::function callback_started, std::function callback_finished, std::function callback_progress, std::function callback_error); #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 1a43a4a..7b7b81e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,6 +22,7 @@ lib_deps = jsc/ArduinoLog fetchOTA INA322 + ESP32Ping board_build.partitions = default.csv upload_protocol = espota upload_port = 192.168.5.181 @@ -37,6 +38,7 @@ lib_deps = robtillaart/INA226@^0.4.4 bblanchon/ArduinoJson@^6.21.3 jsc/ArduinoLog + ESP32Ping board_build.partitions = default.csv upload_protocol = espota upload_port = 192.168.5.181 diff --git a/src/global_data/defines.h b/src/global_data/defines.h index 02cd248..1c6ee8f 100644 --- a/src/global_data/defines.h +++ b/src/global_data/defines.h @@ -7,6 +7,7 @@ #define water_level_min_key "water_level_min" #define water_level_max_key "water_level_max" #define water_volume_key "water_volume" -#define current_software_version Version{0, 0, 12} +#define current_software_version Version{0, 0, 14} +#define REQUIRED_SPIFFS_VERSION Version{2, 0, 0} #define RESISTOR_VALUE 4 \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d40a984..6638e4d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include "networking/json_builder.h" #include "networking/responses.h" #include +#include Preferences prefs; @@ -35,23 +36,11 @@ extern SensorData shunt_data; extern "C" int rom_phy_get_vdd33(); +Version current_spiffs_version; + AsyncWebServer server(80); #define FORMAT_LITTLEFS_IF_FAILED true - - - void run_ota(void* parameter) { - // OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", "1.1.1", "INA233"); - // Firmware fw = ota.getLatestVersionOnServer(); - // Log.verbose("we are done"); - // Serial.printf("Firmware Info: Valid: %d, Version: %d.%d.%d, URL: %s\n", fw.valid, fw.version.major, fw.version.minor, fw.version.patch, fw.url.c_str()); - // Log.verbose("Error message: %s", fw.error.c_str()); - // ota.run_ota_update(fw.url, update_started, update_finished, update_progress, update_error); - vTaskDelete(NULL); - } - - - void setup() { prefs.begin("waterlevel", false); @@ -75,6 +64,19 @@ void setup() Log.verbose("Beginning SPIFFS"); SPIFFS.begin(true); + + // Read the current SPIFFS version from the versions file on the spiffs + File file = SPIFFS.open("/version", FILE_READ); + if (!file) { + Serial.println("Failed to open version file for reading"); + } else { + String version = file.readStringUntil('\n'); + Log.verbose("Version: %s", version); + current_spiffs_version = parseVersion(version.c_str()); + Log.verbose("Current SPIFFS Version: %d.%d.%d", current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch); + } + + Log.verbose("SPIFFS initialized"); display_error_code(19); @@ -162,13 +164,6 @@ void setup() } request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating }); - - server.on("/ota", HTTP_GET, [](AsyncWebServerRequest* request) { - Serial.println("OTA Task start"); - xTaskCreate(run_ota, "OTATask", 1024 * 8, NULL, 1, NULL); - - request->send(200, "text/plain", "OTA done"); - }); setup_api_endpoints(); @@ -220,6 +215,22 @@ void setup() xTaskCreate(display_task, "DisplayTask", 10000, NULL, 1, NULL); xTaskCreate(read_sensor_task, "ReadSensorTask", 2048, NULL, 1, NULL); xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 2048, NULL, 1, NULL); + + // Wait until there is network connection + while (true) { + if (WiFi.status() == WL_CONNECTED || ETH.localIP()) { + int pingResult = Ping.ping("8.8.8.8"); // Use Google's public DNS server as a test IP + if (pingResult >= 0) { + Log.verbose("Network connection established"); + break; + } else { + Log.verbose("Network not ready, retrying..."); + } + } else { + Log.verbose("No WiFi or Ethernet connection, retrying..."); + } + delay(200); // Delay to prevent rapid retry + } xTaskCreate(check_update_task, "CheckUpdateTask", 1024 * 8, NULL, 1, NULL); } diff --git a/src/tools/tools.cpp b/src/tools/tools.cpp index e71b342..2b6c074 100644 --- a/src/tools/tools.cpp +++ b/src/tools/tools.cpp @@ -8,6 +8,8 @@ extern Preferences prefs; extern OTAStatus ota_status; +extern Version current_spiffs_version; + void printSuffix(Print* _logOutput, int logLevel) { _logOutput->print(CR); @@ -74,6 +76,30 @@ void check_update_task(void* parameter) { #else OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", current_software_version, "INA233"); #endif + OTA spiffs_fs("https://iot.tobiasmaier.me/filesystem/waterlevel", REQUIRED_SPIFFS_VERSION, "generic"); + + // Init SPIFFS update and check for update + // If there is a SPIFSS update it will be ran automatically, as SPIFFS is necessary for the firmware to run + Firmware latest_spiff_version = spiffs_fs.getLatestVersionOnServer(); + + Log.verbose("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_spiff_version.version.major, latest_spiff_version.version.minor, latest_spiff_version.version.patch); + + if (latest_spiff_version.valid) { + if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION)) { + // If Required SPIFFS version is newer than current version, update + Log.verbose("New SPIFFS version, running update now"); + run_ota_spiffs_update(latest_spiff_version.url, update_started, update_finished, update_progress, update_error); + // Reboot just to be safe + ESP.restart(); + } else if (isVersionNewer(REQUIRED_SPIFFS_VERSION, latest_spiff_version.version)) { + // If Server has new SPIFFS version but it's not required + Log.verbose("New SPIFFS version available: %d.%d.%d, current version: %d.%d.%d but not necessary to update", latest_spiff_version.version.major, latest_spiff_version.version.minor, latest_spiff_version.version.patch, REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch); + } else { + Log.verbose("No new SPIFFS version available"); + } + } + + while (true) { Firmware fw = ota.getLatestVersionOnServer(); if (fw.valid) { diff --git a/src/tools/tools.h b/src/tools/tools.h index 7956d3d..12098d2 100644 --- a/src/tools/tools.h +++ b/src/tools/tools.h @@ -12,4 +12,5 @@ void run_ota_update_task(void* parameter); typedef struct { OTAStatus ota_status; + Version spiffs_version; } TaskArgs_t; \ No newline at end of file