From 4e60484270ce789fc82e6208997051fd3f57e427 Mon Sep 17 00:00:00 2001 From: host Date: Wed, 29 Jul 2026 19:41:44 +0300 Subject: [PATCH] =?UTF-8?q?v2.3.0=20=E2=80=94=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=20list=5Fdevices=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=B0=D0=B3=D0=BD=D0=BE=D1=81=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B8=20=D0=B8=D0=BD=D0=B2=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- home_assistant_tools.py | 109 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/home_assistant_tools.py b/home_assistant_tools.py index 15e4fbc..2e5d0fb 100644 --- a/home_assistant_tools.py +++ b/home_assistant_tools.py @@ -2,7 +2,7 @@ title: Home Assistant Smart Control description: Управление умным домом через Home Assistant REST API с интерпретацией естественного языка. author: ChatGPT (refactored by MiniMax-M3) -version: 2.2.2 +version: 2.3.0 license: MIT """ @@ -780,4 +780,109 @@ class Tools: else: warnings.append("подходящая сцена не найдена среди " + str(len(all_scripts))) - return actions \ No newline at end of file + return actions + + # ======================================================================== + # Диагностика / справочник устройств (отдельный инструмент) + # ======================================================================== + def list_devices( + self, + domain: str = "", + device_class: str = "", + only_with_state: str = "", + show_unavailable: bool = True, + limit: int = 50, + ) -> str: + """ + Получить список устройств из Home Assistant с фильтрами. + + Используется для инвентаризации: какие устройства есть, в каком состоянии, + какие из них offline. Полезно для отладки и проверки интеграций. + + Args: + domain: фильтр по домену (light, switch, binary_sensor, sensor, climate, ...). + Спецзначение "window_door" — окна и двери. + Пусто — все домены. + device_class: фильтр по device_class атрибуту + (door, window, motion, battery, temperature, ...). + Пусто — все классы. + only_with_state: оставить только с указанным состоянием (on/off/open/closed/...). + Пусто — любые. + show_unavailable: показывать ли устройства со state="unavailable"/"unknown". + limit: максимум устройств в ответе. + + Returns: + Список устройств в формате markdown, сгруппированный по доменам. + """ + if not self.valves.ha_token: + return "Не задан HA Token (Valves)." + + try: + states = self._get_states(force=True) + except Exception as e: + return "Не удалось получить состояния: " + str(e) + + domain = domain.lower().strip() + device_class = device_class.lower().strip() + only_with_state = only_with_state.lower().strip() + + # Фильтрация + filtered: List[Dict[str, Any]] = [] + for s in states: + eid = s["entity_id"] + attrs = s.get("attributes", {}) or {} + cur_state = (s.get("state", "") or "").lower() + dc = (attrs.get("device_class", "") or "").lower() + + # Фильтр по домену + if domain: + if domain == "window_door": + # Спецкатегория: всё что похоже на окно/дверь + if dc not in ("door", "window", "garage_door", "lock") and \ + not any(k in (eid + " " + (attrs.get("friendly_name", "") or "").lower()) + for k in ["окн", "двер", "форточ", "балкон", "калитк", "ворота", "гараж"]): + continue + else: + if not eid.startswith(domain + "."): + continue + + # Фильтр по device_class + if device_class and dc != device_class: + continue + + # Фильтр по состоянию + if only_with_state and cur_state != only_with_state: + continue + + # Скрыть unavailable/unknown + if not show_unavailable and cur_state in ("unavailable", "unknown", "none"): + continue + + filtered.append(s) + + if not filtered: + return ( + "Устройств не найдено по фильтру " + "(domain=" + (domain or "любой") + + ", class=" + (device_class or "любой") + + ", state=" + (only_with_state or "любой") + ")." + ) + + # Группируем по домену + by_domain: Dict[str, List[Dict[str, Any]]] = {} + for s in filtered: + d = s["entity_id"].split(".", 1)[0] + by_domain.setdefault(d, []).append(s) + + lines = ["**Найдено " + str(len(filtered)) + " устройств** (показано до " + str(limit) + "):"] + for d in sorted(by_domain.keys()): + lines.append("") + lines.append("### " + d + " (" + str(len(by_domain[d])) + " шт.)") + for s in by_domain[d][:limit]: + lines.append(self._format_entity(s)) + + if len(filtered) > limit: + lines.append("") + lines.append("... показано " + str(limit) + " из " + str(len(filtered)) + ". Увеличьте `limit` для полного списка.") + + return "\n".join(lines) \ No newline at end of file