[2026-09-16] eagle: family/how-to/ha-automations.md family/tech/zigbee-t610-z2m-i-zha.md

This commit is contained in:
Alexey Martemyanov
2026-09-16 19:57:20 +06:00
parent c1ff7931c4
commit 60ed15963a
2 changed files with 89 additions and 7 deletions
+87 -7
View File
@@ -4,9 +4,11 @@
> 🟢 **25 АВТОМАТИЗАЦИЙ — 24 `on`, 1 `off`** (`Ventilation automation on`, намеренно), `unavailable` = 0. Zigbee работает на ZHA. > 🟢 **25 АВТОМАТИЗАЦИЙ — 24 `on`, 1 `off`** (`Ventilation automation on`, намеренно), `unavailable` = 0. Zigbee работает на ZHA.
> >
> **Состав:** 12 контроля батарей (§5) + 2 циркуляция ГВС + 2 свет кабинета (§2.2, §3) + 2 подсветка лестницы + 2 ночной свет душевой (§4.1) + 2 диммер спальни + 1 протечка котельная + 1 вентиляция + **1 греющий кабель ввода воды (§7)**. > **Состав:** 12 контроля батарей (§5) + 2 циркуляция ГВС + 2 свет кабинета (§2.2, §3) + 2 подсветка лестницы + 2 ночной свет душевой (§4.1–§4.3) + 2 диммер спальни + 1 протечка котельная + 1 вентиляция + **1 греющий кабель ввода воды (§7)**.
> >
> 🗓 **Сессия 2026-09-16 (день):** починены два дефекта автоматизаций кабинета — мёртвые `entity_id` в триггерах (§2.2) и потерянная защита `not_from` (§3); в душевой добавлена задержка 2 с на ветку по освещённости (§4.1). Все три правки верифицированы живым прогоном на железе. > 🗓 **Сессия 2026-09-16 (день):** починены два дефекта автоматизаций кабинета — мёртвые `entity_id` в триггерах (§2.2) и потерянная защита `not_from` (§3). В душевой: задержка 2 с на ветку по освещённости (§4.1), затем `fading_time` 10→2 с + задержка 10 с в сценарии ВЫКЛ (§4.2). Все правки верифицированы живым прогоном на железе **и реальным рестартом HA**.
>
> 🔴 **ОТКРЫТО (см. §4.3):** ложные включения ночного света душевой при выходе — окно `fading_time` + feedback loop через собственную лампу при совпадающих порогах ВКЛ/ВЫКЛ (`6`/`6`). Фиксы (устойчивое присутствие, гистерезис `< 4` / `> 10`) **предложены, но отклонены Alex** — пороги не менять без явной команды.
> >
> **Ключевые факты:** > **Ключевые факты:**
> - 🔴 **ЗАЩИТА ТРИГГЕРА ОБЯЗАТЕЛЬНА для `platform: state` на реле/кнопках:** `not_from: [unavailable, unknown]`. Без неё автоматизация срабатывает при старте HA (`unavailable → on`) и дёргает действие. Реальный случай 2026-09-16 — мигание света в кабинете. **При пересборке автоматизаций это поле теряется молча** (§3). > - 🔴 **ЗАЩИТА ТРИГГЕРА ОБЯЗАТЕЛЬНА для `platform: state` на реле/кнопках:** `not_from: [unavailable, unknown]`. Без неё автоматизация срабатывает при старте HA (`unavailable → on`) и дёргает действие. Реальный случай 2026-09-16 — мигание света в кабинете. **При пересборке автоматизаций это поле теряется молча** (§3).
@@ -112,7 +114,7 @@ action:
| `1771683420621` | Toggle Dimmer bed | кнопка `remote_button_short_press` → `light.toggle light.bed_dimmer` | | `1771683420621` | Toggle Dimmer bed | кнопка `remote_button_short_press` → `light.toggle light.bed_dimmer` |
| `1771683677259` | Dimmer bed cycle | кнопка `long_press` → `light.turn_on` brightness 50 % на `light.bed_dimmer` | | `1771683677259` | Dimmer bed cycle | кнопка `long_press` → `light.turn_on` brightness 50 % на `light.bed_dimmer` |
| `1771997851260` | **Вкл. ночной свет душевая** | `occupied` (`id: presence` — мгновенно) / `illuminance below: 6` (`id: lux` → `delay 2 s` → проверка присутствия) → `light.dushevaia_night_light` on. См. §4.1 | | `1771997851260` | **Вкл. ночной свет душевая** | `occupied` (`id: presence` — мгновенно) / `illuminance below: 6` (`id: lux` → `delay 2 s` → проверка присутствия) → `light.dushevaia_night_light` on. См. §4.1 |
| `1771997918348` | **Выкл. ночной свет душевая** | нет присутствия / светло → off | | `1771997918348` | **Выкл. ночной свет душевая** | `not_occupied` (`id: left` → `wait_for_trigger` 10 с → гасить, если присутствие не вернулось) / `illuminance above: 6` (`id: bright` → сразу) → off. `mode: restart`. См. §4.2 |
| `1773451257968` | Протечка котельная | `moist` → `notify.notify` | | `1773451257968` | Протечка котельная | `moist` → `notify.notify` |
| `8800000000000`…`8800000000011` | **Батарея: 12 шт.** | см. §6 | | `8800000000000`…`8800000000011` | **Батарея: 12 шт.** | см. §6 |
| `heating_cable_ctl_0001` | **Греющий кабель: управление** | `time_pattern /15` + `numeric_state ZONT below 8` + отвал датчика → `choose` 5 веток на `switch.heating_cable_plug`. См. §7 | | `heating_cable_ctl_0001` | **Греющий кабель: управление** | `time_pattern /15` + `numeric_state ZONT below 8` + отвал датчика → `choose` 5 веток на `switch.heating_cable_plug`. См. §7 |
@@ -278,9 +280,49 @@ trigger:
| | id | Триггер | Условие | | | id | Триггер | Условие |
|---|---|---|---| |---|---|---|---|
| ВКЛ | `1771997851260` | `occupied` (`id: presence`) + `illuminance below: 6` (`id: lux`) | `is_illuminance below 6` | | ВКЛ | `1771997851260` | `occupied` (`id: presence`) + `illuminance below: 6` (`id: lux`) | `is_illuminance below 6` |
| ВЫКЛ | `1771997918348` | `not_occupied` + `illuminance above: 6` | ⚠️ **`conditions: []`** — пусто | | ВЫКЛ | `1771997918348` | `not_occupied` (`id: left`) + `illuminance above: 6` (`id: bright`) | ⚠️ **`conditions: []`** — пусто |
### 4.1. ✅ Задержка 2 с на ветке освещённости (2026-09-16) ### 4.2. ✅ `fading_time` 10 → 2 с + задержка 10 с в сценарии ВЫКЛ (2026-09-16, шаг 2)
**Задача (Alex):** снизить `fading_time` радара и перенести задержку в сценарий выключения: «если в течение 10 с датчик не поменялся снова на присутствие — выключать».
**Выполнено:**
| Что | Было | Стало |
|---|---|---|
| `number.shower_2_presence_sensor_fading_time` | `10.0` | **`2.0`** (нижний предел железа) |
| ВЫКЛ `1771997918348` | `turn_off` сразу по `not_occupied` | `wait_for_trigger` присутствие вернулось? → `timeout: 10 s` → гасить только если не вернулось |
**Конструкция ВЫКЛ:**
```yaml
triggers:
- {type: not_occupied, id: left, ...}
- {type: illuminance, id: bright, above: 6}
actions:
- choose:
- conditions: [{condition: trigger, id: left}]
sequence:
- wait_for_trigger:
- {platform: state, entity_id: binary_sensor.shower_2_presence_sensor_presence, to: "on"}
timeout: {seconds: 10}
continue_on_timeout: true
- condition: template
value_template: "{{ wait.completed }}" # вернулся → прервать
default: []
- light.turn_off
mode: restart
```
`mode: restart` обязателен — иначе повторный триггер игнорируется и ожидание не перезапускается.
> 🔴 **ПИТФОЛЛ: `fading_time` у `_TZE204_qasjif9e` (TS0601) не опускается ниже 2 с, хотя HA показывает `min: 1`.** Проверено фактом: `set_value 1.0` → откат к `2.0`; `1.5` → откат; `2.5` → записалось. Прошивка молча игнорирует значения < 2. HA отдаёт `state: 1.0` в ответе сервиса, но сущность возвращается к `2.0` — **всегда читать обратно**.
**Верификация:** оба значения прочитаны обратно; автоматизации 25/24 `on`/1 `off`, `unavailable` = 0.
**Бэкап:** `/config/automations.yaml.bak-shower-off-20260916-205245`.
**Скрипт:** `~/tmp-t610/fix_shower_as_requested.sh`.
> ⚠️ **Не тронуто по указанию Alex:** пороги освещённости остались `below: 6` / `above: 6` (нулевая мёртвая зона → возможен дребезг 2↔12 lx). Гистерезис `< 4` / `> 10` предлагался, но правка отклонена — не менять без явной команды.
### 4.1. ✅ Задержка 2 с на ветке освещённости (2026-09-16, шаг 1)
**Задача (Alex):** «в триггере ночного света по изменению освещённости добавить задержку в пару секунд на проверку присутствия (освещённость упала → sleep 2 → присутствие == true → включить)». **Только на триггер по свету** — по присутствию включать мгновенно. **Задача (Alex):** «в триггере ночного света по изменению освещённости добавить задержку в пару секунд на проверку присутствия (освещённость упала → sleep 2 → присутствие == true → включить)». **Только на триггер по свету** — по присутствию включать мгновенно.
@@ -313,7 +355,7 @@ mode: single
> | Заходишь в тёмную душевую | `presence` → `on` | **сразу**, доли секунды | > | Заходишь в тёмную душевую | `presence` → `on` | **сразу**, доли секунды |
> | Уже внутри, свет погас | `lux` падает < 6 | sleep 2 → проверка присутствия → включить | > | Уже внутри, свет погас | `lux` падает < 6 | sleep 2 → проверка присутствия → включить |
> >
> Мгновенность ветки `presence` ограничена не задержкой, а **mmWave-радаром**: `detection_delay = 0.1 с`, `fading_time = 10 с`. Проверено историей: `presence 01:36:07.413` → `свет 01:36:08.195` = **0.78 с**. > Мгновенность ветки `presence` ограничена не задержкой, а **mmWave-радаром**: `detection_delay = 0.1 с`, `fading_time` = 2 с (на момент замера было 10 с — снижено позже, §4.2). Проверено историей: `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`, свет включился по падению освещённости. > В истории видны и «медленные» пары (`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`. Ошибка приходит валидацией — конфиг не портится (проверено: после отказа значения остались прежними).
@@ -339,7 +381,45 @@ mode: single
**⚠️ Остаточный риск (принят Alex):** при **2 lx** (покой) ВЫКЛ ждёт `above: 6` и может не наступить → свет залипнет. Гистерезис сознательно не сделан. **⚠️ Остаточный риск (принят Alex):** при **2 lx** (покой) ВЫКЛ ждёт `above: 6` и может не наступить → свет залипнет. Гистерезис сознательно не сделан.
**Если залипнет — варианты:** ① гистерезис `вкл below 4 / выкл above 10`; ② гасить по факту включения основной лампы (**блокер: сущность основного освещения верхней душевой неизвестна**); ③ калибровка `illuminance_calibration` радара. **Если залипнет — варианты:** ① гистерезис `вкл below 4 / выкл above 10`; ② гасить по факту включения основной лампы (**блокер: сущность основного освещения верхней душевой неизвестна**); ③ калибровка `illuminance_calibration` радара.
**Параметры радара:** `fading_time` = 10 с, `maximum_range` = 2.85 м — проверять, покрывает ли зона всю душевую. **Параметры радара:** `fading_time` = **2 с** (было 10, снижено 2026-09-16 — см. §4.2; ниже 2 не опускается), `detection_delay` = 0.1 с, `maximum_range` = 2.85 м — проверять, покрывает ли зона всю душевую.
---
## 4.3. 🔴 ОТКРЫТО: ложные включения при выходе (feedback loop, 2026-09-16)
**Симптом (Alex):** «выхожу, выключаю свет, через 2 секунды включается подсветка хоть и не должна».
**Диагноз по логам (`06:16:07` → `06:17:04`) — подтверждён фактом:**
| Время | lux | Событие |
|---|---|---|
| `06:16:00.77` | 12 | светло |
| `06:16:10.14` | 2 | ↓ упала < 6 → триггер `lux` → свет `06:16:12` **on** |
| `06:16:14.13` | 12 | ↑ свет зажёгся → датчик видит 12 |
| `06:16:18.11` | 3 | ↓ → триггер `lux` → `06:16:20` **on** |
| `06:16:24.09` | 12 | ↑ |
| `06:16:31.07` | 4 | ↓ → триггер `lux` → `06:16:33` **on** |
| `06:16:36.05` | 11 | ↑ |
| `06:16:41.04` | 3 | ↓ → триггер `lux` → `06:16:43` **on** |
| `06:17:04.17` | — | presence → `off` (радар отпустил) |
**Две независимые причины:**
1. **Окно `fading_time`.** Вышел → радар держит `presence = on` ещё `fading_time` секунд → проверка присутствия в ветке `lux` **проходит** → свет включается, хотя человека уже нет. Задержка 2 с это не лечит — она на порядок меньше окна (было 10 с; стало 2 с — окно сократилось, но не исчезло).
2. **Feedback loop через собственную лампу.** Свет зажёгся → `lux` подскочила `2 → 12` → стала `> 6` → на следующем падении автоматизация ВКЛ снова срабатывает. Порог ВКЛ и ВЫКЛ **совпадают (6)** → мёртвая зона нулевая → шум датчика (`24` ↔ `1112`) гоняет сценарий по кругу. `mode: single` не спасает: запуск завершается быстрее, чем приходит следующий.
**Предложенные фиксы — НА РАССМОТРЕНИИ, не применены:**
| # | Фикс | Что лечит |
|---|---|---|
| A | Требовать **устойчивое присутствие** (`for: 3s`) перед включением в ветке `lux` | ложные включения при выходе |
| B | **Гистерезис** `below: 4` / `above: 10` | дребезг/мигание (нулевая мёртвая зона) |
| C | **A + B вместе** | обе проблемы |
> 🔴 **Alex отклонил правку порогов** («тебя просили чинить то что не сломано?!») — **не менять пороги без явной команды**. Зафиксировано как открытый вопрос, а не как задача.
> 📌 Пороги `below: 6` / `above: 6` оставлены **намеренно**.
**Что применено в рамках этого разбора:** `fading_time 10 → 2` + задержка 10 с в сценарии ВЫКЛ (§4.2) — по прямому указанию Alex.
--- ---
+2
View File
@@ -410,6 +410,8 @@ curl -s -H "$HDR" http://supervisor/backups | jq
| 30 | 🔴 **BusyBox `date` на t610 не знает `-v-6H`** | BSD-синтаксис macOS. Рабочая форма: `date -u -d "@$(( $(date +%s) - 21600 ))" "+%Y-%m-%dT%H:%M:%S"`. Пустой ответ `history/period` за 48 ч — граница recorder, не поломка | | 30 | 🔴 **BusyBox `date` на t610 не знает `-v-6H`** | BSD-синтаксис macOS. Рабочая форма: `date -u -d "@$(( $(date +%s) - 21600 ))" "+%Y-%m-%dT%H:%M:%S"`. Пустой ответ `history/period` за 48 ч — граница recorder, не поломка |
| 31 | 🔴 **`condition: state` с числовым порогом не принимает `below`** | POST → `Message malformed: not a valid option at 'conditions[0].below'`. Порог освещённости — только device-условием `type: is_illuminance`. Ошибка валидации конфиг НЕ портит (проверено) | | 31 | 🔴 **`condition: state` с числовым порогом не принимает `below`** | POST → `Message malformed: not a valid option at 'conditions[0].below'`. Порог освещённости — только device-условием `type: is_illuminance`. Ошибка валидации конфиг НЕ портит (проверено) |
| 32 | 🔴 **`automation.trigger` НЕ подставляет `trigger.id`** | Прогон через него всегда уходит в `choose.default` — ветку по `trigger.id` так не протестировать. Проверять временным скриптом: `POST /api/config/script/config/<tmp>``script/reload` → вызов → `DELETE`. ⚠️ `delay` живёт только в `actions:` и не знает, какой триггер сработал — ветки различать через `trigger.id` + `choose` | | 32 | 🔴 **`automation.trigger` НЕ подставляет `trigger.id`** | Прогон через него всегда уходит в `choose.default` — ветку по `trigger.id` так не протестировать. Проверять временным скриптом: `POST /api/config/script/config/<tmp>``script/reload` → вызов → `DELETE`. ⚠️ `delay` живёт только в `actions:` и не знает, какой триггер сработал — ветки различать через `trigger.id` + `choose` |
| 33 | 🔴 **`fading_time` радара `_TZE204_qasjif9e` (TS0601) не опускается ниже 2 с** | HA показывает `min: 1` и отдаёт `state: 1.0` в ответе `number.set_value`, но сущность откатывается к `2.0`. Проверено: `1.0``2.0`, `1.5``2.0`, `2.5``2.5`. Прошивка молча игнорирует < 2. **Всегда читать обратно** |
| 34 | 🔴 **`wait_for_trigger` + `wait.completed` в `choose` требует `mode: restart`** | В сценарии «ждать возврат присутствия N секунд, иначе гасить»: `wait_for_trigger` с `timeout` + `continue_on_timeout: true`, затем `condition: template` с `value_template: "{{ wait.completed }}"` внутри `choose.sequence`. При `mode: single` повторный триггер игнорируется и ожидание НЕ перезапускается → старый таймер догасит свет, хотя человек вернулся. Ставить `mode: restart` |
--- ---