fix(envea): correct serial read to prevent spurious spikes
- Replace readline() with read(32) to avoid truncation at 0x0A bytes - Add reset_input_buffer() to clear stale data before each read - Add initial read to consume echo/acknowledgment from sensor - Add frame header validation (0xFF 0x02) to reject invalid data - Add delays to allow sensor response time Fixes issue where NO2/H2S sensors showed random spikes due to binary data containing newline characters being misinterpreted. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,39 +105,56 @@ try:
|
||||
serial_connection = serial_connections[name]
|
||||
try:
|
||||
debug_print(f"Reading from {name}...")
|
||||
|
||||
|
||||
# Flush input buffer to clear any stale data
|
||||
serial_connection.reset_input_buffer()
|
||||
|
||||
# Send command to sensor
|
||||
command = b"\xFF\x02\x13\x30\x01\x02\x03\x04\x05\x06\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x12\xAF\x88\x03"
|
||||
serial_connection.write(command)
|
||||
debug_print(f" → Sent command: {command.hex()}")
|
||||
|
||||
# Wait for sensor response
|
||||
time.sleep(0.5)
|
||||
|
||||
# Read fixed number of bytes (not readline which stops at 0x0A)
|
||||
# First read to consume any echo/acknowledgment
|
||||
initial_data = serial_connection.read(serial_connection.in_waiting or 1)
|
||||
debug_print(f" ← Initial read: {len(initial_data)} bytes")
|
||||
|
||||
# Small delay then read the actual response
|
||||
time.sleep(0.1)
|
||||
data_envea = serial_connection.read(32) # Read fixed 32 bytes
|
||||
debug_print(f" ← Received {len(data_envea)} bytes: {data_envea.hex() if data_envea else 'empty'}")
|
||||
|
||||
# Read response
|
||||
data_envea = serial_connection.readline()
|
||||
debug_print(f" ← Received {len(data_envea)} bytes: {data_envea.hex()}")
|
||||
|
||||
# Validate frame: should start with 0xFF 0x02 and have at least 20 bytes
|
||||
if len(data_envea) >= 20:
|
||||
byte_20 = data_envea[19]
|
||||
raw_value = byte_20
|
||||
calculated_value = byte_20 * coefficient
|
||||
debug_print(f" → Byte 20 value: {raw_value} (0x{raw_value:02X})")
|
||||
debug_print(f" → Calculated value: {raw_value} × {coefficient} = {calculated_value}")
|
||||
|
||||
if name == "h2s":
|
||||
data_h2s = calculated_value
|
||||
elif name == "no2":
|
||||
data_no2 = calculated_value
|
||||
elif name == "o3":
|
||||
data_o3 = calculated_value
|
||||
elif name == "co":
|
||||
data_co = calculated_value
|
||||
elif name == "nh3":
|
||||
data_nh3 = calculated_value
|
||||
elif name == "so2":
|
||||
data_so2 = calculated_value
|
||||
|
||||
debug_print(f" ✓ {name.upper()} = {calculated_value}")
|
||||
# Check frame header (0xFF 0x02 expected for valid CAIRSENS response)
|
||||
if data_envea[0] == 0xFF and data_envea[1] == 0x02:
|
||||
byte_20 = data_envea[19]
|
||||
raw_value = byte_20
|
||||
calculated_value = byte_20 * coefficient
|
||||
debug_print(f" → Byte 20 value: {raw_value} (0x{raw_value:02X})")
|
||||
debug_print(f" → Calculated value: {raw_value} × {coefficient} = {calculated_value}")
|
||||
|
||||
if name == "h2s":
|
||||
data_h2s = calculated_value
|
||||
elif name == "no2":
|
||||
data_no2 = calculated_value
|
||||
elif name == "o3":
|
||||
data_o3 = calculated_value
|
||||
elif name == "co":
|
||||
data_co = calculated_value
|
||||
elif name == "nh3":
|
||||
data_nh3 = calculated_value
|
||||
elif name == "so2":
|
||||
data_so2 = calculated_value
|
||||
|
||||
debug_print(f" ✓ {name.upper()} = {calculated_value}")
|
||||
else:
|
||||
debug_print(f" ✗ Invalid frame header: expected FF 02, got {data_envea[0]:02X} {data_envea[1]:02X}")
|
||||
else:
|
||||
debug_print(f" ✗ Response too short (expected ≥20 bytes)")
|
||||
debug_print(f" ✗ Response too short ({len(data_envea)} bytes, expected ≥20)")
|
||||
|
||||
except serial.SerialException as e:
|
||||
debug_print(f"✗ Error communicating with {name}: {e}")
|
||||
|
||||
Reference in New Issue
Block a user