[2026-09-16] eagle: family/documents/home-automation-wishlist.md family/how-to/ha-automations.md family/how-to/home-automation.md family/tech/ha-registry-operations.md family/tech/heating-cable-water-inlet.md family/tech/local-ustreamer-addon.md

This commit is contained in:
Alexey Martemyanov
2026-09-16 00:07:30 +06:00
parent 6a350cc802
commit 254a1323fa
6 changed files with 101 additions and 292 deletions
+12 -26
View File
@@ -2,30 +2,17 @@
> **Справочник логики автоматизаций** (`automations.yaml` на t610). Топология/команды/Modbus — [[family/how-to/home-automation]].
> 🟢 **АКТУАЛЬНО 2026-09-16: 25 АВТОМАТИЗАЦИЙ — 24 `on`, 1 `off` (`Ventilation automation on`, намеренно), `unavailable` = 0.** Zigbee работает на ZHA.
> 🟢 **25 АВТОМАТИЗАЦИЙ — 24 `on`, 1 `off`** (`Ventilation automation on`, намеренно), `unavailable` = 0. Zigbee работает на ZHA.
>
> ** 2026-09-16: добавлена `Греющий кабель: управление`** (`automation.greiushchii_kabel_upravlenie`, id `heating_cable_ctl_0001`) — управление вводом воды по `min(ZONT-улица, прогноз met.no 24ч)`, пороги −8/−3 °C (выдержка 12 ч) + аварийный 20 °C + fail-safe. Расчёт обоснования порогов — §7.1.
> **Состав:** 12 контроля батарей (§5) + 2 циркуляция ГВС + 2 свет кабинета + 2 подсветка лестницы + 2 ночной свет душевой + 2 диммер спальни + 1 протечка котельная + 1 вентиляция + **1 греющий кабель ввода воды (§7)**.
>
> 📌 **Сверка счёта:** в §1 ниже упоминается «26» — это счёт **включая 2 удалённые батарейные**, которые ещё числились сиротами в реестре. После чистки реестра было **24**, после 2026-09-16 — **25**. Брать 25.
> **Ключевые факты:**
> - 🔴 **`entity_id` автоматизаций HA перегенерирует по alias** — искать по `attributes.id`, не по `entity_id`.
> - 🔴 **REST `GET/POST /api/config/automation/config/<id>` использует поля во множественном числе** — `triggers`/`conditions`/`actions` (в файле — единственное). Ошибка молча уходит в пустоту: POST → `200 ok`, значения НЕ меняются. **Всегда читать обратно.**
> - ⚠️ **Кнопка спальни** шлёт `remote_button_short_press` только после `zha/devices/reconfigure`.
>
> **➕ Добавлено в этот вечер: 12 автоматизаций контроля батарей** (id `8800000000000`…`8800000000011`, все `on`). Порог **20 %**, выдержка **2 ч**, двойной канал: `persistent_notification` + push `notify.mobile_app_sm_s931b`; при возврате заряда уведомление гасится (`notification_id: bat_<slug>`). Детали — §5.
> ⛔ **Удалены 2 прежние батарейные** (`1773451323415`, `1773459663218`) — были с порогом 10 и без push. Их осиротевшие записи в реестре вычищены (питфолл §5.1).
> 🔄 **Переименованы** ссылки после единообразия ID: `light.night_light_shower_2` → `light.dushevaia_night_light`, `sensor.tz3000_akqdg6g7_ts0201_batareia` → `sensor.kabinet_temperature_battery` → `sensor.garderobnaia_temperature_battery` (датчик перенесён в Гардеробную).
> 🔴 **`entity_id` автоматизаций HA перегенерировал по alias** — искать автоматизацию по `attributes.id`, не по `entity_id`. Пример: `automation.datchik_protechki_kotelnaia_batareia` → `automation.batareia_kotelnaia_datchik_protechki`.
> 📄 Полный отчёт о работах: [[family/plans/t610-zigbee-ids-battery-freshsensors-modbus]].
>
> Переезд Zigbee Z2M → ZHA выполнен. Автоматизации были сломаны не по `entity_id`, а глубже — они ссылались на `device_id` + внутренний `entity_id`-UUID, а устройства Z2M удалены. **Пересобраны заново** на ZHA-шные `device_id` + актуальные `entity_id`.
>
> **Что доделано после первичной пересборки:**
> - ✅ **4 «призрака»-автоматизации УДАЛЕНЫ** из `core.entity_registry` (тела не существовало: `GET /api/config/automation/config/<id>` → 404). Файл: 12 блоков vs 16 сущностей.
> - ✅ **2 сценария подсветки лестницы ПЕРЕСОЗДАНЫ** на `sensor.light_sensor_stairs_illuminance` (`light.light_stairs_left`/`_right`), оба `on`.
> - ✅ **`Toggle Dimmer bed` / `Dimmer bed cycle` — залиты и `on`**: триггер от кнопки, действия на `light.bed_dimmer` (было — реле сауны).
> - ⚠️ **Кнопка спальни:** события `remote_button_short_press` идут **только после `zha/devices/reconfigure`**. Дамп кластеров ДО reconfigure вводит в заблуждение.
>
> **Итог на 2026-09-15 (поздний вечер): 26 автоматизаций, `unavailable` = 0.**
>
> **Бэкап:** `/config/automations.yaml.bak-dimmer-fix` (последняя правка) + `.bak-before-autofix-20260915-212636` + `.bak-zha-20260915-211613` ✅
> **Рецепт пересборки + питфоллы — [[family/tech/zigbee-t610-z2m-i-zha]].**
> **Бэкапы перед правками:** `automations.yaml.bak-cable3-20260915-*` (кабель), `.bak-preids-*`, `.bak-gard-*` (единообразие ID). Локальные копии в `~/tmp-t610/`.
> 📄 Рецепт пересборки после Z2M→ZHA и питфоллы — [[family/tech/zigbee-t610-z2m-i-zha]].
>
> 🔴 **ПИТФОЛЛЫ, найденные при починке:**
> 1. **`device`-триггер батареи — тип `battery_level`, НЕ `battery`.** Иначе `Automation ... failed to setup triggers and has been disabled`.
@@ -36,9 +23,8 @@
## 1. Где живёт
- **Файл:** `/config/automations.yaml` в HA Core на t610.
- **Всего:** **25 автоматизаций — 24 `on`, 1 `off`** (`Ventilation automation on`, намеренно, `last_triggered` 12 марта), **`unavailable` = 0**. Файл = 780 строк (650 + 130 новой автоматизации кабеля).
- **Бэкапы перед правками 2026-09-16 (кабель):** `/config/automations.yaml.bak-cable-20260915-234837`, `.bak-cable2-*`, `.bak-cable3-*`; локально — `~/tmp-t610/bak-cable-20260915-234837/automations.yaml`.
- **Бэкапы перед правками 2026-09-15 (поздний вечер):** `/config/automations.yaml.bak-preids-20260915-223427`, `/config/automations.yaml.bak-gard-20260915-225404` (перед переносом датчика в Гардеробную); рабочая копия — `~/tmp-t610/autfix-20260915-223427/automations.yaml` (плюс `.pre-bat` — до добавления батарейных).
- **Всего:** **25 автоматизаций — 24 `on`, 1 `off`** (`Ventilation automation on`, намеренно), **`unavailable` = 0**. Файл = 780 строк.
- **Бэкапы перед правками:** `automations.yaml.bak-cable3-<ts>` (кабель, 2026-09-16), `.bak-preids-*`, `.bak-gard-*`; локально — `~/tmp-t610/bak-cable-20260915-234837/automations.yaml`.
- **Удалены 4 «призрака»** (записи в реестре без тела): `svetlo_vykl_osveshchenie_lestnitsy`, `temno_vkl_podsvetku_lestnitsy`, `datchik_osveshchennosti_lestnitsa_batareia`, `light_switch_bed_batareia`. Тела не было (`config/automation/config/<id>` → 404) — лестничные сценарии **пересозданы заново** с теми же id.
- **Локальная копия:** `~/tmp-t610/automations/automations.yaml`; после пересборки — `~/tmp-t610/automations-new.yaml`, `~/tmp-t610/automations-fixed.yaml`.
- **Читать живьём через API** (не по памяти):
@@ -285,8 +271,8 @@ actions:
> ⚠️ **WS `render_template` возвращает `null`** даже для `{{ 2 + 2 }}` — шаблоны проверять только через REST `POST /api/template`.
> ⚠️ **`automation.trigger` через WS не обновляет `last_triggered`** — прогон подтверждать иначе (значения в `variables`, лог HA).
📄 **План: [[family/plans/t610-heating-cable-automation]]**
🧰 **Инструменты:** `~/tmp-t610/ha_ws.py forecast <entity> <daily|hourly>`, `verify_cable.py`, `rest_tpl.sh`, `verify_calc.sh`.
📄 **План (выполнен):** `family/plans/t610-heating-cable-automation.md`
🧰 **Инструменты:** `~/tmp-t610/ha_ws.py forecast <entity> <daily|hourly>`, `verify_cable.py`, `verify_calc.sh`, `rest_tpl.sh`.
### ⚠️ Не проверено физически
+85 -116
View File
@@ -2,13 +2,13 @@
title: "🏠 Домашняя автоматизация"
aliases: [Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset]
tags: [family, how-to, smarthome]
updated: 2026-09-16 (греющий кабель ввода воды автоматизирован — `automation.greiushchii_kabel_upravlenie`, пороги 8/3 °C / 12 ч, прогноз через `action: weather.get_forecasts`; автоматизаций 25. §2. H2000_PRO: единицы °F→°C через `options_domain: sensor.private`; питфолл доступа к API с Mac — только через SSH. Справочник кабеля: [[family/tech/heating-cable-water-inlet]])
updated: 2026-09-16 (греющий кабель ввода воды автоматизирован — `automation.greiushchii_kabel_upravlenie`, пороги 8/3 °C / 12 ч, прогноз через `action: weather.get_forecasts`; автоматизаций 25. §2. H2000_PRO: единицы °F→°C через `options_domain: sensor.private`; питфолл доступа к API с Mac — только через SSH)
---
# 🏠 Домашняя автоматизация
> **Единственный справочник по домашней автоматизации.** Всё: топология, железо, Zigbee, Modbus, доступ, команды, сценарии, питфоллы.
> **Автоматизации** (16 шт., логика, дефекты) — [[family/how-to/ha-automations]].
> **Автоматизации** (25 шт., логика, дефекты) — [[family/how-to/ha-automations]].
> 📄 Правка этой доки не появится на телефоне после `git push` — нужен прогон sync-петли: [[family/how-to/vault-sync-pipeline]].
> 🧰 Локальные скрипты диагностики: `~/tmp-t610/diag.sh`, `diag2.sh`, `diag3.sh`, `diag4.sh`, `stats.sh` (снимаются на t610 через `scp` + `sh /tmp/…`).
@@ -154,20 +154,20 @@ ssh -i ~/.ssh/id_rsa root@192.168.2.176 '<команда>' # аддон core_
|---|---|---|---|---|
| Terminal & SSH | `core_ssh` | SSH | 22 | ✅ started |
| Mosquitto broker | `core_mosquitto` | MQTT | 1883 | ✅ started |
| Zigbee2MQTT | `45df7312_zigbee2mqtt` | Zigbee v2.14.1 | 8485 | ⏸ **stopped** (2026-09-15 ночь-12 — освобождён стик под ZHA) |
| Zigbee2MQTT | `45df7312_zigbee2mqtt` | Zigbee v2.14.1 | 8485 | ⏸ **stopped** (2026-09-15 — освобождён стик под ZHA) |
| Node-RED | `a0d7b954_nodered` | вентиляция CO₂ | ingress | ⏸ **stopped** (2026-09-15) |
| mbusd | `local_mbusd` | шлюз Modbus RTU→TCP | 502 | ✅ started |
| modbus-bridge | `local_modbus-bridge` | снифф ZONT-шины | — | ✅ started |
| ustreamer (кастомный) | `local_ustreamer` | камера: JPEG раз в N сек | 8090 | ✅ started |
> 🔴 **2026-09-15 (ночь-4): `go2rtc` и `go2rtc-hardware` УДАЛЕНЫ** (`stop` + `uninstall` через Supervisor API). Оба были источником RCU stall (§3.6).
> 🗑 **2026-09-15 (ночь-6): `core_configurator` (File editor) УДАЛЁН.** Веб-редактор `/config` не использовался, зато **писал `GET /` каждые 30 с** и на каждый запрос логировал `502 Bad Gateway` (HA Core лежал) → цикл ретраев + запись лога = постоянная I/O-нагрузка на слабом хосте.
> ⏸ **2026-09-15 (ночь-6): `a0d7b954_nodered` ОСТАНОВЛЕН** (не удалён) — жирный процесс на 1.4 ГБ RAM, для камеры не нужен.
> 🔴 **`go2rtc` и `go2rtc-hardware` УДАЛЕНЫ** (2026-09-15, `stop` + `uninstall` через Supervisor API). Оба были источником RCU stall (§3.6).
> 🗑 **`core_configurator` (File editor) УДАЛЁН.** Веб-редактор `/config` не использовался, зато **писал `GET /` каждые 30 с** и на каждый запрос логировал `502 Bad Gateway` (HA Core лежал) → цикл ретраев + запись лога = постоянная I/O-нагрузка на слабом хосте.
> ⏸ **`a0d7b954_nodered` ОСТАНОВЛЕН** (не удалён) — жирный процесс на 1.4 ГБ RAM, для камеры не нужен.
> ✅ **Текущий список — 7 аддонов** (проверен `GET /addons`): `core_ssh`, `core_mosquitto`, `a0d7b954_nodered` (**stopped**), `45df7312_zigbee2mqtt`, `local_mbusd`, `local_modbus-bridge`, `local_ustreamer`.
> 💡 **Диагностический признак:** аддон в `state: error`, но в логе `Service exited with code 256 (by signal 15)` → это **нормальная остановка**, а `error` — финальный статус. Читать лог, а не только `state`.
> 🧭 **Про Zigbee и переезд Z2M → ZHA — отдельная дока:** [[family/tech/zigbee-t610-z2m-i-zha.md]]. Кратко: HA штатно Zigbee поддерживает (ZHA встроена, стик тот же); **`coordinator_backup.json` у ember-адаптера ВСЕГДА пуст** — перенос «без спаривания» держится на **NVRAM стика**, а не на файле. 🔑 **ZHA сама принимает устройства после `reuse_settings`** — «Add device» и окно спаривания НЕ нужны (проверено: 12 из 16 подхватились без действий). Ручного остаётся: **переименовать сущности** (ZHA даёт технические имена `light.tz3000_*`) + **разбудить 4 батарейных**. **Статус на 2026-09-15 ночь-12: Z2M остановлен, ZHA создана, переезд идёт.**
> 🧭 **Про Zigbee и переезд Z2M → ZHA — отдельная дока:** [[family/tech/zigbee-t610-z2m-i-zha.md]]. Кратко: HA штатно Zigbee поддерживает (ZHA встроена, стик тот же); **`coordinator_backup.json` у ember-адаптера ВСЕГДА пуст** — перенос «без спаривания» держится на **NVRAM стика**, а не на файле. 🔑 **ZHA сама принимает устройства после `reuse_settings`** — «Add device» и окно спаривания НЕ нужны (проверено: 12 из 16 подхватились без действий). Ручного остаётся: **переименовать сущности** (ZHA даёт технические имена `light.tz3000_*`) + **разбудить 4 батарейных**.
**Опции аддонов** меняются только через Supervisor API (не `ha apps`, который умеет лишь start/stop/rebuild). Для PATCH нужен **ПОЛНЫЙ набор опций**, иначе 400.
@@ -189,70 +189,52 @@ ha apps restart local_modbus-bridge
> ⚠️ Два CH340 **без серийников** → by-id идентичен. Только **by-path**.
> `uart: true` в конфиге аддона — udev-алиасы не нужны. В аддоне нет `udevadm`, `/etc/udev/rules.d`.
### 3.1. RCU stall + смерть хоста — что установлено и что ОПРОВЕРГНУТО
### 3.1. RCU stall — причина найдена и устранена
> 🔴 **СТАТУС КАНОНА (2026-09-15, ночь-4):** первопричина RCU stall **НАЙДЕНА И УСТРАНЕНА**. Это **ffmpeg-транскод камеры в go2rtc**: `[exec] timeout` — ffmpeg не укладывается в таймаут, каждый запрос стрима рождал процесс, который жрёт CPU и читает `/dev/video0` с медленного HDD. Именно это (а не камера сама по себе и НЕ память) укладывало хост. **Оба аддона go2rtc удалены**, вместо них `local_ustreamer` (одиночный JPEG по запросу). Детали — §3.6.
> ⛔ Версия «камера на EHCI/USB2 → порт виноват, лечится перестановкой в xHCI» — **ОПРОВЕРГНУТА**: после чистого старта сбросы камеры вернулись и на xHCI (`usb 3-1: reset high-speed ... using xhci_hcd`, t=113 и t=126).
> ⛔ Версия «носитель деградировал» — **ОПРОВЕРГНУТА** (ложный замер, см. §3.4).
> ⛔ Версия «Memory pressure → OOM» — **ОПРОВЕРГНУТА**: `MemFree` падает как **следствие** I/O-шторма, не как причина.
**Первопричина:** ffmpeg-транскод камеры в `go2rtc`. Каждый запрос стрима рождал процесс ffmpeg, который молотил CPU на 2 слабых ядрах и читал `/dev/video0` с HDD 5400 rpm. Не укладывался в таймаут → `[exec] timeout` → процессы копились → load 9.73 на 2 ядрах, `pressure/io 92%`, `MemFree 16 МБ` → RCU grace period не проходит → stall.
**Что доказано фактами:**
**Решение:** оба аддона go2rtc удалены, вместо них `local_ustreamer` (одиночный JPEG по запросу). Детали — §3.6.
**Что опровергнуто фактами:**
| Версия | Почему неверна |
|---|---|
| «Порт виноват (EHCI→xHCI)» | После чистого старта сбросы вернулись и на xHCI |
| «Носитель деградировал» | Ложный замер — `find`/`du` сам создаёт I/O-шторм (§3.4) |
| «Memory pressure → OOM» | `MemFree` падает как **следствие** I/O-шторма, не причина |
| «`OOM is now expected behavior` = кончилась память» | Это голодание kthread, не OOM |
**Что доказано:**
| Наблюдение | Значение |
|---|---|
| `sda` = **WDC WD2500BEVT** (250 ГБ, 5400 rpm, `rotational=1`) | Носитель — ноутбучный **HDD**, не SD/eMMC и не SSD |
| Load 4.47 → `% io 90`, `% sirq 10` в момент приступа | Нагрузка **прерыванийная**, не вычислительная |
| Камера `046d:0825` сбрасывалась на EHCI (USB2-1) **и** на xHCI (USB3-1) | Порт — не причина сбросов |
| `runtime_suspended_time` 124 с на EHCI, 108 с на xHCI | Камера **засыпает и не просыпается** на обоих контроллерах |
| `bMaxPower = 500 mA` | Версия «нехватка питания» остаётся живой, не проверена |
| `sda` = WDC WD2500BEVT, 5400 rpm, `rotational=1` | Носитель — HDD, не SD/eMMC |
| Load 4.47 → `% io 90`, `% sirq 10` | Нагрузка прерыванийная, не вычислительная |
| Камера сбрасывалась и на EHCI, и на xHCI | Порт — не причина |
| `bMaxPower = 500 mA` | Версия «нехватка питания» не проверена |
> ⚠️ **Строка «OOM is now expected behavior» — НЕ диагноз OOM.** Это стандартное предупреждение ядра о голодании kthread. Память тут ни при чём.
**Почему 2 ядра не спасают:** RCU grace period требует quiescent state на **всех** CPU. Залипло одно — второй тоже не прогрессирует. Контейнерные лимиты бесполезны: hardirq обрабатывает ядро.
**Почему 2 ядра не спасают:** нагрузка не вычислительная, а прерыванийная. RCU grace period требует прохождения quiescent state на **ВСЕХ** CPU; залипло одно — второй тоже не может прогрессировать, и htop показывает 100% на обоих. Контейнерные лимиты бесполезны: hardirq обрабатывается ядром. `rcu_preempt` — ядровой kthread, он starved не потому что его «съели», а потому что планировщик не может его разбудить.
### 3.6. go2rtc → local_ustreamer: почему
### 3.6. ✅ ПЕРВОПРИЧИНА RCU stall — ffmpeg-транскод go2rtc
**Механизм поломки:** `go2rtc` не отдаёт MJPEG напрямую — он запускал внешний `ffmpeg` для транскода MJPEG → H.264. На t610 `libx264` в реальном времени не успевает:
1. Каждый запрос стрима рождает новый процесс ffmpeg.
2. Процесс молотит CPU и читает `/dev/video0` с медленного HDD.
3. `[exec] timeout` → поток не отдаётся → `broken pipe`.
4. При шторме процессов load 9.73 на 2 ядрах → RCU stall.
**Установлено 2026-09-15 (вечер-3)** по логу аддона `a889bffc_go2rtc`:
**Замеры шторма:**
```
[exec] timeout source="exec:ffmpeg -hide_banner -v error -f v4l2 -input_format mjpeg \
-i /dev/video0 -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast \
-tune:v zerolatency -pix_fmt:v yuv420p -an -vf \"transpose=1\" ... -f rtsp rtsp://127.0.0.1:8554/<hash>"
WRN [rtsp] error="streams: exec: timeout" stream=usb_camera_h264
ERR mjpeg.go:126 > error="write tcp ...:1984->...: broken pipe"
```
**Механизм:** `go2rtc` не отдаёт MJPEG напрямую, а **запускает внешний `ffmpeg`** для транскода MJPEG → H.264. На t610 (2 слабых ядра + HDD 5400 rpm) `libx264` в реальном времени **не успевает**:
1. Каждый запрос стрима (открытие камеры в HA UI на телефоне) рождает **новый процесс ffmpeg**.
2. ffmpeg молотит CPU и читает `/dev/video0` с медленного HDD.
3. Не укладывается в таймаут → `[exec] timeout` → поток не отдаётся.
4. Клиент (телефон) отваливается → `broken pipe`.
5. При шторме запросов процессы ffmpeg копятся → load 9.73 на 2 ядрах, `pressure/io 92%`, `pressure/memory 57%`, `MemFree 16 МБ` → RCU grace period не проходит → **RCU stall**.
> 🔴 **Итог: камера роняет хост не «железом», а транскодом.** Порт, EHCI/xHCI, автосон, 500 мА — всё это **следствия или второстепенное**. Виновник — CPU-bound транскод на неподходящем железе.
**Замеры шторма (2026-09-15):**
| Метрика | Норма (чистый фон) | В шторме |
| Метрика | Норма | В шторме |
|---|---|---|
| `load average` | 0.751.7 | **9.73** |
| `pressure/io some avg10` | ~16 % | **92.27 %** |
| `pressure/memory some avg10` | ~0 % | **57.18 %** |
| `pressure/io some avg10` | ~16 % | **92 %** |
| `pressure/memory some avg10` | ~0 % | **57 %** |
| `MemFree` | 332 МБ | **16 МБ** |
| `% io` в top | 0 % | **5066 %** |
**Как починено (✅ ПРИМЕНЕНО 2026-09-15, ночь-4):**
**Решение:** оба аддона go2rtc удалены, вместо них `local_ustreamer` — Python-сервер на `/frame` поднимает ffmpeg только по запросу клиента и снимает **один кадр**. H.264 нет вообще. Результат: load 0.76, `pressure/io` 3.26 %.
1.**Транскод убран полностью.** Оба аддона go2rtc **удалены** (`stop` + `uninstall`). Вместо них — собственный аддон **`local_ustreamer`** v2.0.0: Python-сервер на `/frame` поднимает `ffmpeg` **только по запросу клиента**, снимает **один кадр** с `/dev/video0`, поворачивает и отдаёт JPEG. H.264 нет вообще → CPU не тратится в фоне. Детали — §4 «Данные камеры».
2. **Оставлен один потребитель камеры** вместо двух (`go2rtc` + `go2rtc-hardware` — оба снесены).
3. Альтернатива «облегчить ffmpeg» (`-preset ultrafast`, 320×240, `-r 10`) — **не понадобилась**: реалтайм-транскода больше нет.
**Результат:** load вернулся к 0.76, `pressure/io` 3.26 %, 100 % idle. Хост больше не укладывается при обращении к камере.
> ⚠️ **Осиротевший `/config/go2rtc.yaml`** (1085 байт) остался на месте — go2rtc удалён, конфиг читать нечем. Судьба ждёт решения Alex.
> ⛔ Раньше конфиг жил в опциях аддона `a889bffc_go2rtc` (`.data.options` через `/info`); после удаления аддона опции исчезли.
> ⚠️ Транскод-строка с `-vf \"transpose=1\"` = поворот на 90° (`#rotate=90`), см. §4 «Данные камеры».
> ⚠️ **Осиротевший `/config/go2rtc.yaml`** (1085 байт) остался — go2rtc удалён, конфиг читать нечем.
### 3.7. 🔴 Watchdog аддонов ВЫКЛЮЧЕН по умолчанию — упавший аддон не поднимется сам
@@ -284,41 +266,17 @@ curl -s -X POST -H "$H" -H "$CT" -d '{"watchdog":true}' \
| `local_mbusd` | ✅ true |
| `local_modbus-bridge` | ✅ true |
| `a0d7b954_nodered` | ✅ true |
| ~~`a889bffc_go2rtc`~~ | ⛔ аддон удалён 2026-09-15 (ночь-4) |
| ~~`a889bffc_go2rtc`~~ | ⛔ аддон удалён 2026-09-15 |
> ⚠️ Для `local_ustreamer` watchdog **не включался** — проверить, если камера должна подниматься сама.
> 📌 Эндпоинт: **`POST /addons/<slug>/options`** с `{"watchdog":true}`. Отдаёт `{"result":"ok","data":{}}`. Для PATCH нужен ПОЛНЫЙ набор опций (питфолл 15), но `watchdog` в одиночку проходит.
### 3.8. 🔴 Zigbee2MQTT — падение на MQTT-подключении при старте (баг логгера)
### 3.8. Zigbee2MQTT — остановлен
**Симптом (лог аддона):**
```
z2m: Connected to MQTT server
z2m: MQTT failed to connect, exiting... (write after end)
NodeError: write after end
at writeAfterEnd (.../readable-stream/lib/_stream_writable.js:264)
... winston/lib/winston/logger.js ...
Node.js v24.18.1
```
Затем процесс умирает → аддон в `state: error`.
Z2M **остановлен** с 2026-09-15 (стик отдан ZHA), данные целы в `/config/zigbee2mqtt/`. Всё, что ниже относилось к его падениям, — история.
**Это НЕ проблема serial-порта.** В логе Mosquitto видно, что Z2M **подключился** и сам закрыл соединение через 3 с:
```
19:16:49 New client connected from 172.30.33.4 as mqttjs_250063e1 (u'zont')
19:16:52 Client mqttjs_250063e1 disconnected: connection closed by client
```
**Причина:** внутренний баг Z2M (v2.14.1-1) — падение в `winston`-логгере при записи в уже закрытый поток. Триггерится, когда MQTT-брокер отвечает с задержкой (параллельный старт: Z2M в 19:16, Mosquitto в 19:08 ещё дорегистрировался).
**Что НЕ надо проверять (проверено, всё исправно):**
- `serial.port` в `/config/zigbee2mqtt/configuration.yaml` = `by-id/usb-Inswift_Zigbee_ZBP-MG21_535A000001-if00`**by-id, не by-path**, поэтому перестановка USB-портов его **не ломает**. Ссылка резолвится в `ttyACM0` ✅.
- `mqtt.server: mqtt://core-mosquitto:1883`, user `zont` — верны.
- Стик `1a86:55d4` на `USB1-2``ttyACM0` — на месте.
**Фикс:** `ha apps restart 45df7312_zigbee2mqtt` (или `ha addons restart`), после того как Mosquitto стабилен. Плюс включён watchdog (§3.7) — теперь поднимется сам.
> ⚠️ Если при рестарте ответ `Error: Another job is running for job group app_<slug>` — предыдущий рестарт ещё идёт, **подождать**, не долбить повторно.
> 📌 На будущее, если Z2M понадобится снова: он падает при старте с `MQTT failed to connect, exiting... (write after end)` в `winston`. **Это не serial-порт** — в логе Mosquitto видно, что Z2M подключился и сам закрыл соединение через 3 с. Причина — баг логгера Z2M v2.14.1 при задержке ответа брокера. Лечится рестартом после стабилизации Mosquitto. Проверено: `serial.port` = `by-id/...` (перестановка USB его не ломает).
**Диагностика при «HA не отвечает» — порядок:**
1. Пинг + ARP хоста (`/sbin/ping`, `/usr/sbin/arp -an`) — жив ли вообще. `ARP no entry` = L2-ответа нет.
@@ -473,7 +431,7 @@ IEEE-адреса — источник истины `/config/zigbee2mqtt/configu
**Logitech `046d:0825`** (счётчик газа BK-G4T), отдаёт только MJPEG.
> 🔴 **АРХИТЕКТУРА СМЕНИЛАСЬ (2026-09-15, ночь-4) — go2rtc БОЛЬШЕ НЕТ.**
> 🔴 **АРХИТЕКТУРА СМЕНИЛАСЬ — go2rtc БОЛЬШЕ НЕТ.**
> Оба аддона go2rtc **удалены**. Камера теперь обслуживается **собственным аддоном `local_ustreamer`** (порт **8090**):
> ```
> GET http://192.168.2.176:8090/frame → JPEG 480×640, ~19 КБ, ~4.7 с
@@ -481,7 +439,7 @@ IEEE-адреса — источник истины `/config/zigbee2mqtt/configu
> **Принцип:** Python HTTP-сервер на `/frame` запускает `ffmpeg` **только когда есть клиент**, снимает **один кадр**, поворачивает (`transpose`) и отдаёт JPEG. Никакого H.264, никакого реалтайм-транскода, никакого постоянного процесса — снимает и CPU-жор, и RCU stall.
>
> ⚠️ **ОРИЕНТАЦИЯ — НЕ ЗАКРЫТО:** сейчас в фильтре `transpose=1` (90° по часовой), счётчик ложится на бок. Нужен **`transpose=2`** (90° против часовой). Правка в `/addons/ustreamer/` + rebuild аддона.
> ⚠️ **ПОДКЛЮЧЕНИЕ К HA — ДИАГНОЗ ГОТОВ, ПРАВКА НЕ ВНЕСЕНА (2026-09-15, ночь-5).**
> ⚠️ **ПОДКЛЮЧЕНИЕ К HA — ДИАГНОЗ ГОТОВ, ПРАВКА НЕ ВНЕСЕНА.**
> Сущность в HA уже есть — `camera.192_168_2_176`, но она **не обновляется**, потому что интеграция **Generic Camera** (не YAML!) настроена на мёртвые адреса. Полные опции entry:
> ```json
> entry_id: 01M2FX50K72X2RSYY549QSG3XP domain: generic title: 192_168_2_176
@@ -797,7 +755,7 @@ bedroom_co2: correction_offset: -495 → 589.5 495 = 94.5 ❌ (в HA
**Сырой float32 УЖЕ в ppm** — 846.9 ppm для детской и 589.5 ppm для спальни правдоподобны. Обе коррекции — **мусор от старых попыток парсинга** (подбирались, когда парсер читал мало байт). Температура/влажность работают правильно, потому что их `correction_offset: -4.5` подобран верно.
### ✅ ФИКС ВЫПОЛНЕН (2026-09-15, ночь-22:1922:25) — подтверждён фактом
### ✅ ФИКС ВЫПОЛНЕН — подтверждён фактом
1. ✅ Бэкап: `data/config.template.tmpl.bak-co2fix-20260915-221932`
2. ✅ Удалены **обе строки целиком** (awk-скрипт, не perl — **на хосте t610 perl НЕТ**, `perl: command not found`):
@@ -839,36 +797,47 @@ ssh root@192.168.2.176 'ha apps logs local_modbus-bridge | grep -E "Raw RTU|→
## 8. Текущее состояние
> 🕐 Обновлено **2026-09-16** — автоматизация греющего кабеля ввода воды загружена и работает; баг CO2 закрыт (§9), Zigbee переехал на ZHA, камера на `local_ustreamer`.
> 🕐 Обновлено **2026-09-16**.
- ✅ **ГРЕЮЩИЙ КАБЕЛЬ ВВОДА ВОДЫ АВТОМАТИЗИРОВАН (2026-09-16):** `automation.greiushchii_kabel_upravlenie` (id `heating_cable_ctl_0001`), `on`. Пороги по `eff = min(ZONT-улица, прогноз met.no 24ч)`: ВКЛ `8 °C` (выдержка 12 ч), ВЫКЛ `3 °C` (12 ч), аварийный `20 °C` (без выдержки), fail-safe при отвале датчика, алерт обрыва при `power < 5 W`. Прогноз — `action: weather.get_forecasts` + `response_variable` (в Jinja недоступен). Обоснование порога: `d_fn = 0,23·√63,9 = 1,84 м` (суглинок), труба на 4 м не замерзает — опасна только бетонная подушка 30 см. Полный расчёт: [[family/tech/heating-cable-water-inlet]]. **Автоматизаций стало 25** (24 `on`). ⚠️ Физически не проверено: розетка ни разу не включалась (`off`, `0 W`).
- ✅ **MODBUS CO2 ПОЧИНЕН (2026-09-15, ночь-22):** в `data/config.template.tmpl` убраны мусорные `correction_offset: -925` (kids_co2) и `-495` (bedroom_co2); `rebuild` + `start` аддона. Было **−76 / 94**, стало **848 / 599 ppm**. Все три slave (dining/kids/bedroom) публикуют каждые ~10 с, значения правдоподобны. Бэкап `.bak-co2fix-20260915-221932`. Детали — §9.
- ✅ **Сводки `sensor.*_summary` ИСПРАВНЫ** — `dining 24° 519ppm`, `kids 24° 849ppm`, `bedroom 25° 599ppm`, `dining_air 25tvoc 6pm`. Правка `configuration.yaml` **не вносилась** (ложная тревога). ⚠️ Прежняя запись про `TemplateError: round got invalid input 'unknown'` на `sensor.bedroom_summary` — при живых данных не воспроизводится (ошибка была из-за `unavailable` до фикса).
**Работает:**
- ✅ **КАМЕРА ПОЧИНЕНА (архитектурно):** оба аддона go2rtc (обычный + hardware) **удалены** через Supervisor API. Вместо них — собственный аддон **`local_ustreamer`** v2.0.0, порт **8090**: `GET /frame` → JPEG 480×640, ffmpeg поднимается **только при клиенте** и снимает **один кадр**. Реалтайм-транскода H.264 больше нет → причина RCU stall устранена. См. §3.6, §4.
- ✅ **Хост стабилен:** load 0.76, `pressure/io` 3.26 %, 100 % idle. Проверено после сноса.
- ✅ **Все `.bak-*` снесены с t610:** `go2rtc.yaml.bak-*` (3), `/config/*.bak-*` (11), `/config/zigbee2mqtt/*.bak-*` (6) — итого **20 файлов**. Проверено: остатков нет.
- ✅ **Список аддонов после чистки (7):** `core_ssh`, `core_mosquitto`, `a0d7b954_nodered` (⏸ stopped), `45df7312_zigbee2mqtt` (⏸ stopped — стик отдан ZHA), `local_mbusd`, `local_modbus-bridge`, `local_ustreamer`. `core_configurator` удалён (ночь-6); `go2rtc` ×2 удалены (ночь-4).
- 🔴 **ОТКРЫТО, ПЕРВОЕ:** **ориентация кадра неправильная** — в фильтре `/addons/ustreamer/` стоит `transpose=1` (90° по часовой), счётчик лежит на бок. Нужен **`transpose=2`** + rebuild аддона.
- 🔴 **ОТКРЫТО, ВТОРОЕ:** **камера в HA не обновляется — КОРЕНЬ НАЙДЕН, правка НЕ внесена.** Generic Camera (`entry_id 01M2FX50K72X2RSYY549QSG3XP`, сущность `camera.192_168_2_176`) настроена на мёртвые адреса: `still_image_url = http://192.168.2.176:1984/api/frame.jpeg?src=usb_camera_h264` (порт **1984** — удалённый go2rtc) и `stream_source = rtsp://192.168.2.176:8554/usb_camera_h264` (RTSP-сервера нет). Отсюда `404 Not Found` в логе. Менять на `still_image_url: http://192.168.2.176:8090/frame`, `stream_source` — пусто. Опции — в `/config/.storage/core.config_entries`, **не в `configuration.yaml`**. См. §4
- ⚠️ **ОТКРЫТО:** осиротевший `/config/go2rtc.yaml` (1085 байт) остался — go2rtc удалён, читать нечем. Снести?
- ⚠️ **ОТКРЫТО:** старый мёртвый аддон `/addons/ustreamer/` в файловой системе — новая версия живёт в том же пути, старый код перезаписан. Проверить, что лишних файлов нет.
- ⚠️ **ОТКРЫТО:** watchdog для `local_ustreamer` **не включался** (в отличие от 6 других аддонов, §3.7).
- ✅ **Z2M работает** под watchdog; патология `write after end` — баг логгера, не serial-порт. См. §3.8.
- ✅ **Перестановка USB подтверждена в железе:** камера `USB3-1` (xHCI), Zigbee `USB1-2` (OHCI), CH340 #1 `1-3` → `ttyUSB0`, CH340 #2 `1-4` → `ttyUSB1`. Modbus-пути (`0:3`/`0:4`) не тронуты — **mbusd и modbus-bridge работают, данные идут в MQTT** (проверено: столовая 23.8 °C / 51.6 % / PM2.5 0.8 / TVOC 30.0).
- ❌ **Перестановка порта НЕ лечит сбросы камеры** — при чистом старте `usb 3-1: reset high-speed ... using xhci_hcd` на `t=113` и `t=126`. Порт был не причиной.
- **Метрики шторма (вечер-3):** load **9.73**, `pressure/io some` **92 %**, `pressure/memory some` **57 %**, `MemFree` **16 МБ**, `% io` **50–66 %**. После успокоения: load 0.76, `pressure/io` 3.26 %, 100 % idle.
- **Носитель:** `WDC WD2500BEVT-0`, 250 ГБ HDD 5400 rpm, `rotational=1` — **здоров**, деградации нет (ложный вывод снят, см. §3.4). `disk_free 209.8 / 228.5 ГБ`.
- **Снятие образа `sda` НЕВОЗМОЖНО из аддона** — `Operation not permitted` (§3.5). Тестовый прогон дал 20 байт. Реальные пути: `ha backups new` (не образ) либо физически вынуть носитель.
- **Журнал прошлой загрузки отсутствует** — HAOS пишет в RAM, `journalctl -b -1` пуст. События до падения восстановить нечем; диагноз ставить **до** перезагрузки.
- **Потребление по аддонам (2026-09-15):** Node-RED **197 МБ (13 %)** — крупнейший; HA Core 212 МБ (14 %); Supervisor 77 МБ (5 %); modbus-bridge 20 МБ; Mosquitto 19 МБ; go2rtc ×2 по 3.4 МБ; mbusd 0.8 МБ.
- **HAOS** `18.2`, agent `1.10.0`, ядро `6.18.39-haos`, `online_cpus 2`. `ha host info` из аддона работает.
- **`unavailable` (Zigbee) = 0** после миграции на ZHA. Отдельно, вне Zigbee: 7 на slave 10 (AT2-вентиляторы, блок закомментирован; задача снята) + `todo.shopping_list` (системная).
- ✅ **Zigbee: РАБОТАЕТ НА ZHA (2026-09-15).** Z2M ⏸ stopped (данные целы в `/config/zigbee2mqtt/`), стик отдан ZHA. **ZHA: 17 записей (16 устройств + координатор), `unavailable` = 0, 14 автоматизаций (13 `on`, 1 `off` намеренно).** Кнопка `wireless_light_switch_bed` (TS0041) шлёт `remote_button_short_press` только после `zha/devices/reconfigure`. Полный справочник — [[family/tech/zigbee-t610-z2m-i-zha]].
- **`toilet_1_floor_temperature`:** ✅ 24.4 °C / 47.7 % / bat 100 %, зона Туалет.
- **Открытый дефект:** свет кабинета мигает при перезагрузке HA (`office_pass_switch_*`, `platform: state` без `to`). Разбор — [[family/how-to/ha-automations]].
| Контур | Состояние |
|---|---|
| Zigbee | ZHA, 23 устройства, читаемые ID, 0 `unavailable` |
| Батареи | 12 автоматизаций, порог 20 % / 2 ч, push + persistent |
| CO₂ / Modbus | 3 датчика публикуют каждые ~10 с, значения правдоподобны |
| Вентиляция | железо в порядке, контур AT2 отключён (задача снята Alex) |
| Отопление | целиком в ZONT |
| Греющий кабель | `automation.greiushchii_kabel_upravlenie`, `on` (§см. ha-automations §7) |
| Камера | `local_ustreamer` :8090, одиночный JPEG, хост стабилен |
| Хост | load 0.76, `pressure/io` 3.26 %, 100 % idle |
**Открыто:**
- 🔴 **Ориентация кадра камеры** — в `/addons/ustreamer/` стоит `transpose=1` (90° по часовой), счётчик лежит на бок. Нужен `transpose=2` + rebuild аддона.
- 🔴 **Камера в HA не обновляется** — Generic Camera (`entry_id 01M2FX50K72X2RSYY549QSG3XP`, `camera.192_168_2_176`) смотрит на мёртвые адреса удалённого go2rtc: `still_image_url = http://192.168.2.176:1984/api/frame.jpeg` и `stream_source = rtsp://192.168.2.176:8554/...`. Менять на `http://192.168.2.176:8090/frame`, `stream_source` — пусто. Живёт в `/config/.storage/core.config_entries`, **не в `configuration.yaml`**. См. §4.
- ⚠️ **Осиротевший `/config/go2rtc.yaml`** (1085 байт) — go2rtc удалён, читать нечем.
- ⚠️ **Watchdog `local_ustreamer` не включён** (в отличие от остальных 6 аддонов, §3.7).
- ⚠️ **Свет кабинета мигает при перезагрузке HA** — `office_pass_switch_*` с `platform: state` без `to`. Разбор — [[family/how-to/ha-automations]] §3.
- ⚠️ **Греющий кабель не проверен физически** — розетка ни разу не включалась.
**Справочные факты:**
- **Аддоны (7):** `core_ssh`, `core_mosquitto`, `a0d7b954_nodered` (⏸ stopped), `45df7312_zigbee2mqtt` (⏸ stopped — стик отдан ZHA), `local_mbusd`, `local_modbus-bridge`, `local_ustreamer`. `core_configurator` и `go2rtc` ×2 удалены.
- **USB:** камера `USB3-1` (xHCI), Zigbee `USB1-2` (OHCI) → `ttyACM0`, CH340 #1 `1-3` → `ttyUSB0` (вентиляция/mbusd), CH340 #2 `1-4` → `ttyUSB1` (ZONT/modbus-bridge).
- **Носитель:** `WDC WD2500BEVT-0`, 250 ГБ HDD 5400 rpm — здоров, деградации нет (§3.4). `disk_free 209.8 / 228.5 ГБ`.
- **HAOS** `18.2`, agent `1.10.0`, ядро `6.18.39-haos`, `online_cpus 2`.
- **Потребление:** Node-RED 197 МБ — крупнейший; HA Core 212 МБ; Supervisor 77 МБ; modbus-bridge 20 МБ; Mosquitto 19 МБ; mbusd 0.8 МБ.
- **`slave 20`** (газ-котёл): состояние через bridge не читается.
- **`H2000_PRO`** — контроллер отопления, не Zigbee, не трогать.
- ✅ **Шум в логах про `TemplateError: round got invalid input 'unknown'` на `sensor.bedroom_summary` — СНЯТ.** При живых данных не воспроизводится: ошибка была следствием `unavailable`-состояния до фикса CO2 (§9). Правка `configuration.yaml` **не требуется**.
- **Локальные скрипты диагностики:** `~/tmp-t610/` — `diag.sh`…`diag4.sh`, `stats.sh`, `who.sh`, `mem.sh`, `boot.sh`, `z2m.sh`, `cam.sh`, `ports.sh`, `watchdog.sh`, `pull-image.sh`, `remove_go2rtc_baks.sh` (снос аддонов go2rtc + всех .bak, 2026-09-15).
- **Как запускать скрипт на t610 (рабочий паттерн):** `scp <script> root@192.168.2.176:/tmp/ && ssh root@192.168.2.176 'bash /tmp/<script>'`. ⚠️ Алиаса `t610` в `~/.ssh/config` **НЕТ**. ⚠️ Скрипты с `AUTH=*** Bearer ${T}"` **ломаются маскировщиком при `write_file`** — обход: собирать заголовок по частям (`H="Authoriz""ation: Bea""rer $T"`) или запускать через `bash` (см. питфоллы 30, 34, 35).
- **Журнал прошлой загрузки отсутствует** — HAOS пишет в RAM, `journalctl -b -1` пуст. Диагноз ставить **до** перезагрузки.
- **Снятие образа `sda` невозможно из аддона** — `Operation not permitted` (§3.5). Только физически вынув носитель.
**Скрипты:** `~/tmp-t610/` — `diag.sh`…`diag4.sh`, `stats.sh`, `ha_ws.py`, `get_states.sh`, `ghost_purge.sh`, `verify_cable.py`, `verify_calc.sh`.
**Как запускать на t610:** `scp <script> root@192.168.2.176:/tmp/ && ssh root@192.168.2.176 'bash /tmp/<script>'`. ⚠️ Алиаса `t610` в `~/.ssh/config` НЕТ. ⚠️ Скрипты с `AUTH="... Bearer ${T}"` ломаются маскировщиком — собирать заголовок по частям (питфоллы 30, 34, 35, 37).
- **Потребление по аддонам:** Node-RED **197 МБ** — крупнейший; HA Core 212 МБ; Supervisor 77 МБ; modbus-bridge 20 МБ; Mosquitto 19 МБ; mbusd 0.8 МБ.
- **HAOS** `18.2`, agent `1.10.0`, ядро `6.18.39-haos`, `online_cpus 2`.
- **`unavailable` (Zigbee) = 0** после миграции на ZHA. Вне Zigbee: 7 на slave 10 (AT2-вентиляторы, блок закомментирован — задача снята) + `todo.shopping_list` (системная).
- **Zigbee: ZHA** — 23 устройства, `unavailable` = 0. Z2M ⏸ stopped (данные целы в `/config/zigbee2mqtt/`), стик отдан ZHA. Кнопка `wireless_light_switch_bed` (TS0041) шлёт `remote_button_short_press` только после `zha/devices/reconfigure`. Полный справочник — [[family/tech/zigbee-t610-z2m-i-zha]].
- **`toilet_1_floor_temperature`:** 24.4 °C / 47.7 % / bat 100 %, зона Туалет.
- **Шум про `TemplateError` на `sensor.bedroom_summary` — СНЯТ.** Не воспроизводится: был следствием `unavailable` до фикса CO₂ (§9). Правка `configuration.yaml` не требуется.