info
This commit is contained in:
parent
5c930d7742
commit
353adfddd2
9
README
Normal file
9
README
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Phlyght
|
||||||
|
|
||||||
|
This is an async implementation of the v2 Philips Hue API.
|
||||||
|
|
||||||
|
For a brief example of how to use, see [here](test.py)
|
||||||
|
|
||||||
|
## Depends
|
||||||
|
|
||||||
|
pydantic, httpx, yarl
|
@ -1,3 +1,49 @@
|
|||||||
__all__ = ("Router", "route", "RouterMeta", "SubRouter", "HughApi")
|
from .api import Router
|
||||||
|
from .models import (
|
||||||
|
Archetype,
|
||||||
|
Room,
|
||||||
|
Light,
|
||||||
|
Scene,
|
||||||
|
Zone,
|
||||||
|
BridgeHome,
|
||||||
|
GroupedLight,
|
||||||
|
Device,
|
||||||
|
Bridge,
|
||||||
|
DevicePower,
|
||||||
|
ZigbeeConnectivity,
|
||||||
|
ZGPConnectivity,
|
||||||
|
Motion,
|
||||||
|
Temperature,
|
||||||
|
LightLevel,
|
||||||
|
Button,
|
||||||
|
BehaviorScript,
|
||||||
|
BehaviorInstance,
|
||||||
|
GeofenceClient,
|
||||||
|
Geolocation,
|
||||||
|
EntertainmentConfiguration,
|
||||||
|
)
|
||||||
|
|
||||||
from .api import Router, route, RouterMeta, SubRouter, HughApi
|
__all__ = (
|
||||||
|
"Router",
|
||||||
|
"Archetype",
|
||||||
|
"Room",
|
||||||
|
"Light",
|
||||||
|
"Scene",
|
||||||
|
"Zone",
|
||||||
|
"BridgeHome",
|
||||||
|
"GroupedLight",
|
||||||
|
"Device",
|
||||||
|
"Bridge",
|
||||||
|
"DevicePower",
|
||||||
|
"ZigbeeConnectivity",
|
||||||
|
"ZGPConnectivity",
|
||||||
|
"Motion",
|
||||||
|
"Temperature",
|
||||||
|
"LightLevel",
|
||||||
|
"Button",
|
||||||
|
"BehaviorScript",
|
||||||
|
"BehaviorInstance",
|
||||||
|
"GeofenceClient",
|
||||||
|
"Geolocation",
|
||||||
|
"EntertainmentConfiguration",
|
||||||
|
)
|
||||||
|
@ -6,9 +6,16 @@ from typing import Any, Literal, Optional
|
|||||||
|
|
||||||
from httpx import AsyncClient
|
from httpx import AsyncClient
|
||||||
from httpx._urls import URL as _URL
|
from httpx._urls import URL as _URL
|
||||||
from yarl import URL as UR
|
|
||||||
|
|
||||||
# from rich import print
|
try:
|
||||||
|
from yarl import URL as UR
|
||||||
|
except ImportError:
|
||||||
|
...
|
||||||
|
|
||||||
|
try:
|
||||||
|
from rich import print # noqa
|
||||||
|
except ImportError:
|
||||||
|
...
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
@ -32,10 +39,17 @@ def get_url_args(url):
|
|||||||
|
|
||||||
class URL(_URL):
|
class URL(_URL):
|
||||||
def __truediv__(self, other):
|
def __truediv__(self, other):
|
||||||
|
# Why am i doing this? good question.
|
||||||
|
try:
|
||||||
return URL(str(UR(f"{self}") / other.lstrip("/")))
|
return URL(str(UR(f"{self}") / other.lstrip("/")))
|
||||||
|
except NameError:
|
||||||
|
return URL(str(f"{self}/{other.lstrip('/')}"))
|
||||||
|
|
||||||
def __floordiv__(self, other):
|
def __floordiv__(self, other):
|
||||||
|
try:
|
||||||
return URL(str(UR(f"{self}") / other.lstrip("/")))
|
return URL(str(UR(f"{self}") / other.lstrip("/")))
|
||||||
|
except NameError:
|
||||||
|
return URL(str(f"{self}/{other.lstrip('/')}"))
|
||||||
|
|
||||||
|
|
||||||
def ret_cls(cls):
|
def ret_cls(cls):
|
||||||
@ -218,7 +232,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_light(self, light_id: str):
|
async def get_light(self, light_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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,
|
||||||
@ -242,7 +256,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_scenes(self):
|
async def get_scenes(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models._Identifier)
|
||||||
@route("POST", "/resource/scene")
|
@route("POST", "/resource/scene")
|
||||||
async def create_scene(self, **kwargs):
|
async def create_scene(self, **kwargs):
|
||||||
...
|
...
|
||||||
@ -252,12 +266,12 @@ class HughApi(SubRouter):
|
|||||||
async def get_scene(self, scene_id: str):
|
async def get_scene(self, scene_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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)
|
@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):
|
||||||
...
|
...
|
||||||
@ -267,7 +281,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_rooms(self):
|
async def get_rooms(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models._Identifier)
|
||||||
@route("POST", "/resource/room")
|
@route("POST", "/resource/room")
|
||||||
async def create_room(self, **kwargs):
|
async def create_room(self, **kwargs):
|
||||||
...
|
...
|
||||||
@ -277,12 +291,12 @@ class HughApi(SubRouter):
|
|||||||
async def get_room(self, room_id: str):
|
async def get_room(self, room_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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)
|
@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):
|
||||||
...
|
...
|
||||||
@ -292,7 +306,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_zones(self):
|
async def get_zones(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models._Identifier)
|
||||||
@route("POST", "/resource/zone")
|
@route("POST", "/resource/zone")
|
||||||
async def create_zone(self, **kwargs):
|
async def create_zone(self, **kwargs):
|
||||||
...
|
...
|
||||||
@ -302,12 +316,12 @@ class HughApi(SubRouter):
|
|||||||
async def get_zone(self, zone_id: str):
|
async def get_zone(self, zone_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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)
|
@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):
|
||||||
...
|
...
|
||||||
@ -322,7 +336,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_bridge_home(self, bridge_home_id: str):
|
async def get_bridge_home(self, bridge_home_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -337,7 +351,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_grouped_light(self, grouped_light_id: str):
|
async def get_grouped_light(self, grouped_light_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -352,7 +366,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_device(self, device_id: str):
|
async def get_device(self, device_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -367,7 +381,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_bridge(self, bridge_id: str):
|
async def get_bridge(self, bridge_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -382,7 +396,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_device_power(self, device_power_id: str):
|
async def get_device_power(self, device_power_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -397,7 +411,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_zigbee_connectivity(self, zigbee_connectivity_id: str):
|
async def get_zigbee_connectivity(self, zigbee_connectivity_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -412,7 +426,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_zgb_connectivity(self, zgb_connectivity_id: str):
|
async def get_zgb_connectivity(self, zgb_connectivity_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -427,7 +441,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_motion(self, motion_id: str):
|
async def get_motion(self, motion_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -442,7 +456,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_temperature(self, temperature_id: str):
|
async def get_temperature(self, temperature_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -457,7 +471,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_light_level(self, light_level_id: str):
|
async def get_light_level(self, light_level_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -472,7 +486,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_button(self, button_id: str):
|
async def get_button(self, button_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -492,7 +506,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_behavior_instances(self):
|
async def get_behavior_instances(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -502,12 +516,12 @@ class HughApi(SubRouter):
|
|||||||
async def get_behavior_instance(self, behavior_instance_id: str):
|
async def get_behavior_instance(self, behavior_instance_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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)
|
@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):
|
||||||
...
|
...
|
||||||
@ -517,7 +531,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_geofence_clients(self):
|
async def get_geofence_clients(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -527,12 +541,12 @@ class HughApi(SubRouter):
|
|||||||
async def get_geofence_client(self, geofence_client_id: str):
|
async def get_geofence_client(self, geofence_client_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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)
|
@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):
|
||||||
...
|
...
|
||||||
@ -547,7 +561,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_geolocation(self, geolocation_id: str):
|
async def get_geolocation(self, geolocation_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -557,7 +571,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_entertainment_configurations(self):
|
async def get_entertainment_configurations(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -571,7 +585,7 @@ class HughApi(SubRouter):
|
|||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models._Identifier)
|
||||||
@route(
|
@route(
|
||||||
"PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}"
|
"PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}"
|
||||||
)
|
)
|
||||||
@ -580,7 +594,7 @@ class HughApi(SubRouter):
|
|||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models._Identifier)
|
||||||
@route(
|
@route(
|
||||||
"DELETE",
|
"DELETE",
|
||||||
"/resource/entertainment_configuration/{entertainment_configuration_id}",
|
"/resource/entertainment_configuration/{entertainment_configuration_id}",
|
||||||
@ -600,7 +614,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_entertainment(self, entertainment_id: str):
|
async def get_entertainment(self, entertainment_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
@ -615,7 +629,7 @@ class HughApi(SubRouter):
|
|||||||
async def get_homekit(self, homekit_id: str):
|
async def get_homekit(self, homekit_id: str):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@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):
|
||||||
...
|
...
|
||||||
|
@ -1,11 +1,34 @@
|
|||||||
__all__ = ("Room", "Light", "Scene")
|
|
||||||
|
|
||||||
from typing import Any, Literal, Optional, Generic, TypeVar
|
from typing import Any, Literal, Optional, Generic, TypeVar
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"Archetype",
|
||||||
|
"Room",
|
||||||
|
"Light",
|
||||||
|
"Scene",
|
||||||
|
"Zone",
|
||||||
|
"BridgeHome",
|
||||||
|
"GroupedLight",
|
||||||
|
"Device",
|
||||||
|
"Bridge",
|
||||||
|
"DevicePower",
|
||||||
|
"ZigbeeConnectivity",
|
||||||
|
"ZGPConnectivity",
|
||||||
|
"Motion",
|
||||||
|
"Temperature",
|
||||||
|
"LightLevel",
|
||||||
|
"Button",
|
||||||
|
"BehaviorScript",
|
||||||
|
"BehaviorInstance",
|
||||||
|
"GeofenceClient",
|
||||||
|
"Geolocation",
|
||||||
|
"EntertainmentConfiguration",
|
||||||
|
)
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
|
|
||||||
@ -55,70 +78,65 @@ class Archetype(Enum):
|
|||||||
HUE_SIGNE = auto()
|
HUE_SIGNE = auto()
|
||||||
|
|
||||||
|
|
||||||
class _id_v1(str):
|
|
||||||
def __get__(self, instance, owner):
|
|
||||||
return Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$)")
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Dimming:
|
class _Dimming:
|
||||||
brightness: float
|
brightness: float
|
||||||
min_dim_level: Optional[float] = Field(0, repr=False)
|
min_dim_level: Optional[float] = Field(0, repr=False)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class XY:
|
class _XY:
|
||||||
x: float
|
x: float
|
||||||
y: float
|
y: float
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class On:
|
class _On:
|
||||||
on: bool = Field(..., alias="on")
|
on: bool = Field(..., alias="on")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ColorPoint:
|
class _ColorPoint:
|
||||||
xy: XY
|
xy: _XY
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Identifier:
|
class _Identifier:
|
||||||
rid: str
|
rid: str
|
||||||
rtype: str
|
rtype: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Metadata:
|
class _Metadata:
|
||||||
name: str
|
name: str
|
||||||
archetype: Optional[Archetype] = Archetype.UNKNOWN_ARCHETYPE
|
archetype: Optional[Archetype] = Archetype.UNKNOWN_ARCHETYPE
|
||||||
image: Optional[Identifier] = Field(None, repr=False)
|
image: Optional[_Identifier] = Field(None, repr=False)
|
||||||
|
|
||||||
|
|
||||||
class HueGroupedMeta(type):
|
class _HueGroupedMeta(type):
|
||||||
def update(cls):
|
def update(cls):
|
||||||
for v in cls.__dict__.values():
|
for v in cls.__dict__.values():
|
||||||
if hasattr(v, "update_forward_refs"):
|
if hasattr(v, "update_forward_refs"):
|
||||||
v.update_forward_refs()
|
v.update_forward_refs()
|
||||||
|
|
||||||
|
|
||||||
class HueGrouped(metaclass=HueGroupedMeta):
|
class _HueGrouped(metaclass=_HueGroupedMeta):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
class _Lights(HueGrouped):
|
class _Lights(_HueGrouped):
|
||||||
class ColorTemperature(BaseModel):
|
class ColorTemperature(BaseModel):
|
||||||
mirek: Optional[int]
|
mirek: Optional[int]
|
||||||
mirek_valid: bool
|
mirek_valid: bool
|
||||||
mirek_schema: dict[str, float]
|
mirek_schema: dict[str, float]
|
||||||
|
|
||||||
class Gamut(BaseModel):
|
class Gamut(BaseModel):
|
||||||
red: XY
|
red: _XY
|
||||||
green: XY
|
green: _XY
|
||||||
blue: XY
|
blue: _XY
|
||||||
|
|
||||||
class Color(BaseModel):
|
class Color(BaseModel):
|
||||||
xy: 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"]
|
||||||
|
|
||||||
@ -129,7 +147,7 @@ class _Lights(HueGrouped):
|
|||||||
speed_valid: bool
|
speed_valid: bool
|
||||||
|
|
||||||
class Gradient(BaseModel):
|
class Gradient(BaseModel):
|
||||||
points: list[ColorPoint]
|
points: list[_ColorPoint]
|
||||||
points_capable: int
|
points_capable: int
|
||||||
|
|
||||||
class Effects(BaseModel):
|
class Effects(BaseModel):
|
||||||
@ -148,10 +166,10 @@ class _Lights(HueGrouped):
|
|||||||
class Light(Generic[_T], BaseModel):
|
class Light(Generic[_T], BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
metadata: Metadata
|
metadata: _Metadata
|
||||||
on: On = Field(repr=False)
|
on: _On = Field(repr=False)
|
||||||
dimming: 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]
|
||||||
@ -168,40 +186,40 @@ class _Lights(HueGrouped):
|
|||||||
_Lights.update()
|
_Lights.update()
|
||||||
|
|
||||||
|
|
||||||
class _Scenes(HueGrouped):
|
class _Scenes(_HueGrouped):
|
||||||
class Action(BaseModel):
|
class Action(BaseModel):
|
||||||
on: Optional[On]
|
on: Optional[_On]
|
||||||
dimming: Optional[Dimming]
|
dimming: Optional[_Dimming]
|
||||||
color: Optional[ColorPoint]
|
color: Optional[_ColorPoint]
|
||||||
color_temperature: Optional[dict[str, float]]
|
color_temperature: Optional[dict[str, float]]
|
||||||
gradient: Optional[dict[str, list[ColorPoint]]]
|
gradient: Optional[dict[str, list[_ColorPoint]]]
|
||||||
effects: Optional[dict[str, str]]
|
effects: Optional[dict[str, str]]
|
||||||
dynamics: Optional[dict[str, float]]
|
dynamics: Optional[dict[str, float]]
|
||||||
|
|
||||||
class Actions(BaseModel):
|
class Actions(BaseModel):
|
||||||
target: Identifier
|
target: _Identifier
|
||||||
action: "_Scenes.Action" = Field(repr=False)
|
action: "_Scenes.Action" = Field(repr=False)
|
||||||
dimming: Optional[Dimming]
|
dimming: Optional[_Dimming]
|
||||||
color: Optional[ColorPoint]
|
color: Optional[_ColorPoint]
|
||||||
|
|
||||||
class PaletteColor(BaseModel):
|
class PaletteColor(BaseModel):
|
||||||
color: ColorPoint
|
color: _ColorPoint
|
||||||
dimming: Dimming
|
dimming: _Dimming
|
||||||
|
|
||||||
class PaletteTemperature(BaseModel):
|
class PaletteTemperature(BaseModel):
|
||||||
color_temperature: dict[str, float]
|
color_temperature: dict[str, float]
|
||||||
dimming: Dimming
|
dimming: _Dimming
|
||||||
|
|
||||||
class Palette(BaseModel):
|
class Palette(BaseModel):
|
||||||
color: list["_Scenes.PaletteColor"]
|
color: list["_Scenes.PaletteColor"]
|
||||||
dimming: Optional[list[Dimming]]
|
dimming: Optional[list[_Dimming]]
|
||||||
color_temperature: list["_Scenes.PaletteTemperature"]
|
color_temperature: list["_Scenes.PaletteTemperature"]
|
||||||
|
|
||||||
class Scene(BaseModel):
|
class Scene(BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
metadata: Metadata
|
metadata: _Metadata
|
||||||
group: Identifier
|
group: _Identifier
|
||||||
actions: list["_Scenes.Actions"]
|
actions: list["_Scenes.Actions"]
|
||||||
palette: "_Scenes.Palette"
|
palette: "_Scenes.Palette"
|
||||||
speed: float
|
speed: float
|
||||||
@ -215,38 +233,38 @@ _Scenes.update()
|
|||||||
class Room(BaseModel):
|
class Room(BaseModel):
|
||||||
type: Literal["room"]
|
type: Literal["room"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: _id_v1
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
services: list[Identifier]
|
services: list[_Identifier]
|
||||||
metadata: Metadata
|
metadata: _Metadata
|
||||||
children: list[Identifier]
|
children: list[_Identifier]
|
||||||
|
|
||||||
|
|
||||||
class Zone(BaseModel):
|
class Zone(BaseModel):
|
||||||
type: Literal["zone"]
|
type: Literal["zone"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
services: list[Identifier]
|
services: list[_Identifier]
|
||||||
metadata: Metadata
|
metadata: _Metadata
|
||||||
children: list[Identifier]
|
children: list[_Identifier]
|
||||||
|
|
||||||
|
|
||||||
class BridgeHome(BaseModel):
|
class BridgeHome(BaseModel):
|
||||||
type: Literal["bridge_home"]
|
type: Literal["bridge_home"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
services: list[Identifier]
|
services: list[_Identifier]
|
||||||
children: list[Identifier]
|
children: list[_Identifier]
|
||||||
|
|
||||||
|
|
||||||
class GroupedLight(BaseModel):
|
class GroupedLight(BaseModel):
|
||||||
type: Literal["grouped_light"]
|
type: Literal["grouped_light"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
on: On = Field(repr=False)
|
on: _On = Field(repr=False)
|
||||||
alert: list[str]
|
alert: list[str]
|
||||||
|
|
||||||
|
|
||||||
class ProductData(BaseModel):
|
class _ProductData(BaseModel):
|
||||||
model_id: str
|
model_id: str
|
||||||
manufacturer_name: str
|
manufacturer_name: str
|
||||||
product_name: str
|
product_name: str
|
||||||
@ -260,9 +278,9 @@ class Device(BaseModel):
|
|||||||
type: Literal["device"]
|
type: Literal["device"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
services: list[Identifier]
|
services: list[_Identifier]
|
||||||
metadata: Metadata
|
metadata: _Metadata
|
||||||
product_data: ProductData
|
product_data: _ProductData
|
||||||
|
|
||||||
|
|
||||||
class Bridge(BaseModel):
|
class Bridge(BaseModel):
|
||||||
@ -273,7 +291,7 @@ class Bridge(BaseModel):
|
|||||||
time_zone: dict[str, str]
|
time_zone: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
class PowerState(BaseModel):
|
class _PowerState(BaseModel):
|
||||||
battery_state: Literal["normal", "low", "critical"]
|
battery_state: Literal["normal", "low", "critical"]
|
||||||
battery_level: float = Field(lt=100.0, gt=0.0)
|
battery_level: float = Field(lt=100.0, gt=0.0)
|
||||||
|
|
||||||
@ -282,15 +300,15 @@ class DevicePower(BaseModel):
|
|||||||
type: Literal["device_power"]
|
type: Literal["device_power"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
power_state: PowerState
|
power_state: _PowerState
|
||||||
|
|
||||||
|
|
||||||
class ZigbeeConnectivity(BaseModel):
|
class ZigbeeConnectivity(BaseModel):
|
||||||
type: Literal["zigbee_connectivity"]
|
type: Literal["zigbee_connectivity"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
status: Literal[
|
status: Literal[
|
||||||
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
|
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
|
||||||
]
|
]
|
||||||
@ -301,7 +319,7 @@ class ZGPConnectivity(BaseModel):
|
|||||||
type: Literal["zgp_connectivity"]
|
type: Literal["zgp_connectivity"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
status: Literal[
|
status: Literal[
|
||||||
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
|
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
|
||||||
]
|
]
|
||||||
@ -312,7 +330,7 @@ class Motion(BaseModel):
|
|||||||
type: Literal["motion"]
|
type: Literal["motion"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
enabled: bool
|
enabled: bool
|
||||||
motion: dict[str, bool]
|
motion: dict[str, bool]
|
||||||
|
|
||||||
@ -326,7 +344,7 @@ class Temperature(BaseModel):
|
|||||||
type: Literal["temperature"]
|
type: Literal["temperature"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
enabled: bool
|
enabled: bool
|
||||||
temperature: _Temp
|
temperature: _Temp
|
||||||
|
|
||||||
@ -340,7 +358,7 @@ class LightLevel(BaseModel):
|
|||||||
type: Literal["light_level"]
|
type: Literal["light_level"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
enabled: bool
|
enabled: bool
|
||||||
light: _Light
|
light: _Light
|
||||||
|
|
||||||
@ -349,7 +367,7 @@ class Button(BaseModel):
|
|||||||
type: Literal["button"]
|
type: Literal["button"]
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: str = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
||||||
owner: Identifier
|
owner: _Identifier
|
||||||
metadata: dict[Literal["control_id"], int]
|
metadata: dict[Literal["control_id"], int]
|
||||||
button: dict[
|
button: dict[
|
||||||
Literal["last_event"],
|
Literal["last_event"],
|
||||||
@ -375,9 +393,9 @@ class BehaviorScript(BaseModel):
|
|||||||
metadata: dict[str, str]
|
metadata: dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
class Dependee(BaseModel):
|
class _Dependee(BaseModel):
|
||||||
type: str
|
type: str
|
||||||
target: Identifier
|
target: _Identifier
|
||||||
level: str
|
level: str
|
||||||
|
|
||||||
|
|
||||||
@ -389,7 +407,7 @@ class BehaviorInstance(BaseModel):
|
|||||||
enabled: bool
|
enabled: bool
|
||||||
state: Optional[dict[str, Any]]
|
state: Optional[dict[str, Any]]
|
||||||
configuration: dict[str, Any]
|
configuration: dict[str, Any]
|
||||||
dependees: list[Dependee]
|
dependees: list[_Dependee]
|
||||||
status: Literal["initializing", "running", "disabled", "errored"]
|
status: Literal["initializing", "running", "disabled", "errored"]
|
||||||
last_error: str
|
last_error: str
|
||||||
metadata: dict[Literal["name"], str]
|
metadata: dict[Literal["name"], str]
|
||||||
@ -410,9 +428,9 @@ class Geolocation(BaseModel):
|
|||||||
is_configured: bool = False
|
is_configured: bool = False
|
||||||
|
|
||||||
|
|
||||||
class StreamProxy(BaseModel):
|
class _StreamProxy(BaseModel):
|
||||||
mode: Literal["auto", "manual"]
|
mode: Literal["auto", "manual"]
|
||||||
node: Identifier
|
node: _Identifier
|
||||||
|
|
||||||
|
|
||||||
class EntertainmentConfiguration(BaseModel):
|
class EntertainmentConfiguration(BaseModel):
|
||||||
@ -423,8 +441,8 @@ class EntertainmentConfiguration(BaseModel):
|
|||||||
name: Optional[str] = ""
|
name: Optional[str] = ""
|
||||||
configuration_type: Literal["screen", "monitor", "music", "3dspace", "other"]
|
configuration_type: Literal["screen", "monitor", "music", "3dspace", "other"]
|
||||||
status: Literal["active", "inactive"]
|
status: Literal["active", "inactive"]
|
||||||
active_streamer: Identifier
|
active_streamer: _Identifier
|
||||||
stream_proxy: StreamProxy
|
stream_proxy: _StreamProxy
|
||||||
... # TODO: finish the last 4 objects
|
... # TODO: finish the last 4 objects
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,14 +6,13 @@ authors = ["Ra <ra@tcp.direct>"]
|
|||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.11,<4.0.0"
|
python = ">=3.11,<4.0.0"
|
||||||
rich = ">=12.6.0"
|
httpx = ">=0.23.1"
|
||||||
aioredis = ">=2.0.1"
|
pydantic = ">=1.10.2"
|
||||||
httpx = "^0.23.1"
|
yarl = ">=1.8.1"
|
||||||
yarl = "^1.8.1"
|
|
||||||
pydantic = "^1.10.2"
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
black = ">=22.10.0"
|
black = ">=22.10.0"
|
||||||
|
rich = ">=12.6.0"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
12
test.py
12
test.py
@ -1,16 +1,20 @@
|
|||||||
from asyncio import run
|
from asyncio import run
|
||||||
from rich import print
|
|
||||||
|
|
||||||
from phlyght.api import Router
|
from phlyght.api import Router
|
||||||
|
|
||||||
|
try:
|
||||||
|
from rich import print # noqa
|
||||||
|
except ImportError:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
router = Router("Your user key with the hue bridge")
|
router = Router("user api key")
|
||||||
|
|
||||||
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)) # noqa
|
||||||
print(detailed_light)
|
print(light, detailed_light)
|
||||||
|
|
||||||
scenes = await router.get_scenes()
|
scenes = await router.get_scenes()
|
||||||
for scene in scenes:
|
for scene in scenes:
|
||||||
|
Loading…
Reference in New Issue
Block a user