mcpolandc
mcpolandc

Reputation: 227

Using pyUSB to read data from ELM327 OBDII to USB device

I am having problems using the pyUSB library to read data from an ELM327 OBDII to USB device. I know that I need to write a command to the device on the write endpoint and read the received data back on the read endpoint. It doesn't seem to want to work for me though.

I wrote my own class obdusb for this:

import usb.core

class obdusb:

      def __init__(self,_vend,_prod):

    '''Handle to USB device'''
    self.idVendor = _vend
    self.idProduct = _prod
    self._dev = usb.core.find(idVendor=_vend, idProduct=_prod) 

    return None


def GetDevice(self):
    '''Must be called after constructor'''
    return self._dev


def SetupEndpoint(self):
    '''Must be called after constructor'''
    try: 
        self._dev.set_configuration()

    except usb.core.USBError as e:
        sys.exit("Could not set configuration")

    self._endpointWrite = self._dev[0][(0,0)][1]
    self._endpointRead = self._dev[0][(0,0)][0]

    #Resetting device and setting vehicle protocol (Auto)
    #20ms is required as a delay between each written command

    #ATZ resets device
    self._dev.write(self._endpointWrite.bEndpointAddress,'ATZ',0)
    sleep(0.002)
    #ATSP 0 should set vehicle protocol automatically
    self._dev.write(self._endpointWrite.bEndpointAddress,'ATSP 0',0) 
    sleep(0.02)

    return self._endpointRead


def GetData(self,strCommand):

    data = []
    self._dev.write(self._endpintWrite.bEndpointAddress,strCommand,0)
    sleep(0.002)
    data = self._dev.read(self._endpointRead.bEndpointAddress, self._endpointRead.wMaxPacketSize)

    return data

So I then use this class and call the GetData method using this code:

import obdusb

#Setting up library,device and endpoint
lib = obdusb.obdusb(0x0403,0x6001)
myDev = lib.GetDevice()
endp = lib.SetupEndpoint()

#Testing GetData function with random OBD command
#0902 is VIN number of vehicle being requested
dataArr = lib.GetData('0902')
PrintResults(dataArr)

raw_input("Press any key")

def PrintResults(arr):

    size = len(arr)

    print "Data currently in buffer:"

    for i in range(0,size):
        print "[" + str(i) + "]: " + str(make[i])

This only ever prints the numbers 1 and 60 from [0] and [1] element in the array. No other data has been return from the command. This is the case whether the device is connected to a car or not. I don't know what these 2 pieces of information are. I am expecting it to return a string of hexadecimal numbers. Does anyone know what I am doing wrong here?

Upvotes: 2

Views: 4358

Answers (1)

Eric Smekens
Eric Smekens

Reputation: 1621

If you don't use ATST or ATAT, you have to expect a timeout of 200ms at start, between every write/read combination.

Are you sending a '\r' after each command? It looks like you don't, so it's forever waiting for a Carriage Return.

And a hint: test with 010D or 010C or something. 09xx might be difficult what to expect.

UPDATE: You can do that both ways. As long as you 'seperate' each command with a carriage return.

http://elmelectronics.com/ELM327/AT_Commands.pdf http://elmelectronics.com/DSheets/ELM327DS.pdf (Expanded list).

That command list was quite usefull to me.

ATAT can be used to the adjust the timeout. When you send 010D, the ELM chip will wait normally 200 ms, to get all possible reactions. Sometimes you can get more returns, so it waits the 200 ms.

What you also can do, and it's a mystery as only scantools tend to implement this:

'010D1/r'

The 1 after the command, specifies the ELM should report back, when it has 1 reply from the bus. So it reduces the delay quite efficiently, at the cost of not able to get more values from the address '010D'. (Which is speed!)

Sorry for my english, I hope send you in the right direction.

Upvotes: 2

Related Questions