4 Commits

Author SHA1 Message Date
gx 0e9a353d75 controller: jinja2 template для chat overlays + UI marker для icon/text
dynamic_overlays.ChatCfg.template (опц.) — Jinja2 шаблон применяется к
incoming MQTT payload. Доступны переменные payload (raw str) и payload_json
(parsed JSON dict если valid). Используется для извлечения отдельного поля
из JSON, например temperature из z2m sensor.

Применение в controller.yaml:
  chats:
    - id: temp_outside
      source_topic: "zigbee2mqtt/Температура на улице"
      template: "{{ '%+.1f' | format(payload_json.temperature | float) }}°C"

Если template не задан — payload используется как есть (backwards compat
с alerts_chat и подобными).

UI editor static/index.html: для icon/text overlays вместо коробки показываем
точечный маркер 14×14 (синий circle). Причина: filter render_overlay_icon
использует native PNG dimensions, frontend не знает реальный размер
(w_px/h_px хранятся в ChatCfg на server-side). Показ size=10% как было —
вводил в заблуждение. Resize handle тоже скрыт для marker'ов.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 20:55:35 +01:00
gx 6081e33e5a controller: PipelineMonitor — auto-restore overlay state после pipeline restart
Pipeline filter state (overlays, layout, cell_map, audio) живёт в RAM
ffmpeg process. При recreate container (compose up, OOM, NVENC crash,
config change) state lost — controller'у нужно re-push.

Раньше user'у приходилось вручную:
  curl POST /layout/.../set
  docker restart cuda-grid-controller  # для browser/dynamic re-register

Теперь автоматизировано:
  PipelineMonitor polls ZMQ каждые 3 sec (no-op set_layout).
  On timeout/error → mark instance lost.
  First success after lost → trigger restore:
    1. set_layout к state.active_layout
    2. set_audio_output_enabled к state.audio_output_enabled
    3. re-push все overlays из state.overlays
    4. browser/dynamic/frigate hooks: mark_all_unregistered() —
       их loops автоматически re-add на next iteration

Verified test: docker restart cuda-grid-pipeline → 10 sec downtime →
monitor logs lost+restored+restore_done с count=6 overlays.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 07:35:27 +01:00
gx d90c139dce controller: Phase 6+ — Web UI mini dashboard
Static HTML/JS dashboard в cuda_grid_controller/static/index.html, mounted
на /ui и / FastAPI endpoints. Vanilla JS + HLS.js (CDN) для video player.

Controls:
  Audio source — buttons из /audio/{instance} list, switch через POST
  Intercom — Start (music↓) / End (restore)
  Snapshot — opens PNG в new tab
  Manual overlay — form для rect/text/dim/icon types
  Chat — placeholder (info-toast про mosquitto_pub)
  State — refresh каждые 2 sec, shows layout/overlays_count + raw list

Player consumes HLS на http://server:8888/live/index.m3u8 (mediamtx).
TV не нужен — браузер на любом устройстве в LAN.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 05:27:27 +01:00
gx d807cd2c23 controller: Phase 5b+5c+6 — multi-audio + intercom ducking + dynamic overlays
5b — audio source switching:
  AudioSourceCfg list + audio_filter_target в InstanceCfg
  CommandDispatcher._audio_set → ZMQ astreamselect@as map <index>
  REST: GET /audio/{inst}, POST /audio/{inst}/set
  MQTT: cuda_grid/cmd/<inst>/audio/set <source_name>

5c — intercom ducking:
  music_volume_target / intercom_volume_target / music_ducked_volume в InstanceCfg
  CommandDispatcher._intercom_set → 2× ZMQ volume@music/@intercom commands
  REST: POST /intercom/{inst}/start (music↓ + intercom↑) + /end (restore)
  MQTT: cuda_grid/cmd/<inst>/intercom/start|end

6 — dynamic overlays (charts/chats):
  dynamic_overlays.py: ChartCfg/ChatCfg + DynamicRenderer
  PIL rendering: line chart + scrolling text list
  Async loops пишут PNG в icon_dir + invalidate filter cache via reload_icon ZMQ
  MQTT subscriptions для real data (charts: numeric topic, chats: text topic)
  Demo: chart sine wave если data_topic=null
  Wired в __main__.py + mqtt_loop dispatch

+ ZMQ client asyncio.Lock — REQ socket strict send/recv pattern требует
  serialize requests (overlay/audio/intercom concurrent ломали "Operation
  cannot be accomplished in current state")
+ Pillow в Dockerfile (для PIL render)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 21:55:33 +01:00