BACnet (ASHRAE 135) is the standard communication protocol for building-automation systems — HVAC, lighting, access control, and metering. This library is a standalone BACnet stack for .NET: add a NuGet package and talk to BACnet devices from your own code, or expose your application as a BACnet device.
- Transports — BACnet/IP (UDP, IPv4 & IPv6) with BBMD and foreign-device registration; BACnet/Ethernet (pcap); MS/TP and PTP over a serial port
- Client and device (server) roles — send requests and/or answer them from your own object model
- Discovery — Who-Is / I-Am and Who-Has / I-Have, including across routers
- Data access — ReadProperty, WriteProperty, ReadPropertyMultiple, WritePropertyMultiple, ReadRange
- Change of Value — SubscribeCOV / SubscribeProperty and COV notifications
- Alarms & events — event/alarm notifications, alarm summary, and acknowledgement
- More services — object create/delete, atomic file read/write, device-communication-control, reinitialize, time synchronization
- Segmentation of large requests and responses
- Complete ASN.1 encode/decode of the BACnet APDU set, covered by a test suite verified against ASHRAE 135 Annex F
- BACnet
Core stack — pure-managed BACnet/IP, MS/TP & PTP protocol, encode/decode. No native dependencies. - BACnet.Ethernet
pcap-based BACnet/Ethernet (ISO 8802-3) transport (SharpPcap / PacketDotNet). - BACnet.Serial
Physical serial-port transport (System.IO.Ports) for MS/TP and PTP. - BACnet.Logging.CommonLogging
Optional bridge to route the stack's logs toCommon.Logging.
| Package | net48 | netstandard2.0 | net8.0 | net10.0 |
|---|---|---|---|---|
| BACnet (core) | ✅ | ✅ | ✅ | ✅ |
| BACnet.Ethernet | ✅ | — | ✅ | ✅ |
| BACnet.Serial | ✅ | — | ✅ | ✅ |
| BACnet.Logging.CommonLogging | ✅ | ✅ | ✅ | ✅ |
netstandard2.0 covers .NET 6/7 and other runtimes.
dotnet add package BACnet
# optional native transports:
dotnet add package BACnet.Ethernet
dotnet add package BACnet.SerialA minimal Who-Is device discovery over BACnet/IP:
using System.IO.BACnet;
var client = new BacnetClient(new BacnetIpUdpProtocolTransport(0xBAC0));
client.OnIam += (sender, adr, deviceId, maxApdu, seg, vendorId)
=> Console.WriteLine($"Found device {deviceId} at {adr}");
client.Start();
client.WhoIs();
Console.ReadLine();On a host with several network interfaces (e.g. Hyper-V/WSL/Docker virtual adapters), tell the transport which one to bind by passing its IP — otherwise it throws an error listing the candidates:
new BacnetIpUdpProtocolTransport(0xBAC0, localEndpointIp: "192.168.1.50").
The Examples/ folder has runnable samples — basic read/write, a device/server,
COV subscription, alarm/event handling, BBMD, a serial device, and more.
The stack uses Microsoft.Extensions.Logging. By default logging is a no-op; wire a factory once
and everything logs through it:
using Microsoft.Extensions.Logging;
BacnetLogging.Factory = LoggerFactory.Create(b => b.AddConsole());Console, Serilog, NLog, and log4net all work via their MEL providers. If you already use
Common.Logging, add the BACnet.Logging.CommonLogging package and call b.AddCommonLogging().
4.0 has a few breaking changes — see MIGRATION.md for details:
- Logging moved from
Common.LoggingtoMicrosoft.Extensions.Logging(theLogproperty is nowILogger). - Native transports split into optional packages: pcap →
BACnet.Ethernet, serial →BACnet.Serial. The MS/TP and PTP protocols stay in the core; useSerialTransport.Mstp(...)/.Ptp(...)fromBACnet.Serial. - Interface selection is explicit when the host has multiple network interfaces. In that case
BacnetIpUdpProtocolTransportno longer picks one for you —Start()throws and lists the candidates. Pass the interface IP:new BacnetIpUdpProtocolTransport(0xBAC0, localEndpointIp: "192.168.1.50").
Releases are also published to GitHub Packages. To restore from there, add the source
https://nuget.pkg.github.com/ela-compil/index.json (a GitHub PAT with read:packages is required).
The stack was originally developed by Morten Kvistgaard — with significant contributions from F. Chaxel, Steve Karg, and the BACnet Stack (in C) — as part of YABE (Yet Another BACnet Explorer). This repository was forked from the YABE SourceForge SVN and is maintained here by Jakub Bartkowiak and the Ela-compil team as an independent library on NuGet; it is a separate codebase from YABE (YABE keeps its own copy of the stack).
"BACnet" and the BACnet logo are registered trademarks of ASHRAE (the American Society of Heating, Refrigerating and Air-Conditioning Engineers, Inc.). This project is an independent, community-maintained implementation of the BACnet protocol; it is not affiliated with, endorsed by, or sponsored by ASHRAE or BACnet International. The name and logo are used only to identify the protocol this library implements.
