From ac03e26a973b9ff04a5d843ebf0e47e36449bece Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 5 Nov 2012 15:55:14 +0000 Subject: [PATCH 01/20] Decoupling obd_io from wx For users who don't want to install wx (i.e. they're living in a console only environment), we just print the debug message to the screen and ignore the fact that we don't have wx installed. --- .gitignore | 1 + debugEvent.py | 76 ++++++++++++++++++++++++++++----------------------- obd_io.py | 22 +++++++-------- 3 files changed, 54 insertions(+), 45 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7e99e367 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/debugEvent.py b/debugEvent.py index f0587571..c6a57eb3 100644 --- a/debugEvent.py +++ b/debugEvent.py @@ -1,34 +1,42 @@ - #!/usr/bin/env python -########################################################################### -# obd_sensors.py -# -# Copyright 2004 Donour Sizemore (donour@uchicago.edu) -# Copyright 2009 Secons Ltd. (www.obdtester.com) -# -# This file is part of pyOBD. -# -# pyOBD is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# pyOBD is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with pyOBD; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -########################################################################### -import wx - -EVT_DEBUG_ID = 1010 - -class DebugEvent(wx.PyEvent): - """Simple event to carry arbitrary result data.""" - def __init__(self, data): - """Init Result Event.""" - wx.PyEvent.__init__(self) - self.SetEventType(EVT_DEBUG_ID) - self.data = data \ No newline at end of file + #!/usr/bin/env python +########################################################################### +# obd_sensors.py +# +# Copyright 2004 Donour Sizemore (donour@uchicago.edu) +# Copyright 2009 Secons Ltd. (www.obdtester.com) +# +# This file is part of pyOBD. +# +# pyOBD is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# pyOBD is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyOBD; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +########################################################################### +try: + import wx + + EVT_DEBUG_ID = 1010 + + def debug_display(window, position, message): + wx.PostEvent(window, DebugEvent([position, message])) + + class DebugEvent(wx.PyEvent): + """Simple event to carry arbitrary result data.""" + def __init__(self, data): + """Init Result Event.""" + wx.PyEvent.__init__(self) + self.SetEventType(EVT_DEBUG_ID) + self.data = data +except ImportError as e: + def debug_display(window, position, message): + print message + diff --git a/obd_io.py b/obd_io.py index 7dd6d1cb..eaf6f6be 100644 --- a/obd_io.py +++ b/obd_io.py @@ -26,7 +26,6 @@ import string import time from math import ceil -import wx #due to debugEvent messaging import obd_sensors @@ -36,7 +35,7 @@ CLEAR_DTC_COMMAND = "04" GET_FREEZE_DTC_COMMAND = "07" -from debugEvent import * +from debugEvent import debug_display #__________________________________________________________________________ def decrypt_dtc_code(code): @@ -81,9 +80,10 @@ def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): to = SERTIMEOUT self.ELMver = "Unknown" self.State = 1 #state SERIAL is 1 connected, 0 disconnected (connection failed) + self.port = None self._notify_window=_notify_window - wx.PostEvent(self._notify_window, DebugEvent([1,"Opening interface (serial port)"])) + debug_display(self._notify_window, 1, "Opening interface (serial port)") try: self.port = serial.Serial(portnum,baud, \ @@ -94,8 +94,8 @@ def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): self.State = 0 return None - wx.PostEvent(self._notify_window, DebugEvent([1,"Interface successfully " + self.port.portstr + " opened"])) - wx.PostEvent(self._notify_window, DebugEvent([1,"Connecting to ECU..."])) + debug_display(self._notify_window, 1, "Interface successfully " + self.port.portstr + " opened") + debug_display(self._notify_window, 1, "Connecting to ECU...") try: self.send_command("atz") # initialize @@ -104,12 +104,12 @@ def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): return None self.ELMver = self.get_result() - wx.PostEvent(self._notify_window, DebugEvent([2,"atz response:" + self.ELMver])) + debug_display(self._notify_window, 2, "atz response:" + self.ELMver) self.send_command("ate0") # echo off - wx.PostEvent(self._notify_window, DebugEvent([2,"ate0 response:" + self.get_result()])) + debug_display(self._notify_window, 2, "ate0 response:" + self.get_result()) self.send_command("0100") ready = self.get_result() - wx.PostEvent(self._notify_window, DebugEvent([2,"0100 response:" + ready])) + debug_display(self._notify_window, 2, "0100 response:" + ready) return None def close(self): @@ -130,7 +130,7 @@ def send_command(self, cmd): for c in cmd: self.port.write(c) self.port.write("\r\n") - wx.PostEvent(self._notify_window, DebugEvent([3,"Send command:" + cmd])) + debug_display(self._notify_window, 3, "Send command:" + cmd) def interpret_result(self,code): """Internal use only: not a public interface""" @@ -171,10 +171,10 @@ def get_result(self): else: if buffer != "" or c != ">": #if something is in buffer, add everything buffer = buffer + c - wx.PostEvent(self._notify_window, DebugEvent([3,"Get result:" + buffer])) + debug_display(self._notify_window, 3, "Get result:" + buffer) return buffer else: - wx.PostEvent(self._notify_window, DebugEvent([3,"NO self.port!" + buffer])) + debug_display(self._notify_window, 3, "NO self.port!" + buffer) return None # get sensor value from command From 89c31125422ab708e4079377d489eae55875495c Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 5 Nov 2012 16:19:19 +0000 Subject: [PATCH 02/20] Moving scanSerial into its own module Moving scanSerial so it can be used by other things other than pyobd --- obd_recorder.py | 23 +++++++++++++++++++++++ obd_utils.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++ pyobd | 50 ++----------------------------------------------- 3 files changed, 73 insertions(+), 48 deletions(-) create mode 100644 obd_recorder.py create mode 100644 obd_utils.py diff --git a/obd_recorder.py b/obd_recorder.py new file mode 100644 index 00000000..fb242b8b --- /dev/null +++ b/obd_recorder.py @@ -0,0 +1,23 @@ +import obd_io +import serial +import platform + +from obd_utils import scanSerial + +class OBD_Recorder(): + def connect(self): + portnames = scanSerial() + print portnames + for port in portnames: + self.port = obd_io.OBDPort(port, None, 2, 2) + if(self.port.State == 0): + self.port.close() + self.port = None + else: + break + + if(self.port): + print "Connected to "+self.port.port.name + +o = OBD_Recorder() +o.connect() \ No newline at end of file diff --git a/obd_utils.py b/obd_utils.py new file mode 100644 index 00000000..6452c7e7 --- /dev/null +++ b/obd_utils.py @@ -0,0 +1,48 @@ +import serial +import platform + +def scanSerial(): + """scan for available ports. return a list of serial names""" + available = [] + for i in range(256): + try: #scan standart ttyS* + s = serial.Serial(i) + available.append(s.portstr) + s.close() # explicit close 'cause of delayed GC in java + except serial.SerialException: + pass + for i in range(256): + try: #scan USB ttyACM + s = serial.Serial("/dev/ttyACM"+str(i)) + available.append(s.portstr) + s.close() # explicit close 'cause of delayed GC in java + except serial.SerialException: + pass + for i in range(256): + try: + s = serial.Serial("/dev/ttyUSB"+str(i)) + available.append(s.portstr) + s.close() # explicit close 'cause of delayed GC in java + except serial.SerialException: + pass + for i in range(256): + try: + s = serial.Serial("/dev/ttyd"+str(i)) + available.append(s.portstr) + s.close() # explicit close 'cause of delayed GC in java + except serial.SerialException: + pass + + # ELM-USB shows up as /dev/tty.usbmodemXXXX, where XXXX is a changing hex string + # on connection; so we have to search through all 64K options + if len(platform.mac_ver()[0])!=0: #search only on MAC + for i in range (65535): + extension = hex(i).replace("0x","", 1) + try: + s = serial.Serial("/dev/tty.usbmodem"+extension) + available.append(s.portstr) + s.close() + except serial.SerialException: + pass + + return available diff --git a/pyobd b/pyobd index a8180a47..dbc3b4e7 100755 --- a/pyobd +++ b/pyobd @@ -40,6 +40,7 @@ import webbrowser #open browser from python from obd2_codes import pcodes from obd2_codes import ptest +from obd_utils import scanSerial from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin @@ -599,59 +600,12 @@ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 0211 self.ThreadControl=1 self.nb.SetSelection(3) - - def scanSerial(self): - """scan for available ports. return a list of serial names""" - available = [] - for i in range(256): - try: #scan standart ttyS* - s = serial.Serial(i) - available.append(s.portstr) - s.close() # explicit close 'cause of delayed GC in java - except serial.SerialException: - pass - for i in range(256): - try: #scan USB ttyACM - s = serial.Serial("/dev/ttyACM"+str(i)) - available.append(s.portstr) - s.close() # explicit close 'cause of delayed GC in java - except serial.SerialException: - pass - for i in range(256): - try: - s = serial.Serial("/dev/ttyUSB"+str(i)) - available.append(s.portstr) - s.close() # explicit close 'cause of delayed GC in java - except serial.SerialException: - pass - for i in range(256): - try: - s = serial.Serial("/dev/ttyd"+str(i)) - available.append(s.portstr) - s.close() # explicit close 'cause of delayed GC in java - except serial.SerialException: - pass - - # ELM-USB shows up as /dev/tty.usbmodemXXXX, where XXXX is a changing hex string - # on connection; so we have to search through all 64K options - if len(platform.mac_ver()[0])!=0: #search only on MAC - for i in range (65535): - extension = hex(i).replace("0x","", 1) - try: - s = serial.Serial("/dev/tty.usbmodem"+extension) - available.append(s.portstr) - s.close() - except serial.SerialException: - pass - - return available - def Configure(self,e = None): id = 0 diag = wx.Dialog(self.frame, id, title="Configure") sizer = wx.BoxSizer(wx.VERTICAL) - ports = self.scanSerial() + ports = scanSerial() rb = wx.RadioBox(diag, id, "Choose Serial Port", choices = ports, style = wx.RA_SPECIFY_COLS, majorDimension = 2) From b1191a01393245f87aefbd2b4ab0522b2497b7ac Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 5 Nov 2012 16:43:16 +0000 Subject: [PATCH 03/20] If we do have wx installed but have no window, don't crash --- debugEvent.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debugEvent.py b/debugEvent.py index c6a57eb3..555ed234 100644 --- a/debugEvent.py +++ b/debugEvent.py @@ -27,7 +27,10 @@ EVT_DEBUG_ID = 1010 def debug_display(window, position, message): - wx.PostEvent(window, DebugEvent([position, message])) + if window is None: + print message + else: + wx.PostEvent(window, DebugEvent([position, message])) class DebugEvent(wx.PyEvent): """Simple event to carry arbitrary result data.""" From 7d332e21656dc5eb1a16196fec92b6924dcfd06b Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 5 Nov 2012 16:43:46 +0000 Subject: [PATCH 04/20] Removing the infinite read loop and adding checking --- obd_io.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/obd_io.py b/obd_io.py index eaf6f6be..a5fa97c9 100644 --- a/obd_io.py +++ b/obd_io.py @@ -104,11 +104,20 @@ def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): return None self.ELMver = self.get_result() + if(self.ELMver is None): + self.State = 0 + return None + debug_display(self._notify_window, 2, "atz response:" + self.ELMver) self.send_command("ate0") # echo off debug_display(self._notify_window, 2, "ate0 response:" + self.get_result()) self.send_command("0100") ready = self.get_result() + + if(ready is None): + self.State = 0 + return None + debug_display(self._notify_window, 2, "0100 response:" + ready) return None @@ -162,16 +171,26 @@ def interpret_result(self,code): def get_result(self): """Internal use only: not a public interface""" time.sleep(0.1) - if self.port: + repeat_count = 0 + if self.port is not None: buffer = "" while 1: c = self.port.read(1) + if len(c) == 0: + if(repeat_count == 5): + break + repeat_count = repeat_count + 1 + continue + if c == '\r' and len(buffer) > 0: break - else: - if buffer != "" or c != ">": #if something is in buffer, add everything - buffer = buffer + c + + if buffer != "" or c != ">": #if something is in buffer, add everything + buffer = buffer + c + debug_display(self._notify_window, 3, "Get result:" + buffer) + if(buffer == ""): + return None return buffer else: debug_display(self._notify_window, 3, "NO self.port!" + buffer) From 2df3b90997d78f290ea63f9efbd4f84d608ffb58 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 5 Nov 2012 17:37:04 +0000 Subject: [PATCH 05/20] Adding logger and is_connected function to recorder --- obd_recorder.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/obd_recorder.py b/obd_recorder.py index fb242b8b..a543b1f8 100644 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -1,10 +1,20 @@ import obd_io import serial import platform +import logging from obd_utils import scanSerial class OBD_Recorder(): + def __init__(self, filename): + self.port = None + self.logger = logging.getLogger(__name__) + log_handler = logging.FileHandler(filename) + log_formatter = logging.Formatter('%(asctime)s %(message)s') + log_handler.setFormatter(log_formatter) + self.logger.addHandler(log_handler) + self.logger.setLevel(logging.INFO) + def connect(self): portnames = scanSerial() print portnames @@ -19,5 +29,18 @@ def connect(self): if(self.port): print "Connected to "+self.port.port.name -o = OBD_Recorder() -o.connect() \ No newline at end of file + def is_connected(self): + return self.port + +# def record_data(self): +# for n in range(1,10): +# self.logger.info('woo %s %s %s yay', n, n, n) + + + +o = OBD_Recorder('bikestuff.log') +o.connect() +if not o.is_connected(): + print "Not connected" + +#o.record_data() \ No newline at end of file From 10a0ad70ce9e7dc55dccb19a9957365d054fa24b Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Tue, 6 Nov 2012 13:46:57 +0000 Subject: [PATCH 06/20] Adding shortname to sensor list --- obd_sensors.py | 70 +++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/obd_sensors.py b/obd_sensors.py index 7ae4650e..1f8c6d2a 100644 --- a/obd_sensors.py +++ b/obd_sensors.py @@ -126,47 +126,47 @@ def hex_to_bitstring(str): return bitstring class Sensor: - def __init__(self,sensorName, sensorcommand, sensorValueFunction, u): + def __init__(self, shortName, sensorName, sensorcommand, sensorValueFunction, u): + self.shortname = shortName self.name = sensorName self.cmd = sensorcommand self.value= sensorValueFunction self.unit = u SENSORS = [ - Sensor(" Supported PIDs", "0100", hex_to_bitstring ,"" ), - Sensor("Status Since DTC Cleared", "0101", dtc_decrypt ,"" ), - Sensor("DTC Causing Freeze Frame", "0102", cpass ,"" ), - Sensor(" Fuel System Status", "0103", cpass ,"" ), - Sensor(" Calculated Load Value", "0104", percent_scale ,"" ), - Sensor(" Coolant Temperature", "0105", temp ,"C" ), - Sensor(" Short Term Fuel Trim", "0106", fuel_trim_percent ,"%" ), - Sensor(" Long Term Fuel Trim", "0107", fuel_trim_percent ,"%" ), - Sensor(" Short Term Fuel Trim", "0108", fuel_trim_percent ,"%" ), - Sensor(" Long Term Fuel Trim", "0109", fuel_trim_percent ,"%" ), - Sensor(" Fuel Rail Pressure", "010A", cpass ,"" ), - Sensor("Intake Manifold Pressure", "010B", intake_m_pres ,"psi" ), - Sensor(" Engine RPM", "010C", rpm ,"" ), - Sensor(" Vehicle Speed", "010D", speed ,"MPH" ), - Sensor(" Timing Advance", "010E", timing_advance ,"degrees"), - Sensor(" Intake Air Temp", "010F", temp ,"C" ), - Sensor(" Air Flow Rate (MAF)", "0110", maf ,"lb/min" ), - Sensor(" Throttle Position", "0111", throttle_pos ,"%" ), - Sensor(" Secondary Air Status", "0112", cpass ,"" ), - Sensor(" Location of O2 sensors", "0113", cpass ,"" ), - Sensor(" O2 Sensor: 1 - 1", "0114", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 1 - 2", "0115", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 1 - 3", "0116", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 1 - 4", "0117", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 2 - 1", "0118", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 2 - 2", "0119", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 2 - 3", "011A", fuel_trim_percent ,"%" ), - Sensor(" O2 Sensor: 2 - 4", "011B", fuel_trim_percent ,"%" ), - Sensor(" OBD Designation", "011C", cpass ,"" ), - Sensor(" Location of O2 sensors", "011D", cpass ,"" ), - Sensor(" Aux input status", "011E", cpass ,"" ), - Sensor(" Time Since Engine Start", "011F", sec_to_min ,"min" ), - Sensor(" Engine Run with MIL on", "014E", sec_to_min ,"min" ), - + Sensor("pids" , " Supported PIDs", "0100", hex_to_bitstring ,"" ), + Sensor("dtc_status" , "Status Since DTC Cleared", "0101", dtc_decrypt ,"" ), + Sensor("dtc_ff" , "DTC Causing Freeze Frame", "0102", cpass ,"" ), + Sensor("fuel_status" , " Fuel System Status", "0103", cpass ,"" ), + Sensor("load" , " Calculated Load Value", "0104", percent_scale ,"" ), + Sensor("temp" , " Coolant Temperature", "0105", temp ,"C" ), + Sensor("short_term_fuel_trim_1", " Short Term Fuel Trim", "0106", fuel_trim_percent,"%" ), + Sensor("long_term_fuel_trim_1" , " Long Term Fuel Trim", "0107", fuel_trim_percent,"%" ), + Sensor("short_term_fuel_trim_2", " Short Term Fuel Trim", "0108", fuel_trim_percent,"%" ), + Sensor("long_term_fuel_trim_2" , " Long Term Fuel Trim", "0109", fuel_trim_percent,"%" ), + Sensor("fuel_pressure" , " Fuel Rail Pressure", "010A", cpass ,"" ), + Sensor("manifold_pressure" , "Intake Manifold Pressure", "010B", intake_m_pres ,"psi" ), + Sensor("rpm" , " Engine RPM", "010C", rpm ,"" ), + Sensor("speed" , " Vehicle Speed", "010D", speed ,"MPH" ), + Sensor("timing_advance" , " Timing Advance", "010E", timing_advance ,"degrees"), + Sensor("intake_air_temp" , " Intake Air Temp", "010F", temp ,"C" ), + Sensor("maf" , " Air Flow Rate (MAF)", "0110", maf ,"lb/min" ), + Sensor("throttle_pos" , " Throttle Position", "0111", throttle_pos ,"%" ), + Sensor("secondary_air_status" , " Secondary Air Status", "0112", cpass ,"" ), + Sensor("o2_sensor_positions" , " Location of O2 sensors", "0113", cpass ,"" ), + Sensor("o211" , " O2 Sensor: 1 - 1", "0114", fuel_trim_percent,"%" ), + Sensor("o212" , " O2 Sensor: 1 - 2", "0115", fuel_trim_percent,"%" ), + Sensor("o213" , " O2 Sensor: 1 - 3", "0116", fuel_trim_percent,"%" ), + Sensor("o214" , " O2 Sensor: 1 - 4", "0117", fuel_trim_percent,"%" ), + Sensor("o221" , " O2 Sensor: 2 - 1", "0118", fuel_trim_percent,"%" ), + Sensor("o222" , " O2 Sensor: 2 - 2", "0119", fuel_trim_percent,"%" ), + Sensor("o223" , " O2 Sensor: 2 - 3", "011A", fuel_trim_percent,"%" ), + Sensor("o224" , " O2 Sensor: 2 - 4", "011B", fuel_trim_percent,"%" ), + Sensor("obd_standard" , " OBD Designation", "011C", cpass ,"" ), + Sensor("o2_sensor_position_b" ," Location of O2 sensors" , "011D", cpass ,"" ), + Sensor("aux_input" , " Aux input status", "011E", cpass ,"" ), + Sensor("engine_time" , " Time Since Engine Start", "011F", sec_to_min ,"min" ), + Sensor("engine_mil_time" , " Engine Run with MIL on", "014D", sec_to_min ,"min" ), ] From fd868c417474219c15b602473f02c6f20d33a7d8 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Tue, 6 Nov 2012 13:47:13 +0000 Subject: [PATCH 07/20] Adding function to add item to log by shortname in the sensor list --- obd_recorder.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/obd_recorder.py b/obd_recorder.py index a543b1f8..7878594f 100644 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -2,12 +2,14 @@ import serial import platform import logging +import obd_sensors from obd_utils import scanSerial class OBD_Recorder(): def __init__(self, filename): self.port = None + self.sensorlist = [] self.logger = logging.getLogger(__name__) log_handler = logging.FileHandler(filename) log_formatter = logging.Formatter('%(asctime)s %(message)s') @@ -32,6 +34,14 @@ def connect(self): def is_connected(self): return self.port + def add_log_item(self, item): + for e in obd_sensors.SENSORS: + if(item == e.shortname): + self.sensorlist.append(e) + print "Logging item: "+e.name + break + + # def record_data(self): # for n in range(1,10): # self.logger.info('woo %s %s %s yay', n, n, n) @@ -39,8 +49,10 @@ def is_connected(self): o = OBD_Recorder('bikestuff.log') +o.add_log_item("rpm") +o.add_log_item("speed") +o.add_log_item("throttle_pos") o.connect() if not o.is_connected(): print "Not connected" - -#o.record_data() \ No newline at end of file +#o.record_data() From 9646ddb9abb8ab192096087e5f86e4198519d6c2 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Tue, 6 Nov 2012 15:36:21 +0000 Subject: [PATCH 08/20] Correcting debug_display for no port --- obd_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obd_io.py b/obd_io.py index a5fa97c9..e15f698a 100644 --- a/obd_io.py +++ b/obd_io.py @@ -193,7 +193,7 @@ def get_result(self): return None return buffer else: - debug_display(self._notify_window, 3, "NO self.port!" + buffer) + debug_display(self._notify_window, 3, "NO self.port!") return None # get sensor value from command From 32d8e1214257e835e8d4e89b44110a62136a2849 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Tue, 6 Nov 2012 15:36:52 +0000 Subject: [PATCH 09/20] Adding record_data function for logging data for requested items --- obd_recorder.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/obd_recorder.py b/obd_recorder.py index 7878594f..3b16cb90 100644 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -35,16 +35,22 @@ def is_connected(self): return self.port def add_log_item(self, item): - for e in obd_sensors.SENSORS: + for index, e in enumerate(obd_sensors.SENSORS): if(item == e.shortname): - self.sensorlist.append(e) + self.sensorlist.append(index) print "Logging item: "+e.name break -# def record_data(self): -# for n in range(1,10): -# self.logger.info('woo %s %s %s yay', n, n, n) + def record_data(self): + if(self.port is None): + return None + + print "Logging started" + while 1: + for index in self.sensorlist: + (name, value, unit) = self.port.sensor(index) + self.logger.info('%s,%s,%s',obd_sensors.SENSORS[index].shortname,value,unit) @@ -55,4 +61,4 @@ def add_log_item(self, item): o.connect() if not o.is_connected(): print "Not connected" -#o.record_data() +o.record_data() From 31c847c221cd459c9c9ba8624a106e6eaa9301cc Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Tue, 6 Nov 2012 20:10:30 +0000 Subject: [PATCH 10/20] Changing Baud to 38400 as that's what my usb port ends up using. --- obd_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obd_io.py b/obd_io.py index e15f698a..d444d0fc 100644 --- a/obd_io.py +++ b/obd_io.py @@ -73,7 +73,7 @@ class OBDPort: def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): """Initializes port by resetting device and gettings supported PIDs. """ # These should really be set by the user. - baud = 9600 + baud = 38400 databits = 8 par = serial.PARITY_NONE # parity sb = 1 # stop bits From ebcf0f8dc1c6b1321e293e58e968f87635388b2f Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Tue, 6 Nov 2012 22:19:43 +0000 Subject: [PATCH 11/20] Adding checks for ISO OBD connections for UNABLE TO CONNECT and SEARCHING... --- obd_io.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/obd_io.py b/obd_io.py index d444d0fc..7816e455 100644 --- a/obd_io.py +++ b/obd_io.py @@ -183,6 +183,11 @@ def get_result(self): continue if c == '\r' and len(buffer) > 0: + if(buffer == "SEARCHING..."): + buffer = "" + continue + if(buffer == "UNABLE TO CONNECT"): + return None break if buffer != "" or c != ">": #if something is in buffer, add everything From da0a9394ddfa470f3f6da6bf68fa19ddb9c4697c Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Wed, 7 Nov 2012 21:57:16 +0000 Subject: [PATCH 12/20] Adding specific expected message sizes for certain requests --- obd_sensors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/obd_sensors.py b/obd_sensors.py index 1f8c6d2a..ebf323be 100644 --- a/obd_sensors.py +++ b/obd_sensors.py @@ -146,12 +146,12 @@ def __init__(self, shortName, sensorName, sensorcommand, sensorValueFunction, u) Sensor("long_term_fuel_trim_2" , " Long Term Fuel Trim", "0109", fuel_trim_percent,"%" ), Sensor("fuel_pressure" , " Fuel Rail Pressure", "010A", cpass ,"" ), Sensor("manifold_pressure" , "Intake Manifold Pressure", "010B", intake_m_pres ,"psi" ), - Sensor("rpm" , " Engine RPM", "010C", rpm ,"" ), - Sensor("speed" , " Vehicle Speed", "010D", speed ,"MPH" ), + Sensor("rpm" , " Engine RPM", "010C1", rpm ,"" ), + Sensor("speed" , " Vehicle Speed", "010D1", speed ,"MPH" ), Sensor("timing_advance" , " Timing Advance", "010E", timing_advance ,"degrees"), Sensor("intake_air_temp" , " Intake Air Temp", "010F", temp ,"C" ), Sensor("maf" , " Air Flow Rate (MAF)", "0110", maf ,"lb/min" ), - Sensor("throttle_pos" , " Throttle Position", "0111", throttle_pos ,"%" ), + Sensor("throttle_pos" , " Throttle Position", "01111", throttle_pos ,"%" ), Sensor("secondary_air_status" , " Secondary Air Status", "0112", cpass ,"" ), Sensor("o2_sensor_positions" , " Location of O2 sensors", "0113", cpass ,"" ), Sensor("o211" , " O2 Sensor: 1 - 1", "0114", fuel_trim_percent,"%" ), From e702a38483c4bfd5a011865ddf0cbc762b5f2535 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Wed, 7 Nov 2012 22:05:24 +0000 Subject: [PATCH 13/20] Concatenate multiple message lines And use the ">" as the end --- obd_io.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/obd_io.py b/obd_io.py index d444d0fc..8daece6c 100644 --- a/obd_io.py +++ b/obd_io.py @@ -99,6 +99,7 @@ def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): try: self.send_command("atz") # initialize + time.sleep(1) except serial.SerialException: self.State = 0 return None @@ -170,7 +171,7 @@ def interpret_result(self,code): def get_result(self): """Internal use only: not a public interface""" - time.sleep(0.1) + time.sleep(0.01) repeat_count = 0 if self.port is not None: buffer = "" @@ -182,9 +183,12 @@ def get_result(self): repeat_count = repeat_count + 1 continue - if c == '\r' and len(buffer) > 0: - break - + if c == '\r': + continue + + if c == ">": + break; + if buffer != "" or c != ">": #if something is in buffer, add everything buffer = buffer + c From e359c87eb31fc4ed9add5a04ba8b326830d61dd7 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Wed, 7 Nov 2012 22:05:42 +0000 Subject: [PATCH 14/20] Change date format to remove date. --- obd_recorder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/obd_recorder.py b/obd_recorder.py index 3b16cb90..6091094b 100644 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -12,13 +12,14 @@ def __init__(self, filename): self.sensorlist = [] self.logger = logging.getLogger(__name__) log_handler = logging.FileHandler(filename) - log_formatter = logging.Formatter('%(asctime)s %(message)s') + log_formatter = logging.Formatter('%(asctime)s,%(message)s', "%H:%M:%S:%f") log_handler.setFormatter(log_formatter) self.logger.addHandler(log_handler) self.logger.setLevel(logging.INFO) def connect(self): portnames = scanSerial() + #portnames = ['COM10'] print portnames for port in portnames: self.port = obd_io.OBDPort(port, None, 2, 2) From 75dde02f99fcf5f896f92a18173f975594edeb88 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Wed, 7 Nov 2012 22:06:25 +0000 Subject: [PATCH 15/20] Adding script type to script --- obd_recorder.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 obd_recorder.py diff --git a/obd_recorder.py b/obd_recorder.py old mode 100644 new mode 100755 index 3b16cb90..7cae1913 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import obd_io import serial import platform From f36d344936a73d58b288bdd834cbd2f5ba770f87 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Wed, 7 Nov 2012 22:13:22 +0000 Subject: [PATCH 16/20] Erm --- obd_io.py | 17 ++++++++--------- obd_recorder.py | 3 ++- obd_sensors.py | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/obd_io.py b/obd_io.py index 7816e455..8daece6c 100644 --- a/obd_io.py +++ b/obd_io.py @@ -99,6 +99,7 @@ def __init__(self,portnum,_notify_window,SERTIMEOUT,RECONNATTEMPTS): try: self.send_command("atz") # initialize + time.sleep(1) except serial.SerialException: self.State = 0 return None @@ -170,7 +171,7 @@ def interpret_result(self,code): def get_result(self): """Internal use only: not a public interface""" - time.sleep(0.1) + time.sleep(0.01) repeat_count = 0 if self.port is not None: buffer = "" @@ -182,14 +183,12 @@ def get_result(self): repeat_count = repeat_count + 1 continue - if c == '\r' and len(buffer) > 0: - if(buffer == "SEARCHING..."): - buffer = "" - continue - if(buffer == "UNABLE TO CONNECT"): - return None - break - + if c == '\r': + continue + + if c == ">": + break; + if buffer != "" or c != ">": #if something is in buffer, add everything buffer = buffer + c diff --git a/obd_recorder.py b/obd_recorder.py index 7cae1913..76497b35 100755 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -14,13 +14,14 @@ def __init__(self, filename): self.sensorlist = [] self.logger = logging.getLogger(__name__) log_handler = logging.FileHandler(filename) - log_formatter = logging.Formatter('%(asctime)s %(message)s') + log_formatter = logging.Formatter('%(asctime)s,%(message)s', "%H:%M:%S:%f") log_handler.setFormatter(log_formatter) self.logger.addHandler(log_handler) self.logger.setLevel(logging.INFO) def connect(self): portnames = scanSerial() + #portnames = ['COM10'] print portnames for port in portnames: self.port = obd_io.OBDPort(port, None, 2, 2) diff --git a/obd_sensors.py b/obd_sensors.py index 1f8c6d2a..ebf323be 100644 --- a/obd_sensors.py +++ b/obd_sensors.py @@ -146,12 +146,12 @@ def __init__(self, shortName, sensorName, sensorcommand, sensorValueFunction, u) Sensor("long_term_fuel_trim_2" , " Long Term Fuel Trim", "0109", fuel_trim_percent,"%" ), Sensor("fuel_pressure" , " Fuel Rail Pressure", "010A", cpass ,"" ), Sensor("manifold_pressure" , "Intake Manifold Pressure", "010B", intake_m_pres ,"psi" ), - Sensor("rpm" , " Engine RPM", "010C", rpm ,"" ), - Sensor("speed" , " Vehicle Speed", "010D", speed ,"MPH" ), + Sensor("rpm" , " Engine RPM", "010C1", rpm ,"" ), + Sensor("speed" , " Vehicle Speed", "010D1", speed ,"MPH" ), Sensor("timing_advance" , " Timing Advance", "010E", timing_advance ,"degrees"), Sensor("intake_air_temp" , " Intake Air Temp", "010F", temp ,"C" ), Sensor("maf" , " Air Flow Rate (MAF)", "0110", maf ,"lb/min" ), - Sensor("throttle_pos" , " Throttle Position", "0111", throttle_pos ,"%" ), + Sensor("throttle_pos" , " Throttle Position", "01111", throttle_pos ,"%" ), Sensor("secondary_air_status" , " Secondary Air Status", "0112", cpass ,"" ), Sensor("o2_sensor_positions" , " Location of O2 sensors", "0113", cpass ,"" ), Sensor("o211" , " O2 Sensor: 1 - 1", "0114", fuel_trim_percent,"%" ), From 2d656e7442924c3a6cfcacf95949c2cb88faf4c0 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Fri, 23 Nov 2012 18:50:19 +0000 Subject: [PATCH 17/20] Changing time format --- obd_recorder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/obd_recorder.py b/obd_recorder.py index 76497b35..1a1b86ea 100755 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -14,7 +14,7 @@ def __init__(self, filename): self.sensorlist = [] self.logger = logging.getLogger(__name__) log_handler = logging.FileHandler(filename) - log_formatter = logging.Formatter('%(asctime)s,%(message)s', "%H:%M:%S:%f") + log_formatter = logging.Formatter('%(asctime)s:%(msecs).03d,%(message)s', "%H:%M:%S") log_handler.setFormatter(log_formatter) self.logger.addHandler(log_handler) self.logger.setLevel(logging.INFO) @@ -57,7 +57,7 @@ def record_data(self): -o = OBD_Recorder('bikestuff.log') +o = OBD_Recorder('/home/pi/logs/bikelog.log') o.add_log_item("rpm") o.add_log_item("speed") o.add_log_item("throttle_pos") From c6cb31bd245db1f6ed5fb38a1d7049ef32bfae0c Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Sun, 16 Dec 2012 15:14:54 +0000 Subject: [PATCH 18/20] Changing logging to header + comma delimited format Adding gear calculation and load to logging --- obd_io.py | 4 ++-- obd_recorder.py | 55 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/obd_io.py b/obd_io.py index 8daece6c..ed2fa1f9 100644 --- a/obd_io.py +++ b/obd_io.py @@ -140,7 +140,7 @@ def send_command(self, cmd): for c in cmd: self.port.write(c) self.port.write("\r\n") - debug_display(self._notify_window, 3, "Send command:" + cmd) + #debug_display(self._notify_window, 3, "Send command:" + cmd) def interpret_result(self,code): """Internal use only: not a public interface""" @@ -192,7 +192,7 @@ def get_result(self): if buffer != "" or c != ">": #if something is in buffer, add everything buffer = buffer + c - debug_display(self._notify_window, 3, "Get result:" + buffer) + #debug_display(self._notify_window, 3, "Get result:" + buffer) if(buffer == ""): return None return buffer diff --git a/obd_recorder.py b/obd_recorder.py index 1a1b86ea..a6e432ae 100755 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -3,22 +3,27 @@ import obd_io import serial import platform -import logging import obd_sensors +import datetime +import time from obd_utils import scanSerial class OBD_Recorder(): - def __init__(self, filename): + def __init__(self, path, log_items): self.port = None self.sensorlist = [] - self.logger = logging.getLogger(__name__) - log_handler = logging.FileHandler(filename) - log_formatter = logging.Formatter('%(asctime)s:%(msecs).03d,%(message)s', "%H:%M:%S") - log_handler.setFormatter(log_formatter) - self.logger.addHandler(log_handler) - self.logger.setLevel(logging.INFO) - + localtime = time.localtime(time.time()) + filename = path+"bike-"+str(localtime[0])+"-"+str(localtime[1])+"-"+str(localtime[2])+"-"+str(localtime[3])+"-"+str(localtime[4])+"-"+str(localtime[5])+".log" + self.log_file = open(filename, "w", 128) + self.log_file.write("Time,RPM,MPH,Throttle,Gear"); + + for item in log_items: + self.add_log_item(item) + + self.gear_ratios = [34/13, 39/21, 36/23, 27/20, 26/21, 25/22] + #log_formatter = logging.Formatter('%(asctime)s.%(msecs).03d,%(message)s', "%H:%M:%S") + def connect(self): portnames = scanSerial() #portnames = ['COM10'] @@ -50,17 +55,37 @@ def record_data(self): return None print "Logging started" + while 1: + localtime = datetime.now() + current_time = str(localtime.hour)+":"+str(localtime.minute)+":"+str(localtime.second)+"."+str(localtime.microsecond) + log_string = current_time + for index in self.sensorlist: (name, value, unit) = self.port.sensor(index) - self.logger.info('%s,%s,%s',obd_sensors.SENSORS[index].shortname,value,unit) - + log_string = log_string + ","+str(value) + results[obd_sensors.SENSORS[index].shortname] = value; + + gear = self.calculate_gear(results["rpm"], results["speed"]) + log_string = log_string + "," + str(gear) + self.log_file.write(log_string) + def calculate_gear(self, rpm, speed): + rps = rpm/60 + mps = (speed*1.609*1000)/3600 + + primary_gear = 85/46 #street triple + final_drive = 47/16 -o = OBD_Recorder('/home/pi/logs/bikelog.log') -o.add_log_item("rpm") -o.add_log_item("speed") -o.add_log_item("throttle_pos") + tyre_circumference = 1.978 #meters + + current_gear_ratio = (rps*tyre_circumference)/(mps*primary_gear*final_drive) + gear = min((abs(current_gear_ratio - i), i) for i in self.gear_ratios)[1] + return gear + + +logitems = ["rpm", "speed", "throttle_pos", "load"] +o = OBD_Recorder('/home/pi/logs/', logitems) o.connect() if not o.is_connected(): print "Not connected" From 8b168073875db33ac18e96182e1d81ab2a3a23b0 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Sun, 16 Dec 2012 15:17:42 +0000 Subject: [PATCH 19/20] Adding error checking --- obd_recorder.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/obd_recorder.py b/obd_recorder.py index a6e432ae..863150c0 100755 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -71,6 +71,11 @@ def record_data(self): self.log_file.write(log_string) def calculate_gear(self, rpm, speed): + if speed == "" or speed == 0: + return 0 + if rpm == "" or rpm == 0: + return 0 + rps = rpm/60 mps = (speed*1.609*1000)/3600 From 773187211da6373cb6951a35e5357489814b6eb1 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Sun, 16 Dec 2012 16:20:05 +0000 Subject: [PATCH 20/20] Fixing bugs --- obd_io.py | 5 ++++- obd_recorder.py | 10 ++++++---- obd_sensors.py | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/obd_io.py b/obd_io.py index ed2fa1f9..79413af7 100644 --- a/obd_io.py +++ b/obd_io.py @@ -26,6 +26,7 @@ import string import time from math import ceil +from datetime import datetime import obd_sensors @@ -171,7 +172,7 @@ def interpret_result(self,code): def get_result(self): """Internal use only: not a public interface""" - time.sleep(0.01) + #time.sleep(0.01) repeat_count = 0 if self.port is not None: buffer = "" @@ -180,6 +181,7 @@ def get_result(self): if len(c) == 0: if(repeat_count == 5): break + print "Got nothing\n" repeat_count = repeat_count + 1 continue @@ -213,6 +215,7 @@ def get_sensor_value(self,sensor): data = sensor.value(data) else: return "NORESPONSE" + return data # return string of sensor name and value from sensor index diff --git a/obd_recorder.py b/obd_recorder.py index 863150c0..9f0691c2 100755 --- a/obd_recorder.py +++ b/obd_recorder.py @@ -4,7 +4,7 @@ import serial import platform import obd_sensors -import datetime +from datetime import datetime import time from obd_utils import scanSerial @@ -16,7 +16,7 @@ def __init__(self, path, log_items): localtime = time.localtime(time.time()) filename = path+"bike-"+str(localtime[0])+"-"+str(localtime[1])+"-"+str(localtime[2])+"-"+str(localtime[3])+"-"+str(localtime[4])+"-"+str(localtime[5])+".log" self.log_file = open(filename, "w", 128) - self.log_file.write("Time,RPM,MPH,Throttle,Gear"); + self.log_file.write("Time,RPM,MPH,Throttle,Load,Gear\n"); for item in log_items: self.add_log_item(item) @@ -60,7 +60,7 @@ def record_data(self): localtime = datetime.now() current_time = str(localtime.hour)+":"+str(localtime.minute)+":"+str(localtime.second)+"."+str(localtime.microsecond) log_string = current_time - + results = {} for index in self.sensorlist: (name, value, unit) = self.port.sensor(index) log_string = log_string + ","+str(value) @@ -68,7 +68,7 @@ def record_data(self): gear = self.calculate_gear(results["rpm"], results["speed"]) log_string = log_string + "," + str(gear) - self.log_file.write(log_string) + self.log_file.write(log_string+"\n") def calculate_gear(self, rpm, speed): if speed == "" or speed == 0: @@ -85,6 +85,8 @@ def calculate_gear(self, rpm, speed): tyre_circumference = 1.978 #meters current_gear_ratio = (rps*tyre_circumference)/(mps*primary_gear*final_drive) + + print current_gear_ratio gear = min((abs(current_gear_ratio - i), i) for i in self.gear_ratios)[1] return gear diff --git a/obd_sensors.py b/obd_sensors.py index ebf323be..59b58329 100644 --- a/obd_sensors.py +++ b/obd_sensors.py @@ -138,7 +138,7 @@ def __init__(self, shortName, sensorName, sensorcommand, sensorValueFunction, u) Sensor("dtc_status" , "Status Since DTC Cleared", "0101", dtc_decrypt ,"" ), Sensor("dtc_ff" , "DTC Causing Freeze Frame", "0102", cpass ,"" ), Sensor("fuel_status" , " Fuel System Status", "0103", cpass ,"" ), - Sensor("load" , " Calculated Load Value", "0104", percent_scale ,"" ), + Sensor("load" , " Calculated Load Value", "01041", percent_scale ,"" ), Sensor("temp" , " Coolant Temperature", "0105", temp ,"C" ), Sensor("short_term_fuel_trim_1", " Short Term Fuel Trim", "0106", fuel_trim_percent,"%" ), Sensor("long_term_fuel_trim_1" , " Long Term Fuel Trim", "0107", fuel_trim_percent,"%" ),