Files
waterlevel-software/lib/fetchOTA/fetchOTA.cpp
tobimai 3dc339c449
All checks were successful
Compilie project and upload binaries / test (push) Successful in 3m59s
fix ota upload
2025-11-05 22:08:42 +01:00

175 lines
5.9 KiB
C++

#ifndef UNIT_TEST
#include <fetchOTA.h>
#include "Arduino.h"
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <WiFiClient.h>
#include <vector>
#include <Elog.h>
#include <HTTPUpdate.h>
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<Configuration> configs;
for (JsonObject config : doc["Configurations"].as<JsonArray>()) {
if (config.containsKey("Version") && config.containsKey("URL") && config.containsKey("Config")) {
String deviceConfig = config["Config"].as<String>();
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<void()> callback_started, std::function<void()> callback_finished, std::function<void(int, int)> callback_progress, std::function<void(int)> 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<void()> callback_started, std::function<void()> callback_finished, std::function<void(int, int)> callback_progress, std::function<void(int)> 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