The override that fixes one endpoint, and the merge that turns five entities into one
Part 4 controlled which entities become candidates at all. This part picks up the survivors of that filter and does two more jobs. First, Entity Mapping: a scoped, explicit override for one entity on one bridge — a new name, a different Matter device type, an identity detail, a disabled switch — that never touches the Home Assistant entity registry and never turns Matter Hub into a controller. Second, composition: the three separate ways Matter Hub can take a battery sensor, a power sensor and a mode select that Home Assistant keeps as five loose entities and present them to a controller as one device with one card, instead of a pile of fragments.
Filtering picks the candidates. Mapping decides how they show up
The Devices page collects the leaf endpoints of every bridge you have — the actual Matter endpoints Matter Hub built, one card per endpoint, so you can work back from what Matter actually produced to the Home Assistant entity behind it. Entity Mapping is the explicit override for one entity on one bridge, and only that entity: it can change the name, the Matter device type, the identity details, the disabled state, and which helper entities feed it. It does not change the Home Assistant entity registry, and it does not turn Matter Hub into a controller of its own.
Work in this order. The Filter Preview from the previous part controls the candidate set. The Devices page confirms the endpoint that actually got built from that candidate. A mapping is added only for the entities that are exceptions to what Auto Detect already got right. If you override the type and the identity for every entity from the start, you lose the benefit of automatic detection, and you are more likely to land on a type the controller does not support, or an identity that shifts after the device is already commissioned.
flowchart LR F["Filter Preview:
which entities become
candidate endpoints"] --> D["Devices page:
confirm the endpoint
Matter actually built"] D --> M["Entity Mapping:
override only the
exceptions"]
Search, filter, sort, failures and paging — and what each one actually touches
Every control on this page looks like it does one obvious thing. A couple of them do something narrower than the label suggests, and knowing the actual scope saves you a search that comes back empty for no good reason.
| Control | Actual scope | How to use it |
|---|---|---|
| Search | The endpoint display name, the bridge name, and the device type name | It does not search entity_id directly. If the name does not find it, narrow by bridge or type first, then expand the card and look for yourself |
| Bridge filter | Every bridge that is loaded | Shows only the leaf endpoints of the selected bridge, which keeps you from editing the wrong mapping among devices that happen to share a name |
| Type filter | The type names present in the current endpoints | The list is deduplicated and sorted from the device types that actually exist right now; it is not a full catalog of every Matter type you could override to |
| Sort | Name, type, bridge; ascending or descending | When the type and the bridge are equal, it sorts by name next |
| Page size | 12 by default; 10, 25, 50, 100, a custom value, or All | Your choice is written to the browser's local storage. All is stored as 0 and turns off the page slicing entirely |
| Refresh | Reloads the bridge metadata | Device state is loaded per bridge. It is not Force Sync, and it changes nothing in the controller |
?showFailed=true | A summary of the failed entities across every bridge | The Dashboard can link to this focused view, which lists entity_id, the bridge, the reason, and an optional failed time. In Stable 2.0.55 the ordinary cards are still shown below it — the card grid itself is not filtered down to just the failures |
Devices collects only the leaves of the endpoint tree whose endpoint number is not 0; the root node and the aggregator never become ordinary device cards. A card can show reachable, the Home Assistant state, the clusters, the battery percentage, whether the mapping is automatic or explicit, and the matching controller-status chips. When something is missing from the controller, Devices is the first place to check, because it sits one layer closer to the bridge than any controller's own UI does.
showFailed and there happen to be no failures, the page shows an “everything loaded successfully” message. Closing that message removes the query parameter from the address bar; it does not clear the failure record on the backend. And when there are failures, remember the ordinary cards are still rendered below the summary — you are looking at an added list, not a narrowed one.A minimal edit, and the fields that make it possible
-
Step 1
Lock on to the right bridge
Go to Devices in the sidebar, pick the target bridge with the Bridge filter first, then search by name or type. Expand the card and confirm the entity it maps to; in your own notes, write that entity as the placeholder
<ENTITY_ID>rather than the real value. -
Step 2
Open Edit Mapping
Press the mapping edit button in the top right of the card. The dialog first loads that bridge's mappings and looks for an existing entry with the same
entityId. If the load fails, the dialog opens as though there were no existing mapping — which is exactly the wrong moment to start overriding fields. -
Step 3
Keep Auto Detect as the baseline
Leave Matter Device Type on Auto Detect unless there is a clear, specific problem with it. If you do override it, read the suggested types and the controller-support chips on each row first, then read the support warning that follows your choice.
-
Step 4
Fill in only the fields you need
For a naming problem, fill in Custom Name only. Fill in Custom Product Name only when a controller displays the
productName. Change the type only when the endpoint itself is wrong. Turn on Disabled only to pause exposure. An empty field is sent asundefined, not as a blank string. -
Step 5
Save and read the feedback
Press Save. Success shows a saved message; failure keeps the error on screen. Go back to the card and check the mapping and the clusters. Do not run Force Sync, change the filter, and commission again all in the same sitting — one change, one check.
-
Step 6
Verify in the controller
Confirm the support status of the type first, then watch the target controller. If a change to the type or the cluster topology means it has to be discovered or commissioned again, deal with only this one exception device, and keep a way back before you start.
You can also add, edit or delete a mapping in the Entity Mapping section on a single bridge's detail page. When you add one, you search for or type an entity ID. Deleting a mapping returns that entity to automatic detection and its defaults — which is a different thing from excluding it with a filter rule, and does not remove it from the candidate set.
| Field | Precedence / limits | When to use it |
|---|---|---|
entityId | One of the mapping's primary keys; bridgeId keeps bridges apart | Use the real Home Assistant entity ID when you add a mapping. In notes and documentation write only <ENTITY_ID> — never a value from a live environment |
matterDeviceType | Omitted means Auto Detect | Override it only when automatic detection is wrong, or you need a specific alternative presentation. Changing the type can change the endpoint's clusters |
customName | Highest precedence when the resolved nodeLabel name is built | Changes only the name a Matter controller displays, not the Home Assistant entity_id. Good for a local rename that stays inside Matter |
customProductName | Beats the HA device model / model_id, and also the bridge's productNameFromNodeLabel | Use it when a controller displays the name from productName |
customVendorName | Beats the HA device manufacturer field | Corrects or pins the text vendorName. It is not the numeric vendorId — the two are unrelated fields |
customSerialNumber | Beats the HA registry serial and the default hash | Set it only when you understand the controller caching risk. Never paste a real serial number into a document or a shared diagnostic — use <CUSTOM_SERIAL> |
customVendorId | An integer from 1 to 0xFFFE, entered in decimal or 0x format | Bridge Mode can override the numeric vendorId. In Server Mode the root vendorId is fixed at commissioning, so this field is not a safe way to change a controller that is already commissioned |
disabled | Boolean | Keeps the mapping but disables that one entity. Not the same thing as a filter Exclude, and it does not disable the entity inside Home Assistant itself |
Custom Name is a nickname on a name tag, not a change of legal name. The Matter controller reads the nickname on the badge you handed it. Home Assistant's own entity_id is still the name in the filing cabinet, unrelated to what the badge currently says, and the cabinet does not get reindexed just because you wrote a new name on the tag.
Two kinds of rename exist, and they are not interchangeable. Custom Name is a Matter-side override and leaves the Home Assistant entity_id completely alone. Actually renaming the entity inside Home Assistant is a separate operation, and it can pull the endpoint's identity along with it. The bridge feature flag stableIdentity anchors identity to the HA registry unique_id instead of to the name, so a rename does not mint a new device in the controller. Without stable identity turned on, do not bundle a Home Assistant rename, a custom serial change, and a suffix change into one batch on an environment that is already commissioned — any one of the three could look, from the controller's side, like a brand-new device.
flowchart TD A["Endpoint currently on
Auto Detect"] --> B{"Is the detected type
actually wrong for
this endpoint?"} B -->|"no"| C["Leave it on Auto Detect"] B -->|"yes"| D["Open the type picker and
read the A / G / X / Q
chips on each row"] D --> E{"Does any controller
chip read explicit no?"} E -->|"none does"| F["Save the override,
then verify in that
controller"] E -->|"at least one does"| G["Read the warning and
the type note before
you save"]
<CUSTOM_SERIAL> instead.Four round chips, and the difference between “no” and “nobody's checked”
Each row of the type picker can show four round chips: A is Apple Home, G is Google Home, X is Alexa, and Q is Aqara Home. Green means it works, orange means it partly works. Both no and unknown render as gray at a lower opacity, which is the trap — you have to rest the cursor on the chip and read the tooltip to tell “not supported” from “unverified.”
Once you pick a type, the dialog shows an information warning if any controller chip is explicitly no. Some types carry a note of their own on top of that, such as the limits on how a standalone fan is presented in Apple Home. All of this is a point-in-time snapshot taken from the Stable 2.0.55 source, not a permanent guarantee from any controller vendor. SmartThings is not part of this set of four UI chips at all — a missing chip is no basis for inferring either support or the lack of it.
| Status | UI | Your call |
|---|---|---|
| yes | Green | The snapshot marks it usable; still verify the functional details against the controller version you actually run |
| partial | Orange | It may present only some clusters or operations. Read the type note and plan for the degraded case |
| no | Gray, tooltip reads “not supported” | It may not appear at all. Do not let repeated recommissioning stand in for an actual type-compatibility check |
| unknown | Gray, tooltip reads “unverified” | There is no verification data either way. Do not write it down as supported or unsupported |
A gray chip is a locked door with no sign on it. It might be locked because nobody is allowed in — that is no. Or it might be locked because nobody has tried the handle yet — that is unknown. From across the room the two doors look identical. You have to walk up and read the tooltip, the way you would knock, before you can tell which one it is.
One physical device, five scattered entities, and three different ways to bring them back together
Many integrations split one physical device into a primary control entity plus a battery, a temperature-and-humidity pair, a power sensor, a cumulative energy sensor, a mode select, and an action button. If every one of those becomes its own Matter endpoint, a controller can end up showing a pile of fragments, or it simply cannot put a secondary value into the right cluster. Linked fields in Entity Mapping let you say which entity is which kind of data source for the primary endpoint. composedEntities does something different: it builds extra entities as sub-endpoints under the same BridgedNodeEndpoint.
device_class, what the state actually means, and how often it updates. Putting a current sensor into a voltage field does not convert the numbers just because of the field name. Linking the battery sensor of a different physical device to your primary entity produces a false low-battery warning, not a working link. Build one link at a time, then go back to the Devices card and check the mapping and the clusters before moving to the next.Automatic mapping
Enabled by bridge feature flags. Applies to 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
Set in the Entity Mapping dialog. Applies to 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
Set in the composed list in Entity Mapping. Takes an extra entityId plus an optional matterDeviceType, forming a sub-endpoint. Requires the bridge's autoComposedDevices flag; any entry with an empty entityId is filtered out before saving.
flowchart TD H["One Home Assistant device
with several related entities"] --> M1["Automatic mapping:
a bridge feature flag such
as autoComposedDevices"] H --> M2["An explicit linked field:
batteryEntity, powerEntity
and similar, set by hand"] H --> M3["composedEntities:
an extra entityId becomes
its own sub-endpoint"] M1 --> R1["Battery, humidity, pressure,
power and energy merged
into the primary endpoint"] M2 --> R2["One named field feeds one
specific cluster on the
primary endpoint"] M3 --> R3["A new sub-endpoint under
the same BridgedNodeEndpoint"]
autoComposedDevices is the master toggle for automatic composition: turning it on is what allows battery, humidity, pressure, power and energy to be merged automatically at all. Within that, autoBatteryMapping defaults to false; autoHumidityMapping and autoPressureMapping default to true. Filling in batteryEntity and the other linked fields by hand is explicit mapping, and it is worth being precise about that distinction in your own notes — do not describe a hand-filled field as something a flag “found automatically.”
The Devices card lists the battery, humidity, pressure, power, energy, voltage, current, battery-power / battery-energy, charging-switch and current-limit links a mapping carries, and marks the clusters those links produce. A card can be showing runtime automatic mapping and a saved explicit mapping at the same time, so cross-check it against both the bridge flags and the entity mapping before you assume you know which one is responsible for what you see.
Battery, temperature, humidity, pressure, 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 shown on the card |
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 | Builds 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 | Declared in EntityMappingConfig, but the Stable 2.0.55 EntityMappingRequest and dialog have no such field — the existing UI cannot save it. Treat it as a capability gap at the source level, and do not hand-edit storage to work around it |
chargingStateEntity | A vacuum-only charging-state sensor; drives the Matter batChargeState directly | 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 own 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 reports 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 notes, use only <METER_SERIAL> |
pointOfDelivery | A metering point ID as text | Only the utility-meter type persists it. Use only <POINT_OF_DELIVERY> in documentation, 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 |
device_class current into powerEntity because the two numbers look close enough. The field name does not fix the meaning — ElectricalPowerMeasurement now reports current values as if they were power, and nothing in the UI stops you from saving it.device_class is power, in a power unit, goes into powerEntity. The current sensor belongs in currentEntity instead, where it merges into the same device's ElectricalPowerMeasurement correctly labeled as current.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 at all. 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 — it does not duplicate the ordinary electrical group.
Lock, vacuum, fan, cover, select, climate — and the two timers that are not the same thing
Lock
disableLockPin: one lock stops requiring credential verification. If the system already has credentials configured, the default is still to require them. Never put a real lock code in a document — use a placeholder.lockUsercodeService: an optional HA service that syncs the credential a controller sets or clears back to the physical lock; without it, the credential is only kept inside Matter Hub. This is opt-in behavior that writes to an external device, so confirm what the integration's service actually does before you enable it.lockUsercodeSlot: the code slot on the physical lock, default1; the UI only accepts integers of1or more.lockPinMinLength/lockPinMaxLength: the lengths advertised to a controller,1–20, default4and8. 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 a 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 directly.currentRoomEntity: the current-room sensor.cleanedAreaEntity: the cumulative cleaned-area sensor, which together with each area'ssizeSqmadvances the progress.vacuumAscendingRoomOrder: dispatches in ascending area-ID order instead of the controller's own 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: skips building custom areas as per-room RvcRunMode entries, so Apple Home falls back to its own multi-room area picker. Leave this off wherever Google Home or Alexa depends on those 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 yourself 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 Home Assistant at the smallest scope first, before trusting them to a controller-driven room pick.
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, ignores the 100% / High a controller injects and restores the last speed. You can still specify a lower speed while the fan is off.coverSwapOpenClose: swaps open and close for one cover, overriding 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 orinput_selectinto a switch. The two option strings have to match exactly, and after the change that device has to be commissioned again.disableClimateOnOff: skips the climate OnOff cluster, so a voice command that turns a room off does not callclimate.turn_off.disableClimateFanControl: skips FanControl and uses ThermostatDevice instead, for controllers that do not recognize RoomAirConditioner. Home Assistant can still control the fan modes underneath.climateKeepModeOnIdle: when HA is off andhvac_actionis idle, keeps reporting the last mode so an internal cleaning cycle can still be cancelled — HA and Matter deliberately disagree for a while here.climateExposeFan: builds a companion Fan tile alongside the same HA climate entity. The entity has to reportFAN_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_buttonand button entities stop sending the optimistic on→off report, while the underlying HA action still runs. It is a workaround for 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 | Per-entity UI accepts a positive value, clamped 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, clamped 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 milliseconds |
Debounce is waiting for someone to stop knocking before you open the door — you act once, after the knocking stops, and you act on whatever the last knock actually asked for. Throttle is a doorman who lets through at most one person every few seconds, no matter how many are lined up outside; some of the queue simply never gets an individual answer. One waits for quiet before acting; the other rations how often it will act at all.
flowchart LR C["Controller sends a slider
or speed command"] -->|"debounce waits for
the last write"| H["Home Assistant
service call"] S["Home Assistant sensor
state changes"] -->|"throttle limits how
often this fires"| R["Matter attribute report
back to the controller"]
Do not use updateThrottleMs to stop a cover from moving several times, and do not use fan debounce to thin out a power sensor that reports too often — each field is built for the direction of traffic in its own row above, not the other one. Start with one entity and a small value, then adjust from what you see in the logs and how the control actually feels. Profile v1 carries the cover and fan debounce fields but not updateThrottleMs; if you move settings with a profile, cross-check the throttle by hand after the import, and do not assume a profile carried a bridge's global debounce setting across with it.
-
Step 1
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. -
Step 2
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 device alone. -
Step 3
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.
-
Step 4
Set up one group of helpers
Fill in only the fields that serve one purpose at a time — power plus energy, say, or humidity plus pressure. Add a composed entity only when you need an extra sub-endpoint, and confirm the bridge already has
autoComposedDeviceson before you try. -
Step 5
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 fails, delete the mapping you just added to get back to the baseline — do not reset the whole bridge.
-
Step 6
Run the controller-specific check
Check the target controller against the support chips and the maturity notes. For power, utility and EVSE fields, confirm they appear before you test the readings; for anything that issues commands, such as a lock or a vacuum service area, run only the smallest authorized test.
Move mappings between bridges, and give a card a picture — neither one touches the controller
Mapping profiles
A Mapping Profile is JSON at version: 1, holding name, createdAt, domains, entryCount and entries. What it carries is a set of mapping rules, not bridge identity, the fabric, pairing data, or a full backup. The export dialog preselects the existing mappings; you can select or clear all of them, tick them one by one, and give the profile a name.
-
Step 1
Choose what to export
In Entity Mapping on the bridge detail page, press Export. Tick only the entity mappings you intend to share or move, and use a profile name that carries nothing confidential about the environment.
-
Step 2
Save the JSON
Check the downloaded file name and its contents. Before you share it, review
entityIdPattern, custom names, service names, area data and the identity fields by hand, and remove anything that identifies a live environment. A profile is not an automatic de-identification tool. -
Step 3
Pick the import file
Press Import and choose the
.jsonfile. The frontend requiresversionandentriesfirst; then the backend preview validates the entries against the entity IDs that are actually available. -
Step 4
Review the preview
Check the profile name, the total count, matched, unmatched,
matchType(exact or domain) and existing mapping. Every match is ticked by default, so clear the ones you do not want to overwrite. -
Step 5
Apply selectively
After you apply, read applied, skipped and errors. In Stable 2.0.55, apply matches the profile entry's
entityIdPatternagainst the selected IDs, so an exact entity ID match is the most reliable way to work across environments — do not read a domain fallback in the preview as certain to succeed. -
Step 6
Reload and verify one by one
The mappings reload after the import. Look at a few devices first, then widen it. If the result is wrong, delete that mapping to return to automatic detection instead of resetting the whole bridge.
The Stable 2.0.55 profile is not a full backup of EntityMappingConfig. It holds type, customName, disabled, and most of the battery, sensor, energy, vacuum, lock, cover, fan and climate helpers; but the profile type and the export conversion have no customProductName, customVendorName, customSerialNumber, customVendorId, composedEntities, chargingStateEntity, currentRoomEntity, cleanedAreaEntity, coverExposeAsDimmableLight, the select-switch helpers, updateThrottleMs, or disableCustomAreaRoomModes. When you need full disaster recovery, use the real Backup rather than treating a profile as a complete snapshot of the mappings.
Device images
The image sources for a Devices card have this precedence: a custom uploaded file → the Zigbee2MQTT model URL → none. The backend sanitizes the entity_id first, then looks for a file of the same name in the device-images directory in persistent storage. When there is no custom file and the HA device registry has a model, it builds the official Zigbee2MQTT image URL instead. The image affects the Matter Hub UI card only; no image is synced to any Matter controller.
flowchart TD A["Devices card needs
an image"] --> B{"Is there a custom
uploaded file for
this entity_id?"} B -->|"yes"| C["Show the custom file"] B -->|"no"| D{"Does the HA device
registry have a model?"} D -->|"yes"| E["Build the Zigbee2MQTT
image URL and try it"] D -->|"no"| F["Show the built-in
device-type icon"] E --> G{"Does the remote
image load?"} G -->|"yes"| I["Show the z2m image"] G -->|"no"| F
| Action | Limits | Result |
|---|---|---|
| Upload | PNG, JPG / JPEG, GIF, WebP, SVG; 5 MB maximum | Saved under a file name that matches the entity_id. A new extension deletes the file with the old extension for the same entity |
| Remove | Shown only when the source is custom | Deletes the custom file. After it resolves again it may fall back to the z2m image rather than always turning into an icon |
| Auto resolve | Needs a model in the device registry | Builds the z2m image URL. When nothing is there at the far end, the image fails to load and the card falls back to the device icon |
| No image | No custom file and no model | Shows the built-in icon chosen by the Matter device type |
To upload, press the camera button on the card; on success the page bumps the cache version and runs the batch resolve again. A delete resolves again as well. Use only images you have the right to use, and do not upload files that contain pictures of a home interior, serial numbers on labels, or other personal data. When you back up or migrate, count the persistent device-images directory among the assets you plan for — a profile export never carries it.
entityIdPattern match is the reliable path; a domain fallback preview is not certain to succeed once the target environment's entity IDs differ. And regardless of how a device's image resolves, it is display-only inside the Matter Hub UI — nothing about it reaches Apple Home, Google Home, Alexa or any other controller.The symptom you will actually hit, mapped to the page that explains it
| Symptom | Likely cause | What to do |
|---|---|---|
Search cannot find an entity_id you know exists |
Search looks only at the display name, the bridge name and the type | Pick the bridge and the type first, then expand the cards to find the HA entity; or go to that bridge's Entity Mapping section and search with the Entity Autocomplete |
| Failed focus still shows healthy devices | That is what Stable 2.0.55 actually does — showFailed=true shows a summary but does not filter the cards below it |
Take the bridge and the entity_id from the summary and go back to the filter, the mapping and the failed reason to work it out |
| The controller shows nothing after a type override | The chosen type is unsupported or unverified on that controller | Go back to the picker and read the support chips, the tooltip and the warning. Restore Auto Detect first; do not start by changing the identity or by commissioning the whole bridge again |
| The import preview says matched but applying skips it | The profile's entityIdPattern is not exactly the same as the target |
In Stable 2.0.55, apply matches the selected IDs against the entry pattern, and a domain fallback preview is unreliable when the entity IDs differ. Use an exact match, or create the mapping by hand |
| There is still an image after you delete one | Deleting a custom image triggers a fresh resolve | If the HA device has a model, the source falls back to z2m — that is not a failed delete. When the remote URL has no image, the built-in icon appears only after the load error |
| A new device appears in the controller after an HA rename | Identity was not anchored to the registry unique_id |
Confirm whether the bridge uses stableIdentity, and check whether the serial, the unique suffix or the custom serial changed at the same time. Undo the identity changes you did not need. In an environment that is already commissioned, start from the backup and an assessment of the controller impact rather than renaming over and over |
| A manual link saves but shows no value | The linked entity's state is unavailable, or its device_class and unit do not 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 | autoComposedDevices is off, or an entry has an empty entityId |
Confirm the bridge has autoComposedDevices on, 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 | Automatic battery mapping, a manual batteryEntity, or the entity's own battery attribute is misattached |
Work out which of the three it came in through. Turn disableBatteryMapping on for that primary entity; do not switch battery mapping off globally for every device |
| The utility meter or EVSE endpoint does not appear | The target controller is a known no or unknown for that override | Read the pinned matrix first: Utility Meter is an opt-in override where only SmartThings is a yes; EVSE is an opt-in override where only Aqara Home is a yes, and it must never 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 | Dispatch order or a sensor mapping does not match how the machine actually works | 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 own selection order |
| The slider lags, or the device keeps moving | Debounce and throttle are being confused for one another | 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 |
A gap between the Stable 2.0.55 type definitions and the request / 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 |
The ones that come up again and again
What is the difference between Disabled and Exclude?
disabled is an explicit disable saved for one bridge and one entity, on an endpoint that still exists. Deleting the mapping returns to the automatic settings, which is not the same thing as Exclude either.Does Custom Name change the name or the entity_id in Home Assistant?
nodeLabel only. Renaming in Home Assistant itself is a separate operation; if you want the identity to hold steady in the controller across that rename, look at stableIdentity separately.Does a gray controller chip always mean it is unsupported?
Is a Mapping Profile a full backup?
EntityMappingConfig — the identity fields, composedEntities and several vacuum and select-switch helpers are all missing from it. Use the Backup mechanism for a full restore.Does a device image show up in Apple Home or Alexa?
Do I still need manual mapping once Auto Composed Devices is on?
Are composedEntities and humidityEntity the same thing?
composedEntities builds a sub-endpoint carrying an entityId and an optional type, and it requires autoComposedDevices. humidityEntity links humidity data into the relevant cluster on the primary device instead — no sub-endpoint is created.Can I put any sensor into powerEntity?
device_class and a matching power unit. It will not reliably correct a wrong meaning just because you picked it in the autocomplete, so cross-check the HA state metadata first.Do the lock helpers put a real credential into a tutorial or a profile?
Does a larger updateThrottleMs mean more stability?
Why does the utility meter or EVSE type not show up on my controller?
Where to go from here
You can now fix one endpoint by hand, and merge scattered entities into one Matter device instead of a pile of fragments.
The next part goes device by device: the exact mapping rules for switches, lights, covers, fans and climate controls, and then the sensor and energy side — which device class becomes which Matter measurement, and where the edge cases live for each one.
Open the full guidePart 5 of the Home Assistant Matter Hub Complete Guide series on the Apporo blog.
Adapted from the Home Assistant Matter Hub Complete Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.
Light · Air · Water · Control · apporo