#include <DHT.h>
#include <Fuzzy.h>
#include <FuzzyComposition.h>
#include <FuzzyInput.h>
#include <FuzzyIO.h>
#include <FuzzyOutput.h>
#include <FuzzyRule.h>
#include <FuzzyRuleAntecedent.h>
#include <FuzzyRuleConsequent.h>
#include <FuzzySet.h>
#define DHTPIN 22 // El pin DATA del sensor DHT22 se conecta al GPIO 22 del ESP32
#define DHTTYPE DHT22 // Definición del tipo de sensor DHT
DHT dht(DHTPIN, DHTTYPE);
#define LED_PIN_AMBIENT 23 // luces LED para iluminación
#define LED_PIN_HUMIDITY 25 // Luces LED para bombas.
#define LDR_PIN 34 // GPIO 34 lee el valor LDR
Fuzzy *fuzzy = new Fuzzy();
void setup() {
Serial.begin(9600);
pinMode(LED_PIN_AMBIENT, OUTPUT);
pinMode(LED_PIN_HUMIDITY, OUTPUT);
dht.begin();
// Definir conjuntos difusos para LDR
FuzzySet *veryLowLight = new FuzzySet(840, 1000, 1023, 1023);
FuzzySet *lowLight = new FuzzySet(540, 800, 800, 1000);
FuzzySet *mediumLight = new FuzzySet(270, 500, 500, 700);
FuzzySet *highLight = new FuzzySet(32, 230, 230, 400);
FuzzySet *veryHighLight = new FuzzySet(32, 32, 42, 90);
FuzzyInput *light = new FuzzyInput(1);
light->addFuzzySet(veryLowLight);
light->addFuzzySet(lowLight);
light->addFuzzySet(mediumLight);
light->addFuzzySet(highLight);
light->addFuzzySet(veryHighLight);
fuzzy->addFuzzyInput(light);
// Salida difusa: brillo del LED y tiempo de iluminación
FuzzyOutput *ledIntensity = new FuzzyOutput(1);
FuzzySet *intensityVeryStrong = new FuzzySet(204, 230, 255, 255);
FuzzySet *intensityStrong = new FuzzySet(150, 178, 178, 230);
FuzzySet *intensityMedium = new FuzzySet(60, 130, 130, 178);
FuzzySet *intensityWeak = new FuzzySet(0, 60, 60, 130);
FuzzySet *intensityVeryWeak = new FuzzySet(0, 0, 40, 65);
ledIntensity->addFuzzySet(intensityVeryWeak);
ledIntensity->addFuzzySet(intensityWeak);
ledIntensity->addFuzzySet(intensityMedium);
ledIntensity->addFuzzySet(intensityStrong);
ledIntensity->addFuzzySet(intensityVeryStrong);
fuzzy->addFuzzyOutput(ledIntensity);
FuzzyOutput *lightingDuration = new FuzzyOutput(2);
FuzzySet *durationVeryLong = new FuzzySet(13900, 17000, 18000, 18000);
FuzzySet *durationLong = new FuzzySet(9000, 13500, 13500, 13500);
FuzzySet *durationMedium = new FuzzySet(4500, 9000, 9000, 13500);
FuzzySet *durationShort = new FuzzySet(0, 4500, 4500, 9000);
FuzzySet *durationVeryShort = new FuzzySet(0, 0, 450, 4000);
lightingDuration->addFuzzySet(durationVeryShort);
lightingDuration->addFuzzySet(durationShort);
lightingDuration->addFuzzySet(durationMedium);
lightingDuration->addFuzzySet(durationLong);
lightingDuration->addFuzzySet(durationVeryLong);
fuzzy->addFuzzyOutput(lightingDuration);
// Definición de reglas difusas
// Regla 1: Si la intensidad de la luz es baja, el tiempo de iluminación es muy largo y la intensidad de la luz es muy fuerte.
FuzzyRuleAntecedent *ifLightVeryLow = new FuzzyRuleAntecedent();
ifLightVeryLow->joinSingle(veryLowLight);
FuzzyRuleConsequent *thenIntensityVeryStrongAndDurationVeryLong = new FuzzyRuleConsequent();
thenIntensityVeryStrongAndDurationVeryLong->addOutput(intensityVeryStrong);
thenIntensityVeryStrongAndDurationVeryLong->addOutput(durationVeryLong);
fuzzy->addFuzzyRule(new FuzzyRule(1, ifLightVeryLow, thenIntensityVeryStrongAndDurationVeryLong));
// Regla 2: si la intensidad de la luz es baja, el tiempo de iluminación es largo y la intensidad de la luz es fuerte.
FuzzyRuleAntecedent *ifLightLow = new FuzzyRuleAntecedent();
ifLightLow->joinSingle(lowLight);
FuzzyRuleConsequent *thenIntensityStrongAndDurationLong = new FuzzyRuleConsequent();
thenIntensityStrongAndDurationLong->addOutput(intensityStrong);
thenIntensityStrongAndDurationLong->addOutput(durationLong);
fuzzy->addFuzzyRule(new FuzzyRule(2, ifLightLow, thenIntensityStrongAndDurationLong));
// Regla 3: Si la intensidad de la luz es promedio, entonces el tiempo de iluminación es promedio y la intensidad de la luz de la lámpara es promedio.
FuzzyRuleAntecedent *ifLightMedium = new FuzzyRuleAntecedent();
ifLightMedium->joinSingle(mediumLight);
FuzzyRuleConsequent *thenIntensityMediumAndDurationMedium = new FuzzyRuleConsequent();
thenIntensityMediumAndDurationMedium->addOutput(intensityMedium);
thenIntensityMediumAndDurationMedium->addOutput(durationMedium);
fuzzy->addFuzzyRule(new FuzzyRule(3, ifLightMedium, thenIntensityMediumAndDurationMedium));
// Regla 4: Si la intensidad de la luz es alta, el tiempo de iluminación es corto y la intensidad de la luz es débil.
FuzzyRuleAntecedent *ifLightHigh = new FuzzyRuleAntecedent();
ifLightHigh->joinSingle(highLight);
FuzzyRuleConsequent *thenIntensityWeakAndDurationShort = new FuzzyRuleConsequent();
thenIntensityWeakAndDurationShort->addOutput(intensityWeak);
thenIntensityWeakAndDurationShort->addOutput(durationShort);
fuzzy->addFuzzyRule(new FuzzyRule(4, ifLightHigh, thenIntensityWeakAndDurationShort));
// Regla 5: Si la intensidad de la luz es muy alta, el tiempo de iluminación es muy corto y la intensidad de la luz es muy débil.
FuzzyRuleAntecedent *ifLightVeryHigh = new FuzzyRuleAntecedent();
ifLightVeryHigh->joinSingle(veryHighLight);
FuzzyRuleConsequent *thenIntensityVeryWeakAndDurationVeryShort = new FuzzyRuleConsequent();
thenIntensityVeryWeakAndDurationVeryShort->addOutput(intensityVeryWeak);
thenIntensityVeryWeakAndDurationVeryShort->addOutput(durationVeryShort);
fuzzy->addFuzzyRule(new FuzzyRule(5, ifLightVeryHigh, thenIntensityVeryWeakAndDurationVeryShort));
// Definición de conjuntos difusos para DHT
FuzzySet *dry = new FuzzySet(0, 0, 5, 25);
FuzzySet *somewhatDry = new FuzzySet(0, 25, 25, 50);
FuzzySet *moist = new FuzzySet(25, 50, 50, 75);
FuzzySet *wet = new FuzzySet(50, 75, 75, 100);
FuzzySet *veryWet = new FuzzySet(80, 95, 100, 100);
FuzzyInput *humidity = new FuzzyInput(2);
humidity->addFuzzySet(dry);
humidity->addFuzzySet(somewhatDry);
humidity->addFuzzySet(moist);
humidity->addFuzzySet(wet);
humidity->addFuzzySet(veryWet);
fuzzy->addFuzzyInput(humidity);
FuzzySet *veryLowTemperature = new FuzzySet(15, 15, 17, 19);
FuzzySet *lowTemperature = new FuzzySet(15, 21, 21, 27);
FuzzySet *mediumTemperature = new FuzzySet(21, 27, 27, 33);
FuzzySet *highTemperature = new FuzzySet(27, 34, 34, 40);
FuzzySet *veryHighTemperature = new FuzzySet(33, 38, 40, 40);
FuzzyInput *temperature = new FuzzyInput(3);
temperature->addFuzzySet(veryLowTemperature);
temperature->addFuzzySet(lowTemperature);
temperature->addFuzzySet(mediumTemperature);
temperature->addFuzzySet(highTemperature);
temperature->addFuzzySet(veryHighTemperature);
fuzzy->addFuzzyInput(temperature);
// Salida difusa: tiempo de bombeo de agua
FuzzyOutput *wateringDuration = new FuzzyOutput(3);
FuzzySet *wdurationVeryLong = new FuzzySet(650, 1000, 1000, 1200);
FuzzySet *wdurationLong = new FuzzySet(200, 470, 470, 700);
FuzzySet *wdurationMedium = new FuzzySet(130, 230, 230, 330);
FuzzySet *wdurationShort = new FuzzySet(0, 130, 130, 230);
FuzzySet *wdurationVeryShort = new FuzzySet(0, 0, 50, 100);
wateringDuration->addFuzzySet(wdurationVeryShort);
wateringDuration->addFuzzySet(wdurationShort);
wateringDuration->addFuzzySet(wdurationMedium);
wateringDuration->addFuzzySet(wdurationLong);
wateringDuration->addFuzzySet(wdurationVeryLong);
fuzzy->addFuzzyOutput(wateringDuration);
// Definición de reglas difusas
// Regla 1: Si la humedad es muy baja y la temperatura es muy alta, el tiempo de bombeo es muy largo.
FuzzyRuleAntecedent *ifHumidityVeryLowandTemperatureVeryHigh = new FuzzyRuleAntecedent();
ifHumidityVeryLowandTemperatureVeryHigh->joinSingle(dry);
ifHumidityVeryLowandTemperatureVeryHigh->joinSingle(veryHighTemperature);
FuzzyRuleConsequent *thenWdurationVeryLong = new FuzzyRuleConsequent();
thenWdurationVeryLong->addOutput(wdurationVeryLong);
fuzzy->addFuzzyRule(new FuzzyRule(6, ifHumidityVeryLowandTemperatureVeryHigh, thenWdurationVeryLong));
// Regla 2: Si la humedad es muy baja y la temperatura es alta, el tiempo de bombeo es muy largo.
FuzzyRuleAntecedent *ifHumidityVeryLowandTemperatureHigh = new FuzzyRuleAntecedent();
ifHumidityVeryLowandTemperatureHigh->joinSingle(dry);
ifHumidityVeryLowandTemperatureHigh->joinSingle(highTemperature);
thenWdurationVeryLong->addOutput(wdurationVeryLong);
fuzzy->addFuzzyRule(new FuzzyRule(7, ifHumidityVeryLowandTemperatureHigh, thenWdurationVeryLong));
// Regla 3: Si la humedad es muy baja y la temperatura es media, el tiempo de bombeo es muy largo
FuzzyRuleAntecedent *ifHumidityVeryLowandMediumTemperature = new FuzzyRuleAntecedent();
ifHumidityVeryLowandMediumTemperature->joinSingle(dry);
ifHumidityVeryLowandTemperatureHigh->joinSingle(mediumTemperature);
thenWdurationVeryLong->addOutput(wdurationVeryLong);
fuzzy->addFuzzyRule(new FuzzyRule(8, ifHumidityVeryLowandTemperatureHigh, thenWdurationVeryLong));
// Regla 4: Si la humedad es muy baja y la temperatura es baja, el tiempo de bombeo será largo
FuzzyRuleAntecedent *ifHumidityVeryLowandLowTemperature = new FuzzyRuleAntecedent();
ifHumidityVeryLowandLowTemperature->joinSingle(dry);
ifHumidityVeryLowandLowTemperature->joinSingle(lowTemperature);
thenWdurationVeryLong->addOutput(wdurationVeryLong);
fuzzy->addFuzzyRule(new FuzzyRule(9, ifHumidityVeryLowandTemperatureHigh, thenWdurationVeryLong));
// Regla 5: Si la humedad es muy baja y la temperatura es muy baja, el tiempo de bombeo será largo
FuzzyRuleAntecedent *ifHumidityVeryLowandVeryLowTemperature = new FuzzyRuleAntecedent();
ifHumidityVeryLowandVeryLowTemperature->joinSingle(dry);
ifHumidityVeryLowandVeryLowTemperature->joinSingle(veryLowTemperature);
thenWdurationVeryLong->addOutput(wdurationVeryLong);
fuzzy->addFuzzyRule(new FuzzyRule(10, ifHumidityVeryLowandTemperatureHigh, thenWdurationVeryLong));
}
int globalWateringDuration = 0; // Variable global para almacenar el valor de wateringDuration
void loop() {
static unsigned long lastDHTReadTime = 0;
static unsigned long ledOnTime = 0; // Hora en que la luz está encendida
// Leer el valor de DHT22 cada 10 segundos
if (millis() - lastDHTReadTime > 10000) {
lastDHTReadTime = millis();
float hum = dht.readHumidity();
float tem = dht.readTemperature();
fuzzy->setInput(2, hum);
fuzzy->setInput(3, tem);
fuzzy->fuzzify();
globalWateringDuration = fuzzy->defuzzify(3); // Almacenar el valor en una variable global
if (globalWateringDuration > 0) {
digitalWrite(LED_PIN_HUMIDITY, HIGH);
ledOnTime = millis(); // Registre la hora actual cuando se enciende la luz.
} else {
digitalWrite(LED_PIN_HUMIDITY, LOW);
}
Serial.print(" Humedad: ");
Serial.println(hum);
Serial.print(" Temperatura: ");
Serial.println(tem);
Serial.print(" Tiempo de bombeo: ");
Serial.println(globalWateringDuration);
}
// Compruebe si el tiempo transcurrido desde que se encendió la luz es igual al valor de globalWateringDuration hasta que se apagó la luz.
if (digitalRead(LED_PIN_HUMIDITY) == HIGH && millis() - ledOnTime >= globalWateringDuration) {
digitalWrite(LED_PIN_HUMIDITY, LOW);
}
int ldrValue = analogRead(LDR_PIN);
Serial.print("LDR Value: ");
Serial.println(ldrValue);
fuzzy->setInput(1, ldrValue);
fuzzy->fuzzify();
int ledOutputIntensity = fuzzy->defuzzify(1);
int lightingDurationOutput = fuzzy->defuzzify(2);
analogWrite(LED_PIN_AMBIENT, ledOutputIntensity);
Serial.print("LED Intensity: ");
Serial.print(ledOutputIntensity);
Serial.print(", Tiempo de iluminación: ");
Serial.println(lightingDurationOutput);
delay(lightingDurationOutput); // Ajustar la frecuencia de lectura LDR
}