phlyght/phlyght/models.py

580 lines
15 KiB
Python
Raw Normal View History

2022-11-29 23:14:56 +00:00
from typing import (
Any as _Any,
Literal,
Optional as _Optional,
Generic as _Generic,
TypeAlias as _TypeAlias,
TypeVar as _TypeVar,
)
from uuid import UUID as _UUID
from dataclasses import dataclass as _dataclass
from enum import Enum as _Enum, auto as _auto
2022-11-29 23:14:56 +00:00
from pydantic import BaseModel as _BaseModel, Field as _Field
2022-11-28 08:54:10 +00:00
__all__ = (
2022-11-29 23:14:56 +00:00
"_Archetype",
"_RoomType",
2022-11-28 08:54:10 +00:00
"Room",
"Light",
"Scene",
"Zone",
"BridgeHome",
"GroupedLight",
"Device",
"Bridge",
"DevicePower",
"ZigbeeConnectivity",
"ZGPConnectivity",
"Motion",
"Temperature",
"LightLevel",
"Button",
"BehaviorScript",
"BehaviorInstance",
"GeofenceClient",
"Geolocation",
"EntertainmentConfiguration",
2022-11-28 10:48:43 +00:00
"Entertainment",
"Resource",
"Homekit",
2022-11-28 08:54:10 +00:00
)
2022-11-29 23:14:56 +00:00
_T_M: _TypeAlias = "_RoomType | _Archetype | Room | Light | Scene | Zone | BridgeHome | GroupedLight | Device | Bridge | DevicePower | ZigbeeConnectivity | ZGPConnectivity | Motion | Temperature | LightLevel | Button | BehaviorScript | BehaviorInstance | GeofenceClient | Geolocation | EntertainmentConfiguration | Entertainment | Resource | Homekit"
2022-11-28 10:48:43 +00:00
2022-11-29 23:14:56 +00:00
_T = _TypeVar("_T")
2022-11-29 23:14:56 +00:00
class _RoomType(_Enum):
2022-11-28 10:48:43 +00:00
@staticmethod
def _generate_next_value_(name, start, count, last_values):
return name.lower()
2022-11-29 23:14:56 +00:00
LIVING_ROOM = _auto()
KITCHEN = _auto()
DINING = _auto()
BEDROOM = _auto()
KIDS_BEDROOM = _auto()
BATHROOM = _auto()
NURSERY = _auto()
RECREATION = _auto()
OFFICE = _auto()
GYM = _auto()
HALLWAY = _auto()
TOILET = _auto()
FRONT_DOOR = _auto()
GARAGE = _auto()
TERRACE = _auto()
GARDEN = _auto()
DRIVEWAY = _auto()
CARPORT = _auto()
HOME = _auto()
DOWNSTAIRS = _auto()
UPSTAIRS = _auto()
TOP_FLOOR = _auto()
ATTIC = _auto()
GUEST_ROOM = _auto()
STAIRCASE = _auto()
LOUNGE = _auto()
MAN_CAVE = _auto()
COMPUTER = _auto()
STUDIO = _auto()
MUSIC = _auto()
TV = _auto()
READING = _auto()
CLOSET = _auto()
STORAGE = _auto()
LAUNDRY_ROOM = _auto()
BALCONY = _auto()
PORCH = _auto()
BARBECUE = _auto()
POOL = _auto()
OTHER = _auto()
class _Archetype(_Enum):
@staticmethod
def _generate_next_value_(name, start, count, last_values):
return name.lower()
2022-11-29 23:14:56 +00:00
BRIDGE_V2 = _auto()
UNKNOWN_ARCHETYPE = _auto()
CLASSIC_BULB = _auto()
SULTAN_BULB = _auto()
FLOOD_BULB = _auto()
SPOT_BULB = _auto()
CANDLE_BULB = _auto()
LUSTER_BULB = _auto()
PENDANT_ROUND = _auto()
PENDANT_LONG = _auto()
CEILING_ROUND = _auto()
CEILING_SQUARE = _auto()
FLOOR_SHADE = _auto()
FLOOR_LANTERN = _auto()
TABLE_SHADE = _auto()
RECESSED_CEILING = _auto()
RECESSED_FLOOR = _auto()
SINGLE_SPOT = _auto()
DOUBLE_SPOT = _auto()
TABLE_WASH = _auto()
WALL_LANTERN = _auto()
WALL_SHADE = _auto()
FLEXIBLE_LAMP = _auto()
GROUND_SPOT = _auto()
WALL_SPOT = _auto()
PLUG = _auto()
HUE_GO = _auto()
HUE_LIGHTSTRIP = _auto()
HUE_IRIS = _auto()
HUE_BLOOM = _auto()
BOLLARD = _auto()
WALL_WASHER = _auto()
HUE_PLAY = _auto()
VINTAGE_BULB = _auto()
CHRISTMAS_TREE = _auto()
HUE_CENTRIS = _auto()
HUE_LIGHTSTRIP_TV = _auto()
HUE_TUBE = _auto()
HUE_SIGNE = _auto()
@_dataclass
2022-11-28 08:54:10 +00:00
class _Dimming:
brightness: float
2022-11-29 23:14:56 +00:00
min_dim_level: _Optional[float] = _Field(0, repr=False)
2022-11-29 23:14:56 +00:00
@_dataclass
2022-11-28 08:54:10 +00:00
class _XY:
x: float
y: float
2022-11-28 04:03:57 +00:00
2022-11-29 23:14:56 +00:00
@_dataclass
2022-11-28 08:54:10 +00:00
class _On:
2022-11-29 23:14:56 +00:00
on: bool = _Field(..., alias="on")
2022-11-28 04:03:57 +00:00
2022-11-29 23:14:56 +00:00
@_dataclass
2022-11-28 08:54:10 +00:00
class _ColorPoint:
xy: _XY
2022-11-28 04:03:57 +00:00
2022-11-29 23:14:56 +00:00
@_dataclass(frozen=True)
2022-11-28 08:54:10 +00:00
class _Identifier:
rid: str
rtype: str
2022-11-28 04:03:57 +00:00
2022-11-29 23:14:56 +00:00
@_dataclass(frozen=True)
2022-11-28 08:54:10 +00:00
class _Metadata:
name: str
2022-11-29 23:14:56 +00:00
archetype: _Optional[_Archetype | _RoomType] = _Archetype.UNKNOWN_ARCHETYPE
image: _Optional[_Identifier] = _Field(None, repr=False)
2022-11-28 08:54:10 +00:00
class _HueGroupedMeta(type):
def update(cls):
for v in cls.__dict__.values():
if hasattr(v, "update_forward_refs"):
v.update_forward_refs()
2022-11-28 08:54:10 +00:00
class _HueGrouped(metaclass=_HueGroupedMeta):
...
2022-11-28 08:54:10 +00:00
class _Lights(_HueGrouped):
2022-11-29 23:14:56 +00:00
class ColorTemperature(_BaseModel):
mirek: _Optional[int]
2022-11-28 04:03:57 +00:00
mirek_valid: bool
mirek_schema: dict[str, float]
2022-11-28 04:03:57 +00:00
2022-11-29 23:14:56 +00:00
class Gamut(_BaseModel):
2022-11-28 08:54:10 +00:00
red: _XY
green: _XY
blue: _XY
2022-11-28 04:03:57 +00:00
2022-11-29 23:14:56 +00:00
class Color(_BaseModel):
xy: _XY = _Field(None)
gamut: "_Lights.Gamut" = _Field(None)
gamut_type: Literal["A", "B", "C"] = _Field(None)
class Dynamics(_BaseModel):
status: str = _Field(None)
status_values: list[str] = _Field(None)
speed: float = _Field(None)
speed_valid: bool = _Field(None)
class Gradient(_BaseModel):
points: list[_ColorPoint] = _Field([])
points_capable: int = _Field(0)
class Effects(_BaseModel):
effect: _Optional[list[str]] = _Field(repr=False)
status_values: list[str] = _Field(repr=False)
status: str = _Field("")
effect_values: list[str] = _Field(repr=False)
class TimedEffects(_BaseModel):
effect: str = _Field("")
duration: int = _Field(0)
status_values: list[str] = _Field(repr=False)
status: str = _Field("")
effect_values: list[str] = _Field(repr=False)
class Light(_Generic[_T], _BaseModel):
id: _UUID
id_v1: _Optional[str] = _Field(
2022-11-28 10:48:43 +00:00
..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
)
2022-11-29 23:14:56 +00:00
owner: _Optional[_Identifier]
metadata: _Optional[_Metadata]
on: _Optional[_On] = _Field(repr=False)
dimming: _Optional[_Dimming]
dimming_delta: _Optional[dict]
color_temperature: _Optional["_Lights.ColorTemperature"]
color_temperature_delta: _Optional[dict]
color: _Optional["_Lights.Color"]
gradient: _Optional["_Lights.Gradient"]
dynamics: _Optional["_Lights.Dynamics"]
alert: _Optional[dict[str, list[str]]]
signaling: _Optional[dict]
mode: _Optional[str]
effects: _Optional["_Lights.Effects"]
type: Literal["light"] = "light"
_Lights.update()
2022-11-28 08:54:10 +00:00
class _Scenes(_HueGrouped):
2022-11-29 23:14:56 +00:00
class Action(_BaseModel):
on: _Optional[_On]
dimming: _Optional[_Dimming]
color: _Optional[_ColorPoint]
color_temperature: _Optional[dict[str, float]]
gradient: _Optional[dict[str, list[_ColorPoint]]]
effects: _Optional[dict[str, str]]
dynamics: _Optional[dict[str, float]]
class Actions(_BaseModel):
2022-11-28 08:54:10 +00:00
target: _Identifier
2022-11-29 23:14:56 +00:00
action: "_Scenes.Action" = _Field(repr=False)
dimming: _Optional[_Dimming]
color: _Optional[_ColorPoint]
2022-11-29 23:14:56 +00:00
class PaletteColor(_BaseModel):
2022-11-28 08:54:10 +00:00
color: _ColorPoint
dimming: _Dimming
2022-11-29 23:14:56 +00:00
class PaletteTemperature(_BaseModel):
color_temperature: dict[str, float]
2022-11-28 08:54:10 +00:00
dimming: _Dimming
2022-11-29 23:14:56 +00:00
class Palette(_BaseModel):
color: list["_Scenes.PaletteColor"]
2022-11-29 23:14:56 +00:00
dimming: _Optional[list[_Dimming]]
color_temperature: list["_Scenes.PaletteTemperature"]
2022-11-29 23:14:56 +00:00
class Scene(_BaseModel):
id: _UUID
id_v1: _Optional[str] = _Field(
2022-11-28 10:48:43 +00:00
..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
)
2022-11-28 08:54:10 +00:00
metadata: _Metadata
group: _Identifier
actions: list["_Scenes.Actions"]
palette: "_Scenes.Palette"
speed: float
auto_dynamic: bool
2022-11-29 23:14:56 +00:00
type: Literal["scene"] = "scene"
_Scenes.update()
2022-11-29 23:14:56 +00:00
class Room(_BaseModel):
type: Literal["room"] = "room"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
services: list[_Identifier]
metadata: _Metadata
children: list[_Identifier]
2022-11-29 23:14:56 +00:00
class Zone(_BaseModel):
type: Literal["zone"] = "zone"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
services: list[_Identifier]
metadata: _Metadata
children: list[_Identifier]
2022-11-29 23:14:56 +00:00
class BridgeHome(_BaseModel):
type: Literal["bridge_home"] = "bridge_home"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
services: list[_Identifier]
children: list[_Identifier]
2022-11-29 23:14:56 +00:00
class GroupedLight(_BaseModel):
type: Literal["grouped_light"] = "grouped_light"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
on: _On = _Field(repr=False)
2022-11-28 10:48:43 +00:00
alert: dict[str, list[str]]
2022-11-29 23:14:56 +00:00
class _ProductData(_BaseModel):
model_id: str
manufacturer_name: str
product_name: str
2022-11-29 23:14:56 +00:00
product_archetype: _Archetype
certified: bool
2022-11-29 23:14:56 +00:00
software_version: _Optional[str]
hardware_platform_type: _Optional[str]
2022-11-29 23:14:56 +00:00
class Device(_BaseModel):
type: Literal["device"] = "device"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
services: list[_Identifier]
metadata: _Metadata
product_data: _ProductData
2022-11-29 23:14:56 +00:00
class Bridge(_BaseModel):
type: Literal["bridge"] = "bridge"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
bridge_id: str
time_zone: dict[str, str]
2022-11-29 23:14:56 +00:00
class _PowerState(_BaseModel):
battery_state: Literal["normal", "low", "critical"]
2022-11-29 23:14:56 +00:00
battery_level: float = _Field(le=100.0, ge=0.0)
2022-11-29 23:14:56 +00:00
class DevicePower(_BaseModel):
type: Literal["device_power"] = "device_power"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
owner: _Identifier
power_state: _PowerState
2022-11-29 23:14:56 +00:00
class ZigbeeConnectivity(_BaseModel):
type: Literal["zigbee_connectivity"] = "zigbee_connectivity"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
owner: _Identifier
status: Literal[
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
]
mac_address: str
2022-11-29 23:14:56 +00:00
class ZGPConnectivity(_BaseModel):
type: Literal["zgp_connectivity"] = "zgp_connectivity"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
owner: _Identifier
status: Literal[
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
]
source_id: str
2022-11-29 23:14:56 +00:00
class Motion(_BaseModel):
type: Literal["motion"] = "motion"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
owner: _Identifier
enabled: bool
motion: dict[str, bool]
2022-11-29 23:14:56 +00:00
class _Temp(_BaseModel):
temperature: float = _Field(lt=100.0, gt=-100.0)
temperature_valid: bool
2022-11-29 23:14:56 +00:00
class Temperature(_BaseModel):
type: Literal["temperature"] = "temperature"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
owner: _Identifier
2022-11-29 23:14:56 +00:00
enabled: _Optional[bool]
temperature: _Temp
2022-11-29 23:14:56 +00:00
class _Light(_BaseModel):
light_level: _Optional[int]
light_level_valid: _Optional[bool]
2022-11-29 23:14:56 +00:00
class LightLevel(_BaseModel):
type: Literal["light_level"] = "light_level"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: _Optional[_Identifier]
enabled: _Optional[bool]
light: _Optional[_Light]
2022-11-29 23:14:56 +00:00
class Button(_BaseModel):
type: Literal["button"] = "button"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 08:54:10 +00:00
owner: _Identifier
metadata: dict[Literal["control_id"], int]
button: dict[
Literal["last_event"],
Literal[
"initial_press",
"repeat",
"short_release",
"long_release",
"double_short_release",
],
]
2022-11-29 23:14:56 +00:00
class BehaviorScript(_BaseModel):
type: Literal["behavior_script"] = "behavior_script"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
description: str
2022-11-29 23:14:56 +00:00
configuration_schema: dict[str, _Any]
trigger_schema: dict[str, _Any]
state_schema: dict[str, _Any]
version: str
metadata: dict[str, str]
2022-11-29 23:14:56 +00:00
class _Dependee(_BaseModel):
type: str
2022-11-28 08:54:10 +00:00
target: _Identifier
level: str
2022-11-29 23:14:56 +00:00
class BehaviorInstance(_BaseModel):
type: Literal["behavior_instance"] = "behavior_instance"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
script_id: str
enabled: bool
2022-11-29 23:14:56 +00:00
state: _Optional[dict[str, _Any]]
configuration: dict[str, _Any]
2022-11-28 08:54:10 +00:00
dependees: list[_Dependee]
status: Literal["initializing", "running", "disabled", "errored"]
last_error: str
metadata: dict[Literal["name"], str]
2022-11-29 23:14:56 +00:00
migrated_from: _Optional[str] = None
2022-11-29 23:14:56 +00:00
class GeofenceClient(_BaseModel):
type: Literal["geofence_client"] = "geofence_client"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
name: str
2022-11-29 23:14:56 +00:00
class Geolocation(_BaseModel):
type: Literal["geolocation"] = "geolocation"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
is_configured: bool = False
2022-11-29 23:14:56 +00:00
class _StreamProxy(_BaseModel):
mode: Literal["auto", "manual"]
2022-11-28 08:54:10 +00:00
node: _Identifier
2022-11-29 23:14:56 +00:00
class _XYZ(_BaseModel):
x: float = _Field(ge=-1.0, le=1.0)
y: float = _Field(ge=-1.0, le=1.0)
z: float = _Field(ge=-1.0, le=1.0)
2022-11-28 10:48:43 +00:00
2022-11-29 23:14:56 +00:00
class _SegmentRef(_BaseModel):
2022-11-28 10:48:43 +00:00
service: _Identifier
index: int
2022-11-29 23:14:56 +00:00
class _EntertainmentChannel(_BaseModel):
channel_id: int = _Field(ge=0, le=255)
2022-11-28 10:48:43 +00:00
position: _XYZ
members: list[_SegmentRef]
2022-11-29 23:14:56 +00:00
class _ServiceLocation(_BaseModel):
2022-11-28 10:48:43 +00:00
service: _Identifier
position: _XYZ
2022-11-29 23:14:56 +00:00
positions: list[_XYZ] = _Field(max_items=2, min_items=1)
2022-11-28 10:48:43 +00:00
2022-11-29 23:14:56 +00:00
class _EntertainmentLocation(_BaseModel):
service_location: _Optional[list[_ServiceLocation]] = []
2022-11-28 10:48:43 +00:00
2022-11-29 23:14:56 +00:00
class EntertainmentConfiguration(_BaseModel):
type: Literal["entertainment_configuration"] = "entertainment_configuration"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
metadata: dict[Literal["name"], str]
2022-11-29 23:14:56 +00:00
name: _Optional[str] = ""
configuration_type: Literal["screen", "monitor", "music", "3dspace", "other"]
status: Literal["active", "inactive"]
2022-11-29 23:14:56 +00:00
active_streamer: _Optional[_Identifier] = None
2022-11-28 08:54:10 +00:00
stream_proxy: _StreamProxy
2022-11-28 10:48:43 +00:00
channels: list[_EntertainmentChannel]
2022-11-29 23:14:56 +00:00
locations: _Optional[_EntertainmentLocation] = None
2022-11-28 10:48:43 +00:00
light_services: list[_Identifier]
2022-11-29 23:14:56 +00:00
class _Segment(_BaseModel):
start: int = _Field(..., ge=0)
length: int = _Field(..., ge=1)
2022-11-28 10:48:43 +00:00
2022-11-29 23:14:56 +00:00
class _SegmentManager(_BaseModel):
2022-11-28 10:48:43 +00:00
configurable: bool
2022-11-29 23:14:56 +00:00
max_segments: int = _Field(..., ge=1)
2022-11-28 10:48:43 +00:00
segments: list[_Segment]
2022-11-29 23:14:56 +00:00
class Entertainment(_BaseModel):
type: Literal["entertainment"] = "entertainment"
id: _UUID
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 10:48:43 +00:00
owner: _Identifier
renderer: bool
proxy: bool
2022-11-29 23:14:56 +00:00
max_streams: _Optional[int] = _Field(1, ge=1)
segments: _Optional[_SegmentManager] = None
2022-11-29 23:14:56 +00:00
class Homekit(_BaseModel):
id: _UUID
type: _Optional[str] = "resource"
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 10:48:43 +00:00
status: Literal["paired", "pairing", "unpaired"]
2022-11-29 23:14:56 +00:00
class Resource(_BaseModel):
id: _UUID
type: _Optional[str] = "device"
id_v1: _Optional[str] = _Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
2022-11-28 04:03:57 +00:00
Light = _Lights.Light
Scene = _Scenes.Scene