Skip to content

About

BMW I-Bus / K-Bus library (IBus / KBus) for Arduino, ESP32 and other microcontrollers: read, decode and send messages on classic BMWs such as the E46, E39, E38 and E53. Handles checksums, bus arbitration and transceiver sleep.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

6 stars

Watchers

2 watching

Forks

BMW I-Bus / K-Bus library for Arduino, ESP32 and other microcontrollers, showing a decoded frame 50 04 68 32 11 1F

BMW I-Bus / K-Bus Library

Read, decode and send BMW I-Bus and K-Bus messages from your own sketch.
A compact library for Arduino, ESP32, STM32 and Raspberry Pi Pico that handles framing, checksums and bus arbitration, so you can sniff bus traffic or control lights, windows, locks and radio on classic BMWs — E46, E39, E38, E53 and more.

GitHub stars GitHub forks GitHub issues GPL-3.0 license Last commit Build status

Arduino ESP32 tested BMW I-Bus and K-Bus

Installation · Quick Start · API · Wiring · Examples · Where to Connect · FAQ · Firmware Project


🌟 Overview

Classic BMWs link their body and infotainment modules over a single 12 V wire: the I-Bus and K-Bus. Every key-fob click, steering-wheel button and light switch travels across it as a short serial message at 9600 baud, 8E1.

BMW IBus KBus is the library that puts your microcontroller on that bus. You register a callback, call run() in your loop, and the library does the rest.

flowchart LR
    CAR["BMW I-Bus / K-Bus<br/>12 V · single wire"] <--> TRX["Bus transceiver<br/>TH3122.4 · ELMOS 10026B"]
    TRX <-->|"UART · 9600 8E1"| LIB["BMW IBus KBus<br/>library"]
    LIB -->|"packet handler"| APP["Your sketch"]
    APP -->|"write()"| LIB
Loading

Looking for ready-to-flash firmware? The companion project BMW_IBus_KBus has complete sketches for the ESP32 and the Arduino Nano — a web interface to control the car from your phone, welcome lights and follow-me-home — together with an E46 message table.

✨ Features

  • 📥 Reliable receiving — a state machine finds frame boundaries in the byte stream and verifies every checksum.
  • 📤 Safe transmitting — messages are queued and sent only after the bus has been idle, so they never collide with the car's own traffic.
  • 🧮 Automatic checksums — define a message without its checksum and the library appends it, or send a complete frame unchanged.
  • 🎯 Source filter — receive everything, or only the modules you care about.
  • 💤 Sleep support — powers the transceiver down after a period of bus silence, like the car's own modules.
  • 🔎 Built-in debug output — every received and transmitted frame as hex on any Stream.
  • 📍 Configurable pins and an optional header with more than 80 named module addresses.

📡 Supported Vehicles

Chassis Series Years I-Bus K-Bus
E31 8 Series 1989–1999 ✅
E38 7 Series 1994–2001 ✅ ✅
E39 5 Series 1995–2004 ✅ ✅
E46 3 Series 1997–2006 ✅
E52 Z8 2000–2003 ✅
E53 X5 1999–2006 ✅ ✅
E83 X3 2003–2010 ✅
E85 Z4 2002–2008 ✅
E87 1 Series 2004–2013 ✅

📦 Installation

Arduino IDE Library Manager — the library is on its way into the Library Manager. As soon as it is listed, open Sketch → Include Library → Manage Libraries…, search for BMW IBus KBus and click Install.

ZIP file — until then, download this repository as a ZIP (Code → Download ZIP) and choose Sketch → Include Library → Add .ZIP Library…

Git — or clone it into your libraries folder:

git clone https://github.com/muki01/BMW_IBus_KBus_Library.git

PlatformIO — add it to platformio.ini:

lib_deps = https://github.com/muki01/BMW_IBus_KBus_Library.git

🚀 Quick Start

#include <BMW_IBus_KBus.h>
#include <SoftwareSerial.h>

SoftwareSerial debugSerial(7, 8);          // RX, TX — to a USB-serial adapter
BMW_IBus_KBus ibus;

void startTimer() {                        // called on every SEN/STA level change
  ibus.startTimer();
}

void setup() {
  debugSerial.begin(9600);
  ibus.setIbusSerial(Serial);              // bus on the hardware UART (9600 8E1)
  ibus.setIbusDebug(debugSerial);          // print every frame as hex
  ibus.setIbusPacketHandler(packetHandler);
  attachInterrupt(digitalPinToInterrupt(3), startTimer, CHANGE);
}

void loop() {
  ibus.run();
}

void packetHandler(byte *packet) {
  byte source      = packet[0];            // sender module
  byte length      = packet[1];            // bytes that follow (destination … checksum)
  byte destination = packet[2];            // target module
  byte command     = packet[3];            // message type, followed by data bytes

  if (source == 0x50 && destination == 0x68 && command == 0x32) {
    // steering wheel → radio: volume button
  }
}

Example debug output:

Good Message -> 50 04 68 32 11 1F
Good Message -> 00 04 BF 72 22 EB
Good Message -> 80 04 BF 11 01 2B

Tip

On the Arduino Nano and Uno the bus uses the hardware UART (D0 / D1), which is shared with USB. Disconnect the transceiver from D0 / D1 while uploading.

Sending a message

Store the message in PROGMEM without its checksum. The library calculates and appends the checksum, then transmits as soon as the bus is idle.

// diagnostic interface → body module: switch the interior light on
const byte Interior_On[] PROGMEM = {0x3F, 0x05, 0x00, 0x0C, 0x01, 0x01};

ibus.write(Interior_On, sizeof(Interior_On));

If a message already ends with its checksum, pass false as the third argument and it is sent unchanged:

const byte Interior_On_Full[] PROGMEM = {0x3F, 0x05, 0x00, 0x0C, 0x01, 0x01, 0x36};

ibus.write(Interior_On_Full, sizeof(Interior_On_Full), false);

Filtering by module

By default every valid message reaches your packet handler. To receive only certain modules, pass their addresses:

#include <BMW_IBus_KBus_Modules.h>

const byte sourceFilter[] = {M_GM5, M_MFL, M_RAD};   // body module, steering wheel, radio

ibus.setSourceFilter(sourceFilter, sizeof(sourceFilter));

📘 API Reference

Method Description
setIbusSerial(serial) Attach the bus to a hardware UART and configure it for 9600 8E1.
setIbusPacketHandler(fn) Register the function called for every valid message: void fn(byte *packet).
setIbusDebug(stream) Mirror all received and transmitted messages to any Stream as hex.
setPins(senSta, enable, led) Select the SEN/STA, EN and activity-LED pins. Defaults: 3, 4, 13.
setSourceFilter(sources, count) Pass only messages from the listed modules to the handler. count 0 disables the filter.
write(message, size) Queue a PROGMEM message; the checksum is calculated and appended.
write(message, size, false) Queue a PROGMEM message that already includes its checksum.
sleepEnable(seconds) Pull EN low after this many seconds without a valid message.
startTimer() Call from the SEN/STA pin-change interrupt to track bus-idle time.
run() Call continuously from loop() — receives, parses and transmits.
calculateChecksum(data, length) Return the XOR checksum of a buffer in RAM.

The packet passed to the handler is the complete frame:

Index Field Description
packet[0] Source Sender module address
packet[1] Length Number of bytes that follow
packet[2] Destination Target module address
packet[3] Command Message type
packet[4…] Data Payload, followed by the checksum

🔌 Wiring

The bus idles at battery voltage — never connect it directly to a microcontroller pin. The library is designed around the TH3122.4 / ELMOS 10026B bus transceiver:

BMW I-Bus K-Bus transceiver schematic with TH3122.4 or ELMOS 10026B for Arduino

Transceiver pin Arduino Nano / Uno Purpose
TXD D0 (RX) Bus → microcontroller
RXD D1 (TX) Microcontroller → bus
SEN/STA D3 Bus-idle detection before transmitting
EN D4 Transceiver enable / sleep
— D13 Bus activity LED

Use setPins() when your board needs different pins. SEN/STA must be connected to an interrupt-capable pin.

Alternative interface circuits

Optocouplers (PC817) — built from common parts; well suited to sniffing.

BMW K-Bus optocoupler interface schematic with PC817 and BC547

MCP2025 LIN transceiver — compact, with a built-in voltage regulator.

BMW I-Bus K-Bus interface schematic with MCP2025 LIN transceiver

These circuits have no SEN/STA output. Receiving works as shown; for transmitting, the library expects a bus-idle signal on the SEN/STA pin.

Sleep mode

With the TH3122 / ELMOS transceiver powering the microcontroller from its 5 V regulator, sleepEnable(60) pulls EN low after 60 seconds of bus silence. The transceiver switches the regulator off, and bus activity wakes everything up again.

🧩 Platform Support

Platform Status
Arduino Nano / Uno / Mega (ATmega328P, ATmega2560) ✅ Tested in a BMW E46 with an Arduino Nano
ESP32 ✅ Tested in a BMW E46 with an ESP32-C6 (Arduino-ESP32 3.x); compiles on Arduino-ESP32 2.x and 3.x
Raspberry Pi Pico, STM32, UNO R4 🧪 Experimental — compiles, not yet verified in a vehicle

On the ESP32 the examples use Serial1 for the bus and USB for the debug output. Open the port on your pins before the library uses it — the ESP32-C3 has no Serial2, and on the ESP32-C6 Serial2 is the low-power UART:

Serial1.begin(9600, SERIAL_8E1, BUS_RX_PIN, BUS_TX_PIN);
ibus.setIbusSerial(Serial1);

The examples use RX 5, TX 4, SEN/STA 7 and EN 3 on the ESP32-C6, C3 and S3, and RX 16, TX 17, SEN/STA 4 and EN 5 on the classic ESP32, where GPIO 6–11 belong to the flash chip.

Mark your interrupt function with IBUS_ISR_ATTR so that it is placed in RAM:

void IBUS_ISR_ATTR startTimer() {
  ibus.startTimer();
}

If you run the library on one of the experimental platforms, please report how it went.

🧪 Examples

Example What it shows
Bus_Reader Print every message on the bus — start here.
Send_Command Send a message to the car, with and without a pre-calculated checksum.
Key_Fob_Events Filter by module and react to the lock, unlock and trunk buttons of the remote key.

Complete vehicle firmware — welcome lights, goodbye lights, follow-me-home and an ESP32 web interface — and a table of more than 100 E46 messages live in the companion project.

📍 Where to Connect (BMW E46)

The I/K-Bus is not available on the OBD-II port. The easiest access point is the CD-changer connector in the trunk, which is pre-wired on most cars and provides power, ground and the bus in one plug.

BMW E46 trunk, left side trim panel hiding the CD changer wiring BMW E46 CD changer bracket with the pre-wired K-Bus connector behind the trunk trim BMW E46 CD changer connector X18180 with K-Bus, 12 V and ground wires
1. Open the trunk — driver's side 2. Remove the trim to reach the bracket 3. The 3-pin connector X18180
Wire colour Signal
⚪🔴🟡 White / red with yellow dots K-Bus
🔴🟢 Red / green +12 V
🟤 Brown Ground

Alternative: the K-Bus junction block above the fuse box

BMW E46 fuse box with the K-Bus junction block above it BMW E46 connector block removed from above the fuse box
1. Locate the connector block above the fuse box 2. Unclip it and pull it out
BMW E46 K-Bus junction block with terminals marked by arrows BMW E46 K-Bus wires, white and red with yellow dots, joined by a comb connector
3. Find the K-Bus junction block 4. All white / red / yellow wires are K-Bus

📨 Message Format

 50    04    68    32    11    1F
 │     │     │     │     │     └─ Checksum     XOR of all previous bytes
 │     │     │     │     └─────── Data         one or more bytes
 │     │     │     └───────────── Command      message type
 │     │     └─────────────────── Destination  0x68 = radio
 │     └───────────────────────── Length       number of bytes that follow
 └─────────────────────────────── Source       0x50 = multifunction steering wheel

Include BMW_IBus_KBus_Modules.h to use names such as M_MFL, M_RAD, M_IKE and M_LCM instead of raw addresses.

❓ FAQ

What is the difference between the I-Bus and the K-Bus?

Electrically and logically they are the same protocol. The I-Bus (Instrument / Information Bus) connects infotainment devices such as the radio, navigation, telephone and steering-wheel buttons. The K-Bus (Karosserie — body bus) connects body electronics such as the general module, light module, climate control and rain sensor. Cars with both buses link them through the instrument cluster, which acts as a gateway. The E46 uses the K-Bus for everything.

Is the K-Bus the same as the K-Line or OBD-II?

No. The K-Line (ISO 9141 / KWP2000) is the diagnostic line on the OBD-II port. The K-Bus is the car's internal body network and is not present on the OBD-II connector. For K-Line diagnostics see the OBD2 K-Line Library.

Can I connect the bus directly to a microcontroller pin?

No. The bus idles at battery voltage and will destroy a 5 V or 3.3 V input. Always use a transceiver circuit — see Wiring.

Is it only for Arduino boards?

No. It is written for the Arduino framework, so it also builds for the ESP32, STM32, Raspberry Pi Pico and UNO R4. See Platform Support for what has been verified.

Where can I find messages for my car?

The firmware project contains a table of more than 100 messages for the BMW E46 — lights, windows, locks, wipers and more — together with complete sketches.

🤝 Contributing

Contributions are welcome — especially test reports from the experimental platforms and from other chassis. Please read the Contributing Guide and the Code of Conduct, then open an issue or a pull request.

🔗 Related Projects

This library is part of a family of open-source automotive projects. They share the same hardware approach, so what you build for one carries over to the others.

Firmware — flash it and use it
BMW I-Bus / K-Bus Firmware Phone control and key-fob light functions for the BMW E46, on the ESP32 and Arduino. GitHub stars of BMW_IBus_KBus
OBD2 K-Line Reader Scan tool for K-Line cars (ISO 9141-2, KWP2000) with a web dashboard, for the ESP32, ESP8266 and Arduino. GitHub stars of OBD2_K-line_Reader
OBD2 CAN Bus Reader Scan tool for CAN bus cars (ISO 15765-4) with the same web dashboard, for the ESP32. GitHub stars of OBD2_CAN_Bus_Reader
VAG KW1281 KW1281 diagnostics for VW, Audi, Škoda and SEAT: ECU information, measuring groups and fault codes. GitHub stars of VAG_KW1281
Libraries — build your own firmware
BMW IBus KBus Library
you are here
Receives, checks and sends BMW I-Bus and K-Bus messages; the library behind the BMW firmware. GitHub stars of BMW_IBus_KBus_Library
OBD2 K-Line Library K-Line diagnostics behind one API: ISO 9141-2, KWP2000, KW1281, DS2 and KW82. GitHub stars of OBD2_KLine_Library
OBD2 CAN Bus Library OBD-II diagnostics over ISO 15765-4 with the ESP32's built-in CAN controller. GitHub stars of OBD2_CAN_Bus_Library
Interface
OBD2 Diagnostic UI The web dashboard used by the two OBD2 readers. GitHub stars of OBD2-Diagnostic-UI

💼 Custom Development

I design automotive diagnostic tools, firmware and hardware professionally. Whether you need a complete product or only the communication layer, I can help.

Service Details
Protocol implementation BMW I/K-Bus, K-Line (ISO 9141-2 / KWP2000), CAN / UDS, VAG KW1281 and other manufacturer-specific protocols
ECU communication & reverse engineering Bus sniffing, packet decoding, module control, undocumented ECUs and buses
ECU security access Seed-key algorithms and unlock routines for KWP2000 / UDS
Embedded firmware Arduino, ESP32, ESP8266, STM32, Raspberry Pi Pico
Custom hardware Diagnostic dongles, shields and PCBs designed to your requirements
Companion apps Android, iOS and web apps to visualise, log and control your device

Have a project in mind? Reach out through the Contact section below.

📬 Contact

For custom development, collaboration, sponsorship or ready-made devices:

Channel Address
📧 Email muksin.muksin04@gmail.com
💼 LinkedIn linkedin.com/in/muksin-muksin
🐙 GitHub @muki01

☕ Support the Project

If this project helped you, consider supporting its development:

Buy Me a Coffee Donate with PayPal GitHub Sponsors

⚠️ Disclaimer

Warning

This is a hobby and development project. Transmitting on a live vehicle bus can affect lighting, locking and other body functions. Test with the vehicle stationary and proceed at your own risk. The author accepts no responsibility for damage or malfunction.

BMW is a registered trademark of BMW AG. This project is independent and is not affiliated with, endorsed by or sponsored by BMW AG.

📄 License

Released under the GNU General Public License v3.0.

  • You are free to use, study, modify and share this library.
  • If you distribute it — on its own or as part of a product or firmware — you must make the complete source available under the same license.

Closed-source or commercial product? A separate commercial license is available. Get in touch through the Contact section.

Copyright © 2025–2026 Muksin Muksin.


Created by Muki · If this project helped you, please give it a ⭐

BMW · I-Bus · K-Bus · IBus · KBus · E46 · E39 · E38 · E53 · Arduino · ESP32 · STM32 · Raspberry Pi Pico · TH3122 · car hacking

⬆ Back to top

About

BMW I-Bus / K-Bus library (IBus / KBus) for Arduino, ESP32 and other microcontrollers: read, decode and send messages on classic BMWs such as the E46, E39, E38 and E53. Handles checksums, bus arbitration and transceiver sleep.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

6 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages