changed: data-logging configuration to rotate more frequently
fixed: database connection retry interval and storing in local SQLite when DB is down
This commit is contained in:
154
test_pool_decode.py
Normal file
154
test_pool_decode.py
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/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(
|
||||
'<BBBBHhhHHB', chunk
|
||||
)
|
||||
except struct.error:
|
||||
continue
|
||||
|
||||
crc_calculated = crc8_xor(chunk[:-1])
|
||||
if crc_calculated != crc_received:
|
||||
continue
|
||||
|
||||
if version != 1 or nodeId != 1:
|
||||
continue
|
||||
|
||||
# Plausibility checks (unit scaled)
|
||||
if not (-300 <= t_ds10 <= 600): # -30.0 to 60.0°C
|
||||
continue
|
||||
if not (-300 <= t_bme10 <= 600):
|
||||
continue
|
||||
if not (0 <= hum10 <= 1000): # 0.0–100.0%
|
||||
continue
|
||||
if not (8000 <= pres1 <= 11000): # 800.0–1100.0 hPa
|
||||
continue
|
||||
|
||||
score = 0
|
||||
if magic1 == MAGIC1 and magic2 == MAGIC2:
|
||||
score += 2
|
||||
if expected_seq is not None and seq == expected_seq:
|
||||
score += 1
|
||||
# CRC already validated; reward shorter offset to prefer first valid
|
||||
score -= offset * 0.001
|
||||
|
||||
if score > 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!")
|
||||
Reference in New Issue
Block a user