Subscribing with Wildcards

Monitor many devices or variables with a single subscription using + and # wildcards.

Subscribing with wildcards

MQTT wildcards let you subscribe to multiple topics at once, so you can monitor many devices or variables with a single subscription.

WildcardNameMatches
+Single-levelExactly one level in the topic hierarchy
#Multi-levelAll remaining levels — must be the last character

Throughout the examples below, assume three devices:

DeviceVariables
device-atemperature, pressure, humidity
device-btemperature
device-cpressure, humidity

All examples use these connection parameters:

FieldValueRequired
Hostapi.surfact.comYes
Port1883 (no TLS) / 8883 (TLS)Yes
UsernameYour Surfact tokenYes
PasswordAny character or blankNo
Quality of Service0 or 1No

Single-level wildcard (+)

The + wildcard matches exactly one level. Use it when you know the topic structure but want to vary a single segment.

One variable across all devices

/v1.6/devices/+/pressure/lv
/v1.6/devices/+/pressure

This is equivalent to subscribing to pressure on every device that has it (device-a and device-c).

# Last value only
mosquitto_sub -h "api.surfact.com" -t "/v1.6/devices/+/pressure/lv" -u "$SURFACT_TOKEN" -p 8883 -q 1 -v

# Full data point (with timestamp and context)
mosquitto_sub -h "api.surfact.com" -t "/v1.6/devices/+/pressure" -u "$SURFACT_TOKEN" -p 8883 -q 1 -v
import paho.mqtt.client as mqtt

token = "your-surfact-token"

def on_connect(client, userdata, flags, rc):
    client.subscribe("/v1.6/devices/+/pressure/lv")

def on_message(client, userdata, msg):
    # The topic shows which device sent the update
    print(f"Topic: {msg.topic}")
    print(f"Value: {msg.payload.decode()}")

client = mqtt.Client(client_id="my-device-12345678901234567890")
client.username_pw_set(username=token, password="")
client.on_connect = on_connect
client.on_message = on_message
client.connect("api.surfact.com", 8883)
client.loop_forever()

All variables from one device

/v1.6/devices/device-a/+/lv
/v1.6/devices/device-a/+

This subscribes to every variable on device-a (temperature, pressure, humidity).

def on_message(client, userdata, msg):
    parts = msg.topic.split('/')
    variable = parts[3]  # variable is at index 3
    print(f"Variable: {variable} -> {msg.payload.decode()}")

Multi-level wildcard (#)

The # wildcard matches any number of remaining levels and must be the last character in the topic.

All variables from a specific device

/v1.6/devices/device-a/#

Equivalent to subscribing to every variable on device-a. You'll receive full data points (value, timestamp, context) whenever any of its variables update.

mosquitto_sub -h "api.surfact.com" -t "/v1.6/devices/device-a/#" -u "$SURFACT_TOKEN" -p 8883 -q 1 -v
import paho.mqtt.client as mqtt
import json

token = "your-surfact-token"
device_label = "device-a"

def on_connect(client, userdata, flags, rc):
    client.subscribe(f"/v1.6/devices/{device_label}/#")

def on_message(client, userdata, msg):
    parts = msg.topic.split('/')
    variable = parts[3] if len(parts) > 3 else "unknown"
    try:
        data = json.loads(msg.payload.decode())
        print(f"{variable}: value={data.get('value')} ts={data.get('timestamp')}")
    except json.JSONDecodeError:
        print(f"{variable}: {msg.payload.decode()}")

client = mqtt.Client(client_id="my-device-12345678901234567890")
client.username_pw_set(username=token, password="")
client.on_connect = on_connect
client.on_message = on_message
client.connect("api.surfact.com", 8883)
client.loop_forever()

Everything, from all devices

/v1.6/devices/#

This subscribes to all variables on all devices.

🚨

Warning: this can generate extremely high message volumes in production. Use it only for testing or small-scale deployments.

Reading the topic

The topic itself tells you the source of each message — always parse it in your message handler:

/v1.6/devices/device-a/temperature
          │         │          │
          │         │          └─ Variable label
          │         └─ Device label
          └─ API version

Messages can be full JSON objects (base variable topics) or plain values (/lv topics), so your handler should tolerate both.

Use cases & risk

PatternUse caseRisk
/v1.6/devices/+/temperatureOne variable across all devices✅ Low
/v1.6/devices/device-a/+All variables from one device✅ Low
/v1.6/devices/+/+Any variable from any device (one level)⚠️ Medium
/v1.6/devices/device-a/#Everything for one device⚠️ Medium
/v1.6/devices/#Everything, everywhere (testing only)🚨 High

Best practices

Do

  • Use wildcards to reduce the number of subscriptions
  • Parse the topic to identify the source device and variable
  • Prefer single-level (+) wildcards when you know the structure
  • Test with small datasets before deploying to production

⚠️ Don't

  • Use /v1.6/devices/# in production with many devices
  • Subscribe to more data than you can process
  • Forget to handle both JSON and plain-value message formats

Single-level vs. multi-level

FeatureSingle-level (+)Multi-level (#)
MatchesExactly one levelAll remaining levels
PositionAny levelMust be last
Example/v1.6/devices/+/temperature/v1.6/devices/device-a/#
Message volumeMediumHigh to very high

Did this page help you?