133 lines
3.3 KiB
C++
133 lines
3.3 KiB
C++
#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);
|
|
} |