#ifndef UNIT_TEST #include #include "Arduino.h" #include #include #include #include #include OTA::OTA(String server_url, Version currentVersion, String currentDeviceConfiguration) { _serverUrl = server_url; _currentVersion = currentVersion; _current_device_configuration = currentDeviceConfiguration; _current_device_configuration.toLowerCase(); } Firmware OTA::getLatestVersionOnServer() { HTTPClient http; http.begin(_serverUrl); int httpCode = http.GET(); if (httpCode != 200) { return createErrorResponse("HTTP GET request failed with code " + String(httpCode)); } String payload = http.getString(); Log.verbose("Payload: %s", payload.c_str()); DynamicJsonDocument doc(4096); DeserializationError error = deserializeJson(doc, payload); if (error) { return createErrorResponse("Failed to deserialize JSON"); } if (!doc.containsKey("Configurations")) { return createErrorResponse("JSON response does not contain a 'Configurations' key"); } std::vector configs; 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"]), config["URL"], config["Board"], deviceConfig }); } else { Log.verbose("Configuration %s does not match current device configuration %s", deviceConfig.c_str(), _current_device_configuration.c_str()); } } } if (configs.empty()) { return createErrorResponse("No valid configuration found in the JSON response"); } Configuration latest = getLatestConfiguration(configs.data(), configs.size()); if (!isVersionNewer(_currentVersion, latest.version)) { Log.verbose("No newer version found. Server version: %d.%d.%d", latest.version.major, latest.version.minor, latest.version.patch); } return Firmware{ latest.version, latest.url, true, "" }; } Firmware OTA::createErrorResponse(const String& errorMsg) { return Firmware{ Version{0, 0, 0}, "", false, errorMsg }; } void run_ota_update(String url, std::function callback_started, std::function callback_finished, std::function callback_progress, std::function callback_error) { Log.verbose("Starting OTA 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.update(client, url); } else if (url.startsWith("http")) { Log.verbose("HTTP URL"); WiFiClient client; ret = httpUpdate.update(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("Update done"); break; } } 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