BACnet Basics BACnet
BACnet is the protocol most modern building automation runs on. If you touch a chiller plant control panel, a VAV (variable-air-volume) box controller, a JACE or EBO supervisor (the gateways and servers that supervise a building's controllers), a Distech actuator, or a Honeywell rooftop unit, you're almost certainly talking to BACnet. The history, for background: ASHRAE started work on it in 1987 to give building controls one common language that didn't belong to any single vendor, and ASHRAE 135 — the standard that defines it — has been a moving target ever since, picking up new object types and services as the industry's needs have changed. This page is the explainer the BACnet/IP Hex Converter tool's footnote keeps pointing toward.
What BACnet is, and isn't
The defining BACnet idea is that devices describe themselves. A BACnet device on the network doesn't just expose a block of memory full of numbers; it exposes a list of named, typed objects, each with named, typed properties. Ask a device what it has, and it answers. Ask any individual object for its name, units, or current value, and it answers. The protocol carries enough metadata that a client can walk into a building it has never seen before, query a controller, and produce a working point list. That alone makes it feel different from anything older.
The contrast that comes up most is with Modbus.
Modbus is deliberately
dumb — a register is just sixteen bits, and the only thing that knows
whether those bits are a temperature in tenths of a degree or a packed
status word is the vendor's manual. BACnet flips this. A BACnet
Analog Input object knows its Object_Name, its Units,
its Description, its current Present_Value, its high and low
limits, and a couple dozen other properties — none of which need to
live in a separate document. The protocol carries the labels and the
values together.
The other thing BACnet isn't is one specific wire. ASHRAE 135 defines the protocol logic — objects, properties, services, addressing — once, and then defines several data-link options for carrying that logic over different physical media. The two you'll meet in the field are BACnet/IP (the protocol over UDP datagrams on a normal Ethernet/IP network) and BACnet MS/TP (the protocol over RS-485 twisted-pair, with a token-passing master ring). Newer options like BACnet/SC (Secure Connect, over TLS WebSockets) and the older BACnet/Ethernet exist but are rarer in BAS work. The object model and the services don't care which one is underneath.
Devices, objects, properties
Three nested layers carry everything. A device is
the controller — a JACE, a VAV box controller, a chiller's onboard
BACnet card, an MS/TP thermostat. Each device has one globally
unique device instance number on the BACnet network (a value
from 0 to 4,194,302; you'll often see it written as
device:1001) and exposes itself as one
Device object.
Inside the device live the objects. Every input,
output, setpoint, schedule, alarm, calendar entry, file, and logic
point the device wants to make visible on the network is an object.
Each object has a type (Analog Input, Binary
Output, Multi-state Value, Schedule,
…) and an instance number that is unique within the device.
Together those two values form the object's
Object_Identifier — packed into a single 32-bit value
as 10 bits of object type plus 22 bits of instance number, but
always written as the human-readable pair, e.g.
analog-input,3 or AI:3.
Inside the object live the properties. Every object
has at least Object_Identifier, Object_Name,
Object_Type, and a current Present_Value;
most have a dozen or more on top of that. An Analog Input typically
also exposes Units, Description,
Status_Flags, High_Limit,
Low_Limit, COV_Increment, and several
others. The properties are where the actual data lives — every
read and every write targets a specific property on a specific
object on a specific device.
The object types group into a handful of recognizable families. The analog/binary/multi-state split is the one to hold in your head:
Analog · AI · AO · AV
32-bit floating-point values. Analog Input for a sensor reading, Analog Output for a hardware output the controller drives, Analog Value for a setpoint or computed value that lives only in software.
Binary · BI · BO · BV
Two-state values (ACTIVE / INACTIVE). Binary Input for a contact closure, Binary Output for a relay the controller drives, Binary Value for a software-only enable or override flag.
Multi-state · MSI · MSO · MSV
Enumerated values — three or more named states, like OFF / LOW / HIGH or AUTO / HEAT / COOL / OFF. The state names live in the object's State_Text property, addressed by 1-based integer.
Device · DEV
The controller itself, exposed as an object. Carries the device instance number, the vendor ID, the model, the firmware version, and the list of every other object the controller hosts.
Beyond these are Schedule, Calendar,
Trend Log, Notification Class, File,
Loop, Group, and several others — each its
own object type with its own property set. Most BAS work touches the
analog / binary / multi-state families, the Device object for
discovery, and the Schedule family for time-of-day logic; the rest
show up when a specific feature does.
The services you'll see
A service is a verb against the object model — the request a client puts on the wire to read a property, write a property, acknowledge an alarm, or subscribe to a change notification. ASHRAE 135 defines roughly thirty-five services; a handful do almost all the work in a normal BAS:
ReadProperty— fetch one property of one object. The everyday read: "what'sPresent_ValueonAI:3ofdevice:1001?" The response carries the typed value (real, integer, boolean, enumerated, string) the property holds.WriteProperty— set one property of one object. The everyday write: "setPresent_ValueonAO:1to 75 % at priority 16." On commandable objects, the priority is part of the write — see the next section.ReadPropertyMultiple/WritePropertyMultiple— fetch or set many properties in a single request. Polling a controller for a graphic's worth of points uses these, not a thousand individual ReadProperty calls; the network overhead is the same for one property or thirty.SubscribeCOV+ConfirmedCOV-Notification— Change of Value. Instead of polling, the client subscribes once and the device sends a notification each time the value changes by more than the property'sCOV_Increment. Push instead of pull. Where Modbus forces a client to poll often enough to catch a change, BACnet lets the device tell the client when one happens. Subscriptions have a lifetime; clients re-subscribe before it expires.Who-Is/I-Am— the pair of unconfirmed broadcasts that handle discovery. Their own section is next.
Other services — AcknowledgeAlarm,
ReinitializeDevice, AtomicReadFile,
CreateObject, the time-synchronization services — show
up when a specific feature does. The five above carry almost every
everyday read, write, and notification across a building. The fuller
reference — the confirmed / unconfirmed split, the service families,
and how BIBBs say which of these a given device
actually supports — is BACnet
Services.
The priority array — BACnet's command stack
Every commandable object — Analog Output, Binary Output,
and Analog/Binary/Multi-state Value when configured commandable —
has a special property called Priority_Array: a
16-slot array, indexed 1 to 16, that holds pending commands. A
WriteProperty against Present_Value does
not simply overwrite the value; it writes into one slot of the
array, at a chosen priority. The object's actual
Present_Value is then computed as the value in
the lowest-numbered non-null slot, or — if every slot is null
— the value of the
Relinquish_Default property.
Slot 1 is the highest priority and slot 16 is the lowest. The convention across the industry is that low slot numbers are reserved for high-stakes commands (slot 1 is manual life-safety; slots 5 and 6 are critical-equipment / minimum-on-off), slot 8 is the operator's manual override, and slot 16 is the slot the BMS's normal sequence writes from. Slots 9–15 are largely available for application-specific use. The full reservation table is in ASHRAE 135; for everyday troubleshooting, "slot 8 beats slot 16, and a null at slot 8 lets slot 16 take over" is most of what you need.
Walking the worked example: the BMS's sequence writes a damper
position of 65 % to slot 16. A tech, standing at the operator
workstation, hand-overrides the same damper to 0 % at slot 8.
The object's Present_Value now resolves to 0 %
— the slot-8 override wins because it sits at a lower (higher-
priority) index than the sequence at slot 16. When the tech is
done, they write null into slot 8 (the same
WriteProperty request, with a null value). Slot 8
becomes empty; the lowest non-null slot is now slot 16; the
damper drops back to 65 %. The sequence never had to be told
anything; it just becomes the new winner.
Two things to hold in your head when reading commandable BACnet points: first, that the value you see on the graphic is the resolved value, not necessarily the value the BMS sequence is writing. A sequence writing 65 % at priority 16 can appear to be "broken" because slot 8 still carries a years-old override someone forgot to release. Second, that writing null releases; it doesn't overwrite. Forgetting to release an override is the most common way priority-array logic goes wrong in the field.
To work the resolution rule yourself — type into slots, press
× to release one, and watch
Present_Value jump to the next winner — the
Priority Array resolver
is the interactive companion to this section, with the full
16-slot reservation table alongside it.
Who-Is / I-Am — how devices announce themselves
Two unconfirmed services handle device discovery. A client (a BMS,
an engineering tool, a JACE) sends a Who-Is request as
a network-wide broadcast: any device whose instance number is
in this range, please identify yourself. The request can carry
a specific range (low and high device-instance bounds) or no range
at all — "everybody on the network, speak up."
Every device that hears the broadcast and matches the range
responds with I-Am, an unconfirmed broadcast carrying
its own device instance number, its maximum APDU length (how big a
single message it can accept), its segmentation support, and its
vendor ID. The handshake is one-and-done; nothing else is
negotiated.
What this looks like in practice: open EBO's discovery dialog, an
N4 Workbench's BACnet network scan, or a tool like Yabe — they
fire Who-Is, populate a device list from the I-Am responses, and
build the rest of the point browser on top of subsequent
ReadProperty calls. A device that doesn't show up in
that list almost always has a Who-Is / I-Am problem: the broadcast
didn't reach it, or its reply didn't make it back. That story —
why discovery sometimes can't cross a router — is the opening of
BACnet Networking.
MS/TP vs BACnet/IP — same protocol, different transport
The two BACnet data links you'll meet are MS/TP and BACnet/IP. The object model, the property names, the services, and the priority array are identical between them; only the framing around each message changes.
BACnet MS/TP runs over a two-wire RS-485 bus. Up to about thirty masters share the bus by passing a token: only the controller holding the token may transmit, and once it has sent its message (or used its allotted frame budget) it passes the token to the next master in numeric order. The bus runs at one of a small set of baud rates (typically 38400 or 76800), and the whole bus is one BACnet network sharing a single 16-bit network number. Slow compared to Ethernet, but cheap and robust — most VAV controllers, many small unit controllers, and most MS/TP-only thermostats use it.
BACnet/IP wraps the same BACnet messages inside normal UDP datagrams on a normal Ethernet network. The IANA- registered port is UDP 47808 (which is 0xBAC0 in hex — the source of the "BACnet" port mnemonic). A controller on BACnet/IP is reachable by its IP address and port, identifies itself by the same device instance number, and speaks all the same services. The framing wrapping each message — a small BACnet Virtual Link Layer header, then the BACnet network-layer header, then the actual service — is what's different, along with the broadcast story that BACnet Networking opens with.
The split matters for one practical reason: where a conversation can happen. An MS/TP bus is a closed, low-speed serial loop — fast to commission, but every device on it has to be physically on that loop. BACnet/IP rides whatever Ethernet already exists in the building — a riser, a switch, a VLAN — and can carry a conversation between any two devices on the same IP segment. Crossing an L3 boundary (a router, a different subnet) introduces broadcast rules that take their own page to unpack: that's what BACnet Networking opens with.
The deeper MS/TP story — token rotation, the master/slave token-
passing mechanic, Max_Master and
Max_Info_Frames, the per-segment device-count and
cable-length limits — has its own page:
BACnet MS/TP, built
around the moments most BMS techs actually touch it —
commissioning and bus-fault troubleshooting.
What this page didn't cover
The shape of the protocol is enough to read a BACnet point list, form a Read or Write, recognize a priority-array override, and start a Who-Is discovery. The next question is what happens when the device you want to talk to isn't on the same Ethernet segment you're sending from — the broadcast story, the BBMD and Foreign Device Registration machinery, the three layers of addressing, and the EBO hex blob the BACnet/IP converter tool decodes for you. BACnet Networking is the companion page that walks through each.
Out of scope here, by design: the deep MS/TP token mechanics
(token rotation, Max_Master,
Max_Info_Frames, baud rates and cable-length budgets
— now covered by BACnet
MS/TP), segmentation of long messages, alarms and event
notifications, schedules and calendars as their own object types,
trend logs, and the file / group / loop / notification-class
objects. The rest are their own future pages; this one stays on
the object model, the services, and the priority array.