#include <WiFi.h>
#include <HTTPClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <math.h>
// ===== WiFi Configuration =====
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ===== MQTT Configuration =====
const char* mqtt_server = "mqtt.eclipseprojects.io";
const int mqtt_port = 1883;
const char* topicWeather = "weather/data";
const char* topicSensor = "sensors/esp32";
const char* topicPWM = "esp32/pwm";
const char* topicFeedback = "esp32/pwm/feedback";
const char* topicThreshold = "esp32/Thresh";
const char* topicAlert = "alert/BUZZER";
const char* topicTempDHT = "esp32/temp";
const char* topicTempTherm = "esp32/Thermistor";
// ===== Hardware Configuration =====
#define DHTPIN 26
#define DHTTYPE DHT22
#define THERMISTOR_PIN 34
#define FAN_PIN 13
#define LED_PIN 2
#define BUZZER_PIN 5
DHT dht(DHTPIN, DHTTYPE);
// ===== OpenWeatherMap Config =====
const char* apiKey = "0897ec6053fd70b586341d0cc5e0d88a";
const char* city = "Cape Town";
const char* countryCode = "ZA";
// ===== Global Variables =====
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
float tempThreshold = NAN;
bool alertSent = false;
// ===== WiFi Connection =====
void setupWiFi() {
Serial.print("Connecting to WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(300);
Serial.print(".");
}
Serial.println(" connected!");
}
// ===== MQTT Reconnect =====
void reconnectMQTT() {
while (!mqttClient.connected()) {
Serial.print("Connecting to MQTT...");
if (mqttClient.connect("ESP32ClientUnified")) {
Serial.println(" connected.");
mqttClient.subscribe(topicPWM);
mqttClient.subscribe(topicThreshold);
} else {
Serial.print(" failed. Retry in 3s.\n");
delay(3000);
}
}
}
// ===== MQTT Callback =====
void callback(char* topic, byte* payload, unsigned int length) {
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.printf("MQTT [%s]: %s\n", topic, message.c_str());
if (strcmp(topic, topicPWM) == 0) {
int percentage = constrain(message.toInt(), 0, 100);
int pwmValue = map(percentage, 0, 100, 0, 255);
analogWrite(FAN_PIN, pwmValue);
String feedback = "{\"percent\":" + String(percentage) + ",\"pwm\":" + String(pwmValue) + "}";
mqttClient.publish(topicFeedback, feedback.c_str());
}
if (strcmp(topic, topicThreshold) == 0) {
float newThresh = message.toFloat();
if (!isnan(newThresh) && newThresh > 0) {
tempThreshold = newThresh;
Serial.printf("Updated Threshold: %.2f°C\n", tempThreshold);
}
}
}
// ===== Weather Fetching =====
void fetchWeather() {
String url = "http://api.openweathermap.org/data/2.5/weather?q=" + String(city) + "," + countryCode + "&appid=" + apiKey + "&units=metric";
HTTPClient http;
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
StaticJsonDocument<1024> doc;
if (!deserializeJson(doc, payload)) {
StaticJsonDocument<512> outDoc;
outDoc["city"] = city;
outDoc["country"] = countryCode;
outDoc["temp"] = doc["main"]["temp"];
outDoc["humidity"] = doc["main"]["humidity"];
outDoc["description"] = doc["weather"][0]["description"];
outDoc["wind"] = doc["wind"]["speed"];
char buffer[512];
serializeJson(outDoc, buffer);
mqttClient.publish(topicWeather, buffer);
Serial.println("Weather published.");
}
}
http.end();
}
// ===== Thermistor Reading =====
float readThermistorC() {
int analogValue = analogRead(THERMISTOR_PIN);
float voltage = analogValue * 3.3 / 4095.0;
float resistance = (3.3 - voltage) * 10000.0 / voltage;
float tempK = 1.0 / (1.0 / 298.15 + log(resistance / 10000.0) / 3435.0);
return tempK - 273.15;
}
// ===== Sensor Publishing =====
void publishSensorData() {
float dhtTemp = dht.readTemperature();
float dhtHum = dht.readHumidity();
float thermTemp = readThermistorC();
if (!isnan(dhtTemp)) {
char tempBuf[8], humBuf[8], thermBuf[8];
dtostrf(dhtTemp, 1, 2, tempBuf);
dtostrf(dhtHum, 1, 2, humBuf);
dtostrf(thermTemp, 1, 2, thermBuf);
mqttClient.publish(topicTempDHT, tempBuf);
mqttClient.publish(topicTempTherm, thermBuf);
String payload = "{\"dht_temp\":" + String(tempBuf) + ",\"humidity\":" + String(humBuf) + ",\"thermistor\":" + String(thermBuf) + "}";
mqttClient.publish(topicSensor, payload.c_str());
Serial.println("Sensor data published.");
}
}
// ===== Alert Logic =====
void handleAlert(float currentTemp) {
if (isnan(tempThreshold)) return;
if (currentTemp > tempThreshold && !alertSent) {
mqttClient.publish(topicAlert, "HIGH");
tone(BUZZER_PIN, 1000);
digitalWrite(LED_PIN, HIGH);
alertSent = true;
Serial.println("ALERT: Temperature exceeded threshold!");
} else if (currentTemp <= tempThreshold && alertSent) {
mqttClient.publish(topicAlert, "LOW");
noTone(BUZZER_PIN);
digitalWrite(LED_PIN, LOW);
alertSent = false;
Serial.println("Temperature back to normal.");
}
}
// ===== Setup =====
void setup() {
Serial.begin(115200);
pinMode(FAN_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
dht.begin();
setupWiFi();
mqttClient.setServer(mqtt_server, mqtt_port);
mqttClient.setCallback(callback);
}
// ===== Loop =====
unsigned long lastUpdate = 0;
const unsigned long interval = 60000;
void loop() {
if (!mqttClient.connected()) reconnectMQTT();
mqttClient.loop();
unsigned long now = millis();
if (now - lastUpdate > interval) {
lastUpdate = now;
fetchWeather();
publishSensorData();
float dhtTemp = dht.readTemperature();
if (!isnan(dhtTemp)) handleAlert(dhtTemp);
}
}