ZONT-реле котлов уже дают статусы; 2 Zigbee-розетки с мониторингом есть (`recirculation_pump`, `heating_cable_plug`).
ZONT-реле котлов уже дают статусы; 2 Zigbee-розетки с мониторингом есть (`recirculation_pump`, `heating_cable_plug`).
**Добавить:** токовые клещи (Zigbee) на ввод/котёл → видно, где деньги.
**Добавить:** токовые клещи (Zigbee) на ввод/котёл → видно, где деньги.
> ✅ **УТОЧНЕНО 2026-09-16:** `0 Вт / 0 кВт·ч` — **норма, а не поломка**: `switch.heating_cable_plug` = `off`, поэтому нагрузка не потребляет, при этом `voltage = 223 В` (розетка жива). `sauna` в `state.json` = `null`. Полный разбор железа и **расчёт порогов включения греющего кабеля** — [[family/tech/heating-cable-water-inlet]].
> ✅ **УТОЧНЕНО 2026-09-16:** `0 Вт / 0 кВт·ч` — **норма, а не поломка**: `switch.heating_cable_plug` = `off`, поэтому нагрузка не потребляет, при этом `voltage = 223 В` (розетка жива). `sauna` в `state.json` = `null`.
### 8. Дашборд + алерты в Telegram
### 8. Дашборд + алерты в Telegram
Без этого автоматика «невидима». Один экран + пуш на всё критичное. Частично уже в вишлисте UI (см. §4).
Без этого автоматика «невидима». Один экран + пуш на всё критичное. Частично уже в вишлисте UI (см. §4).
> 📌 **Сверка счёта:** в §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.
> **Бэкапы перед правками:** `automations.yaml.bak-cable3-20260915-*` (кабель), `.bak-preids-*`, `.bak-gard-*` (единообразие ID). Локальные копии в `~/tmp-t610/`.
> ⛔ **Удалены 2 прежние батарейные** (`1773451323415`, `1773459663218`) — были с порогом 10 и без push. Их осиротевшие записи в реестре вычищены (питфолл §5.1).
> 📄 Рецепт пересборки после Z2M→ZHA и питфоллы — [[family/tech/zigbee-t610-z2m-i-zha]].
> 🔄 **Переименованы** ссылки после единообразия 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 (поздний вечер):** `/config/automations.yaml.bak-preids-20260915-223427`, `/config/automations.yaml.bak-gard-20260915-225404` (перед переносом датчика в Гардеробную); рабочая копия — `~/tmp-t610/autfix-20260915-223427/automations.yaml` (плюс `.pre-bat` — до добавления батарейных).
- **Удалены 4 «призрака»** (записи в реестре без тела): `svetlo_vykl_osveshchenie_lestnitsy`, `temno_vkl_podsvetku_lestnitsy`, `datchik_osveshchennosti_lestnitsa_batareia`, `light_switch_bed_batareia`. Тела не было (`config/automation/config/<id>` → 404) — лестничные сценарии **пересозданы заново**с теми же id.
- **Удалены 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`.
- **Локальная копия:** `~/tmp-t610/automations/automations.yaml`; после пересборки — `~/tmp-t610/automations-new.yaml`, `~/tmp-t610/automations-fixed.yaml`.
- **Читать живьём через API** (не по памяти):
- **Читать живьём через API** (не по памяти):
@@ -285,8 +271,8 @@ actions:
> ⚠️ **WS `render_template` возвращает `null`** даже для `{{ 2 + 2 }}` — шаблоны проверять только через REST `POST /api/template`.
> ⚠️ **WS `render_template` возвращает `null`** даже для `{{ 2 + 2 }}` — шаблоны проверять только через REST `POST /api/template`.
> ⚠️ **`automation.trigger` через WS не обновляет `last_triggered`** — прогон подтверждать иначе (значения в `variables`, лог HA).
> ⚠️ **`automation.trigger` через WS не обновляет `last_triggered`** — прогон подтверждать иначе (значения в `variables`, лог HA).
aliases:[Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset]
aliases:[Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset]
tags:[family, how-to, smarthome]
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, доступ, команды, сценарии, питфоллы.
> **Единственный справочник по домашней автоматизации.** Всё: топология, железо, Zigbee, Modbus, доступ, команды, сценарии, питфоллы.
| ustreamer (кастомный) | `local_ustreamer` | камера: JPEG раз в N сек | 8090 | ✅ started |
| ustreamer (кастомный) | `local_ustreamer` | камера: JPEG раз в N сек | 8090 | ✅ started |
> 🔴 **2026-09-15 (ночь-4): `go2rtc` и `go2rtc-hardware` УДАЛЕНЫ** (`stop` + `uninstall` через Supervisor API). Оба были источником RCU stall (§3.6).
> 🔴 **`go2rtc` и `go2rtc-hardware` УДАЛЕНЫ** (2026-09-15, `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-нагрузка на слабом хосте.
> 🗑 **`core_configurator` (File editor) УДАЛЁН.** Веб-редактор `/config` не использовался, зато **писал `GET /` каждые 30 с** и на каждый запрос логировал `502 Bad Gateway` (HA Core лежал) → цикл ретраев + запись лога = постоянная I/O-нагрузка на слабом хосте.
> ⏸ **2026-09-15 (ночь-6): `a0d7b954_nodered` ОСТАНОВЛЕН** (не удалён) — жирный процесс на 1.4 ГБ RAM, для камеры не нужен.
> ⏸ **`a0d7b954_nodered` ОСТАНОВЛЕН** (не удалён) — жирный процесс на 1.4 ГБ RAM, для камеры не нужен.
> 💡 **Диагностический признак:** аддон в `state: error`, но в логе `Service exited with code 256 (by signal 15)` → это **нормальная остановка**, а `error` — финальный статус. Читать лог, а не только `state`.
> 💡 **Диагностический признак:** аддон в `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.
**Опции аддонов** меняются только через Supervisor API (не `ha apps`, который умеет лишь start/stop/rebuild). Для PATCH нужен **ПОЛНЫЙ набор опций**, иначе 400.
@@ -189,70 +189,52 @@ ha apps restart local_modbus-bridge
> ⚠️ Два CH340 **без серийников** → by-id идентичен. Только **by-path**.
> ⚠️ Два CH340 **без серийников** → by-id идентичен. Только **by-path**.
> `uart: true` в конфиге аддона — udev-алиасы не нужны. В аддоне нет `udevadm`, `/etc/udev/rules.d`.
> `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.
**Первопричина:**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.
> ⛔ Версия «камера на 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-шторма, не как причина.
**Что доказано фактами:**
**Решение:** оба аддона 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 |
| Камера`046d:0825` сбрасывалась на EHCI (USB2-1) **и** на xHCI (USB3-1) | Порт — не причина сбросов |
| Камера сбрасывалась и на EHCI, и на xHCI | Порт — не причина |
| `runtime_suspended_time` 124 с на EHCI, 108 с на xHCI | Камера **засыпает и не просыпается** на обоих контроллерах |
| `bMaxPower = 500 mA` | Версия «нехватка питания» не проверена |
| `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 не потому что его «съели», а потому что планировщик не может его разбудить.
**Механизм поломки:**`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`:
**Механизм:**`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 транскод на неподходящем железе.
**Решение:** оба аддона 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 «Данные камеры».
> ⚠️ Для `local_ustreamer` watchdog **не включался** — проверить, если камера должна подниматься сама.
> ⚠️ Для `local_ustreamer` watchdog **не включался** — проверить, если камера должна подниматься сама.
> 📌 Эндпоинт: **`POST /addons/<slug>/options`** с `{"watchdog":true}`. Отдаёт `{"result":"ok","data":{}}`. Для PATCH нужен ПОЛНЫЙ набор опций (питфолл 15), но `watchdog` в одиночку проходит.
> 📌 Эндпоинт: **`POST /addons/<slug>/options`** с `{"watchdog":true}`. Отдаёт `{"result":"ok","data":{}}`. Для PATCH нужен ПОЛНЫЙ набор опций (питфолл 15), но `watchdog` в одиночку проходит.
### 3.8. 🔴 Zigbee2MQTT — падение на MQTT-подключении при старте (баг логгера)
### 3.8. Zigbee2MQTT — остановлен
**Симптом (лог аддона):**
Z2M **остановлен**с 2026-09-15 (стик отдан ZHA), данные целы в `/config/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`.
**Это НЕ проблема serial-порта.**В логе Mosquitto видно, что Z2M **подключился** и сам закрыл соединение через 3 с:
> 📌 На будущее, если Z2M понадобится снова: он падает при старте с `MQTT failed to connect, exiting... (write after end)` в `winston`. **Это не serial-порт** — в логе Mosquitto видно, что Z2M подключился и сам закрыл соединение через 3 с. Причина — баг логгера Z2M v2.14.1 при задержке ответа брокера. Лечится рестартом после стабилизации Mosquitto. Проверено: `serial.port` = `by-id/...` (перестановка USB его не ломает).
```
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>` — предыдущий рестарт ещё идёт, **подождать**, не долбить повторно.
**Диагностика при «HA не отвечает» — порядок:**
**Диагностика при «HA не отвечает» — порядок:**
1. Пинг + ARP хоста (`/sbin/ping`, `/usr/sbin/arp -an`) — жив ли вообще. `ARP no entry` = L2-ответа нет.
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.
**Logitech `046d:0825`** (счётчик газа BK-G4T), отдаёт только MJPEG.
> 🔴 **АРХИТЕКТУРА СМЕНИЛАСЬ (2026-09-15, ночь-4) — go2rtc БОЛЬШЕ НЕТ.**
> 🔴 **АРХИТЕКТУРА СМЕНИЛАСЬ — go2rtc БОЛЬШЕ НЕТ.**
> Оба аддона go2rtc **удалены**. Камера теперь обслуживается **собственным аддоном `local_ustreamer`** (порт **8090**):
> Оба аддона go2rtc **удалены**. Камера теперь обслуживается **собственным аддоном `local_ustreamer`** (порт **8090**):
> ```
> ```
> GET http://192.168.2.176:8090/frame → JPEG 480×640, ~19 КБ, ~4.7 с
> 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.
> **Принцип:** Python HTTP-сервер на `/frame` запускает `ffmpeg` **только когда есть клиент**, снимает **один кадр**, поворачивает (`transpose`) и отдаёт JPEG. Никакого H.264, никакого реалтайм-транскода, никакого постоянного процесса — снимает и CPU-жор, и RCU stall.
>
>
> ⚠️ **ОРИЕНТАЦИЯ — НЕ ЗАКРЫТО:** сейчас в фильтре `transpose=1` (90° по часовой), счётчик ложится на бок. Нужен **`transpose=2`** (90° против часовой). Правка в `/addons/ustreamer/` + rebuild аддона.
> ⚠️ **ОРИЕНТАЦИЯ — НЕ ЗАКРЫТО:** сейчас в фильтре `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:
> Сущность в HA уже есть — `camera.192_168_2_176`, но она **не обновляется**, потому что интеграция **Generic Camera** (не YAML!) настроена на мёртвые адреса. Полные опции entry:
@@ -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` подобран верно.
**Сырой float32 УЖЕ в ppm** — 846.9 ppm для детской и 589.5 ppm для спальни правдоподобны. Обе коррекции — **мусор от старых попыток парсинга** (подбирались, когда парсер читал мало байт). Температура/влажность работают правильно, потому что их `correction_offset: -4.5` подобран верно.
> 🕐 Обновлено **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.
- 🔴 **ОТКРЫТО, ПЕРВОЕ:** **ориентация кадра неправильная** — в фильтре `/addons/ustreamer/` стоит `transpose=1` (90° по часовой), счётчик лежит на бок. Нужен **`transpose=2`** + rebuild аддона.
| CO₂ / Modbus | 3 датчика публикуют каждые ~10 с, значения правдоподобны |
- 🔴 **ОТКРЫТО, ВТОРОЕ:** **камера в 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
- ⚠️ **ОТКРЫТО:** старый мёртвый аддон `/addons/ustreamer/` в файловой системе — новая версия живёт в том же пути, старый код перезаписан. Проверить, что лишних файлов нет.
- ✅ **Перестановка 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`. Порт был не причиной.
- 🔴 **Ориентация кадра камеры** — в `/addons/ustreamer/` стоит `transpose=1` (90° по часовой), счётчик лежит на бок. Нужен `transpose=2` + rebuild аддона.
- **Снятие образа `sda` НЕВОЗМОЖНО из аддона** — `Operation not permitted` (§3.5). Тестовый прогон дал 20 байт. Реальные пути: `ha backups new` (не образ) либо физически вынуть носитель.
- 🔴 **Камера в 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.
- **Журнал прошлой загрузки отсутствует** — HAOS пишет в RAM, `journalctl -b -1` пуст. События до падения восстановить нечем; диагноз ставить **до** перезагрузки.
- ⚠️ **Свет кабинета мигает при перезагрузке HA** — `office_pass_switch_*` с `platform: state` без `to`. Разбор — [[family/how-to/ha-automations]] §3.
- **`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]].
- **`slave 20`** (газ-котёл): состояние через bridge не читается.
- **`slave 20`** (газ-котёл): состояние через bridge не читается.
- **`H2000_PRO`** — контроллер отопления, не Zigbee, не трогать.
- **`H2000_PRO`** — контроллер отопления, не Zigbee, не трогать.
- ✅ **Шум в логах про `TemplateError: round got invalid input 'unknown'` на `sensor.bedroom_summary` — СНЯТ.** При живых данных не воспроизводится: ошибка была следствием `unavailable`-состояния до фикса CO2 (§9). Правка `configuration.yaml` **не требуется**.
- **Журнал прошлой загрузки отсутствует** — HAOS пишет в RAM, `journalctl -b -1` пуст. Диагноз ставить **до** перезагрузки.
- **`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` не требуется.
**Труба на 4 м не замерзает физически** — грунт там +2,5…+3,5 °C круглый год.
## 3. Критичная точка — бетонная подушка 30 см
Бетон промерзает быстрее грунта: `λ = 1,7` против `1,4`, снеговой шубы нет.
```
R_возд = 1/15 = 0,067 (м²·К)/Вт
R_бетон = 0,30/1,7 = 0,176 (м²·К)/Вт
→ 72 % перепада падает на бетон
```
| Улица | Труба в бетоне |
|---|---|
| −6 °C | +0,5 °C |
| **−8 °C** | **−0,1 °C** ← порог включения |
| −10 °C | −0,6 °C |
| −15 °C | −1,9 °C |
| −20 °C | −3,1 °C |
| −25 °C | −4,4 °C |
## 4. Пороги
| Событие | Условие | Выдержка |
|---|---|---|
| ВКЛ | `eff ≤ −8 °C` | 12 ч |
| ВЫКЛ | `eff ≥ −3 °C` | 12 ч |
| Аварийный ВКЛ | `eff ≤ −20 °C` | без выдержки |
| Fail-safe | ZONT `unknown`/`unavailable` | ВКЛ |
| Обрыв | розетка `on`, `power < 5 W` | push |
`eff` = ZONT, если датчик жив; иначе прогноз-мин на 24 ч.
**Почему 12 ч:** тепловая инерция бетонной подушки ~сутки. 12 ч отсекает одиночные ночные заморозки, но ловит затяжное похолодание в тот же день.
**Почему саморег:** кабель сбрасывает мощность при нагреве сам, перегрев невозможен. Задержка нужна не «чтобы не спалить», а чтобы не дёргать реле на каждую холодную ночь.
**Почему прогноз:** ZONT — одна точка, может врать или отвалиться. Прогноз — независимый канал; при отвале датчика переключаемся на него, а не остаёмся без защиты.
| WS `{"type":"weather/subscribe_forecast", forecast_type: …}` | ✅ работает |
| **`action: weather.get_forecasts` в автоматизации** | ✅ работает |
Сервис — **`weather.get_forecasts`** (множественное число). В автоматизации вызывается как `action:`с`response_variable`; данные — `wx['weather.forecast_laki_dom']['forecast']`.
### 7.2 `variables:` вычисляются ДО действий
Объявлять `variables:`с данными от `response_variable` только **внутри `actions:`, после вызова сервиса**. На верхнем уровне автоматизации `wx` ещё не существует.
### 7.3 `min([99, fc_min])` ломает fail-safe
Наивная проверка отвала датчика через `float(99)` + `min` не работает: `min([99, 11.1])` = 11.1, условие `eff == 99` не сработает никогда.
Правильно — отдельный флаг по строковому состоянию:
@@ -144,7 +144,7 @@ vf = f"transpose=1" if ROTATE in ("90", "1") else (
---
---
## ✅ Подключение к HA — ПРАВКА ВНЕСЕНА (2026-09-15, ночь-6)
## ✅ Подключение к HA
**Сущность:**`camera.192_168_2_176` («Камера котельной», зона `kotelnaia`) — задана **не через YAML**, а через UI-интеграцию **Generic Camera**. Настройки — в `/config/.storage/core.config_entries`.
**Сущность:**`camera.192_168_2_176` («Камера котельной», зона `kotelnaia`) — задана **не через YAML**, а через UI-интеграцию **Generic Camera**. Настройки — в `/config/.storage/core.config_entries`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.