Open amrnablus opened 4 years ago
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 <luke@code-house.org>
*/
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:
Enjoy!
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.
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!
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.
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.
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
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).
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.
Yes, @splatch 😀
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);
Do you know if plc4x provides bacnet server impl now ?
Thank you for any help
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. AnalogInputObject
s), making amount of work much larger. Yet leaving you a lot of flexibility of how to handle entire thing.
Thank you for the very quick response
I'll use default values for my testing. And keep my bacnet4j implementation also.
Hello and thanks for your great work, I was wondering if you have any example of building a bacnet server with writable properties. Thanks