"""Сборка диагностических скриптов. Три уровня в зависимости от возможностей ELM327: L0 (все клоны) — 5 PIDs + stored DTC L1 (+ATAT1) — 8 PIDs + VIN + stored/pending DTC L2 (+CAF1/CFC1) — 14 PIDs + VIN + калибровки + все ошибки Принцип: - Чем выше уровень — тем больше PIDs и глубже диагностика - Скрипты захардкожены (PIDs по SAE J1979), LLM не составляет - Нет в профиле — не слать (несуществующие команды вешают клонов) """ def build_script_l0() -> dict: """Скрипт для уровня 0 — клоны v1.5 и подобные. Только однокадровые ответы. Без VIN (много-фреймовый, без CFC1 рвётся). """ return { "version": 1, "title": "Диагностика (базовая)", "steps": [ {"id": "elm_atrv", "cmd": "ATRV", "desc": "Напряжение"}, {"id": "pid_05", "cmd": "0105", "desc": "Температура ОЖ"}, {"id": "pid_0C", "cmd": "010C", "desc": "Обороты"}, {"id": "pid_0D", "cmd": "010D", "desc": "Скорость"}, {"id": "pid_11", "cmd": "0111", "desc": "Дроссель"}, {"id": "pid_04", "cmd": "0104", "desc": "Нагрузка"}, {"id": "dtc_03", "cmd": "03", "desc": "Коды ошибок"}, ], } def build_script_l1() -> dict: """Скрипт для уровня 1 — хорошие клоны с ATAT1. Быстрее L0 за счёт адаптивного тайминга. VIN — медленно но возможно. """ return { "version": 1, "title": "Диагностика (стандартная)", "steps": [ {"id": "elm_atrv", "cmd": "ATRV", "desc": "Напряжение"}, {"id": "pid_05", "cmd": "0105", "desc": "Температура ОЖ"}, {"id": "pid_0C", "cmd": "010C", "desc": "Обороты"}, {"id": "pid_0D", "cmd": "010D", "desc": "Скорость"}, {"id": "pid_11", "cmd": "0111", "desc": "Дроссель"}, {"id": "pid_04", "cmd": "0104", "desc": "Нагрузка"}, {"id": "pid_06", "cmd": "0106", "desc": "STFT"}, {"id": "pid_07", "cmd": "0107", "desc": "LTFT"}, {"id": "vin_09", "cmd": "0902", "desc": "VIN"}, {"id": "dtc_03", "cmd": "03", "desc": "Сохр. ошибки"}, {"id": "dtc_07", "cmd": "07", "desc": "Pending ошибки"}, ], } def build_script_l2() -> dict: """Скрипт для уровня 2 — настоящий ELM327 с CAF1+CFC1. Полный фарш: много PIDs, VIN быстро, калибровки, все типы ошибок. """ return { "version": 1, "title": "Диагностика (полная)", "steps": [ {"id": "elm_atrv", "cmd": "ATRV", "desc": "Напряжение"}, {"id": "pid_05", "cmd": "0105", "desc": "Температура ОЖ"}, {"id": "pid_0C", "cmd": "010C", "desc": "Обороты"}, {"id": "pid_0D", "cmd": "010D", "desc": "Скорость"}, {"id": "pid_11", "cmd": "0111", "desc": "Дроссель"}, {"id": "pid_04", "cmd": "0104", "desc": "Нагрузка"}, {"id": "pid_06", "cmd": "0106", "desc": "STFT"}, {"id": "pid_07", "cmd": "0107", "desc": "LTFT"}, {"id": "pid_0B", "cmd": "010B", "desc": "MAP"}, {"id": "pid_0F", "cmd": "010F", "desc": "Темп. воздуха"}, {"id": "pid_10", "cmd": "0110", "desc": "MAF"}, {"id": "pid_1C", "cmd": "011C", "desc": "Стандарт OBD"}, {"id": "vin_09", "cmd": "0902", "desc": "VIN"}, {"id": "cal_09", "cmd": "0904", "desc": "Калибровка"}, {"id": "ecu_09", "cmd": "090A", "desc": "Имя ЭБУ"}, {"id": "dtc_03", "cmd": "03", "desc": "Сохр. ошибки"}, {"id": "dtc_07", "cmd": "07", "desc": "Pending ошибки"}, {"id": "dtc_0A", "cmd": "0A", "desc": "Перманентные"}, ], } # ── Совместимость со старым API ───────────────────────── def build_default_script() -> dict: """Минимальный скрипт (уровень 0).""" return build_script_l0() def build_full_script() -> dict: """Полный скрипт (уровень 2).""" return build_script_l2() def build_script_for_level(level: int) -> dict: """Возвращает скрипт под уровень устройства.""" if level >= 2: return build_script_l2() elif level == 1: return build_script_l1() else: return build_script_l0() def build_dynamic_script() -> dict: """Скрипт для динамического теста — 12 PID, опрос каждые 250мс.""" return { "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": "Время работы"}, ], } def build_test_script(wait_ms: int = 1500, pids: list[str] | None = None, repeat: int = 8) -> dict: """Тестовый скрипт для отладки таймингов ELM327. Сервер управляет таймингами — можно менять wait_ms/pids/repeat без передеплоя APK. Args: wait_ms: пауза ПЕРЕД каждой OBD-командой (ms) pids: список PID для опроса (по умолчанию 010C,0110,0106) repeat: сколько раз повторить цикл """ if pids is None: pids = ["010C", "0106"] # RPM + STFT — минимум для проверки связи pid_names = {"010C": "RPM", "0110": "MAF", "0106": "STFT", "0105": "ОЖ", "0104": "Нагрузка", "0107": "LTFT", "0111": "Дроссель", "010D": "Скорость", "010B": "MAP", "010F": "IAT"} steps = [] # Статика — один проход по всем PID для калибровки for pid in pids: name = pid_names.get(pid, pid) steps.append({"id": f"static_{pid}", "cmd": pid, "desc": f"{name} (статик)", "wait": 0}) # Динамика — repeat циклов for cycle in range(repeat): for pid in pids: name = pid_names.get(pid, pid) steps.append({"id": f"dyn{cycle}_{pid}", "cmd": pid, "desc": f"{name}", "wait": wait_ms}) return { "version": 1, "mode": "test", "title": f"Тест: {len(pids)} PID × {repeat}, пауза {wait_ms}ms", "wait_ms": wait_ms, "repeat": repeat, "steps": steps, }