v2.3.0 — добавлен инструмент list_devices для диагностики и инвентаризации

This commit is contained in:
2026-07-29 19:41:44 +03:00
parent 13141bc22f
commit 4e60484270
+107 -2
View File
@@ -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
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)