protocol: protocol¶
obd_diag.protocol.elm327¶
.. py:module:: obd_diag.protocol.elm327
Minimaler ELM327-Treiber: Befehl senden, Antwort bis zum Prompt lesen.
.. py:exception:: ForbiddenCommandError :module: obd_diag.protocol.elm327
Bases: :py:class:Exception
Ein Befehl außerhalb der Freigabeliste sollte gesendet werden.
Das ist ein Programmierfehler, kein Adapterproblem: bewusst kein ElmError,
damit ihn kein Aufrufer als „Angabe nicht verfügbar“ abfängt. Gesendet wurde nichts.
.. py:function:: is_read_only(cmd) :module: obd_diag.protocol.elm327
True für Adapter-Befehle und lesende OBD-Anfragen der Freigabeliste.
.. py:exception:: ElmError :module: obd_diag.protocol.elm327
Bases: :py:class:Exception
Der Adapter hat einen Befehl abgelehnt oder keine Daten geliefert.
.. py:exception:: NoDataError :module: obd_diag.protocol.elm327
Bases: :py:class:~obd_diag.protocol.elm327.ElmError
NO DATA: kein Steuergerät hat geantwortet (z. B. keine Fehlercodes).
.. py:exception:: UnknownCommandError :module: obd_diag.protocol.elm327
Bases: :py:class:~obd_diag.protocol.elm327.ElmError
?: der Adapter kennt den Befehl nicht oder unterstützt ihn nicht.
.. py:exception:: NoConnectionError :module: obd_diag.protocol.elm327
Bases: :py:class:~obd_diag.protocol.elm327.ElmError
UNABLE TO CONNECT: der Adapter findet kein Steuergerät, mit dem er sprechen kann.
Laut Datenblatt (ELM327DSJ, „Error Messages and Alerts“) hat er dann alle Protokolle
durchprobiert; meist ist die Zündung aus. Am ersten echten Auto (W177) war genau das
die Ursache, HINT sagt dem Nutzer daher, was zu tun ist.
.. py:class:: ObdProtocol(number, name, inferred=None) :module: obd_diag.protocol.elm327
Bases: :py:class:object
Fahrzeugprotokoll laut ATDPN/ATDP.
obd_diag.protocol.frames¶
.. py:module:: obd_diag.protocol.frames
Zerlegt ELM327-Antworten (ohne Header) in Nachrichten, eine je Steuergerät.
Bei CAN setzt der Adapter mehrteilige ISO-TP-Nachrichten selbst zusammen und gibt sie
so aus (ATH0, mit oder ohne Leerzeichen)::
008
0: 43 03 01 33 03 00
1: 01 71 00 00 00 00 00
Die erste Zeile ist die Nutzdatenlänge in Bytes (hex), dann folgen die Frames mit fortlaufender Nummer 0 bis F (danach wieder 0). Der letzte Frame ist aufgefüllt und wird auf die Länge gekürzt. Alle anderen Zeilen sind je eine vollständige Nachricht; sie dürfen auch zwischen den Frames einer mehrteiligen Nachricht stehen (Einzel-Frame eines anderen Steuergeräts).
Senden zwei Steuergeräte gleichzeitig mehrteilige Nachrichten, mischt der ELM327 ohne
Header deren Frames (Datenblatt ELM327DS, „Multiline Responses“, Beispiel 09 04);
eine Zuordnung ist dann unmöglich. Das wird an Lücken in der Frame-Nummerierung und an
unvollständigen Nachrichten erkannt und als FrameSequenceError (ein ValueError)
gemeldet, statt falsche Daten zu liefern. Die Dienste wiederholen die Anfrage dann mit
Headern (ATH1) und ordnen die Frames über die CAN-ID zu (protocol.headers).
.. py:exception:: FrameSequenceError :module: obd_diag.protocol.frames
Bases: :py:class:ValueError
Frames einer mehrteiligen Nachricht fehlen, sind vertauscht oder vermischt.
Ohne Header nicht zu unterscheiden: verlorene Frames oder gleichzeitige mehrteilige
Antworten mehrerer Steuergeräte. Mit Headern (ATH1) lässt sich das klären.
.. py:function:: split_messages(response) :module: obd_diag.protocol.frames
Liefert die Nutzdaten jeder Nachricht in response.
Wirft ValueError bei Zeilen, die keine Hex-Daten sind, und
FrameSequenceError (Unterklasse von ValueError) bei mehrteiligen Nachrichten
mit fehlenden, vertauschten oder vermischten Frames.
obd_diag.protocol.headers¶
.. py:module:: obd_diag.protocol.headers
Antworten mit Headern (ATH1) zerlegen und je Steuergerät zusammensetzen.
Ohne Header kann der ELM327 gleichzeitige mehrteilige Antworten mehrerer Steuergeräte nicht trennen (Datenblatt ELM327DS, „Multiline Responses“, S. 45). Mit Headern trägt jede Zeile ihren Absender, und die Frames lassen sich je Absender nach ISO 15765-2 (ISO-TP) zusammensetzen. Formate einer Zeile (mit oder ohne Leerzeichen):
CAN 11 Bit:
7E8 10 0A 43 04 01 33 03 00: 3 Hex-Ziffern CAN-ID, dann das CAN-Datenfeld samt PCI-Byte(s).CAN 29 Bit:
18 DA F1 10 06 41 00 BE 3F A8 13: 4 Bytes CAN-ID (OBD-Antworten18 DA F1 <Quelle>), dann das Datenfeld.J1850/ISO 9141/KWP:
48 6B 10 41 00 BE 3E B8 11 FA: 3 Header-Bytes (Priorität, Ziel, Quelle), Nutzdaten, 1 Prüfsummen-Byte (Datenblatt S. 44). Die Prüfsumme wird entfernt, aber nicht geprüft (J1850 nutzt eine CRC, ISO 9141/KWP eine Summe; der ELM327 verwirft fehlerhafte Nachrichten ohnehin bzw. meldet<DATA ERROR).
PCI-Byte (ISO 15765-2): 0L Einzel-Frame mit L Bytes; 1L LL erster Frame mit
12-Bit-Länge, dann 6 Bytes; 2N Folge-Frame Nummer N (1, 2, … F, 0, …) mit bis zu
7 Bytes; 3x Flusssteuerung (sendet nur der Tester, wird übersprungen). Füllbytes
nach dem Ende einer Nachricht werden abgeschnitten.
Reihenfolge des Ergebnisses: nach Steuergeräte-Adresse (EcuMessage.ecu), bei
gleicher Adresse in der Reihenfolge, in der die Nachrichten (ihr erster Frame)
eingetroffen sind. Ohne Header gilt dagegen die Eingangsreihenfolge.
.. py:class:: HeaderFormat(*values) :module: obd_diag.protocol.headers
Bases: :py:class:~enum.StrEnum
.. py:class:: EcuMessage(ecu, header, data) :module: obd_diag.protocol.headers
Bases: :py:class:object
Eine vollständige Nachricht eines Steuergeräts.
.. py:function:: header_format(response, *, can=None) :module: obd_diag.protocol.headers
Format der ersten Zeile einer Antwort mit Headern; None, wenn unlesbar.
.. py:function:: parse_header_response(response, *, can=None) :module: obd_diag.protocol.headers
Zerlegt eine Antwort mit Headern in vollständige Nachrichten je Steuergerät.
can: True/False, wenn das Protokoll bekannt ist, None erkennt das
Format je Zeile an der Form (siehe Modul-Doku). Wirft ValueError bei Zeilen
ohne Hex-Daten, ungültigen PCI-Bytes, Folge-Frames ohne ersten Frame, Lücken in der
Nummerierung und unvollständigen Nachrichten.
obd_diag.protocol.dtc_decode¶
.. py:module:: obd_diag.protocol.dtc_decode
Dekodierung von Fehlercodes (DTC) nach SAE J2012 aus Mode-03/07/0A-Antworten.
.. py:exception:: NegativeDtcResponse(mode, nrc) :module: obd_diag.protocol.dtc_decode
Bases: :py:class:ValueError
Ein Steuergerät hat die Anfrage abgelehnt oder noch nicht beantwortet.
Anders als „Mode nicht unterstützt“ heißt das nicht „keine Codes“: der Fehlerspeicher
dieses Steuergeräts ist unbekannt (z. B. 21 beschäftigt, 22 Bedingungen nicht
erfüllt, 78 Antwort folgt).
.. py:function:: decode_dtc(high, low) :module: obd_diag.protocol.dtc_decode
Zwei Rohbytes in einen Code wie P0133 umwandeln.
.. py:function:: parse_dtc_response(response, mode=3, *, can=False) :module: obd_diag.protocol.dtc_decode
Liest alle Codes aus einer Adapter-Antwort.
response ist der Hex-Text des ELM327 ohne Header, mit oder ohne Leerzeichen,
eine Nachricht pro Steuergerät; mehrteilige CAN-Nachrichten (0: …/1: …)
werden zusammengesetzt. Bei CAN (ISO 15765-4) folgt auf das Mode-Byte ein
Zählbyte (SAE J1979); Bytes nach den gezählten Codes sind Füllbytes. Ältere
Protokolle füllen stattdessen mit 00 00 auf. Negative Antworten (7F)
einzelner Steuergeräte werden nur übersprungen, wenn sie „Mode nicht unterstützt“
heißen (UNSUPPORTED_NRCS); jede andere ergibt NegativeDtcResponse, damit eine
Ablehnung nie als „keine Codes“ gelesen wird.
ValueError bei unerwarteten Antworten; FrameSequenceError (Unterklasse),
wenn Frames mehrerer Steuergeräte vermischt sind (dann mit Headern neu lesen).
.. py:function:: parse_dtc_messages(messages, mode=3, *, can=False) :module: obd_diag.protocol.dtc_decode
Wie parse_dtc_response, aber für bereits zerlegte Nachrichten (je Steuergerät).
obd_diag.protocol.obd¶
.. py:module:: obd_diag.protocol.obd
OBD-II-Dienste über den ELM327.
Bis auf clear_dtcs (Mode 04) nur lesend.
.. py:function:: read_with_headers(elm, cmd, reason) :module: obd_diag.protocol.obd
Wiederholt die lesende Anfrage cmd mit Headern und zerlegt je Steuergerät.
Für Antworten, deren Frames sich ohne Header nicht zuordnen lassen (reason).
Reihenfolge: nach Steuergeräte-Adresse, dann Eingang (siehe protocol.headers).
Wirft ElmError, wenn auch das nicht gelingt oder diesmal keine Antwort kommt.
.. py:function:: read_dtcs(elm, mode, *, can, pending_timeout=5.0) :module: obd_diag.protocol.obd
Fehlercodes aller Steuergeräte für Mode 03, 07 oder 0A.
NO DATA heißt: kein Code gespeichert, also eine leere Liste. Sind Frames
mehrerer Steuergeräte vermischt (ohne Header nicht zuzuordnen), wird die Anfrage
einmal mit Headern (ATH1) wiederholt; die Codes kommen dann nach
Steuergeräte-Adresse geordnet (z. B. 7E8 vor 7E9), sonst in Eingangsreihenfolge.
Meldet ein Steuergerät 7F <Mode> 78 (Antwort folgt) und steht die Antwort nicht
schon dabei, wird ohne erneutes Senden bis pending_timeout Sekunden
weitergelesen. Kommt sie nicht, oder lehnt ein Steuergerät aus anderem Grund ab als
„Mode nicht unterstützt“, gibt es NegativeResponseError statt einer leeren Liste:
der Fehlerspeicher ist dann unbekannt, nicht leer.
.. py:exception:: NegativeResponseError(mode, nrc) :module: obd_diag.protocol.obd
Bases: :py:class:~obd_diag.protocol.elm327.ElmError
Ein Steuergerät hat mit 7F <Mode> <NRC> abgelehnt.
.. py:function:: clear_dtcs(elm, *, pending_timeout=10.0) :module: obd_diag.protocol.obd
Mode 04: gespeicherte und ausstehende Codes, Freeze Frame und Readiness löschen.
Schreibender Befehl! Vorbedingungen prüfen und sichern muss der Aufrufer (siehe
services.clear). Erfolg heißt: mindestens ein Steuergerät bestätigt mit 44
und keines lehnt ab. Wirft NegativeResponseError bei 7F 04 xx,
NoDataError ohne Antwort und ElmError bei unerwarteter Antwort.
7F 04 78 (ISO 14229: Anfrage erhalten, Antwort folgt) ist keine Ablehnung: steht
danach noch keine endgültige Antwort, wird ohne erneutes Senden weitergelesen, bis
44 oder 7F 04 xx kommt oder pending_timeout Sekunden (ab dem Senden)
vergangen sind. Ohne Bestätigung bis dahin ElmError („nicht bestätigt“); ist
bereits ein anderes Steuergerät bestätigt, gilt das Löschen als bestätigt (mit
Log-Warnung). Mode 04 wird nie wiederholt.
.. py:function:: read_pid(elm, pid) :module: obd_diag.protocol.obd
Mode 01: Datenbytes des ersten Steuergeräts, das pid beantwortet.
None, wenn kein Steuergerät antwortet (NO DATA) oder alle ablehnen.
.. py:function:: decode_rpm(data) :module: obd_diag.protocol.obd
PID 0C: Motordrehzahl in 1/min, ((A*256)+B)/4.
.. py:function:: read_rpm(elm) :module: obd_diag.protocol.obd
Motordrehzahl in 1/min oder None, wenn sie nicht lesbar ist.
.. py:function:: read_rpms(elm) :module: obd_diag.protocol.obd
Motordrehzahl je Antwort auf 010C, in der Reihenfolge der Antworten.
Antworten mehrere Steuergeräte (z. B. Motor und Getriebe), steht jedes einzeln
darin; None für eine Antwort, die keine gültige Drehzahl ist (Ablehnung,
zu kurz, andere PID). Leer bei NO DATA.
.. py:class:: FreezeFrame(dtc=None, raw=
Bases: :py:class:object
Momentaufnahme (Mode 02, Frame 00) beim Setzen eines Fehlercodes.
raw enthält die Antworten wie empfangen (Befehl -> Hex-Text), values die
daraus dekodierten Werte. Unbeantwortete PIDs fehlen in beiden. Die Schlüssel von
raw zeigen das verwendete Anfrageformat: 020C00 (SAE J1979, mit
Frame-Nummer) oder 020C (ohne, Rückfallebene für manche Steuergeräte).
.. py:function:: read_freeze_frame(elm) :module: obd_diag.protocol.obd
Liest Frame 00 von Mode 02: auslösender Code und einige häufige Werte.
Angefragt wird nach SAE J1979 mit Frame-Nummer (02 <PID> 00). Antwortet das
Fahrzeug auf 020200 mit NO DATA oder 7F 02 12 (Format nicht
unterstützt), wird 0202 ohne Frame-Nummer versucht, wie es python-OBD sendet
und manche Steuergeräte bzw. Adapter erwarten. Liefert das eine Antwort, folgt der
ganze Freeze Frame in diesem Format; sonst (auch bei ? oder unbrauchbarer
Antwort) bleibt es beim J1979-Format für die übrigen PIDs.
obd_diag.protocol.pids¶
.. py:module:: obd_diag.protocol.pids
Mode-01-PIDs für Live-Daten nach SAE J1979: Tabelle, Dekodierung, unterstützte PIDs.
Nur lesend: gesendet werden ausschließlich 01xx-Anfragen über Elm327.query.
Die Formeln folgen SAE J1979 (Anhang B, Service $01) in der Schreibweise der
Wikipedia-Tabelle „OBD-II PIDs“: A, B, C, D sind die Datenbytes nach
41 <PID>. minimum/maximum sind der volle Wertebereich der Kodierung (alle
Bits 0 bzw. 1), nicht der physikalisch plausible Bereich. Die Werte werden nicht
gerundet; das ist Sache der Anzeige.
Eine PID kann mehrere Werte liefern (z. B. Lambdasonde: Spannung und Trimm); dann gibt
es je Wert eine PidSpec mit derselben PID, und read_values fragt die PID nur
einmal ab. decode bekommt immer die ersten size Datenbytes (also auch ein
vorangehendes Statusbyte) und liefert None, wenn der Wert laut Antwort nicht
gilt (Statusbit nicht gesetzt, Sonde nicht im Trimm).
Die Lambdasonden 14-1B, 24-2B und 34-3B heißen hier Sonde 1
bis 8 in der Reihenfolge der PIDs. Welche Bank und Position das ist, legt das
Fahrzeug über PID 13 (2 Bänke zu je 4) oder 1D (4 Bänke zu je 2) fest;
eine feste Zuordnung wie „B1S1“ wäre bei 1D falsch.
Die PIDs 68, 6C, 6D, 70 und 85 meldet der Mercedes A 180 d (W177)
als unterstützt (Bitmasken 0160/0180 in tests/fixtures/traces/mercedes_w177),
Antworten darauf gibt es aber noch keine vom Auto: am Fahrzeug noch nicht geprüft.
Ihr Aufbau (Statusbyte A, welche Werte es gibt, dann die Werte) folgt J1979 in zwei
unabhängigen Darstellungen, die übereinstimmen: der Signalliste von OBDb
(github.com/OBDb/SAEJ1979, signalsets/v3/default.json) und der PID-Liste von
DashLogic (dashlogic.com/docs/technical/obdii_pids). 68 gibt es auch in einer
älteren, kürzeren Form mit zwei Sensoren (Bit 0 und 1, Bytes B und C); sie deckt sich
mit den ersten beiden Sensoren der langen Form, Sensoren dahinter bleiben bei der
kurzen Antwort None (zu wenige Bytes).
Bewusst nicht aufgenommen (offen):
PIDs mit Statusbyte, deren Aufbau in den frei zugänglichen Quellen nicht eindeutig ist oder die das Testauto nicht meldet:
69(AGR),6A,6B,6E,6F,71-79,7A-7C(DPF),7D-84,86,87,89und höher (außerA6).Reine Status- und Bitfelder: der Regelstatus in Byte J von
70,88(SCR-Aufforderungssystem),92(Regelkreise der Kraftstoffanlage).Bitfelder und Aufzählungen ohne Messwert:
01,03,12,13,1C,1D,1E,41,51,65.53/54(Absolut-/Relativdruck Tankentlüftung): Kodierung von54ist in den frei zugänglichen Quellen widersprüchlich (Zweierkomplement oder Offset).
.. py:class:: PidSpec(pid, key, label, unit, size, decode, minimum, maximum, number=None) :module: obd_diag.protocol.pids
Bases: :py:class:object
Ein Live-Wert: PID, Schlüssel, Bezeichnung, Einheit, Dekodierung.
label ist deutsch und darf {n} enthalten (Sonde, Stützpunkt), das number
füllt; name ist die Bezeichnung in der eingestellten Sprache (obd_diag.i18n).
.. py:function:: pid_by_key(key) :module: obd_diag.protocol.pids
Der Wert zu key; KeyError mit verständlicher Meldung, wenn unbekannt.
.. py:function:: parse_supported(base, data) :module: obd_diag.protocol.pids
PIDs aus der Bitmaske einer Antwort auf 01<base> (base = 0x00, 0x20, …).
data sind die vier Datenbytes; Bit 7 des ersten Bytes steht für base + 1,
Bit 0 des vierten für base + 0x20 (der nächste Block wird unterstützt).
Weitere Bytes werden ignoriert. ValueError bei weniger als vier Bytes oder
einer base, die kein Vielfaches von 0x20 zwischen 0x00 und 0xE0 ist.
.. py:function:: read_supported_pids(elm) :module: obd_diag.protocol.pids
Alle PIDs, die mindestens ein Steuergerät unterstützt (Vereinigung).
Fragt 0100 und folgt der Kette (0120, 0140 …), solange ein Steuergerät
das Bit für den nächsten Block setzt, höchstens bis 01C0. NO DATA ergibt
eine leere Menge (bzw. beendet die Kette). Jede Nachricht zählt einzeln; Antworten
ohne 41 <base> oder mit weniger als vier Datenbytes (z. B. 7F 01 12)
werden ignoriert. Die Block-PIDs selbst (0x20, 0x40, …) sind im Ergebnis enthalten.
ElmError bei Adapterfehlern geht an den Aufrufer.
.. py:function:: read_values(elm, specs) :module: obd_diag.protocol.pids
Werte derselben PID mit einer Anfrage, je Schlüssel.
Jeder Wert kommt vom ersten Steuergerät, das ihn gültig meldet: eine Nachricht
41 <pid> mit mindestens spec.size Datenbytes (überzählige werden
ignoriert), deren Dekodierung nicht None ist. None bei NO DATA,
Ablehnung (7F 01 xx), zu kurzer Antwort oder ungültigem Wert; ElmError
bei Adapterfehlern geht an den Aufrufer. Vermischen sich mehrteilige Antworten
mehrerer Steuergeräte, wird die Anfrage einmal mit Headern (ATH1) wiederholt;
gelingt auch das nicht, bleiben die Werte None (TransportError, wenn sich
ATH0 nicht wiederherstellen lässt, geht durch). Verschiedene PIDs in specs sind ein
Programmierfehler (ValueError), ebenso eine leere Liste.
.. py:function:: read_value(elm, spec) :module: obd_diag.protocol.pids
Ein Wert (siehe read_values).
obd_diag.protocol.vehicle_info¶
.. py:module:: obd_diag.protocol.vehicle_info
Mode 09 (Fahrzeuginformationen) je Steuergerät: Name, Kalibrierungs-IDs, CVN und
Überwachungszähler (In-Use Performance Tracking). Die FIN (InfoType 02) liest
services.vehicle.read_vin.
Aufbau der Antworten nach SAE J1979 / ISO 15031-5 (Übersicht in Wikipedia „OBD-II PIDs“,
Service 09, abgerufen 2026-10-11; das Beispiel 09 04 im Datenblatt ELM327DSJ S. 43):
49 00 AA BB CC DD: unterstützte InfoTypes 01 bis 20, Bit 7 von A = 01.49 04 NN+ NN Kalibrierungs-IDs (CALID) zu je 16 ASCII-Zeichen, hinten mit 00 aufgefüllt.49 06 NN+ NN Kalibrierungs-Prüfnummern (CVN) zu je 4 Bytes, als Hex angezeigt.49 08 NNbzw.49 0B NN+ NN Zähler zu je 2 Bytes (Otto- bzw. Dieselmotor): OBDCOND, IGNCNTR, dann je Monitor ein Paar „Test abgeschlossen“ / „Bedingungen erfüllt“ (SPARK_COUNTERS,COMPRESSION_COUNTERS).49 0A 01+ 20 ASCII-Zeichen Steuergerätename (ECM+ 00,-, Langname).
NN ist bei CAN die Zahl der Datenelemente (ISO 15765-4). Bei den älteren Protokollen (J1850, ISO 9141, KWP) steht an dieser Stelle eine laufende Nummer, und jede Nachricht trägt 4 Datenbytes; die Daten werden dann nach Nummer aneinandergehängt.
Weil mehrere Steuergeräte antworten und ohne Header die Reihenfolge der Antworten
wechselt (beim W177 bei jeder Anfrage anders), liest read_ecu_info alles mit Headern
(ATH1) und ordnet nach Absender.
.. py:class:: PerformanceCounter(key, completed, conditions) :module: obd_diag.protocol.vehicle_info
Bases: :py:class:object
Ein Monitor im In-Use Performance Tracking: wie oft der Test abgeschlossen wurde und wie oft die Fahrbedingungen dafür gegeben waren.
.. py:property:: PerformanceCounter.name :module: obd_diag.protocol.vehicle_info :type: str
Deutsche Bezeichnung (msgid); zur Anzeige ``tr(counter.name)``.
.. py:property:: PerformanceCounter.ratio :module: obd_diag.protocol.vehicle_info :type: float | None
Überwachungsquote abgeschlossen / Bedingungen; ``None`` ohne Bedingungen.
.. py:class:: InUsePerformance(compression_ignition: bool, obd_conditions: int, ignition_cycles: int, counters: tuple[obd_diag.protocol.vehicle_info.PerformanceCounter, …] = ()) :module: obd_diag.protocol.vehicle_info
Bases: :py:class:object
.. py:class:: EcuInfo(ecu, name=None, calibration_ids=(), cvns=(), performance=None, supported=()) :module: obd_diag.protocol.vehicle_info
Bases: :py:class:object
Was ein Steuergerät über Mode 09 meldet; nicht gemeldete Angaben bleiben leer.
.. py:function:: parse_supported(message) :module: obd_diag.protocol.vehicle_info
InfoTypes aus 49 00 AA BB CC DD (Legacy mit Nummer davor); sonst None.
.. py:function:: parse_calibration_ids(messages) :module: obd_diag.protocol.vehicle_info
InfoType 04: Kalibrierungs-IDs eines Steuergeräts (leere übersprungen).
.. py:function:: parse_cvns(messages) :module: obd_diag.protocol.vehicle_info
InfoType 06: Kalibrierungs-Prüfnummern als 8 Hex-Ziffern (z. B. 1A2B3C4D).
.. py:function:: parse_ecu_name(messages) :module: obd_diag.protocol.vehicle_info
InfoType 0A: z. B. ECM-EngineControl; None bei leerem Namen.
.. py:function:: parse_performance(info_type, messages) :module: obd_diag.protocol.vehicle_info
InfoType 08 (Otto) oder 0B (Diesel): Überwachungszähler.
Gelesen werden OBDCOND, IGNCNTR und so viele Paare, wie gemeldet sind (J1979:
16, 18 oder 20 Werte, ältere Steuergeräte weniger); mehr Paare als bekannt oder eine
ungerade Zahl von Werten sind ein ValueError.
.. py:function:: read_ecu_info(elm) :module: obd_diag.protocol.vehicle_info
Mode 09 je Steuergerät, sortiert nach Adresse; None ohne Mode-09-Antwort.
Fragt 0900 und dann jeden InfoType aus READ_INFO_TYPES, den mindestens ein
Steuergerät als unterstützt meldet, alles in einem Block mit Headern (ATH1 …
ATH0). Lehnt ein Steuergerät ab oder ist seine Antwort nicht normgerecht, fehlt
nur diese Angabe (mit Log-Eintrag). ElmError, wenn schon 0900 unlesbar ist;
TransportError bricht ab.
obd_diag.protocol.monitor_tests¶
.. py:module:: obd_diag.protocol.monitor_tests
Mode 06: Ergebnisse der On-Board-Überwachungstests mit Grenzwerten (nur CAN).
Aufbau nach SAE J1979 / ISO 15031-5 für ISO 15765-4 (CAN):
06 00,06 20…06 E0: unterstützte Monitor-IDs (OBDMID), Antwort46 <MID> AA BB CC DDwie bei Mode 01 PID 00; das letzte Bit meldet den nächsten Bereich.06 <MID>: Antwort46und je Test 9 Bytes<MID> <TID> <UASID> <Wert 2> <Min 2> <Max 2>. Die Test-ID (TID) ist unter $80 genormt, ab $80 legt sie der Hersteller fest. Die UASID (Unit and Scaling ID) sagt, wie die drei Zahlen umzurechnen sind (UNITS): $01 bis $7F ohne Vorzeichen, $80 bis $FE mit Vorzeichen (Zweierkomplement). Bestanden ist ein Test, wenn Min ≤ Wert ≤ Max.
Die Namen der Monitor-IDs folgen J1979 Anhang D, die Umrechnungen Anhang E; beides
gegengeprüft mit python-OBD (obd/commands.py Mode 06, obd/UnitsAndScaling.py),
siehe tests/verification/test_monitor_tests_differential.py.
Ältere Protokolle (J1850, ISO 9141, KWP) haben für Mode 06 ein anderes, nicht genormt
umrechenbares Format; read_test_results liefert dort None.
.. py:class:: Unit(scale, unit=’’, offset=0.0) :module: obd_diag.protocol.monitor_tests
Bases: :py:class:object
Umrechnung einer UASID: Wert = Rohwert · scale + offset.
.. py:function:: is_signed(uasid) :module: obd_diag.protocol.monitor_tests
UASID $80 bis $FF: Werte mit Vorzeichen (J1979 Anhang E).
.. py:function:: mid_name(mid) :module: obd_diag.protocol.monitor_tests
Bezeichnung einer Monitor-ID in der eingestellten Sprache.
.. py:function:: tid_name(tid) :module: obd_diag.protocol.monitor_tests
Bezeichnung einer Test-ID; ab $80 herstellerspezifisch.
.. py:class:: TestStatus(*values) :module: obd_diag.protocol.monitor_tests
Bases: :py:class:~enum.StrEnum
.. py:class:: TestResult(ecu, mid, tid, uasid, value_raw, min_raw, max_raw) :module: obd_diag.protocol.monitor_tests
Bases: :py:class:object
Ein Testergebnis aus Mode 06, roh gespeichert und bei Bedarf umgerechnet.
.. py:property:: TestResult.value :module: obd_diag.protocol.monitor_tests :type: float | None
Umgerechneter Wert; ``None`` bei unbekannter UASID.
.. py:property:: TestResult.decimals :module: obd_diag.protocol.monitor_tests :type: int
Sinnvolle Nachkommastellen zur Anzeige: so viele, wie die Auflösung hat.
.. py:property:: TestResult.status :module: obd_diag.protocol.monitor_tests :type: ~obd_diag.protocol.monitor_tests.TestStatus
``TestStatus``; verglichen wird mit den Rohwerten samt Vorzeichen, so geht das
auch bei unbekannter UASID (die Umrechnung ist immer steigend).
.. py:function:: parse_supported(message, base) :module: obd_diag.protocol.monitor_tests
MIDs aus 46 <base> AA BB CC DD; None, wenn die Nachricht nicht passt.
.. py:function:: parse_results(message, mid) :module: obd_diag.protocol.monitor_tests
Testergebnisse aus 46 + Blöcken zu 9 Bytes; ValueError, wenn die Länge
nicht aufgeht oder ein Block eine andere MID trägt als angefragt.
.. py:function:: read_test_results(elm) :module: obd_diag.protocol.monitor_tests
Mode 06 aller Steuergeräte, nach Absender, MID und Reihenfolge der Antwort.
None, wenn kein Steuergerät Mode 06 beantwortet oder das Protokoll kein CAN
ist; eine leere Liste, wenn MIDs gemeldet sind, aber keine lesbaren Ergebnisse
kommen. Alles läuft in einem Block mit Headern (ATH1 … ATH0), damit jedes
Ergebnis seinem Steuergerät zugeordnet ist. Lehnt ein Steuergerät eine MID ab
(7F 06 xx) oder ist eine Antwort nicht normgerecht, fehlt nur diese (mit
Log-Eintrag). ElmError, wenn schon die unterstützten MIDs unlesbar sind.