events, few entities fixed
This commit is contained in:
parent
5be9ef5543
commit
61cae385c3
@ -1,49 +1,4 @@
|
|||||||
from .http import Router
|
from .http import Router
|
||||||
from .models import (
|
from .models import Archetype, HueEntsV2
|
||||||
Archetype,
|
|
||||||
Room,
|
|
||||||
Light,
|
|
||||||
Scene,
|
|
||||||
Zone,
|
|
||||||
BridgeHome,
|
|
||||||
GroupedLight,
|
|
||||||
Device,
|
|
||||||
Bridge,
|
|
||||||
DevicePower,
|
|
||||||
ZigbeeConnectivity,
|
|
||||||
ZGPConnectivity,
|
|
||||||
Motion,
|
|
||||||
Temperature,
|
|
||||||
LightLevel,
|
|
||||||
Button,
|
|
||||||
BehaviorScript,
|
|
||||||
BehaviorInstance,
|
|
||||||
GeofenceClient,
|
|
||||||
Geolocation,
|
|
||||||
EntertainmentConfiguration,
|
|
||||||
)
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = ("Router", "Archetype", "HueEntsV2")
|
||||||
"Router",
|
|
||||||
"Archetype",
|
|
||||||
"Room",
|
|
||||||
"Light",
|
|
||||||
"Scene",
|
|
||||||
"Zone",
|
|
||||||
"BridgeHome",
|
|
||||||
"GroupedLight",
|
|
||||||
"Device",
|
|
||||||
"Bridge",
|
|
||||||
"DevicePower",
|
|
||||||
"ZigbeeConnectivity",
|
|
||||||
"ZGPConnectivity",
|
|
||||||
"Motion",
|
|
||||||
"Temperature",
|
|
||||||
"LightLevel",
|
|
||||||
"Button",
|
|
||||||
"BehaviorScript",
|
|
||||||
"BehaviorInstance",
|
|
||||||
"GeofenceClient",
|
|
||||||
"Geolocation",
|
|
||||||
"EntertainmentConfiguration",
|
|
||||||
)
|
|
||||||
|
442
phlyght/http.py
442
phlyght/http.py
@ -1,7 +1,7 @@
|
|||||||
__all__ = ("Router", "route", "RouterMeta", "SubRouter", "HughApi")
|
__all__ = ("Router", "route", "RouterMeta", "SubRouter", "HueAPIv2")
|
||||||
|
|
||||||
from asyncio import get_running_loop, sleep
|
from asyncio import get_running_loop, sleep
|
||||||
from inspect import signature
|
from inspect import signature, Parameter
|
||||||
from re import compile
|
from re import compile
|
||||||
from typing import Any, Literal, Optional
|
from typing import Any, Literal, Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
@ -9,6 +9,7 @@ from time import time
|
|||||||
|
|
||||||
from httpx import AsyncClient
|
from httpx import AsyncClient
|
||||||
from httpx._urls import URL as _URL
|
from httpx._urls import URL as _URL
|
||||||
|
from httpx._exceptions import ReadTimeout as HTTPxReadTimeout
|
||||||
from httpcore._exceptions import ReadTimeout
|
from httpcore._exceptions import ReadTimeout
|
||||||
from attrs import define, field
|
from attrs import define, field
|
||||||
from json import loads
|
from json import loads
|
||||||
@ -26,25 +27,25 @@ except ImportError:
|
|||||||
...
|
...
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
from .models import HueEntsV2
|
||||||
|
|
||||||
|
|
||||||
STR_FMT_RE = compile(r"""(?=(\{([^:]+)(?::([^}]+))?\}))\1""")
|
STR_FMT_RE = compile(r"""(?=(\{([^:]+)(?::([^}]+))?\}))\1""")
|
||||||
URL_TYPES = {"str": str, "int": int}
|
URL_TYPES = {"str": str, "int": int}
|
||||||
IP_RE = compile(r"(?=(?:(?<=[^0-9])|)((?:[0-9]{,3}\.){3}[0-9]{,3}))\1")
|
IP_RE = compile(r"(?=(?:(?<=[^0-9])|)((?:[0-9]{,3}\.){3}[0-9]{,3}))\1")
|
||||||
|
|
||||||
MSG_RE = compile(
|
MSG_RE_BYTES = compile(
|
||||||
b"""(?=((?P<hello>^hi\\n\\n$)|^id:\\s(?P<id>[0-9]+:\\d*?)\\ndata:(?P<data>[^$]+)\\n\\n))\\1"""
|
b"""(?=((?P<hello>^: hi\\n\\n$)|^id:\\s(?P<id>[0-9]+:\\d*?)\\ndata:(?P<data>[^$]+)\\n\\n))\\1"""
|
||||||
|
)
|
||||||
|
MSG_RE_TEXT = compile(
|
||||||
|
r"(?=((?P<hello>^: hi\n\n$)|^id:\s(?P<id>[0-9]+:\d*?)\ndata:(?P<data>[^$]+)\n\n))\1"
|
||||||
)
|
)
|
||||||
TYPE_CACHE = {}
|
TYPE_CACHE = {}
|
||||||
|
|
||||||
for k in models.__all__:
|
for k, v in HueEntsV2.__dict__.items():
|
||||||
if (
|
if k.startswith("__") or not issubclass(v, BaseModel):
|
||||||
k == "Literal"
|
|
||||||
or k.startswith("_")
|
|
||||||
or not issubclass(getattr(models, k), BaseModel)
|
|
||||||
):
|
|
||||||
continue
|
continue
|
||||||
TYPE_CACHE[getattr(models, k).__fields__["type"].default] = getattr(models, k)
|
TYPE_CACHE[getattr(v, "type")] = v
|
||||||
|
|
||||||
|
|
||||||
def get_url_args(url):
|
def get_url_args(url):
|
||||||
@ -122,8 +123,15 @@ class URL(_URL):
|
|||||||
def ret_cls(cls):
|
def ret_cls(cls):
|
||||||
def wrapped(fn):
|
def wrapped(fn):
|
||||||
async def sub_wrap(self, *args, **kwargs):
|
async def sub_wrap(self, *args, **kwargs):
|
||||||
|
ret = loads(
|
||||||
|
(await fn(self, *args, **kwargs))
|
||||||
|
.content.decode()
|
||||||
|
.rstrip("\\r\\n")
|
||||||
|
.lstrip(" ")
|
||||||
|
)
|
||||||
|
|
||||||
kwargs.pop("base_uri", None)
|
kwargs.pop("base_uri", None)
|
||||||
ret = (await fn(self, *args, **kwargs)).json().get("data", [])
|
ret = ret.get("data", [])
|
||||||
_rets = []
|
_rets = []
|
||||||
|
|
||||||
if isinstance(ret, list):
|
if isinstance(ret, list):
|
||||||
@ -142,6 +150,7 @@ def route(method, endpoint) -> Any:
|
|||||||
def wrapped(fn):
|
def wrapped(fn):
|
||||||
async def sub_wrap(
|
async def sub_wrap(
|
||||||
self: "SubRouter",
|
self: "SubRouter",
|
||||||
|
*args,
|
||||||
base_uri=None,
|
base_uri=None,
|
||||||
content: Optional[bytes] = None,
|
content: Optional[bytes] = None,
|
||||||
data: Optional[dict[str, str]] = None,
|
data: Optional[dict[str, str]] = None,
|
||||||
@ -154,10 +163,17 @@ def route(method, endpoint) -> Any:
|
|||||||
headers = kwargs.pop("headers")
|
headers = kwargs.pop("headers")
|
||||||
else:
|
else:
|
||||||
headers = None
|
headers = None
|
||||||
|
|
||||||
for param_name, param in signature(fn).parameters.items():
|
for param_name, param in signature(fn).parameters.items():
|
||||||
if param_name == "self":
|
if param_name == "self":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if param.kind == Parameter.POSITIONAL_ONLY:
|
||||||
|
data[param_name] = param.annotation(args[0])
|
||||||
|
if len(args) > 1:
|
||||||
|
args = args[1:]
|
||||||
|
|
||||||
|
else:
|
||||||
if param_name in fn.__annotations__:
|
if param_name in fn.__annotations__:
|
||||||
anno = fn.__annotations__[param_name]
|
anno = fn.__annotations__[param_name]
|
||||||
if isinstance(anno, type):
|
if isinstance(anno, type):
|
||||||
@ -181,8 +197,8 @@ def route(method, endpoint) -> Any:
|
|||||||
data[param_name] = type_(kwargs.pop(param_name))
|
data[param_name] = type_(kwargs.pop(param_name))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if kwargs.get(param_name, None):
|
if v := kwargs.pop(param_name, param.default):
|
||||||
data[param_name] = type_(kwargs.pop(param_name))
|
data[param_name] = type_(v)
|
||||||
|
|
||||||
url_args = get_url_args(endpoint)
|
url_args = get_url_args(endpoint)
|
||||||
for k, v in url_args.items():
|
for k, v in url_args.items():
|
||||||
@ -251,10 +267,19 @@ class RouterMeta(type):
|
|||||||
|
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
if any(map(lambda x: not x.startswith("__"), kwds.keys())):
|
if any(
|
||||||
|
map(
|
||||||
|
lambda x: not x.startswith("__") and not x.startswith("on_"),
|
||||||
|
kwds.keys(),
|
||||||
|
)
|
||||||
|
):
|
||||||
funcs = list(
|
funcs = list(
|
||||||
filter(
|
filter(
|
||||||
lambda k: not k[0].startswith("__") and callable(k[1]), kwds.items()
|
lambda k: (
|
||||||
|
(not k[0].startswith("__") and not k[0].startswith("on_"))
|
||||||
|
and callable(k[1])
|
||||||
|
),
|
||||||
|
kwds.items(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for k, v in funcs:
|
for k, v in funcs:
|
||||||
@ -305,20 +330,24 @@ class SubRouter(metaclass=RouterMeta):
|
|||||||
cls._api_path = f'{kwargs.get("root")}{cls.BASE_URI}'
|
cls._api_path = f'{kwargs.get("root")}{cls.BASE_URI}'
|
||||||
|
|
||||||
|
|
||||||
class HughApi(SubRouter):
|
class HueAPIv1(SubRouter):
|
||||||
|
BASE_URL = ""
|
||||||
|
|
||||||
|
|
||||||
|
class HueAPIv2(SubRouter):
|
||||||
BASE_URI = "/clip/v2"
|
BASE_URI = "/clip/v2"
|
||||||
|
|
||||||
@ret_cls(models.Light)
|
@ret_cls(HueEntsV2.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(models.Light)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/light/{light_id}")
|
@route("PUT", "/resource/light/{light_id}")
|
||||||
async def set_light(
|
async def set_light(
|
||||||
self,
|
self,
|
||||||
@ -337,400 +366,402 @@ class HughApi(SubRouter):
|
|||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Scene)
|
@ret_cls(HueEntsV2.Scene)
|
||||||
@route("GET", "/resource/scene")
|
@route("GET", "/resource/scene")
|
||||||
async def get_scenes(self):
|
async def get_scenes(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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)
|
@ret_cls(HueEntsV2.Scene)
|
||||||
@route("GET", "/resource/scene/{scene_id}")
|
@route("GET", "/resource/scene/{scene_id}")
|
||||||
async def get_scene(self, scene_id: UUID):
|
async def get_scene(self, scene_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/scene/{scene_id}")
|
@route("PUT", "/resource/scene/{scene_id}")
|
||||||
async def set_scene(self, scene_id: UUID, **kwargs):
|
async def set_scene(self, scene_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("DELETE", "/resource/scene/{scene_id}")
|
@route("DELETE", "/resource/scene/{scene_id}")
|
||||||
async def delete_scene(self, scene_id: UUID):
|
async def delete_scene(self, scene_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Room)
|
@ret_cls(HueEntsV2.Room)
|
||||||
@route("GET", "/resource/room")
|
@route("GET", "/resource/room")
|
||||||
async def get_rooms(self):
|
async def get_rooms(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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)
|
@ret_cls(HueEntsV2.Room)
|
||||||
@route("GET", "/resource/room/{room_id}")
|
@route("GET", "/resource/room/{room_id}")
|
||||||
async def get_room(self, room_id: UUID):
|
async def get_room(self, room_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/room/{room_id}")
|
@route("PUT", "/resource/room/{room_id}")
|
||||||
async def set_room(
|
async def set_room(
|
||||||
self,
|
self,
|
||||||
room_id: UUID,
|
room_id: UUID,
|
||||||
|
/,
|
||||||
metadata: Optional[dict[str, str]] = None,
|
metadata: Optional[dict[str, str]] = None,
|
||||||
children: Optional[models.Identifier] = None,
|
children: Optional[models.Attributes.Identifier] = None,
|
||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("DELETE", "/resource/room/{room_id}")
|
@route("DELETE", "/resource/room/{room_id}")
|
||||||
async def delete_room(self, room_id: UUID):
|
async def delete_room(self, room_id: UUID):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Zone)
|
@ret_cls(HueEntsV2.Zone)
|
||||||
@route("GET", "/resource/zone")
|
@route("GET", "/resource/zone")
|
||||||
async def get_zones(self):
|
async def get_zones(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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)
|
@ret_cls(HueEntsV2.Zone)
|
||||||
@route("GET", "/resource/zone/{zone_id}")
|
@route("GET", "/resource/zone/{zone_id}")
|
||||||
async def get_zone(self, zone_id: UUID):
|
async def get_zone(self, zone_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/zone/{zone_id}")
|
@route("PUT", "/resource/zone/{zone_id}")
|
||||||
async def set_zone(self, zone_id: UUID, **kwargs):
|
async def set_zone(self, zone_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("DELETE", "/resource/zone/{zone_id}")
|
@route("DELETE", "/resource/zone/{zone_id}")
|
||||||
async def delete_zone(self, zone_id: UUID):
|
async def delete_zone(self, zone_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.BridgeHome)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_bridge_home(self, bridge_home_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_bridge_home(self, bridge_home_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.GroupedLight)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_grouped_light(self, grouped_light_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_grouped_light(self, grouped_light_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Device)
|
@ret_cls(HueEntsV2.Device)
|
||||||
@route("GET", "/resource/device")
|
@route("GET", "/resource/device")
|
||||||
async def get_devices(self):
|
async def get_devices(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Device)
|
@ret_cls(HueEntsV2.Device)
|
||||||
@route("GET", "/resource/device/{device_id}")
|
@route("GET", "/resource/device/{device_id}")
|
||||||
async def get_device(self, device_id: UUID):
|
async def get_device(self, device_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/device/{device_id}")
|
@route("PUT", "/resource/device/{device_id}")
|
||||||
async def set_device(self, device_id: UUID, **kwargs):
|
async def set_device(self, device_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Bridge)
|
@ret_cls(HueEntsV2.Bridge)
|
||||||
@route("GET", "/resource/bridges")
|
@route("GET", "/resource/bridges")
|
||||||
async def get_bridges(self):
|
async def get_bridges(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Bridge)
|
@ret_cls(HueEntsV2.Bridge)
|
||||||
@route("GET", "/resource/bridges/{bridge_id}")
|
@route("GET", "/resource/bridges/{bridge_id}")
|
||||||
async def get_bridge(self, bridge_id: UUID):
|
async def get_bridge(self, bridge_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/bridges/{bridge_id}")
|
@route("PUT", "/resource/bridges/{bridge_id}")
|
||||||
async def set_bridge(self, bridge_id: UUID, **kwargs):
|
async def set_bridge(self, bridge_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.DevicePower)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_device_power(self, device_power_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_device_power(self, device_power_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.ZigbeeConnectivity)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_zigbee_connectivity(self, zigbee_connectivity_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_zigbee_connectivity(self, zigbee_connectivity_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.ZGPConnectivity)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_zgb_connectivity(self, zgb_connectivity_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_zgb_connectivity(self, zgb_connectivity_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Motion)
|
@ret_cls(HueEntsV2.Motion)
|
||||||
@route("GET", "/resource/motion")
|
@route("GET", "/resource/motion")
|
||||||
async def get_motions(self):
|
async def get_motions(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Motion)
|
@ret_cls(HueEntsV2.Motion)
|
||||||
@route("GET", "/resource/motion/{motion_id}")
|
@route("GET", "/resource/motion/{motion_id}")
|
||||||
async def get_motion(self, motion_id: UUID):
|
async def get_motion(self, motion_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/motion/{motion_id}")
|
@route("PUT", "/resource/motion/{motion_id}")
|
||||||
async def set_motion(self, motion_id: UUID, **kwargs):
|
async def set_motion(self, motion_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Temperature)
|
@ret_cls(HueEntsV2.Temperature)
|
||||||
@route("GET", "/resource/temperature")
|
@route("GET", "/resource/temperature")
|
||||||
async def get_temperatures(self):
|
async def get_temperatures(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Temperature)
|
@ret_cls(HueEntsV2.Temperature)
|
||||||
@route("GET", "/resource/temperature/{temperature_id}")
|
@route("GET", "/resource/temperature/{temperature_id}")
|
||||||
async def get_temperature(self, temperature_id: UUID):
|
async def get_temperature(self, temperature_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/temperature/{temperature_id}")
|
@route("PUT", "/resource/temperature/{temperature_id}")
|
||||||
async def set_temperature(self, temperature_id: UUID, **kwargs):
|
async def set_temperature(self, temperature_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.LightLevel)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_light_level(self, light_level_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_light_level(self, light_level_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Button)
|
@ret_cls(HueEntsV2.Button)
|
||||||
@route("GET", "/resource/button")
|
@route("GET", "/resource/button")
|
||||||
async def get_buttons(self):
|
async def get_buttons(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Button)
|
@ret_cls(HueEntsV2.Button)
|
||||||
@route("GET", "/resource/button/{button_id}")
|
@route("GET", "/resource/button/{button_id}")
|
||||||
async def get_button(self, button_id: UUID):
|
async def get_button(self, button_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/button/{button_id}")
|
@route("PUT", "/resource/button/{button_id}")
|
||||||
async def set_button(self, button_id: UUID, **kwargs):
|
async def set_button(self, button_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.BehaviorScript)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_behavior_script(self, behavior_script_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.BehaviorInstance)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(models.Attributes.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_behavior_instance(self, behavior_instance_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_behavior_instance(self, behavior_instance_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID):
|
async def delete_behavior_instance(self, behavior_instance_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.GeofenceClient)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(models.Attributes.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)
|
@ret_cls(HueEntsV2.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: UUID):
|
async def get_geofence_client(self, geofence_client_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID, **kwargs):
|
async def set_geofence_client(self, geofence_client_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.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: UUID):
|
async def delete_geofence_client(self, geofence_client_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Geolocation)
|
@ret_cls(HueEntsV2.Geolocation)
|
||||||
@route("GET", "/resource/geolocation")
|
@route("GET", "/resource/geolocation")
|
||||||
async def get_geolocations(self):
|
async def get_geolocations(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Geolocation)
|
@ret_cls(HueEntsV2.Geolocation)
|
||||||
@route("GET", "/resource/geolocation/{geolocation_id}")
|
@route("GET", "/resource/geolocation/{geolocation_id}")
|
||||||
async def get_geolocation(self, geolocation_id: UUID):
|
async def get_geolocation(self, geolocation_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/geolocation/{geolocation_id}")
|
@route("PUT", "/resource/geolocation/{geolocation_id}")
|
||||||
async def set_geolocation(self, geolocation_id: UUID, **kwargs):
|
async def set_geolocation(self, geolocation_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.EntertainmentConfiguration)
|
@ret_cls(HueEntsV2.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)
|
@ret_cls(models.Attributes.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)
|
@ret_cls(HueEntsV2.EntertainmentConfiguration)
|
||||||
@route(
|
@route(
|
||||||
"GET", "/resource/entertainment_configuration/{entertainment_configuration_id}"
|
"GET", "/resource/entertainment_configuration/{entertainment_configuration_id}"
|
||||||
)
|
)
|
||||||
async def get_entertainment_configuration(
|
async def get_entertainment_configuration(
|
||||||
self, entertainment_configuration_id: UUID
|
self, entertainment_configuration_id: UUID, /
|
||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route(
|
@route(
|
||||||
"PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}"
|
"PUT", "/resource/entertainment_configuration/{entertainment_configuration_id}"
|
||||||
)
|
)
|
||||||
async def set_entertainment_configuration(
|
async def set_entertainment_configuration(
|
||||||
self, entertainment_configuration_id: UUID, **kwargs
|
self, entertainment_configuration_id: UUID, /, **kwargs
|
||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route(
|
@route(
|
||||||
"DELETE",
|
"DELETE",
|
||||||
"/resource/entertainment_configuration/{entertainment_configuration_id}",
|
"/resource/entertainment_configuration/{entertainment_configuration_id}",
|
||||||
)
|
)
|
||||||
async def delete_entertainment_configuration(
|
async def delete_entertainment_configuration(
|
||||||
self, entertainment_configuration_id: UUID
|
self, entertainment_configuration_id: UUID, /
|
||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Entertainment)
|
@ret_cls(HueEntsV2.Entertainment)
|
||||||
@route("GET", "/resource/entertainment")
|
@route("GET", "/resource/entertainment")
|
||||||
async def get_entertainments(self):
|
async def get_entertainments(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Entertainment)
|
@ret_cls(HueEntsV2.Entertainment)
|
||||||
@route("GET", "/resource/entertainment/{entertainment_id}")
|
@route("GET", "/resource/entertainment/{entertainment_id}")
|
||||||
async def get_entertainment(self, entertainment_id: UUID):
|
async def get_entertainment(self, entertainment_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/entertainment/{entertainment_id}")
|
@route("PUT", "/resource/entertainment/{entertainment_id}")
|
||||||
async def set_entertainment(self, entertainment_id: UUID, **kwargs):
|
async def set_entertainment(self, entertainment_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Homekit)
|
@ret_cls(HueEntsV2.Homekit)
|
||||||
@route("GET", "/resource/homekit")
|
@route("GET", "/resource/homekit")
|
||||||
async def get_homekits(self):
|
async def get_homekits(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Homekit)
|
@ret_cls(HueEntsV2.Homekit)
|
||||||
@route("GET", "/resource/homekit/{homekit_id}")
|
@route("GET", "/resource/homekit/{homekit_id}")
|
||||||
async def get_homekit(self, homekit_id: UUID):
|
async def get_homekit(self, homekit_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/homekit/{homekit_id}")
|
@route("PUT", "/resource/homekit/{homekit_id}")
|
||||||
async def set_homekit(
|
async def set_homekit(
|
||||||
self,
|
self,
|
||||||
homekit_id: UUID,
|
homekit_id: UUID,
|
||||||
|
/,
|
||||||
type: Optional[str] = None,
|
type: Optional[str] = None,
|
||||||
action: Optional[Literal["homekit_reset"]] = None,
|
action: Optional[Literal["homekit_reset"]] = None,
|
||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Resource)
|
@ret_cls(HueEntsV2.Resource)
|
||||||
@route("GET", "/resource")
|
@route("GET", "/resource")
|
||||||
async def get_resources(self):
|
async def get_resources(self):
|
||||||
...
|
...
|
||||||
@ -739,8 +770,33 @@ class HughApi(SubRouter):
|
|||||||
async def listen_events(self):
|
async def listen_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ret_cls(HueEntsV2.RelativeRotary)
|
||||||
|
@route("GET", "/resource/relative_rotary")
|
||||||
|
async def get_rotaries(self):
|
||||||
|
...
|
||||||
|
|
||||||
class Router(HughApi):
|
@ret_cls(models.Attributes.Identifier)
|
||||||
|
@route("PUT", "/resource/relative_rotary/{relative_rotary_id}")
|
||||||
|
async def set_rotary(self, relative_rotary_id: UUID, /, **kwargs):
|
||||||
|
...
|
||||||
|
|
||||||
|
@ret_cls(HueEntsV2.RelativeRotary)
|
||||||
|
@route("GET", "/resource/relative_rotary/{relative_rotary_id}")
|
||||||
|
async def get_rotary(self, relative_rotary_id: UUID, /):
|
||||||
|
...
|
||||||
|
|
||||||
|
@ret_cls(models.Attributes.Identifier)
|
||||||
|
@route("POST", "/resource/relative_rotary")
|
||||||
|
async def create_rotary(self, **kwargs):
|
||||||
|
...
|
||||||
|
|
||||||
|
@ret_cls(models.Attributes.Identifier)
|
||||||
|
@route("DELETE", "/resource/relative_rotary/{relative_rotary_id}")
|
||||||
|
async def delete_rotary(self, relative_rotary_id: UUID, /):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Router(HueAPIv2):
|
||||||
def __new__(cls, hue_api_key: str, bridge_ip: str = "", max_cache_size: int = 512):
|
def __new__(cls, hue_api_key: str, bridge_ip: str = "", max_cache_size: int = 512):
|
||||||
cls = super().__new__(cls, hue_api_key)
|
cls = super().__new__(cls, hue_api_key)
|
||||||
return cls
|
return cls
|
||||||
@ -763,13 +819,13 @@ class Router(HughApi):
|
|||||||
stream = await self.listen_events(
|
stream = await self.listen_events(
|
||||||
headers={"Accept": "text/event-stream"} | self._headers
|
headers={"Accept": "text/event-stream"} | self._headers
|
||||||
)
|
)
|
||||||
while get_running_loop().is_running():
|
|
||||||
resp = await stream.gen.__anext__()
|
resp = await stream.gen.__anext__()
|
||||||
_bound = resp.stream._stream._httpcore_stream
|
_bound = resp.stream
|
||||||
|
while get_running_loop().is_running():
|
||||||
try:
|
try:
|
||||||
async for msg in _bound:
|
async for msg in _bound:
|
||||||
payload = []
|
payload = []
|
||||||
_match = MSG_RE.search(msg)
|
_match = MSG_RE_BYTES.search(msg)
|
||||||
id_ = ""
|
id_ = ""
|
||||||
if _match:
|
if _match:
|
||||||
if _match.groupdict().get("hello", None):
|
if _match.groupdict().get("hello", None):
|
||||||
@ -781,11 +837,101 @@ class Router(HughApi):
|
|||||||
|
|
||||||
for event in payload:
|
for event in payload:
|
||||||
for ob in event["data"]:
|
for ob in event["data"]:
|
||||||
self.cache.add(TYPE_CACHE[ob["type"]](**ob))
|
_obj = TYPE_CACHE[ob["type"]](**ob)
|
||||||
|
self.cache.add(_obj)
|
||||||
|
|
||||||
print(len(self.cache))
|
if hasattr(self, f"on_{ob['type']}_{event['type']}"):
|
||||||
|
await getattr(self, f"on_{ob['type']}_{event['type']}")(
|
||||||
|
_obj
|
||||||
|
)
|
||||||
|
|
||||||
except ReadTimeout:
|
except (ReadTimeout, HTTPxReadTimeout) as e:
|
||||||
stream = await self.listen_events(
|
stream = await self.listen_events(
|
||||||
headers={"Accept": "text/event-stream"} | self._headers
|
headers={"Accept": "text/event-stream"} | self._headers
|
||||||
)
|
)
|
||||||
|
resp = await stream.gen.__anext__()
|
||||||
|
_bound = resp.stream
|
||||||
|
|
||||||
|
async def on_motion_update(self, motion: HueEntsV2.Motion):
|
||||||
|
print(f"on_motion_update: {motion}")
|
||||||
|
|
||||||
|
async def on_button_update(self, button: HueEntsV2.Button):
|
||||||
|
print(f"on_button_update: {button}")
|
||||||
|
|
||||||
|
async def on_zone_update(self, zone: HueEntsV2.Zone):
|
||||||
|
print(f"on_zone_update: {zone}")
|
||||||
|
|
||||||
|
async def on_zigbee_connectivity_update(self, zigbee: HueEntsV2.ZigbeeConnectivity):
|
||||||
|
print(f"on_zigbee_connectivity_update: {zigbee}")
|
||||||
|
|
||||||
|
async def on_zgp_connectivity_update(
|
||||||
|
self, zgp_connectivity: HueEntsV2.ZGPConnectivity
|
||||||
|
):
|
||||||
|
print(f"on_zgp_connectivity_update: {zgp_connectivity}")
|
||||||
|
|
||||||
|
async def on_temperature_update(self, temperature: HueEntsV2.Temperature):
|
||||||
|
print(f"on_temperature_update: {temperature}")
|
||||||
|
|
||||||
|
async def on_scene_update(self, scene: HueEntsV2.Scene):
|
||||||
|
print(f"on_scene_update: {scene}")
|
||||||
|
|
||||||
|
async def on_room_update(self, room: HueEntsV2.Room):
|
||||||
|
print(f"on_room_update: {room}")
|
||||||
|
|
||||||
|
async def on_resource_update(self, device: HueEntsV2.Resource):
|
||||||
|
print(f"on_device_update: {device}")
|
||||||
|
|
||||||
|
async def on_relative_rotary_update(
|
||||||
|
self, relative_rotary: HueEntsV2.RelativeRotary
|
||||||
|
):
|
||||||
|
print(f"on_relative_rotary_update: {relative_rotary}")
|
||||||
|
|
||||||
|
async def on_light_level_update(self, light_level: HueEntsV2.LightLevel):
|
||||||
|
print(f"on_light_level_update: {light_level}")
|
||||||
|
|
||||||
|
async def on_light_update(self, light: HueEntsV2.Light):
|
||||||
|
print(f"on_light_update: {light}")
|
||||||
|
|
||||||
|
async def on_homekit_update(self, homekit: HueEntsV2.Homekit):
|
||||||
|
print(f"on_homekit_update: {homekit}")
|
||||||
|
|
||||||
|
async def on_grouped_light_update(self, grouped_light: HueEntsV2.GroupedLight):
|
||||||
|
print(f"on_grouped_light_update: {grouped_light}")
|
||||||
|
|
||||||
|
async def on_geolocation_update(self, geolocation: HueEntsV2.Geolocation):
|
||||||
|
print(f"on_geolocation_update: {geolocation}")
|
||||||
|
|
||||||
|
async def on_geofence_client_update(
|
||||||
|
self, geofence_client: HueEntsV2.GeofenceClient
|
||||||
|
):
|
||||||
|
print(f"on_geofence_client_update: {geofence_client}")
|
||||||
|
|
||||||
|
async def on_entertainment_configuration_update(
|
||||||
|
self, entertainment_configuration: HueEntsV2.EntertainmentConfiguration
|
||||||
|
):
|
||||||
|
print(f"on_entertainment_configuration_update: {entertainment_configuration}")
|
||||||
|
|
||||||
|
async def on_entertainment_update(self, entertainment: HueEntsV2.Entertainment):
|
||||||
|
print(f"on_entertainment_update: {entertainment}")
|
||||||
|
|
||||||
|
async def on_device_power_update(self, device_power: HueEntsV2.DevicePower):
|
||||||
|
print(f"on_device_power_update: {device_power}")
|
||||||
|
|
||||||
|
async def on_device_update(self, device: HueEntsV2.Device):
|
||||||
|
print(f"on_device_update: {device}")
|
||||||
|
|
||||||
|
async def on_bridge_home_update(self, bridge_home: HueEntsV2.BridgeHome):
|
||||||
|
print(f"on_bridge_home_update: {bridge_home}")
|
||||||
|
|
||||||
|
async def on_bridge_update(self, bridge: HueEntsV2.Bridge):
|
||||||
|
print(f"on_bridge_update: {bridge}")
|
||||||
|
|
||||||
|
async def on_behavior_script_update(
|
||||||
|
self, behavior_script: HueEntsV2.BehaviorScript
|
||||||
|
):
|
||||||
|
print(f"on_behavior_script_update: {behavior_script}")
|
||||||
|
|
||||||
|
async def on_behavior_instance_update(
|
||||||
|
self, behavior_instance: HueEntsV2.BehaviorInstance
|
||||||
|
):
|
||||||
|
print(f"on_behavior_instance_update: {behavior_instance}")
|
||||||
|
@ -1,4 +1,16 @@
|
|||||||
from typing import Any, Literal, Optional, TypeAlias, TypeVar
|
from typing import (
|
||||||
|
Any,
|
||||||
|
AnyStr,
|
||||||
|
Final,
|
||||||
|
Generic,
|
||||||
|
Literal,
|
||||||
|
Optional,
|
||||||
|
Type,
|
||||||
|
TypeAlias,
|
||||||
|
TypeVar,
|
||||||
|
ClassVar,
|
||||||
|
TypeVarTuple,
|
||||||
|
)
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
|
||||||
@ -12,36 +24,11 @@ except ImportError: # type: ignore
|
|||||||
from json import loads, dumps # noqa
|
from json import loads, dumps # noqa
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = ("Archetype", "RoomType", "HueEnts")
|
||||||
"Archetype",
|
|
||||||
"RoomType",
|
|
||||||
"Room",
|
|
||||||
"Light",
|
|
||||||
"Scene",
|
|
||||||
"Zone",
|
|
||||||
"BridgeHome",
|
|
||||||
"GroupedLight",
|
|
||||||
"Device",
|
|
||||||
"Bridge",
|
|
||||||
"DevicePower",
|
|
||||||
"ZigbeeConnectivity",
|
|
||||||
"ZGPConnectivity",
|
|
||||||
"Motion",
|
|
||||||
"Temperature",
|
|
||||||
"LightLevel",
|
|
||||||
"Button",
|
|
||||||
"BehaviorScript",
|
|
||||||
"BehaviorInstance",
|
|
||||||
"GeofenceClient",
|
|
||||||
"Geolocation",
|
|
||||||
"EntertainmentConfiguration",
|
|
||||||
"Entertainment",
|
|
||||||
"Resource",
|
|
||||||
"Homekit",
|
|
||||||
)
|
|
||||||
|
|
||||||
_T_M: TypeAlias = "RoomType | Archetype | Room | Light | Scene | Zone | BridgeHome | GroupedLight | Device | Bridge | DevicePower | ZigbeeConnectivity | ZGPConnectivity | Motion | Temperature | LightLevel | Button | BehaviorScript | BehaviorInstance | GeofenceClient | Geolocation | EntertainmentConfiguration | Entertainment | Resource | Homekit"
|
# mypy: enable-incomplete-feature=TypeVarTuple
|
||||||
|
|
||||||
|
_T_M = TypeVarTuple("_T_M")
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
@ -167,6 +154,50 @@ class Archetype(Enum):
|
|||||||
HUE_SIGNE = auto()
|
HUE_SIGNE = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Attributes:
|
||||||
|
class Action(BaseModel):
|
||||||
|
on: Optional["Attributes.On"]
|
||||||
|
dimming: Optional["Attributes.Dimming"]
|
||||||
|
color: Optional["Attributes.ColorPoint"]
|
||||||
|
color_temperature: Optional[dict[str, float]]
|
||||||
|
gradient: Optional[dict[str, list["Attributes.ColorPoint"]]]
|
||||||
|
effects: Optional[dict[str, str]]
|
||||||
|
dynamics: Optional[dict[str, float]]
|
||||||
|
|
||||||
|
class Actions(BaseModel):
|
||||||
|
target: Optional["Attributes.Identifier"]
|
||||||
|
action: Optional["Attributes.Action"]
|
||||||
|
dimming: Optional["Attributes.Dimming"]
|
||||||
|
color: Optional["Attributes.ColorPoint"]
|
||||||
|
|
||||||
|
class Button(BaseModel):
|
||||||
|
last_event: Literal[
|
||||||
|
"initial_press",
|
||||||
|
"repeat",
|
||||||
|
"short_release",
|
||||||
|
"long_release",
|
||||||
|
"double_short_release",
|
||||||
|
"long_press",
|
||||||
|
]
|
||||||
|
|
||||||
|
class Color(BaseModel):
|
||||||
|
xy: Optional["Attributes.XY"]
|
||||||
|
gamut: Optional["Attributes.Gamut"]
|
||||||
|
gamut_type: Optional[Literal["A", "B", "C"]]
|
||||||
|
|
||||||
|
class ColorPoint(BaseModel):
|
||||||
|
xy: Optional["Attributes.XY"]
|
||||||
|
|
||||||
|
class ColorTemp(BaseModel):
|
||||||
|
mirek: Optional[int]
|
||||||
|
mirek_valid: Optional[bool]
|
||||||
|
mirek_schema: Optional[dict[str, float]]
|
||||||
|
|
||||||
|
class Dependee(BaseModel):
|
||||||
|
type: Optional[str]
|
||||||
|
target: Optional["Attributes.Identifier"]
|
||||||
|
level: Optional[str]
|
||||||
|
|
||||||
class Dimming(BaseModel):
|
class Dimming(BaseModel):
|
||||||
class Config:
|
class Config:
|
||||||
frozen = True
|
frozen = True
|
||||||
@ -176,29 +207,34 @@ class Dimming(BaseModel):
|
|||||||
brightness: Optional[float]
|
brightness: Optional[float]
|
||||||
min_dim_level: Optional[float] = Field(0, repr=False)
|
min_dim_level: Optional[float] = Field(0, repr=False)
|
||||||
|
|
||||||
|
class Dynamics(BaseModel):
|
||||||
|
status: Optional[str]
|
||||||
|
status_values: Optional[list[str]]
|
||||||
|
speed: Optional[float]
|
||||||
|
speed_valid: Optional[bool]
|
||||||
|
|
||||||
class XY(BaseModel):
|
class Effects(BaseModel):
|
||||||
class Config:
|
effect: Optional[list[str]]
|
||||||
frozen = True
|
status_values: Optional[list[str]]
|
||||||
allow_mutation = False
|
status: Optional[str]
|
||||||
validate_assignment = True
|
effect_values: Optional[list[str]]
|
||||||
|
|
||||||
x: Optional[float]
|
class EntChannel(BaseModel):
|
||||||
y: Optional[float]
|
channel_id: int = Field(ge=0, le=255)
|
||||||
|
position: Optional["Attributes.XYZ"] = None
|
||||||
|
members: Optional[list["Attributes.SegmentRef"]]
|
||||||
|
|
||||||
|
class EntLocation(BaseModel):
|
||||||
|
service_location: Optional[list["Attributes.ServiceLocation"]]
|
||||||
|
|
||||||
class On(BaseModel):
|
class Gamut(BaseModel):
|
||||||
class Config:
|
red: Optional["Attributes.XY"]
|
||||||
frozen = True
|
green: Optional["Attributes.XY"]
|
||||||
allow_mutation = False
|
blue: Optional["Attributes.XY"]
|
||||||
validate_assignment = True
|
|
||||||
|
|
||||||
on: bool = Field(..., alias="on")
|
|
||||||
|
|
||||||
|
|
||||||
class ColorPoint(BaseModel):
|
|
||||||
xy: Optional[XY]
|
|
||||||
|
|
||||||
|
class Gradient(BaseModel):
|
||||||
|
points: Optional[list["Attributes.ColorPoint"]]
|
||||||
|
points_capable: Optional[int]
|
||||||
|
|
||||||
class Identifier(BaseModel):
|
class Identifier(BaseModel):
|
||||||
class Config:
|
class Config:
|
||||||
@ -206,9 +242,12 @@ class Identifier(BaseModel):
|
|||||||
allow_mutation = False
|
allow_mutation = False
|
||||||
validate_assignment = True
|
validate_assignment = True
|
||||||
|
|
||||||
rid: Optional[str]
|
rid: str
|
||||||
rtype: Optional[str]
|
rtype: str
|
||||||
|
|
||||||
|
class LightLevelValue(BaseModel):
|
||||||
|
light_level: Optional[int]
|
||||||
|
light_level_valid: Optional[bool]
|
||||||
|
|
||||||
class Metadata(BaseModel):
|
class Metadata(BaseModel):
|
||||||
class Config:
|
class Config:
|
||||||
@ -218,86 +257,36 @@ class Metadata(BaseModel):
|
|||||||
|
|
||||||
name: Optional[str]
|
name: Optional[str]
|
||||||
archetype: Optional[Archetype | RoomType] = Archetype.UNKNOWN_ARCHETYPE
|
archetype: Optional[Archetype | RoomType] = Archetype.UNKNOWN_ARCHETYPE
|
||||||
image: Optional[Identifier] = Field(None, repr=False)
|
image: Optional["Attributes.Identifier"] = Field(None, repr=False)
|
||||||
|
|
||||||
|
class Motion(BaseModel):
|
||||||
|
motion: Optional[bool]
|
||||||
|
motion_valid: Optional[bool]
|
||||||
|
|
||||||
class ColorTemperature(BaseModel):
|
class On(BaseModel):
|
||||||
mirek: Optional[int]
|
class Config:
|
||||||
mirek_valid: Optional[bool]
|
frozen = True
|
||||||
mirek_schema: Optional[dict[str, float]]
|
allow_mutation = False
|
||||||
|
validate_assignment = True
|
||||||
|
|
||||||
|
on: bool = Field(..., alias="on")
|
||||||
|
|
||||||
class Gamut(BaseModel):
|
class Palette(BaseModel):
|
||||||
red: Optional[XY]
|
color: Optional[list["Attributes.PaletteColor"]]
|
||||||
green: Optional[XY]
|
dimming: Optional[list["Attributes.Dimming"]]
|
||||||
blue: Optional[XY]
|
color_temperature: Optional[list["Attributes.PaletteTemperature"]]
|
||||||
|
|
||||||
|
|
||||||
class Color(BaseModel):
|
|
||||||
xy: Optional[XY]
|
|
||||||
gamut: Optional["Gamut"]
|
|
||||||
gamut_type: Optional[Literal["A", "B", "C"]]
|
|
||||||
|
|
||||||
|
|
||||||
class Dynamics(BaseModel):
|
|
||||||
status: Optional[str]
|
|
||||||
status_values: Optional[list[str]]
|
|
||||||
speed: Optional[float]
|
|
||||||
speed_valid: Optional[bool]
|
|
||||||
|
|
||||||
|
|
||||||
class Gradient(BaseModel):
|
|
||||||
points: Optional[list[ColorPoint]]
|
|
||||||
points_capable: Optional[int]
|
|
||||||
|
|
||||||
|
|
||||||
class Effects(BaseModel):
|
|
||||||
effect: Optional[list[str]]
|
|
||||||
status_values: Optional[list[str]]
|
|
||||||
status: Optional[str]
|
|
||||||
effect_values: Optional[list[str]]
|
|
||||||
|
|
||||||
|
|
||||||
class TimedEffects(BaseModel):
|
|
||||||
effect: Optional[str]
|
|
||||||
duration: Optional[int]
|
|
||||||
status_values: Optional[list[str]]
|
|
||||||
status: Optional[str]
|
|
||||||
effect_values: Optional[list[str]]
|
|
||||||
|
|
||||||
|
|
||||||
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: Optional[Identifier]
|
|
||||||
action: Optional[Action]
|
|
||||||
dimming: Optional[Dimming]
|
|
||||||
color: Optional[ColorPoint]
|
|
||||||
|
|
||||||
|
|
||||||
class PaletteColor(BaseModel):
|
class PaletteColor(BaseModel):
|
||||||
color: Optional[ColorPoint]
|
color: Optional["Attributes.ColorPoint"]
|
||||||
dimming: Optional[Dimming]
|
dimming: Optional["Attributes.Dimming"]
|
||||||
|
|
||||||
|
|
||||||
class PaletteTemperature(BaseModel):
|
class PaletteTemperature(BaseModel):
|
||||||
color_temperature: dict[str, float]
|
color_temperature: dict[str, float]
|
||||||
dimming: Optional[Dimming]
|
dimming: Optional["Attributes.Dimming"]
|
||||||
|
|
||||||
|
|
||||||
class Palette(BaseModel):
|
|
||||||
color: Optional[list[PaletteColor]]
|
|
||||||
dimming: Optional[list[Dimming]]
|
|
||||||
color_temperature: Optional[list[PaletteTemperature]]
|
|
||||||
|
|
||||||
|
class PowerState(BaseModel):
|
||||||
|
battery_state: Literal["normal", "low", "critical"]
|
||||||
|
battery_level: float = Field(le=100.0, ge=0.0)
|
||||||
|
|
||||||
class ProductData(BaseModel):
|
class ProductData(BaseModel):
|
||||||
model_id: Optional[str]
|
model_id: Optional[str]
|
||||||
@ -308,26 +297,59 @@ class ProductData(BaseModel):
|
|||||||
software_version: Optional[str]
|
software_version: Optional[str]
|
||||||
hardware_platform_type: Optional[str]
|
hardware_platform_type: Optional[str]
|
||||||
|
|
||||||
|
class RelativeRotary(BaseModel):
|
||||||
|
last_event: Optional["Attributes.RotaryEvent"]
|
||||||
|
|
||||||
class PowerState(BaseModel):
|
class RotaryEvent(BaseModel):
|
||||||
battery_state: Literal["normal", "low", "critical"]
|
action: Optional[Literal["start", "repeat", "unknown"]]
|
||||||
battery_level: float = Field(le=100.0, ge=0.0)
|
rotation: Optional["Attributes.RotaryRotation"]
|
||||||
|
|
||||||
|
class RotaryRotation(BaseModel):
|
||||||
|
direction: Optional[Literal["clock_wise", "counter_clock_wise"]]
|
||||||
|
duration: Optional[int]
|
||||||
|
steps: Optional[int]
|
||||||
|
|
||||||
|
class Segment(BaseModel):
|
||||||
|
start: int = Field(..., ge=0)
|
||||||
|
length: int = Field(..., ge=1)
|
||||||
|
|
||||||
|
class SegmentManager(BaseModel):
|
||||||
|
configurable: Optional[bool]
|
||||||
|
max_segments: int = Field(..., ge=1)
|
||||||
|
segments: Optional[list["Attributes.Segment"]]
|
||||||
|
|
||||||
|
class SegmentRef(BaseModel):
|
||||||
|
service: Optional["Attributes.Identifier"]
|
||||||
|
index: Optional[int]
|
||||||
|
|
||||||
|
class ServiceLocation(BaseModel):
|
||||||
|
service: Optional["Attributes.Identifier"]
|
||||||
|
position: Optional["Attributes.XYZ"] = None
|
||||||
|
positions: list[Type["Attributes.XYZ"]] = Field(max_items=2, min_items=1)
|
||||||
|
|
||||||
|
class StreamProxy(BaseModel):
|
||||||
|
mode: Literal["auto", "manual"]
|
||||||
|
node: Optional["Attributes.Identifier"]
|
||||||
|
|
||||||
class Temp(BaseModel):
|
class Temp(BaseModel):
|
||||||
temperature: float = Field(lt=100.0, gt=-100.0)
|
temperature: float = Field(lt=100.0, gt=-100.0)
|
||||||
temperature_valid: Optional[bool]
|
temperature_valid: Optional[bool]
|
||||||
|
|
||||||
|
class TimedEffects(BaseModel):
|
||||||
|
effect: Optional[str]
|
||||||
|
duration: Optional[int]
|
||||||
|
status_values: Optional[list[str]]
|
||||||
|
status: Optional[str]
|
||||||
|
effect_values: Optional[list[str]]
|
||||||
|
|
||||||
class LightLevelValue(BaseModel):
|
class XY(BaseModel):
|
||||||
light_level: Optional[int]
|
class Config:
|
||||||
light_level_valid: Optional[bool]
|
frozen = True
|
||||||
|
allow_mutation = False
|
||||||
|
validate_assignment = True
|
||||||
class StreamProxy(BaseModel):
|
|
||||||
mode: Literal["auto", "manual"]
|
|
||||||
node: Optional[Identifier]
|
|
||||||
|
|
||||||
|
x: Optional[float]
|
||||||
|
y: Optional[float]
|
||||||
|
|
||||||
class XYZ(BaseModel):
|
class XYZ(BaseModel):
|
||||||
x: float = Field(ge=-1.0, le=1.0)
|
x: float = Field(ge=-1.0, le=1.0)
|
||||||
@ -335,283 +357,302 @@ class XYZ(BaseModel):
|
|||||||
z: float = Field(ge=-1.0, le=1.0)
|
z: float = Field(ge=-1.0, le=1.0)
|
||||||
|
|
||||||
|
|
||||||
class SegmentRef(BaseModel):
|
class HueEntsV1:
|
||||||
service: Optional[Identifier]
|
class UserConfiguration(Entity):
|
||||||
index: Optional[int]
|
name: str
|
||||||
|
swupdate: dict
|
||||||
|
swupdate2: dict
|
||||||
|
whitelist: list[str]
|
||||||
|
portalstate: dict
|
||||||
|
apiversion: str
|
||||||
|
swversion: str
|
||||||
|
proxyaddress: str
|
||||||
|
|
||||||
|
|
||||||
class EntertainmentChannel(BaseModel):
|
for k, v in Attributes.__dict__.items():
|
||||||
channel_id: int = Field(ge=0, le=255)
|
if k.startswith("__"):
|
||||||
position: Optional[XYZ]
|
continue
|
||||||
members: Optional[list[SegmentRef]]
|
|
||||||
|
v.update_forward_refs()
|
||||||
|
|
||||||
class ServiceLocation(BaseModel):
|
|
||||||
service: Optional[Identifier]
|
|
||||||
position: Optional[XYZ]
|
|
||||||
positions: list[XYZ] = Field(max_items=2, min_items=1)
|
|
||||||
|
|
||||||
|
|
||||||
class EntertainmentLocation(BaseModel):
|
|
||||||
service_location: Optional[list[ServiceLocation]]
|
|
||||||
|
|
||||||
|
|
||||||
class Segment(BaseModel):
|
|
||||||
start: int = Field(..., ge=0)
|
|
||||||
length: int = Field(..., ge=1)
|
|
||||||
|
|
||||||
|
|
||||||
class SegmentManager(BaseModel):
|
|
||||||
configurable: Optional[bool]
|
|
||||||
max_segments: int = Field(..., ge=1)
|
|
||||||
segments: Optional[list[Segment]]
|
|
||||||
|
|
||||||
|
|
||||||
class Dependee(BaseModel):
|
|
||||||
type: Optional[str]
|
|
||||||
target: Optional[Identifier]
|
|
||||||
level: Optional[str]
|
|
||||||
|
|
||||||
|
|
||||||
|
class HueEntsV2:
|
||||||
class BehaviorInstance(Entity):
|
class BehaviorInstance(Entity):
|
||||||
type: Literal["behavior_instance"] = "behavior_instance"
|
type: Final[Literal["behavior_instance"]] = "behavior_instance"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[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: Optional[str]
|
script_id: Optional[str]
|
||||||
enabled: Optional[bool]
|
enabled: Optional[bool]
|
||||||
state: Optional[dict[str, Any]]
|
state: Optional[dict[str, Any]]
|
||||||
configuration: dict[str, Any]
|
configuration: Optional[dict[str, Any]]
|
||||||
dependees: Optional[list[Dependee]]
|
dependees: Optional[list[Attributes.Dependee]]
|
||||||
status: Literal["initializing", "running", "disabled", "errored"]
|
status: Optional[Literal["initializing", "running", "disabled", "errored"]]
|
||||||
last_error: Optional[str]
|
last_error: Optional[str]
|
||||||
metadata: dict[Literal["name"], str]
|
metadata: Optional[dict[Literal["name"], str]]
|
||||||
migrated_from: Optional[str] = None
|
migrated_from: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class BehaviorScript(Entity):
|
class BehaviorScript(Entity):
|
||||||
type: Literal["behavior_script"] = "behavior_script"
|
type: Final[Literal["behavior_script"]] = "behavior_script"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[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: Optional[str]
|
description: Optional[str]
|
||||||
configuration_schema: dict[str, Any]
|
configuration_schema: Optional[dict[str, Any]]
|
||||||
trigger_schema: dict[str, Any]
|
trigger_schema: Optional[dict[str, Any]]
|
||||||
state_schema: dict[str, Any]
|
state_schema: Optional[dict[str, Any]]
|
||||||
version: Optional[str]
|
version: Optional[str]
|
||||||
metadata: dict[str, str]
|
metadata: Optional[dict[str, str]]
|
||||||
|
|
||||||
|
|
||||||
class Bridge(Entity):
|
class Bridge(Entity):
|
||||||
type: Literal["bridge"] = "bridge"
|
type: Final[Literal["bridge"]] = "bridge"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[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: Optional[str]
|
bridge_id: Optional[str]
|
||||||
time_zone: dict[str, str]
|
time_zone: Optional[dict[str, str]]
|
||||||
|
|
||||||
|
|
||||||
class BridgeHome(Entity):
|
class BridgeHome(Entity):
|
||||||
type: Literal["bridge_home"] = "bridge_home"
|
type: Final[Literal["bridge_home"]] = "bridge_home"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
services: Optional[list[Identifier]]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
children: Optional[list[Identifier]]
|
)
|
||||||
|
services: Optional[list[Attributes.Identifier]]
|
||||||
|
children: Optional[list[Attributes.Identifier]]
|
||||||
|
|
||||||
class Button(Entity):
|
class Button(Entity):
|
||||||
type: Literal["button"] = "button"
|
type: Final[Literal["button"]] = "button"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
metadata: dict[Literal["control_id"], int]
|
)
|
||||||
button: Optional[
|
owner: Optional[Attributes.Identifier]
|
||||||
dict[
|
metadata: Optional[dict[Literal["control_id"], int]]
|
||||||
Literal["last_event"],
|
button: Optional[Attributes.Button]
|
||||||
Literal[
|
|
||||||
"initial_press",
|
|
||||||
"repeat",
|
|
||||||
"short_release",
|
|
||||||
"long_release",
|
|
||||||
"double_short_release",
|
|
||||||
],
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class Device(Entity):
|
class Device(Entity):
|
||||||
type: Literal["device"] = "device"
|
type: Final[Literal["device"]] = "device"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
services: Optional[list[Identifier]]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
metadata: Optional[Metadata]
|
)
|
||||||
product_data: Optional[ProductData]
|
services: Optional[list[Attributes.Identifier]]
|
||||||
|
metadata: Optional[Attributes.Metadata]
|
||||||
|
product_data: Optional[Attributes.ProductData]
|
||||||
|
|
||||||
class DevicePower(Entity):
|
class DevicePower(Entity):
|
||||||
type: Literal["device_power"] = "device_power"
|
type: Final[Literal["device_power"]] = "device_power"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
power_state: Optional[PowerState]
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
|
power_state: Optional[Attributes.PowerState]
|
||||||
|
|
||||||
class Entertainment(Entity):
|
class Entertainment(Entity):
|
||||||
type: Literal["entertainment"] = "entertainment"
|
type: Final[Literal["entertainment"]] = "entertainment"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
renderer: Optional[bool]
|
renderer: Optional[bool]
|
||||||
proxy: Optional[bool]
|
proxy: Optional[bool]
|
||||||
max_streams: Optional[int] = Field(1, ge=1)
|
max_streams: Optional[int] = Field(1, ge=1)
|
||||||
segments: Optional[SegmentManager] = None
|
segments: Optional[Attributes.SegmentManager] = None
|
||||||
|
|
||||||
|
|
||||||
class EntertainmentConfiguration(Entity):
|
class EntertainmentConfiguration(Entity):
|
||||||
type: Literal["entertainment_configuration"] = "entertainment_configuration"
|
type: Final[
|
||||||
|
Literal["entertainment_configuration"]
|
||||||
|
] = "entertainment_configuration"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
metadata: dict[Literal["name"], str]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
metadata: Optional[dict[Literal["name"], str]]
|
||||||
name: Optional[str] = ""
|
name: Optional[str] = ""
|
||||||
configuration_type: Literal["screen", "monitor", "music", "3dspace", "other"]
|
configuration_type: Optional[
|
||||||
status: Literal["active", "inactive"]
|
Literal["screen", "monitor", "music", "3dspace", "other"]
|
||||||
active_streamer: Optional[Identifier] = None
|
]
|
||||||
stream_proxy: Optional[StreamProxy]
|
status: Optional[Literal["active", "inactive"]]
|
||||||
channels: Optional[list[EntertainmentChannel]]
|
active_streamer: Optional[Attributes.Identifier] = None
|
||||||
locations: Optional[EntertainmentLocation] = None
|
stream_proxy: Optional[Attributes.StreamProxy]
|
||||||
light_services: Optional[list[Identifier]]
|
channels: Optional[list[Attributes.EntChannel]]
|
||||||
|
locations: Optional[Attributes.EntLocation] = None
|
||||||
|
light_services: Optional[list[Attributes.Identifier]]
|
||||||
|
|
||||||
class GeofenceClient(Entity):
|
class GeofenceClient(Entity):
|
||||||
type: Literal["geofence_client"] = "geofence_client"
|
type: Final[Literal["geofence_client"]] = "geofence_client"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[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: Optional[str]
|
name: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class Geolocation(Entity):
|
class Geolocation(Entity):
|
||||||
type: Literal["geolocation"] = "geolocation"
|
type: Final[Literal["geolocation"]] = "geolocation"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[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: Optional[bool] = False
|
is_configured: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class GroupedLight(Entity):
|
class GroupedLight(Entity):
|
||||||
type: Literal["grouped_light"] = "grouped_light"
|
type: Final[Literal["grouped_light"]] = "grouped_light"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
on: On = Field(repr=False)
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
alert: dict[str, list[str]]
|
)
|
||||||
|
on: Optional[Attributes.On] = Field(repr=False)
|
||||||
|
alert: Optional[dict[str, list[str]]]
|
||||||
|
|
||||||
class Homekit(Entity):
|
class Homekit(Entity):
|
||||||
id: UUID
|
id: UUID
|
||||||
type: str = "resource"
|
type: Final[Literal["resource"]] = "resource"
|
||||||
id_v1: Optional[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})?$"
|
||||||
|
)
|
||||||
status: Optional[Literal["paired", "pairing", "unpaired"]] = "unpaired"
|
status: Optional[Literal["paired", "pairing", "unpaired"]] = "unpaired"
|
||||||
|
|
||||||
|
|
||||||
class Light(Entity):
|
class Light(Entity):
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
metadata: Optional[Metadata]
|
)
|
||||||
on: Optional[On]
|
owner: Optional[Attributes.Identifier]
|
||||||
dimming: Optional[Dimming]
|
metadata: Optional[Attributes.Metadata]
|
||||||
|
on: Optional[Attributes.On]
|
||||||
|
dimming: Optional[Attributes.Dimming]
|
||||||
dimming_delta: Optional[dict]
|
dimming_delta: Optional[dict]
|
||||||
color_temperature: Optional[ColorTemperature]
|
color_temperature: Optional[Attributes.ColorTemp]
|
||||||
color_temperature_delta: Optional[dict]
|
color_temperature_delta: Optional[dict]
|
||||||
color: Optional[Color]
|
color: Optional[Attributes.Color]
|
||||||
gradient: Optional[Gradient]
|
gradient: Optional[Attributes.Gradient]
|
||||||
dynamics: Optional[Dynamics]
|
dynamics: Optional[Attributes.Dynamics]
|
||||||
alert: Optional[dict[str, list[str]]]
|
alert: Optional[dict[str, list[str]]]
|
||||||
signaling: Optional[dict]
|
signaling: Optional[dict]
|
||||||
mode: Optional[str]
|
mode: Optional[str]
|
||||||
effects: Optional[Effects]
|
effects: Optional[Attributes.Effects]
|
||||||
type: Literal["light"] = "light"
|
type: Final[Literal["light"]] = "light"
|
||||||
|
|
||||||
|
|
||||||
class LightLevel(Entity):
|
class LightLevel(Entity):
|
||||||
type: Literal["light_level"] = "light_level"
|
type: Final[Literal["light_level"]] = "light_level"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
enabled: Optional[bool]
|
enabled: Optional[bool]
|
||||||
light: Optional[LightLevelValue]
|
light: Optional[Attributes.LightLevelValue]
|
||||||
|
|
||||||
|
|
||||||
class Motion(Entity):
|
class Motion(Entity):
|
||||||
type: Literal["motion"] = "motion"
|
type: Final[Literal["motion"]] = "motion"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
enabled: Optional[bool]
|
enabled: Optional[bool]
|
||||||
motion: dict[str, bool]
|
motion: Optional[Attributes.Motion]
|
||||||
|
|
||||||
|
class RelativeRotary(Entity):
|
||||||
|
id: UUID
|
||||||
|
type: Final[Literal["relative_rotary"]] = "relative_rotary"
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
|
id_v1: Optional[str] = Field(
|
||||||
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
relative_rotary: Optional[Attributes.RelativeRotary]
|
||||||
|
|
||||||
class Resource(Entity):
|
class Resource(Entity):
|
||||||
id: UUID
|
id: UUID
|
||||||
type: str = "device"
|
type: Final[Literal["device"]] = "device"
|
||||||
id_v1: Optional[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})?$")
|
||||||
|
|
||||||
|
|
||||||
class Room(Entity):
|
class Room(Entity):
|
||||||
type: Literal["room"] = "room"
|
type: Final[Literal["room"]] = "room"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
services: Optional[list[Identifier]]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
metadata: Optional[Metadata]
|
)
|
||||||
children: Optional[list[Identifier]]
|
services: Optional[list[Attributes.Identifier]]
|
||||||
|
metadata: Optional[Attributes.Metadata]
|
||||||
|
children: Optional[list[Attributes.Identifier]]
|
||||||
|
|
||||||
class Scene(Entity):
|
class Scene(Entity):
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field(..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
metadata: Optional[Metadata]
|
..., regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
group: Optional[Identifier]
|
)
|
||||||
actions: Optional[list[Actions]]
|
metadata: Optional[Attributes.Metadata]
|
||||||
palette: Optional[Palette]
|
group: Optional[Attributes.Identifier]
|
||||||
|
actions: Optional[list[Attributes.Actions]]
|
||||||
|
palette: Optional[Attributes.Palette]
|
||||||
speed: Optional[float]
|
speed: Optional[float]
|
||||||
auto_dynamic: Optional[bool]
|
auto_dynamic: Optional[bool]
|
||||||
type: Literal["scene"] = "scene"
|
type: Final[Literal["scene"]] = "scene"
|
||||||
|
|
||||||
|
|
||||||
class Temperature(Entity):
|
class Temperature(Entity):
|
||||||
type: Literal["temperature"] = "temperature"
|
type: Final[Literal["temperature"]] = "temperature"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
enabled: Optional[bool]
|
enabled: Optional[bool]
|
||||||
temperature: Optional[Temp]
|
temperature: Optional[Attributes.Temp]
|
||||||
|
|
||||||
|
|
||||||
class ZGPConnectivity(Entity):
|
class ZGPConnectivity(Entity):
|
||||||
type: Literal["zgp_connectivity"] = "zgp_connectivity"
|
type: Final[Literal["zgp_connectivity"]] = "zgp_connectivity"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
status: Optional[
|
status: Optional[
|
||||||
Literal[
|
Literal[
|
||||||
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
|
"connected",
|
||||||
|
"disconnected",
|
||||||
|
"connectivity_issue",
|
||||||
|
"unidirectional_incoming",
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
source_id: Optional[str]
|
source_id: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class ZigbeeConnectivity(Entity):
|
class ZigbeeConnectivity(Entity):
|
||||||
type: Literal["zigbee_connectivity"] = "zigbee_connectivity"
|
type: Final[Literal["zigbee_connectivity"]] = "zigbee_connectivity"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
owner: Optional[Identifier]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
|
)
|
||||||
|
owner: Optional[Attributes.Identifier]
|
||||||
status: Optional[
|
status: Optional[
|
||||||
Literal[
|
Literal[
|
||||||
"connected", "disconnected", "connectivity_issue", "unidirectional_incoming"
|
"connected",
|
||||||
|
"disconnected",
|
||||||
|
"connectivity_issue",
|
||||||
|
"unidirectional_incoming",
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
mac_address: Optional[str]
|
mac_address: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class Zone(Entity):
|
class Zone(Entity):
|
||||||
type: Literal["zone"] = "zone"
|
type: Final[Literal["zone"]] = "zone"
|
||||||
id: UUID
|
id: UUID
|
||||||
id_v1: Optional[str] = Field("", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$")
|
id_v1: Optional[str] = Field(
|
||||||
services: Optional[list[Identifier]]
|
"", regex=r"^(\/[a-z]{4,32}\/[0-9a-zA-Z-]{1,32})?$"
|
||||||
metadata: Optional[Metadata]
|
)
|
||||||
children: Optional[list[Identifier]]
|
services: Optional[list[Attributes.Identifier]]
|
||||||
|
metadata: Attributes.Metadata
|
||||||
|
children: Optional[list[Attributes.Identifier]]
|
||||||
|
|
||||||
|
|
||||||
|
for k, v in HueEntsV2.__dict__.items():
|
||||||
|
if k.startswith("__"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
v.update_forward_refs()
|
||||||
|
2
test.py
2
test.py
@ -16,7 +16,7 @@ async def main():
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
# this will query for all lights every 10 seconds
|
# this will query for all lights every 10 seconds
|
||||||
print(await router.get_lights)
|
print(await router.get_lights())
|
||||||
await sleep(10.0)
|
await sleep(10.0)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user