This commit is contained in:
76
lib/fetchOTA/fetchOTA.cpp
Normal file
76
lib/fetchOTA/fetchOTA.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#ifndef UNIT_TEST
|
||||
#include <fetchOTA.h>
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
OTA::OTA(String server_url, String currentVersion, String currentDeviceConfiguration) {
|
||||
_serverUrl = server_url;
|
||||
_currentVersion = parseVersion(currentVersion.c_str());
|
||||
_current_device_configuration = currentDeviceConfiguration;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
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")) {
|
||||
configs.push_back(Configuration{
|
||||
parseVersion(config["Version"]),
|
||||
config["URL"],
|
||||
config["Board"],
|
||||
config["Configuration"]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (configs.empty()) {
|
||||
return createErrorResponse("No valid configuration found in the JSON response");
|
||||
}
|
||||
|
||||
Configuration latest = getLatestConfiguration(configs.data(), configs.size());
|
||||
return Firmware{
|
||||
latest.version,
|
||||
latest.url,
|
||||
true,
|
||||
""
|
||||
};
|
||||
}
|
||||
|
||||
Firmware OTA::createErrorResponse(const String& errorMsg) {
|
||||
return Firmware{
|
||||
Version{0, 0, 0},
|
||||
"",
|
||||
false,
|
||||
errorMsg
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
27
lib/fetchOTA/fetchOTA.h
Normal file
27
lib/fetchOTA/fetchOTA.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef UNIT_TEST
|
||||
#include <utils.h>
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
#include<ArduinoFake.h>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class OTA {
|
||||
public:
|
||||
OTA(String server_url, String currentVersion, String currentDeviceConfiguration);
|
||||
Firmware getLatestVersionOnServer();
|
||||
|
||||
bool checkForUpdate();
|
||||
|
||||
private:
|
||||
bool _isHTTPS = false;
|
||||
String _serverUrl;
|
||||
Version _currentVersion;
|
||||
String _current_device_configuration;
|
||||
Firmware createErrorResponse(const String& errorMsg);
|
||||
};
|
||||
|
||||
#endif
|
||||
33
lib/fetchOTA/utils.cpp
Normal file
33
lib/fetchOTA/utils.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <utils.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Version parseVersion(const char *versionStr) {
|
||||
Version v = {0, 0, 0}; // Initialize with default values
|
||||
|
||||
// Buffer to check for any extra content
|
||||
char extraContent;
|
||||
// Try to extract three integers and check for non-numeric trailing characters
|
||||
int parsedCount = sscanf(versionStr, "%d.%d.%d%c", &v.major, &v.minor, &v.patch, &extraContent);
|
||||
|
||||
// If parsed count is not 3, or there is an extra character, mark as invalid
|
||||
if (parsedCount > 3) {
|
||||
v.major = v.minor = v.patch = 0;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
Configuration getLatestConfiguration(Configuration *configs, int count) {
|
||||
Configuration latest = configs[0];
|
||||
for (int i = 1; i < count; i++) {
|
||||
const Version ¤tVersion = configs[i].version;
|
||||
const Version &latestVersion = latest.version;
|
||||
|
||||
// Compare the versions stored in the Configuration structs
|
||||
if (currentVersion.major > latestVersion.major ||
|
||||
(currentVersion.major == latestVersion.major && currentVersion.minor > latestVersion.minor) ||
|
||||
(currentVersion.major == latestVersion.major && currentVersion.minor == latestVersion.minor && currentVersion.patch > latestVersion.patch)) {
|
||||
latest = configs[i];
|
||||
}
|
||||
}
|
||||
return latest;
|
||||
}
|
||||
29
lib/fetchOTA/utils.h
Normal file
29
lib/fetchOTA/utils.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifdef UNIT_TEST
|
||||
#include <string>
|
||||
typedef std::string String;
|
||||
#else
|
||||
#include <WString.h>
|
||||
#endif
|
||||
|
||||
struct Version {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
};
|
||||
|
||||
struct Firmware {
|
||||
Version version;
|
||||
String url;
|
||||
bool valid;
|
||||
String error;
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
Version version;
|
||||
String url;
|
||||
String Board;
|
||||
String Config;
|
||||
};
|
||||
|
||||
Version parseVersion(const char *versionStr);
|
||||
Configuration getLatestConfiguration(Configuration *configs, int count);
|
||||
Reference in New Issue
Block a user