#include <Arduino.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <DHTesp.h>
#include <ESP32Servo.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#define DHT 15
#define LDR_PIN 34
#define SERVO_PIN 18
#define BUZZER 12
WiFiClient espClient;
PubSubClient mqttClient(espClient);
DHTesp dhtSensor;
Servo servo;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
char tempAr[6];
char avgLDRAr[6];
char servoAr[6];
float currentTemp = 0;
static unsigned long lastSampleTime = 0;
static float sampleDuration = 5000; // 5 seconds
static unsigned long averageStartTime = 0;
static float averagingDuration = 120000; // 2 minutes
static int sampleCount = 0;
static float sum = 0;
static float average = 0;
float motorAngle = 0;
float minimumAngle = 30.0;
float controllingFactor = 0.75;
float idealTemp = 30.0;
bool isScheduledON = false;
unsigned long scheduledOnTime;
void setupWifi() {
WiFi.begin("Wokwi-GUEST", "");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(".");
}
Serial.println("");
Serial.println("Wifi connected");
Serial.println("IP address:");
Serial.println(WiFi.localIP());
}
void recieveCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("]");
char payloadCharAr[length];
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
payloadCharAr[i] = (char)payload[i];
}
Serial.println();
if (strcmp(topic, "LDR-SampleInt") == 0) {
sampleDuration = atof(payloadCharAr) * 1000; // Convert seconds to milliseconds
Serial.print("Updated sample interval: ");
Serial.println(sampleDuration);
}
if (strcmp(topic, "LDR-SendingInt") == 0) {
averagingDuration = atof(payloadCharAr) * 1000; // Convert seconds to milliseconds
Serial.print("Updated averaging duration");
Serial.println(averagingDuration);
}
if (strcmp(topic, "SERVO-minAngle") == 0) {
minimumAngle = atof(payloadCharAr);
Serial.print("Updated minAngle: ");
Serial.println(minimumAngle);
}
if (strcmp(topic, "SERVO-ctrlFac") == 0) {
controllingFactor = atof(payloadCharAr);
Serial.print("Updated controllling factor: ");
Serial.println(controllingFactor);
}
if (strcmp(topic, "SERVO-idealTemp") == 0) {
idealTemp = atof(payloadCharAr);
Serial.print("Updated ideal temperature: ");
Serial.println(idealTemp);
}
if (strcmp(topic, "MSE-MAIN-ON-OFF") == 0) {
buzzerOn(payloadCharAr[0] == '1');
} else if (strcmp(topic, "MSE-SCH-ON-OFF") == 0) {
if (payloadCharAr[0] == 'N') {
isScheduledON = false;
} else {
isScheduledON = true;
scheduledOnTime = atol(payloadCharAr);
}
}
}
void setupMqtt() {
mqttClient.setServer("test.mosquitto.org", 1883);
mqttClient.setCallback(recieveCallback);
}
void connectToBroker() {
while (!mqttClient.connected()) {
Serial.print("Attempting connection to MQTT...");
if (mqttClient.connect("ESP-8266-000146984")) {
Serial.println("connected");
//subscribe to topics
mqttClient.subscribe("LDR-SampleInt");
mqttClient.subscribe("LDR-SendingInt");
mqttClient.subscribe("SERVO-minAngle");
mqttClient.subscribe("SERVO-ctrlFac");
mqttClient.subscribe("SERVO-idealTemp");
mqttClient.subscribe("MSE-MAIN-ON-OFF");
mqttClient.subscribe("MSE-SCH-ON-OFF");
//mqttClient.subscribe("ON-OFF");
}
else {
Serial.print("failed ");
Serial.print(mqttClient.state());
Serial.println(" try again in 2 seconds");
delay(5000);
}
}
}
void updateTemp() {
TempAndHumidity data = dhtSensor.getTempAndHumidity();
currentTemp = data.temperature;
String(currentTemp, 2).toCharArray(tempAr, 6);
}
void setServoMotorAngle() {
motorAngle = minimumAngle + ((180 - minimumAngle) * average * controllingFactor * log(sampleDuration / averagingDuration) * (currentTemp / idealTemp));
/*NOTE that, log(sampleDuration/averagingDuration) \
will be a negative value since sampleDuration < averagingDuration
in practical situations, which will result in values less than min.angle(theta offset)
when applying the given equation*/
motorAngle = constrain(motorAngle, 0, 180); // Constrain the angle to be between 0 and 180 degrees
servo.write(motorAngle);
String(motorAngle, 2).toCharArray(servoAr, 6);
Serial.print(" -> Motor Angle: ");
Serial.println(motorAngle);
}
void averageLDR() {
// Sample the LDR
if (millis() - lastSampleTime >= sampleDuration) {
lastSampleTime += sampleDuration;
// Read the LDR value and scale to 0-1
float rawldrValue = map(analogRead(LDR_PIN), 32, 4063, 0, 100); // Map to 0-1 intensity
float ldrValue = rawldrValue / 100.0; // Scale to 0-1
Serial.print("LDR Value: ");
Serial.println(ldrValue);
// Add the LDR value to the sum
sum += ldrValue;
Serial.print("Sum: ");
Serial.println(sum);
sampleCount++;
Serial.print("Sample Count: ");
Serial.println(sampleCount);
}
// Average the LDR
if (millis() - averageStartTime >= averagingDuration) {
averageStartTime += averagingDuration ;
if (sampleCount != 0) {
average = sum / (float)sampleCount;
Serial.print(" -> Average LDR Value: ");
Serial.println(average);
String(average, 2).toCharArray(avgLDRAr, 6);
setServoMotorAngle(); // Update the motor angle based on the average LDR value
}
// Reset for the next averaging period
sum = 0;
sampleCount = 0;
}
}
void buzzerOn(bool on) {
if (on) {
tone(BUZZER, 256);
} else {
noTone(BUZZER);
}
}
unsigned long getTime() {
timeClient.update();
return timeClient.getEpochTime();
}
void checkSchedule() {
if (isScheduledON) {
unsigned long currentTime = getTime();
if (currentTime > scheduledOnTime) {
buzzerOn(true);
isScheduledON = false;
mqttClient.publish ("MSE-MAIN-ESP", "1");
// mqttClient.publish ("MSE-SCH-ESP-ON","0");
Serial.println("Scheduled ON");
}
}
}
void setup() {
Serial.begin(115200);
setupWifi();
setupMqtt();
dhtSensor.setup(DHT, DHTesp::DHT22);
servo.attach(SERVO_PIN);
timeClient.begin();
timeClient.setTimeOffset(5.5 * 3600);
pinMode (BUZZER, OUTPUT);
digitalWrite(BUZZER, LOW);
}
void loop() {
if (!mqttClient.connected()) {
connectToBroker(); //reconnect to mqtt broker
}
mqttClient.loop(); //keep the mqtt connection alive
updateTemp();
mqttClient.publish("DHT-Temperature", tempAr);
averageLDR();
mqttClient.publish("LDR-average", avgLDRAr);
mqttClient.publish("SERVO-motorAngle", servoAr);
checkSchedule();
delay(1000);
}