Files
elmer/doc/history/2026-06-07.md
T
“Naeel” aa37a1a70c v0.48.0 — пробинг ELM327, трехуровневый профиль, рефакторинг obd/
- obd/probe.py: трехуровневый каскад (L0/L1/L2)
- obd/commands.py: каталог всех AT-команд с метаданными
- obd/classifier.py: классификация ответов + определение уровня
- obd/connection.py: транспортный слой (SerialTransport)
- obd/protocol.py: init() только база, без ATAT1/ATST
- api/db.py: таблица device_profiles по BT MAC
- api/scripts.py: три уровня скриптов (l0/l1/l2)
- api/routes.py: /elm/probe, /elm/profile/<mac>, /script?level=
- web/templates/index.html: v0.48.0
- CHANGELOG.md, doc/architecture.md, resume.txt: версии
2026-06-07 05:55:02 +04:00

4.0 KiB

2026-06-07 — Пробинг ELM327, трехуровневый профиль

Проблема

obd/protocol.py — init() посылал ATAT1 и ATSTxx всем устройствам. Большинство клонов v1.5 не знают этих команд → тишина → _exec() делает до 10 ретраев → всё висит на десятки секунд.

Решение

1. Трехуровневый пробинг (obd/probe.py)

Каскадный тест: сначала база, потом улучшения.

Уровень 0 (база, все клоны):
  ATE0 ATL0 ATS0 ATH1 ATSP0 ATDPN ATRV ATI
  → хоть одна не ответила OK → НЕИСПРАВЕН

Уровень 1 (хорошие клоны):
  ATAT1
  → OK → уровень 1

Уровень 2 (настоящие ELM):
  ATCAF1 ATCFC1
  → OK → уровень 2

Результат сохраняется в device_profiles по ключу BT MAC.

2. Fix obd/protocol.py init()

init() теперь шлёт ТОЛЬКО базу (уровень 0): ATE0 ATL0 ATS0 ATH1 ATSP0.

Методы под уровень:

  • init_base() — то же что init()
  • init_l1() — + ATAT1
  • init_l2() — + ATAT1 + ATCAF1 + ATCFC1

3. Таблица device_profiles (api/db.py)

CREATE TABLE device_profiles (
    mac             TEXT PRIMARY KEY,   -- BT MAC
    level           INTEGER NOT NULL,   -- 0/1/2
    elm_version     TEXT,               -- ATI ответ
    elm_desc        TEXT,               -- AT@1 (если есть)
    protocol        TEXT,               -- ATDPN
    voltage         TEXT,               -- ATRV
    supported       TEXT,               -- JSON: ["ATE0","ATL0",...]
    unsupported     TEXT,               -- JSON: ["ATAT1","ATCAF1",...]
    first_seen      TEXT NOT NULL,
    last_seen       TEXT NOT NULL
);

4. Скрипты под уровень (api/scripts.py)

  • build_script_l0() — 5 PIDs + ошибки (однокадровые)
  • build_script_l1() — 8 PIDs + VIN + ошибки
  • build_script_l2() — 14 PIDs + VIN + калибровки + все ошибки

5. Эндпоинты (api/routes.py)

  • POST /api/v1/elm/probe — принимает MAC + ответы, возвращает профиль
  • GET /api/v1/elm/profile/<mac> — достаёт из кэша
  • GET /api/v1/script?level=0|1|2 — скрипт под уровень

6. Рефакторинг: разделение на независимые сервисы

Файлы разбиты по тематике, каждый — отдельный сервис:

obd/
  commands.py   — Каталог ВСЕХ AT-команд ELM327 (с метаданными)
  classifier.py — Классификация ответов + определение уровня
  connection.py — Транспортный слой (SerialTransport)
  probe.py      — Пробинг (использует commands + classifier)
  protocol.py   — Стейт-машина AndrOBD (использует connection)
  state.py      — Состояния/типы ответов
  timing.py     — Адаптивный таймаут

Принцип: каждый модуль делает одно дело, не дублирует логику.

  • commands.py — единственный источник правды о командах
  • classifier.py — единственное место классификации ответов
  • connection.py — единственное место I/O
  • routes.py — тонкая прослойка, без бизнес-логики

5. Эндпоинт (api/routes.py)

POST /api/v1/elm/probe — принимает MAC, возвращает профиль. Сервер сам шлёт команды через реле (Android ElmForwardService).

Ключевое правило

Нет в профиле → не слать. Никаких ретраев на неизвестное.