docs: журнал неудач (12 провалов) + архив старого

This commit is contained in:
Repinoid
2026-07-10 12:39:35 +04:00
parent b9a33403fe
commit 29ace6119e
3 changed files with 220 additions and 2 deletions
+192
View File
@@ -0,0 +1,192 @@
# 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` | исходный | Протокол основного приложения |
+24
View File
@@ -0,0 +1,24 @@
# Тест AndrOBD протокола на клоне v1.5 — 04.07.2026
## Конфигурация
- **ELM:** клон v1.5, протокол A0 (CAN)
- **ECU:** зажигание ON, двигатель OFF
- **Приложение:** ELM Relay v2 (v0.3.1-dev)
- **Инит:** ATSP0→ATI→[без ATAT1/ATST]→ATS0→ATL0→ATE0 (AndrOBD порядок)
## Результат: 14/15 (93%)
| Цикл | PID | Ответ |
|------|-----|-------|
| 0 | 010C | ❌ (хвост инита) |
| 0 | 0105 | ✅ 410579 (ОЖ 79°C) |
| 0 | 0111 | ✅ 410579 |
| 1 | 010C | ✅ 410C0000 (RPM 0) |
| 1-4 | все | ✅ (12/12) |
## Выводы
1. **ATST96 убивает клон v1.5.** Без него — инит работает.
2. **AndrOBD порядок (ATSP0 первый) — правильный.** ATE0 первым не нужен.
3. **93% без залипания на 15 командах.** Раньше залипало на 4-й.
4. **Первая команда провалена** — хвост от ATI/ATSP0 в буфере. Требует drain перед первым PID.
+4 -2
View File
@@ -1,6 +1,8 @@
# ELM327 Relay — хронология ошибок и текущее состояние
# ELM327 Relay — хронология ошибок (АРХИВ)
## Дата: 2026-07-04
> **Устарело**. Актуальный документ: `doc/failures-journal.md`
## Дата: 2026-07-04 | Версия на момент написания: v0.3.7-dev
---