Add notification reactive color strip source with webhook trigger
New source_type "notification" fires one-shot visual effects (flash, pulse, sweep) triggered via POST webhook. Designed as a composite layer for overlay on persistent sources. Includes app color mapping, whitelist/blacklist filtering, and auto-sizing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Color strip source schemas (CRUD)."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Literal, Optional
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -49,7 +49,7 @@ class ColorStripSourceCreate(BaseModel):
|
||||
"""Request to create a color strip source."""
|
||||
|
||||
name: str = Field(description="Source name", min_length=1, max_length=100)
|
||||
source_type: Literal["picture", "static", "gradient", "color_cycle", "effect", "composite", "mapped", "audio", "api_input"] = Field(default="picture", description="Source type")
|
||||
source_type: Literal["picture", "static", "gradient", "color_cycle", "effect", "composite", "mapped", "audio", "api_input", "notification"] = Field(default="picture", description="Source type")
|
||||
# picture-type fields
|
||||
picture_source_id: str = Field(default="", description="Picture source ID (for picture type)")
|
||||
brightness: float = Field(default=1.0, description="Brightness multiplier (0.0-2.0)", ge=0.0, le=2.0)
|
||||
@@ -87,6 +87,14 @@ class ColorStripSourceCreate(BaseModel):
|
||||
# api_input-type fields
|
||||
fallback_color: Optional[List[int]] = Field(None, description="Fallback RGB color [R,G,B] when no data received (api_input type)")
|
||||
timeout: Optional[float] = Field(None, description="Seconds before reverting to fallback (api_input type)", ge=0.0, le=300.0)
|
||||
# notification-type fields
|
||||
notification_effect: Optional[str] = Field(None, description="Notification effect: flash|pulse|sweep")
|
||||
duration_ms: Optional[int] = Field(None, ge=100, le=10000, description="Effect duration in milliseconds")
|
||||
default_color: Optional[str] = Field(None, description="Default hex color (#RRGGBB) for notifications")
|
||||
app_colors: Optional[Dict[str, str]] = Field(None, description="Map of app name to hex color (#RRGGBB)")
|
||||
app_filter_mode: Optional[str] = Field(None, description="App filter mode: off|whitelist|blacklist")
|
||||
app_filter_list: Optional[List[str]] = Field(None, description="App names for filter")
|
||||
os_listener: Optional[bool] = Field(None, description="Whether to listen for OS notifications")
|
||||
# sync clock
|
||||
clock_id: Optional[str] = Field(None, description="Optional sync clock ID for synchronized animation")
|
||||
|
||||
@@ -132,6 +140,14 @@ class ColorStripSourceUpdate(BaseModel):
|
||||
# api_input-type fields
|
||||
fallback_color: Optional[List[int]] = Field(None, description="Fallback RGB color [R,G,B] (api_input type)")
|
||||
timeout: Optional[float] = Field(None, description="Timeout before fallback (api_input type)", ge=0.0, le=300.0)
|
||||
# notification-type fields
|
||||
notification_effect: Optional[str] = Field(None, description="Notification effect: flash|pulse|sweep")
|
||||
duration_ms: Optional[int] = Field(None, ge=100, le=10000, description="Effect duration in milliseconds")
|
||||
default_color: Optional[str] = Field(None, description="Default hex color (#RRGGBB)")
|
||||
app_colors: Optional[Dict[str, str]] = Field(None, description="Map of app name to hex color")
|
||||
app_filter_mode: Optional[str] = Field(None, description="App filter mode: off|whitelist|blacklist")
|
||||
app_filter_list: Optional[List[str]] = Field(None, description="App names for filter")
|
||||
os_listener: Optional[bool] = Field(None, description="Whether to listen for OS notifications")
|
||||
# sync clock
|
||||
clock_id: Optional[str] = Field(None, description="Optional sync clock ID for synchronized animation")
|
||||
|
||||
@@ -179,6 +195,14 @@ class ColorStripSourceResponse(BaseModel):
|
||||
# api_input-type fields
|
||||
fallback_color: Optional[List[int]] = Field(None, description="Fallback RGB color [R,G,B] (api_input type)")
|
||||
timeout: Optional[float] = Field(None, description="Timeout before fallback (api_input type)")
|
||||
# notification-type fields
|
||||
notification_effect: Optional[str] = Field(None, description="Notification effect: flash|pulse|sweep")
|
||||
duration_ms: Optional[int] = Field(None, description="Effect duration in milliseconds")
|
||||
default_color: Optional[str] = Field(None, description="Default hex color (#RRGGBB)")
|
||||
app_colors: Optional[Dict[str, str]] = Field(None, description="Map of app name to hex color")
|
||||
app_filter_mode: Optional[str] = Field(None, description="App filter mode: off|whitelist|blacklist")
|
||||
app_filter_list: Optional[List[str]] = Field(None, description="App names for filter")
|
||||
os_listener: Optional[bool] = Field(None, description="Whether to listen for OS notifications")
|
||||
# sync clock
|
||||
clock_id: Optional[str] = Field(None, description="Optional sync clock ID for synchronized animation")
|
||||
overlay_active: bool = Field(False, description="Whether the screen overlay is currently active")
|
||||
@@ -199,6 +223,13 @@ class ColorPushRequest(BaseModel):
|
||||
colors: List[List[int]] = Field(description="LED color array [[R,G,B], ...] (0-255 each)")
|
||||
|
||||
|
||||
class NotifyRequest(BaseModel):
|
||||
"""Request to trigger a notification on a notification color strip source."""
|
||||
|
||||
app: Optional[str] = Field(None, description="App name for color lookup")
|
||||
color: Optional[str] = Field(None, description="Hex color override (#RRGGBB)")
|
||||
|
||||
|
||||
class CSSCalibrationTestRequest(BaseModel):
|
||||
"""Request to run a calibration test for a color strip source on a specific device."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user