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 | 12 Monterey or newer (Apple Silicon & Intel) |
| For BACnet/IP | Network reachability to devices on UDP/47808 (0xBAC0) |
| For routed/BBMD networks | Reachability 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.
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 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
| 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 |
| Foreign device | BBMD IP, port, lease time (seconds) — for cross-subnet discovery |
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.
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
| 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. 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
- Email: support@voltrus.id
- Product page: /bacnet-explorer/
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.