-
Notifications
You must be signed in to change notification settings - Fork 377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support ELM327 error messages #87
base: master
Are you sure you want to change the base?
Changes from all commits
52d4ec3
0604239
a1a0236
9d823cb
eb87fec
65b50e7
bf84882
17df9c4
281ed1a
5b136f9
ec755ad
11d909a
5d45f3c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -287,15 +287,17 @@ | |
|
||
__mode9__ = [ | ||
# name description cmd bytes decoder ECU fast | ||
# OBDCommand("PIDS_9A" , "Supported PIDs [01-20]" , b"0900", 4, pid, ECU.ENGINE, True), | ||
# OBDCommand("VIN_MESSAGE_COUNT" , "VIN Message Count" , b"0901", 1, uas(0x01), ECU.ENGINE, True), | ||
# OBDCommand("VIN" , "Get Vehicle Identification Number" , b"0902", 20, raw_string, ECU.ENGINE, True), | ||
OBDCommand("PIDS_9A" , "Supported PIDs [01-20]" , b"0900", 4, pid, ECU.ENGINE, True), | ||
OBDCommand("VIN_MESSAGE_COUNT" , "VIN Message Count" , b"0901", 1, uas(0x01), ECU.ENGINE, True), | ||
OBDCommand("VIN" , "Get Vehicle Identification Number" , b"0902", 20, raw_string, ECU.ENGINE, True), | ||
] | ||
|
||
__misc__ = [ | ||
# name description cmd bytes decoder ECU fast | ||
OBDCommand("ELM_VERSION" , "ELM327 version string" , b"ATI", 0, raw_string, ECU.UNKNOWN, False), | ||
OBDCommand("ELM_VOLTAGE" , "Voltage detected by OBD-II adapter" , b"ATRV", 0, elm_voltage, ECU.UNKNOWN, False), | ||
OBDCommand("FAKE_COMMAND_1" , "Non-existing command returning error" , b"ATXYZ", 0, raw_string, ECU.UNKNOWN, False), | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this used for anything here besides development? I don't think python-OBD needs to be shipped with a fake command. |
||
] | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,6 +101,24 @@ class ELM327: | |
# going to be less picky about the time required to detect it. | ||
_TRY_BAUDS = [ 38400, 9600, 230400, 115200, 57600, 19200 ] | ||
|
||
_ERROR_MESSAGES = [ | ||
[b"?", "?: ELM327 reports misundersting command received on the RS232 input."], | ||
[b"ACT ALERT", "ACT ALERT: ELM327 warns no RS232 activity. Might switch to low-power standby mode."], | ||
[b"BUFFER FULL", "BUFFER FULL: ELM327 reports that RS232 buffer is filling at a faster rate than transmission. Increase baud speed."], | ||
[b"BUS BUSY", "BUS BUSY: ELM327 reports too much activity on BUS. Check wiring."], | ||
[b"BUS ERROR", "BUS ERROR: ELM327 reports a BUS error. This might be normal when starting CAN listening."], | ||
[b"CAN ERROR", "CAN ERROR: ELM327 reports a CAN system ERROR. CAN has difficulty initializing, sending or receiving."], | ||
[b"<DATA ERROR", "<DATA ERROR: ELM327 reports an error in the line number following."], | ||
[b"DATA ERROR", "DATA ERROR: ELM327 reports an error response from vehicule, data lost."], | ||
[b"FB ERROR", "EFB ERROR: ELM327 reports a feedBack(FB) error affecting signal. Check cable."], | ||
[b"LP ALERT", "LP ALERT: ELM327 is about to switch to the Low Power (standby) mode within 2 seconds."], | ||
[b"LV RESET", "LV RESET: ELM327 performed a low-voltage reset."], | ||
[b"NO DATA", "NO DATA: ELM327 returns no data, either because answer is empty or not understood or not supported."], | ||
[b"<RX ERROR", "<RX ERROR: ELM327 reports an error in the received CAN data. Check connection parameters."], | ||
[b"STOPPED", "STOPPED: ELM327 reports that OBD operation was interrupted by a received RS232 character, or by a low level on the RTS pin."], | ||
[b"UNABLE TO CONNECT", "UNABLE TO CONNECT: ELM327 tried all available protocols, and could not detect a compatible one."], | ||
[b"ERR", "ERR: ELM327 reports an error number following."] | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is awesome, thanks! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be turned into a dictionary for clarity?
|
||
|
||
|
||
def __init__(self, portname, baudrate, protocol): | ||
|
@@ -117,7 +135,6 @@ def __init__(self, portname, baudrate, protocol): | |
self.__port = None | ||
self.__protocol = UnknownProtocol([]) | ||
|
||
|
||
# ------------- open port ------------- | ||
try: | ||
self.__port = serial.Serial(portname, \ | ||
|
@@ -258,7 +275,7 @@ def auto_protocol(self): | |
def set_baudrate(self, baud): | ||
if baud is None: | ||
# when connecting to pseudo terminal, don't bother with auto baud | ||
if self.port_name().startswith("/dev/pts"): | ||
if self.get_port_name().startswith("/dev/pts"): | ||
logger.debug("Detected pseudo terminal, skipping baudrate setup") | ||
return True | ||
else: | ||
|
@@ -330,29 +347,36 @@ def __error(self, msg): | |
logger.error(str(msg)) | ||
|
||
|
||
def port_name(self): | ||
def get_port_name(self): | ||
if self.__port is not None: | ||
return self.__port.portstr | ||
else: | ||
return "" | ||
|
||
|
||
def status(self): | ||
return self.__status | ||
|
||
|
||
def ecus(self): | ||
return self.__protocol.ecu_map.values() | ||
def get_port_baudrate(self): | ||
if self.__port is not None: | ||
return self.__port.baudrate | ||
else: | ||
return "" | ||
|
||
|
||
def protocol_name(self): | ||
def get_protocol_name(self): | ||
return self.__protocol.ELM_NAME | ||
|
||
|
||
def protocol_id(self): | ||
def get_protocol_id(self): | ||
return self.__protocol.ELM_ID | ||
|
||
|
||
def get_ecus(self): | ||
return self.__protocol.ecu_map.values() | ||
|
||
|
||
def status(self): | ||
return self.__status | ||
|
||
|
||
def close(self): | ||
""" | ||
Resets the device, and sets all | ||
|
@@ -442,14 +466,20 @@ def __read(self): | |
|
||
# if nothing was recieved | ||
if not data: | ||
logger.warning("Failed to read port") | ||
logger.warning("Failed to read port: empty data.") | ||
break | ||
|
||
buffer.extend(data) | ||
|
||
# end on chevron (ELM prompt character) | ||
if self.ELM_PROMPT in buffer: | ||
break | ||
|
||
#Check errors received by ELM327 and write debug | ||
for iError in self._ERROR_MESSAGES: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor nit-pick: in python, we typically prefer lower-case, underscore separated names. For this, simply |
||
if iError[0] in buffer: | ||
logger.debug(iError[1]) | ||
break | ||
|
||
# log, and remove the "bytearray( ... )" part | ||
logger.debug("read: " + repr(buffer)[10:-1]) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -155,40 +155,46 @@ def status(self): | |
return self.interface.status() | ||
|
||
|
||
# not sure how useful this would be | ||
|
||
# def ecus(self): | ||
# """ returns a list of ECUs in the vehicle """ | ||
# if self.interface is None: | ||
# return [] | ||
# else: | ||
# return self.interface.ecus() | ||
def get_ecus(self): | ||
""" returns a list of ECUs in the vehicle """ | ||
if self.interface is None: | ||
return [] | ||
else: | ||
return self.interface.get_ecus() | ||
|
||
|
||
def protocol_name(self): | ||
def get_protocol_name(self): | ||
""" returns the name of the protocol being used by the ELM327 """ | ||
if self.interface is None: | ||
return "" | ||
else: | ||
return self.interface.protocol_name() | ||
return self.interface.get_protocol_name() | ||
|
||
|
||
def protocol_id(self): | ||
def get_protocol_id(self): | ||
""" returns the ID of the protocol being used by the ELM327 """ | ||
if self.interface is None: | ||
return "" | ||
else: | ||
return self.interface.protocol_id() | ||
return self.interface.get_protocol_id() | ||
|
||
|
||
def port_name(self): | ||
def get_port_name(self): | ||
""" Returns the name of the currently connected port """ | ||
if self.interface is not None: | ||
return self.interface.port_name() | ||
return self.interface.get_port_name() | ||
else: | ||
return "" | ||
|
||
|
||
def get_port_baudrate(self): | ||
""" Returns the speed of the currently connected port """ | ||
if self.interface is not None: | ||
return str(self.interface.get_port_baudrate()) | ||
else: | ||
return "" | ||
|
||
|
||
def is_connected(self): | ||
""" | ||
Returns a boolean for whether a connection with the car was made. | ||
|
@@ -207,13 +213,46 @@ def print_commands(self): | |
for c in self.supported_commands: | ||
print(str(c)) | ||
|
||
|
||
def print_discovered(self): | ||
""" | ||
Utility function meant to print all information discovered: | ||
protocol, port name, port baudrate and all supported commands. | ||
""" | ||
if self.interface is not None: | ||
print ("The following settings were used to connect to the ECU:") | ||
print ("Protocole: " + self.get_protocol_name()) | ||
print ("Port name: " + self.get_port_name()) | ||
print ("Port rate: " + self.get_port_baudrate()) | ||
print ("The following OBD commands are supported:") | ||
|
||
_mylist=[] | ||
for c in self.supported_commands: | ||
_mylist.append(str(c)) | ||
_mylist.sort() | ||
for i in _mylist: | ||
print (i) | ||
|
||
else: | ||
print ("Impossible to print discovered information: no connection to the ECU.") | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind rebasing-out these changes? (assuming that they aren't co-dependant) That way, the two changes can cleanly come in via two PR's. Same with the addition of the |
||
def supports(self, cmd): | ||
""" | ||
Returns a boolean for whether the given command | ||
is supported by the car | ||
""" | ||
return cmd in self.supported_commands | ||
|
||
|
||
def get_supported_commands(self): | ||
""" | ||
Returns a list of commands | ||
supported by the car | ||
""" | ||
|
||
if self.interface is not None: | ||
return self.supported_commands | ||
else: | ||
return [] | ||
|
||
|
||
def test_cmd(self, cmd, warn=True): | ||
|
@@ -228,7 +267,7 @@ def test_cmd(self, cmd, warn=True): | |
return False | ||
|
||
# mode 06 is only implemented for the CAN protocols | ||
if cmd.mode == 6 and self.interface.protocol_id() not in ["6", "7", "8", "9"]: | ||
if cmd.mode == 6 and self.interface.get_protocol_id() not in ["6", "7", "8", "9"]: | ||
if warn: | ||
logger.warning("Mode 06 commands are only supported over CAN protocols") | ||
return False | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were you able to get
VIN
to work?