all but 4 structures done, yet to test updating, in theory it works

This commit is contained in:
rooba 2022-11-28 00:13:44 -08:00
parent 99d1049ab9
commit 5c930d7742
4 changed files with 506 additions and 66 deletions

5
.gitignore vendored

@ -1,6 +1,5 @@
**/app.py
**/phlyght.*
**/phlyght.*
**/poetry.lock **/poetry.lock
**/__pycache__ **/__pycache__
**/testing
!test.py !test.py

@ -10,7 +10,7 @@ from yarl import URL as UR
# from rich import print # from rich import print
from .models import Lights from . import models
STR_FMT_RE = compile(r"""(?=(\{([^:]+)(?::([^}]+))?\}))\1""") STR_FMT_RE = compile(r"""(?=(\{([^:]+)(?::([^}]+))?\}))\1""")
@ -208,286 +208,361 @@ class SubRouter(metaclass=RouterMeta):
class HughApi(SubRouter): class HughApi(SubRouter):
BASE_URI = "/clip/v2" BASE_URI = "/clip/v2"
@ret_cls(Lights.Light) @ret_cls(models.Light)
@route("GET", "/resource/light") @route("GET", "/resource/light")
async def get_lights(self, friendly_name: Optional[str] = None): async def get_lights(self, friendly_name: Optional[str] = None):
... ...
@ret_cls(Lights.Light) @ret_cls(models.Light)
@route("GET", "/resource/light/{light_id}") @route("GET", "/resource/light/{light_id}")
async def get_light(self, light_id: str): async def get_light(self, light_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/light/{light_id}") @route("PUT", "/resource/light/{light_id}")
async def set_light( async def set_light(
self, self,
light_id: int, light_id: int,
on: Optional[dict[Literal["on"], bool]] = None, on: Optional[dict[Literal["on"], bool]] = None,
dimming: Optional[dict[str, Any]] = None, dimming: Optional[dict[str, Any]] = None,
**kwargs, dimming_delta: Optional[dict] = None,
color_temperature: Optional[int] = None,
color_temperature_delta: Optional[dict] = None,
color: Optional[dict] = None,
dynamics: Optional[dict] = None,
alert: Optional[dict] = None,
gradient: Optional[dict] = None,
effects: Optional[dict] = None,
timed_effects: Optional[dict] = None,
): ):
... ...
@ret_cls(models.Scene)
@route("GET", "/resource/scene") @route("GET", "/resource/scene")
async def get_scenes(self): async def get_scenes(self):
... ...
@ret_cls(models.Identifier)
@route("POST", "/resource/scene") @route("POST", "/resource/scene")
async def create_scene(self, **kwargs): async def create_scene(self, **kwargs):
... ...
@ret_cls(models.Scene)
@route("GET", "/resource/scene/{scene_id}") @route("GET", "/resource/scene/{scene_id}")
async def get_scene(self, scene_id: str): async def get_scene(self, scene_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/scene/{scene_id}") @route("PUT", "/resource/scene/{scene_id}")
async def set_scene(self, scene_id: str, **kwargs): async def set_scene(self, scene_id: str, **kwargs):
... ...
@ret_cls(models.Identifier)
@route("DELETE", "/resource/scene/{scene_id}") @route("DELETE", "/resource/scene/{scene_id}")
async def delete_scene(self, scene_id: str): async def delete_scene(self, scene_id: str):
... ...
@ret_cls(models.Room)
@route("GET", "/resource/room") @route("GET", "/resource/room")
async def get_rooms(self): async def get_rooms(self):
... ...
@ret_cls(models.Identifier)
@route("POST", "/resource/room") @route("POST", "/resource/room")
async def create_room(self, **kwargs): async def create_room(self, **kwargs):
... ...
@ret_cls(models.Room)
@route("GET", "/resource/room/{room_id}") @route("GET", "/resource/room/{room_id}")
async def get_room(self, room_id: str): async def get_room(self, room_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/room/{room_id}") @route("PUT", "/resource/room/{room_id}")
async def set_room(self, room_id: str, **kwargs): async def set_room(self, room_id: str, **kwargs):
... ...
@ret_cls(models.Identifier)
@route("DELETE", "/resource/room/{room_id}") @route("DELETE", "/resource/room/{room_id}")
async def delete_room(self, room_id: str): async def delete_room(self, room_id: str):
... ...
@ret_cls(models.Zone)
@route("GET", "/resource/zone") @route("GET", "/resource/zone")
async def get_zones(self): async def get_zones(self):
... ...
@ret_cls(models.Identifier)
@route("POST", "/resource/zone") @route("POST", "/resource/zone")
async def create_zone(self, **kwargs): async def create_zone(self, **kwargs):
... ...
@ret_cls(models.Zone)
@route("GET", "/resource/zone/{zone_id}") @route("GET", "/resource/zone/{zone_id}")
async def get_zone(self, zone_id: str): async def get_zone(self, zone_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/zone/{zone_id}") @route("PUT", "/resource/zone/{zone_id}")
async def set_zone(self, zone_id: str, **kwargs): async def set_zone(self, zone_id: str, **kwargs):
... ...
@ret_cls(models.Identifier)
@route("DELETE", "/resource/zone/{zone_id}") @route("DELETE", "/resource/zone/{zone_id}")
async def delete_zone(self, zone_id: str): async def delete_zone(self, zone_id: str):
... ...
@ret_cls(models.BridgeHome)
@route("GET", "/resource/bridge_home") @route("GET", "/resource/bridge_home")
async def get_bridge_homes(self): async def get_bridge_homes(self):
... ...
@ret_cls(models.BridgeHome)
@route("GET", "/resource/bridge_home/{bridge_home_id}") @route("GET", "/resource/bridge_home/{bridge_home_id}")
async def get_bridge_home(self, bridge_home_id: str): async def get_bridge_home(self, bridge_home_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/bridge_home/{bridge_home_id}") @route("PUT", "/resource/bridge_home/{bridge_home_id}")
async def set_bridge_home(self, bridge_home_id: str, **kwargs): async def set_bridge_home(self, bridge_home_id: str, **kwargs):
... ...
@ret_cls(models.GroupedLight)
@route("GET", "/resource/grouped_light") @route("GET", "/resource/grouped_light")
async def get_grouped_lights(self): async def get_grouped_lights(self):
... ...
@ret_cls(models.GroupedLight)
@route("GET", "/resource/grouped_light/{grouped_light_id}") @route("GET", "/resource/grouped_light/{grouped_light_id}")
async def get_grouped_light(self, grouped_light_id: str): async def get_grouped_light(self, grouped_light_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/grouped_light/{grouped_light_id}") @route("PUT", "/resource/grouped_light/{grouped_light_id}")
async def set_grouped_light(self, grouped_light_id: str, **kwargs): async def set_grouped_light(self, grouped_light_id: str, **kwargs):
... ...
@ret_cls(models.Device)
@route("GET", "/resource/device") @route("GET", "/resource/device")
async def get_devices(self): async def get_devices(self):
... ...
@ret_cls(models.Device)
@route("GET", "/resource/device/{device_id}") @route("GET", "/resource/device/{device_id}")
async def get_device(self, device_id: str): async def get_device(self, device_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/device/{device_id}") @route("PUT", "/resource/device/{device_id}")
async def set_device(self, device_id: str, **kwargs): async def set_device(self, device_id: str, **kwargs):
... ...
@ret_cls(models.Bridge)
@route("GET", "/resource/bridges") @route("GET", "/resource/bridges")
async def get_bridges(self): async def get_bridges(self):
... ...
@ret_cls(models.Bridge)
@route("GET", "/resource/bridges/{bridge_id}") @route("GET", "/resource/bridges/{bridge_id}")
async def get_bridge(self, bridge_id: str): async def get_bridge(self, bridge_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/bridges/{bridge_id}") @route("PUT", "/resource/bridges/{bridge_id}")
async def set_bridge(self, bridge_id: str, **kwargs): async def set_bridge(self, bridge_id: str, **kwargs):
... ...
@ret_cls(models.DevicePower)
@route("GET", "/resource/device_power") @route("GET", "/resource/device_power")
async def get_device_powers(self): async def get_device_powers(self):
... ...
@ret_cls(models.DevicePower)
@route("GET", "/resource/device_power/{device_power_id}") @route("GET", "/resource/device_power/{device_power_id}")
async def get_device_power(self, device_power_id: str): async def get_device_power(self, device_power_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/device_power/{device_power_id}") @route("PUT", "/resource/device_power/{device_power_id}")
async def set_device_power(self, device_power_id: str, **kwargs): async def set_device_power(self, device_power_id: str, **kwargs):
... ...
@ret_cls(models.ZigbeeConnectivity)
@route("GET", "/resource/zigbee_connectivity") @route("GET", "/resource/zigbee_connectivity")
async def get_zigbee_connectivities(self): async def get_zigbee_connectivities(self):
... ...
@ret_cls(models.ZigbeeConnectivity)
@route("GET", "/resource/zigbee_connectivity/{zigbee_connectivity_id}") @route("GET", "/resource/zigbee_connectivity/{zigbee_connectivity_id}")
async def get_zigbee_connectivity(self, zigbee_connectivity_id: str): async def get_zigbee_connectivity(self, zigbee_connectivity_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/zigbee_connectivity/{zigbee_connectivity_id}") @route("PUT", "/resource/zigbee_connectivity/{zigbee_connectivity_id}")
async def set_zigbee_connectivity(self, zigbee_connectivity_id: str, **kwargs): async def set_zigbee_connectivity(self, zigbee_connectivity_id: str, **kwargs):
... ...
@ret_cls(models.ZGPConnectivity)
@route("GET", "/resource/zgb_connectivity") @route("GET", "/resource/zgb_connectivity")
async def get_zgb_connectivities(self): async def get_zgb_connectivities(self):
... ...
@ret_cls(models.ZGPConnectivity)
@route("GET", "/resource/zgb_connectivity/{zgb_connectivity_id}") @route("GET", "/resource/zgb_connectivity/{zgb_connectivity_id}")
async def get_zgb_connectivity(self, zgb_connectivity_id: str): async def get_zgb_connectivity(self, zgb_connectivity_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/zgb_connectivity/{zgb_connectivity_id}") @route("PUT", "/resource/zgb_connectivity/{zgb_connectivity_id}")
async def set_zgb_connectivity(self, zgb_connectivity_id: str, **kwargs): async def set_zgb_connectivity(self, zgb_connectivity_id: str, **kwargs):
... ...
@ret_cls(models.Motion)
@route("GET", "/resource/motion") @route("GET", "/resource/motion")
async def get_motions(self): async def get_motions(self):
... ...
@ret_cls(models.Motion)
@route("GET", "/resource/motion/{motion_id}") @route("GET", "/resource/motion/{motion_id}")
async def get_motion(self, motion_id: str): async def get_motion(self, motion_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/motion/{motion_id}") @route("PUT", "/resource/motion/{motion_id}")
async def set_motion(self, motion_id: str, **kwargs): async def set_motion(self, motion_id: str, **kwargs):
... ...
@ret_cls(models.Temperature)
@route("GET", "/resource/temperature") @route("GET", "/resource/temperature")
async def get_temperatures(self): async def get_temperatures(self):
... ...
@ret_cls(models.Temperature)
@route("GET", "/resource/temperature/{temperature_id}") @route("GET", "/resource/temperature/{temperature_id}")
async def get_temperature(self, temperature_id: str): async def get_temperature(self, temperature_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/temperature/{temperature_id}") @route("PUT", "/resource/temperature/{temperature_id}")
async def set_temperature(self, temperature_id: str, **kwargs): async def set_temperature(self, temperature_id: str, **kwargs):
... ...
@ret_cls(models.LightLevel)
@route("GET", "/resource/light_level") @route("GET", "/resource/light_level")
async def get_light_levels(self): async def get_light_levels(self):
... ...
@ret_cls(models.LightLevel)
@route("GET", "/resource/light_level/{light_level_id}") @route("GET", "/resource/light_level/{light_level_id}")
async def get_light_level(self, light_level_id: str): async def get_light_level(self, light_level_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/light_level/{light_level_id}") @route("PUT", "/resource/light_level/{light_level_id}")
async def set_light_level(self, light_level_id: str, **kwargs): async def set_light_level(self, light_level_id: str, **kwargs):
... ...
@ret_cls(models.Button)
@route("GET", "/resource/button") @route("GET", "/resource/button")
async def get_buttons(self): async def get_buttons(self):
... ...
@ret_cls(models.Button)
@route("GET", "/resource/button/{button_id}") @route("GET", "/resource/button/{button_id}")
async def get_button(self, button_id: str): async def get_button(self, button_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/button/{button_id}") @route("PUT", "/resource/button/{button_id}")
async def set_button(self, button_id: str, **kwargs): async def set_button(self, button_id: str, **kwargs):
... ...
@ret_cls(models.BehaviorScript)
@route("GET", "/resource/behavior_script") @route("GET", "/resource/behavior_script")
async def get_behavior_scripts(self): async def get_behavior_scripts(self):
... ...
@ret_cls(models.BehaviorScript)
@route("GET", "/resource/behavior_script/{behavior_script_id}") @route("GET", "/resource/behavior_script/{behavior_script_id}")
async def get_behavior_script(self, behavior_script_id: str): async def get_behavior_script(self, behavior_script_id: str):
... ...
@ret_cls(models.BehaviorInstance)
@route("GET", "/resource/behavior_instance") @route("GET", "/resource/behavior_instance")
async def get_behavior_instances(self): async def get_behavior_instances(self):
... ...
@ret_cls(models.Identifier)
@route("POST", "/resource/behavior_instance") @route("POST", "/resource/behavior_instance")
async def create_behavior_instance(self, **kwargs): async def create_behavior_instance(self, **kwargs):
... ...
@ret_cls(models.BehaviorInstance)
@route("GET", "/resource/behavior_instance/{behavior_instance_id}") @route("GET", "/resource/behavior_instance/{behavior_instance_id}")
async def get_behavior_instance(self, behavior_instance_id: str): async def get_behavior_instance(self, behavior_instance_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/behavior_instance/{behavior_instance_id}") @route("PUT", "/resource/behavior_instance/{behavior_instance_id}")
async def set_behavior_instance(self, behavior_instance_id: str, **kwargs): async def set_behavior_instance(self, behavior_instance_id: str, **kwargs):
... ...
@ret_cls(models.Identifier)
@route("DELETE", "/resource/behavior_instance/{behavior_instance_id}") @route("DELETE", "/resource/behavior_instance/{behavior_instance_id}")
async def delete_behavior_instance(self, behavior_instance_id: str): async def delete_behavior_instance(self, behavior_instance_id: str):
... ...
@ret_cls(models.GeofenceClient)
@route("GET", "/resource/geofence_client") @route("GET", "/resource/geofence_client")
async def get_geofence_clients(self): async def get_geofence_clients(self):
... ...
@ret_cls(models.Identifier)
@route("POST", "/resource/geofence_client") @route("POST", "/resource/geofence_client")
async def create_geofence_client(self, **kwargs): async def create_geofence_client(self, **kwargs):
... ...
@ret_cls(models.GeofenceClient)
@route("GET", "/resource/geofence_client/{geofence_client_id}") @route("GET", "/resource/geofence_client/{geofence_client_id}")
async def get_geofence_client(self, geofence_client_id: str): async def get_geofence_client(self, geofence_client_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/geofence_client/{geofence_client_id}") @route("PUT", "/resource/geofence_client/{geofence_client_id}")
async def set_geofence_client(self, geofence_client_id: str, **kwargs): async def set_geofence_client(self, geofence_client_id: str, **kwargs):
... ...
@ret_cls(models.Identifier)
@route("DELETE", "/resource/geofence_client/{geofence_client_id}") @route("DELETE", "/resource/geofence_client/{geofence_client_id}")
async def delete_geofence_client(self, geofence_client_id: str): async def delete_geofence_client(self, geofence_client_id: str):
... ...
@ret_cls(models.Geolocation)
@route("GET", "/resource/geolocation") @route("GET", "/resource/geolocation")
async def get_geolocations(self): async def get_geolocations(self):
... ...
@ret_cls(models.Geolocation)
@route("GET", "/resource/geolocation/{geolocation_id}") @route("GET", "/resource/geolocation/{geolocation_id}")
async def get_geolocation(self, geolocation_id: str): async def get_geolocation(self, geolocation_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/geolocation/{geolocation_id}") @route("PUT", "/resource/geolocation/{geolocation_id}")
async def set_geolocation(self, geolocation_id: str, **kwargs): async def set_geolocation(self, geolocation_id: str, **kwargs):
... ...
@ret_cls(models.EntertainmentConfiguration)
@route("GET", "/resource/entertainment_configuration") @route("GET", "/resource/entertainment_configuration")
async def get_entertainment_configurations(self): async def get_entertainment_configurations(self):
... ...
@ret_cls(models.Identifier)
@route("POST", "/resource/entertainment_configuration") @route("POST", "/resource/entertainment_configuration")
async def create_entertainment_configuration(self, **kwargs): async def create_entertainment_configuration(self, **kwargs):
... ...
@ret_cls(models.EntertainmentConfiguration)
@route( @route(
"GET", "/resource/entertainment_configuration/{entertainment_configuration_id}" "GET", "/resource/entertainment_configuration/{entertainment_configuration_id}"
) )
@ -496,6 +571,7 @@ class HughApi(SubRouter):
): ):
... ...
@ret_cls(models.Identifier)
@route( @route(
"PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}" "PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}"
) )
@ -504,6 +580,7 @@ class HughApi(SubRouter):
): ):
... ...
@ret_cls(models.Identifier)
@route( @route(
"DELETE", "DELETE",
"/resource/entertainment_configuration/{entertainment_configuration_id}", "/resource/entertainment_configuration/{entertainment_configuration_id}",
@ -513,30 +590,37 @@ class HughApi(SubRouter):
): ):
... ...
@ret_cls(models.Entertainment)
@route("GET", "/resource/entertainment") @route("GET", "/resource/entertainment")
async def get_entertainments(self): async def get_entertainments(self):
... ...
@ret_cls(models.Entertainment)
@route("GET", "/resource/entertainment/{entertainment_id}") @route("GET", "/resource/entertainment/{entertainment_id}")
async def get_entertainment(self, entertainment_id: str): async def get_entertainment(self, entertainment_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/entertainment/{entertainment_id}") @route("PUT", "/resource/entertainment/{entertainment_id}")
async def set_entertainment(self, entertainment_id: str, **kwargs): async def set_entertainment(self, entertainment_id: str, **kwargs):
... ...
@ret_cls(models.Homekit)
@route("GET", "/resource/homekit") @route("GET", "/resource/homekit")
async def get_homekits(self): async def get_homekits(self):
... ...
@ret_cls(models.Homekit)
@route("GET", "/resource/homekit/{homekit_id}") @route("GET", "/resource/homekit/{homekit_id}")
async def get_homekit(self, homekit_id: str): async def get_homekit(self, homekit_id: str):
... ...
@ret_cls(models.Identifier)
@route("PUT", "/resource/homekit/{homekit_id}") @route("PUT", "/resource/homekit/{homekit_id}")
async def set_homekit(self, homekit_id: str, **kwargs): async def set_homekit(self, homekit_id: str, **kwargs):
... ...
@ret_cls(models.Resource)
@route("GET", "/resource") @route("GET", "/resource")
async def get_resources(self): async def get_resources(self):
... ...

@ -1,45 +1,125 @@
from typing import Literal, Optional __all__ = ("Room", "Light", "Scene")
from typing import Any, Literal, Optional, Generic, TypeVar
from uuid import UUID from uuid import UUID
from pydantic import BaseModel from pydantic import BaseModel, Field
from dataclasses import dataclass
from enum import Enum, auto
_T = TypeVar("_T")
class Lights: class Archetype(Enum):
class MetaData(BaseModel): @staticmethod
archetype: str def _generate_next_value_(name, start, count, last_values):
name: str return name.lower()
class Owner(BaseModel): BRIDGE_V2 = auto()
rid: UUID UNKNOWN_ARCHETYPE = auto()
rtype: str 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()
class On(BaseModel):
on: bool
class Dimming(BaseModel): class _id_v1(str):
def __get__(self, instance, owner):
return Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$)")
@dataclass
class Dimming:
brightness: float brightness: float
min_dim_level: float min_dim_level: Optional[float] = Field(0, repr=False)
class MirekSchema(BaseModel):
mirek_minimum: float
mirek_maximum: float
class ColorTemperature(BaseModel): @dataclass
mirek: Optional[int] class XY:
mirek_valid: bool
mirek_schema: "Lights.MirekSchema"
class XY(BaseModel):
x: float x: float
y: float y: float
@dataclass
class On:
on: bool = Field(..., alias="on")
@dataclass
class ColorPoint:
xy: XY
@dataclass(frozen=True)
class Identifier:
rid: str
rtype: str
@dataclass(frozen=True)
class Metadata:
name: str
archetype: Optional[Archetype] = Archetype.UNKNOWN_ARCHETYPE
image: Optional[Identifier] = Field(None, repr=False)
class HueGroupedMeta(type):
def update(cls):
for v in cls.__dict__.values():
if hasattr(v, "update_forward_refs"):
v.update_forward_refs()
class HueGrouped(metaclass=HueGroupedMeta):
...
class _Lights(HueGrouped):
class ColorTemperature(BaseModel):
mirek: Optional[int]
mirek_valid: bool
mirek_schema: dict[str, float]
class Gamut(BaseModel): class Gamut(BaseModel):
red: "Lights.XY" red: XY
green: "Lights.XY" green: XY
blue: "Lights.XY" blue: XY
class Color(BaseModel): class Color(BaseModel):
xy: "Lights.XY" xy: XY
gamut: "Lights.Gamut" gamut: "_Lights.Gamut"
gamut_type: Literal["A"] | Literal["B"] | Literal["C"] gamut_type: Literal["A"] | Literal["B"] | Literal["C"]
class Dynamics(BaseModel): class Dynamics(BaseModel):
@ -48,49 +128,317 @@ class Lights:
speed: float speed: float
speed_valid: bool speed_valid: bool
class Alert(BaseModel):
action_values: list[str]
class GradientColor(BaseModel):
xy: "Lights.XY"
class Gradient(BaseModel): class Gradient(BaseModel):
points: list["Lights.GradientColor"] points: list[ColorPoint]
points_capable: int points_capable: int
class Effects(BaseModel): class Effects(BaseModel):
effect: Optional[list[Literal["fire", "candle", "no_effect"]]] effect: Optional[list[str]] = Field(repr=False)
status_values: list[Literal["fire", "candle", "no_effect"]] status_values: list[str] = Field(repr=False)
status: Literal["fire", "candle", "no_effect"] status: str
effect_values: list[Literal["fire", "candle", "no_effect"]] effect_values: list[str] = Field(repr=False)
class TimedEffects(BaseModel): class TimedEffects(BaseModel):
effect: Literal["sunrise", "no_effect"] effect: str
duration: int duration: int
status_values: list[Literal["sunrise", "no_effect"]] status_values: list[str] = Field(repr=False)
status: Literal["sunrise", "no_effect"] status: str
effect_values: list[Literal["sunrise", "no_effect"]] effect_values: list[str] = Field(repr=False)
class Light(BaseModel): class Light(Generic[_T], BaseModel):
id: UUID id: UUID
id_v1: str id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: "Lights.Owner" owner: Identifier
metadata: "Lights.MetaData" metadata: Metadata
on: "Lights.On" on: On = Field(repr=False)
dimming: "Lights.Dimming" dimming: Dimming
dimming_delta: dict dimming_delta: dict
color_temperature: Optional["Lights.ColorTemperature"] color_temperature: Optional["_Lights.ColorTemperature"]
color_temperature_delta: Optional[dict] color_temperature_delta: Optional[dict]
color: Optional["Lights.Color"] color: Optional["_Lights.Color"]
gradient: Optional["Lights.Gradient"] gradient: Optional["_Lights.Gradient"]
dynamics: "Lights.Dynamics" dynamics: "_Lights.Dynamics"
alert: "Lights.Alert" alert: dict[str, list[str]]
signaling: dict signaling: dict
mode: str mode: str
effects: "Lights.Effects" effects: "_Lights.Effects"
type: Literal["light"]
_Lights.update()
class _Scenes(HueGrouped):
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):
target: Identifier
action: "_Scenes.Action" = Field(repr=False)
dimming: Optional[Dimming]
color: Optional[ColorPoint]
class PaletteColor(BaseModel):
color: ColorPoint
dimming: Dimming
class PaletteTemperature(BaseModel):
color_temperature: dict[str, float]
dimming: Dimming
class Palette(BaseModel):
color: list["_Scenes.PaletteColor"]
dimming: Optional[list[Dimming]]
color_temperature: list["_Scenes.PaletteTemperature"]
class Scene(BaseModel):
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
metadata: Metadata
group: Identifier
actions: list["_Scenes.Actions"]
palette: "_Scenes.Palette"
speed: float
auto_dynamic: bool
type: Literal["scene"]
_Scenes.update()
class Room(BaseModel):
type: Literal["room"]
id: UUID
id_v1: _id_v1
services: list[Identifier]
metadata: Metadata
children: list[Identifier]
class Zone(BaseModel):
type: Literal["zone"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
services: list[Identifier]
metadata: Metadata
children: list[Identifier]
class BridgeHome(BaseModel):
type: Literal["bridge_home"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
services: list[Identifier]
children: list[Identifier]
class GroupedLight(BaseModel):
type: Literal["grouped_light"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
on: On = Field(repr=False)
alert: list[str]
class ProductData(BaseModel):
model_id: str
manufacturer_name: str
product_name: str
product_archetype: Archetype
certified: bool
software_version: Optional[str]
hardware_platform_type: Optional[str]
class Device(BaseModel):
type: Literal["device"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
services: list[Identifier]
metadata: Metadata
product_data: ProductData
class Bridge(BaseModel):
type: Literal["bridge"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
bridge_id: str
time_zone: dict[str, str]
class PowerState(BaseModel):
battery_state: Literal["normal", "low", "critical"]
battery_level: float = Field(lt=100.0, gt=0.0)
class DevicePower(BaseModel):
type: Literal["device_power"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
power_state: PowerState
class ZigbeeConnectivity(BaseModel):
type: Literal["zigbee_connectivity"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
status: Literal[
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
]
mac_address: str
class ZGPConnectivity(BaseModel):
type: Literal["zgp_connectivity"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
status: Literal[
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
]
source_id: str
class Motion(BaseModel):
type: Literal["motion"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
enabled: bool
motion: dict[str, bool]
class _Temp(BaseModel):
temperature: float = Field(lt=100.0, gt=-100.0)
temperature_valid: bool
class Temperature(BaseModel):
type: Literal["temperature"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
enabled: bool
temperature: _Temp
class _Light(BaseModel):
light_level: int
light_level_valid: bool
class LightLevel(BaseModel):
type: Literal["light_level"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
enabled: bool
light: _Light
class Button(BaseModel):
type: Literal["button"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
owner: Identifier
metadata: dict[Literal["control_id"], int]
button: dict[
Literal["last_event"],
Literal[
"initial_press",
"repeat",
"short_release",
"long_release",
"double_short_release",
],
]
class BehaviorScript(BaseModel):
type: Literal["behavior_script"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
description: str
configuration_schema: dict[str, Any]
trigger_schema: dict[str, Any]
state_schema: dict[str, Any]
version: str
metadata: dict[str, str]
class Dependee(BaseModel):
type: str type: str
target: Identifier
level: str
for k in Lights.__dict__.values(): class BehaviorInstance(BaseModel):
if hasattr(k, "update_forward_refs"): type: Literal["behavior_instance"]
k.update_forward_refs() id: UUID
id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
script_id: str
enabled: bool
state: Optional[dict[str, Any]]
configuration: dict[str, Any]
dependees: list[Dependee]
status: Literal["initializing", "running", "disabled", "errored"]
last_error: str
metadata: dict[Literal["name"], str]
migrated_from: Optional[str] = None
class GeofenceClient(BaseModel):
type: Literal["geofence_client"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
name: str
class Geolocation(BaseModel):
type: Literal["geolocation"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
is_configured: bool = False
class StreamProxy(BaseModel):
mode: Literal["auto", "manual"]
node: Identifier
class EntertainmentConfiguration(BaseModel):
type: Literal["entertainment_configuration"]
id: UUID
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
metadata: dict[Literal["name"], str]
name: Optional[str] = ""
configuration_type: Literal["screen", "monitor", "music", "3dspace", "other"]
status: Literal["active", "inactive"]
active_streamer: Identifier
stream_proxy: StreamProxy
... # TODO: finish the last 4 objects
class Entertainment(BaseModel):
...
class Homekit(BaseModel):
...
class Resource(BaseModel):
...
Light = _Lights.Light
Scene = _Scenes.Scene

11
test.py

@ -5,11 +5,20 @@ from phlyght.api import Router
async def main(): async def main():
router = Router("TzPrxDf9hyWZoR5jvUaGDZn4Hlxp2XF67ue4ynSI") router = Router("Your user key with the hue bridge")
lights = await router.get_lights() lights = await router.get_lights()
for light in lights: for light in lights:
detailed_light = await router.get_light(light_id=str(light.id)) detailed_light = await router.get_light(light_id=str(light.id))
print(detailed_light) print(detailed_light)
scenes = await router.get_scenes()
for scene in scenes:
print(scene)
devices = await router.get_devices()
for device in devices:
print(device)
run(main()) run(main())