mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-02 12:07:02 +00:00
refactoring
This commit is contained in:
@@ -261,7 +261,7 @@ uint8_t WebStatusService::upgradeImportantMessages(std::string & version) {
|
|||||||
|
|
||||||
// it's a filename with a .bin or .md extension, try and extract the version from it
|
// it's a filename with a .bin or .md extension, try and extract the version from it
|
||||||
// e.g. EMS-ESP-3_8_2-dev_13-ESP32-16MB+.bin -> major=3 minor=8 patch=2
|
// e.g. EMS-ESP-3_8_2-dev_13-ESP32-16MB+.bin -> major=3 minor=8 patch=2
|
||||||
version::EMSESP_Version latest_version;
|
FirmwareVersion latest_version;
|
||||||
if ((version.find(".bin") != std::string::npos) || (version.find(".md") != std::string::npos)) {
|
if ((version.find(".bin") != std::string::npos) || (version.find(".md") != std::string::npos)) {
|
||||||
std::string filename = version;
|
std::string filename = version;
|
||||||
auto pos = filename.find("EMS-ESP-");
|
auto pos = filename.find("EMS-ESP-");
|
||||||
@@ -282,18 +282,18 @@ uint8_t WebStatusService::upgradeImportantMessages(std::string & version) {
|
|||||||
std::string major_version = filename.substr(pos, underscore1 - pos);
|
std::string major_version = filename.substr(pos, underscore1 - pos);
|
||||||
std::string minor_version = filename.substr(underscore1 + 1, underscore2 - underscore1 - 1);
|
std::string minor_version = filename.substr(underscore1 + 1, underscore2 - underscore1 - 1);
|
||||||
std::string patch_version = filename.substr(underscore2 + 1, dash - underscore2 - 1);
|
std::string patch_version = filename.substr(underscore2 + 1, dash - underscore2 - 1);
|
||||||
latest_version = version::EMSESP_Version(major_version + "." + minor_version + "." + patch_version);
|
latest_version = FirmwareVersion(major_version + "." + minor_version + "." + patch_version);
|
||||||
} else {
|
} else {
|
||||||
// if it's .json file exit
|
// if it's .json file exit
|
||||||
if (version.find(".json") != std::string::npos) {
|
if (version.find(".json") != std::string::npos) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
// treat it like a version string like "3.9.0"
|
// treat it like a version string like "3.9.0"
|
||||||
latest_version = version::EMSESP_Version(version);
|
latest_version = FirmwareVersion(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version::EMSESP_Version current_version(current_version_s); // get current version
|
FirmwareVersion current_version(current_version_s); // get current version
|
||||||
|
|
||||||
if ((current_version.major() <= 3 && current_version.minor() <= 8) && (latest_version.major() == 3 && latest_version.minor() == 9)) {
|
if ((current_version.major() <= 3 && current_version.minor() <= 8) && (latest_version.major() == 3 && latest_version.minor() == 9)) {
|
||||||
return 1; // if moving from below 3.8.x to 3.9.x return 1
|
return 1; // if moving from below 3.8.x to 3.9.x return 1
|
||||||
@@ -311,15 +311,12 @@ uint8_t WebStatusService::upgradeImportantMessages(std::string & version) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// action = getVersions
|
// action = getVersions
|
||||||
// returns the device's current version info plus the cached "stable" and "dev"
|
// returns the device's current version for dev and stable
|
||||||
// entries from emsesp.org/versions.json. The remote fetch is NOT done here: it
|
// The remote fetch runs from the main loop task via WebStatusService::loop() so that we never block the AsyncTCP callback
|
||||||
// runs from the main loop task via WebStatusService::loop() so we never block
|
|
||||||
// the AsyncTCP callback (which has a tiny ~6 KB stack — far too small for an
|
|
||||||
// HTTPS handshake). If we have no cached data yet (no internet, fetch still
|
|
||||||
// pending, parse error) the "stable" and "dev" sections are simply omitted so
|
|
||||||
// the client can detect the offline case.
|
|
||||||
void WebStatusService::getVersions(JsonObject root) {
|
void WebStatusService::getVersions(JsonObject root) {
|
||||||
version::EMSESP_Version current_version(current_version_s);
|
schedule_versions_refresh(); // force a refresh
|
||||||
|
|
||||||
|
FirmwareVersion current_version(current_version_s);
|
||||||
bool is_dev = current_version.prerelease().find("dev") != std::string::npos;
|
bool is_dev = current_version.prerelease().find("dev") != std::string::npos;
|
||||||
|
|
||||||
JsonObject current = root["current"].to<JsonObject>();
|
JsonObject current = root["current"].to<JsonObject>();
|
||||||
@@ -347,8 +344,7 @@ void WebStatusService::getVersions(JsonObject root) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copies a cached entry into root[key]. The upgradeable bool was computed
|
// copies a cached entry into root[key]
|
||||||
// once during refresh_versions_cache() so we just read it here.
|
|
||||||
auto add_section = [&](const char * key, const VersionInfo & info) {
|
auto add_section = [&](const char * key, const VersionInfo & info) {
|
||||||
if (info.version.empty()) {
|
if (info.version.empty()) {
|
||||||
return;
|
return;
|
||||||
@@ -366,17 +362,17 @@ void WebStatusService::getVersions(JsonObject root) {
|
|||||||
JsonObject stable_out = root["stable"].to<JsonObject>();
|
JsonObject stable_out = root["stable"].to<JsonObject>();
|
||||||
stable_out["version"] = "3.8.2";
|
stable_out["version"] = "3.8.2";
|
||||||
stable_out["date"] = "2026-04-25";
|
stable_out["date"] = "2026-04-25";
|
||||||
stable_out["upgradeable"] = version::EMSESP_Version("3.8.2") > current_version;
|
stable_out["upgradeable"] = FirmwareVersion("3.8.2") > current_version;
|
||||||
|
|
||||||
JsonObject dev_out = root["dev"].to<JsonObject>();
|
JsonObject dev_out = root["dev"].to<JsonObject>();
|
||||||
dev_out["version"] = "3.8.3-dev.2";
|
dev_out["version"] = "3.8.3-dev.2";
|
||||||
dev_out["date"] = "2026-04-25";
|
dev_out["date"] = "2026-04-25";
|
||||||
dev_out["upgradeable"] = version::EMSESP_Version("3.8.3-dev.2") > current_version;
|
dev_out["upgradeable"] = FirmwareVersion("3.8.3-dev.2") > current_version;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// periodic refresh (1 hour) of the cached versions.json. Runs on the main loop task,
|
// periodic refresh (1 hour) of the cached versions.json
|
||||||
// which has a much bigger stack than AsyncTCP, so it's safe to do HTTPS here.
|
// runs on the main loop task, which has a much bigger stack than AsyncTCP needed for https
|
||||||
void WebStatusService::loop() {
|
void WebStatusService::loop() {
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
// need a network
|
// need a network
|
||||||
@@ -384,25 +380,17 @@ void WebStatusService::loop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t now = uuid::get_uptime();
|
// 0 = idle, nothing scheduled
|
||||||
|
|
||||||
// first call after we have a network: schedule the initial fetch a little
|
|
||||||
// later so we give NTP / DNS a chance to settle
|
|
||||||
if (versions_next_fetch_ms_ == 0) {
|
if (versions_next_fetch_ms_ == 0) {
|
||||||
versions_next_fetch_ms_ = now + VERSIONS_INITIAL_DELAY_MS;
|
|
||||||
if (versions_next_fetch_ms_ == 0) {
|
|
||||||
versions_next_fetch_ms_ = 1; // avoid the "never scheduled" sentinel
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not time yet (signed difference handles uint32 wrap)
|
// not time yet (signed difference handles uint32 wrap)
|
||||||
if ((int32_t)(now - versions_next_fetch_ms_) < 0) {
|
if ((int32_t)(uuid::get_uptime() - versions_next_fetch_ms_) < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = refresh_versions_cache();
|
bool ok = refresh_versions_cache();
|
||||||
|
|
||||||
uint32_t next = uuid::get_uptime() + (ok ? VERSIONS_REFRESH_INTERVAL_MS : VERSIONS_RETRY_INTERVAL_MS);
|
uint32_t next = uuid::get_uptime() + (ok ? VERSIONS_REFRESH_INTERVAL_MS : VERSIONS_RETRY_INTERVAL_MS);
|
||||||
if (next == 0) {
|
if (next == 0) {
|
||||||
next = 1;
|
next = 1;
|
||||||
@@ -421,14 +409,18 @@ bool WebStatusService::refresh_versions_cache() {
|
|||||||
http.setTimeout(5000);
|
http.setTimeout(5000);
|
||||||
http.useHTTP10(true);
|
http.useHTTP10(true);
|
||||||
|
|
||||||
if (!http.begin("https://emsesp.org/versions.json")) {
|
if (!http.begin(EMSESP_VERSIONS_URL)) {
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
EMSESP::logger().debug("versions.json: failed to start HTTPS request");
|
EMSESP::logger().debug("versions.json: failed to start HTTPS request");
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
if (httpCode != HTTP_CODE_OK) {
|
if (httpCode != HTTP_CODE_OK) {
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
EMSESP::logger().debug("versions.json: HTTP %d", httpCode);
|
EMSESP::logger().debug("versions.json: HTTP %d", httpCode);
|
||||||
|
#endif
|
||||||
http.end();
|
http.end();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -437,11 +429,13 @@ bool WebStatusService::refresh_versions_cache() {
|
|||||||
DeserializationError err = deserializeJson(doc, http.getStream());
|
DeserializationError err = deserializeJson(doc, http.getStream());
|
||||||
http.end();
|
http.end();
|
||||||
if (err) {
|
if (err) {
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
EMSESP::logger().debug("versions.json: parse error (%s)", err.c_str());
|
EMSESP::logger().debug("versions.json: parse error (%s)", err.c_str());
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
version::EMSESP_Version current_version(current_version_s);
|
FirmwareVersion current_version(current_version_s);
|
||||||
|
|
||||||
auto read_section = [&doc, ¤t_version](const char * key, VersionInfo & out) {
|
auto read_section = [&doc, ¤t_version](const char * key, VersionInfo & out) {
|
||||||
JsonObjectConst section = doc[key];
|
JsonObjectConst section = doc[key];
|
||||||
@@ -451,7 +445,7 @@ bool WebStatusService::refresh_versions_cache() {
|
|||||||
}
|
}
|
||||||
out.version = section["version"] | "";
|
out.version = section["version"] | "";
|
||||||
out.date = section["date"] | "";
|
out.date = section["date"] | "";
|
||||||
out.upgradeable = !out.version.empty() && version::EMSESP_Version(out.version) > current_version;
|
out.upgradeable = !out.version.empty() && FirmwareVersion(out.version) > current_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
read_section("stable", versions_stable_);
|
read_section("stable", versions_stable_);
|
||||||
@@ -459,7 +453,10 @@ bool WebStatusService::refresh_versions_cache() {
|
|||||||
|
|
||||||
versions_cache_valid_ = true;
|
versions_cache_valid_ = true;
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
EMSESP::logger().debug("versions.json refreshed (stable=%s dev=%s)", versions_stable_.version.c_str(), versions_dev_.version.c_str());
|
EMSESP::logger().debug("versions.json: refreshed (stable=%s dev=%s), current=%s",
|
||||||
|
versions_stable_.version.c_str(),
|
||||||
|
versions_dev_.version.c_str(),
|
||||||
|
current_version_s.c_str());
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
@@ -470,7 +467,7 @@ bool WebStatusService::current_upgradeable() const {
|
|||||||
if (!versions_cache_valid_) {
|
if (!versions_cache_valid_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
version::EMSESP_Version current_version(current_version_s);
|
FirmwareVersion current_version(current_version_s);
|
||||||
bool is_dev = current_version.prerelease().find("dev") != std::string::npos;
|
bool is_dev = current_version.prerelease().find("dev") != std::string::npos;
|
||||||
return is_dev ? versions_dev_.upgradeable : versions_stable_.upgradeable;
|
return is_dev ? versions_dev_.upgradeable : versions_stable_.upgradeable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#define EMSESP_SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
#define EMSESP_SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
||||||
#define EMSESP_ACTION_SERVICE_PATH "/rest/action"
|
#define EMSESP_ACTION_SERVICE_PATH "/rest/action"
|
||||||
|
|
||||||
#include "../core/EMSESP_Version.h"
|
#define EMSESP_VERSIONS_URL "http://emsesp.org/versions.json"
|
||||||
|
|
||||||
|
#include "../core/firmwareVersion.h"
|
||||||
#include "../emsesp_version.h"
|
#include "../emsesp_version.h"
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
@@ -19,8 +21,8 @@ class WebStatusService {
|
|||||||
return current_version_s;
|
return current_version_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from EMSESP::loop() to refresh the cached versions.json from emsesp.org so that the web
|
// called from EMSESP::loop() to refresh the cached versions.json from emsesp.org
|
||||||
// request handler never has to do blocking HTTPS on the small AsyncTCP stack
|
// so that the web request handler never has to do blocking HTTPS on the small AsyncTCP stack
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
// true once we've had at least one successful versions.json fetch
|
// true once we've had at least one successful versions.json fetch
|
||||||
@@ -28,6 +30,11 @@ class WebStatusService {
|
|||||||
return versions_cache_valid_;
|
return versions_cache_valid_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refresh the versions.json cache
|
||||||
|
void schedule_versions_refresh() {
|
||||||
|
versions_next_fetch_ms_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
bool current_upgradeable() const; // true if a newer version is available
|
bool current_upgradeable() const; // true if a newer version is available
|
||||||
|
|
||||||
// make action function public so we can test in the debug and standalone mode
|
// make action function public so we can test in the debug and standalone mode
|
||||||
@@ -60,13 +67,12 @@ class WebStatusService {
|
|||||||
VersionInfo versions_stable_;
|
VersionInfo versions_stable_;
|
||||||
VersionInfo versions_dev_;
|
VersionInfo versions_dev_;
|
||||||
bool versions_cache_valid_ = false; // true once we've had at least one successful fetch
|
bool versions_cache_valid_ = false; // true once we've had at least one successful fetch
|
||||||
uint32_t versions_next_fetch_ms_ = 0; // uuid::get_uptime() of the next attempt; 0 = ASAP
|
uint32_t versions_next_fetch_ms_ = 0; // uuid::get_uptime() of the next attempt; 0 = idle
|
||||||
|
|
||||||
bool refresh_versions_cache(); // does the actual HTTPS fetch + parse, returns true on success
|
bool refresh_versions_cache(); // does the actual HTTPS fetch + parse, returns true on success
|
||||||
|
|
||||||
static constexpr uint32_t VERSIONS_REFRESH_INTERVAL_MS = 60UL * 60UL * 1000UL; // 1 hour on success
|
static constexpr uint32_t VERSIONS_REFRESH_INTERVAL_MS = 60UL * 60UL * 1000UL; // 1 hour on success
|
||||||
static constexpr uint32_t VERSIONS_RETRY_INTERVAL_MS = 5UL * 60UL * 1000UL; // 5 min after failure
|
static constexpr uint32_t VERSIONS_RETRY_INTERVAL_MS = 5UL * 60UL * 1000UL; // 5 min after failure
|
||||||
static constexpr uint32_t VERSIONS_INITIAL_DELAY_MS = 30UL * 1000UL; // wait 30s after boot
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
Reference in New Issue
Block a user