BACnet协议读取与发送

article/2025/11/1 9:36:34

BACnet协议读取与发送

  • 注意
  • 我的提问:
  • 更新
  • 开发环境
  • BACnet相关基础知识
  • BACnet格式
  • BACnet代码
    • BACnet设备查找
    • BACnet设备读取
    • BACnet写入操作
    • AND其他...
    • **BACpypes库中没有提供非标准数据类型接口!!!!!**
  • 结束

因为项目的需求,需要对接某个厂商的BACnet协议。

可以说是这协议的坑真的不少,自学的时候遇到了一大堆问题…

注意

本文档仅对python完成读取与发送BACnet协议数据的流程做出教程,不对其中的BUG做出解释。一切以本人踩坑为准.jpg

我的提问:

我这边的需求:因为BACnet没有主动推送数据的方式,我现在是写了个循环,对device设备号进行轮巡读取。但是每轮光是读取就需要花费3秒时间(600+个device实例)。各位如果有什么方法优化这个轮巡的话可以直接写在评论区进行交流,先感谢各位了!

更新

因为BACnet的扫描与通信注定不能跨网段,如果要实现跨网段搜索,需要BBMD设备。

开发环境

依旧是python≥3.6,使用了BAC0库。直接PIP安装,这里放上相关的GitHub源码,调试的时候可能会用的上。
BAC0-GitHub
BACpypes(BAC0的依赖库)

BACnet相关基础知识

楼宇自动控制网络数据通讯协议(即: A Data Communication Protocol for Building Automation and Control Networks,简称《BACnet协议》)。其相关的基础知识,这里放上百度百科链接,感兴趣的可以去查询,我这边也只是做了初步的了解。
BACnet百度百科

BACnet格式

我这里直接使用了BACnet模拟器创建了一组虚拟的设备,设置了虚拟的参数以供自己调试。感谢网上大神们无私奉献的链接,直接拿来下载用了,这里也提供给大家。
BACnet模拟器:BACnet Simulator,验证码=gcfb
BACnet调试工具:BACnet调试工具,验证码=mjp7
BACnet调试工具
其中,“Device X”称作device,子项目被称作type,子项目中的各项被称作属性和值,也就是property和value。在代码中,因为“-”具有很多特殊含义,于是代码中规定这些属性的名称按照小驼峰式命名规则。(例:present-value属性,在代码中的名称为presentValue)

BACnet代码

BACnet设备查找

BACnet协议允许通过whois方法扫描某一局域网下的BACnet设备。lite参数中的IP表示运行代码的本机IP,并非是BACnet设备或BACnet服务器的IP。

第一大坑:如果使用BACnet模拟器测试,那么BACnet模拟器和代码不能运行在同一电脑上,他们会互相占用对应端口!
顺便测试代码之前,把你的BACnet调试设备关掉,不然它也会占用端口。

import BAC0
myIPAddr = '192.168.1.1/24'
bacnet = BAC0.lite(ip=myIPAddr, )
bacnet.whois()
print(bacnet.whois())

打印输出:

2023-03-27 16:02:35,756 - INFO    | Starting BAC0 version 22.9.21 (Lite)
2023-03-27 16:02:35,756 - INFO    | Use BAC0.log_level to adjust verbosity of the app.
2023-03-27 16:02:35,756 - INFO    | Ex. BAC0.log_level('silence') or BAC0.log_level('error')
2023-03-27 16:02:35,756 - INFO    | Starting TaskManager
2023-03-27 16:02:35,757 - INFO    | Using ip : 192.169.1.1
2023-03-27 16:02:35,934 - INFO    | Starting app...
2023-03-27 16:02:35,935 - INFO    | BAC0 started
2023-03-27 16:02:35,935 - INFO    | Registered as Simple BACnet/IP App
2023-03-27 16:02:35,966 - INFO    | Update Local COV Task started
[('20:0x000000000000', 0), ('20:0x010000000000', 1), ('192.168.1.2', 4194302)]进程已结束,退出代码0

我这里用的是模拟器,我在模拟器中创建了两个device,显示出了两个模拟设备的网络地址和一个模拟器的地址。

BACnet设备读取

使用bacnet.read()方法。让我们先来读一读源码中的说明:

# 节选自C:\PycharmProjects\bacnet_test\venv\Lib\site-packages\BAC0\core\io\Read.pydef read(self,args,arr_index=None,vendor_id=0,bacoid=None,timeout=10,show_property_name=False,):"""Build a ReadProperty request, wait for the answer and return the value:param args: String with <addr> <type> <inst> <prop> [ <indx> ]:returns: data read from device (str representing data like 10 or True)*Example*::import BAC0myIPAddr = '192.168.1.10/24'bacnet = BAC0.connect(ip = myIPAddr)bacnet.read('2:5 analogInput 1 presentValue')Requests the controller at (Network 2, address 5) for the presentValue ofits analog input 1 (AI:1)."""

bacnet.read()函数接收一个类型为str的参数,字符串中的参数以空格为分隔,包含 addr type inst prop 四个参数.
之前我的模拟器输出了以下的device:
[('20:0x000000000000', 0), ('20:0x010000000000', 1), ('192.168.1.2', 4194302)]
在模拟器这里实际有用的只有前两个。我们以(‘20:0x010000000000’, 1) → AnalogInput 2 → presentValue作为测试项,那么

addr:20:0x010000000000
type:analogValue
inst:2
prop:presentValue

这就是最后的答案了。将其变成read函数需要的字符串参数,就是:'20:0x010000000000 analogValue 2 presentValue'
最终读取代码:

import BAC0
myIPAddr = '192.168.1.1/24'
bacnet = BAC0.lite(ip=myIPAddr, )
# bacnet.whois()  # 可以注释掉,这个的扫描时间比较长
# print(bacnet.whois())
data = bacnet.read('20:0x010000000000 analogValue 2 presentValue')
print(data)

完事了,你学会基本读取操作了

BACnet写入操作

同上,看看bacnet.write()源码说明:

    def write(self, args, vendor_id=0, timeout=10):"""Build a WriteProperty request, wait for an answer, and return status [True if ok, False if not].:param args: String with <addr> <type> <inst> <prop> <value> [ <indx> ] - [ <priority> ]:returns: return status [True if ok, False if not]*Example*::import BAC0bacnet = BAC0.lite()bacnet.write('2:5 analogValue 1 presentValue 100 - 8')Direct the controller at (Network 2, address 5) to write 100 to the presentValues ofits analogValue 1 (AV:1) at priority 8"""

和上面读取没啥大区别,多了一个‘-’和一个优先级。

bacnet.write('20:0x010000000000 analogValue 2 presentValue 12345.0 - 1')

就直接这么写入就可以了。

AND其他…

没错,测试环境很快就通过了,我就信心满满的实际测试了。然后就报错了

bacpypes.errors.InvalidTag: integer application tag required

…TAG标签错误???通过对代码的debug,找到了报错的触发代码:

def decode(self, tag):if (tag.tagClass != Tag.applicationTagClass) or (tag.tagNumber != Tag.realAppTag):raise InvalidTag("real application tag required")if len(tag.tagData) != 4:raise InvalidTag("invalid tag length")

就在(tag.tagNumber != Tag.realAppTag)这个判断上。debug告诉我,tag.tagNumber的值是3,Tag.realAppTag是源码中规定的值4。我到这里才去审查厂家给我提供的BACnet服务器的对接数据,结果发现他们的presentValue类型是Long,而不是Real。

这个时候,我坚定的认为自己在read和write函数里少填写了参数,或者用错函数了,导致数据类型不匹配(你想想,传的参数是个字符串啊,哪能规定数据类型),找到最后,除了在GitHub上找到了一个同样的问题但是没有回答,完全找不到任何的踪迹。于是这个时候我才死心塌地的去对着源码一步一步看。

BACpypes库中没有提供非标准数据类型接口!!!!!

我谢谢他啊…于是没办法,最后根据源码,直接修改了venv/lib/python3.6/site-packages/bacpypes/object.py源码中的数据类型:

@register_object_type
class AnalogValueObject(Object):objectType = 'analogValue'_object_supports_cov = Trueproperties = \[ ReadableProperty('presentValue', Integer)  # 原数据类型为Real, ReadableProperty('statusFlags', StatusFlags), ReadableProperty('eventState', EventState), OptionalProperty('reliability', Reliability), ReadableProperty('outOfService', Boolean), ReadableProperty('units', EngineeringUnits), OptionalProperty('minPresValue', Real), OptionalProperty('maxPresValue', Real), OptionalProperty('resolution', Real), OptionalProperty('priorityArray', PriorityArray), OptionalProperty('relinquishDefault', Real), OptionalProperty('covIncrement', Real), OptionalProperty('timeDelay', Unsigned), OptionalProperty('notificationClass',  Unsigned), OptionalProperty('highLimit', Real), OptionalProperty('lowLimit', Real), OptionalProperty('deadband', Real), OptionalProperty('limitEnable', LimitEnable), OptionalProperty('eventEnable', EventTransitionBits), OptionalProperty('ackedTransitions', EventTransitionBits), OptionalProperty('notifyType', NotifyType), OptionalProperty('eventTimeStamps', ArrayOf(TimeStamp, 3)), OptionalProperty('eventMessageTexts', ArrayOf(CharacterString, 3)), OptionalProperty('eventMessageTextsConfig', ArrayOf(CharacterString, 3)), OptionalProperty('eventDetectionEnable', Boolean), OptionalProperty('eventAlgorithmInhibitRef', ObjectPropertyReference), OptionalProperty('eventAlgorithmInhibit', Boolean), OptionalProperty('timeDelayNormal', Unsigned), OptionalProperty('reliabilityEvaluationInhibit', Boolean), OptionalProperty('minPresValue', Real), OptionalProperty('maxPresValue', Real), OptionalProperty('resolution', Real), OptionalProperty('faultHighLimit', Real), OptionalProperty('faultLowLimit', Real), OptionalProperty('currentCommandPriority', OptionalUnsigned), OptionalProperty('valueSource', ValueSource), OptionalProperty('valueSourceArray', ArrayOf(ValueSource, 16)), OptionalProperty('lastCommandTime', TimeStamp), OptionalProperty('commandTimeArray', ArrayOf(TimeStamp, 16)), OptionalProperty('auditablePriorityFilter', OptionalPriorityFilter)]

就是我写了注释的那行,改完,跑起来了。

总结一下就是,我再也不想用python碰BACnet了,为什么都21.9.21版本了,BAC0库还是没有去尝试修改依赖库或是重写这部分的代码,传参竟然用的是字符串,以空格作为split的参数去分割参数…现在BACnet很多名称中都带有空格了,这库完全没有考虑到兼容性问题。

结束

国内基本都是各种复制粘贴的那三行代码,上面这么多很简单的问题,其实踩过一次坑就明白什么情况了,包括也没人对其中的参数做出一个说明,可惜没有人带我了解一遍这库。希望这篇文章能解决一部分人的问题吧。


http://chatgpt.dhexx.cn/article/USGpX1Cr.shtml

相关文章

Bacnet协议报文格式详解(一)

系统实现基于BACnet/IP&#xff08;又称B/IP&#xff09;网络进行通讯。BACnet虚拟链路层&#xff08;BVLL&#xff09;提供了BACnet网络层和某指定的通讯子系统的接口&#xff0c;本文指定了BACnet虚拟链路控制&#xff08;BVLC&#xff09;要求支持的定向和广播信息。本实现关…

bacnet (收集)

嵌入式系统中BACnet-MS/TP协议栈的实现 一个BACnet设备由一个网络号码和一个MAC地址唯一确定 bacnet MS/TP 走的是485网络 https://www.eefocus.com/mcu-dsp/226727 1 引言 20世纪90年代&#xff0c;Internet经历了爆炸性发展&#xff0c;成为垄断全球的计算机网络。以Cisc…

BACnet

BACnet通讯协议(一) BACnet协议(A Data Communication Protocol for Building Automation and Control Networks)&#xff0c;是由美国采暖、制冷和空调工程师协会&#xff08;ASHRAE&#xff09;制定的一个楼宇自动控制技术标准文件&#xff0c;BACnet协议最根本的目的是提供…

BACnet协议

BACnet协议 BACnet协议层包括物理层&#xff0c;链路层&#xff0c;网络层&#xff0c;应用层和BACnet安全层。 我们知道BACnet是用于楼宇自动化和控制网络的简短形式的数据通信协议。BACnet是主要行业供应商产品中常用的自动化和控制协议之一&#xff0c;如江森自控&#xff…

BACnet协议详解——初识BACnet架构

文章目录 BACnet协议架构BACnet简化的架构简化的四层BACnet体系结构选取BACnet 网络的拓扑结构安全最后声明BACnet协议架构 国际标准化组织在制定计算机网络通讯协议标准时定义了一个模型,称为开放系统互联参考模型(OSI(ISO 7498)。模型的目的是解决计算机与计算机之间普遍…

BACnet基础入门

BACnet入门&#xff1a;一、简单了解 前言协议栈层级与拓扑结构1.层级体系2.拓扑结构 协议栈的相关内容1.应用层a.设备b.对象c.属性e.服务f.扩展g.安全h.互操作基本模块(BIBBs)i.一致性声明&#xff08;PICS&#xff09;j.其他 2.网络层3.数据链路与物理层 工具源码参考 前言 …

BACnet协议介绍

BACnet为BuildingAutomation andControlnetworks的简称&#xff0c;台湾通常翻译为“建筑自动化控制网路通讯协定”&#xff0c;而中国大陆则译为“楼宇自动化与控制网络”。 前言 BACnet是用于智能建筑的通信协议&#xff0c;是国际标准化组织&#xff08;ISO&#xff09;、美…

认识BACnet协议

一、什么是BACnet&#xff1f; BACnet&#xff0c;Building Automation and Control networks的简称&#xff0c;即楼宇自动化与控制网络。是用于智能建筑的通信协议。 一般楼宇自控设备从功能上讲分为两部分&#xff1a;一部分专门处理设备的控制功能&#xff1b;另一部分专…

【块存储block源码分析】 linux内核模块ceph nbd源码分析

jewel 版本支持 rbd-nbd 的特性&#xff0c;需要 map 支持较多特性的 rbd image 时&#xff0c;可以使用该 nbd driver NBD(Network Block Device) 可以将一个远程主机的磁盘空间&#xff0c;当作一个块设备来使用&#xff0c;就像一块硬盘一样。NBD是一个内核模块&#xff0c;…

用户增长 - BG/NBD概率模型预测用户生命周期LTV(二)

文章目录 1 理论1.1 BG / NBD概率模型介绍1.2 Gamma-Gamma模型2 实践案例2.1 lifetimes实践案例一&#xff1a;在线零售业务的交易2.1.1 数据解读2.1.2 BG / NBD - 预期交易的frequency /recency 热力图2.1.3 顾客留存概率热力图2.1.4 评估模型效果方式一&#xff1a;模型验证重…

使用BG/NBD模型与Gamma-Gamma模型预测客户的生命周期价值CLV/LTV

1. 背景 客户生命周期价值CLV: CLV是Customer Lifetime Value的简称&#xff0c;用来衡量一个客户&#xff08;用户&#xff09;在一段时期内对企业有多大价值&#xff0c;也称为LTV。 假如一个客户两年内在某商店内消费2000元&#xff0c;这2000元就是CLV,具有预测性。 CLV…

nbd 相关概念及操作

周五(3月6号)笔者发现有台物理机上挂载了一个并非常用的nbd设备&#xff0c;估计是之前人做的测试留下来的&#xff0c;决定卸载它&#xff0c;顺带了解了下nbd的设备信息。 什么是nbd 全称是network block device&#xff0c;类似于nfs&#xff0c;远程设备可以挂载&#xff…

qemu-nbd挂载虚拟机镜像文件系统

qemu-nbd挂载虚拟机镜像文件系统 基本原理操作步骤1.加载NBD驱动2. 连接 qemu-nbd3.挂载4.解挂 虚机文件系统为LVM实例1.加载驱动2.连接qemu-nbd3.挂载lvm分区4.卸载盘符 虚机文件系统为非LVM虚机文件系统为NTFS 基本原理 nbd&#xff08;网络块设备: Network Block Device&am…

linux qemu-nbd介绍

1. 介绍 NBD&#xff08;Network Block Device&#xff09;&#xff0c;即网络块设备。可以将一个远程主机的磁盘空间&#xff0c;当作一个块设备来使用。就像一块硬盘一样使用它&#xff0c;你可以很方便的将另一台服务器的硬盘空间,增加到本地服务器上。NBD与NFS有所不同&am…

centos7 nbd 挂在qcow2或qcow,raw,虚机镜像,virsh,virt,使用qemu-nbd挂载qcow2镜像文件

基本原理 nbd&#xff08;网络块设备: Network Block Device&#xff09;&#xff0c;利用qemu-nbd将qemu虚拟机镜像挂载到Linux上。   展开来讲&#xff0c;nbd可以将一个远程主机的磁盘空间&#xff0c;当作一个块设备来使用&#xff0c;就像一块硬盘一样。使用它,你可以很…

linux nbd模块,Centos7.3 安装编译nbd模块-Go语言中文社区

未安装nbd模块 [zhaojqlocalhost ~]$modprobe nbd modprobe: FATAL: Module nbd not found. 查看linux版本 [zhaojqlocalhost ~]$cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) [zhaojqlocalhost ~]$uname -r 3.10.0-514.26.2.el7.x86_64 安装 [rootlocalhost…

linux nbd模块,Centos7.3 安装编译nbd模块

未安装nbd模块 [[email protected] ~]$ modprobe nbd modprobe: FATAL: Module nbd not found. [[email protected] ~]$ cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) [[email protected] ~]$ uname -r 3.10.0-514.26.2.el7.x86_64 安装 [[email protected] …

NBD(Network Block Device)简介及基本使用

NBD指的是Network Block Device&#xff0c;正如其名字的意思&#xff0c;NBD让用户可以通过网络访问到某个块设备&#xff0c;或者设备镜像。 你可能会想NFS&#xff08;Network File System&#xff09;不是已经可以实现通过网络挂载各种文件系统并进行访问了吗&#xff0c;…

微信开放平台开发者认证

1.邮箱注册&#xff0c;激活账号 2.企业认证 3.登陆微信开放平台&#xff0c;进行开发者认证 4.填写认证信息 5.发票选择&#xff0c;可以选择不开发票 6. 支付费用300 备注&#xff1a;如有疑问&#xff0c;请联系作者&#xff01;

微信开放平台开发(3) 移动应用微信登录

在这篇微信公众平台开发教程中&#xff0c;我们将介绍如何使用微信开放平台接口实现移动应用微信登录的功能。 移动应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前&#xff0c;在微信开放平台注册开发者帐号&#x…