Make app vehicle-agnostic: JSON vehicle profiles + menu bar
Vehicle data is now DATA, not code. PIDs/scaling/DTCs/presets live in profiles/*.json; the app loads them at runtime, so it works across vehicles and others can contribute profiles (open source). Core: - obdcore/formula.py: safe AST evaluator for scaling formulas (A/B/... byte vars, Torque/FORScan convention). Only arithmetic/bitwise + min/max/abs/ round/int/float; names/attrs/arbitrary calls rejected at load -> a community profile CANNOT execute code. - obdcore/profile.py: load/save/list profiles; compiles each formula into a decode callable. registry.py now profile-backed (PidRegistry/DtcDatabase take a Profile); hardcoded Ford table removed. - store.py: clear()/snapshot()/export_csv() for capture management. Profiles: - profiles/ford-6.0-powerstroke.json (27 PIDs, verified formulas, DTCs) - profiles/generic-obd2.json (standard SAE Mode-01 base, any vehicle) - profiles/README.md (schema + formula language + contributing) GUI: - Menu bar: File (new/record/export/replay capture, quit), Profile (switch/ load/import/reload/edit-JSON/export, live profile list), View (Graph/Table views, gauges P2, toggle PID dock, normalize, light/dark theme), Help (about/confidence legend/profile info). - PID browser + presets rebuild on profile switch; added Table view; raw-JSON profile editor dialog (validates schema+formulas before saving). Tests: profiles load+compile, formula sandbox rejects hostile input, decoders still match real truck bytes, crank/derived/dead-PID/replay -- all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs
This commit is contained in:
+11
-2
@@ -6,7 +6,8 @@ a timer; the scheduler thread does the serial work.
|
||||
"""
|
||||
import time
|
||||
|
||||
from obdcore import PidRegistry, TimeSeriesStore, PollScheduler, CsvRecorder
|
||||
from obdcore import (PidRegistry, DtcDatabase, TimeSeriesStore, PollScheduler,
|
||||
CsvRecorder, load_default, load_profile)
|
||||
from obdcore.mock import MockLink
|
||||
|
||||
# default poll rates (Hz) -- fast for the no-start metrics, slower for the rest
|
||||
@@ -17,13 +18,21 @@ FAST_HZ = 5
|
||||
|
||||
class Controller:
|
||||
def __init__(self):
|
||||
self.reg = PidRegistry()
|
||||
self.profile = load_default()
|
||||
self.reg = PidRegistry(self.profile)
|
||||
self.dtcdb = DtcDatabase(self.profile)
|
||||
self.store = TimeSeriesStore()
|
||||
self.link = None
|
||||
self.sched = None
|
||||
self.t0 = None
|
||||
self.connected = False
|
||||
|
||||
def load_profile(self, path):
|
||||
"""Switch the active vehicle profile (only allowed while disconnected)."""
|
||||
self.profile = load_profile(path)
|
||||
self.reg = PidRegistry(self.profile)
|
||||
self.dtcdb = DtcDatabase(self.profile)
|
||||
|
||||
def connect(self, port=None, baud=38400, mock=False):
|
||||
if mock:
|
||||
self.link = MockLink(clock=time.time)
|
||||
|
||||
Reference in New Issue
Block a user