mirror of
https://github.com/fmtr/haco.git
synced 2026-10-25 18:40:15 -04:00
Move control state/command method wrapping to topic classes
This commit is contained in:
parent
5be372be03
commit
d0808006ab
3 changed files with 36 additions and 29 deletions
|
|
@ -20,7 +20,7 @@ class Capability(Base):
|
|||
|
||||
state: AnnounceTopicState | None = field(default_factory=AnnounceTopicState)
|
||||
command: AnnounceTopicCommand | None = field(default_factory=AnnounceTopicCommand)
|
||||
subscriptions: dict | None = field(default=None, metadata=dict(exclude=True), init=False)
|
||||
|
||||
|
||||
parent: Control | None = None
|
||||
announce = None
|
||||
|
|
@ -31,20 +31,17 @@ class Capability(Base):
|
|||
topic.set_parent(self)
|
||||
|
||||
self.converters = self.converters or self.control.converters
|
||||
self.subscriptions = self.get_subscriptions()
|
||||
|
||||
self.announce = self.get_announce()
|
||||
|
||||
def get_announce(self) -> dict:
|
||||
data = {}
|
||||
for topic in self.topics:
|
||||
data |= topic.announce
|
||||
data |= topic.get_announce()
|
||||
return data
|
||||
|
||||
def get_subscriptions(self) -> dict:
|
||||
data = {}
|
||||
for topic in self.topics:
|
||||
data |= topic.subscriptions
|
||||
data |= topic.get_subscriptions()
|
||||
return data
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -41,13 +41,7 @@ class Control(Base, Generic[DeviceT]):
|
|||
self.subscriptions = self.get_subscriptions()
|
||||
#self.announce = self.get_announce()
|
||||
|
||||
for capability in self.capabilities:
|
||||
for topic in capability.topics:
|
||||
method_name = topic.callback_name
|
||||
method = getattr(self, method_name, None)
|
||||
if not method: continue
|
||||
setattr(self, f'_{method_name}', method)
|
||||
setattr(self, f'{method_name}', topic.wrap_back)
|
||||
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
|
|
@ -56,7 +50,7 @@ class Control(Base, Generic[DeviceT]):
|
|||
def get_announce(self):
|
||||
data = self.model_dump()
|
||||
for cap in self.capabilities:
|
||||
data |= cap.announce
|
||||
data |= cap.get_announce()
|
||||
|
||||
return data
|
||||
|
||||
|
|
@ -89,7 +83,7 @@ class Control(Base, Generic[DeviceT]):
|
|||
data = {}
|
||||
|
||||
for capability in self.capabilities:
|
||||
data |= capability.subscriptions
|
||||
data |= capability.get_subscriptions()
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
from dataclasses import dataclass, field
|
||||
from functools import cached_property
|
||||
from typing import ClassVar, TYPE_CHECKING
|
||||
from typing import ClassVar, TYPE_CHECKING, Callable
|
||||
|
||||
from fmtr.tools import aio
|
||||
from haco.obs import logger
|
||||
|
|
@ -24,12 +24,17 @@ class AnnounceTopic:
|
|||
announce: dict | None = field(default=None, metadata=dict(exclude=True))
|
||||
subscriptions: dict | None = field(default=None, metadata=dict(exclude=True), init=False)
|
||||
|
||||
control_method: Callable | None = field(default=None, metadata=dict(exclude=True))
|
||||
|
||||
def set_parent(self, capability: Capability):
|
||||
self.parent = capability
|
||||
if self.key is None:
|
||||
self.key = self.KEY_DEFAULTS[bool(self.capability.name)]
|
||||
self.announce = self.get_announce()
|
||||
self.subscriptions = self.get_subscriptions()
|
||||
|
||||
method_name = self.callback_name
|
||||
method = getattr(self.capability.control, method_name, None)
|
||||
self.control_method = method
|
||||
setattr(self.capability.control, method_name, self.wrap_back)
|
||||
|
||||
def fill(self, mask):
|
||||
return mask.format(**self.fills)
|
||||
|
|
@ -60,6 +65,10 @@ class AnnounceTopic:
|
|||
|
||||
return f'{self.capability.name}_{self.IO}'
|
||||
|
||||
@property
|
||||
def callback_class_method_name(self):
|
||||
return f'{self.capability.control.__class__.__name__}.{self.callback_name}'
|
||||
|
||||
def get_subscriptions(self):
|
||||
return {}
|
||||
|
||||
|
|
@ -67,6 +76,9 @@ class AnnounceTopic:
|
|||
def capability(self):
|
||||
return self.parent
|
||||
|
||||
def wrap_back(self, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class AnnounceTopicState(AnnounceTopic):
|
||||
|
|
@ -76,20 +88,21 @@ class AnnounceTopicState(AnnounceTopic):
|
|||
return {}
|
||||
|
||||
async def wrap_back(self, value):
|
||||
method = getattr(self.capability.control, f'_{self.callback_name}', None)
|
||||
is_async = aio.is_async(method)
|
||||
|
||||
# test
|
||||
if not self.control_method:
|
||||
logger.error(f'Incomplete base class: {self.callback_class_method_name}')
|
||||
return
|
||||
|
||||
is_async = aio.is_async(self.control_method)
|
||||
try:
|
||||
|
||||
if is_async:
|
||||
value = await method(value)
|
||||
value = await self.control_method(value)
|
||||
else:
|
||||
value = method(value)
|
||||
value = self.control_method(value)
|
||||
|
||||
except NotImplementedError:
|
||||
logger.warning(f'No method implemented for {self.capability.control.__class__.__name__}.{self.callback_name}: {self.topic}')
|
||||
logger.warning(f'Subclass has not implemented method: {self.callback_class_method_name} {self.topic} {value}')
|
||||
return
|
||||
|
||||
value_raw = self.capability.converters.state(value)
|
||||
|
|
@ -105,21 +118,24 @@ class AnnounceTopicCommand(AnnounceTopic):
|
|||
return self.capability.state
|
||||
|
||||
async def wrap_back(self, message):
|
||||
method = getattr(self.capability.control, f'_{self.callback_name}', None)
|
||||
|
||||
is_async = aio.is_async(method)
|
||||
if not self.control_method:
|
||||
logger.error(f'Incomplete base class: {self.callback_class_method_name}')
|
||||
return
|
||||
|
||||
is_async = aio.is_async(self.control_method)
|
||||
value = message.payload.decode('utf-8')
|
||||
value = self.capability.converters.command(value)
|
||||
|
||||
try:
|
||||
|
||||
if is_async:
|
||||
value_raw = await method(value)
|
||||
value_raw = await self.control_method(value)
|
||||
else:
|
||||
value_raw = method(value)
|
||||
value_raw = self.control_method(value)
|
||||
|
||||
except NotImplementedError:
|
||||
logger.warning(f'{self.capability.control.__class__.__name__}.{self.callback_name}: {self.topic}')
|
||||
logger.warning(f'Subclass has not implemented method: {self.callback_class_method_name} {self.topic} {value}')
|
||||
return
|
||||
|
||||
# Echo back as new state
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue