MQTT ingest

Topics, payload, QoS, last-will

OpenSense exposes a multi-tenant MQTT 5 bridge for customers who run their own broker on-premises. See the DIY ESP32 + MQTT page for the device-side guide. This page is the topic / payload / QoS contract.

Bridge endpoint

$ bridge url

mqtts://mqtt.opensense.murzin.digital:8883

  • TLS 1.2 or 1.3, mTLS required.
  • Cert + key + CA bundle is downloaded from the dashboard when you add an MQTT bridge.
  • MQTT 5 only. MQTT 3.1.1 is rejected at handshake.

Topics

Each account has a dedicated topic root: opensense/<account_id>/.

Publish topics (your broker → our broker):

TopicPurpose
opensense/<acc>/<device_id>Measurement payload (JSON)
opensense/<acc>/<device_id>/lwtLast-will / online-status payload
opensense/<acc>/<device_id>/infoFirmware version, model (one-shot)

Subscribe topics (our broker → your broker, optional):

TopicPurpose
opensense/<acc>/<device_id>/cmd/cadenceServer-side request to change cadence
opensense/<acc>/<device_id>/cmd/identify"Make the LED blink" — for finding it

The cmd/* topics are placeholders today; only cmd/identify is implemented. We may extend later.

Measurement payload

Same as POST /v1/ingest:

{
  "ts": "2026-05-17T08:22:00Z",
  "measurements": [
    { "type": "temperature", "value": 4.2 },
    { "type": "humidity",    "value": 64.1 }
  ]
}

device field is omitted — the device id is the second path segment of the topic. ts is optional; if omitted, server-receive time is used.

QoS

TopicRequired QoSRetainWhy
Measurement1falseStream, not state
LWT (last-will)1trueSurvive broker restarts
Info1trueOne-shot retained presence
Cmd (downlink)1falseSingle-shot

QoS 0 is rejected (silent drop) for measurement topics — the bridge will not let you race the network for free. QoS 2 is accepted but downgraded to 1 at the ingest point; the storage layer dedups by content anyway.

Last-will format

{
  "status": "offline",
  "reason": "device-disconnected",
  "at":     "2026-05-17T08:22:00Z"
}

Set as the LWT of your device's MQTT client when connecting to your local broker. Forward via bridge with retain=true. When the local broker promotes the LWT (TCP close on the device), it propagates through the bridge and OpenSense flips the device's connection state.

On reconnect, the device publishes:

{ "status": "online", "at": "2026-05-17T08:23:00Z" }

…and the connection state flips back.

Authentication

mTLS only. The client cert subject CN identifies the account; the topic prefix is enforced on the bridge side against that subject. A client cert for account A cannot publish to account B's topic tree even if it tries.

There is no password-based auth on the MQTT bridge. If you cannot do mTLS, use HTTPS ingest instead — we are not going to weaken MQTT multi-tenancy to ease setup.

Why bridge, not direct device-to-OpenSense MQTT?

Direct device connections are a Team-tier feature. Solo is priced for HTTP-first integrations and the on-prem MQTT bridge is the workaround for customers who cannot do outbound HTTPS but can do MQTT.

For scale (>100 devices), revisit: at that scale you want direct sessions on our broker, which means individual device certificates, which means provisioning workflow — none of which is free.