CLI tool
Ircama/ELM327-emulator avatar
Ircama/ELM327-emulator

ELM327-emulator fakes a car so diagnostic software can be tested

ELM327 Emulator for testing software interfacing OBDII via ELM327 adapter supporting multi-ECU simulation

690 stars126 forksPythonNOASSERTION

At a glance

What is it?
ELM327-emulator is a Python implementation of an ELM327 OBD-II adapter that simulates a vehicle, including multiple ECUs, so diagnostic client software can be developed and tested without a car on the ramp. It speaks serial, TCP/IP and Bluetooth, and can also emulate the diagnostic bus itself as SLCAN CAN or K-Line.
Who is it for?
ELM327-emulator suits a developer writing OBD-II client software who needs a repeatable test target instead of a borrowed car, since the message flow comes from a dictionary rather than from live traffic and the same emulation can be pointed at a real adapter for comparison.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 36 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What it emulates, and what it does not

ELM327-emulator is a Python emulator of the ELM327 OBD-II adapter connected to a vehicle, supporting multi-ECU simulation. The repository description puts it as an ELM327 Emulator for testing software interfacing OBDII via ELM327 adapter supporting multi-ECU simulation.

The scope is worth stating precisely, because the name suggests more than it does. It emulates the adapter and the ECUs behind it, at the diagnostic protocol level. It is not a vehicle dynamics simulator, and it does not model engine behaviour, sensor signals or fault conditions in a physical sense.

What it does cover is broad for a protocol-level tool. It handles basic ELM327 commands and OBD service requests through a stateless request/response method over OBD-II, and it can also handle stateful UDS communication with ISO-TP Flow Control and Keyword Protocol 2000, while emulating multiple ECUs concurrently. Many AT commands are supported, along with some OBDLink AT/ST commands, and Diagnostic Trouble Codes in modes 03, 07 and 0A can be simulated. A mode 01 request can carry multiple PIDs, and requests sent to the functional address 7DF or 18DB33F1 are answered by the emulated ECUs.

The other direction is equally useful. Besides emulating the ELM327 adapter, it can also emulate the diagnostic bus itself, exposing a CAN interface running the SLCAN (Lawicel) firmware or a K-Line ECU (ISO 9141-2 / ISO 14230), so that applications driving a CANable or a VAG KKL adapter can talk to the emulated ECUs.

The project is released under Creative Commons Attribution-NonCommercial-ShareAlike 4.0, which the setup.py header records as (C) Ircama 2021 - CC-BY-NC-SA-4.0, and the README badge agrees. For a tool whose entire purpose is to be part of somebody else's development workflow, that licence choice is the single most consequential fact about it.

How the connection to the client is made

The client side is where the flexibility comes from, and the README lists the options.

The emulator connects client applications to multiple emulated ECUs via the OBD-II interface through different networking systems: serial communication, where pseudo-terminals are used if the operating systems support them, or direct interaction with communication devices, or TCP/IP, or Bluetooth.

The practical consequence is that a test client does not care which transport it uses. A Windows application that expects a COM port, a phone application that expects a Bluetooth ELM327, and a Linux script that opens a TCP socket can all be pointed at the same emulated vehicle.

The command line interface reflects the same thing, with options for a serial port, for TCP/IP, for the native Bluetooth interface and for an OS device, which the README names as the -p, -n, -w and -P interfaces respectively. The Windows installation notes are specific about this: if the interface to use is a serial COM port, you also need com0com, and no installation is needed when using the TCP/IP, native Bluetooth or OS device interfaces.

The daemon mode is what makes the emulator usable as a shared service. On non-Windows systems the package installs python-daemon and lockfile, used for the PID lock file of the daemon mode, which is how several clients can share one emulated vehicle.

The last piece is that the emulator is agnostic of the client application, and it has been tested with python-OBD as well as with many applications on Windows, Linux and on smartphone devices.

The ObdMessage dictionary is the real content

The design decision that makes this project more than a canned script is the ObdMessage dictionary.

An internal dictionary, named ObdMessage, allows configuring the emulation. It is currently set to reproduce the message flow generated by more ECUs, including the basic communication of a Toyota Auris Hybrid car through the scenario car option, and it can be easily extended to simulate communication produced by other vehicles or ECUs.

So the emulator does not contain a hard coded set of responses. It contains a data file describing what a particular vehicle says, and the engine replays that data against whatever the client asks for.

For more complex interactions, such as entering privileged diagnostic sessions and performing reset or flash upload operations, the dictionary can instance tasks, which are implemented through plugins. The README says these are very simple to be developed by users extending the software, and that some example plugins are already included.

The plugin architecture is described as allowing the software to be extended for specific tasks implementing workflows, including the possibility to simulate anomalies for testing purposes. That last point is the most interesting for a diagnostic software developer, because the interesting test cases are the ones where the vehicle misbehaves.

The repository layout matches this structure: an elm/ directory for the emulator, an obd_dictionary/ directory for the auxiliary tool, and a make_mmap_input.py script at the root. There is also a CONTRIBUTING.md, a RELEASES.md, a SECURITY.md and a.jekyll-gh-pages directory for the project pages.

Building the dictionary from a real car

The most distinctive feature is a workflow that closes the loop with real hardware.

ELM327-emulator offers a feature that compares the emulation with the direct connection of an OBD-II adapter, which allows extending the dictionary by reporting unmatched requests. In other words, you run a request against the emulator, and if the emulator has no matching entry, it tells you, and you add one.

On top of that there is an auxiliary scanning tool, obd_dictionary, that builds the ObdMessage dictionary of a specific vehicle by automatically querying all standard OBD service requests one by one, as well as querying additional custom PIDs specified by the user via a CSV file. The dictionary can then be used to emulate the stateless request and responses of a specific car or ECU.

This is a good design, and it is worth understanding why. The hard part of writing an OBD-II test harness is not the protocol handling, it is knowing what a real vehicle actually says for a given request. A tool that interrogates a real car and records the answers, then replays them, converts an unbounded hardware problem into a file.

The obd_dictionary tool needs the obd package, python-OBD, and the README recommends using an updated version of it, for example the one installed from GitHub.

One detail to know if you want to reproduce a specific car: the emulator supports basic ELM327 commands and OBD service requests through a stateless request and response method, but the full stateful UDS exchange with ISO-TP and Keyword Protocol 2000 is the more capable path, and that is where privileged sessions and flash upload operations live.

Installing it, and the running modes

The installation requirement is Python 3.6 or higher, checked with python3 -V, and then a single pip command:

shell
python3 -m pip install ELM327-emulator

The README says that is enough to run the software, and the prerequisites are installed automatically. They are pyyaml, obd and pyserial, plus python-daemon and lockfile on non-Windows systems for the PID lock file of the daemon mode, and pyreadline3 on Windows. On macOS the optional pyobjc-framework-IOBluetooth component is required by the native Bluetooth interface, installed with the extra:

shell
python3 -m pip install "ELM327-emulator[bluetooth]"

There is also a route straight from GitHub:

shell
  python3 -m pip install git+https://github.com/ircama/ELM327-emulator

and the uninstall is python3 -m pip uninstall -y ELM327-emulator.

The Windows preparation notes are longer, and they are worth reading in order: install the latest Python, install git from Git-scm or with the Git for Windows installer if you want the GitHub version, install com0com if you intend to use a serial COM port interface, and optionally upgrade pip.

Running it is a single command, and the batch and interactive modes both exist, with interactive as the default:

shell
python3 -m elm

or simply:

shell
elm

After starting the program the emulator is ready to use, and entering the scenario car command enables the preconfigured set of OBD service requests of a Toyota Auris Hybrid car.

Where it fits, and where it stops

The comparison worth making is with the other two ways to test diagnostic software: a real car, and a canned response script.

Against a real car, the difference is repeatability and availability. A real vehicle gives you authentic behaviour including the things nobody wrote down, and the emulator's dictionary-building workflow exists precisely to capture that authenticity. But a real car is a scarce, shared resource, it cannot be asked to return a specific failure twice, and it has to be physically present. The emulator is available, scriptable and deterministic.

Against a canned script, the difference is fidelity and effort. A hand written response table is quick to produce for a handful of PIDs and becomes unmaintainable for a full mode 01 sweep, and it encodes what its author guessed. The dictionary approach generates the table by interrogation and can report the requests the emulation does not yet cover.

The limits are structural. The emulator is a protocol endpoint, not a vehicle, so a client that depends on real timing, on gradual value drift between reads or on a fault that only appears under specific driving conditions will not find that here. The multi-ECU support is a feature of the emulation and not a model of how real ECUs arbitrate. And the scenario car configuration reproduces one car, a Toyota Auris Hybrid, so a test written against it is testing the emulator's view of that car rather than a general vehicle.

The licence is the practical ceiling for commercial use. CC-BY-NC-SA-4.0 permits use and modification for non-commercial purposes with attribution and share-alike, so a company building a commercial diagnostic product cannot take this code into its own toolchain without checking what that means for the derivative work. The licence file in the repository is the authoritative text, and the setup.py header confirms the terms.

The release history is healthy for a project at version 4.0.0, tagged on 2026-09-17, with v3.0.5 in December 2025 and v3.0.4 in March 2025, and the last push was on 2026-09-17. The pyproject.toml also shows attention to modern Python: it declares setuptools and wheel explicitly because since Python 3.14 the build backend is no longer implicitly injected into the isolated build environment, and the setup.py version helper deliberately avoids pkg_resources for the same reason.

Editorial conclusion

ELM327-emulator suits a developer writing OBD-II client software who needs a repeatable test target instead of a borrowed car, since the message flow comes from a dictionary rather than from live traffic and the same emulation can be pointed at a real adapter for comparison. It is the wrong tool if your product is commercial, because the project is released under CC-BY-NC-SA-4.0 and the setup.py header states that licence explicitly, and it is the wrong tool if you need a full vehicle dynamics simulation rather than a diagnostic protocol endpoint. Before adopting it, read the LICENSE file, and run the obd_dictionary tool against a real adapter and a real vehicle to build the dictionary you intend to replay.

Frequently asked questions

How do I install ELM327-emulator?

Check that Python is 3.6 or higher with python3 -V, then run python3 -m pip install ELM327-emulator. The prerequisites, pyyaml, obd and pyserial, are installed automatically, and on macOS the native Bluetooth interface needs the extra python3 -m pip install "ELM327-emulator[bluetooth]".

How do I start the emulator?

Run python3 -m elm or simply elm, which starts the interactive mode, the default. The batch mode is also available. Once it is running, entering the scenario car command enables the preconfigured set of OBD service requests of a Toyota Auris Hybrid car.

What can ELM327-emulator emulate besides the ELM327 adapter?

It can also emulate the diagnostic bus itself, exposing a CAN interface running the SLCAN (Lawicel) firmware or a K-Line ECU (ISO 9141-2 / ISO 14230), so applications that drive a CANable or a VAG KKL adapter can talk to the emulated ECUs.

How do I build a dictionary for a specific vehicle?

The obd_dictionary tool builds the ObdMessage dictionary by automatically querying all standard OBD service requests one by one, plus any custom PIDs you supply in a CSV file. The emulator can also compare itself against a directly connected OBD-II adapter and report unmatched requests, so the dictionary can be extended from what it does not yet cover.

What licence does ELM327-emulator use?

Creative Commons Attribution-NonCommercial-ShareAlike 4.0, recorded as CC-BY-NC-SA-4.0 in the README badge and in the setup.py header. The non-commercial term is the constraint for anyone intending to use the code inside a commercial product.

Official sources

  1. Ircama/ELM327-emulator on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ircama-elm327-emulator.svg)](https://hysenlabs.com/projects/ircama-elm327-emulator)

Was this useful?