#include <WiFi.
h>
#include <PubSubClient.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <TM1637Display.h>
#include <ESP32Servo.h>
// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// MQTT configuration
const char* mqtt_broker = "broker.emqx.io";
const char* mqtt_user = "emqx";
const char* mqtt_pass = "public";
const int mqtt_port = 1883;
// Pin and constant definitions
#define DHTPIN 13
#define DHTTYPE DHT22
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDRESS 0x3C
#define CLK 16
#define DIO 17
#define PIN_LED 14
#define PIN_SUCCESS_LED 23
#define BUTTON_PIN 0
#define BUZZER_PIN 2
#define GAS_DOUT 34
#define GAS_AOUT 35
#define LIGHT_PIN 32
#define TRIG_PIN 18
#define ECHO_PIN 19
#define SERVO_PIN 5
// Password
const char* correctPassword = "1234";
// Initialize objects
WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
TM1637Display display7seg(CLK, DIO);
Servo servo;
// Global variables
float temperature, humidity;
bool gasDetected;
int gasValue;
int lightValue;
int tm1637Value = 0;
String inputPassword = "";
unsigned long lastUpdate = 0;
const long updateInterval = 100;
unsigned long lastSensorUpdate = 0;
const long sensorUpdateInterval = 5000;
bool lastButtonState = HIGH;
unsigned long lastButtonPress = 0;
const long debounceDelay = 200;
bool ledSwitchState = false;
bool showOLEDGasGraph = false;
bool showOLEDLightGraph = false;
unsigned long lastNotificationTime = 0;
const long notificationInterval = 60000;
float distance = 0;
bool doorState = false; // Track door state (open/closed)
// Light history for graph
#define MAX_POINTS 50
int lightHistory[MAX_POINTS];
int lightIndex = 0;
// Function declarations
void setupWiFi();
void setupMQTT();
void reconnectMQTT();
void callback(char* topic, byte* payload, unsigned int length);
void setupDHT();
void readDHT(float &temperature, float &humidity);
void setupOLED();
void setup7Segment();
void setupLED();
void updateLED(float temperature);
void setupBuzzerButton();
void checkButton();
void setupGasSensor();
void readGasSensor(bool &gasDetected, int &gasValue);
void readLightSensor(int &lightValue);
void processPassword(String password);
void resetPasswordInput();
void updateBuzzer(int gasValue, bool gasDetected);
void updateSerialPlotter();
void drawGasBarGraph(int gasValue);
void drawLightLineGraphOLED(int lightValue);
void setupServo();
void setupUltrasonic();
void readUltrasonic(float &distance);
void setup() {
Serial.begin(115200);
Serial.println("System starting");
Serial.println("Enter password, TM1637 value (0-1000), ON/OFF, OLED_GRAPH, or
OLED_LIGHT:");
Serial.println("Temperature\tHumidity\tGas\tTM1637\tGasDetected\tLight\
tDistance");
// Initialize components
setupWiFi();
setupMQTT();
setupDHT();
setupOLED();
setup7Segment();
setupLED();
setupBuzzerButton();
setupGasSensor();
setupServo();
setupUltrasonic();
// Initialize light history
for (int i = 0; i < MAX_POINTS; i++) {
lightHistory[i] = 0;
}
}
void loop() {
// Reconnect WiFi if disconnected
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi disconnected, reconnecting...");
setupWiFi();
}
// Reconnect MQTT if disconnected
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
unsigned long currentMillis = millis();
// Handle Serial input
if (Serial.available() > 0) {
String input = Serial.readStringUntil('\n');
input.trim();
Serial.print("Debug: Input = [");
Serial.print(input);
Serial.println("]");
if (input.toInt() >= 0 && input.toInt() <= 1000 && input ==
String(input.toInt())) {
tm1637Value = input.toInt();
client.publish("topic/tm1637", String(tm1637Value).c_str());
Serial.println("-------------------");
Serial.print("TM1637 value (Serial): ");
Serial.println(tm1637Value);
Serial.println("-------------------");
} else if (input == "ON" || input == "OFF") {
ledSwitchState = (input == "ON");
client.publish("topic/led_switch", ledSwitchState ? "1" : "0");
Serial.println("-------------------");
Serial.print("Switch Serial: ");
Serial.println(input);
Serial.println("-------------------");
} else if (input == "OLED_GRAPH") {
showOLEDGasGraph = !showOLEDGasGraph;
showOLEDLightGraph = false;
Serial.println("-------------------");
Serial.print("OLED gas graph display: ");
Serial.println(showOLEDGasGraph ? "ON" : "OFF");
Serial.println("-------------------");
if (!showOLEDGasGraph) resetPasswordInput();
} else if (input == "OLED_LIGHT") {
showOLEDLightGraph = !showOLEDLightGraph;
showOLEDGasGraph = false;
Serial.println("-------------------");
Serial.print("OLED light graph display: ");
Serial.println(showOLEDLightGraph ? "ON" : "OFF");
Serial.println("-------------------");
if (!showOLEDLightGraph) resetPasswordInput();
} else {
inputPassword = input;
Serial.println("-------------------");
Serial.print("Processing password (Serial): ");
Serial.println(inputPassword);
processPassword(inputPassword);
Serial.println("-------------------");
}
Serial.println("Enter password, TM1637 value (0-1000), ON/OFF, OLED_GRAPH, or
OLED_LIGHT:");
}
// Update sensors, LED, buzzer, TM1637
if (currentMillis - lastUpdate >= updateInterval) {
display7seg.showNumberDec(tm1637Value, false);
readDHT(temperature, humidity);
readGasSensor(gasDetected, gasValue);
readLightSensor(lightValue);
readUltrasonic(distance);
updateLED(temperature);
updateBuzzer(gasValue, gasDetected);
checkButton();
// Control servo based on distance
if (distance >= 99 && distance <= 101) {
servo.write(180);
Serial.println("Servo: Rotated to 180° due to distance ~100cm");
} else {
servo.write(0);
Serial.println("Servo: Rotated to 0°");
}
// Update OLED display
if (showOLEDGasGraph) {
drawGasBarGraph(gasValue);
} else if (showOLEDLightGraph) {
drawLightLineGraphOLED(lightValue);
}
lastUpdate = currentMillis;
}
// Publish sensor data to MQTT
if (currentMillis - lastSensorUpdate >= sensorUpdateInterval) {
if (!isnan(temperature) && !isnan(humidity)) {
client.publish("topic/temperature", String(temperature, 2).c_str());
client.publish("topic/humidity", String(humidity, 2).c_str());
Serial.println("MQTT Debug: Published Temperature=" + String(temperature) +
", Humidity=" + String(humidity));
} else {
Serial.println("DHT Debug: Not publishing due to invalid values");
client.publish("topic/temperature", "0");
client.publish("topic/humidity", "0");
Serial.println("MQTT Debug: Published default Temperature=0, Humidity=0");
}
if (lightValue >= 0 && lightValue <= 4095) {
client.publish("topic/gas", String(gasValue).c_str());
client.publish("topic/light", String(lightValue).c_str());
client.publish("topic/tm1637", String(tm1637Value).c_str());
client.publish("topic/led_switch", ledSwitchState ? "1" : "0");
client.publish("topic/distance", String(distance, 2).c_str());
client.publish("topic/door_state", doorState ? "Open" : "Closed");
Serial.println("MQTT Debug: Published Gas=" + String(gasValue) +
", Light=" + String(lightValue) +
", Distance=" + String(distance));
} else {
Serial.println("Light Sensor Debug: Invalid light value: " +
String(lightValue));
client.publish("topic/light", "0");
Serial.println("MQTT Debug: Published default Light=0");
}
lastSensorUpdate = currentMillis;
}
}
void setupWiFi() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
}
void setupMQTT() {
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
reconnectMQTT();
// Subscribe to control topics
client.subscribe("topic/password");
client.subscribe("topic/led_switch");
client.subscribe("topic/tm1637");
}
void reconnectMQTT() {
while (!client.connected()) {
String clientId = "esp32-" + String(WiFi.macAddress());
Serial.print("Attempting MQTT connection...");
if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("connected");
// Re-subscribe to topics
client.subscribe("topic/password");
client.subscribe("topic/led_switch");
client.subscribe("topic/tm1637");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retrying in 5 seconds");
delay(5000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (unsigned int i = 0; i < length; i++) {
msg += (char)payload[i];
}
Serial.print("Message received on ");
Serial.print(topic);
Serial.print(": ");
Serial.println(msg);
if (strcmp(topic, "topic/password") == 0) {
inputPassword = msg;
inputPassword.trim();
Serial.println("-------------------");
Serial.print("Processing password (MQTT): ");
Serial.println(inputPassword);
processPassword(inputPassword);
Serial.println("-------------------");
} else if (strcmp(topic, "topic/led_switch") == 0) {
ledSwitchState = (msg == "1" || msg == "ON");
Serial.println("-------------------");
Serial.print("Switch MQTT: ");
Serial.println(ledSwitchState ? "ON" : "OFF");
Serial.println("-------------------");
} else if (strcmp(topic, "topic/tm1637") == 0) {
int value = msg.toInt();
if (value >= 0 && value <= 1000) {
tm1637Value = value;
Serial.println("-------------------");
Serial.print("TM1637 MQTT: ");
Serial.println(tm1637Value);
Serial.println("-------------------");
}
}
}
void setupDHT() {
dht.begin();
Serial.println("DHT22 initialized");
}
void readDHT(float &temperature, float &humidity) {
humidity = dht.readHumidity();
temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
temperature = humidity = 0;
} else {
Serial.print("DHT22 Debug: Temperature=");
Serial.print(temperature);
Serial.print(" C, Humidity=");
Serial.print(humidity);
Serial.println(" %");
}
}
void setupOLED() {
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
Serial.println(F("SSD1306 initialization failed"));
for (;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Enter your password:");
display.display();
Serial.println("OLED initialized");
}
void setup7Segment() {
display7seg.setBrightness(0x0f);
Serial.println("TM1637 initialized");
}
void setupLED() {
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_SUCCESS_LED, OUTPUT);
analogWrite(PIN_LED, 0);
digitalWrite(PIN_SUCCESS_LED, LOW);
Serial.println("LED initialized");
}
void updateLED(float temperature) {
int brightness = ledSwitchState ? 255 : 0;
analogWrite(PIN_LED, brightness);
Serial.print("LED Debug: Switch=");
Serial.print(ledSwitchState ? "ON" : "OFF");
Serial.print(", Brightness=");
Serial.println(brightness);
}
void setupBuzzerButton() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
noTone(BUZZER_PIN);
Serial.println("Buzzer and Button initialized");
}
void checkButton() {
bool currentButtonState = digitalRead(BUTTON_PIN);
if (currentButtonState == LOW && lastButtonState == HIGH &&
millis() - lastButtonPress > debounceDelay) {
Serial.println("Button Debug: Pressed, resetting password input");
resetPasswordInput();
showOLEDGasGraph = false;
showOLEDLightGraph = false;
lastButtonPress = millis();
}
lastButtonState = currentButtonState;
}
void setupGasSensor() {
pinMode(GAS_DOUT, INPUT);
Serial.println("MQ-2 gas sensor initialized");
}
void readGasSensor(bool &gasDetected, int &gasValue) {
gasDetected = digitalRead(GAS_DOUT) == LOW;
gasValue = analogRead(GAS_AOUT);
Serial.print("MQ-2 Debug: Detected=");
Serial.print(gasDetected ? "Yes" : "No");
Serial.print(", Value=");
Serial.println(gasValue);
}
void readLightSensor(int &lightValue) {
lightValue = analogRead(LIGHT_PIN);
Serial.print("Light Sensor Debug: Light=");
Serial.println(lightValue);
lightHistory[lightIndex] = lightValue;
lightIndex = (lightIndex + 1) % MAX_POINTS;
}
void processPassword(String password) {
Serial.println("Debug: processPassword called");
if (showOLEDGasGraph || showOLEDLightGraph) {
Serial.println("Debug: OLED graph active, ignoring password");
return;
}
Serial.println("-------------------");
Serial.print("Displaying password: ");
Serial.println(password);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Password: ");
display.println(password);
display.setCursor(0, 20);
if (password == correctPassword) {
display.println("Unlock successful");
display.setCursor(0, 30);
display.print("Temp: ");
display.print(temperature);
display.println(" C");
display.setCursor(0, 40);
display.print("Humidity: ");
display.print(humidity);
display.println(" %");
Serial.println("Password correct");
digitalWrite(PIN_SUCCESS_LED, HIGH);
doorState = true;
client.publish("topic/door_state", "Open");
Serial.println("MQTT Debug: Door state = Open");
} else {
display.println("Wrong password");
Serial.println("Password incorrect");
digitalWrite(PIN_SUCCESS_LED, LOW);
doorState = false;
client.publish("topic/door_state", "Closed");
Serial.println("MQTT Debug: Door state = Closed");
}
display.display();
Serial.println("-------------------");
}
void resetPasswordInput() {
inputPassword = "";
digitalWrite(PIN_SUCCESS_LED, LOW);
doorState = false;
client.publish("topic/door_state", "Closed");
if (showOLEDGasGraph || showOLEDLightGraph) return;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Enter your password:");
display.display();
Serial.println("Password input reset");
Serial.println("Enter password, TM1637 value (0-1000), ON/OFF, OLED_GRAPH, or
OLED_LIGHT:");
}
void updateBuzzer(int gasValue, bool gasDetected) {
if (gasDetected) {
int frequency = map(gasValue, 0, 4095, 500, 2000);
tone(BUZZER_PIN, frequency);
Serial.print("Buzzer Debug: Gas value=");
Serial.print(gasValue);
Serial.print(", Frequency=");
Serial.println(frequency);
unsigned long currentMillis = millis();
if (currentMillis - lastNotificationTime >= notificationInterval) {
String alert = "Alert: Gas detected! Value: " + String(gasValue);
client.publish("topic/gas_alert", alert.c_str());
Serial.println("Published gas alert: " + alert);
lastNotificationTime = currentMillis;
}
} else {
noTone(BUZZER_PIN);
Serial.println("Buzzer Debug: No gas detected, buzzer off");
}
}
void updateSerialPlotter() {
Serial.print(temperature);
Serial.print("\t");
Serial.print(humidity);
Serial.print("\t");
Serial.print(gasValue);
Serial.print("\t");
Serial.print(tm1637Value);
Serial.print("\t");
Serial.print(gasDetected ? 1 : 0);
Serial.print("\t");
Serial.print(lightValue);
Serial.print("\t");
Serial.println(distance);
}
void drawGasBarGraph(int gasValue) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Gas Value Graph");
const int graphHeight = 32;
const int graphWidth = 100;
const int graphX = 10;
const int graphY = SCREEN_HEIGHT - graphHeight - 5;
int barWidth = 10;
int maxGas = 4095;
int barHeight = map(gasValue, 0, maxGas, 0, graphHeight);
display.fillRect(graphX, graphY + (graphHeight - barHeight), barWidth, barHeight,
SSD1306_WHITE);
display.setCursor(graphX, graphY - 10);
display.print("Gas: ");
display.print(gasValue);
display.display();
}
void drawLightLineGraphOLED(int lightValue) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Light Graph");
const int graphHeight = 32;
const int graphWidth = 100;
const int graphX = 10;
const int graphY = SCREEN_HEIGHT - graphHeight - 5;
int maxLight = 4095;
display.drawLine(graphX, graphY, graphX + graphWidth, graphY, SSD1306_WHITE);
display.drawLine(graphX, graphY, graphX, graphY - graphHeight, SSD1306_WHITE);
for (int i = 1; i < MAX_POINTS; i++) {
int x0 = graphX + (i - 1) * graphWidth / (MAX_POINTS - 1);
int x1 = graphX + i * graphWidth / (MAX_POINTS - 1);
int y0 = graphY - map(lightHistory[(lightIndex - MAX_POINTS + i - 1 +
MAX_POINTS) % MAX_POINTS], 0, maxLight, 0, graphHeight);
int y1 = graphY - map(lightHistory[(lightIndex - MAX_POINTS + i + MAX_POINTS) %
MAX_POINTS], 0, maxLight, 0, graphHeight);
display.drawLine(x0, y0, x1, y1, SSD1306_WHITE);
}
display.setCursor(graphX, graphY - 10);
display.print("Light: ");
display.print(lightValue);
display.display();
}
void setupServo() {
servo.attach(SERVO_PIN);
servo.write(0);
Serial.println("Servo initialized");
}
void setupUltrasonic() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.println("HC-SR04 ultrasonic sensor initialized");
}
void readUltrasonic(float &distance) {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
distance = duration * 0.034 / 2;
if (distance < 2 || distance > 400) {
distance = 0;
Serial.println("HC-SR04 Debug: Invalid distance");
} else {
Serial.print("HC-SR04 Debug: Distance=");
Serial.print(distance);
Serial.println(" cm");
}
}