You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

BAC0配置为BACnet设备时的IPv4数据报异常与对象访问失败问题求助

BAC0配置为BACnet设备时的IPv4数据报异常与对象访问失败问题求助

我尝试用BAC0搭建一个模拟BACnet/IP设备,想让YABE工具能跨网络监控设备的数值,但运行代码时遇到了两个棘手的问题:一是触发了IPv4数据报相关的绑定错误,二是无法访问我定义的“Frequency”模拟输入对象。我已经查阅了BAC0的文档和库帮助文件,但还是没理清问题所在,希望能得到大家的帮助。

我的代码

#!/usr/bin/env python3
import asyncio
from BAC0 import connect
from BAC0.core.devices.local.factory import analog_input

def defining_objects(device):
    from BAC0.core.devices.local.factory import ObjectFactory
    ObjectFactory.clear_objects()

    analog_input(
        instance=10,
        name="Frequency",
        properties={"units": "hertz"},
        description="Frequency",
        presentValue=18.0,
        relinquish_default=21,
    )
    return device

async def main():
    try:
        # Connect to BAC0 device
        #device1 = connect(ip="192.168.13.193/24", port="47808", deviceId="1110")
        device1 = connect(ip="192.168.13.193/24")
        
        defining_objects(device1)

        while True:
            device1["Frequency"].presentValue = 42.0  # Test value
            print("Device 1 Frequency:", device1["Frequency"].presentValue)
            await asyncio.sleep(2)
    except Exception as e:
        print(f"An error occurred: {e}")

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

运行时的错误输出

[12/16/24 12:00:06] INFO     2024-12-16 12:00:06,757 - INFO    |    notes.py:267
                             Starting Asynchronous BAC0 version                 
                             2024.09.10 (Lite)                                  
                    INFO     2024-12-16 12:00:06,760 - INFO    |    notes.py:267
                             Using bacpypes3 version 0.0.98                     
                    INFO     2024-12-16 12:00:06,761 - INFO    |    notes.py:267
                             Use BAC0.log_level to adjust verbosity             
                             of the app.                                        
                    INFO     2024-12-16 12:00:06,762 - INFO    |    notes.py:267
                             Ex. BAC0.log_level('silence') or                   
                             BAC0.log_level('error')                            
                    INFO     2024-12-16 12:00:06,786 - INFO    |     Lite.py:164
                             Using ip : 192.168.13.193/24 on port               
                             47808 | broadcast : 192.168.13.255                 
[12/16/24 12:00:06] INFO     2024-12-16 12:00:06,789 - INFO    |    notes.py:267
                             Using default JSON configuration file              
                    INFO     2024-12-16 12:00:06,796 - INFO    |    notes.py:267
                             Registered as BACnet/IP App | mode                 
                             normal                                             
                    INFO     2024-12-16 12:00:06,798 - INFO    |    notes.py:267
                             Device instance (id) : 3056500                     
An error occurred: 'Frequency'
[12/16/24 12:00:06] INFO     2024-12-16 12:00:06,802 - INFO    |    notes.py:267
                             Installing recurring task Ping Task                
                             (id:128923930364320)                               
Exception in callback IPv4DatagramServer.set_broadcast_transport_protocol(<IPv4Address 192.168.13.193>)(<Task cancell...nit__.py:150>>)
handle: <Handle IPv4DatagramServer.set_broadcast_transport_protocol(<IPv4Address 192.168.13.193>)(<Task cancell...nit__.py:150>>)>
Traceback (most recent call last):
  File "/home/eric/.local/lib/python3.10/site-packages/bacpypes3/ipv4/__init__.py", line 159, in retrying_create_datagram_endpoint
    return await loop.create_datagram_endpoint(
  File "/usr/lib/python3.10/asyncio/base_events.py", line 1385, in create_datagram_endpoint
    raise exceptions[0]
  File "/usr/lib/python3.10/asyncio/base_events.py", line 1369, in create_datagram_endpoint
    sock.bind(local_address)
OSError: [Errno 99] Cannot assign requested address

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/eric/.local/lib/python3.10/site-packages/bacpypes3/ipv4/__init__.py", line 167, in retrying_create_datagram_endpoint
    await asyncio.sleep(BACPYPES_ENDPOINT_RETRY_INTERVAL)
  File "/usr/lib/python3.10/asyncio/tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/home/eric/.local/lib/python3.10/site-packages/bacpypes3/ipv4/__init__.py", line 207, in set_broadcast_transport_protocol
    transport, protocol = task.result()
asyncio.exceptions.CancelledError
Exception in callback IPv4DatagramServer.set_local_transport_protocol(<IPv4Address 192.168.13.193>)(<Task cancell...nit__.py:150>>)
handle: <Handle IPv4DatagramServer.set_local_transport_protocol(<IPv4Address 192.168.13.193>)(<Task cancell...nit__.py:150>>)>
Traceback (most recent call last):
  File "/home/eric/.local/lib/python3.10/site-packages/bacpypes3/ipv4/__init__.py", line 159, in retrying_create_datagram_endpoint
    return await loop.create_datagram_endpoint(
  File "/usr/lib/python3.10/asyncio/base_events.py", line 1402, in create_datagram_endpoint
    await waiter
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/home/eric/.local/lib/python3.10/site-packages/bacpypes3/ipv4/__init__.py", line 176, in set_local_transport_protocol
    transport, protocol = task.result()
asyncio.exceptions.CancelledError


------------------
(program exited with code: 0)
Press return to continue

另外我还不确定能不能用WiFi网卡作为BACnet服务器,核心需求就是让YABE能监控到我代码里更新的数值,麻烦大家帮忙看看怎么配置才对。


问题分析与解决方案

1. 先解决对象访问失败的问题(An error occurred: 'Frequency'

这个问题是因为你直接调用analog_input()工厂函数创建对象,但没有把它注册到device1实例中。BAC0的ObjectFactory创建的对象不会自动关联到设备,需要用设备实例的API来添加。

修改defining_objects函数

def defining_objects(device):
    # 去掉ObjectFactory.clear_objects(),避免清空意外对象
    # 直接用device的add_analog_input方法创建对象,自动关联到设备
    device.add_analog_input(
        instance=10,
        name="Frequency",
        units="hertz",
        description="Frequency",
        presentValue=18.0,
        relinquish_default=21,
    )
    return device

这样创建的模拟输入对象会直接绑定到device1,之后用device1["Frequency"]就能正常访问了。

2. 解决IPv4数据报绑定错误(OSError: [Errno 99] Cannot assign requested address

这个错误的核心是指定的IP地址无法被本地网卡绑定,常见原因和解决方法:

  • 确认IP地址有效性:用ip a(Linux)或ipconfig(Windows)检查本地WiFi网卡的实际IP,确保192.168.13.193是当前机器正在使用的有效IP
  • 自动绑定所有网卡:如果不确定具体IP,改用connect(ip="0.0.0.0/24"),让BAC0自动绑定到所有可用的网络接口,这样兼容性更好
  • 检查端口占用:BAC0默认用47808端口,用ss -tulpn | grep 47808(Linux)或netstat -ano | findstr 47808(Windows)检查是否被其他程序占用,如果被占用可以在connect()时指定其他端口,比如connect(ip="0.0.0.0/24", port="47809")
  • 指定固定设备ID:为了方便YABE查找设备,建议在connect()时指定固定的deviceId,比如connect(ip="0.0.0.0/24", deviceId="1110"),这样扫描时直接找设备ID 1110即可

3. 修改后的完整代码

#!/usr/bin/env python3
import asyncio
from BAC0 import connect

def defining_objects(device):
    device.add_analog_input(
        instance=10,
        name="Frequency",
        units="hertz",
        description="Frequency",
        presentValue=18.0,
        relinquish_default=21,
    )
    return device

async def main():
    try:
        # 改用自动绑定所有网卡,指定固定设备ID方便YABE查找
        device1 = connect(ip="0.0.0.0/24", deviceId="1110")
        
        defining_objects(device1)

        while True:
            device1["Frequency"].presentValue = 42.0  # Test value
            print("Device 1 Frequency:", device1["Frequency"].presentValue)
            await asyncio.sleep(2)
    except Exception as e:
        print(f"An error occurred: {e}")

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

4. 测试验证步骤

  1. 运行修改后的代码,确认控制台能正常输出Device 1 Frequency: 42.0,没有对象访问错误
  2. 打开YABE工具,执行网络扫描(扫描范围选当前网段),找到设备ID为1110的BACnet设备
  3. 进入设备的“模拟输入”对象列表,找到实例10、名称为“Frequency”的对象,就能看到它的presentValue每2秒更新一次
  4. 如果还是看不到设备,检查防火墙是否放行47808端口,确保YABE和BAC0设备在同一网段,或者路由配置允许跨网段访问

关于WiFi网卡作为BACnet服务器的疑问

WiFi网卡完全可以作为BACnet服务器,只要它能正常接入网络,拥有有效IP地址,并且没有防火墙阻止BACnet的UDP 47808端口通信,就可以被YABE等工具扫描到。

备注:内容来源于stack exchange,提问作者Bangor Makerspace

火山引擎 最新活动