================================================================================
  Experiment 4: ESP32 MQTT Publisher (DHT22) & Python MQTT Subscriber
================================================================================

FULL QUESTION:
Develop an ESP32 program to read temperature and humidity data and publish it to an MQTT broker, and develop a Python subscriber program to receive and display the published data.

SHORT QUESTION:
ESP32 MQTT Publisher with Python Subscriber on HiveMQ Public Broker.

================================================================================
README & SETUP INSTRUCTIONS:
================================================================================
# Experiment 4: ESP32 MQTT Publisher & Python Subscriber

## Objective
Read temperature and humidity with an ESP32 and publish the readings to HiveMQ public MQTT broker. A local Python script subscribes and displays incoming data in real time.

## Requirements
- Python package: `pip install paho-mqtt`
- Wokwi libraries: `DHT sensor library`, `PubSubClient`, `Adafruit Unified Sensor`

## Execution Steps
1. **Run Python Subscriber:**
   ```bash
   python subscriber.py
   ```
2. **Run ESP32 Publisher in Wokwi:**
   - Paste `sketch.ino`, `diagram.json`, and `libraries.txt`.
   - Click Play in Wokwi.
   - ESP32 connects to `Wokwi-GUEST` WiFi and publishes data to `broker.hivemq.com`.
3. Observe live sensor data appearing in your terminal.

================================================================================
SOURCE CODE FILES:
================================================================================

1. sketch.ino
--------------------------------------------------------------------------------
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

const char* ssid = "Wokwi-GUEST";
const char* password = "";

const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;

const char* temp_topic = "iot_lab_test/temp";
const char* hum_topic  = "iot_lab_test/humidity";

#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  delay(10);
  Serial.print("Connecting to WiFi: ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWiFi connected: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Connecting to MQTT broker...");
    String clientId = "ESP32-" + String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" retrying in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  delay(2000);

  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  String temp_str = String(temperature, 2);
  String humidity_str = String(humidity, 2);

  client.publish(temp_topic, temp_str.c_str());
  client.publish(hum_topic, humidity_str.c_str());

  Serial.print("Published: Temp=");
  Serial.print(temp_str);
  Serial.print(" C | Hum=");
  Serial.println(humidity_str);
}
--------------------------------------------------------------------------------

2. subscriber.py
--------------------------------------------------------------------------------
import paho.mqtt.client as mqtt

BROKER = "broker.hivemq.com"
PORT = 1883
TEMP_TOPIC = "iot_lab_test/temp"
HUMIDITY_TOPIC = "iot_lab_test/humidity"

def on_connect(client, userdata, flags, rc, *extra):
    if rc == 0:
        print("Connected to HiveMQ broker successfully.")
        client.subscribe(TEMP_TOPIC)
        client.subscribe(HUMIDITY_TOPIC)
        print("Subscribed to:", TEMP_TOPIC, "and", HUMIDITY_TOPIC)
    else:
        print("Connection failed with return code:", rc)

def on_message(client, userdata, msg):
    print(f"[{msg.topic}] : {msg.payload.decode()}")

try:
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
except AttributeError:
    client = mqtt.Client()

client.on_connect = on_connect
client.on_message = on_message

print("Connecting to MQTT Broker...")
client.connect(BROKER, PORT, 60)
client.loop_forever()
--------------------------------------------------------------------------------

3. diagram.json
--------------------------------------------------------------------------------
{
  "version": 1,
  "author": "IoT Lab",
  "editor": "wokwi",
  "parts": [
    { "type": "board-esp32-devkit-c-v4", "id": "esp", "top": 0, "left": 0, "attrs": {} },
    { "type": "wokwi-dht22", "id": "dht1", "top": 0.3, "left": -159, "attrs": {} }
  ],
  "connections": [
    [ "esp:TX", "$serialMonitor:RX", "", [] ],
    [ "esp:RX", "$serialMonitor:TX", "", [] ],
    [ "dht1:GND", "esp:GND.2", "black", [ "v0" ] ],
    [ "dht1:VCC", "esp:3V3", "red", [ "v0" ] ],
    [ "dht1:SDA", "esp:4", "green", [ "v0" ] ]
  ],
  "dependencies": {}
}
--------------------------------------------------------------------------------

4. libraries.txt
--------------------------------------------------------------------------------
DHT sensor library
PubSubClient
Adafruit Unified Sensor
--------------------------------------------------------------------------------
