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")