Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website

  • 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");
        }