diff --git a/container/unraid/aoostar-rs-webui.xml b/container/unraid/aoostar-rs-webui.xml
index 8ccafff..e177eaa 100644
--- a/container/unraid/aoostar-rs-webui.xml
+++ b/container/unraid/aoostar-rs-webui.xml
@@ -24,6 +24,7 @@
/mnt/user/appdata/aoostar-rs/config
/mnt/cache
/mnt/user
+ /sys/class/hwmon
/dev/ttyACM0
/dev/ttyACM0
diff --git a/crates/aster-webui/src/system.rs b/crates/aster-webui/src/system.rs
index c8e89db..2f24311 100644
--- a/crates/aster-webui/src/system.rs
+++ b/crates/aster-webui/src/system.rs
@@ -1,4 +1,4 @@
-use std::sync::OnceLock;
+use std::sync::{Mutex, OnceLock};
use ab_glyph::{FontArc, PxScale};
use chrono::Local;
@@ -43,7 +43,15 @@ pub(crate) fn collect_system_view() -> SystemView {
.unwrap_or_else(|| ("n/a".into(), "n/a".into(), "n/a".into()))
}
- let mut sys = System::new_all();
+ static SYSTEM: OnceLock> = OnceLock::new();
+ let system_lock = SYSTEM.get_or_init(|| {
+ let mut sys = System::new_all();
+ sys.refresh_all();
+ Mutex::new(sys)
+ });
+ let mut sys = system_lock
+ .lock()
+ .expect("system sampler mutex must not be poisoned");
sys.refresh_all();
let load_avg = System::load_average();
@@ -184,7 +192,10 @@ fn render_system_panel_cards() -> RgbImage {
84,
"CPU USAGE",
format!("{} %", system.cpu_usage_percent),
- format!("Load {}", system.load_avg_one),
+ format!(
+ "{} cores | {} procs",
+ system.cpu_count, system.process_count
+ ),
Rgb([124, 231, 191]),
),
(
@@ -240,34 +251,23 @@ fn render_system_panel_meters() -> RgbImage {
let system = collect_system_view();
let mut canvas = RgbImage::from_pixel(DISPLAY_WIDTH, DISPLAY_HEIGHT, Rgb([9, 13, 17]));
- draw_filled_rect_mut(
- &mut canvas,
- Rect::at(0, 0).of_size(DISPLAY_WIDTH, 56),
- Rgb([14, 20, 28]),
- );
- draw_text_line(
- &mut canvas,
- Rgb([216, 253, 114]),
- 24,
- 14,
- 28.0,
- "HTOP STYLE",
- );
-
draw_meter_row(
&mut canvas,
24,
- 84,
+ 38,
"CPU USAGE",
&format!("{}%", system.cpu_usage_percent),
parse_metric_percent(&system.cpu_usage_percent),
Rgb([110, 231, 183]),
- &format!("Load {} {} cores", system.load_avg_one, system.cpu_count),
+ &format!(
+ "{} cores {} procs",
+ system.cpu_count, system.process_count
+ ),
);
draw_meter_row(
&mut canvas,
24,
- 178,
+ 150,
"RAM USAGE",
&format!("{}%", system.mem_usage_percent),
parse_metric_percent(&system.mem_usage_percent),
@@ -277,7 +277,7 @@ fn render_system_panel_meters() -> RgbImage {
draw_meter_row(
&mut canvas,
24,
- 272,
+ 262,
"GPU TEMP",
system.temperature_gpu.as_deref().unwrap_or("-"),
normalize_temperature_bar(system.temperature_gpu.as_deref()),
@@ -306,11 +306,11 @@ pub(crate) fn overlay_system_specs(canvas: &mut RgbImage) {
28,
22.0,
&format!(
- "{host_name} CPU {}% RAM {}% C {}% U {}%",
+ "{host_name} CPU {}% RAM {}% GPU {} C {}%",
system.cpu_usage_percent,
system.mem_usage_percent,
+ system.temperature_gpu.as_deref().unwrap_or("-"),
system.cache_usage_percent,
- system.user_usage_percent
),
);
draw_text_line(
@@ -320,12 +320,10 @@ pub(crate) fn overlay_system_specs(canvas: &mut RgbImage) {
52,
16.0,
&format!(
- "Load {} / {} / {} Temp {} / {} Uptime {} {}",
- system.load_avg_one,
- system.load_avg_five,
- system.load_avg_fifteen,
+ "CPU {} Swap {}% User {}% Uptime {} {}",
system.temperature_cpu.as_deref().unwrap_or("-"),
- system.temperature_gpu.as_deref().unwrap_or("-"),
+ system.swap_usage_percent,
+ system.user_usage_percent,
system.uptime,
timestamp
),
@@ -370,10 +368,10 @@ fn draw_meter_row(
accent: Rgb,
meta: &str,
) {
- draw_text_line(canvas, accent, x, y, 21.0, label);
- draw_text_line(canvas, Rgb([237, 242, 247]), x + 248, y, 21.0, value);
- draw_meter_bar(canvas, x, y + 32, 900, 24, percent, accent);
- draw_text_line(canvas, Rgb([146, 163, 181]), x, y + 64, 18.0, meta);
+ draw_text_line(canvas, accent, x, y, 28.0, label);
+ draw_text_line(canvas, Rgb([237, 242, 247]), x + 600, y, 28.0, value);
+ draw_meter_bar(canvas, x, y + 42, 900, 30, percent, accent);
+ draw_text_line(canvas, Rgb([146, 163, 181]), x, y + 82, 20.0, meta);
}
fn draw_meter_bar(
diff --git a/crates/aster-webui/src/ui.rs b/crates/aster-webui/src/ui.rs
index c87a915..58944b0 100644
--- a/crates/aster-webui/src/ui.rs
+++ b/crates/aster-webui/src/ui.rs
@@ -93,8 +93,21 @@ const INDEX_HTML: &str = r##"
letter-spacing: 0;
}
.brand p { margin: 3px 0 0; color: var(--muted); font-size: .9rem; }
- .layout { display: grid; grid-template-columns: minmax(0, 1.45fr) 520px; gap: 14px; }
+ .layout {
+ display: grid;
+ grid-template-columns: minmax(0, 1.45fr) 520px;
+ gap: 14px;
+ align-items: stretch;
+ }
.stack { display: grid; gap: 16px; }
+ .layout > .stack {
+ height: 100%;
+ }
+ .layout > .stack > .panel {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ }
.tabbar {
display: inline-flex;
gap: 6px;
@@ -234,10 +247,13 @@ const INDEX_HTML: &str = r##"
.status-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
+ grid-template-rows: repeat(3, minmax(0, 1fr));
gap: 10px;
+ height: 100%;
+ align-self: stretch;
}
.status {
- min-height: 84px;
+ min-height: 0;
display: grid;
align-content: space-between;
background: rgba(16, 22, 30, .86);
@@ -582,8 +598,8 @@ const INDEX_HTML: &str = r##"
Memory--
Storage--
Swap--
- Load Avg--
- Temperatures--
+ GPU--
+ System--
@@ -634,10 +650,10 @@ const INDEX_HTML: &str = r##"
diskMetaValue: document.getElementById("diskMetaValue"),
swapUsageValue: document.getElementById("swapUsageValue"),
swapMetaValue: document.getElementById("swapMetaValue"),
- loadValue: document.getElementById("loadValue"),
- uptimeValue: document.getElementById("uptimeValue"),
- tempCpuValue: document.getElementById("tempCpuValue"),
- tempGpuValue: document.getElementById("tempGpuValue"),
+ gpuValue: document.getElementById("gpuValue"),
+ gpuMetaValue: document.getElementById("gpuMetaValue"),
+ systemValue: document.getElementById("systemValue"),
+ systemMetaValue: document.getElementById("systemMetaValue"),
upload: document.getElementById("upload"),
apply: document.getElementById("apply"),
disable: document.getElementById("disable"),
@@ -784,17 +800,17 @@ const INDEX_HTML: &str = r##"
el.displayErrorValue.textContent = state.display.last_error || "";
el.configPathValue.textContent = data.monitor_path;
el.cpuUsageValue.textContent = `${state.system.cpu_usage_percent || "-"} %`;
- el.cpuMetaValue.textContent = `Load ${state.system.load_avg_one || "-"} / ${state.system.load_avg_five || "-"} / ${state.system.load_avg_fifteen || "-"}`;
+ el.cpuMetaValue.textContent = `${state.system.cpu_count || "-"} cores • ${state.system.process_count || "-"} procs`;
el.memUsageValue.textContent = `${state.system.mem_usage_percent || "-"} %`;
el.memMetaValue.textContent = `${state.system.mem_used || "-"} / ${state.system.mem_total || "-"}`;
el.diskUsageValue.innerHTML = `/mnt/cache ${state.system.cache_usage_percent || "-"}%
/mnt/user ${state.system.user_usage_percent || "-"}%`;
el.diskMetaValue.textContent = `${state.system.cache_used || "-"} / ${state.system.cache_total || "-"} | ${state.system.user_used || "-"} / ${state.system.user_total || "-"}`;
el.swapUsageValue.textContent = `${state.system.swap_usage_percent || "-"} %`;
el.swapMetaValue.textContent = `${state.system.swap_used || "-"} / ${state.system.swap_total || "-"}`;
- el.loadValue.textContent = `${state.system.load_avg_one || "-"} / ${state.system.load_avg_five || "-"} / ${state.system.load_avg_fifteen || "-"}`;
- el.uptimeValue.textContent = `${state.system.cpu_count || "-"} cores • ${state.system.process_count || "-"} procs • Uptime ${state.system.uptime || "-"}`;
- el.tempCpuValue.textContent = `CPU ${state.system.temperature_cpu || "-"}`;
- el.tempGpuValue.textContent = `GPU ${state.system.temperature_gpu || "-"}`;
+ el.gpuValue.textContent = state.system.temperature_gpu || "-";
+ el.gpuMetaValue.textContent = `CPU ${state.system.temperature_cpu || "-"}`;
+ el.systemValue.textContent = state.system.uptime || "-";
+ el.systemMetaValue.textContent = `${state.system.cache_usage_percent || "-"}% cache • ${state.system.user_usage_percent || "-"}% user`;
el.displayStatusMirror.textContent = el.displayStatusValue.textContent;
el.displayTargetMirror.textContent = state.display.device || "-";
el.customPanelMirror.textContent = el.customPanelValue.textContent;