LW IT Solutions logo LW IT Solutions logo LW IT Solutions
« Blog Overview /Smart Home/Tutorials / Tutorial: Publishing an MQTT Discovery Payload That...
Read this article in other languages:

Tutorial: Publishing an MQTT Discovery Payload That Reaches the Energy Dashboard

Tutorial: Publishing an MQTT Discovery Payload That Reaches the Energy Dashboard
Contents
  1. The Topic Decides Where the Entity Appears
  2. The Smallest Payload That Actually Works
  3. The Three Fields the Energy Dashboard Reads
  4. Publishing It by Hand
  5. When the Entity Appears and Stays Empty
  6. Removing a Device Without Leaving a Ghost
  7. Questions and answers
  8. Sources

A device that announces itself over MQTT does so with a single message. It lands on a topic Home Assistant is already listening to, it carries JSON, and it has to be retained – otherwise it exists only until the next restart of either side.

Creating an entity that way is a matter of six lines. Getting that entity accepted as an energy source is a matter of three more, and those three are where the work actually sits: each of them is silently ignored when it is wrong, and the symptom is always the same empty dropdown.

A discovery payload on the left with three highlighted lines, and on the right three conditions that all have to hold before the entity can be selected in the Energy dashboard
The entity appears as soon as the payload is valid JSON. The three highlighted fields decide something else: whether it can also be picked as an energy source.

The Topic Decides Where the Entity Appears

Discovery works over a topic pattern rather than a registration call. Home Assistant subscribes to a prefix, and everything published beneath it in the right shape becomes an entity.

homeassistant/sensor/kellerzaehler/energie/config
      │          │         │           │
   prefix     component  node_id    object_id

The prefix is homeassistant unless it was changed in the MQTT integration. The component decides the entity type and has to match what the payload describes – a sensor for a reading, a binary_sensor for a yes-or-no state, a switch for something that can be commanded.

Node ID and object ID are free text and serve only to keep the topic unique. They are not the entity ID: that one is built from the name later, and changing the topic afterwards creates a second entity rather than renaming the first.

The Smallest Payload That Actually Works

Four keys are enough for an entity to exist. A name, the topic the readings arrive on, a unit, and an identifier that stays stable across restarts.

{
  "name": "Cellar meter",
  "state_topic": "haus/keller/zaehler",
  "unit_of_measurement": "kWh",
  "unique_id": "kellerzaehler_energie"
}

Of those four, unique_id is the one worth insisting on. Without it the entity shows up but cannot be renamed, cannot be assigned to an area, and cannot be selected in the Energy dashboard at all. It has to be unique across the whole installation, which is why the topic segments make a good basis for it.

The device block is optional. It groups entities that share the same device identifier under one device, making one device with eight readings easier to manage than eight separate entities.

  "device": {
    "identifiers": ["kellerzaehler"],
    "name": "Cellar meter",
    "manufacturer": "Eastron",
    "model": "SDM630"
  }

The Three Fields the Energy Dashboard Reads

An entity with a number in it is still not an energy source. Three fields have to agree before it turns up in the selection list, and all three describe something different.

Field Required value What it says
device_class energy The number is an amount of energy, not a power
unit_of_measurement an energy unit, e.g. kWh The unit that amount is counted in
state_class total_increasing The value only ever counts upwards

The most frequent mismatch is between the first two. A meter reporting watts is a power sensor: device_class power, state_class measurement, unit W. That sensor is useful and correct, and it will never appear as an energy source, because power is not energy. What the Energy dashboard wants is the counter that adds up.

The third field is the one that decides how a meter reset is handled. With total_increasing, a value that suddenly drops is read as a new counting cycle rather than as negative consumption, and the statistics carry on. With total, the same drop needs a last_reset timestamp to be interpreted, and without it the hour in question becomes a spike. For a physical meter that runs forwards and occasionally starts over, total_increasing is the honest choice.

Publishing It by Hand

Nothing about this needs a device. A single command creates the entity, and the same command with different content updates it.

mosquitto_pub -h 192.168.1.10 -u ha -P geheim -r \
  -t "homeassistant/sensor/kellerzaehler/energie/config" \
  -m '{
    "name": "Cellar meter",
    "state_topic": "haus/keller/zaehler",
    "unit_of_measurement": "kWh",
    "device_class": "energy",
    "state_class": "total_increasing",
    "unique_id": "kellerzaehler_energie",
    "device": { "identifiers": ["kellerzaehler"], "name": "Cellar meter" }
  }'

mosquitto_pub -h 192.168.1.10 -u ha -P geheim -r \
  -t "haus/keller/zaehler" -m "18234.7"

The -r flag is the part that gets forgotten, and it belongs on both messages for different reasons. On the config topic it means the description survives a Home Assistant restart, which would otherwise wipe the entity until the device happens to announce itself again. On the state topic it means the entity has a value immediately after a restart instead of sitting unavailable until the next reading arrives.

One caveat about payload size: firmware that speaks discovery usually sends abbreviated keys – stat_t, dev_cla, stat_cla, unit_of_meas, uniq_id, dev. Both spellings work and can even be mixed. Handwritten payloads are easier to read in full form.

When the Entity Appears and Stays Empty

An entity that exists but shows nothing is almost always a topic mismatch: the state_topic in the payload and the topic the value is published on differ by a character. Subscribing to the wildcard shows both sides at once.

mosquitto_sub -h 192.168.1.10 -u ha -P geheim -v -t "haus/#"

If the value arrives but is nested inside a larger JSON message, a value_template picks it out – "value_template": "{{ value_json.total_kwh }}". Without it the entity receives the whole object and reports it as unknown.

And a note on a field that is easily set too short: expire_after marks the entity unavailable when no update arrives within the given number of seconds. On an energy counter that reveals a dead device without harming the long-term statistics, because unavailable states are skipped there and do not end a counting run. The timeout has to be well above the reporting interval, though: a meter that reports every fifteen minutes needs more than 900 seconds, or it shows as unavailable between two reports.

Patience helps with the last step. Long-term statistics are computed in five-minute intervals and the Energy dashboard aggregates by the hour, so a freshly created sensor stays blank until the first full hour has passed. That is not a fault, and re-publishing the payload does not speed it up.

Removing a Device Without Leaving a Ghost

Deleting the entity in the interface removes it until the next restart, at which point the retained config message recreates it. The removal has to happen where the creation happened.

mosquitto_pub -h 192.168.1.10 -u ha -P geheim -r \
  -t "homeassistant/sensor/kellerzaehler/energie/config" -m ""

An empty retained payload on the config topic deletes both the entity and the stored message. The state topic keeps its own retained value and is worth clearing the same way, otherwise the next device to use that topic inherits a reading that belongs to something else.

Questions and answers

How does a bidirectional meter with import and export get into the Energy dashboard?

As two separate entities, not one. A bidirectional meter keeps two registers, one for import and one for export, labelled 1.8.0 and 2.8.0 in OBIS notation, and both only run forwards. Each gets a config message of its own with its own unique_id, both with device_class energy, state_class total_increasing and the same identifier in the device block, so that they appear under one device. The Energy dashboard asks for the two separately anyway when the grid is set up: energy taken from the grid and energy returned to it.

A single net value that falls during export, by contrast, does not fit total_increasing, which expects values that only count upwards; every drop would be read as a new counting cycle. If a device only supplies such a net value, or only the instantaneous power with a sign, the two directions are best separated before publishing. As a fallback they can be integrated from the power in Home Assistant, although that is less accurate than the meter’s own registers.

What permissions does a device that registers through discovery need on the broker?

Write access to its own config topic under homeassistant/ and to its own state topics, plus at most read access to homeassistant/status, where Home Assistant publishes “online” after every start and a device can then send its config again. Giving every device the same access as Home Assistant allows each of them to create any entity, or to delete one with an empty retained message. Mosquitto separates this through an ACL file with a user of its own for each device.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Write a comment

Experience with other devices or integrations and questions about the setup are welcome here.

The email address is not published. Required fields are marked with an asterisk.

Articles & categories

CCTV

All 6 articles in this category Follow this category by RSS

Cloud & AI

All 18 articles in this category Follow this category by RSS

Data Privacy

All 20 articles in this category Follow this category by RSS

Digital Analytics

All 60 articles in this category Follow this category by RSS

Digital Marketing

All 38 articles in this category Follow this category by RSS

IT & Networks

All 19 articles in this category Follow this category by RSS

Music Production

All 18 articles in this category Follow this category by RSS

Raspberry PI

All 11 articles in this category Follow this category by RSS

SaaS & Internet Earning

Follow this category by RSS

Smart Home

All 18 articles in this category Follow this category by RSS

Web Development

All 11 articles in this category Follow this category by RSS

WordPress Plugins & Tricks

All 15 articles in this category Follow this category by RSS