Networking &
Communications
Building a complete multi-tier IoT network architecture with wireless communication, protocol translation, and cloud integration for the SmartPi Agentic Assistant.
- Individual Assignment: Design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device(s).
01 · System Overview
For my assignment, I implemented a multi-tier wireless network architecture as part of my SmartPi Agentic Assistant final project. The system demonstrates several key networking concepts: wireless communication via Wi-Fi (802.11), network addressing and routing, HTTP/REST API design, JSON-based message protocols, and multi-node architecture with distinct responsibilities.
Three-Node Architecture
My implementation consists of three networked nodes forming a complete IoT system:
- Node 1: Raspberry Pi Pico W (wireless embedded device) — HTTP server at
10.0.0.230:5000with LED matrix and audio output - Node 2: MCP Bridge Server (wired/wireless gateway) — HTTP/MCP server at
0.0.0.0:5055for protocol translation - Node 3: n8n Workflow Automation (cloud/local service) — Automated agent that generates and routes messages
Each node has a unique network address, communicates via standard protocols (HTTP/JSON), and integrates both input (HTTP API) and output (display, audio) devices.
SmartPi Three-Tier Network Architecture
┌──────────────────────────────────────────────────────────────┐
│ Cloud / Internet Layer │
│ ┌────────────────────────────────────────────────────┐ │
│ │ n8n Workflow Engine │ │
│ │ • Gmail API (email input) │ │
│ │ • Google Calendar API (calendar events) │ │
│ │ • OpenWeather API (weather data) │ │
│ │ • Gemini LLM (message generation) │ │
│ └────────────────────┬───────────────────────────────┘ │
└─────────────────────────┼────────────────────────────────────┘
│ HTTPS POST (via NGROK tunnel)
│ JSON payload
▼
┌──────────────────────────────────────────────────────────────┐
│ Local Network / Gateway Layer │
│ ┌────────────────────────────────────────────────────┐ │
│ │ MCP Bridge Server (Python FastAPI) │ │
│ │ Address: 0.0.0.0:5055 │ │
│ │ • MCP protocol handler │ │
│ │ • Message state management │ │
│ │ • Multi-message queuing │ │
│ └────────────────────┬───────────────────────────────┘ │
└─────────────────────────┼────────────────────────────────────┘
│ HTTP POST
│ Local Wi-Fi (802.11 2.4GHz)
▼
┌──────────────────────────────────────────────────────────────┐
│ Embedded Device Layer │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Raspberry Pi Pico W (CircuitPython) │ │
│ │ Address: 10.0.0.230:5000 │ │
│ │ • HTTP server (adafruit_httpserver) │ │
│ │ • Message queue management │ │
│ │ • Output: 64x64 LED matrix (HUB75) │ │
│ │ • Output: I²S audio amplifier (MAX98357) │ │
│ │ • Input: I²S microphone (ICS-43434) │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
- n8n workflow aggregates data from multiple cloud APIs
- Gemini LLM processes and formats messages with theme and priority
- n8n sends JSON payload via HTTPS to NGROK tunnel → Bridge Server
- Bridge Server validates, queues, and forwards messages via HTTP
- Pico W receives messages, updates display and plays audio alerts
02 · Node 1: Raspberry Pi Pico W
Hardware Platform
The Raspberry Pi Pico W serves as the primary embedded wireless node. It integrates the CYW43438 radio chip for 2.4 GHz 802.11n Wi-Fi connectivity, making it an ideal platform for IoT applications requiring wireless communication.
| Component | Specification | Purpose |
|---|---|---|
| Microcontroller | RP2040 (Dual-core ARM Cortex-M0+, 133 MHz) | Main processing and firmware execution |
| Wireless Radio | CYW43438 (802.11n, 2.4 GHz Wi-Fi + Bluetooth) | Network connectivity |
| Network Address | 10.0.0.230:5000 | Static IP assigned by DHCP, HTTP server port |
| Protocol Stack | TCP/IP, HTTP/1.1, JSON | Application-level communication |
| Firmware Platform | CircuitPython 10.0.3 | High-level Python for rapid development |
Network Configuration
The Pico W connects to the local Wi-Fi network using credentials stored in a secrets.py
file. Upon boot, it establishes a connection and starts an HTTP server to listen for incoming
messages.
# Network Initialization (main.py)
import wifi
import socketpool
import adafruit_httpserver
# Connect to Wi-Fi
wifi.radio.connect(secrets["ssid"], secrets["password"])
print(f"Connected to {secrets['ssid']}")
print(f"IP Address: {wifi.radio.ipv4_address}")
# Create socket pool and HTTP server
pool = socketpool.SocketPool(wifi.radio)
server = adafruit_httpserver.Server(pool, "/", debug=True)
REST API Endpoints
The Pico W exposes three HTTP endpoints for message management:
| Endpoint | Method | Purpose | Payload |
|---|---|---|---|
| /messages | POST | Receive new messages for display | JSON array of message objects |
| /status | GET | Query device status and queue size | None |
| /clear | POST | Clear all queued messages | None |
{
"messages": [
{
"text": "Meeting at 10:30AM with John",
"theme": "calendar",
"priority": "urgent"
},
{
"text": "72°F Partly cloudy - Enjoy!",
"theme": "weather",
"priority": "normal"
}
],
"timestamp": "2025-11-16T23:00:00Z"
}
Theme codes: calendar, email, weather, slack, neutral
Priority levels: urgent, important, normal
Local Output Devices
The Pico W controls two primary output devices connected via different interfaces:
1. 64×64 RGB LED Matrix (HUB75 Interface)
- Interface: Parallel digital interface using 13 GPIO pins
- Protocol: HUB75 (R1, G1, B1, R2, G2, B2, A, B, C, D, CLK, LAT, OE)
- Address Lines: 4-bit addressing (A, B, C, D) for row selection
- Display Buffer: Direct memory-mapped pixel data
- Refresh Rate: ~60 Hz via PWM for brightness control
2. I²S Audio Amplifier (MAX98357)
- Interface: I²S (Inter-IC Sound) digital audio bus
- Pins: DIN (GP18), BCLK (GP19), LRCLK (GP20)
- Sample Rate: 16 kHz for voice alerts
- Protocol: Synchronous serial audio (left/right channel, bit clock)
Message Display Logic
The firmware implements a priority-based message queue with filtering:
# Priority Filtering (main.py)
MSG_PRIORITY = "normal" # Configuration: urgent, important, or normal
def _should_display_message(msg_priority):
priority_levels = {"urgent": 2, "important": 1, "normal": 0}
filter_level = priority_levels.get(MSG_PRIORITY, 0)
msg_level = priority_levels.get(msg_priority, 0)
return msg_level >= filter_level # Display if priority meets threshold
# Display with theme+priority prefix
def show_message(text, theme="neutral", priority="normal"):
theme_code = _get_theme_code(theme) # E, C, W, S, N
priority_code = _get_priority_code(priority) # U, I, N
prefix = f"{theme_code}{priority_code} "
display_text(prefix + text) # e.g., "EU Meeting canceled"
03 · Node 2: MCP Bridge Server
Purpose and Architecture
The MCP Bridge Server acts as a protocol translator and message broker between cloud services (n8n) and the embedded device (Pico W). It implements the Model Context Protocol (MCP) for standardized tool invocation and maintains message state for each theme (email, weather, calendar).
Network Configuration
| Parameter | Value | Description |
|---|---|---|
| Host Address | 0.0.0.0:5055 | Listens on all interfaces, port 5055 |
| Target Device | http://10.0.0.230:5000 | Pico W endpoint on local network |
| External Access | NGROK tunnel (HTTPS) | Secure public endpoint for cloud services |
| Protocol | HTTP/JSON + MCP | RESTful API with MCP tool schema |
MCP Protocol Implementation
The server exposes three MCP tools that cloud agents (like n8n) can invoke:
# MCP Tool Invocation Format
POST http://bridge-address:5055/mcp
Content-Type: application/json
{
"tool": "push_messages",
"args": {
"messages": [
{"text": "...", "theme": "email", "priority": "urgent"},
{"text": "...", "theme": "calendar", "priority": "important"}
],
"timestamp": "2025-11-16T23:00:00Z"
}
}
Multi-Message State Management
The bridge server maintains separate queues for each message theme, storing up to 10 messages per theme. This solves the problem of message loss when multiple messages arrive in a single batch.
# State Management (smartpi_mcp_server.py)
# In-memory state: lists of messages per theme
current_messages = {
"email": [], # Up to 10 email messages
"weather": [], # Up to 10 weather messages
"calendar": [] # Up to 10 calendar messages
}
# Append new messages (not overwrite)
for msg in incoming_messages:
theme = msg.get("theme")
current_messages[theme].append(msg)
# Limit per theme (FIFO queue)
if len(current_messages[theme]) > MAX_MESSAGES_PER_THEME:
current_messages[theme].pop(0) # Remove oldest
# Flatten and send all messages to Pico W
all_messages = []
for theme_list in current_messages.values():
all_messages.extend(theme_list)
send_to_device("/messages", {"messages": all_messages})
04 · Node 3: n8n Workflow Engine
Cloud Integration
The n8n workflow engine serves as the third node in the network, aggregating data from multiple cloud APIs and using LLMs to generate formatted messages for the SmartPi display.
Data Sources
- Gmail API: Fetches unread emails from 3 accounts (personal, work, eGov)
- Google Calendar API: Retrieves today's events from 3 calendars
- OpenWeather API: Gets current weather for Cambridge, MA
- Gemini LLM: Processes raw data and generates concise 55-character alerts
Network Communication
The workflow sends HTTP POST requests to the bridge server via an NGROK secure tunnel:
# n8n HTTP Request Node Configuration
Method: POST
URL: https://scenic-tien-piratical.ngrok-free.dev/mcp
Headers:
Content-Type: application/json
ngrok-skip-browser-warning: true
Body (JSON):
{
"tool": "push_messages",
"args": {{ $json.toJsonString() }}
}
Parallel Processing Architecture
The workflow runs three independent parallel tracks (calendar, weather, email), each ending in a separate HTTP request to the bridge server. This ensures that slow data sources don't block others.
- Trigger: Scheduled (hourly for calendar/weather, every 30 min for email)
- Data Collection: Fetch from APIs in parallel
- Merge: Combine results per data source
- LLM Processing: Gemini generates formatted alerts
- JavaScript Transform: Parse LLM output, extract theme/priority
- Send to Bridge: HTTP POST via NGROK tunnel
05 · Networking Protocols
OSI Model Layers
The SmartPi system utilizes several networking layers from the OSI model:
| OSI Layer | Protocol | Implementation |
|---|---|---|
| 1: Physical | 802.11n (2.4 GHz RF) | CYW43438 radio chip on Pico W |
| 2: Data Link | Wi-Fi MAC | CSMA/CA collision avoidance |
| 3: Network | IPv4 | Local network addressing (10.0.0.x/24) |
| 4: Transport | TCP | Reliable connection for HTTP |
| 7: Application | HTTP/1.1, JSON, MCP | RESTful API and message format |
Wireless Channel Characteristics
- Frequency Band: 2.4 GHz ISM (Industrial, Scientific, Medical)
- Channels: 11 overlapping channels (US), typically using channel 6
- Modulation: OFDM (Orthogonal Frequency-Division Multiplexing)
- Channel Sharing: CSMA/CA (Carrier-Sense Multiple Access with Collision Avoidance)
- Range: ~30 meters indoors through walls
- Data Rate: Up to 72 Mbps (802.11n single spatial stream)
Error Handling and Reliability
The system implements multiple layers of error handling to ensure reliable message delivery:
- 3 retry attempts with exponential backoff (1s, 2s, 4s)
- Timeout after 5 seconds per request
- Connection error handling with logging
- HTTP status code validation
- Circular buffer with 50-message capacity
- Overflow handling (drop oldest messages)
- Priority-based filtering
- Graceful degradation if display is busy
06 · Testing and Verification
Network Connectivity Tests
I created several test scripts to verify each component of the network:
1. Pico W HTTP Server Test
# test_pico_endpoint.py
# Test /status endpoint
response = requests.get("http://10.0.0.230:5000/status")
print(f"Device status: {response.json()}")
# Test /messages endpoint
test_messages = {
"messages": [
{"text": "Test message", "theme": "email", "priority": "urgent"}
]
}
response = requests.post("http://10.0.0.230:5000/messages", json=test_messages)
print(f"Messages sent: {response.json()}")
2. Bridge Server MCP Test
# test_bridge.py
# Test MCP tool invocation
mcp_request = {
"tool": "push_messages",
"args": {
"messages": [
{"text": "MCP test", "theme": "calendar", "priority": "important"}
]
}
}
response = requests.post("http://localhost:5055/mcp", json=mcp_request)
print(f"Bridge response: {response.json()}")
Performance Metrics
| Metric | Value | Notes |
|---|---|---|
| Message Latency | 250-400 ms | From n8n to display update |
| Throughput | ~50 messages/min | Limited by display cycle time (5s per message) |
| Reliability | >99% | With retry logic, rare failures on Wi-Fi congestion |
| Queue Capacity | 50 messages (Pico W) 30 messages (Bridge: 10 per theme) |
Prevents message loss during bursts |
07 · Design Considerations
Why Wi-Fi Over Other Protocols?
The choice of Wi-Fi (802.11n) over alternatives like Bluetooth, LoRa, or wired Ethernet was driven by several factors:
- Bandwidth: Wi-Fi provides sufficient bandwidth (Mbps) for JSON messages and future image/audio streaming
- Range: 30m indoor range covers typical home/office environments
- Infrastructure: Leverages existing home Wi-Fi network (no additional gateways)
- Integration: Easy integration with cloud services via standard TCP/IP stack
- Cost: Pico W ($6) includes Wi-Fi at no additional cost
- Bluetooth/BLE: Limited range (~10m), point-to-point only, requires phone pairing
- LoRa: Excellent range (km), but very low bandwidth (kbps), requires gateway
- Ethernet: Reliable but requires wired connection, limits device placement
- 802.11 Wi-Fi: ✅ Best balance of range, bandwidth, and infrastructure compatibility
Bridge Server: Why Not Direct n8n → Pico W?
The MCP Bridge Server might seem like an unnecessary intermediary, but it provides several critical functions:
- Protocol Translation: n8n speaks MCP, Pico W speaks simple HTTP/JSON — bridge translates
- State Management: Maintains message queues per theme, preventing message loss
- Network Isolation: Pico W stays on local network (no public exposure), bridge handles internet access
- Retry Logic: Handles temporary network failures with exponential backoff
- Extensibility: Easy to add new data sources or devices without changing Pico W firmware
Challenges and Solutions
Challenge 1: Message Loss (Initial Design)
Problem: Bridge server was overwriting messages — only last message per theme reached display
Root Cause: State dictionary stored single message per theme instead of list
Solution: Changed to list-based storage with FIFO queue (10 messages per theme)
Challenge 2: NGROK Browser Warning
Problem: NGROK displays browser warning page instead of forwarding requests
Solution: Added ngrok-skip-browser-warning: true header to all requests
08 · Conclusion
The SmartPi Agentic Assistant demonstrates a complete multi-tier IoT network architecture, incorporating wireless communication, protocol translation, and integration with cloud services. The three-node system (n8n → Bridge → Pico W) showcases key networking concepts:
- ✅ Wireless Node Design: Pico W with Wi-Fi, network address, and I/O devices
- ✅ Network Protocols: HTTP/JSON for application layer, TCP/IP for transport
- ✅ Message Routing: Three-tier architecture with gateway for protocol translation
- ✅ Error Handling: Retry logic, queue management, and graceful degradation
- ✅ Scalability: Modular design supports multiple devices and data sources
The system successfully delivers real-time notifications from cloud APIs to a local embedded device, with sub-second latency and >99% reliability. The choice of Wi-Fi as the physical layer and HTTP/JSON as the application protocol provides a good balance of bandwidth, range, and ease of integration with existing infrastructure.