From 29ace6119e23b3cb53ffff49d4f67ef093dfd160 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Fri, 10 Jul 2026 12:39:35 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=B6=D1=83=D1=80=D0=BD=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BD=D0=B5=D1=83=D0=B4=D0=B0=D1=87=20(12=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=D0=BE=D0=B2)=20+=20=D0=B0=D1=80=D1=85=D0=B8?= =?UTF-8?q?=D0=B2=20=D1=81=D1=82=D0=B0=D1=80=D0=BE=D0=B3=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/failures-journal.md | 192 +++++++++++++++++++++++++ doc/history/test-results-2026-07-04.md | 24 ++++ doc/relay-mistakes-2026-07-04.md | 6 +- 3 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 doc/failures-journal.md create mode 100644 doc/history/test-results-2026-07-04.md diff --git a/doc/failures-journal.md b/doc/failures-journal.md new file mode 100644 index 0000000..1bf439a --- /dev/null +++ b/doc/failures-journal.md @@ -0,0 +1,192 @@ +# ELM327 Relay — полный журнал неудач + +## Дата: 2026-07-04–05 | Версия: 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.0–v0.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.x–v0.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` | исходный | Протокол основного приложения | diff --git a/doc/history/test-results-2026-07-04.md b/doc/history/test-results-2026-07-04.md new file mode 100644 index 0000000..b1f0073 --- /dev/null +++ b/doc/history/test-results-2026-07-04.md @@ -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. diff --git a/doc/relay-mistakes-2026-07-04.md b/doc/relay-mistakes-2026-07-04.md index 7beb978..db9e911 100644 --- a/doc/relay-mistakes-2026-07-04.md +++ b/doc/relay-mistakes-2026-07-04.md @@ -1,6 +1,8 @@ -# ELM327 Relay — хронология ошибок и текущее состояние +# ELM327 Relay — хронология ошибок (АРХИВ) -## Дата: 2026-07-04 +> **Устарело**. Актуальный документ: `doc/failures-journal.md` + +## Дата: 2026-07-04 | Версия на момент написания: v0.3.7-dev ---