Add profile conditions, scene presets, MQTT integration, and Scenes tab

Feature 1 — Profile Conditions: time-of-day, system idle (Win32
GetLastInputInfo), and display state (GUID_CONSOLE_DISPLAY_STATE)
condition types for automatic profile activation.

Feature 2 — Scene Presets: snapshot/restore system that captures target
running states, device brightness, and profile enables. Server-side
capture with 5-step activation order. Dedicated Scenes tab with
CardSection-based card grid, command palette integration, and dashboard
quick-activate section.

Feature 3 — MQTT Integration: MQTTService singleton with aiomqtt,
MQTTLEDClient device provider for pixel output, MQTT profile condition
type with topic/payload matching, and frontend support for MQTT device
type and condition editor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 16:57:42 +03:00
parent bd8d7a019f
commit 2e747b5ece
38 changed files with 2269 additions and 32 deletions

View File

@@ -128,6 +128,9 @@
"device.led_type.hint": "RGB (3 channels) or RGBW (4 channels with dedicated white)",
"device.send_latency": "Send Latency (ms):",
"device.send_latency.hint": "Simulated network/serial delay per frame in milliseconds",
"device.mqtt_topic": "MQTT Topic:",
"device.mqtt_topic.hint": "MQTT topic path for publishing pixel data (e.g. mqtt://ledgrab/device/name)",
"device.mqtt_topic.placeholder": "mqtt://ledgrab/device/living-room",
"device.url.hint": "IP address or hostname of the device (e.g. http://192.168.1.100)",
"device.name": "Device Name:",
"device.name.placeholder": "Living Room TV",
@@ -529,6 +532,7 @@
"dashboard.stop_all": "Stop All",
"dashboard.failed": "Failed to load dashboard",
"dashboard.section.profiles": "Profiles",
"dashboard.section.scenes": "Scene Presets",
"dashboard.targets": "Targets",
"dashboard.section.performance": "System Performance",
"dashboard.perf.cpu": "CPU",
@@ -568,6 +572,27 @@
"profiles.condition.application.match_type.topmost": "Topmost (foreground)",
"profiles.condition.application.match_type.topmost_fullscreen": "Topmost + Fullscreen",
"profiles.condition.application.match_type.fullscreen": "Fullscreen",
"profiles.condition.time_of_day": "Time of Day",
"profiles.condition.time_of_day.start_time": "Start Time:",
"profiles.condition.time_of_day.end_time": "End Time:",
"profiles.condition.time_of_day.overnight_hint": "For overnight ranges (e.g. 22:0006:00), set start time after end time.",
"profiles.condition.system_idle": "System Idle",
"profiles.condition.system_idle.idle_minutes": "Idle Timeout (minutes):",
"profiles.condition.system_idle.mode": "Trigger Mode:",
"profiles.condition.system_idle.when_idle": "When idle",
"profiles.condition.system_idle.when_active": "When active",
"profiles.condition.display_state": "Display State",
"profiles.condition.display_state.state": "Monitor State:",
"profiles.condition.display_state.on": "On",
"profiles.condition.display_state.off": "Off (sleeping)",
"profiles.condition.mqtt": "MQTT",
"profiles.condition.mqtt.topic": "Topic:",
"profiles.condition.mqtt.payload": "Payload:",
"profiles.condition.mqtt.match_mode": "Match Mode:",
"profiles.condition.mqtt.match_mode.exact": "Exact",
"profiles.condition.mqtt.match_mode.contains": "Contains",
"profiles.condition.mqtt.match_mode.regex": "Regex",
"profiles.condition.mqtt.hint": "Activate when an MQTT topic receives a matching payload",
"profiles.targets": "Targets:",
"profiles.targets.hint": "Targets to start when this profile activates",
"profiles.targets.empty": "No targets available",
@@ -586,6 +611,36 @@
"profiles.error.name_required": "Name is required",
"profiles.toggle_all.start": "Start all targets",
"profiles.toggle_all.stop": "Stop all targets",
"scenes.title": "Scenes",
"scenes.add": "Capture Scene",
"scenes.edit": "Edit Scene",
"scenes.name": "Name:",
"scenes.name.hint": "A descriptive name for this scene preset",
"scenes.description": "Description:",
"scenes.description.hint": "Optional description of what this scene does",
"scenes.color": "Card Color:",
"scenes.color.hint": "Accent color for the scene card on the dashboard",
"scenes.capture": "Capture",
"scenes.activate": "Activate scene",
"scenes.recapture": "Recapture current state",
"scenes.delete": "Delete scene",
"scenes.targets_count": "targets",
"scenes.devices_count": "devices",
"scenes.profiles_count": "profiles",
"scenes.captured": "Scene captured",
"scenes.updated": "Scene updated",
"scenes.activated": "Scene activated",
"scenes.activated_partial": "Scene partially activated",
"scenes.errors": "errors",
"scenes.recaptured": "Scene recaptured",
"scenes.deleted": "Scene deleted",
"scenes.recapture_confirm": "Recapture current state into \"{name}\"?",
"scenes.delete_confirm": "Delete scene \"{name}\"?",
"scenes.error.name_required": "Name is required",
"scenes.error.save_failed": "Failed to save scene",
"scenes.error.activate_failed": "Failed to activate scene",
"scenes.error.recapture_failed": "Failed to recapture scene",
"scenes.error.delete_failed": "Failed to delete scene",
"autostart.title": "Auto-start Targets",
"autostart.toggle.enabled": "Auto-start enabled",
"autostart.toggle.disabled": "Auto-start disabled",
@@ -961,6 +1016,7 @@
"search.group.pattern_templates": "Pattern Templates",
"search.group.audio": "Audio Sources",
"search.group.value": "Value Sources",
"search.group.scenes": "Scene Presets",
"settings.backup.label": "Backup Configuration",
"settings.backup.hint": "Download all configuration (devices, targets, streams, templates, profiles) as a single JSON file.",
"settings.backup.button": "Download Backup",

View File

@@ -128,6 +128,9 @@
"device.led_type.hint": "RGB (3 канала) или RGBW (4 канала с выделенным белым)",
"device.send_latency": "Задержка отправки (мс):",
"device.send_latency.hint": "Имитация сетевой/серийной задержки на кадр в миллисекундах",
"device.mqtt_topic": "MQTT Топик:",
"device.mqtt_topic.hint": "MQTT топик для публикации пиксельных данных (напр. mqtt://ledgrab/device/name)",
"device.mqtt_topic.placeholder": "mqtt://ledgrab/device/гостиная",
"device.url.hint": "IP адрес или имя хоста устройства (напр. http://192.168.1.100)",
"device.name": "Имя Устройства:",
"device.name.placeholder": "ТВ в Гостиной",
@@ -529,6 +532,7 @@
"dashboard.stop_all": "Остановить все",
"dashboard.failed": "Не удалось загрузить обзор",
"dashboard.section.profiles": "Профили",
"dashboard.section.scenes": "Пресеты сцен",
"dashboard.targets": "Цели",
"dashboard.section.performance": "Производительность системы",
"dashboard.perf.cpu": "ЦП",
@@ -568,6 +572,27 @@
"profiles.condition.application.match_type.topmost": "На переднем плане",
"profiles.condition.application.match_type.topmost_fullscreen": "На переднем плане + Полный экран",
"profiles.condition.application.match_type.fullscreen": "Полный экран",
"profiles.condition.time_of_day": "Время суток",
"profiles.condition.time_of_day.start_time": "Время начала:",
"profiles.condition.time_of_day.end_time": "Время окончания:",
"profiles.condition.time_of_day.overnight_hint": "Для ночных диапазонов (например 22:0006:00) укажите время начала позже времени окончания.",
"profiles.condition.system_idle": "Бездействие системы",
"profiles.condition.system_idle.idle_minutes": "Тайм-аут бездействия (минуты):",
"profiles.condition.system_idle.mode": "Режим срабатывания:",
"profiles.condition.system_idle.when_idle": "При бездействии",
"profiles.condition.system_idle.when_active": "При активности",
"profiles.condition.display_state": "Состояние дисплея",
"profiles.condition.display_state.state": "Состояние монитора:",
"profiles.condition.display_state.on": "Включён",
"profiles.condition.display_state.off": "Выключен (спящий режим)",
"profiles.condition.mqtt": "MQTT",
"profiles.condition.mqtt.topic": "Топик:",
"profiles.condition.mqtt.payload": "Значение:",
"profiles.condition.mqtt.match_mode": "Режим сравнения:",
"profiles.condition.mqtt.match_mode.exact": "Точное совпадение",
"profiles.condition.mqtt.match_mode.contains": "Содержит",
"profiles.condition.mqtt.match_mode.regex": "Регулярное выражение",
"profiles.condition.mqtt.hint": "Активировать при получении совпадающего значения по MQTT топику",
"profiles.targets": "Цели:",
"profiles.targets.hint": "Цели для запуска при активации профиля",
"profiles.targets.empty": "Нет доступных целей",
@@ -586,6 +611,36 @@
"profiles.error.name_required": "Введите название",
"profiles.toggle_all.start": "Запустить все цели",
"profiles.toggle_all.stop": "Остановить все цели",
"scenes.title": "Сцены",
"scenes.add": "Захватить сцену",
"scenes.edit": "Редактировать сцену",
"scenes.name": "Название:",
"scenes.name.hint": "Описательное имя для этого пресета сцены",
"scenes.description": "Описание:",
"scenes.description.hint": "Необязательное описание назначения этой сцены",
"scenes.color": "Цвет карточки:",
"scenes.color.hint": "Акцентный цвет для карточки сцены на панели управления",
"scenes.capture": "Захват",
"scenes.activate": "Активировать сцену",
"scenes.recapture": "Перезахватить текущее состояние",
"scenes.delete": "Удалить сцену",
"scenes.targets_count": "целей",
"scenes.devices_count": "устройств",
"scenes.profiles_count": "профилей",
"scenes.captured": "Сцена захвачена",
"scenes.updated": "Сцена обновлена",
"scenes.activated": "Сцена активирована",
"scenes.activated_partial": "Сцена активирована частично",
"scenes.errors": "ошибок",
"scenes.recaptured": "Сцена перезахвачена",
"scenes.deleted": "Сцена удалена",
"scenes.recapture_confirm": "Перезахватить текущее состояние в \"{name}\"?",
"scenes.delete_confirm": "Удалить сцену \"{name}\"?",
"scenes.error.name_required": "Необходимо указать название",
"scenes.error.save_failed": "Не удалось сохранить сцену",
"scenes.error.activate_failed": "Не удалось активировать сцену",
"scenes.error.recapture_failed": "Не удалось перезахватить сцену",
"scenes.error.delete_failed": "Не удалось удалить сцену",
"autostart.title": "Автозапуск целей",
"autostart.toggle.enabled": "Автозапуск включён",
"autostart.toggle.disabled": "Автозапуск отключён",
@@ -961,6 +1016,7 @@
"search.group.pattern_templates": "Шаблоны паттернов",
"search.group.audio": "Аудиоисточники",
"search.group.value": "Источники значений",
"search.group.scenes": "Пресеты сцен",
"settings.backup.label": "Резервное копирование",
"settings.backup.hint": "Скачать всю конфигурацию (устройства, цели, потоки, шаблоны, профили) в виде одного JSON-файла.",
"settings.backup.button": "Скачать резервную копию",

View File

@@ -128,6 +128,9 @@
"device.led_type.hint": "RGB3通道或 RGBW4通道带独立白色",
"device.send_latency": "发送延迟(毫秒):",
"device.send_latency.hint": "每帧模拟网络/串口延迟(毫秒)",
"device.mqtt_topic": "MQTT 主题:",
"device.mqtt_topic.hint": "用于发布像素数据的 MQTT 主题路径(例如 mqtt://ledgrab/device/name",
"device.mqtt_topic.placeholder": "mqtt://ledgrab/device/客厅",
"device.url.hint": "设备的 IP 地址或主机名(例如 http://192.168.1.100",
"device.name": "设备名称:",
"device.name.placeholder": "客厅电视",
@@ -529,6 +532,7 @@
"dashboard.stop_all": "全部停止",
"dashboard.failed": "加载仪表盘失败",
"dashboard.section.profiles": "配置文件",
"dashboard.section.scenes": "场景预设",
"dashboard.targets": "目标",
"dashboard.section.performance": "系统性能",
"dashboard.perf.cpu": "CPU",
@@ -568,6 +572,27 @@
"profiles.condition.application.match_type.topmost": "最前(前台)",
"profiles.condition.application.match_type.topmost_fullscreen": "最前 + 全屏",
"profiles.condition.application.match_type.fullscreen": "全屏",
"profiles.condition.time_of_day": "时段",
"profiles.condition.time_of_day.start_time": "开始时间:",
"profiles.condition.time_of_day.end_time": "结束时间:",
"profiles.condition.time_of_day.overnight_hint": "跨夜时段(如 22:0006:00请将开始时间设为晚于结束时间。",
"profiles.condition.system_idle": "系统空闲",
"profiles.condition.system_idle.idle_minutes": "空闲超时(分钟):",
"profiles.condition.system_idle.mode": "触发模式:",
"profiles.condition.system_idle.when_idle": "空闲时",
"profiles.condition.system_idle.when_active": "活跃时",
"profiles.condition.display_state": "显示器状态",
"profiles.condition.display_state.state": "显示器状态:",
"profiles.condition.display_state.on": "开启",
"profiles.condition.display_state.off": "关闭(休眠)",
"profiles.condition.mqtt": "MQTT",
"profiles.condition.mqtt.topic": "主题:",
"profiles.condition.mqtt.payload": "消息内容:",
"profiles.condition.mqtt.match_mode": "匹配模式:",
"profiles.condition.mqtt.match_mode.exact": "精确匹配",
"profiles.condition.mqtt.match_mode.contains": "包含",
"profiles.condition.mqtt.match_mode.regex": "正则表达式",
"profiles.condition.mqtt.hint": "当 MQTT 主题收到匹配的消息时激活",
"profiles.targets": "目标:",
"profiles.targets.hint": "配置文件激活时要启动的目标",
"profiles.targets.empty": "没有可用的目标",
@@ -586,6 +611,36 @@
"profiles.error.name_required": "名称为必填项",
"profiles.toggle_all.start": "启动所有目标",
"profiles.toggle_all.stop": "停止所有目标",
"scenes.title": "场景",
"scenes.add": "捕获场景",
"scenes.edit": "编辑场景",
"scenes.name": "名称:",
"scenes.name.hint": "此场景预设的描述性名称",
"scenes.description": "描述:",
"scenes.description.hint": "此场景功能的可选描述",
"scenes.color": "卡片颜色:",
"scenes.color.hint": "仪表盘上场景卡片的强调色",
"scenes.capture": "捕获",
"scenes.activate": "激活场景",
"scenes.recapture": "重新捕获当前状态",
"scenes.delete": "删除场景",
"scenes.targets_count": "目标",
"scenes.devices_count": "设备",
"scenes.profiles_count": "配置",
"scenes.captured": "场景已捕获",
"scenes.updated": "场景已更新",
"scenes.activated": "场景已激活",
"scenes.activated_partial": "场景部分激活",
"scenes.errors": "错误",
"scenes.recaptured": "场景已重新捕获",
"scenes.deleted": "场景已删除",
"scenes.recapture_confirm": "将当前状态重新捕获到\"{name}\"中?",
"scenes.delete_confirm": "删除场景\"{name}\"",
"scenes.error.name_required": "名称为必填项",
"scenes.error.save_failed": "保存场景失败",
"scenes.error.activate_failed": "激活场景失败",
"scenes.error.recapture_failed": "重新捕获场景失败",
"scenes.error.delete_failed": "删除场景失败",
"autostart.title": "自动启动目标",
"autostart.toggle.enabled": "自动启动已启用",
"autostart.toggle.disabled": "自动启动已禁用",
@@ -961,6 +1016,7 @@
"search.group.pattern_templates": "图案模板",
"search.group.audio": "音频源",
"search.group.value": "值源",
"search.group.scenes": "场景预设",
"settings.backup.label": "备份配置",
"settings.backup.hint": "将所有配置(设备、目标、流、模板、配置文件)下载为单个 JSON 文件。",
"settings.backup.button": "下载备份",