diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md new file mode 100644 index 0000000..7ca1103 --- /dev/null +++ b/PROJECT_PLAN.md @@ -0,0 +1,212 @@ +# Проект: оверлей телеметрии Bambu Lab P2S поверх RTSP-потока + +## Цель +Собрать одно-контейнерное приложение, которое: +- получает видеопоток камеры принтера по `rtsps://...:322/streaming/live/1`; +- получает телеметрию/статус по MQTT (LAN-only + developer mode, совместимо с OpenBambuAPI); +- накладывает данные на видео в реальном времени; +- отдает готовый поток для OBS/go2rtc/другого ретранслятора; +- стабильно работает без GPU; +- имеет структурированные логи, healthcheck и устойчивость к пропаданию MQTT/RTSP. + +--- + +## Базовые требования (чек-лист) +- [x] Один Docker-контейнер. +- [x] Автозапуск пайплайна при старте контейнера (без ручных команд). +- [x] Работа на CPU. +- [x] Читаемые логи состояния и ошибок. +- [x] Переживание обрывов MQTT и RTSP без падения процесса. +- [x] HTTP-эндпоинт health/readiness для мониторинга. +- [x] Возможность включить в контейнер сторонний проект (например, go2rtc), но в рамках одного контейнера. + +--- + +## Вариант 1 (рекомендуемый): Python orchestration + FFmpeg drawtext + встроенный RTSP-сервер (MediaMTX) + +### Идея +- Python-процесс: + - подписывается на MQTT, нормализует телеметрию; + - пишет текущий оверлей в текстовый файл (`/run/overlay.txt`); + - держит HTTP `/healthz` и `/readyz`; + - логирует состояние/ошибки (JSON-лог). +- FFmpeg-процесс: + - читает RTSP; + - накладывает `drawtext=textfile=/run/overlay.txt:reload=1`; + - публикует поток в локальный MediaMTX (`rtsp://127.0.0.1:8554/p2s_overlay`). +- MediaMTX в том же контейнере раздает RTSP/RTMP/WebRTC (по необходимости). + +### Плюсы +- Минимум собственного низкоуровневого видео-кода. +- Устойчивость: FFmpeg и MQTT можно рестартовать независимо (через supervisor). +- Простое масштабирование форматирования оверлея. + +### Риски/минусы +- `drawtext` ограничен по сложной верстке (таблицы/иконки сложнее). +- Нужно аккуратно синхронизировать обновление файла оверлея (atomic write). + +### План реализации +1. **Слой конфигурации** + - ENV: IP принтера, пароль, MQTT-топики, формат выдачи, fps/битрейт. +2. **Сбор телеметрии** + - MQTT client (paho-mqtt/asyncio-mqtt), reconnect с backoff. + - Парсер payload по схеме OpenBambuAPI. +3. **Модель состояния** + - Единый `PrinterState` с timestamp последнего обновления. + - Поля: AMS (слот/тип/цвет), статус, прогресс, слой, job name, elapsed/remaining, температуры, вентиляторы, ошибки. +4. **Рендер оверлея в текст** + - Шаблон строк (несколько строк с фиксированным порядком). + - Атомарная запись через tmp + rename. +5. **Видео-пайплайн** + - FFmpeg командой из env (preset, reconnect options). + - В случае потери видео: автоreconnect без завершения контейнера. +6. **Выдача потока** + - Поднять MediaMTX в том же контейнере, публиковать туда выход FFmpeg. +7. **Наблюдаемость** + - `/healthz`: жив ли процесс. + - `/readyz`: есть ли свежая телеметрия и/или видео за N секунд. + - `/metrics` (опционально, Prometheus). +8. **Fail-safe поведение** + - Нет MQTT: показывать `MQTT: disconnected`, последнее известное состояние. + - Нет RTSP: показывать standby/заглушку либо держать процесс с reconnect. +9. **Docker** + - multi-stage build, tini/s6/supervisord как init. + - Один `CMD`, стартующий supervisor, который поднимает все процессы. + +--- + +## Вариант 2: GStreamer (единый мультимедийный граф) + Python для телеметрии + +### Идея +- GStreamer получает RTSP (`rtspsrc`), декодирует CPU (`avdec_h264`), накладывает текст (`textoverlay`/`cairooverlay`), кодирует (`x264enc`), отдает RTSP/UDP. +- Python процесс обновляет shared-state (например, через локальный сокет/redis-inproc-файл). + +### Плюсы +- Гибче компоновка пайплайна и ниже latency при правильной настройке. +- Возможны более сложные оверлеи (через cairo). + +### Риски/минусы +- Более крутая кривая настройки. +- Сложнее сопровождение для команды без опыта GStreamer. + +### План реализации +1. Собрать baseline pipeline с reconnect. +2. Подключить динамический text source. +3. Реализовать health probes + watchdog pipeline. +4. Обернуть в supervisor и Docker. + +--- + +## Вариант 3: go2rtc как ядро ретрансляции + sidecar-процесс оверлея внутри того же контейнера + +### Идея +- go2rtc забирает исходный поток и отдает его локально. +- Отдельный процесс внутри контейнера (FFmpeg/Python) берет поток из go2rtc, добавляет overlay, публикует обратно вторым потоком. + +### Плюсы +- Удобная интеграция, если у вас уже экосистема на go2rtc. +- Гибкая маршрутизация клиентов. + +### Риски/минусы +- Чуть сложнее маршрутизация потоков и конфиги. +- Потребление CPU выше при двойной обработке. + +### План реализации +1. Встроить бинарь go2rtc в образ. +2. Поднять stream source и overlay stream. +3. Прописать стабильные имена потоков и healthchecks. + +--- + +## Рекомендованная структура проекта + +- `app/main.py` — orchestration, lifecycle. +- `app/mqtt_client.py` — подключение/подписки/reconnect. +- `app/state.py` — модель состояния и нормализация. +- `app/overlay_renderer.py` — генерация `/run/overlay.txt`. +- `app/health_api.py` — `/healthz`, `/readyz`, `/metrics`. +- `docker/ffmpeg.sh` — запуск ffmpeg с reconnect-флагами. +- `docker/mediamtx.yml` — конфиг локальной раздачи потоков. +- `docker/supervisord.conf` — процессы: python, ffmpeg, mediamtx. + +--- + +## Формат оверлея (пример) + +```text +P2S | Printing | 42% | Layer 135/320 +Job: gearbox_v7.3mf +AMS: Slot 2 | PLA Basic | #FF7A00 +Elapsed: 01:12:33 | Remaining: 00:35:20 +Nozzle: 218°C | Bed: 60°C | Chamber: 36°C +Fans: Part 70% | Aux 40% | Chamber 35% +MQTT: OK (0.8s) | Video: OK (0.2s) +``` + +--- + +## Отказоустойчивость (обязательная логика) + +1. **MQTT down** + - Не падать. + - Статус в overlay: `MQTT disconnected`. + - Экспоненциальный reconnect (до max interval). +2. **RTSP down** + - Не падать. + - FFmpeg reconnect (`-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 10`). +3. **Оба канала down** + - Контейнер жив, `/healthz = 200`, `/readyz = 503`. +4. **Переполнение/битый payload** + - Валидация входа, лог ошибки, продолжение работы. + +--- + +## Логирование + +- Формат: JSON Lines. +- Поля: `ts`, `level`, `component`, `event`, `message`, `error`, `printer_ip`. +- Важные события: + - connect/disconnect/reconnect (mqtt, rtsp); + - смена статуса печати; + - смена задания; + - деградация readiness. + +--- + +## Health endpoints + +- `GET /healthz` — процесс жив (всегда 200, пока event loop работает). +- `GET /readyz` — готовность сервиса: + - 200: есть видео и/или телеметрия свежее N сек; + - 503: оба источника stale. +- `GET /status` — краткий JSON со state (для дебага). + +--- + +## Docker-стратегия + +- База: `python:3.12-slim` + `ffmpeg` + `mediamtx` (скачанный бинарь). +- PID 1: `tini`. +- Процесс-менеджмент: `supervisord`/`s6-overlay`. +- `HEALTHCHECK` на `curl -f http://127.0.0.1:8080/healthz`. +- Автостарт через `CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]`. + +--- + +## Этапы внедрения (MVP -> production) + +1. **MVP (1–2 дня)** + - MQTT ingest + простой overlay.txt + FFmpeg drawtext + `/healthz`. +2. **Стабилизация (2–4 дня)** + - reconnect стратегия, `/readyz`, структурные логи, docker healthcheck. +3. **Production hardening (3–5 дней)** + - watchdog процессов, graceful shutdown, ограничения CPU/RAM, документация. +4. **Опционально** + - Preset-ы оверлея (минимальный/расширенный), локализация, экспорт метрик. + +--- + +## Что выбрать сейчас + +Для старта рекомендован **Вариант 1** как самый быстрый и предсказуемый для CPU-only контейнера. +Он лучше всего закрывает требования по надежности, простоте сопровождения и интеграции с go2rtc/OBS. diff --git a/README.md b/README.md index ed36a9f..fc0ffac 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# P2S_OSC \ No newline at end of file +# P2S_OSC + +Черновой план проекта по наложению телеметрии Bambu Lab P2S на видеопоток камеры находится в файле `PROJECT_PLAN.md`.