Skip to main content

BACnet Simulator

The Iotistica BACnet Simulator lets you run realistic BACnet/IP networks without any physical hardware. It exposes virtual devices on UDP port 47808 and responds to standard BACnet services — WhoIs, ReadProperty, and WriteProperty — so any BACnet client (JACE, EBO, Niagara, BACnet Browser, or your own integration code) sees real devices.

The simulator includes a browser-based admin UI for managing devices, configuring object behaviors, and saving full configuration snapshots as profiles.

:::tip Live demo A shared instance is available at http://bacnet-sim-iotistica.canadacentral.azurecontainer.io:47900/ :::


Process Flow

Admin UI / REST API


Device & Object DB (SQLite)


Simulation Engine ──── tick every 5 s ────► compute behavior values
│ │
▼ ▼
BACnet/IP stack (bacpypes3) Live value table (WebSocket)
UDP 47808 │
│ ▼
Responds to: Admin UI live column
• WhoIs / I-Am
• ReadProperty
• WriteProperty (output + value types)

Each simulated device has a unique BACnet Device Instance and appears as a separate device to BACnet clients. Each device contains one or more objects (analog-input, analog-output, etc.), each with a behavior that drives its Present_Value property. The engine ticks every 5 seconds, recomputes all values, and pushes updates to the admin UI over WebSocket.


Devices

Each BACnet device is identified by a globally unique Device Instance (1–4,194,302). The simulator auto-increments this value when you add a new device so you never get a collision.

Iotistica BACnet Simulator main view showing the device list sidebar with 13 devices

Adding a Device

Click + Add in the sidebar. The drawer supports:

  • Name — the BACnet Object_Name for the device
  • Device Instance — auto-filled to the next free ID
  • Description — shown in the object header
  • Vendor Name / Model Name — searchable from the BTL (BACnet Testing Laboratories) product database; search and select a known vendor to get a model dropdown
  • Enabled — disable to remove the device from the BACnet network without deleting it

Add Device drawer with name, instance, vendor/model fields

Device Actions

Each device in the sidebar has three icon buttons:

IconAction
EditOpen the device drawer to change any field
CopyDuplicate the device and all its objects to a new instance ID
DeleteRemove the device and all its objects

Objects

Selecting a device opens its object table. Objects are the BACnet data points inside a device — each has a type, an instance number, a name, a unit, and a behavior.

BACnet Simulator objects table showing live values and behavior tags for BMS-Gateway device

Object Types

TypeWritable via BACnet?Typical use
analog-inputNoSensor readings (temperature, flow, pressure)
analog-outputYesControl outputs (valve position, fan speed)
analog-valueYesSetpoints and calculated values
binary-inputNoStatus flags (run/stop, alarm)
binary-outputYesBinary control commands
binary-valueYesOccupancy flags, boolean setpoints

Adding an Object

Click + Add Object to open the object drawer. Choose the type, assign an instance number, give it a name, select engineering units, and pick a behavior. See Behavior Types below.

Object Actions

ButtonAction
EditReopen the drawer to change any field
CopyDuplicate with instance = max + 1 and name "… Copy"
Set(manual behavior only) Override the live value at runtime
DelRemove the object

Activity Log Panel

A global activity log panel sits at the bottom of the screen and shows events from all devices in a single stream, refreshing every 5 seconds. Each entry is tagged with the device it came from in a green chip.

Log entries are generated by:

  • Objects added, updated, or deleted via the UI or REST API
  • Value changes detected on each 5-second simulation tick (float changes ≥ 0.1, or any boolean flip)
  • BACnet WriteProperty commands received from clients

Entries are colour-coded by severity:

ColourLevelMeaning
BlueINFONormal activity (object added, value updated)
YellowWARNNon-critical issues (object deleted)
RedERRORFailures requiring attention

The panel displays the last 200 entries and auto-scrolls to the newest. Click the chevron in the header (or anywhere on the header bar) to collapse the panel; click again to expand it. Click Clear to wipe the in-memory view without affecting the device configuration.


Behavior Types

A behavior controls how an object's Present_Value changes over time. The simulation engine evaluates each object's behavior on every 5-second tick.

Add Object drawer showing the full behavior type dropdown

constant

Returns a fixed value that never changes. Use it for setpoints, ratings, or static flags that don't need to vary.

ParamDescription
valueThe fixed value to return

Example — a heating setpoint permanently locked at 21 °C:

{ "value": 21 }

manual

Holds a value until you explicitly change it. The Set button in the objects table lets you push a new value at any time without editing the object. Use it for occupancy status, override commands, or any point you want to control by hand during a test.

Example — building occupancy flag, starts as occupied. Flip it to false during a demo to simulate the building going unoccupied and watch your HVAC setpoints shift.

sine

Generates a smooth sinusoidal wave based on the simulator's internal wall-clock time. Ideal for temperatures, solar loads, or any quantity that oscillates over a predictable period.

ParamDescription
baseCentre value
amplitudePeak deviation from centre
period_hoursFull cycle length in hours
phase_hoursTime offset (shift the wave left or right)

Example — outside air temperature that swings between 4 °C (at night) and 20 °C (midday) over a 24-hour day:

{ "base": 12, "amplitude": 8, "period_hours": 24 }

The value is base + amplitude × sin(…), so it peaks at 20 and dips to 4.

noise

Adds uniform random noise around a base value on every tick. Use it to make sensor readings feel realistic — a clean constant value rarely looks like a real sensor.

ParamDescription
baseCentre value
noise± maximum deviation per tick

Example — a supply-air temperature sensor that reads around 13 °C but jitters slightly, as a real sensor would:

{ "base": 13, "noise": 0.4 }

Each tick the value is somewhere between 12.6 and 13.4.

random_walk

Drifts randomly from its current value by at most ±step each tick, clamped between min and max. Produces a more natural-looking time series than noise — good for energy counters or slow-changing analogs.

ParamDescription
valueStarting value
stepMaximum change per tick
min / maxHard clamp boundaries

Example — a chiller's power draw that wanders realistically between 80 kW and 320 kW, starting at 200 kW:

{ "value": 200, "step": 8, "min": 80, "max": 320 }

Unlike noise, the value remembers where it was last tick, so you get a continuous wandering trace rather than independent random samples.

schedule

Returns different values based on the current time of day — the BACnet simulator equivalent of a BACnet Schedule object. Use it to test occupied/unoccupied transitions, HVAC setpoint changes, or lighting control sequences.

ParamDescription
defaultValue returned before the first time block
blocksList of { start: "HH:MM", value } entries, evaluated in order

Example — heating setpoint that drops to 18 °C overnight, rises to 21 °C when the building opens at 07:00, and drops back at 18:00:

{
"default": 18,
"blocks": [
{ "start": "07:00", "value": 21 },
{ "start": "18:00", "value": 18 }
]
}

ramp

Linearly interpolates from one value to another over a fixed duration. With repeat: true it cycles continuously — useful for simulating startup/shutdown sequences, valve strokes, or motor speed ramps.

ParamDescription
fromStarting value
toTarget value
duration_minutesHow long the ramp takes
repeatRestart the ramp after it reaches to

Example — a cooling valve that strokes continuously from fully closed (0 %) to fully open (100 %) and back, taking 30 minutes per stroke:

{ "from": 0, "to": 100, "duration_minutes": 30, "repeat": true }

Use repeat: false to simulate a one-shot startup sequence — the value reaches to and stays there.

fault

Wraps any other behavior and randomly injects fault conditions. Use it to test alarm handling, fault detection logic, or BMS alert escalation without waiting for a real failure.

ParamDescription
base_behaviorThe underlying behavior to run during normal operation
base_paramsParameters for the base behavior
fault_typespike — one out-of-range reading; stuck — value freezes at fault_value; offline — value drops to zero
fault_valueThe value reported during a spike or stuck fault
mtbf_minutesMean time between faults (in minutes)
fault_duration_seconds — How long a stuck or offline fault lasts

Fault types explained:

TypeWhat the sensor reportsHow longReal-world analogy
spikefault_value for one reading (5 s), then back to normalInstantA loose wire causing a momentary bad reading
stuckfault_value for fault_duration_seconds, then back to normalConfigurableA frozen sensor reporting a wrong value continuously
offline0 for fault_duration_seconds, then back to normalConfigurableA sensor that loses power or goes offline

Example — a coil temperature sensor that normally reads ~22 °C, but roughly once per hour produces a single spike reading of 85 °C (simulating a bad wire):

{
"base_behavior": "constant",
"base_params": { "value": 22 },
"fault_type": "spike",
"fault_value": 85,
"mtbf_minutes": 60
}

Example — a flow sensor that normally wanders around 48 L/s, but gets stuck at 0 for 2 minutes roughly every 3 hours (simulating an intermittent sensor dropout):

{
"base_behavior": "noise",
"base_params": { "base": 48, "noise": 1.5 },
"fault_type": "offline",
"fault_value": 0,
"mtbf_minutes": 180,
"fault_duration_seconds": 120
}

Templates

Templates bulk-create a realistic set of objects for common HVAC and building equipment types in one click. Instead of adding a dozen objects by hand, pick a template and the simulator creates them all with sensible names, units, and behaviors pre-configured.

Template picker modal showing 8 built-in HVAC templates

Built-in Templates

TemplateObjectsDescription
Air Handling Unit15Supply/return fans, temps, valves, static pressure, filter alarms
VAV Box8Zone temp, damper position, reheat valve, CO₂, occupancy
Fan Coil Unit7Room temp, cooling/heating valves, fan speeds
Chiller Plant15Dual chillers, condenser tower, CW loop flow and temps
Hot Water Boiler11Dual boilers, HW supply/return temps, pumps, gas flow
BMS / Supervisor6Building occupancy, alarms, energy, outside air conditions
Electric Meter6Active power, energy, voltage, current, power factor
Lighting Controller8Zone dimming levels, overrides, occupancy setpoints

Smart Suggestion

When you click From Template on a device that has a vendor and model set, the simulator matches the vendor/model name against a built-in keyword library and pre-selects the most appropriate template. For example, a Siemens PXC50 auto-selects the AHU template.

Custom Templates

After configuring a device's objects to your liking, click Save as Template to persist it to your browser's local storage. Custom templates appear at the top of the template picker and can be deleted individually.


Profiles

A profile is a snapshot of the entire simulator state — all devices and all their objects. Profiles let you switch between different test scenarios instantly without re-creating devices manually.

The active profile name is shown as a blue tag in the header next to the Iotistica logo. The header toolbar provides three profile actions:

ButtonAction
NewClears all devices and starts a blank canvas. If the current state has unsaved changes, you are prompted to save first.
SaveSaves the current configuration. If a profile is already active, it is overwritten in place immediately. If no profile is active, a dialog prompts for a name and optional description.
OpenOpens the saved-profiles drawer. Click any profile to load it — this replaces the current configuration entirely. The drawer closes automatically after loading.

Creating a Profile

  1. Set up devices and objects on the main canvas.
  2. Click Save in the header.
  3. Enter a Name (required) and an optional Description, then click Save Profile.

The profile captures every device and object as they are at that moment. The name appears as a blue tag in the header.

Overwriting a Profile

While a profile is active (its name is shown in the header), clicking Save overwrites it immediately with no confirmation dialog — the same behaviour as Save in any other application.

Loading a Profile

  1. Click Open in the header.
  2. Select a profile from the list.

This replaces the current device/object configuration entirely — useful for switching between test scenarios (e.g. switching from a chiller plant test to a VAV commissioning setup).

Starting Fresh

Click New to clear all devices and start with an empty canvas. If the current configuration has unsaved changes, you are prompted to save before proceeding. After confirming, all devices and objects are removed and the active profile tag is cleared from the header.


BACnet Read / Write

The simulator responds to standard BACnet/IP services on UDP port 47808.

Reading Values (ReadProperty)

Any BACnet client can issue a ReadProperty request to read the Present_Value of any object. The simulator responds with the current computed value from the most recent tick.

Client → ReadProperty(device=1001, object=analog-input:5, property=present-value)
Simulator → ACK: 11.79 (degrees-celsius)

Device-level properties such as Object_List, Object_Name, Vendor_Name, and Model_Name are also supported.

Writing Values (WriteProperty)

WriteProperty is supported on output and value object types:

WritableNot writable
analog-outputanalog-input
analog-valuebinary-input
binary-output
binary-value

When a write is received, the simulator:

  1. Accepts the value and responds with SimpleAck.
  2. Switches the object's behavior to manual and stores the written value persistently.
  3. The written value survives simulation ticks — it will not be overwritten by a previously configured sine or noise behavior.
Client → WriteProperty(device=1001, object=analog-output:10, property=present-value, value=75.0)
Simulator → SimpleAck

Writing to an input object returns a write-access-denied error, matching real BACnet device behaviour.

Device Discovery (WhoIs / I-Am)

The simulator responds to BACnet WhoIs broadcasts. Each virtual device issues its own I-Am response, so BACnet browsers and controllers discover all devices on the network automatically.