Add auto-start targets feature with dashboard section
- Add auto_start boolean field to PictureTarget model (persisted per-target) - Wire auto_start through API schemas, routes, and store - Auto-start targets on server boot in main.py lifespan - Add star toggle button on target cards (next to delete button) - Add auto-start section on dashboard between performance and profiles - Remove auto-start section from profiles tab Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -101,6 +101,7 @@ def _target_to_response(target) -> PictureTargetResponse:
|
|||||||
keepalive_interval=target.keepalive_interval,
|
keepalive_interval=target.keepalive_interval,
|
||||||
state_check_interval=target.state_check_interval,
|
state_check_interval=target.state_check_interval,
|
||||||
description=target.description,
|
description=target.description,
|
||||||
|
auto_start=target.auto_start,
|
||||||
created_at=target.created_at,
|
created_at=target.created_at,
|
||||||
updated_at=target.updated_at,
|
updated_at=target.updated_at,
|
||||||
)
|
)
|
||||||
@@ -112,6 +113,7 @@ def _target_to_response(target) -> PictureTargetResponse:
|
|||||||
picture_source_id=target.picture_source_id,
|
picture_source_id=target.picture_source_id,
|
||||||
key_colors_settings=_kc_settings_to_schema(target.settings),
|
key_colors_settings=_kc_settings_to_schema(target.settings),
|
||||||
description=target.description,
|
description=target.description,
|
||||||
|
auto_start=target.auto_start,
|
||||||
created_at=target.created_at,
|
created_at=target.created_at,
|
||||||
updated_at=target.updated_at,
|
updated_at=target.updated_at,
|
||||||
)
|
)
|
||||||
@@ -121,6 +123,7 @@ def _target_to_response(target) -> PictureTargetResponse:
|
|||||||
name=target.name,
|
name=target.name,
|
||||||
target_type=target.target_type,
|
target_type=target.target_type,
|
||||||
description=target.description,
|
description=target.description,
|
||||||
|
auto_start=target.auto_start,
|
||||||
created_at=target.created_at,
|
created_at=target.created_at,
|
||||||
updated_at=target.updated_at,
|
updated_at=target.updated_at,
|
||||||
)
|
)
|
||||||
@@ -159,6 +162,7 @@ async def create_target(
|
|||||||
picture_source_id=data.picture_source_id,
|
picture_source_id=data.picture_source_id,
|
||||||
key_colors_settings=kc_settings,
|
key_colors_settings=kc_settings,
|
||||||
description=data.description,
|
description=data.description,
|
||||||
|
auto_start=data.auto_start,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Register in processor manager
|
# Register in processor manager
|
||||||
@@ -274,6 +278,7 @@ async def update_target(
|
|||||||
state_check_interval=data.state_check_interval,
|
state_check_interval=data.state_check_interval,
|
||||||
key_colors_settings=kc_settings,
|
key_colors_settings=kc_settings,
|
||||||
description=data.description,
|
description=data.description,
|
||||||
|
auto_start=data.auto_start,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Detect KC brightness VS change (inside key_colors_settings)
|
# Detect KC brightness VS change (inside key_colors_settings)
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class PictureTargetCreate(BaseModel):
|
|||||||
picture_source_id: str = Field(default="", description="Picture source ID (for key_colors targets)")
|
picture_source_id: str = Field(default="", description="Picture source ID (for key_colors targets)")
|
||||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings (for key_colors targets)")
|
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings (for key_colors targets)")
|
||||||
description: Optional[str] = Field(None, description="Optional description", max_length=500)
|
description: Optional[str] = Field(None, description="Optional description", max_length=500)
|
||||||
|
auto_start: bool = Field(default=False, description="Auto-start on server boot")
|
||||||
|
|
||||||
|
|
||||||
class PictureTargetUpdate(BaseModel):
|
class PictureTargetUpdate(BaseModel):
|
||||||
@@ -79,6 +80,7 @@ class PictureTargetUpdate(BaseModel):
|
|||||||
picture_source_id: Optional[str] = Field(None, description="Picture source ID (for key_colors targets)")
|
picture_source_id: Optional[str] = Field(None, description="Picture source ID (for key_colors targets)")
|
||||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings (for key_colors targets)")
|
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings (for key_colors targets)")
|
||||||
description: Optional[str] = Field(None, description="Optional description", max_length=500)
|
description: Optional[str] = Field(None, description="Optional description", max_length=500)
|
||||||
|
auto_start: Optional[bool] = Field(None, description="Auto-start on server boot")
|
||||||
|
|
||||||
|
|
||||||
class PictureTargetResponse(BaseModel):
|
class PictureTargetResponse(BaseModel):
|
||||||
@@ -98,6 +100,7 @@ class PictureTargetResponse(BaseModel):
|
|||||||
picture_source_id: str = Field(default="", description="Picture source ID (key_colors)")
|
picture_source_id: str = Field(default="", description="Picture source ID (key_colors)")
|
||||||
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings")
|
key_colors_settings: Optional[KeyColorsSettingsSchema] = Field(None, description="Key colors settings")
|
||||||
description: Optional[str] = Field(None, description="Description")
|
description: Optional[str] = Field(None, description="Description")
|
||||||
|
auto_start: bool = Field(default=False, description="Auto-start on server boot")
|
||||||
created_at: datetime = Field(description="Creation timestamp")
|
created_at: datetime = Field(description="Creation timestamp")
|
||||||
updated_at: datetime = Field(description="Last update timestamp")
|
updated_at: datetime = Field(description="Last update timestamp")
|
||||||
|
|
||||||
|
|||||||
@@ -147,6 +147,19 @@ async def lifespan(app: FastAPI):
|
|||||||
# Start profile engine (evaluates conditions and auto-starts/stops targets)
|
# Start profile engine (evaluates conditions and auto-starts/stops targets)
|
||||||
await profile_engine.start()
|
await profile_engine.start()
|
||||||
|
|
||||||
|
# Auto-start targets with auto_start=True
|
||||||
|
auto_started = 0
|
||||||
|
for target in targets:
|
||||||
|
if getattr(target, "auto_start", False):
|
||||||
|
try:
|
||||||
|
await processor_manager.start_processing(target.id)
|
||||||
|
auto_started += 1
|
||||||
|
logger.info(f"Auto-started target: {target.name} ({target.id})")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to auto-start target {target.id}: {e}")
|
||||||
|
if auto_started:
|
||||||
|
logger.info(f"Auto-started {auto_started} target(s)")
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
# Shutdown
|
# Shutdown
|
||||||
|
|||||||
@@ -103,6 +103,30 @@ section {
|
|||||||
position: static;
|
position: static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-autostart-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #777;
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: color 0.2s, background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-autostart-btn:hover {
|
||||||
|
color: var(--warning-color, #ffc107);
|
||||||
|
background: rgba(255, 193, 7, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-autostart-btn.active {
|
||||||
|
color: var(--warning-color, #ffc107);
|
||||||
|
}
|
||||||
|
|
||||||
.card-power-btn {
|
.card-power-btn {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ import {
|
|||||||
showTargetEditor, closeTargetEditorModal, forceCloseTargetEditorModal, saveTargetEditor,
|
showTargetEditor, closeTargetEditorModal, forceCloseTargetEditorModal, saveTargetEditor,
|
||||||
startTargetProcessing, stopTargetProcessing,
|
startTargetProcessing, stopTargetProcessing,
|
||||||
startTargetOverlay, stopTargetOverlay, deleteTarget,
|
startTargetOverlay, stopTargetOverlay, deleteTarget,
|
||||||
cloneTarget, toggleLedPreview,
|
cloneTarget, toggleLedPreview, toggleTargetAutoStart,
|
||||||
expandAllTargetSections, collapseAllTargetSections,
|
expandAllTargetSections, collapseAllTargetSections,
|
||||||
} from './features/targets.js';
|
} from './features/targets.js';
|
||||||
|
|
||||||
@@ -302,6 +302,7 @@ Object.assign(window, {
|
|||||||
deleteTarget,
|
deleteTarget,
|
||||||
cloneTarget,
|
cloneTarget,
|
||||||
toggleLedPreview,
|
toggleLedPreview,
|
||||||
|
toggleTargetAutoStart,
|
||||||
|
|
||||||
// color-strip sources
|
// color-strip sources
|
||||||
showCSSEditor,
|
showCSSEditor,
|
||||||
|
|||||||
@@ -363,6 +363,38 @@ export async function loadDashboard(forceFullRender = false) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const autoStartTargets = enriched.filter(t => t.auto_start);
|
||||||
|
if (autoStartTargets.length > 0) {
|
||||||
|
const autoStartItems = autoStartTargets.map(target => {
|
||||||
|
const isRunning = !!(target.state && target.state.processing);
|
||||||
|
const device = devicesMap[target.device_id];
|
||||||
|
const deviceName = device ? device.name : '';
|
||||||
|
const typeIcon = target.target_type === 'key_colors' ? '🎨' : '💡';
|
||||||
|
const statusBadge = isRunning
|
||||||
|
? `<span class="dashboard-badge-active">${t('profiles.status.active')}</span>`
|
||||||
|
: `<span class="dashboard-badge-stopped">${t('profiles.status.inactive')}</span>`;
|
||||||
|
return `<div class="dashboard-target dashboard-autostart" data-target-id="${target.id}">
|
||||||
|
<div class="dashboard-target-info">
|
||||||
|
<span class="dashboard-target-icon">⭐</span>
|
||||||
|
<div>
|
||||||
|
<div class="dashboard-target-name">${escapeHtml(target.name)} ${statusBadge}</div>
|
||||||
|
${deviceName ? `<div class="dashboard-target-subtitle">${typeIcon} ${escapeHtml(deviceName)}</div>` : `<div class="dashboard-target-subtitle">${typeIcon}</div>`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dashboard-target-actions">
|
||||||
|
<button class="btn btn-icon ${isRunning ? 'btn-warning' : 'btn-success'}" onclick="${isRunning ? `dashboardStopTarget('${target.id}')` : `dashboardStartTarget('${target.id}')`}" title="${isRunning ? t('device.stop') : t('device.start')}">
|
||||||
|
${isRunning ? '⏹' : '▶'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
dynamicHtml += `<div class="dashboard-section">
|
||||||
|
${_sectionHeader('autostart', t('autostart.title'), autoStartTargets.length)}
|
||||||
|
${_sectionContent('autostart', autoStartItems)}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
if (profiles.length > 0) {
|
if (profiles.length > 0) {
|
||||||
const activeProfiles = profiles.filter(p => p.is_active);
|
const activeProfiles = profiles.filter(p => p.is_active);
|
||||||
const inactiveProfiles = profiles.filter(p => !p.is_active);
|
const inactiveProfiles = profiles.filter(p => !p.is_active);
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ export function createKCTargetCard(target, sourceMap, patternTemplateMap, valueS
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="card" data-kc-target-id="${target.id}">
|
<div class="card" data-kc-target-id="${target.id}">
|
||||||
|
<div class="card-top-actions">
|
||||||
|
<button class="card-autostart-btn${target.auto_start ? ' active' : ''}" onclick="toggleTargetAutoStart('${target.id}', ${!target.auto_start})" title="${target.auto_start ? t('autostart.toggle.enabled') : t('autostart.toggle.disabled')}">★</button>
|
||||||
<button class="card-remove-btn" onclick="deleteKCTarget('${target.id}')" title="${t('common.delete')}">✕</button>
|
<button class="card-remove-btn" onclick="deleteKCTarget('${target.id}')" title="${t('common.delete')}">✕</button>
|
||||||
|
</div>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
${escapeHtml(target.name)}
|
${escapeHtml(target.name)}
|
||||||
|
|||||||
@@ -689,7 +689,10 @@ export function createTargetCard(target, deviceMap, colorStripSourceMap, valueSo
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="card" data-target-id="${target.id}">
|
<div class="card" data-target-id="${target.id}">
|
||||||
|
<div class="card-top-actions">
|
||||||
|
<button class="card-autostart-btn${target.auto_start ? ' active' : ''}" onclick="toggleTargetAutoStart('${target.id}', ${!target.auto_start})" title="${target.auto_start ? t('autostart.toggle.enabled') : t('autostart.toggle.disabled')}">★</button>
|
||||||
<button class="card-remove-btn" onclick="deleteTarget('${target.id}')" title="${t('common.delete')}">✕</button>
|
<button class="card-remove-btn" onclick="deleteTarget('${target.id}')" title="${t('common.delete')}">✕</button>
|
||||||
|
</div>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<span class="health-dot ${healthClass}" title="${healthTitle}"></span>
|
<span class="health-dot ${healthClass}" title="${healthTitle}"></span>
|
||||||
@@ -884,6 +887,25 @@ export async function cloneTarget(targetId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function toggleTargetAutoStart(targetId, enable) {
|
||||||
|
try {
|
||||||
|
const response = await fetchWithAuth(`/picture-targets/${targetId}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ auto_start: enable }),
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
showToast(t(enable ? 'autostart.toggle.enabled' : 'autostart.toggle.disabled'), 'success');
|
||||||
|
loadTargetsTab();
|
||||||
|
} else {
|
||||||
|
const error = await response.json();
|
||||||
|
showToast(`Failed: ${error.detail}`, 'error');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to toggle auto-start:', error);
|
||||||
|
showToast('Failed to toggle auto-start', 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function deleteTarget(targetId) {
|
export async function deleteTarget(targetId) {
|
||||||
const confirmed = await showConfirm(t('targets.delete.confirm'));
|
const confirmed = await showConfirm(t('targets.delete.confirm'));
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
|
|||||||
@@ -552,6 +552,10 @@
|
|||||||
"profiles.error.name_required": "Name is required",
|
"profiles.error.name_required": "Name is required",
|
||||||
"profiles.toggle_all.start": "Start all targets",
|
"profiles.toggle_all.start": "Start all targets",
|
||||||
"profiles.toggle_all.stop": "Stop all targets",
|
"profiles.toggle_all.stop": "Stop all targets",
|
||||||
|
"autostart.title": "Auto-start Targets",
|
||||||
|
"autostart.toggle.enabled": "Auto-start enabled",
|
||||||
|
"autostart.toggle.disabled": "Auto-start disabled",
|
||||||
|
"autostart.goto_target": "Go to target",
|
||||||
"time.hours_minutes": "{h}h {m}m",
|
"time.hours_minutes": "{h}h {m}m",
|
||||||
"time.minutes_seconds": "{m}m {s}s",
|
"time.minutes_seconds": "{m}m {s}s",
|
||||||
"time.seconds": "{s}s",
|
"time.seconds": "{s}s",
|
||||||
|
|||||||
@@ -552,6 +552,10 @@
|
|||||||
"profiles.error.name_required": "Введите название",
|
"profiles.error.name_required": "Введите название",
|
||||||
"profiles.toggle_all.start": "Запустить все цели",
|
"profiles.toggle_all.start": "Запустить все цели",
|
||||||
"profiles.toggle_all.stop": "Остановить все цели",
|
"profiles.toggle_all.stop": "Остановить все цели",
|
||||||
|
"autostart.title": "Автозапуск целей",
|
||||||
|
"autostart.toggle.enabled": "Автозапуск включён",
|
||||||
|
"autostart.toggle.disabled": "Автозапуск отключён",
|
||||||
|
"autostart.goto_target": "Перейти к цели",
|
||||||
"time.hours_minutes": "{h}ч {m}м",
|
"time.hours_minutes": "{h}ч {m}м",
|
||||||
"time.minutes_seconds": "{m}м {s}с",
|
"time.minutes_seconds": "{m}м {s}с",
|
||||||
"time.seconds": "{s}с",
|
"time.seconds": "{s}с",
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ class KeyColorsPictureTarget(PictureTarget):
|
|||||||
|
|
||||||
def update_fields(self, *, name=None, device_id=None, picture_source_id=None,
|
def update_fields(self, *, name=None, device_id=None, picture_source_id=None,
|
||||||
settings=None, key_colors_settings=None, description=None,
|
settings=None, key_colors_settings=None, description=None,
|
||||||
**_kwargs) -> None:
|
auto_start=None, **_kwargs) -> None:
|
||||||
"""Apply mutable field updates for KC targets."""
|
"""Apply mutable field updates for KC targets."""
|
||||||
super().update_fields(name=name, description=description)
|
super().update_fields(name=name, description=description, auto_start=auto_start)
|
||||||
if picture_source_id is not None:
|
if picture_source_id is not None:
|
||||||
self.picture_source_id = picture_source_id
|
self.picture_source_id = picture_source_id
|
||||||
if key_colors_settings is not None:
|
if key_colors_settings is not None:
|
||||||
@@ -130,6 +130,7 @@ class KeyColorsPictureTarget(PictureTarget):
|
|||||||
picture_source_id=data.get("picture_source_id", ""),
|
picture_source_id=data.get("picture_source_id", ""),
|
||||||
settings=settings,
|
settings=settings,
|
||||||
description=data.get("description"),
|
description=data.get("description"),
|
||||||
|
auto_start=data.get("auto_start", False),
|
||||||
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
|
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
|
||||||
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
|
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class PictureTarget:
|
|||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
|
auto_start: bool = False
|
||||||
|
|
||||||
def register_with_manager(self, manager) -> None:
|
def register_with_manager(self, manager) -> None:
|
||||||
"""Register this target with the processor manager. Subclasses override."""
|
"""Register this target with the processor manager. Subclasses override."""
|
||||||
@@ -25,12 +26,15 @@ class PictureTarget:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def update_fields(self, *, name=None, device_id=None, picture_source_id=None,
|
def update_fields(self, *, name=None, device_id=None, picture_source_id=None,
|
||||||
settings=None, key_colors_settings=None, description=None) -> None:
|
settings=None, key_colors_settings=None, description=None,
|
||||||
|
auto_start=None) -> None:
|
||||||
"""Apply mutable field updates. Base handles common fields; subclasses handle type-specific ones."""
|
"""Apply mutable field updates. Base handles common fields; subclasses handle type-specific ones."""
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
if description is not None:
|
if description is not None:
|
||||||
self.description = description
|
self.description = description
|
||||||
|
if auto_start is not None:
|
||||||
|
self.auto_start = auto_start
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_picture_source(self) -> bool:
|
def has_picture_source(self) -> bool:
|
||||||
@@ -44,6 +48,7 @@ class PictureTarget:
|
|||||||
"name": self.name,
|
"name": self.name,
|
||||||
"target_type": self.target_type,
|
"target_type": self.target_type,
|
||||||
"description": self.description,
|
"description": self.description,
|
||||||
|
"auto_start": self.auto_start,
|
||||||
"created_at": self.created_at.isoformat(),
|
"created_at": self.created_at.isoformat(),
|
||||||
"updated_at": self.updated_at.isoformat(),
|
"updated_at": self.updated_at.isoformat(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ class PictureTargetStore:
|
|||||||
key_colors_settings: Optional[KeyColorsSettings] = None,
|
key_colors_settings: Optional[KeyColorsSettings] = None,
|
||||||
description: Optional[str] = None,
|
description: Optional[str] = None,
|
||||||
picture_source_id: str = "",
|
picture_source_id: str = "",
|
||||||
|
auto_start: bool = False,
|
||||||
) -> PictureTarget:
|
) -> PictureTarget:
|
||||||
"""Create a new picture target.
|
"""Create a new picture target.
|
||||||
|
|
||||||
@@ -138,6 +139,7 @@ class PictureTargetStore:
|
|||||||
keepalive_interval=keepalive_interval,
|
keepalive_interval=keepalive_interval,
|
||||||
state_check_interval=state_check_interval,
|
state_check_interval=state_check_interval,
|
||||||
description=description,
|
description=description,
|
||||||
|
auto_start=auto_start,
|
||||||
created_at=now,
|
created_at=now,
|
||||||
updated_at=now,
|
updated_at=now,
|
||||||
)
|
)
|
||||||
@@ -149,6 +151,7 @@ class PictureTargetStore:
|
|||||||
picture_source_id=picture_source_id,
|
picture_source_id=picture_source_id,
|
||||||
settings=key_colors_settings or KeyColorsSettings(),
|
settings=key_colors_settings or KeyColorsSettings(),
|
||||||
description=description,
|
description=description,
|
||||||
|
auto_start=auto_start,
|
||||||
created_at=now,
|
created_at=now,
|
||||||
updated_at=now,
|
updated_at=now,
|
||||||
)
|
)
|
||||||
@@ -173,6 +176,7 @@ class PictureTargetStore:
|
|||||||
state_check_interval: Optional[int] = None,
|
state_check_interval: Optional[int] = None,
|
||||||
key_colors_settings: Optional[KeyColorsSettings] = None,
|
key_colors_settings: Optional[KeyColorsSettings] = None,
|
||||||
description: Optional[str] = None,
|
description: Optional[str] = None,
|
||||||
|
auto_start: Optional[bool] = None,
|
||||||
) -> PictureTarget:
|
) -> PictureTarget:
|
||||||
"""Update a picture target.
|
"""Update a picture target.
|
||||||
|
|
||||||
@@ -200,6 +204,7 @@ class PictureTargetStore:
|
|||||||
state_check_interval=state_check_interval,
|
state_check_interval=state_check_interval,
|
||||||
key_colors_settings=key_colors_settings,
|
key_colors_settings=key_colors_settings,
|
||||||
description=description,
|
description=description,
|
||||||
|
auto_start=auto_start,
|
||||||
)
|
)
|
||||||
|
|
||||||
target.updated_at = datetime.utcnow()
|
target.updated_at = datetime.utcnow()
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ class WledPictureTarget(PictureTarget):
|
|||||||
def update_fields(self, *, name=None, device_id=None, color_strip_source_id=None,
|
def update_fields(self, *, name=None, device_id=None, color_strip_source_id=None,
|
||||||
brightness_value_source_id=None,
|
brightness_value_source_id=None,
|
||||||
fps=None, keepalive_interval=None, state_check_interval=None,
|
fps=None, keepalive_interval=None, state_check_interval=None,
|
||||||
description=None, **_kwargs) -> None:
|
description=None, auto_start=None, **_kwargs) -> None:
|
||||||
"""Apply mutable field updates for WLED targets."""
|
"""Apply mutable field updates for WLED targets."""
|
||||||
super().update_fields(name=name, description=description)
|
super().update_fields(name=name, description=description, auto_start=auto_start)
|
||||||
if device_id is not None:
|
if device_id is not None:
|
||||||
self.device_id = device_id
|
self.device_id = device_id
|
||||||
if color_strip_source_id is not None:
|
if color_strip_source_id is not None:
|
||||||
@@ -109,6 +109,7 @@ class WledPictureTarget(PictureTarget):
|
|||||||
keepalive_interval=data.get("keepalive_interval", data.get("standby_interval", 1.0)),
|
keepalive_interval=data.get("keepalive_interval", data.get("standby_interval", 1.0)),
|
||||||
state_check_interval=data.get("state_check_interval", DEFAULT_STATE_CHECK_INTERVAL),
|
state_check_interval=data.get("state_check_interval", DEFAULT_STATE_CHECK_INTERVAL),
|
||||||
description=data.get("description"),
|
description=data.get("description"),
|
||||||
|
auto_start=data.get("auto_start", False),
|
||||||
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
|
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
|
||||||
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
|
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user