NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev
High-throughput BACnet/IP client and server for Dart and Flutter, built on bacnet-stack via FFI with an isolate based, non-blocking engine.
Last release 2 days ago
06 Oct 2026
Too new to tell
only 2 release windows
Nearly every release is documented
notes for 5 of 5 stable releases
3 versions withdrawn
withdrawn after publishing
9 months old
8 releases · first in 2026
One column per month.
Tools: the bacnet command line tool, device descriptions, shared COV subscriptions in PropertyMonitor, fuzzing of the native engine. See *Migrating fr
Tools: the bacnet command line tool, device descriptions, shared COV
subscriptions in PropertyMonitor, fuzzing of the native engine. See
Migrating from 0.7.x in the README.
bacnet (dart run bacnet_plugin:bacnet):
discover, read, write (values typed for the property, or
real:/unsigned:/enum:/... prefixes), objects, describe,
watch and routers, with --json output, --address instead of
Who-Is and --bbmd for foreign device registration.client.describeDevice reads every property of
every object (ReadPropertyMultiple ALL, or Property_List and single
reads for devices without it) into a BacnetDeviceDescription that
stores as JSON and lists its objects in EPICS notation (toEpics).useCovMultiple, on by default), batched to the device's APDU size;
properties the device refuses fall back to SubscribeCOV(Property) and
polling.protocolServicesSupported
(Set<BacnetServiceSupported>, new constants) and
protocolObjectTypesSupported (Set<BacnetObjectType>).unsupportedServices) and ReadPropertyMultiple with ALL, REQUIRED and
OPTIONAL.tool/fuzz_native.dart builds a libFuzzer target of
the engine (client and server handlers, segmentation, files, schedules,
trend logs, backup) with AddressSanitizer and UndefinedBehaviorSanitizer.Schedule_Object_Name
check the UTF-8 of stack memory past the string, with an uninitialized
length (found by the native fuzzer).maxSize of addFile/configureFile
(16 MiB by default) and all files together up to 256 MiB; the content
set by the application is not limited (found by the native fuzzer).BacnetBbmdClient retries a request the UDP socket cannot send at once
(send returns 0 on Windows while the previous datagram is on its way).The published package builds: 0.4.0 lacked the BACnet/SC headers that bacapp.h includes (.pubignore excluded the whole datalink/bsc directory), so the
bacapp.h includes (.pubignore excluded the whole datalink/bsc
directory), so the build hook failed in applications.
tool/check_package.dart now builds the package from the published
files before a release.Alarm subscriptions and server alarm events. See *Migrating from 0.3.x* in the README.
Alarm subscriptions and server alarm events. See Migrating from 0.3.x in the README.
client.subscribeAlarms(deviceId, notificationClass: n) adds the client to the Recipient_List (with
WriteProperty for devices without AddListElement) and returns an
AlarmSubscription with its notifications, eventInformation(),
refresh() and cancel(). BacnetClient.localAddress() returns the
BACnet/IP address of the client. BacnetEventSummary lists its
unacknowledgedTransitions with timeStampOf and stateOf for
acknowledging them.alarmAcknowledgements
(AlarmAcknowledgedEvent) and listElementEvents (ListElementEvent,
e.g. to persist Recipient_List changes).FakeBacnetDevice.unsupportedServices rejects services,
to test the fallbacks of applications.FakeBacnetClient.AlarmAcknowledgedEvent and ListElementEvent are new
subclasses of BacnetEvent; classes implementing BacnetClient need
localAddress().BacnetEventSummary.isUnacknowledged is true when any
transition waits for an acknowledgement (before: only the transition
into the current event state, so an alarm that returned to normal
unacknowledged counted as acknowledged).Alarms and events. See *Migrating from 0.2.x* in the README.
Alarms and events. See Migrating from 0.2.x in the README.
eventNotifications delivers
EventNotificationEvents (confirmed and unconfirmed) with the values of
the event algorithm as the sealed BacnetEventValues
(BacnetOutOfRangeValues, BacnetChangeOfStateValues,
BacnetChangeOfValueValues, BacnetBufferReadyValues,
BacnetChangeOfReliabilityValues and the other algorithms;
BacnetOtherEventValues for the rest). acknowledgeAlarm and
acknowledgeEvent (AcknowledgeAlarm), getEventInformation (follows
More_Events) with BacnetEventSummary, getAlarmSummary with
BacnetAlarmSummary.addListElement/removeListElement and the typed
addListElements/removeListElements, e.g. to add this client to the
Recipient_List of a Notification Class.BacnetDestination, the sealed BacnetRecipient
(BacnetRecipient.device, BacnetRecipient.ip), BacnetDaysOfWeek,
BacnetEventPriorities, BacnetEventTransition, BacnetPropertyState,
and the enumerations BacnetEventType, BacnetNotifyType and
BacnetPropertyStateKind. Typed properties recipientList, priority,
ackRequired, notifyType, eventDetectionEnable,
eventMessageTexts and binaryAlarmValue.addNotificationClass, instances 0..63) and enableEventReporting
for Analog and Binary Inputs and Values (OUT_OF_RANGE and
CHANGE_OF_STATE, faults from Reliability). The server sends event and
acknowledgement notifications to the recipients (unconfirmed and
confirmed, device recipients resolved with Who-Is) and answers
AcknowledgeAlarm, GetEventInformation, GetAlarmSummary and
Add/RemoveListElement.FakeBacnetDevice.addNotificationClass,
FakeBacnetObject.enableEventReporting, reportEvent), acknowledgements,
event information, alarm summaries and list services.EventNotificationEvents instead
of UnconfirmedServiceEvents; BacnetEvent has a new subclass.write and addListElements (client, server and fake) accept an int
for a double property: client.write(id, output, BacnetProperties.analogPresentValue, 35) inferred num and failed with
a TypeError. BacnetWritableProperty.encodeValue converts and checks
values.Dependencies: bacnet-stack 1.7.0-rc4 (security fixes for BVLC header encoding, enclosed data and constructed value decoding); the server object table…
Typed identifiers and values, read coalescing, segmentation and request control. Breaking changes are marked; see Migrating from 0.1.x in the README.
BacnetObjectType, BacnetPropertyId,
BacnetEngineeringUnits, error classes/codes, reasons, services and the
other enumerations are extension types over int. The client, server,
models, events and exceptions use them, so a property id passed as an
object type no longer compiles; .label names a value.BacnetValue with one subclass per BACnet datatype (BacnetReal,
BacnetUnsigned, BacnetEnumerated, BacnetCharacterString,
BacnetObject, BacnetList, ...); no public API returns or accepts
dynamic or Object? values any more:
readProperty (client and server) returns Future<BacnetValue>;
Unsigned and Enumerated are no longer both decoded to int, and NULL
is BacnetNull instead of null. Accessors asDouble, asInt,
asBool, asString, asStatusFlags and asList.readMultiple and DeviceScanner.scanDevice return
Map<BacnetObject, Map<BacnetPropertyId, BacnetPropertyResult>>
(a BacnetValue or a BacnetError per property; valueOf/errorOf)
instead of 'type:instance' → int → dynamic maps, and reject
specifications that request a property twice.writeProperty, BacnetPropertyValue, BacnetServer.setPresentValue,
setProperty, addObject and BacnetPresentValueUpdate take a
BacnetValue; the tag: parameters are removed.
BacnetValue.infer converts untyped input explicitly.BacnetObject is an identifier and the ObjectIdentifier value; its
properties map and the getters based on it are removed.CovNotificationEvent.values is Map<BacnetPropertyId, BacnetValue>
(presentValue, statusFlags); PropertyWriteEvent.value is a
BacnetValue?.PropertyUpdate is sealed: PropertyValueUpdate and
PropertyErrorUpdate (with a BacnetException).TrendLogEntry has a sealed datum (TrendLogValue,
TrendLogStatus, TrendLogFailure, TrendLogTimeChange) and
BacnetStatusFlags? statusFlags instead of value and status.readRange takes a sealed BacnetRange instead of
type/reference/count; ReadRangeType is removed.BacnetError moved next to the values; BacnetBitString,
BacnetDate, BacnetTime are BacnetValues.scanDevice takes background/cancelToken instead of
the ignored endDeviceId.DeviceScanner sends background requests by default (background).UnconfirmedServiceEvent remains for event notifications and requests
that cannot be decoded.async functions (see
Fixed); 50 000 concurrent reads run at 170–196k reads/s (AOT,
loopback) instead of 123–138k.readProperty calls to one device are
merged into ReadPropertyMultiple requests (coalesceReads,
maxCoalescedReads, coalescingWindow); identical reads share one
result, devices without RPM support are detected. 50 000 concurrent
reads need 24× fewer requests and run about 3× faster on loopback.maxSegmentsAccepted (default 32,
0 disables). BacnetStats.segmentedReplies counts them.background: true queues requests behind
interactive ones and limits them to 3/4 of the transaction slots and one
slot less per device.offlineAfterTimeouts consecutive timeouts
requests to a device fail immediately with BacnetDeviceOfflineException
(a BacnetTimeoutException); one request probes it after
offlineRetryInterval (doubling while it stays silent), an I-Am brings
it back. BacnetStats.offlineDevices counts them.BacnetCancelToken cancels reads, writes, ReadRange
and raw requests (BacnetCancelledException); queued requests are
dropped from the worker queue.package:bacnet_plugin/testing.dart with
FakeBacnetClient, FakeBacnetDevice and FakeBacnetObject: in-memory
devices with discovery, real error codes, priority arrays, COV
notifications, trend log records, latency and offline simulation, and a
request log for assertions.BacnetProperty<T>/BacnetWritableProperty<T>
and the BacnetProperties catalogue of standard properties;
client.read/client.write (also on BacnetServer and
FakeBacnetClient) return and accept the Dart type, read-only
properties cannot be written, and get reads readMultiple results.BacnetWeeklySchedule, BacnetTimeValue,
BacnetSpecialEvent, BacnetCalendarEntry, BacnetDateRange,
BacnetWeekNDay, BacnetDateTime, BacnetTimeStamp,
BacnetDeviceObjectPropertyReference, BacnetAddressBinding,
BacnetPriorityArray, BacnetEventTransitionBits and
BacnetLimitEnable convert from and to the values of schedules,
calendars, trend logs and event reporting. Checked against
bacnet-stack's bacserv.IHaveEvent, TextMessageEvent and
PrivateTransferEvent instead of raw UnconfirmedServiceEvents;
sendWhoHas (answered by FakeBacnetDevices too).{"datatype": "real", "value": 21.5}).BacnetBinaryPV and BacnetPolarity.dart run) bursts of tens of thousands of
requests stalled for seconds: the client kept one suspended async call
per request, and the VM deoptimizes each of them separately when the
function's optimized code is invalidated. Request methods now use
callbacks; non-BACnet errors of merged reads fail the reads instead of
escaping as uncaught errors.BacnetDecodeException.…ErrorEvent); the *Response names of 0.0.x are deprecated aliases. Internal request/response classes are no longer exported.
Reworked for high-load client and server deployments. See the migration notes in the README.
master); Dart SDK ^3.11.0; ffi 2.2,
json_annotation 4.12, meta 1.16+, hooks 2.2, code_assets 2.1,
native_toolchain_c 0.19, ffigen 22, build_runner 2.16,
json_serializable 6.14, mocktail 1.0.5, test 1.30+, lints 6.1;
example: go_router 18, provider 6.1.5;
CI actions checkout@v7, setup-dart@v1, flutter-action@v2,
setup-java@v6.hook/build.dart for all
platforms (@Native bindings). The package no longer depends on Flutter
and runs in plain Dart programs. Removed the per-platform CMake, Gradle
and CocoaPods files, which were broken (Android CMake path, iOS/macOS
sources, Linux bundling, Windows-only native code).native/src): portable C (no windows.h,
SEH or setjmp), event buffer instead of FFI callbacks, wake-up socket,
generic confirmed request sender, own BACnet/IP port for POSIX systems
based on getifaddrs (accepts interface names and IPv4 addresses).maxConcurrentRequests,
maxConcurrentRequestsPerDevice, maxQueuedRequests and deadlines;
automatic address binding via targeted Who-Is; ReadPropertyMultiple is
split automatically when the answer exceeds the APDU size; datatype
inference for writes (BacnetValue to force a type).covScanInterval); objects with names, descriptions, units, COV
increments and state texts; setPresentValue, updatePresentValues,
setProperty, readProperty, removeObject, sendIAm.DeviceScanner and PropertyMonitor run requests in parallel;
COV subscriptions are renewed and cancelled, notifications carry values.BacnetClient and BacnetServer share one reference counted stack.BacnetEvent hierarchy (IAmEvent,
CovNotificationEvent, PropertyWriteEvent, UnconfirmedServiceEvent,
LogEvent, ErrorEvent); the *Response names of 0.0.x are deprecated
aliases. Internal request/response classes are no longer exported.tool/generate_constants.dart)
and cover every standard object type, property, error code and service;
existing names are unchanged.lib/src; stricter
lints.address_add_binding only updates
existing entries) and routed devices lost their network address.PropertyMonitor never matched them.BacnetRejectException, BacnetAbortException,
BacnetDeviceNotFoundException, BacnetQueueFullException,
BacnetDecodeException, BacnetEncodeException.BacnetStats, client.stats(), iAmEvents, covEvents,
readRange, getTrendLog (decoded log records), timeSynchronization,
sendConfirmedRaw, removeDeviceBinding, isDeviceBound,
unsubscribeCOV, CallbackLogger.BacnetBitString, BacnetStatusFlags, BacnetDate,
BacnetTime, BacnetValue.BacnetEngineeringUnits, BacnetEventState,
BacnetReliability, BacnetDeviceStatus, BacnetSegmentation,
BacnetAbortReason, BacnetRejectReason, BacnetConfirmedService,
BacnetUnconfirmedService; values lists the known values of each.Removed unit tests execution from CI workflow configuration.
BACnet Client - Full client implementation with support for:
Named Constants - Complete set of BACnet protocol constants:
BacnetObjectType - 25+ object types with human-readable namesBacnetPropertyId - 80+ property identifiersBacnetErrorClass and BacnetErrorCode - Comprehensive error constantsModern Logging:
DeveloperBacnetLogger - Dart DevTools integrationConsoleBacnetLogger - Simple console outputType Safety:
JSON Serialization:
toJson()/fromJson()json_serializableImmutable Models:
BacnetObject - Object representation with propertiesBacnetPropertyReference - Property references for RPMBacnetReadAccessSpecification - RPM request specificationBacnetWriteAccessSpecification - WPM request specificationBacnetPropertyValue - Property values for WPMModel Features:
@immutable annotationscopyWith() methods for updates==, hashCode)BacnetException - Base exceptionBacnetTimeoutException - Request timeoutsBacnetNotInitializedException - Uninitialized operationsBacnetProtocolException - Protocol errors with error codesComplete API Documentation:
Project Documentation:
Linting:
Code Generation:
build_runner integrationffi: ^2.1.4 - Foreign Function Interfacejson_annotation: ^4.9.0 - JSON annotationsmeta: ^1.15.0 - Metadata annotationsplugin_platform_interface: ^2.1.8 - Platform interfacebuild_runner: ^2.4.0 - Code generationjson_serializable: ^6.8.0 - JSON serializationmocktail: ^1.0.0 - Mocking for testsflutter_lints: ^6.0.0 - Linting rulesYour coding agent can read these notes before it upgrades. Set up the MCP server →