Skip to content

Commit

Permalink
Add repairs: Unknown group members (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
frenck authored Mar 4, 2023
1 parent 8d17992 commit 85e78dc
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ or to be supported, or well, for starters, to be a good idea.
- [Service for `select`: Select random option](#service-for-select-select-random-option)
- [Repairs](#repairs)
- [Automations: Find use of non-existing areas, devices and entities](#automations-find-use-of-non-existing-areas-devices-and-entities)
- [Groups: Detect unknown group members](#groups-detect-unknown-group-members)
- [Obsolete integration YAML configuration](#obsolete-integration-yaml-configuration)
- [Scripts: Find use of non-existing areas, devices and entities](#scripts-find-use-of-non-existing-areas-devices-and-entities)
- [Frequently Asked Questions](#frequently-asked-questions)
Expand Down Expand Up @@ -416,6 +417,12 @@ Currently Spook will detect the following issues:
_Intention to contribute back to Home Assistant Core once sure no false
postives remain, and it has been extended to catch more situations._

## Groups: Detect unknown group members

> Finds groups that contain references to unknown members (entities). _#aliens_
_Intention to contribute back to Home Assistant Core._

## Obsolete integration YAML configuration

> Finds YAML configuration for an integrations that no longer support it.
Expand Down
108 changes: 108 additions & 0 deletions custom_components/spook/repairs/group_unknown_members.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""Spook - Not your homie."""
from __future__ import annotations

from homeassistant.components import group
from homeassistant.const import (
ENTITY_MATCH_ALL,
ENTITY_MATCH_NONE,
EVENT_COMPONENT_LOADED,
)
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import DATA_ENTITY_PLATFORM, EntityPlatform

from ..const import LOGGER
from . import AbstractSpookRepair


class SpookRepair(AbstractSpookRepair):
"""Spook repair tries to find unknown member entities in groups."""

domain = group.DOMAIN
repair = "group_unknown_members"
events = {
EVENT_COMPONENT_LOADED,
er.EVENT_ENTITY_REGISTRY_UPDATED,
"event_group_reloaded",
"event_input_boolean_reloaded",
"event_input_button_reloaded",
"event_input_number_reloaded",
"event_input_select_reloaded",
"event_input_text_reloaded",
"event_integration_reloaded",
"event_min_max_reloaded",
"event_mqtt_reloaded",
"event_scene_reloaded",
"event_schedule_reloaded",
"event_template_reloaded",
"event_threshold_reloaded",
"event_tod_reloaded",
"event_utility_meter_reloaded",
}

_entity_platforms: list[EntityPlatform]

async def async_activate(self) -> None:
"""Handle the activating a repair."""
self._entity_platforms = self.hass.data[DATA_ENTITY_PLATFORM][self.domain]
await super().async_activate()

async def async_inspect(self) -> None:
"""Trigger a inspection."""
LOGGER.debug("Spook is inspecting: %s", self.repair)

# Two sources for entities. The entities in the entity registry,
# and the entities currently in the state machine. They will have lots
# of overlap, but not all entities are in the entity registry and
# not all have to be in the state machine right now.
# Furthermore, add `all` and `none` to the list of known entities,
# as they are valid targets.
entity_ids = (
{entity.entity_id for entity in self.entity_registry.entities.values()}
.union(self.hass.states.async_entity_ids())
.union({ENTITY_MATCH_ALL, ENTITY_MATCH_NONE})
)

for platform in self._entity_platforms:
# We don't want to check the old style group platform
for entity in platform.entities.values():
members = []
if platform.domain == group.DOMAIN:
members = entity.tracking
elif hasattr(entity, "_entity_ids"):
# pylint: disable-next=protected-access
members = entity._entity_ids # noqa: SLF001
elif hasattr(entity, "_entities"):
# pylint: disable-next=protected-access
members = entity._entities # noqa: SLF001

# Filter out scenes, groups & device_tracker entities.
# Those can be created on the fly with services, which we
# currently cannot detect yet. Let's prevent some false positives.
if unknown_entities := {
entity_id
for entity_id in members
if (
not entity_id.startswith(
("device_tracker.", "group.", "scene."),
)
and entity_id not in entity_ids
)
}:
self.async_create_issue(
issue_id=entity.entity_id,
translation_placeholders={
"entities": "\n".join(
f"- `{entity_id}`" for entity_id in unknown_entities
),
"group": entity.name,
"entity_id": entity.entity_id,
},
)
LOGGER.debug(
"Spook found unknown member entities in %s "
"and created an issue for it; Entities: %s",
entity.entity_id,
", ".join(unknown_entities),
)
else:
self.async_delete_issue(entity.entity_id)
4 changes: 4 additions & 0 deletions custom_components/spook/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
"title": "Unknown entities used in: {automation}",
"description": "Spook has found a ghost in your automations πŸ‘»\n\nWhile floating around, Spook crossed path with the following automation:\n\n[{automation}]({edit}) (`{entity_id}`)\n\nThis automation references the following entities, which are unknown to Home Assistant:\n\n{entities}\n\n\n\nTo fix this error, [edit the automation]({edit}) and remove the use of these non-existing entities.\n\nSpook πŸ‘» Not your homie."
},
"group_unknown_members": {
"title": "Unknown group members in: {group}",
"description": "Spook has found a ghost in your groups πŸ‘»\n\nWhile floating around, Spook crossed path with the following group:\n\n{group} (`{entity_id}`)\n\nThis group has members, which are unknown to Home Assistant:\n\n{entities}\n\n\n\nTo fix this error, edit the group, remove the use of these non-existing entities and restart Home Assistant.\n\nSpook πŸ‘» Not your homie."
},
"obsolete_integration_yaml_config": {
"title": "Obsolete YAML for: {domain}",
"description": "Spook has found a ghost in your YAML configuration πŸ‘»\n\nWhile floating around, Spook came aroud YAML configuration for the `{domain}` integration, which is obsolete (as it is no longer configured via YAML) and thus should be removed/cleaned up. This issue will automatically disappear once your configuration has been adjusted and Home Assistant has been restarted.\n\nSpook πŸ‘» Not your homie."
Expand Down

0 comments on commit 85e78dc

Please sign in to comment.