From d64a0f64207a633bc5d6ad161c48a31580c5499b Mon Sep 17 00:00:00 2001 From: Brian Hanson Date: Fri, 17 Apr 2026 16:12:35 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20thermald=20crash=20on=20startup=20?= =?UTF-8?q?=E2=80=94=20CarState=20is=20in=20cereal.car,=20not=20cereal.log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new fan control plumbing referenced log.CarState.GearShifter.park, but CarState is defined in car.capnp and only DeviceState/PandaState live in log.capnp. Thermald crashed immediately on first carState tick, which meant deviceState stopped publishing entirely. The UI then read stale/default values — freeSpacePercent=0 → "100% full" → "Out of Storage" alert despite 65 GB actually free. The fan also stopped updating. from cereal import car, log (was just log) car.CarState.GearShifter.park (was log.CarState...) Co-Authored-By: Claude Opus 4.6 (1M context) --- selfdrive/thermald/thermald.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index d235054..ac2f845 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -10,7 +10,7 @@ from pathlib import Path import psutil import cereal.messaging as messaging -from cereal import log +from cereal import car, log from cereal.services import SERVICE_LIST from openpilot.common.dict_helpers import strip_deprecated_keys from openpilot.common.filter_simple import FirstOrderFilter @@ -296,7 +296,7 @@ def thermald_thread(end_event, hw_queue) -> None: if sm.seen['carState']: cs = sm['carState'] standstill = cs.standstill - is_parked = cs.gearShifter == log.CarState.GearShifter.park + is_parked = cs.gearShifter == car.CarState.GearShifter.park else: standstill = False is_parked = True # default safe: assume parked, no fan floor