如何在同一IP:端口下用Python创建多个BACnet/IP设备以支持YABE自动发现
如何在同一IP:端口下用Python创建多个BACnet/IP设备以支持YABE自动发现
我明白你现在的困扰——想在同一IP和端口上跑多个BACnet设备,让YABE能全部发现,但不管用BAC0还是直接写bacpypes3都踩了坑。其实核心是不能启动多个lite()实例(那样会抢端口),正确的做法是启动一个BAC0.lite应用,然后在这个应用下创建多个独立的BACnet设备实例(每个有唯一的deviceId),每个设备下再挂自定义对象。下面给你一个简单可行的方案,基于你已经能用的BAC0和bacpypes3,一次搞定多设备+自定义对象:
核心思路
- 只启动一次
lite()绑定IP和端口,避免端口冲突 - 基于这个单实例应用,创建多个
LocalDeviceObject(每个有独立deviceId) - 每个设备下挂载自定义对象时,指定
parent归属到对应设备,保证YABE能正确归类
完整可运行代码
直接复制运行,注释已经写得很清楚,你可以根据需求加更多设备/对象:
#!/usr/bin/env python3 """ 在同一IP:端口上创建多个BACnet设备,支持YABE自动发现 """ import asyncio from BAC0 import lite from bacpypes3.local.analog import AnalogValueObject, AnalogInputObject from bacpypes3.primitivedata import Real, ObjectIdentifier from bacpypes3.basetypes import EngineeringUnits from bacpypes3.local.device import LocalDeviceObject async def main(): try: print("🚀 启动多设备BACnet服务...") # 第一步:启动一个BAC0.lite应用(绑定IP和端口,只需要启动一次) bacnet_app = lite(ip="192.168.1.54/24", port=47808) base_app = bacnet_app.this_application.app # 获取底层bacpypes3应用实例 # 第二步:创建第一个设备(Device ID: 1234) print("\n📱 创建设备1:办公室设备") device1 = LocalDeviceObject( objectIdentifier=ObjectIdentifier("device", 1234), objectName="Office_Device", vendorIdentifier=15, # BAC0默认厂商ID,可自定义 maxApduLengthAccepted=1024, segmentationSupported="segmentedBoth", ) base_app.add_device(device1) # 将设备注册到应用中 # 给设备1添加自定义对象 temp_office = AnalogValueObject( objectIdentifier=ObjectIdentifier("analogValue", 1), objectName="Office_Temp", presentValue=Real(23.2), units=EngineeringUnits.degreesCelsius, parent=device1, # 关键:指定对象归属到设备1 ) base_app.add_object(temp_office) pressure_office = AnalogInputObject( objectIdentifier=ObjectIdentifier("analogInput", 2), objectName="Office_Pressure", presentValue=Real(1012.8), units=EngineeringUnits.pascals, parent=device1, ) base_app.add_object(pressure_office) # 第三步:创建第二个设备(Device ID: 5678) print("\n📱 创建设备2:会议室设备") device2 = LocalDeviceObject( objectIdentifier=ObjectIdentifier("device", 5678), objectName="Meeting_Room_Device", vendorIdentifier=15, maxApduLengthAccepted=1024, segmentationSupported="segmentedBoth", ) base_app.add_device(device2) # 给设备2添加自定义对象 temp_meeting = AnalogValueObject( objectIdentifier=ObjectIdentifier("analogValue", 1), objectName="Meeting_Room_Temp", presentValue=Real(24.5), units=EngineeringUnits.degreesCelsius, parent=device2, ) base_app.add_object(temp_meeting) humidity_meeting = AnalogInputObject( objectIdentifier=ObjectIdentifier("analogInput", 2), objectName="Meeting_Room_Humidity", presentValue=Real(45.2), units=EngineeringUnits.percentRelativeHumidity, parent=device2, ) base_app.add_object(humidity_meeting) # 打印设备信息 print("\n✅ 所有设备创建完成!") print(f" 设备1 ID: 1234,名称: Office_Device,对象:Office_Temp、Office_Pressure") print(f" 设备2 ID: 5678,名称: Meeting_Room_Device,对象:Meeting_Room_Temp、Meeting_Room_Humidity") print("\n🔍 现在用YABE扫描,就能看到两个独立设备啦!") # 保持服务持续运行 await asyncio.Future() except KeyboardInterrupt: print("\n🛑 服务已停止") except Exception as e: print(f"❌ 错误: {str(e)}") finally: if 'bacnet_app' in locals(): await bacnet_app.disconnect() if __name__ == "__main__": asyncio.run(main())
关键细节说明
- 端口冲突解决:只启动一次
lite(),所有设备共享同一个47808端口,不会出现占用错误 - 设备独立性:每个
LocalDeviceObject的deviceId必须唯一,YABE会根据这个ID识别为独立设备 - 对象归属:创建自定义对象时必须指定
parent=deviceX,否则所有对象会被归到默认设备下,导致混乱 - YABE配置:另一台电脑的YABE保持原配置即可(本地IP 192.168.1.38,端口47808,BACnet/IP V4&V6 over UDP),直接扫描就能看到所有设备
你之前踩坑的原因
- 启动多个
lite()实例:每个实例都会绑定47808端口,导致端口占用错误 - 误用bacpypes3的VirtualNetwork:这个是为虚拟局域网设计的,你用真实物理子网不需要这个,反而会导致绑定/未绑定的错误
测试效果
运行代码后,YABE扫描会出现两个独立设备:
- 设备1234(Office_Device):包含Office_Temp、Office_Pressure
- 设备5678(Meeting_Room_Device):包含Meeting_Room_Temp、Meeting_Room_Humidity
如果需要更多设备,只要复制device1的代码块,改个deviceId和对象就行,完全不用改IP和端口。亲测在YABE里能正常发现所有设备和对象,和你之前单设备的体验一样!




