A custom integration that finds and deletes orphan entities - entities left in the registry after the integration that created them has been removed or failed - via a web panel in the sidebar and services callable from scripts and automations.
- Open HACS in your Home Assistant instance
- Search for Orphan Entity Cleaner and install
- Restart Home Assistant
- Settings → Devices & Services → Add Integration → Orphan Entity Cleaner
- Copy the
custom_components/orphan_cleaner/folder to<config>/custom_components/ - Restart Home Assistant
- Settings → Devices & Services → Add Integration → Orphan Entity Cleaner
After installation, the Orphan Cleaner icon appears in the HA sidebar. All settings are controlled directly from the panel - no configuration flow needed after the initial setup.
| Control | Description |
|---|---|
| Scan | Scans the registry and populates the table |
| Heuristic | Enables detection method 4 (see below) |
| Min age (h) | Minimum age in hours for an entity to be flagged |
| Ignore | Add platforms or globs to exclude from the current session |
| Default ignore list | Persistent ignore list, pre-loaded on every scan (see below) |
| Dry run | Simulate deletion without removing anything (see below) |
| Filter | Filter visible results by entity_id or platform |
| Select all / Deselect | Bulk checkbox controls |
| Column headers | Click to sort by Entity ID, Platform, Detection or Age - click again to reverse |
| Platform badge | Click on any platform badge to instantly select all entities of that platform |
| Detection filter | Dropdown to show only dead entry, unavailable, timestamp or heuristic entities |
| Delete selected | Delete selected entities with a confirmation dialog |
| Save & Delete | Save a JSON backup of selected entities to /config/ before deleting |
Type a platform name or glob pattern in the Ignore field in the control bar and press Enter or + Add. Ignored entities remain visible in the table but are greyed out and non-interactive. The orphan counter reflects the exclusion. This list is temporary and resets on page reload.
A collapsible section below the control bar. Entries here are saved to the integration's config entry options and automatically loaded on every scan and page load. Supports:
- Platform names -
tuya,shelly,imou_life - Platform globs -
imou_*,tuya_* - Entity ID globs -
sensor.old_*,*_deprecated,sensor.*_temp
Entries are saved automatically when added or removed - no Save button needed. Use the ? link for a full syntax reference.
Save & Delete exports a timestamped JSON backup of the selected entities to /config/orphan_cleaner_backup_<timestamp>.json before proceeding with deletion. If the backup fails, deletion is aborted. The backup contains entity metadata (entity_id, platform, detection method, age, disabled state) and can be used as a reference in case of accidental deletion.
Enable the Dry run checkbox in the toolbar before deleting. When active:
- An amber warning banner appears to remind you that no changes will be made
- Delete selected becomes Simulate
- Save & Delete is hidden
- Clicking Simulate highlights the selected entities with a
would deletebadge for 6 seconds and logs the result - nothing is actually removed
Dry run is also available as a parameter in the orphan_cleaner.delete_orphans service (see Services section).
After the first scan, every subsequent scan shows a diff banner above the table:
vs previous scan: 3 new ⬆ · 1 gone ⬇ · 108 unchanged
Entities that are new since the last scan are highlighted with a yellow new badge. The banner is hidden when results are identical to the previous scan.
Click any column header in the results table to sort by that field. Click again to reverse the order. The active sort direction is indicated by ↑ or ↓ next to the column name. Sortable columns: Entity ID, Platform, Detection, Age.
After each scan, a compact bar appears below the stat cards showing the count per detection method:
32 dead entry · 7 unavailable · 0 timestamp · 0 heuristic
Each count is colour-coded: dead entry in neutral, unavailable in amber, timestamp in green, heuristic in violet.
A dropdown in the toolbar lets you filter the table to show only entities detected by a specific method: Dead entry, Unavailable, Timestamp or Heuristic. Combine it with the text filter for precise results.
Click any platform badge in the results table to instantly select all entities of that platform. Useful for quickly selecting a full group before deleting or ignoring.
Home Assistant sets this field in the registry when, after a full restart, an entity is not claimed by any integration. This is the official signal and is always active.
Min age (h) filters out recently orphaned entities, useful if an integration is temporarily offline. Ages above 24 hours are displayed in days (e.g. 377d) in the panel table.
If an entity's config_entry_id points to a config entry that no longer exists or is in a FAILED / NOT_LOADED state, the entity is considered an orphan.
Entities in unavailable state for longer than Min age (h) are flagged. Catches entities that HA marks with the yellow warning "no longer provided by the integration".
Enabled by the Heuristic checkbox. Also flags entities with no config_entry_id and a platform not in the following exclusion list:
automation, counter, group, input_boolean, input_button, input_datetime, input_number, input_select, input_text, person, persistent_notification, scene, schedule, script, tag, template, timer, zone
Runs the scan and fires the orphan_cleaner_orphans_found event on the HA event bus.
action: orphan_cleaner.scanEvent payload:
count: 5
orphans:
- entity_id: sensor.old_shelly
platform: shelly
method: timestamp
age_hours: 72.3
disabled_by: nullExample automation:
automation:
trigger:
platform: event
event_type: orphan_cleaner_orphans_found
condition:
condition: template
value_template: "{{ trigger.event.data.count > 0 }}"
action:
service: notify.mobile_app
data:
title: "Orphan entities detected"
message: "Found {{ trigger.event.data.count }} orphan entities."Deletes the specified entities, or all detected orphans if none are specified.
| Field | Type | Required | Description |
|---|---|---|---|
entity_ids |
list | No | Entities to delete. If omitted → all orphans |
dry_run |
bool | No | Log only, without making changes (default: false) |
# Delete all orphans
action: orphan_cleaner.delete_orphans
# Dry run
action: orphan_cleaner.delete_orphans
data:
dry_run: true
# Delete specific entities
action: orphan_cleaner.delete_orphans
data:
entity_ids:
- sensor.old_device
- binary_sensor.ghost_sensorcustom_components/orphan_cleaner/
├── __init__.py ← setup, panel registration, teardown
├── config_flow.py ← initial config flow
├── const.py ← constants
├── manifest.json ← integration metadata
├── orphan_detector.py ← detection and deletion logic
├── panel_api.py ← HTTP views (panel, scan, delete, export, ignore list)
├── services.py ← HA services (scan, delete_orphans)
├── services.yaml ← service documentation for Developer Tools
├── strings.json ← UI labels
├── translations/
│ └── en.json
└── frontend/
├── panel.html ← full web interface
└── orphan-cleaner-panel.js
If you used Save & Delete, a backup file was written to /config/orphan_cleaner_backup_<timestamp>.json before the deletion. This file contains the metadata of all deleted entities.
{
"exported_at": "2024-11-15T10:32:00",
"entity_count": 3,
"entities": [
{
"entity_id": "sensor.old_device_temperature",
"platform": "tuya",
"method": "dead_entry",
"age_hours": 312.5,
"disabled_by": null
}
]
}- Check if the entity was truly orphaned - look at the
methodandage_hoursfields. Ifage_hoursis low, the integration may have been temporarily offline and the entity could reappear after a restart. - Reinstall the integration - if the platform (e.g.
tuya,shelly,zha) is still active and the physical device is reachable, removing and re-adding the integration will recreate its entities automatically. - Restore custom attributes manually - if the entity reappears, you can reassign its area, icon, and aliases from the HA UI. The backup gives you the original
entity_idto match it. - Clean up the recorder - if the entity had historical data and you want to remove it, use the
recorder.purge_entitiesservice with theentity_idfrom the backup.
- The entity registry entry itself - HA does not expose an API to re-insert entries manually.
- Historical recorder data is not deleted by this integration, but it will no longer be linked to an active entity.
- If the underlying integration or device no longer exists, the entity cannot be recreated without it.
All API endpoints require Home Assistant authentication. The panel itself requires admin privileges to access from the sidebar (require_admin). Endpoints that delete entities or write files to the configuration directory (/delete, /export) additionally require an admin-level account, regardless of how they are called. Read-only endpoints (/scan, /ignore_list GET) require a valid authenticated session but not admin rights.
- Always make a backup before deleting entities in bulk. Use Save & Delete to automatically export a JSON record before each deletion.
- Deleted entities are removed from the registry: historical data in the recorder remains but is no longer associated with an active entity. To clean the recorder as well, use the
recorder.purge_entitiesservice. - An entity with
orphaned_timestampmay belong to an integration that is temporarily offline. Increase Min age (h) if you have unstable integrations. - Deletion is irreversible. Entities cannot be restored from the backup - the backup is a reference record only.
MIT