#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
// --------- WiFi (Wokwi) ---------
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
const char* THINGSPEAK_API_KEY = "52LB2FG9BXVLSBFU"; // thingspeak
// --------- Pinos ---------
#define PIN_DHT 15
#define DHTTYPE DHT22
#define PIN_LDR 34 // ADC-only (0..4095 no ESP32)
#define PIN_FAN 16 // LED/Ventilador
#define PIN_HEAT 17 // LED/Aquecedor
#define PIN_CURT 18 // LED/Cortina (fechar)
#define PIN_BUZZ 27 // Buzzer
// I2C do LCD no ESP32: SDA=21, SCL=22
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht(PIN_DHT, DHTTYPE);
// --------- Setpoints / Histerese ---------
float T_FAN_ON = 28.0, T_FAN_OFF = 26.0;
float T_HEAT_ON = 18.0, T_HEAT_OFF = 20.0;
int LUX_CLOSE = 2500, LUX_OPEN = 2000;
// --------- Estados ---------
bool fanOn=false, heatOn=false, curtainClosed=false;
unsigned long lastPost=0;
const unsigned long POST_PERIOD_MS=20000; // ThingSpeak >=15 s
/// --------- Média móvel LDR ---------
const int LDR_NSAMPLES = 8;
int readLdrAveraged() {
long acc = 0;
for (int i=0; i<LDR_NSAMPLES; i++) {
acc += analogRead(PIN_LDR);
delay(2);
}
return (int)(acc / LDR_NSAMPLES);
}
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(200); }
}
void setup() {
Serial.begin(115200);
pinMode(PIN_FAN, OUTPUT);
pinMode(PIN_HEAT, OUTPUT);
pinMode(PIN_CURT, OUTPUT);
pinMode(PIN_BUZZ, OUTPUT);
digitalWrite(PIN_FAN, LOW);
digitalWrite(PIN_HEAT, LOW);
digitalWrite(PIN_CURT, LOW);
digitalWrite(PIN_BUZZ, LOW);
dht.begin();
lcd.init();
lcd.backlight();
lcd.setCursor(0,0); lcd.print("Estufa Online");
lcd.setCursor(0,1); lcd.print("Inicializando");
connectWiFi();
delay(800);
}
void loop() {
// --- Sensores ---
float hum = dht.readHumidity();
float tAir = dht.readTemperature(); // °C
int lux = readLdrAveraged(); // 0..4095
if (isnan(hum) || isnan(tAir)) {
Serial.println("Falha na leitura do DHT22.");
}
// --- Controle com histerese ---
// Ventilador
if (!fanOn && tAir >= T_FAN_ON) fanOn = true;
else if (fanOn && tAir <= T_FAN_OFF) fanOn = false;
// Aquecedor
if (!heatOn && tAir <= T_HEAT_ON) heatOn = true;
else if (heatOn && tAir >= T_HEAT_OFF) heatOn = false;
// Cortina (fechar = reduzir luz)
if (!curtainClosed && lux >= LUX_CLOSE) curtainClosed = true;
else if (curtainClosed && lux <= LUX_OPEN) curtainClosed = false;
// --- Saídas físicas ---
digitalWrite(PIN_FAN, fanOn ? HIGH : LOW);
digitalWrite(PIN_HEAT, heatOn ? HIGH : LOW);
digitalWrite(PIN_CURT, curtainClosed ? HIGH : LOW);
// Alarme (extremos)
if (tAir >= 40.0 || tAir <= 10.0) {
tone(PIN_BUZZ, 2000, 150);
}
// --- LCD ---
lcd.clear();
lcd.setCursor(0,0);
lcd.print("T:");
lcd.print(isnan(tAir)?0:tAir,1);
lcd.print(" H:");
lcd.print(isnan(hum)?0:hum,0);
lcd.print("%");
lcd.setCursor(0,1);
lcd.print("L:");
lcd.print(lux);
/*lcd.print(" Vent");
lcd.print(fanOn?1:0);
lcd.print(" Aq");
lcd.print(heatOn?1:0);
lcd.print(" Cort");
lcd.print(curtainClosed?1:0);*/
// --- ThingSpeak (Field1..Field6) ---
if (WiFi.status()==WL_CONNECTED && (millis()-lastPost)>=POST_PERIOD_MS) {
lastPost = millis();
HTTPClient http;
String url = "http://api.thingspeak.com/update?api_key=" + String(THINGSPEAK_API_KEY) +
"&field1=" + String(isnan(tAir)?0:tAir, 2) +
"&field2=" + String(isnan(hum)?0:hum, 1) +
"&field3=" + String(lux) +
"&field4=" + String(fanOn?1:0) +
"&field5=" + String(heatOn?1:0) +
"&field6=" + String(curtainClosed?1:0);
http.begin(url);
int code = http.GET();
Serial.print("ThingSpeak: "); Serial.println(code);
http.end();
}
// --- Log Serial (em português) ---
Serial.printf("T=%.2fC H=%.0f%% L=%d Vent=%d Aquec=%d Cort=%d\n",
isnan(tAir)?0:tAir, isnan(hum)?0:hum, lux, fanOn, heatOn, curtainClosed);
delay(500);
}