auto-sync: 2026-04-15 14:50:01

This commit is contained in:
Stream
2026-04-15 14:50:01 +03:00
parent f685f73512
commit 0b01124af4
3 changed files with 203 additions and 17 deletions

View File

@@ -0,0 +1,131 @@
# HA Availability Dashboard
## Описание
Дашборд доступности устройств в Home Assistant — показывает uptime устройств в % за три периода (24ч / 7д / 30д) с группировкой по комнатам, цветовой индикацией и sparkline.
## Статус
🟡 **В разработке** — бэкенд работает, дашборд не построен
## Ссылки
- **ТЗ:** `TZ.md`
- **Исходники AppDaemon:** `appdaemon/` (локальная копия, деплой → HA)
- **HA:** `https://ha.homenet542.keenetic.pro`
## Архитектура
```
HA History API ──► AppDaemon (availability.py) ──► sensor.avail_* ──► Lovelace Dashboard
├── REST API (supervisor/core/api) — история, states
└── WebSocket (homeassistant:8123) — area/entity/device registry
```
## Файловая структура
### На HA (`/addon_configs/a0d7b954_appdaemon/apps/`)
```
apps/
├── apps.yaml # регистрация: hello_world + availability
├── availability.py # основной модуль (Availability class)
├── availability_utils.py # утилиты (фильтрация, расчёт, форматирование)
└── hello.py # тестовое приложение (оставлено)
```
### Локально (`tasks/ha-availability-dashboard/`)
```
├── TZ.md # полное ТЗ
├── PROJECT.md # этот файл
└── appdaemon/ # локальная копия для редактирования
├── availability.py
├── availability_utils.py
└── apps.yaml
```
## Компоненты
### AppDaemon
- **Версия:** 4.5.13
- **Addon slug:** `a0d7b954_appdaemon`
- **Python:** 3.12.13
- **Конфиг:** `/addon_configs/a0d7b954_appdaemon/appdaemon.yaml`
- **Таймзона:** Europe/Moscow
### availability.py
Класс `Availability(hass.Hass)`:
- **Cold-start:** полный пересчёт через 30 сек после запуска
- **Расписания:** 24ч/5мин, 7д/15мин, 30д/2ч
- **Подписка:** `input_select.avail_period` — пересчёт при переключении
- **REST API:** `http://supervisor/core/api` с SUPERVISOR_TOKEN
- **WebSocket:** `ws://homeassistant:8123/api/websocket` с ha_token из args
Методы:
| Метод | Назначение |
|-------|-----------|
| `_fetch_entities()` | Получение списка устройств + фильтрация |
| `_fetch_areas()` | WebSocket → area/entity/device registry → маппинг |
| `_fetch_history()` | Batch-запросы по 20 entity, пауза 1 сек |
| `_calc_period()` | Полный цикл расчёта для периода |
| `_set_progress()` | Обновление sensor.avail_calc_progress |
### availability_utils.py
| Функция | Назначение |
|---------|-----------|
| `is_excluded()` | Фильтрация entity по правилам исключения |
| `sanitize_entity_id()` | `light.bra``light_bra` |
| `sanitize_area_name()` | `Без комнаты``bez_komnaty` (транслитерация) |
| `compute_availability()` | Расчёт pct, down_count, max_downtime, last_downtime |
| `compute_sparkline()` | Ежедневные точки за N дней |
| `get_color()` | ≥99→green, 95-99→yellow, 90-95→orange, <90→red |
| `calc_trend()` | Сравнение с предыдущим периодом (up/down/stable) |
### Sensors
- `sensor.avail_<entity_id>` — доступность устройства (state = %)
- `sensor.avail_area_<name>` — средняя доступность по комнате
- `sensor.avail_calc_progress` — прогресс расчёта (`"1/2"` или `"idle"`)
### input_select
- `input_select.avail_period` — переключатель периода (24h / 7d / 30d)
## Аутентификация
| Канал | URL | Токен |
|-------|-----|-------|
| REST API | `http://supervisor/core/api` | SUPERVISOR_TOKEN (авто) |
| WebSocket | `ws://homeassistant:8123/api/websocket` | ha_token (Long-Lived Access Token из apps.yaml) |
⚠️ SUPERVISOR_TOKEN **не подходит** для прямого WebSocket к HA — только для REST через supervisor proxy.
## Известные баги / ограничения
1. **Sparkline для 24ч** — даёт 1 точку, а не 7. Нужна логика по часам
2. **Area cache**`_fetch_areas()` запрашивает registry при каждом расчёте. Можно кэшировать
3. **30д тренд** — запрашивает 60д истории, нужен `purge_keep_days ≥ 65`
4. **Новые устройства**`compute_availability` вернёт 100% (нет истории = нет падений). Корректно, но не информативно
5. **`minimal_response`** — HA может не возвращать entity_id в каждой записи. Fallback на первый entity из батча
## Деплой
```bash
# Обновить файлы на HA
SKILL=~/.openclaw/skills/installer/scripts
$SKILL/ssh_exec.sh --host ha --cmd "cat > /addon_configs/a0d7b954_appdaemon/apps/availability.py << 'ENDOFFILE'
$(cat appdaemon/availability.py)
ENDOFFILE"
$SKILL/ssh_exec.sh --host ha --cmd "cat > /addon_configs/a0d7b954_appdaemon/apps/availability_utils.py << 'ENDOFFILE'
$(cat appdaemon/availability_utils.py)
ENDOFFILE"
# Перезапустить AppDaemon
$SKILL/ssh_exec.sh --host ha --cmd "ha addons restart a0d7b954_appdaemon"
```
## TODO
- [ ] Назначить areas устройствам в HA
- [ ] Увеличить purge_keep_days до 35
- [ ] Установить button-card через HACS
- [ ] Построить Lovelace-дашборд
- [ ] Расширить на другие домены (sensor, binary_sensor, climate, ...)
- [ ] Кэшировать area registry (не запрашивать каждый цикл)
- [ ] Исправить sparkline для 24ч (часовые точки вместо дневных)

View File

@@ -97,7 +97,10 @@ sensor.avail_light_bra_v_spalne:
**Путь приложений:** `/addon_configs/a0d7b954_appdaemon/apps/`
**Путь apps.yaml:** `/addon_configs/a0d7b954_appdaemon/apps/apps.yaml`
**Slug аддона:** `a0d7b954_appdaemon`
**Подключение к HA:** автоматическое через SUPERVISOR_TOKEN (WebSocket), ha_url/token НЕ указывать
**Подключение к HA:**
- REST API: автоматическое через SUPERVISOR_TOKEN (`http://supervisor/core/api`)
- WebSocket (для registry): HA Long-Lived Access Token через `apps.yaml` аргумент `ha_token``ws://homeassistant:8123/api/websocket`
- ⚠️ SUPERVISOR_TOKEN **не подходит** для прямого WebSocket-подключения к HA — только для REST через supervisor proxy
### Первая фаза: только light + switch
Начинаем с минимального набора — только домены `light` и `switch`. После обкатки расширяем на остальные.
@@ -239,25 +242,33 @@ def calc_availability(history_entries, period_start, period_end):
- **button-card** — для строк устройств с прогресс-баром
- **custom:hui-element** — для input_select на дашборде (или использовать стандартный entities card)
### AppDaemon: как писать приложение
### AppDaemon: реализация
```python
import appdaemon.plugins.hass.hassapi as hass
**Модули:**
- `availability.py` — класс `Availability(hass.Hass)`, основная логика
- `availability_utils.py` — чистые функции (фильтрация, расчёт, форматирование)
class Availability(hass.Hass):
def initialize(self):
# Cold-start: сразу пересчёт
self.run_in(self.calc_all, 30) # через 30 сек после старта
# Расписания
self.run_every(self.calc_24h, "now+30", 5 * 60) # каждые 5 мин
self.run_every(self.calc_7d, "now+60", 15 * 60) # каждые 15 мин
self.run_every(self.calc_30d, "now+120", 2 * 3600) # каждые 2 часа
# Подписка на переключение периода
self.listen_state(self.period_changed, "input_select.avail_period")
**Ключевые решения при реализации:**
- `self.sleep()` в AppDaemon 4.x — coroutine, нельзя вызывать синхронно → заменён на `time.sleep()` (блокирует только worker thread)
- `log_level: info` в apps.yaml вызывает `ValueError: Unknown level` → убрать, AppDaemon использует INFO по умолчанию
- HA Registry API (area/entity/device) **недоступен через REST** — только WebSocket (`config/area_registry/list` и т.д.)
- SUPERVISOR_TOKEN работает для REST через supervisor proxy, но **не для прямого WS** к HA
- Entity ID не может содержать кириллицу → `sanitize_area_name()` с транслитерацией (а→a, б→b, ...)
**apps.yaml:**
```yaml
hello_world:
module: hello
class: HelloWorld
availability:
module: availability
class: Availability
ha_token: <Long-Lived Access Token> # для WebSocket registry
```
**⚠️ Секреты:** `ha_token` хранится в apps.yaml на HA. Не дублировать в других файлах.
### Нагрузка
- ~180 устройств
- History API batch-запрос (можно передать несколько entity_id через запятую)
@@ -275,4 +286,24 @@ class Availability(hass.Hass):
3. ~~Установить AppDaemon~~ → ✅ Установлен (4.5.13)
4. ~~Подтвердить список исключений~~ → ✅ Согласовано (см. выше)
5. Доустановить **button-card** через HACS
6. Создать `input_select.avail_period` (опции: 24ч, 7д, 30д)
6. ~~Создать `input_select.avail_period`~~ → ✅ Создан (опции: 24h, 7d, 30d, по умолчанию 7d)
7. Назначить **areas** устройствам в HA (Settings → Areas) — многие показывают «Без комнаты»
8. Построить **Lovelace-дашборд** (после установки button-card)
## Статус деплоя
### ✅ Готово
- AppDaemon 4.5.13 установлен и работает
- availability.py + availability_utils.py задеплоены
- 21 device sensor создан (`sensor.avail_*`)
- 2 area sensor создан (`sensor.avail_area_*`)
- input_select.avail_period создан
- WebSocket registry работает (9 areas, 729 entity mappings)
- Расчёт за все 3 периода (24h/7d/30d)
### ⏳ TODO
- Назначить areas устройствам в HA
- Увеличить purge_keep_days до 35
- Установить button-card через HACS
- Построить Lovelace-дашборд
- Расширить на другие домены (после обкатки)