feat: add fan curve control via temperature-based fan speed curves

- Backend HAL (hal/fans.py): NVML v2 fan read/set/reset with min/max queries
- Server endpoints: GET/POST /api/fans, POST /api/fans/reset, POST /api/fans/speed
- Background fan poller: reads GPU temp every 2s, interpolates fan speed from curve
- Profile integration: fan_curve field saved/applied, auto-restore on shutdown
- Frontend: FanCurveEditor (SVG chart with drag/add/delete points), FanMonitor sidebar
- App.tsx: three-tab layout (Curve, Performance, Fans)
- GaugeCard: optional history sparkline, Fan Mode card without sparkline
- fan_mode field populated as 'curve' or 'auto' in GET /api/fans
This commit is contained in:
ARIA committed 2026-08-01 15:59:39 +02:00
1 parent 7605d21e27
commit 477c4becae
11 files changed
+1288 -10

No files matched your search

@@ -1,7 +1,7 @@
interface Props {
label: string;
value: string;
history: number[];
history?: number[];
unit?: string;
color?: string; // tailwind color class for the sparkline stroke
max?: number;
@@ -44,9 +44,11 @@ export function GaugeCard({ label, value, history, color = '#a78bfa', max }: Pro
<div className="bg-zinc-900 rounded-lg p-3 flex flex-col gap-1 min-w-0">
<div className="text-xs text-zinc-500 uppercase tracking-wider">{label}</div>
<div className="text-xl font-mono font-semibold text-zinc-100">{value}</div>
<div className="mt-1 w-full">
<Sparkline data={history} color={color} max={max} />
</div>
{history && (
<div className="mt-1 w-full">
<Sparkline data={history} color={color} max={max} />
</div>
)}
</div>
);
}