diff options
Diffstat (limited to 'include/py/homekit')
-rw-r--r-- | include/py/homekit/config/config.py | 19 | ||||
-rw-r--r-- | include/py/homekit/modem/config.py | 28 | ||||
-rw-r--r-- | include/py/homekit/mqtt/_config.py | 20 | ||||
-rw-r--r-- | include/py/homekit/mqtt/module/temphum.py | 39 | ||||
-rw-r--r-- | include/py/homekit/util.py | 31 |
5 files changed, 96 insertions, 41 deletions
diff --git a/include/py/homekit/config/config.py b/include/py/homekit/config/config.py index d424888..abdedad 100644 --- a/include/py/homekit/config/config.py +++ b/include/py/homekit/config/config.py @@ -41,6 +41,9 @@ class BaseConfigUnit(ABC): self._data = {} self._logger = logging.getLogger(self.__class__.__name__) + def __iter__(self): + return iter(self._data) + def __getitem__(self, key): return self._data[key] @@ -123,10 +126,10 @@ class ConfigUnit(BaseConfigUnit): return None @classmethod - def _addr_schema(cls, required=False, **kwargs): + def _addr_schema(cls, required=False, only_ip=False, **kwargs): return { 'type': 'addr', - 'coerce': Addr.fromstring, + 'coerce': Addr.fromstring if not only_ip else Addr.fromipstring, 'required': required, **kwargs } @@ -158,6 +161,7 @@ class ConfigUnit(BaseConfigUnit): pass v = MyValidator() + need_document = False if rst == RootSchemaType.DICT: normalized = v.validated({'document': self._data}, @@ -165,16 +169,21 @@ class ConfigUnit(BaseConfigUnit): 'type': 'dict', 'keysrules': {'type': 'string'}, 'valuesrules': schema - }})['document'] + }}) + need_document = True elif rst == RootSchemaType.LIST: v = MyValidator() - normalized = v.validated({'document': self._data}, {'document': schema})['document'] + normalized = v.validated({'document': self._data}, {'document': schema}) + need_document = True else: normalized = v.validated(self._data, schema) if not normalized: raise cerberus.DocumentError(f'validation failed: {v.errors}') + if need_document: + normalized = normalized['document'] + self._data = normalized try: @@ -235,6 +244,8 @@ class TranslationUnit(BaseConfigUnit): class Translation: LANGUAGES = ('en', 'ru') + DEFAULT_LANGUAGE = 'ru' + _langs: dict[str, TranslationUnit] def __init__(self, name: str): diff --git a/include/py/homekit/modem/config.py b/include/py/homekit/modem/config.py index 039d759..16d1ba0 100644 --- a/include/py/homekit/modem/config.py +++ b/include/py/homekit/modem/config.py @@ -1,5 +1,29 @@ -from ..config import ConfigUnit +from ..config import ConfigUnit, Translation +from typing import Optional class ModemsConfig(ConfigUnit): - pass + NAME = 'modems' + + _strings: Translation + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._strings = Translation('modems') + + @classmethod + def schema(cls) -> Optional[dict]: + return { + 'type': 'dict', + 'schema': { + 'ip': cls._addr_schema(required=True, only_ip=True), + 'gateway_ip': cls._addr_schema(required=False, only_ip=True), + 'legacy_auth': {'type': 'boolean', 'required': True} + } + } + + def getshortname(self, modem: str, lang=Translation.DEFAULT_LANGUAGE): + return self._strings.get(lang)[modem]['short'] + + def getfullname(self, modem: str, lang=Translation.DEFAULT_LANGUAGE): + return self._strings.get(lang)[modem]['full']
\ No newline at end of file diff --git a/include/py/homekit/mqtt/_config.py b/include/py/homekit/mqtt/_config.py index e5f2c56..8aa3bfe 100644 --- a/include/py/homekit/mqtt/_config.py +++ b/include/py/homekit/mqtt/_config.py @@ -92,6 +92,7 @@ class MqttNodesConfig(ConfigUnit): 'type': 'dict', 'schema': { 'module': {'type': 'string', 'required': True, 'allowed': ['si7021', 'dht12']}, + 'legacy_payload': {'type': 'boolean', 'required': False, 'default': False}, 'interval': {'type': 'integer'}, 'i2c_bus': {'type': 'integer'}, 'tcpserver': { @@ -109,7 +110,12 @@ class MqttNodesConfig(ConfigUnit): 'legacy_topics': {'type': 'boolean'} } }, - 'password': {'type': 'string'} + 'password': {'type': 'string'}, + 'defines': { + 'type': 'dict', + 'keysrules': {'type': 'string'}, + 'valuesrules': {'type': ['string', 'integer']} + } } } } @@ -163,3 +169,15 @@ class MqttNodesConfig(ConfigUnit): else: resdict[name] = node return reslist if only_names else resdict + + def node_uses_legacy_temphum_data_payload(self, node_id: str) -> bool: + try: + return self.get_node(node_id)['temphum']['legacy_payload'] + except KeyError: + return False + + def node_uses_legacy_relay_power_payload(self, node_id: str) -> bool: + try: + return self.get_node(node_id)['relay']['legacy_topics'] + except KeyError: + return False diff --git a/include/py/homekit/mqtt/module/temphum.py b/include/py/homekit/mqtt/module/temphum.py index fd02cca..6deccfe 100644 --- a/include/py/homekit/mqtt/module/temphum.py +++ b/include/py/homekit/mqtt/module/temphum.py @@ -10,8 +10,8 @@ MODULE_NAME = 'MqttTempHumModule' DATA_TOPIC = 'temphum/data' -class MqttTemphumDataPayload(MqttPayload): - FORMAT = '=ddb' +class MqttTemphumLegacyDataPayload(MqttPayload): + FORMAT = '=dd' UNPACKER = { 'temp': two_digits_precision, 'rh': two_digits_precision @@ -19,39 +19,26 @@ class MqttTemphumDataPayload(MqttPayload): temp: float rh: float - error: int -# class MqttTempHumNodes(HashableEnum): -# KBN_SH_HALL = auto() -# KBN_SH_BATHROOM = auto() -# KBN_SH_LIVINGROOM = auto() -# KBN_SH_BEDROOM = auto() -# -# KBN_BH_2FL = auto() -# KBN_BH_2FL_STREET = auto() -# KBN_BH_1FL_LIVINGROOM = auto() -# KBN_BH_1FL_BEDROOM = auto() -# KBN_BH_1FL_BATHROOM = auto() -# -# KBN_NH_1FL_INV = auto() -# KBN_NH_1FL_CENTER = auto() -# KBN_NH_1LF_KT = auto() -# KBN_NH_1FL_DS = auto() -# KBN_NH_1FS_EZ = auto() -# -# SPB_FLAT120_CABINET = auto() +class MqttTemphumDataPayload(MqttTemphumLegacyDataPayload): + FORMAT = '=ddb' + error: int class MqttTempHumModule(MqttModule): + _legacy_payload: bool + def __init__(self, sensor: Optional[BaseSensor] = None, + legacy_payload=False, write_to_database=False, *args, **kwargs): if sensor is not None: kwargs['tick_interval'] = 10 super().__init__(*args, **kwargs) self._sensor = sensor + self._legacy_payload = legacy_payload def on_connect(self, mqtt: MqttNode): super().on_connect(mqtt) @@ -69,7 +56,7 @@ class MqttTempHumModule(MqttModule): rh = self._sensor.humidity() except: error = 1 - pld = MqttTemphumDataPayload(temp=temp, rh=rh, error=error) + pld = self._get_data_payload_cls()(temp=temp, rh=rh, error=error) self._mqtt_node_ref.publish(DATA_TOPIC, pld.pack()) def handle_payload(self, @@ -77,6 +64,10 @@ class MqttTempHumModule(MqttModule): topic: str, payload: bytes) -> Optional[MqttPayload]: if topic == DATA_TOPIC: - message = MqttTemphumDataPayload.unpack(payload) + message = self._get_data_payload_cls().unpack(payload) self._logger.debug(message) return message + + def _get_data_payload_cls(self): + return MqttTemphumLegacyDataPayload if self._legacy_payload else MqttTemphumDataPayload + diff --git a/include/py/homekit/util.py b/include/py/homekit/util.py index 2680c37..3c73440 100644 --- a/include/py/homekit/util.py +++ b/include/py/homekit/util.py @@ -53,17 +53,21 @@ class Addr: self.host = host self.port = port - @staticmethod - def fromstring(addr: str) -> Addr: - colons = addr.count(':') - if colons != 1: - raise ValueError('invalid host:port format') - - if not colons: - host = addr - port = None + @classmethod + def fromstring(cls, addr: str, port_required=True) -> Addr: + if port_required: + colons = addr.count(':') + if colons != 1: + raise ValueError('invalid host:port format') + + if not colons: + host = addr + port = None + else: + host, port = addr.split(':') else: - host, port = addr.split(':') + port = None + host = addr validate_ipv4_or_hostname(host, raise_exception=True) @@ -74,12 +78,19 @@ class Addr: return Addr(host, port) + @classmethod + def fromipstring(cls, addr: str) -> Addr: + return cls.fromstring(addr, port_required=False) + def __str__(self): buf = self.host if self.port is not None: buf += ':'+str(self.port) return buf + def __repr__(self): + return self.__str__() + def __iter__(self): yield self.host yield self.port |