Remove idle color feature, simplify power to turn-off only, fix settings serial port bug
- Remove static/idle color from entire stack (storage, API, processing, UI, CSS, locales) - Simplify device power button to turn-off only (send black frame, no toggle) - Send black frame on serial port close (AdalightClient.close) - Fix settings modal serial port dropdown showing WLED devices due to stale deviceType Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -100,7 +100,14 @@ class AdalightClient(LEDClient):
|
||||
raise RuntimeError(f"Failed to open serial port {self._port}: {e}")
|
||||
|
||||
async def close(self) -> None:
|
||||
"""Close the serial port."""
|
||||
"""Send black frame and close the serial port."""
|
||||
if self._connected and self._serial and self._serial.is_open and self._led_count > 0:
|
||||
try:
|
||||
black = np.zeros((self._led_count, 3), dtype=np.uint8)
|
||||
frame = self._build_frame(black, brightness=255)
|
||||
await asyncio.to_thread(self._serial.write, frame)
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to send black frame on close: {e}")
|
||||
self._connected = False
|
||||
if self._serial and self._serial.is_open:
|
||||
try:
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
Subclasses only need to override ``device_type`` and ``create_client()``.
|
||||
All common serial-device logic (COM port validation, discovery, health
|
||||
checks, power control via black frames, static colour) lives here.
|
||||
checks, power control via black frames) lives here.
|
||||
"""
|
||||
|
||||
from typing import List, Tuple
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -28,8 +28,7 @@ class SerialDeviceProvider(LEDDeviceProvider):
|
||||
# manual_led_count: user must specify LED count (can't auto-detect)
|
||||
# power_control: can blank LEDs by sending all-black pixels
|
||||
# brightness_control: software brightness (multiplies pixel values before sending)
|
||||
# static_color: can send a solid colour frame
|
||||
return {"manual_led_count", "power_control", "brightness_control", "static_color"}
|
||||
return {"manual_led_count", "power_control", "brightness_control"}
|
||||
|
||||
async def check_health(self, url: str, http_client, prev_health=None) -> DeviceHealth:
|
||||
# Generic serial port health check — enumerate COM ports
|
||||
@@ -116,31 +115,3 @@ class SerialDeviceProvider(LEDDeviceProvider):
|
||||
finally:
|
||||
await client.close()
|
||||
|
||||
async def set_color(self, url: str, color: Tuple[int, int, int], **kwargs) -> None:
|
||||
"""Send a solid color frame to the device.
|
||||
|
||||
Accepts optional kwargs:
|
||||
client: An already-connected LEDClient (e.g. cached idle client).
|
||||
brightness (int): Software brightness 0-255 (default 255).
|
||||
led_count (int), baud_rate (int | None).
|
||||
"""
|
||||
led_count = kwargs.get("led_count", 0)
|
||||
if led_count <= 0:
|
||||
raise ValueError(f"led_count is required to send color frame to {self.device_type} device")
|
||||
|
||||
brightness = kwargs.get("brightness", 255)
|
||||
frame = np.full((led_count, 3), color, dtype=np.uint8)
|
||||
|
||||
existing_client = kwargs.get("client")
|
||||
if existing_client:
|
||||
await existing_client.send_pixels(frame, brightness=brightness)
|
||||
else:
|
||||
baud_rate = kwargs.get("baud_rate")
|
||||
client = self.create_client(url, led_count=led_count, baud_rate=baud_rate)
|
||||
try:
|
||||
await client.connect()
|
||||
await client.send_pixels(frame, brightness=brightness)
|
||||
finally:
|
||||
await client.close()
|
||||
|
||||
logger.info(f"{self.device_type} set_color: sent solid {color} to {url}")
|
||||
|
||||
@@ -47,8 +47,6 @@ class DeviceState:
|
||||
hardware_brightness: Optional[int] = None
|
||||
# Auto-restore: restore device to idle state when targets stop
|
||||
auto_shutdown: bool = False
|
||||
# Static idle color for devices without a rich editor (e.g. Adalight)
|
||||
static_color: Optional[Tuple[int, int, int]] = None
|
||||
# Calibration test mode (works independently of target processing)
|
||||
test_mode_active: bool = False
|
||||
test_mode_edges: Dict[str, Tuple[int, int, int]] = field(default_factory=dict)
|
||||
@@ -159,7 +157,6 @@ class ProcessorManager:
|
||||
baud_rate: Optional[int] = None,
|
||||
software_brightness: int = 255,
|
||||
auto_shutdown: bool = False,
|
||||
static_color: Optional[Tuple[int, int, int]] = None,
|
||||
):
|
||||
"""Register a device for health monitoring."""
|
||||
if device_id in self._devices:
|
||||
@@ -173,7 +170,6 @@ class ProcessorManager:
|
||||
baud_rate=baud_rate,
|
||||
software_brightness=software_brightness,
|
||||
auto_shutdown=auto_shutdown,
|
||||
static_color=static_color,
|
||||
)
|
||||
|
||||
self._devices[device_id] = state
|
||||
@@ -634,22 +630,6 @@ class ProcessorManager:
|
||||
return proc.device_id
|
||||
return None
|
||||
|
||||
async def send_static_color(self, device_id: str, color: Tuple[int, int, int]) -> None:
|
||||
"""Send a solid color to a device via its provider."""
|
||||
ds = self._devices.get(device_id)
|
||||
if not ds:
|
||||
raise ValueError(f"Device {device_id} not found")
|
||||
try:
|
||||
provider = get_provider(ds.device_type)
|
||||
client = await self._get_idle_client(device_id)
|
||||
await provider.set_color(
|
||||
ds.device_url, color,
|
||||
led_count=ds.led_count, baud_rate=ds.baud_rate, client=client,
|
||||
brightness=ds.software_brightness,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send static color for {device_id}: {e}")
|
||||
|
||||
async def clear_device(self, device_id: str) -> None:
|
||||
"""Clear LED output on a device (send black / power off)."""
|
||||
ds = self._devices.get(device_id)
|
||||
@@ -663,9 +643,8 @@ class ProcessorManager:
|
||||
async def _restore_device_idle_state(self, device_id: str) -> None:
|
||||
"""Restore a device to its idle state when all targets stop.
|
||||
|
||||
- If a static color is configured, send it.
|
||||
- For WLED: do nothing — stop() already restored the snapshot.
|
||||
- For other devices without static color: power off (black frame).
|
||||
- For other devices: power off (send black frame).
|
||||
"""
|
||||
ds = self._devices.get(device_id)
|
||||
if not ds or not ds.auto_shutdown:
|
||||
@@ -675,14 +654,7 @@ class ProcessorManager:
|
||||
return
|
||||
|
||||
try:
|
||||
if ds.static_color is not None:
|
||||
await self.send_static_color(device_id, ds.static_color)
|
||||
logger.info(
|
||||
f"Auto-restore: sent static color {ds.static_color} "
|
||||
f"to {ds.device_type} device {device_id}"
|
||||
)
|
||||
elif ds.device_type != "wled":
|
||||
# Non-WLED without static color: power off (send black frame)
|
||||
if ds.device_type != "wled":
|
||||
await self._send_clear_pixels(device_id)
|
||||
logger.info(f"Auto-restore: powered off {ds.device_type} device {device_id}")
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user