removed old markdown files
This commit is contained in:
1 parent
0320cea895
commit
9cf2009d2c
2 files changed
-328
No files matched your search
@@ -1,57 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **Multi-User Authentication (dual mode)**: The server now supports optional login-protected access for shared machines (e.g. AI servers).
|
||||
- **Dual mode**: with no users configured the API/web UI are open (as before); once at least one user exists, every `/api/*` and `/ws/*` endpoint requires a valid session.
|
||||
- **bcrypt password hashing**: passwords are stored as bcrypt (`$2b$`) hashes in `/etc/nvcurve/users.json` (mode `0600`, root-owned). Plaintext is never persisted; login compares the plaintext against the stored hash.
|
||||
- **24-hour sessions**: a successful login creates a session that lasts 24 hours (HttpOnly cookie for browsers, `Authorization: Bearer` token for CLI/scripts). Sessions are in-memory and invalidated on server restart.
|
||||
- **Multi-user**: multiple named accounts are supported (no shared-password mode).
|
||||
- **New CLI**: `nvcurve user add|list|remove|set-password` (root for add/remove/set-password).
|
||||
- **New endpoints**: `GET /api/ping` (public), `GET /api/auth/status`, `POST /api/auth/login`, `POST /api/auth/logout`, `GET /api/auth/users`.
|
||||
- **Web UI**: a sign-in screen appears when authentication is enabled; the status bar shows the signed-in user with a sign-out button. Expired sessions (401) re-show the sign-in screen.
|
||||
- **Brute-force lockout**: 10 failed logins from an IP within 5 minutes triggers a 15-minute lockout.
|
||||
- New dependency: `bcrypt`.
|
||||
|
||||
## [0.5.1] - 2026-05-09
|
||||
|
||||
### Added
|
||||
|
||||
- **Comprehensive Documentation**: Added structured docs covering overview, installation, usage guide, and tips and tricks. README pruned to essentials with links to docs.
|
||||
|
||||
### Changed
|
||||
|
||||
- **VRAM Offset Cap Raised**: Increased the web UI VRAM slider maximum from 1000 MHz to 3000 MHz, matching the NVIDIA driver hard limit. Point 131 now allows the full range.
|
||||
|
||||
## [0.5.0] - 2026-03-23
|
||||
|
||||
### Changed
|
||||
|
||||
- **CLI Architecture Simplification**: The CLI has been decoupled from the FastAPI server and now operates as a stateless direct-HAL hardware administration tool. It no longer relies on the server for data reading or offset writing.
|
||||
- **Consistent Privileges**: All CLI commands that interact with the hardware now explicitly require root privileges.
|
||||
- **Background Daemon**: Added a new lightweight Unix socket daemon (`nvcurve daemon`) to handle auto-loading profiles on boot and managing the server's lifecycle.
|
||||
- **Global Arguments**: Fixed global argument parsing in the CLI to allow global flags (like `--gpu`) to be placed after subcommands.
|
||||
|
||||
## [0.4.0] - 2026-03-17
|
||||
|
||||
### Added
|
||||
|
||||
- **Multi-GPU Support** *(experimental — untested on real multi-GPU hardware)*: The server now manages all detected NVIDIA GPUs simultaneously under a single process. Each GPU gets its own isolated state (write lock, monitor clients, curve clients, active profile). REST endpoints and WebSocket subscriptions accept a `gpu_index` parameter. A new `/api/gpus` endpoint enumerates all GPUs with name, index, UUID, and PCI bus ID.
|
||||
- **GPU Selector in Web UI**: When multiple GPUs are present, the status bar shows a dropdown to switch the active GPU. Switching resets all pending edits, selection state, and live monitoring for the new target.
|
||||
- **Default Profile**: Added the ability to designate a profile as the default — it is applied automatically on server startup.
|
||||
- CLI: `nvcurve profile default <name>` to set, `nvcurve profile default --clear` to unset.
|
||||
- The web UI shows a filled star on the default profile and lets you toggle it with a single click.
|
||||
- The setting persists to `/etc/nvcurve/config.json` (created by `service install`). If the config file is absent, the setting is in-memory for the current session only.
|
||||
- **Curve Flattening**: Selecting two or more points and clicking "Flatten to [anchor]" in the toolbar sets each selected point to a different offset, such that all land on the same effective frequency as the anchor point. The anchor is the last explicitly clicked point (highlighted with an amber halo on the graph); bulk selections (box, range, Ctrl+A) preserve the existing anchor.
|
||||
- **Server-Optional Profile Commands**: `profile apply`, `profile list`, and `profile default` no longer require the server to be running. When the server is absent they fall back to direct HAL calls or config-file writes, escalating to root via `sudo` automatically — the same pattern already used by snapshot commands.
|
||||
- **Automated Setup Check**: `nvcurve setup` runs a consolidated 4-step hardware compatibility check: NvAPI function probe → V/F curve baseline read → non-destructive write-verify → automatic state restore. The write-verify defaults to the last GPU-domain point (safe on all GPU generations); override with `--point` and `--delta`. Pass `--full-mask` if writes fail on older GPUs such as Pascal.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Profile CLI syntax**: Profile commands now take the profile name as a positional argument instead of `--name` (e.g. `nvcurve profile apply balanced` instead of `nvcurve profile apply --name balanced`).
|
||||
- **Improved Diagnostics**: The `read --diag` engine now reports driver version, VRAM totals, power limits, raw clock offsets, memory offset ranges, and raw boost masks in addition to the NvAPI function probe.
|
||||
- **Offline Snapshots**: `snapshot save`, `restore`, and `list` bypass the server and fall back to direct HAL operations when the daemon is not running.
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
# Fan Tab Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Add a third **Fans** tab to the WebUI alongside the existing `Curve` and `Performance` tabs. The tab presents a fan speed curve editor (temperature → target fan %) with a Live Monitor sidebar, and the ability to apply, save in profiles, and reset fan settings.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decision: Fan Control via NVML
|
||||
|
||||
Fan control will use **NVML (pynvml)**, not NvAPI. Rationale:
|
||||
- `nvmlDeviceSetFanSpeed(handle, speed)` is well-documented and widely supported
|
||||
- `nvmlDeviceGetFanSpeed(handle)` is already used in `hal/monitoring.py:108` for reading
|
||||
- `nvmlDeviceGetFanSpeedInfo(handle)` returns current mode (0=auto, 1=manual) and current speed
|
||||
- No need to reverse-engineer NvAPI fan functions — NVML provides a clean, stable API
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Backend — HAL Layer
|
||||
|
||||
#### 1.1 New file: `nvcurve/hal/fans.py`
|
||||
|
||||
Fan curve model: a list of **temperature → fan %** target points, similar to the existing V/F curve concept but simpler (no NvAPI table, just user-defined targets).
|
||||
|
||||
```
|
||||
FanPoint:
|
||||
temp_c: int # temperature threshold in °C (e.g. 30, 40, 50, 60, 70, 80)
|
||||
fan_pct: int # target fan speed at that temp (0-100 %)
|
||||
```
|
||||
|
||||
Functions:
|
||||
- `get_fan_state(gpu_index) -> dict` — returns current fan %, fan mode (auto/manual), min/max fan speeds
|
||||
- `set_fan_speed(gpu_index, pct) -> tuple[bool, str]` — sets fan to a specific % via `nvmlDeviceSetFanSpeed`
|
||||
- `reset_fan(gpu_index) -> tuple[bool, str]` — restores automatic fan control
|
||||
- `get_fan_curve(gpu_index) -> list[dict]` — returns currently stored fan curve points (from config/profile)
|
||||
- `apply_fan_curve(gpu_index, curve) -> None` — background thread that reads temp, interpolates fan % from curve, and calls `set_fan_speed` periodically
|
||||
|
||||
Key detail: Unlike V/F curve or power limits (one-shot writes), a fan curve needs a **continuous feedback loop**. The daemon/server needs a background task that:
|
||||
1. Reads current GPU temp (already available via monitoring poller)
|
||||
2. Interpolates the target fan % from the active fan curve
|
||||
3. Calls `set_fan_speed` with the interpolated value
|
||||
4. Runs at a configurable interval (e.g. every 2-5 seconds)
|
||||
|
||||
**Two approaches for the feedback loop:**
|
||||
|
||||
**A) Server-side poller (Recommended)** — Add a new asyncio task in `server.py` lifespan, similar to `_monitor_poller`. When a fan curve is active, the poller reads temp, interpolates, and sets fan speed each cycle.
|
||||
|
||||
**B) Daemon-side poller** — Run the loop in `daemon.py`. More complex, requires IPC coordination.
|
||||
|
||||
I recommend **approach A** for simplicity and consistency with the existing architecture.
|
||||
|
||||
#### 1.2 Modify: `nvcurve/server.py`
|
||||
|
||||
New REST endpoints:
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` | `/api/fans` | Current fan state: `{fan_pct, fan_mode, min_fan_pct, max_fan_pct, curve}` |
|
||||
| `POST` | `/api/fans` | Set fan curve: `{curve: [{temp_c, fan_pct}]}` — starts/updates the feedback loop |
|
||||
| `POST` | `/api/fans/reset` | Reset to automatic fan control, stops feedback loop |
|
||||
| `POST` | `/api/fans/speed` | One-shot set fan to exact %: `{fan_pct: 50}` |
|
||||
|
||||
New server state:
|
||||
- Per-GPU: `fan_curve: list[dict] | None`, `fan_active: bool`, `fan_poller_task: asyncio.Task | None`
|
||||
- New `_fan_poller(gpu_index)` async task, similar pattern to `_monitor_poller`
|
||||
|
||||
The fan poller reads temp from NVML, interpolates fan % from the stored curve using linear interpolation between nearest points (clamp at min/max), and calls `set_fan_speed`.
|
||||
|
||||
#### 1.3 Modify: `nvcurve/nvapi/types.py`
|
||||
|
||||
Add to `MonitoringSample` (optional — fan_pct already exists):
|
||||
- No change needed; `fan_pct` is already present.
|
||||
|
||||
#### 1.4 Modify: `nvcurve/profiles/native.py`
|
||||
|
||||
Extend `ProfileData`:
|
||||
```python
|
||||
@dataclass
|
||||
class ProfileData:
|
||||
name: str
|
||||
gpu_name: str
|
||||
curve_deltas: Dict[str, int]
|
||||
mem_offset_mhz: Optional[int] = None
|
||||
power_limit_w: Optional[int] = None
|
||||
fan_curve: Optional[List[Dict[str, int]]] = None # NEW: [{temp_c, fan_pct}, ...]
|
||||
```
|
||||
|
||||
Add migration in `load_profile` to handle old profiles without `fan_curve`.
|
||||
|
||||
#### 1.5 Modify: `nvcurve/profiles/apply.py`
|
||||
|
||||
When applying a profile, if `fan_curve` is present, call the new `/api/fans` endpoint (or the HAL function directly) to activate the fan curve.
|
||||
|
||||
#### 1.6 Modify: `nvcurve/server.py` — Profile endpoints
|
||||
|
||||
In the profile save endpoint, include the current active fan curve in the saved profile data.
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Frontend — Types & API
|
||||
|
||||
#### 2.1 Modify: `frontend/src/types.ts`
|
||||
|
||||
New types:
|
||||
```typescript
|
||||
export interface FanPoint {
|
||||
temp_c: number;
|
||||
fan_pct: number;
|
||||
}
|
||||
|
||||
export interface FanState {
|
||||
fan_pct: number | null;
|
||||
fan_mode: number | null; // 0 = auto, 1 = manual
|
||||
min_fan_pct: number | null;
|
||||
max_fan_pct: number | null;
|
||||
curve: FanPoint[];
|
||||
curve_active: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
Extend `ProfileData`:
|
||||
```typescript
|
||||
export interface ProfileData {
|
||||
// ... existing fields
|
||||
fan_curve: FanPoint[] | null;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 Modify: `frontend/src/api/client.ts`
|
||||
|
||||
New API methods:
|
||||
```typescript
|
||||
fans: (gpuIndex: number) => get<FanState>('/fans', gpuIndex),
|
||||
updateFans: (updates: { curve?: FanPoint[] }, gpuIndex: number) => post('/fans', updates, gpuIndex),
|
||||
resetFans: (gpuIndex: number) => post('/fans/reset', undefined, gpuIndex),
|
||||
setFanSpeed: (fanPct: number, gpuIndex: number) => post('/fans/speed', { fan_pct: fanPct }, gpuIndex),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Frontend — Components
|
||||
|
||||
#### 3.1 New file: `frontend/src/components/Fans/FanCurveEditor.tsx`
|
||||
|
||||
Main content area for the Fans tab. Similar visual style to `PerformancePanel` but with a curve visualization:
|
||||
|
||||
**Layout:**
|
||||
- SVG chart: X-axis = temperature (°C, range ~20-100), Y-axis = fan speed (%)
|
||||
- Interactive points on the curve that can be dragged vertically (adjust fan %) and horizontally (adjust temp threshold)
|
||||
- Minimum 2 points, maximum ~10 points
|
||||
- Click to add a new point, drag to adjust, double-click or delete button to remove
|
||||
- Visual style matches `CurveEditor` but simpler (no domain toggle, no zoom/pan needed — the range is small)
|
||||
|
||||
**Controls (header bar, same pattern as PerformancePanel):**
|
||||
- "pending" badge when curve has unsaved changes
|
||||
- Apply / Discard / Reset buttons
|
||||
- ConfirmDialog on apply and reset
|
||||
|
||||
**Data flow:**
|
||||
- On mount: `GET /api/fans` to load current state
|
||||
- User edits → local `pending` state
|
||||
- Apply → `POST /api/fans` with new curve
|
||||
- Reset → `POST /api/fans/reset` to restore auto fan control
|
||||
|
||||
Color scheme: Use `orange-400` / `amber-400` for the fan curve line and points (heat-themed), consistent with the existing zinc/pink/cyan palette.
|
||||
|
||||
#### 3.2 New file: `frontend/src/components/Monitor/FanMonitor.tsx`
|
||||
|
||||
Sidebar component matching `LiveMonitor` / `PerformanceMonitor` style:
|
||||
|
||||
```
|
||||
Live Monitor (header)
|
||||
├─ GaugeCard: Fan Speed (current %, sparkline from history)
|
||||
├─ GaugeCard: GPU Temp (current °C, sparkline from history)
|
||||
├─ GaugeCard: Target Fan (interpolated target %, sparkline)
|
||||
└─ GaugeCard: Fan Mode ("Auto" / "Curve Active", no sparkline)
|
||||
```
|
||||
|
||||
Reuses existing `GaugeCard` component. Data comes from the existing `monitor` and `monitorHistory` from `useMonitor()` hook, plus `fanState` from the new fan API.
|
||||
|
||||
No new WebSocket needed — the existing monitor poller already pushes `fan_pct` and `temp_c`. The "Target Fan" gauge can be computed client-side from the active curve + current temp.
|
||||
|
||||
#### 3.3 Modify: `frontend/src/App.tsx`
|
||||
|
||||
Add `fans` to the tab union type and rendering:
|
||||
|
||||
```tsx
|
||||
const [activeTab, setActiveTab] = useState<'curve' | 'performance' | 'fans'>('curve');
|
||||
```
|
||||
|
||||
Add a third tab button between the existing buttons:
|
||||
```tsx
|
||||
<button onClick={() => setActiveTab('fans')}
|
||||
className={`... ${activeTab === 'fans' ? 'border-pink-500 text-zinc-100' : '...'}`}>
|
||||
Fans
|
||||
</button>
|
||||
```
|
||||
|
||||
Add the fans tab content rendering:
|
||||
```tsx
|
||||
{activeTab === 'fans' && (
|
||||
<div className="flex gap-4 items-start w-full">
|
||||
<div className="flex-1 min-w-0">
|
||||
<FanCurveEditor />
|
||||
</div>
|
||||
<div className="w-80 shrink-0 flex flex-col">
|
||||
<FanMonitor monitor={monitor} history={monitorHistory} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
Import the new components.
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Integration & Polish
|
||||
|
||||
#### 4.1 Profile Integration
|
||||
- When saving a profile, include the active fan curve
|
||||
- When applying a profile with a fan curve, activate it
|
||||
- In `ProfilePanel`, display a small indicator if a profile contains a fan curve
|
||||
|
||||
#### 4.2 Safety Considerations
|
||||
- Validate fan % values: clamp to 0-100
|
||||
- Validate temp values: reasonable range (0-120°C)
|
||||
- Ensure curve points are sorted by temp_c
|
||||
- Warn user before resetting to auto (fan control was manual)
|
||||
- On server disconnect, log a warning that fan curve control is lost
|
||||
|
||||
#### 4.3 Edge Cases
|
||||
- GPU with no controllable fan (e.g., SFF passively cooled) — `nvmlDeviceSetFanSpeed` returns error; show "Fan control not available" message
|
||||
- Multiple GPUs — each GPU has its own fan curve state
|
||||
- Driver doesn't support `nvmlDeviceSetFanSpeed` — graceful degradation, show read-only fan info
|
||||
|
||||
---
|
||||
|
||||
## File Summary
|
||||
|
||||
### New Files
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `nvcurve/hal/fans.py` | NVML fan control HAL (read, set, reset, fan info) |
|
||||
| `frontend/src/components/Fans/FanCurveEditor.tsx` | Fan curve editor with SVG chart |
|
||||
| `frontend/src/components/Monitor/FanMonitor.tsx` | Fan Live Monitor sidebar |
|
||||
|
||||
### Modified Files
|
||||
| File | Changes |
|
||||
|------|---------|
|
||||
| `nvcurve/server.py` | New `/api/fans` endpoints, fan poller task, per-GPU fan state, profile save/apply includes fan curve |
|
||||
| `nvcurve/nvapi/types.py` | No change (fan_pct already exists) |
|
||||
| `nvcurve/profiles/native.py` | `ProfileData` + `fan_curve` field, migration in `load_profile` |
|
||||
| `nvcurve/profiles/apply.py` | Apply fan curve when loading profile |
|
||||
| `frontend/src/types.ts` | `FanPoint`, `FanState` types; extend `ProfileData` |
|
||||
| `frontend/src/api/client.ts` | `fans`, `updateFans`, `resetFans`, `setFanSpeed` methods |
|
||||
| `frontend/src/App.tsx` | Third tab button + fan tab content rendering |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. **Backend HAL** — `hal/fans.py` (read fan, set fan, get fan info)
|
||||
2. **Backend Server** — `/api/fans` endpoints + fan poller in `server.py`
|
||||
3. **Backend Profiles** — extend `ProfileData`, save/apply integration
|
||||
4. **Frontend Types & API** — `types.ts`, `client.ts`
|
||||
5. **Frontend FanMonitor** — sidebar component (reuses existing data)
|
||||
6. **Frontend FanCurveEditor** — main chart component
|
||||
7. **Frontend App.tsx** — wire up the tab
|
||||
8. **Testing** — manual verification of fan control, profile save/apply, reset
|
||||
Reference in new issue
Block a user