fix(envea): add retry logic for sensor read failures

- Retry up to 3 times if no valid frame is received
- Reduced wait time per attempt to 0.8s (total max ~3s with retries)
- Small delay between retries (0.2s)
- Only logs command on first attempt to reduce noise

This should eliminate the occasional 0 values caused by timing issues.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
PaulVua
2026-01-23 17:35:16 +01:00
parent 042b2efa93
commit 80bc16fb26

View File

@@ -106,67 +106,69 @@ try:
try: try:
debug_print(f"Reading from {name}...") debug_print(f"Reading from {name}...")
# Flush input buffer to clear any stale data calculated_value = None
serial_connection.reset_input_buffer() max_retries = 3
# Send command to sensor for attempt in range(max_retries):
command = b"\xFF\x02\x13\x30\x01\x02\x03\x04\x05\x06\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x12\xAF\x88\x03" # Flush input buffer to clear any stale data
serial_connection.write(command) serial_connection.reset_input_buffer()
debug_print(f" → Sent command: {command.hex()}")
# Wait for complete sensor response (sensor needs time to process and reply) # Send command to sensor
time.sleep(1.5) 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)
if attempt == 0:
debug_print(f" → Sent command: {command.hex()}")
# Read all available data from buffer # Wait for sensor response
bytes_available = serial_connection.in_waiting time.sleep(0.8)
debug_print(f" ← Bytes available in buffer: {bytes_available}")
if bytes_available > 0: # Read all available data from buffer
data_envea = serial_connection.read(bytes_available) bytes_available = serial_connection.in_waiting
else: debug_print(f" ← Attempt {attempt + 1}: {bytes_available} bytes available")
# Fallback: try reading with timeout
data_envea = serial_connection.read(32)
debug_print(f" ← Received {len(data_envea)} bytes: {data_envea.hex() if data_envea else 'empty'}") if bytes_available > 0:
data_envea = serial_connection.read(bytes_available)
# Find frame start (0xFF 0x02) in received data - may have echo/garbage before it
frame_start = -1
for i in range(len(data_envea) - 1):
if data_envea[i] == 0xFF and data_envea[i + 1] == 0x02:
frame_start = i
debug_print(f" → Found frame header at position {i}")
break
if frame_start >= 0:
# Extract frame from header position
frame_data = data_envea[frame_start:]
debug_print(f" → Frame data ({len(frame_data)} bytes): {frame_data.hex()}")
if len(frame_data) >= 20:
byte_20 = frame_data[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: else:
debug_print(f" ✗ Frame too short ({len(frame_data)} bytes after header, expected ≥20)") data_envea = serial_connection.read(32)
if len(data_envea) > 0:
debug_print(f" ← Received {len(data_envea)} bytes: {data_envea.hex()}")
# Find frame start (0xFF 0x02) in received data
frame_start = -1
for i in range(len(data_envea) - 1):
if data_envea[i] == 0xFF and data_envea[i + 1] == 0x02:
frame_start = i
break
if frame_start >= 0:
frame_data = data_envea[frame_start:]
if len(frame_data) >= 20:
byte_20 = frame_data[19]
calculated_value = byte_20 * coefficient
debug_print(f" → Found valid frame at position {frame_start}")
debug_print(f" → Byte 20 = {byte_20} × {coefficient} = {calculated_value}")
break # Success, exit retry loop
debug_print(f" ✗ Attempt {attempt + 1} failed, {'retrying...' if attempt < max_retries - 1 else 'giving up'}")
time.sleep(0.2)
if calculated_value is not None:
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: else:
debug_print(f"No valid frame header (FF 02) found in response") debug_print(f"Failed to read {name} after {max_retries} attempts")
except serial.SerialException as e: except serial.SerialException as e:
debug_print(f"✗ Error communicating with {name}: {e}") debug_print(f"✗ Error communicating with {name}: {e}")