ChristianTremblay / BAC0

BAC0 - Library depending on BACpypes3 (Python 3) to build automation script for BACnet applications
GNU Lesser General Public License v3.0
177 stars 100 forks source link

RuntimeError: no running event loop #471

Open leaf188 opened 2 months ago

leaf188 commented 2 months ago

The following error message appears when you run BAC0.lite() ` root@vm01:~# python Python 3.12.0 (main, Oct 21 2023, 17:42:12) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information.

import BAC0 bacnet=BAC0.lite() [09/11/24 07:54:41] INFO 2024-09-11 07:54:41,724 - INFO | Starting Asynchronous BAC0 version 2024.09.10 (Lite) notes.py:267 INFO 2024-09-11 07:54:41,728 - INFO | Using bacpypes3 version 0.0.98 notes.py:267 INFO 2024-09-11 07:54:41,729 - INFO | Use BAC0.log_level to adjust verbosity of the app. notes.py:267 INFO 2024-09-11 07:54:41,730 - INFO | Ex. BAC0.log_level('silence') or BAC0.log_level('error') notes.py:267 Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python3.12/dist-packages/BAC0/scripts/Lite.py", line 141, in init self._ping_task.start() File "/usr/local/lib/python3.12/dist-packages/BAC0/tasks/TaskManager.py", line 143, in start self.aio_task = asyncio.create_task(self.execute(), name=f"aio{self.name}") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/asyncio/tasks.py", line 407, in create_task loop = events.get_running_loop() ^^^^^^^^^^^^^^^^^^^^^^^^^ RuntimeError: no running event loop `

ChristianTremblay commented 2 months ago

You must run

python -m asyncio

This way, an event loop will be available.

Then

import BAC0
bacnet = BAC0.start()

You can also play with a Jupyter Notebook. It will work

haithngn commented 1 month ago

I am facing with the same issue on Mac M1, python 3.12.6 (via pyenv)

also tried,

python -m asyncio
asyncio REPL 3.12.6 (main, Sep  6 2024, 19:03:47) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> import BAC0
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/python@3.12/3.12.6/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.12/3.12.6/Frameworks/Python.framework/Versions/3.12/lib/python3.12/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/opt/homebrew/Cellar/python@3.12/3.12.6/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/__main__.py", line 33, in callback
    coro = func()
           ^^^^^^
  File "<console>", line 1, in <module>
ModuleNotFoundError: No module named 'BAC0'
>>> 

@ChristianTremblay can you please have a look, do I need a Linux or Windows machine?

haithngn commented 1 month ago

update, I have switched to python 3.10.15, now

>>> import asyncio
>>> import BAC0
>>> bacnet = BAC0.start()

it says

2024-09-23 17:10:49,560 - INFO    | Starting Asynchronous BAC0 version 2024.09.10 (Lite)
2024-09-23 17:10:49,560 - INFO    | Using bacpypes3 version 0.0.98
2024-09-23 17:10:49,560 - INFO    | Use BAC0.log_level to adjust verbosity of the app.
2024-09-23 17:10:49,560 - INFO    | Ex. BAC0.log_level('silence') or BAC0.log_level('error')
Unsupported platform
2024-09-23 17:10:49,607 - INFO    | Installing recurring task Ping Task (id:4317581888)

.pyenv/versions/3.10.15/lib/python3.10/ipaddress.py", line 472, in _report_invalid_netmask
    raise NetmaskValueError(msg) from None
ipaddress.NetmaskValueError: 'None' is not a valid netmask

the I tried to run the code from PyCharm, that console said

loop = events.get_running_loop()
RuntimeError: no running event loop
sys:1: RuntimeWarning: coroutine 'Task.execute' was never awaited

finally, I found the ip/mask of the macbook then start on them, then it seems BAC0 is now working, but this still happens in PyCharm IDE

loop = events.get_running_loop()
RuntimeError: no running event loop
sys:1: RuntimeWarning: coroutine 'Task.execute' was never awaited

I will try to read and write data via BAC0 into a YABE device then update the result into this ticket.

2024-09-23 17:17:01,292 - INFO    | Using default JSON configuration file
2024-09-23 17:17:01,310 - INFO    | Registered as BACnet/IP App | mode normal
2024-09-23 17:17:01,312 - INFO    | Device instance (id) : 3056656
>>> 2024-09-23 17:17:01,312 - INFO    | Installing recurring task Ping Task (id:4331449616)
haithngn commented 1 month ago

hi guys, I have succeed read data from a BACnet device (Yabe), confirm BAC0 works fine.

@leaf188 , you have to place BAC0 instance somewhere that you keep it alive, for now, I have to put in into Flask middleware (for workaround).

thank you @ChristianTremblay, this issue can be closed I think. and we can have a more detail example the perfect for developer who is not much familiar with Python.

haithngn commented 1 month ago

p/s: the legacy versions 23.07.03 is still good, there is some news in asyncio version need to be learned before using.

tstorek commented 2 weeks ago

@haithngn I having the same problem doing the transition to asyncio. With former versions I used Pyhton-Threading instead of asyncio. Could you please provide i Minimal working example (MWP) on how you did it. I need to run from PyCharm as well without Jupyter. Thanks

haithngn commented 2 weeks ago

hi @tstorek, here is a tested example, let try

#bac0.py
import BAC0
import asyncio

async def start_bacnet_server():
    # Initialize a BAC0 BAC.lite server
    print("Starting BACnet server...")
    bacnet = BAC0.lite(ip='192.168.1.22/24')  # Replace '192.168.1.22'with your IP address and '/24' with your subnet mask

    # At this point the console should show
    # Starting BACnet server...
    # 2024-11-05 15:18:47,663 - INFO    | Starting Asynchronous BAC0 version 2024.09.10 (Lite)
    # 2024-11-05 15:18:47,663 - INFO    | Using bacpypes3 version 0.0.98
    # 2024-11-05 15:18:47,663 - INFO    | Use BAC0.log_level to adjust verbosity of the app.
    # 2024-11-05 15:18:47,663 - INFO    | Ex. BAC0.log_level('silence') or BAC0.log_level('error')
    # 2024-11-05 15:18:47,672 - INFO    | Using ip : 192.168.1.22/24 on port 47808 | broadcast : 192.168.1.2255
    # 2024-11-05 15:18:47,683 - INFO    | Using default JSON configuration file
    # 2024-11-05 15:18:47,687 - INFO    | Registered as BACnet/IP App | mode normal
    # 2024-11-05 15:18:47,687 - INFO    | Device instance (id) : 3056476
    # 2024-11-05 15:18:47,688 - INFO    | Installing recurring task Ping Task (id:4336789664)

    await bacnet._discover()
    # 2024-11-05 15:18:50,692 - WARNING | BAC0.scripts.Lite | Lite | BAC0.core.functions.Alias | Request timed out for what_is_network_number, no response
    # 2024-11-05 15:18:54,694 - INFO    | Found those networks : set()
    # 2024-11-05 15:18:54,694 - INFO    | No BACnet network found, attempting a simple whois using provided device instances limits (0 - 4194303)
    # 2024-11-05 15:18:54,694 - INFO    | Issuing a local broadcast whois request.
    # 2024-11-05 15:18:57,706 - INFO    | Discovery done. Found 3 devices on 0 BACnet networks.

    print("discovered devices:", bacnet.discoveredDevices)
    # Depending on your bacnet devices, you may see:
    # discovered devices: {'device,2687112': {'object_instance': (<ObjectType: device>, 2687112), 'address': <IPv4Address 192.168.1.226:55199>, 'network_number': {None}, 'vendor_id': 260, 'vendor_name': 'unknown'}, 'device,2687113': {'object_instance': (<ObjectType: device>, 2687113), 'address': <IPv4Address 192.168.1.226:55200>, 'network_number': {None}, 'vendor_id': 260, 'vendor_name': 'unknown'}, 'device,2687111': {'object_instance': (<ObjectType: device>, 2687111), 'address': <IPv4Address 192.168.1.226:55198>, 'network_number': {None}, 'vendor_id': 260, 'vendor_name': 'unknown'}}

    # Keep the server running
    try:
        while True:
            await asyncio.sleep(1)
    except asyncio.CancelledError:
        print("Shutting down BACnet server...")
        bacnet.stop()

async def main():
    # Start the BACnet server in an asyncio task
    task = asyncio.create_task(start_bacnet_server())
    try:
        await asyncio
    except KeyboardInterrupt:
        task.cancel()
        await task

if __name__ == "__main__":
    asyncio.run(main())

run

python bac0.py

To avoid While/True loop, you can wrap into FastAPI or Flask prj