Week 11: Networking and Communications
Group assignment
Week 11Introduction
This week, I will be working on establishing MQTT communication between three different boards, two of which are custom-made PCBs. One of these PCBs was designed and fabricated by a colleague at the fab, making the project even more collaborative and interesting.
The main goal is to use MQTT as the communication protocol to allow the boards to exchange data efficiently and reliably. Through this setup, we plan to control an OLED display and several NeoPixels remotely, enabling the devices to react to transmitted messages in real time.
This project will also help me gain more experience with wireless communication systems, embedded programming, and device synchronization. In addition, working with multiple interconnected boards will improve my understanding of how distributed electronic systems operate together within a single project.
Communications
Low-Level Communication Methods
These methods are based on electrical signals and are typically used for direct control or simple data transfer between devices:
GPIO (Digital Communication)
Uses HIGH/LOW signals. While simple, it can still represent control logic between a main controller and peripheral devices.
PWM (Pulse Width Modulation)
Encodes information in the duty cycle of a signal. Although commonly used for control (like LED brightness or motor speed), it can also be interpreted as a communication method where the peripheral device decodes signal timing.
DAC (Digital-to-Analog Conversion)
Produces variable voltage levels. This can act as a form of analog communication where continuous signals represent data between devices.
Protocol-Based Communication
These methods define rules for data exchange and are designed for reliable communication between multiple devices:
I²C (Inter-Integrated Circuit)
Two-wire protocol (SDA, SCL) that allows multiple devices using addressing.
- One main device + multiple peripherals
SPI (Serial Peripheral Interface)
High-speed communication with dedicated lines (MOSI, MISO, SCK, CS).
- One main device + multiple peripherals (each with select line)
UART (Serial Communication)
Asynchronous communication using TX/RX.
- Point-to-point (main ↔ peripheral)
Networking Communication (IoT & Wireless)
Beyond local communication, embedded systems can connect through networking technologies, enabling distributed systems:
WiFi
Enables devices to connect to local networks or the internet. Ideal for IoT systems with cloud integration.
Bluetooth / BLE
Short-range communication, commonly used for direct interaction with smartphones.
MQTT (Message Queuing Telemetry Transport)
Lightweight publish/subscribe protocol. Devices communicate through a broker, allowing scalable and decoupled systems.
HTTP/HTTPS
Request-response model used for web services and APIs.
WebSockets (WS/WSS)
Enables real-time bidirectional communication between clients and devices.
MQTT protocol
For communication, the MQTT protocol will be used, as it is lightweight, efficient, and ideal for systems with multiple
devices connected to the same broker. One of its main advantages is the publish/subscribe model, which allows three or
more devices to communicate without needing direct connections between them. This reduces complexity, improves scalability,
and enables real-time bidirectional communication.
The broker used will be MQTTX, as it provides an online client that simplifies testing and debugging connections without requiring
local installation. This makes it easier to visualize topics, messages, and device interactions in real time.
MQTT Configuration (MQTTX)
General Settings
Name
Identifier of the device within the MQTT client. It helps distinguish between multiple connected devices.
In this case: Kamilovich_Kamilova
Host
Address of the MQTT broker. In this case, it uses a secure WebSocket connection (WSS) to communicate over the internet.
wss://broker.emqx.io
Port
Communication port used for secure WebSocket connections.
Port 8084 is commonly used for MQTT over WSS.
Client ID
Unique identifier for each device connecting to the broker. It must be different for every client to avoid conflicts.
In this case: mqttx_9164bde9
Path
Endpoint used for WebSocket communication with the broker.
/mqtt
SSL/TLS
Enables encrypted communication, improving security when sending data over the internet.
MQTT Configuration (MQTTX)
Advanced Settings
Connect Timeout
Maximum time the client waits to establish a connection before failing.
10 s
Keep Alive
Time interval in which the client sends a signal to maintain the connection active.
60 s
Clean Session
If enabled, the broker does not store previous session data when the client reconnects.
Auto Reconnect
Allows the client to automatically reconnect if the connection is lost.
Reconnect Period
Time between reconnection attempts.
4000 ms
MQTT Version
Protocol version used. Version 5.0 includes improved features like properties and better error handling.
5.0
MQTT Configuration (MQTTX)
Last Will and Testament
QoS (Quality of Service)
Defines the reliability level of message delivery between sender and receiver in MQTT. It determines how many times a message is sent and if confirmation is required.
QoS 0"At most once" delivery. The message is sent only one time with no confirmation. It is the fastest method but messages can be lost.
QoS 1"At least once" delivery. The message is guaranteed to arrive, but it may be received more than once due to retransmissions.
QoS 2"Exactly once" delivery. Ensures the message arrives only one time using a handshake process. It is the most reliable but also the slowest.
MQTTX Connection and Subscriptions
Once the client information is configured, you can click the “Connect” button to create the connection.
Subscriptions
A subscription is the process by which a client tells the broker that it wants to receive messages from a specific topic.In MQTT, communication works using a publish/subscribe model, meaning:
- Devices do not talk directly to each other
- They communicate through topics managed by the broker
- Make sure the client is connected to the broker
- Click on “New Subscription”
- Assign a topic and customize the preferences
- Click on confirm.
Main
Main
The diagram shows the wiring of the system powered by the 5V output of the XIAO ESP32-C6. This voltage rail supplies power to the NeoPixels, while all GND connections are tied directly to the XIAO’s GND, creating a common ground that ensures stable operation and proper signal reference across the system.
Additionally, the system includes five push buttons used for input commands. These buttons are connected directly to the XIAO pins from D0 to D4 and use the internal pull-up resistor configuration, meaning each pin reads HIGH by default and switches to LOW when the button is pressed.
From pin D5, a 220 Ω resistor is placed in series with the data line that connects to the input (DIN) of the NeoPixels. This resistor helps protect the data line from voltage spikes and improves signal integrity. The NeoPixels are connected in series, where the data flows from the first LED to the next (DOUT to DIN), allowing the microcontroller to control all LEDs through a single data pin.
XIAO ESP32-C6 Board
1.First, we have to create a sketch in Arduino IDE.
XIAO ESP32-C6 Board
2.Then, we have go to the board manager and write XIAO. After doing that, a library will appear, its name is Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III, we must install it.
Uploading
3.After installing the XIAO ESP32-C6 Board, we must click on the tab that says select board and write Seeed XIAO ESP32-C6, then select the PORT where our microcontroller is connected and upload the information. We can also click Tools, then Board and then the library Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III and there look for the XIAO. Both ways will let us set our board as a XIAO.
4.Before uploading our code to the microcontroller we should use the verify tool, that compiles the code before uploading it in order to detect mistakes or problems. The verify tool is the one in the top with the check.
5.Finally, to upload our code we must click the upload tool, that is the one with the arrow pointing to the right. If our code is right, it shall compile. To get the , we must click on Tools in the top menu and select Serial Monitor.
My Code
Network:WiFi connection to MQTT Broker (EMQX).
System:MQTT publish "Macarena" in the topic xiao/boton
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>
// -------- WIFI --------
const char* ssid = "iPhone de Derek";
const char* password = "password";
// -------- MQTT --------
const char* mqttServer = "broker.emqx.io";
const int mqttPort = 1883;
// -------- PINES --------
#define PIN_BOTON D0
#define PIN_KAM D1
#define PIN_RGB D5
#define NUM_LEDS 10
#define LED 23
// -------- OBJETOS --------
WiFiClient esp32Client;
PubSubClient mqttClient(esp32Client);
Adafruit_NeoPixel pixels(NUM_LEDS, PIN_RGB, NEO_GRB + NEO_KHZ800);
// -------- VARIABLES --------
int var = 0;
String resultS = "";
uint32_t pixelHue = 0;
bool lastState = HIGH;
bool before = HIGH;
// -------- WIFI --------
void wifiInit() {
Serial.print("Conectándose a ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("\nConectado a WiFi");
Serial.println(WiFi.localIP());
}
// -------- CALLBACK MQTT --------
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Mensaje recibido [");
Serial.print(topic);
Serial.print("] ");
char payload_string[length + 1];
memcpy(payload_string, payload, length);
payload_string[length] = '\0';
int resultI = atoi(payload_string);
var = resultI;
resultS = "";
for (int i = 0; i < length; i++) {
resultS += (char)payload[i];
}
Serial.println(resultS);
}
// -------- RECONEXIÓN MQTT --------
void reconnect() {
while (!mqttClient.connected()) {
Serial.print("Intentando MQTT...");
String clientId = "Kamilovich-" + String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str())) {
Serial.println("Conectado");
mqttClient.subscribe("fab_test_mine");
} else {
Serial.println(" fallo, reintentando...");
delay(3000);
}
}
}
// -------- SETUP --------
void setup() {
Serial.begin(115200);
pinMode(PIN_BOTON, INPUT_PULLUP);
pinMode(PIN_KAM, INPUT_PULLUP);
pinMode(LED, OUTPUT);
pixels.begin();
pixels.setBrightness(50);
pixels.show();
wifiInit();
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(callback);
}
// -------- LOOP --------
void loop() {
if (!mqttClient.connected()) {
reconnect();
}
mqttClient.loop();
apagarkamil();
leerBoton();
if (var == 0) {
efectoGamer();
}
else if (var == 1) {
efectoRespiracion();
}
}
// -------- BOTÓN --------
void leerBoton() {
bool estado = digitalRead(PIN_BOTON);
if (estado == LOW && lastState == HIGH) {
mqttClient.publish("xiao/boton", "Macarena");
Serial.println("Enviado: Macarena");
delay(50);
}
lastState = estado;
}
// -------- BOTÓN 2 --------
void apagarkamil() {
bool como = digitalRead(PIN_KAM);
if (como == LOW && before == HIGH) {
mqttClient.publish("xiao/boton", "APAGAOS EN NOMBRE DE LO BUENO Y DE LO HONESTO");
Serial.println("Enviado: APAGAOS EN NOMBRE DE LO BUENO Y DE LO HONESTO");
delay(50);
}
before = como;
}
// -------- EFECTO GAMER --------
void efectoGamer() {
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate < 15) return;
for (int i = 0; i < pixels.numPixels(); i++) {
int hueOffset = i * (65536 / pixels.numPixels());
pixels.setPixelColor(i, pixels.gamma32(
pixels.ColorHSV(pixelHue + hueOffset)
));
}
pixels.show();
pixelHue += 256;
lastUpdate = millis();
}
// -------- EFECTO RESPIRACIÓN --------
void efectoRespiracion() {
static int brillo = 0;
static int direccion = 5;
brillo += direccion;
if (brillo <= 0 || brillo >= 255) {
direccion *= -1;
}
for (int i = 0; i < pixels.numPixels(); i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, brillo));
}
pixels.show();
delay(20);
}
Libraries
These libraries enable WiFi connectivity, MQTT communication, and control of NeoPixel LEDs. Together, they allow the system to connect to a network, exchange data, and provide visual feedback through lighting effects.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>
This section defines the WiFi credentials and MQTT broker settings. It allows the device to connect to the internet and communicate with other devices using a publish/subscribe model.
// -------- WIFI --------
const char* ssid = "iPhone de Derek";
const char* password = "password";
// -------- MQTT --------
const char* mqttServer = "broker.emqx.io";
const int mqttPort = 1883;
Pin Definition
This section assigns the physical pins of the microcontroller to specific components such as buttons, LEDs, and the NeoPixel strip.
// -------- PINES --------
#define PIN_BOTON D0
#define PIN_KAM D1
#define PIN_RGB D5
#define NUM_LEDS 10
#define LED 23
Objects Initialization
These objects manage network communication and LED control. They act as interfaces between the hardware and the software logic.
// -------- OBJETOS --------
WiFiClient esp32Client;
PubSubClient mqttClient(esp32Client);
Adafruit_NeoPixel pixels(NUM_LEDS, PIN_RGB, NEO_GRB + NEO_KHZ800);
Global Variables
These variables store incoming data, system states, and control parameters for animations and button detection.
// -------- VARIABLES --------
int var = 0;
String resultS = "";
uint32_t pixelHue = 0;
bool lastState = HIGH;
bool before = HIGH;
WiFi Connection
This function connects the device to the WiFi network and blocks execution until the connection is established.
void wifiInit() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
MQTT Callback
This function processes incoming MQTT messages and converts them into a usable format that controls system behavior.
void callback(char* topic, byte* payload, unsigned int length) {
char payload_string[length + 1];
memcpy(payload_string, payload, length);
payload_string[length] = '\0';
int resultI = atoi(payload_string);
var = resultI;
}
Main Loop
This loop maintains communication, reads inputs, and updates outputs in real time, making the system interactive and responsive.
void loop() {
if (!mqttClient.connected()) {
reconnect();
}
mqttClient.loop();
apagarkamil();
leerBoton();
if (var == 0) {
efectoGamer();
}
else if (var == 1) {
efectoRespiracion();
}
}
XIAO ESP32-C6
Diagram of connections
This diagram represents the wiring of the system powered by a Seeed Studio XIAO ESP32-C6. The red 3.3V line and black GND line form a common power rail that distributes energy to two WS2812B NeoPixels, an OLED display, and a ESP32-WROOM-32 dev module. The green signal line originates from pin D3, passing through a 220Ω resistor (used to protect the data pin from voltage spikes) before reaching the DIN port of the first NeoPixel; the signal then chains from DOUT to the next pixel's DIN. This setup allows the XIAO to act as the controller of the ESP32 and the Neopixels, managing both local visual feedback.
Programming
To code, I used ARDUINO IDE. ARDUINO IDE is a free, open-source application for Windows, macOS, and Linux, used to write, compile, and upload code to Arduino boards. It provides a text editor, toolbar, and serial monitor, supporting C/C++ to create ".ino" sketch files for controlling microcontrollers.
XIAO ESP32-C6 Board
1. First, we have to create a sketch in Arduino IDE.
XIAO ESP32-C6 Board
2. Then, we have go to the board manager and write XIAO. After doing that, a library will appear, its name is Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III, we must install it.
Uploading
3. After installing the XIAO ESP32-C6 Board, we must click on the tab that says select board and write Seeed XIAO ESP32-C6, then select the PORT where our microcontroller is connected and upload the information. We can also click Tools, then Board and then the library Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III and there look for the XIAO. Both ways will let us set our board as a XIAO.
4. Before uploading our code to the microcontroller we should use the verify tool, that compiles the code before uploading it in order to detect mistakes or problems. The verify tool is the one in the top with the check.
5. Finally, to upload our code we must click the upload tool, that is the one with the arrow pointing to the right. If our code is right, it shall compile. To get the , we must click on Tools in the top menu and select Serial Monitor.
My Code
~ Network: WiFi connection to MQTT Broker (EMQX).
~ System: MQTT Callback for "Macarena" mode and Gamer effects.
~ Setup: PIN_BOTON (D0), PIN_RGB (D3), NUM_LEDS (2).
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>
// -------- WIFI --------
const char* ssid = "iPhone de Derek";
const char* password = "9414902012";
// -------- MQTT --------
const char* mqttServer = "broker.emqx.io";
const int mqttPort = 1883;
// -------- PINES --------
#define PIN_BOTON D0
#define PIN_RGB D3
#define NUM_LEDS 2
#define LED 23
// -------- OBJETOS --------
WiFiClient esp32Client;
PubSubClient mqttClient(esp32Client);
Adafruit_NeoPixel pixels(NUM_LEDS, PIN_RGB, NEO_GRB + NEO_KHZ800);
// -------- VARIABLES --------
int var = 0;
String resultS = "";
uint32_t pixelHue = 0;
bool lastState = HIGH;
bool modoMacarena = false;
void wifiInit() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void callback(char* topic, byte* payload, unsigned int length) {
resultS = "";
for (int i = 0; i < length; i++) {
resultS += (char)payload[i];
}
if (String(topic) == "xiao/boton") {
if (resultS == "Macarena") {
modoMacarena = true;
for (int i = 0; i < NUM_LEDS; i++) {
pixels.setPixelColor(i, pixels.Color(255, 0, 0));
}
pixels.show();
} else {
modoMacarena = false;
}
}
var = atoi(resultS.c_str());
}
void reconnect() {
while (!mqttClient.connected()) {
String clientId = "Kamilovich-" + String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str())) {
mqttClient.subscribe("xiao/boton");
} else {
delay(3000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(PIN_BOTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
pixels.begin();
pixels.setBrightness(50);
wifiInit();
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(callback);
}
void loop() {
if (!mqttClient.connected()) { reconnect(); }
mqttClient.loop();
if (!modoMacarena) { efectoGamer(); }
leerBoton();
if (var == 0) { digitalWrite(LED, LOW); }
else if (var == 1) { digitalWrite(LED, HIGH); }
}
void leerBoton() {
bool estado = digitalRead(PIN_BOTON);
if (estado == LOW && lastState == HIGH) {
mqttClient.publish("xiao/boton", "Macarena");
delay(200);
}
lastState = estado;
}
void efectoGamer() {
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate < 15) return;
for (int i = 0; i < pixels.numPixels(); i++) {
int hueOffset = i * (65536 / pixels.numPixels());
pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue + hueOffset)));
}
pixels.show();
pixelHue += 256;
lastUpdate = millis();
}
Neopixels code
if (String(topic) == "xiao/boton") {
if (resultS == "Macarena") {
modoMacarena = true;
for (int i = 0; i < NUM_LEDS; i++) {
pixels.setPixelColor(i, pixels.Color(255, 0, 0));
}
pixels.show();
} else {
modoMacarena = false;
}
}
Macarena.This code processes incoming messages from an MQTT topic to trigger a specific lighting state. When the topic xiao/boton receives the string Macarena, it sets the boolean message modoMacarena to true and executes a for loop that iterates through every Neopixel in the strip, assigning each a solid red color using the pixels.setPixelColor(index, color) function with RGB values of (255, 0, 0). The pixels.show() command is then called to push this data from the microcontroller to the actual hardware, instantly illuminating the strip. If any other message is received, the mode is disabled, and the final line converts the incoming string into an integer using atoi() to maintain compatibility with a secondary Neopixel control on pin 23.
void loop() {
if (!mqttClient.connected()) { reconnect(); }
mqttClient.loop();
if (!modoMacarena) { efectoGamer(); }
leerBoton();
if (var == 0) { digitalWrite(LED, LOW); }
else if (var == 1) { digitalWrite(LED, HIGH); }
}
!Macarena.The loop() function acts as the central execution hub for the system, continuously ensuring that the connection to the MQTT broker is active by calling reconnect() whenever the client is disconnected. It maintains background MQTT processes through mqttClient.loop() and conditionally executes the efectoGamer() LED sequence only if the modoMacarena flag is false, effectively allowing external commands to override the default visual behavior. Finally, it monitors physical input via leerBoton() and performs real-time hardware control by toggling the state of a specific LED pin based on the value of the var variable received from the network.
void efectoGamer() {
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate < 15) return;
for (int i = 0; i < pixels.numPixels(); i++) {
int hueOffset = i * (65536 / pixels.numPixels());
pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue + hueOffset)));
}
pixels.show();
pixelHue += 256;
lastUpdate = millis();
}
efectoGamer(). function implements a non-blocking rainbow animation by utilizing millis() to track elapsed time, allowing the sequence to update every 15 milliseconds without halting the program. It uses pixels.numPixels() to scale calculations across the hardware, while pixels.setPixelColor() assigns colors generated by pixels.ColorHSV() to each LED. These colors are processed through pixels.gamma32() to correct for human light perception, ensuring a naturally vibrant look. To complete the cycle, pixels.show() pushes the data to the LEDs, pixelHue increments by 256 to shift the spectrum, and lastUpdate resets the timing gate to maintain a consistent animation speed.
Neopixels Library
To set the neopixels, we first need to install the library in Arduino. For that we have to go to the Library Manager and write Adafruit Neopixel, then intall the library named like that.
ESP32 WROOM 32
Diagram of connections
This diagram shows the I2C communication setup between an ESP32-WROOM-32 development board and an OLED display. The blue line connects the SDA (Serial Data) pin of the OLED to GPIO 21 on the ESP32, while the yellow line connects the SCL (Serial Clock) pin to GPIO 22. These two pins are the standard hardware I2C default for the ESP32, allowing the microcontroller to send graphical data and text to the screen using a synchronous serial protocol.
Programming
To code, I used ARDUINO IDE. ARDUINO IDE is a free, open-source application for Windows, macOS, and Linux, used to write, compile, and upload code to Arduino boards. It provides a text editor, toolbar, and serial monitor, supporting C/C++ to create ".ino" sketch files for controlling microcontrollers.
ESP32
1. First, we have to create a sketch in Arduino IDE.
ESP32
2. Then, we have go to the board manager and write ESP32. After doing that, a library will appear, its name is esp32 by Espressif Systems, we must install it.
Uploading
3. After installing the ESP32 Board, we must click on the tab that says select board and write ESP32 Dev Module, then select the PORT where our microcontroller is connected and upload the information.
4. Before uploading our code to the microcontroller we should use the verify tool, that compiles the code before uploading it in order to detect mistakes or problems. The verify tool is the one in the top with the check.
5. Finally, to upload our code we must click the upload tool, that is the one with the arrow pointing to the right. If our code is right, it shall compile. To get the , we must click on Tools in the top menu and select Serial Monitor.
My Code
~ Device: ESP32-WROOM-32 Receiver.
~ Display: SSD1306 OLED via I2C (SDA: 21, SCL: 22).
~ Action: Real-time visualization of messages from topic xiao/boton.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// -------- CONFIGURACIÓN OLED --------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// -------- WIFI & MQTT --------
const char* ssid = "iPhone de Derek";
const char* mqttServer = "broker.emqx.io";
WiFiClient esp32Client;
PubSubClient mqttClient(esp32Client);
void actualizarOLED(String mensaje) {
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.println(mensaje);
display.display();
}
void callback(char* topic, byte* payload, unsigned int length) {
String mensaje = "";
for (int i = 0; i < length; i++) { mensaje += (char)payload[i]; }
actualizarOLED(mensaje);
}
void reconnect() {
while (!mqttClient.connected()) {
String clientId = "Kamo_Display_" + String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str())) {
mqttClient.subscribe("xiao/boton");
} else { delay(3000); }
}
}
void setup() {
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { for(;;); }
display.clearDisplay();
actualizarOLED("Esperando WiFi...");
wifiInit();
mqttClient.setServer(mqttServer, 1883);
mqttClient.setCallback(callback);
}
void loop() {
if (!mqttClient.connected()) { reconnect(); }
mqttClient.loop();
}
OLED code
void actualizarOLED(String mensaje) {
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.println(mensaje);
display.display();
}
actualizarOLED(). The actualizarOLED() function manages the physical rendering of data on the display by first executing display. clearDisplay() to wipe the existing buffer, preventing new text from overlapping with old pixels. It then prepares the visual layout by resetting the text "anchor" to the top-left corner with display. setCursor(0, 0), setting the font scale via display. setTextSize(1), and defining the pixel state with display. setTextColor(SSD1306_WHITE). After the string is written to the internal memory buffer using display. println(mensaje), the function calls display.display(), which is the critical final step that pushes the processed data from the ESP32’s RAM to the OLED hardware, making the message visible to the user.
void callback(char* topic, byte* payload, unsigned int length) {
String mensaje = "";
for (int i = 0; i < length; i++) { mensaje += (char)payload[i]; }
actualizarOLED(mensaje);
}
callback().The callback() function serves as the system's message processor, automatically triggering whenever a new message is received from the subscribed MQTT topic. It begins by initializing an empty string and using a for loop to iterate through the incoming payload, casting each byte into a character to reconstruct the full text message. Once the loop finishes and the complete mensaje is assembled, the function immediately passes this string to actualizarOLED(), ensuring that the hardware display is updated in real-time with the data received from the network.
Adafruit Library
To set the OLED, we first need to install the library in Arduino. For that we have to go to the Library Manager and write Adafruit GFX and the Adafruit SSD1306, then intall the library named like that.
Results
Learning outcomes
This week, I learned a great deal about communication systems and how devices can exchange information with one another. One of the most important things I learned was how to establish communication between different boards using MQTT and a broker. Through this process, I gained a better understanding of how messages are transmitted, received, and managed within a network of connected devices.
I also continued working with an I2C OLED display, which helped me improve my understanding of communication protocols and device addressing. In addition, I kept experimenting with NeoPixels, learning more about how to control their lighting effects and synchronize them with incoming data.
Overall, this week helped me strengthen my knowledge of embedded systems, wireless communication, and hardware integration by combining multiple technologies into a single project.