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
macOS13 Ventura or newer (Apple Silicon & Intel)
For BACnet/IPNetwork reachability to devices on UDP/47808 (0xBAC0)
For routed/BBMD networksNot supported: the app does not register as a foreign device. Connect to devices by IP address and port

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 target a device IP directly. The app does not register with a BBMD.

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 on another subnet

If devices are on another subnet, Who-Is broadcasts will not reach them, because routers do not forward UDP broadcasts. The app does not register as a BBMD foreign device, so connect to the device by IP address and port, as long as your Mac can route to it.

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

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.

Trend logs and CSV export

Open a Trend Log or Trend Log Multiple object to read its logged records with timestamps, and export them to CSV from the viewer.

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. Connect to a known device IP directly instead.

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.

Export to SCADA

The object browser has an Export to SCADA button (Pro). It writes the objects you browsed as a tag file for Ignition (BACnet driver), Kepware (BACnet/IP driver), a RustRED flow, Voltrus SCADA or generic CSV and JSON. It is in the current source and ships with the next app update after BACnet Explorer 1.2.1.

Step-by-step: Ignition, Kepware, RustRED and Voltrus SCADA. The guides are written for Modbus Poll and each has a BACnet Explorer section.

Support

When reporting a discovery or read issue, attach a packet capture (tcpdump or Wireshark, with IPs redacted) and note the controller vendor, device instance, and whether you're crossing a router/BBMD.