• Recent
    • Tags
    • Popular
    • Register
    • Login

    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 Mango 5 Documentation Website

    How to integrate BACnet Change Of Value (COV) using BACnet4J

    BACnet4J general discussion
    4
    17
    14.1k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • G
      Gatos
      last edited by

      Hello,

      as this is my first post, I start by saying many thanks for bacnet4j, great work!

      I am "updating" this thread because I have seen a couple of questions about implementing COV subscriptions, but not many answers.
      The SimpleSubscriptionClient, which is mentioned in another thread, seems to be missing from the current release (?)

      I also have difficulties with COV. More concretely:
      I am trying to subscribe using the following method, passing it a RemoteDevice for which I have checked that d.getServicesSupported().isSubscribeCovProperty() returns true and an oid which corresponds to a Binary Input:

      public int subscribeCOV(RemoteDevice d, ObjectIdentifier oid) {
      SubscribeCOVRequest covReq = new SubscribeCOVRequest(new UnsignedInteger(0), oid, new Boolean(true), new UnsignedInteger(0));
      try {
      localDevice.send(d, covReq);
      System.out.println("Subsciption of " + oid.getObjectType() + "-" + oid.getInstanceNumber() + " done.");
      return Properties.SUCCESS;
      } catch (BACnetException be) {
      System.out.println("Unable to send <SubscribeCOVRequest> for the Object " + oid.getObjectType()+ "-" + oid.getInstanceNumber()+ ":\n"+ be.getMessage());
      return Properties.FAIL;
      }
      }

      and the exception occurs giving the message:
      ErrorAPDU(choice=5, errorClass=Services, errorCode=Cov subscription failed)
      Can someone tell me when and why this occurs?

      Thanks a lot in advance. I will post again here if I solve the problem.

      Best regards,
      Gatos

      1 Reply Last reply Reply Quote 0
      • J
        japearson
        last edited by

        Hi Gatos,

        The SimpleSubscriptionClient is a test class, you need go and download the latest source to get at it.

        http://bacnet4j.cvs.sourceforge.net/bacnet4j/ then click Download GNU tarball
        Or download from CVS using the instructions here: http://sourceforge.net/scm/?type=cvs&group_id=224576

        To get the test working, simply start the SlaveDeviceTest, and then run the SimpleSubscriptionClient in another window and you should see COV's coming through. I've run those classes in my Eclipse and it worked fine for me.

        Cheers,

        -Joel

        1 Reply Last reply Reply Quote 0
        • G
          Gatos
          last edited by

          Hello Joel,

          many thanks for your response!

          I am now a bit stuck with the test.
          Although the slave test device receives the iAm from the subscription client, the latter blocks at:
          d = localDevice.findRemoteDevice(new Address(new byte[] { (byte) 192, (byte) 168, (byte) 56, (byte) 255}, 2068), null, 1968);
          while the slave device test periodically throws the exception:

          com.serotonin.bacnet4j.exception.BACnetException: Error while creating APDU:
          at com.serotonin.bacnet4j.npdu.ip.IpMessageControl$IncomingMessageExecutor.parseApdu(IpMessageControl.java:662)
          at com.serotonin.bacnet4j.npdu.ip.IpMessageControl$IncomingMessageExecutor.runImpl(IpMessageControl.java:530)
          at com.serotonin.bacnet4j.npdu.ip.IpMessageControl$IncomingMessageExecutor.run(IpMessageControl.java:518)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
          at java.lang.Thread.run(Unknown Source)
          Caused by: java.lang.IllegalArgumentException: Unknown id: 7
          at com.serotonin.bacnet4j.enums.MaxSegments.valueOf(MaxSegments.java:71)
          at com.serotonin.bacnet4j.apdu.ConfirmedRequest.<init>(ConfirmedRequest.java:255)
          at com.serotonin.bacnet4j.apdu.APDU.createAPDU(APDU.java:44)
          at com.serotonin.bacnet4j.npdu.ip.IpMessageControl$IncomingMessageExecutor.parseApdu(IpMessageControl.java:655)
          ... 5 more

          Note: This exception starts to be thrown only in the case of a successfully received iAm.
          Further, I noticed that if I provide a port other than 2068 to the method findRemoteDevice, this exception is not thrown, unless I provide 47808. Then, exactly the same exception is thrown, but at the subscription client this time.

          Any ideas?

          Thanks + regards
          Gatos

          1 Reply Last reply Reply Quote 0
          • J
            japearson
            last edited by

            Hi Gatos,

            Download the source code again, the source was broken for few days when Matthew fixed the [url=http://forum.infiniteautomation.com/forum/posts/list/1242.page]UDP 7 segments bug

            1 Reply Last reply Reply Quote 0
            • G
              Gatos
              last edited by

              Hello,

              Many thanks, it works now!

              However, it took me a while to find out why subscriptions did not work with my own client although they worked with the SimpleSubscriptionClient.
              Therefore, just in case someone is as stupid as I am :-), I note where the problem was:

              It is necessary that also the client sends the "iAm" -> Line 24 of the SimpleSubscriptionClient: localDevice.sendBroadcast(2068, localDevice.getIAm());
              Just because I could do discoveries, reads, and writes without having done this (i.e., my client was sending only a "whoIs"), I did not think that it would be needed for subscriptions, so I had ignored the above call and was always getting the error ErrorAPDU(choice=5, errorClass=Services, errorCode=Cov subscription failed)...

              Best regards
              Gatos

              1 Reply Last reply Reply Quote 0
              • J
                japearson
                last edited by

                Hi Gatos,

                I think the SlaveDeviceTest needs to know about the SimpleSubscriptionClient before it will accept COV requests from it. I found that if you start the SlaveDeviceTest, then the SimpleSubscriptionClient, stop the SimpleSubscriptionClient, comment out the sendBroadcast and then start it again. COV requests still work, that is because the slave device already knows about the SimpleSubscriptionClient.

                An alternative to a broadcast would be to send a direct iAm to the slave device by adding this after line 25:

                localDevice.sendUnconfirmed(d.getAddress(), null, localDevice.getIAm());
                

                I'm still pretty new to BACnet myself, so I'm not sure the technical reason why simply attempting to subscribe by COV, doesn't implicitly add the device to the SlaveDeviceTest.

                1 Reply Last reply Reply Quote 0
                • G
                  Gatos
                  last edited by

                  Hey,

                  Thanks, again!

                  I've read in the forum that you have done some research on the issue "COV subscriptions for Analog Inputs/Outputs".
                  Could you tell me what's the status there? Any solutions or workarounds for implementing it with bacnet4j described somewhere?

                  Cheers,
                  Gatos

                  1 Reply Last reply Reply Quote 0
                  • J
                    japearson
                    last edited by

                    Hi Gatos,

                    We're still in discussions with our client if they want us to implement COV subscriptions for analog values.

                    A simple workaround or "dirty hack" is simply to add

                    
                    supportedObjectTypes.add(ObjectType.analogValue);
                    supportedObjectTypes.add(ObjectType.analogInput);
                    supportedObjectTypes.add(ObjectType.analogOutput);
                    
                    

                    to ObjectCovSubscription

                    That will make it accept the COV subscriptions, and it will send COV notifications, however, it will send a COV notification for any change of the analog value. Which for analog values is probably a bad thing, because they could be changing all the time. The real solution needs to implement some sort of threshold, so that COV notifications are only sent once the value changes enough.

                    1 Reply Last reply Reply Quote 0
                    • M
                      manjunathm
                      last edited by

                      Hi This Taresh,

                      can u please send me code to read analog values,

                      as it is urgently required for our project

                      1 Reply Last reply Reply Quote 0
                      • J
                        japearson
                        last edited by

                        Hi Taresh,

                        If you're talking about the analog COV subscription changes, that was merged in Nov 2012, see: http://forum.infiniteautomation.com/forum/posts/list/1207.page

                        1 Reply Last reply Reply Quote 0
                        • M
                          manjunathm
                          last edited by

                          Can u please share the code to read (Request and response sorce code for analog values)

                          am trying some what like this ,, but am getting timeout exception

                          package com.lnt.TestApp;

                          import java.util.List;

                          import com.serotonin.bacnet4j.LocalDevice;
                          import com.serotonin.bacnet4j.RemoteDevice;
                          import com.serotonin.bacnet4j.enums.MaxApduLength;
                          import com.serotonin.bacnet4j.npdu.ip.IpNetwork;
                          import com.serotonin.bacnet4j.service.acknowledgement.AcknowledgementService;
                          import com.serotonin.bacnet4j.service.acknowledgement.AtomicReadFileAck;
                          import com.serotonin.bacnet4j.service.acknowledgement.ReadPropertyAck;
                          import com.serotonin.bacnet4j.service.confirmed.AtomicReadFileRequest;
                          import com.serotonin.bacnet4j.service.confirmed.ConfirmedRequestService;
                          import com.serotonin.bacnet4j.service.confirmed.ReadPropertyRequest;
                          import com.serotonin.bacnet4j.service.unconfirmed.WhoIsRequest;
                          import com.serotonin.bacnet4j.transport.Transport;
                          import com.serotonin.bacnet4j.type.Encodable;
                          import com.serotonin.bacnet4j.type.constructed.Address;
                          import com.serotonin.bacnet4j.type.constructed.SequenceOf;
                          import com.serotonin.bacnet4j.type.enumerated.ObjectType;
                          import com.serotonin.bacnet4j.type.enumerated.PropertyIdentifier;
                          import com.serotonin.bacnet4j.type.enumerated.Segmentation;
                          import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier;
                          import com.serotonin.bacnet4j.type.primitive.OctetString;
                          import com.serotonin.bacnet4j.util.RequestUtils;

                          public class Test {
                          static LocalDevice lDevice;
                          static Address addr = new Address(0, "IP");

                          public Test() {
                          }
                          
                          public static void main(String args[]) {
                          	initializeDevice();
                          }
                          
                          public static void initializeDevice() {
                          	try {
                          		System.out.println("Initializing...");
                          		IpNetwork ipNetwork = new IpNetwork("Ip", 47808,"Ip");
                          		Transport transport = new Transport(ipNetwork);
                          		lDevice = new LocalDevice(9899, transport);
                          		lDevice.initialize();
                          		lDevice.getEventHandler().addListener(new Listener());
                          		lDevice.sendGlobalBroadcast(new WhoIsRequest());
                          		Thread.sleep(500);
                          
                          		getObjectList(lDevice, "Ip",	47808, 0);
                          	} catch (Exception e) {
                          		System.out.println("Error : " + e.getMessage());
                          	} finally {
                          		closeDevice();
                          	}
                          }
                          
                          public static AcknowledgementService send(LocalDevice d,
                          		ConfirmedRequestService s) throws Exception {
                          

                          // Address a = new Address(InetAddrCache.get("localhost", 0xbac1));
                          return d.send(addr, null, MaxApduLength.UP_TO_1476, Segmentation.segmentedBoth, s);
                          }

                          public static void closeDevice() {
                          	try {
                          		lDevice.terminate();
                          	} catch (Exception e) {
                          		System.out.println(e.getMessage());
                          	}
                          }
                          
                          private static void getObjectList(LocalDevice localDevice, String ip,
                          		int port, int deviceId) throws Exception {
                          	RemoteDevice fileDev = null;
                          	ObjectIdentifier file = null;
                          	ReadPropertyRequest readPropertyRequest;
                          	ReadPropertyAck reaPropertyAck;
                          	
                          	
                          	for (RemoteDevice d : localDevice.getRemoteDevices()) {
                          

                          // ObjectIdentifier oid = d.getObjectIdentifier();
                          @SuppressWarnings("unchecked")
                          List<ObjectIdentifier> oids = ((SequenceOf<ObjectIdentifier>) RequestUtils
                          .sendReadPropertyAllowNull(localDevice, d, d.getObjectIdentifier(),PropertyIdentifier.objectList)).getValues();

                          		Address address[] = lDevice.getAllLocalAddresses();
                          		OctetString octetString = new OctetString("Ip", 47808);
                          		
                          		for (int i = 0; i < oids.size(); i++) {
                          			System.out.println("OBjectIdentifier"+oids);
                          		}
                          		
                          		for (ObjectIdentifier oid : oids) {
                          			readPropertyRequest = new ReadPropertyRequest(oid,	PropertyIdentifier.objectName);
                          			reaPropertyAck = (ReadPropertyAck) localDevice.send(d, readPropertyRequest); 
                          			System.out.println("Value: " + reaPropertyAck.getValue());
                          			
                          			if (oid.getObjectType().equals(ObjectType.file)) {
                          				fileDev = d;
                          				file = oid;
                          				AtomicReadFileRequest request = new AtomicReadFileRequest(file, false, 0, 1412);
                          				AtomicReadFileAck response = (AtomicReadFileAck) localDevice.send(fileDev, request);
                          				System.out.println("eof: " + response.getEndOfFile());
                          				System.out.println("start: "+ response.getFileStartPosition());
                          				System.out.println("data: "	+ new String(response.getFileData().getBytes()));
                          				System.out.println("length: "+ response.getFileData().getBytes().length);
                          			}
                          			
                          			if (oid.getObjectType().equals(ObjectType.analogValue)) {
                          				fileDev = d;
                          				file = oid;
                          				readPropertyRequest = new ReadPropertyRequest(new ObjectIdentifier(ObjectType.analogValue, 243), PropertyIdentifier.clientCovIncrement);
                          				reaPropertyAck = (ReadPropertyAck) localDevice.send(d, readPropertyRequest); 
                          				System.out.println(reaPropertyAck.getValue());
                          			}
                            		}
                          	}
                          }
                          

                          }

                          am getting timke exception for reading analog values

                          1 Reply Last reply Reply Quote 0
                          • J
                            japearson
                            last edited by

                            I haven't used BACNet4j for over a year, but from the code you provided, it doesn't look like you have another bacnet device that would be responding to the requests. You'd need to have a BACnet "server" or slave device actually sending the values.

                            For example, to get this test to work:

                            http://bacnet4j.cvs.sourceforge.net/viewvc/bacnet4j/BACnet4J/src_test/com/serotonin/bacnet4j/test/SimpleSubscriptionClient.java?view=markup

                            You need to have this test already running in the background:

                            http://bacnet4j.cvs.sourceforge.net/viewvc/bacnet4j/BACnet4J/src_test/com/serotonin/bacnet4j/test/SlaveDeviceTest.java?view=markup

                            I'd recommend that you start by getting the samples working, before trying other things.

                            1 Reply Last reply Reply Quote 0
                            • M
                              manjunathm
                              last edited by

                              No i have server running in my premisis,,,,

                              i can see the list of devices also.... if u see my output you can see objects

                              and the link u shared, am not able to open bcz restriction,,, can u please share the code??

                              1 Reply Last reply Reply Quote 0
                              • J
                                japearson
                                last edited by

                                I'm not going to paste the code in the forum, because you really need the bacnet4j source so that you can test it out, download the source from http://sourceforge.net/projects/bacnet4j/files/bacnet4j/1.3/

                                and make sure you don't have any problems with running all the tests.

                                And as I said before, it's been over a year since I touched bacnet4j, so good luck, I'm sure once you have the source, you'll figure out what is going wrong.

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post