phlyght/phlyght/models.py

948 lines
31 KiB
Python

from enum import Enum, auto
from typing import Any, ClassVar, Literal, Optional, Type, TypeVar
from uuid import UUID as _UUID
from uuid import uuid4
import ujson
from orjson import dumps as _dumps
from orjson import loads
from pydantic import BaseConfig, BaseModel, Field, validator
from pydantic.dataclasses import dataclass
_type = type
_T = TypeVar("_T")
_D = TypeVar("_D", bound=dict)
__all__ = (
"Entity",
"Archetype",
"RoomType",
"Attributes",
"HueEntsV2",
"HueEntsV1",
"_XY",
)
# mypy: enable-incomplete-feature=TypeVarTuple
Ent = TypeVar("Ent", bound="Entity")
def default_uuid():
return UUID(str(uuid4()))
def config_dumps(obj: Any) -> str:
return ret if isinstance(ret := dumps(obj), str) else ret.decode()
def dumps(obj: Any) -> str:
return _dumps(ret.encode() if isinstance(ret := dumps(obj), str) else ret).decode()
class Config(BaseConfig):
json_loads = loads
# json_dumps = lambda *args, **kwargs: (
# d if isinstance(d := dumps(*args, **kwargs), str) else d.decode()
# )
json_dumps = dumps
smart_union = True
allow_mutations = True
class HueConfig(BaseConfig):
allow_population_by_field_name = True
json_loads = ujson.loads
json_dumps = ujson.dumps
smart_union = True
allow_mutation = True
class UUID(_UUID):
def __json__(self):
return self.__str__()
def validate(*args, **kwargs):
return kwargs
class Entity(BaseModel):
__module__ = "phlyght"
__cache__: ClassVar[dict[str, Type]] = {}
id: Optional[UUID] = Field(
default_factory=lambda: UUID("00000000-0000-0000-0000-000000000000")
)
type: ClassVar[str] = "unknown"
Config = HueConfig
__config__ = HueConfig
@classmethod
def cache_client(cls, client):
Entity.client = client
@classmethod
def get_entities(cls) -> dict[str, Type]:
return cls.__cache__
@classmethod
def get_plural(cls, name):
if name.endswith("y"):
return name[:-1] + "ies"
return name + "s"
def __new__(cls, client=None, **kwargs):
clz = type(cls.__name__, (BaseModel,), {}).__new__(cls)
return clz
async def get(self):
async for ob in getattr(self.client, f"get_{self.type}")(self.id):
yield ob
async def create(self, **kwargs):
if not hasattr(self.client, f"create_{self.type}"):
return
for k, v in kwargs.items():
if hasattr(self, k) and getattr(self, k) != v:
setattr(self, k, v)
await getattr(self.client, f"create_{self.type}")(self)
async def update(self, **kwargs):
for k, v in kwargs.items():
if hasattr(self, k) and getattr(self, k) != v:
setattr(self, k, v)
return await getattr(self.client, f"set_{self.type}")(self.id, self, **kwargs)
async def delete(self):
if _fn := getattr(self.client, f"delete_{self.type}", None):
await _fn(self.id, self)
def __init_subclass__(cls, **_):
super().__init_subclass__()
Entity.__cache__[
_.get_default() if (_ := cls.__fields__.get("type")) else "unknown"
] = cls
def __hash__(self) -> int:
return hash(self.id)
def __json__(self):
return ujson.dumps(self)
class BaseAttribute(BaseModel):
Config = HueConfig
__config__ = HueConfig
def __init_subclass__(cls, *args, **kwargs):
cls.Config = HueConfig
cls.__config__ = HueConfig
class RoomType(Enum):
@staticmethod
def _generate_next_value_(name, *_):
return name.lower()
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()
def __json__(self):
return f'"{self.value}"'
class Archetype(Enum):
@staticmethod
def _generate_next_value_(name, *_):
return name.lower()
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()
def __json__(self):
return f'"{self.value}"'
_T = TypeVar("_T")
@dataclass
class _XY:
x: float
y: float
def __post_init__(self):
if self.x < 0.01:
self.x = 0.01
if self.y < 0.01:
self.y = 0.01
if self.x > 0.99:
self.x = 0.99
if self.y > 0.99:
self.y = 0.99
def __json__(self):
return (
'{"y":' + f'{int(10000*self.x)/10000}, "x": {int(10000*self.y)/10000}' + "}"
)
@dataclass
class On:
on: bool = True
def __json__(self):
return '{"on": ' + f"{self.on}" + "}"
XY = _XY | tuple[float, float]
class Attributes:
class Action(BaseAttribute):
on: "Attributes.On" = Field(default_factory=lambda: Attributes.On(on=True))
dimming: "Attributes.Dimming" = Field(
default_factory=lambda: Attributes.Dimming(
brightness=100.0, min_dim_level=100.0
)
)
color: "Attributes.ColorPoint" = Field(
default_factory=lambda: Attributes.ColorPoint()
)
color_temperature: "Attributes.ScenePaletteColorTemp" = Field(
default_factory=lambda: Attributes.ScenePaletteColorTemp(mirek=500)
)
gradient: "Attributes.Gradient" = Field(
default_factory=lambda: Attributes.Gradient(points_capable=2, points=[])
)
effects: "Attributes.Effects" = Field(
default_factory=lambda: Attributes.Effects()
)
dynamics: "Attributes.SceneDynamics" = Field(
default_factory=lambda: Attributes.SceneDynamics(duration=1)
)
class Actions(BaseAttribute):
target: "Attributes.Identifier" = Field(...)
action: "Attributes.Action" = Field(default_factory=lambda: Attributes.Action())
dimming: "Attributes.Dimming" = Field(
default_factory=lambda: Attributes.Dimming(
brightness=100.0, min_dim_level=100.0
)
)
color: "Attributes.ColorPoint" = Field(
default_factory=lambda: Attributes.ColorPoint()
)
class Alert(BaseAttribute):
action: Literal["breathe", "unknown"] = "unknown"
class Button(BaseAttribute):
last_event: Literal[
"initial_press",
"repeat",
"short_release",
"long_release",
"double_short_release",
"long_press",
] = "initial_press"
class Color(BaseAttribute):
xy: "Attributes.XY" = Field(default_factory=lambda: Attributes.XY(x=0.0, y=0.0))
gamut: "Attributes.Gamut" = Field(default_factory=lambda: Attributes.Gamut())
gamut_type: Literal["A", "B", "C"] = "A"
class ColorPointColor(BaseAttribute):
color: "Attributes.ColorPoint" = Field(
default_factory=lambda: Attributes.ColorPoint()
)
class ColorPoint(BaseAttribute):
xy: "Attributes.XY" = Field(default_factory=lambda: Attributes.XY(x=0.0, y=0.0))
class ColorMirekSchema(BaseAttribute):
mirek_minimum: int = Field(default=153, ge=153, le=500)
mirek_maximum: int = Field(default=500, ge=153, le=500)
class ColorTemp(BaseAttribute):
mirek: Optional[int] = Field(default=0, ge=153, le=500)
mirek_valid: Optional[bool] = True
mirek_schema: Optional["Attributes.ColorMirekSchema"] = Field(
default_factory=lambda: Attributes.ColorMirekSchema()
)
class Dependee(BaseAttribute):
type: str = "unknown"
target: "Attributes.Identifier" = Field(...)
level: str = "unknown"
class Dimming(BaseAttribute):
brightness: float = Field(default=99.0, ge=0, le=100.0)
min_dim_level: float = Field(default=99.0, ge=0, le=100.0)
class DimmingDelta(BaseAttribute):
action: Optional[Literal["up", "down", "stop"]] = "stop"
brightness_delta: Optional[float] = Field(default=0, ge=0, le=100)
class Dynamics(BaseAttribute):
status: str = "unknown"
status_values: Optional[list[str]] = Field(default_factory=list)
speed: Optional[float] = Field(default=0.0, ge=0, le=100)
speed_valid: Optional[bool] = True
class Effects(BaseAttribute):
effect: Optional[list[str]] = Field(default_factory=list)
status_values: Optional[list[str]] = Field(default_factory=list)
status: str = "unknown"
effect_values: Optional[list[str]] = Field(default_factory=list)
class EntChannel(BaseAttribute):
channel_id: int = Field(ge=0, le=255)
position: Optional["Attributes.XYZ"] = Field(
default_factory=lambda: Attributes.XYZ(x=0.0, y=0.0, z=0.0)
)
members: list["Attributes.SegmentRef"] = Field(default_factory=list)
class EntLocation(BaseAttribute):
service_location: list["Attributes.ServiceLocation"] = Field(
default_factory=list
)
class Gamut(BaseAttribute):
red: XY = Field(default_factory=lambda: Attributes.XY(x=0.0, y=0.0))
green: XY = Field(default_factory=lambda: Attributes.XY(x=0.0, y=0.0))
blue: XY = Field(default_factory=lambda: Attributes.XY(x=0.0, y=0.0))
class Gradient(BaseAttribute):
points: Optional[list["Attributes.ColorPointColor"]] = Field(
default_factory=list
)
points_capable: Optional[int] = Field(default=1, ge=0, le=255)
class Identifier(BaseAttribute):
rid: UUID = Field(default_factory=default_uuid)
rtype: str = "unknown"
class LightColor(BaseAttribute):
xy: Optional["Attributes.XY"] = Field(
default_factory=lambda: Attributes.XY(x=0.8, y=0.8)
)
class LightLevelValue(BaseAttribute):
light_level: Optional[int] = Field(default=0, ge=0, le=100000)
light_level_valid: Optional[bool] = True
class LightEffect(BaseAttribute):
effect: Optional[Literal["fire", "candle", "no_effect"]] = "no_effect"
class Metadata(BaseAttribute):
# @validator("name", always=True)
# def validate_name(cls, v, values):
# return v.replace(" ", "_").replace("-", "_").lower()
name: str = "unknown"
archetype: Archetype | RoomType = Archetype.UNKNOWN_ARCHETYPE
image: "Attributes.Identifier" = Field(
default_factory=lambda: Attributes.Identifier(), repr=False
)
class Motion(BaseAttribute):
motion: Optional[bool] = Field(default=False)
motion_valid: Optional[bool] = Field(default=True)
class On(BaseAttribute):
on: Optional[bool] = Field(default=True, alias="on")
class Palette(BaseAttribute):
color: Optional[list["Attributes.PaletteColor"]] = Field(default_factory=list)
dimming: Optional[list["Attributes.Dimming"]] = Field(default_factory=list)
color_temperature: list["Attributes.PaletteTemperature"] = Field(
default_factory=list
)
class PaletteColor(BaseAttribute):
color: Optional["Attributes.ColorPoint"] = Field(
default_factory=lambda: Attributes.ColorPoint()
)
dimming: Optional["Attributes.Dimming"] = Field(
default_factory=lambda: Attributes.Dimming(brightness=99.0)
)
class PaletteTemperature(BaseAttribute):
color_temperature: Optional["Attributes.ScenePaletteColorTemp"] = Field(
default_factory=lambda: Attributes.ScenePaletteColorTemp(mirek=500)
)
dimming: Optional["Attributes.Dimming"] = Field(
default_factory=lambda: Attributes.Dimming(
brightness=100.0, min_dim_level=100.0
)
)
class PowerState(BaseAttribute):
battery_state: Optional[Literal["normal", "low", "critical"]] = "normal"
battery_level: Optional[float] = Field(default=100.0, le=100.0, ge=0.0)
class ProductData(BaseAttribute):
model_id: Optional[str] = "unknown"
manufacturer_name: Optional[str] = "unknown"
product_name: Optional[str] = "unknown"
product_archetype: Optional[Archetype] = Archetype.UNKNOWN_ARCHETYPE
certified: Optional[bool] = False
software_version: Optional[str] = Field(
default="0.0.0", regex=r"\d+\.(?:\d+\.)*\d+"
)
hardware_platform_type: Optional[str] = "unknown"
class RelativeRotary(BaseAttribute):
last_event: Optional["Attributes.RotaryEvent"] = Field(
default_factory=lambda: Attributes.RotaryEvent()
)
class RotaryEvent(BaseAttribute):
action: Optional[Literal["start", "repeat", "unknown"]] = "unknown"
rotation: Optional["Attributes.RotaryRotation"] = Field(
default_factory=lambda: Attributes.RotaryRotation(
direction="clock_wise", duration=0.0, steps=0
)
)
class RotaryRotation(BaseAttribute):
direction: Literal["clock_wise", "counter_clock_wise"] = "clock_wise"
duration: Optional[float] = Field(0.0, ge=0.0)
steps: Optional[int] = Field(0, ge=0)
class SceneDynamics(BaseAttribute):
duration: Optional[int] = Field(0, ge=0)
class SceneEffects(BaseAttribute):
effect: Optional[Literal["fire", "candle", "no_effect"]] = "no_effect"
class ScenePaletteColorTemp(BaseAttribute):
mirek: int = Field(153, ge=153, le=500)
class Segment(BaseAttribute):
start: int = Field(0, ge=0)
length: int = Field(1, ge=0)
class SegmentManager(BaseAttribute):
configurable: Optional[bool] = True
max_segments: Optional[int] = Field(default=1, ge=1)
segments: Optional[list["Attributes.Segment"]] = Field(default_factory=list)
class SegmentRef(BaseAttribute):
service: "Attributes.Identifier" = Field(
default_factory=lambda: Attributes.Identifier()
)
index: int = 0
class ServiceLocation(BaseAttribute):
service: "Attributes.Identifier" = Field(
default_factory=lambda: Attributes.Identifier()
)
position: "Attributes.XYZ" = Field(
default_factory=lambda: Attributes.XYZ(x=0.0, y=0.0, z=0.0)
)
positions: list[Type["Attributes.XYZ"]] = Field(max_items=2, min_items=1)
class StreamProxy(BaseAttribute):
mode: Literal["auto", "manual"] = "manual"
node: "Attributes.Identifier" = Field(
default_factory=lambda: Attributes.Identifier()
)
class Temp(BaseAttribute):
temperature: float = Field(default=0.0, lt=100.0, gt=-100.0)
temperature_valid: bool = True
class TimedEffects(BaseAttribute):
effect: Optional[str] = "none"
duration: Optional[float] = Field(default=0.0, ge=0.0)
status_values: Optional[list[str]] = Field(default_factory=list)
status: Optional[str] = "unknown"
effect_values: Optional[list[str]] = Field(default_factory=list)
class XY(BaseAttribute):
x: float = Field(0.0, ge=0.0, le=1.0)
y: float = Field(0.0, ge=0.0, le=1.0)
class XYZ(BaseAttribute):
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)
class HueEntsV1:
class UserConfiguration(Entity):
name: str
swupdate: dict
swupdate2: dict
whitelist: list[str]
portalstate: dict
apiversion: str
swversion: str
proxyaddress: str
v: BaseModel
for k, v in Attributes.__dict__.items():
if k.startswith("__"):
continue
if isinstance(v, type) and issubclass(v, BaseModel):
v.update_forward_refs()
class HueEntsV2:
class BehaviorInstance(Entity):
type: ClassVar[str] = "behavior_instance"
cfg_prefix: ClassVar[str] = "bhv_inst_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
script_id: str = Field("", regex=r"^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$")
enabled: bool = True
state: Optional[dict[str, Any]] = Field(default_factory=dict)
configuration: dict[str, Any] = Field(default_factory=dict)
dependees: list[Attributes.Dependee] = Field(default_factory=list)
status: Literal[
"initializing", "running", "disabled", "errored"
] = "initializing"
last_error: str = "none"
migrated_from: str = "unknown"
class BehaviorScript(Entity):
type: ClassVar[str] = "behavior_script"
cfg_prefix: ClassVar[str] = "bhv_script_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
description: str = ""
configuration_schema: dict[Any, Any] = Field(default_factory=dict)
trigger_schema: dict[Any, Any] = Field(default_factory=dict)
state_schema: dict[Any, Any] = Field(default_factory=dict)
version: str = Field("0.0.1", regex=r"^[0-9]+\.[0-9]+\.[0-9]+$")
supported_features: list[str] = Field(default_factory=list)
max_number_of_instances: int = Field(default=0, ge=0, le=255)
class Bridge(Entity):
type: ClassVar[str] = "bridge"
cfg_prefix: ClassVar[str] = "brdg_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
bridge_id: str = ""
time_zone: dict[str, str] = Field(default_factory=dict)
class BridgeHome(Entity):
type: ClassVar[str] = "bridge_home"
cfg_prefix: ClassVar[str] = "brdg_hm_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
services: list[Attributes.Identifier] = Field(default_factory=list)
children: list[Attributes.Identifier] = Field(default_factory=list)
class Button(Entity):
type: ClassVar[str] = "button"
cfg_prefix: ClassVar[str] = "btn_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
button: Attributes.Button = Field(default_factory=Attributes.Button)
class Device(Entity):
type: ClassVar[str] = "device"
cfg_prefix: ClassVar[str] = "dvc_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
services: list[Attributes.Identifier] = Field(default_factory=list)
product_data: Attributes.ProductData = Field(
default_factory=lambda: Attributes.ProductData()
)
class DevicePower(Entity):
type: ClassVar[str] = "device_power"
cfg_prefix: ClassVar[str] = "dvc_pwr_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
power_state: Attributes.PowerState = Field(
default_factory=Attributes.PowerState
)
class Entertainment(Entity):
type: ClassVar[str] = "entertainment"
cfg_prefix: ClassVar[str] = "ent_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
renderer: bool = False
proxy: bool = False
max_streams: int = Field(1, ge=1)
segments: Attributes.SegmentManager = Field(
default_factory=Attributes.SegmentManager
)
class EntertainmentConfiguration(Entity):
type: ClassVar[str] = "entertainment_configuration"
cfg_prefix: ClassVar[str] = "ent_cfg_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
name: str = ""
configuration_type: Optional[
Literal["screen", "monitor", "music", "3dspace", "other"]
] = "screen"
status: Literal["active", "inactive"] = "inactive"
active_streamer: Attributes.Identifier = Field(
default_factory=Attributes.Identifier
)
stream_proxy: Attributes.StreamProxy = Field(
default_factory=Attributes.StreamProxy
)
channels: list[Attributes.EntChannel] = Field(default_factory=list)
locations: Attributes.EntLocation = Field(
default_factory=Attributes.EntLocation
)
light_services: list[Attributes.Identifier] = Field(default_factory=list)
class GeofenceClient(Entity):
type: ClassVar[str] = "geofence_client"
cfg_prefix: ClassVar[str] = "geo_clnt_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
name: str = ""
is_at_home: Optional[bool] = True
class Geolocation(Entity):
type: ClassVar[str] = "geolocation"
cfg_prefix: ClassVar[str] = "geoloc_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
is_configured: bool = False
class GroupedLight(Entity):
type: ClassVar[str] = "grouped_light"
cfg_prefix: ClassVar[str] = "grp_lt_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
on: Attributes.On = Field(default_factory=Attributes.On)
alert: Attributes.Alert = Field(default_factory=Attributes.Alert)
class Homekit(Entity):
type: ClassVar[str] = "resource"
cfg_prefix: ClassVar[str] = "hm_kt_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
status: Literal["paired", "pairing", "unpaired"] = "unpaired"
class Light(Entity):
type: ClassVar[str] = "light"
cfg_prefix: ClassVar[str] = "l_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: Optional[str] = Field(
default="", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$", exclude=True
)
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
on: Attributes.On = Field(default_factory=Attributes.On)
dimming: Attributes.Dimming = Field(default_factory=Attributes.Dimming)
dimming_delta: Attributes.DimmingDelta = Field(
default_factory=Attributes.DimmingDelta
)
color_temperature: Attributes.ColorTemp = Field(
default_factory=Attributes.ColorTemp
)
color_temperature_delta: dict = Field(default_factory=dict)
color: Attributes.LightColor = Field(default_factory=Attributes.LightColor)
gradient: Attributes.Gradient = Field(default_factory=Attributes.Gradient)
dynamics: Attributes.Dynamics = Field(default_factory=Attributes.Dynamics)
alert: Attributes.Alert = Field(default_factory=Attributes.Alert)
signaling: dict = Field(default_factory=dict)
mode: Literal["normal", "streaming"] = "normal"
effects: Attributes.LightEffect = Field(
default_factory=lambda: Attributes.LightEffect(effect="fire")
)
timed_effects: Attributes.TimedEffects = Field(
default_factory=Attributes.TimedEffects
)
class LightLevel(Entity):
type: ClassVar[str] = "light_level"
cfg_prefix: ClassVar[str] = "l_lvl_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
enabled: bool = True
light: Attributes.LightLevelValue = Field(
default_factory=Attributes.LightLevelValue
)
class Motion(Entity):
type: ClassVar[str] = "motion"
cfg_prefix: ClassVar[str] = "mtn_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
enabled: bool = True
motion: Attributes.Motion = Field(default_factory=Attributes.Motion)
class RelativeRotary(Entity):
type: ClassVar[str] = "relative_rotary"
cfg_prefix: ClassVar[str] = "rel_rot_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
relative_rotary: Attributes.RelativeRotary = Field(
default_factory=Attributes.RelativeRotary
)
class Resource(Entity):
type: ClassVar[str] = "device"
cfg_prefix: ClassVar[str] = "res_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
class Room(Entity):
type: ClassVar[str] = "room"
cfg_prefix: ClassVar[str] = "rm_"
id: Optional[UUID]
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: Optional[str] = Field(
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
)
services: Optional[list[Attributes.Identifier]] = Field(
default_factory=list, alias="service"
)
children: Optional[list[Attributes.Identifier]] = Field(default_factory=list)
class Scene(Entity):
type: ClassVar[str] = "scene"
cfg_prefix: ClassVar[str] = "scn_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
group: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
actions: list[Attributes.Actions] = Field(default_factory=list)
palette: Attributes.Palette = Field(default_factory=Attributes.Palette)
speed: float = 0.0
auto_dynamic: bool = False
class Temperature(Entity):
type: ClassVar[str] = "temperature"
cfg_prefix: ClassVar[str] = "tmp_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
enabled: bool = True
temperature: Attributes.Temp = Field(default_factory=Attributes.Temp)
class ZGPConnectivity(Entity):
type: ClassVar[str] = "zgp_connectivity"
cfg_prefix: ClassVar[str] = "zgp_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Attributes.Identifier = Field(default_factory=Attributes.Identifier)
status: Optional[
Literal[
"connected",
"disconnected",
"connectivity_issue",
"unidirectional_incoming",
]
] = "connected"
source_id: str = ""
class ZigbeeConnectivity(Entity):
type: ClassVar[str] = "zigbee_connectivity"
cfg_prefix: ClassVar[str] = "zig_conn_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: Optional[str] = Field(
None, regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
)
owner: Optional[Attributes.Identifier] = Field(
default_factory=Attributes.Identifier
)
status: Optional[
Literal[
"connected",
"disconnected",
"connectivity_issue",
"unidirectional_incoming",
]
] = "connected"
mac_address: Optional[str] = Field("", regex=r"^(?:[0-9a-fA-F]{2}:?){6}")
class ZigbeeDeviceDiscovery(Entity):
type: ClassVar[str] = "zigbee_device_discovery"
cfg_prefix: ClassVar[str] = "zig_dev_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: Optional[str] = Field(
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
)
owner: Optional[Attributes.Identifier] = Field(
default_factory=Attributes.Identifier
)
status: Optional[Literal["active", "ready"]] = "ready"
class Zone(Entity):
type: ClassVar[str] = "zone"
cfg_prefix: ClassVar[str] = "zn_"
id: UUID
metadata: Attributes.Metadata = Field(default_factory=Attributes.Metadata)
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
services: list[Attributes.Identifier] = Field(
default_factory=list, alias="service"
)
children: list[Attributes.Identifier] = Field(default_factory=list)
for k, v in HueEntsV2.__dict__.items():
if k.startswith("__"):
continue
if isinstance(v, type) and issubclass(v, BaseModel):
v.update_forward_refs()