Entities
Every entity type follows the same shape: a *Config class holding its Home Assistant discovery fields (all deriving from EntityConfig), and an entity class deriving from HaEntity<TConfig> that computes MQTT topics and publishes discovery/state/commands. Full member lists are in the API Reference; this page is a task-oriented overview of what each one is for.
| Entity | Component | Read/write | Notes |
|---|---|---|---|
| Sensor | sensor |
Read-only | A reported value, e.g. a temperature reading. |
| BinarySensor | binary_sensor |
Read-only | A two-state value, e.g. a door sensor. |
| Switch | switch |
Read/write | A simple on/off control. |
| Button | button |
Write-only | A stateless, momentary action. |
| Number | number |
Read/write | A numeric value with min/max/step. |
| Text | text |
Read/write | A free-form string value. |
| Select | select |
Read/write | A value from a fixed list of options. |
| Light | light |
Read/write | On/off + optional brightness, using Home Assistant's JSON light schema. |
| MediaPlayer | (composite) | Read/write | Not a single component - see Media players. |
| AlarmControlPanel | alarm_control_panel |
Read/write | Arm/disarm/trigger. |
| LockEntity | lock |
Read/write | Lock/unlock, optionally open. Named LockEntity to avoid colliding with System.Threading.Lock. |
| Siren | siren |
Read/write | On/off alarm sounder. |
| Scene | scene |
Write-only | A stateless trigger, like Button under Home Assistant's "scene" domain. |
| Notify | notify |
Write-only | Receives text messages Home Assistant sends it. |
| Date, Time, DateTimeEntity | date, time, datetime |
Read/write | Date/time values, formatted as ISO 8601. DateTimeEntity to avoid colliding with System.DateTime. |
| DeviceTracker | device_tracker |
Read-only | Home/away presence. |
| Event | event |
Read-only | Discrete named events, e.g. a doorbell's press types. |
| Update | update |
Read/write | Available software updates, with an optional Install action. |
| Image | image |
Write-only | A still image (published base64-encoded). |
| Camera | camera |
Write-only | A live-updating image feed (published base64-encoded). |
| Cover | cover |
Read/write | Open/close/stop, optionally with position and/or tilt. |
| Valve | valve |
Read/write | Open/close/stop, or an open-to-a-position valve. |
| Fan | fan |
Read/write | On/off, optionally with speed percentage and/or named presets. |
| Humidifier | humidifier |
Read/write | On/off with target humidity, optionally with named modes. |
| Vacuum | vacuum |
Read/write | Start/pause/stop/return/clean-spot/locate, optionally with fan speed. |
| LawnMower | lawn_mower |
Read/write | Start/dock/pause, with an activity report. |
| WaterHeater | water_heater |
Read/write | Operating mode plus target/current temperature. |
| Climate | climate |
Read/write | Thermostat: mode, temperature (or a range), and optional fan/swing/preset mode, humidity, and a separate power toggle. |
Note
Home Assistant's MQTT integration also has an infrared platform (emitter/receiver schemas), but it's very new/still landing upstream as of this writing, so it isn't implemented here yet.
Shared configuration
Every *Config class inherits these fields from EntityConfig:
Name,UniqueId(required),ObjectId,Device(required)Icon,DeviceClass,EntityCategory,EnabledByDefault,QosAvailability- overrides the connection-level availability topic for just this entity
See the Home Assistant MQTT integration docs for the full set of fields each component understands, and the API reference for each *Config class for what this library exposes.
Read-only entities
Sensor, BinarySensor, DeviceTracker, Event, Image, and Camera never accept commands - they just report state (or, for Image/Camera, publish binary content):
var doorSensor = new BinarySensor(connection, new BinarySensorConfig
{
Name = "Front Door",
UniqueId = "front-door",
Device = device,
DeviceClass = "door",
});
await doorSensor.PublishDiscoveryAsync();
await doorSensor.PublishStateAsync(true); // maps to PayloadOn/PayloadOff ("ON"/"OFF" by default)
Controllable entities
Most other entities accept commands from Home Assistant. Each exposes a CommandReceived (or a more specific name, like Pressed on Button or Activated on Scene) event, and accepts an equivalent callback in its constructor:
var volume = new Number(connection, new NumberConfig
{
Name = "Volume",
UniqueId = "speaker-volume",
Device = device,
Min = 0,
Max = 100,
Step = 1,
});
volume.CommandReceived += async value =>
{
SetHardwareVolume(value);
await volume.PublishStateAsync(value);
};
PublishDiscoveryAsync() subscribes to the entity's command topic(s) in addition to publishing its discovery payload, so commands only start arriving once you've called it.
Light
Light uses Home Assistant's MQTT JSON light schema, so state and commands are small JSON objects (LightState) rather than plain strings:
var lamp = new Light(connection, new LightConfig
{
Name = "Lamp",
UniqueId = "living-room-lamp",
Device = device,
SupportsBrightness = true,
});
lamp.CommandReceived += async state =>
{
ApplyToHardware(state.State == "ON", state.Brightness);
await lamp.PublishStateAsync(state);
};
Multi-topic entities
Home Assistant's MQTT schema for some components has more than one independently-optional command/state topic pair - a cover's position is separate from its open/close/stop commands; a climate device has a topic pair for each of mode, temperature, fan mode, swing mode, preset mode, and humidity. Cover, Fan, Humidifier, Vacuum, WaterHeater, and Climate model this with config flags that turn optional features on, each adding its own event and PublishXAsync method:
var thermostat = new Climate(connection, new ClimateConfig
{
Name = "Thermostat",
UniqueId = "living-room-thermostat",
Device = device,
SupportsFanMode = true,
SupportsPresetMode = true,
PresetModes = new List<string> { "eco", "away" },
});
thermostat.ModeCommandReceived += async mode => { SetMode(mode); await thermostat.PublishModeAsync(mode); };
thermostat.TargetTemperatureCommandReceived += async temp => { SetTarget(temp); await thermostat.PublishTargetTemperatureAsync(temp); };
thermostat.FanModeCommandReceived += async mode => { SetFanMode(mode); await thermostat.PublishFanModeAsync(mode); };
thermostat.PresetModeCommandReceived += async preset => { SetPreset(preset); await thermostat.PublishPresetModeAsync(preset); };
await thermostat.PublishDiscoveryAsync();
await thermostat.PublishCurrentTemperatureAsync(21.0);
Leaving a flag off (e.g. not setting SupportsFanMode) simply omits that topic pair from discovery and leaves the corresponding event/method unused - see each type's XML doc comments (or the API reference) for its full set of flags.
Removing an entity
Call RemoveAsync() to delete an entity from Home Assistant (publishes an empty retained payload to its discovery topic, and unsubscribes its command topic(s) if it has any).
Adding your own entity type
More Home Assistant MQTT components (the infrared platform noted above, or a future one) can be added by subclassing HaEntity<TConfig> the same way the built-in types under src/HaMqttDiscoverable/Entities do:
- A
*Config : EntityConfigwith the fields specific to that component, and an overriddenComponentproperty (e.g."cover"). - An entity class deriving from
HaEntity<TConfig>, overridingSupportsCommands(andHasStateTopic, if the component has no state topic) andOnCommandReceivedAsyncto parse incoming commands, exposing whatever events make sense for that component. - If the component needs more than one command topic, call the protected
RegisterAuxiliaryCommandTopic(topic, handler)from the constructor for each extra one -HaEntityhandles subscribing/unsubscribing them alongside the primary command topic.
Switch is the simplest example to copy from; Light shows how to work with a JSON-schema entity instead of a plain-string one; Cover and Climate show the auxiliary-topic pattern for entities with more than one command topic.