Skip to content

week11. Networking and Communications

Assignment

Group assignment

  • send a message between two projects

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

For more information about group projects, please see the group project page on the FabLab Kannai website. Group assignment page is here

🌐 Networked Communication Between Microcontroller and Web Server

This assignment explores the implementation of a wireless network node using XIAO ESP32-C3 that communicates with a remote server and displays data in a browser via real-time web protocols.

Building on the foundation from the week4 assignment page, the microcontroller is now mounted on the custom development board created in week8, and functions as part of a networked system that retrieves data from an external API and transmits it to a browser via a server pipeline.

This application was inspired by Fab Academy 2021's Nadieh, and showcases real-time communication between an embedded device and web client.

1. Node Design and Network Integration

  • The XIAO ESP32-C3 functions as a wireless network node by connecting to a Wi-Fi network and obtaining an IP address.

  • It acts as a client that fetches data (a joke) from a public API over HTTP.

  • Communication is established through a multi-stage data pipeline:

    ESP32-C3 → Wi-Fi (HTTP) → Serial → Node.js → Socket.IO → Browser

┌──────────────────────┐
│   Joke API (Cloud)   │
│ https://official...  │
└────────────┬─────────┘
             │ HTTP GET

┌──────────────────────┐
│  ESP32-C3 (Wi-Fi)     │
│  - Retrieves Joke     │
│  - Outputs via UART   │
└────────────┬─────────┘
             │ Serial (USB)

┌──────────────────────┐
│ Node.js Server        │
│ - Reads serial input  │
│ - Emits via Socket.IO │
└────────────┬─────────┘
             │ WebSocket

┌──────────────────────┐
│   Web Browser (UI)    │
│ - Displays joke       │
└──────────────────────┘

2. Data Transmission Behavior

  • The microcontroller sends an HTTP request every 15 seconds to obtain new data from an external API.
  • The received data is sent through its serial interface to a Node.js server.
  • The server then emits the message to connected clients using WebSocket-style communication (via Socket.IO).

output1.jpg

JavaScript and Socket Communication

JavaScript is used on the client side to receive real-time updates from the Node.js server and update the browser view without refreshing the page. This showcases a dynamic web communication model.

Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript

Node.js and WebSocket Pipeline

Node.js enables server-side event-driven programming. In this project, it acts as the intermediary that receives data from the microcontroller (via serial) and relays it to the browser using socket.io.

Reference:
https://nodejs.org/en/

Server Setup (macOS)

brew install node
npm install
node index.js

🧩 System Structure

realtime-communication/
├── node_modules/
├── public/
│   └── index.html      # Web interface
├── index.js            # Node.js server (receives & emits data)
├── package.json
├── package-lock.json

🖥 Node.js server (index.js)

This server listens on a serial port for incoming data from the microcontroller and broadcasts it to all connected browser clients.

const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const { SerialPort } = require("serialport");
const { ReadlineParser } = require("@serialport/parser-readline");

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

app.use(express.static("public"));

async function findAndConnectSerialPort() {
  try {
    const ports = await SerialPort.list();

    const targetPort = ports.find((port) => {
      return (
          port.path.includes("usbmodem") || // macOS
          port.path.includes("usbserial")   // Windows/Linux fallback
      );
    });

    if (!targetPort) {
      console.error("No compatible serial port found.");
      return;
    }

    console.log(`✅ Found serial port: ${targetPort.path}`);

    const port = new SerialPort({ path: targetPort.path, baudRate: 9600 });
    const parser = port.pipe(new ReadlineParser({ delimiter: "\n" }));

    parser.on("data", (data) => {
      const trimmed = data.trim();
      console.log("Received:", trimmed);
      io.emit("joke", trimmed);
    });

    port.on("error", (err) => {
      console.error("SerialPort Error:", err.message);
    });
  } catch (err) {
    console.error("Failed to list serial ports:", err);
  }
}

server.listen(3000, () => {
  console.log("Server running at http://localhost:3000");
  findAndConnectSerialPort();
});

🌐 Browser Client (index.html)

This file implements the real-time front-end logic that receives the joke from the server and updates the UI.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Joke Viewer</title>
  <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
  <style>
    body {
      font-family: sans-serif;
      background-color: #CEE6C1;
      text-align: center;
      padding: 50px;
    }

    h1 {
      font-size: 2rem;
    }

    #joke {
      font-size: 1.5rem;
      margin-top: 30px;
      color: #333;
      padding: 20px;
      border: 2px solid #eee;
      background: #fff;
      display: inline-block;
      max-width: 600px;
      white-space: pre-wrap;
      word-wrap: break-word;
      text-align: left;
    }
  </style>
</head>
<body>
<h1>🤣 Live Joke Display</h1>
<div id="joke">Waiting for joke...</div>

<script>
  const socket = io();
  socket.on("joke", (data) => {
    document.getElementById("joke").textContent = data;
  });
</script>
</body>
</html>

📡 ESP32-C3 Code: Wireless Node Behavior

This microcontroller program:

  • connects to Wi-Fi
  • accesses a cloud API every 15 seconds
  • and relays the fetched content to a connected computer over the serial line.
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// Wi-Fi Configuration
const char* ssid = "*******";
const char* password = "*******";

// Joke API
const String url = "https://official-joke-api.appspot.com/random_joke";

// Joke acquisition interval (milliseconds)
const unsigned long interval = 15000;  // 15 sec.
unsigned long lastFetchTime = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Booting...");

  Serial.println("Connecting to WiFi...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // Get the first joke right away
  lastFetchTime = millis() - interval;
}

void loop() {
  unsigned long currentTime = millis();
  if (currentTime - lastFetchTime >= interval) {
    lastFetchTime = currentTime;
    String joke = getJoke();
    Serial.println(joke);
  }
}

String getJoke() {
  Serial.println("Fetching joke...");
  HTTPClient http;
  http.useHTTP10(true);
  http.begin(url);
  int httpCode = http.GET();

  if (httpCode <= 0) {
    Serial.print("HTTP error: ");
    Serial.println(httpCode);
    http.end();
    return "<HTTP error>";
  }

  String result = http.getString();
  http.end();

  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, result);

  if (error) {
    Serial.print("JSON parse error: ");
    Serial.println(error.c_str());
    return "<parse error>";
  }

  String setup = doc["setup"].as<String>();
  String punchline = doc["punchline"].as<String>();

  return setup + " / " + punchline;
}

Communication Flow Demonstration

The following video shows the ESP32-C3 functioning as a wireless communication node: retrieving data, transmitting it through a Node.js server, and displaying it in the browser in real time.

Afterthoughts

  • This week's focus on networking and communication allowed me to build a full pipeline from microcontroller to web client.
  • While it began as an output device experiment, it evolved into a system with layered data transmission, protocol bridging, and network awareness.
  • The ESP32-C3 served as a capable networked node, showcasing how microcontrollers can participate in modern data systems.