A practical workshop for streaming manufacturing sensor data from MQTT to TimescaleDB on Tiger Cloud.
This project demonstrates a real-time data pipeline:
- MQTT Broker — Publishes sensor data from manufacturing equipment
- Python Application — Subscribes to MQTT topics and processes messages
- TimescaleDB — Stores time-series sensor readings and metadata
The architecture separates concerns into modular components:
config.py— Environment configuration and secretsdatabase.py— Database operations and schema managementmqtt.py— MQTT subscription and message handlingmain.py— Application lifecycle and signal handling
- Python 3.8+
mosquitto-clients(for MQTT testing)psql(PostgreSQL client, for database testing)- TimescaleDB connection details (host, port, credentials)
- MQTT broker access
-
Verify your environment is set up correctly:
The devcontainer installs everything automatically, so start by confirming each tool is available:
# Python + dependencies (paho-mqtt, psycopg2, python-dotenv) python3 -c "import paho.mqtt.client, psycopg2, dotenv; print('Python dependencies OK')" # Mosquitto MQTT client mosquitto_sub --version # PostgreSQL client psql --version # Grafana (runs on port 3000) curl -s http://localhost:3000/api/health
Each command should run without errors
-
Create environment file:
cp .env.example .env
-
Fill in your Tiger Cloud credentials:
# Edit .env with: PGPASSWORD=your-password PGUSER=your-username PGDATABASE=sensor_data PGHOST=your-timescale-host PGPORT=5432 # Optional: Override default MQTT broker MQTT_HOST=your-mqtt-host MQTT_PORT=1883
Open a terminal and subscribe to the manufacturing sensor topics:
# Subscribe to all manufacturing sensors
mosquitto_sub -h 54.160.239.103 -p 1883 -t "UNS/manufacturing/#" -v
# Or subscribe to a specific machine
mosquitto_sub -h 54.160.239.103 -p 1883 -t "UNS/manufacturing/plant1/area1/machine1/#" -vBecause the credentials file uses the standard PG* variable names, you can
load it into your shell and run psql with no arguments — libpq reads the
connection details (including the password) straight from the environment:
# Export everything in the credentials file, then connect
set -a
source .env
set +a
psqlOr, you can manuallly enter the connection details with the following command:
# Connect to your TimescaleDB instance
psql -h your-timescale-host -U your-username -d sensor_data -W
# Enter your password when promptedInstead of letting the Python application create the tables on startup, you can
load them manually. Run the files in order — tag_meta.sql first, since
tag_history has a foreign key to it. Assuming your credentials are already
exported (see above), psql picks up the connection details automatically:
psql -f mqtt_to_timescaledb/sql/tag_meta.sql
psql -f mqtt_to_timescaledb/sql/tag_history.sqlSign in to an interactive psql session:
psqlThen run the verification commands:
-- List all tables
\dt
-- View table structure
\d tag_meta
\d tag_history
-- Check if tag_history is a hypertable
SELECT * FROM timescaledb_information.hypertables;When you're done, sign out of the session:
\qpython mqtt_to_timescaledb.pyThe application will:
- Load configuration from environment variables
- Connect to TimescaleDB and initialize tables/hypertable
- Connect to MQTT broker and subscribe to
UNS/manufacturing/# - Process incoming messages and store readings in the database
- Log all activities to console
Press Ctrl+C to trigger graceful shutdown:
- Stops MQTT subscription
- Closes database connection
- Logs shutdown information
Running in a browser-based Codespace?
Ctrl+Cmay be intercepted by the browser and never reach the application. If pressingCtrl+Cdoes nothing, the simplest fix is to kill the terminal — click the trash-can icon on the terminal panel (or run Terminal: Kill the Active Terminal Instance from the Command Palette) and open a new one. Opening the Codespace in the VS Code desktop app also restores normalCtrl+Cbehavior.
The application logs important events:
2024-07-11 10:15:23 - mqtt_to_timescaledb - INFO - Connected to TimescaleDB
2024-07-11 10:15:24 - mqtt_to_timescaledb - INFO - Connected to MQTT broker
2024-07-11 10:15:25 - mqtt_to_timescaledb - INFO - Inserted plant1/area1/machine1/bearing_temperature: 65.3 °C at 2024-07-11 10:30:00
Sign in to an interactive psql session:
psqlThen run the queries:
-- Get latest readings for a specific tag
SELECT time, value, tag_id
FROM tag_history
WHERE tag_id = 'plant1/area1/machine1/bearing_temperature'
ORDER BY time DESC
LIMIT 10;
-- Get metadata for all tags
SELECT tag_id, tag_name, unit, description
FROM tag_meta;When you're done, sign out of the session:
\qGrafana runs alongside the app and is forwarded on port 3000. Open with the 'open in browser' icon in the PORTS tab. Log in with username admin and password admin (see .devcontainer/docker-compose.yml).
-
In Grafana, go to Connections → Data sources → Add data source → PostgreSQL.
-
Fill in your Tiger Cloud credentials (the same
PG*values from.env):- Host:
PGHOST:PGPORT(e.g.your-host:39171) - Database:
PGDATABASE(e.g.tsdb) - User:
PGUSER(e.g.tsdbadmin) - Password:
PGPASSWORD - TLS/SSL Mode:
require
⚠️ The Host field must include the port, joined with a colon (your-host:39171). Tiger Cloud does not use the default5432, and Grafana has no separate port field — if you enter only the hostname the connection will fail. Also set TLS/SSL Mode torequire; Tiger Cloud rejects unencrypted connections. - Host:
-
Click Save & test — you should see a success message.
- Go to Dashboards → New → Import.
- Click Upload dashboard JSON file and choose grafana/sensor_readings_dashboard.json (or paste its contents).
- When prompted, select the TimescaleDB data source you created above.
- Click Import.
The dashboard shows a time-series panel of sensor value over time, one series
per tag_id, auto-refreshing every 10 seconds. Make sure the Python reader is
running so there's fresh data to plot.
# Test MQTT broker connectivity
mosquitto_sub -h 54.160.239.103 -p 1883 -t '$SYS/#' -W 1
# Check if broker is responding
timeout 2 bash -c 'cat < /dev/null > /dev/tcp/54.160.239.103/1883' && echo "Port is open"# Test connection manually
psql -h your-timescale-host -U your-username -d sensor_data -c "SELECT version();"
# Verify credentials in environment file
cat .env | grep PG-
Verify MQTT messages are being published:
mosquitto_sub -h 54.160.239.103 -p 1883 -t "UNS/manufacturing/#" -v -
Check Python application logs for errors in message parsing
-
Verify message format — must include
timestampandvaluefields -
Check database tables exist:
SELECT table_name FROM information_schema.tables WHERE table_schema='public';
- Clone or open in Codespaces
- Install dependencies (
pip install -r requirements.txt) - Configure TimescaleDB credentials
- Run the Python application
- Publish a test MQTT message
- Verify data in database with
psql
- Subscribe to MQTT topics with
mosquitto_sub - Publish multiple sensor readings with different tags
- Query data using TimescaleDB time-bucket aggregations
- Modify the message format and re-run application
- Create additional SQL views for common queries
- Add continuous aggregates in TimescaleDB
- Modify the Python code to handle additional payload fields
- Set up monitoring/alerting for sensor thresholds
mqtt_to_timescaledb.py # Top-level entry point script
mqtt_to_timescaledb/
├── __init__.py # Package initialization
├── __main__.py # Module entry point
├── config.py # Configuration and env loading
├── database.py # TimescaleDB manager
├── mqtt.py # MQTT reader and message handling
├── main.py # Application entry point
└── sql/
├── tag_meta.sql # tag_meta table DDL
└── tag_history.sql # tag_history hypertable DDL
grafana/
└── sensor_readings_dashboard.json # Importable Grafana dashboard
| Variable | Default | Purpose |
|---|---|---|
MQTT_HOST |
54.160.239.103 |
MQTT broker hostname |
MQTT_PORT |
1883 |
MQTT broker port |
PGHOST |
localhost |
TimescaleDB hostname |
PGPORT |
5432 |
TimescaleDB port |
PGDATABASE |
sensor_data |
Database name |
PGUSER |
postgres |
Database user |
PGPASSWORD |
password |
Database password |
- Scale the pipeline: Add message queuing, batch inserts, or compression
- Visualization: Connect Grafana or similar tools to TimescaleDB
- Real-time alerts: Implement threshold monitoring and notifications
- Data retention: Configure TimescaleDB compression and data retention policies
- Testing: Add unit tests for message parsing and database operations
For questions or issues:
- Check the Troubleshooting section above
- Review application logs for error messages
- Test MQTT and database connectivity separately
- Reach out to the workshop facilitator