# ESP32-C3 Fan Controller

An automatic server fan controller built on the ESP32-C3. Drives a 5 V fan over PWM through an IRLZ44N MOSFET, auto-selects fan speed from a temperature table with hysteresis, shows live status on an OLED, and publishes sensor/fan state to Home Assistant over MQTT.

## Features

- **Temperature-driven PWM fan control** — 5 discrete speed levels, selected automatically from the current temperature
- **Hysteresis** — 1 °C drop-down margin prevents level flapping
- **DHT22 sensor** — reads temperature and humidity every 3 s
- **SSD1306 OLED** — displays live temp, humidity, fan state, and level
- **MQTT publishing** — streams sensor and fan data for Home Assistant
- **WiFi** — connects on boot, auto-reconnects WiFi and MQTT if they drop

## Hardware

| Component | Details |
|---|---|
| Microcontroller | ESP32-C3 |
| Sensor | DHT22 (temperature + humidity) |
| Driver | IRLZ44N N-channel MOSFET (logic-level) |
| Fan | 2-wire 5 V fan |
| Display | SSD1306 128×64 OLED (I²C) |

## Wiring

| ESP32-C3 Pin | Connected To |
|---|---|
| `GPIO2` | DHT22 DATA (+ 4.7 kΩ pullup to 3V3) |
| `GPIO3` | MOSFET gate (via ~150 Ω) + 100 kΩ gate→GND pulldown |
| `GPIO5` (SDA) | OLED SDA |
| `GPIO6` (SCL) | OLED SCL |
| `3V3` | DHT22 VCC, OLED VCC |
| `GND` | DHT22 GND, OLED GND, MOSFET source, fan − |

Fan wiring:

- Fan **+** → USB 5 V
- Fan **−** → MOSFET **drain**
- MOSFET **source** → GND
- MOSFET **gate** → `GPIO3`

## Configuration

Copy `main/secrets.h.example` to `main/secrets.h` and fill in your values:

```cpp
#define WIFI_SSID     "your_wifi_ssid"
#define WIFI_PASS     "your_wifi_password"
#define MQTT_HOST     "192.168.1.X"
#define MQTT_PORT     1883
#define MQTT_USER     "mqtt_user"
#define MQTT_PASS     "mqtt_password"
#define MQTT_CLIENT   "esp32c3_fan"
```

`secrets.h` is gitignored.

### Fan Level Table

Fan speed is selected from a table of (temperature threshold → PWM duty) in `main/main.ino`:

| Level | Temp ≥ | PWM duty (0–255) |
|-------|--------|------------------|
| 0 (off) | —      | 0                |
| 1     | 28 °C  | 230              |
| 2     | 30 °C  | 236              |
| 3     | 32 °C  | 242              |
| 4     | 34 °C  | 249              |
| 5     | 36 °C  | 255              |

`TEMP_HYST` (default `1.0 °C`) controls the drop-down margin: the fan only drops a level once temperature falls this much below that level's threshold. Below level 1's threshold minus hysteresis, the fan turns off.

Tune `LEVELS[]` and `TEMP_HYST` in `main/main.ino` to match your thermal setup.

## MQTT Topics

All topics are publish-only (the firmware does not accept remote commands).

| Topic | Payload | Notes |
|---|---|---|
| `esp32c3_fan/temperature` | `23.5` | °C, every loop |
| `esp32c3_fan/humidity`    | `41`   | %, every loop |
| `esp32c3_fan/fan/state`   | `ON` / `OFF` | retained |
| `esp32c3_fan/fan/speed`   | `0`..`5` | current level, retained |

## Home Assistant Setup

Add to `configuration.yaml`:

```yaml
mqtt:
  sensor:
    - name: "Room Temperature"
      unique_id: "esp32c3_temperature"
      state_topic: "esp32c3_fan/temperature"
      unit_of_measurement: "°C"
      device_class: temperature

    - name: "Room Humidity"
      unique_id: "esp32c3_humidity"
      state_topic: "esp32c3_fan/humidity"
      unit_of_measurement: "%"
      device_class: humidity

    - name: "Server Fan Level"
      unique_id: "esp32c3_fan_level"
      state_topic: "esp32c3_fan/fan/speed"

  binary_sensor:
    - name: "Server Fan"
      unique_id: "esp32c3_fan"
      state_topic: "esp32c3_fan/fan/state"
      payload_on: "ON"
      payload_off: "OFF"
      device_class: running
```

Restart HA after saving. Requires the **Mosquitto broker** add-on installed and running.

## Dependencies

Install via Arduino IDE Library Manager:

- [U8g2](https://github.com/olikraus/u8g2) — OLED display
- [DHT sensor library](https://github.com/adafruit/DHT-sensor-library) — DHT22
- [PubSubClient](https://github.com/knolleary/pubsubclient) — MQTT client
- WiFi (built-in with ESP32 board package)

## Project Structure

```
fan4life/
├── main/
│   ├── main.ino            # Main sketch
│   ├── secrets.h           # WiFi & MQTT credentials (gitignored)
│   └── secrets.h.example   # Credentials template
├── cad/                    # Mechanical / enclosure files
├── .gitignore
└── README.md
```

## License

MIT
