LW IT Solutions
« Blog Overview /Smart Home/Tutorials / Tutorial: Publishing an MQTT Discovery Payload That...

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. 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.

A device block is optional and pays for itself immediately: entities that share the same identifier are grouped under one device, and one device with eight readings is far easier to live with than eight loose 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 Wh, kWh, MJ or GJ 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 warning about a field that looks helpful: expire_after marks the entity unavailable when no update arrives within the given number of seconds. On a switch that is useful. On an energy counter it tears holes into the long-term statistics, because every gap ends a counting run. A meter that reports every fifteen minutes is better off without it.

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.

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

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

ALL ARTICLES & CATEGORIES

CCTV

Follow this category by RSS

Cloud & AI

Follow this category by RSS

Data Privacy

All 11 articles in this category Follow this category by RSS

Digital Analytics

All 44 articles in this category Follow this category by RSS

Digital Marketing

All 25 articles in this category Follow this category by RSS

IT & Networks

All 15 articles in this category Follow this category by RSS

Raspberry PI

Follow this category by RSS

Smart Home

All 13 articles in this category Follow this category by RSS

Web Development

Follow this category by RSS

WordPress Plugins & Tricks

Follow this category by RSS