Skip to content

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.

  • 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
RequirementDetails
Python 3.8+With pip
paho-mqttpip install paho-mqtt
SiliconWit.io accountFree tier works
  1. Log in to siliconwit.io and go to Devices
  2. Click Add Device
  3. Optionally pick a template, or click Start from scratch
  4. 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)

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.

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.

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")
[
{ "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" }
]
  1. Click Create Device
  2. Copy your Device ID and Access Token from the device detail page
Terminal window
pip install paho-mqtt

Verify:

Terminal window
python -c "import paho.mqtt.client as mqtt; print('OK')"
┌──────────────────────────────────────────┐
│ 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 │
└──────────────────────────────────────────┘
SettingValue
Brokermqtt.siliconwit.io
Port8883 (TLS required)
UsernameYour Device ID
PasswordYour Access Token
Topicd/{device_id}/t

For Example A (temperature, humidity, battery):

import ssl
import json
import time
import random
import paho.mqtt.client as mqtt
DEVICE_ID = "SWD-XXXXXX" # Replace with your Device ID
ACCESS_TOKEN = "your-token" # Replace with your Access Token
BROKER = "mqtt.siliconwit.io"
PORT = 8883
TOPIC = 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_connect
client.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.")

For Example B (accelerometer + GPS) or Example C (environmental station), send nested JSON objects that match your field schema:

import ssl
import json
import time
import random
import paho.mqtt.client as mqtt
DEVICE_ID = "SWD-XXXXXX"
ACCESS_TOKEN = "your-token"
BROKER = "mqtt.siliconwit.io"
PORT = 8883
TOPIC = f"d/{DEVICE_ID}/t"
INTERVAL = 10
BASE_LAT = -1.2921
BASE_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_connect
client.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.z on one chart tab (“Accelerometer”)
  • Plots iri on its own tab
  • Shows gps.lat/gps.lon on the map (not on line charts)
  1. Go to your device in the dashboard
  2. 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.

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.

SymptomCauseFix
Connection failed with code: 5Invalid credentialsCheck Device ID and Access Token
Connection refusedWrong port or brokerUse mqtt.siliconwit.io port 8883
SSL: CERTIFICATE_VERIFY_FAILEDOld CA certificatesRun pip install --upgrade certifi
429 Rate Limit ExceededSending too fastMatch INTERVAL to device’s data interval setting
Data not on dashboardWrong topicMust be d/{device_id}/t with actual ID
Fields missing from chartKey mismatchJSON keys must match field name exactly
No map showingNo location roleAdd "role": "location" to your GPS field
ModuleNotFoundError: pahoNot installedRun pip install paho-mqtt
AttributeError: CallbackAPIVersionOld paho-mqttRun pip install --upgrade paho-mqtt (need v2.0+)