Add static color for simple devices, change auto-shutdown to auto-restore

- Add `static_color` capability to Adalight provider with `set_color()` method
- Add `static_color` field to Device model, DeviceState, and API schemas
- Add GET/PUT `/devices/{id}/color` API endpoints
- Change auto-shutdown behavior: restore device to idle state instead of
  powering off (WLED uses snapshot/restore, Adalight sends static color
  or black frame)
- Rename `_auto_shutdown_device_if_idle` to `_restore_device_idle_state`
- Add inline color picker on device cards for devices with static_color
- Add auto_shutdown toggle to device settings modal
- Update labels from "Auto Shutdown" to "Auto Restore" (en + ru)
- Remove backward-compat KC aliases from ProcessorManager
- Align card action buttons to bottom with flex column layout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 13:42:05 +03:00
parent fc779eef39
commit d6cf45c873
13 changed files with 349 additions and 48 deletions

View File

@@ -4,7 +4,7 @@ import json
import uuid
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional
from typing import Dict, List, Optional, Tuple
from wled_controller.core.capture.calibration import (
CalibrationConfig,
@@ -35,6 +35,7 @@ class Device:
baud_rate: Optional[int] = None,
software_brightness: int = 255,
auto_shutdown: bool = False,
static_color: Optional[Tuple[int, int, int]] = None,
calibration: Optional[CalibrationConfig] = None,
created_at: Optional[datetime] = None,
updated_at: Optional[datetime] = None,
@@ -48,6 +49,7 @@ class Device:
self.baud_rate = baud_rate
self.software_brightness = software_brightness
self.auto_shutdown = auto_shutdown
self.static_color = static_color
self.calibration = calibration or create_default_calibration(led_count)
self.created_at = created_at or datetime.utcnow()
self.updated_at = updated_at or datetime.utcnow()
@@ -71,6 +73,8 @@ class Device:
d["software_brightness"] = self.software_brightness
if self.auto_shutdown:
d["auto_shutdown"] = True
if self.static_color is not None:
d["static_color"] = list(self.static_color)
return d
@classmethod
@@ -87,6 +91,9 @@ class Device:
else create_default_calibration(data["led_count"])
)
static_color_raw = data.get("static_color")
static_color = tuple(static_color_raw) if static_color_raw else None
return cls(
device_id=data["id"],
name=data["name"],
@@ -97,6 +104,7 @@ class Device:
baud_rate=data.get("baud_rate"),
software_brightness=data.get("software_brightness", 255),
auto_shutdown=data.get("auto_shutdown", False),
static_color=static_color,
calibration=calibration,
created_at=datetime.fromisoformat(data.get("created_at", datetime.utcnow().isoformat())),
updated_at=datetime.fromisoformat(data.get("updated_at", datetime.utcnow().isoformat())),
@@ -256,6 +264,18 @@ class DeviceStore:
logger.info(f"Updated device {device_id}")
return device
def set_static_color(
self, device_id: str, color: Optional[Tuple[int, int, int]]
) -> "Device":
"""Set or clear the static idle color for a device."""
device = self._devices.get(device_id)
if not device:
raise ValueError(f"Device {device_id} not found")
device.static_color = color
device.updated_at = datetime.utcnow()
self.save()
return device
def delete_device(self, device_id: str):
"""Delete device."""
if device_id not in self._devices: