BACnet Explorer
The BACnet Explorer lets you discover BACnet/IP devices on your network, browse their objects and properties, monitor live values, trend data over time, manage alarms, and map BACnet data points to GEM zones.
Open BACnet Explorer
BACnet is a premium integration. Adding a bacnet / bacnet_ip device — and opening the BACnet Explorer — requires the BACnet product in your license. Core drivers are always included, and existing devices keep running if a license later changes. See License.
Prerequisites
A BACnet/IP client device with the driver set to bacnet_ip. Until one exists the
Explorer shows a Create BACnet IP Device button — it opens the device editor over
this page, already set to the right driver, and selects the device it creates, so you
never have to leave for System > Devices. You can create multiple BACnet devices if
needed (for example, to communicate on different network interfaces); additional ones
are added from System > Devices as usual.
Reaching devices across subnets or a VPN
BACnet/IP discovery normally relies on a broadcast Who-Is, which only reaches the local subnet. A device on another subnet, or one reachable only over a VPN / overlay network (netbird, WireGuard, etc.), never receives that broadcast — so it never appears and every command fails with invalid bacnet device id. Binding to a different network interface does not change this; the interface field is only a local bind, not a way to target a remote device.
There are two ways to reach such a device:
- Static Peers (directed Who-Is) — set the Static Peers attribute on the BACnet device (in System > Devices, Connection group) to a comma/space/newline-separated list of device IPs (or
ip:port). The driver sends a directed (unicast) Who-Is to each peer on connect and on every Who-Is interval. The device replies with iAm and is then read/written over unicast like any other — discovered automatically, no need to know its BACnet instance number ahead of time. This is the right choice for a VPN/overlay IP (e.g. a netbird100.xaddress), since unicast UDP traverses the tunnel where broadcast does not. The port defaults to the device's BACnet/IP port when omitted. - BBMD Address — for a true other-subnet network behind a BACnet router, point BBMD Address at a BBMD on the remote subnet to register as a foreign device. Use this when you need to participate in the remote subnet's broadcasts; for a single directly-reachable device, Static Peers is simpler.
When using Static Peers over a VPN, leave the interface bind on auto-detect (0.0.0.0) or set it to the GEM host's own VPN IP — do not bind to a LAN-only interface, or the device's reply can't route back.
Toolbar
The toolbar at the top of the page is shared across all tabs:
| Field | Description |
|---|---|
| GEM Device | Select which BACnet/IP device (GEM driver instance) to use. Lists BACnet / IP and Daikin DZK devices, which answer the same explorer commands. The open icon beside it opens that device's configuration over the page. |
| Network Interface | Select which network interface to bind the BACnet stack to. Shows available interfaces with their IP addresses (e.g., eth0 (192.168.1.50)). |
| Button | Description |
|---|---|
| Set Interface | Saves the selected network interface, reloads the device, and sends a Who-Is broadcast. |
| Clear Interface | Removes the network interface binding (after a confirmation prompt) and reverts the device to auto-detect (0.0.0.0). |
| Refresh | Re-queries the BACnet device for discovered devices and refreshes the explorer tree. |
| Export CSV | Exports the discovered device list (ID, name, model, vendor, address) to a CSV file. |
You must select both a GEM Device and a network interface, then click Set Interface, before BACnet discovery will work. The BACnet stack needs to bind to a specific network interface to send and receive BACnet/IP packets.
Tabs
The page has eight tabs: Explorer, Watch List, Trending, Alarms, Zone Mapping, Network Tools, Diagnostics, and Settings.
Sharing the BACnet port
BACnet/IP uses UDP port 47808, and a host can only receive replies on one socket per port. Every BACnet / IP and Daikin DZK device in GEM bound to the same network interface and port therefore shares one socket:
- Each device still discovers devices with its own Who-Is, keeps its own device list, zones and polling, and receives only its own change-of-value notifications.
- The socket stays open while any device uses it, and closes when the last one disconnects.
- The watchdog rebinds a stuck socket only when none of the devices sharing it has succeeded recently. One device whose controllers are offline cannot reset the socket under another device that is working.
- A device set to a different port, or bound to a different specific network interface, gets a socket of its own. Use that for a separate BACnet/IP network on another port.
The Diagnostics tab's Client Health table shows the socket and the other devices sharing it.
Explorer Tab
The Explorer tab is a split-pane view with a device/object tree on the left and a property browser on the right.
Device Tree (Left Panel)
After discovery, all BACnet devices appear in the tree. Click a device to expand it and load its details. The tree shows:
- Device name, ID, and IP address for each device
- Device info bar showing model, vendor, firmware, object count, and RPM support
- Object groups organized by BACnet object type (analog input, binary output, etc.)
- Object filter to search objects by name or instance number
Objects are loaded in two phases with a live progress bar driven by server-side bacnet_object_progress events:
- Reading object list — fetching the full
object-listarray. - Reading object names — pulling
object_namefor every discovered object.
The driver tries the most efficient path each device supports: a single segmented ReadProperty(object-list), then RPM-paged walks (50 indices per call), then parallel single reads. Devices that fail the whole-array read are remembered so subsequent loads skip straight to the paged path.
If a device silently drops name reads for a range of objects (typically points behind an offline field-bus trunk on a supervisory controller), the name sweep gives up on the remaining names after 25 consecutive timeouts rather than spending an APDU timeout on every object. Affected objects display as type_instance (e.g. analog_input_1401) in the tree; selecting one still reads its live properties on demand.
Property Browser (Right Panel)
Select an object in the tree to view its properties. The property browser shows:
| Column | Description |
|---|---|
| Property | The BACnet property name. |
| ID | The BACnet property identifier number. |
| Value | The current value. Writable properties appear in blue — click to edit inline. |
The units property is shown with a friendly label in parentheses after the raw enum number — for example 64 (degrees fahrenheit) — so you don't have to look up the BACnet EngineeringUnits codes. The number is the value on the wire; the label is resolved server-side from the standard enumeration.
Writable properties: present_value, description, object_name, out_of_service, relinquish_default, cov_increment, notification_class, event_enable, high_limit, low_limit, deadband, and limit_enable. When editing present_value, a priority selector (P1–P16) appears.
To enumerate an object's properties the driver reads the device's Property_List and then batch-reads the values. Property_List only became mandatory at BACnet protocol revision 14, so older controllers reject the read; for those the driver falls back to the standard required-property set for the object type (present value, status flags, units, and so on) instead of showing an empty list.
Toolbar buttons:
| Button | Description |
|---|---|
| Refresh | Re-reads all properties from the device. |
| Watch | Adds the current object to the Watch List for live monitoring. |
| Priority Array | Loads and displays the 16-level BACnet priority array for the object. |
Priority Array
The priority array section shows all 16 priority levels with their current values. The winning (highest active) priority is highlighted in green. For each active priority level, you can click Relinquish to release that priority's command.
Watch List Tab
The Watch List monitors multiple BACnet objects simultaneously by polling their present values at a configurable interval.
Adding Items
Add objects to the watch list by selecting an object in the Explorer tab and clicking Watch in the property browser.
Controls
| Control | Description |
|---|---|
| Start Polling / Stop | Toggles automatic polling of all watch items. |
| Rate | Poll interval: 1s, 2s, 5s, 10s, or 30s. |
| Read All | Performs a single read of all items. |
| Clear | Removes all items and stops polling. |
Watch Table
| Column | Description |
|---|---|
| Name | Object name. |
| Type | BACnet object type. |
| Device | BACnet device ID. |
| Instance | Object instance number. |
| Value | Current present value (flashes yellow on change). |
| Delta | Change from previous reading (green for increase, red for decrease). |
| Updated | Timestamp of last read. |
| COV | Change of Value subscription status. Click to toggle. |
COV Subscriptions
Each watch item has a COV badge. Click OFF to subscribe to Change of Value notifications from the BACnet device (1-hour lifetime). Click COV to unsubscribe. COV provides push-based updates instead of polling, which is more efficient for slowly changing values.
COV support depends on the remote BACnet device. If the device does not support COV for a given object type, the subscription will fail with a warning message.
Trending Tab
The Trending tab charts live BACnet values over time using interactive graphs.
Setup
- Add objects to the Watch List first.
- In the Trending tab, select items from the sidebar by checking their checkboxes.
- Click Start Trending to begin collecting data.
Controls
| Control | Description |
|---|---|
| Start / Stop Trending | Toggles data collection. |
| Rate | Sample interval: 1s, 2s, 5s, or 10s. |
| Type | Chart type: Line or Area. |
| Max Points | Maximum data points per series (100, 200, 500, or 1000). Older points are trimmed. |
| CSV | Exports all trend data to a CSV file. |
| Clear | Stops trending and clears all chart data. |
Statistics Bar
When trending is active, a statistics bar below the chart shows min, max, average, and current values for each series.
Alarms Tab
The Alarms tab queries BACnet alarm summaries and event information from devices.
Controls
| Control | Description |
|---|---|
| Device | Select a discovered BACnet device to query. |
| Load | Queries alarm summary and event information. |
| Filter | Filter alarms: All, Active, or Normal. |
| Auto-Refresh | Toggles periodic re-query (every 30 seconds). |
Alarm Table
Lists alarms with object type, instance, state (color-coded badge), and acknowledgment status. Click an alarm row to select it for acknowledgment.
Alarm states: Normal (green), Fault (red), Offnormal (amber), High Limit, Low Limit, Life Safety Alarm (red, pulsing).
Acknowledging Alarms
After selecting an alarm, an acknowledgment form appears. Enter an optional message and click Acknowledge to send an alarm acknowledgment to the BACnet device.
Events Table
Below the alarms, an events table shows event information including object, event state, event type, and notify type.
Alarm summary and event information support varies by BACnet device. Some devices may not implement these services.
Zone Mapping Tab
The Zone Mapping tab maps BACnet objects to GEM zones for automated monitoring and control.
Mapping a Point
The form reads top to bottom:
- Select an object in the Explorer tab first — the Zone Mapping tab shows the selected object.
- Pick the ① Subsystem and ② Zone the object belongs to. Use + New Zone (enabled once a subsystem is chosen) to create one inline — see Creating a zone inline.
- Choose what it ③ Maps to from the grouped dropdown (Climate / Lighting / Shade / Power / Generic), then set the Direction toggle to Read or Write. Read-only functions (Temperature, Power, Energy) lock the toggle to Read. For anything outside the list, type a name in the custom field — it's prefixed with
bacnet_and normalized to lowercase-with-underscores (e.g., "Fault Code" with direction Read becomesbacnet_fault_code_read). The grey preview shows the exact attribute that will be written. - Optionally click Test Read to fetch the object's live present value through the gateway before committing — the value (or the error) renders inline, so you confirm you picked the right point without leaving the tab.
- Click Map Point.
The BACnet object reference is stored as a zone attribute in the format device_id,object_type,object_instance.
Mode maps from state text
A mode point also needs a map from the object's numbers to mode names: fan_modes for Fan Mode, system_modes for System Mode, occupancy_modes for Occupancy Mode. When the selected object is a multi-state object and Maps to is one of those modes, the mapper reads the object's state_text and shows the map it implies under the attribute preview. For example, Cont, Auto, FanCirculate gives fan_modes: 1=on, 2=auto, 3=circulate. Binary objects work the same way from their inactive and active text (0 and 1).
Each state text is lowercased with underscores, and common vendor spellings become the names the climate controls show buttons for:
| Mode | Names | Accepted spellings (examples) |
|---|---|---|
| Fan | on, auto, circulate | Cont, Continuous, Fan On · Automatic, Cycle · Circ, FanCirculate |
| System | heat, cool, auto, off, emergency_heat | Heating · Cooling, Cold · Automatic, Changeover · Disabled · Emer Heat, Aux Heat |
| Occupancy | occupied, unoccupied, standby | Occ · Unocc · Stby |
Any other text keeps its lowercased form (Dehumidify → dehumidify). It works by name in commands and macros, but no climate control button appears for it. A text that comes out blank, or the same as an earlier state, is skipped and listed in the preview.
- Map Point also writes the map when the zone has none. If the zone already has a different map, you are asked before it is replaced. A matching map is left alone.
- Generate fan_modes (or
system_modes/occupancy_modes) writes only the map, without mapping the point. Use it on zones whose mode points were mapped before this existed: select the zone and the mode object, choose the mode under Maps to, then click it.
The map is an ordinary zone attribute, so you can still edit it on the zone's Attributes tab.
The former Point Type field (a category-tab row plus a read X / write X dropdown) is replaced by Maps to + the Direction toggle. The attribute names written are unchanged, so existing mappings are unaffected.
Creating a zone inline
If the zone doesn't exist yet, click + New Zone under the Zone picker (it activates once a subsystem is selected). Enter a name (lowercase letters, numbers, underscores) and an optional display label, then Create Zone. The new zone is created in the chosen subsystem, assigned to this BACnet device so polling picks it up immediately, and auto-selected.
Copying points from another zone
When rooms share the same controller model, the point map is the same except for the BACnet device id. Use Copy points from to reuse a zone's mapping:
- New zone — the + New Zone form has a Copy points from (optional) picker. When you click Create Zone, the template's points are copied onto the new zone before it loads.
- Existing zone — select the zone, click Copy points from… above the Zone picker, choose a template and click Copy Points. A mapping with the same name on that zone is replaced, and its other mappings are left alone.
The picker lists every zone that has BACnet point mappings, with its point count and the device id they use. Enter the device id the copied points should use. It defaults to the device of the object selected in the Explorer.
Every bacnet_*_read / bacnet_*_write mapping on the template is copied:
- Mappings on the template's device are re-pointed to the new device id, keeping the object type and instance.
- Mappings on any other device, such as a shared outdoor-air sensor, are copied unchanged.
- Each point's
_scalingrow is copied unchanged.
With Also copy … checked, the copy also includes the template's system_modes, fan_modes, occupancy_modes, deadband, priority, min, max and decimal_places. Live values such as temperature or setpoint are never copied. The template zone itself is not changed.
Zone not assigned to this device
A zone is only polled by a BACnet device when the zone — or its subsystem — is assigned to that device. If you select a zone that isn't, an amber notice warns that this device won't poll it. Click Bind to <device> to assign the zone to the current device (a lightweight rebind that doesn't reconnect the device), or map it anyway if you intend to bind it later. Zones created with + New Zone are bound automatically.
Functions
The Maps to dropdown groups functions by category. Each function plus the Read/Write toggle produces the attribute name below:
Climate Points
| Attribute written | Description |
|---|---|
bacnet_setpoint_read | Read setpoint |
bacnet_setpoint_write | Write setpoint |
bacnet_cool_setpoint_read | Read cooling setpoint |
bacnet_cool_setpoint_write | Write cooling setpoint |
bacnet_heat_setpoint_read | Read heating setpoint |
bacnet_heat_setpoint_write | Write heating setpoint |
bacnet_temperature_read | Read temperature sensor |
bacnet_humidity_read | Read humidity sensor |
bacnet_humidity_write | Write humidity value |
bacnet_fan_mode_read | Read fan mode |
bacnet_fan_mode_write | Write fan mode |
bacnet_system_mode_read | Read system mode |
bacnet_system_mode_write | Write system mode |
bacnet_occupancy_mode_read | Read occupancy mode (selects occupancy setpoints) |
bacnet_occupancy_mode_write | Write occupancy mode |
bacnet_occupied_read | Read occupied state |
bacnet_occupied_write | Write occupied state |
bacnet_bypass_override_read | Read bypass override state |
bacnet_bypass_override_write | Write bypass override state |
Decimal places. Analog reads and stored setpoints are rounded to whole numbers by default. Set decimal_places (0–4) on the zone, or on the BACnet device for all its zones, to keep fractions — 1 keeps a 21.5 °C setpoint as 21.5. The value written to the device is never rounded.
Scaling. Most BACnet analogs already report engineering units. A point that reports counts or a raw signal, such as an analog input on a generic I/O module, can be scaled on the Zone Mapping tab: set Scaling to Range and enter the raw, signal and output ranges. For example, a 12-bit 0–5 V input read as 0–100 % turns 3042 into 3042 / 4095 × 5 V = 3.714 V = 74.3 %. The fields, presets and stored shape match the Modbus mapper (see Scaling an analog input). The range is saved as bacnet_<point>_scaling, one row shared by the point's read and write mappings. Reads are scaled before rounding. A setpoint written to a scaled point is converted back to the raw value, and the zone keeps the engineering value. If the scaling sets Decimals, those replace decimal_places for that point. Mode points are never scaled.
Occupancy setpoints. setpoint and get_setpoint with both mode and occupancy use bacnet_<occupancy>_<mode>_setpoint_read / _write (e.g. bacnet_occupied_cool_setpoint_write), and the zone poller keeps those points current for every pair in the zone's system_modes × occupancy_modes. The older spelling bacnet_setpoint_<occupancy>_<mode>_* is still read and written.
Older mode mappings. Zones mapped before this page used the driver's names carry bacnet_fanmode_* / bacnet_systemmode_*. The driver reads and writes those as the fan and system mode points too, so nothing needs remapping; a bacnet_fan_mode_* / bacnet_system_mode_* attribute on the same zone takes precedence.
Custom and unlisted points. Any other bacnet_<point>_read / bacnet_<point>_write mapping (for example a custom bacnet_fault_code_read) is polled each pass and stored on the zone under the bare point name, fault_code. A point mapped both ways is read once, from the read address; a write-only mapping is read from its write address. No <point>_write attribute is created either way. The mode points (system_mode, fan_mode, occupancy_mode) are always read through the zone's mode maps, so their zone attributes hold the mode name, never the raw number.
Lighting, Shade, Power & Generic Points
| Attribute written | Description |
|---|---|
bacnet_level_read | Read level (lighting) |
bacnet_level_write | Write level (lighting) |
bacnet_state_read | Read on/off state |
bacnet_state_write | Write on/off state |
bacnet_position_read | Read position (shades) |
bacnet_position_write | Write position (shades) |
bacnet_power_read | Read power |
bacnet_energy_read | Read energy |
bacnet_generic_read | Generic read |
bacnet_generic_write | Generic write |
Existing Mappings
Below the mapping form, a table shows all existing zone attribute mappings for the currently selected BACnet object. Each mapping can be removed with the delete button.
Bulk point mapping with the AI Assistant
The tab above maps one point at a time, which is the right tool for a handful of objects. A whole floor of VAV boxes is a different shape of job — twenty boxes at six points each is roughly 140 form round-trips, and every device_id,object_type,object_instance triple is a chance to mistype an instance or forget the _write half (the classic cause of "why won't the setpoint change?").
For that, the AI Assistant has a map_bacnet_points skill. Paste a point list from the controller submittal — or from this Explorer's own discovery — and ask it to create the zones:
Map the BACnet points for VAV-101 through VAV-118 on the JACE controller.
It creates (or updates) one zone per box bound to the BACnet device, then writes one attribute per point. What it handles for you:
- Point notation. All of
12345,2,5,2,5,analogValue:5,AV:5,MSV:2,AI 3, a bare instance number, and{device_id, object_type, object_instance}normalize to the numeric triple the driver expects. Object-type names map to the BACnet enum (analogInput=0, analogOutput=1, analogValue=2, binaryInput=3, binaryOutput=4, binaryValue=5, multiStateInput=13, multiStateOutput=14, multiStateValue=19). A sharedbacnet_device_iddefault fills in the device instance when the triples omit it. - The read/write pair. A bare value sets
_read; for setpoint and mode keys it sets_writeas well, since present-value is normally the same object both ways. Pass read and write separately to split them, or mark a point read-only. - Validation before any write. The parent device must be on the
bacnetdriver chain, every triple must parse, and zone names and addresses must not collide — in the batch or against existing zones. A single bad entry cancels the whole call before anything is written, and a mid-batch failure rolls back every created zone and restores every attribute it touched.
Ask for a dry run first whenever the assistant had to interpret a pasted list — it returns the fully-resolved triples per zone and writes nothing, which is exactly what you want to eyeball before committing. Zones are reloaded after mapping, so the driver picks them into its polling map without a restart. Caps are 60 zones per call and 40 points per zone.
Use the Zone Mapping tab for fixing one point on one zone, and this Explorer's discovery (or the driver's get_objects command) to find the objects in the first place — the assistant maps what discovery found, it does not discover.
Network Tools Tab
The Network Tools tab provides BACnet network management commands.
Device Discovery (Who-Is)
Send a Who-Is broadcast to discover devices. Optionally specify a device ID range (low/high) to limit the broadcast. Leave the range empty for a global broadcast — results appear in the Explorer tab.
Device Management
Select a discovered device to view its info card (name, model, vendor, ID, address, firmware).
Time Synchronization
Send the server's current time to a BACnet device. Choose between local time sync and UTC time sync.
Reinitialize Device
Send a coldstart or warmstart reinitialize command to a remote BACnet device. Requires confirmation before sending.
Reinitializing a device will restart it and may cause it to be temporarily unavailable. Use with caution in production environments.
Communication Control
Control whether a remote BACnet device talks on the network. Pick an Action — Enable, Disable, or Disable Initiation (the device stops initiating messages but still responds) — optionally set a Duration (min), and click Send. Set the duration to 0 for indefinite. Requires confirmation.
Disabling communication may make the device unreachable until the duration expires or communication is re-enabled.
Diagnostics Tab
The Diagnostics tab surfaces the BACnet driver's runtime health signals so an integrator can debug write failures, priority lockouts, COV subscription staleness, and transport-level errors without grepping logs.
Summary Cards
Quick-glance counters across the driver state:
- Mapped zones — total BACnet zones currently in memory
- Priority lockouts — zones flagged with
priority_lockout=true(a stronger slot than GEM's write priority is holding at least one point, so GEM's writes to it are ignored) - Zones w/ unsupported points — zones where the driver has marked specific points as priority-unsupported after repeated priority-array read failures
- Recent write failures — count of write errors in the ring buffer (last 20)
- COV subs — active Change-of-Value subscriptions, with a stale count if any have failed renewal 3+ times
- Consecutive op failures — current run of failed reads/writes (the watchdog trips a recycle once this crosses the threshold AND no op has succeeded in ~2 min)
- Client recycles — how many times the underlying BACnet client has been torn down and rebuilt since boot
Client Health
Watchdog state and the last transport-level error message. A non-zero recycle count is informative, not necessarily bad — a single recycle after a transient blip is expected. Sustained recycles point at flapping interfaces or unreachable controllers.
COV Subscriptions
Per-subscription detail: device ID, object, subscribe ID, lifetime (s), seconds since last renewed, and the renewal failure count. Stale rows (3+ failures) highlight in red — the value-on-change stream is dead until you re-subscribe.
Priority Lockouts
Zones where a stronger BACnet priority slot than the one GEM writes at is holding a point, so the device ignores GEM's writes to that point. The Points column names the held points. Investigate by reading the priority array from the Explorer tab.
GEM writes at the zone's priority attribute when it is set to 1–16, otherwise at the device's Default Write Priority (16 unless set). A lower number is a stronger priority. A point is locked out when its strongest occupied slot is a lower number than GEM's; a slot equal to GEM's priority is GEM's own write. Each poll records the result per point as <point>_priority_lockout on the zone, and priority_lockout is set when any point is locked.
Priority-Unsupported Points
Per-(zone, point) entries the driver has given up on after 3 consecutive priority-array read failures. Subsequent writes still go through but skip priority handling. To re-check, clear the <point>_priority_supported attribute on the zone.
In-Memory Priority Failure Counters
A live tally of priority-array read failures per (zone, point) since the driver was last loaded. A count is shown only while it is climbing; once it reaches 3 the point is promoted to the Priority-Unsupported Points list above and the result is persisted on the zone's _priority_supported attribute. Use this table to spot a point that is intermittently failing priority reads before it gets locked out.
Recent Write Failures
Ring buffer of the last 20 write errors with structured diagnostics — device, object, property, ASN.1 tag, JS value type, priority, array index, and the error message. Class:2 Code:9 in the error column means the device rejected the ASN.1 tag — compare the tag column to the value_type to find the mismatch.
Toolbar
- Refresh — re-query the driver
- Auto-refresh — poll every 10 seconds
Settings Tab
The Settings tab shows the current BACnet connection configuration:
- Selected GEM BACnet device (ID, name, driver) — click the device name to open its full configuration in an in-place modal without leaving the Explorer (your device selection and discovery state are preserved)
- Current network interface binding
- Number of discovered devices
This tab also contains descriptions of the GEM Device and Network Interface fields for reference.
Related Documentation
- Devices — Creating the BACnet/IP device
- Zones — Zone configuration
- Attributes — Zone attribute mappings