greendeck/greendeck/config.py
2023-08-30 16:56:45 -05:00

144 lines
3.6 KiB
Python

from typing import Annotated
from typing import Literal
from typing import Union
from pydantic import BaseModel
from pydantic import Field
from pydantic import ValidationError
from pydantic import root_validator
from pydantic import validator
from pydantic.color import Color
# from pydantic_yaml import YamlModel
from typing_extensions import Self
class HomeAssistantConfig(BaseModel):
token: str
hostname: str
port: int | None
secure: bool = True
@validator("port")
def check_port(cls, v):
if v <= 0 or v >= 65536:
raise ValidationError("port must be greater than 0 and less than 65536")
return v
class StreamDeckConfig(BaseModel):
index: int | None
serial_number: str | None
brightness: int | float
screensaver: int
screen: str
@root_validator
def check_index_serial_number(cls: type[Self], values: dict):
index = values.get("index")
serial_number = values.get("serial_number")
if index is None and serial_number is None:
raise ValidationError("must set either index or serial_number")
if index is not None and serial_number is not None:
raise ValidationError("cannot set both index and serial_number")
return values
@validator("brightness")
def check_brightness(cls: type[Self], v: int | float) -> int | float:
if isinstance(v, int):
if v < 0 or v > 100:
raise ValidationError("brightness")
return v
if isinstance(v, float):
if v < 0.0 or v > 1.0:
raise ValidationError("brightness")
return v
raise ValidationError("brightness must be an int or a float")
class ColorConfig(BaseModel):
foreground: Color
background: Color
# class HomeAssistantIconImageStateConfig(BaseModel):
# state: str | None
# icon: str
# up: ColorConfig
# down: ColorConfig
class ImageConfig(BaseModel):
icon: str
up: ColorConfig
down: ColorConfig
class HomeAssistantIconImageConfig(BaseModel):
type: Literal["homeassistant-icon"]
entity_id: str
states: dict[str | None, ImageConfig]
@root_validator
def check_states(cls: type[Self], values: dict) -> dict:
states = values.get("states")
if None not in states:
raise ValidationError("must define default state by using '~' in yaml")
return values
class StaticIconImageConfig(ImageConfig):
type: Literal["static-icon"]
# icon: str
# up: ColorConfig
# down: ColorConfig
class ImageTextConfig(ImageConfig):
icon: str
text: str
class StaticTextIconImageConfig(ImageTextConfig):
type: Literal["static-icon-text"]
class HomeAssistantServiceActionConfig(BaseModel):
type: Literal["homeassistant-service"]
domain: str
service: str
data: dict
class PulseAudioActionConfig(BaseModel):
type: Literal["pulseaudio-action"]
application_name: str
action: Literal["volume-up", "volume-down", "toggle-mute"]
class ActionConfig(BaseModel):
__root__: Annotated[
Union[HomeAssistantServiceActionConfig, PulseAudioActionConfig],
Field(discriminator="type"),
]
ImageTypes = Annotated[
Union[
StaticIconImageConfig, StaticTextIconImageConfig, HomeAssistantIconImageConfig
],
Field(discriminator="type"),
]
class TileConfig(BaseModel):
position: tuple[int, int]
image: ImageTypes
actions: list[ActionConfig]
class Config(BaseModel):
homeassistant: HomeAssistantConfig
streamdecks: list[StreamDeckConfig]
screens: dict[str, list[TileConfig]]