Files
obsidian-vault/family/plans/t610-zigbee-ids-battery-freshsensors-modbus.md
T

368 lines
22 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.
---
title: "План и результат: читаемые ID Zigbee, алерты батарей, виртуальные Modbus-датчики"
created: '2026-09-15'
updated: '2026-09-16 (ночь: добавлены этапы 5–6 — снос призраков реестра, починка плана этажей и H2000_PRO)'
type: plan
namespace: family
status: 🟢 ВЫПОЛНЕНО 2026-09-16. Шаги 14 закрыты 2026-09-15; 5–6 (вычистка призраков + починка UI) закрыты 2026-09-16 ночью. Всё проверено фактами.
tags:
- t610
- zigbee
- zha
- modbus
- battery
related:
- '[[family/tech/zigbee-t610-z2m-i-zha]]'
- '[[family/how-to/home-automation]]'
- '[[family/how-to/ha-automations]]'
---
# План и результат: читаемые ID, алерты батарей, виртуальные Modbus-датчики
> Задача от Alex (2026-09-15): 1) убедиться, что у **всех** Zigbee-устройств читаемые ID; 2) каждому **батарейному** — оповещение о низком заряде; 3) каждый **температурный** Zigbee-датчик прописать как виртуальное устройство Modbus в bridge; 4) обновить доку.
>
> ✅ **Всё выполнено в тот же вечер.** Ниже — план И фактический результат.
---
## 0. Исходная точка (снимок до работ)
Пришло **+7 новых TS0201** (датчики тёплых полов). ZHA: 24 записи (23 устройства + координатор), было 17.
| IEEE | Исходное `name_by_user` | Модель | Зона |
|---|---|---|---|
| `a4c13827ea585609` | `Темп теплый пол гостиная` | TS0201 | living_room |
| `a4c1382ac15720dd` | `Температура серая` | TS0201 | severnaia |
| `a4c1382dac5e10e2` | `Темп теплый пол кабинет` | TS0201 | kabinet |
| `a4c13837021f5298` | `Темп теплый пол кухня` | TS0201 | kitchen |
| `a4c13867875ee7d3` | `Темп теплый пол ванная` | TS0201 | vannaia |
| `a4c138cde6eed013` | `Темп теплый пол прихожая` | TS0201 | prikhozhaia |
| `a4c13865e226312d` | `Темп теплый пол душевая` | TS0201 | dushevaia |
### 0.1. 🔴 Дефекты ID, найденные при проверке
| # | Дефект | Пример | Итог |
|---|---|---|---|
| D1 | **Имя устройства по-русски** (HA транслитерирует) | `Темп теплый пол гостиная``sensor.temp_teplyi_pol_gostinaia_temperatura` | ✅ исправлено |
| D2 | **Перепутан префикс: `tualet_` при зоне `prikhozhaia`** | `sensor.tualet_temp_teplyi_pol_prikhozhaia_temperatura` | ✅ исправлено |
| D3 | **Дубли `_2` / `_3` у LQI/RSSI** (остатки миграции) | `sensor.tz3000_gjnozsaz_ts011f_lqi_2`, `_3` | ✅ исправлено |
| D4 | `sauna` — зона `tualet` | `switch.sauna` в зоне ТУАЛЕТ | ⛔ **НЕ дефект** — Alex: «Её зона туалет 1». Оставлено |
| D5 | `select`-сущности `sauna` названы `bed_dimmer_*` | `select.bed_dimmer_power_on_behavior` | ✅ исправлено |
### 0.2. Исходная занятость Modbus-адресов bridge
| Slave | Что | Регистр |
|---|---|---|
| 100 | `sensor.office_temperature_sensor_temperature` (Room temp) | 100 |
| 101 | снифф `dining_temperature` + **запись** `switch.recirculation_pump` | 100 / 1 |
| 102 | снифф `kids_temperature` | 100 |
| 103 | снифф `bedroom_temperature` | 100 |
| 104 | Zigbee-реле `switch.boiler_controller_power` | 1 |
Свободно: **105+**. Оповещений о низком заряде не было ни у одного батарейного.
---
## 1. ✅ РЕЗУЛЬТАТ — Шаг 1: единый вид ID (23 устройства)
**Формат: `<устройство>_<роль>`.** Для датчиков `_temperature` / `_humidity` / `_battery` / `_lqi` / `_rssi`, плюс `button.<dev>_identify` и `update.<dev>_firmware`. Для реле `_power` / `_voltage` / `_current` / `_energy`, `select.<dev>_indicator_mode` / `_power_outage_memory`.
| Было | Стало |
|---|---|
| `Темп теплый пол гостиная` | `living_room_floor_temperature` |
| `Температура серая` | `severnaia_floor_temperature` |
| `Темп теплый пол кабинет` | `kabinet_floor_temperature` |
| `Темп теплый пол кухня` | `kitchen_floor_temperature` |
| `Темп теплый пол ванная` | `vannaia_floor_temperature` |
| `Темп теплый пол прихожая` | `prikhozhaia_floor_temperature` |
| `Темп теплый пол душевая` | `dushevaia_floor_temperature` |
| `office_temperature_sensor` | `kabinet_temperature` |
| `light.night_light_shower_2` | `light.dushevaia_night_light` |
| `binary_sensor.tz3000_hy6ncvmw_ts0222` | `binary_sensor.light_sensor_stairs` |
**Масштаб:** **140 переименований** (8 устройств + 68 + 16 + 56 + 2 сущностей). Все 23 устройства в зонах, «без зоны» — нет.
### 1.1. 🔴 Механика — `name_by_user` НЕ переименовывает `entity_id`
HA перегенерирует `entity_id` только у **новых** сущностей. Нужны **два** шага:
```python
# Шаг 1 — имя устройства
{"type":"config/device_registry/update","device_id": D, "name_by_user": "living_room_floor_temperature"}
# Шаг 2 — КАЖДАЯ сущность отдельно
{"type":"config/entity_registry/update","entity_id":"sensor.old_name","new_entity_id":"sensor.new_name"}
```
### 1.2. Команды (воспроизведение)
```bash
# Полный аудит: устройства + сущности + зоны
cd ~/tmp-t610 && python3 zha_devs.py
# Переименование устройств (WS)
python3 rename_step1.py
# Переименование сущностей пакетом
python3 gen_rename_all.py # → /tmp/rename_all_plan.json (защита от конфликтов)
python3 apply_rename_all.py
# Аудит остатка нечитаемых
python3 audit_rest.py
```
**Скрипты:** `~/tmp-t610/{zha_devs,rename_step1,gen_rename_all,apply_rename_all,audit_rest,rename_ents,fix_last}.py`
### 1.3. 🔴 Побочный эффект: рвутся ссылки в автоматизациях
После переименования **молча** сломались 2 ссылки в `automations.yaml`:
- `light.night_light_shower_2` (×2) → `light.dushevaia_night_light`
- `sensor.tz3000_akqdg6g7_ts0201_batareia``sensor.kabinet_temperature_battery`
**Проверка (обязательна после любого переименования):**
```bash
curl -s -H @/tmp/h1 "$B/api/states" | jq -r '[.[].entity_id]' > /tmp/all_ents.json
ssh -i ~/.ssh/id_rsa root@192.168.2.176 'cat /config/automations.yaml' \
| grep -oE 'entity_id: [a-z_]+\.[a-zA-Z0-9_]+' | awk '{print $2}' | sort -u \
| while read e; do jq -e --arg e "$e" 'index($e)' /tmp/all_ents.json >/dev/null || echo "BROKEN: $e"; done
```
---
## 2. ✅ РЕЗУЛЬТАТ — Шаг 2: чиста наследия миграции
- `select.bed_dimmer_power_on_behavior` / `_switch_type` под `sauna``select.sauna_power_on_behavior` / `_switch_type`
- Все дубли `_2`/`_3` у LQI/RSSI/energy/identify приведены к `<device>_<role>`
- `sauna` в зоне `tualet`**оставлено** (не дефект, подтверждено Alex)
---
## 3. ✅ РЕЗУЛЬТАТ — Шаг 3: 12 автоматизаций контроля батарей
**Порог 20 %, выдержка 2 ч, двойной канал:** `persistent_notification` (видно в UI) + `notify.mobile_app_sm_s931b` (push). При возврате заряда выше порога уведомление гасится само.
```yaml
- id: '8800000000000' # …8800000000011 — 12 штук
alias: 'Батарея: <место>'
triggers:
- trigger: numeric_state
entity_id: sensor.<device>_battery
below: 20
for: '02:00:00'
id: low
- trigger: numeric_state
entity_id: sensor.<device>_battery
above: 20
id: ok
actions:
- choose:
- conditions: [{condition: trigger, id: low}]
sequence:
- action: persistent_notification.create
data: {title: '🔋 Батарея разряжена', notification_id: 'bat_<slug>'}
- action: notify.mobile_app_sm_s931b
- conditions: [{condition: trigger, id: ok}]
sequence:
- action: persistent_notification.dismiss
data: {notification_id: 'bat_<slug>'}
mode: single
```
**Покрытие (12 сущностей):** туалет 1 · лестница · душевая · котельная (протечка) · кабинет (воздух) · гостиная · серая · кабинет (пол) · кухня · ванная · прихожая · спальня (кнопка).
### 3.1. Заменённые старые
Две прежние автоматизации (`1773451323415`, `1773459663218`) **удалены** — были с порогом 10 и без push.
### 3.2. 🔴 Сироты: `unavailable` при чистом YAML
Тело удалено из `automations.yaml`, запись в реестре осталась → `unavailable`. Удаление:
```python
# Если config/entity_registry/remove падает с id_reuse:
# "Identifier values have to increase"
{"type":"config/entity_registry/update","entity_id": E, "disabled_by": "user"} # сначала это
{"type":"config/entity_registry/remove","entity_id": E} # потом это
```
**Скрипты:** `~/tmp-t610/{add_battery_autos,rm_orphans,rm_orphan2,rm_orphan3}.py`
### 3.3. Границы
`sensor.wireless_light_switch_bed_battery` = `unknown` — кнопка спальни спит. Автоматизация создана, но триггера не будет, пока датчик не проснётся (лечится нажатием кнопки).
---
## 4. ✅ РЕЗУЛЬТАТ — Шаг 4: виртуальные Modbus-датчики (slave 100 + 105112)
Добавлены в `/addons/modbus-bridge/data/config.template.tmpl`, `int16`, `divider: 10`:
| Slave | HA-сущность |
|---|---|
| **100** | `sensor.garderobnaia_temperature_temperature` (исторический «Room temp»; был `office_temperature_sensor``kabinet_temperature`) |
| 105 | `sensor.living_room_floor_temperature_temperature` |
| 106 | `sensor.severnaia_floor_temperature_temperature` |
| 107 | `sensor.kabinet_floor_temperature_temperature` |
| 108 | `sensor.kitchen_floor_temperature_temperature` |
| 109 | `sensor.vannaia_floor_temperature_temperature` |
| 110 | `sensor.prikhozhaia_floor_temperature_temperature` |
| 111 | `sensor.dushevaia_floor_temperature_temperature` |
| 112 | `sensor.toilet_1_floor_temperature_temperature` |
Итого в шаблоне **14 маппингов**. Свободно: `113+`.
### 4.1. 🔴 НАЙДЕНА И ИСПРАВЛЕНА РЕАЛЬНАЯ ПОЛОМКА: slave 100 отдавал `0`
Slave 100 ссылался на **старое** имя `sensor.office_temperature_sensor_temperature` — после переименования сущность стала `kabinet_temperature_temperature`. Bridge молча возвращал `0 [00 00]`.
```
ДО: → Response: 1 register(s) from 100 (ha:sensor.kabinet_temperature_temperature) = 0 [00 00]
ПОСЛЕ: → Response: 1 register(s) from 100 (ha:sensor.kabinet_temperature_temperature) = 23.97 [00 F0]
```
> 📌 **ПРАВИЛО: переименовал HA-сущность → проверь маппинг в `config.template.tmpl` + `rebuild`.**
> 📌 **Проверка slave'а без ZONT'а невозможна** — bridge это serial-slave, отвечает только на запрос. Признаки работы:
> 1. `ha apps logs local_modbus-bridge | grep "HA poll -> sensor.<entity>"` — поллер кэширует HA-значение.
> 2. `... | grep -A3 "Slave: 100"` → `Response: ... = <val> [<hex>]`.
### 4.2. Дубликат slave 113 — убран
При правке добавился «Kabinet air temp» (113) на ту же сущность, что slave 100. Удалён как дубль.
### 4.3. Команды
```bash
# правка шаблона → rebuild ОБЯЗАТЕЛЕН (Dockerfile: COPY data/config.template.tmpl)
scp config.template.tmpl root@192.168.2.176:/addons/modbus-bridge/data/config.template.tmpl
ssh root@192.168.2.176 'ha apps rebuild local_modbus-bridge && ha apps start local_modbus-bridge'
```
**Скрипты:** `~/tmp-t610/{add_modbus_temps,dedup_slave113,fix_slave100}.py`
---
## 4bis. ✅ ПОСЛЕ ПЛАНА — датчик перенесён в Гардеробную (2026-09-15, 22:5423:56)
**Задача Alex (вне исходного плана):** «Переименуй этот датчик в датчик гардеробная и перемести в нее и обнови конфиг моста» → «Кабинет который» (т.е. исторический `office_temperature_sensor`).
**Контекст:** в UI датчик не находился под старым именем (`office_temperature_sensor`) — потому что был переименован в `kabinet_temperature` шагом 1. Именно он и был перенесён.
| Что | Было | Стало |
|---|---|---|
| Имя устройства | `kabinet_temperature` | `garderobnaia_temperature` |
| Зона | `kabinet` | `garderobnaia` |
| Сущности (7) | `sensor.kabinet_temperature_*` | `sensor.garderobnaia_temperature_*` |
| Bridge slave 100 | `sensor.kabinet_temperature_temperature` | `sensor.garderobnaia_temperature_temperature` |
| Автоматизация батареи | «Кабинет (температура)», `bat_kabinet_temperature` | «Гардеробная (температура)`, `bat_garderobnaia_temperature` |
| entity_id автоматизации | `automation.batareia_kabinet_temperatura` | `automation.batareia_garderobnaia_temperatura` |
**Проверено фактом:** `Response: 1 register(s) from 100 (ha:sensor.garderobnaia_temperature_temperature) = 24.61 [00 F6]`.
### 🔴 Питфолл: `id_reuse: Identifier values have to increase`
При переименовании сущностей **6 из 7 упали** с этой ошибкой (хотя целевые `entity_id` были свободны). Это внутренний счётчик реестра, **не поломка**.
**Обход (проверен, 6/6 успешно):** переименовать в промежуточное имя, затем из него в целевое.
```python
# entity_id → dom.tmp_xxx → dom.новое_имя
{"type":"config/entity_registry/update","entity_id": old, "new_entity_id": tmp}
{"type":"config/entity_registry/update","entity_id": tmp, "new_entity_id": new}
# при провале second step — откат на old
```
> 📌 Тот же приём уже применялся для сироты-автоматизации (§3.2, `disabled_by` + `remove`). Общее правило: **любая операция реестра с `id_reuse` лечится промежуточным состоянием.**
### 🔴 Питфолл: HA сам перегенерировал `entity_id` автоматизаций
После `automation/reload` автоматизации получили новые `entity_id` **по alias**: `automation.datchik_protechki_kotelnaia_batareia` → `automation.batareia_kotelnaia_datchik_protechki`. Проверять автоматизации по **`attributes.id`**, а не по `entity_id`.
### Аудит автоматизаций (запрошен Alex: «убедись что автоматизация вся корректная»)
| Метрика | Значение |
|---|---|
| Всего | 24 |
| `on` | 23 |
| `off` | 1 — `Ventilation automation on` (намеренно) |
| `unavailable` | **0** |
| Битых ссылок | **0** (22 проверено) |
| Батарейных | 12, все `on` |
**Бэкапы этого этапа:** `/config/automations.yaml.bak-gard-20260915-225404`, `/addons/modbus-bridge/data/config.template.tmpl.bak-gard-20260915-225404`, реестры в `~/tmp-t610/backup-gard-20260915-225404.json`.
**Скрипты:** `~/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 и оно недоступно», затем «light.smart_light_stairs_l1 — тоже недоступен».
**Причина найдена — записи лежали в архиве реестра**, а не в runtime: `core.entity_registry → data.deleted_entities`. Поэтому `/api/states`, WS-реестр и `repairs/list_issues` их не видели, а UI «Обслуживание» — видел.
**Решение:** контролируемый снос скриптом `~/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`.
---
## 5. ✅ РЕЗУЛЬТАТ — Шаг 5: дока обновлена
- `family/tech/zigbee-t610-z2m-i-zha.md` — карта 16 → 23 устройств, §2.1 «как переименовывать», §4 батареи, §5 виртуальные Modbus, питфоллы 1721.
- `family/how-to/home-automation.md` — шапка, §1 итог, §6 карта slave'ов 100112.
- `family/how-to/ha-automations.md` — карта автоматизаций 14 → 26, батарейные.
- Коммит vault: **`ddba016`**.
---
## 6. Бэкапы, снятые перед работами (2026-09-15 22:34)
| Что | Где |
|---|---|
| Снапшот HA (full) | `23a119f4.tar` в `/backup/` на t610 |
| Реестры (entities/devices/areas) | `~/tmp-t610/backup-preids-20260915-223427/registries-before.json` |
| Реестры (на t610) | `/config/.storage.bak-preids-20260915-223427/` |
| `automations.yaml` | `/config/automations.yaml.bak-preids-20260915-223427` |
| `config.template.tmpl` | `/addons/modbus-bridge/data/config.template.tmpl.bak-preids-20260915-223427` |
---
## 7. Ключевые уроки
| # | Урок |
|---|---|
| 1 | `name_by_user` и `entity_id` — **разные вещи**, менять оба |
| 2 | Переименование рвёт ссылки в `automations.yaml` **молча** — проверять всегда |
| 3 | Переименование рвёт маппинг bridge → slave отдаёт `0` **молча** |
| 4 | Сирота-автоматизация (`unavailable` при чистом YAML) → `remove`, а при `id_reuse` — сначала `disabled_by: user` |
| 5 | Bridge нельзя проверить без ZONT'а иначе, чем через `HA poll ->` в логе |
| 6 | `rebuild` (не `restart`) после правки `data/config.template.tmpl` |
| 7 | Русские имена устройств → HA транслитерирует в мусорные `entity_id` |
| 8 | `id_reuse: Identifier values have to increase` — штатная ошибка реестра, обходится промежуточным именем (`old → tmp → new`) |
| 9 | HA перегенерирует `entity_id` автоматизаций по alias при `reload` — искать по `attributes.id` |
| 10 | Датчик, «не находимый в UI», может быть переименован — искать по IEEE в реестре, а не по старому имени |
## Связанные заметки
- [[family/tech/zigbee-t610-z2m-i-zha]] — справочник ZHA: устройства, рецепт переименования, батареи, Modbus slave'ы
- [[family/how-to/home-automation]] — топология, аддоны, Modbus §6
- [[family/how-to/ha-automations]] — логика автоматизаций