Python Frame - Asyncio issue

Python and python framework

Moderator: leecollings

Post Reply
pipiche
Posts: 2016
Joined: Monday 02 April 2018 20:33
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: France
Contact:

Python Frame - Asyncio issue

Post by pipiche »

It looks like it is not possible to run 2 instances of plugin defining/using an event loop


Here after is a simple plugin.py using asyncio and event loop.

If you create one instance it will work well, if now you create a 2nd instance and you run it you get the following exception which seems to tell that there is some issue around the access to the event loop
Mar 27 20:07:10 rasp domoticz[15489]: Exception in thread Transport:
Mar 27 20:07:10 rasp domoticz[15489]: Traceback (most recent call last):
Mar 27 20:07:10 rasp domoticz[15489]: File "/usr/lib/python3.9/threading.py", line 973, in _bootstrap_inner
Mar 27 20:07:10 rasp domoticz[15489]: self.run()
Mar 27 20:07:10 rasp domoticz[15489]: File "/usr/lib/python3.9/threading.py", line 910, in run
Mar 27 20:07:10 rasp domoticz[15489]: self._target(*self._args, **self._kwargs)
Mar 27 20:07:10 rasp domoticz[15489]: File "/var/lib/domoticz/plugins/Asyncio/plugin.py", line 59, in transport
Mar 27 20:07:10 rasp domoticz[15489]: loop.run_until_complete(task)
Mar 27 20:07:10 rasp domoticz[15489]: File "/usr/lib/python3.9/asyncio/base_events.py", line 618, in run_until_complete
Mar 27 20:07:10 rasp domoticz[15489]: self._check_running()
Mar 27 20:07:10 rasp domoticz[15489]: File "/usr/lib/python3.9/asyncio/base_events.py", line 578, in _check_running
Mar 27 20:07:10 rasp domoticz[15489]: raise RuntimeError('This event loop is already running')
Mar 27 20:07:10 rasp domoticz[15489]: RuntimeError: This event loop is already running
Mar 27 20:07:10 rasp domoticz[15489]: /usr/lib/python3.9/threading.py:975: RuntimeWarning: coroutine 'radio_start' was never awaited
Mar 27 20:07:10 rasp domoticz[15489]: self._invoke_excepthook(self)
Mar 27 20:07:10 rasp domoticz[15489]: RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Code: Select all

"""
<plugin key="asyncio" name="AsyncIO plugin Crash" author="pipiche38" version="0.0.1" >
    <description>
        <h1> Plugin ZNP (TI CC2531, CC13x2, CC26x2 radio)</h1><br/>
            <br/><h2> Informations</h2><br/>
                <ul style="list-style-type:square">
                    <li>&Documentations : &<a href="https://github.com/pipiche38/Domoticz-Zigate-Wiki/blob/master/en-eng/Home.md">English wiki</a>|<a href="https://github.com/pipiche38/Domoticz-Zigate-Wiki/blob/master/fr-fr/Home.md">Wiki Français</a></li>
                    <li>&Forums : &<a href="https://www.domoticz.com/forum/viewforum.php?f=68">English (www.domoticz.com)</a>|<a href="https://easydomoticz.com/forum/viewforum.php?f=28">Français (www.easydomoticz.com)</a></li>
                    <li>&List of supported devices : &<a href="https://zigbee.blakadder.com/zigate.html">www.zigbee.blakadder.com</a></li>
                </ul>
            <br/><h2>Parameters</h2>
    </description>
    <params>
        <param field="Mode1" label="Radio module" width="150px" required="true" default="zigate" >
            <description><br/>Select the Radio module  (zigate, znp)</description>
        </param>
        <param field="SerialPort" label="Serial Port" width="150px" required="true" default="/dev/ttyUSB0" >
            <description><br/>Set the serial port where the Radio module is connected (/dev/ttyUSB0 for example)</description>
        </param>
        <param field="Mode6" label="Debugging" width="150px" required="true" default="None">
        <description><br/><h3>Plugin debug</h3>This debugging option has been moved to the WebUI > Tools > Debug<br/>
        </description>
            <options>
                        <option label="None" value="2"  default="true"/>
            </options>
        </param>
    </params>
</plugin>
"""
import Domoticz

try:
    from Domoticz import Devices, Images, Parameters, Settings
except ImportError:
    pass


import queue
import threading
import time
import sys
import asyncio


class BasePlugin:

    def __init__(self):
        self.running = True
        self.ListeningThread = threading.Thread(name="Transport", target=BasePlugin.transport, args=(self,))


    def transport( self ):

        loop = get_or_create_eventloop()

        task = radio_start(self)

        loop.run_until_complete(task)
        loop.run_until_complete(asyncio.sleep(1))
        loop.close()

    def onStart(self):
        self._serialPort = Parameters["SerialPort"]
        self._radiomodule = Parameters["Mode1"]
        self.ListeningThread.start()


    def onHeartbeat(self):
        pass

    def onStop(self):
        self.running = False
        self.ListeningThread.join()

        for thread in threading.enumerate():
            if (thread.name != threading.current_thread().name):
                Domoticz.Log("'"+thread.name+"' is running, it must be shutdown otherwise Domoticz will abort on plugin exit.")


        # Wait until queue thread has exited
        Domoticz.Log("Threads still active: "+str(threading.active_count())+", should be 1.")
        while (threading.active_count() > 1):
            for thread in threading.enumerate():
                if (thread.name != threading.current_thread().name):
                    Domoticz.Log("'"+thread.name+"' is still running, waiting otherwise Domoticz will abort on plugin exit.")
            time.sleep(1.0)


def handle_thread_error( e):
    trace = []
    tb = e.__traceback__
    Domoticz.Error("'%s' failed '%s'" % (tb.tb_frame.f_code.co_name, str(e)))
    while tb is not None:
        Domoticz.Error( "----> Line %s in '%s', function %s"% (
                tb.tb_lineno,
                tb.tb_frame.f_code.co_filename,
                tb.tb_frame.f_code.co_name))
        tb = tb.tb_next

def get_or_create_eventloop():
    try:
        return asyncio.get_event_loop()
    except RuntimeError as ex:
        if "There is no current event loop in thread" in str(ex):
            asyncio.set_event_loop(asyncio.new_event_loop())
            return asyncio.get_event_loop()


async def radio_start(self):

    while self.running:
        Domoticz.Log("Waiting in radio_start")
        await asyncio.sleep(.5)


global _plugin
_plugin = BasePlugin()

def onStart():
    global _plugin
    _plugin.onStart()

def onStop():
    global _plugin
    _plugin.onStop()

def onHeartbeat():
    global _plugin
    _plugin.onHeartbeat()



async def radio(self, auto_form=False ):

    # Run forever
    Domoticz.Log("Starting work loop")

    while self.running:
        Domoticz.Log("Continue loop")
        await asyncio.sleep(.5)

    Domoticz.Log("Exiting work loop")
Zigbee for Domoticz plugin / RPI3B+ / Electrolama ZZH-P / 45 devices

If the plugin provides you value, you can support me with a donation Paypal.

Wiki is available here.

Zigbee for Domoticz FAQ
keros
Posts: 77
Joined: Saturday 27 July 2019 0:39
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Python Frame - Asyncio issue

Post by keros »

Same issue for me with DomoticZ stable 2022.1 on a Raspberry 3B+ with Python 3.7.3.
Moderator on Easydomoticz.com, the French DomoticZ forum.
French writer for ZigBeeForDomoticZ Plugin Wiki
pipiche
Posts: 2016
Joined: Monday 02 April 2018 20:33
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: France
Contact:

Re: Python Frame - Asyncio issue

Post by pipiche »

we are investigating this issue on GitHub https://github.com/zigbeefordomoticz/Do ... ssues/1117
Zigbee for Domoticz plugin / RPI3B+ / Electrolama ZZH-P / 45 devices

If the plugin provides you value, you can support me with a donation Paypal.

Wiki is available here.

Zigbee for Domoticz FAQ
pipiche
Posts: 2016
Joined: Monday 02 April 2018 20:33
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: France
Contact:

Re: Python Frame - Asyncio issue

Post by pipiche »

@Dnpwwo for your information, we have reported the issue to cpython and they have confirmed that asyncio is not multi-instance ready.
However a good workaround has been suggested and we do confirmed that it fixes our issue.

for more information all is there: https://github.com/zigbeefordomoticz/Do ... ssues/1117
Zigbee for Domoticz plugin / RPI3B+ / Electrolama ZZH-P / 45 devices

If the plugin provides you value, you can support me with a donation Paypal.

Wiki is available here.

Zigbee for Domoticz FAQ
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest