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: версии
This commit is contained in:
“Naeel”
2026-06-07 05:55:02 +04:00
parent 7ae0fc5702
commit aa37a1a70c
13 changed files with 918 additions and 158 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# Архитектура elmAI
> v0.36.0-dev, 31 мая 2026
> v0.48.0, 7 июня 2026
## Общая схема
+96
View File
@@ -0,0 +1,96 @@
# 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).
## Ключевое правило
**Нет в профиле → не слать. Никаких ретраев на неизвестное.**