From 2f5d2fd4680a1d1cdc95831fc852efa07a7fb1de Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sun, 8 Dec 2019 13:20:14 -0800 Subject: [PATCH 01/24] Add support for Mode 9 PIDS This adds support for the Mode 9 PIDS, including VIN and CVN. This is baed on the original work by Paul Mundt (https://github.com/brendan-w/python-OBD/pull/151). This patch includes adding a few test cases for the new decoders. Signed-off-by: Alistair Francis --- README.md | 1 + docs/Command Tables.md | 22 ++++++++++++++++++++++ obd/commands.py | 23 +++++++++++++++++++++++ obd/decoders.py | 29 +++++++++++++++++++++++++++++ tests/test_decoders.py | 8 ++++++++ 5 files changed, 83 insertions(+) diff --git a/README.md b/README.md index cb386a1d..319594e7 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Here are a handful of the supported commands (sensors). For a full list, see [th - Time since trouble codes cleared - Hybrid battery pack remaining life - Engine fuel rate +- Vehicle Identification Number (VIN) Common Issues ------------- diff --git a/docs/Command Tables.md b/docs/Command Tables.md index 8ea0046f..9b8d6e45 100644 --- a/docs/Command Tables.md +++ b/docs/Command Tables.md @@ -261,3 +261,25 @@ The return value will be encoded in the same structure as the Mode 03 `GET_DTC` | N/A | GET_CURRENT_DTC | Get DTCs from the current/last driving cycle | [special](Responses.md#diagnostic-trouble-codes-dtcs) |
+ +# Mode 09 + +*WARNING: mode 09 is experimental. While it has been tested on a hardware simulator, only a subset of the supported +commands have (00-06) been tested. Any debug output for this mode, especially for the untested PIDs, would be greatly appreciated.* + +|PID | Name | Description | Response Value | +|----|------------------------------|----------------------------------------------------|-----------------------| +| 00 | PIDS_9A | Supported PIDs [01-20] | BitArray | +| 01 | VIN_MESSAGE_COUNT | VIN Message Count | Unit.count | +| 02 | VIN | Vehicle Identification Number | string | +| 03 | CALIBRATION_ID_MESSAGE_COUNT | Calibration ID message count for PID 04 | Unit.count | +| 04 | CALIBRATION_ID | Calibration ID | string | +| 05 | CVN_MESSAGE_COUNT | CVN Message Count for PID 06 | Unit.count | +| 06 | CVN | Calibration Verification Numbers | hex string | +| 07 | PERF_TRACKING_MESSAGE_COUNT | Performance tracking message count | TODO | +| 08 | PERF_TRACKING_SPARK | In-use performance tracking (spark ignition) | TODO | +| 09 | ECU_NAME_MESSAGE_COUNT | ECU Name Message Count for PID 0A | TODO | +| 0a | ECU_NAME | ECU Name | TODO | +| 0b | PERF_TRACKING_COMPRESSION | In-use performance tracking (compression ignition) | TODO | + +
diff --git a/obd/commands.py b/obd/commands.py index 43ec8f3c..9162f1c8 100644 --- a/obd/commands.py +++ b/obd/commands.py @@ -279,6 +279,27 @@ OBDCommand("GET_CURRENT_DTC", "Get DTCs from the current/last driving cycle", b"07", 0, dtc, ECU.ALL, False), ] + +__mode9__ = [ + # name description cmd bytes decoder ECU fast + OBDCommand("PIDS_9A" , "Supported PIDs [01-20]" , b"0900", 7, pid, ECU.ALL, True), + OBDCommand("VIN_MESSAGE_COUNT" , "VIN Message Count" , b"0901", 3, count, ECU.ENGINE, True), + OBDCommand("VIN" , "Vehicle Identification Number" , b"0902", 22, encoded_string(17), ECU.ENGINE, True), + OBDCommand("CALIBRATION_ID_MESSAGE_COUNT","Calibration ID message count for PID 04" , b"0903", 3, count, ECU.ALL, True), + OBDCommand("CALIBRATION_ID" , "Calibration ID" , b"0904", 18, encoded_string(16), ECU.ALL, True), + OBDCommand("CVN_MESSAGE_COUNT" , "CVN Message Count for PID 06" , b"0905", 3, count, ECU.ALL, True), + OBDCommand("CVN" , "Calibration Verification Numbers" , b"0906", 10, cvn, ECU.ALL, True), + +# +# NOTE: The following are untested +# +# OBDCommand("PERF_TRACKING_MESSAGE_COUNT", "Performance tracking message count" , b"0907", 3, count, ECU.ALL, True), +# OBDCommand("PERF_TRACKING_SPARK" , "In-use performance tracking (spark ignition)" , b"0908", 4, raw_string, ECU.ALL, True), +# OBDCommand("ECU_NAME_MESSAGE_COUNT" , "ECU Name Message Count for PID 0A" , b"0909", 3, count, ECU.ALL, True), +# OBDCommand("ECU_NAME" , "ECU Name" , b"090a", 20, raw_string, ECU.ALL, True), +# OBDCommand("PERF_TRACKING_COMPRESSION" , "In-use performance tracking (compression ignition)", b"090b", 4, raw_string, ECU.ALL, True), +] + __misc__ = [ 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), @@ -303,6 +324,7 @@ def __init__(self): __mode6__, __mode7__, [], + __mode9__, ] # allow commands to be accessed by name @@ -350,6 +372,7 @@ def base_commands(self): """ return [ self.PIDS_A, + self.PIDS_9A, self.MIDS_A, self.GET_DTC, self.CLEAR_DTC, diff --git a/obd/decoders.py b/obd/decoders.py index 3020be0c..fffca50a 100644 --- a/obd/decoders.py +++ b/obd/decoders.py @@ -94,6 +94,10 @@ def decode_uas(messages, id_): Return pint Quantities """ +def count(messages): + d = messages[0].data[2:] + v = bytes_to_int(d) + return v * Unit.count # 0 to 100 % def percent(messages): @@ -484,3 +488,28 @@ def monitor(messages): mon.add_test(test) return mon + + +def encoded_string(length): + """ Extract an encoded string from multi-part messages """ + return functools.partial(decode_encoded_string, length=length) + + +def decode_encoded_string(messages, length): + d = messages[0].data[2:] + + if len(d) < length: + logger.debug("Invalid string {}. Discarding...", d) + return None + + # Encoded strings come in bundles of messages with leading null values to + # pad out the string to the next full message size. We strip off the + # leading null characters here and return the resulting string. + return d.strip().strip(b'\x00' b'\x01' b'\x02' b'\\x00' b'\\x01' b'\\x02') + + +def cvn(messages): + d = decode_encoded_string(messages, 4) + if d is None: + return None + return bytes_to_hex(d) diff --git a/tests/test_decoders.py b/tests/test_decoders.py index 9f49b062..062d9655 100644 --- a/tests/test_decoders.py +++ b/tests/test_decoders.py @@ -295,6 +295,14 @@ def test_dtc(): ("B0003", ""), ] +def test_vin_message_count(): + assert d.count(m("0901")) == 0 + +def test_vin(): + assert d.encoded_string(17)(m("0201575030" + "5A5A5A39395A54" + "53333932313234")) == bytearray(b'WP0ZZZ99ZTS392124') + +def test_cvn(): + assert d.cvn(m("6021791bc8216e0b")) == '791bc8216e' def test_monitor(): # single test ----------------------------------------- From 74ba2bc673a292a3bf2ea2305b4a7ec43f670680 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 26 Feb 2020 22:21:12 -0800 Subject: [PATCH 02/24] travis: Drop support for Python2 Signed-off-by: Alistair Francis --- .travis.yml | 4 ---- tox.ini | 18 ++---------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index ae1b63cb..54f43108 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,8 @@ install: matrix: include: - - python: '2.7' - env: TOXENV=check27 - python: '3.6' env: TOXENV=check36 - - python: '2.7' - env: TOXENV=py27 - python: '3.4' env: TOXENV=py34 - python: '3.5' diff --git a/tox.ini b/tox.ini index 50d3cff8..3812569d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,9 @@ [tox] envlist = - check{27,36}, - py{27,py,34,35,36,37}, + check{36}, + py{34,35,36,37}, coverage - [testenv] usedevelop = true setenv = @@ -19,22 +18,9 @@ commands = rm -vf {toxinidir}/.coverage_{envname} pytest --cov-report= --cov=obd {posargs} -[testenv:check27] -basepython = python2.7 -skipsdist = true -deps = - check-manifest==0.37 - flake8==3.7.7 -commands = - flake8 {envsitepackagesdir}/obd - python setup.py check --strict --metadata - - [testenv:check36] basepython = python3.6 skipsdist = true -deps = {[testenv:check27]deps} -commands = {[testenv:check27]commands} [testenv:coverage] From c6af7e12cab51ea78d16aedd858f67b6465d7722 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 26 Feb 2020 22:23:37 -0800 Subject: [PATCH 03/24] travis: Test Python 3.8 Signed-off-by: Alistair Francis --- .travis.yml | 5 ++++- tox.ini | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 54f43108..57c84096 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python dist: xenial sudo: false - install: - pip install tox @@ -10,6 +9,8 @@ matrix: include: - python: '3.6' env: TOXENV=check36 + - python: '3.8' + env: TOXENV=check38 - python: '3.4' env: TOXENV=py34 - python: '3.5' @@ -18,6 +19,8 @@ matrix: env: TOXENV=py36 - python: '3.7' env: TOXENV=py37 + - python: '3.8' + env: TOXENV=py38 script: - tox diff --git a/tox.ini b/tox.ini index 3812569d..2de0b4a1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = - check{36}, - py{34,35,36,37}, + check{36,38}, + py{34,35,36,37,38}, coverage [testenv] From c14db6a3f13c3b0cf43dc6701d146cc92b08e5eb Mon Sep 17 00:00:00 2001 From: Catalin Ghenea Date: Fri, 10 Jul 2020 03:55:29 +0300 Subject: [PATCH 04/24] Fix ECU ID for legacy protocol #### Issues Addressed When using OBD over legacy protocols like K-line the message is rejected because the ecu id is undefined even if the data is retrieved correctly. #### Summary of changes Add the ENGINE ID and TRANSMISSION ID to the list of ecu map at object creation time to have it available when receiving the message. #### Summary of testing Data is retrieved correctly on K-Line. Car used VW Lupo GTI Data is retrieved correctly on CAN cars. Car used Ford Focus. Signed-off-by: Catalin Ghenea --- obd/protocols/protocol.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/obd/protocols/protocol.py b/obd/protocols/protocol.py index e677c03d..b07d2f7c 100644 --- a/obd/protocols/protocol.py +++ b/obd/protocols/protocol.py @@ -146,6 +146,12 @@ def __init__(self, lines_0100): # for example: self.TX_ID_ENGINE : ECU.ENGINE self.ecu_map = {} + if (self.TX_ID_ENGINE is not None): + self.ecu_map[self.TX_ID_ENGINE] = ECU.ENGINE + + if (self.TX_ID_TRANSMISSION is not None): + self.ecu_map[self.TX_ID_TRANSMISSION] = ECU.TRANSMISSION + # parse the 0100 data into messages # NOTE: at this point, their "ecu" property will be UNKNOWN messages = self(lines_0100) From d5a0fcd87b2df57cf38dd4ecd4b7b6b9cac018fd Mon Sep 17 00:00:00 2001 From: Ircama Date: Fri, 12 Mar 2021 13:35:06 +0100 Subject: [PATCH 05/24] Support slow OBD adapters Increase "0100" query (PIDS_A) timeout to support inexpensive/slow OBDII adapters. This patch fixes the case in which "SEARCHING" is not shown after "0100", due to slow response of cheap devices. ``` [obd.elm327] write: '0100\r' [obd.elm327] read: b'SEARCHING...\r... ``` It should also fix the case in which the debug mode needs to be active: in fact the debug logs might slow down the query timeout enough to be able to catch the query answer. Reference #205 Reference #200 Reference #187 --- obd/elm327.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obd/elm327.py b/obd/elm327.py index 79e6abff..96b1b4dd 100644 --- a/obd/elm327.py +++ b/obd/elm327.py @@ -244,7 +244,7 @@ def auto_protocol(self): r = self.__send(b"ATSP0") # -------------- 0100 (first command, SEARCH protocols) -------------- - r0100 = self.__send(b"0100") + r0100 = self.__send(b"0100", delay=1) if self.__has_message(r0100, "UNABLE TO CONNECT"): logger.error("Failed to query protocol 0100: unable to connect") return False From a36cfccf5a58eb5a26f9dc5390162e36336ed07a Mon Sep 17 00:00:00 2001 From: Catalin Ghenea Date: Mon, 21 Jun 2021 04:07:35 +0100 Subject: [PATCH 06/24] Fix protocol auto detect on BT Elm 327 #### Issues addressed Can't auto detect protocol on BT connection even if the elm devices detects the protocol successfully. Add delay after erasing stored protocols so the adapter can read the discover command #### Summary of testing Tested on an Mazda MX5. The protocol can be detected successfully on each run. Tested for about 10 times in a row. Signed-off-by: Catalin Ghenea --- obd/elm327.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obd/elm327.py b/obd/elm327.py index 96b1b4dd..db11355c 100644 --- a/obd/elm327.py +++ b/obd/elm327.py @@ -241,7 +241,7 @@ def auto_protocol(self): """ # -------------- try the ELM's auto protocol mode -------------- - r = self.__send(b"ATSP0") + r = self.__send(b"ATSP0", delay=1) # -------------- 0100 (first command, SEARCH protocols) -------------- r0100 = self.__send(b"0100", delay=1) From fe6f472c1d49738ee3e77bc99f7fece5370a442a Mon Sep 17 00:00:00 2001 From: Paul Tiedtke Date: Sun, 2 Jan 2022 00:00:23 +0100 Subject: [PATCH 07/24] Fix broken anchor link in connection docs --- docs/Connections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Connections.md b/docs/Connections.md index 8ffa9051..fe314cdf 100644 --- a/docs/Connections.md +++ b/docs/Connections.md @@ -26,7 +26,7 @@ connection = obd.OBD(ports[0]) # connect to the first port in the list `baudrate`: The baudrate at which to set the serial connection. This can vary from adapter to adapter. Typical values are: 9600, 38400, 19200, 57600, 115200. The default value (`None`) will auto select a baudrate. -`protocol`: Forces python-OBD to use the given protocol when communicating with the adapter. See [protocol_id()](Connections.md/#protocol_id) for possible values. The default value (`None`) will auto select a protocol. +`protocol`: Forces python-OBD to use the given protocol when communicating with the adapter. See [protocol_id()](#protocol_id) for possible values. The default value (`None`) will auto select a protocol. `fast`: Allows commands to be optimized before being sent to the car. Python-OBD currently makes two such optimizations: From a61b3de3b3dd689fc9478954c4ccc14d70dbd215 Mon Sep 17 00:00:00 2001 From: Roman Nyukhalov Date: Thu, 14 Apr 2022 19:04:15 +1000 Subject: [PATCH 08/24] Define CI pipeline using Github Actions --- .github/workflows/ci.yml | 28 ++++++++++++++++++++++++++++ .travis.yml | 29 ----------------------------- tox.ini | 9 ++++++++- 3 files changed, 36 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e9e764ca --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +name: CI Pipeline + +on: + push: + branches: 'master' + pull_request: + branches: '*' + +jobs: + build: + runs-on: ubuntu-18.04 + strategy: + max-parallel: 4 + fail-fast: false + matrix: + python-version: ['3.5', '3.6', '3.7', '3.8'] + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install tox tox-gh-actions + - name: Test with tox + run: tox \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 57c84096..00000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: python -dist: xenial -sudo: false - -install: - - pip install tox - -matrix: - include: - - python: '3.6' - env: TOXENV=check36 - - python: '3.8' - env: TOXENV=check38 - - python: '3.4' - env: TOXENV=py34 - - python: '3.5' - env: TOXENV=py35 - - python: '3.6' - env: TOXENV=py36 - - python: '3.7' - env: TOXENV=py37 - - python: '3.8' - env: TOXENV=py38 - -script: - - tox - -cache: - pip: true diff --git a/tox.ini b/tox.ini index 2de0b4a1..ab6217bb 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,16 @@ [tox] envlist = check{36,38}, - py{34,35,36,37,38}, + py{35,36,37,38}, coverage +[gh-actions] +python = + 3.5: py35 + 3.6: py36 + 3.7: py37 + 3.8: py38 + [testenv] usedevelop = true setenv = From a08424da2f61f64a123cf9dbabe351bd90348d94 Mon Sep 17 00:00:00 2001 From: Roman Nyukhalov Date: Wed, 27 Apr 2022 19:42:05 +1000 Subject: [PATCH 09/24] Fix test_populate_ecu_map test --- tests/test_protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_protocol.py b/tests/test_protocol.py index b2757276..0c6ccc75 100644 --- a/tests/test_protocol.py +++ b/tests/test_protocol.py @@ -74,4 +74,4 @@ def test_populate_ecu_map(): # if no messages were received, then the map is empty p = SAE_J1850_PWM([]) - assert len(p.ecu_map) == 0 + assert p.ecu_map[p.TX_ID_ENGINE] == ECU.ENGINE From dbfd379d0b5f5b65dec9d96986e8c045dd4e8f59 Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Fri, 20 May 2022 09:51:12 -0400 Subject: [PATCH 10/24] Only treat "OK" as a response terminator when appropriate Right now __read() will stop reading at "OK" even if a ">" is still coming. This can cause the ">" to be seen as the response to the next command, which confuses the initialization sequence, since the initialization sequence expects a very specific set of responses to its commands. This changes __read() so that by default it only treats ">" as the response terminator. When we issue the "ATLP" command to enter low-power mode, we will use "OK" as the response terminator instead, since that's the only time we don't expect to see a prompt. This should fix #226 and should also fix #227. --- obd/elm327.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/obd/elm327.py b/obd/elm327.py index db11355c..b543effc 100644 --- a/obd/elm327.py +++ b/obd/elm327.py @@ -55,7 +55,9 @@ class ELM327: ecus() """ + # chevron (ELM prompt character) ELM_PROMPT = b'>' + # an 'OK' which indicates we are entering low power state ELM_LP_ACTIVE = b'OK' _SUPPORTED_PROTOCOLS = { @@ -391,7 +393,7 @@ def low_power(self): logger.info("cannot enter low power when unconnected") return None - lines = self.__send(b"ATLP", delay=1) + lines = self.__send(b"ATLP", delay=1, end_marker=self.ELM_LP_ACTIVE) if 'OK' in lines: logger.debug("Successfully entered low power mode") @@ -466,13 +468,14 @@ def send_and_parse(self, cmd): messages = self.__protocol(lines) return messages - def __send(self, cmd, delay=None): + def __send(self, cmd, delay=None, end_marker=ELM_PROMPT): """ unprotected send() function will __write() the given string, no questions asked. returns result of __read() (a list of line strings) - after an optional delay. + after an optional delay, until the end marker (by + default, the prompt) is seen """ self.__write(cmd) @@ -482,13 +485,13 @@ def __send(self, cmd, delay=None): time.sleep(delay) delayed += delay - r = self.__read() + r = self.__read(end_marker=end_marker) while delayed < 1.0 and len(r) <= 0: d = 0.1 logger.debug("no response; wait: %f seconds" % d) time.sleep(d) delayed += d - r = self.__read() + r = self.__read(end_marker=end_marker) return r def __write(self, cmd): @@ -512,11 +515,12 @@ def __write(self, cmd): else: logger.info("cannot perform __write() when unconnected") - def __read(self): + def __read(self, end_marker=ELM_PROMPT): """ "low-level" read function - accumulates characters until the prompt character is seen + accumulates characters until the end marker (by + default, the prompt character) is seen returns a list of [/r/n] delimited strings """ if not self.__port: @@ -543,9 +547,8 @@ def __read(self): buffer.extend(data) - # 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: + # end on specified end-marker sequence + if end_marker in buffer: break # log, and remove the "bytearray( ... )" part From d64064d64a1fa05393d9055c92065333b91bfd58 Mon Sep 17 00:00:00 2001 From: Roman Niukhalov Date: Mon, 11 Apr 2022 19:08:09 +0800 Subject: [PATCH 11/24] Update pint version to 0.19.* --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 17a9c7e8..2e542b81 100644 --- a/setup.py +++ b/setup.py @@ -30,5 +30,5 @@ packages=find_packages(), include_package_data=True, zip_safe=False, - install_requires=["pyserial==3.*", "pint==0.7.*"], + install_requires=["pyserial==3.*", "pint==0.19.*"], ) From c7be924a21c5d0be87cce51e3087e8fb21a0ecf2 Mon Sep 17 00:00:00 2001 From: Roman Niukhalov Date: Fri, 3 Jun 2022 09:12:14 +1000 Subject: [PATCH 12/24] Update the python version range to 3.8-3.10 --- .github/workflows/ci.yml | 4 ++-- tox.ini | 17 +++++------------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9e764ca..0bc5b768 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: max-parallel: 4 fail-fast: false matrix: - python-version: ['3.5', '3.6', '3.7', '3.8'] + python-version: ['3.8', '3.9', '3.10'] steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} @@ -25,4 +25,4 @@ jobs: python -m pip install --upgrade pip python -m pip install tox tox-gh-actions - name: Test with tox - run: tox \ No newline at end of file + run: tox diff --git a/tox.ini b/tox.ini index ab6217bb..ffee2943 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,13 @@ [tox] envlist = - check{36,38}, - py{35,36,37,38}, + py{38,39,310}, coverage [gh-actions] python = - 3.5: py35 - 3.6: py36 - 3.7: py37 3.8: py38 + 3.9: py39 + 3.10: py310 [testenv] usedevelop = true @@ -17,19 +15,14 @@ setenv = COVERAGE_FILE={toxinidir}/.coverage_{envname} deps = pdbpp==0.9.6 - pytest==3.10.1 - pytest-cov==2.6.1 + pytest==7.1.2 + pytest-cov==3.0.0 whitelist_externals = rm commands = rm -vf {toxinidir}/.coverage_{envname} pytest --cov-report= --cov=obd {posargs} -[testenv:check36] -basepython = python3.6 -skipsdist = true - - [testenv:coverage] skipsdist = true deps = From c55a7a98f29c427365a35491bee328762bf38a9b Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 24 Jan 2023 22:28:43 +1000 Subject: [PATCH 13/24] tox.ini: Bump the python and pypi versions Signed-off-by: Alistair Francis --- tox.ini | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tox.ini b/tox.ini index ffee2943..20476082 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py{38,39,310}, + py{38,39,310,311}, coverage [gh-actions] @@ -8,19 +8,17 @@ python = 3.8: py38 3.9: py39 3.10: py310 + 3.11: py311 [testenv] usedevelop = true setenv = COVERAGE_FILE={toxinidir}/.coverage_{envname} deps = - pdbpp==0.9.6 - pytest==7.1.2 - pytest-cov==3.0.0 -whitelist_externals = - rm + pdbpp==0.10.3 + pytest==7.2.1 + pytest-cov==4.0.0 commands = - rm -vf {toxinidir}/.coverage_{envname} pytest --cov-report= --cov=obd {posargs} [testenv:coverage] @@ -29,7 +27,6 @@ deps = coverage whitelist_externals = /bin/bash - rm commands = /bin/bash -c 'coverage combine {toxinidir}/.coverage_*' coverage html -i @@ -38,7 +35,6 @@ commands = [flake8] max-line-length = 120 - [coverage:run] omit = .tox/* From 7642ad61da237a79b8fc43bdf39debcdfbde330c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 24 Jan 2023 22:33:41 +1000 Subject: [PATCH 14/24] setup.py: Bump pint version Signed-off-by: Alistair Francis --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2e542b81..c0936440 100644 --- a/setup.py +++ b/setup.py @@ -30,5 +30,5 @@ packages=find_packages(), include_package_data=True, zip_safe=False, - install_requires=["pyserial==3.*", "pint==0.19.*"], + install_requires=["pyserial==3.*", "pint==0.20.*"], ) From e952b9172d43c21f5507b08220ec04408ec95a9f Mon Sep 17 00:00:00 2001 From: Mario Niedermeyer <61496163+Mario2407@users.noreply.github.com> Date: Tue, 7 Mar 2023 12:45:49 +0100 Subject: [PATCH 15/24] Fixed printing with brackets --- docs/Async Connections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Async Connections.md b/docs/Async Connections.md index b4074be1..8250ab04 100644 --- a/docs/Async Connections.md +++ b/docs/Async Connections.md @@ -32,7 +32,7 @@ connection = obd.Async() # a callback that prints every new value to the console def new_rpm(r): - print r.value + print (r.value) connection.watch(obd.commands.RPM, callback=new_rpm) connection.start() From d95554a0f970647b56c4f0563698c087a5866db4 Mon Sep 17 00:00:00 2001 From: Brendan Whitfield Date: Sun, 9 Jul 2023 20:08:02 -0700 Subject: [PATCH 16/24] bumped to v0.7.2 --- obd/__version__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/obd/__version__.py b/obd/__version__.py index f0788a87..fb9b668f 100644 --- a/obd/__version__.py +++ b/obd/__version__.py @@ -1 +1 @@ -__version__ = '0.7.1' +__version__ = '0.7.2' diff --git a/setup.py b/setup.py index c0936440..a5e30300 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name="obd", - version="0.7.1", + version="0.7.2", description=("Serial module for handling live sensor data from a vehicle's OBD-II port"), long_description=long_description, long_description_content_type="text/markdown", From 7d5cd0559f1ecedf4107484aa66107bc7bbde32a Mon Sep 17 00:00:00 2001 From: green-green-avk <45503261+green-green-avk@users.noreply.github.com> Date: Sun, 9 Jul 2023 15:28:38 -0700 Subject: [PATCH 17/24] Proper `obd.Unit.percent` --- obd/UnitsAndScaling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obd/UnitsAndScaling.py b/obd/UnitsAndScaling.py index b49650b1..fe0fae4d 100644 --- a/obd/UnitsAndScaling.py +++ b/obd/UnitsAndScaling.py @@ -36,8 +36,8 @@ # export the unit registry Unit = pint.UnitRegistry() -Unit.define("percent = [] = %") Unit.define("ratio = []") +Unit.define("percent = 1e-2 ratio = %") Unit.define("gps = gram / second = GPS = grams_per_second") Unit.define("lph = liter / hour = LPH = liters_per_hour") Unit.define("ppm = count / 1000000 = PPM = parts_per_million") From eb8679eb9a9e7b744a17acfee3cf38a1c80516aa Mon Sep 17 00:00:00 2001 From: Brendan Whitfield Date: Sun, 13 Aug 2023 18:43:43 -0700 Subject: [PATCH 18/24] Added readthedocs yaml config file before config files are enforced --- .readthedocs.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..ae5ae2ee --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,5 @@ +version: 2 + +mkdocs: + configuration: mkdocs.yml + fail_on_warning: false From 3ecbf6fd19d91690e3ae32162c0b58ec9667396b Mon Sep 17 00:00:00 2001 From: Brendan Whitfield Date: Sun, 13 Aug 2023 18:51:07 -0700 Subject: [PATCH 19/24] Fixed mkdocs pages -> nav config --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index bec2ac65..ad9086bb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,7 @@ repo_url: https://github.com/brendan-w/python-OBD repo_name: GitHub extra_javascript: - assets/extra.js -pages: +nav: - 'Getting Started': 'index.md' - 'OBD Connections': 'Connections.md' - 'Command Lookup': 'Command Lookup.md' From d7aad00c270598cf464741bd100c71f54bc52c63 Mon Sep 17 00:00:00 2001 From: Brendan Whitfield Date: Sun, 13 Aug 2023 18:56:18 -0700 Subject: [PATCH 20/24] Revert docs updates: This is more finicky than I anticipated Moving to a feature branch This reverts commit 3ecbf6fd19d91690e3ae32162c0b58ec9667396b. This reverts commit eb8679eb9a9e7b744a17acfee3cf38a1c80516aa. --- .readthedocs.yaml | 5 ----- mkdocs.yml | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index ae5ae2ee..00000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,5 +0,0 @@ -version: 2 - -mkdocs: - configuration: mkdocs.yml - fail_on_warning: false diff --git a/mkdocs.yml b/mkdocs.yml index ad9086bb..bec2ac65 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,7 @@ repo_url: https://github.com/brendan-w/python-OBD repo_name: GitHub extra_javascript: - assets/extra.js -nav: +pages: - 'Getting Started': 'index.md' - 'OBD Connections': 'Connections.md' - 'Command Lookup': 'Command Lookup.md' From d7c781a595e10316084454b16adccff6ee183935 Mon Sep 17 00:00:00 2001 From: Brendan Whitfield Date: Sun, 13 Aug 2023 18:43:43 -0700 Subject: [PATCH 21/24] Added readthedocs yaml config file before config files are enforced Also fixed some of the doc headers for more modern versions of mkdocs --- .readthedocs.yaml | 14 ++++++++++++++ docs/Async Connections.md | 2 ++ docs/Command Lookup.md | 2 ++ docs/Command Tables.md | 18 ++++++++++-------- docs/Connections.md | 1 + docs/Custom Commands.md | 12 ++++++------ docs/Debug.md | 2 ++ docs/Responses.md | 18 ++++++++++-------- docs/Troubleshooting.md | 5 ++--- docs/index.md | 8 ++++---- docs/requirements.txt | 1 + mkdocs.yml | 2 +- 12 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 .readthedocs.yaml create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..9c6dea9a --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,14 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +python: + install: + - requirements: docs/requirements.txt + +mkdocs: + configuration: mkdocs.yml + fail_on_warning: false diff --git a/docs/Async Connections.md b/docs/Async Connections.md index 8250ab04..d655faff 100644 --- a/docs/Async Connections.md +++ b/docs/Async Connections.md @@ -1,3 +1,5 @@ +# Async Connections + Since the standard `query()` function is blocking, it can be a hazard for UI event loops. To deal with this, python-OBD has an `Async` connection object that can be used in place of the standard `OBD` object. `Async` is a subclass of `OBD`, and therefore inherits all of the standard methods. However, `Async` adds a few in order to control a threaded update loop. This loop will keep the values of your commands up to date with the vehicle. This way, when the user `query`s the car, the latest response is returned immediately. The update loop is controlled by calling `start()` and `stop()`. To subscribe a command for updating, call `watch()` with your requested OBDCommand. Because the update loop is threaded, commands can only be `watch`ed while the loop is `stop`ed. diff --git a/docs/Command Lookup.md b/docs/Command Lookup.md index 43e9ace7..1610657d 100644 --- a/docs/Command Lookup.md +++ b/docs/Command Lookup.md @@ -1,3 +1,5 @@ +# Command Lookup + `OBDCommand`s are objects used to query information from the vehicle. They contain all of the information neccessary to perform the query, and decode the cars response. Python-OBD has [built in tables](Command Tables.md) for the most common commands. They can be looked up by name, or by mode & PID. ```python diff --git a/docs/Command Tables.md b/docs/Command Tables.md index 9b8d6e45..aebaf85d 100644 --- a/docs/Command Tables.md +++ b/docs/Command Tables.md @@ -1,4 +1,6 @@ -# OBD-II adapter (ELM327 commands) +# Commands + +## OBD-II adapter (ELM327 commands) |PID | Name | Description | Response Value | |-----|-------------|-----------------------------------------|-----------------------| @@ -7,7 +9,7 @@
-# Mode 01 +## Mode 01 |PID | Name | Description | Response Value | |----|---------------------------|-----------------------------------------|-----------------------| @@ -110,7 +112,7 @@
-# Mode 02 +## Mode 02 Mode 02 commands are the same as mode 01, but are metrics from when the last DTC occurred (the freeze frame). To access them by name, simple prepend `DTC_` to the Mode 01 command name. @@ -124,7 +126,7 @@ obd.commands.DTC_RPM # the Mode 02 command
-# Mode 03 +## Mode 03 Mode 03 contains a single command `GET_DTC` which requests all diagnostic trouble codes from the vehicle. The response will contain the codes themselves, as well as a description (if python-OBD has one). See the [DTC Responses](Responses.md#diagnostic-trouble-codes-dtcs) section for more details. @@ -135,7 +137,7 @@ Mode 03 contains a single command `GET_DTC` which requests all diagnostic troubl
-# Mode 04 +## Mode 04 |PID | Name | Description | Response Value | |-----|-----------|-----------------------------------------|-----------------------| @@ -143,7 +145,7 @@ Mode 03 contains a single command `GET_DTC` which requests all diagnostic troubl
-# Mode 06 +## Mode 06 *WARNING: mode 06 is experimental. While it passes software tests, it has not been tested on a real vehicle. Any debug output for this mode would be greatly appreciated.* @@ -252,7 +254,7 @@ Mode 06 commands are used to monitor various test results from the vehicle. All
-# Mode 07 +## Mode 07 The return value will be encoded in the same structure as the Mode 03 `GET_DTC` command. @@ -262,7 +264,7 @@ The return value will be encoded in the same structure as the Mode 03 `GET_DTC`
-# Mode 09 +## Mode 09 *WARNING: mode 09 is experimental. While it has been tested on a hardware simulator, only a subset of the supported commands have (00-06) been tested. Any debug output for this mode, especially for the untested PIDs, would be greatly appreciated.* diff --git a/docs/Connections.md b/docs/Connections.md index fe314cdf..1df861fd 100644 --- a/docs/Connections.md +++ b/docs/Connections.md @@ -1,3 +1,4 @@ +# Connections After installing the library, simply `import obd`, and create a new OBD connection object. By default, python-OBD will scan for Bluetooth and USB serial ports (in that order), and will pick the first connection it finds. The port can also be specified manually by passing a connection string to the OBD constructor. You can also use the `scan_serial` helper retrieve a list of connected ports. diff --git a/docs/Custom Commands.md b/docs/Custom Commands.md index 466deb29..e726030d 100644 --- a/docs/Custom Commands.md +++ b/docs/Custom Commands.md @@ -1,3 +1,4 @@ +# Custom Commands If the command you need is not in python-OBDs tables, you can create a new `OBDCommand` object. The constructor accepts the following arguments (each will become a property). @@ -13,8 +14,7 @@ If the command you need is not in python-OBDs tables, you can create a new `OBDC | header (optional) | string | If set, use a custom header instead of the default one (7E0) | -Example -------- +## Example ```python from obd import OBDCommand, Unit @@ -58,7 +58,7 @@ Here are some details on the less intuitive fields of an OBDCommand: --- -### OBDCommand.decoder +## OBDCommand.decoder The `decoder` argument is a function of following form. @@ -83,7 +83,7 @@ def (messages): --- -### OBDCommand.ecu +## OBDCommand.ecu The `ecu` argument is a constant used to filter incoming messages. Some commands may listen to multiple ECUs (such as DTC decoders), where others may only be concerned with the engine (such as RPM). Currently, python-OBD can only distinguish the engine, but this list may be expanded over time: @@ -94,13 +94,13 @@ The `ecu` argument is a constant used to filter incoming messages. Some commands --- -### OBDCommand.fast +## OBDCommand.fast The optional `fast` argument tells python-OBD whether it is safe to append a `"01"` to the end of the command. This will instruct the adapter to return the first response it recieves, rather than waiting for more (and eventually reaching a timeout). This can speed up requests significantly, and is enabled for most of python-OBDs internal commands. However, for unusual commands, it is safest to leave this disabled. --- -### OBDCommand.header +## OBDCommand.header The optional `header` argument tells python-OBD to use a custom header when querying the command. If not set, python-OBD assumes that the default 7E0 header is needed for querying the command. The switch between default and custom header (and vice versa) is automatically done by python-OBD. diff --git a/docs/Debug.md b/docs/Debug.md index 0f929826..5e1df610 100644 --- a/docs/Debug.md +++ b/docs/Debug.md @@ -1,3 +1,5 @@ +# Debug + python-OBD uses python's builtin logging system. By default, it is setup to send output to `stderr` with a level of WARNING. The module's logger can be accessed via the `logger` variable at the root of the module. For instance, to enable console printing of all debug messages, use the following snippet: ```python diff --git a/docs/Responses.md b/docs/Responses.md index 30b992e6..0eef78f9 100644 --- a/docs/Responses.md +++ b/docs/Responses.md @@ -1,3 +1,5 @@ +# Responses + The `query()` function returns `OBDResponse` objects. These objects have the following properties: | Property | Description | @@ -11,7 +13,7 @@ The `query()` function returns `OBDResponse` objects. These objects have the fol --- -### is_null() +## is_null() Use this function to check if a response is empty. Python-OBD will emit empty responses when it is unable to retrieve data from the car. @@ -25,7 +27,7 @@ if not r.is_null(): --- -# Pint Values +## Pint Values The `value` property typically contains a [Pint](http://pint.readthedocs.io/en/latest/) `Quantity` object, but can also hold complex structures (depending on the request). Pint quantities combine a value and unit into a single class, and are used to represent physical values such as "4 seconds", and "88 mph". This allows for consistency when doing math and unit conversions. Pint maintains a registry of units, which is exposed in python-OBD as `obd.Unit`. @@ -71,7 +73,7 @@ import obd --- -# Status +## Status The status command returns information about the Malfunction Indicator Light (check-engine light), the number of trouble codes being thrown, and the type of engine. @@ -111,7 +113,7 @@ Here are all of the tests names that python-OBD reports: --- -# Diagnostic Trouble Codes (DTCs) +## Diagnostic Trouble Codes (DTCs) Each DTC is represented by a tuple containing the DTC code, and a description (if python-OBD has one). For commands that return multiple DTCs, a list is used. @@ -129,7 +131,7 @@ response.value = ("P0104", "Mass or Volume Air Flow Circuit Intermittent") --- -# Fuel Status +## Fuel Status The fuel status is a tuple of two strings, telling the status of the first and second fuel systems. Most cars only have one system, so the second element will likely be an empty string. The possible fuel statuses are: @@ -144,7 +146,7 @@ The fuel status is a tuple of two strings, telling the status of the first and s --- -# Air Status +## Air Status The air status will be one of these strings: @@ -157,7 +159,7 @@ The air status will be one of these strings: --- -# Oxygen Sensors Present +## Oxygen Sensors Present Returns a 2D structure of tuples (representing bank and sensor number), that holds boolean values for sensor presence. @@ -183,7 +185,7 @@ response.value[1][2] == True # Bank 1, Sensor 2 is present ``` --- -# Monitors (Mode 06 Responses) +## Monitors (Mode 06 Responses) All mode 06 commands return `Monitor` objects holding various test results for the requested sensor. A single monitor response can hold multiple tests, in the form of `MonitorTest` objects. The OBD standard defines some tests, but vehicles can always implement custom tests beyond the standard. Here are the standard Test IDs (TIDs) that python-OBD will recognize: diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md index f2b9baca..7889e251 100644 --- a/docs/Troubleshooting.md +++ b/docs/Troubleshooting.md @@ -1,4 +1,3 @@ - # Debug Output If python-OBD is not working properly, the first thing you should do is enable debug output. Add the following line before your connection code to print all of the debug information to your console: @@ -52,7 +51,7 @@ Here are some common logs from python-OBD, and their meanings: ### Unresponsive ELM -``` +```none [obd] ========================== python-OBD (v0.4.0) ========================== [obd] Explicit port defined [obd] Opening serial port '/dev/pts/2' @@ -93,7 +92,7 @@ print ports # ['/dev/ttyUSB0', '/dev/ttyUSB1'] ### Unresponsive Vehicle -``` +```none [obd] ========================== python-OBD (v0.4.0) ========================== [obd] Explicit port defined [obd] Opening serial port '/dev/pts/2' diff --git a/docs/index.md b/docs/index.md index 7688edea..3d2c1e69 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ Python-OBD is a library for handling data from a car's [**O**n-**B**oard **D**ia
-# Installation +## Installation Install the latest release from pypi: @@ -22,7 +22,7 @@ $ sudo apt-get install bluetooth bluez-utils blueman
-# Basic Usage +## Basic Usage ```python import obd @@ -41,7 +41,7 @@ OBD connections operate in a request-reply fashion. To retrieve data from the ca
-# Module Layout +## Module Layout ```python import obd @@ -59,7 +59,7 @@ obd.logger # the OBD module's root logger (for debug)
-# License +## License GNU General Public License V2 diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..49ec98c5 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +mkdocs==1.5.2 diff --git a/mkdocs.yml b/mkdocs.yml index bec2ac65..ad9086bb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,7 @@ repo_url: https://github.com/brendan-w/python-OBD repo_name: GitHub extra_javascript: - assets/extra.js -pages: +nav: - 'Getting Started': 'index.md' - 'OBD Connections': 'Connections.md' - 'Command Lookup': 'Command Lookup.md' From e0304c3209ac8eb3e75cf0ad5f7afdd6612d28e3 Mon Sep 17 00:00:00 2001 From: Ion Mironov <97184530+ion-mironov@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:47:27 -0500 Subject: [PATCH 22/24] Several spelling and grammatical fixes. --- docs/Command Lookup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Command Lookup.md b/docs/Command Lookup.md index 1610657d..f87ea39a 100644 --- a/docs/Command Lookup.md +++ b/docs/Command Lookup.md @@ -1,6 +1,6 @@ # Command Lookup -`OBDCommand`s are objects used to query information from the vehicle. They contain all of the information neccessary to perform the query, and decode the cars response. Python-OBD has [built in tables](Command Tables.md) for the most common commands. They can be looked up by name, or by mode & PID. +`OBDCommand`s are objects used to query information from the vehicle. They contain all of the information necessary to perform the query and decode the car's response. Python-OBD has [built in tables](Command Tables.md) for the most common commands. They can be looked up by name or by mode & PID. ```python import obd From 54cf9b403337c0cdf6cbbd9d3ab674a665dd6fc7 Mon Sep 17 00:00:00 2001 From: BritishCopsAreClowns Date: Mon, 11 Mar 2024 23:50:59 +0000 Subject: [PATCH 23/24] Copied Wireless config stuff from here https://github.com/dailab/python-OBD-wifi --- obd/elm327.py | 121 +++++++++++++------------------------------------- 1 file changed, 30 insertions(+), 91 deletions(-) diff --git a/obd/elm327.py b/obd/elm327.py index b543effc..c3de4aa0 100644 --- a/obd/elm327.py +++ b/obd/elm327.py @@ -34,6 +34,7 @@ import serial import time import logging +import socket from .protocols import * from .utils import OBDStatus @@ -105,15 +106,14 @@ class ELM327: # going to be less picky about the time required to detect it. _TRY_BAUDS = [38400, 9600, 230400, 115200, 57600, 19200] - def __init__(self, portname, baudrate, protocol, timeout, + def __init__(self, addr, port, protocol, timeout, check_voltage=True, start_low_power=False): """Initializes port by resetting device and gettings supported PIDs. """ - logger.info("Initializing ELM327: PORT=%s BAUD=%s PROTOCOL=%s" % + logger.info("Initializing ELM327: ADDR=%s PORT=%s" % ( - portname, - "auto" if baudrate is None else baudrate, - "auto" if protocol is None else protocol, + addr, + port )) self.__status = OBDStatus.NOT_CONNECTED @@ -121,14 +121,11 @@ def __init__(self, portname, baudrate, protocol, timeout, self.__protocol = UnknownProtocol([]) self.__low_power = False self.timeout = timeout - - # ------------- open port ------------- + + # ------------- open port ------------- try: - self.__port = serial.serial_for_url(portname, - parity=serial.PARITY_NONE, - stopbits=1, - bytesize=8, - timeout=10) # seconds + self.__port = socket.socket() + self.__port.connect((addr, port)) except serial.SerialException as e: self.__error(e) return @@ -141,12 +138,6 @@ def __init__(self, portname, baudrate, protocol, timeout, self.__write(b" ") time.sleep(1) - # ------------------------ find the ELM's baud ------------------------ - - if not self.set_baudrate(baudrate): - self.__error("Failed to set baudrate") - return - # ---------------------------- ATZ (reset) ---------------------------- try: self.__send(b"ATZ", delay=1) # wait 1 second for ELM to initialize @@ -190,16 +181,15 @@ def __init__(self, portname, baudrate, protocol, timeout, self.__error("Incorrect response from 'AT RV'") return # by now, we've successfuly connected to the OBD socket - self.__status = OBDStatus.OBD_CONNECTED + self.__status = OBDStatus.OBD_CONNECTED # try to communicate with the car, and load the correct protocol parser if self.set_protocol(protocol): self.__status = OBDStatus.CAR_CONNECTED - logger.info("Connected Successfully: PORT=%s BAUD=%s PROTOCOL=%s" % + logger.info("Connected Successfully: PORT=%s PORT=%s" % ( - portname, - self.__port.baudrate, - self.__protocol.ELM_ID, + addr, + port )) else: if self.__status == OBDStatus.OBD_CONNECTED: @@ -243,10 +233,10 @@ def auto_protocol(self): """ # -------------- try the ELM's auto protocol mode -------------- - r = self.__send(b"ATSP0", delay=1) + #r = self.__send(b"ATSP0") # -------------- 0100 (first command, SEARCH protocols) -------------- - r0100 = self.__send(b"0100", delay=1) + r0100 = self.__send(b"0100") if self.__has_message(r0100, "UNABLE TO CONNECT"): logger.error("Failed to query protocol 0100: unable to connect") return False @@ -284,55 +274,6 @@ def auto_protocol(self): logger.error("Failed to determine protocol") return False - 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"): - logger.debug("Detected pseudo terminal, skipping baudrate setup") - return True - else: - return self.auto_baudrate() - else: - self.__port.baudrate = baud - return True - - def auto_baudrate(self): - """ - Detect the baud rate at which a connected ELM32x interface is operating. - Returns boolean for success. - """ - - # before we change the timout, save the "normal" value - timeout = self.__port.timeout - self.__port.timeout = self.timeout # we're only talking with the ELM, so things should go quickly - - for baud in self._TRY_BAUDS: - self.__port.baudrate = baud - self.__port.flushInput() - self.__port.flushOutput() - - # Send a nonsense command to get a prompt back from the scanner - # (an empty command runs the risk of repeating a dangerous command) - # The first character might get eaten if the interface was busy, - # so write a second one (again so that the lone CR doesn't repeat - # the previous command) - - # All commands should be terminated with carriage return according - # to ELM327 and STN11XX specifications - self.__port.write(b"\x7F\x7F\r") - self.__port.flush() - response = self.__port.read(1024) - logger.debug("Response from baud %d: %s" % (baud, repr(response))) - - # watch for the prompt character - if response.endswith(b">"): - logger.debug("Choosing baud %d" % baud) - self.__port.timeout = timeout # reinstate our original timeout - return True - - logger.debug("Failed to choose baud") - self.__port.timeout = timeout # reinstate our original timeout - return False def __isok(self, lines, expectEcho=False): if not lines: @@ -357,7 +298,7 @@ def __error(self, msg): def port_name(self): if self.__port is not None: - return self.__port.portstr + return "192.168.0.10" else: return "" @@ -393,7 +334,7 @@ def low_power(self): logger.info("cannot enter low power when unconnected") return None - lines = self.__send(b"ATLP", delay=1, end_marker=self.ELM_LP_ACTIVE) + lines = self.__send(b"ATLP", delay=1) if 'OK' in lines: logger.debug("Successfully entered low power mode") @@ -468,14 +409,13 @@ def send_and_parse(self, cmd): messages = self.__protocol(lines) return messages - def __send(self, cmd, delay=None, end_marker=ELM_PROMPT): + def __send(self, cmd, delay=None): """ unprotected send() function will __write() the given string, no questions asked. returns result of __read() (a list of line strings) - after an optional delay, until the end marker (by - default, the prompt) is seen + after an optional delay. """ self.__write(cmd) @@ -485,13 +425,13 @@ def __send(self, cmd, delay=None, end_marker=ELM_PROMPT): time.sleep(delay) delayed += delay - r = self.__read(end_marker=end_marker) + r = self.__read() while delayed < 1.0 and len(r) <= 0: d = 0.1 logger.debug("no response; wait: %f seconds" % d) time.sleep(d) delayed += d - r = self.__read(end_marker=end_marker) + r = self.__read() return r def __write(self, cmd): @@ -503,9 +443,7 @@ def __write(self, cmd): cmd += b"\r" # terminate with carriage return in accordance with ELM327 and STN11XX specifications logger.debug("write: " + repr(cmd)) try: - self.__port.flushInput() # dump everything in the input buffer - self.__port.write(cmd) # turn the string into bytes and write - self.__port.flush() # wait for the output buffer to finish transmitting + self.__port.send(cmd) # turn the string into bytes and write except Exception: self.__status = OBDStatus.NOT_CONNECTED self.__port.close() @@ -515,12 +453,11 @@ def __write(self, cmd): else: logger.info("cannot perform __write() when unconnected") - def __read(self, end_marker=ELM_PROMPT): + def __read(self): """ "low-level" read function - accumulates characters until the end marker (by - default, the prompt character) is seen + accumulates characters until the prompt character is seen returns a list of [/r/n] delimited strings """ if not self.__port: @@ -532,7 +469,8 @@ def __read(self, end_marker=ELM_PROMPT): while True: # retrieve as much data as possible try: - data = self.__port.read(self.__port.in_waiting or 1) + #data = self.__port.read(self.__port.in_waiting or 1) + data = self.__port.recv(32) except Exception: self.__status = OBDStatus.NOT_CONNECTED self.__port.close() @@ -547,8 +485,9 @@ def __read(self, end_marker=ELM_PROMPT): buffer.extend(data) - # end on specified end-marker sequence - if end_marker in buffer: + # 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 # log, and remove the "bytearray( ... )" part @@ -567,4 +506,4 @@ def __read(self, end_marker=ELM_PROMPT): # splits into lines while removing empty lines and trailing spaces lines = [s.strip() for s in re.split("[\r\n]", string) if bool(s)] - return lines + return lines \ No newline at end of file From 8404e5f5df8814514a6c719d913440d66364e74b Mon Sep 17 00:00:00 2001 From: BritishCopsAreClowns Date: Tue, 12 Mar 2024 00:06:47 +0000 Subject: [PATCH 24/24] Found messed up indent --- obd/elm327.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obd/elm327.py b/obd/elm327.py index c3de4aa0..aee9fb12 100644 --- a/obd/elm327.py +++ b/obd/elm327.py @@ -181,7 +181,7 @@ def __init__(self, addr, port, protocol, timeout, self.__error("Incorrect response from 'AT RV'") return # by now, we've successfuly connected to the OBD socket - self.__status = OBDStatus.OBD_CONNECTED + self.__status = OBDStatus.OBD_CONNECTED # try to communicate with the car, and load the correct protocol parser if self.set_protocol(protocol):