Tutorials
Serial Bridge

Serial Bridge

Route data from microcontrollers that output serial/UART data through a Raspberry Pi gateway to Plexus. This pattern works with any MCU that can print to a serial port — no networking stack required on the device side.

When to Use This

  • MCU without WiFi — bare-metal STM32, Arduino Uno, or other boards with no network interface
  • MCU with WiFi, but you want a Pi as aggregator — offload connectivity, logging, and buffering to a gateway
  • Legacy serial equipment — RS-232 lab instruments, CNC controllers, industrial sensors
  • Multiple serial devices into one gateway — fan out several USB-serial adapters from a single Pi

Architecture

┌─────────────┐     UART     ┌──────────────┐    HTTPS     ┌─────────────┐
│  ESP32 /    │──────TX/RX──▶│  Raspberry   │─────────────▶│   Plexus    │
│  STM32 MCU  │              │  Pi Gateway  │              │   Cloud     │
└─────────────┘              │              │              └─────────────┘
                             │  plexus-python│
┌─────────────┐     UART     │  + pyserial  │
│  Arduino /  │──────TX/RX──▶│              │
│  Other MCU  │              └──────────────┘
└─────────────┘

The gateway:

  1. Opens one or more serial ports
  2. Parses incoming lines into metric name/value pairs
  3. Sends metrics to Plexus using the Python agent

Wiring

MCU PinPi PinNotes
TXRX (GPIO 15/RXD)MCU transmit → Pi receive
RXTX (GPIO 14/TXD)Pi transmit → MCU receive (optional)
GNDGNDCommon ground required

Voltage levels: Both ESP32 and Raspberry Pi use 3.3V logic — safe to connect directly. Arduino Uno is 5V — use a level shifter or voltage divider on the TX line to avoid damaging the Pi.

Device Side (the MCU)

The SerialAdapter supports three parser modes. Pick the one that matches your firmware's output format.

Line mode (simplest)

Print one key:value pair per line. This is the easiest way to get started — no libraries needed.

// On your ESP32/STM32/Arduino — just printf over UART
while (1) {
    float temp = read_temperature();
    float hum = read_humidity();
    printf("temperature:%.1f\n", temp);
    printf("humidity:%.1f\n", hum);
    sleep(1);
}

JSON mode

Print a JSON object per line. Good when you want to send multiple metrics atomically.

printf("{\"temperature\":%.1f,\"humidity\":%.1f}\n", temp, hum);

CSV mode

Print a header line once, then data lines. Useful for high-throughput logging.

// First line = headers (sent once)
printf("temperature,humidity,pressure\n");
// Then data lines
printf("%.1f,%.1f,%.1f\n", temp, hum, press);

Gateway Side (the Pi)

1. Install the agent with serial support

pip install plexus-python[serial]

2. Set your API key

export PLEXUS_API_KEY="plx_your_key_here"

3. Run the bridge

import os
import time
from plexus import Plexus
from plexus.adapters import SerialAdapter
 
px = Plexus(
    api_key=os.environ["PLEXUS_API_KEY"],
    source_id="serial-gateway",
)
 
adapter = SerialAdapter(
    port="/dev/ttyUSB0",
    baudrate=115200,
    parser="line",             # "line", "json", or "csv"
)
adapter.connect()
 
while True:
    metrics = adapter.poll()
    for m in metrics:
        px.send(m.name, m.value, timestamp=m.timestamp)
 
    if metrics:
        px.flush()
 
    time.sleep(0.1)

Switching parser modes

For JSON output from the MCU, change the parser argument:

adapter = SerialAdapter(
    port="/dev/ttyUSB0",
    baudrate=115200,
    parser="json",
)

For CSV output:

adapter = SerialAdapter(
    port="/dev/ttyUSB0",
    baudrate=115200,
    parser="csv",
)

The poll loop stays the same — adapter.poll() returns Metric objects regardless of parser mode.

Multiple Devices

To bridge several serial devices through one Pi, create a separate adapter for each port and prefix the source ID so metrics stay organized in Plexus:

import os
import time
from plexus import Plexus
from plexus.adapters import SerialAdapter
 
px = Plexus(
    api_key=os.environ["PLEXUS_API_KEY"],
    source_id="serial-gateway",
)
 
adapters = [
    ("mcu-engine", SerialAdapter(port="/dev/ttyUSB0", baudrate=115200, parser="line")),
    ("mcu-cabin",  SerialAdapter(port="/dev/ttyUSB1", baudrate=9600,   parser="json")),
    ("mcu-gps",    SerialAdapter(port="/dev/ttyACM0", baudrate=38400,  parser="csv")),
]
 
for _, adapter in adapters:
    adapter.connect()
 
while True:
    for prefix, adapter in adapters:
        metrics = adapter.poll()
        for m in metrics:
            px.send(f"{prefix}/{m.name}", m.value, timestamp=m.timestamp)
 
    px.flush()
    time.sleep(0.1)

Running as a Service

For production gateways, run as a systemd service:

# /etc/systemd/system/plexus-serial-bridge.service
[Unit]
Description=Plexus Serial Bridge
After=network-online.target
Wants=network-online.target
 
[Service]
Type=simple
User=pi
Environment=PLEXUS_API_KEY=plx_your_key_here
ExecStart=/usr/bin/python3 /home/pi/serial_bridge.py
Restart=always
RestartSec=10
 
[Install]
WantedBy=multi-user.target
sudo systemctl enable plexus-serial-bridge
sudo systemctl start plexus-serial-bridge

Next Steps