#!/usr/bin/env python3 """Test pool payload decoding with the new MQTT message format""" import json import struct from typing import Optional PAYLOAD_SIZE = 15 MAGIC1 = 0x42 MAGIC2 = 0x99 def crc8_xor(data: bytes) -> int: """Simple XOR checksum used by the pool payload.""" c = 0 for b in data: c ^= b return c def decode_pool_payload(candidate_bytes: bytes, expected_seq: Optional[int] = None): """Scan a byte stream for a plausible pool payload. Slides a 15-byte window, validates with CRC, version/nodeId, and range checks, and scores candidates. Returns the best decoded dict or None. """ # Drop leading preamble (0xAA) if present while candidate_bytes.startswith(b"\xaa"): candidate_bytes = candidate_bytes[1:] best = None best_score = -1 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( ' best_score: best_score = score best = { "offset": offset, "magic_ok": magic1 == MAGIC1 and magic2 == MAGIC2, "version": version, "nodeId": nodeId, "sequence": seq, "t_ds_c": t_ds10 / 10.0, "t_bme_c": t_bme10 / 10.0, "humidity": hum10 / 10.0, "pressure_hpa": pres1 / 10.0, "crc_valid": True, } return best # Test with the actual MQTT message mqtt_message = { "time": "2025-12-27T13:26:47", "model": "pool", "count": 1, "num_rows": 1, "rows": [ { "len": 143, "data": "429901013400a801f6002b0294272a000000" } ], "codes": ["{143}429901013400a801f6002b0294272a000000"] } print("Testing pool payload decode with new MQTT format:") print(f"MQTT message: {json.dumps(mqtt_message, indent=2)}") print() hex_data = mqtt_message['rows'][0]['data'] print(f"Hex data from rows[0]['data']: {hex_data}") print(f"Hex data length: {len(hex_data)} chars ({len(hex_data)//2} bytes)") # Strip 'aaaaaa' prefix if present if hex_data.startswith('aaaaaa'): hex_data = hex_data[6:] print(f"Stripped 'aaaaaa' prefix, remaining: {hex_data}") byte_data = bytes.fromhex(hex_data) print(f"Byte data: {byte_data.hex()}") print() # Decode with sliding window decoded = decode_pool_payload(byte_data) if decoded: print("✓ Payload decoded successfully!") print(json.dumps(decoded, indent=2)) print() print("Generated sensor messages:") bme_msg = { 'time': mqtt_message['time'], 'model': 'pool', 'id': decoded['nodeId'] * 10 + 1, 'battery_ok': 1, 'temperature_C': decoded['t_bme_c'], 'humidity': decoded['humidity'], 'pressure_rel': decoded['pressure_hpa'], 'mic': 'CRC' } ds_msg = { 'time': mqtt_message['time'], 'model': 'pool', 'id': decoded['nodeId'] * 10 + 2, 'battery_ok': 1, 'temperature_C': decoded['t_ds_c'], 'mic': 'CRC' } print("BME280 message:") print(json.dumps(bme_msg, indent=2)) print() print("DS18B20 message:") print(json.dumps(ds_msg, indent=2)) else: print("✗ Failed to decode payload!")