#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>
// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// MQTT Broker settings
const char* mqtt_server = "test.mosquitto.org";
const int mqtt_port = 1883;
const char* mqtt_client_id = "";
// Pin definitions
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define PIR_PIN 21
#define BUTTON_PIN 27
#define RELAY_LAMP_PIN 12
#define RELAY_PUMP_PIN 13
#define BUZZER_PIN 14
#define TRIG_PIN 5
#define ECHO_PIN 18
// Objects
DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient client(espClient);
// Variables
float temperature = 0;
float humidity = 0;
float waterLevel = 0;
bool motionDetected = false;
bool lampStatus = false;
bool pumpStatus = false;
bool alarmStatus = false;
bool buttonPressed = false;
bool lastButtonState = HIGH;
unsigned long lastMotionTime = 0;
unsigned long lastSensorRead = 0;
unsigned long lastPublish = 0;
const unsigned long MOTION_TIMEOUT = 20000; // 20 seconds
const unsigned long SENSOR_INTERVAL = 2000; // 2 seconds
const unsigned long PUBLISH_INTERVAL = 1000; // 1 second
// MQTT Topics
const char* TOPIC_TEMP = "smarthome/temperature";
const char* TOPIC_HUMIDITY = "smarthome/humidity";
const char* TOPIC_WATER_LEVEL = "smarthome/waterlevel";
const char* TOPIC_MOTION = "smarthome/motion";
const char* TOPIC_LAMP_STATUS = "smarthome/lamp/status";
const char* TOPIC_LAMP_CONTROL = "smarthome/lamp/control";
const char* TOPIC_PUMP_STATUS = "smarthome/pump/status";
const char* TOPIC_ALARM_STATUS = "smarthome/alarm/status";
void setup() {
Serial.begin(115200);
// Initialize pins
pinMode(PIR_PIN, INPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RELAY_LAMP_PIN, OUTPUT);
pinMode(RELAY_PUMP_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// Initialize outputs
digitalWrite(RELAY_LAMP_PIN, LOW);
digitalWrite(RELAY_PUMP_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
// Initialize DHT sensor
dht.begin();
// Connect to WiFi
setupWiFi();
// Setup MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqttCallback);
Serial.println("Smart Home System Started!");
}
void loop() {
// Maintain MQTT connection
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
// Read sensors periodically
if (millis() - lastSensorRead >= SENSOR_INTERVAL) {
readSensors();
lastSensorRead = millis();
}
// Check button press
checkButton();
// Check motion timeout
checkMotionTimeout();
// Control pump based on water level
controlPump();
// Control alarm
controlAlarm();
// Publish data periodically
if (millis() - lastPublish >= PUBLISH_INTERVAL) {
publishData();
lastPublish = millis();
}
delay(50);
}
void setupWiFi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(mqtt_client_id)) {
Serial.println("connected");
// Subscribe to control topics
client.subscribe(TOPIC_LAMP_CONTROL);
Serial.println("Subscribed to lamp control topic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// Handle lamp control from dashboard
if (String(topic) == TOPIC_LAMP_CONTROL) {
if (message == "ON" || message == "1") {
lampStatus = true;
digitalWrite(RELAY_LAMP_PIN, HIGH);
Serial.println("Lamp turned ON via MQTT");
} else if (message == "OFF" || message == "0") {
lampStatus = false;
digitalWrite(RELAY_LAMP_PIN, LOW);
Serial.println("Lamp turned OFF via MQTT");
} else if (message == "TOGGLE") {
toggleLamp();
}
}
}
void readSensors() {
// Read DHT22 sensor
float newTemp = dht.readTemperature();
float newHumidity = dht.readHumidity();
if (!isnan(newTemp) && !isnan(newHumidity)) {
temperature = newTemp;
humidity = newHumidity;
}
// Read ultrasonic sensor for water level
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
float distance = duration * 0.034 / 2; // Convert to cm
// Convert distance to water level (assuming tank height is 300cm)
waterLevel = 300 - distance;
if (waterLevel < 0) waterLevel = 0;
if (waterLevel > 300) waterLevel = 300;
// Read PIR sensor
bool currentMotion = digitalRead(PIR_PIN);
if (currentMotion && !motionDetected) {
motionDetected = true;
lastMotionTime = millis();
Serial.println("Motion detected!");
} else if (currentMotion) {
lastMotionTime = millis(); // Update last motion time
}
// Print sensor readings
Serial.printf("Temp: %.1f°C, Humidity: %.1f%%, Water Level: %.1fcm, Motion: %s\n",
temperature, humidity, waterLevel, motionDetected ? "YES" : "NO");
}
void checkButton() {
bool currentButtonState = digitalRead(BUTTON_PIN);
if (currentButtonState == LOW && lastButtonState == HIGH) {
// Button pressed (falling edge)
delay(30); // Debounce
if (digitalRead(BUTTON_PIN) == LOW) {
toggleLamp();
Serial.println("Button pressed - Lamp toggled");
}
}
lastButtonState = currentButtonState;
}
void toggleLamp() {
lampStatus = !lampStatus;
digitalWrite(RELAY_LAMP_PIN, lampStatus ? HIGH : LOW);
if (lampStatus) {
lastMotionTime = millis(); // Reset motion timer when lamp is manually turned on
}
Serial.printf("Lamp %s\n", lampStatus ? "ON" : "OFF");
}
void checkMotionTimeout() {
if (motionDetected && (millis() - lastMotionTime >= MOTION_TIMEOUT)) {
motionDetected = false;
if (lampStatus) {
lampStatus = false;
digitalWrite(RELAY_LAMP_PIN, LOW);
Serial.println("No motion for 20s - Lamp turned OFF automatically");
}
}
}
void controlPump() {
bool newPumpStatus = pumpStatus;
if (waterLevel < 100) {
newPumpStatus = true;
} else if (waterLevel > 200) {
newPumpStatus = false;
}
// Between 100-200cm: maintain current status
if (newPumpStatus != pumpStatus) {
pumpStatus = newPumpStatus;
digitalWrite(RELAY_PUMP_PIN, pumpStatus ? HIGH : LOW);
Serial.printf("Pump %s (Water level: %.1fcm)\n", pumpStatus ? "ON" : "OFF", waterLevel);
}
}
void controlAlarm() {
bool newAlarmStatus = (waterLevel > 200 && temperature > 30);
if (newAlarmStatus != alarmStatus) {
alarmStatus = newAlarmStatus;
digitalWrite(BUZZER_PIN, alarmStatus ? HIGH : LOW);
Serial.printf("Alarm %s (Water: %.1fcm, Temp: %.1f°C)\n",
alarmStatus ? "ON" : "OFF", waterLevel, temperature);
}
}
void publishData() {
if (client.connected()) {
// Publish sensor data
client.publish(TOPIC_TEMP, String(temperature, 1).c_str());
client.publish(TOPIC_HUMIDITY, String(humidity, 1).c_str());
client.publish(TOPIC_WATER_LEVEL, String(waterLevel, 1).c_str());
// Publish status data
client.publish(TOPIC_MOTION, motionDetected ? "1" : "0");
client.publish(TOPIC_LAMP_STATUS, lampStatus ? "1" : "0");
client.publish(TOPIC_PUMP_STATUS, pumpStatus ? "1" : "0");
client.publish(TOPIC_ALARM_STATUS, alarmStatus ? "1" : "0");
// Publish JSON data for dashboard
StaticJsonDocument<200> doc;
doc["temperature"] = temperature;
doc["humidity"] = humidity;
doc["waterLevel"] = waterLevel;
doc["motion"] = motionDetected;
doc["lamp"] = lampStatus;
doc["pump"] = pumpStatus;
doc["alarm"] = alarmStatus;
doc["timestamp"] = millis();
String jsonString;
serializeJson(doc, jsonString);
client.publish("smarthome/data", jsonString.c_str());
}
}