"The chiller speaks BACnet" is the sentence that starts most building integration projects and settles almost nothing. BACnet is not a data format you can simply read; it is an object model, an addressing scheme and a set of services, and an integration succeeds or fails on whether those three were written down properly before anyone connected a cable. The queries that bring people to this subject are revealing: they are not about what BACnet is, they are about device instances, object identifiers, network numbers and which fields a points map actually needs. That is the right question, and this article answers it.
The message up front: in BACnet, the addressable unit is an object inside a device, identified by an object identifier, which is an object type plus an instance number. Devices themselves are identified by a device instance number that must be unique across the entire interconnected system, not merely unique on its cable. Everything that goes wrong at integration time traces back to one of three things: duplicate device instances, undocumented network numbers, or a points map keyed on object names rather than object identifiers. Fix those three in the documentation and the integration becomes routine.
1. What BACnet is, formally, and why that matters here
BACnet is published by ASHRAE as Standard 135, and is also adopted internationally as ISO 16484-5. That matters for a practical reason rather than a bureaucratic one: because it is a published standard with a conformance testing regime behind it, the object model and the addressing rules are the same across manufacturers, and you can specify against them. A device that claims BACnet conformance is claiming to implement these structures, not merely to exchange data somehow.
This article deliberately stays at the object and addressing layer. If you want the introduction to what BACnet is and where it sits against other protocols, start with BACnet explained, and for the protocol choice itself see BACnet versus Modbus. One structural difference between the two is worth holding in mind throughout: Modbus addresses storage locations, as described in Modbus explained, whereas BACnet addresses named objects that carry their own metadata. That is why a BACnet points map has more fields than a Modbus register list, and why it is more often incomplete.
One note on spelling. BACnet object types are written in the standard as analog-input and similar, with the American spelling, and I use the standard's spelling for object type names throughout even though the surrounding prose uses British spelling for the word analogue. Getting these names exactly right matters when you are writing them into a configuration file.
2. The object: BACnet's unit of information
A BACnet device presents its information as a collection of objects. An object is a named, typed container with a defined set of properties, and it is the thing you read from and write to. A space temperature is not a register at an address; it is an analog-input object with a present-value property, a units property, an object-name, a description, status flags and more.
This is the conceptual leap that catches people arriving from register-based protocols. You do not read "address 40001 as a 16-bit signed integer and divide by ten". You read a specific property of a specific object, and the device tells you the engineering units itself. The benefit is that the data is self-describing. The cost is that there is more to specify, and a vaguer specification produces a vaguer result.
Every object in a device also has a parent: the device's own device object, which describes the device and holds its object list. Reading that object list is how a discovery tool finds out what a device offers, and whether that list is complete and sensibly named is the first thing I would check on any new device.
3. The object types you will actually meet
The standard defines a long list of object types and most devices implement a small subset. These are the ones that appear in the great majority of real integrations:
| Object type | What it represents | Typically read or written | What to watch for |
|---|---|---|---|
analog-input | A measured varying value: temperature, pressure, humidity, flow | Read | Check units rather than assuming. Also check whether out-of-service is set, which means the value is being simulated |
analog-output | A varying command to a physical device: valve or damper position, drive speed reference | Written | Commandable, so it has a priority array. Writing without understanding priority is the classic integration fault |
analog-value | A varying value held in software: a setpoint, a calculated value, a parameter | Either | Often commandable, often not. The same object type behaves differently between devices |
binary-input | A two-state measured condition: run status, fault, filter dirty, switch position | Read | Confirm which state is active. Polarity is a property, and it is sometimes set so that active means stopped |
binary-output | A two-state command: start, stop, enable | Written | Commandable. Also carries minimum on and off time behaviour in some devices |
binary-value | A two-state software value: a mode flag, an enable, an override | Either | The most frequently misunderstood object, because its meaning is entirely device-specific |
multi-state-input / -output / -value | An enumerated state: occupancy mode, fan speed step, unit mode | Either | The numbers mean nothing without the state text. Always obtain state-text or the vendor's enumeration table |
device | The device itself, its identity and its object list | Read | Exactly one per device. Its instance number is the device instance, covered in section 7 |
schedule / calendar | Time-of-day and date-based control, and exception dates | Either | Writing schedules over BACnet is possible and frequently fragile. Many integrators read them and change them at the head end instead |
trend-log | Historical samples held in the device | Read | Buffer size and whether it stops or wraps when full. A log that has wrapped has silently lost data |
notification-class / event-enrollment | Alarm and event routing and conditions | Either | Where BACnet alarming is configured. Often left at defaults, so alarms exist but reach nobody |
loop | A control loop with its own tuning parameters | Either | Implemented inconsistently. Many manufacturers expose loops through their own value objects instead |
The pattern worth internalising is the three-way split across input, output and value. Input means measured from the physical world. Output means commanded to the physical world. Value means held in software. It is the same distinction as the status-versus-command problem in conventional points list design, which is why the discipline described in BMS points lists and field devices maps directly onto BACnet object selection.
4. The object identifier: type plus instance
Each object inside a device is identified by an object identifier, which is a pair: the object type, and an instance number within that type. So analog-input instance 4 and binary-input instance 4 are two different objects that coexist happily, because the type distinguishes them. Instance numbers are unique per type within a device, not globally unique.
Encoded, the object identifier packs the object type and the instance number into a single value, with the instance number occupying a 22-bit field. The practical consequence is the range: instance numbers run from 0 up to 4194302, with the top value of the 22-bit field, 4194303, reserved by the standard rather than available for assignment. That reserved value has a specific use, as a wildcard when a client wants to ask a device to identify its own device object without already knowing its instance number.
A caution on those figures. They are consistently documented across manufacturers' BACnet implementation guides and the BACnet Institute's own material, but I have also seen vendor documentation state the upper bound differently, including at least one case that looks like a simple typographical error in a driver manual. Where a number matters to your configuration, the standard governs and the device's own protocol implementation conformance statement is the next authority, not a third-party summary including this one.
Key your points map on the identifier, never the name
This is the single most useful thing in this article. object-name is a writable property on many devices, it is frequently edited during commissioning, and it is not guaranteed stable. The object identifier is structural. A points map that records "AHU3 Supply Air Temp" as its key will break the first time somebody tidies up the naming; a points map that records device instance plus analog-input plus instance 7 will not. Record both, by all means, but join on the identifier and treat the name as a label for humans.
5. Properties, and the handful that decide whether a value is trustworthy
Objects carry properties, and most integrations read only present-value. That is usually a mistake, because several other properties tell you whether the present-value means anything:
present-value. The current value. Read for inputs, written for commandable objects.status-flags. A small set of flags covering conditions such as whether the object is in alarm, whether it has a fault, whether it has been overridden, and whether it is out of service. Readingpresent-valuewithoutstatus-flagsmeans you cannot distinguish a good reading from a faulted one.out-of-service. When set, the object is decoupled from the physical world and its value can be written for testing. Devices get left in this state after commissioning, and a value that appears perfectly plausible is then entirely fictional. Any integration that reads critical data should read this property too.reliability. Why the object believes its value may be unreliable: open circuit, shorted, over range, communications failure. Extremely useful and almost universally ignored.units. The engineering units, from a standard enumeration. Read it rather than assuming, particularly for pressure, where the difference between pascals and kilopascals is a factor of a thousand and both are plausible.object-nameanddescription. Human-readable labels. Useful, not structural, and discussed above.state-text. For multi-state objects, the text for each enumerated state. Without it, a value of 3 is unknowable.priority-arrayandrelinquish-default. For commandable objects. The subject of the next section, because it causes more trouble than everything else here combined.
6. Command priority: the thing that surprises everyone once
BACnet does not simply let a client write a value to a commandable object. It accepts writes at one of sixteen priority levels, keeps every outstanding write in a priority array, and the object's actual value is determined by the highest-priority write currently present. Lower numbers are higher priority. When no write is present at any level, the object falls back to its relinquish-default.
This mechanism exists for an excellent reason. It lets a life-safety interlock override an operator, and an operator override a schedule, without any of them having to know about the others, and without a lower-priority system being able to stamp on a higher-priority decision. It is genuinely good design.
It is also the source of the most common integration incident I have seen described in building controls work: a value written and never released. An integration writes a damper position or a setpoint at a given priority, the project ends, nobody relinquishes the write, and the array keeps that entry indefinitely. The building's own schedules and sequences then operate at a lower priority and are silently ignored. The system looks healthy, the sequence logic is correct, and the plant does not respond to it. Finding this requires reading the priority array, which most front ends do not show by default.
The practical rules I would apply to any BACnet integration that writes:
- Agree the priority level in writing before any write is configured, with the controls contractor, and record it in the points map alongside the object identifier. An undocumented write priority is a time bomb with a long fuse.
- Never write at a level reserved for safety functions. The standard assigns specific meanings to certain high-priority levels, including life-safety use. Check the standard and the device's own documentation for the level assignments rather than taking a number from any summary, including this one, and keep ordinary integration writes well away from the reserved region.
- Release explicitly when you are finished. Writing a null at your priority level clears your entry and lets lower priorities resume. Build this into the integration as a deliberate operation, not an afterthought.
- Read the priority array during commissioning and at handover, on every object your integration writes to, and record what you find. This is a five-minute check that prevents a multi-year mystery.
- Treat a non-empty priority array on an object nobody is deliberately commanding as a finding, not as background noise.
7. The device instance number, and why duplicates are the classic site fault
Every BACnet device has exactly one device object, and its instance number is the device instance: the number by which the whole device is known. It occupies the same 22-bit instance field as any other object, so the same range applies.
The rule that matters is the scope of uniqueness. A device instance number must be unique across the entire interconnected BACnet system, not merely unique on its own cable or subnet. This is stricter than people expect, and it is the single most common cause of a site that mostly works and intermittently does not.
The failure is unpleasant because it is not a clean break. Two devices sharing an instance number will both answer requests addressed to that instance. A client may discover one, then the other, then see values flickering between two unrelated pieces of plant. Trend data becomes a blend of two devices. A write intended for one lands on the other. Nothing reports an error, because from each device's point of view it is behaving correctly.
It happens for mundane reasons. Controllers ship with a default instance number and get installed without being changed. A panel is replaced and the replacement is configured from a factory default. Two buildings each numbered their controllers from 1, and then somebody joined the two networks together to build a portfolio head end, which is exactly the moment a dormant duplicate becomes a live fault.
Allocate device instances from a plan, before anyone installs anything
Treat device instance numbers the way a network team treats IP addressing: as a numbering scheme owned by one party, documented in one place, with blocks allocated per site, per building and per system, and deliberate gaps left for growth. Encoding meaning into the number, so that a block identifies a site and a range within it identifies a system, costs nothing at design stage and makes every future discovery, fault find and portfolio consolidation easier. The alternative is what most estates have: numbers assigned by whoever commissioned each panel, no record, and a duplicate waiting for the day two networks meet.
8. Addressing below the device: networks and MAC addresses
Device instance is the logical identity. Underneath it sits the physical routing: which network the device is on, and what its address is on that network.
- Network number. Each BACnet network segment carries a 16-bit network number, which must be unique across the interconnected system. The assignable range runs from 1 to 65534, with 0 reserved to mean the local network. The standard also distinguishes a broadcast intended for one remote network from a global broadcast intended to reach every node on every network, and reserves a network number for that purpose; check the standard for the exact reserved value rather than relying on a summary.
- Routers. A BACnet router joins networks of different types, commonly an MS/TP trunk to a BACnet/IP network, and a well-documented site records which router serves which network number. Misconfigured or duplicated network numbers on routers produce routing loops and unreachable devices, and they are difficult to diagnose without the documentation.
- MS/TP MAC address. On an MS/TP trunk, which is BACnet over twisted-pair serial, each device has a MAC address on that trunk. Manufacturer documentation commonly gives the master device range as 0 to 127, with a wider range available for slave devices, and many integrators adopt a narrower house convention on top of that. The MAC address is separate from the device instance: one is the address on the cable, the other is the logical identity on the whole system, and conflating them is a common documentation error.
- Trunk physical limits. MS/TP is a serial bus with real limits on device count, cable length, topology and termination, and these are set by the electrical standard beneath it rather than by BACnet. A trunk that exceeds them produces intermittent communications that look like a software fault. The planning guidance here belongs to the manufacturer's own network design documentation.
9. BACnet/IP, broadcasts and BBMDs
BACnet/IP carries BACnet over UDP, conventionally on port 47808, and it is where most modern site integration happens. It introduces one structural problem that accounts for a large share of "we can see some devices but not all of them" situations.
BACnet relies on broadcasts for several essential functions, device discovery among them. IP broadcasts do not cross router boundaries between subnets. So a BACnet/IP system spanning more than one IP subnet cannot discover itself using broadcasts alone, which is why BACnet defines a mechanism to carry them across.
- The BBMD. A BACnet Broadcast Management Device sits on a subnet and forwards broadcasts to its peers on other subnets. Each subnet containing BACnet/IP devices needs one, and each BBMD holds a broadcast distribution table listing the BBMDs in the system, including itself.
- One per subnet. Two BBMDs on the same subnet is a misconfiguration that produces duplicated traffic, and it is a common accident when a second supplier adds equipment without knowing a BBMD already exists.
- Consistency. The distribution tables must agree with one another. A BBMD missing from one table produces a system where visibility depends on which device you look from, which is a confusing symptom to chase.
- Foreign device registration. A device or client on a subnet with no BBMD of its own can register as a foreign device with a BBMD elsewhere, which then forwards broadcasts to it for the duration of the registration. Registrations have a lifetime and must be renewed, so a foreign device that stops renewing goes quietly deaf to broadcasts while still appearing connected. Workstations and integration gateways are commonly configured this way.
- Firewalls and network policy. The traffic is UDP and includes broadcast forwarding between subnets, which is exactly the kind of thing a corporate network policy blocks by default. Involve the network team early, and record what was opened and between which addresses.
Because this layer is a genuine route into the building's control system, it belongs in the security conversation and not only the commissioning one. The considerations are in BMS cybersecurity for connected buildings.
10. The data model fields an integration actually needs
Most BACnet points maps I have seen are too thin, which is why integrations take longer than quoted. The field list below is what makes a map usable by somebody who was not present when it was written. This is the deliverable to specify, not a spreadsheet of names and values.
| Field | What it holds | Why the integration needs it |
|---|---|---|
| Device instance | The device object's instance number | The logical address of the device. The primary key of the whole map |
| Device name and location | Human-readable identity and physical position | So an engineer can find the thing the row describes |
| Network number | The BACnet network the device sits on | Routing, and diagnosing why a device is unreachable |
| Data link and address | BACnet/IP address and port, or MS/TP trunk and MAC | The physical path. Needed for any fault find below the logical layer |
| Router and BBMD | Which router serves the network, which BBMD serves the subnet | The two pieces of information most often missing when discovery fails |
| Object type | analog-input, binary-value and so on, spelled exactly | Half of the object identifier |
| Object instance | The instance number within that type | The other half. Together these are the stable key |
| Object name | The device's own label | For humans. Explicitly not the join key |
| Engineering units | The units enumeration the object reports | Prevents the scaling and magnitude errors that survive commissioning |
| Range and expected values | Plausible operating band, or the state enumeration | Lets you write sanity rules that catch failed sensors |
| State text | Text per state for multi-state objects | Without it the numbers are meaningless |
| Read or write | Direction of the integration's access | Scope, and a control on accidental writes |
| Write priority | The agreed priority level, where the row is written | Prevents the stuck-write failure described in section 6 |
| Poll or subscribe | Polling interval, or change-of-value subscription and its parameters | Determines network load and data freshness. The most common cause of an overloaded trunk |
| Target in the receiving system | Where the value lands downstream | Makes the map a mapping rather than an inventory |
Two of these rows carry more weight than the rest. Write priority, for the reason given above. And poll or subscribe, because polling every point every few seconds across an MS/TP trunk is a reliable way to make a working system unreliable, and because change-of-value subscriptions have to be renewed, so a subscription-based integration that loses its renewals goes stale without any visible error.
11. The addressing mistakes that account for most lost days
| Mistake | What it looks like on site | How to avoid it |
|---|---|---|
| Duplicate device instance | Values flickering between unrelated plant, a device that appears and disappears, writes landing on the wrong unit | Allocate from a documented numbering plan. Scan for duplicates before joining any two networks |
| Duplicate or undocumented network number | Devices unreachable from one workstation and fine from another, routing loops | One owner for network numbering, recorded against every router |
| Confusing MAC address with device instance | A points map that cannot be used to reach anything, because it records the wrong identifier | Separate columns for both, as in section 10 |
| Keying the map on object name | The integration breaks after a commissioning tidy-up, with no change to either system | Join on object identifier, carry the name as a label |
| Writing without an agreed priority | Plant stops following its own schedules, sequences appear to be ignored, no alarm | Agree and document the level; read the priority array at handover |
| Never relinquishing a write | The same symptom, persisting for years after the project that caused it ended | Explicit release as a designed operation, and a priority array check in the handover evidence |
| Missing BBMD, or two on one subnet | Partial discovery, duplicated traffic, inconsistent device lists | One per subnet, consistent distribution tables, both recorded |
| Expired foreign device registration | A gateway that was working and now sees nothing new, while still looking connected | Monitor the registration, not just the link |
Ignoring out-of-service | Analytics built on values that are simulated rather than measured | Read the property; treat a set flag as a finding |
| Assuming units | Plausible-looking data wrong by a factor of ten, a thousand, or an offset | Read units and record it in the map |
| Over-polling a trunk | Intermittent communications faults that look like hardware problems | Size the polling regime deliberately; prefer change-of-value where supported |
Where this article stops, and what governs instead
Two limits. First, my own domain is enterprise systems, data models and integration at the systems level rather than controls engineering: what I can speak to is how this data gets structured, documented and consumed by the systems downstream of the BMS, and the project failure modes around that. Design decisions about the control strategy itself belong to a controls engineer. Second, every specific value in this article, the instance range, the network number range, the MS/TP address ranges, the port, the priority level assignments, is reported here as it is consistently documented across manufacturers' implementation material, and vendor documents do occasionally disagree with each other. For anything you are about to configure, the standard itself and the device's own protocol implementation conformance statement are the authorities. Use this page to know which questions to ask and which fields to demand, not as the source of a number you will type into a configuration file.
12. What to require as a BACnet integration deliverable
If you are specifying or accepting an integration, these are the items I would make contractual rather than hoping for:
- The protocol implementation conformance statement for every device type involved. This is the manufacturer's own declaration of which objects, properties and services the device supports, and it tells you what is possible before anyone tries it.
- The completed points map with every field from section 10 populated, in a spreadsheet or database rather than only a document.
- The device instance and network number allocation record for the whole site, including spare blocks.
- A network topology drawing showing subnets, routers, BBMDs, MS/TP trunks and device counts per trunk.
- Evidence of a duplicate scan: a device discovery across the whole system with no duplicate instances found.
- Priority array evidence for every object the integration writes to, at handover, showing only the expected entries.
- A documented polling and subscription regime with the resulting traffic estimate per trunk.
- A demonstrated release test: write a value, confirm the plant follows, release it, confirm control returns to the building's own logic. This takes ten minutes and proves the most consequential thing on the list.
Where the integration feeds a maintenance or facilities system rather than another control system, the architecture around it matters as much as the map, and that is covered in the BMS and CAFM integration reference architecture and, for the enterprise side, BMS integration with ERP.
The idea to walk away with
BACnet gives you a self-describing, standardised, well-tested way to address information in a building, and it removes most of the ambiguity that register-based protocols leave behind. What it does not do is document your site for you. The protocol defines the structures; whether anyone wrote down your device instances, your network numbers, your BBMD layout and your write priorities is a project discipline question, and that is where integrations actually succeed or fail.
So the useful summary is short. Objects are addressed by type plus instance, and that pair is your stable key. Devices are addressed by a device instance that must be unique across everything that will ever be joined together. Writes carry a priority and must be released. Broadcasts need BBMDs once more than one subnet is involved. Get those four written into the points map and the topology drawing, and the next integration on that building is a short job instead of an archaeology project.
Final thoughts
The reason this layer is worth learning, even for someone whose job sits well above the controls network, is that it determines what the building can tell your other systems. Asset performance reporting, condition-based maintenance triggers, energy analytics and any form of fault detection all rest on a map of objects that somebody has to have written down correctly.
If you inherit a building with no BACnet documentation, the first hour is well spent running a discovery and simply counting: how many devices answer, how many duplicates appear, how many have default names, and how many objects report themselves out of service. That count is usually the most honest statement available about the state of the system, and it is the thing I would want in front of me before agreeing any integration scope at all.
Disclosure
Alongside advisory work I also build a CMMS and CAFM platform, so I have a commercial interest in this category. Nothing above is a recommendation for it, and no vendor named here has paid for inclusion or had any editorial input. Weigh the analysis accordingly.
Specifying or accepting a BACnet integration?
Independent review of BACnet points maps, device and network numbering plans, write-priority documentation and integration handover evidence, plus how the data lands in your CMMS, CAFM or analytics layer. 22+ years across CMMS, CAFM, EAM and ERP implementations. No controls vendor margins, no reseller arrangements.
Book a conversationRelated reading: BACnet explained, BACnet vs Modbus, Modbus explained, BMS points lists and field devices, BMS and CAFM integration architecture, BMS cybersecurity, BMS point-to-asset mapping, The alert-to-work-order audit trail.
Muhammad Abbas
CMMS / CAFM Manager & Independent Advisor · 22+ years across enterprise CMMS, EAM, CAFM and ERP implementations in utilities, oil and gas, manufacturing, government and facility operations.
Work with me