208 files
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -54,6 +54,28 @@ repair_issue_present:
|
||||
- critical
|
||||
- error
|
||||
- warning
|
||||
is_at_target_temperature:
|
||||
target:
|
||||
entity:
|
||||
- domain: climate
|
||||
- domain: water_heater
|
||||
fields:
|
||||
behavior:
|
||||
required: true
|
||||
default: any
|
||||
selector:
|
||||
automation_behavior:
|
||||
mode: condition
|
||||
tolerance:
|
||||
required: false
|
||||
default: 0
|
||||
example: 0.5
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 10
|
||||
step: 0.1
|
||||
mode: box
|
||||
quota:
|
||||
fields:
|
||||
limit:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -8,7 +8,10 @@ from homeassistant.components import automation
|
||||
from homeassistant.helpers import area_registry as ar
|
||||
|
||||
from ....entity_filtering import async_filter_known_area_ids, async_get_all_area_ids
|
||||
from ....reference_extraction import extract_targets_from_config
|
||||
from ....reference_extraction import (
|
||||
extract_targets_from_config,
|
||||
only_in_disabled_steps,
|
||||
)
|
||||
from . import AbstractSpookAutomationReferencesRepair
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -45,6 +48,10 @@ class SpookRepair(AbstractSpookAutomationReferencesRepair):
|
||||
# references nested in some step types, like repeat sequences.
|
||||
if raw_config := getattr(entity, "raw_config", None):
|
||||
area_ids.update(extract_targets_from_config(raw_config).area_ids)
|
||||
# A disabled step does nothing, so what only it names is left out.
|
||||
area_ids -= only_in_disabled_steps(
|
||||
raw_config, lambda found: extract_targets_from_config(found).area_ids
|
||||
)
|
||||
|
||||
return async_filter_known_area_ids(
|
||||
self.hass,
|
||||
|
||||
@@ -8,7 +8,10 @@ from homeassistant.components import automation
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from ....entity_filtering import async_filter_known_device_ids, async_get_all_device_ids
|
||||
from ....reference_extraction import extract_targets_from_config
|
||||
from ....reference_extraction import (
|
||||
extract_targets_from_config,
|
||||
only_in_disabled_steps,
|
||||
)
|
||||
from ....template_extraction import extract_device_ids_from_config
|
||||
from . import AbstractSpookAutomationReferencesRepair
|
||||
|
||||
@@ -91,6 +94,14 @@ class SpookRepair(AbstractSpookAutomationReferencesRepair):
|
||||
)
|
||||
# Devices referenced via device_entities() in templates.
|
||||
device_ids.update(extract_device_ids_from_config(entity.raw_config))
|
||||
# A disabled step does nothing, so what only it names is left out.
|
||||
device_ids -= only_in_disabled_steps(
|
||||
entity.raw_config,
|
||||
lambda found: (
|
||||
extract_targets_from_config(found).device_ids
|
||||
| extract_device_ids_from_config(found)
|
||||
),
|
||||
)
|
||||
|
||||
return async_filter_known_device_ids(
|
||||
self.hass,
|
||||
|
||||
@@ -13,6 +13,7 @@ from ....action_extraction import (
|
||||
async_extract_entities_from_value,
|
||||
)
|
||||
from ....entity_filtering import async_get_all_entity_ids, async_get_all_services
|
||||
from ....reference_extraction import without_disabled_steps
|
||||
from ....template_extraction import (
|
||||
KNOWN_DOMAINS,
|
||||
async_extract_entities_from_config,
|
||||
@@ -291,6 +292,21 @@ class SpookRepair(AbstractSpookAutomationReferencesRepair):
|
||||
)
|
||||
self._known_services = async_get_all_services(self.hass)
|
||||
|
||||
async def _async_named_in(self, config: dict[str, Any]) -> set[str]:
|
||||
"""Return the entities a configuration names, the way this repair reads it.
|
||||
|
||||
The same reading the report is built from, structure and templates
|
||||
alike, so comparing it with and without the disabled steps leaves out
|
||||
exactly what only those name.
|
||||
"""
|
||||
named = await extract_entities_from_automation_config(
|
||||
self.hass, config, self._known_services
|
||||
)
|
||||
named |= await async_extract_entities_from_config(
|
||||
self.hass, config, self._known_services
|
||||
)
|
||||
return named
|
||||
|
||||
async def _async_compute_unknown_references(self, entity: Any) -> set[str]:
|
||||
"""Return unknown entity IDs referenced by ``entity`` (incl. templates)."""
|
||||
all_entities = set(entity.referenced_entities)
|
||||
@@ -314,6 +330,15 @@ class SpookRepair(AbstractSpookAutomationReferencesRepair):
|
||||
)
|
||||
)
|
||||
|
||||
# Home Assistant's own list includes disabled steps, triggers and
|
||||
# conditions too. Something parked that way does nothing, so what only
|
||||
# it names is left out of the report: whatever this repair finds in
|
||||
# the configuration, and no longer finds once those are pruned.
|
||||
if isinstance(raw_config := getattr(entity, "raw_config", None), dict):
|
||||
named = await self._async_named_in(raw_config)
|
||||
still_named = await self._async_named_in(without_disabled_steps(raw_config))
|
||||
all_entities -= named - still_named
|
||||
|
||||
return await async_filter_known_entity_ids_with_templates(
|
||||
self.hass,
|
||||
entity_ids=all_entities,
|
||||
|
||||
@@ -8,7 +8,10 @@ from homeassistant.components import automation
|
||||
from homeassistant.helpers import floor_registry as fr
|
||||
|
||||
from ....entity_filtering import async_filter_known_floor_ids, async_get_all_floor_ids
|
||||
from ....reference_extraction import extract_targets_from_config
|
||||
from ....reference_extraction import (
|
||||
extract_targets_from_config,
|
||||
only_in_disabled_steps,
|
||||
)
|
||||
from . import AbstractSpookAutomationReferencesRepair
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -44,6 +47,10 @@ class SpookRepair(AbstractSpookAutomationReferencesRepair):
|
||||
# references nested in some step types, like repeat sequences.
|
||||
if raw_config := getattr(entity, "raw_config", None):
|
||||
floor_ids.update(extract_targets_from_config(raw_config).floor_ids)
|
||||
# A disabled step does nothing, so what only it names is left out.
|
||||
floor_ids -= only_in_disabled_steps(
|
||||
raw_config, lambda found: extract_targets_from_config(found).floor_ids
|
||||
)
|
||||
|
||||
return async_filter_known_floor_ids(
|
||||
self.hass,
|
||||
|
||||
@@ -8,7 +8,10 @@ from homeassistant.components import automation
|
||||
from homeassistant.helpers import label_registry as lr
|
||||
|
||||
from ....entity_filtering import async_filter_known_label_ids, async_get_all_label_ids
|
||||
from ....reference_extraction import extract_targets_from_config
|
||||
from ....reference_extraction import (
|
||||
extract_targets_from_config,
|
||||
only_in_disabled_steps,
|
||||
)
|
||||
from . import AbstractSpookAutomationReferencesRepair
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -44,6 +47,10 @@ class SpookRepair(AbstractSpookAutomationReferencesRepair):
|
||||
# references nested in some step types, like repeat sequences.
|
||||
if raw_config := getattr(entity, "raw_config", None):
|
||||
label_ids.update(extract_targets_from_config(raw_config).label_ids)
|
||||
# A disabled step does nothing, so what only it names is left out.
|
||||
label_ids -= only_in_disabled_steps(
|
||||
raw_config, lambda found: extract_targets_from_config(found).label_ids
|
||||
)
|
||||
|
||||
return async_filter_known_label_ids(
|
||||
self.hass,
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,13 +13,47 @@ from homeassistant.components.homeassistant.exposed_entities import (
|
||||
async_expose_entity,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
|
||||
CONF_ASSISTANTS = "assistants"
|
||||
CONF_CONFIG_ENTRY_ID = "config_entry_id"
|
||||
CONF_DOMAIN = "domain"
|
||||
|
||||
CONFIG_ENTRY_SERVICE_SCHEMA = {
|
||||
vol.Optional(CONF_CONFIG_ENTRY_ID): vol.All(cv.ensure_list, [cv.string]),
|
||||
# Every entry of these integrations: the ones added later included, which
|
||||
# a list of entry IDs written down today would miss.
|
||||
vol.Optional(CONF_DOMAIN): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
|
||||
def async_config_entry_ids(hass: HomeAssistant, call: ServiceCall) -> list[str]:
|
||||
"""Return the integration entries an action asks for, by ID and by domain.
|
||||
|
||||
A domain without any entries is refused rather than skipped: a typo in it
|
||||
would otherwise do nothing, and say nothing about it either.
|
||||
"""
|
||||
entry_ids: list[str] = list(call.data.get(CONF_CONFIG_ENTRY_ID, []))
|
||||
domains: list[str] = call.data.get(CONF_DOMAIN, [])
|
||||
|
||||
if not entry_ids and not domains:
|
||||
msg = "Name the integration entries to change, or their integration"
|
||||
raise ServiceValidationError(msg)
|
||||
|
||||
for domain in domains:
|
||||
if not (entries := hass.config_entries.async_entries(domain)):
|
||||
msg = f"The {domain} integration has no entries"
|
||||
raise ServiceValidationError(msg)
|
||||
entry_ids.extend(
|
||||
entry.entry_id for entry in entries if entry.entry_id not in entry_ids
|
||||
)
|
||||
|
||||
return entry_ids
|
||||
|
||||
|
||||
EXPOSURE_SERVICE_SCHEMA = {
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -4,13 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryDisabler
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
from . import CONFIG_ENTRY_SERVICE_SCHEMA, async_config_entry_ids
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
@@ -21,11 +19,11 @@ class SpookService(AbstractSpookAdminService):
|
||||
|
||||
domain = DOMAIN
|
||||
service = "disable_config_entry"
|
||||
schema = {vol.Required("config_entry_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
schema = CONFIG_ENTRY_SERVICE_SCHEMA
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
for config_entry_id in call.data["config_entry_id"]:
|
||||
for config_entry_id in async_config_entry_ids(self.hass, call):
|
||||
await self.hass.config_entries.async_set_disabled_by(
|
||||
config_entry_id,
|
||||
disabled_by=ConfigEntryDisabler.USER,
|
||||
|
||||
@@ -4,12 +4,10 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
from . import CONFIG_ENTRY_SERVICE_SCHEMA, async_config_entry_ids
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
@@ -20,11 +18,11 @@ class SpookService(AbstractSpookAdminService):
|
||||
|
||||
domain = DOMAIN
|
||||
service = "enable_config_entry"
|
||||
schema = {vol.Required("config_entry_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
schema = CONFIG_ENTRY_SERVICE_SCHEMA
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
for config_entry_id in call.data["config_entry_id"]:
|
||||
for config_entry_id in async_config_entry_ids(self.hass, call):
|
||||
await self.hass.config_entries.async_set_disabled_by(
|
||||
config_entry_id,
|
||||
disabled_by=None,
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user