every hardware project starts with one device and ends with three. cloud-direct works fine for one or two. around the third device you start wanting one local thing to coordinate, buffer, and forward instead of N independent connections to the internet.
this tutorial builds that. a $35 raspberry pi running mosquitto and a 40-line python bridge, two ESP32s publishing temperature over MQTT, everything landing in plexus as separate sources. ~30 minutes.
ESP32 #1 (greenhouse) ─┐
│ MQTT raspberry pi
├─────────▶ mosquitto ─HTTPS─▶ plexus
ESP32 #2 (fridge) ───┘ bridge.py
(each ESP32
lands as
its own source)three boxes, two pipes. each ESP32 publishes temperature over MQTT to a topic that includes its source_id — plexus/esp32-greenhouse/temperature, plexus/esp32-fridge/temperature. mosquitto on the pi relays MQTT locally, no plexus knowledge. bridge.py subscribes to plexus/+/+, parses the topic, and forwards each message to plexus with the right source_id attached.
the result: each ESP32 shows up in plexus as its own source. your threshold monitors and the anomaly detector from the last tutorial work unchanged — they query by source_id, and now there are real per-device source_ids.
this is one valid topology, not the only one. cloud-direct is fine for one or two devices and one less thing to maintain. the pi earns its keep when you want local buffering during WAN flakes, a single egress connection instead of N, or somewhere to run edge logic without round-tripping to the cloud.
total new spend on the pi side: ~$50.
raspberry pi imager handles this — we won’t tutorialize it.
plexus-pi.local), enable SSH, set username/password, pre-fill WiFi credentials.ssh pi@plexus-pi.localstuck on headless setup? the pi imager docs cover the screen-and-keyboard path too.
three things on the pi: mosquitto (MQTT broker), plexus-python (the SDK), and bridge.py (next step).
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
python3 -m venv ~/plexus-bridge
source ~/plexus-bridge/bin/activate
pip install plexus-python paho-mqttmosquitto needs to accept LAN connections — drop a small override:
echo "listener 1883
allow_anonymous true" | sudo tee /etc/mosquitto/conf.d/local.conf
sudo systemctl restart mosquittoallow_anonymous true is fine on a home LAN. for production, see going further.
verify mosquitto is listening:
mosquitto_sub -h localhost -t '#' -vleave that running in a second terminal — you’ll watch ESP32 messages arrive there in step 4.
bridge.py subscribes to MQTT, parses topics shaped plexus/<source_id>/<metric>, and forwards each message to plexus with the right source_id attached.
# ~/bridge.py
import json
import os
import paho.mqtt.client as mqtt
from plexus import Plexus
MQTT_HOST = os.environ.get("MQTT_HOST", "localhost")
TOPIC = os.environ.get("MQTT_TOPIC", "plexus/+/+")
clients = {}
def get_client(source_id):
if source_id not in clients:
clients[source_id] = Plexus(source_id=source_id)
return clients[source_id]
def on_message(_c, _u, msg):
parts = msg.topic.split("/")
if len(parts) != 3 or parts[0] != "plexus":
return
_, source_id, metric = parts
payload = msg.payload.decode("utf-8", errors="replace")
try:
value = float(payload)
except ValueError:
try:
value = json.loads(payload)
except ValueError:
value = payload
get_client(source_id).send(metric, value)
c = mqtt.Client()
c.on_message = on_message
c.connect(MQTT_HOST)
c.subscribe(TOPIC)
print(f"bridging {TOPIC} → plexus")
c.loop_forever()systemd unit so it auto-starts on boot:
# /etc/systemd/system/plexus-bridge.service
[Unit]
Description=Plexus MQTT bridge
After=network-online.target mosquitto.service
Wants=mosquitto.service
[Service]
Type=simple
User=pi
Environment="PLEXUS_API_KEY=plx_your_key_here"
ExecStart=/home/pi/plexus-bridge/bin/python /home/pi/bridge.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetthen:
sudo systemctl daemon-reload
sudo systemctl enable --now plexus-bridge
sudo systemctl status plexus-bridgejournalctl -u plexus-bridge -f tails the logs.
each device publishes its readings to the pi’s broker instead of straight to the cloud — topic shaped plexus/<SOURCE_ID>/<metric>, plain float payload:
// any MQTT client works — on ESP32, PubSubClient by Nick O'Leary
const char* MQTT_HOST = "192.168.1.42"; // your pi's LAN IP
const char* SOURCE_ID = "esp32-greenhouse"; // unique per device
// publish each reading to plexus/<SOURCE_ID>/<metric>
snprintf(topic, sizeof(topic), "plexus/%s/temperature", SOURCE_ID);
mqtt.publish(topic, String(temperature_c, 1).c_str());on an ESP32 the usual choice is PubSubClient by Nick O’Leary, via Sketch → Include Library → Manage Libraries.
flash both ESP32s, each with its own SOURCE_ID (e.g., esp32-greenhouse, esp32-fridge). serial monitor shows:
WiFi connected. IP: 192.168.1.78
MQTT connected to 192.168.1.42:1883
PUB plexus/esp32-greenhouse/temperature 22.3your second terminal (running mosquitto_sub) now shows the messages arriving at the pi:
plexus/esp32-greenhouse/temperature 22.3
plexus/esp32-fridge/temperature 4.8
plexus/esp32-greenhouse/humidity 54.1both ESP32s now show up in plexus as their own sources, streaming temperature, humidity, pressure. the anomaly detector points at any of them by changing one constant.
Flash Raspberry Pi OS Lite, install Mosquitto, and run the ~40-line Python bridge below to forward MQTT telemetry to Plexus. Start to finish is about 30 minutes from a fresh Pi to a working monitor.
Yes. One Pi running Mosquitto becomes a local hub for your LAN — every ESP32 or sensor publishes over MQTT and the bridge aggregates them into a single network monitoring feed, buffering through WAN outages and forwarding over one egress connection.
Each device lands in Plexus as its own source, so temperature, humidity, and pressure stream into one dashboard with per-device threshold monitors and anomaly detection — no separate Grafana or InfluxDB stack to run.
bridge.py is plain python — add a filter in on_message to drop noisy metrics before they leave the LAN, or downsample 10 Hz traffic to 1 Hz before forwarding. saves bandwidth and storage.next week: time-series storage. how plexus stores all this, and what your options are if you want more of it locally.
bridge.py, plexus-bridge.service, and the full walkthrough live in the docs.