/********* Pleasedontcode.com ********** Pleasedontcode thanks you for automatic code generation! Enjoy your code! - Terms and Conditions: You have a non-exclusive, revocable, worldwide, royalty-free license for personal and commercial use. Attribution is optional; modifications are allowed, but you're responsible for code maintenance. We're not liable for any loss or damage. For full terms, please visit pleasedontcode.com/termsandconditions. - Project: Smart Automation - Source Code NOT compiled for: ESP32 DevKit V1 - Source Code created on: 2025-11-19 21:19:09 ********* Pleasedontcode.com **********/ /****** SYSTEM REQUIREMENTS *****/ /****** SYSTEM REQUIREMENT 1 *****/ /* relé umidificatore On se rh da dht11 <82 e off se */ /* rh da dht11 >85. relé ventole (AC e DC) on 6 volte */ /* in 24 ore per 74 secondi ogni volta. relé luci 12 */ /* ore on e 12 ore off */ /****** END SYSTEM REQUIREMENTS *****/ /* START CODE */ /******************************************************* * ESP32 + Blynk IoT + DHT11 + Fototransistor + 4 Relè + Buzzer * - Umidificatore: isteresi RHmin/RHmax (editabili da app) * - Ventole: 6 cicli/24h, ON 74 s ciascuno (2 relè: DC e AC) * - Luci: 12 h ON / 12 h OFF (ciclo relativo all'avvio) * - Fototransistor: verifica accensione luci (soglia editabile) * - Allarmi (buzzer attivo): * A) RH < RHmin per 30 min: 1 min beep 1 s ON / 1 s OFF * B) Luci dovrebbero essere ON ma luce < soglia per 30 min: * 1 min beep 2 s ON / 2 s OFF * Dopo 1 min l'allarme si ferma; la finestra 30 min riparte. *******************************************************/ #define BLYNK_TEMPLATE_ID "TMPL4X0xNGkPD" #define BLYNK_TEMPLATE_NAME "Camera Fruttificazione" #define BLYNK_AUTH_TOKEN "yu5gwTTfR31Gf1GBrGyEn8i2rxM7Ie9y" #define BLYNK_PRINT Serial #include #include // Blynk IoT per ESP32 (Virtual Pins, BlynkTimer) #include // Adafruit DHT library // ---- Credenziali Wi-Fi ---- char ssid[] = "WiFi"; char pass[] = "azz"; // ====== Pinout ====== #define PIN_DHT 4 #define PIN_PHOTO 34 // ADC1 (necessario con WiFi attivo) #define PIN_RELAY_HUM 26 #define PIN_RELAY_FAN_DC 27 #define PIN_RELAY_FAN_AC 25 #define PIN_RELAY_LIGHT 33 #define PIN_BUZZER 32 // Moduli relè spesso "active LOW" #define RELAY_ACTIVE_ON LOW #define RELAY_ACTIVE_OFF HIGH // ====== DHT ====== #define DHTTYPE DHT11 DHT dht(PIN_DHT, DHTTYPE); // ====== Blynk ====== BlynkTimer timer; // Virtual Pins #define VP_HUM V0 #define VP_TMP V1 #define VP_HUM_RLY V2 #define VP_FAN_DC V3 #define VP_FAN_AC V4 #define VP_LIGHT_RLY V5 #define VP_PHOTO V6 #define VP_RH_MIN V7 #define VP_RH_MAX V8 #define VP_LUX_THR V9 #define VP_EMERG V10 #define VP_ALARM V11 // ====== Parametri editabili da app (default) ====== volatile float rhMin = 82.0; // % RH volatile float rhMax = 85.0; // % RH volatile int lightThreshold = 200; // ADC 0..4095 // ====== Stati ====== bool emergency = false; bool humidifierOn = false; bool fanDCOn = false; bool fanACOn = false; bool lightsOn = false; // Scheduli const unsigned long FAN_PERIOD = 4UL * 60UL * 60UL * 1000UL; // ogni 4 h (6 volte/24h) const unsigned long FAN_ON_TIME = 74UL * 1000UL; // 74 s unsigned long nextFanMillis = 0; const unsigned long LIGHT_HALF_DAY = 12UL * 60UL * 60UL * 1000UL; // 12 h unsigned long nextLightToggle = 0; // Allarmi (finestre 30 min) const unsigned long WINDOW_30M = 30UL * 60UL * 1000UL; unsigned long lowRHStart = 0; unsigned long darkStart = 0; // ====== Buzzer / allarme ====== enum AlarmType { ALARM_NONE, ALARM_HUM_LOW, ALARM_LIGHT_FAIL }; AlarmType currentAlarm = ALARM_NONE; bool alarmActive = false; bool buzzerState = false; // stato ON/OFF corrente del buzzer uint16_t buzzerPeriodMs = 1000; // 1000 o 2000 int buzzerToggleTimerId = -1; int alarmStopTimerId = -1; // ====== Prototipi funzioni ====== void setRelay(int pin, bool on); void publishStates(); void startBuzzer(AlarmType t, uint16_t periodMs, const char* logEventCode, const char* msg); void readAndPublishSensors(); void controlHumidifier(); void fanScheduler(); void lightScheduler(); void checkAlarms(); // Callback timer (no lambda) void buzzerToggleTask(); void alarmStopTask(); void fanOffTask(); // ====== Utility ====== void setRelay(int pin, bool on) { digitalWrite(pin, on ? RELAY_ACTIVE_ON : RELAY_ACTIVE_OFF); } void publishStates() { Blynk.virtualWrite(VP_HUM_RLY, humidifierOn); Blynk.virtualWrite(VP_FAN_DC, fanDCOn); Blynk.virtualWrite(VP_FAN_AC, fanACOn); Blynk.virtualWrite(VP_LIGHT_RLY, lightsOn); } // ====== Blynk ====== BLYNK_CONNECTED() { Blynk.syncVirtual(VP_RH_MIN, VP_RH_MAX, VP_LUX_THR, VP_EMERG); } BLYNK_WRITE(VP_RH_MIN) { rhMin = param.asFloat(); } BLYNK_WRITE(VP_RH_MAX) { rhMax = param.asFloat(); } BLYNK_WRITE(VP_LUX_THR){ lightThreshold = param.asInt(); } BLYNK_WRITE(VP_EMERG) { emergency = param.asInt(); if (emergency) { // spegni tutto humidifierOn = fanDCOn = fanACOn = lightsOn = false; setRelay(PIN_RELAY_HUM, false); setRelay(PIN_RELAY_FAN_DC,false); setRelay(PIN_RELAY_FAN_AC,false); setRelay(PIN_RELAY_LIGHT, false); publishStates(); } else { // riavvia scheduler da ora nextFanMillis = millis() + FAN_PERIOD; nextLightToggle = millis() + LIGHT_HALF_DAY; } } // ====== Sensori e logiche ====== void readAndPublishSensors() { float h = dht.readHumidity(); float t = dht.readTemperature(); if (!isnan(h) && !isnan(t)) { Blynk.virtualWrite(VP_HUM, h); Blynk.virtualWrite(VP_TMP, t); } int raw = analogRead(PIN_PHOTO); // 0..4095 Blynk.virtualWrite(VP_PHOTO, raw); // Gestione finestre 30 min unsigned long now = millis(); if (!isnan(h)) { if (h < rhMin) { if (lowRHStart == 0) lowRHStart = now; } else { lowRHStart = 0; } } if (lightsOn) { if (raw < lightThreshold) { if (darkStart == 0) darkStart = now; } else { darkStart = 0; } } else { darkStart = 0; } } void controlHumidifier() { if (emergency || alarmActive) return; float h = dht.readHumidity(); if (isnan(h)) return; if (!humidifierOn && h < rhMin) { humidifierOn = true; } else if (humidifierOn && h > rhMax) { humidifierOn = false; } setRelay(PIN_RELAY_HUM, humidifierOn); Blynk.virtualWrite(VP_HUM_RLY, humidifierOn); } void fanScheduler() { if (emergency || alarmActive) return; unsigned long now = millis(); if (now >= nextFanMillis) { // Avvia ON di 74 s per entrambe le ventole fanDCOn = fanACOn = true; setRelay(PIN_RELAY_FAN_DC, true); setRelay(PIN_RELAY_FAN_AC, true); publishStates(); // Spegni dopo 74 s (callback senza lambda) timer.setTimeout(FAN_ON_TIME, fanOffTask); nextFanMillis = now + FAN_PERIOD; } } void lightScheduler() { if (emergency || alarmActive) return; unsigned long now = millis(); if (now >= nextLightToggle) { lightsOn = !lightsOn; // 12 h ON / 12 h OFF setRelay(PIN_RELAY_LIGHT, lightsOn); Blynk.virtualWrite(VP_LIGHT_RLY, lightsOn); nextLightToggle = now + LIGHT_HALF_DAY; } } void checkAlarms() { if (alarmActive || emergency) return; unsigned long now = millis(); // A) Umidità bassa persistente 30 min if (lowRHStart != 0 && (now - lowRHStart >= WINDOW_30M)) { lowRHStart = 0; startBuzzer(ALARM_HUM_LOW, 1000, "humidity_low_30m", "Umidità sotto soglia per 30 minuti"); return; } // B) Luci ON attese ma non rilevate per 30 min if (darkStart != 0 && (now - darkStart >= WINDOW_30M)) { darkStart = 0; startBuzzer(ALARM_LIGHT_FAIL, 2000, "light_fail_30m", "Luci attese ON ma non rilevate per 30 minuti"); return; } } // ====== Buzzer ====== void startBuzzer(AlarmType t, uint16_t periodMs, const char* logEventCode, const char* msg) { if (alarmActive) return; alarmActive = true; currentAlarm = t; buzzerPeriodMs = periodMs; if (logEventCode) { Blynk.logEvent(logEventCode, msg); // Richiede eventi creati nel Template } Blynk.virtualWrite( VP_ALARM, (t == ALARM_HUM_LOW) ? "ALLARME: Umidità bassa" : (t == ALARM_LIGHT_FAIL) ? "ALLARME: Luci non rilevate" : "" ); pinMode(PIN_BUZZER, OUTPUT); buzzerState = true; digitalWrite(PIN_BUZZER, HIGH); // Toggle periodico (1 s o 2 s) buzzerToggleTimerId = timer.setInterval(buzzerPeriodMs, buzzerToggleTask); // Stop dopo 60 s alarmStopTimerId = timer.setTimeout(60UL * 1000UL, alarmStopTask); } void buzzerToggleTask() { buzzerState = !buzzerState; digitalWrite(PIN_BUZZER, buzzerState ? HIGH : LOW); } void alarmStopTask() { if (buzzerToggleTimerId != -1) { timer.disable(buzzerToggleTimerId); timer.deleteTimer(buzzerToggleTimerId); buzzerToggleTimerId = -1; } digitalWrite(PIN_BUZZER, LOW); alarmActive = false; currentAlarm = ALARM_NONE; Blynk.virtualWrite(VP_ALARM, ""); } void fanOffTask() { fanDCOn = fanACOn = false; setRelay(PIN_RELAY_FAN_DC, false); setRelay(PIN_RELAY_FAN_AC, false); publishStates(); } // ====== Setup/Loop ====== void setup() { Serial.begin(115200); // Relè pinMode(PIN_RELAY_HUM, OUTPUT); pinMode(PIN_RELAY_FAN_DC, OUTPUT); pinMode(PIN_RELAY_FAN_AC, OUTPUT); pinMode(PIN_RELAY_LIGHT, OUTPUT); // Tutto OFF setRelay(PIN_RELAY_HUM, false); setRelay(PIN_RELAY_FAN_DC,false); setRelay(PIN_RELAY_FAN_AC,false); setRelay(PIN_RELAY_LIGHT, false); publishStates(); // ADC: 12 bit e attenuazione 11 dB (~0..3.1 V) analogReadResolution(12); analogSetPinAttenuation(PIN_PHOTO, ADC_11db); dht.begin(); Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass); // Timers (funzioni senza lambda) timer.setInterval(2000, readAndPublishSensors); // ogni 2 s timer.setInterval(1000, controlHumidifier); // ogni 1 s timer.setInterval(1000, fanScheduler); // ogni 1 s timer.setInterval(1000, lightScheduler); // ogni 1 s timer.setInterval(5000, publishStates); // ogni 5 s timer.setInterval(10000, checkAlarms); // ogni 10 s // Inizializza scheduler da "adesso" unsigned long now = millis(); nextFanMillis = now; // prima accensione ventole subito lightsOn = true; // avvia con 12 h ON setRelay(PIN_RELAY_LIGHT, lightsOn); Blynk.virtualWrite(VP_LIGHT_RLY, lightsOn); nextLightToggle = now + LIGHT_HALF_DAY; } void loop() { Blynk.run(); timer.run(); } /* END CODE */