Week 11
This is my 11 week at Fab Academy, this week I was learning about netwroking and communications. The assignment of the week consisted of:
individual assignment: design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device(s) group assignment: send a message between two projects
Individual Assignment
Regarding the individual part of the work, I implemented a networking system to generate a server in one XIAO ESP32C3 that reads ambient moisture and temperature (DHT 11 sensor), uploads this information into a website, and then a second XIAO ESP32C3 connects to the generated WiFi netwok, reads the temperature and moisture and plots it into an OLED screen.
First I implemented the DHT moisture and temperature reading algorithm to make sure that the XIAO is properly measuring temperature and moisture, this is how it looks like:
#include <DHT.h>
#define DHTPIN D5 //
#define DHTTYPE DHT11 //
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin(); //
}
void loop() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Error of reading DHT11");
return;
}
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" °C");
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.println(" %");
delay(1000);
}
Once, that was done, I first implemented a simple code for generating the server in the first Xiao ESP32. For that I just used the code of the Server example in Arduino IDE setting up a specific name and password for my server. Also I included a part for implementing the temperature and moisture reading in the code:
#include <WiFi.h>
#include <DHT.h>
#include <Preferences.h>
// Wi-Fi configuration
const char *ssid = "wifi_pablo";
const char *password = "12345678";
// Initialize server on port 80
WiFiServer server(80);
// DHT11 sensor
#define DHTPIN D10
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// For optional saved configuration
Preferences preferences;
void setup() {
Serial.begin(115200);
delay(1000);
// Initialize WiFi as Access Point
WiFi.softAP(ssid, password);
Serial.println("✅ Wi-Fi Access Point created");
IPAddress myIP = WiFi.softAPIP();
Serial.print("📡 Server IP: ");
Serial.println(myIP);
server.begin();
Serial.println("✅ Web server started");
// Initialize DHT sensor
dht.begin();
Serial.println("🌡 DHT11 sensor started");
}
void loop() {
// Wait for clients
WiFiClient client = server.available();
if (client) {
Serial.println("👤 Client connected");
String request = "";
while (client.connected()) {
if (client.available()) {
char c = client.read();
request += c;
if (c == '\n') break; // end of HTTP request
}
}
// Read temperature and humidity
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Check if the reading is valid
bool dataValid = !(isnan(temperature) || isnan(humidity));
// Send HTTP response
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// HTML with auto-refresh every 1 second
client.println("<!DOCTYPE html><html>");
client.println("<head>");
client.println("<meta charset='UTF-8'>");
client.println("<meta http-equiv='refresh' content='3'>"); // <-- Auto-refresh
client.println("<title>DHT11 - Data</title>");
client.println("</head>");
client.println("<body>");
client.println("<h1>DHT11 Sensor Reading</h1>");
if (dataValid) {
client.print("<p><strong>Temperature:</strong> ");
client.print(temperature);
client.println(" °C</p>");
client.print("<p><strong>Humidity:</strong> ");
client.print(humidity);
client.println(" %</p>");
} else {
client.println("<p><strong>Error:</strong> Could not read from DHT11 sensor</p>");
}
client.println("</body></html>");
client.stop();
Serial.println("🚪 Client disconnected");
delay(100); // small pause to avoid overload
}
delay(500); // smoother loop
}
To verify that it was properly working, I connected my movile phone to the generated Wifi using the aforementioned password. Then I browsed the corresponding IP address which is the one used by deafult in the server example, this worked fine and here you can see a capture from the network working when I connected to it from my phone:
Once that was working I started working in the client to read the temperature and moisture and plot it in an OLED screen. To achieve it I encountered several issues. In the following I summarize the process I followed until reaching the solution:
- Initial Problem Setup: Objective: You were trying to read the temperature and humidity values from a DHT11 sensor connected to an ESP32 and display the results on a serial monitor.
The ESP32 is set up to send HTTP requests to a server that provides temperature and humidity data.
The web server, when queried, provides an HTML response with the temperature and humidity values.
- Issues Encountered: Incorrect or Null Values: When the ESP32 received the response from the server, the displayed temperature and humidity values were incorrect (showing 0.00 for both).
The expected behavior was that the sensor’s readings would be reflected on the serial monitor based on the server’s HTML response, but initially, there was a mismatch between the server’s data and the values shown in the serial output.
- Troubleshooting and Solution: Then I began by checking the server’s response to ensure the HTML format and the sensor data (temperature and humidity) were being transmitted correctly.
Upon inspecting the HTML response from the server, I observed that the data was being displayed in a simple HTML format:
html Copiar Editar
Temperature: 25.40 °C
Moisture: 71.00 %
The values for temperature (25.40°C) and humidity (71.00%) were correctly present in the response.- Correct Parsing: I corrected the parsing logic on the ESP32 side to ensure that the temperature and humidity values could be extracted from the HTML content properly.
Initially, it seemed that the values were not being extracted correctly, as shown by the repeated 0.00 outputs for both temperature and humidity.
After ensuring the code correctly searches for the patterns in the HTML (“Temperature:” and “Humidity:”), the ESP32 could then correctly extract and store the temperature and humidity values.
I added specific parsing logic to identify and correctly extract the numeric values for temperature and humidity by locating the strings in the HTML and extracting the values that follow them.
- Final Outcome: After implementing the necessary parsing logic, the ESP32 successfully connected to the server and received the correct temperature and humidity values.
The extracted values were then displayed correctly on the serial monitor. For example:
Temperature: 26.80°C
Humidity: 71.00%
This confirmed that the communication between the ESP32 and the server was working correctly, and the data was being parsed and displayed as expected.
- Additional Steps: The server was set to refresh every 3 seconds, providing updated data in real-time.
The ESP32 successfully handled the repeated requests to the server and updated the displayed values accordingly.
Conclusion: Through this process, I identified and resolved the issue of retrieving correct temperature and humidity data from the web server. By refining the parsing logic, I ensured that the correct values (temperature: 26.80°C, humidity: 71.00%) were extracted and displayed on the serial monitor. The server and ESP32 setup are now working as expected, and the data is being refreshed periodically as intended.
Here you can see the resulting code for creating the server afther the aforementioned corrections:
#include <WiFi.h>
#include <DHT.h>
#include <Preferences.h>
// Wi-Fi configuration
const char *ssid = "wifi_pablo";
const char *password = "12345678";
// Initialize server on port 80
WiFiServer server(80);
// DHT11 sensor
#define DHTPIN D10
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// For optional saved configuration
Preferences preferences;
void setup() {
Serial.begin(115200);
delay(1000);
// Initialize WiFi as Access Point
WiFi.softAP(ssid, password);
Serial.println("✅ Wi-Fi Access Point created");
IPAddress myIP = WiFi.softAPIP();
Serial.print("📡 Server IP: ");
Serial.println(myIP);
server.begin();
Serial.println("✅ Web server started");
// Initialize DHT sensor
dht.begin();
Serial.println("🌡 DHT11 sensor started");
}
void loop() {
// Wait for clients
WiFiClient client = server.available();
if (client) {
Serial.println("👤 Client connected");
String request = "";
while (client.connected()) {
if (client.available()) {
char c = client.read();
request += c;
if (c == '\n') break; // end of HTTP request
}
}
// Read temperature and humidity
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Check if the reading is valid
bool dataValid = !(isnan(temperature) || isnan(humidity));
// Send HTTP response
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// HTML with auto-refresh every 1 second
client.println("<!DOCTYPE html><html>");
client.println("<head>");
client.println("<meta charset='UTF-8'>");
client.println("<meta http-equiv='refresh' content='3'>"); // <-- Auto-refresh
client.println("<title>DHT11 - Data</title>");
client.println("</head>");
client.println("<body>");
client.println("<h1>DHT11 Sensor Reading</h1>");
if (dataValid) {
client.print("<p><strong>Temperature:</strong> ");
client.print(temperature);
client.println(" °C</p>");
client.print("<p><strong>Humidity:</strong> ");
client.print(humidity);
client.println(" %</p>");
} else {
client.println("<p><strong>Error:</strong> Could not read from DHT11 sensor</p>");
}
client.println("</body></html>");
client.stop();
Serial.println("🚪 Client disconnected");
delay(100); // small pause to avoid overload
}
delay(500); // smoother loop
}
And here you can see the code used for the client to connect:
#include <WiFi.h>
#include "esp_system.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const char* ssid = "wifi_pablo";
const char* password = "12345678";
const char* serverIP = "192.168.4.1";
const int serverPort = 80;
const int maxReconnectAttempts = 5;
WiFiClient client;
bool keepReading = true;
void connectToWiFi() {
Serial.println("Connecting to AP...");
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
attempts++;
if (attempts >= maxReconnectAttempts) {
Serial.println("\n⚠ Failed to connect to AP after several attempts.");
while (true);
}
}
Serial.println("\n✅ Connected to AP");
}
bool connectToServer() {
Serial.println("Trying to connect to server...");
int attempts = 0;
while (!client.connect(serverIP, serverPort)) {
Serial.print(".");
delay(1000);
attempts++;
if (attempts >= maxReconnectAttempts) {
Serial.println("\n⚠ Failed to connect to the server.");
return false;
}
}
Serial.println("✅ Connected to the server");
return true;
}
void drawBarGraph(float temperature, float humidity) {
display.clearDisplay();
// Labels
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("T: ");
display.print(temperature);
display.println(" C");
display.setCursor(0, 10);
display.print("H: ");
display.print(humidity);
display.println(" %");
// Simple scaling (you can adjust these factors)
int tempBar = map(temperature, 0, 50, 0, 100);
int humBar = map(humidity, 0, 100, 0, 100);
// Bars
display.fillRect(70, 0, 10, tempBar, SSD1306_WHITE); // temperature
display.fillRect(90, 0, 10, humBar, SSD1306_WHITE); // humidity
// Bar borders
display.drawRect(70, 0, 10, 50, SSD1306_WHITE);
display.drawRect(90, 0, 10, 50, SSD1306_WHITE);
display.display();
}
void loop() {
while (keepReading) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠ WiFi connection lost. Reconnecting...");
connectToWiFi();
}
if (!connectToServer()) {
delay(2000);
continue;
}
client.println("GET / HTTP/1.1");
client.println("Host: 192.168.4.1");
client.println("Connection: close");
client.println();
String responseFull = "";
unsigned long startTime = millis();
while (client.connected() && millis() - startTime < 3000) {
while (client.available()) {
String line = client.readStringUntil('\n');
responseFull += line;
}
}
client.stop();
// Debug: Print full server response
//Serial.println("Full server response:");
//Serial.println(responseFull);
// Search for temperature
float temperature = -1;
int tempStart = responseFull.indexOf("<strong>Temperatura:</strong>");
if (tempStart != -1) {
int tempValueStart = responseFull.indexOf(">", tempStart) + 1;
int tempValueEnd = responseFull.indexOf("°C", tempValueStart);
if (tempValueStart != -1 && tempValueEnd != -1) {
String tempStr = responseFull.substring(tempValueStart, tempValueEnd);
Serial.print("Temperature found: ");
Serial.println(tempStr); // Show found value
tempStr.trim(); // Remove extra spaces
// Extract only the numeric part
int numberStart = tempStr.indexOf(' ') + 1; // Find the space to separate the number
tempStr = tempStr.substring(numberStart); // Extract only the numeric part
temperature = tempStr.toFloat();
}
}
// Search for humidity
float humidity = -1;
int humStart = responseFull.indexOf("<strong>Humedad:</strong>");
if (humStart != -1) {
int humValueStart = responseFull.indexOf(">", humStart) + 1;
int humValueEnd = responseFull.indexOf("%", humValueStart);
if (humValueStart != -1 && humValueEnd != -1) {
String humStr = responseFull.substring(humValueStart, humValueEnd);
Serial.print("Humidity found: ");
Serial.println(humStr); // Show found value
humStr.trim(); // Remove extra spaces
// Extract only the numeric part
int numberStart = humStr.indexOf(' ') + 1; // Find the space to separate the number
humStr = humStr.substring(numberStart); // Extract only the numeric part
humidity = humStr.toFloat();
}
}
// If both values are valid, show them on screen
if (temperature != -1 && humidity != -1) {
Serial.print("🌡 Temp: ");
Serial.print(temperature);
Serial.print(" C, 💧 Hum: ");
Serial.print(humidity);
Serial.println(" %");
drawBarGraph(temperature, humidity);
} else {
Serial.println("⚠ Invalid data received");
}
delay(1000);
if (Serial.available()) {
char input = Serial.read();
if (input == 'E' || input == 'e') {
Serial.println("\n🛑 Input 'E' detected. Stopping readings.");
keepReading = false;
break;
}
}
}
Serial.println("\nDone. No more requests will be made.");
while (true);
}
void setup() {
Serial.begin(115200);
delay(1000);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("⚠ OLED screen not detected"));
while (true);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Fabacademy 2025");
display.setCursor(0, 10);
display.println("Pablo Guindos");
display.display();
connectToWiFi();
}
Here you can see the videos capturing my work in the networking, the second XIAO is retrieving the temperature and moisture reading from the first XIAO:
Group Assignment
Regarding the group assignment, along with my colleagues we mixed two projects. Pepe was implementing a network for reading the weights of some balances and we used this as server. As second microcontroller, we used my project as I previously implemented a code for moving a servo, therefore we used this as client and moved the servo according to the weight reading of the server. Here in this link you can see all the details:
https://fabacademy.org/2025/labs/aindustriosa/week11.html
Files for download and replication
Here you can download the ino files of the Server and Client of my networking and communication project.