From 3a70f82edb63e2050e8f20df49eff1973e132998 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Mon, 14 Sep 2026 19:02:32 +0600 Subject: [PATCH] [2026-09-14] eagle: family/plans/t610-home-automation.md --- family/plans/t610-home-automation.md | 85 ++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/family/plans/t610-home-automation.md b/family/plans/t610-home-automation.md index 8990382a..1dc2eb46 100644 --- a/family/plans/t610-home-automation.md +++ b/family/plans/t610-home-automation.md @@ -10,7 +10,8 @@ **Этап 1 ✅ · Этап 2 ✅ · Этап 3 ✅ ЗАКРЫТ.** Этап 4 — **ПОЧТИ ЗАКРЫТ (3 из 4):** ① Caddy → t610 (`mallexxx.duckdns.org` → HA на t610, HTTP 200); ② Node-RED flows перенесены, `Connected to HA`, наружу не выпущен (решение Alex «оставляем так», доступ через ingress); ③ **ZONT MQTT-редирект переключён на t610** (DNAT на роутере `.197`→`.176`, живой поток идёт). **ОСТАЛОСЬ:** погасить/отключить сервисы TrueNAS (заблокировано — Caddy на TrueNAS держит точку входа) + хвосты (static IP, бэкап). **Последнее действие (2026-09-14, ~19:45): 🔴 t610 ВЫКЛЮЧЕН** — Alex: *«Отправь ему shutdown»*, выполнено `ha host shutdown` (exit 0), probe доступности запрещён. Вся автоматизация офлайн; включение только физически. План на включение — §5-кватер-И-6. -**Последняя верификация перед выключением: 2026-09-14 (вечер-12) — ⚠️ RTSP/WebRTC НЕ ЗАВЕРШЕНО, камера ЗАЛИПЛА на USB-уровне.** Задача Alex: *«добавь rtsp... на truenas был mjpg+rtsp»* — для работы WebRTC в мобильном приложении HA (сейчас `DESCRIBE failed: 404`, HLS при этом работает). **Установлено:** ustreamer **RTSP не умеет** (только MJPEG/HTTP) → поставлен **аддон go2rtc** (`a889bffc_go2rtc`, репо AlexxIT, v1.9.14) — он даёт MJPEG + **RTSP :8554** + WebRTC из одного источника. **RTSP и MJPEG через go2rtc РАБОТАЮТ** (RTSP `200 OK`, MJPEG 2.4 МБ/10 с). **НО:** камера залипла на уровне ядра (`uvcvideo: Failed to resubmit video URB (-1)`) после параллельного запуска go2rtc + ustreamer → **t610 выключен (см. строку выше), power-cycle при включении лечит залипший USB**; Generic Camera на RTSP отдаёт `stream_source: timeout` (причина не установлена). Канон, питфоллы и статус — **§5-кватер-И-6**. +**Последняя верификация: 2026-09-14 (вечер-13) — ✅✅ RTSP/WebRTC РЕШЕНО.** Камера работает через **аддон `go2rtc-hardware`** (ffmpeg-транскод MJPEG→H.264) → RTSP `rtsp://192.168.2.176:8554/usb_camera_h264`, WebRTC в приложении HA **работает** (Alex: «Супер, работает»). ustreamer остановлен (`boot: manual`). Канон, доказательства, питфоллы — **§5-кватер-И-6**. +**История (вечер-12, ❌ не дало результата):** обычный go2rtc без ffmpeg + попытка RTSP → `JPEG/90000`, `stream_source: timeout`, залипание USB (лечится power-cycle). Оставлено как урок в §5-кватер-И-6. **Предыдущая верификация (вечер-11) — ✅✅ КАМЕРА: СХЕМА ВОЗВРАЩЕНА «КАК НА TrueNAS», РАБОТАЛА.** Камера на TrueNAS **была** — `cam.mallexxx.duckdns.org → 192.168.2.197:8090` (отдельный **HTTP-MJPEG-сервис**, `ustreamer`), контейнер **утрачен при пересоздании пула** (локальный образ не пережил `.ix-apps`; след остался в `Caddyfile.bak`). **ЧТО СДЕЛАНО (вечер-11):** ① блок `camera: platform: ffmpeg` из `configuration.yaml` **снесён** (бэкап `.bak-rmcam-20260914-185240`) → `/dev/video0` освобождён; ② поднят **локальный аддон `local_ustreamer`** на t610 (`/addons/ustreamer/`) — отдаёт MJPEG на **:8090**; ③ в HA заведена **Generic Camera** по URL потока → `camera.192_168_2_176` с **`unique_id`** → **зона `kotelnaia` назначена**, имя «Камера котельной». Проверено: кадр JPEG 640×480 (HTTP 200, 25 КБ), MJPEG-стрим `multipart/x-mixed-replace` живой, `Resource busy` больше не воспроизводится. Канон и питфоллы — **§5-кватер-И-3/И-5**. До этого: фикс bridge (T3.5) держится, `dining` стабилен; static IP t610 + триггер душевой. **HA long-lived token — в §5-кватер-И-3.** **Осталось (обновлено вечер-12 → shutdown):** ① включить t610 физически; ② **сначала снять автозапуск у `local_ustreamer`** (иначе снова подерётся с go2rtc за `/dev/video0`); ③ поднять только go2rtc, проверить оживление камеры; ④ камеру в HA переключить на `rtsp://192.168.2.176:8554/usb_camera`, проверить WebRTC; ⑤ снять устаревшую строку `cam.*` из `truenas-infrastructure.md`. ⚠️ `/config/go2rtc.yaml` **НЕ удалять** — он нужен аддону go2rtc (прежняя пометка «удалить лишний» относилась к встроенному go2rtc Core и **опровергнута**). | Что | Факт | @@ -49,7 +50,7 @@ | **`sensor.fan_at2_*` / `switch.fan_3_*` — сироты** | В `configuration.yaml` **весь блок slave 10 (AT2 fans) закомментирован** → эти сущности физически не могут получать данные. Не задача — просто известный факт состояния конфига | | `switch.sauna` = `unknown` | Розетка физически отключена (`lastSeen` 8+ ч) — не баг | | ZONT не перенаправлен | **✅ ПЕРЕНАПРАВЛЕН 2026-09-14 (вечер-3, §5-кватер-Д):** DNAT на роутере `192.168.2.2` (`redirect[0]` MQTT + `rule[3]`) переключён `.197`→`.176`; ZONT пишет в mosquitto **t610** (живой поток kids/bedroom). ⚠️ Не решено: `dining/*` не публикуется — **ответ на шине есть, bridge его не отдаёт** (§5-кватер-Д, задача №3) | -| Камера | ⚠️ **НЕ ЗАВЕРШЕНО + t610 ВЫКЛЮЧЕН (2026-09-14, вечер-12).** Цель: перейти на **RTSP (`go2rtc`)** ради WebRTC в мобильном приложении (сейчас `DESCRIBE 404`; HLS работает). Базовая схема (вечер-11, **работала**): USB-вебка Logitech `046d:0825` (физически в t610) → **аддон `local_ustreamer`** → MJPEG на **`:8090`** → **Generic Camera** → **`camera.192_168_2_176`** (имя «Камера котельной», **зона `kotelnaia`**). **Поставлен аддон `go2rtc`** (`a889bffc_go2rtc`, v1.9.14) — MJPEG+RTSP :8554+WebRTC **работают**, но камера **залипла на USB-уровне** (`uvcvideo: URB -1`) от параллельного запуска с ustreamer. Лечится power-cycle (t610 выключен → вылечится при включении). Детали, канон, питфоллы — **§5-кватер-И-6**. **❌ ОТВЕРГНУТО:** `camera: platform: ffmpeg` внутри Core (`Resource busy` + нет `unique_id`); ustreamer как источник RTSP (RTSP не умеет) | +| Камера | ✅ **ГОТОВО (2026-09-14, вечер-13).** USB-вебка Logitech `046d:0825` (только MJPEG) → **аддон `a889bffc_go2rtc-hardware`** (ffmpeg-транскод MJPEG→H.264) → **RTSP `rtsp://192.168.2.176:8554/usb_camera_h264`** → **Generic Camera** → **`camera.192_168_2_176`** (имя «Камера котельной», **зона `kotelnaia`**, `unique_id 01M2FX50K72X2RSYY549QSG3XP`). **WebRTC в приложении HA работает** (Alex подтвердил), HLS тоже. `local_ustreamer` — `boot: manual`, `stopped` (откат). Детали, каноны, питфоллы — **§5-кватер-И-6**. **❌ ОТВЕРГНУТО:** `camera: platform: ffmpeg` в Core (`Resource busy` + нет `unique_id`); ustreamer как RTSP-источник (RTSP не умеет); обычный go2rtc без ffmpeg (транскод невозможен) | --- @@ -2311,7 +2312,81 @@ POST /api/config/config_entries/flow/ {"confirmed_ok": true} --- -## 5-кватер-И-6. 📹 RTSP / WebRTC: аддон go2rtc (2026-09-14, вечер-12) — ⚠️ НЕ ЗАВЕРШЕНО +## 5-кватер-И-6. 📹 RTSP / WebRTC: аддон go2rtc — ✅✅ РЕШЕНО (2026-09-14, вечер-13) + +**Триггер:** Alex — *«добавь rtsp. на truenas был mjpg+rtsp почему ты так не сделал сразу?»* и *«ustreamer не подходит нам?»*. + +**Причина задачи:** в мобильном приложении HA при просмотре камеры — `Failed to start WebRTC stream: ... method DESCRIBE failed: 404 (Not Found)`. **Диагноз:** источник — MJPEG; go2rtc Core не имеет потока `generic_01M2FX50K72X2RSYY549QSG3XP` → DESCRIBE 404. **HLS работал**, WebRTC — нет. Для WebRTC нужен **H.264**. + +**Почему ustreamer не подходит:** отдаёт **только MJPEG и H.264 по HTTP**, **RTSP не умеет**. На TrueNAS «mjpg+rtsp» — связка двух сервисов. ✅ **go2rtc умеет всё три** (MJPEG / RTSP / WebRTC). + +### 🏁 РАБОЧЕЕ РЕШЕНИЕ (финал) + +**Аддон: `a889bffc_go2rtc-hardware`** (репо `https://github.com/AlexxIT/hassio-addons`, v1.9.14-hardware) — **именно hardware-вариант**, в нём есть **ffmpeg** для транскода. У обычного `a889bffc_go2rtc` ffmpeg НЕТ → транскод невозможен (`HTTP 500 codecs not matched: video:JPEG => video:H264`). + +**Файл `/config/go2rtc.yaml` (ФИНАЛ, проверен):** +```yaml +log: {level: info} +api: {listen: ":1984"} +rtsp: {listen: ":8554"} +webrtc: {listen: ":8555"} +streams: + usb_camera_h264: ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480#video=h264 +``` + +**Камера в HA (Generic Camera, entry `01M2FX50K72X2RSYY549QSG3XP`):** +- `stream_source`: `rtsp://192.168.2.176:8554/usb_camera_h264` +- `still_image_url`: `http://192.168.2.176:1984/api/frame.jpeg?src=usb_camera_h264` +- `rtsp_transport: tcp`, `framerate: 15`, `verify_ssl: false` + +### ✅ Доказательства работы (факты вечер-13) + +| Проверка | Результат | +|---|---| +| RTSP SDP | `a=rtpmap:96 H264/90000` + `sprop-parameter-sets` + `profile-level-id=640029` ✅ (было `JPEG/90000`) | +| RTSP-данные | **743 808 байт за 6 с** ✅ (было **0**) | +| MP4-транскод | 1 097 728 байт, валидный контейнер `ftypiso5/moov/trak` ✅ | +| Generic Camera options flow | `type: create_entry`, **`errors: null`** ✅ (было `stream_source: timeout`) | +| Камера в HA | `state: idle`, кадр через HA — JPEG 640×480, 15 855 байт ✅ | +| capabilities камеры | `["web_rtc", "hls"]` ✅ | +| `camera/webrtc/offer` | `success: true` ✅ (404 DESCRIBE больше нет) | +| **WebRTC в приложении** | ✅ **Alex: «Супер, работает»** | + +### 🔑 КАНОНЫ (вечер-13) + +1. **Транскод = отдельный поток через `ffmpeg:`, а НЕ суффикс `#video=h264`.** + - `v4l2:...#video=h264` → `codecs not matched: video:JPEG => video:H264` (суффикс только *запрашивает* кодек, не транскодит). + - `ffmpeg:usb_camera#video=h264` (ссылка на другой go2rtc-поток) → `Output file does not contain any stream` (ленивость: поток-источник не запущен). + - ✅ **Правильно:** `ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480#video=h264` — **ffmpeg сам читает v4l2**. +2. **Нужен аддон `-hardware`** (с ffmpeg). У обычного go2rtc ffmpeg нет. +3. **Синтаксис v4l2 (go2rtc ≥ 1.9.9):** параметры через `?`: `v4l2:device?video=/dev/video0&input_format=mjpeg`. **`input_format` обязателен** (иначе `invalid input_format`); `device=/dev/video0` не работает (`no such file or directory` — и это НЕ значит «устройства нет»). +4. **Камера = ОДИН процесс.** ustreamer и go2rtc вместе → залипание USB (`uvcvideo: Failed to resubmit video URB (-1)`), лечится **только power-cycle/ребутом** (sysfs в SSH-аддоне **read-only**). **В конфиге оставлен только один поток** (`usb_camera_h264`) — нативный MJPEG убран. +5. **Generic Camera options flow: шаг `user_confirm` ждёт поле `confirmed_ok: true`** (boolean!). Без него flow крутится `init ↔ user_confirm` и не применяется. Успех = `type: create_entry`. +6. `ha apps` (CLI) **не умеет** менять `boot` — только Supervisor API `POST /addons//options {"boot":"manual"}`. + +### 🔴 Питфоллы вечер-12/13 (не повторять) + +| Питфолл | Симптом | Решение | +|---|---|---| +| `v4l2:device=/dev/video0` | `streams: no such file or directory` | Синтаксис `v4l2:device?video=...&input_format=mjpeg` | +| нет `input_format` | `v4l2: invalid input_format` | `input_format=mjpeg` для C270 | +| обычный go2rtc + `#video=h264` | `codecs not matched: video:JPEG => video:H264` | Ставить **`-hardware`** аддон (в нём ffmpeg) | +| `ffmpeg:<другой поток>#video=h264` | `Output file does not contain any stream` | `ffmpeg:device?...` — ffmpeg читает камеру сам | +| Два сервиса на `/dev/video0` | `Failed to resubmit video URB (-1)`, камера залипает | **Один процесс = одна камера**; ustreamer → `boot: manual` | +| Сброс USB через sysfs | `/sys/.../authorized: Read-only file system` | `/sys` RO → **reboot хоста** или физический перетк | +| options flow Generic Camera | `stream_source: timeout` (пока источник MJPEG/JPEG-RTSP) | Дать **настоящий H.264** RTSP → валидация проходит | +| options flow не завершается | `init ↔ user_confirm` по кругу | Отправить `{"confirmed_ok": true}` | +| `netstat`/`ss` в SSH-аддоне | пусто | Проверять порты **снаружи** (`curl`, socket-скрипт) | +| `ha store apps` вывод | **YAML, не JSON** | `jq` падает — парсить `grep` | +| `ffprobe` на Mac | нет | RTSP проверять socket-скриптами (`~/tmp-go2rtc/`) | + +### 📌 Статус ustreamer + +`local_ustreamer` — **оставлен установленным, `boot: manual`, `stopped`** (откат одной командой). Больше **не нужен** — go2rtc закрывает все три протокола. + +### Рабочие файлы (вечер-12/13, на Mac) + +`~/tmp-go2rtc/` — `go2rtc.yaml` (**итоговый конфиг**), `rtsp-check.py` (OPTIONS+DESCRIBE), `rtsp-play.py` / `rtsp-play-h264.py` (SETUP+PLAY, счёт байт), `rtsp-codec.py` (проверка кодека), `ws-caps.py` / `ws-webrtc.py` (websocket: capabilities + webrtc offer), `boot-off.sh` (boot→manual через Supervisor API), `cam-*.sh` (Generic Camera flow), `usb-reset.sh` (упёрлась в RO). **Триггер:** Alex — *«добавь rtsp. на truenas был mjpg+rtsp почему ты так не сделал сразу?»* и *«ustreamer не подходит нам?»*. @@ -2340,10 +2415,10 @@ v4l2:device?video=/dev/video0&input_format=mjpeg&video_size=640x480 - Камера C270 отдаёт только **MJPEG** (`CAP: Using format: MJPEG` в логе ustreamer) — поэтому `input_format=mjpeg&video_size=640x480`. - Целевой параметр `#video=h264` в URL **не дал эффекта** — go2rtc отдал JPEG на обоих треках (SDP: `a=rtpmap:96 JPEG/90000`). **ffmpeg-транскод в аддоне не сработал** (проверка `GET /api/ffmpeg` → пусто). -### 🔑 КАНОН-2: адрес хоста, видимый из Core +### 📜 Остатки вечер-12 (оставлено как история ошибок, не руководство) - `ha core info` → **`ip_address: 172.30.32.1`** — Core видит хост HA по этому адресу (NAT-шлюз hassio-сети). - Аддон с `host_network: true` слушает на `0.0.0.0` → доступен и как `192.168.2.176`, и как `172.30.32.1`. -- ❌ **Generic Camera: submit с `rtsp://192.168.2.176:8554/usb_camera` → `{"errors":{"stream_source":"timeout"}}`.** Повтор с `rtsp://172.30.32.1:8554/usb_camera` — **тоже `timeout`**. Прогрев потока (активный клиент) не помог. **Причина НЕ установлена** — HA-валидация RTSP отваливается по таймауту. Теорий не строить, проверять фактом. +- ❌ **ОПРОВЕРГНУТО (вечер-13):** `stream_source: timeout` был не багом HA, а следствием **пустого RTSP-потока** (`a=recvonly`, 0 байт данных), потому что go2rtc отдавал **JPEG** без транскода. С настоящим **H.264** (через `ffmpeg:`-поток в `-hardware` аддоне) валидация проходит: `type: create_entry`, `errors: null`. ### 🔴 БЛОКЕР: залипание USB-уровня камеры После манипуляций (go2rtc + ustreamer одновременно) камера залипла **на уровне драйвера ядра**: