# Динамические тесты — архитектура > 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 // 12 ответов ELM ) val samples = mutableListOf() // в памяти, быстро ``` ### После СТОП — попытка отправки ```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 / акселерометр — не сейчас - Автодетект фаз (разгон/сброс) — ручной СТАРТ/СТОП - Отправка пачками в реальном времени — копим всё до СТОП