Table of Contents

Getting started

Install

dotnet add package HaMqttDiscoverable

The package targets .NET 10 and depends on MQTTnet for the underlying MQTT client.

1. Connect to your broker

Every entity is published through a single HaMqttConnection, configured with MqttSettings. Create one connection per application (or per broker) and share it across every entity you create.

using HaMqttDiscoverable;
using HaMqttDiscoverable.Entities;

var connection = new HaMqttConnection(new MqttSettings
{
    Host = "192.168.1.10",
    Username = "ha",
    Password = "secret",
});

await connection.ConnectAsync();

By default the connection also publishes a device-wide availability topic backed by an MQTT last-will message (see Connections & availability), so Home Assistant marks every entity unavailable if your process crashes rather than showing stale state forever.

2. Describe your device

A Device groups related entities together under one device in Home Assistant's device registry:

var device = Device.Create(
    identifier: "weather-station-1",
    name: "Weather Station",
    manufacturer: "Acme",
    model: "WS-100");

3. Create and publish an entity

Each entity type has a config class describing its Home Assistant discovery fields (here, SensorConfig) and an entity class (Sensor) that computes MQTT topics and publishes discovery/state:

var temperature = new Sensor(connection, new SensorConfig
{
    Name = "Temperature",
    UniqueId = "weather-station-1_temperature",
    Device = device,
    UnitOfMeasurement = "°C",
    DeviceClass = "temperature",
    StateClass = "measurement",
});

await temperature.PublishDiscoveryAsync();
await temperature.PublishStateAsync("21.5");

PublishDiscoveryAsync() publishes the retained discovery payload Home Assistant reads to create the entity - call it once after connecting. PublishStateAsync(...) publishes the current value; call it whenever the value changes.

4. Handle commands from Home Assistant

Entities that Home Assistant can control (switch, number, select, text, button, light, and the sub-entities of MediaPlayer) raise a C# event when a command arrives, in addition to accepting a callback in their constructor:

var relay = new Switch(connection, new SwitchConfig
{
    Name = "Relay",
    UniqueId = "garage-relay",
    Device = device,
});

relay.CommandReceived += async isOn =>
{
    SetHardwareRelay(isOn);
    await relay.PublishStateAsync(isOn); // confirm the new state back to Home Assistant
};

await relay.PublishDiscoveryAsync(); // also subscribes to the command topic

See Entities for the full list of entity types and what each one supports.

5. Clean up

Call RemoveAsync() on an entity to delete it from Home Assistant (publishes an empty retained discovery payload), and dispose the connection when your application shuts down:

await temperature.RemoveAsync();
await connection.DisposeAsync();

Full example

See samples/SimpleSensorDemo in the repository for a complete, runnable console app that publishes a sensor, a switch, and a button, and keeps the sensor's value updating on a timer.