Skip to content
MQTT readings

Docs contents

Smart home

Show MQTT readings on a dashboard

Connect Denframe to a broker you already run, read one exact state topic, and show live temperature and battery readings with clear freshness and availability.

You’ll have

A Temperature block reading 21.5 °C and a Battery bar at 76% that go stale when the sensor stops sending.

You’ll need
  • Any Denframe build on Downloads, which offers MQTT broker when you add a custom source.
  • Administrator access to Denframe and an existing MQTT broker the Denframe host can reach. The website and your screens never connect to the broker.
  • A broker account allowed to read the exact state topic and the optional availability topic. Readings need no write permission; sharing Denframe with Home Assistant needs separately approved publish and command access. A separate authorized test client publishes the examples.
  • The broker's hostname as it appears on its TLS certificate, its port and, for a private certificate authority, the CA certificate in PEM format. Native macOS arm64 and container checks passed; native Windows MQTT TLS and reconnect behaviour is not yet verified.
  • An unused demo topic prefix to replace denframe-demo/unused-check in every example. Never reuse a household command topic. If these sensors are already in Home Assistant, Show Home Assistant sensor values needs no broker connection.

Follow these steps in your own Denframe. This website never connects to your household, your accounts or your devices, and never asks for your credentials.

  1. Save and test the broker

    In Studio, open Sources, then Custom. Choose Add a custom source, then MQTT broker.

    Choose Add MQTT broker and enter Broker name, Broker hostname and Broker port. Enter a hostname, not an mqtt:// address or a topic.

    Keep Connection security on TLS (port 8883). Set MQTT version to MQTT 5 or MQTT 3.1.1 to match your broker. Under Broker authentication, keep Username and password and fill in MQTT username and MQTT password; choose Anonymous only if your broker explicitly allows it.

    For a private CA, paste its certificate into CA certificate PEM (optional); left blank, system trust is used. Never paste a private key; certificate checking can't be turned off.

    For an intentionally unencrypted private-LAN test, choose Trusted LAN plaintext (port 1883). Only private LAN and loopback addresses are allowed; anything public needs TLS. In a container, localhost is the container itself: use the broker address that container can reach.

    Choose Save broker, then Test broker connection. A successful test proves the host can connect, not that your account can read the topic or that a sensor is fresh. A saved broker can serve other sources too.

  2. Capture a single reading

    Set Exact state topic to your unused prefix followed by /state. Under Payload format choose Number, and leave Delivery quality on QoS 1.

    Choose Capture a sample. Within 30 seconds, publish the value below to that exact topic from your separately authorized test client, without the retained option. Set up the client's authentication privately in its own configuration file; no password belongs in the command.

    Synthetic scalar · external test client (POSIX shell)
    mosquitto_pub -h test-broker.example.invalid -p 8883 \
      --cafile test-ca.pem -t denframe-demo/unused-check/state -q 1 -m '21.5'

    Replace the placeholder host, CA path and topic with your test configuration. For a publicly trusted broker, set up the client's system trust as its documentation says. Denframe never publishes this message. Don't add -r for this live test.

    Wait until the sheet says Live sample captured. A single value maps at /value. Text and Boolean work the same way; Boolean expects true or false. A payload pasted under Paste a setup sample can help build mappings, but never proves live delivery or supplies a reading.

  3. Capture temperature and battery as JSON

    Switch Payload format to JSON; this throws away the old sample and preview. Choose Capture a sample again, then send the JSON below to the same exact state topic from your authorized client.

    Synthetic JSON · replace observed_at with the current UTC time
    {
      "temperature": 21.5,
      "battery": 76,
      "observed_at": "2026-09-11T12:00:00Z"
    }

    For a quick live example, leave out observed_at and leave the observation timestamp path blank: freshness then counts from when Denframe received it. To use the producer's measurement time instead, put the current UTC time in observed_at before each publish and set /observed_at as the timestamp path on every value that should use it. Never reuse the example date unchanged.

    With mosquitto_pub, save your JSON as denframe-demo.json and replace -m '21.5' in the earlier command with -f denframe-demo.json. Each message is a complete document, not a patch: include every mapped field.

  4. Map the two values

    Set Display name to Temperature. In its first field, keep Value type on Metric, choose /temperature in Available fields (or type it under Advanced field path), and set Label to Temperature and Unit to °C. Under Presentation, choose Hero number. Replace the default /value path; don't leave an extra unmapped field.

    Choose Add another value and set its Display name to Battery. In its first field, set Value type to Range, choose /battery, and set Label to Battery, Minimum to 0, Maximum to 100 and Unit to %. Under Presentation, choose Bars. Each value can fill its own Custom block.

    Set Visibility to Household on both. For this short test, set Fresh for (seconds) and Keep delayed values for (seconds) to 30 on each; the usual defaults are 600 and 3600. If you send timestamps, set the observation timestamp path of both values to /observed_at.

  5. Preview and put it on a dashboard

    Choose Preview selected values. Pick each one in Value to show and look at both TV 16:9 and Portrait under Preview screen. Temperature reads 21.5 °C and Battery 76%. Previewing creates nothing live.

    With Temperature in Value to show, tick a dashboard under Show on and choose Add source. If you started from a Custom block you selected in Studio, it fills that exact block. Then publish a new complete JSON reading: the saved source waits for one.

    To show Battery, add or select another Custom block in Studio, choose the same MQTT source and pick Battery. The first block keeps Temperature. Blocks sharing a source don't add broker subscriptions. A public dashboard can't show Household or Private values.

  6. Add an availability topic

    Open the source on the Custom page and choose Edit MQTT connection and data. Expand Availability and event ordering and set Exact availability topic (optional) to your unused prefix followed by /availability. Keep Online value as online and Offline value as offline. Capture and preview a new state sample, then choose Save.

    From the test client, publish online to the availability topic, then a new complete JSON state to /state. Publish offline to the availability topic: the value becomes unavailable at once. Publish online again: it still needs a new valid state before it is fresh.

    To test recovery, restart only a disposable test broker. Denframe reconnects and subscribes again; send online (if availability is set up) and then a new state.

    Don't interrupt a shared household broker for this walkthrough.

    A retained message without a valid producer timestamp is ignored for display and reported as retained_age_unknown; it can still be captured for setup. A retained JSON reading inside its freshness window keeps its original age: replay never makes it newly measured. Missing or malformed configured timestamps, readings more than five minutes ahead, older readings and conflicting timestamp ties are rejected; small future skew is capped at the time of receipt.

    QoS 1 can deliver twice. Denframe uses clean sessions and keeps the latest state, not a history or exactly-once processing, so messages sent while offline and data in flight during a crash can be lost. Setting Event ID path (optional) suppresses duplicates; reusing an ID with different content is rejected. An empty state message is not a valid reading, including a retained-value clearing message.

  7. Look after the connection

    Open the saved source on the Custom page to see when it last received data and the last valid observation, and choose Check broker diagnostics for the broker's state. MQTT has no refresh: publish from the producer or run a capture to test delivery.

    Use Edit MQTT connection and data to change the topic, mapping or availability; capture and preview again before Save. Older queued readings can't refill the edited setup. Pause and Resume are in the source's menu; resuming waits for valid data.

    To replace a shared password or CA, choose Edit shared broker and review the sources it lists. Tick Replace saved credentials and CA, enter the new set and choose Save broker. A blank CA clears the old one and uses system trust. Every source on that broker waits for data from the updated connection.

    Deleting a source removes its subscription only when no other source or capture needs the topic. Delete unused broker works once the broker has no sources. Unticking Broker enabled pauses every source on that broker.

    After restoring a backup, brokers stay disabled even when their credentials were included. Review the host, credentials and CA, turn the intended broker back on and check for a fresh delivery. Library imports never contain broker hosts, topics, passwords or permission to subscribe.

    This release reads exact MQTT 3.1.1 and 5.0 topics over TCP or verified TLS. Limits: 8 brokers, 64 sources, 128 exact topic subscriptions in all (captures included), 128 KiB payloads and an 8 MiB pending queue. A source maps up to 12 values with 8 fields each, of type Metric, Range, Status or Text, and updates at most once a second (20 a second across all sources). There is no wildcard browsing, command publishing, broker hosting or discovery, Home Assistant MQTT discovery, WebSockets, client certificates, multi-topic joins or chart history.

  8. Check freshness

    Publish a new complete JSON document with temperature 22.5, battery 75 and, if you use one, a new current timestamp. Both blocks change. A sample capture, a connection test or an online message never renews a reading.

    Stop the test publisher. With the 30-second settings, the reading goes stale after 30 seconds and expires 30 seconds later; observation timestamps can make that sooner. Put production durations back afterwards.

If it doesn’t work

MQTT broker isn't offered

Check the installed build. Direct MQTT arrived in 0.1.0-pilot.6; pilot.5 and earlier can't follow this guide, so install the current one from Downloads.

The connection fails or keeps reconnecting

Check DNS and port reachability from the Denframe host or container. Use a hostname without mqtt://. Plaintext accepts only private LAN or loopback addresses. Look at Check broker diagnostics, fix the setup and try again.

TLS or sign-in is rejected

Use the hostname on the certificate, a trusted CA and the intended account. Check the host's clock and the password. Replace credentials or the CA with Edit shared broker; Denframe never shows the saved password.

Connected, but no sample arrives

Topics are exact and case-sensitive. Check the read permissions, the producer's actual topic and the payload format. Some brokers accept a subscription but quietly withhold an unauthorized topic; others refuse it. A healthy connection proves neither permission nor freshness. A capture ends after 30 seconds.

A retained sample doesn't show

A replay without a valid observation timestamp is retained_age_unknown. Send a live, non-retained reading, or set up a genuine producer timestamp. Never stamp old data with a new time to make it fresh.

A mapped value is unavailable

Check the paths, number types and every observation timestamp path. Numbers sent as text need Convert numeric text. Don't map a missing field as zero. A failed field doesn't renew its old expiry or spoil correctly mapped values beside it.

The preview works but the dashboard is empty

Publish a new message after saving. With availability set up, send online before the new state. Check Visibility against the dashboard's audience, and choose the exact value in each Custom block.

Saving conflicts, or other sources stop updating

Reopen the editor to load the latest version. Changes to a shared broker affect every source on it and clear old readings: check their mappings and send new data once it reconnects.

Official references

Related guides