// ESP32 + DHT22 (GPIO15) + MQTT over WebSocket (WSS:443) for Wokwi
// Uses DHT22.h, ArduinoMqttClient, ArduinoHttpClient
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoHttpClient.h> // WebSocketClient
#include <ArduinoMqttClient.h> // MQTT over WebSocket
#include "DHT22.h" // Normal DHT22 library
// ---------- USER CONFIG ----------
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = ""; // Wokwi-GUEST has no password
const char* MQTT_HOST = "mqtt.makerspace-um.my";
const int MQTT_WSS_PORT = 443; // WebSocket over TLS
const char* WS_PATH = "/mqtt"; // Change to "/ws" if your server uses that
const char* MQTT_TOPIC = "makerspace/dht22";
#define DHTPIN 15 // DHT22 data pin on GPIO 15
const uint32_t PUBLISH_MS = 5000; // publish interval (ms)
// ---------- GLOBALS ----------
DHT22 dht(DHTPIN);
WiFiClientSecure tlsClient; // TLS layer
WebSocketClient wsClient(tlsClient, MQTT_HOST, MQTT_WSS_PORT);
MqttClient mqttClient(wsClient);
unsigned long lastPublish = 0;
void connectWiFi() {
Serial.print("Connecting WiFi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
int dots = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(400);
Serial.print(".");
if (++dots % 30 == 0) Serial.println();
}
Serial.println("\nWiFi connected. IP: " + WiFi.localIP().toString());
}
bool connectMQTT() {
// For quick Wokwi testing ONLY (disables cert validation). Pin a CA in production.
tlsClient.setInsecure();
Serial.print("Opening WSS ");
Serial.print(MQTT_HOST);
Serial.print(":");
Serial.print(MQTT_WSS_PORT);
Serial.print(" ");
Serial.println(WS_PATH);
// WebSocketClient uses begin(path). No beginSSL().
if (!wsClient.begin(WS_PATH)) {
Serial.println("WebSocket begin() failed");
return false;
}
mqttClient.setKeepAliveInterval(30); // seconds
mqttClient.setTimeout(10); // seconds for network ops
String clientId = "wokwi-esp32-" + String((uint32_t)ESP.getEfuseMac(), HEX);
Serial.print("Connecting MQTT (clientId=");
Serial.print(clientId);
Serial.println(") ...");
if (!mqttClient.connect(clientId.c_str())) {
Serial.print("MQTT connect failed, code=");
Serial.println(mqttClient.connectError());
return false;
}
Serial.println("MQTT connected over WebSocket.");
return true;
}
void ensureConnectivity() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi dropped, reconnecting...");
connectWiFi();
}
if (!mqttClient.connected()) {
Serial.println("MQTT not connected, reconnecting...");
wsClient.stop(); // close any stale WS
connectMQTT();
}
}
void publishReading() {
float t = dht.getTemperature(); // °C
float h = dht.getHumidity(); // % RH
if (isnan(t) || isnan(h)) {
Serial.println("DHT22 read failed (NaN). Skipping publish.");
return;
}
String payload = String("{\"temp\":") + String(t, 2) +
String(",\"humidity\":") + String(h, 2) + "}";
Serial.print("Publishing to ");
Serial.print(MQTT_TOPIC);
Serial.print(": ");
Serial.println(payload);
if (!mqttClient.beginMessage(MQTT_TOPIC)) {
Serial.println("beginMessage() failed");
return;
}
mqttClient.print(payload);
mqttClient.endMessage();
}
void setup() {
Serial.begin(115200);
delay(200);
// If your DHT22 library supports .begin(), uncomment:
// dht.begin();
connectWiFi();
for (int i = 0; i < 5 && !mqttClient.connected(); i++) {
if (connectMQTT()) break;
delay(1500);
}
}
void loop() {
mqttClient.poll(); // keep MQTT alive
ensureConnectivity(); // auto-reconnect if needed
unsigned long now = millis();
if (now - lastPublish >= PUBLISH_MS && mqttClient.connected()) {
lastPublish = now;
publishReading();
}
}