Composed devices and linked entities
Link scattered Home Assistant sensors, selects, switches and buttons to one primary Matter endpoint, and keep automatic feature flags, explicit linked fields, composed sub-endpoints and controller support apart.
Several HA entities do not have to become several controller cards
Many integrations split one physical device into a primary control entity, a battery, temperature and humidity, power, cumulative energy, a mode select and an action button. If every one of those entities becomes its own Matter endpoint, a controller can end up showing a pile of fragments, or it cannot put the secondary values into the right cluster. The linked fields in Entity Mapping let you say which entity is which kind of data source; composedEntities instead builds the extra entities as sub-endpoints under the same BridgedNodeEndpoint.
Before you compose anything, confirm the unit, the device_class, what the state means and how often it updates. Putting a current sensor into the voltage field does not convert it correctly just because of the field name, and linking the battery sensor of a different physical device to the primary entity produces a false warning. Build one link at a time, then go back to the Devices card and check the mapping and the clusters.
electrical_utility_meter is an opt-in Matter 1.4 override inside Stable, and the pinned sources do not mark it experimental: Apple / Google / Alexa do not support it, Aqara is unverified, SmartThings supports it. EVSE is a Stable override: Apple / Google / Alexa do not support it, Aqara supports it, SmartThings is unverified; a bridged EVSE can break Alexa's device recognition, so it must not go on an Alexa bridge.Automatic mapping, explicit links and composed sub-endpoints
| Model | Where to enable it | Applies to | Limits |
|---|---|---|---|
| Automatic mapping | Bridge feature flags | Battery, humidity, pressure, power and energy from the same HA device | Derived from the registry relationship and the device class; it does not cover every vacuum, EVSE, lock or select helper. |
| An explicit linked field | The Entity Mapping dialog | Single-purpose fields such as batteryEntity and powerEntity | You are responsible for picking the right entity, unit and meaning; some fields only appear for a matching domain or type. |
composedEntities | The composed list in Entity Mapping | An extra entityId plus an optional matterDeviceType, forming a sub-endpoint | The source comment explicitly requires autoComposedDevices; any entry with an empty entityId is filtered out before saving. |
autoComposedDevices is the master toggle for automatic composition: turning it on lets battery, humidity, pressure, power and energy be merged automatically. autoBatteryMapping defaults to false; autoHumidityMapping and autoPressureMapping default to true. Filling in batteryEntity and the other fields by hand is explicit mapping, and you should not describe it in a document as something a flag found automatically.
The Devices card lists the battery, humidity, pressure, power, energy, voltage, current, battery power / energy, charging switch and current limit links in a mapping, and marks the matching clusters from them. That card can be showing runtime automatic mapping and a saved mapping at the same time, so cross-check it against the bridge flags and the entity mapping when you read it.
Battery, temperature/humidity/pressure, filters and faults
| Field | Data source / effect | Watch out |
|---|---|---|
batteryEntity | A battery percentage sensor; attaches the PowerSource cluster | Usable with any kind of sensor; where it overlaps with automatic battery mapping, check the actual mapping. |
disableBatteryMapping | Stops the same device's automatic battery, and the entity's own battery attributes, from being attached | Good for a mains-powered device that an integration wrongly reports a battery for; defaults to false. |
temperatureEntity | Links a temperature sensor to a primary endpoint such as a fan or an air purifier | The UI shows it for an explicit air_purifier type; pick the right temperature unit and a valid state. |
humidityEntity | Adds humidity to a temperature sensor, or to a fan / air purifier | Lets you build a temperature-and-humidity combination; not the same as the automatic same-device inference in autoHumidityMapping. |
pressureEntity | Adds atmospheric pressure to a temperature sensor | Forms a temperature plus pressure combination; not the same as autoPressureMapping. |
filterLifeEntity | A 0–100 filter-cartridge life sensor, for monitoring the HEPA filter in an air purifier | The UI shows it for an auto-detected fan or an air_purifier type. |
faultEntity | A problem / safety binary sensor on the same device; drives hardwareFaultAlert on a smoke/CO alarm | It is declared in EntityMappingConfig, but the v2.0.55 EntityMappingRequest and dialog have no such field, so do not claim the existing UI can save it. Treat it as a capability gap at the source level, and do not hand-edit storage. |
chargingStateEntity | A vacuum-only charging-state sensor; drives the Matter batChargeState directly | It replaces the inference from docked plus battery level; profile v1 does not include this field. |
Battery Storage has its own batteryPowerEntity and batteryEnergyEntity. Do not confuse them with the battery percentage of an ordinary device: they describe the charge and discharge power and the lifetime throughput of home energy storage, while batteryEntity describes where the device itself draws its charge from.
Power, energy, voltage, current, utility meter and EVSE
| Field | Expected entity / value | Effect in Matter |
|---|---|---|
powerEntity | A sensor with device_class power and a power unit | Adds instantaneous power to ElectricalPowerMeasurement. |
energyEntity | A sensor with device_class energy holding cumulative energy | Adds cumulative energy to ElectricalEnergyMeasurement. |
voltageEntity | A sensor with device_class voltage | Merged into the same device's ElectricalPowerMeasurement. |
currentEntity | A sensor with device_class current | Merged into the same device's ElectricalPowerMeasurement. |
batteryPowerEntity | Home energy-storage power; in HA a positive value is discharge and a negative value is charge | On the BatteryStorage side, charging is reported as a positive imported value and discharging as a negative exported value. |
batteryEnergyEntity | Lifetime energy for home energy storage | The ElectricalEnergyMeasurement of BatteryStorage. |
meterSerialNumber | A meter serial as text | Only electrical_utility_meter persists it, reported through MeterIdentification; left empty it reports unavailable. In documentation use only <METER_SERIAL>. |
pointOfDelivery | A metering point ID as text | Only the utility meter type persists it; in documentation use only <POINT_OF_DELIVERY>, and never publish the real supply identifier. |
chargingSwitchEntity | The switch that starts and stops EVSE charging | EnableCharging turns it on, Disable turns it off. |
currentLimitEntity | A number entity whose value is in amps | Sets and reports the maximum charging current; a write is clamped to a sensible range. |
An ordinary switch, light or plug-in unit can take power and energy; on_off_switch is presented as a plain On/Off Light, and the UI offers it no electrical fields. electrical_meter, solar_power, electrical_sensor and electrical_utility_meter show the full power/energy/voltage/current group. EVSE shows the charging switch, the current limit and optional power/energy, so it does not duplicate the ordinary group.
Every lock, vacuum, fan, cover, select and climate helper
Lock
disableLockPin: one lock stops requiring credential verification; if the system has credentials configured, the default is still to require them. Never put a real lock code in a document.lockUsercodeService: an optional HA service that syncs the credential a controller sets or clears to the physical lock; without it the credential is only kept in Matter Hub. This is opt-in behavior that writes to an external device, so confirm what the integration's service does first.lockUsercodeSlot: the code slot on the physical lock, default 1; the UI only accepts integers of 1 or more.lockPinMinLength/lockPinMaxLength: the lengths advertised to a controller, 1–20, default 4 and 8; they are fixed attributes and a controller may cache them until the next commissioning. Record the lengths only, never the real credential.
Vacuums and areas
cleaningModeEntity: the cleaning-mode select; when it is not set, the backend can derive the conventional name from the vacuum entity ID.suctionLevelEntityandmopIntensityEntity: the suction and mop-water selects, which add intensity variants to the cleaning modes.roomEntities: an array of room / scene buttons; after Matter picks a room, the matching button is pressed. The UI can read the related buttons and also lets you type an entity ID.currentRoomEntity: the current-room sensor.cleanedAreaEntity: the cumulative cleaned-area sensor, which together with each area'ssizeSqmadvances the progress.vacuumAscendingRoomOrder: dispatch in ascending area-ID order instead of the controller's selection order; it also changes which area the current room and the progress are attributed to.vacuumRoomSwitches: creates a momentary sibling switch per area, for routines on platforms that cannot send an array command.disableCustomAreaRoomModes: does not build custom areas as per-room RvcRunMode entries, so Apple Home uses its multi-room area picker; leave it off where Google or Alexa depends on the modes.valetudoIdentifier: keeps the exact case of the Valetudo MQTT identifier; unset, it is derived from the lowercase entity ID.customFanSpeedTags: a map from HA option strings to Matter ModeTag numbers, overriding the default speed tags.cleanAreaRooms: filled in automatically at runtime when the vacuum supports HA 2026.3 CLEAN_AREA, as a mapping from HA area to Matter ServiceArea ID; it is not a field you fill in the dialog.
Every area in customServiceAreas carries a required name and service, plus an optional target, a plain-object data, batchDispatch and sizeSqm. batchDispatch takes the service and target of the first matching area as a template, and can merge arrays, join primitives with commas and inject the selection metadata; the default is to dispatch area by area. data has to be a JSON object — the UI rejects an array or a primitive as invalid. These services make a real device act, so verify them in HA at the smallest scope first.
Fan, cover, select, climate and momentary
fanWindPresets.natural/.sleep: arrays of localized HA preset names mapped to the Matter wind modes; the UI takes them comma-separated.fanRestoreSpeedOnPowerOn: when a fan is turned on from off, ignore the 100% / High a controller injects and restore the last speed; you can still specify a lower speed while it is off.coverSwapOpenClose: swaps open and close for one cover and overrides the bridge flag.coverExposeAsDimmableLight: an Alexa workaround that uses level as the position and on/off as open and close; there is no stop, and it should not go into the lights group of an Alexa room.selectExposeAsSwitchtogether withselectSwitchOnOption/selectSwitchOffOption: turns a select or input_select into a switch; the two options have to match exactly, and after the change that device has to be commissioned again.disableClimateOnOff: skips the climate OnOff, so a voice command that turns a room off does not call climate.turn_off.disableClimateFanControl: skips FanControl and uses ThermostatDevice instead, for controllers that do not recognize RoomAirConditioner; HA can still control the fan modes.climateKeepModeOnIdle: when HA is off and hvac_action is idle, keep reporting the last mode so an internal cleaning cycle can be cancelled; HA and Matter deliberately disagree for a while.climateExposeFan: builds a companion Fan tile alongside the same HA climate; the entity has to report FAN_MODE, and it re-registers that air conditioner as a composed device, which means commissioning that one air conditioner again.climateAutoMode: onlyheatorcool, pinning the Matter direction of a single-setpoint auto climate.disableMomentaryFlip: script, scene, automation, input_button and button stop sending the optimistic on→off report, while the underlying HA action still runs; it is a workaround for the Echo units that get stuck on that report pair.
Throttle and debounce are not interchangeable
| Field | Direction | Scope / precedence | What it is for |
|---|---|---|---|
coverSliderDebounceMs | Controller → HA command | The per-entity UI only accepts a positive value and clamps it to 5000; empty or 0 falls back to the bridge value or the built-in one | Waits for the last write from the slider, so the cover does not travel to an intermediate position first. |
fanSliderDebounceMs | Controller → HA command | Per-entity wins over the bridge, and the UI clamps it to 5000; empty or 0 falls back or sends immediately | Merges consecutive fan speed writes, cutting down repeated IR / UART commands. |
updateThrottleMs | HA state → Matter report | A positive value in the UI, maximum 60000; 0 or empty keeps the default | Limits chatty power / energy sensors to at most one update every N ms. |
Debounce waits until after the last input before it acts, which adds control latency; throttle limits how often reports go out, which can skip intermediate states. Do not use updateThrottleMs to stop a cover moving several times, and do not use fan debounce to thin out a power sensor that reports too often. Start with one entity and a small value, then adjust from the logs and from how the control feels.
Profile v1 carries the cover and fan debounce but not updateThrottleMs. If you move settings with a profile, cross-check the throttle by hand after the import, and do not assume a mapping profile carried the bridge's global debounce across.
Build a linked mapping you can roll back
Confirm the primary entity and the same-device sources
In Home Assistant, read-only, confirm the primary entity, the device relationship, and each sensor's device_class, unit and valid state. Record them in a local list; do not paste a live entity ID or a supply identifier into a document.
Check the bridge's automatic flags
Look at
autoComposedDevicesand the auto battery, humidity and pressure flags. If the automatic result is already right, do not link it again by hand; if only one device is the exception, use Entity Mapping for that one.Open the primary entity's mapping
On the Devices card, press Edit Mapping and keep the correct primary Matter type. Use the field autocomplete to pick the battery, humidity, power and other sources; the dedicated groups only appear for a matching type or domain.
Set up one group of helpers
Fill in only the fields that serve one purpose at a time, for example power plus energy, or humidity plus pressure. Add a composed entity only when you need an extra sub-endpoint, and confirm the bridge already has autoComposedDevices on.
Save and check the endpoint
Go back to the Devices card, expand the clusters and confirm the linked entity labels and their values. If the endpoint failed, delete the mapping you just added to get back to the baseline; do not reset the bridge.
Run the controller-specific check
Check the target controller against the support chips and the maturity. For power, utility and EVSE, confirm they appear before you test the readings; for features that issue commands, such as a lock or a vacuum service area, run only the smallest authorized test.
Troubleshooting composed and linked entities
A manual link saves but shows no value
Check whether the linked entity's state is available and whether its device_class and unit match the field. Being able to pick it in the autocomplete does not mean the value means the right thing. Clear that link first and confirm the primary endpoint recovers.
Composed entities did not become sub-endpoints
Confirm the bridge has
autoComposedDeviceson, and that every composed entityId is non-empty and its type is supported. Then look at the failed entities; do not mistake an ordinary linked field for a composed sub-endpoint.A mains-powered device shows a low battery in the controller
Work out whether it came in through automatic battery, a manual batteryEntity or the entity's own battery attribute. Turn
disableBatteryMappingon for that primary entity; do not switch battery off globally for every device.The utility meter or EVSE endpoint does not appear
Read the pinned matrix first: Utility Meter is an opt-in Stable override and only SmartThings is a yes; for EVSE only Aqara is a yes, and it must not be added to an Alexa bridge. On the other no / unknown platforms, go back to a type the controller supports rather than changing the identity or re-running commissioning over and over.
Vacuum room progress lands on the wrong area
Confirm currentRoomEntity, cleanedAreaEntity, each area's sizeSqm and the actual dispatch order. Turn vacuumAscendingRoomOrder on only if the machine works in area-ID order; otherwise keep the controller's selection order.
The slider lags, or the device keeps moving
Tell the two directions apart: consecutive commands call for cover or fan debounce, and state reports that are too dense call for update throttle. Lower or clear the per-entity value step by step to fall back to the bridge default; do not change the global value and the per-entity value at the same time.
faultEntity is documented but the UI has no field
This is a gap between the v2.0.55 types and the request and the dialog. Do not hand-edit storage and do not invent a procedure; keep the default smoke/CO mapping and wait for a version with real API and UI support.
Composed and linked entity FAQ
Do I still need manual mapping once Auto Composed Devices is on?
Are composedEntities and humidityEntity the same thing?
Can I put any sensor into powerEntity?
Do the lock helpers put a real credential into a tutorial or a profile?
Does a larger updateThrottleMs mean more stability?
Stable 2.0.55 pinned-version sources
- entity-mapping.ts: every composed and linked field, and the Matter types
- bridge-data.ts: the automatic mapping feature flags
- EntityMappingDialog.tsx: field display, resolution, ranges and saving
- EndpointCard.tsx: linked mappings and cluster display
- bridge-registry.ts: how automatic composition is decided
- The official v2.0.55 release