#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
// -------------------- Hardware --------------------
#define DHTPIN 14
#define DHTTYPE DHT22
#define LED_PIN 2
#define BUTTON_PIN 4
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD 20x4
// -------------------- Wi-Fi --------------------
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// -------------------- MQTT --------------------
const char* MQTT_HOST = "mqtt-dashboard.com";
uint16_t MQTT_PORT = 8884; // TLS
const char* MQTT_CLIENT_ID = "pnc_iot_deec002";
const char* TOPIC_STATUS = "pnc-iot/deec002/status";
const char* TOPIC_SENSOR = "pnc-iot/deec002/sensor";
const char* TOPIC_ALARM = "pnc-iot/deec002/alarm";
const char* TOPIC_LED = "pnc-iot/deec002/led";
WiFiClientSecure tlsClient;
WiFiClient plainClient; // for fallback
PubSubClient mqtt(tlsClient);
// -------------------- State --------------------
bool ledState = false;
bool usingTLS = true;
uint8_t mqttAttempts = 0;
const uint8_t MQTT_MAX_TLS_ATTEMPTS = 3;
unsigned long lastPublish = 0;
const unsigned long SENSOR_INTERVAL = 30000; // 30 sec
// -------------------- Functions --------------------
void printMQTTState(int s) {
Serial.print("[MQTT] State ");
Serial.print(s);
Serial.print(" -> ");
switch (s) {
case -4: Serial.println("CONNECTION_TIMEOUT"); break;
case -3: Serial.println("CONNECTION_LOST"); break;
case -2: Serial.println("CONNECT_FAILED"); break;
case -1: Serial.println("DISCONNECTED"); break;
case 0: Serial.println("CONNECTED"); break;
case 1: Serial.println("BAD_PROTOCOL"); break;
case 2: Serial.println("BAD_CLIENT_ID"); break;
case 3: Serial.println("UNAVAILABLE"); break;
case 4: Serial.println("BAD_CREDENTIALS"); break;
case 5: Serial.println("NOT_AUTHORIZED"); break;
default: Serial.println("UNKNOWN"); break;
}
}
void connectWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
Serial.print("[Wi-Fi] Connecting to ");
Serial.println(WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("[Wi-Fi] OK. IP: ");
Serial.println(WiFi.localIP());
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
String msg = (char*)payload;
Serial.print("[MQTT IN] ");
Serial.print(topic);
Serial.print(" => ");
Serial.println(msg);
if (String(topic) == TOPIC_LED) {
if (msg.equalsIgnoreCase("ON")) {
digitalWrite(LED_PIN, HIGH);
ledState = true;
} else if (msg.equalsIgnoreCase("OFF")) {
digitalWrite(LED_PIN, LOW);
ledState = false;
}
lcd.setCursor(0, 2);
lcd.print("LED: ");
lcd.print(ledState ? "ON " : "OFF");
}
}
void connectMQTT() {
while (!mqtt.connected()) {
Serial.printf("[MQTT] Connecting to %s:%u (%s) ...\n",
MQTT_HOST, MQTT_PORT, usingTLS ? "TLS" : "plain");
bool ok = mqtt.connect(
MQTT_CLIENT_ID,
TOPIC_STATUS, // LWT
0,
true,
"offline"
);
if (ok) {
Serial.println("[MQTT] CONNECTED.");
mqtt.publish(TOPIC_STATUS, "online", true);
mqtt.subscribe(TOPIC_LED);
Serial.println("[MQTT] Subscribed to LED topic");
mqttAttempts = 0;
return;
}
Serial.println("[MQTT] Connect FAILED.");
printMQTTState(mqtt.state());
mqttAttempts++;
if (usingTLS && mqttAttempts >= MQTT_MAX_TLS_ATTEMPTS) {
Serial.println("[MQTT] TLS attempts exceeded. Fallback to port 1883");
usingTLS = false;
MQTT_PORT = 1883;
mqtt.setClient(plainClient);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqttAttempts = 0;
}
delay(5000);
}
}
void publishSensor() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("[DHT] Failed to read");
return;
}
char payload[80];
snprintf(payload, sizeof(payload), "{\"temp\":%.2f,\"hum\":%.2f}", t, h);
mqtt.publish(TOPIC_SENSOR, payload);
Serial.print("[MQTT OUT] Sensor -> ");
Serial.println(payload);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(t);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print("Hum: ");
lcd.print(h);
lcd.print(" %");
lcd.setCursor(0, 2);
lcd.print("LED: ");
lcd.print(ledState ? "ON " : "OFF");
lcd.setCursor(0, 3);
lcd.print("Btn=Alarm");
}
void setup() {
Serial.begin(115200);
delay(100);
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
digitalWrite(LED_PIN, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Booting...");
dht.begin();
connectWiFi();
WiFi.setSleep(true); // Enable Wi-Fi modem sleep
tlsClient.setInsecure();
mqtt.setBufferSize(512);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(mqttCallback);
connectMQTT();
lcd.clear();
lcd.print("System Ready");
lastPublish = millis() - SENSOR_INTERVAL;
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[Wi-Fi] Lost. Reconnecting...");
connectWiFi();
}
if (!mqtt.connected()) {
connectMQTT();
}
mqtt.loop();
unsigned long now = millis();
if (now - lastPublish >= SENSOR_INTERVAL) {
lastPublish = now;
publishSensor();
}
if (digitalRead(BUTTON_PIN) == LOW) {
mqtt.publish(TOPIC_ALARM, "Alarm Triggered!");
Serial.println("[ALARM] Button pressed.");
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
}
}
LCD (20x4) I2C: SDA=21 SCL=22
LED Control via MQTT:
pnc-iot/deec002/led
Button -> Publish Alarm:
pnc-iot/deec002/alarm