diff --git a/family/how-to/home-automation.md b/family/how-to/home-automation.md index b7245aa3..352bf3b3 100644 --- a/family/how-to/home-automation.md +++ b/family/how-to/home-automation.md @@ -48,6 +48,7 @@ updated: 2026-09-15 (✅ поздний вечер — Zigbee: +7 новых TS0 > 🔴 **2026-09-16 (ночь): вычищены 185 призраков Z2M** из архива реестра (`deleted_entities` 360 → 175). Призраки живут **именно в архиве**, а не в `entities` — UI «Обслуживание» их показывал, `/api/states` и WS-реестр нет. Живые (572) не тронуты. Снесены также остатки аддонов `go2rtc`/`file_editor`/`samba_share` и старые `switch_as_x`-обёртки. > 🔴 **План этажей (`home-plan`) ссылался на снесённого призрака** `light.smart_light_stairs_l1` → ошибка на карте. Исправлено на `light.light_stairs_left`. Проверять ссылки плана после сноса: `~/tmp-t610/fix_plan_stairs.sh`. > 🔴 **H2000_PRO отдавал °F** — ручной override `sensor.private.suggested_unit_of_measurement: "°F"` у трёх сущностей. Сброшено через WS с **`options_domain: "sensor.private"`** (через `"sensor"` update проходит, но НЕ меняет). Стало 12.9 / 28.2 / 30.2 °C. +> 📄 **Реестры HA (переименование, опции, снос призраков) — отдельный справочник:** [[family/tech/ha-registry-operations]]. > > 🔴 **Ключевой факт:** переименование HA-сущности **молча ломает** маппинг bridge → slave отдаёт `0`. Проверено на живом случае: slave 100 (кабинет) отдавал `0`, после правки — `23.97`. Правило: **переименовал сущность → проверь `data/config.template.tmpl` + `rebuild` + ссылки в `automations.yaml`.** > diff --git a/family/plans/t610-zigbee-ids-battery-freshsensors-modbus.md b/family/plans/t610-zigbee-ids-battery-freshsensors-modbus.md index 57ceae76..f152506d 100644 --- a/family/plans/t610-zigbee-ids-battery-freshsensors-modbus.md +++ b/family/plans/t610-zigbee-ids-battery-freshsensors-modbus.md @@ -1,10 +1,10 @@ --- title: "План и результат: читаемые ID Zigbee, алерты батарей, виртуальные Modbus-датчики" created: '2026-09-15' -updated: '2026-09-15' +updated: '2026-09-16 (ночь: добавлены этапы 5–6 — снос призраков реестра, починка плана этажей и H2000_PRO)' type: plan namespace: family -status: 🟢 ВЫПОЛНЕНО 2026-09-15 (поздний вечер). Все 4 шага закрыты, проверено фактами. +status: 🟢 ВЫПОЛНЕНО 2026-09-16. Шаги 1–4 закрыты 2026-09-15; 5–6 (вычистка призраков + починка UI) закрыты 2026-09-16 ночью. Всё проверено фактами. tags: - t610 - zigbee @@ -289,19 +289,38 @@ ssh root@192.168.2.176 'ha apps rebuild local_modbus-bridge && ha apps start loc **Скрипты:** `~/tmp-t610/{gard_step1,gard_step2,gard_step2b,gard_fix,fix_aut_entid}.py`. **Коммит vault:** `db20bb8`. -### ⚠️ НЕ ЗАКРЫТО (на момент записи) +### ✅ ЗАКРЫТО (2026-09-16, ночь): «Office temperature sensor battery недоступно» -Alex сообщил: «**Office temperature sensor battery** — HA ругается что у устройства нет уникального id и оно недоступно». +Alex: «Office temperature sensor battery — HA ругается что у устройства нет уникального id и оно недоступно», затем «light.smart_light_stairs_l1 — тоже недоступен». -**Проверено — призрака в бэкенде НЕТ:** -- `sensor.office_temperature_sensor*` в `/api/states` — отсутствует; -- в реестре сущностей (572 записи) — нет упоминаний; -- MQTT-сущности без `unique_id` — **0**; -- MQTT-устройства-призраки Z2M — 4, все легитимные (3 сниффера + H2000); -- config entries `mqtt`/`zha`/`generic` — 3, все `loaded`, призраков нет; -- лог HA Core на `unique_id`/`office` — пусто. +**Причина найдена — записи лежали в архиве реестра**, а не в runtime: `core.entity_registry → data.deleted_entities`. Поэтому `/api/states`, WS-реестр и `repairs/list_issues` их не видели, а UI «Обслуживание» — видел. -**Вывод:** источник сообщения — UI-кэш (браузер/приложение) либо дашборд-карточка. Требуется уточнение от Alex: **в каком именно экране ругается** (Настройки → Устройства → MQTT / дашборд / Developer Tools / лог автоматизаций). Следующая сессия: спросить экран и вычистить прицельно. +**Решение:** контролируемый снос скриптом `~/tmp-t610/ghost_purge.sh` (исключает живое + вентиляцию, dry-run по умолчанию). +- Снято **185** записей: 6 точечно (`office_temperature_sensor_*` ×5 + `smart_light_stairs_l1`) + 179 пачкой. +- Архив реестра 360 → **175**. Живых 572 — не тронуто. +- На dry-run поймано 3 живых `switch_as_x`-записи (`light.night_light_shower_2`, `light.smart_light_office_left/right`) — исключены. + +**Сопутствующее (этап 6):** +- **План этажей** (`home-plan`) ругался «недоступно» — ссылался на снесённого `light.smart_light_stairs_l1`. Исправлено на `light.light_stairs_left`. Все 29 ссылок валидны. +- **H2000_PRO** отдавал °F — ручной override `sensor.private.suggested_unit_of_measurement: "°F"`. Сброшено через WS с `options_domain: "sensor.private"` (⚠️ через `"sensor"` — `success: true`, но НЕ меняет). Стало 12.9 / 28.2 / 30.2 °C. + +**Бэкапы:** `core.entity_registry.bak-ghostpurge-20260916-002503`, `.bak-purge-20260916-000530`, `.bak-ghosts-20260916-000329`, `lovelace.home_plan.bak-fixplan-20260916-003231`. + +**Детали:** [[family/tech/zigbee-t610-z2m-i-zha]] §13, [[family/tech/ha-registry-operations]]. + +--- + +## 4a. ✅ ЭТАП 6 — починка UI после сноса призраков (2026-09-16) + +| Проблема | Причина | Фикс | +|---|---|---| +| План этажей: «недоступно» на карте | `state-icon` → снесённый `light.smart_light_stairs_l1` | → `light.light_stairs_left` | +| H2000_PRO: °F вместо °C | override `sensor.private.suggested_unit_of_measurement` | сброс через `options_domain: "sensor.private"` | + +**Правило:** **после сноса призраков — проверять ссылки дашбордов.** План этажей жалуется «недоступно» из-за мёртвой ссылки, а не из-за поломки устройства. + +**Скрипты:** `fix_plan_stairs.sh` (ссылки плана), `fix_h2000_all.py` (единицы). +**Коммит vault:** `ee86207`. --- diff --git a/family/tech/ha-registry-operations.md b/family/tech/ha-registry-operations.md new file mode 100644 index 00000000..6ff6b860 --- /dev/null +++ b/family/tech/ha-registry-operations.md @@ -0,0 +1,198 @@ +--- +title: "Реестры Home Assistant — операции (справочник)" +created: '2026-09-16' +updated: '2026-09-16' +type: tech +namespace: family +status: 🟢 Проверено фактами на t610 (HA 2026.9.2). Переиспользуемый справочник — не привязан к Zigbee. +tags: + - home-assistant + - haos + - t610 + - registry + - websocket +related: + - '[[family/tech/zigbee-t610-z2m-i-zha]]' + - '[[family/how-to/home-automation]]' +--- + +# Реестры Home Assistant — операции + +> **Справочник по работе с `core.entity_registry` / `core.device_registry` / `core.area_registry`.** Все факты проверены на t610. +> ⚠️ Записи реестра — **только WebSocket**. REST `/api/config/*_registry/list` отдаёт **404**. + +--- + +## 1. Структура `core.entity_registry` + +```json +{ + "version": 1, + "minor_version": 23, + "key": "core.entity_registry", + "data": { + "entities": [...], // ЖИВЫЕ сущности + "deleted_entities": [...], // АРХИВ удалённых (их HA не грузит, но UI показывает!) + "settings": {...} + } +} +``` + +> 🔴 **Ключевой факт: `entities` и `deleted_entities` — разные секции одного файла.** +> Призраки живут в `deleted_entities` — поэтому их НЕ видно в `/api/states` и WS-реестре, но они вылезают в UI «Обслуживание» и в ссылках дашбордов. + +```bash +jq '.data.entities|length' /config/.storage/core.entity_registry # живое +jq '.data.deleted_entities|length' /config/.storage/core.entity_registry # архив +jq -r '.data.entities[].entity_id' ... # список живых +jq -r '.data.deleted_entities[].entity_id' ... # список архивных +``` + +--- + +## 2. WS API — рабочие команды + +| Задача | Команда | +|---|---| +| Список сущностей (живых) | `config/entity_registry/list` | +| Список устройств | `config/device_registry/list` | +| Список зон | `config/area_registry/list` | +| Получить сущность | `config/entity_registry/get {entity_id}` | +| Переименовать сущность | `config/entity_registry/update {entity_id, new_entity_id}` | +| Переименовать устройство | `config/device_registry/update {device_id, name_by_user}` | +| Сменить зону устройства | `config/device_registry/update {device_id, area_id}` | +| Удалить запись | `config/entity_registry/remove {entity_id}` | +| Проблемы (Обслуживание) | `repairs/list_issues` | +| Записи интеграций | `config_entries/get` | + +> ⚠️ `/api/config/*_registry/list` (REST) → **404**. Только WS. +> ⚠️ `repairs/list_issues` может быть **пуст**, даже когда UI «Обслуживание» что-то показывает — если источник в `deleted_entities`. + +--- + +## 3. 🔴 Переименование сущности + +### 3.1. `name_by_user` НЕ переименовывает `entity_id` + +Смена имени устройства (`device_registry/update`) меняет только `name_by_user`. HA **не перегенерирует** `entity_id` существующих сущностей — только у новых. + +```python +# Шаг 1 — имя устройства +{"type":"config/device_registry/update","device_id": D, "name_by_user": "new_name"} +# Шаг 2 — КАЖДАЯ сущность отдельно +{"type":"config/entity_registry/update","entity_id":"sensor.old","new_entity_id":"sensor.new"} +``` + +### 3.2. Обход `id_reuse: Identifier values have to increase` + +Внутренний счётчик реестра. **Штатный случай, не поломка.** Обход — через промежуточное имя: + +``` +sensor.old → sensor.tmp_xxx → sensor.new +``` + +### 3.3. Сироты-автоматизации + +Тело удалено из `automations.yaml`, но запись в реестре осталась → сущность `unavailable`. +`config/entity_registry/remove` → если `id_reuse` → **сначала** `update` c `disabled_by: "user"`, **затем** `remove`. + +> 🔴 **После любого переименования — проверять ссылки:** +> - в `automations.yaml` (все `entity_id:` сверить со `/api/states`); +> - в дашбордах (`lovelace.*`), см. §5; +> - в маппингах `modbus-bridge`, см. [[family/tech/zigbee-t610-z2m-i-zha]] §5. + +--- + +## 4. 🔴 Опции сущности: `options_domain` — важно какой + +Опции хранятся по доменам. Пример структуры: + +```json +"options": { + "conversation": {"should_expose": false}, + "sensor": {"suggested_display_precision": 1}, + "sensor.private": {"suggested_unit_of_measurement": "°F"} +} +``` + +Обновление: + +```python +{"type":"config/entity_registry/update", + "entity_id":"sensor.x", + "options_domain":"sensor.private", # ⚠️ ТОЧНЫЙ домен, не общий + "options":{"suggested_unit_of_measurement": None}} +``` + +> 🔴 **ПИТФОЛЛ: `options_domain: "sensor"` даёт `success: true`, но единицу НЕ меняет.** Проверено фактом на H2000_PRO: заход через `"sensor"` не подействовал, после смены на `"sensor.private"` — сработало. +> **Всегда читать обратно** (`config/entity_registry/get`) и сверять результат в `/api/states`. + +### Кейс: датчик показывает °F вместо °C + +Причина — ручной override `sensor.private.suggested_unit_of_measurement: "°F"`. Значения тоже конвертируются (55.22 °F = 12.9 °C), поэтому цифры выглядят правдоподобно и ошибку легко не заметить. +**Фикс:** сброс в `null` через `options_domain: "sensor.private"`. + +--- + +## 5. Проверка ссылок дашбордов + +```bash +# все ссылки плана этажей (picture-elements) +jq -r '.data.config.views[].sections[].cards[]? + | select(.type=="picture-elements") + | .elements[]? | select(.entity?!=null) | .entity' \ + /config/.storage/lovelace.home_plan | sort -u +# затем сверить список со живыми из /api/states +``` + +> 🔴 **Правило: после сноса призраков — проверять ссылки дашбордов.** План этажей показывает «недоступно» из-за мёртвой ссылки, а не из-за поломки устройства. + +Дашборды t610: `home_plan` (storage-mode, `/config/.storage/lovelace.home_plan`, карта `/config/www/floorplan/*.svg`), реестр дашбордов — `lovelace_dashboards`. + +--- + +## 6. Контролируемый снос призраков + +**Принцип: только то, что в архиве И не живое. Никогда по grep — только по точному `entity_id`.** + +Скрипт `~/tmp-t610/ghost_purge.sh`: +1. строит `live_all` (`.data.entities`) и `ghost_all` (`.data.deleted_entities`); +2. `comm -23` → в архиве и НЕ живое; +3. `grep -viE 'fan|at2|damper|vent|shopping_list'` → исключает вентиляцию (по требованию Alex); +4. dry-run по умолчанию, `--apply` — снос; +5. `--apply` → бэкап `*.bak-ghostpurge-` → `jq`-фильтр → отчёт. + +**Обязательно после сноса:** рестарт HA (`POST /api/services/homeassistant/restart`), иначе правка `.storage` не подхватится. Проверить: `entities` не изменилось, `deleted_entities` уменьшилось. + +```bash +scp ~/tmp-t610/ghost_purge.sh root@192.168.2.176:/tmp/ +ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_registry' # dry-run +ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_registry --apply' +``` + +> ⚠️ **Питфолл `set -e` в bash:** `comm`/`grep` возвращают 1 при пустом результате и валят скрипт молча. Использовать `set -uo pipefail` (без `-e`) + `|| true` на таких строках. +> ⚠️ **На t610 нет `python3`.** Только `jq` 1.8.1 (`/usr/bin/jq`). Скрипты для t610 писать на jq/bash, не на Python. + +--- + +## 7. Питфоллы (сводка) + +| # | Питфолл | Обход | +|---|---|---| +| 1 | REST `/api/config/*_registry/list` → 404 | Только WebSocket | +| 2 | `name_by_user` не меняет `entity_id` | Переименовывать устройство И сущности отдельно | +| 3 | `id_reuse: Identifier values have to increase` | Промежуточное имя: `old → tmp → new` | +| 4 | Сирота-автоматизация `unavailable` | `remove`, при `id_reuse` — сначала `disabled_by: user` | +| 5 | `options_domain: "sensor"` не меняет единицу | Точный домен: `"sensor.private"` | +| 6 | Призраки не видны в API, но видны в UI | Они в `deleted_entities`, а не в `entities` | +| 7 | Правка `.storage` без рестарта не действует | `POST /api/services/homeassistant/restart` | +| 8 | После сноса призраков дашборд ругается | Проверить ссылки дашбордов (§5) | +| 9 | Удаление `device_id` сбрасывает `area_id` | Восстановить через `device_registry/update` | +| 10 | На t610 нет `python3` | Скрипты на `jq`/bash | + +--- + +## Связанные заметки + +- [[family/tech/zigbee-t610-z2m-i-zha]] — Zigbee на ZHA, §13 вычистка призраков +- [[family/how-to/home-automation]] — t610: топология, аддоны, доступ diff --git a/family/tech/zigbee-t610-z2m-i-zha.md b/family/tech/zigbee-t610-z2m-i-zha.md index d72f4da3..7129130e 100644 --- a/family/tech/zigbee-t610-z2m-i-zha.md +++ b/family/tech/zigbee-t610-z2m-i-zha.md @@ -1,10 +1,10 @@ --- title: "Zigbee на t610 — ZHA (справочник)" created: '2026-09-15' -updated: '2026-09-15 (поздний вечер: +7 новых TS0201 тёплых полов, ЕДИНООБРАЗИЕ ID у 23 устройств, 12 алертов батарей, виртуальные Modbus slave 105–112)' +updated: '2026-09-16 (ночь: вычищены 185 призраков Z2M из архива реестра `deleted_entities` 360→175; план этажей починен — ссылка на снесённого `light.smart_light_stairs_l1` → `light.light_stairs_left`; H2000_PRO °F→°C сбросом `sensor.private` override)' type: tech namespace: family -status: 🟢 РАБОТАЕТ. ZHA: 24 записи (23 устройства + координатор), `unavailable` = 0. Все устройства с читаемыми ID в едином виде, все в зонах. 26 автоматизаций: 25 `on`, 1 `off` намеренно. Bridge: 9 Zigbee-температур отдаются ZONT'у (slave 100–112). +status: 🟢 РАБОТАЕТ. ZHA: 24 записи (23 устройства + координатор), `unavailable` = 0. Все устройства с читаемыми ID в едином виде, все в зонах. 24 автоматизации: 23 `on`, 1 `off` намеренно. Bridge: 9 Zigbee-температур отдаются ZONT'у (slave 100–112). Призраки Z2M в архиве реестра вычищены; план этажей и H2000_PRO исправлены. `unavailable` всего 8 — вентиляция AT2 + `todo.shopping_list` (намеренно). tags: - t610 - haos @@ -400,9 +400,88 @@ curl -s -H "$HDR" http://supervisor/backups | jq --- +## 13. Вычистка призраков Z2M и починка UI (2026-09-16, ночь) + +### 13.1. 🔴 Призраки живут в `deleted_entities`, а НЕ в `entities` + +**Симптом:** во вкладке «Обслуживание» висят сущности с пометкой «недоступно» — `sensor.office_temperature_sensor_battery`, `light.smart_light_stairs_l1` и др. При этом `/api/states` их не отдаёт, WS-реестр (`config/entity_registry/list`) — тоже, `repairs/list_issues` пуст. + +**Причина:** записи лежат в **архиве удалённых** `core.entity_registry → data.deleted_entities`. HA их не загружает в runtime, но UI их показывает. + +```bash +# живое vs архив — РАЗНЫЕ секции одного файла +jq '.data.entities|length' /config/.storage/core.entity_registry # 572 — живое +jq '.data.deleted_entities|length' /config/.storage/core.entity_registry # 360 → 175 — архив +``` + +> ⚠️ **`config/entity_registry/get` по такому entity_id → `not_found`.** Это ожидаемо и НЕ значит, что записи нет. +> ⚠️ Правка `.storage` вступает в силу только после рестарта HA. + +### 13.2. Контролируемый снос — скрипт `~/tmp-t610/ghost_purge.sh` + +Сам исключает: (1) `entity_id`, который сейчас живой; (2) вентиляцию (`fan|at2|damper|vent|shopping_list`). Dry-run по умолчанию. + +```bash +scp ~/tmp-t610/ghost_purge.sh root@192.168.2.176:/tmp/ +ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_registry' # dry-run +ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_registry --apply' # снос +``` + +**Результат 2026-09-16:** снято **185** записей (179 в пачке + 6 точечных ранее). Архив 360 → 175. Живых 572 — не тронуто. + +**Что снесено:** старые Z2M-сущности (`_linkquality`, префиксы `0x…`), остатки удалённых аддонов (`go2rtc`, `go2rtc_hardware`, `file_editor`, `samba_share`), HACS/Tuya-флаги, старые `switch_as_x`-обёртки, 4 автоматизации-дубля. + +**Что НЕ тронуто:** 175 записей, чей `entity_id` живой (ZHA-устройства, телефон `sm_s931b`, вентиляция, снифферы Modbus) — плюс отдельно `light.night_light_shower_2`, `light.smart_light_office_left/right` (тот же тип `switch_as_x`, но живые). + +> 📌 Питфолл `set -e` в bash-скриптах: `comm`/`grep` возвращают 1 при пустом результате и валят скрипт. Использовать `set -uo pipefail` (без `-e`) + `|| true` на таких строках. + +### 13.3. План этажей ссылался на снесённого призрака + +**Дашборд:** `home_plan` (storage-mode, `url_path: home-plan`), конфиг — `/config/.storage/lovelace.home_plan`, карта — `/config/www/floorplan/floor1_ha.svg`, `floor2_ha.svg`. + +**Симптом:** после сноса призраков на карте ошибка «недоступно». +**Причина:** элемент `state-icon` ссылался на снесённый `light.smart_light_stairs_l1` (был `switch_as_x`-обёрткой). Живой = `light.light_stairs_left/right`. + +```bash +# 1) вытащить все ссылки плана +jq -r '.data.config.views[].sections[].cards[]? | select(.type=="picture-elements") | .elements[]? | select(.entity?!=null) | .entity' \ + /config/.storage/lovelace.home_plan | sort -u +# 2) сверить со списком живых из /api/states +# 3) заменить мёртвые → скрипт +ssh root@192.168.2.176 'bash /tmp/fix_plan_stairs.sh /config/.storage/lovelace.home_plan --apply' +``` + +> 🔴 **Правило: после сноса призраков — проверять ссылки дашбордов.** План этажей жалуется «недоступно» именно из-за мёртвой ссылки, а не из-за поломки устройства. Все 29 ссылок плана после фикса валидны. + +### 13.4. 🔴 H2000_PRO показывал °F + +**Симптом:** три датчика `sensor.h2000_pro_temperatura_*` (улица/подача/тёплый пол) отдавали °F. Значения тоже были в °F (55.22 °F = 12.9 °C). + +**Причина:** ручной override в опциях сущности — `sensor.private.suggested_unit_of_measurement: "°F"` (все три). + +**Фикс (WS):** +```python +{"type":"config/entity_registry/update", + "entity_id":"sensor.h2000_pro_temperatura_ulitsa", + "options_domain":"sensor.private", # ⚠️ не "sensor"! + "options":{"suggested_unit_of_measurement": None}} +``` + +> 🔴 **ПИТФОЛЛ: `options_domain: "sensor"` даёт `success: true`, но единицу НЕ меняет.** Проверено фактом: первый заход не подействовал, после смены на `"sensor.private"` — сработало. +> ⚠️ `H2000_PRO` — контроллер отопления, **не Zigbee**. Приходит через MQTT-discovery (ZONT). **Не трогать интеграцию** — только опции сущности. + +**Результат:** 12.9 / 28.2 / 30.2 °C. + +**Скрипты сессии:** `~/tmp-t610/ghost_purge.sh` (снос призраков), `ghost_inventory.sh` (инвентаризация), `fix_plan_stairs.sh` (ссылки плана), `fix_h2000_all.py` (единицы °F→°C), `clean_ghosts.sh` (ранняя версия). + +**Бэкапы:** `core.entity_registry.bak-ghostpurge-20260916-002503`, `.bak-purge-20260916-000530`, `.bak-ghosts-20260916-000329`, `lovelace.home_plan.bak-fixplan-20260916-003231`. + +--- + ## Связанные заметки - [[family/how-to/home-automation]] — топология, аддоны t610, первопричина RCU stall, Modbus +- [[family/tech/ha-registry-operations]] — реестры HA: переименование, опции, снос призраков - [[family/how-to/ha-automations]] — автоматизации - [[family/plans/t610-backup-to-truenas]] — автобэкап `/config/zigbee2mqtt/` - [[family/tech/local-ustreamer-addon]] — камера на том же хосте