# 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