Technische Dokumentation
OBD-Adapter-BRIDGE V2
Paket V2.1 · Bridge v3.1 · Receiver v1.3 · Simulator v1.1 · GUI v2.1 · © 2026 Ralf Burger · GPL v3
StandMärz 2026
HardwareHeltec WiFi LoRa 32 (V3)
LizenzGPL v3

Überblick

Das OBD-Adapter-BRIDGE-Projekt liest Fahrzeugdaten über einen handelsüblichen BLE-OBD-Dongle aus und stellt sie gleichzeitig auf drei unabhängigen Kanälen bereit: OLED-Display, TCP/WLAN und LoRa-Funk. Smartphone, App oder Abo sind nicht erforderlich.

Das System besteht aus vier eigenständigen Modulen, die über gemeinsame Header-Dateien (Symlinks) konfiguriert werden. Alle Module sind über ein einheitliches Telnet-CLI steuerbar — entweder per USB-Serial oder per TCP auf Port 1234.

Open Source · GPL v3. Alle Quelltexte können frei verwendet, verändert und weitergegeben werden — unter der Bedingung, dass Derivate ebenfalls unter GPL v3 veröffentlicht werden. Kontakt: ralf@RalfBurger.com

Voraussetzungen

Hardware

ModulHardwareChipHinweis
MOD-01 BridgeHeltec WiFi LoRa 32 (V3)ESP32-S3 + SX1262SSD1306 OLED onboard
MOD-02 ReceiverHeltec WiFi LoRa 32 (V3)ESP32-S3 + SX1262Identische Hardware wie MOD-01
MOD-03 GUIPC / Linux / macOS / WindowsPython 3, tkinter
MOD-04 SimulatorESP32 WROOM-32 + MCP2515ESP32 + TJA1050CAN-Transceiver TJA1050
DongleBLE-OBD-II-DongleELM327-kompatibelUUID 0x18F0 / 0xFFE0 / 0xFFF0 …

Software / Entwicklungsumgebung

Quickstart

  1. Datei wifi_config.h im Projektroot mit eigenen WLAN-Daten befüllen (SSID, Passwort, AP-Credentials)
  2. Bridge flashen: obd_identify.sh erkennt den Port automatisch, dann obd_flash.sh bridge
  3. Heltec starten, OLED zeigt Bootsequenz — Bridge verbindet sich ins WLAN oder öffnet eigenen AP (192.168.4.1)
  4. Mit nc <IP> 1234 verbinden und live on eingeben — Fahrzeugdaten werden live ausgegeben
  5. Python-GUI starten: python3 obd_gui2.py --bridge <IP>
  6. Optionaler LoRa-Receiver: Receiver-Firmware flashen, zweites Heltec-Board starten
Ohne Fahrzeug: Bridge im Demo-Modus starten (demo-Befehl im CLI) oder MOD-04 Simulator verwenden. Der Simulator antwortet auf alle OBD-Anfragen des Dongles via CAN-Bus.

Systemaufbau

Alle Verbindungen laufen über offene Protokolle auf Standard-Hardware. Der Simulator ermöglicht vollständige Tests ohne laufendes Fahrzeug.

Fahrzeug
OBD-II
BLE-Dongle
BLE / NimBLE
MOD-01
obd_bridge
Heltec LoRa V3
TCP 1234
MOD-03
Python GUI
obd_gui2.py
LoRa 868 MHz
MOD-02
obd_lora_receiver
Heltec LoRa V3

Gestrichelt: optionaler Test-Pfad — MOD-04 (Simulator + MCP2515) ersetzt das Fahrzeug via CAN-Bus.

Kommunikationskanäle

KanalProtokollPort / FrequenzRichtung
BLENimBLE 1.4.x (GATT Client)2,4 GHzDongle → Bridge
TCPRohdaten-Stream + CLI1234Bridge/Receiver → PC/GUI
HTTPEinfacher JSON-/HTML-Server80Bridge/Receiver → Browser
LoRaSX1262, Extended-Pakete (TLV)868 MHz, SF7Bridge → Receiver
SerialUART CLI (identisch zu TCP)115200 BdPC ↔ µC (USB)
CANISO 15765-4, 500 kBit/sSimulator → OBD-Dongle

Symlinks & Shared Headers

Drei Konfigurationsdateien sind als Symlinks realisiert, damit alle Module stets denselben Stand haben. Es gibt einen einzigen Änderungspunkt: die echten Dateien liegen in src/obd_bridge/ bzw. src/wifi_config.h.

Symlink-PfadZielInhalt
obd_lora_receiver/wifi_config.h../wifi_config.hSSID, Passwort, AP-Credentials, TCP-Port
obd_simulator/wifi_config.h../wifi_config.hSSID, Passwort, AP-Credentials, TCP-Port
obd_bridge/wifi_config.h../wifi_config.hSSID, Passwort, AP-Credentials, TCP-Port
obd_lora_receiver/pid_registry.h../obd_bridge/pid_registry.hPID-Enum, Tabelle, Prioritäten, Scaling
obd_lora_receiver/pid_registry.cpp../obd_bridge/pid_registry.cppPID-Implementierung (43 Einträge)
obd_lora_receiver/http_server.h../obd_bridge/http_server.hHTTP-Server-Implementierung
Wichtig beim Archivieren: Beim Packen mit tar bleiben Symlinks automatisch erhalten. ZIP-Tools lösen Symlinks in der Regel auf — daher immer tar -czf projekt.tgz ... verwenden.

wifi_config.h — Struktur

// wifi_config.h — gemeinsam für Bridge, Receiver, Simulator
#define WIFI_SSID     "MeinHeimnetz"
#define WIFI_PASS     "meinPasswort"
#define AP_SSID       "obdBT-Bridge"
#define AP_PASS       "obd12345"
#define TCP_PORT      1234
#define HTTP_PORT     80

PID-Registry

Die Datei pid_registry.h/.cpp definiert alle 43 OBD-PIDs zentral. Bridge und Receiver teilen sich dieselbe Tabelle über Symlinks — ein Sync-Fehler zwischen den µCs ist damit strukturell ausgeschlossen.

Jeder Eintrag enthält: OBD-Modus und PID-Byte, Anzeigename, Einheit, Scaling-Faktor (×1 / ×10 / ×100), Priorität (HIGH / MED / LOW) und Gruppe (Motor, Kraftstoff, Abgas, Zündung, Fehler, Info). Der Blind-Scan beim Start testet automatisch, welche PIDs das angeschlossene Fahrzeug unterstützt.

MOD-01 · obd_bridge

Heltec WiFi LoRa 32 (V3) · ESP32-S3 · SX1262

Die Bridge ist das Kernmodul. Sie verbindet sich per BLE mit dem OBD-Dongle, liest alle verfügbaren PIDs in einem Prioritätspoller aus und stellt die Daten gleichzeitig auf OLED, TCP und LoRa bereit. Das Polling läuft dauerhaft und unabhängig von aktiven TCP-Verbindungen.

BLE-Client

Die Bridge scannt eigenständig nach BLE-OBD-Dongles. Beim Start durchsucht sie alle in Reichweite befindlichen Geräte nach bekannten Service-UUIDs:

UUIDProfil
0x18F0Standard BLE OBD (häufigster Typ)
0xFFE0Alternativer OBD-Service
0xFFF0ELM327-kompatibel Typ 2
0xAE30Herstellerspezifisch Typ A
0xAE3AHerstellerspezifisch Typ B

Bei Verbindungsverlust startet automatisch ein erneuter Scan. Ein Hardware-Watchdog (60 s Timeout, esp_task_wdt) verhindert, dass die Bridge dauerhaft hängt.

TCP & HTTP

Die Bridge öffnet nach dem WLAN-Connect einen TCP-Server auf Port 1234. Mehrere gleichzeitige Clients sind möglich. Das Protokoll ist Klartext (UTF-8): Zeilenpräfixe BSC (Basis-PIDs) und EXT (erweiterte PIDs) kennzeichnen die Datenzeilen.

Auf Port 80 läuft ein minimaler HTTP-Server, der eine JSON-Statusseite und eine einfache HTML-Übersicht liefert. Konfiguriert über http_server.h.

WiFi-Verhalten: Die Bridge versucht sich zuerst ins konfigurierte Heimnetz (STA) einzubuchen. Schlägt das nach dem Timeout fehl, öffnet sie automatisch einen eigenen Access-Point (192.168.4.1).

LoRa TX

Die Bridge sendet ausschließlich Extended-Pakete (Typ 0x03, TLV-Format) mit allen aktiven PIDs. Das Sendeintervall wird dynamisch aus der tatsächlichen Airtime berechnet (Semtech-Formel), sodass der 1%-Duty-Cycle für DE/EU (868 MHz, SRD-Band) zu keiner Zeit überschritten wird.

Zusätzlich wird beim Start ein Config-Paket (Typ 0x02) gesendet, das dem Receiver die aktuellen LoRa-Parameter mitteilt (SF, Region, Sendeleistung).

OLED-Display

Das SSD1306-Display (128×64 Pixel, I²C) zeigt bis zu 5 konfigurierbare Seiten. Ein Button steuert kurzen Druck (Seite blättern) und langen Druck (aktuelle Seite fixieren). Die Helligkeit ist per CLI-Befehl dim 0..255 regelbar; dim 0 versetzt das Display in den Sleep-Modus (SSD1306 Display-Off).

Jede Seite zeigt unten links ein Status-Cluster (B/R · ST/AP/-- · OBD/SIM/---) und rechts unten den Page-Indicator (Punkte). Fehlerzustände blinken als !.

RPM km/h 3142 87 91°C 13.8V Ld45% B ST OBD
Bridge · Page 1 · RPM+Speed
Thermik & Druck KWT: 91°C IAT: 22°C MAP: 68 kPa Last:45.2% B ST OBD
Bridge · Page 2 · Thermik
TPS/Volt/Akku TPS: 45.2% Ubat:13.82V Akku:3.84V 72% SF7 868MHz TX#42 B ST OBD
Bridge · Page 3 · TPS/Volt
Rohdaten PID: 010C Resp: 41 0C 31 14 192.168.28.97 B ST OBD
Bridge · Page 4 · Rohdaten+IP
RPM km/h 2340 74 88°C 13.8V Ld34% B ST SIM
Bridge · Demo-Modus · SIM
RPM km/h 3142 87 91°C 13.8V 45% RSSI:-68 SNR:9 R ST OBD
Receiver · Page 1 · RPM+Speed
Pakete & Netz BSC:128 EXT:127 Vl:0 Err:0 CFG:1 Letztes: vor 2s 192.168.28.78 R ST OBD
Receiver · Page 4 · Statistik
RPM km/h ---- --- --°C --.--V --% Warte auf Sender R ST ---!
Receiver · Kein Signal · Fehler!

Die Punkte unten rechts zeigen die aktuelle Seite (ausgefüllt). Das Status-Cluster unten links: B=Bridge / R=Receiver · ST=WLAN-Client / AP=Access Point / --=kein WLAN · OBD=Fahrzeugdaten / SIM=Simulation / ---=keine Daten. ! blinkt bei Fehler.

CLI-Befehle (Bridge)

BefehlWirkung
System
help / ?Alle Befehle auflisten
info Alias: status, sBLE-, WLAN-, LoRa-, OBD-Status, Akku, Statistik
version Alias: verBuild-Zeitstempel und Sketch-Mtime ausgeben
debugDebug-Ausgaben auf Serial/TCP ein-/ausschalten
demoDemo-Modus ein-/ausschalten (simulierte PIDs)
reboot Alias: restartµC neu starten
BLE
scanNeuen BLE-Scan starten, Gerät wählen
disco Alias: disconnectBLE-Verbindung trennen, neuer Scan
OBD / PIDs
pid listAlle PIDs mit Gruppe, Priorität, Aktivstatus anzeigen
pid statusGruppenübersicht + LoRa-Paketgröße + Duty-Cycle
pid scanCapability-Scan (0100–0160) neu starten
pid enable <grp/id/all>PID(s) aktivieren · Gruppen: motor kraftstoff abgas zuendung fehler info all
pid disable <grp/id/all>PID(s) deaktivieren
pid blind on/offBlindscan: PIDs ohne Cap-Bit-Bestätigung abfragen
pid intervalLoRa-Sendeintervall aus aktueller Paketgröße neu berechnen
pid profile fastNur Kern-PIDs: RPM, Speed, Temp, MAP, Last, TPS, IAT, Spannung
pid profile fullAlle unterstützten PIDs aktivieren
pid profile customIntervall neu berechnen ohne Profilwechsel
DTC Fehlercodes
dtc Alias: readdtc, dtc readFehlercodes auslesen (Mode 03)
cleardtc Alias: dtc clearFehlerspeicher löschen (Mode 04)
Polling
poll <ms>OBD-Polling-Intervall setzen (100–5000 ms)
poll statusAktuelles Intervall anzeigen
Live-Stream (TCP)
live Alias: lLive-Ausgabe auf TCP umschalten
live on / offLive-Ausgabe explizit ein-/ausschalten
Display (OLED)
next / prevDisplay-Page weiterschalten
page NPage 1–5 direkt anspringen
pagetime NAuto-Cycle: alle N Sekunden weiterschalten (0 = aus)
pagelay R SPage-0 Schriftgröße für RPM (R) und Speed (S), je 1–3
dim NOLED-Helligkeit (0 = aus, 255 = max)
Beeper (lokal)
beep on / offPiezo-Beeper Dauerton ein/aus (GPIO 48)
beep ackDoppelpiep (Bestätigung)
LoRa CTRL → Receiver
ctrl beep on / off / ackReceiver-Beeper per LoRa steuern
ctrl beep pulse D NN Pieps à D×10 ms an Receiver senden
ctrl gpio PINReceiver-GPIO lesen (Antwort per LoRa)
ctrl gpio PIN 0/1Receiver-GPIO setzen
ctrl pingReceiver anpingen
GPIO (lokal)
gpio PINLokalen GPIO-Pin lesen
gpio PIN 0/1Lokalen GPIO-Pin setzen
LoRa
lora statusFrequenz, SF, Power, Intervall, TX-Zähler anzeigen
lora sf7 … sf12Spreading Factor setzen (beide Seiten müssen gleich sein)
lora de / eu / intRegion: DE/EU = 868 MHz 14 dBm · INT = 915 MHz 20 dBm
lora pw<N>Sendeleistung 2–22 dBm (z. B. lora pw14)

MOD-02 · obd_lora_receiver

Heltec WiFi LoRa 32 (V3) · ESP32-S3 · SX1262

Der Receiver empfängt die LoRa-Pakete der Bridge, dekodiert den TLV-Payload und stellt die Werte auf seinem eigenen OLED sowie per TCP auf Port 1234 bereit. Er benötigt keine direkte Verbindung zum Fahrzeug oder zum Dongle.

LoRa RX & Paket-Dekodierung

Der Receiver empfängt Extended-Pakete (Typ 0x03) und Config-Pakete (Typ 0x02). Extended-Pakete werden per TLV dekodiert — jeder Tag entspricht einem PID-Index aus der gemeinsamen pid_registry. Eine Sequenznummer ermöglicht die Zählung verlorener Pakete.

Das OLED zeigt 5 Seiten; Seite 4 scrollt durch alle empfangenen Extended-PIDs. Der Paket-Modus ist per CLI umschaltbar: pkt auto (Standard), pkt basic oder pkt extended.

WiFi-Verhalten: STA ins Heimnetz → bei Fehler automatisch STA in den AP der Bridge (192.168.4.1).

CLI-Befehle (Receiver)

BefehlWirkung
System
status Alias: s, infoLoRa-RSSI, SNR, Paketzähler, WLAN-Status, Akku
version Alias: verBuild-Zeitstempel ausgeben
wifiWLAN-Verbindungsinfo anzeigen
loraLoRa-Parameter anzeigen (SF, Frequenz, RSSI)
reboot Alias: rµC neu starten
PIDs
pid list Alias: pidAlle empfangenen PID-Werte mit Einheit anzeigen
Paketfilter
pkt autoBasic- und Extended-Pakete anzeigen (Standard)
pkt basicNur Basic-Pakete (Typ 0x01) anzeigen
pkt extendedNur Extended-Pakete (Typ 0x03) anzeigen
Live-Stream (TCP)
live Alias: lLive-Ausgabe auf TCP umschalten
live on / offLive-Ausgabe explizit ein-/ausschalten
Display (OLED)
next / prevDisplay-Page weiterschalten
page NPage 1–5 direkt anspringen
pagetime NAuto-Cycle: alle N Sekunden weiterschalten (0 = aus)
pagelay R SPage-0 Schriftgröße für RPM (R) und Speed (S), je 1–3
dim NOLED-Helligkeit (0 = aus, 255 = max)
Beeper (lokal)
beep on / offLokalen Piezo-Beeper dauerhaft ein/aus
beep ackLokaler Doppelpiep (Bestätigung)
beep rx on / offQuittungs-Piep bei jedem empfangenen LoRa-Paket
LoRa CTRL → Bridge
ctrl beep on / off / ackBridge-Beeper per LoRa-Rückkanal steuern
ctrl beep pulse D NN Pieps à D×10 ms an Bridge senden
ctrl gpio PINBridge-GPIO lesen (Antwort kommt per LoRa zurück)
ctrl gpio PIN 0/1Bridge-GPIO setzen
ctrl pingBridge anpingen
GPIO (lokal)
gpio PINLokalen GPIO-Pin lesen
gpio PIN 0/1Lokalen GPIO-Pin setzen

MOD-03 · obd_gui2.py

Python 3 · tkinter · TCP-Client

Das Python-Dashboard verbindet sich per TCP mit der Bridge oder dem Receiver und zeigt die Fahrzeugdaten als animierte Rundinstrumente (Gauges) und Balkenanzeigen an. Es läuft auf jedem Desktop-System mit Python 3 und tkinter.

Starten

# Direkt mit Bridge verbinden (RSSI-Balken ausgeblendet)
python3 obd_gui2.py --bridge <IP-der-Bridge>

# Mit Receiver verbinden (LoRa-RSSI-Balken aktiv)
python3 obd_gui2.py <IP-des-Receivers>

# Style beim Start wählen (1=F1, 2=Sci-Fi, 3=Aviation, 4=Luxury)
python3 obd_gui2.py --bridge <IP> --style 2

Styles & Tastenkürzel

TasteStyleBeschreibung
1F1Dunkles Carbon-Design, rote Akzente
2Sci-FiDunkles Blau/Cyan-Design
3AviationGrau/Amber, Cockpit-Style
4LuxuryHell, Holzton, klassisch
LCSV-Logging ein-/ausschalten (Sentinel-gefiltert)
Q / EscProgramm beenden

Im --bridge-Modus wird der LoRa-RSSI-Balken ausgeblendet, da die Verbindung direkt zur Bridge läuft. CSV-Logging schreibt alle empfangenen Werte mit Zeitstempel in eine Datei; Sentinel-Werte (fehlerhafte Antworten des Dongles) werden automatisch herausgefiltert.

MOD-04 · obd_simulator

ESP32 WROOM-32 · MCP2515 · TJA1050 · CAN 500 kBit/s

Der Simulator emuliert ein Fahrzeug-ECU via CAN-Bus nach ISO 15765-4. Er antwortet auf OBD-II-Anfragen des Dongles, sodass die komplette Toolchain ohne laufendes Fahrzeug getestet werden kann.

Ab dem Boot sendet der Simulator automatisch BSC- und EXT-Live-Pakete mit realistisch simulierten Fahrdynamikwerten (Drehzahl, Geschwindigkeit, Temperatur usw.). Über ein Web-Interface können alle Werte manuell gesetzt werden.

Unterstützte OBD-Modi

ModeFunktionPIDs / Details
01Live-Daten19 PIDs (RPM, Speed, Temp, Last, MAP, TPS, O2, …)
03DTC-Fehlercodes lesenKonfigurierbare DTCs
04DTC-Fehlercodes löschenSetzt MIL-Status zurück
09FahrzeuginfoVIN, Kalibrier-ID, ECU-Name

CLI-Befehle (Simulator)

BefehlWirkung
statusCAN-Status, WLAN, aktuelle Simulationswerte
live on / offAutomatische Live-Pakete ein-/ausschalten
verbose on / offDetailliertes CAN-Logging ein-/ausschalten
set rpm NDrehzahl manuell setzen (0–8000)
set speed NGeschwindigkeit manuell setzen (0–250 km/h)
set temp NKühlmitteltemperatur manuell setzen
rebootµC neu starten

Hardware-Verdrahtung

MOD-01 · Bridge (Heltec WiFi LoRa 32 V3)

Der Heltec LoRa V3 hat SX1262, OLED und LoRa-Antenne bereits onboard. Externe Verdrahtung beschränkt sich auf den Beeper.

GPIOFunktionRichtungHinweis
0BTN (BOOT-Taste)INOnboard, INPUT_PULLUP — kurz: Seite blättern, lang: fixieren
1BAT_ADCINAkkuspannung (ADC1_CH0), intern
9LORA_SCKOUTSX1262 SPI, intern
10LORA_MOSIOUTSX1262 SPI, intern
11LORA_MISOINSX1262 SPI, intern
12LORA_RSTOUTSX1262 Reset, intern
13LORA_BUSYINSX1262 Busy, intern
14LORA_IRQ (DIO1)INSX1262 Interrupt, intern
8LORA_CSOUTSX1262 Chip-Select, intern
17OLED_SDAI²CSSD1306, intern
18OLED_SCLI²CSSD1306, intern
21OLED_RSTOUTSSD1306 Reset, intern
36VEXTOUTExterne 3,3V-Versorgung (OLED), LOW = an
48STATIC_BEEPOUTExtern: Piezo-Beeper direkt an GPIO 48 und GND
Beeper-Anschluss: Statischer Piezo-Summer (kein aktiver Tongenerator nötig) direkt zwischen GPIO 48 und GND. 3,3V Output des ESP32-S3 reicht aus — kein Widerstand, kein Transistor erforderlich. HIGH = Beeper an, LOW = aus.

MOD-02 · LoRa-Receiver (Heltec WiFi LoRa 32 V3)

Identische Hardware wie MOD-01, identische Pin-Belegung. Kein Beeper. Kein externer Anschluss nötig.

MOD-04 · Simulator (ESP32 WROOM-32 + MCP2515)

Der MCP2515 CAN-Controller wird per SPI angebunden. Der TJA1050 CAN-Transceiver ist auf dem MCP2515-Modul (HW-184) bereits integriert.

ESP32 GPIOMCP2515 PinFunktion
18SCKSPI Clock
19SO (MISO)SPI Master In
23SI (MOSI)SPI Master Out
5CSChip-Select (CAN_CS_PIN)
4INTInterrupt (CAN_INT_PIN)
3,3VVCCVersorgung MCP2515-Modul
GNDGNDMasse

OBD-II-Stecker beim Test ohne Fahrzeug

Der BLE-OBD-Dongle wird direkt am Simulator-Board betrieben. Es werden nur die Pins belegt die für CAN-OBD (ISO 15765-4) benötigt werden.

Für den Testaufbau empfiehlt sich ein 3D-gedruckter OBD-II-Stecker (Buchse): Thingiverse Thing 6350647 von TA1GI, lizenziert unter CC BY-SA 4.0. Die Kabel werden direkt an die gewünschten Pins angelötet, Zugentlastung über die Trägerplatte.

OBD-II PinBelegungQuelle
4Chassis GNDGND des Simulator-Netzteils
16+12V (Batterie)12V Netzteil oder Labornetzteil
6CAN-HighCANH des TJA1050 (auf MCP2515-Modul)
14CAN-LowCANL des TJA1050 (auf MCP2515-Modul)
alle anderennicht belegt
Abschlusswiderstand: CAN-Bus benötigt 120Ω zwischen CAN-H und CAN-L an beiden Enden. Das MCP2515-Modul HW-184 hat einen Jumper (R2) für den Abschlusswiderstand — sicherstellen dass er gesetzt ist. Beim Dongle ist in der Regel ebenfalls ein 120Ω-Widerstand intern verbaut.

CAN-Bus Diagnose

Bei CAN ERROR vom Dongle oder ausbleibenden OBD-Antworten systematisch vorgehen:

Schritt 1 — Simulator-Hardware prüfen (Loopback-Test)

Im Simulator per Serial oder Telnet:

can test loopback

Erwartete Ausgabe: [CAN-TEST] Loopback: OK — MCP2515, SPI und TX/RX-Puffer funktionieren. Schlägt dieser Test fehl, liegt das Problem am Simulator-Board selbst (SPI-Verdrahtung, Stromversorgung, Quarz).

Schritt 2 — Spannungen messen (Multimeter)

CAN-Bus im Ruhezustand (kein aktiver Traffic) hat definierte Ruhepegel:

MessungSollwertAbweichung bedeutet
CAN-H gegen GND~2.5 V0 V = Leitung unterbrochen oder kurzgeschlossen gegen GND
CAN-L gegen GND~2.5 V5 V = Leitung kurzgeschlossen gegen VCC
CAN-H gegen CAN-L~0 V>0.5 V = Bus aktiv oder Terminierung fehlt
Messstrategie bei CAN ERROR: Immer an beiden Enden messen — am MCP2515-Modul und am OBD-Stecker bzw. Dongle-Anschluss. Ein korrekter Wert am Board bei falschem Wert am Stecker zeigt einen Fehler in der Verbindung (Stecker, Crimping, Kabelbruch). Typischer Befund: CAN-H und CAN-L am Board korrekt (~2.5 V), aber am Stecker CAN-H = 0 V und CAN-L = 2.4 V — H und L im Stecker vertauscht.

Schritt 3 — Häufige Fehler

SymptomUrsacheLösung
CAN ERROR, Loopback OKCAN-H/L zwischen Dongle und MCP2515 vertauschtStecker prüfen, Spannung an beiden Enden messen
CAN ERROR, Loopback OKAbschlusswiderstand fehlt120Ω-Jumper am MCP2515-Modul prüfen
CAN ERROR, Loopback OKGND nicht durchverbundenGND Dongle ↔ MCP2515 ↔ Netzteil prüfen
CAN ERROR, Loopback FEHLERMCP2515 nicht erreichbarSPI-Pins, CS-Pin, 3.3V/5V, Quarz 8MHz prüfen
Dongle verbindet nicht per BLEKein CAN-Bus → Dongle bleibt in Fehler-LEDErst CAN-Verbindung herstellen, dann BLE-Verbindung kommt automatisch
ATSP6 schlägt fehlFalsches CAN-ProtokollSimulator läuft auf ISO 15765-4 500kbit/s (ATSP6) — Dongle-Einstellung prüfen

Taster-Belegung

ModulTasterGPIOKurzdruckLanger Druck (>1s)
BridgeBOOT (onboard)0Display-Seite blätternAktuelle Seite dauerhaft fixieren
ReceiverBOOT (onboard)0Display-Seite blätternAktuelle Seite dauerhaft fixieren
Simulatorkein Taster implementiert

Freie GPIOs (Bridge & Receiver)

Folgende GPIOs des Heltec LoRa V3 sind im aktuellen Code nicht belegt und für Erweiterungen verfügbar:

GPIOHinweis
2, 3Frei, ADC-fähig
4, 5, 6, 7Frei, digitale I/O
15, 16Frei — Hinweis: Boot-Strapping-Pins, mit Vorsicht verwenden
19, 20Frei (USB D-/D+, nur verwenden wenn kein USB-CDC genutzt wird)
26, 33, 34, 35Frei, digitale I/O
37, 38Frei, ADC-fähig
45, 46, 47Frei — Hinweis: Strapping-Pins, beim Boot beachten

Flash-Workflow

Das Projekt enthält zwei Shell-Skripte, die den Flash-Prozess automatisieren: obd_identify.sh erkennt die angeschlossenen Module und obd_flash.sh kompiliert und flasht.

obd_identify.sh

Das Skript liest die USB-Gerätebeschreibungen aus und vergleicht sie mit bekannten Heltec- und ESP32-Signaturen. Es gibt für jedes erkannte Modul den fertigen Flash-Befehl aus — inklusive korrektem Port.

# Alle angeschlossenen Module anzeigen
./obd_identify.sh

# Beispielausgabe:
[PORT]  /dev/ttyUSB0  →  Heltec LoRa V3  (Bridge)
[PORT]  /dev/ttyUSB1  →  Heltec LoRa V3  (Receiver / Bridge?)
[CMD]   obd_flash.sh bridge --port /dev/ttyUSB0

obd_flash.sh

Kompiliert das jeweilige Modul mit arduino-cli und flasht es. Der Build-Zeitstempel wird als Compiler-Define ins Binary eingebettet (BUILD_TIME, SKETCH_MTIME) und ist per version-Befehl abrufbar.

# Bridge flashen (Port automatisch erkannt)
./obd_flash.sh bridge

# Bridge mit explizitem Port
./obd_flash.sh bridge --port bridge=/dev/ttyUSB0

# Receiver flashen
./obd_flash.sh receiver

# Simulator flashen
./obd_flash.sh simulator

# Remote-Flash: Kompilierung auf PC1, Flash über SSH auf PC2
./obd_flash.sh bridge --ssh user@pc2
Partition Scheme: Alle Heltec-Module benötigen das Scheme Huge APP (3 MB Flash, no OTA), da die Bridge-Firmware mit NimBLE, LoRa und WLAN die Standard-Partitionsgröße überschreitet.

PID-Tabelle (alle 43)

Die vollständige Tabelle aus pid_registry.h/.cpp. Scale: ×1 = Ganzzahl, ×10 = eine Dezimalstelle, ×100 = zwei Dezimalstellen (TLV-Scaling).

IDXOBD-IDNameEinheitScaleGruppePrio
00010CRPM1/min×1MotorHIGH
01010DSpeedkm/h×1MotorHIGH
020105Kuehlmittel°C×10MotorHIGH
03010FAnsaugluft°C×10MotorMED
04010BMAPkPa×10MotorHIGH
050104Motorlast%×100MotorHIGH
060111TPS%×100MotorMED
08012FTankfuellstand%×100KraftstoffLOW
09015EVerbrauchL/h×100KraftstoffMED
100110MAFg/s×100KraftstoffMED
110133BarokPa×10KraftstoffLOW
120143AbsTPS%×100KraftstoffMED
130145RelTPS%×100KraftstoffMED
140149Gaspedal%×100KraftstoffMED
15014CSchubventil%×100KraftstoffMED
180114O2_B1S1_VV×100AbgasMED
190115O2_B1S2_VV×100AbgasMED
200116O2_B1S3_VV×100AbgasLOW
210117O2_B1S4_VV×100AbgasLOW
220124O2_B1S1_WBλ×100AbgasMED
230125O2_B1S2_WBλ×100AbgasMED
240144Lambdaλ×100AbgasMED
250146Umgebungsluft°C×10AbgasLOW
26014BKruemmerdruckkPa×10AbgasMED
27010EZuendwinkelKW×10ZündungMED
280142ECU_SpannungV×100ZündungMED
29015COeltemp°C×10ZündungLOW
30015DEinspritzdruckkPa×100ZündungMED
310167Kuehlmittel2°C×10ZündungLOW
330101MIL_Status×1FehlerHIGH
340121Dist_MIL_ankm×1FehlerLOW
350130Warmlaufzyklen×1FehlerLOW
360131Dist_Resetkm×1FehlerLOW
37014DZeit_MIL_anmin×1FehlerLOW
38014EZeit_Resetmin×1FehlerLOW
390151Kraftstofftyp×1InfoLOW
400902VINInfoLOW
410904KalibIDInfoLOW
42090AECU_NameInfoLOW

TCP-Protokoll

Alle Daten werden als UTF-8-Klartext auf Port 1234 übertragen. Der Stream enthält abwechselnd BSC- und EXT-Zeilen, getrennt durch \n.

# BSC-Zeile (Basis-PIDs, hohe Priorität)
BSC RPM:2847 SPD:92 T:91 Ld:38.4 MAP:102 V:13.82 TX#1247

# EXT-Zeile (erweiterte PIDs)
EXT Ansaugluft:34 TPS:22.35 Gaspedal:28.62 Zuendwinkel:12.0 Lambda:1.000 Oeltemp:82

# Status-/Info-Zeile (kein festes Format)
[INFO] BLE connected: OBD-DONGLE-BT  RSSI:-58

CLI-Eingaben werden auf derselben TCP-Verbindung gesendet und mit \n abgeschlossen. IAC-Bytes (Telnet-Steuersequenzen) werden automatisch herausgefiltert — die Verbindung ist damit vollständig telnet-kompatibel.

LoRa-Paketformat

Alle LoRa-Pakete beginnen mit einem 1-Byte-Typ-Feld. Aktuell verwendet werden Typ 0x02 (Config) und Typ 0x03 (Extended / TLV).

Extended-Paket (Typ 0x03)

Byte 0:  0x03            Pakettyp Extended
Byte 1:  SeqNr           Sequenznummer (uint8, rollover)
Byte 2:  N               Anzahl TLV-Einträge

# TLV-Eintrag (wiederholt N-mal):
Byte k+0: Tag             PID-Index (aus pid_registry, 0–42)
Byte k+1: Len             Länge Value (1 oder 2 Bytes)
Byte k+2: Value[Len]      Skalierter Wert (int16, Big-Endian)

Der tatsächliche Wert ergibt sich durch Division mit dem Scale-Faktor aus der PID-Registry: Wert = Value / Scale.

Config-Paket (Typ 0x02)

Byte 0:  0x02            Pakettyp Config
Byte 1:  SF              Spreading Factor (7–12)
Byte 2:  Region          0x01 = EU868, 0x02 = US915
Byte 3:  Power           Sendeleistung in dBm

Verzeichnisstruktur & Deployment

Das Archiv OBD.tgz entpackt sich direkt in das Webserver-Verzeichnis. Nach dem Entpacken nach / liegt die Website unter /OBD/, die Quelldateien unter /OBD/src/.

Verzeichnisstruktur nach dem Entpacken

/OBD/
├── index.shtml          # Einstiegspunkt (SSI-Includes)
├── includes/            # Website-Bausteine (nav, hero, story, …)
├── images/              # Fotos, Screenshots, friese.png, friese.jpg
├── favicon.ico          # Favicon (Friese, 16×16 + 32×32)
├── favicon.png          # Favicon als PNG (32×32)
├── doku.html            # Diese Dokumentation
├── .htaccess            # Apache SSI + Kompression
├── LICENSE              # GPL v3 (englisch, rechtsverbindlich)
├── LICENSE.de           # GPL v3 (deutsch, nicht rechtsverbindlich)
├── OBD.tgz              # Komplettarchiv (hier ablegen für Download-Link)
└── src/
    ├── wifi_config.h    # Gemeinsame Konfiguration (SSID, AP, TCP-Port)
    ├── obd_flash.sh     # Flash-Script (erkennt src/-Struktur automatisch)
    ├── obd_identify.sh  # Modul-Erkennung an USB-Ports
    ├── obd_gui2.py      # Python-Dashboard
    ├── obd_bridge/      # Bridge-Firmware + echte Header-Dateien
    ├── obd_lora_receiver/ # Receiver-Firmware + Symlinks auf obd_bridge/
    └── obd_simulator/   # Simulator-Firmware + Symlink auf wifi_config.h

Deployment auf Apache

# 1. Archiv entpacken
cd /
tar -xzf OBD.tgz

# 2. Rechte setzen
bash /OBD/src/fix_permissions.sh

# 3. Apache mod_include aktivieren
a2enmod include
systemctl restart apache2

# 4. VHost: AllowOverride All  (damit .htaccess greift)
# 5. OBD.tgz in /OBD/ ablegen (für den Download-Link auf der Seite)
cp OBD.tgz /OBD/

# Aufruf: https://deinedomain.de/OBD/

Rechte setzen (fix_permissions.sh)

Das Script src/fix_permissions.sh setzt alle Rechte kollisionsfrei für den Webserver: Verzeichnisse 755, Dateien 644, Shell- und Python-Scripts 755.

cd /
sudo bash /OBD/src/fix_permissions.sh

Nginx (Alternative)

# nginx.conf — SSI aktivieren
location /OBD/ {
    ssi on;
    ssi_silent_errors on;
}

Lokaler Test mit Docker

docker run -p 8080:80 \
  -v $(pwd)/OBD:/usr/local/apache2/htdocs/OBD \
  httpd:alpine
# Aufruf: http://localhost:8080/OBD/index.shtml

Website-Features

Die Website enthält mehrere interaktive Elemente, die clientseitig per JavaScript realisiert sind — kein externes Framework, kein CDN.

Animierte Rundinstrumente (Hero-Bereich)

Im Hero-Bereich laufen 6 Canvas-Rundinstrumente mit simulierten OBD-Werten: Drehzahl, Speed, Kühlmitteltemperatur, Motorlast, MAP und ECU-Spannung. Jedes Instrument zeigt eine vollständige Rundinstrumenten-Skala mit Skalenstrichen, Beschriftung, farbigem Warnbereich und einem feinen beweglichen Zeiger. Der Zeiger wechselt bei Grenzwertüberschreitung auf Orange bzw. Rot. Die Simulation läuft dauerhaft im Hintergrund — ohne Server, ohne WebSocket.

Lightbox

Alle Bilder auf der Seite — Fotos, Screenshots und der Friese — sind klickbar und öffnen eine Lightbox in voller Größe. Klick auf den Hintergrund oder Escape schließt sie wieder. Implementiert als einzelner <div id="lb-overlay"> in head.html, gesteuert per lbOpen(src, event).

Favicon

Der Friese dient als Favicon (favicon.ico mit 16×16 und 32×32 px, zusätzlich favicon.png). Beide Dateien liegen direkt im /OBD/-Verzeichnis. Die <link>-Tags stehen in includes/head.html mit relativem Pfad ohne führendes ./ — damit funktioniert die Auflösung korrekt durch SSI.

SSI-Struktur

index.shtml besteht ausschließlich aus <!--#include virtual="./includes/..."-->-Direktiven. Jeder Seitenbereich ist eine eigene Datei in includes/ — Änderungen an einzelnen Bereichen erfordern kein Anfassen von index.shtml.


Lizenz

Alle Quelltexte dieses Projekts stehen unter der GNU General Public License v3 (GPL v3). Das bedeutet: freie Nutzung, Veränderung und Weitergabe — aber Derivate müssen ebenfalls unter GPL v3 veröffentlicht werden. Closed-Source-Derivate sind nicht zulässig.

Die originalen Copyright-Hinweise (Copyright (C) 2026 Ralf Burger) müssen in allen Kopien und abgeleiteten Werken erhalten bleiben.

Der vollständige Lizenztext liegt als LICENSE (englisch, rechtsverbindlich) und LICENSE.de (deutsche Übersetzung, nicht rechtsverbindlich) im Projektroot. Online: gnu.org/licenses/gpl-3.0

ralf@RalfBurger.com · Systemintegration Ralf Burger · Roenskenstr. 37 · 46562 Voerde