[2026-09-16] eagle: family/how-to/ha-automations.md family/plans/t610-zigbee-ids-battery-freshsensors-modbus.md

This commit is contained in:
Alexey Martemyanov
2026-09-16 12:19:45 +06:00
parent 8c20f0526c
commit 03c9720ebf
2 changed files with 89 additions and 2 deletions
+9
View File
@@ -307,6 +307,15 @@ mode: single
Распределение по триггерам: **`lux` → sleep 2 → проверка присутствия → включить; `presence` → сразу.** Распределение по триггерам: **`lux` → sleep 2 → проверка присутствия → включить; `presence` → сразу.**
> ⚠️ **Не путать поведение по сценариям** (формулировка «включится через 2–3 с» — НЕВЕРНА):
> | Сценарий | Триггер | Когда включается |
> |---|---|---|
> | Заходишь в тёмную душевую | `presence` → `on` | **сразу**, доли секунды |
> | Уже внутри, свет погас | `lux` падает < 6 | sleep 2 → проверка присутствия → включить |
>
> Мгновенность ветки `presence` ограничена не задержкой, а **mmWave-радаром**: `detection_delay = 0.1 с`, `fading_time = 10 с`. Проверено историей: `presence 01:36:07.413` → `свет 01:36:08.195` = **0.78 с**.
> В истории видны и «медленные» пары (`04:53:27.744` → свет `04:53:45.979` = 18 с; `05:14:36.901` → `05:14:50.149` = 13 с) — это НЕ срабатывание по присутствию, а ветка `lux`: радар не переиздал `on`, присутствие уже было `true`, свет включился по падению освещённости.
> 🔴 **ПИТФОЛЛ: `condition: state` с числовым порогом НЕ принимает `below`.** HA отбивает POST: `Message malformed: not a valid option at 'conditions[0].below'`. Порог по освещённости задаётся **только** device-условием `type: is_illuminance`. Ошибка приходит валидацией — конфиг не портится (проверено: после отказа значения остались прежними). > 🔴 **ПИТФОЛЛ: `condition: state` с числовым порогом НЕ принимает `below`.** HA отбивает POST: `Message malformed: not a valid option at 'conditions[0].below'`. Порог по освещённости задаётся **только** device-условием `type: is_illuminance`. Ошибка приходит валидацией — конфиг не портится (проверено: после отказа значения остались прежними).
> 🔴 **ПИТФОЛЛ: `automation.trigger` НЕ подставляет `trigger.id`.** Прогон через него всегда уходит в `default` — ветку `choose` по `trigger.id` так **не протестировать**. Проверять воспроизведением логики временным скриптом (`/api/config/script/config/<tmp>` → reload → вызов → DELETE). > 🔴 **ПИТФОЛЛ: `automation.trigger` НЕ подставляет `trigger.id`.** Прогон через него всегда уходит в `default` — ветку `choose` по `trigger.id` так **не протестировать**. Проверять воспроизведением логики временным скриптом (`/api/config/script/config/<tmp>` → reload → вызов → DELETE).
> ⚠️ `delay` живёт **только в `actions:`** — он не знает, какой триггер сработал. Различать ветки обязательно через `trigger.id` + `choose`. > ⚠️ `delay` живёт **только в `actions:`** — он не знает, какой триггер сработал. Различать ветки обязательно через `trigger.id` + `choose`.
@@ -1,10 +1,10 @@
--- ---
title: "План и результат: читаемые ID Zigbee, алерты батарей, виртуальные Modbus-датчики" title: "План и результат: читаемые ID Zigbee, алерты батарей, виртуальные Modbus-датчики"
created: '2026-09-15' created: '2026-09-15'
updated: '2026-09-16 (ночь: добавлены этапы 5–6 — снос призраков реестра, починка плана этажей и H2000_PRO)' updated: '2026-09-16 (день: добавлен этап 7 — починка автоматизаций кабинета + задержка в душевой)'
type: plan type: plan
namespace: family namespace: family
status: 🟢 ВЫПОЛНЕНО 2026-09-16. Шаги 14 закрыты 2026-09-15; 5–6 (вычистка призраков + починка UI) закрыты 2026-09-16 ночью. Всё проверено фактами. status: 🟢 ВЫПОЛНЕНО 2026-09-16. Шаги 14 закрыты 2026-09-15; 5–6 (вычистка призраков + починка UI) — 2026-09-16 ночью; 7 (починка автоматизаций кабинета + задержка в душевой) — 2026-09-16 днём. Всё проверено фактами.
tags: tags:
- t610 - t610
- zigbee - zigbee
@@ -324,6 +324,80 @@ Alex: «Office temperature sensor battery — HA ругается что у ус
--- ---
## 4b. ✅ ЭТАП 7 — последствия переименования: починка автоматизаций кабинета + задержка в душевой (2026-09-16, день)
**Контекст:** этапы 1–4 переименовали сущности в единый вид `<device>_<role>`, но **две автоматизации кабинета остались на старых ZHA-именах** — хабы симптомов, найденных на следующий день.
### 7.1. Свитч у стола в кабинете не переключал свет
**Симптом (Alex):** «свитч у стола не тригерит переключение света». Сначала прозвучало «вчера ещё работало».
**Первопричина — урок №2 из §7, реализовавшийся буквально:** переименование рвёт ссылки в `automations.yaml` молча. Из 25 автоматизаций переехали 23, эти две — нет.
| id | alias | Было (мёртвое, 404) | Стало (живое) |
|---|---|---|---|
| `5735cb9f855e462dbdbdf680d0d6a66f` | `office_pass_switch_table` | `light.tz3000_5gey1ohx_ts0002_osveshchenie` | `light.office_table_light_switch_light` |
| `45b96f6f38f6488ba70266fa5da665f5` | `office_pass_switch_main` | `light.tz3000_5gey1ohx_ts0002_osveshchenie_2` | `light.office_table_light_switch_light_2` |
**Как доказано:** триггерные сущности → **404** в `/api/states`; реле при этом живы и щёлкали (нажатия доходили до Zigbee), но целевые `light.smart_light_office_left/right` висели `off` без изменений.
> ⚠️ **Ключевой признак, который легко пропустить:** автоматизация с мёртвым триггером остаётся **`state: on`** — `unavailable` НЕ появляется, ошибок в UI нет. Единственный симптом — `last_triggered` не растёт.
### 7.2. Свет мигал при перезагрузке HA — потерялась защита `not_from`
**Причина:** на TrueNAS триггеры несли `not_from: [unavailable, unknown]` (`~/tmp-t610/stage3/truenas/automations.yaml` — эталон). При пересборке автоматизаций под ZHA поле **не перенесли** → голая `platform: state` срабатывала на старте HA (`unavailable → on`) и дёргала `light.toggle`.
**Фикс:** восстановлен `not_from: [unavailable, unknown]` в обеих автоматизациях.
**Верификация — реальный рестарт HA Core, а не рассуждение:**
| Метрика | До | После | Итог |
|---|---|---|---|
| `office_pass_switch_table.last_triggered` | `05:43:07` | `05:43:07` | не изменился ✅ |
| `office_pass_switch_main.last_triggered` | `05:43:20` | `05:43:20` | не изменился ✅ |
| `light.smart_light_office_left/right` | `off` | `off` | не мигнул ✅ |
В logbook: `automation.office_pass_switch_table → unavailable` (`05:45:02.156`), через 3 мс `→ on` — и **ни одной** записи `triggered by state`. Событие отфильтровано.
> 🆕 **Урок №11:** защитные поля триггера (`not_from`/`to`) **теряются при пересборке автоматизаций**. При любой пересборке — сверять их наличие, а не только `entity_id`. `to:` как альтернатива **не нужен**: наблюдаемый порядок `unavailable → on` отсекается `not_from`.
### 7.3. Задержка 2 с на ветке освещённости в душевой
**Задача (Alex):** освещённость упала → sleep 2 → присутствие == true → включить. **Только на триггер по свету**, по присутствию — мгновенно.
**Зачем:** радар mmWave отдаёт `presence` с задержкой; при падении освещённости присутствие не успевало выставиться → условие не проходило → свет не включался.
**Решение:** триггеры размечены `trigger.id` (`lux` / `presence`), задержка повешена на ветку `lux` через `choose`:
```yaml
triggers:
- {type: occupied, entity_id: binary_sensor.shower_2_presence_sensor_presence, id: presence}
- {type: illuminance, entity_id: sensor.shower_2_presence_sensor_illuminance, below: 6, id: lux}
actions:
- choose:
- conditions: [{condition: trigger, id: lux}]
sequence:
- {delay: {seconds: 2}}
- {condition: device, type: is_occupied, entity_id: binary_sensor...presence}
default: []
- {action: light.turn_on, target: {entity_id: light.dushevaia_night_light}}
```
**Верификация:** замер по `last_changed` — вызов `06:13:34` → свет `06:13:37.24` (2 с выдержаны); ветка `lux` при `presence=off` свет **не** включает.
> 🔴 **ПИТФОЛЛ:** `condition: state` с числовым порогом **не принимает `below`** → `Message malformed: not a valid option at 'conditions[0].below'`. Порог освещённости задаётся только device-условием `type: is_illuminance`.
> 🔴 **ПИТФОЛЛ:** `automation.trigger` **не подставляет `trigger.id`** → прогон всегда уходит в `choose.default`, ветку так не протестировать. Проверять временным скриптом (`/api/config/script/config/<tmp>` → reload → вызов → DELETE).
> ⚠️ `delay` живёт только в `actions:` и не знает, какой триггер сработал — ветки различать через `trigger.id` + `choose`.
**ВЫКЛ (`1771997918348`) НЕ тронут** — по решению Alex задержка нужна только на триггере по свету.
**Бэкапы:** `/config/automations.yaml.bak-office-20260916-124244`, `.bak-showerdelay-20260916-131126` на t610; `~/tmp-t610/automations/automations.yaml.{office-before,shower-before}` локально.
**Скрипты:** `fix_office_switch.sh`, `fix_office_guard.sh`, `fix_shower_lux_delay.sh`, `test_shower_lux_branch.sh`, `test_delay_timing.sh` — все в `~/tmp-t610/`.
**Детали:** [[family/how-to/ha-automations]] §2.2, §3, §4.1; питфоллы №2732 в [[family/tech/zigbee-t610-z2m-i-zha]].
---
## 5. ✅ РЕЗУЛЬТАТ — Шаг 5: дока обновлена ## 5. ✅ РЕЗУЛЬТАТ — Шаг 5: дока обновлена
- `family/tech/zigbee-t610-z2m-i-zha.md` — карта 16 → 23 устройств, §2.1 «как переименовывать», §4 батареи, §5 виртуальные Modbus, питфоллы 1721. - `family/tech/zigbee-t610-z2m-i-zha.md` — карта 16 → 23 устройств, §2.1 «как переименовывать», §4 батареи, §5 виртуальные Modbus, питфоллы 1721.
@@ -359,6 +433,10 @@ Alex: «Office temperature sensor battery — HA ругается что у ус
| 8 | `id_reuse: Identifier values have to increase` — штатная ошибка реестра, обходится промежуточным именем (`old → tmp → new`) | | 8 | `id_reuse: Identifier values have to increase` — штатная ошибка реестра, обходится промежуточным именем (`old → tmp → new`) |
| 9 | HA перегенерирует `entity_id` автоматизаций по alias при `reload` — искать по `attributes.id` | | 9 | HA перегенерирует `entity_id` автоматизаций по alias при `reload` — искать по `attributes.id` |
| 10 | Датчик, «не находимый в UI», может быть переименован — искать по IEEE в реестре, а не по старому имени | | 10 | Датчик, «не находимый в UI», может быть переименован — искать по IEEE в реестре, а не по старому имени |
| 11 | **Защитные поля триггера (`not_from`) теряются при пересборке автоматизаций** — при пересборке сверять не только `entity_id`, но и их наличие. Симптом-близнец: свет мигает при рестарте HA |
| 12 | **Автоматизация с мёртвым триггером остаётся `state: on`** — `unavailable` не появляется. Признак один: `last_triggered` не растёт. Проверять сверкой всех `entity_id:` из YAML со `/api/states` |
| 13 | `automation.trigger` не подставляет `trigger.id` → ветку `choose` по `trigger.id` так не протестировать; нужен временный скрипт |
| 14 | `condition: state` не принимает числовой `below` — порог только device-условием `type: is_illuminance` |
## Связанные заметки ## Связанные заметки