Files
P2S_OSD/README.md
T

237 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 в этом репозитории.