fix: Yaris 2013 OBD compatibility hardening

- _decode_odometer: catch all exceptions and return None instead of raising.
  PID 0xA6 (odometer) is not guaranteed on 2013 Toyota Yaris — a garbage
  response or unsupported PID previously raised ValueError through python-obd's
  decoder, which app_obd._query() caught and treated as a lost connection,
  killing the entire OBD session. Now it gracefully returns None.

- connect_obd: reset all sensor globals (rpm, coolant_temp, fuel_level,
  throttle_position, mil_on, dtc_codes, odometer, timestamps) on each new
  connection so the UI doesn't display stale readings from the previous
  ignition cycle while fresh polls are completing.

- yaris-obd.service: add commented OBD_PROTOCOL=6 hint for post-confirmation
  pinning (eliminates 3-5s auto-probe delay after first confirmed connection).

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-10 05:22:36 -04:00
co-authored by Copilot
parent a56e4252d3
commit 10dea22f9a
2 changed files with 27 additions and 4 deletions
+5
View File
@@ -12,6 +12,11 @@ WorkingDirectory=/home/yaris/app/yaris-obd
# the log file promptly instead of sitting in Python's stdout buffer indefinitely # the log file promptly instead of sitting in Python's stdout buffer indefinitely
# when it's redirected to a file instead of a TTY. # when it's redirected to a file instead of a TTY.
Environment=PYTHONUNBUFFERED=1 Environment=PYTHONUNBUFFERED=1
# Once OBD is confirmed working on this car, pin the protocol to skip the
# 3-5s auto-detect probe on every ignition-on: e.g. OBD_PROTOCOL=6 for
# ISO 15765-4 CAN 11-bit 500kbps (correct for 2013 Toyota Yaris).
# Leave unset during initial setup so auto-detect can find the right value.
#Environment=OBD_PROTOCOL=6
ExecStart=/home/yaris/app/yaris-obd/venv/bin/python app.py ExecStart=/home/yaris/app/yaris-obd/venv/bin/python app.py
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5
+19 -1
View File
@@ -52,10 +52,13 @@ connection = None
def _decode_odometer(messages): def _decode_odometer(messages):
try:
data = messages[0].data[2:] data = messages[0].data[2:]
if len(data) != 4: if len(data) != 4:
raise ValueError(f"expected 4 odometer bytes, received {len(data)}") return None
return int.from_bytes(bytes(data), byteorder="big") / 10 return int.from_bytes(bytes(data), byteorder="big") / 10
except Exception:
return None
ODOMETER_COMMAND = obd.OBDCommand( ODOMETER_COMMAND = obd.OBDCommand(
@@ -225,6 +228,21 @@ def connect_obd():
_emit_disconnected() _emit_disconnected()
return None return None
# Reset stale sensor values from the previous ignition cycle so the
# UI doesn't briefly display outdated readings before the first polls.
global rpm, coolant_temp, fuel_level, throttle_position, mil_on, dtc_codes, odometer
global mil_updated_at, dtc_updated_at, speed_updated_at
rpm = None
coolant_temp = None
fuel_level = None
throttle_position = None
mil_on = None
dtc_codes = []
odometer = None
mil_updated_at = None
dtc_updated_at = None
speed_updated_at = None
_log_connection_diagnostics(candidate) _log_connection_diagnostics(candidate)
app_events.socketio.emit("obd_status", obd_status[1]) app_events.socketio.emit("obd_status", obd_status[1])
_start_polling_threads() _start_polling_threads()