# GPU Fan Controller Usermod

This usermod allows WLED to control PWM PC fans based on GPU temperature data received from an external source (typically a Python script running on your PC).

## Features

- **Web API Integration**: Receives GPU temperature via HTTP API
- **Fixed Speed Mode**: Set a constant fan speed (0-100%)
- **Temperature Curve Mode**: Automatically adjusts fan speed based on temperature
- **Visual Curve Editor**: Interactive web-based graph editor at `/gpu-fan.htm`
- **Up to 5 Curve Points**: Define custom temperature-to-speed mappings
- **Safety Fallback**: Automatically runs at 100% if temperature data is lost
- **WLED UI Integration**: Control and monitor from the WLED web interface
- **Live Temperature Display**: See current GPU temp and fan speed in real-time

## Hardware Requirements

- ESP32 development board (ESP32 Dev Module recommended)
- 4-pin PWM PC fan (12V)
- 12V power supply for the fan
- Common ground connection between ESP32 and power supply

## Wiring

| Fan Pin | Connection |
|---------|------------|
| GND (Black) | ESP32 GND + 12V PSU GND |
| +12V (Yellow) | 12V Power Supply + |
| PWM (Blue) | ESP32 GPIO 13 (configurable) |
| TACH (Green) | Not used |

**Important:** 
- Connect 12V power supply GND to ESP32 GND (common ground)
- DO NOT connect +12V to any ESP32 pins

## Installation

### Option 1: Using platformio_override.ini (Recommended)

1. Copy the `GPU_Fan_Controller` folder to `wled00/usermods/`

2. Create or edit `platformio_override.ini` in the WLED root directory:

```ini
[env:esp32dev_gpu_fan]
extends = env:esp32dev
build_flags = ${env:esp32dev.build_flags}
  -D USERMOD_GPU_FAN_CONTROLLER
  -D PWM_FAN_PIN=13
custom_usermods = GPU_Fan_Controller
```

3. Build and upload:
```bash
pio run -e esp32dev_gpu_fan -t upload
```

4. Upload the custom page (optional but recommended):
```bash
pio run -e esp32dev_gpu_fan -t uploadfs
```

### Option 2: Manual Integration

1. Copy `GPU_Fan_Controller.cpp` to `wled00/usermods/GPU_Fan_Controller/`

2. Add to your build flags:
```
-D USERMOD_GPU_FAN_CONTROLLER
```

## Visual Curve Editor

Access the visual curve editor at: `http://YOUR_WLED_IP/gpu-fan.htm`

![Curve Editor Screenshot](curve-editor.png)

Features:
- **Drag points** on the graph to adjust temperature/speed mappings
- **Live temperature indicator** shows current GPU temp on the graph
- **Real-time updates** - see fan speed change as you adjust
- **Table view** for precise value entry
- **Add/remove points** - use 2-5 curve points
- **Mode toggle** - switch between Fixed and Curve modes

## Configuration

### Via WLED Web Interface

Navigate to Config → Usermods to configure:

- **enabled**: Enable/disable the fan controller
- **pwm-pin**: GPIO pin for PWM output (default: 13)
- **mode**: 0 = Fixed, 1 = Curve
- **fixed-speed**: Speed percentage when in fixed mode
- **timeout-ms**: Temperature timeout in milliseconds (default: 10000)
- **curve-t1 to curve-t5**: Temperature points (°C)
- **curve-s1 to curve-s5**: Speed points (%)
- **curve-points**: Number of curve points to use (2-5)

### Via JSON API

```json
{
  "GPU-Fan": {
    "enabled": true,
    "mode": 1,
    "fixed-speed": 50,
    "curve-points": 4,
    "curve-t1": 30, "curve-s1": 30,
    "curve-t2": 50, "curve-s2": 50,
    "curve-t3": 70, "curve-s3": 75,
    "curve-t4": 85, "curve-s4": 100
  }
}
```

## API Endpoints

### Update Temperature

Send GPU temperature to the controller:

```http
POST /json/state
Content-Type: application/json

{
  "GPU-Fan": {
    "temperature": 65.5
  }
}
```

### Set Manual Speed

```http
POST /json/state
Content-Type: application/json

{
  "GPU-Fan": {
    "speed": 75
  }
}
```

### Set Mode

```http
POST /json/state
Content-Type: application/json

{
  "GPU-Fan": {
    "mode": 1
  }
}
```

Where mode: 0 = Fixed, 1 = Curve

### Get Status

```http
GET /json/info
```

Response includes GPU temperature, fan speed, and mode in the "u" (user) object.

## Python GPU Monitor Script

Use the included `gpu_temp_monitor.py` script to send GPU temperatures to the ESP32:

### Installation

```bash
pip install requests nvidia-ml-py
# OR for multi-vendor support:
pip install requests gpustat
```

### Usage

```bash
# Basic usage
python gpu_temp_monitor.py --wled-ip 192.168.1.100

# Specify GPU type
python gpu_temp_monitor.py --wled-ip 192.168.1.100 --gpu-type nvidia

# Custom update interval
python gpu_temp_monitor.py --wled-ip 192.168.1.100 --interval 3
```

### Running as a Service

#### Windows (Task Scheduler)
Create a batch file and add to startup:
```batch
@echo off
python C:\path\to\gpu_temp_monitor.py --wled-ip 192.168.1.100
```

#### Linux (systemd)
Create `/etc/systemd/system/gpu-fan-monitor.service`:
```ini
[Unit]
Description=GPU Fan Controller Monitor
After=network.target

[Service]
Type=simple
User=yourusername
ExecStart=/usr/bin/python3 /path/to/gpu_temp_monitor.py --wled-ip 192.168.1.100
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

Enable and start:
```bash
sudo systemctl enable gpu-fan-monitor
sudo systemctl start gpu-fan-monitor
```

## Temperature Curve

The default curve provides quiet operation at low temperatures and aggressive cooling at high temperatures:

| Temperature | Fan Speed |
|-------------|-----------|
| ≤30°C | 30% |
| 50°C | 50% |
| 70°C | 75% |
| ≥85°C | 100% |

Speeds between points are linearly interpolated.

## Troubleshooting

### Fan not spinning
1. Check wiring connections
2. Verify the fan is PWM-compatible (4-pin)
3. Check that 12V power supply is adequate
4. Try a different GPIO pin

### Temperature not updating
1. Check the Python script is running
2. Verify ESP32 IP address is correct
3. Check firewall settings
4. Test with: `curl -X POST http://ESP32_IP/json/state -H "Content-Type: application/json" -d '{"GPU-Fan":{"temperature":50}}'`

### Curve not saving
1. Make sure to click "Save" in the curve editor
2. Check the browser console for errors
3. Try refreshing the page and re-saving

### WLED doesn't show the usermod
1. Ensure the build flag `-D USERMOD_GPU_FAN_CONTROLLER` is set
2. Rebuild and re-upload the firmware
3. Check serial output for initialization messages

## Technical Details

- **PWM Frequency**: 25kHz (Intel 4-pin fan specification)
- **PWM Resolution**: 8-bit (0-255)
- **Default GPIO**: 13 (configurable)
- **Update Interval**: 2 seconds
- **Safety Timeout**: 10 seconds (runs at 100% if no temperature data)
- **Max Curve Points**: 5

## License

This usermod is released under the same license as WLED (MIT).

## Credits

- WLED project: https://github.com/wled/WLED
- PWM fan control techniques adapted from various ESP32 fan controller projects
