diff options
Diffstat (limited to 'src/home/mqtt/payload')
-rw-r--r-- | src/home/mqtt/payload/__init__.py | 2 | ||||
-rw-r--r-- | src/home/mqtt/payload/base_payload.py | 28 | ||||
-rw-r--r-- | src/home/mqtt/payload/esp.py | 78 | ||||
-rw-r--r-- | src/home/mqtt/payload/inverter.py | 6 | ||||
-rw-r--r-- | src/home/mqtt/payload/relay.py | 90 | ||||
-rw-r--r-- | src/home/mqtt/payload/sensors.py | 4 | ||||
-rw-r--r-- | src/home/mqtt/payload/temphum.py | 14 |
7 files changed, 130 insertions, 92 deletions
diff --git a/src/home/mqtt/payload/__init__.py b/src/home/mqtt/payload/__init__.py index 9fcaf3e..eee6709 100644 --- a/src/home/mqtt/payload/__init__.py +++ b/src/home/mqtt/payload/__init__.py @@ -1 +1 @@ -from .base_payload import MQTTPayload
\ No newline at end of file +from .base_payload import MqttPayload
\ No newline at end of file diff --git a/src/home/mqtt/payload/base_payload.py b/src/home/mqtt/payload/base_payload.py index 108e0c0..1abd898 100644 --- a/src/home/mqtt/payload/base_payload.py +++ b/src/home/mqtt/payload/base_payload.py @@ -5,7 +5,21 @@ import re from typing import Optional, Tuple -class MQTTPayload(abc.ABC): +def pldstr(self) -> str: + attrs = [] + for field in self.__class__.__annotations__: + if hasattr(self, field): + attr = getattr(self, field) + attrs.append(f'{field}={attr}') + if attrs: + attrs_s = ' ' + attrs_s += ', '.join(attrs) + else: + attrs_s = '' + return f'<%s{attrs_s}>' % (self.__class__.__name__,) + + +class MqttPayload(abc.ABC): FORMAT = '' PACKER = {} UNPACKER = {} @@ -70,7 +84,7 @@ class MQTTPayload(abc.ABC): bf_number = -1 i += 1 - if issubclass(field_type, MQTTPayloadCustomField): + if issubclass(field_type, MqttPayloadCustomField): kwargs[field] = field_type.unpack(data[i]) else: kwargs[field] = cls._unpack_field(field, data[i]) @@ -87,15 +101,18 @@ class MQTTPayload(abc.ABC): @classmethod def _unpack_field(cls, name, val): - if isinstance(val, MQTTPayloadCustomField): + if isinstance(val, MqttPayloadCustomField): return if cls.UNPACKER and name in cls.UNPACKER: return cls.UNPACKER[name](val) else: return val + def __str__(self): + return pldstr(self) -class MQTTPayloadCustomField(abc.ABC): + +class MqttPayloadCustomField(abc.ABC): def __init__(self, **kwargs): for field in self.__class__.__annotations__: setattr(self, field, kwargs[field]) @@ -109,6 +126,9 @@ class MQTTPayloadCustomField(abc.ABC): def unpack(cls, *args, **kwargs): pass + def __str__(self): + return pldstr(self) + def bit_field(seq_no: int, total_bits: int, bits: int): return type(f'MQTTPayloadBitField_{seq_no}_{total_bits}_{bits}', (object,), { diff --git a/src/home/mqtt/payload/esp.py b/src/home/mqtt/payload/esp.py new file mode 100644 index 0000000..171cdb9 --- /dev/null +++ b/src/home/mqtt/payload/esp.py @@ -0,0 +1,78 @@ +import hashlib + +from .base_payload import MqttPayload, MqttPayloadCustomField + + +class OTAResultPayload(MqttPayload): + FORMAT = '=BB' + result: int + error_code: int + + +class OTAPayload(MqttPayload): + secret: str + filename: str + + # structure of returned data: + # + # uint8_t[len(secret)] secret; + # uint8_t[16] md5; + # *uint8_t data + + def pack(self): + buf = bytearray(self.secret.encode()) + m = hashlib.md5() + with open(self.filename, 'rb') as fd: + content = fd.read() + m.update(content) + buf.extend(m.digest()) + buf.extend(content) + return buf + + def unpack(cls, buf: bytes): + raise RuntimeError(f'{cls.__class__.__name__}.unpack: not implemented') + # secret = buf[:12].decode() + # filename = buf[12:].decode() + # return OTAPayload(secret=secret, filename=filename) + + +class DiagnosticsFlags(MqttPayloadCustomField): + state: bool + config_changed_value_present: bool + config_changed: bool + + @staticmethod + def unpack(flags: int): + # _logger.debug(f'StatFlags.unpack: flags={flags}') + state = flags & 0x1 + ccvp = (flags >> 1) & 0x1 + cc = (flags >> 2) & 0x1 + # _logger.debug(f'StatFlags.unpack: state={state}') + return DiagnosticsFlags(state=(state == 1), + config_changed_value_present=(ccvp == 1), + config_changed=(cc == 1)) + + def __index__(self): + bits = 0 + bits |= (int(self.state) & 0x1) + bits |= (int(self.config_changed_value_present) & 0x1) << 1 + bits |= (int(self.config_changed) & 0x1) << 2 + return bits + + +class InitialDiagnosticsPayload(MqttPayload): + FORMAT = '=IBbIB' + + ip: int + fw_version: int + rssi: int + free_heap: int + flags: DiagnosticsFlags + + +class DiagnosticsPayload(MqttPayload): + FORMAT = '=bIB' + + rssi: int + free_heap: int + flags: DiagnosticsFlags diff --git a/src/home/mqtt/payload/inverter.py b/src/home/mqtt/payload/inverter.py index 1d4099c..09388df 100644 --- a/src/home/mqtt/payload/inverter.py +++ b/src/home/mqtt/payload/inverter.py @@ -1,13 +1,13 @@ import struct -from .base_payload import MQTTPayload, bit_field +from .base_payload import MqttPayload, bit_field from typing import Tuple _mult_10 = lambda n: int(n*10) _div_10 = lambda n: n/10 -class Status(MQTTPayload): +class Status(MqttPayload): # 46 bytes FORMAT = 'IHHHHHHBHHHHHBHHHHHHHH' @@ -65,7 +65,7 @@ class Status(MQTTPayload): load_connected: bit_field(0, 16, 1) -class Generation(MQTTPayload): +class Generation(MqttPayload): # 8 bytes FORMAT = 'II' diff --git a/src/home/mqtt/payload/relay.py b/src/home/mqtt/payload/relay.py index 1a38201..4902991 100644 --- a/src/home/mqtt/payload/relay.py +++ b/src/home/mqtt/payload/relay.py @@ -1,53 +1,13 @@ -import hashlib +from .base_payload import MqttPayload +from .esp import ( + OTAResultPayload, + OTAPayload, + InitialDiagnosticsPayload, + DiagnosticsPayload +) -from .base_payload import MQTTPayload, MQTTPayloadCustomField - -# _logger = logging.getLogger(__name__) - -class StatFlags(MQTTPayloadCustomField): - state: bool - config_changed_value_present: bool - config_changed: bool - - @staticmethod - def unpack(flags: int): - # _logger.debug(f'StatFlags.unpack: flags={flags}') - state = flags & 0x1 - ccvp = (flags >> 1) & 0x1 - cc = (flags >> 2) & 0x1 - # _logger.debug(f'StatFlags.unpack: state={state}') - return StatFlags(state=(state == 1), - config_changed_value_present=(ccvp == 1), - config_changed=(cc == 1)) - - def __index__(self): - bits = 0 - bits |= (int(self.state) & 0x1) - bits |= (int(self.config_changed_value_present) & 0x1) << 1 - bits |= (int(self.config_changed) & 0x1) << 2 - return bits - - -class InitialStatPayload(MQTTPayload): - FORMAT = '=IBbIB' - - ip: int - fw_version: int - rssi: int - free_heap: int - flags: StatFlags - - -class StatPayload(MQTTPayload): - FORMAT = '=bIB' - - rssi: int - free_heap: int - flags: StatFlags - - -class PowerPayload(MQTTPayload): +class PowerPayload(MqttPayload): FORMAT = '=12sB' PACKER = { 'state': lambda n: int(n), @@ -60,37 +20,3 @@ class PowerPayload(MQTTPayload): secret: str state: bool - - -class OTAResultPayload(MQTTPayload): - FORMAT = '=BB' - result: int - error_code: int - - -class OTAPayload(MQTTPayload): - secret: str - filename: str - - # structure of returned data: - # - # uint8_t[len(secret)] secret; - # uint8_t[16] md5; - # *uint8_t data - - def pack(self): - buf = bytearray(self.secret.encode()) - m = hashlib.md5() - with open(self.filename, 'rb') as fd: - content = fd.read() - m.update(content) - buf.extend(m.digest()) - buf.extend(content) - return buf - - def unpack(cls, buf: bytes): - raise RuntimeError(f'{cls.__class__.__name__}.unpack: not implemented') - # secret = buf[:12].decode() - # filename = buf[12:].decode() - # return OTAPayload(secret=secret, filename=filename) - diff --git a/src/home/mqtt/payload/sensors.py b/src/home/mqtt/payload/sensors.py index 3ecc243..f99b307 100644 --- a/src/home/mqtt/payload/sensors.py +++ b/src/home/mqtt/payload/sensors.py @@ -1,10 +1,10 @@ -from .base_payload import MQTTPayload +from .base_payload import MqttPayload _mult_100 = lambda n: int(n*100) _div_100 = lambda n: n/100 -class Temperature(MQTTPayload): +class Temperature(MqttPayload): FORMAT = 'IhH' PACKER = { 'temp': _mult_100, diff --git a/src/home/mqtt/payload/temphum.py b/src/home/mqtt/payload/temphum.py new file mode 100644 index 0000000..5b45ecb --- /dev/null +++ b/src/home/mqtt/payload/temphum.py @@ -0,0 +1,14 @@ +from .base_payload import MqttPayload + +two_digits_precision = lambda x: round(x, 2) + + +class TempHumDataPayload(MqttPayload): + FORMAT = '=dd' + UNPACKER = { + 'temp': two_digits_precision, + 'rh': two_digits_precision + } + + temp: float + rh: float |