from typing import Any, Callable from pydantic import BaseModel, ConfigDict class Report(BaseModel): model_config = ConfigDict(validate_assignment=True) speed_mph: float = 0.0 rpm: float = 0.0 fuel_level_pct: float = 0.0 oil_temp_f: float = 0.0 coolant_temp_f: float = 0.0 @staticmethod def _coerce_numeric(value: Any) -> float: if value is None: return 0.0 if hasattr(value, "magnitude"): value = value.magnitude return float(value) def set_speed(self, value: Any) -> None: self.speed_mph = self._coerce_numeric(value) def set_rpm(self, value: Any) -> None: self.rpm = self._coerce_numeric(value) def set_fuel(self, value: Any) -> None: self.fuel_level_pct = self._coerce_numeric(value) def set_oil_temp(self, value: Any) -> None: self.oil_temp_f = self._coerce_numeric(value) def set_coolant_temp(self, value: Any) -> None: self.coolant_temp_f = self._coerce_numeric(value) class Scan(BaseModel): cmd: Any = None interval: float = 10.0 callback: Callable[[float], None] | None = None transform: Callable[[Any], float] | None = None