Rename /version endpoint to /firmware_info; add heap memory statistics to firmware data and UI.
This commit is contained in:
@@ -1327,12 +1327,17 @@ async fn get_version(
|
|||||||
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
let hash = &env!("VERGEN_GIT_SHA")[0..8];
|
||||||
|
|
||||||
let board = board.board_hal.get_esp();
|
let board = board.board_hal.get_esp();
|
||||||
|
let heap = esp_alloc::HEAP.stats();
|
||||||
VersionInfo {
|
VersionInfo {
|
||||||
git_hash: branch + "@" + hash,
|
git_hash: branch + "@" + hash,
|
||||||
build_time: env!("VERGEN_BUILD_TIMESTAMP").to_owned(),
|
build_time: env!("VERGEN_BUILD_TIMESTAMP").to_owned(),
|
||||||
current: format!("{:?}", board.current),
|
current: format!("{:?}", board.current),
|
||||||
slot0_state: format!("{:?}", board.slot0_state),
|
slot0_state: format!("{:?}", board.slot0_state),
|
||||||
slot1_state: format!("{:?}", board.slot1_state),
|
slot1_state: format!("{:?}", board.slot1_state),
|
||||||
|
heap_total: heap.size,
|
||||||
|
heap_used: heap.current_usage,
|
||||||
|
heap_free: heap.size.saturating_sub(heap.current_usage),
|
||||||
|
heap_max_used: heap.max_usage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1343,4 +1348,8 @@ struct VersionInfo {
|
|||||||
current: String,
|
current: String,
|
||||||
slot0_state: String,
|
slot0_state: String,
|
||||||
slot1_state: String,
|
slot1_state: String,
|
||||||
|
heap_total: usize,
|
||||||
|
heap_used: usize,
|
||||||
|
heap_free: usize,
|
||||||
|
heap_max_used: usize,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ pub(crate) async fn get_solar_state<T, const N: usize>(
|
|||||||
Ok(Some(serde_json::to_string(&state)?))
|
Ok(Some(serde_json::to_string(&state)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_version_web<T, const N: usize>(
|
pub(crate) async fn get_firmware_info_web<T, const N: usize>(
|
||||||
_request: &mut Connection<'_, T, N>,
|
_request: &mut Connection<'_, T, N>,
|
||||||
) -> FatResult<Option<String>> {
|
) -> FatResult<Option<String>> {
|
||||||
let mut board = BOARD_ACCESS.get().await.lock().await;
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::fat_error::{FatError, FatResult};
|
|||||||
use crate::webserver::backup_manager::{backup_config, backup_info, get_backup_config};
|
use crate::webserver::backup_manager::{backup_config, backup_info, get_backup_config};
|
||||||
use crate::webserver::get_json::{
|
use crate::webserver::get_json::{
|
||||||
delete_save, get_battery_state, get_config, get_live_moisture, get_log_localization_config,
|
delete_save, get_battery_state, get_config, get_live_moisture, get_log_localization_config,
|
||||||
get_solar_state, get_time, get_timezones, get_version_web, list_saves, tank_info,
|
get_firmware_info_web, get_solar_state, get_time, get_timezones, list_saves, tank_info,
|
||||||
};
|
};
|
||||||
use crate::webserver::get_log::{get_live_log, get_log};
|
use crate::webserver::get_log::{get_live_log, get_log};
|
||||||
use crate::webserver::get_static::{serve_bundle, serve_favicon, serve_index};
|
use crate::webserver::get_static::{serve_bundle, serve_favicon, serve_index};
|
||||||
@@ -73,7 +73,7 @@ impl Handler for HTTPRequestRouter {
|
|||||||
"/get_backup_config" => get_backup_config(conn).await?,
|
"/get_backup_config" => get_backup_config(conn).await?,
|
||||||
&_ => {
|
&_ => {
|
||||||
let json = match path {
|
let json = match path {
|
||||||
"/version" => Some(get_version_web(conn).await),
|
"/firmware_info" => Some(get_firmware_info_web(conn).await),
|
||||||
"/time" => Some(get_time(conn).await),
|
"/time" => Some(get_time(conn).await),
|
||||||
"/battery" => Some(get_battery_state(conn).await),
|
"/battery" => Some(get_battery_state(conn).await),
|
||||||
"/solar" => Some(get_solar_state(conn).await),
|
"/solar" => Some(get_solar_state(conn).await),
|
||||||
|
|||||||
@@ -183,6 +183,10 @@ export interface VersionInfo {
|
|||||||
current: string,
|
current: string,
|
||||||
slot0_state: string,
|
slot0_state: string,
|
||||||
slot1_state: string,
|
slot1_state: string,
|
||||||
|
heap_total: number,
|
||||||
|
heap_used: number,
|
||||||
|
heap_free: number,
|
||||||
|
heap_max_used: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BatteryState {
|
export interface BatteryState {
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ export class Controller {
|
|||||||
|
|
||||||
async version(): Promise<void> {
|
async version(): Promise<void> {
|
||||||
controller.progressview.addIndeterminate("version", "Getting buildVersion")
|
controller.progressview.addIndeterminate("version", "Getting buildVersion")
|
||||||
const response = await fetch(PUBLIC_URL + "/version");
|
const response = await fetch(PUBLIC_URL + "/firmware_info");
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const versionInfo = json as VersionInfo;
|
const versionInfo = json as VersionInfo;
|
||||||
controller.progressview.removeProgress("version");
|
controller.progressview.removeProgress("version");
|
||||||
@@ -499,7 +499,7 @@ export class Controller {
|
|||||||
|
|
||||||
waitForReboot() {
|
waitForReboot() {
|
||||||
console.log("Check if controller online again")
|
console.log("Check if controller online again")
|
||||||
fetch(PUBLIC_URL + "/version", {
|
fetch(PUBLIC_URL + "/firmware_info", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
signal: AbortSignal.timeout(5000)
|
signal: AbortSignal.timeout(5000)
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
<div class="subtitle">
|
<div class="subtitle">
|
||||||
Current Firmware
|
Current Firmware
|
||||||
</div>
|
</div>
|
||||||
|
<button style="margin-left: auto;" type="button" id="refresh_firmware_info">Refresh</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flexcontainer">
|
<div class="flexcontainer">
|
||||||
<span class="otakey">Buildtime:</span>
|
<span class="otakey">Buildtime:</span>
|
||||||
@@ -42,12 +43,35 @@
|
|||||||
<span class="otakey">State1:</span>
|
<span class="otakey">State1:</span>
|
||||||
<span class="otavalue" id="firmware_state1"></span>
|
<span class="otavalue" id="firmware_state1"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flexcontainer">
|
<div class="flexcontainer">
|
||||||
<form class="otaform" id="upload_form" method="post">
|
<form class="otaform" id="upload_form" method="post">
|
||||||
<input class="otachooser" type="file" name="file1" id="firmware_file"><br>
|
<input class="otachooser" type="file" name="file1" id="firmware_file"><br>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flexcontainer">
|
||||||
|
<div class="subtitle">
|
||||||
|
Heap Memory
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div class="flexcontainer">
|
||||||
|
<span class="otakey">Free:</span>
|
||||||
|
<span class="otavalue" id="heap_free"></span>
|
||||||
|
</div>
|
||||||
|
<div class="flexcontainer">
|
||||||
|
<span class="otakey">Used:</span>
|
||||||
|
<span class="otavalue" id="heap_used"></span>
|
||||||
|
</div>
|
||||||
|
<div class="flexcontainer">
|
||||||
|
<span class="otakey">Total:</span>
|
||||||
|
<span class="otavalue" id="heap_total"></span>
|
||||||
|
</div>
|
||||||
|
<div class="flexcontainer">
|
||||||
|
<span class="otakey">Peak used:</span>
|
||||||
|
<span class="otavalue" id="heap_max_used"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="display:flex">
|
<div class="display:flex">
|
||||||
<button style="margin-left: 16px; margin-top: 8px;" class="col-6" type="button" id="test">Self-Test</button>
|
<button style="margin-left: 16px; margin-top: 8px;" class="col-6" type="button" id="test">Self-Test</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import {Controller} from "./main";
|
import {Controller} from "./main";
|
||||||
import {VersionInfo} from "./api";
|
import {VersionInfo} from "./api";
|
||||||
|
|
||||||
|
function fmtBytes(n: number): string {
|
||||||
|
return `${n} B (${(n / 1024).toFixed(1)} KiB)`;
|
||||||
|
}
|
||||||
|
|
||||||
export class OTAView {
|
export class OTAView {
|
||||||
readonly file1Upload: HTMLInputElement;
|
readonly file1Upload: HTMLInputElement;
|
||||||
readonly firmware_buildtime: HTMLDivElement;
|
readonly firmware_buildtime: HTMLDivElement;
|
||||||
@@ -8,19 +12,26 @@ export class OTAView {
|
|||||||
readonly firmware_partition: HTMLDivElement;
|
readonly firmware_partition: HTMLDivElement;
|
||||||
readonly firmware_state0: HTMLDivElement;
|
readonly firmware_state0: HTMLDivElement;
|
||||||
readonly firmware_state1: HTMLDivElement;
|
readonly firmware_state1: HTMLDivElement;
|
||||||
|
readonly heap_free: HTMLDivElement;
|
||||||
|
readonly heap_used: HTMLDivElement;
|
||||||
|
readonly heap_total: HTMLDivElement;
|
||||||
|
readonly heap_max_used: HTMLDivElement;
|
||||||
|
|
||||||
constructor(controller: Controller) {
|
constructor(controller: Controller) {
|
||||||
(document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html")
|
(document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html")
|
||||||
|
|
||||||
let test = document.getElementById("test") as HTMLButtonElement;
|
let test = document.getElementById("test") as HTMLButtonElement;
|
||||||
|
let refresh = document.getElementById("refresh_firmware_info") as HTMLButtonElement;
|
||||||
|
|
||||||
this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement;
|
this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement;
|
||||||
this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement;
|
this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement;
|
||||||
this.firmware_partition = document.getElementById("firmware_partition") as HTMLDivElement;
|
this.firmware_partition = document.getElementById("firmware_partition") as HTMLDivElement;
|
||||||
|
|
||||||
this.firmware_state0 = document.getElementById("firmware_state0") as HTMLDivElement;
|
this.firmware_state0 = document.getElementById("firmware_state0") as HTMLDivElement;
|
||||||
this.firmware_state1 = document.getElementById("firmware_state1") as HTMLDivElement;
|
this.firmware_state1 = document.getElementById("firmware_state1") as HTMLDivElement;
|
||||||
|
this.heap_free = document.getElementById("heap_free") as HTMLDivElement;
|
||||||
|
this.heap_used = document.getElementById("heap_used") as HTMLDivElement;
|
||||||
|
this.heap_total = document.getElementById("heap_total") as HTMLDivElement;
|
||||||
|
this.heap_max_used = document.getElementById("heap_max_used") as HTMLDivElement;
|
||||||
|
|
||||||
const file = document.getElementById("firmware_file") as HTMLInputElement;
|
const file = document.getElementById("firmware_file") as HTMLInputElement;
|
||||||
this.file1Upload = file
|
this.file1Upload = file
|
||||||
@@ -36,6 +47,10 @@ export class OTAView {
|
|||||||
test.onclick = () => {
|
test.onclick = () => {
|
||||||
controller.selfTest();
|
controller.selfTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refresh.onclick = () => {
|
||||||
|
controller.version();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setVersion(versionInfo: VersionInfo) {
|
setVersion(versionInfo: VersionInfo) {
|
||||||
@@ -44,5 +59,9 @@ export class OTAView {
|
|||||||
this.firmware_partition.innerText = versionInfo.current;
|
this.firmware_partition.innerText = versionInfo.current;
|
||||||
this.firmware_state0.innerText = versionInfo.slot0_state;
|
this.firmware_state0.innerText = versionInfo.slot0_state;
|
||||||
this.firmware_state1.innerText = versionInfo.slot1_state;
|
this.firmware_state1.innerText = versionInfo.slot1_state;
|
||||||
|
this.heap_free.innerText = fmtBytes(versionInfo.heap_free);
|
||||||
|
this.heap_used.innerText = fmtBytes(versionInfo.heap_used);
|
||||||
|
this.heap_total.innerText = fmtBytes(versionInfo.heap_total);
|
||||||
|
this.heap_max_used.innerText = fmtBytes(versionInfo.heap_max_used);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user