// Include necessary libraries
#include <BlynkSimpleEsp32.h>
#define BLYNK_TEMPLATE_ID "TMPL6WYL2lU0t"
#define BLYNK_TEMPLATE_NAME "ESP32 Wifi"


// Define pins for CO2 sensor and occupancy sensor
#define CO2_SENSOR_PIN A0
#define OCCUPANCY_SENSOR_PIN 2

// Define pins for exhaust fan and supply fan
#define EXHAUST_FAN_PIN 3
#define SUPPLY_FAN_PIN 4

// Define Blynk authentication token
//char auth[] = "YourAuthToken";
#define BLYNK_AUTH_TOKEN "AWU3cRitexU1I96KKR26B0kJQZIntrVD"

// Define variables for CO2 level and occupancy status
int co2Level;
int occupancyStatus;

// Define variables for output PWM values
int exhaustFanSpeed;
int supplyFanSpeed;

// Setup function
void setup() {
  // Initialize serial communication
  Serial.begin(9600);

  // Initialize Blynk with authentication token
  Blynk.begin(auth);

  // Set pin modes for exhaust fan and supply fan
  pinMode(EXHAUST_FAN_PIN, OUTPUT);
  pinMode(SUPPLY_FAN_PIN, OUTPUT);
}

// Loop function
void loop() {
  // Get CO2 level from sensor
  co2Level = analogRead(CO2_SENSOR_PIN);

  // Get occupancy status from sensor
  occupancyStatus = digitalRead(OCCUPANCY_SENSOR_PIN);

  // Calculate exhaust fan speed using fuzzy logic
  exhaustFanSpeed = fuzzyLogic(co2Level, occupancyStatus);

  // Set exhaust fan speed using PWM
  analogWrite(EXHAUST_FAN_PIN, exhaustFanSpeed);

  // Calculate supply fan speed using fuzzy logic
  supplyFanSpeed = fuzzyLogic(co2Level, !occupancyStatus);

  // Set supply fan speed using PWM
  analogWrite(SUPPLY_FAN_PIN, supplyFanSpeed);

  // Send CO2 level and occupancy status to Blynk app
  Blynk.virtualWrite(V0, co2Level);
  Blynk.virtualWrite(V1, occupancyStatus);

  // Wait for 1 second
  delay(1000);
}

// Function for fuzzy logic
int fuzzyLogic(int co2Level, int occupancyStatus) {
  // Define variables for fuzzy logic
  int exhaustFanSpeed;
  int supplyFanSpeed;

  // If CO2 level is high and occupancy status is low, increase exhaust fan speed
  if (co2Level > 1000 && occupancyStatus == 0) {
    exhaustFanSpeed = 255;
  }
  // If CO2 level is low and occupancy status is high, decrease exhaust fan speed
  else if (co2Level < 1000 && occupancyStatus == 1) {
    exhaustFanSpeed = 0;
  }
  // If CO2 level is high and occupancy status is high, increase supply fan speed
  else if (co2Level > 1000 && occupancyStatus == 1) {
    supplyFanSpeed = 255;
  }
  // If CO2 level is low and occupancy status is low, decrease supply fan speed
  else if (co2Level < 1000 && occupancyStatus == 0) {
    supplyFanSpeed = 0;
  }

  // Return exhaust fan speed if it is defined, otherwise return supply fan speed
  if (exhaustFanSpeed) {
    return exhaustFanSpeed;
  }
  else {
    return supplyFanSpeed;
  }
}

// Blynk function for updating CO2 level and occupancy status
BLYNK_WRITE(V0) {
  co2Level = param.asInt();
}

BLYNK_WRITE(V1) {
  occupancyStatus = param.asInt();
}

// Blynk function for updating exhaust fan speed
BLYNK_WRITE(V2) {
  exhaustFanSpeed = param.asInt();
  analogWrite(EXHAUST_FAN_PIN, exhaustFanSpeed);
}

// Blynk function for updating supply fan speed
BLYNK_WRITE(V3) {
  supplyFanSpeed = param.asInt();
  analogWrite(SUPPLY_FAN_PIN, supplyFanSpeed);
}

// Blynk function for displaying CO2 level and occupancy status on app
BLYNK_READ(V0) {
  Blynk.virtualWrite(V0, co2Level);
}

BLYNK_READ(V1) {
  Blynk.virtualWrite(V1, occupancyStatus);
}

// Blynk function for displaying exhaust fan speed on app
BLYNK_READ(V2) {
  Blynk.virtualWrite(V2, exhaustFanSpeed);
}

// Blynk function for displaying supply fan speed on app
BLYNK_READ(V3) {
  Blynk.virtualWrite(V3, supplyFanSpeed);
}

// Reference: https://github.com/blynkkk/blynk-library/blob/master/examples/GettingStarted/BlynkBlink/BlynkBlink.ino