Maintainer for BACNET binding

Looking at this tweet, maybe you should liaise with @splatch?

@Kai, thanks for mentioning me here. Indeed, I started working on bacnet/ip binding for OH2 which is my primary runtime these days. I’ve tried to run same binding as mentioned, but it didn’t work with current codebase.

Main problem is licensing (and also API quality) of bacnet4j which is used under the hood. Bacnet4j is GPL and forces same license of binding. This means it can not be maintained together with ASL v2 licensed sources of openhab. Bacnet4j API and concurrency handling is quite old thus it is not clear and using it directly in openhab would result in complete mess. Because of that I decided to create small overlay to hide all strangeness of library and provide limited interface to discover devices, read list of their properties, get and set values.

@LeXLuther422 which version of OH do you run and what kind of device you would like to bridge into your hub?

I am communicating with a Autani Manager with just a few devices but for control I need to be able to utilize multi state input. I have gotten the other BACnet binding to work with 1.8.1 for now I have not used 2.0 at all mainly because of all the different devices I am using. I plan on interfacing with other BACnet devices mainly thermostats and VAV controllers like the Automated Logic ZN341V+

Here is a screen cap of YABE device list.

My Current BACnet config is this

######################### Bacnet Binding################
#Refresh interval in milliseconds (optional, defaults to 60000ms)
bacnet:refresh=10000
Group Autani (All)
Group Assembly (All)
Group Shipping (All)
//Switch Pole_Light1 "Parking Light Pole Light"  (Autani) {bacnet="12345:3:592"}
Number Shipping_Temp1 "Shipping Temp [%.1f °F]" <temperature> (Autani,Temperature,Shipping,Building_Temp) {bacnet="12345:0:752"}
Dimmer Light_Assembly_Supervisor_Dim "Assembly Supervisor Dimming" (Autani,Lights,Assembly) {bacnet="12345:2:871"}
Switch Light_Assembly_Supervisor "Assembly Supervisor" (Autani,Lights,Assembly) {bacnet="12345:3:864"}
Switch Light_Assembly_Highbay1 "High Bay Lights"  (Autani,Lights,Assembly) {bacnet="12345:3:704"}
Switch Light_Assembly_Overhead2 "Overhead Line-A" (Autani,Lights,Assembly) {bacnet="12345:3:592"}
Switch Light_Assembly_Overhead1 "Overhead Line-B" (Autani,Lights,Assembly) {bacnet="12345:3:624"}
Dimmer Shipping_Fan1 "Shipping Fan Speed [%%d]" <fan>	(Autani,Fan,Shipping) {bacnet="12345:2:823"}

I don’t have possibility to verify multistate object types, all simulators are paid or short trial periods just for windows. I will try to get it somehow implemented with bacnet4j and post new version for tests. I made test program available in my github repo which will fetch all devices and it’s properties. I just failed to packate it in deployable jar which could be easily run. If this program is able to fetch your device list it will work with openhab too. If it will be displayed in wacnet (available here) I will be able to get it into openhab too, cause it is based on same lib.

Please give a try to 1.9 with version deployed here and let me know if it does work. Configuration is in other format
bacnet="device=12345, type=analogInput, id=624". Just set trace logging to org.openhab.binding.bacnet before deploying jar. Refresh period is fixed and set to 30 seconds.

I am working now on custom refresh intervals for properties to better utilize network, cause even for my basic AHU there are switches which are not frequently updated.

Wacnet seemed to work for reading values. here is a device cap list.

description
BACnet Gateway
unknown-4000
Curtailment Stage 2
object-instance
12345
unknown-4002
15
protocol-version
1
device-id
12345
unknown-4001
1
local-time
17:51:56.14
utc-offset
360
object-type
8
segmentation-supported
no-segmentation
application-software-version
1.0
protocol-revision
12
object-list
[:device 12345]
[:analog-input 752]
[:analog-value 823]
[:analog-value 871]
[:analog-value 870]
[:analog-value 710]
[:analog-value 598]
[:analog-value 630]
[:analog-value 752]
[:analog-value 753]
[:analog-value 754]
[:analog-value 755]
[:analog-value 756]
[:analog-value 757]
[:binary-input 864]
[:binary-input 704]
[:binary-input 592]
[:binary-input 624]
[:binary-input 736]
[:unknown-40 752]
[:multi-state-input 643]
[:multi-state-input 723]
[:multi-state-input 787]
[:multi-state-input 851]
[:multi-state-input 756]
[:multi-state-input 757]
[:multi-state-input 758]
[:multi-state-value 868]
[:multi-state-value 708]
[:multi-state-value 596]
[:multi-state-value 628]
[:multi-state-value 753]
[:multi-state-value 752]
[:multi-state-value 754]
[:multi-state-value 755]
local-date
2016-07-11
apdu-timeout
3000
system-status
operational
number-of-apdu-retries
3
device-address-binding
daylight-savings-status
true
units
firmware-revision
0.8.0
max-apdu-length-accepted
1476
database-revision
0
protocol-services-supported
atomic-read-file
true
confirmed-text-message
false
unconfirmed-text-message
false
time-synchronization
true
confirmed-event-notification
false
reinitialize-device
true
who-is
true
who-has
true
unconfirmed-event-notification
false
subscribe-cov-property
false
vt-data
false
unconfirmed-private-transfer
true
create-object
false
delete-object
false
read-property-conditional
false
add-list-element
false
vt-open
false
remove-list-element
false
get-event-information
false
confirmed-cov-notification
true
i-am
true
device-communication-control
true
acknowledge-alarm
false
get-alarm-summary
false
i-have
false
subscribe-cov
true
confirmed-private-transfer
false
vt-close
false
request-key
false
read-property-multiple
true
write-property
true
life-safety-operation
false
read-property
true
atomic-write-file
true
utc-time-synchronization
true
get-enrollment-summary
false
write-property-multiple
true
unconfirmed-cov-notification
true
read-range
true
authenticate
false
protocol-object-types-supported
averaging
false
multi-state-input
true
load-control
false
schedule
false
multi-state-output
false
binary-output
false
analog-value
true
life-safety-point
false
group
false
notification-class
false
analog-input
true
trend-log-multiple
false
event-log
false
file
false
command
false
life-safety-zone
false
binary-input
true
loop
false
multi-state-value
true
analog-output
false
access-door
false
calendar
false
event-enrollment
false
pulse-converter
false
device
true
trend-log
false
binary-value
false
program
false
accumulator
false
structured-view
false
model-name
BACnet Interface

New build is uploaded and available in thread New version of bacnet binding for openhab. I’ve just added support for multistate items which according to spec should be mapped to Unsigned (Integer) type.

OK here is where the fun begins… I am trying to control one of the bacnet devices 1 id is a switch state and the other is a multistatevalue the multi is the actual control. here is what I tried to do and it fails miserable.

Switch Light_Assembly_Overhead1C		"Overhead Line-B Control [%s]"					(Autani, Assembly)								{bacnet="<[device=12345,type=binaryInput,id=624] >[ON:device=12345,type=multiStateValue,id=628,value=4] >[OFF:device=12345,type=multiStateValue,id=628,value=5]"}

Can you please attach log output for this? This will give me some more information on what goes on.

It gives a parsing error for the items file. when I get to work tomorrow I will post detail. I don’t believe the binding is set to support individual out commands or setting “value=#”. I modeled the formatting after the SNMP binding.

This binding is very simple cause there was no need for me to support such things directly in code. I have analog input in my device which is accepting multiple values and I managed to get it work via sitemap:

Selection item=Air_Mode mappings=["1.0" = "Mode 1", "2.0" = "Mode 2", "3.0" = "Mode 3", "4.0" = "Schedule"]"
String Air_Mode "Mode [%s]" (Ventilation) { bacnet="device=1111,type=analogValue,id=11,refreshInterval=10000" }

Can you try that?

OnOff commands are supported only for binary items in bacnet. Multistate items require integer values in bacnet thus binding require number input for them - this means that rule or action you generate should return an Integer or parsable String for that.

Here is an example of how different values can be set in my SNMP binding. I use this to read one value for if the port is active or not on the incoming command and set the port to enabled or disabled on the outgoing command. they are different int’s for each but because the binding lets me set an outgoing value it can be accomplished without have to go heavy in the rules or create custom sitemaps. it also makes it so groups of different devices can be controlled with group on off and counted with sum.

Switch Switch_PortEnable03 "Port 03 [%s]" <port> (ports)	{ snmp="<[192.168.0.140:private:.1.3.6.1.2.1.2.2.1.8.3:10000:MAP(SwitchState.map)] >[OFF:192.168.0.140:private:.1.3.6.1.2.1.2.2.1.7.3:2] >[ON:192.168.0.140:private:.1.3.6.1.2.1.2.2.1.7.3:1]" }

it would also enable someone to remap the items output if the logic is inverted. say the 1 is OFF and the 0 is ON

You still may use MAP or SCALE transformations which are built into openhab. This will offer you centralized place for transformation logic with no effort. I’m not sure if adding such mapping directly into binding is valid. Multistate items by spec are unbounded, meaning they have any N states. No one will ever be able to use channel with more than 3 values.

Can you pelase try first with approach proposed ealier and let me know if it at least works? I didn’t have any chance to test multistate items.

@splatch Do you consider to develop this plugin for openhab2?
And how can i start a discovery of the BACnet Objects?

@joschi36,
Hey, I got bussy with other stuff, but this binding works fine with openhab 2 if you enter object identifiers in item configurations. Reason why I had to step back from implementing this straight away for OH2 was exactly discovery which didn’t work at all (because bacnet4j specific reasons). Now my highest priority is support for authentication and I don’t have time to work on OH2 binding code yet. It will be delayed for some time, however I am all for maintaining current binding implementation.
If you would like to scan your bacnet network for objects and available properties there are two ways. You can use wacnet - which offers GUI, or run bacnet4j wrapper discovery program. I made very simple class which can be launched from IDE or command line after maven build.

Please let me know if you need any assistance in bringing your devices to OH2.

Hi,
struggling to get the binding to work - can not read the property due to:
2017-02-27 22:47:33.205 [INFO ] [b.core.service.AbstractActiveService] - BacNet Service has been started
2017-02-27 22:47:33.206 [WARN ] [inding.bacnet.internal.BacNetBinding] - Could not find property 1001.ANALOG_INPUT.6 for item humidifier_mesured_value cause device was not discovered

And there is no “discovered device” message in the log.

Item definition:
Number humidifier_mesured_value “Humidifier measured value” {bacnet=“device=1001,type=analogInput,id=6,refreshInterval=5”}

the tool from http://sourceforge.net/projects/vts/ sees following traffic from openhab:

I’ve also run the DiscoveryMain util class to se what gets discovered - the device responds but there is error in reading some property:

/usr/java/jdk1.8.0_101/bin/java -Djava.net.preferIPv4Stack=true -cp org.openhab.binding.bacnet-1.9.0-SNAPSHOT.jar:api-1.0.0-SNAPSHOT.jar:ip-1.0.0-SNAPSHOT.jar:slf4j-api-1.7.24.jar:f4j-simple-1.7.24.jar org.openhab.binding.bacnet.internal.util.DiscoveryMain
Fetching network interfaces
Fetching devices for 192.168.9.255 addres with 30 second timeout
=> Device id 1001
Metadata
Address: 192.168.9.164:47808
Name: RS
Model: RS
Vendor:
Exception in thread “main” org.code_house.bacnet4j.wrapper.api.BacNetClientException: Unable to fetch property description
at org.code_house.bacnet4j.wrapper.ip.BacNetIpClient.createProperty(BacNetIpClient.java:273)
at org.code_house.bacnet4j.wrapper.ip.BacNetIpClient.getDeviceProperties(BacNetIpClient.java:166)
at org.openhab.binding.bacnet.internal.util.DiscoveryMain.main(DiscoveryMain.java:63)
Caused by: com.serotonin.bacnet4j.exception.RejectAPDUException: Reject(originalInvokeId=6, rejectReason=Unrecognized service)
at com.serotonin.bacnet4j.transport.ServiceFutureImpl.get(ServiceFutureImpl.java:80)
at org.code_house.bacnet4j.wrapper.ip.BacNetIpClient.createProperty(BacNetIpClient.java:261)
… 2 more

Any ideas?

Tnx,
Ugis

Hey @Ugis_Springis,
Sorry for coming so late with reply to you, have busy time at work. From network dump you shared I see all looks fine, meaning devices/networks are visible to each other. Initially I thought it is network issue but stack trace says something completely different. The underlying library used for bacnet communication receives rejected frame, meaning router or device itself does not allow to fetch vendor property description. DiscoveryMain try to read as much as possible to collect complete device information and error while fetching description should not stop it from continuing to read more data.
Since this is possible to happen I can add handling of such errors in discovery process because device vendor is not mandatory to get OH1 binding to work. Can you verify if its possible to “change” visibility of vendor in device or router settings?

Please add issue in https://github.com/openhab/org.openhab.binding.bacnet so I will continue working on it.
Kind regards,
Lukasz

Hi,
the issue with device not discovered turned out to be silly error by me - I did specify binding address as local IP instead of “0.0.0.0”. Broadcast traffic is received only on socket bound to “0.0.0.0”. Maybe this should be mentioned in readme.md that this should be wildcard address, not interface address.

Regarding reading of device properties, this only influences DiscoveryMain as I understand. Probably it is worth processing “not supported” exceptions, and skip to next property there.

I’m currently experimenting with creating OH2 BACnet binding with discovery - to discover devices as things, and objects as channels. Will see where will this lead :slight_smile:

Yeah, broadcast address is not documented. DiscoveryMain by default reads this information from network interface configuration so it is portable and requires minimal effort to discover devices. All it needs is proper configuration. 0.0.0.0 is an specific value which means that you want to listen on all interfaces, it doesn’t really need to be like this, usually it is sufficient to set latest octet in your interface settings to 255. Ie if your computer interface is 192.168.x.15 then broadcast address is 192.168.x.255. Broadcast addresses are coming from bacnet/ip specification. You can find over internet some short description how frame is structured, sadly now I have no copy of such document locally.

I started work on bacnet binding from OH2 but troubles with bacnet4j and its api forced me to take it aside and clean up interactions. To test if everything works I made DiscoveryMain. Sadly I got stuck with OH2 and dynamic channels (each discovered property becomes new channel for device) a while ago. Everything is described here: https://www.eclipse.org/forums/index.php/t/1079027/. I didn’t go back since then to OH2 binding code, but made quickly OH1 version which anyway was starting point for all fights. I still should have last years copy of OH2 code. If you are interested in playing with it I will push it to github.
Feel free to post pull requests if you can for both bacnet4j wrapper and binding as well.

Cheers,
Lukasz

Yes, this would be a help to check.

I’ve managed to move the bacnet4j to v4 branch of https://github.com/infiniteautomation/BACnet4J repository,
and the RequestUtils.getObjectList(localDevice,remoteDevice) works nice for my device, so looks hopfull.
Also - in v4 of the bacnet4J they have created a lot of utilities, so will check the need for bacnet4j-wrapper.

regards,
Ugis