chore: v1
This commit is contained in:
41
.gitignore
vendored
Normal file
41
.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode/
|
||||
|
||||
# Arduino
|
||||
build/
|
||||
.clang-format
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
# Arduino IDE
|
||||
.pioenvs/
|
||||
.piolibdeps/
|
||||
.pio/
|
||||
.vscode-pio
|
||||
|
||||
# PlatformIO
|
||||
.platformio/
|
||||
platformio.ini
|
||||
|
||||
# Build directories
|
||||
bin/
|
||||
obj/
|
||||
|
||||
# Editor backups
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
# Dependencies and libraries
|
||||
node_modules/
|
||||
dist/
|
||||
120
README.md
Normal file
120
README.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# 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.
|
||||
|
||||
## 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
|
||||
|
||||
## Hardware
|
||||
|
||||
| Component | Details |
|
||||
|---|---|
|
||||
| Microcontroller | ESP32-C3 (with onboard OLED) |
|
||||
| Sensor | DHT22 (temperature + humidity) |
|
||||
| Relay | 5V relay module (active-LOW) |
|
||||
| Fan | USB 5V fan |
|
||||
| Display | SSD1306 128×64 OLED (I2C) |
|
||||
|
||||
## Wiring
|
||||
|
||||
| ESP32-C3 Pin | Connected To |
|
||||
|---|---|
|
||||
| `GPIO2` | DHT22 DATA (+ 4.7kΩ pullup to 3V3) |
|
||||
| `GPIO3` | Relay IN |
|
||||
| `GPIO5` (SDA) | OLED SDA |
|
||||
| `GPIO6` (SCL) | OLED SCL |
|
||||
| `3V3` | DHT22 VCC, OLED VCC |
|
||||
| `GND` | DHT22 GND, OLED GND, Relay GND |
|
||||
|
||||
Relay wiring:
|
||||
- **COM** → USB 5V
|
||||
- **NO** → Fan + (red wire)
|
||||
- Fan − (black wire) → GND
|
||||
|
||||
## Configuration
|
||||
|
||||
Copy `secrets.h.example` to `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"
|
||||
```
|
||||
|
||||
### Temperature Thresholds
|
||||
|
||||
Edit these defines in `fan_controller.ino`:
|
||||
|
||||
```cpp
|
||||
#define TEMP_ON 28.0 // Fan turns ON above this (°C)
|
||||
#define TEMP_OFF 25.0 // Fan turns OFF below this (°C)
|
||||
```
|
||||
|
||||
## MQTT Topics
|
||||
|
||||
| Topic | Direction | Payload |
|
||||
|---|---|---|
|
||||
| `esp32c3/temperature` | Publish | `23.5` (°C) |
|
||||
| `esp32c3/humidity` | Publish | `41` (%) |
|
||||
| `esp32c3/fan/state` | Publish | `ON` / `OFF` |
|
||||
|
||||
## Home Assistant Setup
|
||||
|
||||
Add to `configuration.yaml`:
|
||||
|
||||
```yaml
|
||||
mqtt:
|
||||
sensor:
|
||||
- name: "Room Temperature"
|
||||
unique_id: "esp32c3_temperature"
|
||||
state_topic: "esp32c3/temperature"
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
|
||||
- name: "Room Humidity"
|
||||
unique_id: "esp32c3_humidity"
|
||||
state_topic: "esp32c3/humidity"
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
|
||||
binary_sensor:
|
||||
- name: "Server Fan"
|
||||
unique_id: "esp32c3_fan"
|
||||
state_topic: "esp32c3/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
|
||||
|
||||
```
|
||||
esp32c3-fan-controller/
|
||||
├── fan_controller.ino # Main sketch
|
||||
├── secrets.h # WiFi & MQTT credentials (gitignored)
|
||||
├── secrets.h.example # Credentials template
|
||||
├── .gitignore
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
133
arduino/main.ino
Normal file
133
arduino/main.ino
Normal file
@@ -0,0 +1,133 @@
|
||||
#include <U8g2lib.h>
|
||||
#include <DHT.h>
|
||||
#include <WiFi.h>
|
||||
#include <PubSubClient.h>
|
||||
|
||||
// --- WiFi ---
|
||||
#define WIFI_SSID "GL-AXT1800-714"
|
||||
#define WIFI_PASS "BDX924MWFW"
|
||||
|
||||
// --- MQTT ---
|
||||
#define MQTT_HOST "192.168.8.101" // your HA IP
|
||||
#define MQTT_PORT 1883
|
||||
#define MQTT_USER "mqtt_user" // Mosquitto user
|
||||
#define MQTT_PASS "Naughty0pArrot"
|
||||
#define MQTT_CLIENT "esp32c3_fan"
|
||||
|
||||
// Topics
|
||||
#define TOPIC_TEMP "esp32c3_fan/temperature"
|
||||
#define TOPIC_HUMIDITY "esp32c3_fan/humidity"
|
||||
#define TOPIC_FAN_STATE "esp32c3_fan/fan/state"
|
||||
#define TOPIC_FAN_CMD "esp32c3_fan/fan/set" // HA sends ON/OFF here
|
||||
|
||||
// --- Pins ---
|
||||
#define DHTPIN 2
|
||||
#define DHTTYPE DHT22
|
||||
#define RELAY_PIN 3
|
||||
|
||||
// --- Thresholds ---
|
||||
#define TEMP_ON 28.0
|
||||
#define TEMP_OFF 25.0
|
||||
|
||||
// --- OLED ---
|
||||
#define OLED_RESET U8X8_PIN_NONE
|
||||
#define OLED_SDA 5
|
||||
#define OLED_SCL 6
|
||||
|
||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, OLED_RESET, OLED_SCL, OLED_SDA);
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
WiFiClient wifiClient;
|
||||
PubSubClient mqtt(wifiClient);
|
||||
|
||||
int xOffset = 30;
|
||||
int yOffset = 30;
|
||||
bool fanState = false;
|
||||
|
||||
void setFan(bool on) {
|
||||
fanState = on;
|
||||
digitalWrite(RELAY_PIN, on ? LOW : HIGH); // active-LOW relay
|
||||
mqtt.publish(TOPIC_FAN_STATE, on ? "ON" : "OFF", true);
|
||||
}
|
||||
|
||||
void connectWiFi() {
|
||||
Serial.printf("Connecting to %s", WIFI_SSID);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500); Serial.print(".");
|
||||
}
|
||||
Serial.printf("\nWiFi connected: %s\n", WiFi.localIP().toString().c_str());
|
||||
}
|
||||
|
||||
void connectMQTT() {
|
||||
while (!mqtt.connected()) {
|
||||
Serial.print("Connecting MQTT...");
|
||||
if (mqtt.connect(MQTT_CLIENT, MQTT_USER, MQTT_PASS)) {
|
||||
Serial.println("connected!");
|
||||
} else {
|
||||
Serial.printf("failed rc=%d, retry in 5s\n", mqtt.state());
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_oled(float tempC, float humidity) {
|
||||
char line1[20], line2[20], line3[20];
|
||||
snprintf(line1, sizeof(line1), "T: %.1f C", tempC);
|
||||
snprintf(line2, sizeof(line2), "H: %.0f %%", humidity);
|
||||
snprintf(line3, sizeof(line3), "Fan: %s", fanState ? "ON" : "OFF");
|
||||
|
||||
u8g2.clearDisplay();
|
||||
u8g2.clearBuffer();
|
||||
u8g2.setFont(u8g2_font_4x6_tr);
|
||||
u8g2.drawStr(xOffset, yOffset, line1);
|
||||
u8g2.drawStr(xOffset, yOffset + 10, line2);
|
||||
u8g2.drawStr(xOffset, yOffset + 20, line3);
|
||||
u8g2.sendBuffer();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
dht.begin();
|
||||
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
setFan(false); // fan OFF at boot
|
||||
|
||||
u8g2.begin();
|
||||
u8g2.setContrast(255);
|
||||
u8g2.setBusClock(400000);
|
||||
u8g2.clearDisplay();
|
||||
|
||||
connectWiFi();
|
||||
mqtt.setServer(MQTT_HOST, MQTT_PORT);
|
||||
connectMQTT();
|
||||
|
||||
Serial.println("Ready.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!mqtt.connected()) connectMQTT();
|
||||
mqtt.loop();
|
||||
|
||||
float tempC = dht.readTemperature();
|
||||
float humidity = dht.readHumidity();
|
||||
|
||||
if (isnan(tempC) || isnan(humidity)) {
|
||||
Serial.println("DHT22 read failed");
|
||||
delay(2000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto fan control with hysteresis
|
||||
if (!fanState && tempC >= TEMP_ON) setFan(true);
|
||||
if (fanState && tempC <= TEMP_OFF) setFan(false);
|
||||
|
||||
// Publish to MQTT
|
||||
char buf[10];
|
||||
dtostrf(tempC, 4, 1, buf); mqtt.publish(TOPIC_TEMP, buf);
|
||||
dtostrf(humidity, 4, 0, buf); mqtt.publish(TOPIC_HUMIDITY, buf);
|
||||
|
||||
Serial.printf("T:%.1fC H:%.0f%% Fan:%s\n", tempC, humidity, fanState ? "ON" : "OFF");
|
||||
handle_oled(tempC, humidity);
|
||||
|
||||
delay(3000);
|
||||
}
|
||||
Reference in New Issue
Block a user