Skip to content

Vehicle communication

Communication with ECUs in a vehicle can take place in several different ways, depending on the protocol used. This page lists examples of different ways in which such communication can take place. See the documentation page on vehicle communication for more information.

ISO-TP communication

The example below demonstrates how a VIN can be read from a vehicle using the ISO-TP protocol. This is done by configuring the required bus, specifying an ECU, and starting a stream to communicate with that ECU.

from openobd import *


# Start an openOBD session on a ticket
openobd = OpenOBD()
openobd_session = openobd.start_session_on_ticket(TICKET_ID)    # The ticket ID needs to be filled in (as a string)

# Start the SessionTokenHandler to ensure the openOBD session remains authenticated
SessionTokenHandler(openobd_session)

# Define two buses with the ISO-TP protocol
print("Configuring buses...")
bus_configs = [
    (BusConfiguration(bus_name="bus_6_14",
                      can_bus=CanBus(pin_plus=6, pin_min=14, can_protocol=CanProtocol.CAN_PROTOCOL_ISOTP,
                                     can_bit_rate=CanBitRate.CAN_BIT_RATE_500,
                                     transceiver=TransceiverSpeed.TRANSCEIVER_SPEED_HIGH))),
    (BusConfiguration(bus_name="bus_3_11",
                      can_bus=CanBus(pin_plus=3, pin_min=11, can_protocol=CanProtocol.CAN_PROTOCOL_ISOTP,
                                     can_bit_rate=CanBitRate.CAN_BIT_RATE_500,
                                     transceiver=TransceiverSpeed.TRANSCEIVER_SPEED_HIGH)))
]
# Open a configureBus stream, send the bus configurations, and close the stream
bus_config_stream = StreamHandler(openobd_session.configure_bus)
bus_config_stream.send_and_close(bus_configs)
print("Buses have been configured.")

# Define the engine control module, which is present on bus pins 6, 14, with CAN IDs 7E0-7E8, and turn on frame padding
ecm_channel = IsotpChannel(bus_name="bus_6_14", request_id=0x7E0, response_id=0x7E8, padding=Padding.PADDING_ENABLED)
# Start a stream to communicate with the engine
ecm = IsotpSocket(openobd_session, ecm_channel)

# Start an extended diagnostic session, with silent set to True so no ResponseException will be raised on an incorrect response
print("Sending 1003...")
response = ecm.request("1003", silent=True)
print(f"Response: {response}")

try:
    # Request the VIN from the engine, attempting it up to 2 times, each attempt waiting a maximum of 5 seconds for a response
    print("Sending 22F190...")
    response = ecm.request("22F190", tries=2, timeout=5)
    print(f"Response: {response}")

    # Decode and print the VIN, ignoring the first 3 bytes of the response
    vin = bytes.fromhex(response[6:]).decode("utf-8")
    print(f"VIN: {vin}")

# Catch any exceptions that are raised because of the ECU returning a negative response, or not responding at all
except ResponseException as e:
    print(f"Request failed: {e}")

finally:
    # Close the stream regardless of the result
    ecm.stop_stream()

# Close the session with a successful result
result = ServiceResult(result=[Result.RESULT_SUCCESS])
openobd_session.finish(result)

CAN frame communication

The frames protocol can be used when it is desired to have direct control over the frames that are being exchanged with an ECU. Below is an example in which a VIN is read from an ECU while using the frames protocol. It demonstrates how to set up a frames stream and how to handle multi-frame messages.

from openobd import *


# Start an openOBD session on a ticket
openobd = OpenOBD()
openobd_session = openobd.start_session_on_ticket(TICKET_ID)    # The ticket ID needs to be filled in (as a string)

# Start the SessionTokenHandler to ensure the openOBD session remains authenticated
SessionTokenHandler(openobd_session)

# Define a bus with the frames protocol
print("Configuring buses...")
bus_configs = [
    (BusConfiguration(bus_name="bus_6_14",
                      can_bus=CanBus(pin_plus=6, pin_min=14, can_protocol=CanProtocol.CAN_PROTOCOL_FRAMES,
                                     can_bit_rate=CanBitRate.CAN_BIT_RATE_500,
                                     transceiver=TransceiverSpeed.TRANSCEIVER_SPEED_HIGH)))
]
# Open a configureBus stream, send the bus configurations, and close the stream
StreamHandler(openobd_session.configure_bus).send_and_close(bus_configs)
print("Buses have been configured.")

# Define the engine control module, which is present on bus pins 6, 14, with CAN IDs 7E0-7E8
ecm_channel = RawChannel(bus_name="bus_6_14", request_id=0x7E0, response_id=0x7E8)
# Start a stream to communicate with the engine
ecm = RawSocket(openobd_session, ecm_channel)

# Start an extended diagnostic session
try:
    print("Sending 1003...")
    # Send the entire 8-byte long CAN frame to the engine
    ecm.send("0210030000000000")
    # Wait max 5 seconds for a response
    response = ecm.receive(timeout=5)
    print(f"Received frame: {response}")
except OpenOBDStreamTimeoutException:
    print("No frame received.")

# Send a "tester present" message to the engine control module to keep its diagnostic session active
ecm.send("023E800000000000")

# Request the VIN, which does not fit in a single frame and therefore requires multiple frames to be received
try:
    print("Sending 22F190...")
    ecm.send("0322F19000000000")
    response = ecm.receive()    # Default timeout is 10 seconds
    print(f"Received frame: {response}")

    # Determine how long the response will be using info from the first frame
    total_bytes = int(response[1:4], 16)
    received_payload = response[4:]
    received_bytes = 6

    # Send a flow control frame to indicate that the engine should continue sending frames
    ecm.send("3000000000000000")

    # Continue receiving frames until all the bytes have been received
    while received_bytes < total_bytes:
        response = ecm.receive(timeout=2)
        print(f"Received frame: {response}")
        received_payload += response[2:]
        received_bytes += 7

    # Decode and print the VIN, ignoring the first 3 bytes of the response
    vin = bytes.fromhex(received_payload[6:]).decode("utf-8")
    print(f"VIN: {vin}")

except OpenOBDStreamTimeoutException:
    print("No frame received.")

# Close the stream
ecm.stop_stream()

# Close the session with a successful result
result = ServiceResult(result=[Result.RESULT_SUCCESS])
openobd_session.finish(result)