raspberry pi monitoring: building a fleet observer
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.
What you’ll build
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.
What you need
- a raspberry pi 3B+ or newer — ~$35 new, less used. Pi 4 and Pi 5 fine, even overkill. 1 GB RAM is plenty.
- a microSD card — 16 GB+, class 10. ~$8.
- a power supply — USB-C for Pi 4/5, micro-USB for Pi 3. official ones are reliable; cheap ones aren't.
- one or two MQTT-capable devices — ESP32s with a BME280 are the classic fit — any board that can publish MQTT works.
- a plexus API key — from the API keys page at app.plexus.company.
total new spend on the pi side: ~$50.
Step 1 of 4: flash the pi
raspberry pi imager handles this — we won’t tutorialize it.
- install raspberry pi imager, pick Raspberry Pi OS Lite (64-bit).
- click the gear icon. set hostname (e.g.,
plexus-pi.local), enable SSH, set username/password, pre-fill WiFi credentials. - write the SD card. insert it, power on, wait ~60 seconds.
ssh pi@plexus-pi.localstuck on headless setup? the pi imager docs cover the screen-and-keyboard path too.
Step 2 of 4: install mosquitto and plexus-python
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-mqtt<2"the paho-mqtt<2 pin matters: paho-mqtt 2.x changed how mqtt.Client() is created, and the bridge below is written for 1.x.
mosquitto 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.
Step 3 of 4: drop the bridge
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, PlexusError
MQTT_HOST = os.environ.get("MQTT_HOST", "localhost")
TOPIC = os.environ.get("MQTT_TOPIC", "plexus/+/+")
BUFFER_DIR = os.path.expanduser("~/plexus-bridge/buffers")
os.makedirs(BUFFER_DIR, exist_ok=True)
clients = {}
def get_client(source_id):
if source_id not in clients:
# one buffer file per device, so a backlog saved during an outage
# is sent again under the device it came from
clients[source_id] = Plexus(
source_id=source_id,
buffer_path=os.path.join(BUFFER_DIR, f"{source_id}.db"),
)
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
try:
get_client(source_id).send(metric, value)
except (PlexusError, ValueError) as e:
# send() raises when the network is down (the point is buffered and
# retried on the next send) and Plexus() raises on a bad source id
print(f"{source_id}/{metric}: {e}")
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.
Step 4 of 4: point the ESP32s at the pi
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.
raspberry pi monitoring, answered
How do you set up Raspberry Pi monitoring?
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.
Can a Raspberry Pi handle network monitoring for multiple devices?
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.
How do you view a Raspberry Pi monitoring dashboard?
Each device lands in Plexus as its own source, so temperature, humidity, and pressure stream into one dashboard with per-device threshold monitors — no separate Grafana or InfluxDB stack to run.
Going further: three directions
- multi-pi setups. one pi per site (lab, greenhouse, warehouse). each pi runs its own bridge with its own API key; nothing else changes.
- edge-side filtering.
bridge.pyis plain python — add a filter inon_messageto drop noisy metrics before they leave the LAN, or downsample 10 Hz traffic to 1 Hz before forwarding. saves bandwidth and storage. - when to put compute on the pi vs the cloud. rule of thumb: if the logic depends on local state (per-device baselines, smoothing, cross-sensor correlations on this site), the pi is the natural home. if it depends on fleet-wide context, the cloud is.
next week: time-series storage. how plexus stores all this, and what your options are if you want more of it locally.
Get the code: clone, run, file an issue if it breaks.
bridge.py, plexus-bridge.service, and the full walkthrough live in the docs.