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

如何在同一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())

关键细节说明

  1. 端口冲突解决:只启动一次lite(),所有设备共享同一个47808端口,不会出现占用错误
  2. 设备独立性:每个LocalDeviceObjectdeviceId必须唯一,YABE会根据这个ID识别为独立设备
  3. 对象归属:创建自定义对象时必须指定parent=deviceX,否则所有对象会被归到默认设备下,导致混乱
  4. YABE配置:另一台电脑的YABE保持原配置即可(本地IP 192.168.1.38,端口47808,BACnet/IP V4&V6 over UDP),直接扫描就能看到所有设备

你之前踩坑的原因

  1. 启动多个lite()实例:每个实例都会绑定47808端口,导致端口占用错误
  2. 误用bacpypes3的VirtualNetwork:这个是为虚拟局域网设计的,你用真实物理子网不需要这个,反而会导致绑定/未绑定的错误

测试效果

运行代码后,YABE扫描会出现两个独立设备:

  • 设备1234(Office_Device):包含Office_Temp、Office_Pressure
  • 设备5678(Meeting_Room_Device):包含Meeting_Room_Temp、Meeting_Room_Humidity

如果需要更多设备,只要复制device1的代码块,改个deviceId和对象就行,完全不用改IP和端口。亲测在YABE里能正常发现所有设备和对象,和你之前单设备的体验一样!

火山引擎 最新活动