BACnet/SC
- Specification reference: ANSI/ASHRAE 135-2024, Annex AB (BACnet/SC), Protocol Revision 30.
BACnet Secure Connect (BACnet/SC) carries BACnet messages over TLS-encrypted WebSocket connections instead of UDP. This page explains what it changes and how it works, and what the CAS BACnet Stack provides. Adding it to a product is covered on these pages:
- Integration guide: the ten steps from loading the stack to running the main loop.
- Certificates: the certificate File objects, certificate changes and CSR requests, and test certificates for the lab.
- Transport callbacks: the WebSocket callbacks your application implements.
- Operations and troubleshooting: the Network Port properties, heartbeats, reconnect and failover, common problems and questions.
- Moving from BACnet/IP: adding BACnet/SC to a product that already runs BACnet/IP.
- Reference: the property reference, compile flags and sizes, the API summary, a glossary and the conformance statement.
The problem with BACnet/IP in modern buildings
Section titled “The problem with BACnet/IP in modern buildings”BACnet/IP has served the building automation industry well for over two decades. But it was designed for a different era, one where building controllers lived on isolated, air-gapped networks, safely separated from the enterprise and the internet.
That world no longer exists.
Today, HVAC controllers, energy meters, lighting systems and access control panels are connected to corporate networks, monitored from cloud dashboards and managed remotely. The attack surface has expanded dramatically, and the security assumptions built into BACnet/IP have not kept up.
BACnet/IP has no encryption, no authentication and no access control.
Any device on the same network segment can read and write BACnet objects. Any attacker who gains network access can impersonate a BACnet controller, inject false sensor readings or issue commands to physical equipment.
IT security teams know this. That is why BACnet/IP traffic is often blocked at the corporate firewall, why UDP port-forwarding requests from facilities teams are rejected, and why compliance audits flag unencrypted building automation traffic as a finding.
What BACnet/SC solves
Section titled “What BACnet/SC solves”BACnet/SC (Secure Connect) is the ASHRAE standard’s answer to these problems. Defined in Annex AB of ANSI/ASHRAE 135-2024, it replaces the BACnet/IP transport while leaving the BACnet application layer unchanged.
| Problem | BACnet/IP | BACnet/SC |
|---|---|---|
| Traffic is plaintext | All messages readable by anyone on the network | TLS 1.3 encrypts every connection |
| No device authentication | Any device can send traffic and be trusted | Every device presents an X.509 certificate; both ends verify each other |
| Broadcasts and BBMDs | UDP broadcast needs BBMD configuration across subnets | Hub-and-spoke topology: no UDP broadcast, no BBMD |
| Firewall and NAT hostile | UDP port forwarding required, often blocked by IT | Outbound TCP (secure WebSocket), which passes firewalls the way HTTPS does |
| No access control | No concept of who may read or write | Certificate-based identity makes policy enforcement possible |
| IT integration friction | “BACnet is a security risk” | The same kind of infrastructure as HTTPS, which IT teams understand |
The key point: your BACnet services, objects and properties do not change. ReadProperty, WriteProperty, Who-Is, I-Am, COV subscriptions, alarms and schedules all work exactly as before. BACnet/SC changes only the transport underneath.
The business case for BACnet/SC
Section titled “The business case for BACnet/SC”Regulatory and customer pressure
Section titled “Regulatory and customer pressure”- NIST SP 800-82 (the NIST guide to operational technology security) recommends protecting OT network traffic.
- NERC CIP standards set security requirements for the electric sector’s OT systems.
- Government and defence programmes such as FedRAMP and CMMC can bring the building systems of their facilities into scope.
- Corporate security baselines at large enterprises (finance, healthcare, data centres) flag unencrypted building automation protocols.
Building automation manufacturers who cannot offer BACnet/SC are losing bids to competitors who can.
Faster IT approval
Section titled “Faster IT approval”The biggest non-technical benefit of BACnet/SC is less friction with IT. WebSocket over TLS, the BACnet/SC transport, is the same protocol stack as HTTPS. IT departments that will not open a UDP port will approve an outbound HTTPS-style connection much more readily. BACnet/SC moves a product from “blocked at the firewall” to “approved by IT” without changing its building automation functionality.
Future-proofing
Section titled “Future-proofing”BACnet/SC is part of the current standard, Annex AB of ANSI/ASHRAE 135-2024, which covers the BACnet/SC data link, the hub function, direct connections and certificate management. The CAS BACnet Stack implements it at Protocol Revision 30. Products built for BACnet/SC today interoperate with the building automation platforms, gateways and supervisory systems that adopt it.
Is BACnet/SC right for your product?
Section titled “Is BACnet/SC right for your product?”BACnet/SC is the right choice if your customers ask questions like these:
- “Can your BACnet traffic be encrypted?”
- “How do we keep unauthorised devices off the BACnet network?”
- “Our IT department will not open UDP ports. What are our options?”
- “Does your product support BACnet Secure Connect?”
- “We need to bring the building automation system into our enterprise security monitoring.”
If any of those applies, BACnet/SC is the path forward.
BACnet/SC in the CAS BACnet Stack
Section titled “BACnet/SC in the CAS BACnet Stack”The CAS BACnet Stack includes a BACnet/SC implementation:
| Capability | Detail |
|---|---|
| Hub connector (node) | Primary and failover hub, automatic reconnect |
| Hub function | Accepts and forwards node connections |
| Direct connections | Peer-to-peer, both initiating and accepting |
| Certificate management | Certificate files and CSR requests over the network (File objects, Network Port commands); keys and TLS stay in your TLS library |
| Transport independence | Works with the WebSocket and TLS library of your choice |
| Standard | ANSI/ASHRAE 135-2024, Annex AB, Protocol Revision 30 |
| Test coverage | Unit tests for the ANSI/ASHRAE 135.1-2023 clause 12.5 BACnet/SC test cases |
BACnet/SC can run alongside BACnet/IP on the same device, a migration path that adds secure connectivity while keeping compatibility with existing BACnet/IP installations.
1. Introduction & Scope
Section titled “1. Introduction & Scope”This manual describes how to integrate BACnet Secure Connect (BACnet/SC) into a server-class device - a BACnet/SC node that connects outward to a hub, exposes BACnet objects (analog inputs, binary values, schedules, etc.), and serves read/write requests over the SC transport.
In scope:
- Conceptual primer on BACnet/SC for developers familiar with BACnet/IP or MS/TP.
- Step-by-step C/C++ integration of the CAS BACnet Stack BACnet/SC features.
- The transport callback contract (WebSocket bridge) the application must implement.
- The certificate model: operational certificate and issuer (CA) certificates - including the application-owned file-storage model.
- A worked example creating a single Analog Input on an SC node.
- A self-signed certificate appendix for lab testing.
Out of scope:
- Implementing a BACnet/SC hub function (server that accepts node connections). The hub function is supported by the stack but is not the focus of this manual.
- Direct connect (peer-to-peer) initiator/acceptor. Briefly mentioned where it interacts with this guide.
- BACnet/SC routing between SC and BACnet/IP or MS/TP.
- Choosing or implementing a specific WebSocket / TLS library. The stack is library-agnostic.
- Production certificate authority (CA) administration. The CSR API is described; CA operations are vendor-specific.
- Migrating an existing BACnet/IP device to add BACnet/SC alongside it. See Moving from BACnet/IP to BACnet/SC for that scenario.
2. BACnet/SC Primer
Section titled “2. BACnet/SC Primer”2.1 What BACnet/SC is
Section titled “2.1 What BACnet/SC is”BACnet/SC (Secure Connect) is a datalink layer for BACnet, defined in ANSI/ASHRAE 135-2024 Annex AB. It replaces the UDP-based BACnet/IP transport with WebSocket (RFC 6455) over TLS 1.3, providing:
- Encryption of all BACnet traffic (TLS 1.3, RFC 8446).
- Mutual authentication using X.509 v3 certificates.
- Firewall- and NAT-friendly transport using TCP (typically port 443 or 4443).
- Hub-and-spoke topology - no UDP broadcast, no BBMDs.
The BACnet application layer is unchanged. Every BACnet service (ReadProperty, WriteProperty, Who-Is, I-Am, SubscribeCOV, alarms, ReadRange, etc.) continues to work the same way. Only the bytes underneath the NPDU change.
Mental model: BACnet/SC is to BACnet/IP what HTTPS is to HTTP - same upper protocol, secured transport beneath.
2.2 Why BACnet/SC
Section titled “2.2 Why BACnet/SC”BACnet/IP was designed for trusted, isolated networks; BACnet/SC was designed to run on ordinary IT infrastructure. What BACnet/SC solves, above, compares the two.
2.3 Hub-and-spoke topology
Section titled “2.3 Hub-and-spoke topology” +------------------+ | Primary Hub | | (Hub Function) | +--+----+----+----+ / | \ / | \ +---v--+ +--v---+ +-v----+ | Node | | Node | | Node | | A | | B | | C | +------+ +------+ +------+
Optional: direct-connect peering between nodes Node A <==========================> Node CEvery node opens an outbound wss:// connection to the hub. The hub forwards messages between connected nodes. Two nodes that need higher throughput or lower latency can optionally establish a peer-to-peer direct connect WebSocket, bypassing the hub.
2.4 Identity: Device UUID, VMAC, Device Instance
Section titled “2.4 Identity: Device UUID, VMAC, Device Instance”A BACnet/SC node has three identifiers that are easy to confuse:
| Identifier | Size | Lifetime | Used for |
|---|---|---|---|
| Device UUID | 16 bytes (RFC 4122) | Permanent per physical device | TLS / Connect-Request handshake; Device_UUID (507) on the Device object |
| VMAC (Virtual MAC) | 6 bytes | Per-network address | Hub addressing; MAC_Address on the Network Port |
| Device Instance | 22-bit (0–4 194 302) | Per BACnet network | Standard BACnet object identifier |
The UUID is the persistent identity of the box. Generate it once at manufacturing time (or first boot) and store it in non-volatile memory. The VMAC addresses the device on a given SC network. Each BACnet/SC port has one VMAC, used on its hub connection, by its hub function and on its direct connections. If you do not configure one, it is derived from the UUID (its last six octets, in the Random-48 form), so it is the same on every boot. The device instance is the same concept you already know from BACnet/IP.
2.5 Connection lifecycle (node side)
Section titled “2.5 Connection lifecycle (node side)” +------------------+ | Idle / cold | +--------+---------+ | application configured + Tick() running v +--------+---------+ TLS handshake fails | TLS dial +---------+ +--------+---------+ | | TLS OK | v v +--------+---------+ +-----+-----+ | WS Upgrade | | Error / | +--------+---------+ | Reconnect | | WS open | delay | v +-----+-----+ +--------+---------+ | | Connect-Request |<--------+ +--------+---------+ | Connect-Accept v +--------+---------+ | OPERATIONAL | | (Encap-NPDU, | | Heartbeats) | +--------+---------+ | error / Disconnect-Request v reconnect with backoffThe CAS BACnet Stack drives this state machine internally. Your application is responsible only for the WebSocket transport (open / send / receive / close) and for telling the stack the WebSocket connect/disconnect events through notification calls.
2.6 BVLC for BACnet/SC
Section titled “2.6 BVLC for BACnet/SC”BACnet/SC defines its own BVLC (BACnet Virtual Link Control) message set. Each BVLC message is sent as a single WebSocket binary frame.
| Function | Hex | Direction | Purpose |
|---|---|---|---|
| BVLC-Result | 0x00 | both | ACK / NAK for control messages |
| Encapsulated-NPDU | 0x01 | both | Carries the BACnet NPDU |
| Address-Resolution | 0x02 | node→node (relayed by the hub), or node→hub | Resolve VMAC to direct-connect URI |
| Address-Resolution-ACK | 0x03 | resolved node→requester | Resolution response, sent by the node whose VMAC was resolved (the hub answers only for itself) |
| Advertisement | 0x04 | both | Announces the sender’s capabilities (sent unsolicited, or in answer to a solicitation) |
| Advertisement-Solicitation | 0x05 | both | Asks the peer for its Advertisement |
| Connect-Request | 0x06 | initiator→peer | Begin SC session (node to hub, or node to node for a direct connection) |
| Connect-Accept | 0x07 | peer→initiator | Confirm SC session |
| Disconnect-Request | 0x08 | both | Begin graceful close |
| Disconnect-ACK | 0x09 | both | Confirm close |
| Heartbeat-Request | 0x0A | both | Liveness check |
| Heartbeat-ACK | 0x0B | both | Liveness response |
| Proprietary-Message | 0x0C | both | Vendor-specific |
You do not encode/decode BVLC by hand. The stack builds and parses every BVLC-SC message, control messages (Connect-Request, heartbeats, Advertisements and the rest) as well as Encapsulated-NPDU. Your code moves whole BVLC-SC messages, as opaque bytes, between the WebSocket and the existing RegisterCallbackSendMessageForPort / RegisterCallbackReceiveMessageForPort callbacks (one message per WebSocket binary frame), plus a small set of SC-specific transport callbacks. It neither parses nor builds NPDUs.
2.7 Certificates
Section titled “2.7 Certificates”BACnet/SC uses TLS 1.3 with mutual authentication. Each device needs:
- An operational certificate - the device’s X.509 v3 leaf certificate.
- Issuer certificates - the CA chain (typically root + intermediate, exactly two).
- A private key - never exposed as a BACnet property.
The CAS BACnet Stack does not generate or store private keys, and it does not perform TLS itself - that lives in your TLS/WebSocket library. The stack also does not store the certificate bytes: it tracks which File objects hold the operational, issuer, and CSR certificates and exposes those references through the SC Network Port properties (Operational_Certificate_File, Issuer_Certificate_Files, Certificate_Signing_Request_File), but the actual PEM bytes live in your application and are served on demand through RegisterCallbackReadFile / RegisterCallbackWriteFile. It also handles the BACnet requests for cert updates: AtomicWriteFile to deliver the new bytes, and ReinitializeDevice to activate them. A CSR is requested through the Network Port command callback (BACnetStack_RegisterCallbackNetworkPortCommand, §16.6); the stack has no certificate-validation callback.
3. Roles, Topology, and What This Manual Covers
Section titled “3. Roles, Topology, and What This Manual Covers”The BACnet/SC standard defines four roles. This manual covers role 1 (the node) in depth.
| Role | Description | Required for a server device? |
|---|---|---|
| 1. Hub Connector (node) | Outbound wss:// client to the hub. Carries this device’s BACnet traffic. |
Yes - minimum requirement. |
| 2. Hub Function | Listens for inbound wss:// connections from nodes; forwards traffic. |
No - only if the device is the project hub. |
| 3. Direct Connect Initiator | Opens a peer-to-peer wss:// to another node. |
Optional. |
| 4. Direct Connect Acceptor | Listens for peer-to-peer wss:// connections. |
Optional. |
A typical BACnet/SC server device implements role 1 only.
4. Architecture: Where the Stack Ends and Your Code Begins
Section titled “4. Architecture: Where the Stack Ends and Your Code Begins”The CAS BACnet Stack does not open WebSockets, perform TLS, or handle TCP sockets. The stack is transport-agnostic by design. It also does not hold certificate bytes in its own storage - see §2.7. The application owns:
- The WebSocket library (e.g., libwebsockets, Boost.Beast, uWebSockets, mongoose).
- The TLS library (e.g., OpenSSL, mbedTLS, wolfSSL, BoringSSL).
- Certificate bytes and file I/O on disk / flash.
- Threading, sleep, polling.
The contract between your application and the stack is a small set of callbacks and notification functions:
+-----------------------+ +----------------------------------+ | Application | | CAS BACnet Stack (DLL/static) | | (your code) | | | | | | - Device & object database | | WebSocket library | <-----> | - BACnet APDU/NPDU encode/dec | | TLS library | CBs | - BACnet/SC BVLC + state mach. | | Cert bytes on disk | | - Hub connector state machine | | Main loop / Tick | | - Heartbeat + reconnect timing | +-----------------------+ +----------------------------------+
Direction of calls: Stack -> App : Initiate/Disconnect WebSocket, Send raw bytes, Read property values, Read/Write File bytes, Network Port command (DISCARD_CHANGES, GENERATE_CSR_FILE) App -> Stack : Tick(), SetBACnetSCWebSocketStatus(Connected/Disconnected/Error), Receive raw bytes (via callback return)Two consequences flow from this design:
- The stack will tell you to open a connection, but you decide how. Your handler reads a URI string and calls into your WebSocket library. The actual TLS negotiation, certificate selection, and SNI handling are all yours.
- The stack does not “know” a connection succeeded until you tell it via
BACnetStack_SetBACnetSCWebSocketStatus. If you forget this notification, the SC handshake will never start and the node will appear hung.
Contact Chipkin
Section titled “Contact Chipkin”Chipkin has more than 25 years of BACnet experience and has helped hundreds of companies integrate BACnet into their products.
- Phone: 1-866-383-1657
- Web: store.chipkin.com/services/stacks/bacnet-stack
- Email: [email protected]

