summaryrefslogtreecommitdiff
path: root/src/home/mqtt/payload
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2023-05-11 04:18:08 +0300
committerEvgeny Zinoviev <me@ch1p.io>2023-05-11 04:18:12 +0300
commit0aba139aeff8ff80757c5d36502413299a0b449e (patch)
tree2b8e760ff14d4691783eb7c7d341f093199aab82 /src/home/mqtt/payload
parent586d84b0c0a8b4dc1b5057733892b754397234ec (diff)
mqtt, esp: add new esp8266-based device
Diffstat (limited to 'src/home/mqtt/payload')
-rw-r--r--src/home/mqtt/payload/__init__.py2
-rw-r--r--src/home/mqtt/payload/base_payload.py28
-rw-r--r--src/home/mqtt/payload/esp.py78
-rw-r--r--src/home/mqtt/payload/inverter.py6
-rw-r--r--src/home/mqtt/payload/relay.py90
-rw-r--r--src/home/mqtt/payload/sensors.py4
-rw-r--r--src/home/mqtt/payload/temphum.py14
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