A Python emulator of the ELM327 OBD-II adapter connected to a vehicle supporting multi-ECU simulation.
ELM327-emulator connects client applications to multiple emulated ECUs via OBD-II interface through different networking systems, including serial communication (where pseudo-terminals are used if supported by the operating systems), or direct interaction with communication devices, or TCP/IP, or Bluetooth. The software simulates an ELM327 adapter connected to a vehicle, includes a command-line interface for extensive monitoring and offers a documented Python development framework to implement ECU emulation objects.
ELM327-emulator is able to support basic ELM327 commands and OBD service requests through stateless request/response method via OBD-II, but can also handle stateful UDS communication with ISO-TP Flow Control and Keyword Protocol 2000, concurrently emulating multiple ECUs. It is designed to be extended via a plugin architecture to allow easy development of specific tasks implementing workflows, including the possibility to simulate anomalies for testing purposes. Many AT commands are supported, as well as some OBDLink AT/ST commands.
ELM327-emulator supports different operating systems including Windows, macOS and UNIX/Linux; it is agnostic of the client application and has been tested with python-OBD as well as with many applications on Windows, Linux and on smartphone devices.
An internal dictionary (named ObdMessage) allows configuring the emulation, which 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 can be easily extended to simulate communication produced by other vehicles or ECUs. In case of more complex interactions (e.g., entering privileged diagnostic sessions and performing reset or flash upload operations), the dictionary can instance tasks, which are implemented through plugins, very simple to be developed by users extending the software. Some example of plugins is already included.
ELM327-emulator also offers a feature that compares the emulation with the direct connection of an OBD-II adapter to allow extending the dictionary by reporting unmatched requests. In addition, it provides 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 CSV file); the dictionary can then be used to emulate stateless request/responses of a specific car or ECU.
Check that the Python version is 3.6 or higher (python3 -V), then install ELM327-emulator with the following command:
python3 -m pip install ELM327-emulator
This is enough to run the software.
Prerequisite components: pyyaml, python-daemon, obd; in addition, with Windows also pyreadline3. All needed prerequisites are automatically installed with the package.
obd (python-OBD) is needed for obd_dictionary. It is better to use an updated version of python-OBD package (e.g., the one installed from GitHub with python3 -m pip install --upgrade git+https://github.com/brendan-w/python-OBD.git).
Alternatively to the above mentioned installation method, the following steps allow installing the latest version from GitHub.
shell
sudo apt-get update
sudo apt-get -y upgrade
sudo add-apt-repository universe # this is only needed if "sudo apt install python3-pip" fails
sudo apt-get update
sudo apt install -y python3-pip
python3 -m pip install --upgrade pip
sudo apt install -y git
Optional preliminary configuration with Windows:
install the latest version of Python (also available from Microsoft Store);
optionally, check that PIP is upgraded (python3 -m pip install --upgrade pip).
Run this command:
python3 -m pip install git+https://github.com/ircama/ELM327-emulator
To uninstall:
python3 -m pip uninstall -y ELM327-emulator
The emulator allows batch and interactive mode. The latter is the default and can be executed as follows:
python3 -m elm
or simply:
elm
After starting the program, the emulator is ready to use.
To enable the preconfigured set of OBD service requests of a Toyota Auris Hybrid car, enter scenario car (or, alternatively, run the emulator with the -s car option, i.e python3 -m elm -s car).
By default, ELM327-emulator uses serial communication. The external application interfacing the emulator just needs to connect to the virtual device shown by the emulator and interact with the vehicle as if it was accessing a real ELM327 adapter.
Alternatively to the serial communication, ELM327-emulator supports TCP/IP networking through the -n option, followed by the port number (wich in most cases is 35000). Example:
python3 -m elm -n 35000
All subsequent information is not needed for basic usage of the tool and allows mastering ELM327-emulator, exploiting it to test specific features including the simulation of communication exceptions, which are not always easy to be reproduced with a real link.
The elm327-emulator.zip archive in the Releases folder incudes the elm327-emulator.exe executable asset; the ZIP archive is auto-generated by a GitHub Action. elm327-emulator.exe is a Windows application that can be directly executed.
ELM327-emulator has been tested with Python 3.6, 3.7, 3.8, 3.9. Previous Python versions are not supported.
When using serial communication, with UNIX/Linux OSs, this code uses pty pseudo-terminals. With Windows, you should first install com0com (a kernel-mode virtual serial port driver), or other virtual serial port software; alternatively, cygwin and Windows Subsystem for Linux (WSL) are supported.
The description of the ELM327-emulator command-line option is the following:
usage: elm [-h] [-V] [-e] [-l] [-t] [-d] [-b FILE] [-p PORT] [-P DEVICE_PORT] [-a BAUDRATE] [-v LOG] [-s SCENARIO] [-n INET_PORT]
[-H INET_FORWARD_HOST] [-N INET_FORWARD_PORT] [-S FORWARD_SERIAL_PORT] [-B FORWARD_SERIAL_BAUDRATE] [-T FORWARD_TIMEOUT]
optional arguments:
-h, --help show this help message and exit
-V, --version Print ELM327-emulator version and exit
-e, --no-echo Disable echo by default
-l, --newline Use newline (<NL>) instead of carriage return <CR> for detecting a line separator
-t, --terminate Terminate the daemon process sending SIGTERM
-d, --daemon Run ELM327-emulator in daemon mode.
-b FILE, --batch FILE
Run ELM327-emulator in batch mode. Argument is the output file. The first line in that file will be the virtual
serial device
-p PORT, --port PORT Set a serial communication port instead of using a pseudo-tty.
-P DEVICE_PORT, --device DEVICE_PORT
Set the communication device to be opened instead of using a pseudo-tty port.
-a BAUDRATE, --baudrate BAUDRATE
Set the serial device baud rate used by ELM327-emulator.
-v LOG, --log LOG Preset a log level in interactive mode.
-s SCENARIO, --scenario SCENARIO
Set the scenario used by ELM327-emulator.
-n INET_PORT, --net INET_PORT
Set the INET socket port used by ELM327-emulator.
-H INET_FORWARD_HOST, --forward_host INET_FORWARD_HOST
Set the INET host used by ELM327-emulator.when forwarding the client interaction to a remote OBD-II port.
-N INET_FORWARD_PORT, --forward_port INET_FORWARD_PORT
Set the INET socket port used by ELM327-emulator when forwarding the client interaction to a remote OBD-II port.
-S FORWARD_SERIAL_PORT, --forward_serial_port FORWARD_SERIAL_PORT
Set the serial device port used by ELM327-emulator when forwarding the client interaction to a serial device.
-B FORWARD_SERIAL_BAUDRATE, --forward_serial_baudrate FORWARD_SERIAL_BAUDRATE
Set the device baud rate used by ELM327-emulator when forwarding the client interaction to a serial device.
-T FORWARD_TIMEOUT, --forward_timeout FORWARD_TIMEOUT
Set forward timeout as floating number (default is 5 seconds).
ELM327-emulator v3.0.0 - ELM327 OBD-II adapter emulator
The communication port to be used by the application interfacing the emulator is displayed when starting the program. E.g. on UNIX/Linux:
ELM327-emulator is running on /dev/pts/0
When running on Windows, the following message is shown:
ELM327-emulator is running on com0com serial port pair reading from COM3
A dictionary named ObdMessage is used to define commands and PIDs. The dictionary includes more sections (named scenarios):
'AT': set of default AT and ST commands'default': set of default PIDs'car': PIDs of a Toyota Auris Hybrid vehicle'mt05': basic set of PIDs of an MT05 ECU from Delphi used in many motorbikes and ATV'sDefault settings include both the 'AT' and the 'default' scenarios.
The dictionary used to parse each ELM command is dynamically built as a union of three defined scenarios in the following order: 'default', 'AT', custom scenario (when applied). Each subsequent scenario redefines the commands of the previous scenarios. In principle, 'AT' scenario is added to 'default' and, if a custom scenario is used, this is also added on top, and all equal keys are replaced. Then the Priority key defines the precedence to match elements.
If a custom scenario is selected through the scenario command, any key defined in the custom scenario replaces the default settings ('AT' and 'default' scenarios).
The key used in the dictionary consists of a unique identifier for each PID. Allowed case-insensitive values for each key (PID):
'Request': received data; a regular expression can be used'Descr': string describing the PID'Exec': command to be executed'Log': logging.debug argument'Info': logging.info argument'Warning': logging.warning argument'ResponseFooter': run a function and returns a footer to the response (a lambda function can be used)'ResponseHeader': run a function and returns a header to the response (a lambda function can be used)'Response': returned data; can be a string, or a list/tuple of strings; if more strings are included (e.g., if a tuple or a list is used), the emulator selects one of them each time, according to the criteria defined by the choose command, which can be either sequential (default) or random.'Action': can be set to 'skip' in order to skip the processing of the PID'Header': if set, process the command only if the corresponding header (CAN ID) matches'Priority'=number: when set, the key has higher priority than the default (highest number = 1, lowest = 10 = default)'Task': if set, the related header/request activates a specific task referring to an installed plugin.The emulator provides a monitoring front-end, supporting commands and controlling the backend thread which executes the actual process.
At the CMD> prompt, the emulator accepts the commands described in the following table.
| Command | Description |
|---|---|
help |
List available commands (or detailed help with "help cmd"). |
port |
Print the used TCP/IP port, or the used device, |
$ claude mcp add ELM327-emulator \
-- python -m otcore.mcp_server <graph>