#include <WiFi.h>
#include <HTTPClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
// WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// MQTT
const char* mqtt_server = "mqtt.eclipseprojects.io";
// Pins
#define DHT_PIN 26
#define DHTTYPE DHT22
#define THERMISTOR_PIN 34
#define BUZZER_PIN 15
#define FAN_PIN 13
WiFiClient wifiClient;
PubSubClient client(wifiClient);
DHT dht(DHT_PIN, DHTTYPE);
float tempThreshold = -1;
int fanSpeed = 0;
unsigned long lastSensorMsg = 0;
unsigned long lastWeatherFetch = 0;
const unsigned long sensorInterval = 2000;
const unsigned long weatherInterval = 10000;
// Connect WiFi
void setup_wifi() {
Serial.print("Connecting to WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" connected!");
}
// Fetch Weather
void fetchWeather() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = "http://api.openweathermap.org/data/2.5/weather?q=Cape%20Town&appid=83150fd88d660b2f89ae2145034eef25&units=metric";
http.begin(url);
int httpCode = http.GET();
if (httpCode == 200) {
String rawPayload = http.getString();
DynamicJsonDocument doc(4096);
if (deserializeJson(doc, rawPayload) == DeserializationError::Ok) {
DynamicJsonDocument newJson(512);
newJson["lat"] = doc["coord"]["lat"];
newJson["lon"] = doc["coord"]["lon"];
newJson["weather"] = doc["weather"][0]["main"];
newJson["description"] = doc["weather"][0]["description"];
newJson["temp"] = doc["main"]["temp"];
newJson["feels_like"] = doc["main"]["feels_like"];
newJson["humidity"] = doc["main"]["humidity"];
newJson["pressure"] = doc["main"]["pressure"];
newJson["wind_speed"] = doc["wind"]["speed"];
newJson["wind_deg"] = doc["wind"]["deg"];
newJson["country"] = doc["sys"]["country"];
newJson["sunrise"] = doc["sys"]["sunrise"];
newJson["sunset"] = doc["sys"]["sunset"];
String output;
serializeJson(newJson, output);
client.publish("weather/custom_json", output.c_str());
Serial.println("Published weather data.");
}
}
http.end();
}
}
// MQTT Callback
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) msg += (char)payload[i];
msg.trim();
if (String(topic) == "/dht/threshold") {
float newThreshold = msg.toFloat();
if (newThreshold > 0 && newThreshold < 100) {
tempThreshold = newThreshold;
Serial.print("Threshold updated: ");
Serial.println(tempThreshold);
}
} else if (String(topic) == "commands/fan/set_speed") {
fanSpeed = msg.toInt();
fanSpeed = constrain(fanSpeed, 0, 100);
int pwmValue = map(fanSpeed, 0, 100, 0, 255);
ledcWrite(0, pwmValue);
Serial.print("Fan PWM set to: ");
Serial.println(pwmValue);
if (pwmValue > 0) {
Serial.println("LED (Fan) is ON");
} else {
Serial.println("LED (Fan) is OFF");
}
}
}
// MQTT Reconnect
void reconnect() {
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect("ESP32UnifiedClient")) {
Serial.println(" connected!");
client.subscribe("/dht/threshold");
client.subscribe("commands/fan/set_speed");
client.publish("/dht/status", "ESP32 online");
} else {
Serial.print(" failed, rc=");
Serial.print(client.state());
Serial.println(" retrying...");
delay(5000);
}
}
}
// Setup
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
dht.begin();
pinMode(BUZZER_PIN, OUTPUT);
// Setup PWM for fan (LED)
ledcAttach(FAN_PIN, 5000, 8); // Attach fan pin to channel 0
}
// Main loop
void loop() {
if (!client.connected()) reconnect();
client.loop();
unsigned long now = millis();
// Sensor Readings & Alert
if (now - lastSensorMsg >= sensorInterval) {
lastSensorMsg = now;
float dhtTemp = dht.readTemperature();
int analogVal = analogRead(THERMISTOR_PIN);
float voltage = analogVal * (3.3 / 4095.0); // Wokwi uses 3.3V ADC
float tempC = (voltage - 0.5) * 100.0;
if (!isnan(dhtTemp)) {
client.publish("/dht/temp", String(dhtTemp, 2).c_str());
client.publish("/sensor/temp", String(tempC, 2).c_str());
Serial.print("DHT Temp: ");
Serial.println(dhtTemp);
Serial.print("Thermistor Temp: ");
Serial.println(tempC);
if (tempThreshold > 0 && dhtTemp > tempThreshold) {
digitalWrite(BUZZER_PIN, HIGH);
client.publish("/dht/buzzer", "ON");
client.publish("/dht/alert", ("ALERT: Threshold exceeded by " + String(dhtTemp - tempThreshold, 1) + "°C").c_str());
Serial.println("Buzzer ON");
} else {
digitalWrite(BUZZER_PIN, LOW);
client.publish("/dht/buzzer", "OFF");
client.publish("/dht/alert", "Temperature normal.");
Serial.println("Buzzer OFF");
}
} else {
Serial.println("DHT read failed.");
}
}
// Weather Fetch
if (now - lastWeatherFetch >= weatherInterval) {
lastWeatherFetch = now;
fetchWeather();
}
}