Rename /version endpoint to /firmware_info; add heap memory statistics to firmware data and UI.

This commit is contained in:
Kai Börnert
2026-04-27 15:46:29 +02:00
parent f0c9ed4e7f
commit c04109a76c
7 changed files with 64 additions and 8 deletions

View File

@@ -1327,12 +1327,17 @@ async fn get_version(
let hash = &env!("VERGEN_GIT_SHA")[0..8];
let board = board.board_hal.get_esp();
let heap = esp_alloc::HEAP.stats();
VersionInfo {
git_hash: branch + "@" + hash,
build_time: env!("VERGEN_BUILD_TIMESTAMP").to_owned(),
current: format!("{:?}", board.current),
slot0_state: format!("{:?}", board.slot0_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,
slot0_state: String,
slot1_state: String,
heap_total: usize,
heap_used: usize,
heap_free: usize,
heap_max_used: usize,
}

View File

@@ -109,7 +109,7 @@ pub(crate) async fn get_solar_state<T, const N: usize>(
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>,
) -> FatResult<Option<String>> {
let mut board = BOARD_ACCESS.get().await.lock().await;

View File

@@ -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::get_json::{
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_static::{serve_bundle, serve_favicon, serve_index};
@@ -73,7 +73,7 @@ impl Handler for HTTPRequestRouter {
"/get_backup_config" => get_backup_config(conn).await?,
&_ => {
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),
"/battery" => Some(get_battery_state(conn).await),
"/solar" => Some(get_solar_state(conn).await),

View File

@@ -183,6 +183,10 @@ export interface VersionInfo {
current: string,
slot0_state: string,
slot1_state: string,
heap_total: number,
heap_used: number,
heap_free: number,
heap_max_used: number,
}
export interface BatteryState {

View File

@@ -194,7 +194,7 @@ export class Controller {
async version(): Promise<void> {
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 versionInfo = json as VersionInfo;
controller.progressview.removeProgress("version");
@@ -499,7 +499,7 @@ export class Controller {
waitForReboot() {
console.log("Check if controller online again")
fetch(PUBLIC_URL + "/version", {
fetch(PUBLIC_URL + "/firmware_info", {
method: "GET",
signal: AbortSignal.timeout(5000)
}).then(response => {

View File

@@ -21,6 +21,7 @@
<div class="subtitle">
Current Firmware
</div>
<button style="margin-left: auto;" type="button" id="refresh_firmware_info">Refresh</button>
</div>
<div class="flexcontainer">
<span class="otakey">Buildtime:</span>
@@ -42,12 +43,35 @@
<span class="otakey">State1:</span>
<span class="otavalue" id="firmware_state1"></span>
</div>
<div class="flexcontainer">
<form class="otaform" id="upload_form" method="post">
<input class="otachooser" type="file" name="file1" id="firmware_file"><br>
</form>
</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">
<button style="margin-left: 16px; margin-top: 8px;" class="col-6" type="button" id="test">Self-Test</button>
</div>

View File

@@ -1,6 +1,10 @@
import {Controller} from "./main";
import {VersionInfo} from "./api";
function fmtBytes(n: number): string {
return `${n} B (${(n / 1024).toFixed(1)} KiB)`;
}
export class OTAView {
readonly file1Upload: HTMLInputElement;
readonly firmware_buildtime: HTMLDivElement;
@@ -8,19 +12,26 @@ export class OTAView {
readonly firmware_partition: HTMLDivElement;
readonly firmware_state0: 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) {
(document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html")
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_githash = document.getElementById("firmware_githash") as HTMLDivElement;
this.firmware_partition = document.getElementById("firmware_partition") as HTMLDivElement;
this.firmware_state0 = document.getElementById("firmware_state0") 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;
this.file1Upload = file
@@ -36,6 +47,10 @@ export class OTAView {
test.onclick = () => {
controller.selfTest();
}
refresh.onclick = () => {
controller.version();
}
}
setVersion(versionInfo: VersionInfo) {
@@ -44,5 +59,9 @@ export class OTAView {
this.firmware_partition.innerText = versionInfo.current;
this.firmware_state0.innerText = versionInfo.slot0_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);
}
}