15 KiB
elmAI — полное описание проекта для AI-агентов
Последнее обновление: 2026-07-10 | Версия app: 1.18.0-dev | Версия raw: 0.4.1-dev
1. ЧТО ЭТО
elmAI — OBD2-диагностика автомобиля через ELM327-адаптер + LLM (DeepSeek).
Телефон подключается к ELM327 по Bluetooth, собирает данные с ЭБУ, отправляет на сервер, сервер анализирует через LLM и возвращает диагноз.
2. РЕПОЗИТОРИИ
| Репо | URL | Ветка | Что внутри |
|---|---|---|---|
| Сервер | gitea.services.ngcloud.ru/Nail/elmer |
dynamic-tests |
Python Flask + elmAI бэкенд |
| Android | github.com/Repinoid/elmer-android |
opus-fixes |
Kotlin Android-приложение |
ВАЖНО: Android-репо лежит ВНУТРИ серверного: /home/naeel/elmer/android/. Это отдельный git-репо со своим remote. Коммитить и пушить надо ИЗНУТРИ android/.
3. СЕРВЕР (obdai.ru, 5.172.178.213)
elmer/
├── api/ # Flask API
│ ├── routes.py # Основные эндпоинты (script, upload, chat, probe, sessions)
│ ├── raw_elm.py # Командная очередь для raw-реле (SQLite table command_queue)
│ ├── db.py # SQLite (sessions, device_profiles, command_queue)
│ ├── scripts.py # Сборка диагностических скриптов L0/L1/L2 + dynamic
│ ├── parser.py # Парсинг ответов ELM327 (PID, DTC, VIN)
│ ├── dtc.py # Эндпоинты DTC
│ ├── ping.py # Эндпоинты ping/ping-llm
│ └── config.py # Загрузка config.yaml
├── brain/ # LLM-клиент
│ ├── client.py # Diagnoser — HTTP к DeepSeek
│ └── prompts.py # Промпты для диагностики
├── obd/ # ELM327 протокол (Python)
│ ├── protocol.py # Стейт-машина AndrOBD (ElmProt.java)
│ ├── connection.py, commands.py, classifier.py, probe.py, state.py, timing.py
├── web/ # Flask web
│ ├── app.py # Точка входа, регистрация blueprints
│ ├── templates/index.html # Страница загрузки APK
│ └── static/ # APK-файлы
├── doc/ # ВСЯ документация
├── config.yaml # API-ключи, порты
└── deploy.sh # Скрипт деплоя
Стек: Python 3, Flask, gunicorn (4 воркера, порт 8000), nginx (:443 → :8000), SQLite.
Сервис: sudo systemctl restart elmer
4. ANDROID
4.1. Основное приложение (app/) — прямая диагностика
Пакет: ru.elmer.client | Версия: 1.18.0-dev (versionCode 38)
app/src/main/java/ru/elmer/client/
├── Config.kt # Константы: HOST, SCRIPT_URL, defaultScript(), client()
├── db/SessionDb.kt # SQLite: sessions, responses
├── elm/
│ ├── ElmProtocol.kt # Стейт-машина AndrOBD (1:1 с ElmProt.java)
│ ├── ElmChecker.kt # Проверка ELM: checkDevice(), checkEcu(), scanDtc(), sendRaw()
│ └── ObdDecoder.kt # Декодер PID/DTC/VIN (object-синглтон)
├── script/
│ └── DynamicCollector.kt # Циклический опрос PID с интервалом
├── server/
│ └── ServerClient.kt # HTTP к серверу (OkHttp): ping, pingLlm, chat, getSessions, uploadSession, downloadScript
└── ui/
└── MainActivity.kt # UI: индикаторы, кнопка-трансформер, чат, диагностика, динамический тест
8 классов. Зависимости: OkHttp 4.12.0, AndroidX, org.json. БЕЗ Room, Coroutines, DI.
Поток диагностики: MainActivity → ElmChecker → ElmProtocol → команды → ObdDecoder → SessionDb → ServerClient.uploadSession() → ответ от LLM.
4.2. Raw-реле (raw/) — ретранслятор команд
Пакет: ru.elmer.raw | Версия: 0.4.1-dev (versionCode 18)
raw/src/main/java/ru/elmer/raw/
├── ElmProtocol.kt # 1:1 копия app/ElmProtocol.kt
├── ElmActor.kt # Single-thread executor вокруг ElmProtocol
├── RawRelayService.kt # Foreground-сервис: BT→init→поллинг команд→ответ
├── RelayClient.kt # HTTP к /api/v1/elm/raw/* (OkHttp, БЕЗ X-Api-Key)
└── MainActivity.kt # Минимальный UI (выбор BT, статус, счётчики)
5 классов. Отдельный APK (applicationId: ru.elmer.raw).
Поток: RawRelayService → connectBt → ElmProtocol.init() → hello → цикл: pollCommand → sendCommand → postResponse.
Назначение: тупой ретранслятор. Сервер диктует команды, телефон передаёт в ELM и возвращает ответы. Используется для интерактивной диагностики через Copilot и тестов 3 мин / 5 мин.
5. ANDROID — ЧТО СДЕЛАНО (рефакторинг 2026-07-10)
Ветка opus-fixes, 8 коммитов:
- Config.kt — единый источник хоста (
https://obdai.ru), замена всех хардкодов - default_script.json →
assets/, DEFAULT_SCRIPT из кода удалён - ServerClient — добавлены
chat()иgetSessions(), весь HTTP через OkHttp + X-Api-Key - HttpURLConnection выпилен из MainActivity
- ElmChecker.sendRaw() — инкапсуляция ElmProtocol,
getElm()удалён - FQN → import — все полные имена заменены на нормальные import'ы
- Удалён мёртвый код: ScriptRunnerService, ScriptEngine, UploadProgress + FOREGROUND_SERVICE permissions
Результат: 8 классов (было 10), 0 HttpURLConnection, 0 FQN, 0 getElm(), 0 obdai.ru вне Config, весь HTTP аутентифицирован.
6. ANDROID — ЧТО НЕ СДЕЛАНО (TODO)
app/
- Разбить MainActivity (~750 строк) — вынести логику из UI
- Разбить ElmChecker (372 строки) — отделить BT от ELM-команд
- v1.5 клоны: деградация после 10-12 команд (ограничение железа)
raw/
- deviceId генерится заново при каждом создании RelayClient — сохранить в SharedPreferences
- Нет аутентификации — BuildConfig.API_KEY есть, но RelayClient его не шлёт
- Нет retry при ошибках HTTP
- SERVER_URL захардкожен в build.gradle.kts и дублируется в Intent extra
- drainInput() в write() — потенциальный сдвиг буфера (Неудача #5 из failures-journal.md)
Сервер
- Script Engine для режимов «3 мин на месте» / «5 мин в движении» — НЕ РЕАЛИЗОВАН
- Дублирование: routes.py и script_endpoint.py (script_endpoint.py — мёртвый)
7. РЕЖИМЫ ДИАГНОСТИКИ
Режим 1: Прямая диагностика (app/)
Однократный сбор данных: скрипт → батч ответов → сервер → LLM → диагноз.
Режим 2: Динамический тест (app/)
Циклический опрос PID. Кнопка СТАРТ/СТОП. Сервер подбирает тайминги через /api/v1/test/next.
Режим 3: Raw-реле (raw/)
Сервер управляет потоком команд. Телефон — тупой ретранслятор.
Режим 4: Прогрев на месте (raw/, 3 минуты)
3 PID (RPM, темп, дроссель) каждые 2 секунды × 90 циклов = 270 запросов. Оценка прогрева, холостых, реакции на газ.
Режим 5: В движении (raw/, 5 минут)
Те же 3 PID каждые 2 секунды × 150 циклов = 450 запросов. Нагрузочный тест, динамика разгона.
Режимы 4 и 5 требует реализации Script Engine на сервере.
8. API ЭНДПОИНТЫ
Основные (app/)
| Метод | Путь | Назначение |
|---|---|---|
| GET | /api/v1/ping |
Проверка сервера |
| GET | /api/v1/ping-llm |
Проверка LLM |
| GET | /api/v1/script?mode=test |
Скрипт диагностики |
| POST | /api/v1/session/upload |
Загрузка батча + LLM-анализ |
| POST | /api/v1/chat |
Чат с LLM |
| GET | /api/v1/sessions |
Список сессий |
| POST | /api/v1/test/next |
Следующий шаг динамического теста |
| GET/PUT | /api/v1/elm/profile/<mac> |
Профиль скорости ELM |
Raw-реле (raw/)
| Метод | Путь | Назначение |
|---|---|---|
| POST | /api/v1/elm/raw/hello |
Android: «я готов» (чистит старые команды) |
| POST | /api/v1/elm/raw/cmd |
Copilot/сервер: поставить команду в очередь |
| GET | /api/v1/elm/raw/cmd?device_id=X |
Android: забрать pending команду |
| POST | /api/v1/elm/raw/response |
Android: вернуть ответ |
| GET | /api/v1/elm/raw/response?device_id=X&seq=N |
Copilot: прочитать ответ |
| GET | /api/v1/elm/raw/status |
Статус устройства |
9. ДЕПЛОЙ
9.1. Сервер
cd /home/naeel/elmer
git add -A && git commit -m "..." && git push origin dynamic-tests
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
"
9.2. Android APK (app)
# 1. Bump версии в app/build.gradle.kts (versionCode и versionName)
cd /home/naeel/elmer/android
sed -i 's/versionCode = XX/versionCode = YY/' app/build.gradle.kts
sed -i 's/versionName = "X.Y.Z-dev"/versionName = "X.Y+1.Z-dev"/' app/build.gradle.kts
# 2. Закоммитить + запушить
git add -A && git commit -m "bump vX.Y+1.Z-dev" && git push origin opus-fixes
# 3. Залить исходники на сервер и собрать APK
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/
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 "
rm -rf /opt/elmer/android && tar xzf /tmp/android-src.tar.gz -C /opt/elmer/
cd /opt/elmer/android && gradle wrapper --gradle-version 8.7
export ANDROID_SDK_ROOT=\$HOME/android-sdk
./gradlew :app:clean :app:assembleDebug
cp app/build/outputs/apk/debug/app-debug.apk /opt/elmer/web/static/
"
# 4. Обновить версию в /opt/elmer/web/templates/index.html и /opt/elmer/templates/index.html
9.3. Raw APK
# Аналогично app, но:
# - bump версии в raw/build.gradle.kts
# - сборка: ./gradlew :raw:assembleDebug
# - копия: cp raw/build/outputs/apk/debug/raw-debug.apk /opt/elmer/web/static/elm-raw-v022.apk
10. ПРАВИЛА (НЕ НАРУШАТЬ)
- НИЧЕГО не делать без прямого указания пользователя. Даже если видишь проблему — только сказать.
- На вопрос — только ответ. Не продолжать «а ещё могу...», не предлагать помощь.
- После выполнения команды — сказать «готово» и ЖДАТЬ.
- Коммит + push после КАЖДОЙ правки. Один коммит = одна правка. Формат:
fix:,feat:,refactor:,bump:,docs:,style:,chore:. - При деплое — всегда bump версии. Инкрементировать патч (Z в X.Y.Z-dev).
- ELM327 — только как AndrOBD (ElmProt.java). Никакой самодеятельности в протоколе. Init: ATSP0→ATAT1→ATS0→ATL0→ATE0. Никакого drainInput() перед write().
- Не материться. Пользователь матерится — ты нет.
- Не гадать. Если не уверен — проверить факты чтением кода.
- Код правит ТОЛЬКО пользователь или Copilot по команде. Не исполнять советы Opus по ELM-командам — Opus специалист по архитектуре кода, а не по ELM327.
11. КЛЮЧЕВЫЕ ДОКУМЕНТЫ
| Файл | Содержание |
|---|---|
AGENTS.md |
Этот файл — полное описание проекта |
PLANS.md |
Мастер-план: что сделано, что предстоит |
doc/architecture.md |
Архитектура сервера и Android |
doc/diagnostic-logic.md |
5 режимов диагностики |
doc/failures-journal.md |
12 провалов при разработке raw-реле |
doc/SETUP.md |
Настройка окружения |
doc/CHANGELOG.md |
История версий |
doc/STRUCTURE.md |
Полное дерево файлов |
doc/QUICKSTART.md |
Быстрый старт |
doc/resume.txt |
Краткое резюме для нового чата |
.github/copilot-instructions.md |
Правила для Copilot |
android/README.md |
Документация Android-проекта |
android/RAW-FIX-PLAN.md |
План исправлений raw-реле |
android/doc/opus-response-arch-2026-07-10.md |
Анализ архитектуры от Opus |
android/doc/opus-response-plan-2026-07-10.md |
План рефакторинга от Opus |
12. КОНТАКТЫ / ДОСТУП
- Сервер: 5.172.178.213, SSH:
naeel@5.172.178.213, ключ:~/.ssh/naeel_vm_id_ed25519 - Домен: obdai.ru (SSL через certbot)
- Gitea: gitea.services.ngcloud.ru/Nail/elmer
- GitHub: github.com/Repinoid/elmer-android