diff --git a/README.md b/README.md index 018a4d5..18ebcc7 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,87 @@ # ESP32-C3 Fan Controller -An automatic server fan controller built on the ESP32-C3, featuring temperature-based relay control, OLED status display, and Home Assistant integration via MQTT. +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 -- **Auto fan control** — relay switches ON/OFF based on temperature thresholds with hysteresis -- **DHT22 sensor** — reads temperature and humidity every second -- **SSD1306 OLED** — displays live temp, humidity, and fan state -- **MQTT publishing** — streams sensor data and fan state to Home Assistant -- **WiFi** — connects on boot, auto-reconnects if MQTT drops +- **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 (with onboard OLED) | +| Microcontroller | ESP32-C3 | | Sensor | DHT22 (temperature + humidity) | -| Relay | 5V relay module (active-LOW) | -| Fan | USB 5V fan | -| Display | SSD1306 128×64 OLED (I2C) | +| 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.7kΩ pullup to 3V3) | -| `GPIO3` | Relay IN | +| `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, Relay GND | +| `GND` | DHT22 GND, OLED GND, MOSFET source, fan − | -Relay wiring: +Fan wiring: -- **COM** → USB 5V -- **NO** → Fan + (red wire) -- Fan − (black wire) → GND +- Fan **+** → USB 5 V +- Fan **−** → MOSFET **drain** +- MOSFET **source** → GND +- MOSFET **gate** → `GPIO3` ## Configuration -Copy `secrets.h.example` to `secrets.h` and fill in your values: +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" // Home Assistant IP -#define MQTT_USER "mqtt_user" -#define MQTT_PASS "mqtt_pass" +#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" ``` -### Temperature Thresholds +`secrets.h` is gitignored. -Edit these defines in `fan_controller.ino`: +### Fan Level Table -```cpp -#define TEMP_ON 28.0 // Fan turns ON above this (°C) -#define TEMP_OFF 25.0 // Fan turns OFF below this (°C) -``` +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 -| Topic | Direction | Payload | +All topics are publish-only (the firmware does not accept remote commands). + +| Topic | Payload | Notes | |---|---|---| -| `esp32c3_fan/temperature` | Publish | `23.5` (°C) | -| `esp32c3_fan/humidity` | Publish | `41` (%) | -| `esp32c3_fan/fan/state` | Publish | `ON` / `OFF` | +| `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 @@ -85,6 +102,10 @@ mqtt: 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" @@ -108,10 +129,12 @@ Install via Arduino IDE Library Manager: ## Project Structure ``` -esp32c3-fan-controller/ -├── fan_controller.ino # Main sketch -├── secrets.h # WiFi & MQTT credentials (gitignored) -├── secrets.h.example # Credentials template +fan4life/ +├── main/ +│ ├── main.ino # Main sketch +│ ├── secrets.h # WiFi & MQTT credentials (gitignored) +│ └── secrets.h.example # Credentials template +├── cad/ # Mechanical / enclosure files ├── .gitignore └── README.md ``` diff --git a/main/secrets.h.example b/main/secrets.h.example new file mode 100644 index 0000000..794f72a --- /dev/null +++ b/main/secrets.h.example @@ -0,0 +1,13 @@ +// Copy this file to `secrets.h` and fill in your values. +// `secrets.h` is gitignored so credentials stay out of version control. + +// --- WiFi --- +#define WIFI_SSID "your_wifi_ssid" +#define WIFI_PASS "your_wifi_password" + +// --- MQTT --- +#define MQTT_HOST "192.168.1.X" // Home Assistant / broker IP +#define MQTT_PORT 1883 +#define MQTT_USER "mqtt_user" +#define MQTT_PASS "mqtt_password" +#define MQTT_CLIENT "esp32c3_fan"