[co7io] BACnet v2 binding for openHAB 2.x

Hey all,
I would like to announce and invite you to test a new version of BACnet binding. This binding works with openHAB v2 and finally offers a first class discovery. Sources are available at github, bacnet part is licensed under GPL3.

Among new features there is support for new object types (but still without valid support for Schedule…); very early, very experimental support for BACnet/MSTP. If hardware you run openHAB onto is capable of handling RS485 inputs you now can try to talk directly to device over serial interface. Be aware that end device should support segmentation.

Installation
Download kar, copy it to addons folder and look for openhab-binding-bacnet.

As of beginning of May 2020 binding downloads are available through connectorio.com website where you can “purchase” item after leaving your contact details.

Binary builds are available with no costs. Binding for openHAB 2.5 is supposed to receive less effort over time. There are no license keys. Binding yo get have no data-point limit. You simply get an archive which you can install multiple times on any number of devices.

You can use provided binaries for commercial deployments. Its open source. Do your own tests. If it works then its up to you if you want to pay for it (we can invoice). We collect cash to get real hardware, pay for further services, compensate our efforts and simply keep things up and running in a proper state.

Downloads: BACnet binding for openHAB 3.x, BACnet 2.x binding. Installation manual in pdf format.

Release history

  • 20210322 - (3.0.0-snapshot)
    Solves troubles with writing of Contact items.
  • 20210315 - (3.0.0-snapshot, unpublished)
    Support for writing openHAB Quantity types back to BACnet analogs.
  • 20210129 - (3.0.0-snapshot, unpublished)
    Addresses linking issues with openHAB 3.0.
  • 20210109
    First release compatible with openHAB 3.0.
  • 20201006:
    Small updates towards stabilization of connection handling which do not impact BACnet integration directly.
  • 20200504 - Initial release, tested with reading scenarios. Write access not working, no COV support.
  • Full discovery of network interfaces, BACnet devices and their properties.
  • Support for configuration via *.things and *.items files.

In case of troubles you can use this calendar to schedule a support call: Calendly - Łukasz Dywicki.

Quick FAQ:
Q: Why there is no binary release?
A: Because sources are available for free for everyone.

Q: Why I need to register?
A: We want to keep touch with our users, also people who don’t have forum accounts.

Calling directly earlier users so you can catch the spot:
@Pierre-Luc_Pelletier
@kazemiprince
@Craigkh
@LeXLuther422
@joschi36
@Ugis_Springis
@AusSandman
@MikeHinton
@tcbcontrols
@tagada

3 Likes

Hi @splatch,

this is great ! I tried to install the binding, but must be doing something wrong. I copied the file in the addons folder and restarted the openhab2 service but I cannot find the binding in PaperUI and do not see it if I run the bundle:list command. Do I need to uninstall the old 1.13 binding ?

Hey Pierre,
There is no need to uninstall old binding. All you need is to drop KAR file to /usr/share/openhab2/addons, wait a bit and then go to Paper UI.

If you do not see binding in the UI then there are two diagnostic commands to run:

openhab> kar:list
KAR Name
─────────────────
siemens-2.5.1.M1
bacnet-2.5.1.M1
beckhoff-2.5.1.M1

and

openhab> feature:list|grep -i bacnet
co7io-binding-base                                x 2.5.1.M1         x          x Started     x bacnet                   x ConnectorIO Binding Base
openhab-binding-bacnet                            x 2.5.1.M1         x          x Uninstalled x bacnet                   x BACnet Binding
bacnet4j-wrapper                                  x 1.2.0            x          x Started     x bacnet                   x bacnet4j wrapper library
co7io-binding-bacnet                              x 2.5.1.M1         x x        x Started     x bacnet                   x BACnet Binding
bacnet                                            x 2.5.1.M1         x          x Uninstalled x bacnet                   x ConnectorIO - Binding - Features - Distributions

If you see bacnet-x.y.z in output of first command then you should be able to see openhab-binding-bacnet in the second one. The old binding do not have a feature nor marketplace item thus it should not interfere with anything.

Hi @splatch,

thanks, I see it now. I still cannot run it because de bind address is already being used by the previous version of the binding on my openhab machine.

I will set aside some time to test this in the next few days and will keep you posted.

@Pierre-Luc_Pelletier it should be sufficient just to stop old binding for tests. Since you asked about commands. That is procedure from the shell:

openhab> la -l|grep -i bacnet
246 x Active    x  80 x 1.2.0                   x mvn:org.code-house.bacnet4j/api/1.2.0
247 x Active    x  80 x 1.2.0                   x mvn:org.code-house.bacnet4j/ip/1.2.0
248 x Active    x  80 x 1.2.0                   x mvn:org.code-house.bacnet4j/mstp/1.2.0
249 x Active    x  80 x 2.5.1.M1                x mvn:org.connectorio.binding/bacnet/2.5.1.M1
261 x Active x  80 x 1.13.0.201812290105     x file:/usr/share/openhab2/addons/org.openhab.binding.bacnet-1.13.0.jar

From above list you can see that bundle 261 is old binding and you can stop it with command stop 261. If you will execute command refresh 249 it should cause re-allocation of port by new binding.

Thanks, I tried it and found a few things :

I seem to get an error on multi-state value objects

2020-05-05 16:08:04.857 [INFO ] [g.discovery.internal.PersistentInbox] - Added new thing 'multistate-value::90002' to inbox.

2020-05-05 16:08:04.861 [ERROR] [g.discovery.internal.PersistentInbox] - Could not post event of type 'added'.

java.lang.NullPointerException: null

	at org.eclipse.smarthome.config.discovery.dto.DiscoveryResultDTOMapper.map(DiscoveryResultDTOMapper.java:41) ~[?:?]

	at org.eclipse.smarthome.config.discovery.inbox.events.InboxEventFactory.map(InboxEventFactory.java:129) ~[?:?]

	at org.eclipse.smarthome.config.discovery.inbox.events.InboxEventFactory.createAddedEvent(InboxEventFactory.java:85) ~[?:?]

	at org.eclipse.smarthome.config.discovery.internal.PersistentInbox.postEvent(PersistentInbox.java:532) ~[?:?]

	at org.eclipse.smarthome.config.discovery.internal.PersistentInbox.notifyListeners(PersistentInbox.java:524) ~[?:?]

	at org.eclipse.smarthome.config.discovery.internal.PersistentInbox.add(PersistentInbox.java:222) ~[?:?]

	at org.eclipse.smarthome.config.discovery.internal.PersistentInbox.thingDiscovered(PersistentInbox.java:376) ~[?:?]

	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl$1.run(DiscoveryServiceRegistryImpl.java:265) ~[?:?]

	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl$1.run(DiscoveryServiceRegistryImpl.java:1) ~[?:?]

	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_222]

	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.thingDiscovered(DiscoveryServiceRegistryImpl.java:262) ~[?:?]

	at org.eclipse.smarthome.config.discovery.AbstractDiscoveryService.thingDiscovered(AbstractDiscoveryService.java:279) ~[?:?]

	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[?:1.8.0_222]

	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_222]

	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_222]

	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) ~[?:1.8.0_222]

	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[?:1.8.0_222]

	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) ~[?:1.8.0_222]

	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[?:1.8.0_222]

	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[?:1.8.0_222]

	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_222]

	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485) ~[?:1.8.0_222]

	at org.connectorio.binding.bacnet.internal.discovery.BACnetPropertyDiscoveryService.lambda$startScan$2(BACnetPropertyDiscoveryService.java:84) ~[?:?]

	at java.util.Optional.ifPresent(Optional.java:159) [?:1.8.0_222]

	at org.connectorio.binding.bacnet.internal.discovery.BACnetPropertyDiscoveryService.startScan(BACnetPropertyDiscoveryService.java:81) [bundleFile:?]

	at org.eclipse.smarthome.config.discovery.AbstractDiscoveryService.startScan(AbstractDiscoveryService.java:209) [bundleFile:?]

	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:382) [bundleFile:?]

	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScans(DiscoveryServiceRegistryImpl.java:358) [bundleFile:?]

	at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:216) [bundleFile:?]

	at org.eclipse.smarthome.io.rest.core.internal.discovery.DiscoveryResource.scan(DiscoveryResource.java:97) [bundleFile:?]

	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_222]

	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_222]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_222]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_222]

	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) [bundleFile:?]

	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144) [bundleFile:?]

	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161) [bundleFile:?]

	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160) [bundleFile:?]

	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99) [bundleFile:?]

	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389) [bundleFile:?]

	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347) [bundleFile:?]

	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102) [bundleFile:?]

	at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326) [bundleFile:?]

	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) [bundleFile:?]

	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) [bundleFile:?]

	at org.glassfish.jersey.internal.Errors.process(Errors.java:315) [bundleFile:?]

	at org.glassfish.jersey.internal.Errors.process(Errors.java:297) [bundleFile:?]

	at org.glassfish.jersey.internal.Errors.process(Errors.java:267) [bundleFile:?]

	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317) [bundleFile:?]

	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305) [bundleFile:?]

	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154) [bundleFile:?]

	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473) [bundleFile:?]

	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427) [bundleFile:?]

	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388) [bundleFile:?]

	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341) [bundleFile:?]

	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228) [bundleFile:?]

	at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76) [bundleFile:?]

	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:852) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:544) [bundleFile:9.4.20.v20190813]

	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) [bundleFile:?]

	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:536) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1581) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1307) [bundleFile:9.4.20.v20190813]

	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) [bundleFile:?]

	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:482) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1549) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1204) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [bundleFile:9.4.20.v20190813]

	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) [bundleFile:?]

	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.Server.handle(Server.java:494) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:374) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:268) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782) [bundleFile:9.4.20.v20190813]

	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918) [bundleFile:9.4.20.v20190813]

	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222]

The other thing is I have a master device (on the Bacnet/IP network) fronting a slave device connected to it via MS/TP. The old binding supported it after you made some modifications, but the discovery does not seem to work for the slave device with the new binding. It works fine on the master one connected via Bacnet/IP.

Happy to send you more details on the setup or other logs if you want to troubleshoot this further.

Thanks !

Hey Pierre,
I can do additional round with multistate objects/properties. With regard to mstp over ip - underlying library in v2 binding is the same as it was for legacy one thus it should not change much.

I’ve checked older topic you made Bacnet binding error on start - and it seems that error we been fixing was related to address handling.
In order to fully support your case I would need to take a look on installation and wireshark dumps cause you have a nested device of two kinds. Currently binding requires ip devices to be attached to ip bridge and mstp devices to be attached to mstp bridge, what you have is a device with mstp address under ip bridge and ip network. It is possible to be covered, yet I need to determine how to construct valid frames for that.

Best,
Łukasz

Hi @splatch,

the V1 binding works fine for my use case as it is, but I am happy to help troubleshoot on this new one if you want to cover the use case. If so, let me know what kind of wireshark capture you need and I will do my best to give you the info.

The best would be
A) discovery of devices
B) command to mstp device

Based on that I will be able to determine how to constuct requests. You can generate above using any bacnet tool - ie YABE.

Hi @splatch,

sent you the pcap files via direct message. Let me know if you need anything more.

Hello,
i have successfully installed the add-on. I also see the bacnet objects. Unfortunately I cannot write on the objects. I can only read the values. Where can I look for the error?

It is not an error, write part is not implemented yet. I haven’t had time to fully port 1.x functionality.

Aaa ok. good to know. Do you already have an idea in which version this could be possible? That would be a useful function for my building project.

I am currently busy with canopen binding and updates for OH3. I can take a look on bacnet writing somewhere in next week. Are you fine with analog/binary/multistate input/output types or you need something more?

Hello,
thank you for the info.
The following types are currently interesting for me to read and write:

AI / AO / AV
BI / BO /
MI / MO / MV

Otherwise your add-on will work without any problems.
With the expansion of the write function, I can perfectly equip the control from the manufacturer Kieback & Peter (Germany) with a small visualization. Editing schedules is then the crown in the end. But that’s not really that important for me personally.

High praise for your work.

@Kaoth I’ve uploaded 2.5.2-SNAPSHOT version of binding with support for writes, please test (you need to go over download procedure again).

Most of things gets mapped to ints so you need to work a bit with sitemaps. It works for analogs and binary I/O. I have no possibility to test multistate objects.

Anyone else interested in OH3 testing - please stand up! :slight_smile:

Best,
Łukasz

Hello Łukasz,
I just tested that. I can write the AV’s.
But I have a problem with the BO’s. I can write this. The outputs on the PLC control then also switch on, but I can then no longer switch off via OpenHab.
It’s like a button that turns on once. In the “Paper UI” the slider is not echoed either.
It immediately jumps back to the “OFF” position.

Am I doing something wrong?

Greetings
Marcus

I believe this might be related to binding logic which is currently implemented. My test device have read only binary outputs hence I can’t test what’s going on.

I have to take a closer look on that.

Hello, i am quite new to openhab, really starting to love it. Wanted to try the BACnet binding, looks very interesting. but when i try to install i get the following error. it is on a new OH3. What am i doing wrong?

2020-12-25 17:55:03.038 [ERROR] [core.karaf.internal.FeatureInstaller] - Failed installing ‘openhab-binding-bacnet’: Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity=openhab-binding-bacnet; type=karaf.feature; version="[2.5.2.SNAPSHOT,2.5.2.SNAPSHOT]"; filter:="(&(osgi.identity=openhab-binding-bacnet)(type=karaf.feature)(version>=2.5.2.SNAPSHOT)(version<=2.5.2.SNAPSHOT))" [caused by: Unable to resolve openhab-binding-bacnet/2.5.2.SNAPSHOT: missing requirement [openhab-binding-bacnet/2.5.2.SNAPSHOT] osgi.identity; osgi.identity=co7io-binding-bacnet; type=karaf.feature [caused by: Unable to resolve co7io-binding-bacnet/2.5.2.SNAPSHOT: missing requirement [co7io-binding-bacnet/2.5.2.SNAPSHOT] osgi.identity; osgi.identity=org.connectorio.binding.bacnet; type=osgi.bundle; version="[2.5.2.SNAPSHOT,2.5.2.SNAPSHOT]"; resolution:=mandatory [caused by: Unable to resolve org.connectorio.binding.bacnet/2.5.2.SNAPSHOT: missing requirement [org.connectorio.binding.bacnet/2.5.2.SNAPSHOT] osgi.wiring.package; filter:="(&(osgi.wiring.package=org.connectorio.binding.base.config)(version>=2.5.0)(!(version>=3.0.0)))" [caused by: Unable to resolve org.connectorio.binding.base/2.5.2.SNAPSHOT: missing requirement [org.connectorio.binding.base/2.5.2.SNAPSHOT] osgi.wiring.package; filter:="(&(osgi.wiring.package=org.eclipse.smarthome.core.thing)(version>=2.5.0)(!(version>=3.0.0)))"]]]]

Version which is published is compatible with OH2. I pushed updated source code to github. All necessary changes to compile against OH3 are there. I haven’t had time to test and deploy most recent binary build. I will post update soon. Sorry that it takes so long.