#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <time.h>
// 🛠️ Pin Definitions
#define DHTPIN 26
#define DHTTYPE DHT22
#define BUTTON_PIN 14
#define LED_PIN 19
#define ALARM_PIN 33
// 📡 WiFi & MQTT Configuration
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "broker.hivemq.com";
// 📦 MQTT Topics
const char* mqtt_topic_pub = "MS1/NG/sensor";
const char* mqtt_topic_time = "MS1/NG/time";
const char* mqtt_topic_sub = "MS1/NG/led";
const char* mqtt_topic_status = "MS1/PDD/status";
const char* mqtt_topic_alarm = "MS1/NG/alarm";
// 📚 Global Variables
WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool ledState = false;
bool alarmSent = false;
unsigned long lastMsg = 0;
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 200;
char msg[100];
// 🌐 Connect to WiFi
void setup_wifi() {
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("\nWiFi connected successfully!");
}
// 🔄 MQTT Callback (LCD print removed)
void callback(char* topic, byte* payload, unsigned int length) {
payload[length] = 0;
String command = String((char*)payload);
command.trim();
command.toUpperCase();
Serial.print("Received MQTT message: ");
Serial.println(command);
if (command == "ON") {
digitalWrite(LED_PIN, HIGH);
ledState = true;
} else if (command == "OFF") {
digitalWrite(LED_PIN, LOW);
ledState = false;
}
}
// 🔌 MQTT Reconnection
void reconnect() {
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESP32ClientDevice", NULL, NULL,
mqtt_topic_status, 0, true, "offline")) {
Serial.println("MQTT connected successfully");
client.publish(mqtt_topic_status, "online", true);
client.subscribe(mqtt_topic_sub);
} else {
Serial.print("MQTT connection failed, status=");
Serial.println(client.state());
delay(2000);
}
}
}
// 🕒 Time Sync
void syncTime() {
Serial.println("Syncing time...");
configTime(8 * 3600, 0, "pool.ntp.org");
struct tm timeinfo;
while (!getLocalTime(&timeinfo)) {
Serial.println("Waiting for time sync...");
delay(1000);
}
Serial.println("Time synchronized");
}
// 🚀 Setup
void setup() {
Serial.begin(115200);
Serial.println("Starting setup()...");
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
pinMode(ALARM_PIN, INPUT_PULLUP);
lcd.init();
lcd.backlight();
lcd.clear();
dht.begin();
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
syncTime();
Serial.println("setup() complete, entering loop()");
}
// 🔁 Loop
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
// 📤 Sensor publish every 5 seconds
if (now - lastMsg > 5000) {
lastMsg = now;
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
struct tm timeinfo;
getLocalTime(&timeinfo);
char timeStr[30];
strftime(timeStr, sizeof(timeStr), "%H:%M:%S", &timeinfo);
snprintf(msg, sizeof(msg), "{\"TEMPERATURE\": %.1f, \"HUMIDITY\": %.1f}", t, h);
client.publish(mqtt_topic_pub, msg);
client.publish(mqtt_topic_time, timeStr);
lcd.clear();
lcd.setCursor(0, 0);
lcd.printf("T:%.1fC H:%.1f%%", t, h);
lcd.setCursor(0, 1);
lcd.print(timeStr);
}
// 🔘 LED toggle via button
if (digitalRead(BUTTON_PIN) == LOW && now - lastButtonPress > debounceDelay) {
lastButtonPress = now;
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
Serial.printf("Button pressed, LED: %s\n", ledState ? "ON" : "OFF");
}
// 📨 Serial message forwarding
if (Serial.available() > 0) {
String inputMessage = Serial.readStringUntil('\n');
inputMessage.trim();
if (inputMessage.length() > 0) {
client.publish(mqtt_topic_pub, inputMessage.c_str());
Serial.print("Published to MQTT: ");
Serial.println(inputMessage);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Sent to MQTT:");
lcd.setCursor(0, 1);
lcd.print(inputMessage);
}
}
// 🚨 Alarm placeholder (ready to implement)
// if (digitalRead(ALARM_PIN) == LOW && !alarmSent) { ... }
}