Welcome to doipclient’s documentation!

doipclient is a pure Python Diagnostic over IP (DoIP) client which can be used for communicating with modern ECU’s over automotive ethernet.

To discover ECU’s on your network, you can use the Vehicle Identification Announcement broadcast message (sent at powerup) as follows:

from doipclient import DoIPClient address, announcement = DoIPClient.await_vehicle_announcement() # Power cycle your ECU and wait for a few seconds for the broadcast to be # received logical_address = announcement.logical_address ip, port = address print(ip, port, logical_address) 

Alternatively, you can request a Vehicle Identification Response message:

from doipclient import DoIPClient address, announcement = DoIPClient.get_entity() logical_address = announcement.logical_address ip, port = address print(ip, port, logical_address) 

Once you have the IP address and Logical Address for your ECU, you can connect to it and begin interacting.

client = DoIPClient(ip, logical_address) print(client.request_entity_status()) 

You can also use UDS for diagnostic communication with the udsoncan library.

from doipclient.connectors import DoIPClientUDSConnector from udsoncan.client import Client from udsoncan.services import * uds_connection = DoIPClientUDSConnector(client) with Client(uds_connection) as uds_client: client.ecu_reset(ECUReset.ResetType.hardReset) 

DoIPClient

class doipclient.DoIPClient(ecu_ip_address, ecu_logical_address, tcp_port=13400, udp_port=13400, activation_type=ActivationType.Default, protocol_version=2, client_logical_address=3584, client_ip_address=None, use_secure=False, auto_reconnect_tcp=False)

A Diagnostic over IP (DoIP) Client implementing the majority of ISO-13400-2:2019 (E).

This is a basic DoIP client which was designed primarily for use with the python-udsoncan package for UDS communication with ECU’s over automotive ethernet. Certain parts of the specification would require threaded operation to maintain the time-based state described by the ISO document. However, in practice these are rarely important, particularly for use with UDS - especially with scripts that tend to go through instructions as fast as possible.

Parameters:
  • ecu_ip_address (str) – This is the IP address of the target ECU. This should be a string representing an IPv4 address like “192.168.1.1” or an IPv6 address like “2001:db8::”. Like the logical_address, if you don’t know the value for your ECU, utilize the get_entity() or await_vehicle_announcement() method.

  • ecu_logical_address (int) – The logical address of the target ECU. This should be an integer. According to the specification, the correct range is 0x0001 to 0x0DFF (“VM specific”). If you don’t know the logical address, either use the get_entity() method OR the await_vehicle_announcement() method and power cycle the ECU - it should identify itself on bootup.

  • tcp_port (int, optional) – The destination TCP port for DoIP data communication. By default this is 13400 for unsecure and 3496 when using TLS.

  • activation_type (RoutingActivationRequest.ActivationType, optional) – The activation type to use on initial connection. Most ECU’s require an activation request before they’ll respond, and typically the default activation type will do. The type can be changed later using request_activation() method. Use None to disable activation at startup.

  • protocol_version (int) – The DoIP protocol version to use for communication. Represents the version of the ISO 13400 specification to follow. 0x02 (2012) is probably correct for most ECU’s at the time of writing, though technically this implementation is against 0x03 (2019).

  • client_logical_address (int) – The logical address that this DoIP client will use to identify itself. Per the spec, this should be 0x0E00 to 0x0FFF. Can typically be left as default.

  • client_ip_address (str, optional) – If specified, attempts to bind to this IP as the source for both UDP and TCP communication. Useful if you have multiple network adapters. Can be an IPv4 or IPv6 address just like ecu_ip_address, though the type should match.

  • use_secure (Union[bool,ssl.SSLContext]) – Enables TLS. If set to True, a default SSL context is used. For more control, a preconfigured SSL context can be passed directly. Untested. Should be combined with changing tcp_port to 3496.

  • log_level (int) – Logging level

  • auto_reconnect_tcp (bool) – Attempt to automatically reconnect TCP sockets that were closed by peer

Raises:
  • ConnectionRefusedError – If the activation request fails

  • ValueError – If the IPAddress is neither an IPv4 nor an IPv6 address

class TransportType(value)

An enumeration.

classmethod await_vehicle_announcement(udp_port=13400, timeout=None, ipv6=False, source_interface=None, sock=None)

Receive Vehicle Announcement Message

When an ECU first turns on, it’s supposed to broadcast a Vehicle Announcement Message over UDP 3 times to assist DoIP clients in determining ECU IP’s and Logical Addresses. Will use an IPv4 socket by default, though this can be overridden with the ipv6 parameter.

Parameters:
  • udp_port (int, optional) – The UDP port to listen on. Per the spec this should be 13400, but some VM’s use a custom one.

  • timeout (float, optional) – Maximum amount of time to wait for message

  • ipv6 (bool, optional) – Bool forcing IPV6 socket instead of IPV4 socket

  • source_interface (str, optional) – Interface name (like “eth0”) to bind to for use with IPv6. Defaults to None which will use the default interface (which may not be the one connected to the ECU). Does nothing for IPv4, which will bind to all interfaces uses INADDR_ANY.

Returns:

IP Address of ECU and VehicleAnnouncementMessage object

Return type:

tuple

Raises:

TimeoutError – If vehicle announcement not received in time

close()

Close the DoIP client

empty_rxqueue()

Implemented for compatibility with udsoncan library. Nothing useful to be done yet

empty_txqueue()

Implemented for compatibility with udsoncan library. Nothing useful to be done yet

classmethod get_entity(ecu_ip_address='255.255.255.255', protocol_version=2, eid=None, vin=None)

Sends a VehicleIdentificationRequest and awaits a VehicleIdentificationResponse from the ECU, either with a specified VIN, EIN, or nothing. Equivalent to the request_vehicle_identification() method but can be called without instantiation.

Parameters:

ecu_ip_address – This is the IP address of the target ECU for unicast. Defaults to broadcast if

the address is not known. :type ecu_ip_address: str, optional :param protocol_version: The DoIP protocol version to use for communication. Represents the version of the ISO 13400

specification to follow. 0x02 (2012) is probably correct for most ECU’s at the time of writing, though technically this implementation is against 0x03 (2019).

Parameters:
  • eid (bytes, optional) – EID of the Vehicle

  • vin (str, optional) – VIN of the Vehicle

Returns:

The vehicle identification response message

Return type:

VehicleIdentificationResponse

read_doip(timeout=2, transport=TransportType.TRANSPORT_TCP)

Helper function to read from the DoIP socket.

Parameters:
  • timeout (float, optional) – Maximum time allowed for response from ECU

  • transport (DoIPClient.TransportType, optional) – The IP transport layer to read from, either UDP or TCP

Raises:
  • IOError – If DoIP layer fails with negative acknowledgement

  • TimeoutException – If ECU fails to respond in time

receive_diagnostic(timeout=None)

Receive a raw diagnostic payload (ie: UDS) from the ECU.

Returns:

Raw UDS payload

Return type:

bytearray

Raises:

TimeoutError – No diagnostic response received in time

reconnect(close_delay=2)

Attempts to re-establish the connection. Useful after an ECU reset

Parameters:

close_delay (float, optional) – Time to wait between closing and re-opening socket

request_activation(activation_type, vm_specific=None, disable_retry=False)

Requests a given activation type from the ECU for this connection using payload type 0x0005

Parameters:
  • activation_type (RoutingActivationRequest.ActivationType) – The type of activation to request - see Table 47 (“Routing activation request activation types”) of ISO-13400, but should generally be 0 (default) or 1 (regulatory diagnostics)

  • vm_specific (int, optional) – Optional 4 byte long int

  • disable_retry (bool, optional) – Disables retry regardless of auto_reconnect_tcp flag. This is used by activation requests during connect/reconnect.

Returns:

The resulting activation response object

Return type:

RoutingActivationResponse

request_alive_check()

Request that the ECU send an alive check response

Returns:

Alive Check Response object

Return type:

AliveCheckResopnse

request_diagnostic_power_mode()

Request that the ECU send a Diagnostic Power Mode response

Returns:

Diagnostic Power Mode Response object

Return type:

DiagnosticPowerModeResponse

request_entity_status()

Request that the ECU send a DoIP Entity Status Response

Returns:

DoIP Entity Status Response

Return type:

EntityStatusResponse

request_vehicle_identification(eid=None, vin=None)

Sends a VehicleIdentificationRequest and awaits a VehicleIdentificationResponse from the ECU, either with a specified VIN, EIN, or nothing. :param eid: EID of the Vehicle :type eid: bytes, optional :param vin: VIN of the Vehicle :type vin: str, optional :return: The vehicle identification response message :rtype: VehicleIdentificationResponse

send_diagnostic(diagnostic_payload, timeout=2)

Send a raw diagnostic payload (ie: UDS) to the ECU.

Parameters:

diagnostic_payload (bytearray) – UDS payload to transmit to the ECU

Raises:

IOError – DoIP negative acknowledgement received

send_doip(payload_type, payload_data, transport=TransportType.TRANSPORT_TCP, disable_retry=False)

Helper function to send to the DoIP socket.

Adds the correct DoIP header to the payload and sends to the socket.

Parameters:
  • payload_type (int) – The payload type (see Table 17 “Overview of DoIP payload types” in ISO-13400

  • transport (DoIPClient.TransportType, optional) – The IP transport layer to send to, either UDP or TCP

  • disable_retry (bool, optional) – Disables retry regardless of auto_reconnect_tcp flag. This is used by activation requests during connect/reconnect.

send_doip_message(doip_message, transport=TransportType.TRANSPORT_TCP, disable_retry=False)

Helper function to send an unpacked message to the DoIP socket.

Packs the given message and adds the correct DoIP header before sending to the socket

Parameters:
  • doip_message (object) – DoIP message object

  • transport (DoIPClient.TransportType, optional) – The IP transport layer to send to, either UDP or TCP

  • disable_retry (bool, optional) – Disables retry regardless of auto_reconnect_tcp flag. This is used by activation requests during connect/reconnect.

Encrypted Communication

TLS/SSL can be enabled by setting the use_secure parameter when creating an instance of DoIPClient.

client = DoIPClient( ip, logical_address, use_secure=True, # Enable encryption tcp_port=3496, ) 

If more control is required, a preconfigured SSL context can be provided. For instance, to enforce the use of TLSv1.2, create a context with the desired protocol version:

import ssl # Enforce use of TLSv1.2 ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) client = DoIPClient( ip, logical_address, use_secure=ssl_context, tcp_port=3496, ) 

Note

Since the communication is encrypted, debugging without the pre-master secret is not possible. To decrypt the TLS traffic for analysis, the pre-master secret can be dumped to a file and loaded into Wireshark. This can be done via the built-in mechanism or with sslkeylog when using Python 3.7 and earlier.