<Java物联网> 从主动到被动:Java中的BACnet设备属性查询_java bacnet

模拟器

拿其中一个模拟器Yabe来配合这次学习

安装好后,我们只需要用到这两个功能即可。

我们点击Simulator功能,会弹出这么一个模拟框。

这是模拟一个真实设备温度设备,底下的deviceId则为设备唯一标识。

我们同时打开多台,就可以发现他们的唯一标识不一样。

接下来打开Yabe

选择Add device,然后输入本机ip地址

然后你就会发现,它把我们刚刚打开的两台模拟设备扫描进去了。

选中其中一台设备后,下面Address Space会显示几行数据,对某个数据右键选择订阅后,你会发现,我们可以拿到模拟设备中的某个值的实时数据。

从而,我们能判断出,哪个属性值对应的是模拟设备中的什么,基于软件对设备的通讯到此就结束了。

重点在于我们如何使用Java来使用BACnet进行设备之间的通讯。

使用Java主动查

引入maven

在开始示例之前,请确保已经下载并配置了BACnet4J库。

        <!-- https://github.com/infiniteautomation/BACnet4J -->
        <dependency>
            <groupId>com.infiniteautomation</groupId>
            <artifactId>bacnet4j</artifactId>
            <version>6.0.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/lib/bacnet/bacnet4j-6.0.0.jar</systemPath>
        </dependency>
        

通过测试,单引用bacnet4j依赖,是远远不够的。使用起来会报各种异常,

比如

  • slf4j的 NoClassDefFoundError: org/slf4j/LoggerFactory
  • warp的 NoClassDefFoundError: lohbihler/warp/WarpScheduledExecutorService
  • commons的 NoClassDefFoundError: org/apache/commons/lang3/StringUtils

因此还需要引入以下maven依赖

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version> 
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version> 
        </dependency>
        <dependency>
            <groupId>ai.serotonin.oss</groupId>
            <artifactId>sero-scheduler</artifactId>
            <version>1.1.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/ai.serotonin.oss/sero-warp -->
        <dependency>
            <groupId>ai.serotonin.oss</groupId>
            <artifactId>sero-warp</artifactId>
            <version>1.0.0</version>
        </dependency>
创建网络对象

首先获取网段内的模拟设备,

//创建网络对象
IpNetwork ipNetwork = new IpNetworkBuilder()
    //本机的ip
    .withLocalBindAddress("192.168.1.12")
    //掩码和长度,如果不知道本机的掩码和长度的话,可以使用代码的工具类IpNetworkUtils获取
    .withSubnet("255.255.255.0", 24)
    //默认的UDP端口
    .withPort(47808)
    .withReuseAddress(true)
    .build();
//创建虚拟的本地设备,随意设置一个deviceId 设备的唯一标识
LocalDevice localDevice = new LocalDevice(LOCAL_DEVICE_ID, new DefaultTransport(ipNetwork));
//初始化本地设备
localDevice.initialize();
//搜寻网段内远程设备
localDevice.startRemoteDeviceDiscovery();

如果是ubuntu的情况下,建议去掉 withLocalBindAddress(“192.168.1.12”),它会默认监听"0.0.0.0"这个地址,达到一样的效果。

跨网段的话,修改withSubnet()方法

获取远程设备

可以使用 LocalDevice 对象来获取远程设备,根据业务来选择以下方法:

//某个远程设备的id
private static final Integer REMOTE_DEVICE_ID = 311400;

//获取某个远程设备,REMOTE_DEVICE_ID是远程设备ID
RemoteDevice remoteDevice = localDevice.getRemoteDeviceBlocking(REMOTE_DEVICE_ID);

//获取所有远程设备
List<RemoteDevice> remoteDevices = localDevice.getRemoteDevices();

通过debug得知,获取到的数据没有区别。

获取设备属性

在物联网中,有一个叫物模型的抽象思想,其中有一个概念叫做属性,简单的说,一个温度检测设备里,它的在线离线是一个属性,温度也是一个属性。

接下来我们就去获取这个设备的所有属性。

//获取远程设备的标识符对象
List<ObjectIdentifier> objectList = RequestUtils.getObjectList(localDevice,remoteDevice).getValues();

通过debug可以看到这个属性集合中的数据


是否觉得眼熟呢?是的,他就是对应上面进行订阅步骤的Address Space数据

这里就是它的属性。

通过对比,我们可以知道Analog_Input:0是我们需要的温度属性。

使用Java8获取温度属性对象

List<ObjectIdentifier> filter = objectList.stream().filter(e -> e.getObjectType().equals(ObjectType.analogInput) && e.getInstanceNumber() == 0).collect(Collectors.toList());

然后循环不断的获取该属性值的实时数据

while (true) {
                //根据对象属性标识符的类型进行取值操作 [测试工具模拟的设备点位的属性有objectName、description、present-value等等]
                //analog-input
                PropertyValues pvAiObjectName = readValueByProperty(localDevice, remoteDevice, filter, null, PropertyIdentifier.objectName);
                PropertyValues pvAiPresentValue = readValueByProperty(localDevice, remoteDevice, filter, null, PropertyIdentifier.presentValue);
                PropertyValues pvAiDescription = readValueByProperty(localDevice, remoteDevice, filter, null, PropertyIdentifier.description);
                for (ObjectIdentifier oi : filter) {
                    //取出点位对象不同类型分别对应的值
                    System.out.println(oi.getObjectType().toString() + " " + oi.getInstanceNumber() + " Name: " + pvAiObjectName.get(oi, PropertyIdentifier.objectName).toString());
                    System.out.println(oi.getObjectType().toString() + " " + oi.getInstanceNumber() + " PresentValue: " + pvAiPresentValue.get(oi, PropertyIdentifier.presentValue).toString());
                    System.out.println(oi.getObjectType().toString() + " " + oi.getInstanceNumber() + " Description: " + pvAiDescription.get(oi, PropertyIdentifier.description).toString());
                }
                Thread.sleep(1000);
}


抽一个通用的方法 readValueByProperty

public static PropertyValues readValueByProperty(final LocalDevice localDevice, final RemoteDevice d,final List<ObjectIdentifier> ois, final ReadListener callback, PropertyIdentifier propertyIdentifier) throws BACnetException
    {
        if (ois.size() == 0) {
            return new PropertyValues();
        }

        final PropertyReferences refs = new PropertyReferences();
        for (final ObjectIdentifier oid : ois) {
            refs.add(oid, propertyIdentifier);
        }

        return RequestUtils.readProperties(localDevice, d, refs, false, callback);
}

然后不断的读取和打印

这样就可以不断获取最新的实时值。

使用DeviceEventAdapter订阅

  1. 初始化本地BACnet设备和IP网络配置:
//创建网络对象
IpNetwork ipNetwork = new IpNetworkBuilder()
    //本机的ip
    .withLocalBindAddress("192.168.1.12")
    //掩码和长度,如果不知道本机的掩码和长度的话,可以使用代码的工具类IpNetworkUtils获取
    .withSubnet("255.255.255.0", 24)
    //默认的UDP端口
    .withPort(47808)
    .withReuseAddress(true)
    .build();
//创建虚拟的本地设备,随意设置一个deviceId 设备的唯一标识
LocalDevice localDevice = new LocalDevice(LOCAL_DEVICE_ID, new DefaultTransport(ipNetwork));

* 首先,它创建了一个本地BACnet设备,并指定设备号为123,并为其分配了一个默认的传输实例(DefaultTransport)。
* 然后,它使用`IpNetworkBuilder`构建了一个IP网络配置,包括本地绑定地址、子网掩码和长度、默认UDP端口和地址重用等,

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

…(img-H1ZL9FHW-1715842438833)]

[外链图片转存中…(img-jWgIDblF-1715842438833)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要连接BACnet并读取/写入数据,您需要使用BACnet协议栈和Java BACnet库。以下是一个简单的示例,使用BACnet4J库: ```java import java.util.List; import java.net.InetAddress; import com.serotonin.bacnet4j.*; import com.serotonin.bacnet4j.exception.BACnetException; import com.serotonin.bacnet4j.service.unconfirmed.WhoIsRequest; import com.serotonin.bacnet4j.obj.BACnetObject; import com.serotonin.bacnet4j.type.enumerated.ObjectType; import com.serotonin.bacnet4j.type.enumerated.PropertyIdentifier; import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier; import com.serotonin.bacnet4j.type.primitive.UnsignedInteger; public class BacnetExample { public static void main(String[] args) throws Exception { // 创建BACnet协议栈 final LocalDevice localDevice = new LocalDevice(1234, "127.0.0.1"); localDevice.initialize(); // 发送Who-Is请求以获取设备列表 final List<RemoteDevice> devices = localDevice.sendGlobalBroadcast(new WhoIsRequest()).getDevices(); // 打印设备列表 for (final RemoteDevice device : devices) { System.out.println("Device: " + device); } // 读取设备属性 final RemoteDevice device = devices.get(0); final ObjectIdentifier objectId = new ObjectIdentifier(ObjectType.analogInput, 0); final BACnetObject object = localDevice.getObject(device, objectId); final UnsignedInteger presentValue = (UnsignedInteger) object.getProperty(PropertyIdentifier.presentValue); System.out.println("Present value: " + presentValue); // 写入设备属性 final UnsignedInteger newValue = new UnsignedInteger(42); localDevice.setProperty(device, objectId, PropertyIdentifier.presentValue, newValue); } } ``` 请注意,此示例仅适用于本地连接。如果您需要连接到远程BACnet设备,则需要更改代码以使用远程设备的IP地址和端口号。此外,您可能需要在代码添加错误处理和异常捕获。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值