BACnet Explorer Documentation

Installation

MacTools BACnet Explorer is a native macOS app built with Rust and Tauri. It runs natively on Apple Silicon and Intel Macs — no Rosetta, no Parallels, no Wine, no Java. One-time purchase, no subscription.

Download

System Requirements

RequirementMinimum
macOS12 Monterey or newer (Apple Silicon & Intel)
For BACnet/IPNetwork reachability to devices on UDP/47808 (0xBAC0)
For routed/BBMD networksReachability to the BBMD, plus its UDP/47808 unreachable-port registration

First Launch

If you downloaded the direct build outside the App Store, macOS Gatekeeper may block the unsigned binary on first run. Right-click the app, choose Open, then confirm. This is only required once.

BACnet/IP uses UDP, not TCP. Discovery (Who-Is) is a broadcast on UDP/47808. If your Mac is on a different VLAN from the devices, broadcast discovery will fail and you must register with the site's BBMD or target a device IP directly.

Quick Start

1. Discover devices on the local subnet (2 minutes)

This is the most common path — finding BACnet/IP controllers, VAV boxes, and AHUs on the same LAN as your Mac.

  1. Open the app and click Discover (or press ⌘D).
  2. Leave the destination as the local broadcast (255.255.255.255) and port 47808.
  3. Set the device-instance range to scan (default 0–4194303, or narrow it to 0–1000 for a typical site).
  4. Click Send Who-Is. Every reachable device replies with an I-Am carrying its instance number, vendor ID, and segmentation support.
  5. Click a device in the list to open its object tree.

If no devices appear, jump to Troubleshooting — the most frequent cause is being on a different subnet than the BACnet devices, where broadcasts don't propagate.

2. Browse and read an object's properties

  1. Select a discovered device to read its Device Object — this lists every object the controller exposes (analog-input, analog-value, binary-output, multi-state-value, etc.).
  2. Expand an object (e.g. analog-input 1) to see its properties: present-value, object-name, description, units, out-of-service.
  3. The present-value is polled live. For analog objects the engineering-unit reading (°C, %RH, kPa) is shown next to the raw value.

3. Write a value to a controllable object

  1. Find a writable object — typically an analog-output or binary-output (a setpoint, a damper command).
  2. Check out-of-service first. To command a value from the network, the point must be true (out of service / release from local control). Writing present-value while in-service is rejected by most controllers.
  3. Set out-of-service to true, then write the target present-value.
  4. Restore out-of-service to false to hand control back to the controller's sequence of operation.

4. Target a device behind a router / BBMD

If devices are on another subnet, register your Mac as a foreign device with the site's BBMD. Enter the BBMD IP, port 47808, and a lease time (e.g. 300 s). The app then sends Who-Is as a directed broadcast that the BBMD forwards, and forwards I-Am replies back to you.

Configuration

Discovery Targets

ModeParameters
Local broadcastDestination 255.255.255.255, UDP/47808, instance range low/high
Directed (unicast)Specific device IP + port, instance range — use when broadcast is blocked
Foreign deviceBBMD IP, port, lease time (seconds) — for cross-subnet discovery

Object Types

Object TypeCodeTypical Use
analog-input0Sensor reading — temperature, humidity, pressure
analog-output1Commanded analog value — setpoint, actuator position
analog-value2Calculated/stored value — setpoint that isn't a physical output
binary-input3Discrete state — fan status, door contact
binary-output4Discrete command — on/off relay, enable
multi-state-value14Enumerated state — occupied/unoccupied/standby, 4-pipe mode
device8The controller itself — holds the object list and device info

Key Properties You Will Read

PropertyWhy It Matters
object-identifierType + instance — the unique handle for ReadPropertyMultiple
present-valueThe live process value (the one you trend and command)
description / object-nameHuman-readable label — the only way to map AI 1 to "Zone Temp 3"
unitsEngineering units — degrees-celsius, percent-relative-humidity, pascals
out-of-serviceWhether the point is network-commandable (true) or under local control (false)
relinquish-defaultThe value the output returns to when all writes are released
cov-incrementThe deadband for COV (Change of Value) notifications

Read Strategies

The app prefers ReadPropertyMultiple (one request, many properties) which is far more efficient on a busy network than single-property reads. If a device reports segmentation = segmented-both in its I-Am, large responses are split across multiple UDP frames automatically. Devices reporting no-segmentation force smaller read batches.

Polling & COV

Two ways to stay live: polled (re-read present-value on an interval, 1–10 s is typical for BACnet) or COV subscriptions (the device pushes a notification only when the value changes by more than the cov-increment). COV is lighter on the network but requires the device to support SubscribeCOV, and many older controllers don't.

Key Features

Full object tree browsing

The Device Object's object-list is read once and cached, then every object's properties are fetched lazily as you expand. You see the same hierarchy a BAS workstation uses — not a flat address dump.

Who-Is / I-Am with vendor decoding

I-Am replies include a vendor ID. The app decodes the common ones (8 = Tridium, 15 = Delta, 24 = Honeywell, 85 = Distech, 96 = Schneider/TAC, 165 = Reliable, 367 = KMC) so you know whose controller you're looking at before you open it.

ReadPropertyMultiple for fast polling

One round-trip reads present-value, units, description, and out-of-service for an entire object set. On a site with 500 points, this is the difference between a 2-second refresh and a 30-second crawl.

COV subscription monitoring

Subscribe to a point and the device notifies on change. The app maps confirmed-COV-notifications back to the object row so you watch a live trend without hammering the network with polls.

Foreign device & BBMD support

Register as a foreign device with a BBMD to cross subnets — essential on segmented corporate/building networks where the controller VLAN is not your Mac's VLAN.

Property-level traffic log

Every BACnet PDU is decoded: service choice (Who-Is, ReadProperty, WriteProperty, etc.), invoke-ID, object reference, and the value/abort. Filter by invoke-ID to trace a single round-trip, or by service to find the device that keeps rejecting writes.

Troubleshooting

Who-Is returns no devices

Symptom: Discovery completes immediately with an empty device list.
Fix: Broadcast discovery only reaches the local subnet. Confirm your Mac is on the same VLAN as the controllers. From Terminal:

sudo tcpdump -i en0 udp port 47808 -n

Send a Who-Is from the app. If you see the outgoing Who-Is broadcast but no I-Am replies, you are on the wrong subnet or a firewall drops the replies. Switch to a directed unicast to a known device IP, or register with the BBMD.

BACnet reject and abort codes

CodeNameLikely Cause
Reject 02Parameter out of rangeObject instance or property ID doesn't exist on that device
Reject 03Too many argumentsReadPropertyMultiple batch exceeds the device's segmentation limit — send smaller batches
Reject 05Missing required parameterMalformed request — usually a bug in the object-identifier encoding
Abort 00OtherDevice couldn't process the PDU — often an oversized unsegmented response
Abort 02Buffer overflowResponse too large; device can't segment. Reduce the batch size or poll one property at a time
Abort 05TimeoutDevice took too long to assemble the response

WriteProperty rejected / value doesn't change

Symptom: You write present-value, no error, but the reading doesn't change.
Fix: The point is almost certainly in service (out-of-service = false), so the controller's local logic is overriding your write. Set out-of-service to true, re-send the write, and confirm the output. Also check the priority-array — a write at priority 16 (minimum) is overridden by any higher-priority entry (8 = manual operator, 5 = hardware). Write at a higher priority or relinquish the lower ones.

Duplicate device instances

Symptom: Two devices answer to the same instance number, I-Am replies interleave.
Fix: A BACnet network must have unique device instances. The two controllers were commissioned with the same default (often 1, 2, or the MAC address). Re-address one of them in its engineering tool. The app's traffic log shows both source IPs replying to the same instance — that's your clue.

ReadPropertyMultiple returns Abort (buffer overflow)

Symptom: A batch read aborts with reason "buffer-overflow" on older controllers.
Fix: The device can't segment large responses (segmentation = no-segmentation in its I-Am). Drop the batch size to 5–10 properties, or fall back to single ReadProperty requests for that device. The app auto-detects segmentation support and throttles accordingly, but some devices misreport it.

Foreign device registration expires

Symptom: Cross-subnet discovery works for 5 minutes, then devices disappear.
Fix: Your BBMD lease expired. The lease must be renewed before it lapses, or the BBMD stops forwarding. Use a longer lease (e.g. 600–3600 s) and let the app keep the registration alive in the background. Re-register manually if the Mac slept — sleep drops the socket and the lease lapses.

Support

When reporting a discovery or read issue, attach the traffic log (exported as JSON or CSV, with IPs redacted) and note the controller vendor, device instance, and whether you're crossing a router/BBMD.