Files
elmer/doc/dynamic-tests.md
T

108 lines
4.4 KiB
Markdown

# Динамические тесты — архитектура
> v0.49.0-dev, 7 июня 2026
> Ветка: `dynamic-tests`
## Концепция
Два теста: **на месте** и **в движении**. Разница — только в подсказке юзеру.
Физически оба делают одно: опрашивают 12 PID каждые 250мс, копят в памяти, отправляют на сервер одной пачкой.
## Flow
```
Юзер → кнопка «⏱ На месте» / «🚗 В движении»
→ подсказка в окне вывода
→ кнопка «▶ Старт»
→ опрос 12 PID каждые 250мс, вывод: «запись... N отсчётов»
→ кнопка «⏹ Стоп»
→ отправка на сервер POST /api/v1/session/upload
→ LLM-анализ → вывод в чат
```
## Скрипт (сервер)
Новый режим `?mode=dynamic` в `api/scripts.py`:
```json
{
"version": 1,
"title": "Динамический тест",
"mode": "dynamic",
"interval_ms": 250,
"steps": [
{"id": "pid_04", "cmd": "0104", "desc": "Нагрузка"},
{"id": "pid_05", "cmd": "0105", "desc": "ОЖ"},
{"id": "pid_06", "cmd": "0106", "desc": "STFT"},
{"id": "pid_07", "cmd": "0107", "desc": "LTFT"},
{"id": "pid_0B", "cmd": "010B", "desc": "MAP"},
{"id": "pid_0C", "cmd": "010C", "desc": "RPM"},
{"id": "pid_0D", "cmd": "010D", "desc": "Скорость"},
{"id": "pid_0E", "cmd": "010E", "desc": "Зажигание"},
{"id": "pid_0F", "cmd": "010F", "desc": "IAT"},
{"id": "pid_10", "cmd": "0110", "desc": "MAF"},
{"id": "pid_11", "cmd": "0111", "desc": "Дроссель"},
{"id": "pid_1F", "cmd": "011F", "desc": "Время работы"}
]
}
```
## Хранение данных (Android)
### До отправки — в памяти
```kotlin
data class DynamicSample(
val ts: Long, // System.currentTimeMillis()
val responses: List<RawResponse> // 12 ответов ELM
)
val samples = mutableListOf<DynamicSample>() // в памяти, быстро
```
### После СТОП — попытка отправки
```kotlin
1. Собираем все samples в JSON
2. POST /api/v1/session/upload
3. Если 200 ОК, забыли
4. Если ошибка пишем ВСЁ в SessionDb
```
### Локальное хранение — через SessionDb (уже есть)
```sql
-- Таблица sessions (уже существует)
session_type = "dynamic" -- отличаем от обычных
-- Таблица responses (уже существует)
-- Каждый сэмпл = одна запись в responses:
-- session_id, step_id = "sample_N", cmd = "batch",
-- raw = JSON всего опроса, decoded = "запись №N"
```
**Плюсы**: не надо новой таблицы, `SessionDb` уже умеет `createSession`/`addResponse`/`getResponses`.
**Объём**: 30 секунд × 4 опроса/с × 12 PID = 1440 записей ≈ ~100KB — норм.
### Ретрай непосланных сессий
При старте приложения: `db.getUnuploadedSessions()` → отправить → пометить `uploaded=1`.
## Промпт для LLM (сервер)
Отдельный `DYNAMIC_PROMPT` в `brain/prompts.py`:
```
Ты — эксперт по диагностике. Получены временные ряды 12 параметров с интервалом 250мс.
Проанализируй:
1. Отклик дросселя — есть ли задержка/провалы
2. STFT/LTFT — богатая или бедная смесь под нагрузкой и при сбросе
3. RPM — плавность роста/падения, пропуски
4. MAP — соответствует ли оборотам
5. Зажигание — есть ли коррекция, детонация
6. Аномалии — резкие скачки, выбросы
Отвечай кратко: 2-3 предложения вывода, затем по пунктам что не так.
```
## Что НЕ делаем
- GPS / акселерометр — не сейчас
- Автодетект фаз (разгон/сброс) — ручной СТАРТ/СТОП
- Отправка пачками в реальном времени — копим всё до СТОП