Files
obdash/profiles/PROFILE_SPEC.md
T
justin d893ff383a Gauge redline zones + C/F units toggle + cleaner dials
Gauges:
- Optional per-metric warning zones (warn_hi/redline_hi/warn_lo/redline_lo) in
  the profile schema; gauges draw colored redline/warn bands and color the
  needle + readout by zone. Default neutral when unset (no false redline).
- Removed the value progress-arc fill (it dominated the dial / looked wrong) ->
  clean tach face: bezel, ticks, numeric scale, needle, redline band, readout.
- Auto-derivation rejected: bad direction/threshold vary per metric, so zones
  are config (with a sensible neutral default).

Units:
- New Units menu: Temperature C / F. Converts gauges, graph, table, and PID
  browser (values, scale, zones, unit labels) at display time; data stays C.

Ford 6.0 profile: zones for ICP (red<500), FICM (red<40/amber40-48/green48+),
ECT/EOT (high redline), RPM (redline 3800), boost, battery; tightened FICM
(38-52) and battery (9-15) ranges so redline bands land sensibly.

Docs: profiles/PROFILE_SPEC.md -- canonical, AI-agent-ready profile spec
(schema, formula language, zones, confidence, rules); README points to it.

Validated headless: zones parse/classify, F conversion (112C->233.6F, zones
converted), gauges render; obdcore + diagnostics tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs
2026-06-30 15:52:49 -04:00

8.3 KiB

OBDash Vehicle Profile Specification (v1)

This is the canonical, self-contained spec for an OBDash vehicle profile. A profile is a single JSON file that teaches OBDash how to read one vehicle: its PIDs (with scaling), trouble-code meanings, dashboards (presets), and gauge warning zones. Profiles are pure data — they cannot run code.

Using an AI agent to build a profile? Paste this whole file into your agent and say: "Research and produce an OBDash vehicle profile JSON that conforms exactly to this spec." Then drop the result in profiles/ and open a PR. See "Rules for authors / agents" below.

Spec version: 1 (matches the top-level "schema": 1). This document is kept in sync with the loader (obdcore/profile.py) and the PID model (obdcore/registry.py) — if they disagree, the loader wins; file an issue.


1. Top-level shape

{
  "schema": 1,                       // required, must be 1
  "meta":    { ... },                // vehicle identity (object)
  "presets": { "name": ["KEY", ...], ... },  // named dashboards (object)
  "pids":    [ { ...pid... }, ... ], // signals (array)
  "dtcs":    [ { ...dtc... }, ... ]  // trouble-code dictionary (array)
}

2. meta

Field Req Meaning
name Display name, shown in the Profile menu (e.g. "Ford 6.0L Power Stroke")
make, model, years, engine Vehicle identity strings
protocol One EXACT value (see below), or "auto"
author Your name / handle
version Profile semver, e.g. "1.0.0"
notes Provenance, caveats, confidence policy

protocol must be one of: "SAE J1850 PWM", "SAE J1850 VPW", "ISO 9141-2", "ISO 14230 KWP2000", "ISO 15765 CAN", or "auto". The ELM327 auto-negotiates regardless, so this is a hint/record — but get it right when you can.

3. pids — the signal definitions

Each PID object:

Field Req Type Meaning
key string Unique id, UPPER_SNAKE (e.g. ICP, STFT1). Used in presets + derived deps.
name string Display name
mode string "01" generic SAE · "22" manufacturer-enhanced · "atrv" adapter pin voltage · "derived" computed from other PIDs
pid mode 01/22 string Request id hex — "0C" (mode 01) or "1446" (mode 22). Omit for atrv/derived.
nbytes mode 01/22 int Number of data bytes in the response the formula uses
formula mode 01/22/derived string Scaling expression (see §4). Omit for atrv.
unit string "rpm", "C", "kPa", "psi", "%", "V", "km/h", …
group string One of: fuel air engine driveline power ficm misc
vmin, vmax number Display range (used by gauges + the Normalize overlay)
confidence string verified · doc · tentative (see §6)
round int Display rounding: omit = raw float, 0 = integer, 2 = 2 dp
deps derived string[] PID keys the derived formula references
notes string Gotchas / provenance; shown as a tooltip
warn_hi redline_hi warn_lo redline_lo number Gauge warning zones (see §5)

Always include this adapter-voltage pseudo-PID:

{"key":"BATT","name":"Battery (OBD port)","mode":"atrv","unit":"V","group":"power","vmin":0,"vmax":16,"confidence":"verified"}

4. Formula language

Arithmetic over data-byte variables A, B, C, … (= response byte 0, 1, 2 …) — the same convention as Torque / FORScan / ScanGauge. For derived PIDs the variables are other PID keys instead.

A safe AST evaluator (obdcore/formula.py) runs formulas. Allowed:

  • Numbers and the declared variables (A/B/… or dep keys)
  • Operators: + - * / // % ** and bitwise & | ^ << >> and unary - ~, parentheses
  • Functions: min, max, abs, round, int, float

Rejected at load (so a hostile profile can't run code): any other name, attribute access (x.y), subscripts (x[0]), or any other function call.

Canonical standard SAE J1979 Mode-01 formulas:

RPM 010C: (A*256+B)/4    Speed 010D: A           ECT 0105: A-40
IAT 010F: A-40           MAP 010B: A (kPa)        MAF 0110: (A*256+B)/100 (g/s)
TPS 0111: A*100/255      Load 0104: A*100/255     Timing 010E: A/2-64
STFT/LTFT 0106-0109: A*100/128-100                Fuel pressure 010A: A*3
O2 voltage 0114-011B: A/200   Runtime 011F: A*256+B   Module V 0142: (A*256+B)/1000
Ambient 0146: A-40       Fuel level 012F: A*100/255   Baro 0133: A

Examples (enhanced): (A*256+B)*0.57 (ICP psi), (A>>1)&1 (a status bit), A//2 (gear), "MAP-BARO" with "deps":["MAP","BARO"] (boost).

5. Gauge warning zones (optional)

Make a gauge color-code like a real tach. All optional; omit for a neutral gauge.

Field Meaning
redline_hi value >= this → RED (high redline)
warn_hi value >= this → AMBER
redline_lo value <= this → RED (low redline)
warn_lo value <= this → AMBER

Use high zones where high is bad (ECT/EOT/RPM/boost) and low zones where low is bad (ICP/FICM/oil pressure; both for battery). The gauge draws a colored band on the dial and turns the needle + readout amber/red in-zone.

Examples (Ford 6.0): "ICP": redline_lo 500, warn_lo 600 (must make ~500 psi to fire); "ECT": warn_hi 105, redline_hi 110; "RPM": warn_hi 3500, redline_hi 3800.

6. confidence tiers

Value Meaning
verified SAE-standard PID, OR multi-source AND confirmed on a real vehicle
doc Documented in sources, not yet read on this vehicle
tentative Single-source, or disputed scaling — sanity-check before trusting

Standard Mode-01 PIDs are verified (they're SAE-mandated). Manufacturer-enhanced PIDs you found in one community list are doc or tentative.

7. presets and dtcs

presets: named dashboards → a list of PID keys, e.g. "basic": ["RPM","SPEED","ECT","MAP","TPS","BATT"], "fuel": ["STFT1","LTFT1","O2B1S1"]. Reference only keys you define. Provide at least basic (and fuel if the vehicle reports trims/O2).

dtcs: array of {"code","desc","system","no_start","causes"}. code like "P0301"; system is freeform (engine/fuel/emissions/…); no_start: true flags drive-disabling faults (shown bold red). Include generic P0xxx plus manufacturer-specific P1xxx you can source.

8. Rules for authors / agents

  • Standard Mode-01 PIDs are the reliable backbone — include the ones this engine actually supports (MAF vs MAP by induction type; the O2/trim banks it really has). Mark them verified.
  • Never invent a PID number or formula. Enhanced PIDs need a documented id AND scaling; mark doc/tentative and cite in notes. If you can't verify, leave it out.
  • Don't fabricate signals the stock stream lacks. Many vehicles have no EGT or engine-oil-pressure PID (e.g. the 6.0 reports ICP + EOT only). Don't add them.
  • Every formula must obey §4 (only A/B/… or dep keys + allowed ops/funcs).
  • Validate before PR: the loader compiles every formula and rejects bad ones. Quick check: python -c "from obdcore import load_profile; load_profile('profiles/<file>.json')" (no exception = it's valid). The app's Profile → Edit JSON dialog also validates on save.

9. Minimal valid example

{
  "schema": 1,
  "meta": {"name":"Example 2.0L","make":"Example","model":"Demo","years":"1999",
           "engine":"2.0L I4","protocol":"auto","author":"you","version":"0.1.0"},
  "presets": {"basic": ["RPM","ECT","BATT"]},
  "pids": [
    {"key":"RPM","name":"Engine RPM","mode":"01","pid":"0C","nbytes":2,
     "formula":"(A*256+B)/4","round":0,"unit":"rpm","group":"engine",
     "vmin":0,"vmax":8000,"confidence":"verified","warn_hi":6000,"redline_hi":6800},
    {"key":"ECT","name":"Engine Coolant Temp","mode":"01","pid":"05","nbytes":1,
     "formula":"A-40","round":0,"unit":"C","group":"engine","vmin":-40,"vmax":215,
     "confidence":"verified","warn_hi":110,"redline_hi":118},
    {"key":"BATT","name":"Battery (OBD port)","mode":"atrv","unit":"V",
     "group":"power","vmin":0,"vmax":16,"confidence":"verified",
     "warn_lo":12.0,"redline_lo":11.0}
  ],
  "dtcs": [
    {"code":"P0301","desc":"Cylinder 1 misfire","system":"engine","no_start":false}
  ]
}