This guide covers operation, troubleshooting, and customization of the unified monitoring platform.
- Getting Started
- Dashboard Overview
- Viewing Sensor Data
- Troubleshooting
- Customization
- InfluxDB Queries
-
Start the services:
./start_services.sh
-
Wait for initialization (~10 seconds for all services)
-
Access Grafana:
- URL: http://localhost:3000
- Username:
admin - Password:
admin - You'll be prompted to change the password on first login
-
The dashboard auto-provisions - no manual import needed!
| Service | URL | Credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin/admin |
| InfluxDB UI | http://localhost:8086 | admin/admin123456 |
| Dashboard | http://localhost:3000/d/unified-monitoring | - |
The unified dashboard displays all 4 sensor nodes in organized panels:
┌─────────────────────────────────────────────────────────┐
│ Temperature Overview │
│ (All 4 nodes on single time-series graph) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Humidity Overview │
│ (All 4 nodes on single time-series graph) │
└─────────────────────────────────────────────────────────┘
┌───────────┬───────────┬───────────┬───────────┐
│ LoRa-1 │ LoRa-2 │ Modbus-1 │ Modbus-2 │
│ Temp │ Temp │ Temp │ Temp │
│ (Stat) │ (Stat) │ (Stat) │ (Stat) │
└───────────┴───────────┴───────────┴───────────┘
┌───────────────────────┬─────────────────────────┐
│ LoRaWAN Signal │ BME680 Environment │
│ (RSSI/SNR) │ (Pressure/Gas) │
└───────────────────────┴─────────────────────────┘
| Panel | Data Source | Description |
|---|---|---|
| Temperature Overview | All nodes | Combined temp graph with legends |
| Humidity Overview | All nodes | Combined humidity graph |
| Node Stat Panels | Individual | Current reading per node |
| LoRaWAN Signal | LoRa-1/2 | RSSI and SNR quality metrics |
| BME680 Environment | LoRa-2 only | Pressure (hPa) and gas resistance |
The dashboard auto-refreshes every 10 seconds by default. You can change this:
- Click the refresh dropdown (top-right)
- Select interval: 5s, 10s, 30s, 1m, etc.
Use the time picker (top-right) to view historical data:
- Last 15 minutes, 1 hour, 6 hours, 24 hours
- Custom range with date picker
Click on a legend item to:
- Single click: Toggle that series on/off
- Ctrl+click: Show only that series
For comprehensive troubleshooting including LoRaWAN, Modbus, Docker, Grafana, display, and firmware flashing issues, see TROUBLESHOOTING.md.
No data showing?
# Check services are running
docker compose ps
# Check bridge logs
docker compose logs mqtt-bridge --tail 20 # LoRaWAN
docker compose logs modbus-bridge --tail 20 # ModbusThe LoRaWAN nodes (LoRa-1 and LoRa-2) display their status on the OLED screen:
| Display | Meaning |
|---|---|
Join:X + Connecting... |
Attempting to join network (attempt X) |
TX:N + Joined |
Connected, N uplinks sent, awaiting next TX |
TX:N + S:X R:Y |
Connected with SNR (X dB) and RSSI (Y dBm) |
Key behaviors:
- Sensor readings and LCD display work even without gateway connectivity
- Nodes attempt 5 join attempts on startup, then retry every ~60 seconds
- Uplinks are sent every ~30 seconds once joined
- If gateway goes offline, nodes continue displaying sensor data locally
- Stale session detection: Every 5th uplink is confirmed; after 3 failed confirmations, node automatically rejoins
Edit modbus_to_influx.py:
MODBUS_DEVICES = [
{"name": "modbus1", "host": "10.10.10.100", "port": 502, "sensor": "SHT3x"},
{"name": "modbus2", "host": "10.10.10.200", "port": 502, "sensor": "SHT3x"},
# Add new device:
{"name": "modbus3", "host": "10.10.10.201", "port": 502, "sensor": "SHT3x"},
]Restart the bridge:
docker compose restart modbus-bridgeModbus polling (default 2s):
# In modbus_to_influx.py
POLL_INTERVAL = 5 # Change to 5 seconds- Edit dashboard in Grafana UI
- Save changes (Ctrl+S or Save icon)
- Export JSON: Dashboard Settings → JSON Model → Copy
- Replace
grafana/dashboards/unified-dashboard.json
In Grafana:
- Edit a panel
- Click "Alert" tab
- Configure conditions (e.g., temp > 30°C)
- Set notification channel (email, Slack, etc.)
- Go to http://localhost:8086
- Login with admin/admin123456
- Navigate to Data Explorer
- Select bucket:
sensors
Last reading from all nodes:
from(bucket: "sensors")
|> range(start: -5m)
|> filter(fn: (r) => r._field == "temperature")
|> last()
Average temperature by node (last hour):
from(bucket: "sensors")
|> range(start: -1h)
|> filter(fn: (r) => r._field == "temperature")
|> mean()
|> group(columns: ["node"])
LoRaWAN signal quality:
from(bucket: "sensors")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "lorawan_sensor")
|> filter(fn: (r) => r._field == "rssi" or r._field == "snr")
Compare protocols:
from(bucket: "sensors")
|> range(start: -1h)
|> filter(fn: (r) => r._field == "temperature")
|> group(columns: ["protocol"])
|> mean()
docker exec influxdb influx query '
from(bucket: "sensors")
|> range(start: -5m)
|> filter(fn: (r) => r._field == "temperature")
' --org my-org --token my-super-secret-auth-tokenDefault: Data is retained indefinitely.
To set retention policy:
docker exec influxdb influx bucket update \
--name sensors \
--retention 30d \
--org my-org \
--token my-super-secret-auth-tokenThis keeps only the last 30 days of data.
docker exec influxdb influx backup /tmp/backup \
--org my-org \
--token my-super-secret-auth-token
docker cp influxdb:/tmp/backup ./influxdb-backup-$(date +%Y%m%d)docker cp ./influxdb-backup-20260110 influxdb:/tmp/backup
docker exec influxdb influx restore /tmp/backup \
--org my-org \
--token my-super-secret-auth-tokenDashboards are stored in grafana/dashboards/ and provisioned automatically - they're already backed up in your Git repository.
docker compose logs -fdocker compose logs -f mqtt-bridge
docker compose logs -f modbus-bridge
docker compose logs -f grafana
docker compose logs -f influxdbAdd to bridge scripts:
import logging
logging.basicConfig(level=logging.DEBUG)Document Version: 1.2 Last Updated: 2026-01-22