brendan-w / python-OBD

OBD-II serial module for reading engine data
GNU General Public License v2.0
1.02k stars 360 forks source link

Synchronisation issue with ELM327 #226

Closed ddowling closed 2 years ago

ddowling commented 2 years ago

I was having problems getting the python-obd library to reliably sync with a cheap ELM327 clone. I believe the problem is due to some code added to elm327.py to support low power mode. Specifically the line line elm327.py:548

      # end on chevron (ELM prompt character) or an 'OK' which
      # indicates we are entering low power state
      if self.ELM_PROMPT in buffer or self.ELM_LP_ACTIVE in buffer:
          break

During start up the following exchange happens with the ELM327:

[obd.elm327] Initializing ELM327: PORT=/dev/ttyUSB0 BAUD=auto PROTOCOL=auto
[obd.elm327] Response from baud 38400: b'?\r\r>'
[obd.elm327] Choosing baud 38400
[obd.elm327] write: b'ATZ\r'
[obd.elm327] wait: 1 seconds
[obd.elm327] read: b'\xfc\r\rELM327 v1.5\r\r>'
[obd.elm327] write: b'ATE0\r'
[obd.elm327] read: b'ATE0\rOK'
[obd.elm327] write: b'ATH1\r'
[obd.elm327] read: b'>'
[obd.elm327] closing port
[obd.elm327] write: b'ATZ\r'
[obd.elm327] ATH1 did not return 'OK', or echoing is still ON

Note how after ATE0 is sent to the ELM327 we receive back the echoed command and then an OK. This OK matches the ELM_LP_ACTIVE clause and the command returns before reading the next line containing the chevron prompt. When the ATH1 command is sent to the ELM327 the chevron prompt is then read and the code assumes this command has failed.

The fix is to always attempt to read up to the chevron prompt and to not bail out early if we read OK in the response stream. If I change line 548 to the following the adapter connects reliably everytime:

    if self.ELM_PROMPT in buffer:
                break
[obd.elm327] Initializing ELM327: PORT=/dev/ttyUSB0 BAUD=auto PROTOCOL=auto
[obd.elm327] Response from baud 38400: b'\x7f\x7f\r?\r\r>'
[obd.elm327] Choosing baud 38400
[obd.elm327] write: b'ATZ\r'
[obd.elm327] wait: 1 seconds
[obd.elm327] read: b'ATZ\r\xfc\r\rELM327 v1.5\r\r>'
[obd.elm327] write: b'ATE0\r'
[obd.elm327] read: b'ATE0\rOK\r\r>'
[obd.elm327] write: b'ATH1\r'
[obd.elm327] read: b'OK\r\r>'
[obd.elm327] write: b'ATL0\r'
[obd.elm327] read: b'OK\r\r>'
[obd.elm327] write: b'AT RV\r'
[obd.elm327] read: b'0.0V\r\r>'
[obd.elm327] OBD2 socket disconnected

I am not sure how my change will impact the low power mode as I am not using this but I am happy to test out an alternate fix if required.

interfect commented 2 years ago

I ran into this today too. I have a fix where I made the end marker an argument to the reading function, pulled it through to __send, and then set it to the prompt by default and the low power mode acknowledgment only when we send the command to enter low power mode. That seems to work and should not break low power mode.

I will try and make a PR of this soon; I have to pull it off the computer that can go into the car.