WEEK 11
Networking and Communications
Group assignment:
- Send a message between two projects.
- Document your work to the group work page and reflect on your individual page what you learned.
What I Learned From Teamwork
Installing the MQTT Protocol
For this group assignment, we will install the MQTTX program by following the indicated steps.
Creating an MQTT connection for IoT communication on a local network
At this stage, a new connection was created in the MQTTX application in order to establish communication with a broker using the MQTT protocol. To do this, the basic parameters were configured, such as the connection name, the server address (host), the communication port (1883), and the client ID. This setup allows the system to connect correctly to the broker and send and receive data from external devices such as the ESP32-C3 programmed in Arduino IDE. This step is essential for enabling IoT communication and verifying real-time data flow between hardware and software.
We will use the general name ASSIGNMENT11 and keep the default options as shown in the image.
Then we will click NEW SUBSCRIPTION to create a new subscription, and in the topic field we will enter fabacademy/contador.
Finally, we will click CONNECT to establish the connection with the broker.
We verified that the shared data uses the topic fabacademy/contador and that it is set to the Plaintext option; then we checked the connections on more computers.
Establishing the WiFi connection and sending data via MQTT
At this stage, the WiFi connection of the ESP32-C3 microcontroller was established, allowing it to access the local network and communicate with a broker through the MQTT protocol. Arduino IDE was used for programming, and the PubSubClient library was installed. This library makes it easy to implement MQTT communication on the ESP32, enabling functions such as connecting to the broker, publishing sensor data, and subscribing to different topics. Thanks to this implementation, the device can send information in real time, becoming part of a functional IoT system.
This test code was generated in Gemini to verify the WiFi connection and MQTT communication.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// WiFi
const char* ssid = "TU_WIFI";
const char* password = "TU_PASSWORD";
// MQTT
const char* mqtt_server = "broker.emqx.io";
WiFiClient espClient;
PubSubClient client(espClient);
String mensaje = "";
void setup() {
Serial.begin(115200);
// OLED
Wire.begin(4, 5);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
// WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// MQTT
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void reconnect() {
while (!client.connected()) {
if (client.connect("XIAOClient")) {
client.subscribe("fabacademy/servo");
} else {
delay(2000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
mensaje = "";
for (int i = 0; i < length; i++) {
mensaje += (char)payload[i];
}
Serial.println(mensaje);
// Mostrar en OLED
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println(mensaje);
display.display();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
In the serial monitor, the connection and some messages sent by my classmates can be observed.
It is time to connect the two projects.
TRANSMITTER
In this case, my classmate will be the transmitter, and the PCB he will use is Adrian Torres's FABXIAO, specifically only the button connected to pin D7. To do this, he connected his board to his computer and uploaded the following code.
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi
const char* ssid = "IoT_UP";
const char* password = "ti6WzfPsk3WnqZpt8d";
// MQTT
const char* mqtt_server = "broker.emqx.io";
WiFiClient espClient;
PubSubClient client(espClient);
int boton = D7;
int contador = 0;
bool estadoAnterior = HIGH;
void setup() {
Serial.begin(115200);
pinMode(boton, INPUT_PULLUP);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
client.setServer(mqtt_server, 1883);
}
void reconnect() {
while (!client.connected()) {
client.connect("XIAO_BOTON");
}
}
void loop() {
if (!client.connected()) reconnect();
client.loop();
bool estadoActual = digitalRead(boton);
// Detecta pulsación
if (estadoAnterior == HIGH && estadoActual == LOW) {
contador++;
String msg = String(contador);
Serial.println(msg);
client.publish("fabacademy/contador", msg.c_str());
delay(300); // anti rebote
}
estadoAnterior = estadoActual;
}
RECEIVER
In this case, I will be the receiver and I will use the board that has the OLED, specifically pin D4 for SDA and pin D5 for SCL. To do this, I connected my board to my computer and uploaded the following code.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// WiFi
const char* ssid = "IoT_UP";
const char* password = "ti6WzfPsk3WnqZpt8d";
// MQTT
const char* mqtt_server = "broker.emqx.io";
WiFiClient espClient;
PubSubClient client(espClient);
String mensaje = "";
bool nuevoMensaje = false;
void setup() {
Serial.begin(115200);
// OLED
Wire.begin(D4, D5);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Contador");
display.display();
// WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// MQTT
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void reconnect() {
while (!client.connected()) {
if (client.connect("XIAO_OLED")) {
client.subscribe("fabacademy/contador");
} else {
delay(2000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
mensaje = "";
for (int i = 0; i < length; i++) {
mensaje += (char)payload[i];
}
Serial.println(mensaje);
nuevoMensaje = true;
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
if (nuevoMensaje) {
display.clearDisplay();
display.setTextSize(3);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 20);
display.println(mensaje);
display.display();
nuevoMensaje = false;
}
}
The video shows the communication between the transmitter and the receiver, where pressing the transmitter button increases the counter and displays it on the receiver OLED. This confirms that the MQTT connection is working correctly and that the data is being transmitted effectively between both devices.
Some Failed Attempts
We encountered some issues when testing the connection with a microservo, since it did not rotate according to the data sent from another computer.
Conclusion
In conclusion, during this week I was able to understand and apply the use of the MQTT protocol to establish communication between two projects within a local network. First, I configured MQTTX to connect to the broker and monitor data in real time; then I verified the WiFi connection of the ESP32-C3 and the publication of messages using code in Arduino IDE. Finally, I confirmed the communication between a transmitter and a receiver, where pressing a button sent data that was then correctly displayed on an OLED screen. This whole process helped me better understand the integration between hardware, software, and IoT communication, as well as the importance of testing and adjustments to ensure stable system performance.
Individual assignment:
- design, build and connect wired or wireless node(s) with network or bus addresses and a local input and/or output device(s).
Access Point Mode for My ESP32
At this stage, the ESP32-C3 microcontroller was configured in Access Point (AP) mode, allowing it to generate its own WiFi network without needing an external router. Using Arduino IDE, an embedded web server was implemented on the device, which can be accessed from a browser through a local IP address. This approach allows direct communication between the user and the ESP32 within a local wireless network, meeting the requirement of creating connected nodes without depending on the internet.
Since I only had the RP2040 board package installed, it was necessary to install the ESP32 package and look for the XIAO ESP32 C3.
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
I asked Gemini to generate a test code to start the network and let me connect from my phone to turn on the LED on my board, which is connected to pin D2.
#include <WiFi.h>
#include <WebServer.h>
// Configura el nombre de tu red y la contraseña
const char* ssid = "Red_David_Fab";
const char* password = "fabacademy2026";
// Definimos el pin del LED (D2 en el XIAO es GPIO 4)
const int ledPin = 4;
WebServer server(80);
// Esta función crea la página que verás en tu celular
void handleRoot() {
String html = "<html><style>body{font-family:sans-serif; text-align:center; padding:50px;}";
html += "button{padding:20px; font-size:20px; cursor:pointer;}</style>";
html += "<body><h1>Control PCB</h1>";
html += "<p><a href='/on'><button>ON LED</button></a></p>";
html += "<p><a href='/off'><button>OFF LED</button></a></p>";
html += "</body></html>";
server.send(200, "text/html", html);
}
void handleOn() {
digitalWrite(ledPin, HIGH);
server.sendHeader("Location", "/");
server.send(303);
}
void handleOff() {
digitalWrite(ledPin, LOW);
server.sendHeader("Location", "/");
server.send(303);
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
// Configuramos la placa como un Access Point (Emisor de señal)
WiFi.softAP(ssid, password);
Serial.println("Red iniciada");
Serial.print("IP de la placa: ");
Serial.println(WiFi.softAPIP()); // Esto mostrará 192.168.4.1
// Definimos qué pasa cuando entramos a cada dirección
server.on("/", handleRoot);
server.on("/on", handleOn);
server.on("/off", handleOff);
server.begin();
}
void loop() {
server.handleClient(); // Mantiene el servidor escuchando
}
We verified that the network started correctly and wrote down the IP: 192.168.4.1
From the phone, we connect to the WiFi network created by the ESP32 and then enter the IP address in our browser to access the control page. By clicking the "ON LED" button, the LED connected to pin D2 on the board turns on, and by clicking "OFF LED" it turns off. This confirms that the communication between the phone and the ESP32 through the Access Point is working correctly, allowing the hardware to be controlled wirelessly.
We asked Gemini to modify the web page colors and translate it into Spanish as a test
#include <WiFi.h> #include <WebServer.h> // Configura el nombre de tu red y la contraseña const char* ssid = "Red_David_Fab"; const char* password = "fabacademy2026"; // Definimos el pin del LED (D2 en el XIAO es GPIO 4) const int ledPin = 4; WebServer server(80); // Esta función crea la página que verás en tu celular void handleRoot() { String html = "<html><head><meta name='viewport' content='width=device-width, initial-scale=1'>"; html += "<style>"; html += "body { font-family: 'Arial'; text-align: center; background-color: #f4f4f4; padding-top: 50px; }"; html += "h1 { color: #333; }"; html += ".button { display: inline-block; padding: 15px 25px; font-size: 24px; cursor: pointer; text-align: center; "; html += "text-decoration: none; outline: none; color: #fff; border: none; border-radius: 15px; box-shadow: 0 9px #999; margin: 10px; }"; html += ".btn-on { background-color: #4CAF50; }"; // Verde html += ".btn-off { background-color: #f44336; }"; // Rojo html += ".button:active { box-shadow: 0 5px #666; transform: translateY(4px); }"; html += "</style></head><body>"; html += "<h1>Parametri-k Control Panel</h1>"; html += "<p>Estado del LED en D2</p>"; html += "<a href='/on' class='button btn-on'>ENCENDER</a>"; html += "<a href='/off' class='button btn-off'>APAGAR</a>"; html += "</body></html>"; server.send(200, "text/html", html); } void handleOn() { digitalWrite(ledPin, HIGH); server.sendHeader("Location", "/"); server.send(303); } void handleOff() { digitalWrite(ledPin, LOW); server.sendHeader("Location", "/"); server.send(303); } void setup() { Serial.begin(115200); pinMode(ledPin, OUTPUT); // Configuramos la placa como un Access Point (Emisor de señal) WiFi.softAP(ssid, password); Serial.println("Red iniciada"); Serial.print("IP de la placa: "); Serial.println(WiFi.softAPIP()); // Esto mostrará 192.168.4.1 // Definimos qué pasa cuando entramos a cada dirección server.on("/", handleRoot); server.on("/on", handleOn); server.on("/off", handleOff); server.begin(); } void loop() { server.handleClient(); // Mantiene el servidor escuchando }
The video shows that the servo motor moves correctly when the button is pressed, and the LED turns on while the servo motor is moving. This indicates that the code works correctly and that the output device is functioning properly.
Testing with My Input and Output Devices
I asked Gemini to create a web control panel for my LDR module and my microservo, so that the module would be shown in a graph like the serial plotter and the microservo would move to 45, 90, and 180 degrees. This was the result.
#include #include #include // --- Datos de tu Red --- const char* ssid = "Red_David_Fab"; const char* password = "fabacademy2026"; // --- Pines de tu PCB (XIAO ESP32-C3) --- const int ledPin = 4; // D2 const int ldrPin = 3; // D1 (GPIO 3) const int servoPin = 2; // D0 (GPIO 2) WebServer server(80); Servo myServo; // --- Interfaz Web con Auto-Escala --- void handleRoot() { String html = ""; html += ""; html += " HEXAMODULAR PANEL
"; // Gráfico con estilo Osciloscopio html += ""; html += ""; html += "LDR Real-Time Plotter
"; html += ""; html += "Valor: --
"; // JavaScript Inteligente html += ""; server.send(200, "text/html", html); } void handleLDR() { int lectura = analogRead(ldrPin); server.send(200, "text/plain", String(lectura)); } void setup() { Serial.begin(115200); pinMode(ledPin, OUTPUT); myServo.attach(servoPin); // Modo Access Point WiFi.softAP(ssid, password); Serial.println("--- SISTEMA INICIADO ---"); Serial.print("IP: "); Serial.println(WiFi.softAPIP()); // Rutas server.on("/", handleRoot); server.on("/readLDR", handleLDR); server.on("/on", [](){ digitalWrite(ledPin, HIGH); server.sendHeader("Location", "/"); server.send(303); }); server.on("/off", [](){ digitalWrite(ledPin, LOW); server.sendHeader("Location", "/"); server.send(303); }); server.on("/s45", [](){ myServo.write(45); server.sendHeader("Location", "/"); server.send(303); }); server.on("/s90", [](){ myServo.write(90); server.sendHeader("Location", "/"); server.send(303); }); server.on("/s180", [](){ myServo.write(180); server.sendHeader("Location", "/"); server.send(303); }); server.begin(); } void loop() { server.handleClient(); }Control Servo
"; html += ""; html += ""; html += "
The video shows a control and monitoring panel from my phone connected to my PCB, which I customized thanks to Gemini's code.
Conclusions: