#ifndef UNIT_TEST #include #include "Arduino.h" #include #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(); Logger.log(0, ELOG_LEVEL_DEBUG, "HTTP Code: %d", httpCode); if (httpCode != 200) { return createErrorResponse("HTTP GET request failed with code " + String(httpCode)); } String payload = http.getString(); Logger.log(0, ELOG_LEVEL_DEBUG, "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 { Logger.log(0, ELOG_LEVEL_DEBUG, "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)) { Logger.log(0, ELOG_LEVEL_DEBUG, "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) { Logger.log(0, ELOG_LEVEL_DEBUG, "Starting OTA upgrade"); Logger.log(0, ELOG_LEVEL_DEBUG, "URL: %s", url); HTTPUpdate httpUpdate; httpUpdate.onStart(callback_started); httpUpdate.onEnd(callback_finished); httpUpdate.onProgress(callback_progress); httpUpdate.onError(callback_error); Logger.log(0, ELOG_LEVEL_DEBUG, "Defined callbacks, Starting update now"); t_httpUpdate_return ret; if (url.startsWith("https")) { Logger.log(0, ELOG_LEVEL_DEBUG, "HTTPS URL"); HTTPClient http_client; http_client.begin(url); ret = httpUpdate.update(http_client, url); } else if (url.startsWith("http")) { Logger.log(0, ELOG_LEVEL_DEBUG, "HTTP URL"); HTTPClient http_client; http_client.begin(url); ret = httpUpdate.update(http_client, url); } else { Logger.log(0, ELOG_LEVEL_ERROR, "URL is not valid: \n%s", url.c_str()); } switch (ret) { case HTTP_UPDATE_FAILED: Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break; case HTTP_UPDATE_NO_UPDATES: Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_NO_UPDATES"); break; case HTTP_UPDATE_OK: Logger.log(0, ELOG_LEVEL_DEBUG, "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) { Logger.log(0, ELOG_LEVEL_DEBUG, "Starting OTA SPIFFS upgrade"); HTTPUpdate httpUpdate; httpUpdate.onStart(callback_started); httpUpdate.onEnd(callback_finished); httpUpdate.onProgress(callback_progress); httpUpdate.onError(callback_error); Logger.log(0, ELOG_LEVEL_DEBUG, "Defined callbacks, Starting update now"); t_httpUpdate_return ret; if (url.startsWith("https")) { Logger.log(0, ELOG_LEVEL_DEBUG, "HTTPS URL"); HTTPClient http_client; http_client.begin(url); // client.setInsecure(); ret = httpUpdate.updateSpiffs(http_client, url); } else if (url.startsWith("http")) { Logger.log(0, ELOG_LEVEL_DEBUG, "HTTP URL"); HTTPClient http_client; http_client.begin(url); ret = httpUpdate.updateSpiffs(http_client, url); } else { Logger.log(0, ELOG_LEVEL_ERROR, "URL is not valid: \n%s", url.c_str()); } switch (ret) { case HTTP_UPDATE_FAILED: Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break; case HTTP_UPDATE_NO_UPDATES: Logger.log(0, ELOG_LEVEL_ERROR, "HTTP_UPDATE_NO_UPDATES"); break; case HTTP_UPDATE_OK: Logger.log(0, ELOG_LEVEL_DEBUG, "SPIFFS Update done"); break; } } #endif