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:
- Scans for local devices (BLE, serial, etc.)
- Reads sensor data via the appropriate protocol
- 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.pyExample 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 Variable | Default | Description |
|---|---|---|
PLEXUS_API_KEY | — | Your Plexus API key (required) |
PLEXUS_SOURCE_ID | ble-gateway | Source identifier in Plexus |
BLE_SERVICE_UUIDS | 181A | Comma-separated GATT service UUIDs |
BLE_NAME_FILTER | — | Only relay matching device names |
BLE_SCAN_DURATION | 5 | BLE scan duration (seconds) |
POLL_INTERVAL | 10 | Seconds 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.targetsudo systemctl enable plexus-gateway
sudo systemctl start plexus-gateway