Skip to main content

Connect Coreflux to Building Automation

The BACnet route connects Coreflux to building automation controllers (ASHRAE 135) using the unified OT TAG system. Define the BACnet configuration, add Tags for continuous polling or COV subscriptions, and handle alarm operations.
BACnet is the dominant protocol for building management systems. If your controller supports BACnet/IP, this route maps each data point to an MQTT topic using the same TAG model as every other Coreflux industrial route.

When to use this

Use the BACnet route when you need to integrate HVAC, lighting, metering, or access-control controllers that expose BACnet/IP — read live values on a schedule, subscribe to change notifications, write setpoints from MQTT, receive intrinsic alarms, or run ad-hoc reads and writes triggered by MQTT commands.

Key capabilities

  • BACnet/IP over UDP — standard port 47808 (0xBAC0) with broadcast or direct-IP discovery
  • TAG-based polling — per-point MQTT topics with a configurable polling interval
  • Change-of-Value (COV) — push subscriptions per tag (WITH COV true) without polling
  • Event alarms — BACnet Event-Notifications to MQTT with per-tag or device-wide streams
  • Bidirectional writes — MQTT-triggered writes to analog, binary, and value objects
  • On-demand eventsADD EVENT with READ, WRITE, and ACK queries triggered by any MQTT publish
  • Operator ACK workflow — auto-registered ACK handler per alarming tag
  • Direct IP mode — connect to controllers that do not respond to Who-Is/I-Am
  • Docker and hostname support — resolve container service names before opening the BACnet socket

Quick Start

Pick the starting point that matches what you need. Each tag publishes to {SOURCE_TOPIC}/{tagName} unless the tag sets its own SOURCE_TOPIC.
Connect to a controller and read a room temperature every five seconds:
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH DEVICE_ID 1234
    ADD MAPPING RoomSensors
        WITH SOURCE_TOPIC "bacnet/bms"
        WITH EVERY 5 SECONDS
        ADD TAG RoomTemp
            WITH ADDRESS "AI:0"
            WITH DATA_TYPE "FLOAT"
            WITH UNIT "degC"

Protocol Overview

BACnet (Building Automation and Control networks) is an open protocol for building automation, standardized as ANSI/ASHRAE 135 and ISO 16484-5. It enables interoperability between devices from different manufacturers in HVAC, lighting, fire detection, access control, and energy management.
ConceptDescription
Object modelEvery data point is a typed object (Analog Input, Binary Value, etc.) identified by instance number, accessed by properties (Present Value, High Limit, Event State, …)
Service modelClients read and write properties using BACnet services (ReadProperty, WriteProperty, SubscribeCOV, AcknowledgeAlarm)
Device discoveryWho-Is/I-Am broadcast locates devices by Device Instance without knowing the IP address
Intrinsic alarmingControllers generate Event-Notifications when values cross configured limits — alarm logic lives in the device

BACnet variants

VariantTransportPort / LayerNotes
BACnet/IPUDP/IP47808 (0xBAC0)Most common; fully supported
BACnet MSTPSerial RS-485N/ANot supported
BACnet over EthernetEthernet (Annex H)Not supported
BACnet/SCTLS/WebSocketNot currently implemented
Coreflux supports BACnet/IP (UDP). MS/TP parameters are parsed but the transport is not validated. Use BACnet/IP for all production deployments.

Supported controllers and platforms

CategoryExamples
HVAC controllersSiemens Desigo, Johnson Controls Metasys, Honeywell WEBs, Carrier i-Vu
DDC / field panelsDistech Controls ECB, Alerton Ascent, Delta Controls ORCAview
Meters and sensorsVeris BMeter, Onset HOBO, Accuenergy Acuvim
GatewaysContemporary Controls BASRT-B, Babel Buster (Modbus→BACnet)
SimulatorsIOTech BACnet device simulator (Docker); VTS (Visual Test Shell)
Integration platformsNiagara (Tridium), EBO (Schneider)

Configuration

Only DEVICE_ID is strictly required. For a working route, also set IP and add at least one ADD MAPPING with tags.
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH DEVICE_ID 1234
    ADD MAPPING RoomSensors
        WITH SOURCE_TOPIC "bacnet/bms"
        WITH EVERY 5 SECONDS
        ADD TAG RoomTemp
            WITH ADDRESS "AI:0"
            WITH DATA_TYPE "FLOAT"
            WITH UNIT "degC"

All configuration options

DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH PORT 47808
        WITH LOCAL_PORT 0
        WITH DEVICE_ID 1234
        WITH TIMEOUT 3
        WITH DISCOVERY_TIMEOUT 5
        WITH DIRECT_IP false
        WITH WRITE_PRIORITY 8
        WITH RETRIES 3
        WITH MAX_APDU 1476
        WITH COV_LIFETIME 300
        WITH COV_CONFIRMED false
        WITH LOCAL_DEVICE_ID 4194300
        WITH ALARMS false
        WITH ALARMS_TOPIC "bacnet/bms/alarms"

Configuration parameters

SettingRequiredDefaultDescription
DEVICE_IDYes1Target BACnet device instance (Who-Is/I-Am and ReadProperty)
IP / HOST / ADDRESSConditional192.168.1.1Remote device IPv4 or hostname. Required when WITH DIRECT_IP true; strongly recommended for Docker and routed networks
PORTNo47808Remote device BACnet/IP UDP listen port
LOCAL_PORTNo0Local UDP port the broker binds on this host (0 = OS ephemeral)
TRANSPORTNoIPIP or MSTP (MS/TP not validated — use BACnet/IP)
TIMEOUTNo3Read/write timeout in seconds
DISCOVERY_TIMEOUTNo5Who-Is/I-Am wait in seconds
DIRECT_IPNofalseSkip discovery; connect to IP:PORT and verify with ReadProperty
WRITE_PRIORITYNo8BACnet command priority (1 = highest, 16 = lowest)
RETRIESNo3Retry count on failure
MAX_APDUNo1476Max APDU length (BACnet/IP)
COV_LIFETIMENo300Default COV subscription lifetime in seconds (0 = infinite)
COV_CONFIRMEDNofalseRequest confirmed COV notifications by default
LOCAL_DEVICE_IDConditional0Local device instance for directed I-Am. Required when WITH ALARMS true or any TAG has WITH ALARM true
ALARMSNofalsePublish all device Event-Notifications to ALARMS_TOPIC
ALARMS_TOPICNobacnet/{routeName}/alarmsMQTT topic for device-wide alarms when WITH ALARMS true
ALARM_TOPICNoAlias for ALARMS_TOPIC on BACNET_CONFIG

Network setup: IP, PORT, and LOCAL_PORT

BACnet/IP is UDP. Three settings control two different endpoints — the BACnet device (remote) and the Coreflux broker (local).
SettingSideWhat it isTypical value
IPRemoteIPv4 address or hostname of the BACnet controller192.168.1.10, coreflux-route-bacnet
PORTRemoteUDP port where the device accepts BACnet/IP traffic47808
LOCAL_PORTLocalUDP port the broker binds on before sending/receiving0 (OS-assigned)
ScenarioIPPORTLOCAL_PORT
Sandbox simulator on the same host127.0.0.1478080
Simulator in Docker, broker in another containercoreflux-route-bacnet (docker container name)478080
Device on non-standard port10.0.0.5478090
Firewall requires fixed source port10.0.0.54780847808
WITH IP accepts hostnames and Docker service names (for example coreflux-route-bacnet, host.docker.internal). The broker resolves them to IPv4 before opening the BACnet socket.

Direct IP mode

Use when the controller does not respond to Who-Is/I-Am but accepts ReadProperty at a known UDP endpoint:
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "10.0.0.50"
        WITH PORT 47808
        WITH DEVICE_ID 1234
        WITH DIRECT_IP true

Write priority

Present-value writes use BACnet priority slots (1 = highest, 16 = lowest). If a device holds a value at a higher priority, a write at a lower priority will not override the active present value. The IOTech sandbox profile seeds AO:0 at priority 1 — use WITH WRITE_PRIORITY 1 for that test device.
If a write appears to succeed but the present value does not change, the device may be holding the value at a higher priority. Try WITH WRITE_PRIORITY 1 and check whether a BMS already owns the point.

TAG System

Mapping parameters

    ADD MAPPING RoomSensors
        WITH SOURCE_TOPIC "bacnet/bms"
        WITH EVERY 5 SECONDS
        ADD TAG RoomTemp
            WITH ADDRESS "AI:0"
            WITH DATA_TYPE "FLOAT"
            WITH UNIT "degC"
            WITH WRITABLE false
            WITH COV false
            WITH ALARM false
ParameterRequiredDefaultDescription
SOURCE_TOPICYes*Base MQTT topic; each tag publishes to {SOURCE_TOPIC}/{tagName} unless the tag sets its own
EVERYConditionalPolling interval (e.g. 1 SECONDS, 200 MILLISECONDS). Required when the mapping has polled tags; omit for COV-only mappings
ADD TAGYesAt least one tag per mapping
* You may set SOURCE_TOPIC on each tag instead of on the mapping, but one of the two is required.

Tag parameters

ADD TAG RoomTemp
    WITH ADDRESS "AI:0"
    WITH DATA_TYPE "FLOAT"
    WITH UNIT "degC"
    WITH WRITABLE false
    WITH COV false
    WITH ALARM false
ParameterRequiredDefaultDescription
ADDRESSYesBACnet object TYPE:INSTANCE (e.g. AI:0, AV:3, BI:0)
DATA_TYPEYesBOOL, INT16, UINT16, INT32, UINT32, FLOAT, DOUBLE, STRING
SOURCE_TOPICConditional{mapping SOURCE_TOPIC}/{tagName}MQTT topic for tag data. Required on the tag or on the parent mapping
DESTINATION_TOPICConditionalMQTT topic to subscribe for writes. Required when WITH WRITABLE true
ADDRESS_TYPENoPRESENT_VALUEBACnet property to read/write (e.g. OBJECT_NAME, HIGH_LIMIT)
STRING_SIZENo256Max string length when DATA_TYPE is STRING
WRITABLENofalseAllow MQTT writes to this object
SCALINGNo1.0Multiply raw value
OFFSETNo0.0Add after scaling
UNITNo""Engineering unit label (e.g. degC, %RH)
DECIMAL_PLACESNo2Rounding precision
DEADBANDNo0.0Minimum change before republishing
MIN_VALUE / MAX_VALUENoClamp published values
PUBLISH_MODENoVALUE_ONLYVALUE_ONLY or JSON
DESCRIPTIONNo""Documentation string only
COVNofalseSubscribe to BACnet Change-of-Value instead of polling
COV_LIFETIMENoroute COV_LIFETIMEPer-tag COV subscription lifetime in seconds
COV_CONFIRMEDNoroute COV_CONFIRMEDRequest confirmed COV for this tag
ALARMNofalseEnable MQTT alarm stream on {tag_topic}/alarms
ALARM_TOPICNo{tag_topic}/alarmsOverride alarm MQTT topic (only when WITH ALARM true)

Object address format

ShorthandFull nameExample
AIANALOG_INPUTAI:0
AOANALOG_OUTPUTAO:1
AVANALOG_VALUEAV:0
BIBINARY_INPUTBI:0
BOBINARY_OUTPUTBO:0
BVBINARY_VALUEBV:0
MSVMULTISTATE_VALUEMSV:0
ADDRESS_TYPE is the BACnet property (e.g. PRESENT_VALUE, OBJECT_NAME), not the object type.

Change-of-Value (COV)

Tags with WITH COV true subscribe to BACnet Change-of-Value notifications instead of polling. A mapping with only COV tags does not need WITH EVERY. Mixed mappings poll non-COV tags on EVERY and receive COV tags via push.
COV requires support on the device side. If you receive no change notifications, confirm the controller supports COV and that WITH COV true is set on the tag.

Alarms and Event Notifications

The broker receives BACnet Event-Notification messages from the field device and publishes them to MQTT. Alarm limits and Notification Class membership are configured on the controller — the broker only needs the device to send events to its LOCAL_DEVICE_ID.

Alarm message format

Every time the BACnet device reports an alarm or state change, the broker publishes one JSON object to the alarm topic. Subscribe to that topic to see events as they happen, or subscribe to {alarm_topic}/active for a retained snapshot of alarms that are still open. Example — a room temperature crosses its high limit (bacnet/bms/RoomTemp/alarms):
{
  "route_name": "BMS",
  "device_id": 1234,
  "address": "AI:0",
  "tag_name": "RoomTemp",
  "tag_topic": "bacnet/bms/RoomTemp",
  "alarm_topic": "bacnet/bms/RoomTemp/alarms",
  "object_type": "ANALOG_INPUT",
  "instance": 0,
  "event_type": "EVENT_OUT_OF_RANGE",
  "from_state_short": "NORMAL",
  "to_state_short": "HIGH_LIMIT",
  "fundamental_state": "OFFNORMAL",
  "transition": "TO_OFFNORMAL",
  "event_state_to_ack": "HIGH_LIMIT",
  "ack_required": true,
  "present_value": 28.5,
  "bacnet_timestamp": "2026-06-10T15:28:21.000Z",
  "timestamp": "2026-06-10T16:28:21.003Z"
}
Fields to know:
FieldWhat it tells you
addressWhich BACnet point raised the alarm (e.g. AI:0 = Analog Input 0)
tag_name / tag_topicThe route TAG and MQTT topic for live values on that point
from_state_shortto_state_shortState change just reported (e.g. NORMALHIGH_LIMIT)
transitionDirection of the change: TO_OFFNORMAL (new alarm), TO_NORMAL (cleared), or TO_FAULT
fundamental_stateOverall condition: OFFNORMAL (limit alarm), FAULT, or NORMAL
present_valueValue on the device when the event fired (when provided)
ack_requiredIf true, an operator must acknowledge the alarm on the device
event_state_to_ackState to send when acknowledging — use this in ACK payloads
bacnet_timestampWhen the device recorded the event — include when acknowledging
Common to_state_short values:
ValueMeaning
HIGH_LIMITValue rose above the configured high limit
LOW_LIMITValue fell below the configured low limit
FAULTDevice reported a fault condition
NORMALPoint returned to normal (alarm cleared)

Setting Alarms on BACnet ROUTE

ModeConfigurationDefault MQTT topicCoverage
Device-wideWITH ALARMS true on BACNET_CONFIGbacnet/{routeName}/alarms (+ retained …/active)Every Event-Notification from the device
Per-tagWITH ALARM true on TAG{tag_topic}/alarms (+ retained …/active)Only events matching the TAG’s ADDRESS
Both modes can coexist. When both are enabled for the same object, the event is published to both topics.
Publish every Event-Notification from the device to a single MQTT topic — useful for commissioning and catch-all monitoring:
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH DEVICE_ID 1234
        WITH LOCAL_DEVICE_ID 4194300
        WITH ALARMS true
        WITH ALARMS_TOPIC "bacnet/bms/alarms"
    ADD MAPPING CovPoints
        WITH SOURCE_TOPIC "bacnet/bms"
        ADD TAG CovCounter
            WITH ADDRESS "AV:0"
            WITH DATA_TYPE "FLOAT"
            WITH COV true
Alarm events appear on bacnet/bms/alarms. Operator ACK via bacnet/bms/alarms/ack.
On connect, when alarms are enabled and LOCAL_DEVICE_ID is set, the broker sends a directed I-Am so Notification Class recipients learn the broker’s UDP endpoint.
Set a non-zero WITH LOCAL_DEVICE_ID before enabling alarms. Without it, Event-Notifications are unlikely to arrive because the field device does not know where to send them.

Active alarm list

In addition to live events on {alarm_topic}, the broker maintains a retained snapshot on {alarm_topic}/active. Subscribe here to build an alarm panel — late subscribers receive the current state immediately without waiting for the next transition.
TopicRetainUse for
{alarm_topic}NoLive transitions as they happen (logging, notifications)
{alarm_topic}/activeYesCurrent open alarms (dashboards, alarm panels)
How the list updates:
EventEffect on /active
TO_OFFNORMAL or TO_FAULTAdd or update the entry for that BACnet address
TO_NORMALRemove the entry for that address
Successful ACK on {alarm_topic}/ackRemove the entry matching address + event_state_to_ack
Per-tag lists usually hold 0 or 1 entry (one BACnet object per tag). Device-wide lists hold one entry per alarming object on the device. Example — device-wide active list on bacnet/bms/alarms/active:
{
  "route_name": "BMS",
  "device_id": 1234,
  "alarm_topic": "bacnet/bms/alarms",
  "active_topic": "bacnet/bms/alarms/active",
  "updated_at": "2026-06-16T12:00:00.000Z",
  "count": 2,
  "alarms": [
    {
      "address": "AI:0",
      "tag_name": "RoomTemp",
      "to_state_short": "HIGH_LIMIT",
      "fundamental_state": "OFFNORMAL",
      "transition": "TO_OFFNORMAL",
      "event_state_to_ack": "HIGH_LIMIT",
      "ack_required": true,
      "present_value": 28.5,
      "bacnet_timestamp": "2026-06-10T15:28:21.000Z"
    },
    {
      "address": "AI:2",
      "tag_name": "ChillerPressure",
      "to_state_short": "HIGH_LIMIT",
      "fundamental_state": "OFFNORMAL",
      "transition": "TO_OFFNORMAL",
      "event_state_to_ack": "HIGH_LIMIT",
      "ack_required": false,
      "present_value": 95.2,
      "bacnet_timestamp": "2026-06-10T15:30:05.000Z"
    }
  ]
}
Each object in the alarms array uses the same fields as a single live alarm event. When no alarms are active, count is 0 and alarms is [] — the broker still publishes valid retained JSON.

Acknowledging alarms

When a BACnet device raises an alarm, the broker publishes it to MQTT. To clear or acknowledge it on the device, an operator publishes to the ACK topic. The broker sends AcknowledgeAlarm to the controller and replies with a result. How it works:
  1. Subscribe to the alarm topic (live events) or {alarm_topic}/active (current alarm list).
  2. Publish your acknowledgement to {alarm_topic}/ack.
  3. Check {alarm_topic}/ack/result for success: true or false.
No additional configuration is needed for ACK — the broker registers the handler automatically when you enable device-wide alarms or per-tag WITH ALARM true.
TopicWhat you see
{alarm_topic}Live alarm events as they happen
{alarm_topic}/activeRetained list of alarms that are still active
{alarm_topic}/ackPublish here to acknowledge
{alarm_topic}/ack/resultSuccess or failure of your acknowledgement
Before expecting MQTT alarms, confirm on the BMS or engineering tool:
  1. Notification Class — recipient list includes LOCAL_DEVICE_ID
  2. Intrinsic alarming on each object — NOTIFICATION_CLASS, HIGH_LIMIT / LOW_LIMIT, EVENT_ENABLE, LIMIT_ENABLE
  3. Present value actually crosses a configured limit
COV working does not guarantee alarms — they use separate BACnet services.

On-Demand Events

Use ADD EVENT when you need a single read, write, or alarm acknowledgement triggered by an MQTT publish — instead of continuous TAG polling.
ParameterRequiredDescription
SOURCE_TOPICYesMQTT topic that triggers the BACnet operation
DESTINATION_TOPICYesMQTT topic where the JSON result is published
QUERYYesBACnet operation: READ:…, WRITE:…, ACK:…, or JSON
EVERYNoNot supported on BACnet events — use TAG polling instead

Query formats

StyleExampleNotes
Colon-separated readREAD:AI:0:PRESENT_VALUEShorthand or full type name
Colon-separated writeWRITE:AV:0:PRESENT_VALUE:72.5Value is everything after the property
JSON{"operation":"READ","object_type":"AI","instance":"0","property":"PRESENT_VALUE"}Also supports "operation":"WRITE" with "value"
Topic placeholderREAD:{topic[0]}:0:PRESENT_VALUE{topic[0]} replaced from the matched MQTT topic segment
Dynamic payload{payload}Use the MQTT message body as the query (e.g. WRITE:AV:0:PRESENT_VALUE:21.5)
Supported operations: READ, WRITE, and ACK (alarm acknowledgement).
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH DEVICE_ID 1234
    ADD EVENT ReadProperty
        WITH SOURCE_TOPIC "bacnet/cmd/read"
        WITH DESTINATION_TOPIC "bacnet/cmd/read/result"
        WITH QUERY "READ:AI:0:PRESENT_VALUE"
Publish any message to bacnet/cmd/read and the result appears on bacnet/cmd/read/result:
{
  "success": true,
  "route_name": "BMS",
  "operation": "READ",
  "address": "AI:0",
  "property": "PRESENT_VALUE",
  "value": 22.5,
  "timestamp": "2026-05-31T10:00:00.000Z"
}
The route must be connected before events run. If an event returns "success": false, check that the device is reachable and that the object and property in the query are correct.

When to use what

NeedRecommended approach
Periodic telemetryADD MAPPING + ADD TAG + WITH EVERY
Write from MQTTWITH WRITABLE true + WITH DESTINATION_TOPIC on a tag
Ad-hoc read/write on commandADD EVENT + WITH QUERY
Alarm acknowledgementAuto-registered handler on {tag_topic}/alarms/ack, or custom ADD EVENT

Examples

Reads two analog inputs and one analog value every five seconds:
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH DEVICE_ID 1234
    ADD MAPPING RoomSensors
        WITH SOURCE_TOPIC "bacnet/bms"
        WITH EVERY 5 SECONDS
        ADD TAG RoomTemp
            WITH ADDRESS "AI:0"
            WITH DATA_TYPE "FLOAT"
            WITH UNIT "degC"
        ADD TAG Humidity
            WITH ADDRESS "AI:1"
            WITH DATA_TYPE "FLOAT"
            WITH UNIT "%RH"
        ADD TAG Setpoint
            WITH ADDRESS "AV:0"
            WITH DATA_TYPE "FLOAT"
            WITH UNIT "degC"
Publishes to bacnet/bms/RoomTemp22.5, bacnet/bms/Humidity55.0, bacnet/bms/Setpoint21.0.

Combining with Models and Actions

A BACnet route publishes each point to its own MQTT topic, so the rest of LoT can use that data like any other topic.
First, the route publishes each point under bacnet/bms:
DEFINE ROUTE BMS WITH TYPE BACNET
    ADD BACNET_CONFIG
        WITH IP "192.168.1.10"
        WITH DEVICE_ID 1234
    ADD MAPPING RoomSensors
        WITH SOURCE_TOPIC "bacnet/bms"
        WITH EVERY 5 SECONDS
        ADD TAG RoomTemp
            WITH ADDRESS "AI:0"
            WITH DATA_TYPE "FLOAT"
        ADD TAG Humidity
            WITH ADDRESS "AI:1"
            WITH DATA_TYPE "FLOAT"
        ADD TAG Setpoint
            WITH ADDRESS "AV:0"
            WITH DATA_TYPE "FLOAT"
Then the model aggregates those topics into one object on bacnet/bms/Info:
DEFINE MODEL BacnetRoomSensors COLLAPSED WITH TOPIC "bacnet/bms/Info"
    ADD DOUBLE "RoomTemp" WITH TOPIC "bacnet/bms/RoomTemp" AS TRIGGER
    ADD DOUBLE "Humidity" WITH TOPIC "bacnet/bms/Humidity"
    ADD DOUBLE "Setpoint" WITH TOPIC "bacnet/bms/Setpoint"
    ADD STRING "TimeStamp" WITH TIMESTAMP "ISO"

Best Practices

The default 192.168.1.1 is rarely correct. On Docker or routed networks, broadcast Who-Is may never reach the device. Set WITH IP to the controller’s address or hostname.
If a device does not answer Who-Is/I-Am, set WITH DIRECT_IP true to connect to IP:PORT and verify with ReadProperty. Otherwise the route waits on discovery timeout every connect.
Polling at one-second intervals wastes bandwidth on BACnet/IP. Use WITH COV true for occupancy sensors, fast process variables, and alarm-related points.
The broker must announce itself as a BACnet device via directed I-Am so the field device knows where to send Event-Notifications.
If a BMS holds a point at priority 1, a write at priority 8 will not change the present value. Match priority to your application and verify on the device.
COV-only mappings do not need a polling interval. Adding WITH EVERY on a COV-only mapping adds confusion without benefit.
Per-tag alarms (WITH ALARM true) give each monitoring point its own ACK topic. Use device-wide (WITH ALARMS true) as a catch-all or for commissioning.
Include event_state_to_ack and bacnet_timestamp from the received alarm message. Wrong state or missing timestamp causes ACK to fail.

Troubleshooting

Connection check

Publish -checkRouteConnection BMS to $SYS/Coreflux/Command. The broker returns a JSON status for the named route indicating whether the BACnet device was reached.
SymptomCheckSolution
Route never connectsIP and DEVICE_ID correct?Verify device IP; use Wireshark to confirm Who-Is packet sent
Device not discoveredDevice answers broadcast Who-Is?Set WITH DIRECT_IP true if the device does not respond to Who-Is
Docker: route cannot reach deviceWITH IP "127.0.0.1" in Docker?Use the container hostname (e.g. coreflux-route-bacnet)
Discovery timeout on every connectDISCOVERY_TIMEOUT too low?Increase to 10+ seconds for slow devices
SymptomCheckSolution
No MQTT valuesDEVICE_ID match device?Sandbox default is 1234 — confirm with device profile
Wrong object valueInstance number correct?Verify object index in device BACnet browser or profile
Write has no effectPriority conflict?Try WITH WRITE_PRIORITY 1; check if BMS holds a higher priority
COV notifications not arrivingDevice supports COV?Check device profile; simulator may require --cov flag
SymptomCheckSolution
No MQTT alarms (COV works)LOCAL_DEVICE_ID set?Add non-zero LOCAL_DEVICE_ID; verify device Notification Class recipient
Alarms on wrong topicSOURCE_TOPIC or ALARM_TOPIC misconfigured?Default is {SOURCE_TOPIC}/{tagName}/alarms
ACK returns success: falseWrong event_state_to_ack?Echo the received alarm JSON with ack_text field added
Events only after reconnectDirected I-Am not sent?Ensure LOCAL_DEVICE_ID is set and alarms are enabled before first connect
SymptomSolution
PORT vs LOCAL_PORT confusionPORT is the device’s listen port (47808). LOCAL_PORT is the broker’s bind port (leave 0)
Event returns success: falseRoute not connected, or wrong object/property in QUERY; check broker logs
LOCAL_DEVICE_ID is 0 warningSet a non-zero device instance unique on the BACnet network

Additional resources


Next Steps

Industrial Overview

Learn the patterns shared across all OT routes.

OPC UA

Connect to cross-platform industrial servers with OPC UA.
Last modified on July 3, 2026