Ah, so you are interested in getting started with BACnet and Python. Welcome to BACpypes, I hope you enjoy your journey. This tutorial starts with some just enough of the basics of BACnet to get a workstation communicating with another device, installing the library, and downloading and configuring the samples applications.
Assume that you are a software developer and it is your job to communicate with a device from another company that uses BACnet. Your employer has given you a test device and purchased a copy of the standard. You have in your office...
- a development workstation running some flavor of Linux complete with the latest version of Python 2.7 and setup tools.
- a small hub you can plug in your workstation and this misterious device and not get distracted by lots of other LAN traffic.
Before getting this test environment set up and you are still connected to the internet, install the BACpypes library:
$ sudo easy_install bacpypes
And while you are at it, get a copy of the project from SourceForge that has the library source code, sample code, and this documentation:
$ svn checkout svn://svn.code.sf.net/p/bacpypes/code/trunk bacpypes
No protocol analysis workbench would be complete without an installed copy of Wireshark:
$ sudo apt-get install wireshark
Configuring the Workstation¶
The test device that you have is going to come with some configuration information by default and sometimes it is easier to set up the test environment with same set of assumtions than come up with a fresh set from scratch.
- IP Address
- The device will probably come with an IP address, assume that it is 192.168.0.10, subnet mask 255.255.0.0, gateway address 192.168.0.1. You are going to be joining the same network, so pick 192.168.0.11 for the workstation address with the same subnet mask.
- Device Name
- Every BACnet device on a BACnet network has a unique name which is a character string. There is nothing on a BACnet network that enforces this uniqueness, but it is a real headache for integrators when it isn’t followed. You will need to pick a name for your workstation. My collegues and I use star names so the sample congiuration files will have “Betelgeuse”.
- Device Identifier
- Every BACnet device will have a unique identifier, a 22-bit unsigned non-zero value. It is critical that this be unique for every device and most large customers will have someone or a group responsible for maintaining device identifiers across the site. Keep track of the device identifier for the test device, assume that it is 1000 and you are going to pick 1001 for your workstation.
There are a few more configuration values that you will need, but you won’t need to change the values in the sample configuration file until you get deeper into the protocol.
- Maximum APDU Length Accepted
- BACnet works on lots of different types of networks, from high speed Ethernet to “slower” and “cheaper” ARCNET or MS/TP (a serial bus protocol used for a field bus defined by BACnet). For devices to exchange messages they have to know the maximum size message the device can handle.
- Segmentation Supported
- A vast majority of BACnet communications traffic fits in one message, but thre can be times when larger messages are convinient and more efficient. Segmentation allows larger messages to be broken up into segemnts and spliced back together. It is not unusual for “low power” field equipment to not support segmentation.
There are other configuration parameters in the INI file that are used by other applications, just leave them alone for now.
Updating the INI File¶
Now that you know what these values are going to be you can configure the BACnet part of your workstation. Change into the samples directory that you checked out earlier, make a copy of the sample configuration file, and edit it for your site:
$ cd bacpypes/samples $ cp BACpypes~.ini BACpypes.ini
The sample applications are going to look for this file, and you can direct them to other INI files on the command line, so it is simple to keep multiple configurations.
At some point you will probably running both “client” and “server” applications on your workstation, so you will want separate configuration files for them. Keep in mind that BACnet devices communicate as peers, so it is not unusual for an application to act as both a client and a server at the same time.
UDP Communications Issues¶
BACnet devices comunicate using UDP rather than TCP. This is so that devices do not need to implement a full IP stack (although many of them do becuase they support multiple protocols, including having embedded web servers).
There are two types of UDP messages; unicast which is a message from one specific IP address and port to another one, and broadcast which is received and processed by all devices that have the port open. BACnet uses both types of messages and your workstation will need to receive both types.
The BACpypes.ini file has an address parameter which is an IP address in CIDR notation and can be followed by a port number. For example, 192.168.0.11/16 specifies both the IP address and the number of bits in the network portion, which in turn implies a subnet mask, in this case 255.255.0.0. Unicast messages will be sent to the IP address, and broadcast messages will be sent to the broadcast address 192.168.255.255 which is the network portion of the configuration value will all 1’s in the host portion.
To receive both unicast and broadcast addresses, BACpypes will open two sockets, one for unicast traffic and one that only listens for broadcast messages. The operating system will typically not allow two applications to open the same socket at the same time so to run two BACnet applciations at the same time they need to be configured with different ports.
The BACnet protocol has port 47808 (hex 0xBAC0) assigned to it by the Internet Assigned Numbers Authority, and sequentially higher numbers are used in many applications. There are some BACnet routing and networking isseus with this, but that is for antoher tutorial.
Starting An Application¶
The simplest BACpypes sample application is the WhoIsIAm.py application. It can send out Who-Is and I-Am messages and displays the results it receives. What are these things?
As mentioned before, BACnet has unique device identifiers and most applications use these identifiers in their configuration to know who their peers are. Once these identifiers are given to a device they typically do not change, even as the network topology changes.
BACnet devices use the Who-Is request to translate device identifiers into network addresses. This is very similar to a decentralized DNS service, but the names are unsigned integers. The request is broadcast on the network and the client waits around to listen for I-Am messages. The source address of the I-Am response is “bound” to the device identifier and most communications is unicast after that.
First, start up Wireshark on your workstation and a capture session with a BACnet capture filter:
udp and port 47808
You might start seeing BACnet traffic from your test device, and if you wait to power it on after starting your capture you should see at least a broadcast I-Am message. By looking in the I-Am packet decoding you will see some of its configuration parameters that should match what you expected them to be.
Now start the application:
$ python WhoIsIAm.py
You will be presented with a prompt, and you can get help:
> help Documented commands (type help <topic>): ======================================== EOF buggers bugin bugout exit gc help iam shell whois
The details of the commands will be described in the next section.
Generating An I-Am¶
Now that the application is configured it is nice to see some BACnet communications traffic. Just generate an I-Am message:
You should see your configuration parameters in the I-Am message in Wireshark, this is a “global broadcast” message, so your test device will see it but since your test device probably isn’t looking for you, it will not respond with anything.
Binding to the Test Device¶
Now to confirm that the workstation can receive the messages that the test device sends out, generate a Who-Is request. This one will be “unconstrained” which means that every device will respond. Do not generate these types of unconstrained requests on a large network because it will create a lot of traffic that can cause conjestion. Here is a Who-Is:
You should see the request in Wireshark and the response from the device, and then a summary line of the response on the workstation.
There are a few different forms of the whois command this simple application allows and you can see the basic form with the help command:
> help whois whois [ <addr>] [ <lolimit> <hilimit> ]
This is like a BNF syntax, the whois command is optionally followed by an address, and then optionally followed by a low limit and high limit. The most common use of the Who-Is request is to look for a specific device given its device identifier:
> whois 1000 1000
And if the site has a numbering scheme for groups of BACnet devices like all those in a specific building, then it is common to look for all of them as a group:
> whois 203000 203099
Every once in a while a contractor might install a BACnet device that hasn’t been properly configured. Assuming that it has an IP address, you can send an unconstrained request to the specific device and hope that it responds:
> whois 192.168.0.10
There are other forms of BACnet addresses used in BACpypes, but that is a subject of an other tutorial.
The next tutorial will describe the different ways this application can be run, and what the commands can tell you about how it is working. All of the “console” applications, those that prompt for commands, use the same basic commands and work the same way.