diff --git a/README b/README.md similarity index 100% rename from README rename to README.md diff --git a/phlyght/api.py b/phlyght/api.py index ddc80a2..df9b709 100644 --- a/phlyght/api.py +++ b/phlyght/api.py @@ -3,6 +3,7 @@ __all__ = ("Router", "route", "RouterMeta", "SubRouter", "HughApi") from inspect import signature from re import compile from typing import Any, Literal, Optional +from uuid import UUID from httpx import AsyncClient from httpx._urls import URL as _URL @@ -58,8 +59,10 @@ def ret_cls(cls): kwargs.pop("base_uri", None) ret = (await fn(self, *args, **kwargs)).json().get("data", []) _rets = [] + if isinstance(ret, list): for r in ret: + print(r) _rets.append(cls(**r)) else: return cls(**ret) @@ -263,17 +266,17 @@ class HughApi(SubRouter): @ret_cls(models.Scene) @route("GET", "/resource/scene/{scene_id}") - async def get_scene(self, scene_id: str): + async def get_scene(self, scene_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/scene/{scene_id}") - async def set_scene(self, scene_id: str, **kwargs): + async def set_scene(self, scene_id: UUID, **kwargs): ... @ret_cls(models._Identifier) @route("DELETE", "/resource/scene/{scene_id}") - async def delete_scene(self, scene_id: str): + async def delete_scene(self, scene_id: UUID): ... @ret_cls(models.Room) @@ -288,17 +291,22 @@ class HughApi(SubRouter): @ret_cls(models.Room) @route("GET", "/resource/room/{room_id}") - async def get_room(self, room_id: str): + async def get_room(self, room_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/room/{room_id}") - async def set_room(self, room_id: str, **kwargs): + async def set_room( + self, + room_id: UUID, + metadata: Optional[dict[str, str]] = None, + children: Optional[models._Identifier] = None, + ): ... @ret_cls(models._Identifier) @route("DELETE", "/resource/room/{room_id}") - async def delete_room(self, room_id: str): + async def delete_room(self, room_id: UUID): ... @ret_cls(models.Zone) @@ -313,17 +321,17 @@ class HughApi(SubRouter): @ret_cls(models.Zone) @route("GET", "/resource/zone/{zone_id}") - async def get_zone(self, zone_id: str): + async def get_zone(self, zone_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/zone/{zone_id}") - async def set_zone(self, zone_id: str, **kwargs): + async def set_zone(self, zone_id: UUID, **kwargs): ... @ret_cls(models._Identifier) @route("DELETE", "/resource/zone/{zone_id}") - async def delete_zone(self, zone_id: str): + async def delete_zone(self, zone_id: UUID): ... @ret_cls(models.BridgeHome) @@ -333,12 +341,12 @@ class HughApi(SubRouter): @ret_cls(models.BridgeHome) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models.GroupedLight) @@ -348,12 +356,12 @@ class HughApi(SubRouter): @ret_cls(models.GroupedLight) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models.Device) @@ -363,12 +371,12 @@ class HughApi(SubRouter): @ret_cls(models.Device) @route("GET", "/resource/device/{device_id}") - async def get_device(self, device_id: str): + async def get_device(self, device_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/device/{device_id}") - async def set_device(self, device_id: str, **kwargs): + async def set_device(self, device_id: UUID, **kwargs): ... @ret_cls(models.Bridge) @@ -378,12 +386,12 @@ class HughApi(SubRouter): @ret_cls(models.Bridge) @route("GET", "/resource/bridges/{bridge_id}") - async def get_bridge(self, bridge_id: str): + async def get_bridge(self, bridge_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/bridges/{bridge_id}") - async def set_bridge(self, bridge_id: str, **kwargs): + async def set_bridge(self, bridge_id: UUID, **kwargs): ... @ret_cls(models.DevicePower) @@ -393,12 +401,12 @@ class HughApi(SubRouter): @ret_cls(models.DevicePower) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models.ZigbeeConnectivity) @@ -408,12 +416,12 @@ class HughApi(SubRouter): @ret_cls(models.ZigbeeConnectivity) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models.ZGPConnectivity) @@ -423,12 +431,12 @@ class HughApi(SubRouter): @ret_cls(models.ZGPConnectivity) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models.Motion) @@ -438,12 +446,12 @@ class HughApi(SubRouter): @ret_cls(models.Motion) @route("GET", "/resource/motion/{motion_id}") - async def get_motion(self, motion_id: str): + async def get_motion(self, motion_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/motion/{motion_id}") - async def set_motion(self, motion_id: str, **kwargs): + async def set_motion(self, motion_id: UUID, **kwargs): ... @ret_cls(models.Temperature) @@ -453,12 +461,12 @@ class HughApi(SubRouter): @ret_cls(models.Temperature) @route("GET", "/resource/temperature/{temperature_id}") - async def get_temperature(self, temperature_id: str): + async def get_temperature(self, temperature_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/temperature/{temperature_id}") - async def set_temperature(self, temperature_id: str, **kwargs): + async def set_temperature(self, temperature_id: UUID, **kwargs): ... @ret_cls(models.LightLevel) @@ -468,12 +476,12 @@ class HughApi(SubRouter): @ret_cls(models.LightLevel) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models.Button) @@ -483,12 +491,12 @@ class HughApi(SubRouter): @ret_cls(models.Button) @route("GET", "/resource/button/{button_id}") - async def get_button(self, button_id: str): + async def get_button(self, button_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/button/{button_id}") - async def set_button(self, button_id: str, **kwargs): + async def set_button(self, button_id: UUID, **kwargs): ... @ret_cls(models.BehaviorScript) @@ -498,7 +506,7 @@ class HughApi(SubRouter): @ret_cls(models.BehaviorScript) @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: UUID): ... @ret_cls(models.BehaviorInstance) @@ -513,17 +521,17 @@ class HughApi(SubRouter): @ret_cls(models.BehaviorInstance) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models._Identifier) @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: UUID): ... @ret_cls(models.GeofenceClient) @@ -538,17 +546,17 @@ class HughApi(SubRouter): @ret_cls(models.GeofenceClient) @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: UUID): ... @ret_cls(models._Identifier) @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: UUID, **kwargs): ... @ret_cls(models._Identifier) @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: UUID): ... @ret_cls(models.Geolocation) @@ -558,12 +566,12 @@ class HughApi(SubRouter): @ret_cls(models.Geolocation) @route("GET", "/resource/geolocation/{geolocation_id}") - async def get_geolocation(self, geolocation_id: str): + async def get_geolocation(self, geolocation_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/geolocation/{geolocation_id}") - async def set_geolocation(self, geolocation_id: str, **kwargs): + async def set_geolocation(self, geolocation_id: UUID, **kwargs): ... @ret_cls(models.EntertainmentConfiguration) @@ -581,7 +589,7 @@ class HughApi(SubRouter): "GET", "/resource/entertainment_configuration/{entertainment_configuration_id}" ) async def get_entertainment_configuration( - self, entertainment_configuration_id: str + self, entertainment_configuration_id: UUID ): ... @@ -590,7 +598,7 @@ class HughApi(SubRouter): "PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}" ) async def set_entertainment_configuration( - self, entertainment_configuration_id: str, **kwargs + self, entertainment_configuration_id: UUID, **kwargs ): ... @@ -600,7 +608,7 @@ class HughApi(SubRouter): "/resource/entertainment_configuration/{entertainment_configuration_id}", ) async def delete_entertainment_configuration( - self, entertainment_configuration_id: str + self, entertainment_configuration_id: UUID ): ... @@ -611,12 +619,12 @@ class HughApi(SubRouter): @ret_cls(models.Entertainment) @route("GET", "/resource/entertainment/{entertainment_id}") - async def get_entertainment(self, entertainment_id: str): + async def get_entertainment(self, entertainment_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/entertainment/{entertainment_id}") - async def set_entertainment(self, entertainment_id: str, **kwargs): + async def set_entertainment(self, entertainment_id: UUID, **kwargs): ... @ret_cls(models.Homekit) @@ -626,12 +634,17 @@ class HughApi(SubRouter): @ret_cls(models.Homekit) @route("GET", "/resource/homekit/{homekit_id}") - async def get_homekit(self, homekit_id: str): + async def get_homekit(self, homekit_id: UUID): ... @ret_cls(models._Identifier) @route("PUT", "/resource/homekit/{homekit_id}") - async def set_homekit(self, homekit_id: str, **kwargs): + async def set_homekit( + self, + homekit_id: UUID, + type: Optional[str] = None, + action: Optional[Literal["homekit_reset"]] = None, + ): ... @ret_cls(models.Resource) diff --git a/phlyght/models.py b/phlyght/models.py index 8c169aa..5f7f901 100644 --- a/phlyght/models.py +++ b/phlyght/models.py @@ -1,4 +1,4 @@ -from typing import Any, Literal, Optional, Generic, TypeVar +from typing import Any, Literal, Optional, Generic, TypeAlias, TypeVar from uuid import UUID from dataclasses import dataclass from enum import Enum, auto @@ -7,6 +7,7 @@ from pydantic import BaseModel, Field __all__ = ( "Archetype", + "RoomType", "Room", "Light", "Scene", @@ -27,11 +28,64 @@ __all__ = ( "GeofenceClient", "Geolocation", "EntertainmentConfiguration", + "Entertainment", + "Resource", + "Homekit", ) +_T_M: TypeAlias = "Archetype | Room | Light | Scene | Zone | BridgeHome | GroupedLight | Device | Bridge | DevicePower | ZigbeeConnectivity | ZGPConnectivity | Motion | Temperature | LightLevel | Button | BehaviorScript | BehaviorInstance | GeofenceClient | Geolocation | EntertainmentConfiguration | Entertainment | Resource | Homekit" + + _T = TypeVar("_T") +class RoomType(Enum): + @staticmethod + def _generate_next_value_(name, start, count, last_values): + 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() + + class Archetype(Enum): @staticmethod def _generate_next_value_(name, start, count, last_values): @@ -109,7 +163,7 @@ class _Identifier: @dataclass(frozen=True) class _Metadata: name: str - archetype: Optional[Archetype] = Archetype.UNKNOWN_ARCHETYPE + archetype: Optional[Archetype | RoomType] = Archetype.UNKNOWN_ARCHETYPE image: Optional[_Identifier] = Field(None, repr=False) @@ -165,7 +219,9 @@ class _Lights(_HueGrouped): class Light(Generic[_T], BaseModel): id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field( + ..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$" + ) owner: _Identifier metadata: _Metadata on: _On = Field(repr=False) @@ -217,7 +273,9 @@ class _Scenes(_HueGrouped): class Scene(BaseModel): id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field( + ..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$" + ) metadata: _Metadata group: _Identifier actions: list["_Scenes.Actions"] @@ -233,7 +291,7 @@ _Scenes.update() class Room(BaseModel): type: Literal["room"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") services: list[_Identifier] metadata: _Metadata children: list[_Identifier] @@ -242,7 +300,7 @@ class Room(BaseModel): class Zone(BaseModel): type: Literal["zone"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") services: list[_Identifier] metadata: _Metadata children: list[_Identifier] @@ -251,7 +309,7 @@ class Zone(BaseModel): 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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") services: list[_Identifier] children: list[_Identifier] @@ -259,9 +317,9 @@ class BridgeHome(BaseModel): 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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") on: _On = Field(repr=False) - alert: list[str] + alert: dict[str, list[str]] class _ProductData(BaseModel): @@ -277,7 +335,7 @@ class _ProductData(BaseModel): class Device(BaseModel): type: Literal["device"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") services: list[_Identifier] metadata: _Metadata product_data: _ProductData @@ -286,20 +344,20 @@ class Device(BaseModel): class Bridge(BaseModel): type: Literal["bridge"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + 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] class _PowerState(BaseModel): battery_state: Literal["normal", "low", "critical"] - battery_level: float = Field(lt=100.0, gt=0.0) + battery_level: float = Field(le=100.0, ge=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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier power_state: _PowerState @@ -307,7 +365,7 @@ class DevicePower(BaseModel): 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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier status: Literal[ "connected", "disconnected", "connectivity_issue", "unidirectional_incoming" @@ -318,7 +376,7 @@ class ZigbeeConnectivity(BaseModel): 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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier status: Literal[ "connected", "disconnected", "connectivity_issue", "unidirectional_incoming" @@ -329,7 +387,7 @@ class ZGPConnectivity(BaseModel): class Motion(BaseModel): type: Literal["motion"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier enabled: bool motion: dict[str, bool] @@ -343,7 +401,7 @@ class _Temp(BaseModel): class Temperature(BaseModel): type: Literal["temperature"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier enabled: bool temperature: _Temp @@ -357,7 +415,7 @@ class _Light(BaseModel): 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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier enabled: bool light: _Light @@ -366,7 +424,7 @@ class LightLevel(BaseModel): class Button(BaseModel): type: Literal["button"] id: UUID - id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") owner: _Identifier metadata: dict[Literal["control_id"], int] button: dict[ @@ -384,7 +442,7 @@ class Button(BaseModel): 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})?$") + id_v1: Optional[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] @@ -402,7 +460,7 @@ class _Dependee(BaseModel): class BehaviorInstance(BaseModel): type: Literal["behavior_instance"] id: UUID - id_v1: str = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") script_id: str enabled: bool state: Optional[dict[str, Any]] @@ -417,14 +475,14 @@ class BehaviorInstance(BaseModel): 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})?$") + id_v1: Optional[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})?$") + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") is_configured: bool = False @@ -433,29 +491,81 @@ class _StreamProxy(BaseModel): node: _Identifier +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) + + +class _SegmentRef(BaseModel): + service: _Identifier + index: int + + +class _EntertainmentChannel(BaseModel): + channel_id: int = Field(ge=0, le=255) + position: _XYZ + members: list[_SegmentRef] + + +class _ServiceLocation(BaseModel): + service: _Identifier + position: _XYZ + positions: list[_XYZ] = Field(max_items=2, min_items=1) + + +class _EntertainmentLocation(BaseModel): + service_location: Optional[list[_ServiceLocation]] = [] + + 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})?$") + id_v1: Optional[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 + active_streamer: Optional[_Identifier] = None stream_proxy: _StreamProxy - ... # TODO: finish the last 4 objects + channels: list[_EntertainmentChannel] + locations: Optional[_EntertainmentLocation] = None + light_services: list[_Identifier] + + +class _Segment(BaseModel): + start: int = Field(..., ge=0) + length: int = Field(..., ge=1) + + +class _SegmentManager(BaseModel): + configurable: bool + max_segments: int = Field(..., ge=1) + segments: list[_Segment] class Entertainment(BaseModel): - ... + type: Literal["entertainment"] + id: UUID + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + owner: _Identifier + renderer: bool + proxy: bool + max_streams: Optional[int] = Field(1, ge=1) + segments: Optional[_SegmentManager] = None class Homekit(BaseModel): - ... + id: UUID + type: Optional[str] + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") + status: Literal["paired", "pairing", "unpaired"] class Resource(BaseModel): - ... + id: UUID + type: Optional[str] + id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$") Light = _Lights.Light diff --git a/test.py b/test.py index da85068..caef8ca 100644 --- a/test.py +++ b/test.py @@ -9,20 +9,31 @@ except ImportError: async def main(): - router = Router("user api key") + router = Router("your api key") - lights = await router.get_lights() - for light in lights: - detailed_light = await router.get_light(light_id=str(light.id)) # noqa - print(light, detailed_light) - - scenes = await router.get_scenes() - for scene in scenes: - print(scene) - - devices = await router.get_devices() - for device in devices: - print(device) + print(await router.get_lights()) + print(await router.get_scenes()) + print(await router.get_devices()) + print(await router.get_rooms()) + print(await router.get_zones()) + print(await router.get_bridge_homes()) + print(await router.get_grouped_lights()) + print(await router.get_bridges()) + print(await router.get_device_powers()) + print(await router.get_zigbee_connectivities()) + print(await router.get_zgb_connectivities()) + print(await router.get_motions()) + print(await router.get_temperatures()) + print(await router.get_light_levels()) + print(await router.get_buttons()) + print(await router.get_behavior_scripts()) + print(await router.get_behavior_instances()) + print(await router.get_geofence_clients()) + print(await router.get_geolocations()) + print(await router.get_entertainment_configurations()) + print(await router.get_entertainments()) + print(await router.get_homekits()) + print(await router.get_resources()) run(main())