Skip to content

feat: wire real Linux hardware sensors into the instrument panel - #9

Merged
rghamilton3 merged 4 commits into
mainfrom
feat/linux-provider
Jun 1, 2026
Merged

rghamilton3 merged 4 commits into
mainfrom
feat/linux-provider

Conversation

@rghamilton3

Copy link
Copy Markdown
Contributor

Summary

Makes the built-in LinuxProvider real and feeds live hardware data into the instrument panel. The provider reads /proc and /sys directly (no external binaries) and emits the same canonical sensor IDs the panel binds to, so it's a drop-in for the demo mock — verified live on an AMD machine (CPU/clock/temp, discrete-GPU util/temp, memory all render real, changing values).

Changes

LinuxProvider → canonical sensors (crates/providers/src/linux.rs)

  • cpu.total.utilization (/proc/stat delta), cpu.clock (mean of cpufreq/scaling_cur_freq), cpu.temperature (k10temp Tctl / coretemp package)
  • gpu.total.utilization + gpu.temperature — discrete GPU chosen by largest mem_info_vram_total; util and edge-temp read from that same card's node/hwmon (avoids mixing iGPU/dGPU)
  • memory.used.percent and memory.used (MB)
  • Unit strings match the mock verbatim (%, °C, MHz, MB) so the UI renders correctly; failed sources are skipped + logged, never panic
  • Pure parse/select helpers are unit-tested (CI-safe); a #[cfg(target_os="linux")] + #[ignore] test exercises real hardware locally

Provider selection (apps/desktop/src-tauri/src/lib.rs)

  • select_provider() driven by ASTRAGAUGE_PROVIDER = auto (default) | mock | linux
  • auto: LinuxProvider on Linux unless it discovers 0 sensors → fall back to demo mock; non-Linux → mock
  • All LinuxProvider references cfg(target_os="linux")-gated (compiles cross-platform); commands + sensors-update emitter unchanged

Testing

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo build --workspace, cargo test --workspace — all clean (hardware test stays #[ignore]d in CI)
  • cargo test -p astragauge-providers -- --ignored on a real AMD box: all 7 canonical sensors read plausible values (CPU ~50 °C / ~3.7 GHz, discrete GPU ~45–55 °C, memory ~67% of 61.8 GB)
  • Launched the app: live panel renders real, changing values for all seven instruments (GPU not N/A)

Notes / follow-ups

LinuxProvider now reads /proc and /sys (no external binaries) and emits
the same canonical sensor IDs the instrument panel binds to, so it is
interchangeable with the demo mock:
  cpu.total.utilization (/proc/stat), cpu.clock (cpufreq mean),
  cpu.temperature (k10temp Tctl / coretemp package),
  gpu.total.utilization + gpu.temperature (discrete GPU by largest VRAM,
  util + edge temp read from that same card), memory.used.percent,
  memory.used (MB). Unit strings match the mock verbatim (%, °C, MHz, MB).

Pure parsing/selection helpers are unit-tested (CI-safe, no /sys reads);
a #[cfg(target_os="linux")] + #[ignore] integration test exercises real
hardware locally. Failed sources are skipped and logged, never panic.
Adds select_provider() driven by ASTRAGAUGE_PROVIDER (auto|mock|linux,
default auto): on Linux, use LinuxProvider unless it discovers 0 sensors,
otherwise fall back to the demo MockProvider; non-Linux uses the mock.
All LinuxProvider references are cfg(target_os="linux")-gated so the app
still compiles cross-platform. The env-var selector is an interim
mechanism (see #8) — useful now to force mock for demo capture or force
linux for testing. Commands and the sensors-update emitter unchanged.
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

opencode session  |  github run

… ids, tests

Apply the PR#9 review feedback across the LinuxProvider and provider selection:

- Surface I/O errors: add read_sys_file/read_sys_dir helpers (silent on
  NotFound, warn! with path otherwise) and route every /proc + /sys reader
  through them, so a permission/IO error no longer silently drops a sensor.
- Fix pick_discrete_gpu tie-break to match its doc (first-seen, not last) via
  reduce-with-strict->; add a tie test.
- select_provider auto path: handle a discover() Err explicitly (error! log +
  distinct reason) instead of mislabeling it as "0 sensors"; extract a pure
  parse_provider_mode() with unit tests.
- Hoist the 7 canonical sensor ids + unit strings into a shared
  astragauge_domain::canonical module; reference it from mock.rs, linux.rs, and
  the hardware test. Pin the literal id/unit values in canonical.rs (the test
  that actually catches a rename).
- meminfo_used now returns Option<MemoryUsage>; returns None (not a misleading
  100%) when MemAvailable is absent.
- Remove the unreachable cpu/gpu.temperature collision guard; reword the
  misleading collision/gating comments; simplify the kB->MB comment.
- Add coverage: meminfo no-MemAvailable/zero-total, mixed-input freq, negative
  millidegrees, cpuinfo no-match, make_temp_sensor_id SensorId round-trip +
  unsanitizable-name cases, mock unit-contract test.

Verified: fmt/clippy(-D warnings)/build/test --workspace clean; the #[ignore]d
hardware test reads all 7 canonical sensors with correct units on real AMD hw.
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

opencode session  |  github run

The opencode review action fails on every run: its GLM/Zhipu model call
(ZHIPU_API_KEY) errors at session.prompt step 0 before producing any review,
so the check is a persistent red with no findings. Remove the workflow rather
than leave a perpetually-failing check on every PR.
@rghamilton3
rghamilton3 merged commit 3f226bb into main Jun 1, 2026
4 checks passed
@rghamilton3
rghamilton3 deleted the feat/linux-provider branch June 1, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant