- Add `tags: List[str]` field to all 13 entity types (devices, output targets, CSS sources, picture sources, audio sources, value sources, sync clocks, automations, scene presets, capture/audio/PP/pattern templates) - Update all stores, schemas, and route handlers for tag CRUD - Add GET /api/v1/tags endpoint aggregating unique tags across all stores - Create TagInput component with chip display, autocomplete dropdown, keyboard navigation, and API-backed suggestions - Display tag chips on all entity cards (searchable via existing text filter) - Add tag input to all 14 editor modals with dirty check support - Add CSS styles and i18n keys (en/ru/zh) for tag UI - Also includes code review fixes: thread safety, perf, store dedup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
83 lines
4.8 KiB
Python
83 lines
4.8 KiB
Python
"""Automation-related schemas."""
|
|
|
|
from datetime import datetime
|
|
from typing import List, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class ConditionSchema(BaseModel):
|
|
"""A single condition within an automation."""
|
|
|
|
condition_type: str = Field(description="Condition type discriminator (e.g. 'application')")
|
|
# Application condition fields
|
|
apps: Optional[List[str]] = Field(None, description="Process names (for application condition)")
|
|
match_type: Optional[str] = Field(None, description="'running' or 'topmost' (for application condition)")
|
|
# Time-of-day condition fields
|
|
start_time: Optional[str] = Field(None, description="Start time HH:MM (for time_of_day condition)")
|
|
end_time: Optional[str] = Field(None, description="End time HH:MM (for time_of_day condition)")
|
|
# System idle condition fields
|
|
idle_minutes: Optional[int] = Field(None, description="Idle timeout in minutes (for system_idle condition)")
|
|
when_idle: Optional[bool] = Field(None, description="True=active when idle (for system_idle condition)")
|
|
# Display state condition fields
|
|
state: Optional[str] = Field(None, description="'on' or 'off' (for display_state condition)")
|
|
# MQTT condition fields
|
|
topic: Optional[str] = Field(None, description="MQTT topic to watch (for mqtt condition)")
|
|
payload: Optional[str] = Field(None, description="Expected payload value (for mqtt condition)")
|
|
match_mode: Optional[str] = Field(None, description="'exact', 'contains', or 'regex' (for mqtt condition)")
|
|
# Webhook condition fields
|
|
token: Optional[str] = Field(None, description="Secret token for webhook URL (for webhook condition)")
|
|
|
|
|
|
class AutomationCreate(BaseModel):
|
|
"""Request to create an automation."""
|
|
|
|
name: str = Field(description="Automation name", min_length=1, max_length=100)
|
|
enabled: bool = Field(default=True, description="Whether the automation is enabled")
|
|
condition_logic: str = Field(default="or", description="How conditions combine: 'or' or 'and'")
|
|
conditions: List[ConditionSchema] = Field(default_factory=list, description="List of conditions")
|
|
scene_preset_id: Optional[str] = Field(None, description="Scene preset to activate")
|
|
deactivation_mode: str = Field(default="none", description="'none', 'revert', or 'fallback_scene'")
|
|
deactivation_scene_preset_id: Optional[str] = Field(None, description="Scene preset for fallback deactivation")
|
|
tags: List[str] = Field(default_factory=list, description="User-defined tags")
|
|
|
|
|
|
class AutomationUpdate(BaseModel):
|
|
"""Request to update an automation."""
|
|
|
|
name: Optional[str] = Field(None, description="Automation name", min_length=1, max_length=100)
|
|
enabled: Optional[bool] = Field(None, description="Whether the automation is enabled")
|
|
condition_logic: Optional[str] = Field(None, description="How conditions combine: 'or' or 'and'")
|
|
conditions: Optional[List[ConditionSchema]] = Field(None, description="List of conditions")
|
|
scene_preset_id: Optional[str] = Field(None, description="Scene preset to activate")
|
|
deactivation_mode: Optional[str] = Field(None, description="'none', 'revert', or 'fallback_scene'")
|
|
deactivation_scene_preset_id: Optional[str] = Field(None, description="Scene preset for fallback deactivation")
|
|
tags: Optional[List[str]] = None
|
|
|
|
|
|
class AutomationResponse(BaseModel):
|
|
"""Automation information response."""
|
|
|
|
id: str = Field(description="Automation ID")
|
|
name: str = Field(description="Automation name")
|
|
enabled: bool = Field(description="Whether the automation is enabled")
|
|
condition_logic: str = Field(description="Condition combination logic")
|
|
conditions: List[ConditionSchema] = Field(description="List of conditions")
|
|
scene_preset_id: Optional[str] = Field(None, description="Scene preset to activate")
|
|
deactivation_mode: str = Field(default="none", description="Deactivation behavior")
|
|
deactivation_scene_preset_id: Optional[str] = Field(None, description="Fallback scene preset")
|
|
tags: List[str] = Field(default_factory=list, description="User-defined tags")
|
|
webhook_url: Optional[str] = Field(None, description="Webhook URL for the first webhook condition (if any)")
|
|
is_active: bool = Field(default=False, description="Whether the automation is currently active")
|
|
last_activated_at: Optional[datetime] = Field(None, description="Last time this automation was activated")
|
|
last_deactivated_at: Optional[datetime] = Field(None, description="Last time this automation was deactivated")
|
|
created_at: datetime = Field(description="Creation timestamp")
|
|
updated_at: datetime = Field(description="Last update timestamp")
|
|
|
|
|
|
class AutomationListResponse(BaseModel):
|
|
"""List of automations response."""
|
|
|
|
automations: List[AutomationResponse] = Field(description="List of automations")
|
|
count: int = Field(description="Number of automations")
|