Skip to content

Commit

Permalink
Merge pull request brendan-w#129 from Ircama/manage_exceptions
Browse files Browse the repository at this point in the history
Better Async management
  • Loading branch information
alistair23 authored Dec 31, 2018
2 parents 64109ec + 684a5e4 commit 6bb6a4a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
19 changes: 18 additions & 1 deletion docs/Async Connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ Since the standard `query()` function is blocking, it can be a hazard for UI eve

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.

General sequence to enable an asynchronous connection allowing non-blocking queries:
- *Async()* # set-up the connection (to be used in place of *OBD()*)
- *watch()* # add commands to the watch list
- *start()* # start a thread performing the update loop in background
- *query()* # perform the non-blocking query

Example:

```python
import obd

connection = obd.Async() # same constructor as 'obd.OBD()'
connection = obd.Async() # same constructor as 'obd.OBD()'; see below.

connection.watch(obd.commands.RPM) # keep track of the RPM

Expand Down Expand Up @@ -39,6 +47,15 @@ connection.stop()

---

### Async(portstr=None, baudrate=None, protocol=None, fast=True, timeout=0.1, check_voltage=True, delay_cmds=0.25)

Create asynchronous connection.
Arguments are the same as 'obd.OBD()' with the addition of *delay_cmds*, which defaults to 0.25 seconds and allows
controlling a delay after each loop executing all *watch*ed commands in background. If *delay_cmds* is set to 0,
the background thread continuously repeats the execution of all commands without any delay.

---

### start()

Starts the update loop.
Expand Down
9 changes: 8 additions & 1 deletion obd/asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ class Async(OBD):
"""

def __init__(self, portstr=None, baudrate=None, protocol=None, fast=True,
timeout=0.1, check_voltage=True):
timeout=0.1, check_voltage=True, delay_cmds=0.25):
super(Async, self).__init__(portstr, baudrate, protocol, fast,
timeout, check_voltage)
self.__commands = {} # key = OBDCommand, value = Response
self.__callbacks = {} # key = OBDCommand, value = list of Functions
self.__thread = None
self.__running = False
self.__was_running = False # used with __enter__() and __exit__()
self.__delay_cmds = delay_cmds


@property
Expand Down Expand Up @@ -215,6 +216,11 @@ def run(self):
if len(self.__commands) > 0:
# loop over the requested commands, send, and collect the response
for c in self.__commands:
if not self.is_connected():
logger.info("Async thread terminated because device disconnected")
self.__running = False
self.__thread = None
return

# force, since commands are checked for support in watch()
r = super(Async, self).query(c, force=True)
Expand All @@ -225,6 +231,7 @@ def run(self):
# fire the callbacks, if there are any
for callback in self.__callbacks[c]:
callback(r)
time.sleep(self.__delay_cmds)

else:
time.sleep(0.25) # idle
22 changes: 18 additions & 4 deletions obd/elm327.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,16 @@ def __write(self, cmd):
if self.__port:
cmd += b"\r" # terminate with carriage return in accordance with ELM327 and STN11XX specifications
logger.debug("write: " + repr(cmd))
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
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
except Exception:
self.__status = OBDStatus.NOT_CONNECTED
self.__port.close()
self.__port = None
logger.critical("Device disconnected while writing")
return
else:
logger.info("cannot perform __write() when unconnected")

Expand All @@ -466,7 +473,14 @@ def __read(self):

while True:
# retrieve as much data as possible
data = self.__port.read(self.__port.in_waiting or 1)
try:
data = self.__port.read(self.__port.in_waiting or 1)
except Exception:
self.__status = OBDStatus.NOT_CONNECTED
self.__port.close()
self.__port = None
logger.critical("Device disconnected while reading")
return []

# if nothing was recieved
if not data:
Expand Down

0 comments on commit 6bb6a4a

Please sign in to comment.