Files
wiki/tasks/ha-availability-dashboard/TZ.md
2026-04-15 00:40:01 +03:00

157 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ТЗ: Дашборд доступности устройств в Home Assistant
## Цель
Дашборд, показывающий **uptime устройств** в процентах за три периода: день, неделю, месяц. С сортировкой по убыванию доступности.
## Метрика
**Доступность** = время в статусе «доступен» / общее время периода × 100%
- «Доступен» — любой статус, кроме `unavailable` и `unknown`
- «Недоступен» — статус `unavailable` или `unknown`
- Результат: процент (0%100%), один знак после точки
## Периоды
| Период | Формула | Обновление |
|--------|---------|------------|
| День | за последние 24 часа | каждые 5 мин |
| Неделя | за последние 7 дней | каждые 30 мин |
| Месяц | за последние 30 дней | каждые 2 часа |
## Какие устройства отслеживать
Все entity из доменов физических устройств:
- `binary_sensor`, `sensor`, `switch`, `light`
- `climate`, `cover`, `lock`, `media_player`
- `device_tracker`, `vacuum`, `fan`, `humidifier`
- `water_heater`, `siren`, `button`
**Исключения** (не показывать на дашборде):
- Вспомогательные entity Zigbee2MQTT (`sensor.*_update_state`, `update.*`, `button.zigbee2mqtt_*`)
- Entity с суффиксами `_battery_low`, `_battery`, `_linkquality`, `_update`, `_identify`
- Виртуальные/template сенсоры (без device_id)
- Автоматически создаваемые Select/Number для Zigbee-устройств (настройки radar_sensitivity и т.п.)
## Архитектура решения
### 1. Вычисление доступности — через长期的 sensor
Для каждого отслеживаемого устройства создать **template sensor** (или один Python-скрипт через REST), который:
1. Запрашивает историю из `/api/history/period/<start>?filter_entity_id=<id>&minimal_response&no_attributes`
2. Считает суммарное время в `unavailable`/`unknown`
3. Вычисляет процент доступности
4. Записывает результат как sensor state
### 2. Варианты реализации
#### Вариант A: Utility Meter + Template Sensor (нативный HA)
- На каждое устройство — `binary_sensor` доступности (доступен/нет)
- `utility_meter` считает время в каждом статусе
- Template sensor вычисляет процент
-**Минус:** нужен `custom:utility_meter` или `history_stats` — много entity на каждое устройство, сложная конфигурация при 180+ устройствах
#### Вариант B: Python-скрипт + AppDaemon (рекомендуемый)
- Один Python-скрипт, работающий по расписанию
- Читает историю через HA API для всех устройств сразу
- Вычисляет доступность за все 3 периода
- Создаёт/обновляет `sensor.availability_<entity_id>_<period>` через `states` API
-**Плюсы:** один скрипт, легко масштабировать, минимальная нагрузка на HA
- ⚠️ **Требует:** AppDaemon или HA Python script / custom component
#### Вариант C: Custom HA Integration (HACS)
- Кастомная интеграция, регистрирует sensor-ы через `async_setup_platform`
- Берёт данные из recorder напрямую (SQL)
-**Плюсы:** максимально нативно, работает через recorder без API
- ⚠️ **Минусы:** сложнее разработка, нужен доступ к БД recorder
#### Вариант D: SQL Sensor + Jinja (самый простой)
- `sql` integration — прямые запросы к MariaDB/SQLite recorder
- Один sensor на устройство×период с SQL-запросом
-**Плюсы:** без внешних зависимостей, работает из коробки
-**Минусы:** 180 устройств × 3 периода = 540 SQL-запросов по расписанию — нагрузка на БД
### Рекомендация: Вариант B (AppDaemon / Python-скрипт)
Оптимальный баланс сложности и производительности. Один скрипт, batch-обработка, минимальная нагрузка.
## Дашборд
### Карточка: таблица доступности
```
┌──────────────────────────┬────────┬────────┬────────┐
│ Устройство │ День │ Неделя │ Месяц │
├──────────────────────────┼────────┼────────┼────────┤
│ 💡 Бра в спальне │ 99.8% │ 98.5% │ 95.2% │
│ 🔌 Лесной колодец насос │ 100.0% │ 99.1% │ 97.8% │
│ 🌡️ Улица температура │ 85.3% │ 92.1% │ 88.7% │
│ ... │ ... │ ... │ ... │
└──────────────────────────┴────────┴────────┴────────┘
```
**Функциональность:**
- Сортировка по любому столбцу (по умолчанию — по месячной доступности, убывание)
- Цветовая индикация:
- 🟢 99-100% — зелёный
- 🟡 95-99% — жёлтый
- 🟠 90-95% — оранжевый
- 🔴 <90% — красный
- Фильтр по домену (switch, sensor, light...)
- Обновление: при загрузке дашборда + по расписанию
### Карточка: сводка
```
┌──────────────────────────────────┐
│ 📊 Доступность устройств │
│ │
│ Средняя за день: 97.3% │
│ Средняя за неделю: 96.1% │
│ Средняя за месяц: 94.8% │
│ │
│ Устройств <95% (месяц): 5 │
│ Устройств <90% (месяц): 2 │
└──────────────────────────────────┘
```
## Технические детали
### Источник данных
- HA History API: `/api/history/period/<start>?filter_entity_id=<ids>&minimal_response&no_attributes`
- Возвращает массив пар `(state, last_changed)` — достаточно для расчёта времени
### Расчёт (алгоритм)
```python
def calc_availability(history_entries, period_start, period_end):
unavailable_seconds = 0
for entry in history_entries:
state = entry['state']
changed = parse_datetime(entry['last_changed'])
if state in ('unavailable', 'unknown'):
# Сколько времени устройство было в этом статусе
# до следующего изменения или до period_end
next_change = get_next_change(entry) or period_end
unavailable_seconds += (next_change - changed).total_seconds()
total_seconds = (period_end - period_start).total_seconds()
availability = (1 - unavailable_seconds / total_seconds) * 100
return round(availability, 1)
```
### Хранение результатов
- Каждый результат — `sensor.avail_<sanitized_id>_<period>`
- Атрибуты: `entity_id`, `period`, `availability_%`, `last_updated`
- Группировка: `group.availability_day`, `group.availability_week`, `group.availability_month`
### Нагрузка
- ~180 устройств
- History API batch-запрос (можно передать несколько entity_id через запятую)
- За день: ~180 × 3 = 540 точек данных (при batch — 3 API-вызова)
- За неделю/месяц: данные уже рассчитаны, обновляются реже
## Ограничения
- `purge_keep_days` в recorder — по умолчанию 10 дней. Для месячной статистики нужно **увеличить до 35 дней**
- Если устройство добавлено недавно — показывать доступность с момента добавления (не с начала периода)
- Если устройство удалено — перестать показывать на дашборде
## Что нужно от Славы
1. Подтвердить вариант реализации (рекомендую B — AppDaemon/Python)
2. Увеличить `purge_keep_days` до 35 (иначе не будет данных за месяц)
3. Установить AppDaemon (если выбран вариант B) — или подтвердить другой вариант
4. Подтвердить список исключений (какие entity не отслеживать)