How to interface with a BACnet internetwork in python?

249 views Asked by At

I have a BACnet network that creates virtual devices behind a single static IP (192.168.2.100). The devices are published behind that IP on the BAC0 47808 port. I use the YABE client and can see both the parent network device, and all of the devices behind it reported as being provided "via" the parent IP (192.168.2.100). The other device IPs look like 0.8.28.77:0, with the 77 incrementing for each device.

In case anyone is specifically familiar, this is a Daikin DCM601A71 central controller emitting BACnet IP on the local IP network. Also, to be clear, I can't change any of the underlying network, including the IPs, as it's being used by another application I can't update.

I want to control these devices programmatically. YABE is able to change the state, so it must be possible with their implementation in C#. My stack is written in python, however and I'm struggling to find the right invocation for how one would address this device when using bacpypes.

I've tried referencing just the 0.8.28.77:0 IP of the end devices to no avail. I've also tried the router (192.168.2.100) IP with the final device's BACnet device ID with the BAC0 points functionality, but it also didn't work. Both of these just lead to timeouts which is the expected behavior for an address that's not able to be found on the network, implying this is just the wrong way to address the devices.

I've read online about BACnet internetworks, and it seems like I may need to also include a network number for the devices, but I don't know how to tell what the devices' network numbers are. I'm also not sure if appending the network number in front of the address works for BACnet IP the way it does for BACnet MS/TP.

My research has also mentioned BBMD multiple times. I have been assuming this isn't necessary because my device is on 192.168.2.0, same as the router. If I'm mistaken and I still need to use BBMD to access the virtual devices behind the router please let me know.

3

There are 3 answers

0
Edward On

This is not a BBMD issue, but a routing one.

Your virtual device is behind a BACnet Router (192.168.2.100), so your message, to get to the "end device" has to be sent to the BACnet Router, but also needs to include the final "Destination Address" or "DADR" (NN:ADR) in the NPCI part of the NPDU.

These DADR parameters can be established by looking at the SADR (Source Address) parameters of any message from the device in question. (Look at e.g. Wireshark) after e.g. a Who-Is. (This is what YABE does in order to establish the route to the device).

This is covered in section 6.5.3 "Network Layer Procedures for the Transmission of Remote Traffic"

PS: You will discover that your virtual devices "BACnet_Address" (NN:ADR) will include the Network Number (NN). This will be a configuration parameter in your system, and this NN will have to be unique (different to all other NNs) on a BACnet system. The ADR can be 1-6 bytes, in your case it is probably 6 bytes, attempting to be displayed as an IP:Port (0.8.28.77:0), but could be 4, 3 bytes inappropriately displayed.

0
DennisVM-D2i On

As an overlap, I'll try to explain some of it in a different (/supplemental) manner.

First off, YABE does not display the 'DADR'/MAC-Address value nicely/in a EUI-48/MAC-Address format, it is displaying it in IPv4 address format, hence the (confusing) references such as '0.8.28.77:0' (- I believe YABE calls them the 'routed-source'); so a MAC address of '01-02-03-04-05-06' will likely display something like this '1.2.3.4:1286'.

When it comes to devices that are (effectively tucked behind/) accessed via a parent BACnet Router device or BACnet Gateway device, think of the (parent "192.168.2.100") IP address as being the street address for a block of flats (- gets you a third of the way there), and the DNET/network-number value as being the floor number, and the DADR/MAC-address value as being the door number upon that floor (/segment of the building); otherwise, the IP address alone would be sufficient to identity a house/standalone device/controller.

(It's probably best to avoid 'BBMD's from now on/where easily possible - and one shouldn't be required for this particular situation.)

You can use tools such as 'VTS' and 'Wireshark' (or Windows 'NetSH') datagram/packet-captures to see the structure of these kind of router-ed/gateway-ed communications, as well as by debugging with 'YABE' too.

I don't use Python nor 'BAC0' myself, but I thought the BAC0 'read()' function had a leading 'address' parameter, that might be the 'DNET:DADR'/DNET & DADR value (?), possibly something like this - e.g. DNET = '2' & 'DADR' = '5', but I could be wrong:

    bacnet.read('2:5 analogInput 1 presentValue')
0
OneSystem On

BAC0 is based on bacpypes. In bacpypes documentation it states that default subnet mask when connecting to network is /24 (255.255.255.0)

When initiating connection using BAC0, you can specify desired subnet mask by specifically setting it:

bacnet = BAC0.lite(ip='192.168.8.199/22'), where the "/22" is the specific subnet for your network.

Handy reference for subnets is here: https://cnes.com/subnets.html