Merge pull request #4 from deadcxap/codex/design-data-overlay-for-3d-printer-video-puxzay

Обновить README: добавить архитектурные варианты и план реализации OSD для Bambu P2S
This commit is contained in:
deadcxap
2026-04-15 04:24:53 +03:00
committed by GitHub
+236 -1
View File
@@ -1 +1,236 @@
# P2S_OSC # P2S_OSD
Проект наложения телеметрии печати Bambu Lab P2S поверх RTSP-видеопотока камеры принтера.
## Цель
Получить единый выходной видеопоток (для OBS/go2rtc/других клиентов), в котором уже «вклеены»:
- состояние принтера;
- данные задания печати;
- текущий слой и прогресс;
- параметры AMS (катушка, тип, цвет, слот);
- температуры (сопло, стол, камера);
- скорости вентиляторов и иные доступные метрики.
Ограничения:
- принтер в режиме `LAN-only` + включённый `Developer Mode`;
- взаимодействие по MQTT (как в OpenBambuAPI);
- входное видео по `rtsps://...:322/streaming/live/1`;
- работа **без GPU** (CPU-only);
- один Docker-контейнер;
- автозапуск без ручных команд после старта контейнера;
- читаемые логи;
- устойчивость при пропаже MQTT/RTSP;
- endpoint healthcheck для мониторинга.
---
## Вариант 1 (рекомендуется): Python + GStreamer + Cairo/Pango OSD
### Идея
Собрать сервис на Python, который:
1. читает RTSP через GStreamer;
2. рисует OSD-слой на кадре в пайплайне (`cairooverlay`/`textoverlay`);
3. держит отдельный MQTT-клиент для статуса принтера;
4. публикует выход как RTSP (через встроенный `gst-rtsp-server`) или SRT/MPEG-TS;
5. поднимает HTTP endpoint `/healthz` и `/metrics`.
### Инструменты
- `python:3.12-slim`;
- `gstreamer1.0` + `-plugins-base/-good/-bad/-ugly`;
- Python-библиотеки: `paho-mqtt`, `fastapi`/`aiohttp`, `uvicorn`, `pydantic`;
- `gst-rtsp-server` (через C-плагин в runtime, либо запуск отдельного процесса `gst-rtsp-launch`, но внутри того же контейнера).
### Плюсы
- нативный real-time видеопайплайн;
- хорошая отказоустойчивость за счёт рестартуемых веток пайплайна;
- OSD рендерится без полного декод/энкод в Python-коде;
- удобная интеграция метрик и health endpoint.
### Минусы
- сложнее в настройке GStreamer;
- нужно аккуратно подобрать кодек/битрейт CPU-only.
### План реализации
1. **Каркас приложения**
- `app/main.py` (оркестратор), `app/config.py`, `app/logging.py`.
2. **MQTT-адаптер**
- подключение к топикам Bambu;
- нормализация в единый `PrinterState`.
3. **State Store**
- thread-safe/async-safe store;
- TTL-поля (чтобы помечать устаревшие данные как `N/A`).
4. **Видеопайплайн**
- RTSP ingest → decode → overlay → encode (`x264enc ultrafast`) → RTSP output.
5. **OSD layout**
- несколько блоков: job, printer, temps, fans, AMS;
- fallback-текст при отсутствии данных.
6. **Resilience**
- retry с backoff для MQTT и RTSP;
- watchdog пайплайна, автоматический re-init.
7. **Observability**
- структурные логи JSON/текст;
- `/healthz` (liveness/readiness), `/metrics`.
8. **Docker**
- `ENTRYPOINT` запускает единый процесс-супервизор.
---
## Вариант 2: Go + FFmpeg filtergraph (`drawtext`/`overlay`) + MQTT
### Идея
Go-сервис получает MQTT-статус, генерирует текстовый OSD (или bitmap), а FFmpeg-процесс выполняет транскод и наложение через фильтры.
### Инструменты
- Go 1.23+;
- `ffmpeg` (libx264, drawtext);
- MQTT-клиент (`eclipse/paho.mqtt.golang`);
- HTTP сервер (`chi`/`net/http`) для health.
### Плюсы
- проще найти специалистов по FFmpeg;
- один стабильный бинарь-оркестратор;
- предсказуемое поведение в Docker.
### Минусы
- `drawtext` обновляется через перезапись textfile/zmq-команды, что усложняет динамику;
- сложнее сделать богатый UI (цветные блоки, иконки) без дополнительных костылей.
### План реализации
1. Go-daemon с подсистемами `mqtt`, `state`, `ffmpeg`, `health`.
2. Генерация `osd.txt` (atomic write) каждые 250500 мс.
3. Запуск FFmpeg с `-vf drawtext=textfile=...:reload=1`.
4. Выходной поток: RTSP push в локальный go2rtc (внутри контейнера) или прямой RTMP/SRT.
5. Контроль процесса FFmpeg (перезапуск + throttling).
6. Prometheus/health endpoints.
---
## Вариант 3: Встроенный go2rtc + sidecar-процесс OSD внутри одного контейнера
### Идея
В одном контейнере работают:
- `go2rtc` как универсальный ретранслятор;
- отдельный OSD-процесс (Python/Go), который берёт исходный поток и публикует «обогащённый» поток обратно в go2rtc.
> Несмотря на два процесса, это **один контейнер**, что соответствует требованию.
### Плюсы
- сразу готовая интеграция с экосистемой go2rtc;
- удобно раздавать в разные протоколы (WebRTC/RTSP/HLS).
### Минусы
- нужно корректно организовать процесс-менеджмент (s6/supervisord/tini + watchdog);
- сложнее отладка при циклической маршрутизации потоков.
### План реализации
1. Собрать image с `go2rtc` + OSD service.
2. Статический `go2rtc.yaml` с входным потоком принтера и выходом `stream_osd`.
3. OSD service публикует в локальный ingest (`rtsp://127.0.0.1:8554/...`).
4. Единый `/healthz` агрегирует состояние обоих процессов.
5. Логи обоих процессов в stdout/stderr контейнера.
---
## Рекомендуемая архитектура MVP
Для первого релиза: **Вариант 1**.
Почему:
- лучший баланс между гибкостью OSD и стабильностью в real-time;
- можно начать с простого текстового overlay и постепенно добавить графические элементы;
- проще контролировать reconnect-логику в одном коде.
### MVP scope (итерация 1)
- вход RTSP;
- MQTT-подписка на базовые поля (status/progress/layers/temps);
- простое OSD (2 колонки);
- выход RTSP;
- `/healthz` и `/readyz`;
- Docker + `HEALTHCHECK`;
- устойчивый reconnect.
### Итерция 2
- AMS-детализация (тип/цвет/слот);
- красивые плашки/цвета;
- экспорт метрик Prometheus;
- профили качества (low/medium/high CPU).
---
## Структура репозитория (предложение)
```text
.
├─ app/
│ ├─ main.py
│ ├─ config.py
│ ├─ logging.py
│ ├─ state/
│ │ ├─ models.py
│ │ └─ store.py
│ ├─ mqtt/
│ │ ├─ client.py
│ │ └─ parser.py
│ ├─ video/
│ │ ├─ pipeline.py
│ │ └─ overlay.py
│ └─ api/
│ └─ health.py
├─ Dockerfile
├─ docker-compose.example.yml
├─ .env.example
└─ README.md
```
---
## Ключевые нефункциональные требования и как их закрыть
1. **Не падать при отсутствии коннекта**
- бесконечный reconnect c exponential backoff;
- «деградированный режим» (OSD показывает `NO MQTT` / `NO VIDEO`).
2. **Читаемые логи**
- уровни `INFO/WARN/ERROR`, correlation-id сессии подключения;
- отдельные события `mqtt_connected`, `rtsp_disconnected`, `pipeline_restarted`.
3. **Автозапуск**
- `ENTRYPOINT ["python", "-m", "app.main"]`;
- никаких ручных post-start команд.
4. **Проверка работоспособности**
- `/healthz` (жив ли процесс);
- `/readyz` (есть ли свежие state/video за N сек).
5. **CPU-only**
- `x264enc tune=zerolatency speed-preset=ultrafast`;
- ограничить fps/разрешение в конфиге.
---
## Что подготовить перед кодированием
- список точных MQTT topic/payload полей (по OpenBambuAPI и фактическим payload вашего принтера);
- целевой формат выходного потока (RTSP/RTMP/WebRTC);
- допустимая задержка (например, ≤ 2–3 с);
- CPU-бюджет хоста (число vCPU).
После этого можно переходить к реализации MVP в этом репозитории.