- C++ 66.1%
- Python 33.4%
- C 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| docs | ||
| scripts | ||
| src | ||
| tests | ||
| .gitignore | ||
| platformio.ini | ||
| README.md | ||
Octavia diagnostic device
An ESP32-S3-Zero reader for a Skoda Octavia 1.8T ARX. It reports engine coolant temperature, intake air temperature, actual charge pressure after the turbocharger, and optionally Haldex oil temperature.
The board smoke test is complete. Firmware octavia-reader/0.6.0 contains an
autonomous, read-only KW1281 reader with connectionless BLE telemetry. It starts
on power-up, continuously alternates engine groups without an added poll delay,
samples Haldex every five minutes (first sample after about 30 seconds), and
uses a configured 100 ms BLE interval.
No computer or serial monitor is needed. With corrected RX11/TX10 wiring, the
engine and Haldex controllers both communicate and return all four requested
quantities. The latest verified implementation is now on branch master.
See BLE payload, flags, timing, and decoder.
No Wi-Fi, pairing, Bluetooth connection, or display is required.
Standalone pin tester
Branch codex/pin-tester adds the separate PlatformIO environment pin-test.
See pin tester instructions for the external-power test.
It drives GPIO10 HIGH/LOW every five seconds and reads GPIO11 without an internal
pull-up or pull-down. It reports both levels over USB every second and on changes.
The default esp32-s3-zero environment still builds the diagnostic reader.
Hardware and wiring
| Connection | ESP32-S3-Zero |
|---|---|
| Adapter receiver output to ESP | GPIO11, K-line RX |
| ESP output to adapter transmitter input | GPIO10, K-line TX |
| KKL logic ground | GND, common with ESP32 |
| Computer | Board USB-C, programming and USB serial |
The owner confirmed a modified KKL cable exposing 3.3 V-compatible UART signals. The adapter uses a comparator circuit; its former FTDI UART traces now connect to the ESP. Both earlier pin assignments were tried without a reply. The owner corrected the ESP header labels on 2026-10-11 to RX11/TX10 as shown above. Earlier captures used the misread RX10/TX9 assignment or its swap. The adapter performs K-line level conversion. These GPIO connections refer to the UART side inside the adapter; they are not connections to the vehicle's 12 V K-line. GPIO numbers are used, not physical header positions.
The configuration targets the standard ESP32-S3-Zero: 4 MB flash and 2 MB PSRAM.
The upload tool confirmed these memory sizes on the connected board. PSRAM is
unused. The generic DevKitC board definition is overridden to use 4 MB
flash and Arduino's default.csv 4 MB partition layout. Native USB serial is
separate from K-line hardware UART1 on GPIO11/10.
Prerequisites and commands
PlatformIO Core 6.2.0 is installed at the path below. This project's Espressif32 platform is pinned to 7.1.3. The first build downloads its compiler and framework. Run these PowerShell commands in this project directory:
$env:PYTHONIOENCODING = 'utf-8'
$octaviaPio = 'C:\Users\uzivatel\.platformio\penv\Scripts\pio.exe'
& $octaviaPio run -e esp32-s3-zero
& $octaviaPio device list
# Substitute the current board port if it differs from COM6.
& $octaviaPio run -e esp32-s3-zero -t upload --upload-port COM6
& $octaviaPio device list
& $octaviaPio device monitor --port COM6 --baud 115200
Close the monitor before uploading. Use Ctrl+C to close it. Re-enumerate after
upload because Windows can assign a different COM number. The connected board
initially appears as USB VID:PID 303A:1001, serial B4:3A:45:AE:5D:B8, on COM6;
COM3 is Intel AMT and is not the board.
Verification status
The BLE build fits the original application slot: 925,013 bytes flash
and 49,132 bytes static RAM; PSRAM remains unused. Upload passed on COM6.
Firmware 0.6.0 passed a 350-second real-car capture with 495 BLE reports,
zero read/decode errors, and Haldex visits 300.109 seconds apart. Engine readings
were fresh between visits; the two switches reached nine-second reported engine
ages, then recovered. Haldex remained available through a reported age of
302 seconds. This reduces the pause frequency while preserving protocol timing.
The earlier firmware 0.5.0 passed a running-engine capture across four Haldex visits with
no missing engine values or read faults. BLE schema 2 carries sample ages;
cached values stay available during a controller switch and are explicitly
stale. Live engine sampling still pauses while Haldex uses the shared K-line.
Group 115/4 measures absolute charge pressure before the throttle, so a
near-atmospheric reading at idle does not measure manifold vacuum.
The final 0.4.0 firmware also passed a physical standalone check: the owner
moved the board to separate USB power, COM6 disappeared, and the computer's BLE
receiver continued receiving all four measurements across scheduled Haldex
visits. An intentionally wrong-baud engine connection produced BLE error flags
and invalid engine values; automatic mode then recovered valid readings.
See the development log for capture counts and timing limits.
The following USB-only evidence describes the earlier 0.3.0 reader: USB runtime
verification of the final 0.3.0 reader passed: ten consecutive heartbeats before
and after software reset, with reset_reason=software(3). Engine and Haldex
polling and two direct controller round trips also passed in the car.
Runtime reports ESP32-S3 at 240 MHz and 4,194,304 bytes of flash.
USB verification does not verify KKL wiring, protocol support, or sensor values.
See development log for milestones and evidence.
The final USB capture is artifacts/reader-0.3-usb-verification.log (ignored by Git).
The separate-power test confirms autonomous operation after the USB supply
change. Physical RESET-button operation and the exact reset cause during that
change were not observed.
With ignition on and engine stopped, corrected GPIO11 RX / GPIO10 TX connected
to engine 06A906032HJ at 10400 baud and Haldex 02D900554C at 9600 baud.
Both reported KW1281. Engine groups 004/3 and 004/4 returned coolant and intake
temperatures of 12 degC; 115/4 returned actual charge pressure 970 mbar absolute.
118 agreed with intake temperature and pressure. Haldex 002/2 returned oil
temperature 12 degC. These are real ECU readings with matching units; sensor
accuracy and behavior during engine warm-up/boost have not been checked.
Earlier unsuccessful captures used misread ESP pin labels.
Standalone BLE operation
Power the ESP and adapter, with common ground and ignition on. The firmware starts BLE before its first K-line handshake, reads the engine at 10400 baud, and visits Haldex at 9600 every five minutes, first due 30 seconds after startup. BLE validity/error flags cover failed reads, stale values, startup, and controller switches. Schema 3 retains engine samples for at most 20 seconds, reports their ages, and marks them stale in the reference decoder after 2 seconds or on a read fault. Haldex expires after 320 seconds. Because controllers share K-line, engine samples age while Haldex is sampled/reconnecting. Expired or never-read samples remain unavailable. Firmware automatically retries engine connection with a five-second backoff after failed attempts. Advertising runs independently of these transactions. The measured roughly eight-second engine pause now occurs every five minutes; validated KW1281 timings remain unchanged. See sampling gap investigation.
Use a BLE scanner to inspect Service Data UUID
37f8fc84-7412-4ac3-adc3-adb94faab82c, or run scripts/ble_scan.py as described
in the message specification. That receiver does not use
COM6. The 13-byte message and its decoder are documented there. Existing
schema-1/2 receivers must be updated: availability bits permit cached values,
and schema 3 encodes Haldex age in two-second units. Inspect decoded sample ages
and error flags before displaying a reading as fresh.
For a compact live view with units and stale/error markers:
$env:PYTHONIOENCODING = 'utf-8'
& 'C:\Users\uzivatel\.platformio\penv\Scripts\python.exe' scripts/ble_scan.py --values --seconds 0
Stop with Ctrl+C. This mode prints changed measurements only; the full JSONL capture is still saved. It uses Bluetooth and does not require the ESP USB port.
Optional USB diagnostics
Serial output is optional and never enables normal operation. s reports
status, counters, and BLE payload; x pauses reads and broadcasts unavailable
values with error flags; a resumes automatic mode; r restarts. Manual engine/
Haldex commands below override automatic mode until a or reboot. Verbose
group/byte printing is off by default to avoid slowing the reader.
The banner reports firmware, chip, flash, Arduino/SDK versions, reset reason, and reserved K-line pins. A monitor connected after boot also receives a banner. Each heartbeat includes a sequence number, uptime in milliseconds, and free heap. The firmware continues running when no USB monitor is attached.
Send s for another status banner or r for a software reset; no line ending is
required. The reset acknowledgment is followed by a new banner and restarted
heartbeat sequence after the USB connection returns. Reconnect the monitor if
the operating system closes the port during reset. The reset reason should be
software(3).
GPIO10 starts HIGH and GPIO11 is an input with a weak pull-up. UART1 starts
automatically when the diagnostic scheduler runs. See
communication commands and captures.
Use e to connect the engine at 10400 baud, then m for a temperature/pressure
snapshot or p for continuous polling. Use h to switch to Haldex at 9600 baud,
then o for oil temperature or p for polling. x disconnects. These are
sequential sessions on the shared K-line; polling the engine does not sample
Haldex simultaneously. g/v/i still read 004/115/118 explicitly.
Named sensor=... lines include source group/field, timestamp, units, and
valid=true; a failed/unsupported response is unavailable in the serial sample
line. BLE may retain its previous successful sample with explicit age/error
status until expiry. d enables automatic byte traces;
t prints the most recent buffered trace even with verbose tracing disabled.
The old USB-only smoke/reader verifier below applies to versions 0.1-0.3. It is not a test of autonomous 0.4 and later polling/advertising (blocking controller handshakes affect heartbeat timing). For current verification, use the BLE receiver.
& 'C:\Users\uzivatel\.platformio\penv\Scripts\python.exe' scripts/verify_usb.py --port COM6
This checks the banner, 4 MB flash report, pin configuration, and ten consecutive
heartbeats; requests a USB-console software reset; then checks the reset reason
and ten more heartbeats. It follows the device serial number if Windows changes
the port. Each phase has a 45-second timeout. Captures go to ignored
artifacts/usb-smoke.log. This verifies software restart, not a physical RESET
button press or cold power cycle.
The verifier keeps its USB handle open across software restart and opens ports with DTR and RTS inactive. PlatformIO's monitor uses the same inactive control lines. This prevents a second USB-controlled reset from masking the software reset reason. The board's USB Serial/JTAG controller uses these control signals for reset and boot selection.
Troubleshooting
- If automatic bootloader entry fails, hold BOOT, press and release RESET, then release BOOT. Re-enumerate the port and retry upload. Press RESET after upload if the board stays in the bootloader.
- If output is missing, check the current port and use a USB cable that carries data. Native USB CDC must remain enabled in the build configuration.
- If a port is busy, close VAG-COM, another monitor, or another program using it.
- An initial
reset_reason=other(0)can occur after a USB-controlled hardware reset with this SDK. Thercommand, verified with a continuously open USB handle, reportsreset_reason=software(3). PYTHONIOENCODING=utf-8avoids the observed PlatformIO dependency-listing failure caused by Windows CP1250 being unable to encode tree symbols.
References
- Diagnostic mappings and first car session: candidates for coolant/intake temperatures, actual charge pressure, and optional Haldex oil temperature, with sources and validation steps.
- KW1281 communication and electrical diagnostics
- Waveshare ESP32-S3-Zero hardware specifications
- Pinned PlatformIO Espressif32 release