Files
elmer/doc/failures-journal.md
T

193 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` | исходный | Протокол основного приложения |