Files
elmer/doc/failures-journal.md
T

14 KiB
Raw Blame History

ELM327 Relay — полный журнал неудач

Дата: 2026-07-0405 | Версия: v0.4.0-dev


Итоговое состояние

Параметр Значение
Версия на сервере v0.4.0-dev (commit ebc41e0)
Основа 1:1 с app/.../ElmProtocol.kt (AndrOBD)
Клон 1 (v1.5) 12/12 → 13/16 (72-81%)
Клон 2 (v1.5) 13/18 (72%)
Характер отказов Деградация после 10-12 команд
Двигатель заглушен PID не работают (STOPPED), только ATRV

НЕУДАЧА 1: Игнорирование рабочего кода

Симптом: raw/ElmProtocol.kt написан с нуля вместо копирования app/ElmProtocol.kt Когда: создание raw-модуля (июнь 2026) Что сделано не так: В репозитории УЖЕ был app/src/.../ElmProtocol.kt — рабочий протокол на основе AndrOBD. Вместо копирования написан новый с «улучшениями». Корневая причина: предположение что raw-реле требует особой логики. Не проверено что app/ElmProtocol.kt уже работает. Исправлено: v0.4.0-dev — raw/ElmProtocol.kt = 1:1 копия app/ElmProtocol.kt Урок: всегда проверять существующий код перед созданием нового.


НЕУДАЧА 2: Доверие Opus без проверки исходников

Симптом: init() с ATE0 первым, ATST96 для клонов, drain перед write Когда: июнь–июль 2026 Что сделано не так: Opus посоветовал — реализовано без сверки с AndrOBD (ElmProt.java). AndrOBD 10 лет в проде, все «улучшения» были ошибками. Корневая причина: доверие внешнему анализу вместо проверки первоисточника. Исправлено: полная сверка с ElmProt.java (fr3ts0n/AndrOBD). Все отличия задокументированы. Урок: первоисточник (код) > любой анализ.


НЕУДАЧА 3: ATST96 убивает клон v1.5

Симптом: клон зависает намертво после init, даже ATRV не отвечает Когда: v0.3.0-dev Что сделано не так: добавлен ATST96 (150×4=600ms) для клонов. Команда не поддерживается клоном v1.5 и вешает его. Корневая причина: предположение что клону нужен фиксированный таймаут. AndrOBD использует updateAtst() с адаптивным таймаутом для всех устройств. Исправлено: ATST96 удалён. updateAtst() теперь вызывается всегда (как в AndrOBD). Урок: не добавлять команды, которых нет в AndrOBD.


НЕУДАЧА 4: ATI в init() ломает порядок

Симптом: буферный сдвиг после каждой команды Когда: v0.3.0v0.3.7-dev Что сделано не так: ATI вставлен в середину init() для детекта клона. AndrOBD не использует ATI — версия определяется из ответа ELM на MODEL. Корневая причина: желание детектить клон внутри init(). AndrOBD определяет клона иначе. Исправлено: v0.4.0-dev — ATI удалён из init(). Init: ATSP0→ATAT1→ATST→ATS0→ATL0→ATE0. Урок: не вставлять команды в init(), которых нет в AndrOBD.


НЕУДАЧА 5: drainInput() в write()

Симптом: ответ команды N читается как ответ команды N+1 Когда: все версии raw Что сделано не так: write() вызывает drainInput() перед отправкой. Если ответ предыдущей команды запаздывает, drain съедает его и наступает сдвиг буфера на 1 позицию. Корневая причина: AndrOBD не использует drain. Синхронная модель (sendCommand → ждать ответ) требует drain для очистки мусора, но drain сам создаёт мусор если ответ приходит с задержкой. Статус: НЕ ИСПРАВЛЕНО. Остаётся в коде v0.4.0-dev. Без drain буфер забивается мусором, с drain — сдвиг на 1 команду. Меньшее из зол. Урок: синхронная модель принципиально ограничена. AndrOBD использует асинхронную (поток читает → handleTelegram) и не имеет этой проблемы.


НЕУДАЧА 6: Freeze detection через ATRV

Симптом: ответ "12.6V" читается как ответ на PID, все команды возвращают одно и то же Когда: v0.3.0-dev Что сделано не так: каждые 10 команд слался ATRV для проверки залипания. Ответ ATRV попадал в буфер и читался как ответ следующего PID. Корневая причина: ATRV — AT-команда, не OBD. Её ответ не должен смешиваться с PID-ответами. В синхронной модели это неизбежно. Исправлено: удалено в v0.3.2-dev. Урок: не смешивать AT-команды с OBD-командами в одном потоке.


НЕУДАЧА 7: AT-команды в handle()

Симптом: после STOPPED/BUS_ERROR следующая команда получает мусор Когда: v0.1.xv0.3.3-dev Что сделано не так: handle() при ошибках слал ATPC, ATWS, ATSP0. Эти AT-команды отправлялись внутри обработки ответа текущей команды, их ответы загрязняли буфер. Корневая причина: handle() вызывается из exec() который находится в процессе чтения ответа. Отправка AT-команд внутри exec() создаёт вложенные чтения, которые путают буфер. Исправлено: в v0.4.0-dev handle() шлёт AT-команды только для BUS_ERROR и ERROR (как в AndrOBD). Для STOPPED — только state tracking. Урок: AT-команды в handle() допустимы только если их ответы полностью потребляются (tryRead с таймаутом).


НЕУДАЧА 8: Recovery ATSP0 в relayLoop

Симптом: тест показывает 0/60 (все таймауты) Когда: v0.3.5-dev Что сделано не так: после STOPPED или пустого ответа relayLoop слал ATSP0 через sendBlocking. ATSP0 блокирует single-thread executor на 3+ секунд. Все последующие команды ждут в очереди, тест видит таймауты. Корневая причина: recovery выполнялся в том же потоке что и обработка команд. Команды накапливались в очереди executor'а. Исправлено: удалено в v0.4.0-dev. Recovery теперь только в handle(). Урок: recovery должен быть частью протокольного уровня (ElmProtocol), а не оркестратора (relayLoop).


НЕУДАЧА 9: Дренаж 0100 после init

Симптом: relay не отвечает ни на одну команду после init Когда: v0.3.6-dev Что сделано не так: после init отправлялся 0100 для поглощения буферного сдвига. Дренаж сам создавал сдвиг и дезориентировал клон. Корневая причина: попытка «подчистить» буфер создаёт новую команду и новый ответ, который тоже надо чистить — бесконечная рекурсия. Исправлено: удалено в v0.3.7-dev. Урок: не пытаться чистить буфер дополнительными командами.


НЕУДАЧА 10: Тест читал чужие ответы

Симптом: тест показывал OK (411100) когда relay возвращал пустоту Когда: все тесты до исправления сервера Что сделано не так: тестовый скрипт вызывал /response?wait=3 без device_id. Сервер возвращал ответы от других устройств или предыдущих сессий. Корневая причина: серверный SQL не фильтровал по device_id. Тест не обновлял seq. Исправлено: сервер (api/raw_elm.py) — /response принимает device_id. Тест обновляет seq после каждого ответа. Урок: всегда проверять что тест читает данные того устройства которое тестируется.


НЕУДАЧА 11: Версия на сайте не обновлялась

Симптом: сайт показывал v0.3.0-dev при v0.4.0-dev на сервере Когда: все деплои Что сделано не так: sed правил только /opt/elmer/web/templates/index.html. Flask использует /opt/elmer/templates/index.html. Корневая причина: два index.html в разных директориях, неизвестно какой использует Flask. Исправлено: деплой обновляет оба файла. Выяснено что Flask использует /opt/elmer/templates/. Урок: проверять какой файл реально сервится перед правкой.


НЕУДАЧА 12: v0.4.0-dev не долетел до телефона

Симптом: пользователь тестировал v0.3.7-dev думая что это v0.4.0-dev Когда: 2026-07-04 вечер Что сделано не так: деплой v0.4.0-dev прошёл, APK на сервере, но пользователь не переустановил приложение. Корневая причина: отсутствие проверки версии на телефоне. Исправлено: явное указание версии при каждом деплое. Проверка MD5 APK на сервере. Урок: всегда проверять что пользователь обновил APK перед тестированием.


ОГРАНИЧЕНИЯ КЛОНОВ v1.5 (железо)

Параметр Значение
Надёжность (холодный) 100% первые 10-12 команд
Надёжность (горячий) 70-80%, деградация после 10-12 команд
Буферный сдвиг после init 1-2 команды (неизбежно в синхронной модели)
Двигатель заглушен PID не работают, ATRV — ок
Двигатель заведён 70-80% успех
ATST96 Убивает клон намертво
ATAT1 Клон игнорирует, не мешает
Время восстановления 2-3 секунды паузы

ТЕКУЩАЯ АРХИТЕКТУРА (v0.4.0-dev)

Android phone                    Server (obdai.ru)
┌──────────────────┐            ┌─────────────────────┐
│ RawRelayService  │──HTTP────→│ /api/v1/elm/raw/cmd  │
│   relayLoop()    │←──poll───│ /api/v1/elm/raw/     │
│     ↓            │            │   response           │
│   ElmActor       │            └─────────────────────┘
│     ↓            │
│   ElmProtocol    │──BT────→ ELM327 → OBD-II → ECU
│     (AndrOBD)    │←──BT───
└──────────────────┘

КЛЮЧЕВЫЕ ФАЙЛЫ

Файл Версия Описание
raw/.../ElmProtocol.kt v0.4.0-dev 1:1 с app/ElmProtocol.kt
raw/.../ElmActor.kt v0.4.0-dev Single-thread executor
raw/.../RawRelayService.kt v0.4.0-dev Поллинг + обработка ответов
api/raw_elm.py исправлен /response с device_id
app/.../ElmProtocol.kt исходный Протокол основного приложения