- 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: версии
97 lines
4.0 KiB
Markdown
97 lines
4.0 KiB
Markdown
# 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`)
|
|
|
|
```sql
|
|
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).
|
|
|
|
## Ключевое правило
|
|
|
|
**Нет в профиле → не слать. Никаких ретраев на неизвестное.**
|