fix up example a bit, modify defaults for models
This commit is contained in:
parent
39162d3013
commit
9e23aef973
3
.flake8
3
.flake8
@ -1,3 +1,2 @@
|
|||||||
[flake8]
|
[flake8]
|
||||||
ignore = W503
|
ignore = W503, E501
|
||||||
ignoreExtra = E501, E203
|
|
||||||
|
9
config_example.yaml
Normal file
9
config_example.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
api_key:
|
||||||
|
bridge_ip: 192.168.1.1
|
||||||
|
aliases:
|
||||||
|
lights:
|
||||||
|
00000000-0000-0000-0000-000000000000: entry
|
||||||
|
11111111-1111-1111-1111-111111111111: bed
|
||||||
|
22222222-2222-2222-2222-222222222222: kitchen
|
||||||
|
33333333-3333-3333-3333-333333333333: bathroom
|
||||||
|
44444444-4444-4444-4444-444444444444: footrest
|
66
example.py
66
example.py
@ -1,56 +1,54 @@
|
|||||||
from asyncio import get_running_loop, sleep, create_task
|
from asyncio import get_running_loop, sleep
|
||||||
from uuid import UUID
|
|
||||||
|
|
||||||
from phlyght import HueEntsV2, Router
|
from phlyght import HueEntsV2, Router, Attributes, _XY
|
||||||
from phlyght import models
|
|
||||||
from rich import print
|
from rich import print
|
||||||
from random import random, randint
|
from random import random
|
||||||
|
|
||||||
from uvloop import install
|
try:
|
||||||
|
from uvloop import install
|
||||||
|
|
||||||
install()
|
install()
|
||||||
|
except ImportError:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
class HueRouter(Router):
|
class HueRouter(Router):
|
||||||
async def on_light_update(self, light: HueEntsV2.Light):
|
async def on_light_update(self, light: HueEntsV2.Light):
|
||||||
print(f"A light was updated: {light}")
|
print(f"A light was updated: {light}")
|
||||||
|
return True
|
||||||
|
|
||||||
async def on_button_update(self, button: HueEntsV2.Button):
|
async def on_button_update(self, button: HueEntsV2.Button):
|
||||||
print(f"A button was pressed: {button}")
|
print(f"A button was pressed: {button}")
|
||||||
|
return True
|
||||||
|
|
||||||
async def on_grouped_light_update(self, grouped_light: HueEntsV2.GroupedLight):
|
async def _shift(self, light: HueEntsV2.Light):
|
||||||
print(f"A grouped light was updated: {grouped_light}")
|
|
||||||
|
|
||||||
async def on_ready(self):
|
|
||||||
create_task(self._random_cycle("1795db24-4b81-4763-a6db-1d0d44373599"))
|
|
||||||
await sleep(0.3)
|
|
||||||
create_task(self._random_cycle("3c9d5ba7-ea43-45f8-a823-f3b32168776d"))
|
|
||||||
await sleep(0.3)
|
|
||||||
create_task(self._random_cycle("93a1533e-bfeb-4103-a150-180943a3ff3b"))
|
|
||||||
await sleep(0.3)
|
|
||||||
create_task(self._random_cycle("a9093d1b-8508-4311-8d8a-62b5389dae30"))
|
|
||||||
await sleep(0.3)
|
|
||||||
create_task(self._random_cycle("e3b73801-9040-440c-9284-fa16ac3d8713"))
|
|
||||||
await sleep(0.3)
|
|
||||||
|
|
||||||
async def _random_cycle(self, id: str):
|
|
||||||
while get_running_loop().is_running():
|
while get_running_loop().is_running():
|
||||||
|
light.color = Attributes.LightColor(xy=_XY(x=random(), y=random()))
|
||||||
|
light.dimming = Attributes.Dimming(brightness=100.0, min_dim_level=0.2)
|
||||||
|
# We can modify the attributes of the lights and send the light object as the parameter to set_light()
|
||||||
await self.set_light(
|
await self.set_light(
|
||||||
id,
|
light.id,
|
||||||
HueEntsV2.Light(
|
light,
|
||||||
color=models.LightColor(xy=models._XY(x=random(), y=random())),
|
|
||||||
on=models.On(on=True),
|
|
||||||
dimming=models.Dimming(brightness=randint(25, 100)),
|
|
||||||
effects=models.LightEffect(effect="candle"),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
await sleep(0.3)
|
||||||
|
# Could potentially get more in / at a faster update rate but its getting pretty close to making the bridge unresponsive at this rate
|
||||||
|
|
||||||
|
async def on_ready(self): # This will be called once, right after startup
|
||||||
|
for light in [
|
||||||
|
self.entry,
|
||||||
|
self.bed,
|
||||||
|
self.kitchen,
|
||||||
|
self.bathroom,
|
||||||
|
self.footrest,
|
||||||
|
]:
|
||||||
|
# These are all aliases defined in the config, accessible as an attribute using the name on the router
|
||||||
|
self.new_task(self._shift(light))
|
||||||
await sleep(0.5)
|
await sleep(0.5)
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
router = HueRouter(
|
router = HueRouter(
|
||||||
"your access key",
|
"Your API Key",
|
||||||
bridge_ip="https://your gateway address",
|
bridge_ip="https://192.168.1.1",
|
||||||
max_cache_size=1024,
|
max_cache_size=64,
|
||||||
)
|
)
|
||||||
router.run()
|
router.run()
|
||||||
|
@ -1,81 +1,13 @@
|
|||||||
from .http import Router
|
from .http import Router
|
||||||
from .models import (
|
from .models import Archetype, HueEntsV2, Attributes, RoomType, Entity, HueEntsV1, _XY
|
||||||
Archetype,
|
|
||||||
HueEntsV2,
|
|
||||||
RoomType,
|
|
||||||
Entity,
|
|
||||||
HueEntsV1,
|
|
||||||
Action,
|
|
||||||
Actions,
|
|
||||||
Alert,
|
|
||||||
Button,
|
|
||||||
Color,
|
|
||||||
ColorMirekSchema,
|
|
||||||
ColorPoint,
|
|
||||||
ColorPointColor,
|
|
||||||
ColorTemp,
|
|
||||||
EntChannel,
|
|
||||||
LightColor,
|
|
||||||
PaletteColor,
|
|
||||||
ScenePaletteColorTemp,
|
|
||||||
Dependee,
|
|
||||||
Dimming,
|
|
||||||
DimmingDelta,
|
|
||||||
Dynamics,
|
|
||||||
SceneDynamics,
|
|
||||||
ProductData,
|
|
||||||
Effects,
|
|
||||||
EntLocation,
|
|
||||||
LightEffect,
|
|
||||||
SceneEffects,
|
|
||||||
TimedEffects,
|
|
||||||
RotaryEvent,
|
|
||||||
Gamut,
|
|
||||||
Gradient,
|
|
||||||
Identifier,
|
|
||||||
LightLevelValue,
|
|
||||||
ServiceLocation,
|
|
||||||
Motion,
|
|
||||||
SegmentManager,
|
|
||||||
)
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
"Router",
|
"Router",
|
||||||
"Entity",
|
"Entity",
|
||||||
"Archetype",
|
"Archetype",
|
||||||
"RoomType",
|
"RoomType",
|
||||||
|
"Attributes",
|
||||||
"HueEntsV2",
|
"HueEntsV2",
|
||||||
"HueEntsV1",
|
"HueEntsV1",
|
||||||
"Action",
|
"_XY",
|
||||||
"Actions",
|
|
||||||
"Alert",
|
|
||||||
"Button",
|
|
||||||
"Color",
|
|
||||||
"ColorMirekSchema",
|
|
||||||
"ColorPoint",
|
|
||||||
"ColorPointColor",
|
|
||||||
"ColorTemp",
|
|
||||||
"EntChannel",
|
|
||||||
"LightColor",
|
|
||||||
"PaletteColor",
|
|
||||||
"ScenePaletteColorTemp",
|
|
||||||
"Dependee",
|
|
||||||
"Dimming",
|
|
||||||
"DimmingDelta",
|
|
||||||
"Dynamics",
|
|
||||||
"SceneDynamics",
|
|
||||||
"ProductData",
|
|
||||||
"Effects",
|
|
||||||
"EntLocation",
|
|
||||||
"LightEffect",
|
|
||||||
"SceneEffects",
|
|
||||||
"TimedEffects",
|
|
||||||
"RotaryEvent",
|
|
||||||
"Gamut",
|
|
||||||
"Gradient",
|
|
||||||
"Identifier",
|
|
||||||
"LightLevelValue",
|
|
||||||
"ServiceLocation",
|
|
||||||
"Motion",
|
|
||||||
"SegmentManager",
|
|
||||||
)
|
)
|
||||||
|
271
phlyght/http.py
271
phlyght/http.py
@ -1,36 +1,45 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from asyncio import get_running_loop, new_event_loop
|
from asyncio import gather, get_running_loop, new_event_loop, sleep
|
||||||
from inspect import signature, Parameter
|
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, TypeVar, Generic
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from httpx import AsyncClient, ConnectError, ConnectTimeout, _content
|
from httpx import AsyncClient, ConnectError, ConnectTimeout, _content
|
||||||
from httpx._urls import URL as HttpxURL
|
from httpx._urls import URL as _URL
|
||||||
from httpx._exceptions import ReadTimeout as HTTPxReadTimeout
|
from httpx._exceptions import ReadTimeout as HTTPxReadTimeout
|
||||||
from httpcore._exceptions import ReadTimeout
|
from httpcore._exceptions import ReadTimeout
|
||||||
from ujson import loads, JSONDecodeError
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from yarl import URL as YarlURL
|
from pydantic.dataclasses import dataclass
|
||||||
|
from pydantic.generics import GenericModel
|
||||||
|
from yaml import Loader, load
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from .models import HueEntsV2, Entity, UUID
|
from .models import HueEntsV2, Entity, UUID
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ujson import dumps
|
from ujson import dumps, loads, JSONDecodeError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
from orjson import dumps
|
from orjson import dumps, loads, JSONDecodeError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from json import dumps
|
from json import dumps, loads, JSONDecodeError
|
||||||
|
|
||||||
setattr(_content, "json_dumps", dumps)
|
setattr(_content, "json_dumps", dumps)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from yarl import URL as UR
|
||||||
|
except ImportError:
|
||||||
|
...
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from rich import print # noqa
|
from rich import print # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
__all__ = ("Router", "route", "RouterMeta", "SubRouter", "HueAPIv2")
|
__all__ = ("Router", "route", "RouterMeta", "SubRouter", "HueAPIv2")
|
||||||
|
|
||||||
ENDPOINT_METHOD = compile(r"^(?=((?:get|set|create|delete)\w+))\1")
|
ENDPOINT_METHOD = compile(r"^(?=((?:get|set|create|delete)\w+))\1")
|
||||||
@ -42,7 +51,7 @@ MSG_RE_BYTES = compile(
|
|||||||
rb"(?=((?P<hello>^: hi\n\n$)|^id:\s(?P<id>[0-9]+:\d*?)\ndata:(?P<data>[^$]+)\n\n))\1"
|
rb"(?=((?P<hello>^: hi\n\n$)|^id:\s(?P<id>[0-9]+:\d*?)\ndata:(?P<data>[^$]+)\n\n))\1"
|
||||||
)
|
)
|
||||||
MSG_RE_TEXT = compile(
|
MSG_RE_TEXT = compile(
|
||||||
r"(?=((?P<hello>^: hi\n*?$)|^(?:id:\s(?P<id>[0-9]+:[0-9]?)\n*?)|data:[\n\s]*?(?P<data>[^$]+)[\n\s]*?))\1"
|
r"(?=((?P<hello>^: hi\n\n$)|^id:\s(?P<id>[0-9]+:\d*?)\ndata:(?P<data>[^$]+)\n\n))\1"
|
||||||
)
|
)
|
||||||
TYPE_CACHE = {}
|
TYPE_CACHE = {}
|
||||||
|
|
||||||
@ -52,6 +61,11 @@ for k, v in HueEntsV2.__dict__.items():
|
|||||||
TYPE_CACHE[getattr(v, "type")] = v
|
TYPE_CACHE[getattr(v, "type")] = v
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass()
|
||||||
|
class PhlyghtConfig:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def get_url_args(url):
|
def get_url_args(url):
|
||||||
kwds = {}
|
kwds = {}
|
||||||
match = STR_FMT_RE.finditer(url)
|
match = STR_FMT_RE.finditer(url)
|
||||||
@ -65,9 +79,12 @@ def get_url_args(url):
|
|||||||
return kwds
|
return kwds
|
||||||
|
|
||||||
|
|
||||||
class Event(BaseModel):
|
class Event(GenericModel, Generic[_T]):
|
||||||
|
class Config:
|
||||||
|
__root__ = _T
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
object: Entity
|
object: _T
|
||||||
type: str
|
type: str
|
||||||
|
|
||||||
|
|
||||||
@ -76,26 +93,30 @@ class LRUItem(BaseModel):
|
|||||||
value: Any = object()
|
value: Any = object()
|
||||||
|
|
||||||
def __id__(self):
|
def __id__(self):
|
||||||
return id(self.value.id)
|
return id(self.value)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.value.id)
|
return hash(self.value)
|
||||||
|
|
||||||
|
|
||||||
class LRU(set):
|
class LRU(set):
|
||||||
def __init__(self, *items, maxsize=128):
|
def __init__(self, maxsize, /, *items):
|
||||||
self.maxsize = maxsize
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.maxsize = maxsize
|
||||||
for item in items[:maxsize]:
|
for item in items[:maxsize]:
|
||||||
self.add(LRUItem(value=item))
|
self.add(LRUItem(value=item))
|
||||||
|
|
||||||
def add(self, item):
|
def add(self, item):
|
||||||
if len(self) + 1 > self.maxsize:
|
if len(self) + 1 > self.maxsize:
|
||||||
self ^= set(
|
new = self ^ set(
|
||||||
sorted(self, key=lambda x: x.access_time)[
|
sorted(self, key=lambda x: x.access_time)[::-1][
|
||||||
: len(self) + 1 - self.maxsize
|
: len(self) + 1 - self.maxsize
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
old = self - new
|
||||||
|
for fut in old:
|
||||||
|
fut.value.cancel()
|
||||||
|
self -= old
|
||||||
|
|
||||||
super().add(LRUItem(value=item))
|
super().add(LRUItem(value=item))
|
||||||
|
|
||||||
@ -108,22 +129,29 @@ class LRU(set):
|
|||||||
def extend(self, *items):
|
def extend(self, *items):
|
||||||
len_new = len(self) + len(items)
|
len_new = len(self) + len(items)
|
||||||
if len_new > self.maxsize:
|
if len_new > self.maxsize:
|
||||||
self ^= set(
|
new = self ^ set(
|
||||||
sorted(self, key=lambda x: x.access_time)[: len_new - self.maxsize]
|
sorted(self, key=lambda x: x.access_time)[::-1][
|
||||||
|
: len_new - self.maxsize
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
old = self - new
|
||||||
|
for fut in old:
|
||||||
|
fut.value.cancel()
|
||||||
|
self -= old
|
||||||
self |= set([LRUItem(value=item) for item in items])
|
self |= set([LRUItem(value=item) for item in items])
|
||||||
|
|
||||||
|
|
||||||
class URL(HttpxURL):
|
class URL(_URL):
|
||||||
def __truediv__(self, other):
|
def __truediv__(self, other):
|
||||||
|
# Why am i doing this? good question.
|
||||||
try:
|
try:
|
||||||
return URL(str(YarlURL(f"{self}") / other.lstrip("/")))
|
return URL(str(UR(f"{self}") / other.lstrip("/")))
|
||||||
except NameError:
|
except NameError:
|
||||||
return URL(f"{self}{other.lstrip('/')}")
|
return URL(f"{self}{other.lstrip('/')}")
|
||||||
|
|
||||||
def __floordiv__(self, other):
|
def __floordiv__(self, other):
|
||||||
try:
|
try:
|
||||||
return URL(str(YarlURL(f"{self}") / other.lstrip("/")))
|
return URL(str(UR(f"{self}") / other.lstrip("/")))
|
||||||
except NameError:
|
except NameError:
|
||||||
return URL(f"{self}{other.lstrip('/')}")
|
return URL(f"{self}{other.lstrip('/')}")
|
||||||
|
|
||||||
@ -180,6 +208,7 @@ def route(method, endpoint) -> Any:
|
|||||||
ents = set(filter(lambda x: isinstance(x, Entity), args))
|
ents = set(filter(lambda x: isinstance(x, Entity), args))
|
||||||
args = tuple(args - ents)
|
args = tuple(args - ents)
|
||||||
ent: BaseModel
|
ent: BaseModel
|
||||||
|
|
||||||
for ent in ents:
|
for ent in ents:
|
||||||
json |= loads(
|
json |= loads(
|
||||||
ent.json(exclude_unset=True, exclude_none=True, skip_defaults=True)
|
ent.json(exclude_unset=True, exclude_none=True, skip_defaults=True)
|
||||||
@ -190,7 +219,7 @@ def route(method, endpoint) -> Any:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if param.kind == Parameter.POSITIONAL_ONLY:
|
if param.kind == Parameter.POSITIONAL_ONLY:
|
||||||
data[param_name] = param.annotation(args[0])
|
data[param_name] = param.annotation(str(args[0]))
|
||||||
if len(args) > 1:
|
if len(args) > 1:
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
|
|
||||||
@ -246,6 +275,7 @@ def route(method, endpoint) -> Any:
|
|||||||
new_endpoint = URL(_url_base) / endpoint.format(**url_args)
|
new_endpoint = URL(_url_base) / endpoint.format(**url_args)
|
||||||
else:
|
else:
|
||||||
new_endpoint = URL(_url_base) / endpoint
|
new_endpoint = URL(_url_base) / endpoint
|
||||||
|
|
||||||
if headers and headers.get("Accept", "") == "text/event-stream":
|
if headers and headers.get("Accept", "") == "text/event-stream":
|
||||||
return self._client.stream(
|
return self._client.stream(
|
||||||
method,
|
method,
|
||||||
@ -256,7 +286,7 @@ def route(method, endpoint) -> Any:
|
|||||||
headers=headers,
|
headers=headers,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return await self._client.request(
|
resp = await self._client.request(
|
||||||
method,
|
method,
|
||||||
new_endpoint,
|
new_endpoint,
|
||||||
content=content,
|
content=content,
|
||||||
@ -265,6 +295,7 @@ def route(method, endpoint) -> Any:
|
|||||||
headers=headers,
|
headers=headers,
|
||||||
json=json,
|
json=json,
|
||||||
)
|
)
|
||||||
|
return resp
|
||||||
|
|
||||||
return sub_wrap
|
return sub_wrap
|
||||||
|
|
||||||
@ -349,9 +380,12 @@ class SubRouter(metaclass=RouterMeta):
|
|||||||
if kwargs.get("root"):
|
if kwargs.get("root"):
|
||||||
cls._api_path = f'{kwargs.get("root")}{cls.BASE_URI}'
|
cls._api_path = f'{kwargs.get("root")}{cls.BASE_URI}'
|
||||||
|
|
||||||
|
def __getattribute__(self, key) -> Any:
|
||||||
|
return object.__getattribute__(self, key)
|
||||||
|
|
||||||
|
|
||||||
class HueAPIv1(SubRouter):
|
class HueAPIv1(SubRouter):
|
||||||
BASEHttpxURL = ""
|
BASE_URL = ""
|
||||||
|
|
||||||
|
|
||||||
class HueAPIv2(SubRouter):
|
class HueAPIv2(SubRouter):
|
||||||
@ -367,7 +401,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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,
|
||||||
@ -392,7 +426,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -402,12 +436,12 @@ class HueAPIv2(SubRouter):
|
|||||||
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, /):
|
||||||
...
|
...
|
||||||
@ -417,7 +451,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -427,18 +461,18 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -448,7 +482,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -458,12 +492,12 @@ class HueAPIv2(SubRouter):
|
|||||||
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, /):
|
||||||
...
|
...
|
||||||
@ -478,7 +512,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -493,7 +527,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -508,7 +542,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -523,7 +557,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -538,7 +572,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -553,7 +587,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -568,7 +602,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -583,7 +617,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -598,7 +632,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -613,7 +647,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -628,7 +662,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -648,7 +682,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -658,12 +692,12 @@ class HueAPIv2(SubRouter):
|
|||||||
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, /):
|
||||||
...
|
...
|
||||||
@ -673,7 +707,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -683,12 +717,12 @@ class HueAPIv2(SubRouter):
|
|||||||
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, /):
|
||||||
...
|
...
|
||||||
@ -703,7 +737,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -713,7 +747,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -729,7 +763,7 @@ class HueAPIv2(SubRouter):
|
|||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@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}"
|
||||||
)
|
)
|
||||||
@ -738,7 +772,7 @@ class HueAPIv2(SubRouter):
|
|||||||
):
|
):
|
||||||
...
|
...
|
||||||
|
|
||||||
@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}",
|
||||||
@ -760,7 +794,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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):
|
||||||
...
|
...
|
||||||
@ -775,7 +809,7 @@ class HueAPIv2(SubRouter):
|
|||||||
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,
|
||||||
@ -800,7 +834,7 @@ class HueAPIv2(SubRouter):
|
|||||||
async def get_rotaries(self):
|
async def get_rotaries(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("PUT", "/resource/relative_rotary/{relative_rotary_id}")
|
@route("PUT", "/resource/relative_rotary/{relative_rotary_id}")
|
||||||
async def set_rotary(self, relative_rotary_id: UUID, /, **kwargs):
|
async def set_rotary(self, relative_rotary_id: UUID, /, **kwargs):
|
||||||
...
|
...
|
||||||
@ -810,12 +844,12 @@ class HueAPIv2(SubRouter):
|
|||||||
async def get_rotary(self, relative_rotary_id: UUID, /):
|
async def get_rotary(self, relative_rotary_id: UUID, /):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("POST", "/resource/relative_rotary")
|
@route("POST", "/resource/relative_rotary")
|
||||||
async def create_rotary(self, **kwargs):
|
async def create_rotary(self, **kwargs):
|
||||||
...
|
...
|
||||||
|
|
||||||
@ret_cls(models.Identifier)
|
@ret_cls(models.Attributes.Identifier)
|
||||||
@route("DELETE", "/resource/relative_rotary/{relative_rotary_id}")
|
@route("DELETE", "/resource/relative_rotary/{relative_rotary_id}")
|
||||||
async def delete_rotary(self, relative_rotary_id: UUID, /):
|
async def delete_rotary(self, relative_rotary_id: UUID, /):
|
||||||
...
|
...
|
||||||
@ -930,76 +964,121 @@ class HueAPIv2(SubRouter):
|
|||||||
|
|
||||||
|
|
||||||
class Router(HueAPIv2):
|
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 = 10):
|
||||||
cls = super().__new__(cls, hue_api_key)
|
cls = super().__new__(cls, hue_api_key)
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, hue_api_key: str, bridge_ip: Optional[str] = None, max_cache_size=512
|
self,
|
||||||
|
hue_api_key: Optional[str] = None,
|
||||||
|
bridge_ip: Optional[str] = None,
|
||||||
|
max_cache_size=10,
|
||||||
):
|
):
|
||||||
super().__init__(hue_api_key)
|
with open("config.yaml", "r+") as f:
|
||||||
|
self.config = load(f, Loader=Loader)
|
||||||
|
super().__init__(hue_api_key or self.config.api_key)
|
||||||
|
self.cache = LRU(max_cache_size)
|
||||||
self._client = AsyncClient(headers=self._headers, verify=False)
|
self._client = AsyncClient(headers=self._headers, verify=False)
|
||||||
self._subscription = None
|
self._subscription = None
|
||||||
self._bridge_ip = bridge_ip or ""
|
self._bridge_ip = bridge_ip or self.config.bridge_ip
|
||||||
self._last_id = None
|
self._tasks = []
|
||||||
self.cache = LRU(maxsize=max_cache_size)
|
self.lights = {}
|
||||||
|
self.bridges = {}
|
||||||
|
self.entertainment_configurations = {}
|
||||||
|
self.entertainments = {}
|
||||||
|
self.buttons = {}
|
||||||
|
self.rooms = {}
|
||||||
|
self.scenes = {}
|
||||||
|
self.zones = {}
|
||||||
|
self.rotaries = {}
|
||||||
|
self.geofences = {}
|
||||||
|
self.behavior_instances = {}
|
||||||
|
self.bridge_homes = {}
|
||||||
|
self.zgb_connectivities = {}
|
||||||
|
self.zigbee_connectivities = {}
|
||||||
|
|
||||||
def subscribe(self, *args, **kwargs):
|
def subscribe(self, *args, **kwargs):
|
||||||
if not self._subscription or self._subscription.done():
|
if not self._subscription or self._subscription.done():
|
||||||
self._subscription = get_running_loop().create_task(self._subscribe())
|
self._subscription = self.new_task(self._subscribe(*args, **kwargs))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
loop = new_event_loop()
|
loop = new_event_loop()
|
||||||
try:
|
try:
|
||||||
loop.run_until_complete(self._subscribe())
|
loop.run_until_complete(self._startup())
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
for t in self._tasks:
|
||||||
|
t.cancel()
|
||||||
|
for t in self.cache:
|
||||||
|
t.value.cancel()
|
||||||
print("Exiting..")
|
print("Exiting..")
|
||||||
loop.stop()
|
loop.stop()
|
||||||
loop.close()
|
loop.close()
|
||||||
|
|
||||||
def _parse_payload(self, payload: str):
|
def new_task(self, coro):
|
||||||
_match = MSG_RE_TEXT.search(payload)
|
self._tasks.append(t := get_running_loop().create_task(coro))
|
||||||
|
return t
|
||||||
|
|
||||||
|
async def _startup(self):
|
||||||
|
try:
|
||||||
|
loop = get_running_loop()
|
||||||
|
for k, v in self.config["aliases"].items():
|
||||||
|
fn = getattr(self, f"get_{k}")
|
||||||
|
objs = await fn()
|
||||||
|
for obj in objs:
|
||||||
|
alias = v.get(str(obj.id))
|
||||||
|
if alias:
|
||||||
|
ob = obj.__class__(id=obj.id)
|
||||||
|
getattr(self, k)[alias] = ob
|
||||||
|
setattr(self, alias, ob)
|
||||||
|
|
||||||
|
self.new_task(self._subscribe())
|
||||||
|
|
||||||
|
while loop.is_running():
|
||||||
|
await sleep(60)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
await gather(*self._tasks)
|
||||||
|
|
||||||
|
def _parse_payload(self, payload: bytes):
|
||||||
|
_match = MSG_RE_BYTES.search(payload)
|
||||||
if not _match:
|
if not _match:
|
||||||
return None
|
return None
|
||||||
_events, _data, _id = [], "", ""
|
_events, _data, _id = [], b"", b""
|
||||||
_parsed_events = []
|
if (_data := _match.group("data")) and (_id := _match.group("id")):
|
||||||
if _data := _match.group("data"):
|
|
||||||
_events.extend(loads(_data))
|
_events.extend(loads(_data))
|
||||||
|
|
||||||
elif _id := _match.group("id"):
|
|
||||||
self._last_id = _id
|
|
||||||
return
|
|
||||||
|
|
||||||
for _event in _events:
|
for _event in _events:
|
||||||
for _ent in _event["data"]:
|
for _ent in _event["data"]:
|
||||||
self.cache.add(
|
_event_id = _id.decode()
|
||||||
event := Event(
|
_event_type = _event["type"]
|
||||||
id=_id,
|
_object = TYPE_CACHE[_ent["type"]](**_ent)
|
||||||
object=TYPE_CACHE[_ent["type"]](**_ent),
|
event = Event(
|
||||||
type=_event["type"],
|
id=_event_id,
|
||||||
)
|
object=_object,
|
||||||
|
type=_event_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
_parsed_events.append(event)
|
|
||||||
if hasattr(self, f"on_{event.object.type}_{event.type}"):
|
if hasattr(self, f"on_{event.object.type}_{event.type}"):
|
||||||
get_running_loop().create_task(
|
self.cache.add(
|
||||||
getattr(self, f"on_{event.object.type}_{event.type}")(event)
|
get_running_loop().create_task(
|
||||||
|
getattr(self, f"on_{event.object.type}_{event.type}")(
|
||||||
|
_object
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _subscribe(self, *args, **kwargs):
|
async def _subscribe(self, *args, **kwargs):
|
||||||
loop = get_running_loop()
|
|
||||||
if hasattr(self, "on_ready"):
|
if hasattr(self, "on_ready"):
|
||||||
loop.create_task(getattr(self, "on_ready")())
|
self.new_task(self.on_ready())
|
||||||
|
while get_running_loop().is_running():
|
||||||
while loop.is_running():
|
|
||||||
stream = await self.listen_events(
|
|
||||||
headers={**self._headers, **{"Accept": "text/event-stream"}}
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
|
stream = await self.listen_events(
|
||||||
|
headers={**self._headers, **{"Accept": "text/event-stream"}}
|
||||||
|
)
|
||||||
async with stream as _iter:
|
async with stream as _iter:
|
||||||
async for msg in _iter.aiter_lines():
|
async for msg in _iter.aiter_bytes():
|
||||||
self._parse_payload(msg)
|
self._parse_payload(msg)
|
||||||
|
|
||||||
except (ReadTimeout, HTTPxReadTimeout, ConnectTimeout, ConnectError):
|
except (ReadTimeout, HTTPxReadTimeout, ConnectTimeout, ConnectError):
|
||||||
...
|
...
|
||||||
|
await sleep(1)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user