chore: move docs (CHANGELOG, STRUCTURE, QUICKSTART, resume, logo) to doc/, update AGENTS.md and PLANS.md paths
This commit is contained in:
@@ -0,0 +1,338 @@
|
||||
# elmAI — Changelog / Полное описание проекта
|
||||
|
||||
> Файл для нового агента: прочитай — и ты в курсе всего.
|
||||
> Актуально: v0.95.0-dev, 10 июня 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. Идентификация
|
||||
|
||||
| Поле | Значение |
|
||||
|------|----------|
|
||||
| Название | **elmAI** (ранее Elmer, elmAI rebrand в конце мая) |
|
||||
| Суть | OBD2-диагностика: Android → ELM327 → LLM (анализ ошибок) |
|
||||
| Репозиторий сервера | `gitea.services.ngcloud.ru/Nail/elmer` |
|
||||
| Репозиторий Android | `github.com/Repinoid/elmer-android` (отдельный!) |
|
||||
| Сервер (prod) | `obdai.ru` (5.172.178.213) |
|
||||
| Язык сервера | Python 3 + Flask + gunicorn |
|
||||
| Язык клиента | Kotlin, minSdk 24 |
|
||||
| LLM-провайдер | `api.aillm.ru` (OpenAI-совместимый) |
|
||||
| База данных | SQLite (WAL mode) |
|
||||
|
||||
---
|
||||
|
||||
## 2. Архитектура (master — продакшен, актуально)
|
||||
|
||||
```
|
||||
📱 Android → ELM327 (Bluetooth SPP)
|
||||
│
|
||||
▼ ScriptRunnerService (фоновая служба)
|
||||
│ выполняет скрипт: OBD-команды → ждёт ответы → пишет лог
|
||||
│ HTTPS POST /api/v1/session/upload
|
||||
▼
|
||||
🌐 obdai.ru (nginx :443 → gunicorn :8000)
|
||||
│
|
||||
├── web/app.py — точка входа Flask
|
||||
├── api/routes.py — 5 эндпоинтов
|
||||
├── api/db.py — SQLite (sessions, cars, dtc, params)
|
||||
├── api/parser.py — парсинг батча ELM-ответов (VIN, DTC, PID)
|
||||
├── api/scripts.py — сборка диагностических скриптов
|
||||
├── api/config.py — загрузка config.yaml (c lru_cache)
|
||||
├── brain/client.py — Diagnoser: HTTP к api.aillm.ru
|
||||
├── brain/prompts.py — SYSTEM_PROMPT (10 правил, табличный формат)
|
||||
└── obd/protocol.py — AndrOBD-стейт-машина (1:1 копия ElmProt.java)
|
||||
```
|
||||
|
||||
### Модули подробно
|
||||
|
||||
#### `api/` — REST + БД + парсинг
|
||||
|
||||
**5 эндпоинтов:**
|
||||
|
||||
| Эндпоинт | Метод | Что делает | Время |
|
||||
|----------|-------|-----------|-------|
|
||||
| `/api/v1/ping` | GET | `{"ok": true}` — проверка сервера | ~5ms |
|
||||
| `/api/v1/ping-llm` | GET | Проверка LLM (кэш 60с, глобальная переменная) | ~2s |
|
||||
| `/api/v1/script?mode=full` | GET | Выдача скрипта диагностики (JSON со steps) | ~50ms |
|
||||
| `/api/v1/session/upload` | POST | Приём батча + LLM-анализ, идемпотентность | ~30-120s |
|
||||
| `/api/v1/chat` | POST | Свободный вопрос к LLM (с историей) | ~5-15s |
|
||||
|
||||
**Ключевые особенности:**
|
||||
- `upload_session()`: принимает `responses` (массив `{cmd, raw, decoded}`) + `request_id` (UUID для идемпотентности). Если `request_id` уже есть в БД — возвращает кэшированный ответ (200).
|
||||
- LLM fallback: если нет API key или LLM ошибка — возвращает `format_no_llm()` (сырые данные без анализа).
|
||||
- `_build_diagnosis_prompt()`: собирает промпт из VIN, DTC stored/pending, параметров, raw_log. Требует глубокого разбора.
|
||||
- `/chat`: передаёт историю как массив `messages[{role, content}]`, срез последних 10.
|
||||
- `config.load()` — `@lru_cache(maxsize=1)`, сбрасывать рестартом процесса.
|
||||
|
||||
**База данных (SQLite, WAL):**
|
||||
- `sessions` — сводная таблица (клиент, ELM, авто, LLM, request_id, response_json для кэша)
|
||||
- `cars` — VIN → id (уникальные)
|
||||
- `diagnostic_tokens`, `llm_messages`, `ecu_parameters`, `dtc_codes` — детальные таблицы (не используются в upload, только legacy)
|
||||
- `PRAGMA journal_mode=WAL`, `busy_timeout=30000`, `check_same_thread=False`
|
||||
|
||||
**Парсер (`parser.py`):**
|
||||
- `parse_batch(responses)` → `{vin, dtc_stored[], dtc_pending[], parameters[{name,value}], raw_log[]}`
|
||||
- Парсит из `decoded` поля, fallback из сырого HEX (490201..., 43..., 47...)
|
||||
- DTC из HEX: декодирует P/B/C/U коды из байтов после 43/47
|
||||
- PID: всё что с `:` в decoded, кроме VIN/DTC/ELM/Protocol
|
||||
|
||||
**Скрипты (`scripts.py`):**
|
||||
- `build_full_script()`: 7 PID (ОЖ, RPM, скорость, дроссель, нагрузка, STFT, LTFT)
|
||||
- `build_default_script()`: 1 PID (0105 — температура ОЖ) для отладки
|
||||
|
||||
#### `brain/` — LLM
|
||||
|
||||
- `Diagnoser(api_key, model="gpt-oss-120b", base_url, timeout=180)`
|
||||
- `diagnose(system, user_prompt, history=None)` → str
|
||||
- Ошибки: `LLMError` с безопасным для клиента сообщением (без деталей)
|
||||
- Различает: Timeout, HTTP 429 («слишком много запросов»), HTTP 5xx, HTTP 4xx
|
||||
- `SYSTEM_PROMPT`: 10 правил, формат ответа — таблицы, степени уверенности в %, план действий по приоритету
|
||||
- Модели: `gpt-oss-120b` (основная), `qwen3-6-27b-fp8` (быстрая, но с CoT leak bug)
|
||||
|
||||
#### `obd/protocol.py` — ELM327 стейт-машина (AndrOBD)
|
||||
|
||||
**Состояния:** `UNDEFINED → INITIALIZING → READY → BUSY → READY`, ошибка → `ERROR`/`DISCONNECTED`
|
||||
|
||||
**Классификация ответов (Rsp.identify):**
|
||||
| Ответ | Тип | Реакция |
|
||||
|-------|-----|---------|
|
||||
| `>` | PROMPT | Конец ответа |
|
||||
| `OK` | OK | Уменьшить таймаут |
|
||||
| `SEARCHING...` | SEARCHING | Нормально при ините |
|
||||
| `NODATA` | NODATA | Увеличить таймаут, ATST |
|
||||
| `UNABLE/BUS BUSY/CAN ERROR` | BUS ERROR | DISCONNECTED → ATPC → ATSP0 |
|
||||
| `ERROR/DATA ERROR/BUFFER FULL` | ERROR | ATWS (warm start) |
|
||||
| Всё остальное | DATA | Успех, уменьшить таймаут |
|
||||
|
||||
**Ключевые особенности (1:1 с AndrOBD):**
|
||||
- Побайтовое чтение с поллингом 1ms (НЕ readLine!)
|
||||
- `>` (0x3E) — не спецсигнал, а разделитель строк как CR/LF
|
||||
- Адаптивный таймаут: 50-2000ms, шаг 20ms, ATST = timeout/4
|
||||
- `_write()`: `reset_input_buffer()` перед записью — чистит хвосты
|
||||
- Инициализация: ATSP0 → ATAT1 → ATST → ATS0 → ATL0 → ATE0 (без ATZ)
|
||||
- BUS ERROR recovery: ATPC → ATSP0
|
||||
- `_read()`: требует `>` перед возвратом, иначе TimeoutError
|
||||
|
||||
#### `web/app.py` — точка входа
|
||||
|
||||
- `sys.path.insert(0, корень_проекта)` — чтобы импортировать `api/`, `brain/`, `obd/`
|
||||
- `config = load()` — глобально
|
||||
- `register_api(app)` — подключает эндпоинты
|
||||
- `/elmer.apk` → `send_from_directory("static", "app-debug.apk")`
|
||||
|
||||
---
|
||||
|
||||
## 3. Версии и история
|
||||
|
||||
### Система версионирования
|
||||
- **Сервер:** `web/templates/index.html` (два места: подзаголовок и подпись APK)
|
||||
- **Android:** `android/app/build.gradle.kts` → `versionName`
|
||||
- **Документация:** заголовки `.md` файлов
|
||||
- **Менять одновременно во всех местах**
|
||||
|
||||
### История версий (сервер)
|
||||
|
||||
#### v0.93.0-dev (10 июня 2026)
|
||||
- **Speed-test ELM327:** при первом подключении нового ELM — замер скорости ответа на 3 PID (RPM, MAF, STFT) × 3 раза каждый
|
||||
- **Адаптивный интервал:** динамический тест использует `max(250, avg_response × 3 × 1.5)` вместо жёстких 250ms
|
||||
- **Профиль устройства:** колонка `response_time_ms` в `device_profiles`, API `PUT /api/v1/elm/profile/<mac>`
|
||||
- **Fix:** `threading.Lock()` в `Database` — 0 ошибок при 20 конкурентных записях (было 8/20)
|
||||
- **UI:** прогресс speed-теста показывается пользователю
|
||||
- Деплой v0.93.0-dev на obdai.ru
|
||||
|
||||
#### v0.48.0 (7 июня 2026)
|
||||
- **Пробинг ELM327:** трехуровневый каскад (L0/L1/L2)
|
||||
- **Рефакторинг `obd/`:** разделение на независимые сервисы
|
||||
- `commands.py` — каталог всех AT-команд
|
||||
- `classifier.py` — классификация ответов + определение уровня
|
||||
- `connection.py` — транспортный слой (SerialTransport)
|
||||
- **Fix:** `init()` больше не шлёт ATAT1/ATST (висли на клонах v1.5)
|
||||
- **Скрипты:** три уровня (`build_script_l0/l1/l2`)
|
||||
- **БД:** таблица `device_profiles` по BT MAC
|
||||
- **API:** `POST /api/v1/elm/probe`, `GET /api/v1/elm/profile/<mac>`
|
||||
- `api/routes.py` — `/script?level=0|1|2`
|
||||
|
||||
#### v0.36.0-dev (31 мая 2026)
|
||||
- Ребрендинг Elmer → elmAI (лого, сайт)
|
||||
- Opus review: серверные фиксы (WAL, идемпотентность, таймауты LLM, кэш ping-llm)
|
||||
- `api/config.py` — `@lru_cache`, `api/db.py` — контекстный менеджер + request_id
|
||||
- `brain/client.py` — обработка ошибок (различает 429, 5xx, Timeout), DEFAULT_MODEL
|
||||
- `obd/protocol.py` — `reset_input_buffer()`, не затирать ERROR
|
||||
- CI/CD: GitHub Actions для Android APK (сборка + деплой на сервер)
|
||||
- Правило №1 в `.instructions.md`: вопрос → только ответ, никаких действий
|
||||
|
||||
#### v0.35.0-dev (29-30 мая 2026)
|
||||
- Рефакторинг архитектуры: `elmer/` → `api/` + `brain/` + `obd/`
|
||||
- Удалён мёртвый код (`elmer/diagnose.py`, `elmer/elm.py`, `elmer/prompts.py`, `web/raw_endpoint.py`)
|
||||
- `doc/architecture.md` — полное описание структуры
|
||||
- `obd/protocol.py` — вынесен из elm_proto, доработан
|
||||
|
||||
#### v0.13.0-dev (28 мая 2026) — AndrOBD стейт-машина
|
||||
- Стейт-машина 1:1 с AndrOBD (ElmProt.java)
|
||||
- 5 багов исправлено (команды подряд без пауз, ATST не читал ответ, частичный read, таймаут 200ms, BUS ERROR recovery)
|
||||
- AdaptiveTiming (500ms start, 50-2000ms range, ATST)
|
||||
- OkHttp timeout 30→120с
|
||||
- `tools/mock_elm327_v2.py` — мок с реалистичными задержками
|
||||
- `tools/test_androbd.py` — тест стейт-машины (2/3 зелёные)
|
||||
|
||||
#### v0.11.0-prod (25-27 мая 2026) — fat-client архитектура
|
||||
- Fat-client: телефон сам гоняет протокол, сервер только батч-анализ
|
||||
- Скрипт диагностики: GET /api/v1/script
|
||||
- Загрузка батча: POST /api/v1/session/upload
|
||||
- Эндпоинт /chat
|
||||
- Исследование 19 ELM/BT проектов → AndrOBD = золотой стандарт
|
||||
- `doc/elm-reference.md` — 1100+ строк паттернов
|
||||
- Домен obdai.ru, решение НЕ деплоить до стабильного ELM↔Android
|
||||
|
||||
#### v0.x — ранние версии (fat-client ветка)
|
||||
- `TestService.kt` — зелёная кнопка: самостоятельный прогон протокола (100% работает)
|
||||
- `ElmForwardService.kt` — транспорт BT/TCP ↔ HTTP (проблемы: deadlock, паузы)
|
||||
- Побайтовое чтение в mock (исправлен мусор `\r` vs `\r\n`)
|
||||
- Фиксированный debug.keystore (пароль `android`, alias `androiddebugkey`)
|
||||
- `AndroidManifest.xml`: `usesCleartextTraffic="true"`
|
||||
|
||||
---
|
||||
|
||||
## 4. Android-клиент (отдельный репо)
|
||||
|
||||
### Структура
|
||||
```
|
||||
app/src/main/java/ru/elmer/client/
|
||||
├── elm/
|
||||
│ └── ElmProtocol.kt — ELM327 стейт-машина (AndrOBD)
|
||||
├── obd/
|
||||
│ └── ObdDecoder.kt — декодер PID/DTC/VIN
|
||||
├── server/
|
||||
│ └── ServerClient.kt — HTTP к серверу (retry 3x, OkHttp)
|
||||
├── script/
|
||||
│ ├── ScriptEngine.kt — движок скриптов
|
||||
│ └── ScriptRunnerService.kt — фоновая диагностика
|
||||
├── db/
|
||||
│ └── SessionDb.kt — локальная SQLite история
|
||||
└── ui/
|
||||
└── MainActivity.kt — UI + кнопки
|
||||
```
|
||||
|
||||
### Что НЕ ДОРАБОТАНО (по opus-fix-plan, этап 3-4):
|
||||
- [ ] `request_id` на клиенте (UUID до цикла ретраев, в JSON + заголовок Idempotency-Key)
|
||||
- [ ] `X-Api-Key` через `BuildConfig.API_KEY` из `local.properties`
|
||||
- [ ] `ElmProtocol.sendCommand()` — не затирать ERROR, дренаж буфера
|
||||
- [ ] `SessionDb.onUpgrade()` — ALTER TABLE вместо DROP TABLE
|
||||
- [ ] `MainActivity` — троттлинг `/ping-llm` (не чаще 60с), убрать дублирующий receiver
|
||||
- [ ] `ScriptRunnerService` — null intent → stopSelf, try/finally для progress.stop()
|
||||
- [ ] Exponential backoff в ретраях
|
||||
|
||||
---
|
||||
|
||||
## 5. Деплой
|
||||
|
||||
```bash
|
||||
# Сервер
|
||||
ssh obdai.ru "cd /opt/elmer && git pull origin master && sudo systemctl restart elmer"
|
||||
|
||||
# APK (локально)
|
||||
cd android && ./gradlew assembleDebug
|
||||
scp app/build/outputs/apk/debug/app-debug.apk obdai.ru:/opt/elmer/web/static/app-debug.apk
|
||||
```
|
||||
|
||||
**Сервер:** gunicorn `-w 4 -b 127.0.0.1:8000 web.app:app`, nginx :443 → :8000, SSL certbot.
|
||||
**Ветка:** `master` — продакшен.
|
||||
**Никаких** Docker, Kubernetes. Сервер на голом железе. Android APK: GitHub Actions → сборка → авто-деплой на сервер.
|
||||
|
||||
---
|
||||
|
||||
## 6. Правила работы (критически важно!)
|
||||
|
||||
1. **Вопрос в любой форме → только ответить. НИЧЕГО НЕ ПРЕДПРИНИМАТЬ.** Только прямые императивы («сделай», «исправь», «напиши») — команда к действию.
|
||||
2. **Не выдумывать инфраструктуру.** Никаких Docker, K8s. GitHub Actions можно (Android).
|
||||
3. **Читать документацию перед действиями.** `doc/architecture.md` — канонический источник.
|
||||
4. **Не редактировать отчёты Опуса** (`doc/opus-review*.md` — только для чтения).
|
||||
5. **После правок:** коммит → пуш → (если сервер) деплой через SSH.
|
||||
6. **Версию менять в трёх местах:** `index.html`, `build.gradle.kts`, доки.
|
||||
7. **Не редактировать файлы Android-репо** (elmer-android) — это отдельный репо.
|
||||
|
||||
---
|
||||
|
||||
## 7. Известные архитектурные решения
|
||||
|
||||
- **Почему не Docker:** владелец принципиально против. Всё вручную через git + systemd.
|
||||
- **Почему fat-client (скрипт + батч):** в движении связи с сервером нет. Телефон сам гоняет протокол, потом заливает данные.
|
||||
- **Почему AndrOBD (не своё):** AndrOBD — 10 лет продакшена, 1993⭐, вылизанный протокол. Копировать 1:1, не изобретать.
|
||||
- **Почему не PostgreSQL:** SQLite достаточно для одного сервера. Миграция будет когда-нибудь потом.
|
||||
- **Почему obdai.ru не в продакшене:** пока не отлажен ELM↔Android на 100%. Телефон + ноутбук в одной WiFi — быстрее и надёжнее.
|
||||
|
||||
---
|
||||
|
||||
## 8. Ветки
|
||||
|
||||
| Ветка | Описание |
|
||||
|-------|----------|
|
||||
| `master` | Продакшен (актуальная: v0.36.0-dev) |
|
||||
| `opus-fixes` | Правки по отчётам Опуса (31 мая; влита в master) |
|
||||
| `arch-refactor` | Рефакторинг elmer/ → api/ brain/ obd/ |
|
||||
| `fat-client` | Старая fat-client архитектура (устарела) |
|
||||
| `androbd-proto` | Прототип AndrOBD стейт-машины (устарела) |
|
||||
| `elm-layer-v2` | Старый ELM-слой (устарела) |
|
||||
|
||||
---
|
||||
|
||||
## 9. Динамический тест — START/STOP (v0.93+, 10.06.2026)
|
||||
|
||||
### Цель
|
||||
Выявить **потерю мощности, подсос воздуха, забитый фильтр, проблемы смеси** — ловля STFT/LTFT на сбросе газа.
|
||||
|
||||
### 5 быстрых PID (планировалось)
|
||||
1. **RPM** (010C)
|
||||
2. **MAF** (0110)
|
||||
3. **STFT** (0106)
|
||||
4. **LTFT** (0107)
|
||||
5. **TPS** (0111)
|
||||
|
||||
→ После тестов #43-#45 выяснилось: ELM327 v1.5 не успевает 5 PID за 250ms (данные склеиваются).
|
||||
→ После тестов #47-#48 (v0.93.0-dev): даже 3 PID × 250ms — 94% ошибок, ELM перестаёт отвечать после ~15 сэмплов.
|
||||
→ **Решение (текущее, v0.93.0): Speed-test при первом подключении ELM + адаптивный интервал.**
|
||||
|
||||
### Текущая стратегия (v0.93+)
|
||||
|
||||
#### Этап 0 — Speed-test (только при первом подключении нового ELM)
|
||||
- После инициализации ELM: замерить время ответа на 010C, 0110, 0106 — каждый 3 раза
|
||||
- Показать пользователю: `"⏱ Тест скорости: RPM 82ms MAF 91ms STFT 82ms"`
|
||||
- Сохранить `response_time_ms` в профиль устройства (по BT MAC)
|
||||
- Интервал = `max(250, avg_response × 3 × 1.5)`
|
||||
- При повторных запусках — использовать сохранённое значение
|
||||
|
||||
#### Этап 1 — Статика (перед СТАРТ)
|
||||
- Снять все доступные PID по одному разу
|
||||
- Определить какие PID отвечают, какие нет (7F 01 12)
|
||||
- **Запомнить** неподдерживаемые — больше не опрашивать
|
||||
- Время: ~3-4 секунды
|
||||
|
||||
#### Этап 2 — Динамика (250ms)
|
||||
- **3 PID**: RPM (010C), MAF (0110), STFT (0106)
|
||||
- LTFT, TPS, MAP, Load, coolant, IAT — один раз в статике
|
||||
|
||||
#### Этап 3 — Контроль качества
|
||||
- После СТОП проверить количество сэмплов и % ошибок
|
||||
- Если < 6-8 сэмплов или > 30% errors — сообщить водителю:
|
||||
> «Слишком быстро. Нажмите СТАРТ, плавно наберите ~3000 об/мин, **сбросьте газ, подождите 3-4 секунды**, нажмите СТОП.»
|
||||
|
||||
### Процедура для водителя
|
||||
1. Дождаться ДИАГНОСТИКА → зелёный
|
||||
2. Нажать СТАРТ
|
||||
3. Плавно газ до ~3000 об/мин
|
||||
4. **Резко сбросить газ**
|
||||
5. **Подождать 3-4 секунды** (без нажатий) — ЭБУ корректирует смесь
|
||||
6. СТОП
|
||||
7. ➤ (Send) — отправка на сервер
|
||||
|
||||
### Зачем ждать 3-4 секунды после сброса
|
||||
- MAF падает → STFT резко уходит в минус/плюс
|
||||
- ЭБУ пытается стабилизировать смесь
|
||||
- LTFT начинает подстраиваться
|
||||
- Именно эти 3-4 секунды — самое ценное для анализа
|
||||
|
||||
### Планы
|
||||
- Скорость — потом через GPS (не через OBD)
|
||||
- ~~Адаптивный интервал если ELM быстрее (v2.x)~~ ✅ Сделано в v0.93.0
|
||||
- Логирование в историю каждого теста
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Быстрый старт
|
||||
|
||||
## Тест без машины (mock ELM327 + Android клиент)
|
||||
|
||||
Три шага на ноутбуке + телефон.
|
||||
|
||||
### 1. Клонировать репо на ноутбуке
|
||||
|
||||
```bash
|
||||
git clone https://gitea.services.ngcloud.ru/Nail/elmer.git ~/elmer
|
||||
cd ~/elmer
|
||||
pip install flask requests pyserial
|
||||
```
|
||||
|
||||
### 2. Терминал 1 — Mock ELM327
|
||||
|
||||
```bash
|
||||
python tools/mock_elm327.py
|
||||
# → Listening on 0.0.0.0:35000
|
||||
```
|
||||
|
||||
### 3. Терминал 2 — Flask сервер
|
||||
|
||||
```bash
|
||||
python web/app.py
|
||||
# → Running on http://0.0.0.0:5005
|
||||
```
|
||||
|
||||
### 4. Телефон
|
||||
|
||||
- Скачать APK: https://github.com/Repinoid/elmer-android/actions → последний зелёный билд → артефакт `elmer-debug`
|
||||
- Установить (разрешить неизвестные источники)
|
||||
- В поле URL ввести: `IP_ноутбука:35000` (например `192.168.1.42:35000`)
|
||||
- Нажать кнопку
|
||||
|
||||
### 5. Ожидаемый результат
|
||||
- Телефон: ⏳ TCP подключение... → TCP: OK → обновления статуса
|
||||
- Терминал 1 (mock): AT-команды, VIN, DTC, PID — ответы
|
||||
- Терминал 2 (сервер): HTTP POST от телефона, парсинг, ответы
|
||||
|
||||
---
|
||||
|
||||
## Тест ELM327 в машине (Bluetooth + ноутбук)
|
||||
|
||||
## Один раз: Bluetooth
|
||||
|
||||
```bash
|
||||
bash scripts/setup-bt.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Тест 1: только чтение (без LLM)
|
||||
|
||||
```bash
|
||||
python run.py --no-llm
|
||||
```
|
||||
|
||||
Что должно произойти:
|
||||
- Подключится к ELM327
|
||||
- Прочитает VIN
|
||||
- Прочитает коды ошибок
|
||||
- Прочитает параметры (обороты, температура, скорость...)
|
||||
- Сохранит в elmer.db
|
||||
|
||||
Если ошибка «Не удалось открыть порт» — запусти `bash scripts/setup-bt.sh` ещё раз.
|
||||
|
||||
---
|
||||
|
||||
## Тест 2: полный цикл (с DeepSeek)
|
||||
|
||||
```bash
|
||||
DEEPSEEK_API_KEY=sk-твой-ключ python run.py
|
||||
```
|
||||
|
||||
То же самое + отправит в DeepSeek и покажет диагноз.
|
||||
|
||||
---
|
||||
|
||||
## Веб-интерфейс (на ноутбуке)
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
DEEPSEEK_API_KEY=sk-твой-ключ python web/app.py
|
||||
# Открыть http://localhost:5005
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Если ELM327 не отвечает
|
||||
|
||||
1. Проверь что ELM327 запитана (горит лампочка)
|
||||
2. Проверь сопряжение: `bluetoothctl paired-devices`
|
||||
3. Проверь порт: `ls -la /dev/rfcomm0`
|
||||
4. Попробуй вручную: `sudo rfcomm bind 0 MAC-адрес`
|
||||
@@ -0,0 +1,181 @@
|
||||
# Структура репозитория elmAI
|
||||
|
||||
> **elmAI** — сервис OBD2-диагностики автомобилей через ELM327 + LLM (DeepSeek).
|
||||
> Android-приложение + Python-сервер. Анализ ошибок ЭБУ, live-параметры, диагноз через ИИ.
|
||||
|
||||
---
|
||||
|
||||
## Корневые файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `run.py` | Главная точка входа (CLI). Подключается к ELM327 по Bluetooth, читает VIN/DTC/PID, сохраняет в SQLite, отправляет в LLM. Запуск: `python run.py [--no-llm] [--port]` |
|
||||
| `config.yaml` | Конфигурация: LLM (API key, модель), ELM327 (порт, baudrate), список PID для чтения |
|
||||
| `requirements.txt` | Зависимости Python: pyserial, pyyaml, requests, flask, flask-cors |
|
||||
| `deploy.sh` | Скрипт деплоя на сервер obdai.ru: обновление репо, venv, systemd-сервис (gunicorn), nginx, SSL (certbot) |
|
||||
| `legacy-deploy.sh` | Устаревшая версия деплоя (ветка fat-client, GPT-OSS модель) |
|
||||
| `analysis.md` | Анализ и план проекта от 2025-05-25: железо, ЦА, требования, компоненты, протокол, риски |
|
||||
| `idea.md` | Концепция сервиса: OBD2 + AI диагностика, три компонента (сервер, Android, десктоп) |
|
||||
| `morda.md` | Макет UI (морда) v2: иконки-светофоры, кнопка-трансформер, поле вывода, поле ввода |
|
||||
| `QUICKSTART.md` | Быстрый старт: тест с mock ELM327, тест в машине, веб-интерфейс |
|
||||
| `resume.txt` | Резюме проекта для нового чата: версия v0.77.0-dev, инструкции по деплою |
|
||||
| `legacy-resume.txt` | Устаревшее резюме (v0.48.0, ветка master) |
|
||||
| `CHANGELOG.md` | Полное описание проекта: архитектура, модули, эндпоинты, БД, стейт-машина (актуально v0.95.0-dev) |
|
||||
| `token.txt` | Токены и ключи: gitea, DeepSeek API, SSH-ключ VM |
|
||||
| `STRUCTURE.md` | **Этот файл** — описание структуры репозитория |
|
||||
|
||||
---
|
||||
|
||||
## `api/` — Flask REST API + БД + парсинг
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `__init__.py` | Пустой (пакет) |
|
||||
| `config.py` | Загрузка `config.yaml` с подстановкой `${VAR}` из переменных окружения. Кэш через `@lru_cache` |
|
||||
| `db.py` | SQLite-база данных (WAL mode). Таблицы: `sessions`, `cars`, `diagnostic_tokens`, `llm_messages`, `ecu_parameters`, `dtc_codes`, `command_queue`. Класс `Database` |
|
||||
| `routes.py` | Основные эндпоинты: `GET /api/v1/script`, `POST /api/v1/session/upload`, `POST /api/v1/chat`, `POST /api/v1/elm/probe`. Проверка X-Api-Key, сборка промпта для LLM |
|
||||
| `dtc.py` | DTC-эндпоинты: `POST /api/v1/dtc/decode` (расшифровка кодов из справочника), `POST /api/v1/dtc/upload`. Справочник из `doc/dtc_codes.txt` |
|
||||
| `ping.py` | Эндпоинты проверки: `GET /api/v1/ping` (доступность), `GET /api/v1/ping-llm` (проверка LLM с адаптивным кэшем 60с/7с) |
|
||||
| `parser.py` | Парсинг батча ELM-ответов: VIN (из decoded и raw HEX), DTC stored/pending (mode 03/07), PID-параметры (mode 01) |
|
||||
| `scripts.py` | Сборка диагностических скриптов трёх уровней: L0 (5 PID + stored DTC), L1 (8 PID + VIN + stored/pending), L2 (14 PID + калибровки). + динамические скрипты |
|
||||
| `raw_elm.py` | Сырое взаимодействие с ELM327: локальный режим (прямое подключение) и удалённый (через Android-реле). HTTP-очередь команд |
|
||||
|
||||
---
|
||||
|
||||
## `brain/` — LLM-клиент и промпты
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `__init__.py` | Пустой (пакет) |
|
||||
| `client.py` | `Diagnoser` — HTTP-клиент к OpenAI-совместимому API (api.aillm.ru). Модели: `gpt-oss-120b`, `qwen3-6-27b-fp8`. Обработка ошибок: Timeout, 429, 5xx, 4xx |
|
||||
| `prompts.py` | `SYSTEM_PROMPT` (10 правил для диагноза: расшифровка, отклонения, степени уверенности), `DYNAMIC_PROMPT` (для динамических тестов), `build_user_prompt()` |
|
||||
|
||||
---
|
||||
|
||||
## `obd/` — ELM327-протокол (Python, порт AndrOBD)
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `__init__.py` | Пустой (пакет) |
|
||||
| `connection.py` | `SerialTransport` — транспортный слой: открыть serial/Bluetooth порт, побайтовое чтение до `>`, запись + flush |
|
||||
| `protocol.py` | `AndrOBD` — стейт-машина ELM327 (порт ElmProt.java). Состояния: UNDEFINED → INITIALIZING → READY → BUSY → ERROR. Канонический init, обработка BUS ERROR |
|
||||
| `state.py` | `State` (enum состояний) и `Rsp` (классификация ответов: PROMPT, OK, SEARCHING, ERROR, BUS_ERROR, NODATA и т.д.) |
|
||||
| `timing.py` | `AdaptiveTiming` — адаптивный таймаут (50..2000мс). Увеличивается при таймаутах, уменьшается при быстрых ответах, сброс при BUS ERROR |
|
||||
| `commands.py` | Каталог AT-команд ELM327 с метаданными: name, desc, level (0/1/2), safe. L0 (универсальные), L1 (ATAT), L2 (CAF/CFC) |
|
||||
| `classifier.py` | Классификация сырых ответов ELM327 и определение уровня устройства по ответам на пробинг |
|
||||
| `probe.py` | Пробинг ELM327: трехуровневый каскад (L0→L1→L2), каждая команда с таймаутом 500мс, без ретраев |
|
||||
| `raw_console.py` | `RawELM` — сырой слой без стейт-машины: только send/read/drain/available. Для изучения поведения ELM327 |
|
||||
|
||||
---
|
||||
|
||||
## `web/` — Веб-интерфейс (Flask)
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `app.py` | Точка входа Flask: регистрация эндпоинтов, режим RAW (блокировка всех, кроме `/elm/raw/*`), раздача APK, главная страница |
|
||||
| `script_builder.py` | Сборка диагностических скриптов (устаревшая версия — дублирует `api/scripts.py`) |
|
||||
| `script_endpoint.py` | Эндпоинты скриптов (устаревшая версия — дублирует `api/routes.py`) |
|
||||
| `script_parser.py` | Парсинг батча (устаревшая версия — дублирует `api/parser.py`) |
|
||||
| `templates/index.html` | Главная HTML-страница: скачивание APK, десктоп-диагностика, отображение результатов |
|
||||
| `static/style.css` | Стили: тёмная тема, оранжевый акцент, карточки, спиннеры, DTC-бейджи |
|
||||
|
||||
---
|
||||
|
||||
## `android/` — Android-приложение (Kotlin)
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `build.gradle.kts` | Корневой build-файл Gradle: плагины Android + Kotlin |
|
||||
| `settings.gradle.kts` | Настройки Gradle-проекта |
|
||||
| `gradle.properties` | Свойства Gradle |
|
||||
| `gradlew` | Gradle Wrapper (исполняемый) |
|
||||
| `app/build.gradle.kts` | Модуль app: minSdk 24, OkHttp 4.12.0, зависимости |
|
||||
| `app/src/` | Исходники Android-приложения (Kotlin) — основной клиент + raw-реле |
|
||||
| `raw/build.gradle.kts` | Модуль raw — ретранслятор ELM327 через HTTP |
|
||||
| `doc/opus-review-android.md` | Рецензия кода Android-приложения |
|
||||
| `doc/opus-questions-android.md` | Вопросы по Android после рецензии |
|
||||
| `gradle/wrapper/` | Gradle Wrapper JAR и настройки |
|
||||
|
||||
---
|
||||
|
||||
## `tools/` — Вспомогательные утилиты
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `mock_elm327.py` | Эмулятор ELM327 v1.5 через TCP (порт 35000). Отвечает на AT-команды, PID, DTC, VIN. Для тестирования без реального сканера |
|
||||
| `mock_elm327_v2.py` | Улучшенный мок: поддержка `>` как разделителя, ATST, случайные ошибки (BUS BUSY, UNABLE), побайтовая отправка |
|
||||
| `elm_console.py` | Интерактивная консоль ELM327 (сырой режим). Команды: ATZ, 0105, !drain, !timeout, !log. Для изучения поведения ELM |
|
||||
| `elm_relay.py` | Интерактивная консоль удалённого управления ELM327 через Android-реле. HTTP-команды: `!status`, `!history`, `!mode` |
|
||||
| `test_androbd.py` | Тест AndrOBD-протокола против Mock ELM327 v2: проверка что ответы не перемешаны (VIN → DTC → RPM → coolant) |
|
||||
| `analyze_sessions.py` | Анализ сессий из SQLite: статистика команд, ошибок, пустых ответов |
|
||||
|
||||
---
|
||||
|
||||
## `scripts/` — Скрипты развёртывания
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `setup-bt.sh` | Настройка Bluetooth-сопряжения с ELM327: поиск, pairing, rfcomm bind на /dev/rfcomm0 |
|
||||
|
||||
---
|
||||
|
||||
## `tests/` — Автотесты
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `test_all.py` | Сквозные тесты (без LLM): сборка скриптов, парсер ELM-ответов (VIN из decoded/raw, DTC, PID), работа с БД, идемпотентность, эндпоинты |
|
||||
|
||||
---
|
||||
|
||||
## `doc/` — Документация и исследования
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `architecture.md` | Полная архитектура проекта: два режима (app/raw), схема, эндпоинты, модули |
|
||||
| `roadmap.md` | План развития проекта |
|
||||
| `research.md` | Исследования и заметки |
|
||||
| `competitors.md` | Анализ конкурентов |
|
||||
| `diagnostic-logic.md` | Логика диагностики |
|
||||
| `dynamic-diagnostics-analysis-2026-06-14.md` | Анализ динамической диагностики |
|
||||
| `dynamic-tests.md` | Динамические тесты |
|
||||
| `dtc_codes.txt` | Справочник DTC-кодов (формат: `P0301=Пропуски зажигания цилиндр 1`) |
|
||||
| `elm-reference.md` | Справочник по ELM327 |
|
||||
| `elm-raw-relay-plan.md` | План raw-реле |
|
||||
| `failures-journal.md` | Журнал отказов |
|
||||
| `field-test-2026-06-07.md` | Полевой тест |
|
||||
| `git-guide.md` | Гайд по Git |
|
||||
| `morda-v2.md` | Макет UI v2 |
|
||||
| `mpscholar-automotive-sensing-actuators.md` | Обучающий материал |
|
||||
| `opinion-dynamic-diagnostics-2026-06-14.md` | Мнение по динамической диагностике |
|
||||
| `relay-mistakes-2026-07-04.md` | Ошибки реле |
|
||||
| `test-cases.md` | Тест-кейсы |
|
||||
| `SETUP.md` | Инструкция по установке |
|
||||
| `audit-2026-06-07.md` | Аудит проекта |
|
||||
| `audit-prompt.md` | Промпт для аудита |
|
||||
| `opus-review.md` | Рецензия кода (Opus) |
|
||||
| `opus-fix-plan.md` | План исправлений по рецензии |
|
||||
| `opus-questions.md` | Вопросы к Opus |
|
||||
| `opus-questions-post-tests-2026-06-29.md` | Вопросы после тестов |
|
||||
| `opus-recheck-request-2026-06-28.md` | Запрос на перепроверку |
|
||||
| `opus-review-android.md` | Рецензия Android-кода |
|
||||
| `sonnet-apk-cache-questions-2026-06-28.md` | Вопросы по кэшу APK |
|
||||
| `android-bugs-2026-05-25.md` | Баги Android |
|
||||
| `claude-analysis-elm.md` / `claude-analysis-elm-v2.md` | Анализ ELM от Claude |
|
||||
| `claude-request-elm.md` / `claude-request-elm-v2.md` | Запросы к Claude по ELM |
|
||||
| `session-*.md` | Логи сессий разработки по датам |
|
||||
| `session-resume-2026-06-14.md` | Резюме сессии |
|
||||
| `history/` | Архив старых заметок, логов сессий и результатов тестов по датам |
|
||||
| `history/2026-05-31.md` | Лог сессии 31 мая |
|
||||
| `history/2026-06-03.md` | Лог сессии 3 июня |
|
||||
| `history/2026-06-05.md` | Лог сессии 5 июня |
|
||||
| `history/2026-06-06.md` | Лог сессии 6 июня |
|
||||
| `history/2026-06-07.md` | Лог сессии 7 июня |
|
||||
| `history/2026-06-07-plans.md` | Планы на 7 июня |
|
||||
| `history/2026-06-10.md` | Лог сессии 10 июня |
|
||||
| `history/opus-recheck-analysis-2026-06-28.md` | Анализ перепроверки Opus |
|
||||
| `history/opus-sonnet-comparison-2026-06-29.md` | Сравнение Opus vs Sonnet |
|
||||
| `history/session-summary-2026-06-28.md` | Сводка сессии 28 июня |
|
||||
| `history/sonnet-response-post-tests-2026-06-29.md` | Ответ Sonnet после тестов |
|
||||
| `history/test-results-2026-06-28.md` | Результаты тестов 28 июня |
|
||||
| `history/test-results-2026-07-04.md` | Результаты тестов 4 июля |
|
||||
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
+180
@@ -0,0 +1,180 @@
|
||||
# Резюме elmAI — для нового чата
|
||||
|
||||
> Создано: 2026-07-10 | Предыдущий чат: relay-отладка
|
||||
|
||||
## Проект
|
||||
|
||||
elmAI — OBD2-диагностика через ELM327 + LLM (DeepSeek).
|
||||
Два репо: `elmer/` (gitea, сервер) и `elmer/android/` (github, Android).
|
||||
|
||||
## Версии
|
||||
|
||||
| Компонент | Версия |
|
||||
|-----------|--------|
|
||||
| Основной APK (app) | v0.42.0-dev |
|
||||
| Raw-реле APK (raw) | v0.4.0-dev |
|
||||
|
||||
## Два режима
|
||||
|
||||
1. **app/** — прямая диагностика: телефон→ELM→скрипт→батч→сервер→LLM
|
||||
2. **raw/** — ретранслятор: Copilot→сервер→телефон→ELM→ответ. HTTP-поллинг.
|
||||
|
||||
## Raw-реле (raw/)
|
||||
|
||||
```
|
||||
Copilot → POST /cmd → очередь SQLite → GET /cmd (телефон) → sendCommand() → ELM
|
||||
↓
|
||||
Copilot ← GET /response?device_id=X&seq=N ← POST /response (телефон) ← ответ
|
||||
```
|
||||
|
||||
**Ключевые файлы:**
|
||||
- `ElmProtocol.kt` — 1:1 с `app/.../ElmProtocol.kt` (AndrOBD: ATSP0→ATAT1→ATST→ATS0→ATL0→ATE0)
|
||||
- `ElmActor.kt` — single-thread executor
|
||||
- `RawRelayService.kt` — foreground-сервис: BT→init→поллинг
|
||||
- `RelayClient.kt` — HTTP к `/api/v1/elm/raw/*`
|
||||
|
||||
**handle()**: BUS_ERROR→ATPC+ATSP0, ERROR→ATWS, STOPPED→только state. MAX_RETRIES=3.
|
||||
|
||||
## Результаты тестов (клоны v1.5)
|
||||
|
||||
- Клон #1: 12/12 (100% первые 12), потом 13/16 (81%)
|
||||
- Клон #2: 13/18 (72%)
|
||||
- Закономерность: деградация после 10-12 команд
|
||||
- Двигатель заглушен: PID не работают (STOPPED)
|
||||
- RPM: 2688–2807, темп: 84–88°C, дроссель: 0–1.5% — данные верны
|
||||
|
||||
## Сервер (obdai.ru, 5.172.178.213)
|
||||
|
||||
- nginx:443 → gunicorn:8000 (4 воркера)
|
||||
- Flask: `web/app.py`, blueprints: routes, dtc, ping, raw_elm
|
||||
- SQLite: `command_queue` (raw), `sessions` (app)
|
||||
- `/api/v1/elm/raw/*`: hello, cmd×2, response×2, status
|
||||
- **device_id обязателен** в `/response`
|
||||
- **Flask использует** `/opt/elmer/templates/index.html` (не web/templates)
|
||||
|
||||
## 12 главных провалов (подробно: `doc/failures-journal.md`)
|
||||
|
||||
1. Не скопировал рабочий `app/ElmProtocol.kt` — писал с нуля
|
||||
2. Доверял Opus вместо проверки AndrOBD
|
||||
3. ATST96 убивает клон
|
||||
4. ATI в init ломает порядок
|
||||
5. drainInput() в write() — буферный сдвиг
|
||||
6. Freeze detection через ATRV
|
||||
7. AT-команды в handle()
|
||||
8. Recovery ATSP0 в relayLoop
|
||||
9. Дренаж 0100 после init
|
||||
10. Тест без device_id
|
||||
11. Версия сайта не обновлялась
|
||||
12. APK не долетел до телефона
|
||||
|
||||
## Правила (`.github/copilot-instructions.md`)
|
||||
|
||||
1. НИЧЕГО не делать без прямого указания
|
||||
2. На вопросы — только отвечать
|
||||
3. Коммит + push после каждой правки
|
||||
4. При деплое — bump версии в build.gradle.kts
|
||||
5. Формат: fix/feat/refactor/bump/docs
|
||||
6. ELM327 — только как AndrOBD, без самодеятельности
|
||||
7. Рассуждение ≠ команда
|
||||
|
||||
## Деплой raw APK
|
||||
|
||||
```bash
|
||||
cd android
|
||||
sed -i 's/appVersionCode = XX/appVersionCode = YY/' raw/build.gradle.kts
|
||||
sed -i 's/X.Y.Z-dev/X.Y+1.Z-dev/' raw/build.gradle.kts
|
||||
git add -A && git commit -m "bump vX.Y+1.Z-dev" && git push origin opus-fixes
|
||||
scp raw/build.gradle.kts raw/src/.../*.kt obdai.ru:/opt/elmer/android/raw/
|
||||
ssh obdai.ru './gradlew :raw:assembleDebug && cp ...apk /opt/elmer/web/static/elm-raw-v022.apk'
|
||||
# Обновить версию в /opt/elmer/templates/index.html и /opt/elmer/web/templates/index.html
|
||||
```
|
||||
|
||||
## Ключевые документы
|
||||
|
||||
- `doc/failures-journal.md` — 12 провалов
|
||||
- `doc/architecture.md` — полная архитектура
|
||||
- `doc/diagnostic-logic.md` — режимы диагностики
|
||||
- `STRUCTURE.md` — все файлы и папки
|
||||
|
||||
### Репозитории
|
||||
- Сервер: https://gitea.services.ngcloud.ru/Nail/elmer (ветка **dynamic-tests**)
|
||||
- Android: https://github.com/Repinoid/elmer-android (ветка **dynamic-tests**)
|
||||
- Сервер живёт на 5.172.178.213 (SSH: naeel@5.172.178.213, ключ ~/.ssh/naeel_vm_id_ed25519)
|
||||
|
||||
### Деплой (localhost → сервер)
|
||||
```bash
|
||||
# 1. bump версии в android/app/build.gradle.kts на локальной машине!
|
||||
# 2. закоммитить + запушить (dynamic-tests!)
|
||||
cd /home/naeel/elmer && git add -A && git commit -m "..." && git push origin dynamic-tests
|
||||
|
||||
# 3. залить android-исходники на сервер
|
||||
|
||||
# 3. залить android-исходники на сервер
|
||||
cd /home/naeel/elmer && tar czf /tmp/android-src.tar.gz --exclude='.git' --exclude='build' --exclude='.gradle' android/
|
||||
scp -i ~/.ssh/naeel_vm_id_ed25519 /tmp/android-src.tar.gz naeel@5.172.178.213:/tmp/
|
||||
|
||||
# 4. на сервере: обновить сервер + собрать APK
|
||||
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 "
|
||||
cd /opt/elmer && git checkout dynamic-tests && git pull origin dynamic-tests
|
||||
pip install -r requirements.txt
|
||||
sudo systemctl restart elmer
|
||||
|
||||
rm -rf android && tar xzf /tmp/android-src.tar.gz
|
||||
cd android && gradle wrapper --gradle-version 8.7
|
||||
export ANDROID_SDK_ROOT=\$HOME/android-sdk
|
||||
./gradlew clean assembleDebug
|
||||
cp app/build/outputs/apk/debug/app-debug.apk /opt/elmer/web/static/
|
||||
"
|
||||
```
|
||||
|
||||
### Структура проекта
|
||||
```
|
||||
elmer/
|
||||
android/ — Android-приложение (Kotlin)
|
||||
.../client/
|
||||
MainActivity.kt — UI + приёмники
|
||||
ElmForwardService.kt — BT/TCP-реле
|
||||
TestService.kt — автономный тест ELM
|
||||
api/ — Flask API (Python)
|
||||
db.py — БД (sessions + device_profiles)
|
||||
routes.py — эндпоинты
|
||||
scripts.py — скрипты L0/L1/L2
|
||||
parser.py — парсинг ответов
|
||||
config.py, dtc.py, ping.py
|
||||
brain/ — LLM-клиент, промпты
|
||||
obd/ — ELM-протокол (Python)
|
||||
commands.py — каталог AT-команд
|
||||
classifier.py — классификация ответов
|
||||
connection.py — SerialTransport
|
||||
probe.py — пробинг ELM
|
||||
protocol.py — стейт-машина AndrOBD
|
||||
state.py — состояния/ответы
|
||||
timing.py — адаптивный таймаут
|
||||
doc/ — Документация, сессии
|
||||
web/ — Flask web, статика
|
||||
```
|
||||
|
||||
### Что сделано (сессия 2026-06-07)
|
||||
|
||||
#### Сервер
|
||||
- **Пробинг ELM**: трехуровневый каскад (L0/L1/L2), профили в БД по MAC
|
||||
- **Fix init**: больше не шлём ATAT1/ATSTxx (вешало клоны)
|
||||
- **Скрипты под уровень**: L0 (5 PIDs), L1 (8 + VIN), L2 (14 + калибровки)
|
||||
- **Рефакторинг**: код разбит на независимые модули (commands, classifier, connection...)
|
||||
|
||||
#### Android
|
||||
- **Вывод**: append вместо overwrite (строки не перекрываются)
|
||||
- **Таймер**: отдельный TextView, тикает только во время обмена (Engine Time)
|
||||
- **TestService**: адаптивные таймауты, ATS0, \r терминатор
|
||||
|
||||
### Что НЕ сделано (TODO)
|
||||
- Полевой тест на машине ← СЕЙЧАС
|
||||
- Разбить MainActivity.kt
|
||||
- Разбить ElmChecker.kt
|
||||
|
||||
### Важные правила
|
||||
- ELM327 v1.5 — фейк, НЕ слать ATAT1/AT@1/AT@2/ATST/ATCAF1/ATCFC1
|
||||
- Все статусы через append("\n..."), не tvStatus.text =
|
||||
- Таймер операций (opTimerStart/Stop), не сессии
|
||||
- Версию поднимать ВЕЗДЕ: build.gradle.kts, index.html (2 места), CHANGELOG.md, resume.txt, doc/architecture.md
|
||||
- В проекте elmer — НИЧЕГО не делать без прямого указания
|
||||
Reference in New Issue
Block a user