diff --git a/interface/src/AuthenticatedRouting.tsx b/interface/src/AuthenticatedRouting.tsx
index 43f03d00a..7fd3701b1 100644
--- a/interface/src/AuthenticatedRouting.tsx
+++ b/interface/src/AuthenticatedRouting.tsx
@@ -58,7 +58,7 @@ const AuthenticatedRouting = () => {
} />
} />
} />
- } />
+ } />
} />
} />
diff --git a/interface/src/app/main/Customizations.tsx b/interface/src/app/main/Customizations.tsx
index b8f3aaef0..3fcb102b0 100644
--- a/interface/src/app/main/Customizations.tsx
+++ b/interface/src/app/main/Customizations.tsx
@@ -38,7 +38,7 @@ import {
import { useTheme } from '@table-library/react-table-library/theme';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
-import RestartMonitor from 'app/status/RestartMonitor';
+import SystemMonitor from 'app/status/SystemMonitor';
import {
BlockNavigation,
ButtonRow,
@@ -737,7 +737,7 @@ const Customizations = () => {
return (
{blocker ? : null}
- {restarting ? : renderContent()}
+ {restarting ? : renderContent()}
{selectedDeviceEntity && (
{
return (
{blocker ? : null}
- {restarting ? : content()}
+ {restarting ? : content()}
);
};
diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx
index 7bb1d8dca..b32850e1d 100644
--- a/interface/src/app/settings/DownloadUpload.tsx
+++ b/interface/src/app/settings/DownloadUpload.tsx
@@ -9,7 +9,7 @@ import { API, callAction } from 'api/app';
import { useRequest } from 'alova/client';
import type { APIcall } from 'app/main/types';
-import RestartMonitor from 'app/status/RestartMonitor';
+import SystemMonitor from 'app/status/SystemMonitor';
import {
FormLoader,
SectionContent,
@@ -123,7 +123,7 @@ const DownloadUpload = () => {
};
return (
- {restarting ? : content()}
+ {restarting ? : content()}
);
};
diff --git a/interface/src/app/settings/Settings.tsx b/interface/src/app/settings/Settings.tsx
index 7aba45df7..96d25853b 100644
--- a/interface/src/app/settings/Settings.tsx
+++ b/interface/src/app/settings/Settings.tsx
@@ -151,7 +151,7 @@ const Settings = () => {
bgcolor="#5d89f7"
label={LL.DOWNLOAD_UPLOAD()}
text={LL.DOWNLOAD_UPLOAD_1()}
- to="upload"
+ to="downloadUpload"
/>
diff --git a/interface/src/app/settings/Version.tsx b/interface/src/app/settings/Version.tsx
index c17804e50..c3c954b5f 100644
--- a/interface/src/app/settings/Version.tsx
+++ b/interface/src/app/settings/Version.tsx
@@ -24,7 +24,7 @@ import { getDevVersion, getStableVersion } from 'api/system';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
-import RestartMonitor from 'app/status/RestartMonitor';
+import SystemMonitor from 'app/status/SystemMonitor';
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
@@ -224,7 +224,7 @@ const Version = () => {
<>
- Firmware Version
+ Firmware {LL.VERSION()}
{
};
return (
- {restarting ? : content()}
+ {restarting ? : content()}
);
};
diff --git a/interface/src/app/settings/network/NetworkSettings.tsx b/interface/src/app/settings/network/NetworkSettings.tsx
index c521b116e..65283817d 100644
--- a/interface/src/app/settings/network/NetworkSettings.tsx
+++ b/interface/src/app/settings/network/NetworkSettings.tsx
@@ -43,7 +43,7 @@ import { updateValueDirty, useRest } from 'utils';
import { validate } from 'validators';
import { createNetworkSettingsValidator } from 'validators/network';
-import RestartMonitor from '../../status/RestartMonitor';
+import SystemMonitor from '../../status/SystemMonitor';
import { WiFiConnectionContext } from './WiFiConnectionContext';
import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector';
@@ -400,7 +400,7 @@ const NetworkSettings = () => {
return (
{blocker ? : null}
- {restarting ? : content()}
+ {restarting ? : content()}
);
};
diff --git a/interface/src/app/status/RestartMonitor.tsx b/interface/src/app/status/RestartMonitor.tsx
deleted file mode 100644
index 7006776b0..000000000
--- a/interface/src/app/status/RestartMonitor.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { useState } from 'react';
-
-import {
- Box,
- CircularProgress,
- Dialog,
- DialogContent,
- Typography
-} from '@mui/material';
-
-import { readSystemStatus } from 'api/system';
-
-import { dialogStyle } from 'CustomTheme';
-import { useRequest } from 'alova/client';
-import MessageBox from 'components/MessageBox';
-import { useI18nContext } from 'i18n/i18n-react';
-import { useInterval } from 'utils';
-
-const RestartMonitor = () => {
- const [errorMessage, setErrorMessage] = useState();
-
- const { LL } = useI18nContext();
-
- let count = 0;
-
- const { data, send } = useRequest(readSystemStatus, {
- force: true,
- initialData: { status: 'Getting ready...' },
- async middleware(_, next) {
- if (count++ >= 1) {
- // skip first request (1 second) to allow AsyncWS to send its response
- await next();
- }
- }
- })
- .onSuccess((event) => {
- if (event.data.status === 'ready' || event.data.status === undefined) {
- document.location.href = '/';
- }
- })
- .onError((error) => {
- setErrorMessage(error.message);
- });
-
- useInterval(() => {
- void send();
- }, 1000); // check every second
-
- return (
-
- );
-};
-
-export default RestartMonitor;
diff --git a/interface/src/app/status/Status.tsx b/interface/src/app/status/Status.tsx
index 97613c837..cfc7c93f2 100644
--- a/interface/src/app/status/Status.tsx
+++ b/interface/src/app/status/Status.tsx
@@ -40,7 +40,7 @@ import { NTPSyncStatus, NetworkConnectionStatus } from 'types';
import { useInterval } from 'utils';
import { formatDateTime } from 'utils/time';
-import RestartMonitor from './RestartMonitor';
+import SystemMonitor from './SystemMonitor';
const SystemStatus = () => {
const { LL } = useI18nContext();
@@ -349,7 +349,7 @@ const SystemStatus = () => {
};
return (
- {restarting ? : content()}
+ {restarting ? : content()}
);
};
diff --git a/interface/src/app/status/SystemMonitor.tsx b/interface/src/app/status/SystemMonitor.tsx
new file mode 100644
index 000000000..3fc607bb1
--- /dev/null
+++ b/interface/src/app/status/SystemMonitor.tsx
@@ -0,0 +1,122 @@
+import { useState } from 'react';
+
+import CancelIcon from '@mui/icons-material/Cancel';
+import {
+ Box,
+ Button,
+ CircularProgress,
+ Dialog,
+ DialogContent,
+ Typography
+} from '@mui/material';
+
+import { callAction } from 'api/app';
+import { readSystemStatus } from 'api/system';
+
+import { dialogStyle } from 'CustomTheme';
+import { useRequest } from 'alova/client';
+import MessageBox from 'components/MessageBox';
+import { useI18nContext } from 'i18n/i18n-react';
+import { SystemStatusCodes } from 'types';
+import { useInterval } from 'utils';
+
+const SystemMonitor = () => {
+ const [errorMessage, setErrorMessage] = useState();
+
+ const { LL } = useI18nContext();
+
+ let count = 0;
+
+ const { send: setSystemStatus } = useRequest(
+ (status: string) => callAction({ action: 'systemStatus', param: status }),
+ {
+ immediate: false
+ }
+ );
+
+ const { data, send } = useRequest(readSystemStatus, {
+ force: true,
+ async middleware(_, next) {
+ if (count++ >= 1) {
+ // skip first request (1 second) to allow AsyncWS to send its response
+ await next();
+ }
+ }
+ })
+ .onSuccess((event) => {
+ if (
+ event.data.status === SystemStatusCodes.SYSTEM_STATUS_NORMAL ||
+ event.data.status === undefined
+ ) {
+ document.location.href = '/';
+ } else if (
+ event.data.status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD
+ ) {
+ setErrorMessage('Please check system logs for possible causes');
+ }
+ })
+ .onError((error) => {
+ setErrorMessage(error.message);
+ });
+
+ useInterval(() => {
+ void send();
+ }, 1000); // check every second
+
+ const onCancel = () => {
+ setErrorMessage(undefined);
+ setSystemStatus(SystemStatusCodes.SYSTEM_STATUS_NORMAL as unknown as string);
+ document.location.href = '/';
+ };
+
+ return (
+
+ );
+};
+
+export default SystemMonitor;
diff --git a/interface/src/types/system.ts b/interface/src/types/system.ts
index 8b0023881..9b1f5dcf1 100644
--- a/interface/src/types/system.ts
+++ b/interface/src/types/system.ts
@@ -2,6 +2,17 @@ import type { busConnectionStatus } from 'app/main/types';
import type { NetworkConnectionStatus } from './network';
+export enum SystemStatusCodes {
+ SYSTEM_STATUS_NORMAL = 0,
+ SYSTEM_STATUS_PENDING_UPLOAD = 1,
+ SYSTEM_STATUS_UPLOADING = 2,
+ SYSTEM_STATUS_ERROR_UPLOAD = 3,
+ SYSTEM_STATUS_RESTARTING = 4,
+ SYSTEM_STATUS_ERROR = 5,
+ SYSTEM_STATUS_PENDING_RESTART = 6,
+ SYSTEM_STATUS_RESTART_REQUESTED = 7
+}
+
export interface SystemStatus {
emsesp_version: string;
bus_status: busConnectionStatus;
@@ -41,7 +52,7 @@ export interface SystemStatus {
model: string;
has_loader: boolean;
has_partition: boolean;
- status: string;
+ status: number; // SystemStatusCodes which matches SYSTEM_STATUS in System.h
temperature?: number;
}
diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts
index d7b3e7596..d7221e81e 100644
--- a/mock-api/rest_server.ts
+++ b/mock-api/rest_server.ts
@@ -70,7 +70,6 @@ let settings = {
let system_status = {
emsesp_version: 'XX.XX.XX', // defined later
bus_status: 0,
- // status: 2,
uptime: 77186,
bus_uptime: 77121,
num_devices: 2,
@@ -108,7 +107,8 @@ let system_status = {
has_loader: true,
model: '',
// model: 'BBQKees Electronics EMS Gateway E32 V2 (E32 V2.0 P3/2024011)',
- status: 'downloading'
+ // status: 0,
+ status: 3
};
let VERSION_IS_UPGRADEABLE: boolean;
diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp
index 14d0ae020..3d82b458c 100644
--- a/src/ESP32React/UploadFileService.cpp
+++ b/src/ESP32React/UploadFileService.cpp
@@ -118,7 +118,8 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
request->_tempFile.close(); // close the file handle as the upload is now done
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
- emsesp::EMSESP::system_.restart_pending(true); // will be handled by the main loop. We use pending for the Web's RestartMonitor
+ emsesp::EMSESP::system_.systemStatus(
+ emsesp::SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART); // will be handled by the main loop. We use pending for the Web's SystemMonitor
return;
}
@@ -127,7 +128,8 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
if (_is_firmware && !request->_tempObject) {
AsyncWebServerResponse * response = request->beginResponse(200);
request->send(response);
- emsesp::EMSESP::system_.restart_pending(true); // will be handled by the main loop. We use pending for the Web's RestartMonitor
+ emsesp::EMSESP::system_.systemStatus(
+ emsesp::SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART); // will be handled by the main loop. We use pending for the Web's SystemMonitor
return;
}
diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp
index af90e7bd1..0f7dd6ccd 100644
--- a/src/core/emsesp.cpp
+++ b/src/core/emsesp.cpp
@@ -1734,29 +1734,34 @@ void EMSESP::loop() {
esp32React.loop(); // web services
system_.loop(); // does LED and checks system health, and syslog service
- // if we're doing an OTA upload, skip everything except from console refresh
- static bool upload_status = true; // ready for any OTA uploads
- if (!system_.upload_isrunning()) {
+ // run the loop, unless we're in the middle of an OTA upload
+ if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_NORMAL) {
// service loops
webLogService.loop(); // log in Web UI
rxservice_.loop(); // process any incoming Rx telegrams
shower_.loop(); // check for shower on/off
temperaturesensor_.loop(); // read sensor temperatures
analogsensor_.loop(); // read analog sensor values
- publish_all_loop(); // with HA messages in parts to avoid flooding the mqtt queue
+ publish_all_loop(); // with HA messages in parts to avoid flooding the MQTT queue
mqtt_.loop(); // sends out anything in the MQTT queue
webModulesService.loop(); // loop through the external library modules
if (system_.PSram() == 0) { // run non-async if there is no PSRAM available
webSchedulerService.loop();
}
-
scheduled_fetch_values(); // force a query on the EMS devices to fetch latest data at a set interval (1 min)
+ }
- } else if (upload_status) {
- // start an upload from a URL, if it exists. This is blocking.
- if (!system_.uploadFirmwareURL()) {
- upload_status = false; // abort all other attempts, until reset (after a restart normally)
- system_.upload_isrunning(false);
+ if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_PENDING_UPLOAD) {
+ // start an upload from a URL, assuming if the URL exists from a previous pass.
+ // Note this function is synchronous and blocking.
+ if (system_.uploadFirmwareURL()) {
+ // firmware has been uploaded, set status to uploading
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_UPLOADING);
+ } else {
+ // if it fails to pass, reset
+ Shell::loop_all(); // flush log buffers so latest error message are shown in console
+ system_.uploadFirmwareURL("reset");
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_ERROR_UPLOAD);
}
}
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 18d00f245..ba9e3f646 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -83,8 +83,6 @@ uuid::log::Logger System::logger_{F_(system), uuid::log::Facility::KERN};
// init statics
PButton System::myPButton_;
-bool System::restart_requested_ = false;
-bool System::restart_pending_ = false;
bool System::test_set_all_active_ = false;
uint32_t System::max_alloc_mem_;
uint32_t System::heap_mem_;
@@ -298,8 +296,7 @@ void System::system_restart(const char * partitionname) {
}
// make sure it's only executed once
- restart_requested(false);
- restart_pending(false);
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL);
store_nvs_values(); // save any NVS values
Shell::loop_all(); // flush log to output
@@ -565,27 +562,10 @@ void System::led_init(bool refresh) {
}
}
-// returns true if OTA is uploading
-bool System::upload_isrunning() {
-#if defined(EMSESP_STANDALONE)
- return false;
-#else
- return upload_isrunning_ || Update.isRunning();
-#endif
-}
-
-void System::upload_isrunning(bool in_progress) {
- // if we've just started an upload
- if (!upload_isrunning_ && in_progress) {
- EMSuart::stop();
- }
- upload_isrunning_ = in_progress;
-}
-
// checks system health and handles LED flashing wizardry
void System::loop() {
// check if we're supposed to do a reset/restart
- if (restart_requested()) {
+ if (systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED) {
system_restart();
}
@@ -706,7 +686,7 @@ void System::heartbeat_json(JsonObject output) {
#ifndef EMSESP_STANDALONE
output["freemem"] = getHeapMem();
output["max_alloc"] = getMaxAllocMem();
-#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
+#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
output["temperature"] = temperature_;
#endif
#endif
@@ -790,8 +770,8 @@ void System::system_check() {
#ifndef EMSESP_STANDALONE
#if defined(CONFIG_IDF_TARGET_ESP32)
- uint8_t raw = temprature_sens_read();
- temperature_ = (raw - 32) / 1.8f; // convert to Celsius
+ uint8_t raw = temprature_sens_read();
+ temperature_ = (raw - 32) / 1.8f; // convert to Celsius
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
temp_sensor_read_celsius(&temperature_);
@@ -1901,7 +1881,7 @@ bool System::load_board_profile(std::vector & data, const std::string &
return true;
}
-// format command - factory reset, removing all config files
+// format command - factory reset, removing all config fi`les
bool System::command_format(const char * value, const int8_t id) {
LOG_INFO("Removing all config files");
#ifndef EMSESP_STANDALONE
@@ -1915,8 +1895,8 @@ bool System::command_format(const char * value, const int8_t id) {
}
#endif
- EMSESP::system_.restart_requested(true); // will be handled by the main loop
-
+ // restart will be handled by the main loop
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED);
return true;
}
@@ -1926,11 +1906,13 @@ bool System::command_restart(const char * value, const int8_t id) {
// if it has an id then it's a web call and we need to queue the restart
// default id is -1 when calling /api/system/restart directly for example
LOG_INFO("Preparing to restart system");
- EMSESP::system_.restart_pending(true);
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART);
return true;
}
+
LOG_INFO("Restarting system immediately");
- EMSESP::system_.restart_requested(true); // will be handled by the main loop
+ // restart will be handled by the main loop
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED);
return true;
}
@@ -2022,25 +2004,38 @@ String System::getBBQKeesGatewayDetails() {
// Stream from an URL and send straight to OTA uploader service.
//
-// This function needs to be called twice, once with a url to persist it, and second with no arguments to start the upload
+// This function needs to be called twice, 1st pass once with a url to persist it, 2nd pass with no arguments to start the upload
// This is to avoid timeouts in callback functions, like calling from a web hook.
bool System::uploadFirmwareURL(const char * url) {
#ifndef EMSESP_STANDALONE
static String saved_url;
- // if the URL is not empty, store the URL for the 2nd pass
+ // if the URL is not empty, store the URL for the 2nd pass and exit
if (url && strlen(url) > 0) {
+ // if the passed URL is "reset" abort the current upload. This is called when an error happens during OTA
+ if (strncmp(url, "reset", 5) == 0) {
+ LOG_DEBUG("Firmware upload - resetting");
+ saved_url.clear();
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL);
+ return true;
+ }
+
+ // given a URL to download from, save it
saved_url = url;
- EMSESP::system_.upload_isrunning(true); // tell EMS-ESP we're ready to start the uploading process
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_PENDING_UPLOAD); // we're ready to start the upload
return true;
}
- // make sure we have a valid URL
+ // assumed we have a valid URL from the 1st pass
if (saved_url.isEmpty()) {
+ LOG_ERROR("Firmware upload failed - invalid URL");
return false; // error
}
+ LOG_INFO("Firmware downloading from %s", saved_url.c_str());
+ Shell::loop_all(); // flush log buffers so latest messages are shown in console
+
// Configure temporary client
HTTPClient http;
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); // important for GitHub 302's
@@ -2051,42 +2046,46 @@ bool System::uploadFirmwareURL(const char * url) {
// start a connection, returns -1 if fails
int httpCode = http.GET();
if (httpCode != HTTP_CODE_OK) {
- LOG_ERROR("Firmware upload failed. URL %s, HTTP code %d", saved_url.c_str(), httpCode);
+ LOG_ERROR("Firmware upload failed - HTTP code %d", httpCode);
+ http.end();
return false; // error
}
// check we have enough space for the upload in the ota partition
int firmware_size = http.getSize();
- LOG_INFO("Firmware uploading (file: %s, size: %d bytes). Please wait...", saved_url.c_str(), firmware_size);
+ LOG_INFO("Firmware uploading (size: %d bytes). Please wait...", firmware_size);
if (!Update.begin(firmware_size)) {
LOG_ERROR("Firmware upload failed - no space");
+ http.end();
return false; // error
}
- // flush log buffers so latest messages are shown
- Shell::loop_all();
+
+ Shell::loop_all(); // flush log buffers so latest messages are shown in console
+
+ // TODO do we need to stop the UART with EMSuart::stop() ?
// get tcp stream and send it to Updater
WiFiClient * stream = http.getStreamPtr();
if (Update.writeStream(*stream) != firmware_size) {
LOG_ERROR("Firmware upload failed - size differences");
+ http.end();
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_ERROR_UPLOAD);
return false; // error
}
if (!Update.end(true)) {
LOG_ERROR("Firmware upload failed - general error");
+ http.end();
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_ERROR_UPLOAD);
return false; // error
}
+ // finished with upload
http.end();
-
- EMSESP::system_.upload_isrunning(false);
saved_url.clear(); // prevent from downloading again
-
LOG_INFO("Firmware uploaded successfully. Restarting...");
-
- restart_pending(true);
-
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED);
#endif
return true; // OK
@@ -2148,4 +2147,14 @@ bool System::command_read(const char * value, const int8_t id) {
return readCommand(value);
}
+// set the system status code - SYSTEM_STATUS in system.h
+void System::systemStatus(uint8_t status_code) {
+ systemStatus_ = status_code;
+ LOG_DEBUG("Setting System status code %d", status_code);
+}
+
+uint8_t System::systemStatus() {
+ return systemStatus_;
+}
+
} // namespace emsesp
diff --git a/src/core/system.h b/src/core/system.h
index 2e5eca7da..761655fae 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -59,6 +59,17 @@ namespace emsesp {
enum PHY_type : uint8_t { PHY_TYPE_NONE = 0, PHY_TYPE_LAN8720, PHY_TYPE_TLK110 };
+enum SYSTEM_STATUS : uint8_t {
+ SYSTEM_STATUS_NORMAL = 0,
+ SYSTEM_STATUS_PENDING_UPLOAD = 1,
+ SYSTEM_STATUS_UPLOADING = 2,
+ SYSTEM_STATUS_ERROR_UPLOAD = 3,
+ SYSTEM_STATUS_RESTARTING = 4,
+ SYSTEM_STATUS_ERROR = 5,
+ SYSTEM_STATUS_PENDING_RESTART = 6,
+ SYSTEM_STATUS_RESTART_REQUESTED = 7
+};
+
class System {
public:
void start();
@@ -88,8 +99,7 @@ class System {
void store_nvs_values();
void system_restart(const char * partition = nullptr);
- void upload_isrunning(bool in_progress);
- bool upload_isrunning();
+
void show_mem(const char * note);
void reload_settings();
void syslog_init();
@@ -122,6 +132,9 @@ class System {
void button_init(bool refresh);
void commands_init();
+ void systemStatus(uint8_t status_code);
+ uint8_t systemStatus();
+
static void extractSettings(const char * filename, const char * section, JsonObject output);
static bool saveSettings(const char * filename, const char * section, JsonObject input);
@@ -130,20 +143,6 @@ class System {
static bool readCommand(const char * data);
- static void restart_requested(bool restart_requested) {
- restart_requested_ = restart_requested;
- }
- static bool restart_requested() {
- return restart_requested_;
- }
-
- static void restart_pending(bool restart_pending) {
- restart_pending_ = restart_pending;
- }
- static bool restart_pending() {
- return restart_pending_;
- }
-
bool telnet_enabled() {
return telnet_enabled_;
}
@@ -341,11 +340,12 @@ class System {
private:
static uuid::log::Logger logger_;
- static bool restart_requested_;
- static bool restart_pending_; // used in 2-stage process to call restart from Web API
- static bool test_set_all_active_; // force all entities in a device to have a value
- static uint32_t max_alloc_mem_;
- static uint32_t heap_mem_;
+
+ static bool test_set_all_active_; // force all entities in a device to have a value
+ static uint32_t max_alloc_mem_;
+ static uint32_t heap_mem_;
+
+ uint8_t systemStatus_; // uses SYSTEM_STATUS enum
// button
static PButton myPButton_; // PButton instance
diff --git a/src/version.h b/src/version.h
index 7fe9140fd..c643d8b34 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define EMSESP_APP_VERSION "3.7.2-dev.11"
+#define EMSESP_APP_VERSION "3.7.2-dev.12"
diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp
index 08a6a74dc..3d1476bb7 100644
--- a/src/web/WebCustomizationService.cpp
+++ b/src/web/WebCustomizationService.cpp
@@ -160,7 +160,8 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
if (LittleFS.remove(EMSESP_CUSTOMIZATION_FILE)) {
AsyncWebServerResponse * response = request->beginResponse(205); // restart needed
request->send(response);
- EMSESP::system_.restart_pending(true);
+ emsesp::EMSESP::system_.systemStatus(
+ emsesp::SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART); // will be handled by the main loop. We use pending for the Web's SystemMonitor
return;
}
diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp
index 931eb26eb..5459173e7 100644
--- a/src/web/WebSchedulerService.cpp
+++ b/src/web/WebSchedulerService.cpp
@@ -523,7 +523,7 @@ void WebSchedulerService::loop() {
void WebSchedulerService::scheduler_task(void * pvParameters) {
while (1) {
delay(10); // no need to hurry
- if (!EMSESP::system_.upload_isrunning()) {
+ if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_NORMAL) {
EMSESP::webSchedulerService.loop();
}
}
diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp
index 4014b9edc..1a0d52df0 100644
--- a/src/web/WebStatusService.cpp
+++ b/src/web/WebStatusService.cpp
@@ -42,7 +42,7 @@ WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * se
// /rest/systemStatus
// This contains both system & hardware Status to avoid having multiple costly endpoints
-// This is also used for polling during the RestartMonitor to see if EMS-ESP is alive
+// This is also used for polling during the SystemMonitor to see if EMS-ESP is alive
void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap
@@ -146,12 +146,11 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
root["has_partition"] = false;
}
- // Matches status codes in RestartMonitor.tsx
- if (EMSESP::system_.restart_pending()) {
- root["status"] = "restarting";
- EMSESP::system_.restart_requested(true); // tell emsesp loop to start restart
- } else {
- root["status"] = EMSESP::system_.upload_isrunning() ? "uploading" : "ready";
+ // Also used in SystemMonitor.tsx
+ root["status"] = EMSESP::system_.systemStatus(); // send the status. See System.h for status codes
+ if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART) {
+ // we're ready to do the actual restart ASAP
+ EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED);
}
#endif
@@ -194,6 +193,8 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json)
ok = getCustomSupport(root);
} else if (action == "uploadURL" && is_admin) {
ok = uploadURL(param.c_str());
+ } else if (action == "systemStatus" && is_admin) {
+ ok = setSystemStatus(param.c_str());
}
#if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY)
@@ -359,4 +360,11 @@ bool WebStatusService::uploadURL(const char * url) {
return true;
}
+// action = systemStatus
+// sets the system status
+bool WebStatusService::setSystemStatus(const char * status) {
+ emsesp::EMSESP::system_.systemStatus(Helpers::atoint(status));
+ return true;
+}
+
} // namespace emsesp
diff --git a/src/web/WebStatusService.h b/src/web/WebStatusService.h
index 6c3c0c6c2..beefd2611 100644
--- a/src/web/WebStatusService.h
+++ b/src/web/WebStatusService.h
@@ -27,7 +27,7 @@ class WebStatusService {
bool exportData(JsonObject root, std::string & type);
bool getCustomSupport(JsonObject root);
bool uploadURL(const char * url);
-
+ bool setSystemStatus(const char * status);
void allvalues(JsonObject output);
};