For this week's assignment, I developed an IoT communication system connecting a XIAO ESP32-C6 with an HTML interface through the MQTT protocol. I implemented a publish-subscribe architecture that allows for real-time data exchange.
I used the RTC sensor to send the time to an HTML page. With my XIAO ESP32-C6, I read the real-time clock from a DS3231 RTC sensor via the I2C protocol.
Once the time was obtained, the microcontroller connects to Wi-Fi and acts as a Publisher, sending the text string to the HiveMQ broker under the topic danna/sensor2.
The webpage uses the mqtt.js library to connect to the same broker via WebSockets (port 8884) depending on which broker you are using. The page functions as a Subscriber.
MQTT (Message Queuing Telemetry Transport) is a lightweight messaging protocol designed for machine-to-machine (M2M) communication. It works under a Publish/Subscribe model:.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "RTClib.h"
const char* ssid = "MyWifi123_2.4Gnormal";
const char* password = "holamundo123";
const char* mqtt_server = "broker.hivemq.com";
const char* topic_time = "danna/sensor2";
WiFiClient espClient;
PubSubClient client(espClient);
RTC_DS3231 rtc;
void setup_wifi() {
delay(10);
Serial.print("\nConnecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected!");
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("XIAO_C6_Clock_Only")) {
Serial.println("Connected!");
} else {
Serial.print("Error: ");
Serial.print(client.state());
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
// Initialize I2C on pins D4 (SDA) and D5 (SCL)
Wire.begin();
if (!rtc.begin()) {
Serial.println("RTC module not detected. Check SDA/SCL wires.");
while (1);
}
// Only if the clock lost power, sync with the computer's time
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// GET TIME FROM I2C SENSOR
DateTime now = rtc.now();
char horaFormateada[12];
sprintf(horaFormateada, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
// SEND TO MQTT (Topic: danna/sensor2)
client.publish(topic_time, horaFormateada);
Serial.print("Time sent to Dashboard: ");
Serial.println(horaFormateada);
delay(1000);
}
WiFi.h: Enables the board to connect to the internet.
PubSubClient.h: The library that manages the MQTT protocol.
Wire.h: Allows I2C communication.
RTClib.h: Specific for reading the clock sensor (RTC).
Next, we define our network name, password, and server address along with the topic.
setup_wifi(): Attempts to connect to your local network.
reconnect(): If connection to the HiveMQ server is lost, it tries to reconnect every 5 seconds.
rtc.begin(): Initializes communication with the clock.
client.setServer(mqtt_server, 1883);: We indicate where the data will be sent.
The time is obtained, and the data is formatted to be readable.
client.publish(topic_time, horaFormateada): Publishes the data to the topic we previously defined.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RTC Monitor - Danna</title>
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<style>
:root {
--bg: #C9EEFB; /* Colors used on the page */
--strong-blue: #004B75;
--text-main: #000000;
--text-label: #888888;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', -apple-system, system-ui, sans-serif;
background-color: var(--bg);
color: var(--text-main);
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.dashboard {
text-align: center;
width: 100%;
max-width: 600px;
}
.label {
font-size: 0.8rem;
font-weight: 800;
color: var(--strong-blue);
text-transform: uppercase;
letter-spacing: 5px;
margin-bottom: 30px;
}
.clock-container {
padding: 60px 40px;
border: 4px solid var(--text-main);
border-radius: 50px;
transition: all 0.3s ease;
background-color: rgba(255, 255, 255, 0.3);
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.clock-container:hover {
border-color: var(--strong-blue);
transform: translateY(-5px);
}
.cat-img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 30px;
transition: border-color 0.3s ease;
}
.clock-container:hover .cat-img {
border-color: var(--strong-blue);
}
.time-value {
font-size: 7rem;
font-weight: 900;
letter-spacing: -5px;
line-height: 0.9;
}
@media (max-width: 600px) {
.time-value { font-size: 4rem; letter-spacing: -2px; }
.clock-container { padding: 40px 20px; border-width: 3px; }
.cat-img { width: 100px; height: 100px; }
}
</style>
</head>
<body>
<div class="dashboard">
<div class="label">Hora enviada desde el RTC</div>
<div class="clock-container">
<img src="cat.png" alt="Gato Jumper" class="cat-img">
<div id="reloj" class="time-value">--:--:--</div>
</div>
</div>
<script>
const broker = "wss://broker.hivemq.com:8884/mqtt";
const client = mqtt.connect(broker);
client.on("connect", () => {
client.subscribe("danna/sensor2");
});
client.on("message", (topic, message) => {
if (topic === "danna/sensor2") {
document.getElementById("reloj").innerText = message.toString();
}
});
</script>
</body>
</html>
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>: We import the library to use MQTT.
client.on("connect"): It connects and subscribes to the topic danna/sensor2.
document.getElementById("reloj").innerText = message.toString(): We add the time read from the topic and write it where there were previously dashes.
Here you can download the source files created during this week: