Files
P2S_OSD/PROJECT_PLAN.md
T

10 KiB
Raw Blame History

Проект: оверлей телеметрии Bambu Lab P2S поверх RTSP-потока

Цель

Собрать одно-контейнерное приложение, которое:

  • получает видеопоток камеры принтера по rtsps://...:322/streaming/live/1;
  • получает телеметрию/статус по MQTT (LAN-only + developer mode, совместимо с OpenBambuAPI);
  • накладывает данные на видео в реальном времени;
  • отдает готовый поток для OBS/go2rtc/другого ретранслятора;
  • стабильно работает без GPU;
  • имеет структурированные логи, healthcheck и устойчивость к пропаданию MQTT/RTSP.

Базовые требования (чек-лист)

  • Один Docker-контейнер.
  • Автозапуск пайплайна при старте контейнера (без ручных команд).
  • Работа на CPU.
  • Читаемые логи состояния и ошибок.
  • Переживание обрывов MQTT и RTSP без падения процесса.
  • HTTP-эндпоинт health/readiness для мониторинга.
  • Возможность включить в контейнер сторонний проект (например, 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.

Формат оверлея (пример)

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 (12 дня)
    • MQTT ingest + простой overlay.txt + FFmpeg drawtext + /healthz.
  2. Стабилизация (2–4 дня)
    • reconnect стратегия, /readyz, структурные логи, docker healthcheck.
  3. Production hardening (35 дней)
    • watchdog процессов, graceful shutdown, ограничения CPU/RAM, документация.
  4. Опционально
    • Preset-ы оверлея (минимальный/расширенный), локализация, экспорт метрик.

Что выбрать сейчас

Для старта рекомендован Вариант 1 как самый быстрый и предсказуемый для CPU-only контейнера. Он лучше всего закрывает требования по надежности, простоте сопровождения и интеграции с go2rtc/OBS.