v0.48.0 — пробинг ELM327, трехуровневый профиль, рефакторинг obd/
- 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: версии
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
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]
|
||||
Reference in New Issue
Block a user