auto-sync: 2026-04-15 00:40:01

This commit is contained in:
Stream
2026-04-15 00:40:01 +03:00
parent 937d082740
commit 2925fd8e0c

View File

@@ -0,0 +1,156 @@
# ТЗ: Дашборд доступности устройств в 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 не отслеживать)