BACnet Objects and Properties: The Object Model Explained
BACnet is not a register-based protocol like Modbus. It uses an object-oriented data model where every data point is an object with typed properties. This single architectural difference is why BACnet devices can describe themselves, why BACnet tools can discover networks without manual configuration, and why BACnet integration is more structured but more complex than Modbus.
If you are moving from Modbus to BACnet, or if you are integrating BACnet devices into a SCADA system, you need to understand the object model. This is not optional. The entire protocol is built on it. Every read operation, every write operation, and every discovery message works in terms of objects and properties. Once you understand how objects work, BACnet makes sense. Without that understanding, BACnet feels like a mysterious black box.
The Object-Oriented Model: Why BACnet Is Different
In Modbus, you read register 40001. That is it. The register contains a 16-bit value. What that value means, what units it uses, whether it is valid or faulted — none of that is defined by the protocol. The protocol delivers raw bits. The meaning is external, in the device manual.
In BACnet, you read the Present-Value property of Analog Input object 2. The object tells you what it is (a temperature sensor). The property tells you the value (72.5 degrees). The object's other properties tell you the units (degrees Fahrenheit), the description ("Room 201 Temperature"), and the reliability status (whether the sensor is online or faulted). The data carries its own metadata.
This self-description is why BACnet is powerful. A BACnet client can connect to a device it has never seen before, read the object list, read each object's properties, and build a complete picture of what the device contains without any external documentation. Modbus cannot do this. Modbus requires the device manual to know what register 40001 represents.
The trade-off is complexity. In Modbus, you send a single function code to read a block of registers. In BACnet, you construct a ReadPropertyRequest for a specific object and property. You need to know the object type, the object instance, and the property identifier. More moving parts, but more capability.
BACnet Object Types: The Six You Will Use Most
The BACnet standard defines dozens of object types. In practice, six object types cover 90% of building automation applications. Memorize these and you can work with almost any BACnet device on the market.
0134839Analog Input (Type 0)
This is the workhorse object for sensor data. Every temperature sensor, every pressure transmitter, every flow meter, every humidity sensor exposes its data as an Analog Input object. The Present-Value property contains the current measurement. The Units property tells you whether the value is in degrees Fahrenheit, degrees Celsius, PSI, or liters per minute.
Analog Output (Type 1)
Analog Output objects represent setpoints and control values. When you send a command to open a valve to 50%, you are writing to an Analog Output object's Present-Value property. When you adjust a temperature setpoint from 72 to 68 degrees, you are writing to an Analog Output (or sometimes an Analog Value, which is a read/write version of Analog Input).
Binary Input (Type 3)
Binary Input objects represent on/off status inputs. A limit switch that is open or closed, a door contact that indicates secure or breached, a run-status contactor that shows a motor running or stopped. The Present-Value is either 0 (OFF/INACTIVE) or 1 (ON/ACTIVE). The polarity tells you whether 0 means active or inactive.
Binary Output (Type 4)
Binary Output objects represent on/off commands. When you turn a fan on or off, when you enable or disable a heating stage, when you latch a relay, you are writing to a Binary Output object's Present-Value property. Unlike Modbus coils, BACnet Binary Outputs include feedback — you can read back the last commanded state.
Device (Type 8)
Every BACnet device has exactly one Device object (object instance 0 or a configurable number). This object contains device-wide information: the device name, the firmware version, the vendor ID, the model number, and — critically — the object list. The object list is a property that contains an array of all other objects in the device. When you perform BACnet discovery, you are reading the Device object's object-list property.
CharacterString (Type 39)
CharacterString objects hold text. They are less common but important for alarm messages, display labels, and status text. When a BACnet controller generates an alarm message like "Filter Dirty - AHU-01", that text lives in a CharacterString object or is written to a CharacterString property.
BACnet Properties: The Data Inside Objects
If objects are containers, properties are the fields inside those containers. Each object type has a set of standard properties defined by the BACnet standard. Some properties are required (must be present), some are optional (may be present if the device supports them), and some are proprietary (vendor-specific extensions).
Present-Value (Property 85)
Present-Value is the most important property in BACnet. It holds the object's current value. For an Analog Input temperature sensor, Present-Value is the temperature reading. For a Binary Output relay, Present-Value is 0 (OFF) or 1 (ON). For an Analog Output setpoint, Present-Value is the commanded value. This is the property you read 90% of the time.
Description (Property 28)
The Description property is a human-readable text string that identifies the object. It might say "Room 201 Temperature" or "Supply Air Fan Status" or "Boiler 1 Outlet Temp". This is what appears as the label in BACnet explorer tools and SCADA dashboards. The Description is how you know which Analog Input object corresponds to which physical sensor.
Units (Property 117)
The Units property tells you what the Present-Value means numerically. Is the temperature in Fahrenheit or Celsius? Is the pressure in PSI or bar? Is the flow rate in gallons per minute or liters per second? BACnet defines standard unit enumerations for every engineering unit. The Units property is an integer that maps to these standard units. 95 means degrees Fahrenheit. 62 means degrees Celsius. 100 means percent. 63 means PSI. This eliminates the ambiguity that plagues Modbus implementations.
Status-Flags (Property 111)
Status-Flags is a 4-bit bitmap that indicates the reliability of the Present-Value. Each bit has a meaning:
- Bit 0 (IN_ALARM): The object has an active alarm condition.
- Bit 1 (FAULT): The object has a hardware or communication fault.
- Bit 2 (OVERRIDDEN): The value is manually overridden at the device.
- Bit 3 (OUT_OF_SERVICE): The object is manually taken out of service.
You should always read Status-Flags along with Present-Value. If Present-Value says 72.5 degrees but Status-Flags has the FAULT bit set, that temperature reading is unreliable. The sensor may be disconnected, the wiring may be broken, or the transmitter may be failed. Modbus has no equivalent to this. In Modbus, a failed sensor typically returns a fixed fault value like 0x7FFF or 0x8000, but the protocol provides no standard way to indicate "this value is not to be trusted."
Object-Name (Property 77)
Object-Name is an alternative human-readable identifier. It serves the same purpose as Description but is typically shorter and more structured. Description might be "Room 201 Temperature Sensor". Object-Name might be "RM-201-TEMP". Both serve as labels for the object in user interfaces.
Object-Type (Property 75)
Every object includes an Object-Type property that identifies what kind of object it is. This might seem redundant (you already know the object type when you address it), but it allows for generic enumeration operations. When you iterate through the object list, you read the Object-Type property of each entry to know whether you are dealing with an Analog Input, Binary Output, or something else.
Object Identifiers: How BACnet Addresses Data
In BACnet, every object has a unique identifier composed of two parts: the object type and the object instance. The object type tells you what kind of object it is (Analog Input, Binary Output, etc.). The object instance distinguishes between multiple objects of the same type.
The Three-Part Address
To read a specific value in BACnet, you need three pieces of information:
- Device ID: The BACnet device instance number (configured per device, often matching the last octet of the IP address or a manual setting).
- Object Type: The numeric object type code (0 for Analog Input, 3 for Binary Input, etc.).
- Object Instance: The instance number that distinguishes this object from other objects of the same type.
For example, to read the temperature from Room 201, you might send a ReadPropertyRequest to device 1234, object type Analog Input (0), object instance 2, property Present-Value (85). The response returns the current temperature.
This three-level addressing is more complex than Modbus, which only requires a device address and a register number. But BACnet's addressing is hierarchical and self-describing. In Modbus, you need external documentation to know that register 40001 is the Room 201 temperature. In BACnet, you read the Description property of Analog Input instance 2, and it tells you "Room 201 Temperature".
Object Instance Numbering
Object instance numbers are assigned by the device manufacturer. Some devices start at 1. Some start at 0. Some use structured numbering where instance 23401 means floor 23, device 401, point 01. Others use sequential numbering where the first Analog Input is instance 1, the second is instance 2, and so on.
This is why BACnet discovery is important. Because instance numbering is not standardized, you cannot guess that Analog Input instance 1 is the temperature you want. You have to read the object list, then read the Description property of each object, to find the one labeled "Room 201 Temperature".
Optional Properties and READ-ACCESS
Not every object supports every property. The Description property is optional. The Units property is optional for some object types. The Status-Flags property is optional for binary objects. Before you read a property, you need to confirm that the object supports it. The BACnet protocol includes a ReadPropertyConditional request that can test whether a property exists without causing an error if it does not.
This optional property model is flexible but adds complexity. In Modbus, every device has the same four register tables. In BACnet, every device can have a different combination of objects and properties. The trade-off is expressiveness. BACnet can model almost any building automation concept. Modbus can only model 16-bit registers.
BACnet Discovery: How Who-Is/I-Am Maps to Objects
Modbus has no built-in discovery mechanism. To find Modbus devices on a network, you have to manually configure the device addresses and register maps, or you have to write a script that pings every possible address and checks for a response. This is time-consuming and error-prone.
BACnet includes discovery in the protocol itself. The Who-Is/I-Am service allows a client to ask "What devices are on this network?" and every device responds with its Device object. Here is how it works:
Who-Is Request
The client broadcasts a Who-Is request to the BACnet network. The request can specify a range of device instance numbers (e.g., "Who is between 1000 and 2000?"). If you leave the range empty, every device on the network responds.
I-Am Response
Every device whose instance number falls within the requested range responds with an I-Am message. The I-Am contains the device's BACnet object identifier (Device object with the device's instance number), the maximum APDU length (how large a message the device can accept), the segmentation support (whether the device can handle split messages), and the vendor ID.
Reading the Object List
After the I-Am responses arrive, the client has a list of device IDs. The client then connects to each device and reads the Device object's object-list property. This property returns an array of object identifiers: [[analogInput,1], [analogInput,2], [binaryOutput,1], [binaryOutput,2], ...]. The client now knows every object in every device.
Building the Tree
The client then reads the Description and Object-Name properties of each object. This builds a complete tree structure: Device 1234 → Analog Input 1 → "Room 201 Temperature". This entire tree is built automatically without any manual configuration. This is why BACnet tools like Voltrus BACnet Explorer can display a fully populated device tree seconds after connecting to a network.
BACnet vs Modbus: The Object Model Difference
The fundamental difference between BACnet and Modbus is the data model. This affects everything from how you read values to how you configure devices.
The Modbus approach is simpler to implement and faster to execute, but it requires external knowledge. The BACnet approach is more complex, but it is self-contained. You can point a generic BACnet explorer tool at any BACnet device and immediately see what it contains. You cannot do the same with Modbus without the device manual.
Practical Usage: Reading and Writing BACnet Objects
When you work with BACnet in practice, you perform the same operations repeatedly.
Reading a Sensor Value
To read a temperature sensor, you send a ReadPropertyRequest to the device's Device ID, object type Analog Input (0), object instance (whatever the instance number is), property Present-Value (85). The response includes the value and the data type. If the value is 72.5 degrees Fahrenheit, the response includes the value and indicates that the units are Fahrenheit (property 117 = 95).
Checking Reliability
After reading Present-Value, you also read Status-Flags (property 111). If the FAULT bit (bit 1) is set, the value is unreliable. You should not use it for control logic or display it as a valid reading. Your SCADA system should flag it as "Sensor Fault" rather than displaying the last known value.
Writing a Setpoint
To write a setpoint, you send a WritePropertyRequest to an Analog Output or Analog Value object. You specify the property Present-Value (85) and the new value. The device updates the setpoint and confirms the write. You can then read back Present-Value to verify it was accepted.
Controlling a Relay
To turn on a fan, you send a WritePropertyRequest to a Binary Output object. You write 1 to the Present-Value property (85). The relay energizes. To turn it off, you write 0. The Binary Output object tracks the last commanded state, so you can read Present-Value to confirm whether the relay is currently commanded on or off.
How Voltrus BACnet Explorer Works with Objects
Voltrus BACnet Explorer is a native macOS application that speaks BACnet/IP and MS/TP. It uses the object model to provide automatic discovery and visual object browsing.
Automatic Discovery
When you launch BACnet Explorer and click "Scan Network", it sends a Who-Is broadcast to the configured subnet. Every device responds with its Device object. BACnet Explorer reads the object-list property of each device, then reads the Description and Present-Value of every object. Within seconds, you have a complete tree of every device, every object, and every current value on the network.
Visual Object Tree
The device tree is organized hierarchically: Device → Object Type → Object Instance → Properties. You can expand a device to see its Analog Inputs, Binary Outputs, and other objects. Clicking an object shows its properties: Present-Value, Description, Units, Status-Flags. No manual configuration required.
Real-Time Monitoring
Select any object and click "Monitor". BACnet Explorer polls the Present-Value and Status-Flags properties at the configured interval (default 1 second). You see the live value update in real-time, with color-coding for fault and alarm states. This is invaluable for commissioning and troubleshooting.
Property Editing
For writable objects (Analog Output, Binary Output, Analog Value), BACnet Explorer allows you to write to the Present-Value property. You can test setpoints, toggle relays, and verify control logic without needing the full BAS frontend. The write dialog shows the current value, allows you to enter the new value, and confirms the write succeeded.
Export and Documentation
After discovery, you can export the object tree to CSV or JSON. This includes every device, every object, every Description, and every Present-Value. You can use this export for documentation, for import into a SCADA system, or for audit trails.
Frequently Asked Questions
What is the difference between BACnet objects and Modbus registers?
BACnet uses an object-oriented model where each data point is an object with typed properties (Present-Value, Description, Units, Status). Modbus uses a flat register map where data is stored in 16-bit registers at specific addresses. BACnet objects self-describe their type and supported properties; Modbus registers require external documentation to interpret. BACnet objects are organized in a hierarchical address space (Device, Object, Property); Modbus uses a linear addressing scheme (table prefix + register number).
How do I read a BACnet object's current value?
To read a BACnet object's current value, you send a ReadPropertyRequest for the Present-Value property of the target object. For example, to read Analog Input object 2, you request object-identifier 2, property-identifier 85 (Present-Value). The device responds with the current value and the data type. Unlike Modbus where you read register 40001, in BACnet you explicitly request the Present-Value property of a specific object instance.
What are the most common BACnet object types?
The most common BACnet object types are: Analog Input (0) for sensor readings like temperature and pressure; Analog Output (1) for setpoints and control values; Binary Input (3) for on/off status like limit switches; Binary Output (4) for relay commands; Device (8) for the controller itself; and CharacterStringValue (39) for text displays. These six object types cover 90% of building automation applications.
What is BACnet Present-Value vs Status-Flags?
Present-Value is the primary data property that holds the object's current value (the temperature, the state, the setpoint). Status-Flags is a bitmap property that indicates the reliability of that Present-Value (whether the value is valid, overridden, out of service, or has an alarm). You always read both when you need reliable data: Present-Value tells you what the value is, Status-Flags tells you whether to trust it.
How does BACnet Who-Is/I-Am discovery work?
BACnet discovery uses broadcast messages: Who-Is asks 'What devices are out there?' and I-Am replies 'I am device X, here is my object list.' When you send a Who-Is request with a device instance range, every device in that range responds with its Device object containing its vendor ID, firmware version, and object list. This is how BACnet tools build an inventory of all devices on a network without needing to know their addresses in advance.
Explore BACnet Networks on macOS
Voltrus BACnet Explorer automatically discovers devices, browses objects, reads Present-Value and Status-Flags in real-time, and writes to writable properties. Native macOS app, no JVM required. $49 lifetime.
Download BACnet Explorer