bacnet4j-wrapper icon indicating copy to clipboard operation
bacnet4j-wrapper copied to clipboard

Support for BACnet server functionality

Open amrnablus opened this issue 5 years ago • 12 comments

Hello and thanks for your great work, I was wondering if you have any example of building a bacnet server with writable properties. Thanks

amrnablus avatar Mar 02 '20 16:03 amrnablus

Hey @amrnablus, Library currently serves a client facade and doesn't do anything related to hosting server functionalities. Over 4 years ago when I first attempted to do it with bacnet4j it was quite bad and I couldn't find any working code samples. I must say that it is improved, unit tests provide decent amount of samples.

Inspired by your inquiry I made a small test and managed to get it running. See code below.

// Free sample, use it at your own risk. Remember bacnet4j is licensed under GPL.
package com.connectorio.bacnet;

import java.util.List;
import java.util.Random;
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.obj.AnalogInputObject;
import com.serotonin.bacnet4j.transport.DefaultTransport;
import com.serotonin.bacnet4j.transport.Transport;
import com.serotonin.bacnet4j.type.enumerated.EngineeringUnits;
import com.serotonin.bacnet4j.type.enumerated.PropertyIdentifier;
import com.serotonin.bacnet4j.type.primitive.Real;

/**
 * Sample bacnet4j server which exposes data over BACnet/IP.
 *
 * @author Łukasz Dywicki <[email protected]>
 */
public class Main {
    public static void main(String[] args) throws Exception {

        IpNetwork network = new IpNetworkBuilder().withBroadcast("x.y.z.w", 24).build();
        Transport transport = new DefaultTransport(network);
        transport.setTimeout(500000);
        transport.setSegTimeout(15000);
        final LocalDevice localDevice = new LocalDevice(11338, transport);

        AnalogInputObject aio1 = new AnalogInputObject(localDevice, 1, "test1", 1000.0f, EngineeringUnits.wattHours,
                false);

        final int min = 10, max = 35;

        Thread simulation = new Thread(new Runnable() {
            @Override public void run() {
                while (true) {
                    float random = new Random().nextFloat();
                    float value = min + random * (max - min);

                    aio1.writePropertyInternal(PropertyIdentifier.presentValue, new Real(value));
                }
            }
        }, "simulation");
        simulation.setDaemon(true);
        simulation.start();

        localDevice.initialize();

        System.in.read();
        localDevice.terminate();
    }

}

Below is a proof it actually works as designed: yabe-bacnet4j

Enjoy!

splatch avatar Mar 03 '20 14:03 splatch

Thanks @splatch, that's pretty much what i did, the tricky part was accepting writes from YABE to my backend server, i ended up with something like this:

public class ThermostatAdapeter extends DeviceEventAdapter ....
public class ThermostatEventListener ...
ThermostatAdapeter listener = new ThermostatAdapeter(executor, new ThermostatEventListener());

masterDevice.getEventHandler().addListener(listener);

My adapter gets triggered whenever there is a change on the properties.

That said, if you plan on wrapping the server code let me know, i might be able to contribute to that.

amrnablus avatar Mar 03 '20 16:03 amrnablus

Thanks for feedback and contribution proposal. Having server functionality is definitely interesting, but currently not yet in roadmap, if you don't mind I will mark issue as feature request.

In some undefined future I hope to port this facade to rely on BACnet support provided by Apache PLC4X project. It has Apache license by default, uses netty and NIO making at least java part closer to usual routine. It is also a bit more complex in some areas as it does more things than just a building automation. Currently Apache PLC4X offers support for "passive" mode - meaning replaying PCAPs with bacnet traffic, but I made my first experiments with live connection which prove that library, witch some glitches, is working. Obviously it is fresh and lacks many of bacnet4j features such as segmentation, server side handling, but it also has certain advantages coming from young codebase.

Here is abstract notation of protocol frames (messages): https://github.com/apache/plc4x/blob/release/0.6.0/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec

And here is brief logic of passive handling of protocol (notice this is available in develop/snapshot version): https://github.com/apache/plc4x/blob/7f8e033de7ea5dc48f3811c273f5e8a7b3d5175a/sandbox/test-java-bacnetip-driver/src/main/java/org/apache/plc4x/java/bacnetip/protocol/PassiveBacNetIpProtocolLogic.java#L104

Please feel yourself invited to plc4x community!

splatch avatar Mar 03 '20 17:03 splatch

Interesting, if i may suggest, why not create a generic wrapper with backend options being bacnet4j or plc4x (kinda like JPA but for bacnet).

Either way i'll keep an eye on the work here and i'll be happy to help.

amrnablus avatar Mar 03 '20 17:03 amrnablus

What you propose is really neat idea. I actually did a brief attempt two years ago with d28e8382ad053d3f1c7949b0ca4ae5588f5a0698 commit (2.0.x branch). Overall idea was to bring ASLv2 API and use BACnet4J as an implementation detail. Given current circumstances it makes even more sense now to bring this idea back.

splatch avatar Mar 03 '20 18:03 splatch

Yep, that looks exactly like what i have in mind, we can start by writing a generic interface which later a facade can be written for each provider in order to have it be "JBA (Java Bacnet API)?" compatible

amrnablus avatar Mar 04 '20 16:03 amrnablus

JBA sounds awesome. I like it a lot because it will not confuse people who come from Niagara/Tridium and know what their BAJA shortcut stands for (Building Automation Java Architecture).

splatch avatar Mar 04 '20 23:03 splatch

Hey @baardl, would you be interested in such functionality for your experiments? This will allow to make a bridge between your lab devices and rest of existing 0xBAC0 infrastructure in the building.

splatch avatar Mar 04 '20 23:03 splatch

Yes, @splatch 😀

baardl avatar Mar 05 '20 16:03 baardl

Hello,

I am also implementing a bacnet server. Current tests are going ok.

I am wondering what these values do : transport.setTimeout(500000); transport.setSegTimeout(15000);

  1. Will the transport shutdown after 500000 (No idea what unit) ?
  2. Do you know if plc4x provides bacnet server impl now ?

Thank you for any help

AmbroiseS avatar Oct 16 '23 14:10 AmbroiseS

I can't remember exactly why these values got in. Timeout is in ms (I suppose), its mostly there for debugging purposes because transport thread/threads are being used to dispatch events to callbacks you implement. Segmentation timeout is probably in seconds and its extra long for that reason too. You should be fine without these values or reverted to reasonable levels.

The plc4x work is a bit forward from where it was, however its still not even close to bacnet4j. Later one is full blown sdk, whereas plc4x is still at the library level for bacnet. If you look closer at plc4x sources, there is updated code which answers for bacnet whois requests, but not much more than that. Also, there is very little structuring behind (i.e. AnalogInputObjects), making amount of work much larger. Yet leaving you a lot of flexibility of how to handle entire thing.

splatch avatar Oct 16 '23 14:10 splatch

Thank you for the very quick response

I'll use default values for my testing. And keep my bacnet4j implementation also.

AmbroiseS avatar Oct 16 '23 14:10 AmbroiseS