- obd/probe.py: трехуровневый каскад (L0/L1/L2) - obd/commands.py: каталог всех AT-команд с метаданными - obd/classifier.py: классификация ответов + определение уровня - obd/connection.py: транспортный слой (SerialTransport) - obd/protocol.py: init() только база, без ATAT1/ATST - api/db.py: таблица device_profiles по BT MAC - api/scripts.py: три уровня скриптов (l0/l1/l2) - api/routes.py: /elm/probe, /elm/profile/<mac>, /script?level= - web/templates/index.html: v0.48.0 - CHANGELOG.md, doc/architecture.md, resume.txt: версии
144 lines
6.8 KiB
Python
144 lines
6.8 KiB
Python
"""
|
|
obd/commands.py — Каталог AT-команд ELM327.
|
|
|
|
Все известные команды ELM327 с метаданными:
|
|
- name: имя команды (напр. "ATE0")
|
|
- desc: краткое описание
|
|
- level: минимальный уровень устройства (0/1/2)
|
|
- safe: можно ли слать при пробинге (False для опасных)
|
|
|
|
Принцип:
|
|
- Нет в профиле → не слать.
|
|
- Опасные команды (меняют baud rate, мониторинг) — никогда не пробингуются.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import List
|
|
|
|
|
|
@dataclass
|
|
class AtCommand:
|
|
"""AT-команда ELM327 с метаданными."""
|
|
name: str # "ATE0"
|
|
desc: str # "Echo off"
|
|
level: int = 0 # минимальный уровень (0=все, 1=ATAT1, 2=CAF1/CFC1)
|
|
safe: bool = True # можно ли пробинговать
|
|
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# Уровень 0 — Универсальные (есть у ВСЕХ клонов)
|
|
# ══════════════════════════════════════════════════════════
|
|
|
|
CMDS_L0: List[AtCommand] = [
|
|
AtCommand("ATE0", "Echo off"),
|
|
AtCommand("ATE1", "Echo on", safe=False), # не слать — вернём эхо
|
|
AtCommand("ATL0", "Linefeeds off"),
|
|
AtCommand("ATL1", "Linefeeds on", safe=False),
|
|
AtCommand("ATS0", "Spaces off"),
|
|
AtCommand("ATS1", "Spaces on", safe=False),
|
|
AtCommand("ATH0", "Headers off"),
|
|
AtCommand("ATH1", "Headers on"),
|
|
AtCommand("ATSP0", "Auto protocol"),
|
|
AtCommand("ATDPN", "Describe protocol number"),
|
|
AtCommand("ATRV", "Read voltage"),
|
|
AtCommand("ATI", "Identify"),
|
|
AtCommand("ATWS", "Warm start", safe=False), # сбрасывает состояние
|
|
AtCommand("ATPC", "Protocol close", safe=False),
|
|
AtCommand("ATR0", "Responses off", safe=False),
|
|
AtCommand("ATR1", "Responses on"),
|
|
AtCommand("ATNL", "Normalize length"),
|
|
AtCommand("ATAL", "Allow long messages"),
|
|
AtCommand("ATAR", "Auto receive", safe=False), # включает авто-приём
|
|
AtCommand("ATSW", "Stop waiting"),
|
|
AtCommand("ATFE", "Forget events"),
|
|
AtCommand("ATSI", "Slow init"),
|
|
AtCommand("ATFI", "Fast init"),
|
|
AtCommand("ATKW", "Keyword"),
|
|
AtCommand("ATTA", "Tester address"),
|
|
AtCommand("ATTP", "Try protocol"),
|
|
AtCommand("ATWM", "Wakeup message"),
|
|
AtCommand("ATIGN", "Ignore"),
|
|
AtCommand("ATIFR", "IFR"),
|
|
AtCommand("ATIIA", "ISO init address"),
|
|
AtCommand("ATRD", "Read data"),
|
|
AtCommand("ATCS", "CAN silent"),
|
|
AtCommand("ATCV", "Calibrate voltage"),
|
|
AtCommand("ATD0", "Display off"),
|
|
AtCommand("ATM0", "Memory off"),
|
|
AtCommand("ATM1", "Memory on"),
|
|
]
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# Уровень 1 — Хорошие клоны и оригиналы
|
|
# ══════════════════════════════════════════════════════════
|
|
|
|
CMDS_L1: List[AtCommand] = [
|
|
AtCommand("ATAT0", "Adaptive timing off", level=1),
|
|
AtCommand("ATAT1", "Adaptive timing on", level=1),
|
|
AtCommand("ATAT2", "Adaptive timing aggressive", level=1),
|
|
]
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# Уровень 2 — Только настоящий ELM327
|
|
# ══════════════════════════════════════════════════════════
|
|
|
|
CMDS_L2: List[AtCommand] = [
|
|
AtCommand("ATCAF0", "CAN auto formatting off", level=2),
|
|
AtCommand("ATCAF1", "CAN auto formatting on", level=2),
|
|
AtCommand("ATCFC0", "CAN flow control off", level=2),
|
|
AtCommand("ATCFC1", "CAN flow control on", level=2),
|
|
AtCommand("ATCM", "CAN mask", level=2),
|
|
AtCommand("ATCRA", "CAN receive address", level=2),
|
|
AtCommand("ATCP", "CAN priority", level=2),
|
|
AtCommand("ATSH", "Set header", level=2),
|
|
AtCommand("AT@1", "Device description", level=2),
|
|
AtCommand("AT@2", "Device identifier", level=2),
|
|
AtCommand("ATJE", "J1939 ELM", level=2),
|
|
AtCommand("ATJS", "J1939 setup", level=2),
|
|
AtCommand("ATIB", "ISO baud", level=2, safe=False),
|
|
]
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# ОПАСНЫЕ — никогда не пробинговать
|
|
# ══════════════════════════════════════════════════════════
|
|
|
|
CMDS_DANGEROUS: List[AtCommand] = [
|
|
AtCommand("ATZ", "Hard reset", safe=False),
|
|
AtCommand("ATD", "Set defaults", safe=False),
|
|
AtCommand("ATBD", "Baud rate", safe=False),
|
|
AtCommand("ATBRD", "Baud rate divisor", safe=False),
|
|
AtCommand("ATMA", "Monitor all", safe=False),
|
|
AtCommand("ATMR", "Monitor receiver", safe=False),
|
|
AtCommand("ATMT", "Monitor transmitter", safe=False),
|
|
]
|
|
|
|
|
|
# ── Хелперы ─────────────────────────────────────────────
|
|
|
|
def get_commands_for_level(level: int) -> List[str]:
|
|
"""Возвращает имена команд, доступных на заданном уровне."""
|
|
result = [c.name for c in CMDS_L0 if c.safe]
|
|
if level >= 1:
|
|
result += [c.name for c in CMDS_L1 if c.safe]
|
|
if level >= 2:
|
|
result += [c.name for c in CMDS_L2 if c.safe]
|
|
return result
|
|
|
|
|
|
def get_probe_commands() -> dict:
|
|
"""Возвращает команды для пробинга, сгруппированные по уровням.
|
|
|
|
Returns: {"L0": ["ATE0",...], "L1": ["ATAT1",...], "L2": ["ATCAF1",...]}
|
|
"""
|
|
return {
|
|
"L0": [c.name for c in CMDS_L0 if c.safe and c.level == 0][:8],
|
|
"L1": [c.name for c in CMDS_L1 if c.safe],
|
|
"L2": [c.name for c in CMDS_L2 if c.safe],
|
|
}
|
|
|
|
|
|
# Плоские списки для импорта (обратная совместимость)
|
|
L0_NAMES = [c.name for c in CMDS_L0 if c.safe and c.level == 0]
|
|
L1_NAMES = [c.name for c in CMDS_L1 if c.safe]
|
|
L2_NAMES = [c.name for c in CMDS_L2 if c.safe]
|