11. Networking and Communications

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.

1. MQTT

MQTT (Message Queuing Telemetry Transport) is a lightweight messaging protocol designed for machine-to-machine (M2M) communication. It works under a Publish/Subscribe model:.

2. ARDUINO CODE


#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); 
}
        

Explanation

Libraries

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.

Network Configuration

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.

Setup Block

rtc.begin(): Initializes communication with the clock.

client.setServer(mqtt_server, 1883);: We indicate where the data will be sent.

Loop Block

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.

3. HTML CODE


<!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>
        

Explanation

<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.

4. RESULT

FILES

Here you can download the source files created during this week: