MrYsLab / pymata-aio

This is the second generation PyMata client.
https://github.com/MrYsLab/pymata-aio/wiki
GNU Affero General Public License v3.0
155 stars 51 forks source link

issues running from secondary thread #61

Closed Denao2 closed 6 years ago

Denao2 commented 6 years ago

I am trying to run the pymata elements of my program in a separate thread as the main thread is utilised bu the GUI.

I have managed to get as far as getting the board to initialise and set initial pin states, after adding the following inside my thread:

loop = asyncio.new_event_loop() asyncio.set_event_loop(loop)

However, further calls to change the state of pins will not take affect and on terminating the application I get he following error:

Task was destroyed but it is pending! task: <Task pending coro=<PymataCore._command_dispatcher() running at /home/deano/.local/lib/python3.5/site-packages/pymata_aio/pymata_core.py:1296> wait_for=>

This occurs both when the update call is made from within the thread and externally (from GUI thread).

Additionally when trying to call from GUI thread I get the following error:

File "AquariumMonitor.py", line 39, in update_IOput self.backendController.ioputs[IOputName].setValue(IOValue)
File "/home/deano/PiAquarium/AqFirmataInput.py", line 47, in setValue self.disable() File "/home/deano/PiAquarium/AqFirmataInput.py", line 73, in disable self.device.digital_write (self.pin, self.disable_state) File "/home/deano/.local/lib/python3.5/site-packages/pymata_aio/pymata3.py", line 121, in digital_write self.loop.run_until_complete(task) File "/usr/lib/python3.5/asyncio/base_events.py", line 446, in run_until_complete future = tasks.ensure_future(future, loop=self) File "/usr/lib/python3.5/asyncio/tasks.py", line 555, in ensure_future raise ValueError('loop argument must agree with Future')

and then the following on termination:

task: <Task pending coro=<PymataCore.digital_write() running at /home/deano/.local/lib/python3.5/site-packages/pymata_aio/pymata_core.py:541>> Task was destroyed but it is pending!

wrapping the change state calls within a asyncio.ensure_future() clears the errors on calling from GUI, but the pin state never changes.

I suspect the issues is around the event loop, but I'm afraid I have run out of expertise!

MrYsLab commented 6 years ago

I am not sure which GUI you are using, but I successfully integrated both tkinter and kivy in the xibot project. The project uses a library I call xidekit, which is part of the xideco project. Xideco has been replaced by python_banyan

You can take a look at how I did the integration in xibot here: https://github.com/MrYsLab/xibot/wiki/Integrating-XideKit-Components-with-External-Event-Loops

And there is a discussion on integrating python_banyan with GUIs here: https://mryslab.github.io/python_banyan/#integrating-a-gui-with-python-banyan

And information on integrating python_banyan with an Arduino here: https://mryslab.github.io/python_banyan/#adding-an-arduino-component-into-the-mix

python_banyan is actually very easy to use, and I suggest reading the entire [user's guide'(https://mryslab.github.io/python_banyan/) to get a feel of how to use it.

Denao2 commented 6 years ago

Thanks for information. My GUI is currently implemented in QT Quick through pyqt5. It may be that your suggested approach could work, I will have to build a demo and see. As I also like to resolve the blocks that I encounter any thoughts on how the issue could be resolved with my current approach? Would passing the event loop created in my thread down through the pymata classes so they could use it explicitly solve the issue?

MrYsLab commented 6 years ago

In general, the reason to move to asyncio is to avoid using threads, and unfortunately, I have no real experience in combining the two. I did find this package on github that may meet your needs: https://github.com/harvimt/quamash

However, you might need to hack pymata_core to get it to work with this package(only a guess). I suspect that separating out both GUI and Arduino events as python_banyan messages would be faster and simpler, but having no real experience with QT or its event loop, again, only a guess.

MrYsLab commented 6 years ago

Another thought, can you use the callback feature to link into the QT event loop? I have an explanation of its use here: https://github.com/MrYsLab/pymata-aio/wiki/Digital-And-Analog-Data-Reporting-Callback--Usage-Guidelines

MrYsLab commented 6 years ago

I am closing this issue, but if you have any other comments, you can still add them to this thread and I will receive notification of them.

Denao2 commented 6 years ago

Thank you for your insights. I did look into changing the pymata code to use a provided event loop, but ultimately was unsuccessful. The alternate method you suggested however, using python-banyan, is showing promise and actually fits well with my aim of an easily reconfigurable and modular application.