Files
shturman/docs/contracts/data-model.md
T
kk0t9 76596408e1 docs(data-model): ретро-ревью (5 находок)
- dtc_count диапазон 0..255 → 0..127 (поле 7-битное)
- добавлено runtime-поле quality (valid/stale/unavailable) + max_age, ортогонально
  статической availability (синхрон с ipc GetSignal/SignalChanged)
- §3: детект Mode 03/07/0A через trial-read (нет support-bitmask); пустой PID 0x00
  не каскадит «всё Unavailable»; MVP (mil_on + Mode 03) не зависит от пробинга
- убран ложный ярлык «SI» (km/h, rpm, °C — не СИ) → «канонический набор единиц»
- module_voltage: отметка, что property в ipc = ModuleVoltage

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 00:51:10 +03:00

149 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Контракт: модель данных машины (VSS-подобная)
> Канонический каталог сигналов, которые публикует `VehicleData`. Наполняет
> конкретикой ipc-контракт, кормит контекст ассистента, домен E и killer-фичу.
Статус: **v1 (на ревью).**
Связано с: [ipc.md](ipc.md) (`VehicleData`) · [domains/](../domains/README.md) (E: Vehicle-Data) · [hardware.md](hardware.md) · [principles.md](../principles.md) (#4)
---
## 1. Подход: VSS-aligned, но лёгкий
- Имена сигналов — в стиле **COVESA VSS** (иерархические пути), типы и единицы — по
VSS. Но держим **свой лёгкий каталог**, а не тащим полный VSS-тулинг (Franca/
генераторы). Достаточно совместимости «по духу», чтобы говорить на общем языке и
легко расширяться.
- 🟡 *Выбор на подтверждение:* лёгкий VSS-aligned каталог (рекомендую) vs полное
принятие VSS-спеки с тулингом (тяжелее, избыточно на старте).
## 2. Модель сигнала
Каждый сигнал описывается:
| Поле | Смысл |
|------|-------|
| `id` | канонический VSS-стиль путь (напр. `Vehicle.Speed`) |
| `alias` | короткое имя для эргономики (`speed`) |
| `type` | `float` / `int` / `bool` / `enum` |
| `unit` | каноническая единица (**фиксированный набор**, метрические/авто-конвенциональные — часть не-СИ: km/h, rpm, °C, V, %, g/s, kPa) |
| `range` | допустимый диапазон |
| `source` | откуда читается: OBD-PID / native-CAN(DBC) / **computed** |
| `availability` | **статически**: поддерживается ли PID данной машиной (пробинг на старте) |
| `quality` | **рантайм-валидность значения**: `valid` / `stale` / `unavailable` (таймаут, двигатель заглушен) — ортогонально `availability` |
| `max_age` | порог свежести (per-signal): старше → `quality=stale` |
| `ts` | метка времени значения |
**Транспорт-агностичность (важно):** сигнал каноничен, а **источник — это
per-vehicle маппинг.** Один и тот же `Vehicle.Speed` может читаться через ELM327
(OBD-PID `0x0D`) или нативный SocketCAN (сигнал из DBC). Это и есть мост «ELM327 на
старте → SocketCAN в проде» и основа портирования под разные авто (см. [hardware.md](hardware.md)).
**Единицы и локаль:** в модели — канонический набор единиц; отображение (km vs miles) —
дело shell/настроек, конвертация на презентации, не в модели.
## 3. Доступность сигналов (per-vehicle)
Не все машины отдают все PID. `VehicleData` при старте **пробит поддерживаемые
PID** (Mode 01, PID `0x00/0x20/0x40/…` — битовые маски поддержки) и помечает
сигнал `Unavailable`, если его нет. Консьюмеры (ассистент, UI) обязаны это
учитывать — «нет данных», а не падение (принцип #4).
**Сервисные функции (Mode 03/07/0A DTC) — детектятся отдельно:** support-bitmask у
них нет, feature-detection = trial-read (валидный ответ → есть; NACK/timeout → нет).
**Если пробинг (PID 0x00) пуст/недоступен — НЕ каскадим «всё Unavailable»:** fallback
на best-effort прямой опрос приоритетного набора PID + trial Mode 03. **MVP killer-фичи**
(`mil_on` PID 01 + DTC Mode 03) **не зависит от bitmask-пробинга** — доступность
определяется прямым чтением этих PID/сервисов.
> Рантайм-устаревание (≠ статической доступности) несёт поле `quality` (§2), синхрон с ipc.
## 4. Каталог стартовых сигналов (OBD-II Mode 01)
> `id` — наш канонический путь (≈ VSS, **точные VSS-листы сверяем со спецификацией
> при реализации**). Базовый набор; расширяем по ходу домена E.
>
> **`mil_on` (PID 0x01) — ключевой для killer-фичи** «почему горит чек»: это сам
> факт горящей лампы + число ошибок, отдельно от их чтения (Mode 03).
> `module_voltage` (0x42) — напряжение питания ЭБУ ≈ бортсеть (близко, но не ровно клеммы АКБ); property в ipc — `ModuleVoltage`.
| alias | id (≈ VSS) | PID | type | unit | range |
|-------|-----------|-----|------|------|-------|
| `speed` | `Vehicle.Speed` | 0x0D | int | km/h | 0..255 |
| `rpm` | `Vehicle.Powertrain.CombustionEngine.Speed` | 0x0C | float | rpm | 0..16383 |
| `engine_load` | `…CombustionEngine.Load` | 0x04 | float | % | 0..100 |
| `coolant_temp` | `…CombustionEngine.ECT` | 0x05 | int | °C | -40..215 |
| `intake_temp` | `…CombustionEngine.IAT` | 0x0F | int | °C | -40..215 |
| `maf` | `…CombustionEngine.MAF` | 0x10 | float | g/s | 0..655 |
| `throttle` | `…CombustionEngine.TPS` | 0x11 | float | % | 0..100 |
| `intake_pressure` | `…CombustionEngine.MAP` | 0x0B | int | kPa | 0..255 |
| `fuel_level` | `Vehicle.Powertrain.FuelSystem.Level` | 0x2F | float | % | 0..100 |
| `module_voltage` | `Vehicle.LowVoltageBattery.Voltage` | 0x42 | float | V | 0..65.5 |
| `ambient_temp` | `Vehicle.Exterior.AirTemperature` | 0x46 | int | °C | -40..215 |
| `oil_temp` | `…CombustionEngine.EOT` | 0x5C | int | °C | -40..215 |
| `fuel_rate` | `…CombustionEngine.FuelRate` | 0x5E | float | L/h | 0..3212 |
| `run_time` | `…CombustionEngine.RunTime` | 0x1F | int | s | 0..65535 |
| `mil_on` | `Vehicle.OBD.IsMILOn` | 0x01 | bool | — | вкл/выкл |
| `dtc_count` | `Vehicle.OBD.DTCCount` | 0x01 | int | шт | 0..127 (7-бит) |
| `distance_mil` | `Vehicle.OBD.DistanceWithMIL` | 0x21 | int | km | 0..65535 |
## 5. Производные (computed) сигналы
Слой поверх сырых — считаются внутри VehicleData (или отдельного компонента):
- **Мгновенный расход** — если есть прямой `fuel_rate` (0x5E), берём его; иначе
**оценка** из MAF (предполагает бензин/стехиометрию — помечаем как `estimate`,
зависит от типа топлива).
- **Пробег поездки / средний расход** (интеграл по времени; нужен trip-стейт).
- **Состояние машины** (`off` / `accessory` / `running`) — грубо из RPM/зажигания;
нужно ассистенту, чтобы отличать «двигатель заглушен» от «сигнал недоступен» от «ноль».
- Помечаются `source = computed`; зависят от наличия исходных сигналов.
## 6. Модель DTC (диагностические коды)
- **Формат кода:** буква (`P` powertrain / `C` chassis / `B` body / `U` network) +
4 hex-цифры. Грубо: `0` — стандарт SAE/ISO, `1` — производитель (полная карта
сложнее: `P2xxx` тоже стандарт, `P3xxx` смешанные).
- **Статусы:** `confirmed` (Mode 03), `pending` (Mode 07), `permanent` (Mode 0A).
- **Чтение:** Modes 03/07/0A — это **чтение**, разрешено.
**Сброс (Mode 04) — НЕТ.** Read-only (принцип #2).
- **Расшифровка двухслойная:** статическая база `код → стандартное описание`
(живёт в домене E, `vehicle/dtc/`) + **LLM** даёт человеческое объяснение
по-русски в контексте машины. Manufacturer-specific (`P1xxx`) требуют вендорской
базы (задел, §7).
## 7. Расширение: вендорские сигналы и коды (задел)
- Нативный CAN конкретного авто описывается **DBC-файлом** → даёт сигналы сверх
стандартного OBD и вендорские DTC.
- Это per-vehicle/per-OEM маппинг, ложится на **HAL/board-support** ([hardware.md](hardware.md))
и на портирование силами автопроизводителей/энтузиастов (vision: «API под
конкретное железо/авто»). Плагин/порт может поставлять свой DBC + базу кодов.
---
## Открытые вопросы (найдено на self-review → роутинг)
- **Минимальный набор PID на простых авто.** Старые/простые машины (наша целевая
аудитория — Lada и т.п.) отдают мало Mode-01 PID. **MVP killer-фичи опирается на
универсальное:** `mil_on` + чтение DTC (Mode 03); богатые PID — best-effort. → домен E.
- **«Почему вырос расход».** Для этого кейса из vision полезны топливные коррекции
(Short/Long Term Fuel Trim, PID 0x060x09) и данные O2 — диагностическое расширение. → домен E.
- **Идентификация авто (VIN).** Mode 09 PID 0x02 — даёт привязку к конкретной машине
(память о водителе, вендорские базы кодов). Задел. → домен E + домен D.
- **DBC для нативного CAN часто проприетарны** или добываются реверсом
(community-DBC, opendbc). Учесть в портировании. → [hardware.md](hardware.md) + домен E.
---
## Журнал решений (data-model)
| Решение | Выбор | Дата |
|---------|-------|------|
| Глубина VSS | лёгкий VSS-aligned каталог (🟡 на подтверждение) | 2026-06-16 |
| Источник сигнала | транспорт-агностичен: канон + per-vehicle маппинг (PID / DBC / computed) | 2026-06-16 |
| Единицы | канонический набор единиц (метрич./авто-конвенц., часть не-СИ); конвертация на презентации | 2026-06-16 |
| Валидность значения | runtime-поле `quality` (valid/stale/unavailable) + `max_age`, ортогонально `availability` | 2026-06-16 |
| DTC | чтение Modes 03/07/0A; сброс (04) запрещён; расшифровка база + LLM | 2026-06-16 |