Skip to content

Commit 889ceea

Browse files
author
Brendan Whitfield
committed
Merge branch 'devel'
2 parents c39ba5b + c633d04 commit 889ceea

36 files changed

+2466
-1229
lines changed

docs/Commands.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ obd.commands.has_pid(1, 12) # True
6161

6262
<br>
6363

64+
# OBD-II adapter (ELM327 commands)
65+
66+
|PID | Name | Description |
67+
|-----|-------------|-----------------------------------------|
68+
| N/A | ELM_VERSION | OBD-II adapter version string |
69+
| N/A | ELM_VOLTAGE | Voltage detected by OBD-II adapter |
70+
71+
<br>
72+
6473
# Mode 01
6574

6675
|PID | Name | Description |

docs/Connections.md

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
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 scanSerial helper retrieve a list of connected ports.
2+
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.
33

44
```python
55
import obd
@@ -12,18 +12,36 @@ connection = obd.OBD("/dev/ttyUSB0") # create connection with USB 0
1212

1313
# OR
1414

15-
ports = obd.scanSerial() # return list of valid USB or RF ports
15+
ports = obd.scan_serial() # return list of valid USB or RF ports
1616
print ports # ['/dev/ttyUSB0', '/dev/ttyUSB1']
1717
connection = obd.OBD(ports[0]) # connect to the first port in the list
1818
```
1919

20+
21+
<br>
22+
23+
### OBD(portstr=None, baudrate=38400, protocol=None, fast=True):
24+
25+
`portstr`: The UNIX device file or Windows COM Port for your adapter. The default value (`None`) will auto select a port.
26+
27+
`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
28+
29+
`protocol`: Forces python-OBD to use the given protocol when communicating with the adapter. See `protocol_id()` for possible values. The default value (`None`) will auto select a protocol.
30+
31+
`fast`: Allows commands to be optimized before being sent to the car. Python-OBD currently makes two such optimizations:
32+
33+
- Sends carriage returns to repeat the previous command.
34+
- Appends a response limit to the end of the command, telling the adapter to return after it receives *N* responses (rather than waiting and eventually timing out). This feature can be enabled and disabled for individual commands.
35+
36+
Disabling fast mode will guarantee that python-OBD outputs the unaltered command for every request.
37+
2038
<br>
2139

2240
---
2341

2442
### query(command, force=False)
2543

26-
Sends an `OBDCommand` to the car, and returns a `OBDResponse` object. This function will block until a response is recieved from the car. This function will also check whether the given command is supported by your car. If a command is not marked as supported, it will not be sent to the car, and an empty `Response` will be returned. To force an unsupported command to be sent, there is an optional `force` parameter for your convenience.
44+
Sends an `OBDCommand` to the car, and returns a `OBDResponse` object. This function will block until a response is received from the car. This function will also check whether the given command is supported by your car. If a command is not marked as supported, it will not be sent to the car, and an empty `Response` will be returned. To force an unsupported command to be sent, there is an optional `force` parameter for your convenience.
2745

2846
*For non-blocking querying, see [Async Querying](Async Connections.md)*
2947

@@ -36,24 +54,92 @@ r = connection.query(obd.commands.RPM) # returns the response from the car
3654

3755
---
3856

57+
### status()
58+
59+
Returns a string value reflecting the status of the connection. These values should be compared against the `OBDStatus` class. The fact that they are strings is for human readability only. There are currently 3 possible states:
60+
61+
```python
62+
from obd import OBDStatus
63+
64+
# no connection is made
65+
OBDStatus.NOT_CONNECTED # "Not Connected"
66+
67+
# successful communication with the ELM327 adapter
68+
OBDStatus.ELM_CONNECTED # "ELM Connected"
69+
70+
# successful communication with the ELM327 and the vehicle
71+
OBDStatus.CAR_CONNECTED # "Car Connected"
72+
```
73+
74+
The middle state, `ELM_CONNECTED` is mostly for diagnosing errors. When a proper connection is established, you will never encounter this value.
75+
76+
---
77+
3978
### is_connected()
4079

41-
Returns a boolean for whether a connection was established.
80+
Returns a boolean for whether a connection was established with the vehicle. It is identical to writing:
81+
82+
```python
83+
connection.status() == OBDStatus.CAR_CONNECTED
84+
```
4285

4386
---
4487

45-
### get_port_name()
88+
### port_name()
4689

4790
Returns the string name for the currently connected port (`"/dev/ttyUSB0"`). If no connection was made, this function returns `"Not connected to any port"`.
4891

4992
---
5093

94+
### get_port_name()
95+
96+
**Deprecated:** use `port_name()` instead
97+
98+
---
99+
51100
### supports(command)
52101

53102
Returns a boolean for whether a command is supported by both the car and python-OBD
54103

55104
---
56105

106+
### protocol_id()
107+
### protocol_name()
108+
109+
Both functions return string names for the protocol currently being used by the adapter. Protocol *ID's* are the short values used by your adapter, whereas protocol *names* are the human-readable versions. The `protocol_id()` function is a good way to lookup which value to pass in the `protocol` field of the OBD constructor (though, this is mainly for advanced usage). These functions do not make any serial requests. When no connection has been made, these functions will return empty strings. The possible values are:
110+
111+
|ID | Name |
112+
|---|--------------------------|
113+
| 1 | SAE J1850 PWM |
114+
| 2 | SAE J1850 VPW |
115+
| 3 | AUTO, ISO 9141-2 |
116+
| 4 | ISO 14230-4 (KWP 5BAUD) |
117+
| 5 | ISO 14230-4 (KWP FAST) |
118+
| 6 | ISO 15765-4 (CAN 11/500) |
119+
| 7 | ISO 15765-4 (CAN 29/500) |
120+
| 8 | ISO 15765-4 (CAN 11/250) |
121+
| 9 | ISO 15765-4 (CAN 29/250) |
122+
| A | SAE J1939 (CAN 29/250) |
123+
124+
---
125+
126+
<!--
127+
128+
### ecus()
129+
130+
Returns a list of identified "Engine Control Units" visible to the adapter. Each value in the list is a constant representing that ECU's function. These constants are found in the `ECU` class:
131+
132+
```python
133+
from obd import ECU
134+
135+
ECU.UNKNOWN
136+
ECU.ENGINE
137+
```
138+
139+
Python-OBD can currently only detect the engine computer, but future versions may extend this capability.
140+
141+
-->
142+
57143
### close()
58144

59145
Closes the connection.

docs/Custom Commands.md

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,102 @@
11

22
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).
33

4-
| Argument | Type | Description |
5-
|----------------------|----------|--------------------------------------------------------------------------|
6-
| name | string | (human readability only) |
7-
| desc | string | (human readability only) |
8-
| mode | string | OBD mode (hex) |
9-
| pid | string | OBD PID (hex) |
10-
| bytes | int | Number of bytes expected in response |
11-
| decoder | callable | Function used for decoding the hex response |
12-
| supported (optional) | bool | Flag to prevent the sending of unsupported commands (`False` by default) |
13-
14-
*When the command is sent, the `mode` and `pid` properties are simply concatenated. For unusual codes that don't follow the `mode + pid` structure, feel free to use just one, while setting the other to an empty string.*
4+
| Argument | Type | Description |
5+
|----------------------|----------|----------------------------------------------------------------------------|
6+
| name | string | (human readability only) |
7+
| desc | string | (human readability only) |
8+
| command | string | OBD command in hex (typically mode + PID |
9+
| bytes | int | Number of bytes expected in response |
10+
| decoder | callable | Function used for decoding messages from the OBD adapter |
11+
| ecu (optional) | ECU | ID of the ECU this command should listen to (`ECU.ALL` by default) |
12+
| fast (optional) | bool | Allows python-OBD to alter this command for efficieny (`False` by default) |
1513

16-
The `decoder` argument is a function of following form.
14+
15+
Example
16+
-------
1717

1818
```python
19-
def <name>(_hex):
20-
...
21-
return (<value>, <unit>)
19+
from obd import OBDCommand
20+
from obd.protocols import ECU
21+
from obd.utils import bytes_to_int
22+
23+
def rpm(messages):
24+
d = messages[0].data
25+
v = bytes_to_int(d) / 4.0 # helper function for converting byte arrays to ints
26+
return (v, Unit.RPM)
27+
28+
c = OBDCommand("RPM", \ # name
29+
"Engine RPM", \ # description
30+
"010C", \ # command
31+
2, \ # number of return bytes to expect
32+
rpm, \ # decoding function
33+
ECU.ENGINE, \ # (optional) ECU filter
34+
True) # (optional) allow a "01" to be added for speed
2235
```
2336

24-
The `_hex` argument is the data recieved from the car, and is guaranteed to be the size of the `bytes` property specified in the OBDCommand.
37+
By default, custom commands will be treated as "unsupported by the vehicle". There are two ways to handle this:
2538

26-
For example:
39+
```python
40+
# use the `force` parameter when querying
41+
o = obd.OBD()
42+
o.query(c, force=True)
43+
```
44+
45+
or
2746

2847
```python
29-
from obd import OBDCommand
30-
from obd.utils import unhex
48+
# add your command to the set of supported commands
49+
o = obd.OBD()
50+
o.supported_commands.add(c)
51+
o.query(c)
52+
```
53+
54+
<br>
55+
56+
Here are some details on the less intuitive fields of an OBDCommand:
3157

32-
def rpm(_hex):
33-
v = unhex(_hex) # helper function to convert hex to int
34-
v = v / 4.0
35-
return (v, obd.Unit.RPM)
58+
---
59+
60+
### OBDCommand.decoder
61+
62+
The `decoder` argument is a function of following form.
3663

37-
c = OBDCommand("RPM", "Engine RPM", "01", "0C", 2, rpm)
64+
```python
65+
def <name>(<list_of_messages>):
66+
...
67+
return (<value>, <unit>)
68+
```
69+
70+
Decoders are given a list of `Message` objects as an argument. If your decoder is called, this list is garaunteed to have at least one message object. Each `Message` object has a `data` property, which holds a parsed byte array, and is also garauteed to have the number of bytes specified by the command.
71+
72+
*NOTE: If you are transitioning from an older version of Python-OBD (where decoders were given raw hex strings as arguments), you can use the `Message.hex()` function as a patch.*
73+
74+
```python
75+
def <name>(messages):
76+
_hex = messages[0].hex()
77+
...
78+
return (<value>, <unit>)
3879
```
3980

81+
*You can also access the original string sent by the adapter using the `Message.raw()` function.*
82+
83+
---
84+
85+
### OBDCommand.ecu
86+
87+
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:
88+
89+
- `ECU.ALL`
90+
- `ECU.ALL_KNOWN`
91+
- `ECU.UNKNOWN`
92+
- `ECU.ENGINE`
93+
94+
---
95+
96+
### OBDCommand.fast
97+
98+
The `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.
99+
40100
---
41101

42102
<br>

docs/Troubleshooting.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ This is likely a problem with the serial connection between the OBD-II adapter a
8080
- you are connecting to the right port in `/dev` (or that there is any port at all)
8181
- you have the correct permissions to write to the port
8282

83-
You can use the `scanSerial()` helper function to determine which ports are available for writing.
83+
You can use the `scan_serial()` helper function to determine which ports are available for writing.
8484

8585
```python
8686
import obd
8787

88-
ports = obd.scanSerial() # return list of valid USB or RF ports
88+
ports = obd.scan_serial() # return list of valid USB or RF ports
8989
print ports # ['/dev/ttyUSB0', '/dev/ttyUSB1']
9090
```
9191

docs/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Install the latest release from pypi:
1212
$ pip install obd
1313
```
1414

15-
If you are using a bluetooth adapter on Debian-based linux, you will need to install the following packages:
15+
*Note: If you are using a Bluetooth adapter on Linux, you may also need to install and configure your Bluetooth stack. On Debian-based systems, this usually means installing the following packages:*
1616

1717
```shell
1818
$ sudo apt-get install bluetooth bluez-utils blueman
@@ -35,6 +35,8 @@ print(response.value)
3535
print(response.unit)
3636
```
3737

38+
OBD connections operate in a request-reply fashion. To retrieve data from the car, you must send commands that query for the data you want (e.g. RPM, Vehicle speed, etc). In python-OBD, this is done with the `query()` function. The commands themselves are represented as objects, and can be looked up by name or value in `obd.commands`. The `query()` function will return a response object with parsed data in its `value` and `unit` properties.
39+
3840
<br>
3941

4042
# License

0 commit comments

Comments
 (0)