mirror of
https://github.com/deadcxap/P2S_OSD.git
synced 2026-07-01 21:33:46 +03:00
Добавить варианты архитектуры и план реализации OSD сервиса
This commit is contained in:
@@ -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) каждые 250–500 мс.
|
||||
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 в этом репозитории.
|
||||
|
||||
Reference in New Issue
Block a user