#include <WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// --- OLED Display Setup ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// --- DHT22 Sensor ---
#define DHTPIN 14
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// --- TMP36GZ Analog Temp Sensor ---
#define ANALOG_TEMP_PIN 34
// --- DS18B20 Setup ---
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds18b20(&oneWire);
// --- LED & Buzzer Pins ---
const int RED_LED = 23;
const int GREEN_LED = 18;
const int FAN_LED = 5;
const int MQTT_LED = 19;
const int BUZZER = 27;
#define SCREEN_SDA 21
#define SCREEN_SCL 22
// --- Wi-Fi Credentials ---
const char* ssid = "Afrihost Fibre DJ";
const char* password = "0824435505";
// --- MQTT Settings ---
const char* mqttServer = "mqtt.eclipseprojects.io";
const int mqttPort = 1883;
const char* mqttClientID = "ESP32-SensorClient12";
const char* publishTopic = "esp/sensors12";
const char* subscribeTopic = "esp/threshold12";
const char* fanStatusTopic = "esp/fan12/status";
// --- MQTT Client ---
WiFiClient espClient;
PubSubClient client(espClient);
// --- Display and Serial Timing ---
unsigned long lastScreenSwitch = 0;
unsigned long screenInterval = 2500;
int displayIndex = 0;
unsigned long lastSerialPrint = 0;
unsigned long serialInterval = 3000;
// --- Control Variables ---
float thresholdTemp = 1000.0;
bool fanStatus = false;
bool buzzerActive = false;
unsigned long buzzerStartTime = 0;
const unsigned long buzzerDuration = 500;
void connectWiFi() {
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Connected");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* message, unsigned int length) {
String incoming = "";
for (int i = 0; i < length; i++) {
incoming += (char)message[i];
}
Serial.print("Message received [");
Serial.print(topic);
Serial.print("]: ");
Serial.println(incoming);
if (String(topic) == subscribeTopic) {
thresholdTemp = incoming.toFloat();
Serial.print("Updated Threshold: ");
Serial.println(thresholdTemp);
digitalWrite(MQTT_LED, HIGH);
delay(50);
digitalWrite(MQTT_LED, LOW);
}
if (String(topic) == fanStatusTopic) {
bool isOn = (incoming == "ON");
if (isOn && !fanStatus) {
Serial.println("📢 Fan turned ON → Beep + LED ON");
buzzerActive = true;
buzzerStartTime = millis();
digitalWrite(BUZZER, HIGH);
digitalWrite(FAN_LED, HIGH);
} else if (!isOn && fanStatus) {
Serial.println("Fan turned OFF → LED OFF");
digitalWrite(FAN_LED, LOW);
}
fanStatus = isOn;
}
}
void connectMQTT() {
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect(mqttClientID)) {
Serial.println("connected");
client.subscribe(subscribeTopic);
client.subscribe(fanStatusTopic); // subscribe to fan ON/OFF status
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
delay(1000);
}
}
}
void setup() {
Serial.begin(115200);
dht.begin();
ds18b20.begin();
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(FAN_LED, OUTPUT);
pinMode(MQTT_LED, OUTPUT);
pinMode(BUZZER, OUTPUT);
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
digitalWrite(FAN_LED, LOW);
digitalWrite(MQTT_LED, LOW);
digitalWrite(BUZZER, LOW);
Wire.begin(SCREEN_SDA, SCREEN_SCL);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Starting up...");
display.display();
delay(2500);
connectWiFi();
digitalWrite(GREEN_LED, HIGH);
connectMQTT();
display.clearDisplay();
display.setCursor(0, 0);
display.println("WiFi OK");
display.setCursor(0, 16);
display.println(WiFi.localIP());
display.display();
delay(2500);
lastScreenSwitch = millis();
lastSerialPrint = millis();
}
void loop() {
client.loop();
// --- Read sensors ---
float tempDHT = dht.readTemperature();
float humDHT = dht.readHumidity();
int analogValue = analogRead(ANALOG_TEMP_PIN);
float voltage = analogValue * (3.3 / 4095.0);
float analogTemp = (voltage - 0.5) * 100.0;
ds18b20.requestTemperatures();
float dsTemps[3];
for (int i = 0; i < 3; i++) {
dsTemps[i] = ds18b20.getTempCByIndex(i);
}
// --- Handle buzzer timeout ---
if (buzzerActive && millis() - buzzerStartTime >= buzzerDuration) {
buzzerActive = false;
digitalWrite(BUZZER, LOW);
}
// --- Serial logging ---
if (millis() - lastSerialPrint >= serialInterval) {
lastSerialPrint = millis();
Serial.println("=== Sensor Readings ===");
Serial.print("DHT Temp: "); Serial.print(tempDHT); Serial.println(" C");
Serial.print("Humidity: "); Serial.print(humDHT); Serial.println(" %");
Serial.print("TMP36 Temp: "); Serial.print(analogTemp); Serial.println(" C");
for (int i = 0; i < 3; i++) {
Serial.print("DS18B20 #"); Serial.print(i + 1); Serial.print(": ");
Serial.print(dsTemps[i]); Serial.println(" C");
}
Serial.println(fanStatus ? "FAN ON" : "FAN OFF");
}
// --- Publish sensor JSON ---
String payload = "{";
payload += "\"temperature\":" + String(tempDHT, 1);
payload += ",\"humidity\":" + String(humDHT, 1);
payload += ",\"analogTemp\":" + String(analogTemp, 1);
for (int i = 0; i < 3; i++) {
payload += ",\"ds18b20_" + String(i + 1) + "\":" + String(dsTemps[i], 1);
}
payload += ",\"fan\":\"" + String(fanStatus ? "on" : "off") + "\"}";
client.publish(publishTopic, payload.c_str());
// --- Rotate OLED screen info ---
if (millis() - lastScreenSwitch >= screenInterval) {
lastScreenSwitch = millis();
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
switch (displayIndex) {
case 0:
display.println("Room Temp:");
display.setCursor(0, 16);
isnan(tempDHT) ? display.println("Error") : display.printf("%.1f C", tempDHT);
break;
case 1:
display.println("Room Humidity:");
display.setCursor(0, 16);
isnan(humDHT) ? display.println("Error") : display.printf("%.1f %%", humDHT);
break;
case 2:
display.println("TMP36 Temp:");
display.setCursor(0, 16);
display.printf("%.1f C", analogTemp);
break;
case 3:
display.println("Intake Temp:");
display.setCursor(0, 16);
display.printf("%.1f C", dsTemps[0]);
break;
case 4:
display.println("Exhaust Temp:");
display.setCursor(0, 16);
display.printf("%.1f C", dsTemps[1]);
break;
case 5:
display.println("Outside Temp:");
display.setCursor(0, 16);
display.printf("%.1f C", dsTemps[2]);
break;
}
display.display();
displayIndex = (displayIndex + 1) % 6;
}
delay(50);
}