A unified platform for IoT monitoring, environmental sensors, and network infrastructure management
»
Project Here!
»
Report Bug
·
Request Feature
Operations stack for DPX show sites. Unified platform for IoT monitoring, environmental sensors, network infrastructure management, and live event operations. Get sensor data flowing into InfluxDB with Grafana dashboards in minutes. Includes MQTT pub/sub messaging, time-series storage, real-time schedule tracking, and remote access via Tailscale or Cloudflare Tunnel.
Current Deployment: IoT monitoring via cloud API + ESP32 BLE gateways, SNMP monitoring (Geist Watchdog, ControlByWeb, d3 SMC), network device backups (Netgear M4300), and live festival schedule tracking Future: Additional sensor types, metrics-driven automation workflows, consumables tracking, LTC monitoring — see roadmap for details
Key features:
- Govee IoT Stack: Temperature/humidity monitoring via Govee sensors (cloud API + BLE)
- ESP32 BLE Gateways: Real-time BLE data collection (<5 sec latency)
- SNMP Monitoring: Environmental and system monitoring (Geist Watchdog, ControlByWeb X-410, D3 SMC)
- Network Backups: Automated Netgear M4300 switch configuration backups via TFTP
- Set Schedule: Real-time festival schedule tracking with slip calculations and WebSocket sync (by Sean Green)
- MQTT Broker: Eclipse Mosquitto for sensor data pub/sub
- Time Series DB: InfluxDB 2.x for storing sensor readings
- Visualization: Grafana dashboards with public sharing
- Data Pipeline: Telegraf for MQTT→InfluxDB routing with tag enrichment
- Grafana Live Demo: HERE
- Set Schedule Live Demo; HERE
For real-time BLE data collection (<5 sec latency), deploy ESP32 hardware gateways running OpenMQTTGateway:
- Board: Custom ESP32-based hardware (WiFi enabled)
- Firmware: OpenMQTTGateway esp32feather-ble build
- Flash Tool: Browser-based web installer (no code required)
- Setup Time: 5-10 minutes per gateway
- Multi-Site: Deploy multiple gateways for coverage
Quick Deploy: Open the web installer, select esp32feather-ble, flash, and configure WiFi + MQTT broker.
Fallback: Theengs Gateway on Windows available for testing/development.
- Container Orchestration: Docker Engine 20.10+ with Docker Compose
- Time Series Database: InfluxDB 2.x
- Visualization: Grafana
- Message Broker: Eclipse Mosquitto
- Data Pipeline: Telegraf
- Data Sources:
- govee2mqtt (AWS IoT bridge for cloud data)
- ble-decoder (Python service for real-time BLE data)
- SNMP devices (Geist Watchdog, ControlByWeb X-410, D3 SMC)
- Netgear M4300 switches (configuration backups)
- Applications:
- Set Schedule (festival schedule tracker by Sean Green)
- Hardware Gateways: ESP32 with OpenMQTTGateway firmware
- Infrastructure: Docker, systemd, cron
- Remote Access: Tailscale, Cloudflare Tunnel (optional)
🆕 First time? See the Complete Setup Guide — covers everything from creating the VM to Cloudflare tunnels, step by step.
Deploy the entire stack in minutes with our interactive wizard. Perfect for fresh Ubuntu/Debian systems:
curl -fsSL https://raw.githubusercontent.com/dubpixel/dpx_showsite_ops/master/install.sh | bashWhat the wizard does:
- ✅ Installs Docker automatically (if needed)
- ✅ Guides you through Govee credentials setup (no vim/vi required!)
- ✅ Validates email and API key format
- ✅ Auto-detects timezone and system settings
- ✅ Optional system optimizations (IPv6 disable, avahi, Tailscale)
- ✅ Deploys all services via Docker Compose
- ✅ Installs
iotmanagement command system-wide - ✅ Shows you exactly how to access Grafana
Time to deploy: 5-10 minutes on a fresh VM
Tested on: wizard not currently tested. - dev system runs on ubuntu 24.04 LTS
For advanced users or custom setups:
- OS: Ubuntu 22.04+ (tested on Ubuntu Server 24.04)
- Docker: Docker Engine 20.10+ with Compose plugin
- Network: Static IP recommended (set your
<server-ip>) - Optional: Tailscale for remote access, Cloudflare Tunnel for public dashboards
-
Clone the repository
git clone https://github.com/dubpixel/dpx_showsite_ops.git cd dpx_showsite_ops -
Run interactive setup wizard
./setup.sh
The wizard will:
- Check for Docker/Compose (installs if needed)
- Guide you through credential entry (email, password, API key)
- Validate inputs before proceeding
- Configure timezone and display preferences
- Offer system optimizations (IPv6, avahi, Tailscale)
- Set up the
iotmanagement command - Optionally deploy the stack immediately
-
Access services
- Grafana: http://:3000 (admin/grafanapass123)
- InfluxDB: http://:8086 (admin/influxpass123)
- MQTT: :1883 (anonymous)
The iot command is your main interface:
iot up # Start all services
iot down # Stop all services
iot restart [svc] # Restart service(s)
iot status # Show container status
# Logs
iot lg [n] # govee2mqtt logs (last n lines)
iot lt [n] # telegraf logs
iot lm [n] # mosquitto logs
iot li [n] # influxdb logs
iot lf [n] # grafana logs
iot lb [n] # ble-decoder logs
iot la [n] # all logs
# BLE Decoder Service
iot ble-up # Start BLE decoder
iot ble-down # Stop BLE decoder
iot ble-restart # Restart BLE decoder
iot ble-rebuild # Rebuild container image
iot ble-status # Show status
iot ble-logs [n] # View logs (alias: iot lb)
iot ble-follow # Stream logs in real-time
iot ble-decode # Run manually in foreground (debugging)
# Data & Monitoring
iot query [range] [rows] # Query InfluxDB directly
iot query-tags [range] [rows] # Query with device metadata columns
iot mqtt [topic] [count] # Subscribe to MQTT topics
iot watch-gv2 # Subscribe to Govee sensor topics
# Maintenance
iot backup # Backup Grafana + InfluxDB volumes
iot update # Refresh device name mappings from Govee API
iot cron-on # Enable hourly device map updates
iot cron-off # Disable cron job
# Utilities
iot ip # Show VM IP addresses
iot web # Show all service URLs
iot env # Show current .env config
iot conf # Show telegraf config
iot help # Show all commands
# Remote Access & Tunneling
# Cloudflare tunnels run in background, provide public HTTPS URLs
# Tunnel state tracked in ~/logs/tunnel/ (PID, URL, logs)
iot tunnel # Start Grafana tunnel (default)
iot tunnel-grafana # Start Grafana tunnel (port 3000)
iot tunnel-influxdb # Start InfluxDB tunnel (port 8086)
iot tunnel-schedule # Start set-schedule tunnel (port 8000)
iot tunnel-stop # Stop all running tunnels
iot tunnel-stop-grafana # Stop Grafana tunnel only
iot tunnel-stop-influxdb # Stop InfluxDB tunnel only
iot tunnel-stop-schedule # Stop schedule tunnel only
iot tunnel-status # Show status of all tunnels (PID, URL)
iot tunnel-logs [name] [n] # View tunnel logs (name: grafana/influxdb/schedule)Tunnel usage example:
# Start a tunnel to share Grafana dashboard publicly
iot tunnel-grafana
# ✓ grafana tunnel ready: https://abc-xyz-123.trycloudflare.com
# Check all tunnels
iot tunnel-status
# NAME STATUS PID URL
# grafana running 12345 https://abc-xyz-123.trycloudflare.com
# Stop when done
iot tunnel-stop-grafana
# ✓ Grafana tunnel stoppedThe stack automatically discovers Govee devices from your account:
- Add device in Govee app and assign to a room
- Wait for hourly cron job, OR run:
iot update - Device mappings update in
telegraf.conf - Telegraf auto-restarts if config changed
- Data appears in Grafana (may need to refresh queries)
Note: Devices MUST be assigned to a room in the Govee app, or the API won't return data.
The Govee API sometimes returns auto-generated garbage names like h5075_5a9 (model + MAC suffix). You can override these locally with meaningful names:
# View all devices with current names
iot list-devices
# Interactive rename (prompts for device selection and new name)
iot rename-device
# Change room assignment
iot set-room
# Remove local override (revert to API name)
iot clear-overrideHow it works:
- Overrides stored in
telegraf/conf.d/device-overrides.json(local-only, .gitignored) - Applied automatically during
iot updateand BLE decoder startup - Survives API changes and service restarts
- Works offline if govee2mqtt API is unavailable
Naming rules:
- Lowercase letters, numbers, and underscores only
- 3-50 characters
- No leading/trailing underscores
Example:
$ iot rename-device
Devices:
================================================================================
[1] MAC: 33FA4381ECA1... | Name: h5075_5a9 | Room: unassigned | SKU: H5075
[2] MAC: 19544381ECB1... | Name: studio_main | Room: studio_down | SKU: H5051
[0] Cancel
Select device number: 1
Enter new name (or 'cancel' to abort): green_room_sensor
Also change room? Current: 'unassigned' [y/N]: y
Enter new room name: green_room
✓ Override saved: h5075_5a9 → green_room_sensor
✓ Room updated: unassigned → green_room
Restart services to apply changes? [Y/n] y
✓ Services restartedManage the festival schedule tracking application (Phase 6):
Production commands (port 8000):
iot schedule-up # Start production service
iot schedule-down # Stop production service
iot schedule-restart # Restart production service
iot schedule-rebuild # Rebuild and redeploy production
iot schedule-status # Show container status
iot schedule-logs [n] # View logs (last n lines)
iot schedule-follow # Stream logs in real-time
iot schedule-shell # Open shell in containerDevelopment commands (port 8001):
iot schedule-dev-build # Build dev image from ../COACHELLA_SET_SCHEDULE
iot schedule-dev-up # Start dev service
iot schedule-dev-down # Stop dev service
iot schedule-dev-restart # Restart dev service
iot schedule-dev-rebuild # Build and start dev service
iot schedule-dev-logs [n] # View dev logs
iot schedule-dev-follow # Stream dev logs in real-time
iot schedule-dev-shell # Open shell in dev containerAccess:
- Production: http://:8000
- Development: http://:8001
- View-only mode: append
/to URL - Operator mode: append
/editto URL
Browser UI for sending scrolling text to WLED LED matrix signs via MQTT.
Access: http://<server-ip>:8090
| URL | Purpose |
|---|---|
/ |
Blast form |
/messages |
Recent blast history (live, auto-refreshes every 5s) |
/status |
JSON — active message + queue per sign |
Palette options: Solid (RGB picker), Rainbow, Party, Fire, Lava, Ocean, Aurora — maps to WLED's built-in palette indices.
iot matrix-blast-rebuild # Rebuild image + restart ← use after code changes
iot matrix-blast-restart # Restart only ← use for .env/config changes
iot matrix-blast-logs [n] # View logs
iot matrix-blast-follow # Stream logs in real-time
iot matrix-blast-status # Show active message + queue (alias: mb-status)
iot tunnel-matrix # Cloudflare tunnel to port 8090Config: services/matrix-blast/config.yaml
Automate Netgear M4300 switch configuration backups via TFTP (Phase 5):
# Backup Operations
iot m4300-backup # Run config backup for all switches
iot m4300-backup-mock # Run in mock mode (testing, no real switches)
# View Logs & Results
iot m4300-logs [n] # View backup logs (last n entries)
iot m4300-log-view <file> # Display specific log file
iot m4300-list [n] # List recent backups (last n)
iot m4300-list-all # List all backup files
# Maintenance
iot m4300-clean # Remove empty backup folders
iot m4300-list-switches # Show parsed switch inventory
iot m4300-rebuild # Rebuild netgear-backup container
iot tftp-rebuild # Recreate TFTP server containerConfiguration:
- Edit
config/switches.confto define switch inventory - Set credentials in
.env:M4300_USERNAME,M4300_PASSWORD_M4300,M4300_PASSWORD_OTHER - TFTP server runs on port 69 (UDP)
- Backups stored in Docker volume:
netgear-backups:/backups
Automate Grafana dashboard backups and convert them to provisioning format for version control:
First-time setup (on server):
sudo pip3 install requests
# or: sudo apt install python3-requestsBackup dashboards:
iot backup-dashboards # Fetches all dashboards via API
# Saves to ~/backups/grafana/dashboards/YYYY-MM-DD-HHMMSS/Convert to provisioning format:
# Interactive picker - shows backups grouped by session
iot provision-dashboard
# Or specify file directly
iot provision-dashboard ~/backups/grafana/dashboards/2026-02-18-120000/dashboard-abc123.json
# Auto-detects format (v2beta1 or legacy JSON)
# Removes instance-specific metadata (version, id, timestamps)
# Saves to grafana/provisioning/dashboards/
# Grafana auto-loads within 10 secondsRemove from provisioning:
# Interactive picker - shows all provisioned dashboards
iot deprovision-dashboard
# Or specify file directly
iot deprovision-dashboard grafana/provisioning/dashboards/dashboard-xyz.json
# Grafana auto-removes dashboard within 10 secondsOptional daily backups:
iot setup-dashboard-cron # Install 2am daily backup job
iot remove-dashboard-cron # Remove cron jobRestore dashboard from backup:
iot restore-dashboard [file] # Restore dashboard via Grafana APIWorkflow:
- Make dashboard changes in Grafana UI
- Run
iot backup-dashboardsto export - Run
iot provision-dashboardto convert (interactive picker) - Git commit the provisioned file for version control
- Run
iot deprovision-dashboardto remove old versions (optional)
Power-user commands for advanced data management and system control.
Configure ESP32 hardware gateways for optimal BLE scanning:
iot esp32-enable # Enable ESP32 BLE gateway decoder mode
iot esp32-verbose # Configure for maximum scan frequencyThese commands adjust BLE decoder settings to work with ESP32 OpenMQTTGateway hardware.
iot clear-retained [topic] # Clear retained MQTT messages
# Useful for removing stale sensor dataWARNING: These commands permanently delete data. Use with extreme caution.
iot delete-device-data # Interactive deletion wizard
# Options: old data, current device, or all data
iot nuke # Delete ALL data in sensors bucket
# Cannot be undone
iot nuke-geist # Delete all Geist measurements
# Useful for schema changesSafe workflow for schema changes:
- Backup data first:
iot backup - Run
iot nuke-geistto clear old measurements - Restart Telegraf:
iot restart telegraf - Verify new data flows correctly
govee2mqtt won't connect to AWS IoT (timeout errors)
- Symptom: Logs show "timeout connecting to aqm3wd1qlc3dy-ats.iot.us-east-1.amazonaws.com:8883"
- Cause: IPv6 is enabled but can't route to internet (common on Hyper-V VMs)
- Fix:
sudo sysctl -w net.ipv6.conf.eth0.disable_ipv6=1 echo "net.ipv6.conf.eth0.disable_ipv6=1" | sudo tee -a /etc/sysctl.conf iot restart govee2mqtt
Telegraf shows "parsing 'Available': invalid syntax"
- Cause: govee2mqtt publishes status messages on sensor topics
- Impact: Harmless noise in logs, data still flows correctly
- Fix: Planned for Phase 4 (separate topic filtering)
No data showing up in Grafana
- Check devices are assigned to rooms in Govee app
- Verify govee2mqtt is running:
iot lg - Check MQTT messages:
iot mqtt "gv2mqtt/#" 10 - Query InfluxDB directly:
iot query 1h 10 - Make sure Grafana queries use correct tags (device_name, room, sensor_type)
Docker containers won't start
# Check Docker is running
sudo systemctl status docker
# Check for port conflicts
sudo netstat -tlnp | grep -E ':(3000|8086|1883)'
# View detailed container errors
docker compose logs [service-name]- Docker Compose stack with 6 services
- govee2mqtt polling Govee Cloud API every 10 minutes
- MQTT broker for pub/sub messaging
- Telegraf for MQTT→InfluxDB routing
- InfluxDB 2.x for time-series storage
- Grafana for dashboards
- ble-decoder for real-time BLE data processing
- Static IP configuration ()
- mDNS support via avahi-daemon (dpx-showsite-ops.local)
- Tailscale mesh VPN for secure remote SSH
- Cloudflare Tunnel for temporary public dashboard sharing
- Grafana public dashboard links
- Telegraf regex processors to extract device_id from MQTT topics
- Telegraf enum processors to map device_id → device_name and room
update-device-map.shscript to fetch device info from govee2mqtt API- Hourly cron job to auto-update mappings when devices change
- Setup automation (setup.sh)
- Documentation (README, ARCHITECTURE, GRAFANA_SETUP)
- Volume backup/restore scripts
- Full deployment testing
- ble-decoder service dockerized and operational (Dockerfile.ble-decoder, docker-compose integration)
- ESP32 gateways deployed with OpenMQTTGateway firmware
- Theengs Gateway available as fallback
- Real-time BLE data (<5 sec latency) alongside cloud data
- Unified Telegraf config with source tagging (gv_cloud, dpx_ops_decoder)
- Process guards prevent duplicate decoder instances
- Management commands: ble-up/down/restart/rebuild/status/logs/follow
- Grafana dashboards showing both data sources
- ✅ TFTP server deployed in docker-compose with persistent storage
- ✅ dpx-netgear-backup integrated as submodule with 11 CLI commands
- ✅ M4300 backup automation via TFTP protocol
- ✅ Switch inventory management via config/switches.conf
- 🚧 M4300 SNMP monitoring (port status, VLANs, errors, uptime) — pending implementation
- 🚧 Grafana dashboards for backup status — pending implementation
- ✅ Git submodule integrated (services/set-schedule)
- ✅ Docker services deployed on port 8000 (production) + 8001 (dev)
- ✅ 16 management commands implemented (8 production + 8 dev)
- ✅ Real-time WebSocket sync across all connected clients
- ✅ Operator + view-only modes for schedule tracking
- ✅ Google Sheets integration for schedule data persistence
- ✅ Art-Net DMX implementation complete (app/artnet.py, test_artnet.py)
- ✅ Slip tracking and downstream impact projections
- 🚧 Art-Net hardware testing blocked by Phase 11 VLAN configuration
- Govee + Hue API integration for lighting control
- ControlByWeb relay devices (HTTP/SNMP API)
- Digital Loggers Web Power Switch integration
- Rule engine for threshold-based automation
- Grafana control panels for manual device control
- Govee H5194 meat probe BLE decoder (proof-of-concept underway)
- Scripts: scan_h5194.py/scan_h5194_simple.py for packet reverse engineering
- Integration plan: Merge H5194 logic into ble_decoder.py container
- HID keyboard + push button input interfaces
- Hotdog consumption tracking with leaderboard/stats dashboards
- Temperature monitoring for food safety compliance
- InfluxDB + Grafana for consumption analytics
- Compatibility research (H5179, H5075 models)
- BLE integration for multi-probe deployment
- Specialized monitoring dashboards
- Use cases: food storage, equipment rooms, HVAC validation
- Real-time Linear Timecode signal monitoring
- rs-ltc-qc integration for quality analysis
- Sub-100ms latency target
- Grafana dashboards for A/V sync health
- Outstanding: Hardware setup adjacent to NIC
- VLAN segmentation for show site operations
- Traffic analysis: Art-Net (VLAN 20), IoT (110), Internet (90), System (50)
- IP schema redesign with CIDR ranges (ready/in-progress)
- M4300 VLAN configuration with inter-VLAN routing
- Coachella spreadsheet network documentation
- Blocks: Phase 6 Art-Net testing (requires VLAN 20)
- Web-based VLAN config generator
- Outputs deployment scripts for M4300
- Streamlines multi-site deployments
- Status: Low priority, may be deferred indefinitely
See the open issues for a full list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This software is licensed under the GNU General Public License v3.0 (GPL-3.0) — the Free Software Foundation's strong copyleft license for software.
In plain terms:
- Use it, learn from it, build on it — go buck wild!!
- Modify and distribute — you can change it and share your changes
- Share your source code — if you distribute modified versions, you must share the source under GPL-3.0
- Give credit — preserve copyright notices and attributions
- Commercial use is allowed — sell it, deploy it commercially, just keep it open source
- No warranty — software is provided as-is
The GPL-3.0 ensures this remains free and open source software forever. See the LICENSE file for the full legal text.
Questions about the license? Open an issue or reach out.
This project has evolved through different licenses:
| Version | License | Period | Git Reference |
|---|---|---|---|
| v1.0 | MIT License | Feb 5, 2026 | f9a0428 |
| v1.0.1 - v1.4.2 | CC BY-SA 4.0 | Feb 5 - Mar 5, 2026 | 1a415f0 onwards |
| v2.0.0+ | GPL-3.0 | March 5, 2026+ | Current |
Why the changes?
- MIT → CC BY-SA 4.0: Initial attempt to prevent unmodified commercial resale
- CC BY-SA 4.0 → GPL-3.0: CC BY-SA is designed for creative works (documentation, art), not software. GPL-3.0 is the proper strong copyleft license for software projects.
As the sole copyright holder, the author has relicensed the codebase. Previous versions obtained during earlier license periods remain available under those original licenses.
Joshua Fleitell - i@dubpixel.tv
Project Link: https://github.com/dubpixel/dpx_showsite_ops
- Tim Nauss – for giving me the Govee sensors last year and being an ever-present source of truth and strength.
- Sean Green – for validating my exploration into self-built showsite tools and pushing me to go further.
- Govee for the cloud API and sensor platform
- Eclipse Mosquitto for reliable MQTT brokering
- Influx Data for InfluxDB time-series database
- Grafana Labs for visualization platform
- Telegraf contributors for data pipeline