Python MQTT Client
Build a Python MQTT client that sends sensor data to SiliconWit.io. This tutorial covers device creation, field configuration, and publishing both flat and nested JSON telemetry.
What You Will Learn
Section titled “What You Will Learn”- How to create a device and configure fields (including via JSON import)
- How to connect securely to the MQTT broker with TLS
- How to publish flat and nested JSON telemetry
- How charts, maps, and grouping are derived from your field schema
Prerequisites
Section titled “Prerequisites”| Requirement | Details |
|---|---|
| Python 3.8+ | With pip |
| paho-mqtt | pip install paho-mqtt |
| SiliconWit.io account | Free tier works |
Step 1: Create a Device
Section titled “Step 1: Create a Device”- Log in to siliconwit.io and go to Devices
- Click Add Device
- Optionally pick a template, or click Start from scratch
- Fill in the required fields:
- Device Name: e.g., “Road Monitor”
- Device Type: Sensor (or Tracker if GPS is primary)
- Data Interval: 10 seconds (for testing)
Step 2: Configure Fields
Section titled “Step 2: Configure Fields”Fields define what data your device sends and how it displays on the dashboard. You can add fields one by one, or click Import and paste JSON.
Example A: Flat fields
Section titled “Example A: Flat fields”Simple temperature and humidity sensor:
[ { "name": "temperature", "label": "Temperature", "unit": "°C" }, { "name": "humidity", "label": "Humidity", "unit": "%" }, { "name": "battery", "label": "Battery", "unit": "%" }]All three fields plot together on one chart.
Example B: Nested fields with GPS
Section titled “Example B: Nested fields with GPS”Road monitor with accelerometer axes grouped together and GPS on the map:
[ { "name": "iri", "label": "Road Roughness", "unit": "m/km" }, { "name": "acc", "label": "Accelerometer", "unit": "g", "children": [ { "name": "x", "label": "X" }, { "name": "y", "label": "Y" }, { "name": "z", "label": "Z" } ]}, { "name": "gps", "label": "GPS", "role": "location", "children": [ { "name": "lat", "label": "Latitude" }, { "name": "lon", "label": "Longitude" } ]}]This creates:
- “Accelerometer” chart tab: X, Y, Z plotted together
- “Other” chart tab: IRI alone
- Map section: GPS trail (excluded from line charts because of
role: "location")
Example C: Environmental station
Section titled “Example C: Environmental station”[ { "name": "env", "label": "Environment", "children": [ { "name": "temp", "label": "Temperature", "unit": "°C" }, { "name": "humidity", "label": "Humidity", "unit": "%" }, { "name": "pressure", "label": "Pressure", "unit": "hPa" } ]}, { "name": "power", "label": "Power", "children": [ { "name": "voltage", "label": "Voltage", "unit": "V" }, { "name": "current", "label": "Current", "unit": "A" } ]}, { "name": "gps", "label": "Location", "role": "location", "children": [ { "name": "lat", "label": "Latitude" }, { "name": "lon", "label": "Longitude" } ]}, { "name": "battery", "label": "Battery", "unit": "%" }, { "name": "online", "label": "Online", "role": "boolean" }]- Click Create Device
- Copy your Device ID and Access Token from the device detail page
Step 3: Install paho-mqtt
Section titled “Step 3: Install paho-mqtt”pip install paho-mqttVerify:
python -c "import paho.mqtt.client as mqtt; print('OK')"Step 4: Connection Architecture
Section titled “Step 4: Connection Architecture”┌──────────────────────────────────────────┐│ SiliconWit.io Cloud ││ ││ Dashboard ←→ MQTT Broker (TLS:8883) ││ ↑ ││ d/{device_id}/t │└────────────────────┬─────────────────────┘ │ TLS 1.2+ (port 8883)┌────────────────────┴─────────────────────┐│ Python Client (paho-mqtt) ││ ││ Authenticates: device_id + token ││ Publishes: JSON on d/{id}/t │└──────────────────────────────────────────┘| Setting | Value |
|---|---|
| Broker | mqtt.siliconwit.io |
| Port | 8883 (TLS required) |
| Username | Your Device ID |
| Password | Your Access Token |
| Topic | d/{device_id}/t |
Step 5: Flat Fields Client
Section titled “Step 5: Flat Fields Client”For Example A (temperature, humidity, battery):
import sslimport jsonimport timeimport randomimport paho.mqtt.client as mqtt
DEVICE_ID = "SWD-XXXXXX" # Replace with your Device IDACCESS_TOKEN = "your-token" # Replace with your Access TokenBROKER = "mqtt.siliconwit.io"PORT = 8883TOPIC = f"d/{DEVICE_ID}/t"INTERVAL = 10 # Must match device's data interval
def on_connect(client, userdata, flags, reason_code, properties): status = "Connected" if reason_code == 0 else f"Failed ({reason_code})" print(f"[MQTT] {status}")
def read_sensors(): return { "temperature": round(random.uniform(20.0, 35.0), 1), "humidity": round(random.uniform(30.0, 80.0), 1), "battery": round(random.uniform(60.0, 100.0), 0), }
client = mqtt.Client( callback_api_version=mqtt.CallbackAPIVersion.VERSION2, client_id=DEVICE_ID, protocol=mqtt.MQTTv311,)client.username_pw_set(DEVICE_ID, ACCESS_TOKEN)client.tls_set(tls_version=ssl.PROTOCOL_TLS_CLIENT)client.on_connect = on_connectclient.reconnect_delay_set(min_delay=1, max_delay=60)
print(f"Connecting to {BROKER}:{PORT}...")client.connect(BROKER, PORT, keepalive=60)client.loop_start()
try: while True: if client.is_connected(): data = read_sensors() client.publish(TOPIC, json.dumps(data), qos=1) print(f"Sent: {data}") time.sleep(INTERVAL)except KeyboardInterrupt: client.loop_stop() client.disconnect() print("Done.")Step 6: Nested Fields Client
Section titled “Step 6: Nested Fields Client”For Example B (accelerometer + GPS) or Example C (environmental station), send nested JSON objects that match your field schema:
import sslimport jsonimport timeimport randomimport paho.mqtt.client as mqtt
DEVICE_ID = "SWD-XXXXXX"ACCESS_TOKEN = "your-token"BROKER = "mqtt.siliconwit.io"PORT = 8883TOPIC = f"d/{DEVICE_ID}/t"INTERVAL = 10
BASE_LAT = -1.2921BASE_LNG = 36.8219
def on_connect(client, userdata, flags, reason_code, properties): print(f"[MQTT] {'Connected' if reason_code == 0 else f'Failed ({reason_code})'}")
def read_sensors(step): """Simulate road monitor with accelerometer + GPS.""" return { "iri": round(random.uniform(1.5, 6.5), 2), "acc": { "x": round(random.uniform(0.8, 3.2), 2), "y": round(random.uniform(0.8, 3.2), 2), "z": round(random.uniform(0.8, 3.2), 2), }, "gps": { "lat": round(BASE_LAT + step * 0.001, 6), "lon": round(BASE_LNG + step * 0.001, 6), }, }
client = mqtt.Client( callback_api_version=mqtt.CallbackAPIVersion.VERSION2, client_id=DEVICE_ID, protocol=mqtt.MQTTv311,)client.username_pw_set(DEVICE_ID, ACCESS_TOKEN)client.tls_set(tls_version=ssl.PROTOCOL_TLS_CLIENT)client.on_connect = on_connectclient.connect(BROKER, PORT, keepalive=60)client.loop_start()
try: step = 0 while True: if client.is_connected(): data = read_sensors(step) client.publish(TOPIC, json.dumps(data), qos=1) print(f"[{step+1}] iri={data['iri']} acc=({data['acc']['x']},{data['acc']['y']},{data['acc']['z']}) gps=({data['gps']['lat']},{data['gps']['lon']})") step += 1 time.sleep(INTERVAL)except KeyboardInterrupt: client.loop_stop() client.disconnect() print("Done.")The nested acc and gps objects match the field schema you configured in Step 2. The platform automatically:
- Groups
acc.x,acc.y,acc.zon one chart tab (“Accelerometer”) - Plots
irion its own tab - Shows
gps.lat/gps.lonon the map (not on line charts)
Step 7: View Your Data
Section titled “Step 7: View Your Data”- Go to your device in the dashboard
- You should see:
- Latest Reading: current values for each field
- Chart tabs: auto-grouped by field structure (Accelerometer, Other, etc.)
- Map: GPS trail if you have location fields
- Data table: all telemetry rows with timestamps
The data interval you configured controls the rate limit. If you send faster than the interval, extra requests get a 429 response. You can change the interval in your device’s Settings tab.
Step 8: Verify What Was Stored
Section titled “Step 8: Verify What Was Stored”Check the data table on your device page. For nested payloads, the table shows columns for each leaf field (e.g., acc.x, acc.y, gps.lat).
If fields are missing from the chart or table, check that your JSON keys exactly match the field name values in your schema. Extra fields are silently dropped in strict mode.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
Connection failed with code: 5 | Invalid credentials | Check Device ID and Access Token |
Connection refused | Wrong port or broker | Use mqtt.siliconwit.io port 8883 |
SSL: CERTIFICATE_VERIFY_FAILED | Old CA certificates | Run pip install --upgrade certifi |
| 429 Rate Limit Exceeded | Sending too fast | Match INTERVAL to device’s data interval setting |
| Data not on dashboard | Wrong topic | Must be d/{device_id}/t with actual ID |
| Fields missing from chart | Key mismatch | JSON keys must match field name exactly |
| No map showing | No location role | Add "role": "location" to your GPS field |
ModuleNotFoundError: paho | Not installed | Run pip install paho-mqtt |
AttributeError: CallbackAPIVersion | Old paho-mqtt | Run pip install --upgrade paho-mqtt (need v2.0+) |
What’s Next
Section titled “What’s Next”- Field Schema guide for roles, auto-detect, and edge cases
- HTTP ingestion as an alternative to MQTT
- Python HTTP + Snapshots tutorial for camera devices
- Alerts to get notified on thresholds
- Public sharing to share device data publicly