前言
因为公司项目需求要对接bacnet协议的设备,参考网上的一些文章对比下来决定使用bacnet4j进行java开发。老实说目前国内关于bacnet的文章蛮少的,所以我就来贡献一篇关于COV事件报文订阅的文章,其他事件的订阅其实也大同小异了。
一、Bacnet4J
GitHub上的bacnet4j项目包源码
我下面的内容基本上是参考他的测试代码写的,大家有兴趣可以多去研究研究源码。
二、使用步骤
1.Bacnet4J
Maven配置
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>ias-snapshots</id>
<name>Infinite Automation Snapshot Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
</repository>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>ias-releases</id>
<name>Infinite Automation Release Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.infiniteautomation</groupId>
<artifactId>bacnet4j</artifactId>
<version>5.0.2</version>
</dependency>
</dependencies>
2.实例代码
主线程代码:
package BACnet;
import BACnet.listener.CovNotifListener;
import com.serotonin.bacnet4j.LocalDevice;
import com.serotonin.bacnet4j.RemoteDevice;
import com.serotonin.bacnet4j.npdu.ip.IpNetwork;
import com.serotonin.bacnet4j.npdu.ip.IpNetworkBuilder;
import com.serotonin.bacnet4j.service.confirmed.SubscribeCOVRequest;
import com.serotonin.bacnet4j.transport.DefaultTransport;
import com.serotonin.bacnet4j.type.enumerated.ObjectType;
import com.serotonin.bacnet4j.type.primitive.Boolean;
import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier;
import com.serotonin.bacnet4j.type.primitive.Real;
import com.serotonin.bacnet4j.type.primitive.UnsignedInteger;
import com.serotonin.bacnet4j.util.RequestUtils;
/**
* @author BoringDragon
* @date 2021-08-20
*/
public class BacnetCovSubscribe {
public static void main(String[] args) {
LocalDevice d = null;
try {
//根据自己的实际IP地址进行配置
IpNetwork ipNetwork = new IpNetworkBuilder()
.withLocalBindAddress("127.0.0.1")
.withSubnet("255.255.255.0", 24)
.withPort(47808)
.withReuseAddress(true)
.build();
//deviceNumber 是在本地创建一个虚拟的设备进行通信,这个只要在本地不重复就可以随意写
d = new LocalDevice(10000, new DefaultTransport(ipNetwork));
//初始化设备
d.initialize();
//添加监听器
d.getEventHandler().addListener(new CovNotifListener());
//发送WhoIs请求网段的远端设备
d.startRemoteDeviceDiscovery();
//根据远端设备id获取远程设备
RemoteDevice rd = d.getRemoteDevice(1605654).get();
//发送订阅COV报文 对应为订阅标识(不可为0),订阅对象,是否要发送确认报文,订阅时长(0为永久)
d.send(rd, new SubscribeCOVRequest(new UnsignedInteger(4), new ObjectIdentifier(ObjectType.analogValue, 0), Boolean.TRUE,
new UnsignedInteger(0))).get();
while (true){
//修改值为77
RequestUtils.writePresentValue(d, rd, new ObjectIdentifier(ObjectType.analogValue, 0), new Real(77));
Thread.sleep(2000);
}
} catch (Exception e) {
e.printStackTrace();
if(d != null){
d.terminate();
}
}
}
}
监听器代码:
package BACnet.listener;
import com.serotonin.bacnet4j.event.DeviceEventAdapter;
import com.serotonin.bacnet4j.type.constructed.PropertyValue;
import com.serotonin.bacnet4j.type.constructed.SequenceOf;
import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier;
import com.serotonin.bacnet4j.type.primitive.UnsignedInteger;
/**
* @author BoringDragon
* @date 2021-08-20
*/
public class CovNotifListener extends DeviceEventAdapter {
@Override
public void covNotificationReceived(final UnsignedInteger subscriberProcessIdentifier,
final ObjectIdentifier initiatingDevice, final ObjectIdentifier monitoredObjectIdentifier,
final UnsignedInteger timeRemaining, final SequenceOf<PropertyValue> listOfValues) {
System.out.println("======================= Receive COV =======================");
System.out.println("======================= subscriberProcessIdentifier =======================");
System.out.println(subscriberProcessIdentifier);
System.out.println("======================= initiatingDevice =======================");
System.out.println(initiatingDevice);
System.out.println("======================= monitoredObjectIdentifier =======================");
System.out.println(monitoredObjectIdentifier);
System.out.println("======================= timeRemaining =======================");
System.out.println(timeRemaining);
System.out.println("======================= listOfValues =======================");
System.out.println(listOfValues);
System.out.println(listOfValues.get(0).getValue());
System.out.println("===========================================================");
}
}
使用的模拟设备工具为Yabe的Bacnet.Room.Simulator,下图两个红框从上到下分别为我上面代码订阅的温度和设备id
总结
结果如下图,因为没有设置OutOfService为false所以改值后会变回21.0