doc: полный лог сессии — архитектура, ошибки, решение с offline-скриптами

This commit is contained in:
Repinoid
2026-05-26 10:33:52 +03:00
parent 8103343688
commit a46f16d24b
2 changed files with 84 additions and 1 deletions
+83
View File
@@ -48,6 +48,89 @@ CI упал с `org.gradle.api.artifacts.SelfResolvingDependency`. Причин
И создан `gradle/wrapper/gradle-wrapper.properties` с `gradle-8.5-bin.zip`.
---
## ЧАСТЬ 2: Тест с реальным ELM327 (Фаэтон)
### Зелёная кнопка (TestService) — 100% работает
- BT-подключение к ELM327 ✅
- ATZ → ATEx → ATH1 ✅
- VIN: получен (16-ричные данные) ✅
- DTC stored/pending: получены ✅
- PID'ы: RPM, ОЖ, скорость, дроссель и др. ✅
- **Тайминги:** `Thread.sleep(250)` между командами — критически важно
### Оранжевая кнопка (ElmForwardService + сервер) — НЕ работает
Проблема: стейт-машина сервера шлёт команды мгновенно, без пауз. ELM327 не успевает.
- ATZ → OK
- ATEx → OK
- 0902 → SEARCHING...UNABLE TO CONNECT (ELM не может выполнить режим 09)
- Сервер переходит к DTC → шлёт 03 → ELM отвечает `?` → бесконечный цикл `?`
**Корень проблемы:** тонкий клиент требует server-driven архитектуру (сервер даёт команду → клиент пишет в ELM → ELM отвечает → клиент шлёт ответ серверу → сервер даёт следующую). Но сервер не делает пауз, а ELM327 требует ~200мс между командами.
### Почему Deadlock при первом запуске оранжевой кнопки
1. Клиент: BT-коннект ✅, входит в loop()
2. ELM327: ждёт команду (не шлёт приветствие без запроса)
3. Клиент: `read()` блокируется — нет данных
4. Сервер: не получает "READY" — не шлёт ATZ
5. **DEADLOCK**
**Исправлено:** `fwd("READY")` сразу после коннекта — кикстарт сервера.
---
## Вывод: архитектура телефон↔сервер в реальных условиях
### Проблема
В движении связи с сервером нет. Архитектура «сервер рулит каждой командой» нежизнеспособна.
### Решение (обсуждено)
**Две фазы работы:**
**Фаза 1 — ОФЛАЙН (в машине):**
- Клиент получает со старта **скрипт** от сервера
- Скрипт: последовательность команд + промпты водителю
- Клиент сам гоняет протокол (как зелёная кнопка)
- Данные пишутся локально (SQLite) с таймстемпами
- Водитель видит промпты: «Разгон 0-100», «Кикдаун», «Холостой ход 30с»
- Кнопка Старт / Стоп
**Фаза 2 — ОНЛАЙН (дома):**
- Клиент заливает всю сессию одним POST на сервер
- Сервер парсит, анализирует, LLM → диагноз
- Возможно — выдаёт следующий скрипт для нового теста
### Формат скрипта (пример):
```json
{
"name": "Тест турбины",
"steps": [
{"type": "obd", "cmd": "ATZ"},
{"type": "obd", "cmd": "010C", "label": "RPM"},
{"type": "prompt", "text": "Разгон 0-100, кикдаун"},
{"type": "loop", "pid": "010C", "duration": 30, "rate_ms": 200},
{"type": "obd", "cmd": "03"},
{"type": "upload"}
]
}
```
### Кто что делает
| Компонент | Файл | Статус | Что добавить |
|-----------|------|--------|-------------|
| Тестовый клиент | `TestService.kt` | ✅ гоняет протокол | Сохранение в БД, скрипты, промпты |
| Транспортный клиент | `ElmForwardService.kt` | ⚠️ требует стабильной связи | Возможно удалить |
| Стейт-машина | `raw_endpoint.py` | ⚠️ нет пауз | Переделать под батчевую обработку |
| Mock ELM327 | `mock_elm327.py` | ✅ эмулятор | Добавить задержки для реализма |
| Сервер приёма | `web/app.py` | ✅ | POST-эндпоинт для заливки сессии |
### Договорённости по процессу
- **НИКОГДА не кодить без прямой команды**
- Сначала обсуждать → потом делать
- Коммитить часто, с понятными сообщениями
- Документировать все ошибки и решения
### 08:40 — Ошибка 3: Коммиты не в ту ветку
Изначально все изменения ушли в `master`, но рабочая ветка — `relay-only`.
+1 -1
View File
@@ -210,7 +210,7 @@ def register(app):
logger.info(f"[{session_id}] {parsed}")
# SEARCHING/NO DATA — ждём, не продвигаем стейт
is_skip = raw.startswith("SEARCHING") or raw == "NO DATA" or raw == "STOPPED"
is_skip = raw.startswith("SEARCHING") or raw in ("NO DATA", "STOPPED", "?")
if is_skip:
sess["retries"] = sess.get("retries", 0) + 1
if sess["retries"] > 3: