#include "sketch.h"

// SENSORS
#define DHT_PIN  38
DHT22 dht22(DHT_PIN);
#define LDR_PIN  1
#define TRIG_PIN 39
#define ECHO_PIN 2
#define PH_PIN 18
#define SOIL_PIN 8
#define TEMPERATURE_PIN 10
#define ILLUMINATION_PIN 11
#define SOIL_HUMIDITY_PIN 12
#define SOIL_PH_PIN 13
#define LOW_WATER_ALARM_PIN 14


void setup() {
  Serial.begin(9600);
 
  pinMode(LDR_PIN, INPUT);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(PH_PIN, INPUT);
  pinMode(SOIL_PIN, INPUT);
  pinMode(TEMPERATURE_PIN, OUTPUT);
  pinMode(ILLUMINATION_PIN, OUTPUT);
  pinMode(SOIL_HUMIDITY_PIN, OUTPUT);
  pinMode(SOIL_PH_PIN, OUTPUT);
  pinMode(LOW_WATER_ALARM_PIN, OUTPUT);

  printMutex = xSemaphoreCreateMutex();
  temperatureMutex = xSemaphoreCreateMutex();
  humidityMutex = xSemaphoreCreateMutex();
  illuminationMutex = xSemaphoreCreateMutex();
  waterMutex = xSemaphoreCreateMutex();
  soilPHMutex = xSemaphoreCreateMutex();
  soilHumidityMutex = xSemaphoreCreateMutex();

  connectWiFi();
  MQTTClient.setServer(MQTT_BROKER.c_str(), MQTT_PORT);
	MQTTClient.setBufferSize(512);
  MQTTClient.setCallback(cmd);
  connectMQTT();

  // Create tasks
  xTaskCreate(connect, "connect", 4096, NULL, 1, NULL);
  xTaskCreate(sendData, "sendData", 4096, NULL, 1, NULL);

  xTaskCreate(readTemperature, "readTemperature", 2048, NULL, 3, NULL);
  xTaskCreate(readHumidity, "readHumidity", 2048, NULL, 3, NULL);
  xTaskCreate(readIllumination, "readIllumination", 2048, NULL, 3, NULL);
  xTaskCreate(readWater, "readWater", 2048, NULL, 3, NULL);
  xTaskCreate(readSoilPH, "readSoilPH", 2048, NULL, 3, NULL);
  xTaskCreate(readSoilHumidity, "readSoilHumidity", 2048, NULL, 3, NULL);

  xTaskCreate(controlTemperature, "controlTemperature", 2048, NULL, 1, NULL);
  xTaskCreate(controlIllumination, "controlIllumination", 2048, NULL, 1, NULL);
  xTaskCreate(controlSoilPH, "controlSoilPH", 2048, NULL, 3, NULL);
  xTaskCreate(readHumidity, "controlSoilHumidity", 2048, NULL, 3, NULL);
  xTaskCreate(readIllumination, "readIllumination", 2048, NULL, 3, NULL);
  xTaskCreate(readWater, "controlLowWaterAlarm", 2048, NULL, 3, NULL);
}

void loop() {
  MQTTClient.loop();
}

void controlTemperature(void *pvParameters) {
  while(true) {
    float localTemperature;
    if (xSemaphoreTake(temperatureMutex, portMAX_DELAY) == pdTRUE) {
      localTemperature = temperature;
      xSemaphoreGive(temperatureMutex);
    }
    unsigned long now = millis();
    if ( (now < temperatureActuatorTime && temperatureActuatorAction) || (temperatureActuatorTime < now &&
      (localTemperature < temperatureObjective - temperatureRange || localTemperature > temperatureObjective + temperatureRange))) {
      digitalWrite(TEMPERATURE_PIN, HIGH);
    } else {
      digitalWrite(TEMPERATURE_PIN, LOW);
    }
    vTaskDelay(periodControlTemperature / portTICK_PERIOD_MS);
  }
}

void controlIllumination(void *pvParameters) {
  while(true) {
    float localIllumination;
    if (xSemaphoreTake(illuminationMutex, portMAX_DELAY) == pdTRUE) {
      localIllumination = illumination;
      xSemaphoreGive(illuminationMutex);
    }
    unsigned long now = millis();
    if ((now < illuminationActuatorTime && illuminationActuatorAction) || (illuminationActuatorTime < now &&
      (localIllumination < temperatureObjective))) {
      digitalWrite(ILLUMINATION_PIN, HIGH);
    } else {
      digitalWrite(ILLUMINATION_PIN, LOW);
    }
    vTaskDelay(periodControlIllumination / portTICK_PERIOD_MS);
  }
}

void controlSoilPH(void *pvParameters) {
  while(true) {
    float localSoilPH;
    if (xSemaphoreTake(soilPHMutex, portMAX_DELAY) == pdTRUE) {
      localSoilPH = soilPH;
      xSemaphoreGive(soilPHMutex);
    }
    unsigned long now = millis();
    if ((now < soilPHActuatorTime && soilPHActuatorAction) || (soilPHActuatorTime < now &&
      (localSoilPH < soilPHObjective - soilPHRange || localSoilPH > soilPHObjective + soilPHRange))) {
      digitalWrite(SOIL_PH_PIN, HIGH);
    } else {
      digitalWrite(SOIL_PH_PIN, LOW);
    }
    vTaskDelay(periodControlSoilPH / portTICK_PERIOD_MS);
  }
}

void controlSoilHumidity(void *pvParameters) {
  while(true) {
    float localSoilHumidity;
    if (xSemaphoreTake(soilHumidityMutex, portMAX_DELAY) == pdTRUE) {
      localSoilHumidity = soilHumidity;
      xSemaphoreGive(soilHumidityMutex);
    }
    unsigned long now = millis();
    if ((now < soilHumidityActuatorTime && soilHumidityActuatorAction) || (soilHumidityActuatorTime < now &&
    (localSoilHumidity < soilHumidityObjective))) {
      digitalWrite(SOIL_HUMIDITY_PIN, HIGH);
    } else {
      digitalWrite(SOIL_HUMIDITY_PIN, LOW);
    }
    vTaskDelay(periodControlSoilHumidity / portTICK_PERIOD_MS);
  }
}

void controlLowWaterAlarm(void *pvParameters) {
  while(true) {
    float localWater;
    if (xSemaphoreTake(waterMutex, portMAX_DELAY) == pdTRUE) {
      localWater = water;
      xSemaphoreGive(waterMutex);
    }
    unsigned long now = millis();
    if ((now < waterActuatorTime && waterActuatorAction) || (waterActuatorTime < now &&
      (localWater < waterLimit))) {
      digitalWrite(LOW_WATER_ALARM_PIN, HIGH);
    } else {
      digitalWrite(LOW_WATER_ALARM_PIN, LOW);
    }
    vTaskDelay(periodControlWater / portTICK_PERIOD_MS);
  }
}

void cmd(char* topic, byte* payload, unsigned int length) {
  String topicString = String(topic);
	String message = String(std::string((char * ) payload, length).c_str());

  if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
    Serial.println("[" + topicString + "] " + message);
    xSemaphoreGive(printMutex);
  }

	StaticJsonDocument <200> doc;
	DeserializationError error = deserializeJson(doc, message);
  if (error) {
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.print("Error al deserializar el JSON: ");
      Serial.println(error.c_str());
      xSemaphoreGive(printMutex);
    }
		return;
  }

  if (topicString == TOPIC_SUB_CONFIG | topicString == TOPIC_SUB_CONFIG_ALL) {
    
    if (doc.containsKey("DEVICE_ID")) {
      DEVICE_ID = doc["DEVICE_ID"].as<String>();
      Serial.print("Var DEVICE_ID changed to " + DEVICE_ID);
    }
    if (doc.containsKey("WIFI_SSID")) {
      WIFI_SSID = doc["WIFI_SSID"].as<String>();
      Serial.print("Var WIFI_SSID changed to " + WIFI_SSID);
    }
    if (doc.containsKey("WIFI_PASSWORD")) {
      WIFI_PASSWORD = doc["WIFI_PASSWORD"].as<String>();
      Serial.print("Var WIFI_PASSWORD changed to " + WIFI_PASSWORD);
    }
    if (doc.containsKey("MQTT_PORT")) {
      MQTT_PORT = doc["MQTT_PORT"].as<int>();
      Serial.print("Var MQTT_PORT changed to " + MQTT_PORT);
    }
    if (doc.containsKey("MQTT_BROKER")) {
      MQTT_BROKER = doc["MQTT_BROKER"].as<String>();
      Serial.print("Var MQTT_BROKER changed to " + MQTT_BROKER);
    }
    if (doc.containsKey("MQTT_USER")) {
      MQTT_USER = doc["MQTT_USER"].as<String>();
      Serial.print("Var MQTT_USER changed to " + MQTT_USER);
    }
    if (doc.containsKey("MQTT_PASSWORD")) {
      MQTT_PASSWORD = doc["MQTT_PASSWORD"].as<String>();
      Serial.print("Var MQTT_PASSWORD changed to " + MQTT_PASSWORD);
    }
    if (doc.containsKey("TOPIC_PUB_STATUS")) {
      TOPIC_PUB_STATUS = doc["TOPIC_PUB_STATUS"].as<String>();
      Serial.print("Var TOPIC_PUB_STATUS changed to " + TOPIC_PUB_STATUS);
    }
    if (doc.containsKey("TOPIC_PUB_DATA")) {
      TOPIC_PUB_DATA = doc["TOPIC_PUB_DATA"].as<String>();
      Serial.print("Var TOPIC_PUB_DATA changed to " + TOPIC_PUB_DATA);
    }
    if (doc.containsKey("TOPIC_SUB_CONFIG")) {
      TOPIC_SUB_CONFIG = doc["TOPIC_SUB_CONFIG"].as<String>();
      Serial.print("Var TOPIC_SUB_CONFIG changed to " + TOPIC_SUB_CONFIG);
    }
    if (doc.containsKey("TOPIC_SUB_CONFIG_ALL")) {
      TOPIC_SUB_CONFIG_ALL = doc["TOPIC_SUB_CONFIG_ALL"].as<String>();
      Serial.print("Var TOPIC_SUB_CONFIG_ALL changed to " + TOPIC_SUB_CONFIG_ALL);
    }
    if (doc.containsKey("FIRST_MESSAGE")) {
      FIRST_MESSAGE = doc["FIRST_MESSAGE"].as<String>();
      Serial.print("Var FIRST_MESSAGE changed to " + FIRST_MESSAGE);
    }
    if (doc.containsKey("LAST_MESSAGE")) {
      LAST_MESSAGE = doc["LAST_MESSAGE"].as<String>();
      Serial.print("Var LAST_MESSAGE changed to " + LAST_MESSAGE);
    }
    if (doc.containsKey("periodSendData")) {
      periodSendData = doc["periodSendData"].as<int>();
      Serial.print("Var periodSendData changed to " + periodSendData);
    }
    if (doc.containsKey("periodConnect")) {
      periodConnect = doc["periodConnect"].as<int>();
      Serial.print("Var periodConnect changed to " + periodConnect);
    }
    if (doc.containsKey("periodReadTemperature")) {
      periodReadTemperature = doc["periodReadTemperature"].as<int>();
      Serial.print("Var periodReadTemperature changed to " + periodReadTemperature);
    }
    if (doc.containsKey("periodReadHumidity")) {
      periodReadHumidity = doc["periodReadHumidity"].as<int>();
      Serial.print("Var periodReadHumidity changed to " + periodReadHumidity);
    }
    if (doc.containsKey("periodReadIllumination")) {
      periodReadIllumination = doc["periodReadIllumination"].as<int>();
      Serial.print("Var periodReadIllumination changed to " + periodReadIllumination);
    }
    if (doc.containsKey("periodReadWater")) {
      periodReadWater = doc["periodReadWater"].as<int>();
      Serial.print("Var periodReadWater changed to " + periodReadWater);
    }
    if (doc.containsKey("periodReadSoilPH")) {
      periodReadSoilPH = doc["periodReadSoilPH"].as<int>();
      Serial.print("Var periodReadSoilPH changed to " + periodReadSoilPH);
    }
    if (doc.containsKey("periodReadSoilHumidity")) {
      periodReadSoilHumidity = doc["periodReadSoilHumidity"].as<int>();
      Serial.print("Var periodReadSoilHumidity changed to " + periodReadSoilHumidity);
    }
    if (doc.containsKey("periodControlTemperature")) {
        periodControlTemperature = doc["periodControlTemperature"].as<int>();
      Serial.print("Var periodControlTemperature changed to " + periodControlTemperature);
    }
    if (doc.containsKey("periodControlHumidity")) {
        periodControlHumidity = doc["periodControlHumidity"].as<int>();
      Serial.print("Var periodControlHumidity changed to " + periodControlHumidity);
    }
    if (doc.containsKey("periodControlIllumination")) {
        periodControlIllumination = doc["periodControlIllumination"].as<int>();
      Serial.print("Var periodControlIllumination changed to " + periodControlIllumination);
    }
    if (doc.containsKey("periodControlWater")) {
        periodControlWater = doc["periodControlWater"].as<int>();
      Serial.print("Var periodControlWater changed to " + periodControlWater);
    }
    if (doc.containsKey("periodControlSoilPH")) {
        periodControlSoilPH = doc["periodControlSoilPH"].as<int>();
      Serial.print("Var periodControlSoilPH changed to " + periodControlSoilPH);
    }
    if (doc.containsKey("periodControlSoilHumidity")) {
        periodControlSoilHumidity = doc["periodControlSoilHumidity"].as<int>();
      Serial.print("Var periodControlSoilHumidity changed to " + periodControlSoilHumidity);
    }
    if (doc.containsKey("temperatureObjective")) {
        temperatureObjective = doc["temperatureObjective"].as<float>();
      Serial.print("Var temperatureObjective changed to " + String(temperatureObjective));
    }
    if (doc.containsKey("temperatureRange")) {
        temperatureRange = doc["temperatureRange"].as<float>();
      Serial.print("Var temperatureRange changed to " + String(temperatureRange));
    }
    if (doc.containsKey("illuminationObjective")) {
        illuminationObjective = doc["illuminationObjective"].as<float>();
      Serial.print("Var illuminationObjective changed to " + String(illuminationObjective));
    }
    if (doc.containsKey("soilPHObjective")) {
        soilPHObjective = doc["soilPHObjective"].as<float>();
      Serial.print("Var soilPHObjective changed to " + String(soilPHObjective));
    }
    if (doc.containsKey("soilPHRange")) {
        soilPHRange = doc["soilPHRange"].as<float>();
      Serial.print("Var soilPHRange changed to " + String(soilPHRange));
    }
    if (doc.containsKey("soilHumidityObjective")) {
        soilHumidityObjective = doc["soilHumidityObjective"].as<float>();
      Serial.print("Var soilHumidityObjective changed to " + String(soilHumidityObjective));
    }

  } else if (topicString == TOPIC_SUB_ACTUATORS | topicString == TOPIC_SUB_ACTUATORS_ALL) {

    if (doc.containsKey("temperatureActuator")) {
      JsonObject jsonObj = doc["temperatureActuator"];
      if (jsonObj.containsKey("action") && jsonObj.containsKey("time")) {
        temperatureActuatorAction = jsonObj["action"].as<bool>();
        temperatureActuatorTime = millis() + jsonObj["time"].as<unsigned long>();
        Serial.print("Temperature actuator set to " + String(temperatureActuatorAction) + " during " + String(temperatureActuatorTime) + "ms");
      }
    }

    if (doc.containsKey("humidityActuator")) {
      JsonObject jsonObj = doc["humidityActuator"];
      if (jsonObj.containsKey("action") && jsonObj.containsKey("time")) {
        humidityActuatorAction = jsonObj["action"].as<bool>();
        humidityActuatorTime = millis() + jsonObj["time"].as<unsigned long>();
        Serial.print("Temperature actuator set to " + String(humidityActuatorAction) + " during " + String(humidityActuatorTime) + "ms");
      }
    }

    if (doc.containsKey("illuminationActuator")) {
      JsonObject jsonObj = doc["illuminationActuator"];
      if (jsonObj.containsKey("action") && jsonObj.containsKey("time")) {
        illuminationActuatorAction = jsonObj["action"].as<bool>();
        illuminationActuatorTime = millis() + jsonObj["time"].as<unsigned long>();
        Serial.print("Illumination actuator set to " + String(illuminationActuatorAction) + " during " + String(illuminationActuatorTime) + "ms");
      }
    }

    if (doc.containsKey("waterActuator")) {
      JsonObject jsonObj = doc["waterActuator"];
      if (jsonObj.containsKey("action") && jsonObj.containsKey("time")) {
        waterActuatorAction = jsonObj["action"].as<bool>();
        waterActuatorTime = millis() + jsonObj["time"].as<unsigned long>();
        Serial.print("Water actuator set to " + String(waterActuatorAction) + " during " + String(waterActuatorTime) + "ms");
      }
    }

    if (doc.containsKey("soilPHActuator")) {
      JsonObject jsonObj = doc["soilPHActuator"];
      if (jsonObj.containsKey("action") && jsonObj.containsKey("time")) {
        soilPHActuatorAction = jsonObj["action"].as<bool>();
        soilPHActuatorTime = millis() + jsonObj["time"].as<unsigned long>();
        Serial.print("Soil pH actuator set to " + String(soilPHActuatorAction) + " during " + String(soilPHActuatorTime) + "ms");
      }
    }

    if (doc.containsKey("soilHumidityActuator")) {
      JsonObject jsonObj = doc["soilHumidityActuator"];
      if (jsonObj.containsKey("action") && jsonObj.containsKey("time")) {
        soilHumidityActuatorAction = jsonObj["action"].as<bool>();
        soilHumidityActuatorTime = millis() + jsonObj["time"].as<unsigned long>();
        Serial.print("Soil Humidity actuator set to " + String(soilHumidityActuatorAction) + " during " + String(soilHumidityActuatorTime) + "ms");
      }
    }

  }

}

void connectWiFi() {
  if (WiFi.status() != WL_CONNECTED) {
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Connecting to WIFI SSID " + String(WIFI_SSID) + " ");
      xSemaphoreGive(printMutex);
    }
    WiFi.mode(WIFI_STA);
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Connected to WIFI SSID " + String(WIFI_SSID) + " with IP " +  WiFi.localIP().toString());
      xSemaphoreGive(printMutex);
    }
  }
}

void connectMQTT() {
  if (!MQTTClient.connected()) {

    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Connecting to MQTT broker " + String(MQTT_BROKER));
      xSemaphoreGive(printMutex);
    }

    while(!MQTTClient.connected()) {
      if (MQTTClient.connect(DEVICE_ID.c_str(), NULL, NULL, TOPIC_PUB_STATUS.c_str(), 2, true, LAST_MESSAGE.c_str())) {

        if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
          Serial.println("Connected to MQTT broker " + String(MQTT_BROKER));
          xSemaphoreGive(printMutex);
        }

        MQTTClient.publish(TOPIC_PUB_STATUS.c_str(), FIRST_MESSAGE.c_str(), true);

        MQTTClient.subscribe(TOPIC_SUB_CONFIG.c_str());
        if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
          Serial.println("Suscribed to " + TOPIC_SUB_CONFIG);
          xSemaphoreGive(printMutex);
        }

			  MQTTClient.subscribe(TOPIC_SUB_CONFIG_ALL.c_str());
        if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
          Serial.println("Suscribed to " + TOPIC_SUB_CONFIG_ALL);
          xSemaphoreGive(printMutex);
        }

        MQTTClient.subscribe(TOPIC_SUB_ACTUATORS.c_str());
        if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
          Serial.println("Suscribed to " + TOPIC_SUB_ACTUATORS);
          xSemaphoreGive(printMutex);
        }

        MQTTClient.subscribe(TOPIC_SUB_ACTUATORS_ALL.c_str());
        if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
          Serial.println("Suscribed to " + TOPIC_SUB_ACTUATORS_ALL);
          xSemaphoreGive(printMutex);
        }

      }
    }

  }
}

void connect(void *pvParameters) {
  while(true){
    connectWiFi();
    connectMQTT();
    vTaskDelay(periodConnect / portTICK_PERIOD_MS);
  }
}

void sendData(void *pvParameters) {
  float localTemperature;
  float localHumidity;
  float localIllumination;
  float localWater;
  float localSoilPH;
  float localSoilHumidity;
  StaticJsonDocument<200> jsonDocument;
  String jsonString;

  while(true){
    
    if (xSemaphoreTake(temperatureMutex, portMAX_DELAY) == pdTRUE) {
      localTemperature = temperature;
      xSemaphoreGive(temperatureMutex);
    }
    if (xSemaphoreTake(humidityMutex, portMAX_DELAY) == pdTRUE) {
      localHumidity = humidity;
      xSemaphoreGive(humidityMutex);
    }
    if (xSemaphoreTake(illuminationMutex, portMAX_DELAY) == pdTRUE) {
      localIllumination = illumination;
      xSemaphoreGive(illuminationMutex);
    }
    if (xSemaphoreTake(waterMutex, portMAX_DELAY) == pdTRUE) {
      localWater = water;
      xSemaphoreGive(waterMutex);
    }
    if (xSemaphoreTake(soilPHMutex, portMAX_DELAY) == pdTRUE) {
      localSoilPH = soilPH;
      xSemaphoreGive(soilPHMutex);
    }
    if (xSemaphoreTake(soilHumidityMutex, portMAX_DELAY) == pdTRUE) {
      localSoilHumidity = soilHumidity;
      xSemaphoreGive(soilHumidityMutex);
    }

    jsonDocument["device"] = DEVICE_ID;
    jsonDocument["temperature"] = localTemperature;
    jsonDocument["humidity"] = localHumidity;
    jsonDocument["illumination"] = localIllumination;
    jsonDocument["water"] = localWater;
    jsonDocument["soilPH"] = localSoilPH;
    jsonDocument["soilHumidity"] = localSoilHumidity;

    serializeJson(jsonDocument, jsonString);
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Sending JSON data to cloud: " + jsonString);
      xSemaphoreGive(printMutex);
    }

    MQTTClient.publish(TOPIC_PUB_DATA.c_str(), jsonString.c_str(), false);

    vTaskDelay(periodSendData / portTICK_PERIOD_MS);
  }
  
}

void readTemperature(void *pvParameters) {
  float localTemperature = 0;
  while(true) {
    localTemperature = dht22.getTemperature();
    if (xSemaphoreTake(temperatureMutex, portMAX_DELAY) == pdTRUE) {
      temperature = localTemperature;
      xSemaphoreGive(temperatureMutex);
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Temperature: " + String(localTemperature) + " °C");
      xSemaphoreGive(printMutex);
    }
    vTaskDelay(periodReadTemperature / portTICK_PERIOD_MS);
  }
}

void readHumidity(void *pvParameters) {
  float localHumidity = 0;
  while(true) {
    localHumidity = dht22.getHumidity();
    if (xSemaphoreTake(humidityMutex, portMAX_DELAY) == pdTRUE) {
      humidity = localHumidity;
      xSemaphoreGive(humidityMutex);
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Humidity: " + String(localHumidity) + "%");
      xSemaphoreGive(printMutex);
    }
    vTaskDelay(periodReadHumidity / portTICK_PERIOD_MS);
  }
}

void readIllumination(void *pvParameters) {
  const float GAMMA = 0.7, RL10 = 50;
  float localIllumination = 0, voltage, resistance;
  int analogValue;
  while(true) {
    analogValue = analogRead(LDR_PIN);
    voltage = analogValue / 1024. * 5;
    resistance = 2000 * voltage / (1 - voltage / 5);
    localIllumination = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
    if (isfinite(localIllumination)) {
      if (xSemaphoreTake(illuminationMutex, portMAX_DELAY) == pdTRUE) {
        illumination = localIllumination;
        xSemaphoreGive(illuminationMutex);
      }
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Illumination: " + String(localIllumination) + " lux");
      xSemaphoreGive(printMutex);
    }
    vTaskDelay(periodReadIllumination / portTICK_PERIOD_MS);
  }
}

void readWater(void *pvParameters) {
  float localWater = 0;
  while(true) {
    taskENTER_CRITICAL(&cs_spinlock);
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);
    taskEXIT_CRITICAL(&cs_spinlock);
    localWater = pulseIn(ECHO_PIN, HIGH) / 58;
    if (xSemaphoreTake(waterMutex, portMAX_DELAY) == pdTRUE) {
      water = localWater;
      xSemaphoreGive(waterMutex);
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Water level: " + String(localWater) + " cm");
      xSemaphoreGive(printMutex);
    }
    vTaskDelay(periodReadWater / portTICK_PERIOD_MS);
  }
}

void readSoilPH(void *pvParameters) {
  float localSoilPH = 0;
  while(true) {
    localSoilPH = analogRead(PH_PIN) / 409.6;
    if (xSemaphoreTake(soilPHMutex, portMAX_DELAY) == pdTRUE) {
      soilPH = localSoilPH;
      xSemaphoreGive(soilPHMutex);
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Soil pH: " + String(localSoilPH));
      xSemaphoreGive(printMutex);
    }
    vTaskDelay(periodReadSoilPH / portTICK_PERIOD_MS);
  }
}

void readSoilHumidity(void *pvParameters) {
  float localSoilHumidity = 0;
  while(true) {
    localSoilHumidity = analogRead(SOIL_PIN) / 40.96;
    if (xSemaphoreTake(soilHumidityMutex, portMAX_DELAY) == pdTRUE) {
      soilHumidity = localSoilHumidity;
      xSemaphoreGive(soilHumidityMutex);
    }
    if (xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
      Serial.println("Soil Humidity: " + String(localSoilHumidity) + "%");
      xSemaphoreGive(printMutex);
    }
    vTaskDelay(periodReadSoilHumidity / portTICK_PERIOD_MS);
  }
}
$abcdeabcde151015202530354045505560fghijfghij
Loading
esp32-s3-devkitc-1