456 files
This commit is contained in:
1 parent
4192ecbaae
commit
5d6d845ebf
456 files changed
+64951
-3828
No files matched your search
@@ -9,6 +9,7 @@ from homeassistant.helpers import area_registry as ar
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ..task_origin import origin_is_duty, task_origin
|
||||
from ._model import (
|
||||
_entity_matches,
|
||||
_entity_unit,
|
||||
@@ -42,6 +43,11 @@ def _entity_watchers(hass: HomeAssistant) -> dict[str, set[str]]:
|
||||
base = catalog_base_name(name)
|
||||
if base != name and base in known:
|
||||
name = base
|
||||
# 2.95: a task adopted from a duty claims as that duty,
|
||||
# whatever it is called now (its fingerprint).
|
||||
origin = task_origin(task)
|
||||
if origin is not None and origin.get("kind") == "integration" and origin.get("duty"):
|
||||
name = origin["duty"].lower()
|
||||
for eid in normalize_entity_ids(tc):
|
||||
out.setdefault(eid, set()).add(name)
|
||||
return out
|
||||
@@ -80,6 +86,42 @@ def _matches_catalog_key(entry: er.RegistryEntry, key: str, catalog_keys: set[st
|
||||
)
|
||||
|
||||
|
||||
def reset_button_for(
|
||||
hass: HomeAssistant,
|
||||
sig: Any,
|
||||
matched: list[er.RegistryEntry],
|
||||
device_id: str,
|
||||
integration: str,
|
||||
catalog_keys: set[str],
|
||||
*,
|
||||
tk_authoritative: bool = False,
|
||||
) -> dict[str, Any] | None:
|
||||
"""The integration's own reset button for this duty's counter on the same
|
||||
device (2.95, helpers/reset_wiring.py) — ``{entity_id, name, disabled}``,
|
||||
or None when the duty has none or the button is missing / user-disabled."""
|
||||
if not sig.resets or not matched:
|
||||
return None
|
||||
from ..reset_wiring import pressable_reset_buttons
|
||||
|
||||
buttons = pressable_reset_buttons(hass, device_id, integration)
|
||||
for entry in matched:
|
||||
for sensor_key, button_key in sig.resets:
|
||||
if not _matches_catalog_key(entry, sensor_key, catalog_keys, tk_authoritative=tk_authoritative):
|
||||
continue
|
||||
hits = [b for b in buttons if _entity_matches(b, button_key, tk_authoritative=tk_authoritative)]
|
||||
# Several buttons under one key (a Matter purifier's HEPA and
|
||||
# carbon filter both reset via 'reset_filter_condition') cannot be
|
||||
# told apart — wiring a guess could reset the wrong filter.
|
||||
if len(hits) == 1:
|
||||
button = hits[0]
|
||||
return {
|
||||
"entity_id": button.entity_id,
|
||||
"name": button.name or button.original_name or button.entity_id,
|
||||
"disabled": button.disabled_by is not None,
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
def _appliance_type(hass: HomeAssistant, device: Any, integration: str, key: str | None) -> str | None:
|
||||
"""The appliance type the integration's own config entry names for this
|
||||
device (WashData: ``device_type``) — options first, then data."""
|
||||
@@ -93,15 +135,32 @@ def _appliance_type(hass: HomeAssistant, device: Any, integration: str, key: str
|
||||
return None
|
||||
|
||||
|
||||
def _adopted_as(tasks: dict[str, Any], integration: str | None, proposal: dict[str, Any]) -> str | None:
|
||||
"""The name of the target's task adopted from this very duty (and entity
|
||||
label, for per-entity duties) — found by its fingerprint, not its name."""
|
||||
if not integration:
|
||||
return None
|
||||
for task in tasks.values():
|
||||
origin = task_origin(task)
|
||||
if (
|
||||
origin_is_duty(task, integration, proposal["catalog_task_name"], proposal["direction"])
|
||||
and origin is not None
|
||||
and (origin.get("entity_label") or None) == (proposal.get("entity_label") or None)
|
||||
):
|
||||
return str(task.get("name", ""))
|
||||
return None
|
||||
|
||||
|
||||
def annotate_for_target(
|
||||
hass: HomeAssistant, proposals: list[dict[str, Any]], entry: Any, *, device_name: str = ""
|
||||
hass: HomeAssistant, proposals: list[dict[str, Any]], entry: Any, *, device_name: str = "", integration: str | None = None
|
||||
) -> tuple[list[dict[str, Any]], list[dict[str, str]]]:
|
||||
"""Split proposals against the target object's tasks (2.94).
|
||||
|
||||
A duty the target already has BY NAME (any language) goes to ``already``
|
||||
with the existing task's name — shown, never adopted. The rest keeps
|
||||
``covered_by`` (helpers.adopt_match.covering_task): a likely duplicate
|
||||
under another name, which the dialog shows unticked.
|
||||
under another name, which the dialog shows unticked. A task adopted from
|
||||
the same duty counts as present under any name (2.95 fingerprint).
|
||||
"""
|
||||
from ...const import CONF_TASKS
|
||||
from ..adopt_match import covering_task
|
||||
@@ -113,8 +172,9 @@ def annotate_for_target(
|
||||
already: list[dict[str, str]] = []
|
||||
for proposal in proposals:
|
||||
hit = set(by_lower) & proposal_name_variants(proposal["catalog_task_name"], proposal["entity_label"])
|
||||
if hit:
|
||||
already.append({"task_name": proposal["task_name"], "task_name_localized": proposal["task_name_localized"], "existing_name": by_lower[sorted(hit)[0]]})
|
||||
existing = by_lower[sorted(hit)[0]] if hit else _adopted_as(tasks, integration, proposal)
|
||||
if existing is not None:
|
||||
already.append({"task_name": proposal["task_name"], "task_name_localized": proposal["task_name_localized"], "existing_name": existing})
|
||||
continue
|
||||
covered = (
|
||||
covering_task(hass, (proposal["task_name_localized"], proposal["task_name"]), proposal["entity_ids"], tasks, ignore=ignore)
|
||||
@@ -252,6 +312,7 @@ def discover_integration_setups(hass: HomeAssistant, *, targets: dict[str, str]
|
||||
else:
|
||||
target_id = suggested["entry_id"] if suggested else (candidate["entry_id"] if candidate else None)
|
||||
target = hass.config_entries.async_get_entry(target_id) if target_id else None
|
||||
device_catalog_keys = {key for s in catalog.tasks for key in s.keys}
|
||||
raw: list[dict[str, Any]] = []
|
||||
for (_integ, task_name, direction), group in sig_map.items():
|
||||
entity_ids = sorted(group["entity_ids"])
|
||||
@@ -283,13 +344,23 @@ def discover_integration_setups(hass: HomeAssistant, *, targets: dict[str, str]
|
||||
"entity_ids": ids,
|
||||
"threshold": _threshold_for(sig, hass, ids[0]),
|
||||
"direction": direction,
|
||||
# 2.95: completing it also presses this reset button
|
||||
"reset": reset_button_for(
|
||||
hass,
|
||||
sig,
|
||||
[group["entries"][eid] for eid in ids],
|
||||
device_id,
|
||||
integration,
|
||||
device_catalog_keys,
|
||||
tk_authoritative=catalog.translation_keys_authoritative,
|
||||
),
|
||||
}
|
||||
)
|
||||
# Duties already present on the target BY NAME (any language) are not
|
||||
# proposed — covers manually created calendar tasks whose trigger
|
||||
# watches no entity (the entity-watched exclusion misses them); since
|
||||
# 2.94 they are listed as ``already`` so the dialog can say so.
|
||||
tasks, already = annotate_for_target(hass, raw, target, device_name=device_name)
|
||||
tasks, already = annotate_for_target(hass, raw, target, device_name=device_name, integration=integration)
|
||||
if not tasks and targets is None:
|
||||
continue
|
||||
tasks.sort(key=lambda t: (t["task_name"], t["direction"]))
|
||||
|
||||
Reference in new issue
Block a user