Trio with pexpect (gatttool)

I have a python-raspberryPi project that needs some Asynch IO so it can do multiple read/action and not get blocked. One action is reading (distance) values from a Bluetooth device. I have a script that uses pexpect and gatttool with send/expect wrapped up in try-except that works standalone. However the BLE device is a bit flaky. It takes 3-5sec for pexpect-gatttool to respond to a ‘connect’, a few seconds to wait between data retrieval, etc. It can timeout about 5-10% of the time, basically requiring killing the pexpect and restarting it (5sec or so). This sort of IO bound task is classic for running async threads.

I found the Trio library for python which seems to provide a nice encapsulation and abstraction of the whole async thing but have yet to find and references or examples of using Trio with pexpect.

Has anyone tried using trio with pexpect?
I see from docs that p.expect(cmd, async=True) will return an asyncio coroutine, but nothing with trio?

Digging a bit into pexpect, it uses @asyncio.coroutine for its async function … gitHub for pexpect/

Perhaps using the trio-asyncio layer or just using pexpect w/o async and encapsulate it in a trio function(s)? Working with the latter approach for now… if the dang BLE device will stop powering down randomly.

And digging into the Trio side i just found the Spawning Subprocesses section of docs. ItWouldBeNice to have a Trio version of ‘expect’ perhaps.
However, i got my code to work - ugly but working - so moving along to making the rest of this server Trio async’d.
If/when i get some time, perhaps I can extract some example code for this.

I think you’re right that there isn’t currently any version of pexpect that works with Trio. You’re also right that it would be great if there were :slight_smile:

I guess it would not even be too hard to write a generic expect function, that you could use like await expect(patterns, trio_stream_object)? Where usually trio_stream_object would be some_process.stdout. There’s some related discussion about generic stream helpers in this issue:

Another possible workaround: I think gatttool might also be usable in non-interactive mode, like shown here: But, I’ve never used it, so it might not be helpful at all, I dunno.

non-interactive might be ok… bascially split each line into a separate process spawnAndWait, retaining the CCC etc. That might add a lot of overhead in the spawning. The other way to go would be directly down into the BlueZ levels. More spelunking required there.
Digging around this weekend on getting this and other io/data working together. Part of issue is recognizing when the BLE device connection has been lost vs just a temporary timeout thing. With handling being to retry same read/timeout, restarting the process and asking, and giving up and asking the user if the device got turned off. A bad power supply/wiring made the latter very common, till i switched back to using AAA batteries.
This is a lot of work to just get a distance measurement! :wink:
(liking Trio a lot. y’all doing a lot of good work here.)

Spawning processes by itself is pretty cheap, but I don’t know how gatttool works – if it has to do something like spend several seconds re-establishing the bluetooth connection on every invocation, then interactive mode might be way faster.

Distributed systems + hardware? You’re brave :slight_smile: Sounds like a fun project though!