Extend from RemoteDevice
-
Hi guys,
If I "extend" from the class "RemoteDevice" and then create a object of that, I can't use it to send regular BACnet requests. I always run in a NullPointerException./17:02:40.933 [BACnet4J transport for device 10001] ERROR com.serotonin.bacnet4j.transport.DefaultTransport - Error during send: OutgoingConfirmed [maxAPDULengthAccepted=-1, segmentationSupported=null, service=ReadPropertyRequest [objectIdentifier=device 2098177, propertyIdentifier=object-list, propertyArrayIndex=null], consumer=com.serotonin.bacnet4j.transport.ServiceFutureImpl@10a4064, address=Address [networkNumber=0, macAddress=[c0,a8,1,b1,ba,c0]], linkService=null] java.lang.NullPointerException: null at com.serotonin.bacnet4j.transport.DefaultTransport$OutgoingConfirmed.sendImpl(DefaultTransport.java:380) at com.serotonin.bacnet4j.transport.DefaultTransport$Outgoing.send(DefaultTransport.java:336) at com.serotonin.bacnet4j.transport.DefaultTransport.run(DefaultTransport.java:486) at java.base/java.lang.Thread.run(Thread.java:830) 17:02:40.933 [BACnet4J transport for device 10001] ERROR com.serotonin.bacnet4j.transport.DefaultTransport - Original send stack java.lang.Exception: null at com.serotonin.bacnet4j.transport.DefaultTransport.send(DefaultTransport.java:292) at com.serotonin.bacnet4j.transport.DefaultTransport.send(DefaultTransport.java:283) at com.serotonin.bacnet4j.LocalDevice.send(LocalDevice.java:989) at com.serotonin.bacnet4j.util.RequestUtils.sendOneAtATime(RequestUtils.java:425) at com.serotonin.bacnet4j.util.RequestUtils.readProperties(RequestUtils.java:396) at com.serotonin.bacnet4j.util.RequestUtils.readProperties(RequestUtils.java:257) at com.serotonin.bacnet4j.util.RequestUtils.getProperties(RequestUtils.java:141) at com.serotonin.bacnet4j.util.RequestUtils.getProperties(RequestUtils.java:136) at com.bacnetbrowser.schoko.DeviceTest$Listener.iAmReceived(DeviceTest.java:40) at com.serotonin.bacnet4j.event.DeviceEventHandler.fireIAmReceived(DeviceEventHandler.java:97) at com.serotonin.bacnet4j.service.unconfirmed.IAmRequest.lambda$handle$0(IAmRequest.java:118) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:830)
The code I used for testing:
public class DeviceTest { static LocalDevice localDevice; public static void main(String[] args) throws Exception { int localDevice_ID = 10001; IpNetworkBuilder ipNetworkBuilder = new IpNetworkBuilder(); ipNetworkBuilder.withLocalBindAddress(IpNetwork.DEFAULT_BIND_IP); ipNetworkBuilder.withBroadcast("255.255.255.255", IpNetwork.BVLC_TYPE); ipNetworkBuilder.withPort(47808); DefaultTransport transport = new DefaultTransport(ipNetworkBuilder.build()); localDevice = new LocalDevice(localDevice_ID, transport); localDevice.getEventHandler().addListener(new Listener()); localDevice.initialize(); localDevice.startRemoteDeviceDiscovery(); } static class Listener extends DeviceEventAdapter { @Override public void iAmReceived(RemoteDevice d) { System.out.println("I am received" + d); Device device = new Device(localDevice, d.getInstanceNumber(), d.getAddress()); try { Map<PropertyIdentifier, Encodable> values = RequestUtils.getProperties( localDevice, device, device.getObjectIdentifier(),null, PropertyIdentifier.objectList); System.out.println(values); } catch (BACnetException e) { e.printStackTrace(); } } } static class Device extends RemoteDevice{ public Device(LocalDevice localDevice, int instanceNumber, Address address) { super(localDevice, instanceNumber, address); } } }
I would be glad if somone could have a look and give me a feedback ;-)
BR
Andreas -
@andreas-vogt what version of the code are you using? I can't see how that happens when reading the code on the
master
branch of BACnet4J. I would suggest you put a breakpoint in and find what is null. Then let me know and I can help you from there. -
Hello @terrypacker, thank you for answering! :)
I am using:
<dependency> <groupId>com.infiniteautomation</groupId> <artifactId>bacnet4j</artifactId> <version>5.0.2</version> </dependency>
As I followd the stacktrace I found in the "DefaultTransport" that at the line 769 "Segmentation" is needed. So the "Segmentation" is the object which is null in the "extended" class.
If I try:static class Listener extends DeviceEventAdapter { @Override public void iAmReceived(RemoteDevice d) { //Not null d.getSegmentationSupported(); Device device = new Device(localDevice,d.getInstanceNumber(),d.getAddress()); //Here happens a null pointer device.getSegmentationSupported(); } }
Therefore I was thinking of override this property and tried this:
public class DeviceTest { static LocalDevice localDevice; public static void main(String[] args) throws Exception { int localDevice_ID = 10001; IpNetworkBuilder ipNetworkBuilder = new IpNetworkBuilder(); ipNetworkBuilder.withLocalBindAddress(IpNetwork.DEFAULT_BIND_IP); ipNetworkBuilder.withBroadcast("255.255.255.255", IpNetwork.BVLC_TYPE); ipNetworkBuilder.withPort(47808); DefaultTransport transport = new DefaultTransport(ipNetworkBuilder.build()); localDevice = new LocalDevice(localDevice_ID, transport); localDevice.getEventHandler().addListener(new Listener()); localDevice.initialize(); localDevice.startRemoteDeviceDiscovery(); } static class Listener extends DeviceEventAdapter { @Override public void iAmReceived(RemoteDevice d) { Device device = new Device(localDevice, d.getInstanceNumber(), d.getAddress(), d.getSegmentationSupported()); try { Map<PropertyIdentifier, Encodable> values = RequestUtils.getProperties( localDevice, device, device.getObjectIdentifier(),null, PropertyIdentifier.objectList); System.out.println(values); } catch (BACnetException e) { e.printStackTrace(); } } } static class Device extends RemoteDevice{ Segmentation segmentation; public Device(LocalDevice localDevice, int instanceNumber, Address address, Segmentation segmentation) { super(localDevice, instanceNumber, address); this.segmentation = segmentation; } @Override public Segmentation getSegmentationSupported() { return this.segmentation; } } }
But I am running in a new exception:
10:32:31.350 [BACnet4J transport for device 10001] ERROR com.serotonin.bacnet4j.transport.DefaultTransport - Error during send: OutgoingConfirmed [maxAPDULengthAccepted=-1, segmentationSupported=segmented-both, service=ReadPropertyRequest [objectIdentifier=device 2098177, propertyIdentifier=object-list, propertyArrayIndex=null], consumer=com.serotonin.bacnet4j.transport.ServiceFutureImpl@36f5e9d5, address=Address [networkNumber=0, macAddress=[c0,a8,1,b1,ba,c0]], linkService=null] java.lang.NegativeArraySizeException: -7 at com.serotonin.bacnet4j.transport.DefaultTransport$OutgoingConfirmed.sendImpl(DefaultTransport.java:392) at com.serotonin.bacnet4j.transport.DefaultTransport$Outgoing.send(DefaultTransport.java:336) at com.serotonin.bacnet4j.transport.DefaultTransport.run(DefaultTransport.java:486) at java.base/java.lang.Thread.run(Thread.java:830) 10:32:31.350 [BACnet4J transport for device 10001] ERROR com.serotonin.bacnet4j.transport.DefaultTransport - Original send stack java.lang.Exception: null at com.serotonin.bacnet4j.transport.DefaultTransport.send(DefaultTransport.java:292) at com.serotonin.bacnet4j.transport.DefaultTransport.send(DefaultTransport.java:283) at com.serotonin.bacnet4j.LocalDevice.send(LocalDevice.java:989) at com.serotonin.bacnet4j.util.RequestUtils.sendOneAtATime(RequestUtils.java:425) at com.serotonin.bacnet4j.util.RequestUtils.readProperties(RequestUtils.java:396) at com.serotonin.bacnet4j.util.RequestUtils.readProperties(RequestUtils.java:257) at com.serotonin.bacnet4j.util.RequestUtils.getProperties(RequestUtils.java:141) at com.serotonin.bacnet4j.util.RequestUtils.getProperties(RequestUtils.java:136) at com.bacnetbrowser.schoko.DeviceTest$Listener.iAmReceived(DeviceTest.java:41) at com.serotonin.bacnet4j.event.DeviceEventHandler.fireIAmReceived(DeviceEventHandler.java:97) at com.serotonin.bacnet4j.service.unconfirmed.IAmRequest.lambda$handle$0(IAmRequest.java:118) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:830)
This time there sems a problem with the getMaxAPDULengthAccepted() of the Remote Device so I overrided this property as well:
public class DeviceTest { static LocalDevice localDevice; public static void main(String[] args) throws Exception { int localDevice_ID = 10001; IpNetworkBuilder ipNetworkBuilder = new IpNetworkBuilder(); ipNetworkBuilder.withLocalBindAddress(IpNetwork.DEFAULT_BIND_IP); ipNetworkBuilder.withBroadcast("255.255.255.255", IpNetwork.BVLC_TYPE); ipNetworkBuilder.withPort(47808); DefaultTransport transport = new DefaultTransport(ipNetworkBuilder.build()); localDevice = new LocalDevice(localDevice_ID, transport); localDevice.getEventHandler().addListener(new Listener()); localDevice.initialize(); localDevice.startRemoteDeviceDiscovery(); } static class Listener extends DeviceEventAdapter { @Override public void iAmReceived(RemoteDevice d) { Device device = new Device(localDevice, d.getInstanceNumber(), d.getAddress(), d.getSegmentationSupported()); try { Map<PropertyIdentifier, Encodable> values = RequestUtils.getProperties( localDevice, device, device.getObjectIdentifier(),null, PropertyIdentifier.objectList); System.out.println(values); } catch (BACnetException e) { e.printStackTrace(); } } } static class Device extends RemoteDevice{ Segmentation segmentation; int maxAPDULengthAccepted = 1476; public Device(LocalDevice localDevice, int instanceNumber, Address address, Segmentation segmentation) { super(localDevice, instanceNumber, address); this.segmentation = segmentation; } @Override public Segmentation getSegmentationSupported() { return this.segmentation; } @Override public int getMaxAPDULengthAccepted() { return maxAPDULengthAccepted; } } }
This is working but I do not know if I am on the right way.
BR
Andreas -
@Andreas-Vogt you are not on the correct path with this solution. I suggest you take a look at how the IamRequest class calls iAmReceived(RemoteDevice d).
Specifically this section of code from around line 110:
final RemoteDevice rd = new RemoteDevice(localDevice, remoteDoi, from); rd.setDeviceProperty(PropertyIdentifier.maxApduLengthAccepted, maxAPDULengthAccepted); rd.setDeviceProperty(PropertyIdentifier.segmentationSupported, segmentationSupported); rd.setDeviceProperty(PropertyIdentifier.vendorIdentifier, vendorId);
-
Hi guys, its been a while since I opened this thread. I am sorry for my late answer but I was very busy lately..
I have followed the call @terrypacker has mentioned and wanted to let you konw how I implemnted my BACnetDevice class which extends from the RemoteDevice back then. I am sure there is a better way but for me it is working. I guess that there are not many cases in which someone really needs to "extend" from Remotedevice.
But...
I'll have a closer look in the next weeks cause I'll do a littlebit refactoring in my code, if I can get a better solution I'll post the progress here. Just in case someone needs to know :)So my current implementation:
In the constructor of my own class I am forcing to implement the missing properties.
public BACnetDevice(LocalDevice localDevice, int instanceNumber, Address address, Segmentation segmentation, int vendorIdentifier,int maxAPDULengthAccepted) { super(localDevice, instanceNumber, address); this.setDeviceProperty(PropertyIdentifier.maxApduLengthAccepted, new UnsignedInteger(maxAPDULengthAccepted)); this.setDeviceProperty(PropertyIdentifier.segmentationSupported, segmentation); this.setDeviceProperty(PropertyIdentifier.vendorIdentifier, new UnsignedInteger(vendorIdentifier)); }
By the listener I am fetching the needed properties from the existing instanz
@Override public void iAmReceived(RemoteDevice d) { BACnetDevice bacnetDevice = new BACnetDevice(localDevice, d.getInstanceNumber(), d.getAddress(), d.getSegmentationSupported(), d.getVendorIdentifier(), d.getMaxAPDULengthAccepted()); waitingRoomBacnetDevices.put(bacnetDevice.getInstanceNumber(), bacnetDevice); LOG.info("Remote device " + d.getInstanceNumber() + " registered in waiting room of LocalDevice"); }