Pool sensor v2: VCC monitoring, database resilience, receiver improvements
- Added voltage monitoring table and storage pipeline - Extended pool payload to 17 bytes with VCC field (protocol v2) - Improved database connection pool resilience (reduced pool size, aggressive recycling, pool disposal on failure) - Added environment variable support for database configuration - Fixed receiver MQTT deprecation warning (CallbackAPIVersion.VERSION2) - Silenced excessive RSSI status logging in receiver - Added reset flag tracking and reporting - Updated Docker compose with DB config and log rotation limits
This commit is contained in:
@@ -8,6 +8,12 @@ from typing import Optional, Tuple, Dict
|
||||
PAYLOAD_SIZE = 15
|
||||
MAGIC1 = 0x42
|
||||
MAGIC2 = 0x99
|
||||
RESET_FLAG_MAP = [
|
||||
(0x1, "PORF (power-on)"),
|
||||
(0x2, "EXTRF (external reset)"),
|
||||
(0x4, "BORF (brown-out)"),
|
||||
(0x8, "WDRF (watchdog)"),
|
||||
]
|
||||
|
||||
|
||||
def crc8_xor(data: bytes) -> int:
|
||||
@@ -18,6 +24,13 @@ def crc8_xor(data: bytes) -> int:
|
||||
return c
|
||||
|
||||
|
||||
def parse_version_and_reset_flags(version_byte: int):
|
||||
protocol_version = version_byte & 0x0F
|
||||
reset_flags = (version_byte >> 4) & 0x0F
|
||||
reset_causes = [desc for bit, desc in RESET_FLAG_MAP if reset_flags & bit]
|
||||
return protocol_version, reset_flags, reset_causes
|
||||
|
||||
|
||||
def decode_pool_payload(candidate_bytes: bytes, expected_seq: Optional[int] = None):
|
||||
"""Scan a byte stream for a plausible pool payload.
|
||||
|
||||
@@ -34,7 +47,7 @@ def decode_pool_payload(candidate_bytes: bytes, expected_seq: Optional[int] = No
|
||||
for offset in range(0, len(candidate_bytes) - PAYLOAD_SIZE + 1):
|
||||
chunk = candidate_bytes[offset:offset + PAYLOAD_SIZE]
|
||||
try:
|
||||
magic1, magic2, version, nodeId, seq, t_ds10, t_bme10, hum10, pres1, crc_received = struct.unpack(
|
||||
magic1, magic2, version_byte, nodeId, seq, t_ds10, t_bme10, hum10, pres1, crc_received = struct.unpack(
|
||||
'<BBBBHhhHHB', chunk
|
||||
)
|
||||
except struct.error:
|
||||
@@ -44,7 +57,9 @@ def decode_pool_payload(candidate_bytes: bytes, expected_seq: Optional[int] = No
|
||||
if crc_calculated != crc_received:
|
||||
continue
|
||||
|
||||
if version != 1 or nodeId != 1:
|
||||
protocol_version, reset_flags, reset_causes = parse_version_and_reset_flags(version_byte)
|
||||
|
||||
if protocol_version != 1 or nodeId != 1:
|
||||
continue
|
||||
|
||||
# Plausibility checks (unit scaled)
|
||||
@@ -70,7 +85,10 @@ def decode_pool_payload(candidate_bytes: bytes, expected_seq: Optional[int] = No
|
||||
best = {
|
||||
"offset": offset,
|
||||
"magic_ok": magic1 == MAGIC1 and magic2 == MAGIC2,
|
||||
"version": version,
|
||||
"version": protocol_version,
|
||||
"version_byte": version_byte,
|
||||
"reset_flags": reset_flags,
|
||||
"reset_causes": reset_causes,
|
||||
"nodeId": nodeId,
|
||||
"sequence": seq,
|
||||
"t_ds_c": t_ds10 / 10.0,
|
||||
@@ -83,9 +101,10 @@ def decode_pool_payload(candidate_bytes: bytes, expected_seq: Optional[int] = No
|
||||
return best
|
||||
|
||||
|
||||
def build_payload(seq: int, t_ds10: int, t_bme10: int, hum10: int, pres1: int) -> bytes:
|
||||
def build_payload(seq: int, t_ds10: int, t_bme10: int, hum10: int, pres1: int, reset_flags: int = 0) -> bytes:
|
||||
"""Build a valid payload with CRC appended."""
|
||||
header = struct.pack('<BBBBHhhHH', MAGIC1, MAGIC2, 1, 1, seq, t_ds10, t_bme10, hum10, pres1)
|
||||
version_byte = ((reset_flags & 0x0F) << 4) | 0x01
|
||||
header = struct.pack('<BBBBHhhHH', MAGIC1, MAGIC2, version_byte, 1, seq, t_ds10, t_bme10, hum10, pres1)
|
||||
crc = crc8_xor(header)
|
||||
return header + bytes([crc])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user