#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Define the LED, LDR, PIR sensor, Buzzer, Temperature Sensor, and Stepper Motor pins
#define LED1_PIN 4
#define LDR_PIN 14
#define PIR_PIN 13
#define BUZZER_PIN 12
#define DHT_PIN 15
#define DIRECTION_PIN 26 // ESP32 pin for direction
#define STEP_PIN 25 // ESP32 pin for step
#define LED_PIN 2 // Onboard LED for ESP32
// PID constants
float Kp = 2.0;
float Ki = 0.5;
float Kd = 1.0;
// Define the DHT sensor type
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
// Initialize the LCD with the I2C address 0x27 and dimensions 16x2
LiquidCrystal_I2C lcd(0x27, 16, 2);
// PID control variables
float setpoint = 26.0; // Desired temperature setpoint
float previousError = 0;
float integral = 0;
unsigned long lastTime = 0;
// Create mutexes for accessing shared resources
SemaphoreHandle_t dhtMutex;
SemaphoreHandle_t lcdMutex;
SemaphoreHandle_t motorMutex;
// Task 1 function - Monitors Temperature and Humidity
void Task1(void *parameter) {
dht.begin(); // Initialize the DHT sensor
while (1) {
if (xSemaphoreTake(dhtMutex, portMAX_DELAY)) {
float temperature = dht.readTemperature(); // Read temperature in Celsius
float humidity = dht.readHumidity(); // Read humidity percentage
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Failed to read from DHT sensor!");
} else {
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print(" °C, Humidity: ");
Serial.print(humidity);
Serial.println(" %");
if (humidity < 0 || humidity > 100) {
Serial.println("Warning: Humidity out of expected range.");
}
}
xSemaphoreGive(dhtMutex);
}
vTaskDelay(2000 / portTICK_PERIOD_MS); // Run every 2 seconds
}
}
// Task 2 function - Controls LED1 based on LDR input
void Task2(void *parameter) {
pinMode(LED1_PIN, OUTPUT);
pinMode(LDR_PIN, INPUT);
while (1) {
int ldrValue = digitalRead(LDR_PIN);
Serial.print("LDR Value: ");
Serial.println(ldrValue);
if (ldrValue == LOW) { // Low light (low lux value)
digitalWrite(LED1_PIN, HIGH); // Turn on LED1 when it's dark
} else { // High light (high lux value)
digitalWrite(LED1_PIN, LOW); // Turn off LED1 when there's light
}
vTaskDelay(1000 / portTICK_PERIOD_MS); // Run every 1 second
}
}
// Task 3 function - Controls Buzzer based on PIR sensor input
void Task3(void *parameter) {
pinMode(PIR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
while (1) {
if (digitalRead(PIR_PIN) == HIGH) {
digitalWrite(BUZZER_PIN, HIGH); // Turn on the Buzzer if motion is detected
} else {
digitalWrite(BUZZER_PIN, LOW); // Turn off the Buzzer if no motion
}
vTaskDelay(500 / portTICK_PERIOD_MS); // Run every 500 milliseconds
}
}
// Task 4 function - Displays Temperature on I2C LCD
void Task4(void *parameter) {
lcd.init(); // Initialize the LCD
lcd.backlight(); // Turn on the LCD backlight
while (1) {
if (xSemaphoreTake(dhtMutex, portMAX_DELAY)) {
float temperature = dht.readTemperature(); // Read temperature in Celsius
xSemaphoreGive(dhtMutex);
lcd.clear(); // Clear the LCD screen
lcd.setCursor(0, 0); // Set cursor to the first line
lcd.print("Temp: ");
lcd.print(temperature);
lcd.print(" C");
}
vTaskDelay(2000 / portTICK_PERIOD_MS); // Update every 2 seconds
}
}
// Task 5 function - Controls the Stepper Motor using PID based on Temperature
void Task5(void *parameter) {
pinMode(DIRECTION_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
while (1) {
float temperature;
if (xSemaphoreTake(dhtMutex, portMAX_DELAY)) {
temperature = dht.readTemperature(); // Read temperature in Celsius
xSemaphoreGive(dhtMutex);
}
if (!isnan(temperature)) {
// Calculate PID error
float error = setpoint - temperature;
integral += error;
float derivative = error - previousError;
float output = Kp * error + Ki * integral + Kd * derivative;
previousError = error;
// Determine motor direction based on temperature difference
if (temperature > 27.0) {
digitalWrite(DIRECTION_PIN, HIGH); // Open window if temperature is too high
} else if (temperature < 25.0) {
digitalWrite(DIRECTION_PIN, LOW); // Close window if temperature is too low
} else {
output = 0; // No movement if temperature is within the range
}
int steps = abs(output); // Get absolute steps
if (xSemaphoreTake(motorMutex, portMAX_DELAY)) {
for (int n = 0; n < steps; n++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(20);
digitalWrite(STEP_PIN, LOW);
delay(10);
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Flash LED
}
xSemaphoreGive(motorMutex);
}
}
vTaskDelay(100 / portTICK_PERIOD_MS); // Run every 100 milliseconds
}
}
// Task 6 function - Monitors System Health
void Task6(void *parameter) {
while (1) {
// Check if other tasks are running (simplified version)
Serial.println("Monitoring system health...");
// Here you could add checks or logs for specific task statuses if applicable
vTaskDelay(5000 / portTICK_PERIOD_MS); // Run every 5 seconds
}
}
void setup() {
// Initialize Serial for debugging
Serial.begin(115200);
// Initialize LEDs and DHT sensor
pinMode(LED1_PIN, OUTPUT);
digitalWrite(LED1_PIN, LOW);
dht.begin();
// Create mutexes
dhtMutex = xSemaphoreCreateMutex();
lcdMutex = xSemaphoreCreateMutex();
motorMutex = xSemaphoreCreateMutex();
// Create Tasks
xTaskCreate(Task1, "Task1", 10000, NULL, 0, NULL); // Temperature & Humidity Monitoring
xTaskCreate(Task2, "Task2", 10000, NULL, 1, NULL); // LED Control
xTaskCreate(Task3, "Task3", 10000, NULL, 2, NULL); // Motion Detection and Security Alert
xTaskCreate(Task4, "Task4", 10000, NULL, 1, NULL); // User Interface (LCD Display)
xTaskCreate(Task5, "Task5", 10000, NULL, 1, NULL); // Motor Control with PID
xTaskCreate(Task6, "Task6", 10000, NULL, 3, NULL); // System Health Monitoring
}
void loop() {
// Empty loop
}