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
- Direct purchase: buy direct ($29.99 one-time): you receive a download link by email
- Product page: /bacnet-explorer/
System Requirements
| Requirement | Minimum |
|---|---|
| macOS | 13 Ventura or newer (Apple Silicon & Intel) |
| For BACnet/IP | Network reachability to devices on UDP/47808 (0xBAC0) |
| For routed/BBMD networks | Not 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.
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.
- Open the app and click Discover (or press
⌘D). - Leave the destination as the local broadcast (
255.255.255.255) and port47808. - Set the device-instance range to scan (default 0–4194303, or narrow it to 0–1000 for a typical site).
- Click Send Who-Is. Every reachable device replies with an I-Am carrying its instance number, vendor ID, and segmentation support.
- 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
- 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.).
- Expand an object (e.g.
analog-input 1) to see its properties:present-value,object-name,description,units,out-of-service. - The
present-valueis 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
- Find a writable object, typically an analog-output or binary-output (a setpoint, a damper command).
- Check
out-of-servicefirst. To command a value from the network, the point must betrue(out of service / release from local control). Writingpresent-valuewhile in-service is rejected by most controllers. - Set
out-of-servicetotrue, then write the targetpresent-value. - Restore
out-of-servicetofalseto 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
| Mode | Parameters |
|---|---|
| Local broadcast | Destination 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 Type | Code | Typical Use |
|---|---|---|
| analog-input | 0 | Sensor reading: temperature, humidity, pressure |
| analog-output | 1 | Commanded analog value: setpoint, actuator position |
| analog-value | 2 | Calculated/stored value: setpoint that isn't a physical output |
| binary-input | 3 | Discrete state: fan status, door contact |
| binary-output | 4 | Discrete command: on/off relay, enable |
| multi-state-value | 14 | Enumerated state: occupied/unoccupied/standby, 4-pipe mode |
| device | 8 | The controller itself: holds the object list and device info |
Key Properties You Will Read
| Property | Why It Matters |
|---|---|
| object-identifier | Type + instance: the unique handle for ReadPropertyMultiple |
| present-value | The live process value (the one you trend and command) |
| description / object-name | Human-readable label: the only way to map AI 1 to "Zone Temp 3" |
| units | Engineering units: degrees-celsius, percent-relative-humidity, pascals |
| out-of-service | Whether the point is network-commandable (true) or under local control (false) |
| relinquish-default | The value the output returns to when all writes are released |
| cov-increment | The 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
| Code | Name | Likely Cause |
|---|---|---|
| Reject 02 | Parameter out of range | Object instance or property ID doesn't exist on that device |
| Reject 03 | Too many arguments | ReadPropertyMultiple batch exceeds the device's segmentation limit: send smaller batches |
| Reject 05 | Missing required parameter | Malformed request: usually a bug in the object-identifier encoding |
| Abort 00 | Other | Device couldn't process the PDU: often an oversized unsegmented response |
| Abort 02 | Buffer overflow | Response too large; device can't segment. Reduce the batch size or poll one property at a time |
| Abort 05 | Timeout | Device 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
- Email: [email protected]
- Product page: /bacnet-explorer/
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.