Most techs meet BACnet/SC as a checkbox on a spec and a set of fields nobody has filled in yet: a hub URI, a failover URI, a certificate file. Fill them in wrong and the device just sits there. To fix that with any confidence, you need a working picture of what the device is trying to do.
If you haven't read the BACnet/SC introduction, start there for the why. This article is the how: the parts, the order things happen in, and the messages that go back and forth once a connection is up. None of it changes the BACnet you already know. Objects, properties, priority arrays and COV all work exactly as before. What changes is the datalink underneath them.
wss://) running on TLS 1.3, with both ends of every connection proving who they are with an X.509 certificate.The parts: hub function, hub connector, nodes
BACnet/IP is a party line. Every device on the subnet hears every broadcast, and BBMDs stitch subnets together. BACnet/SC throws that away and replaces it with hub and spoke.
The hub function
A piece of software that accepts connections from nodes and forwards traffic between them. Unicast from node A to node B goes to the hub and out to B. A broadcast goes to the hub and out to every connection it has. The hub function isn't a special box; it runs on some device that has it enabled — a supervisor, a router, a controller or a software package.
The hub connector
The client side that every node has. It makes an outbound connection to the hub. The device hosting the hub function usually also has a hub connector of its own, so it participates in the network like any other node.
Nodes
Anything with an SC datalink: controllers, supervisors, routers, workstations. Each node knows two addresses: the primary hub URI and the failover hub URI. Every node must support both.
The outbound direction matters more than it sounds. Nodes call the hub; the hub never calls the nodes. That means IT only has to allow one TCP port inbound to the hub and one to the failover hub. Nodes can sit behind DHCP, because nobody needs to know their address in advance. No UDP broadcasts, no BBMDs, no foreign device registration.
Primary and failover
A node tries its primary hub. If it can't reach it, it connects to the failover hub. That's the whole redundancy model, and it only works if the failover hub doesn't share a failure with the primary. Put it on a different device, on a different power circuit, behind a different switch. Two hub functions on the same supervisor, or two supervisors on the same UPS and switch, is a failover plan on paper only. The rollout planning article covers placement in detail.
Direct connections
The standard also allows optional direct connections node to node, bypassing the hub, where both ends support it. Think of a supervisor pulling a lot of trend data from one controller. It's optional, it's not universal, and on most sites I'd expect nearly all traffic to go through the hub. Know it exists so the term doesn't throw you on a data sheet.
Addressing: VMAC and Device UUID
There are no IP addresses in BACnet/SC addressing and no MS/TP-style MACs. Each node has two identifiers:
- VMAC — a 6-octet random virtual MAC address. This is the node's address on the SC network, the thing that goes in the source and destination fields of each message.
X'FFFFFFFFFFFF'is the broadcast VMAC. - Device UUID — an RFC 4122 UUID, generated before deployment, persistent, and never changes. It identifies the physical device across reboots and reconnections.
Both are meant to be unique by construction. The place they stop being unique is the field: someone builds one controller, exports the configuration, and loads it into five more. If that copy carries the VMAC or UUID with it, you now have duplicates, and the hub will refuse the second one to arrive. I cover what that looks like in the troubleshooting article. For now: when you clone a config, check that the SC identity was regenerated.
The connection sequence, step by step
This is the part worth memorising, because every SC fault is a failure at one of these steps, and each step fails differently.
1. Resolve the name (if the URI uses one)
The hub URI carries the host and the port, for example wss://10.1.10.5:443/ or wss://hub1.site.local:8443/. There is no standard BACnet/SC port number — the port is whatever is in the URI. 443 is common; some platforms use 8443 or something else. If the host is a name, the node asks DNS first.
2. TCP connection
An ordinary TCP three-way handshake to the hub's address and port. If a firewall drops it, the node sends SYNs that never get answered. If nothing is listening on that port, the hub's machine answers with a reset.
3. TLS 1.3 with mutual authentication
Now the security. The node and hub run a TLS 1.3 handshake, and both present certificates. The hub checks that the node's certificate was signed by a CA it trusts and is in date; the node does the same to the hub. Cipher options include 128- and 256-bit elliptic-curve suites. Either side can refuse, and when it does, the connection closes almost immediately after the handshake starts. This is where expired certificates, wrong CAs and bad clocks show up. The certificates article covers the lifecycle.
4. WebSocket upgrade
Inside the encrypted tunnel, the node sends an HTTP GET with Upgrade: websocket and Sec-WebSocket-Protocol: hub.bsc.bacnet.org. The hub answers 101 Switching Protocols. Direct connections use dc.bsc.bacnet.org instead. A hub rejects a missing or unknown subprotocol, so a generic WebSocket client can't just wander in.
5. Connect-Request / Connect-Accept
Now BACnet itself speaks. The node sends a Connect-Request carrying its VMAC, its Device UUID and the maximum BVLC and NPDU lengths it can handle. The hub answers Connect-Accept with its own, or a BVLC-Result NAK with an error class and code if it won't take the node — a duplicate VMAC, for example.
6. Traffic and heartbeats
From here on, BACnet messages travel as Encapsulated-NPDU. When the connection is idle, the ends exchange Heartbeat-Request and Heartbeat-ACK so each knows the other is still there. The heartbeat timeout is configurable and typically measured in minutes. If a firewall or NAT between them forgets idle connections faster than that, the connection dies silently between heartbeats — a classic “drops every few minutes” fault.
The BVLC-SC messages
Once the WebSocket is up, everything is a BVLC-SC message. There are thirteen function codes. You'll only see them decoded in Wireshark (dissector bscvlc) when you have the TLS keys, but the names show up in device logs and status pages, so it's worth knowing what they are.
| Code | Message | What it's for |
|---|---|---|
| 0 | BVLC-Result | ACK or NAK to a request; a NAK carries an error class and code. |
| 1 | Encapsulated-NPDU | Carries ordinary BACnet traffic — reads, writes, Who-Is, I-Am, COV. |
| 2 | Address-Resolution | Asks a node about itself, used around direct connections. |
| 3 | Address-Resolution-ACK | The answer to Address-Resolution. |
| 4 | Advertisement | Reports hub connection status (none, primary, failover) and whether direct connections are accepted. |
| 5 | Advertisement-Solicitation | Asks a node to send its Advertisement. |
| 6 | Connect-Request | Node asks to join, with its VMAC, UUID and max lengths. |
| 7 | Connect-Accept | Hub (or peer) accepts the connection. |
| 8 | Disconnect-Request | Orderly close requested. |
| 9 | Disconnect-ACK | Close acknowledged (Wireshark labels it Disconnect-Accept). |
| 10 | Heartbeat-Request | “Are you still there?” on an idle connection. |
| 11 | Heartbeat-ACK | “Yes.” |
| 12 | Proprietary-Message | Vendor-specific extensions. |
The Advertisement is the one I find most useful day to day. It tells you, from the node's point of view, whether it's on the primary hub, the failover hub or nothing. If every node on a site is advertising “failover”, your primary hub has a problem, even if the building looks fine from the front end.
How a Who-Is gets anywhere
Discovery still works the way you expect from the BACnet side: a workstation sends Who-Is, devices answer I-Am. The difference is the path.
- The workstation wraps the Who-Is in an Encapsulated-NPDU with the destination VMAC set to broadcast,
X'FFFFFFFFFFFF', and sends it up its one connection to the hub. - The hub function sees the broadcast address and copies the message to every other connection it holds.
- Each device that matches the Who-Is range answers with an I-Am. That reply goes back to the hub addressed to the workstation's VMAC, or as a broadcast, and the hub forwards it on.
So a “broadcast” on SC is really a fan-out done by the hub over individual encrypted connections. There's no UDP broadcast on the wire, no subnet boundary to worry about, and nothing for a BBMD to do. A device that isn't connected to the hub simply doesn't hear it. That's why “it doesn't show up in discovery” on SC almost always means “it isn't connected”, and you go back to the connection sequence.
How legacy BACnet/IP and MS/TP join
BACnet/SC is a datalink, so the normal BACnet network layer still sits on top of it. That means ordinary BACnet routing works. A router with an SC port on one side and a BACnet/IP or MS/TP port on the other joins the two as separate BACnet networks with their own network numbers, exactly like an IP-to-MS/TP router does today.
In practice that's how almost every site will look for years: an SC network across the IP backbone, with routers bringing in MS/TP trunks and pockets of older BACnet/IP devices that don't have SC firmware. Two things to keep straight:
- SC doesn't secure what's behind the router. The MS/TP trunk is exactly as open as it was. The BACnet/IP segment behind an SC router still uses UDP 47808 with no authentication. Segmentation still matters — see segmentation and talking to IT and why BACnet and Modbus have no security.
- Network numbers still have to be unique. The SC network gets its own number. Treat it like any other network when you plan routing.
A device that's been moved to SC but is still sending BACnet/IP broadcasts is a common migration leftover: the SC port is enabled, but so is the old IP port. It'll usually work, which is exactly why nobody notices it until someone looks at a capture.
Where all this lives in the device
Every setting I've mentioned is configured through the SC Network Port object: primary and failover hub URIs, minimum and maximum reconnect times, connect and disconnect wait timeouts, the heartbeat timeout, whether the hub function is enabled, and references to the certificate files. The Network Port object also reports status — whether the hub connector is connected, to which hub, and on many devices a record of failed connection attempts. When you're on a site, that status is often the first thing I read, before any capture. Your front end or the device's own configuration tool will present these differently; the underlying properties are the same.
If you want to see the port numbers side by side with the rest of the building protocols, the BAS Port Reference has them, including why SC's port depends on the URI rather than a fixed number.
What to take away
- Nodes connect out to a hub. One TCP port inbound to each hub, and that's the firewall conversation.
- Six steps: DNS, TCP, TLS with both certificates, WebSocket upgrade, Connect-Request/Accept, then traffic and heartbeats. Every fault sits at one of them.
- VMAC and UUID are the identity. Don't clone them.
- Broadcasts are a hub fan-out, not a UDP broadcast. Not connected means not discovered.
- Legacy networks join through routers, and stay exactly as secure as they were.
Go deeper
BACnet from the wire up, written for the tech on site
Datalinks, network numbers, routing, discovery and the diagnostic method that works across BACnet, Modbus and the rest. BAS Communication is the protocol layer underneath this article.
Get BAS Communication — A Field ReferenceFound a wrong number or a broken link? Tell me and I’ll fix it.