mirror of
https://github.com/fmtr/haco.git
synced 2026-10-25 18:40:15 -04:00
Implement per-control/capability state/command datatype converters
This commit is contained in:
parent
1604e2447e
commit
879bc347f8
5 changed files with 39 additions and 13 deletions
|
|
@ -1,11 +1,12 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from fmtr.tools.iterator_tools import strip_none
|
||||
from haco.base import Base
|
||||
from haco.topics import AnnounceTopicState, AnnounceTopicCommand
|
||||
from haco.utils import Converters
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from haco.control import Control
|
||||
|
|
@ -15,6 +16,8 @@ if TYPE_CHECKING:
|
|||
class Capability(Base):
|
||||
name: str | None = None
|
||||
|
||||
converters: Type[Converters] | None = field(default=None, metadata=dict(exclude=True))
|
||||
|
||||
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)
|
||||
|
|
@ -27,6 +30,7 @@ class Capability(Base):
|
|||
for topic in self.topics:
|
||||
topic.set_parent(self)
|
||||
|
||||
self.converters = self.converters or self.control.converters
|
||||
self.subscriptions = self.get_subscriptions()
|
||||
|
||||
self.announce = self.get_announce()
|
||||
|
|
|
|||
|
|
@ -1,24 +1,25 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, TypeVar, Generic, Type, ClassVar
|
||||
|
||||
from fmtr.tools.json_tools import to_json
|
||||
from haco.base import Base
|
||||
from haco.capabilities import Capability
|
||||
from haco.obs import logger
|
||||
from haco.utils import sanitize_name
|
||||
from haco.utils import sanitize_name, Converters, ConvertersBool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from haco.device import Device
|
||||
|
||||
DeviceT = TypeVar("DeviceT", bound="Device")
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class Control(Base):
|
||||
class Control(Base, Generic[DeviceT]):
|
||||
converters: ClassVar[Type[Converters]] = ConvertersBool
|
||||
|
||||
name: str
|
||||
|
||||
|
||||
device: Device = field(default=None, init=False)
|
||||
device: DeviceT = field(default=None, init=False)
|
||||
capabilities: None | list[Capability] = field(default=None, metadata=dict(exclude=True))
|
||||
unique_id: str | None = field(default=None, init=False)
|
||||
availability_topic: str | None = field(default=None, init=False)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
from haco.control import Control
|
||||
from haco.utils import ConvertersString
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
|
|
@ -8,6 +9,7 @@ class Select(Control):
|
|||
DATA = dict(
|
||||
platform='select'
|
||||
)
|
||||
converters = ConvertersString
|
||||
|
||||
options: list[str]
|
||||
|
||||
|
|
|
|||
|
|
@ -84,14 +84,15 @@ class AnnounceTopicState(AnnounceTopic):
|
|||
try:
|
||||
|
||||
if is_async:
|
||||
value_raw = await method(value)
|
||||
value = await method(value)
|
||||
else:
|
||||
value_raw = method(value)
|
||||
value = method(value)
|
||||
|
||||
except NotImplementedError:
|
||||
logger.warning(f'No method implemented for {self.capability.control.__class__.__name__}.{self.callback_name}: {self.topic}')
|
||||
return
|
||||
|
||||
value_raw = self.capability.converters.state(value)
|
||||
await self.capability.control.device.client.publish(self.topic, value_raw)
|
||||
return value_raw
|
||||
|
||||
|
|
@ -107,13 +108,11 @@ class AnnounceTopicCommand(AnnounceTopic):
|
|||
method = getattr(self.capability.control, self.callback_name, None)
|
||||
|
||||
is_async = aio.is_async(method)
|
||||
|
||||
#test
|
||||
value = message.payload.decode('utf-8')
|
||||
value = self.capability.converters.command(value)
|
||||
|
||||
try:
|
||||
|
||||
value = message.payload.decode('utf-8')
|
||||
|
||||
if is_async:
|
||||
value_raw = await method(value)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import string
|
||||
from dataclasses import dataclass
|
||||
from typing import Callable
|
||||
|
||||
from fmtr.tools.datatype_tools import to_bool
|
||||
|
||||
CHARS_ALLOWED = string.ascii_lowercase + string.digits
|
||||
SEPS = '_- /'
|
||||
|
|
@ -10,6 +13,9 @@ RECONNECT_DELAY_SEC = 5
|
|||
ON = 'ON'
|
||||
OFF = 'OFF'
|
||||
|
||||
BOOL_MAP = {True: ON, False: OFF}
|
||||
|
||||
to_bool_ha = BOOL_MAP.get
|
||||
|
||||
def sanitize_name(s, sep='-'):
|
||||
chars = []
|
||||
|
|
@ -28,6 +34,20 @@ def sanitize_name(s, sep='-'):
|
|||
return sanitized
|
||||
|
||||
|
||||
class Converters:
|
||||
command: Callable = None
|
||||
state: Callable = None
|
||||
|
||||
|
||||
class ConvertersBool(Converters):
|
||||
command: Callable = to_bool
|
||||
state: Callable = to_bool_ha
|
||||
|
||||
|
||||
class ConvertersString(Converters):
|
||||
command: Callable = str
|
||||
state: Callable = str
|
||||
|
||||
@dataclass
|
||||
class Metadata:
|
||||
exclude: bool = False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue