Tutorials
Gateway Pattern

Gateway Pattern

Route data from devices that can't reach the internet — BLE sensors, UART MCUs, LoRa nodes — through a local gateway to Plexus.

When to Use This

Many hardware devices lack WiFi or Ethernet:

  • BLE sensors — temperature pucks, heart rate monitors, asset tags
  • UART microcontrollers — bare-metal MCUs connected via serial
  • LoRa / Zigbee nodes — low-power mesh devices
  • Legacy equipment — RS-485, Modbus RTU, analog sensors

A gateway bridges these devices to the internet. The gateway runs the Plexus agent, polls local protocols, and forwards telemetry to the cloud.

Architecture

┌─────────────┐     BLE      ┌──────────────┐    HTTPS     ┌─────────────┐
│ BLE Sensor  │─────────────▶│  Raspberry   │─────────────▶│   Plexus    │
│  (no WiFi)  │              │  Pi Gateway  │              │   Cloud     │
└─────────────┘              │              │              └─────────────┘
                             │  plexus-python│
┌─────────────┐     BLE      │  + bleak     │
│ BLE Sensor  │─────────────▶│              │
│  (no WiFi)  │              └──────────────┘
└─────────────┘

The gateway:

  1. Scans for local devices (BLE, serial, etc.)
  2. Reads sensor data via the appropriate protocol
  3. Sends metrics to Plexus using the Python agent

Setup

1. Install the agent with BLE support

pip install plexus-python[ble]

2. Set your API key

export PLEXUS_API_KEY="plx_your_key_here"

3. Run the gateway

python gateway_ble_relay.py

Example Code

import os
import time
from plexus import Plexus
from plexus.adapters import BLERelayAdapter
 
px = Plexus(
    api_key=os.environ["PLEXUS_API_KEY"],
    source_id="ble-gateway",
)
 
adapter = BLERelayAdapter(
    service_uuids=["181A"],       # Environmental Sensing service
    scan_duration=5.0,            # Scan for 5 seconds
    name_filter="EnvSensor",      # Only devices with this in their name
    source_prefix="ble-gateway",
)
adapter.connect()
 
while True:
    metrics = adapter.poll()
    for m in metrics:
        px.send(m.name, m.value, timestamp=m.timestamp)
 
    if metrics:
        px.flush()
        print(f"Relayed {len(metrics)} metrics")
 
    time.sleep(10)

Configuration

Env VariableDefaultDescription
PLEXUS_API_KEYYour Plexus API key (required)
PLEXUS_SOURCE_IDble-gatewaySource identifier in Plexus
BLE_SERVICE_UUIDS181AComma-separated GATT service UUIDs
BLE_NAME_FILTEROnly relay matching device names
BLE_SCAN_DURATION5BLE scan duration (seconds)
POLL_INTERVAL10Seconds between poll cycles

Extending to Other Protocols

The gateway pattern works with any Plexus adapter. Swap BLERelayAdapter for another:

# Serial/UART gateway
from plexus.adapters import SerialAdapter
adapter = SerialAdapter(port="/dev/ttyUSB0", baudrate=115200)
 
# CAN bus gateway
from plexus.adapters import CANAdapter
adapter = CANAdapter(interface="socketcan", channel="can0")
 
# Modbus RTU gateway
from plexus.adapters import ModbusAdapter
adapter = ModbusAdapter(port="/dev/ttyUSB0", method="rtu")

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

Running as a Service

For production gateways, run as a systemd service:

# /etc/systemd/system/plexus-gateway.service
[Unit]
Description=Plexus BLE Gateway
After=bluetooth.target 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/gateway_ble_relay.py
Restart=always
RestartSec=10
 
[Install]
WantedBy=multi-user.target
sudo systemctl enable plexus-gateway
sudo systemctl start plexus-gateway