"We are logging the BACnet data" is a sentence that can describe three completely different arrangements, with different data quality, different failure modes and different recovery behaviour after an outage. The difference rarely surfaces during a project and always surfaces later, usually as a question about why a chart has a gap on a day when the building was definitely running.
The message up front: decide deliberately between polling the present value, subscribing to changes, and reading the controller's own trend log objects, because they are not interchangeable. Polling gives you an even series with coarse resolution and no memory of what happened between samples. Subscription gives you every change and nothing when the link drops. Trend log objects give you the controller's own record, including what it captured while you were disconnected, which is the only one of the three that survives an outage. Most robust integrations use a combination, and the combination should be a design decision rather than whatever the gateway defaulted to.
1. The three collection mechanisms
All three sit on top of the object model described in BACnet objects, device instances and addressing, and all three are asking the same devices about the same points. What differs is who initiates, and where the data waits.
| Mechanism | How it works | What you get | What it loses |
|---|---|---|---|
| Polling the present value | Your collector asks each point for its current value on a timer | An evenly spaced series, easy to reason about, works on any device | Everything between samples. A value that spiked and returned inside one interval never existed as far as your data is concerned |
| Change-of-value subscription | You register an interest and the device reports when the value moves by more than a defined increment | Every meaningful change, far less network traffic on slow-moving points | Everything during a dropout, because nobody was storing it. Also needs renewal, covered in COV subscription recovery |
| Reading trend log objects | The controller records samples into its own buffer; you read the buffer periodically and take what is new | The controller's own record, including the period while you were disconnected. Timestamps from the device | Nothing, until the buffer wraps. Limited by buffer size, and not every device implements it well |
The third is the one most often unused and most often the right answer for anything that matters, because it is the only mechanism with memory. A controller logging to its own buffer keeps recording through a network outage, and a collector that reads the buffer afterwards recovers the gap. Polling and subscription both simply have a hole.
2. Trend log objects, and their one hard limit
A trend log object is a point's own recorder inside the controller. It has a configured sampling behaviour, a buffer of a fixed size, and a defined response when the buffer fills: either stop logging, or wrap and overwrite the oldest samples.
That choice matters more than it looks:
- Stop when full preserves the oldest data and silently stops recording new data. You notice because the series ends.
- Wrap when full keeps recording and silently discards the oldest. You do not notice at all, because the series looks continuous; it just does not go back as far as you thought.
Wrapping is the usual default and the usual source of quiet data loss, because the buffer depth sets a hard ceiling on how long an outage you can recover from. A buffer that holds a few hours of samples recovers a few hours. Everybody assumes it is longer.
The practical questions to put to whoever configures the controllers: what is the buffer size per trend log, what is the sampling interval, what is the full behaviour, and therefore how many hours of history does each log actually hold. Record the answers in the integration documentation, because they are the specification for how much outage your data survives.
Read the trend log more often than the buffer takes to fill
The single rule that makes trend log collection reliable: your collection interval must be comfortably shorter than the time it takes the buffer to wrap, with margin for the longest outage you expect to tolerate. If a log wraps in six hours and you read it daily, you are discarding most of the data every day and will not notice, because what arrives is still a plausible series. Work out the wrap time per log from buffer size and sampling interval, set the read frequency from that, and check it again whenever anybody changes a sampling rate. This is also why the sampling-interval decisions in BACnet polling schedules are not purely a network-load question.
3. Which mechanism for which point
A sensible default pattern, assuming the devices support all three:
- Anything feeding analytics, energy reporting or a maintenance trigger: trend log objects. These need continuity more than they need freshness, and continuity is what the buffer provides.
- Anything driving a live display: polling. Freshness matters, history does not, and a simple even series is easiest to render.
- Alarms and binary state changes: subscription. You want the transition at the moment it happens, and transitions are rare enough that subscription is efficient.
- Slow-moving analogue values on a loaded trunk: subscription with a sensible increment. Polling a thousand points every few seconds to watch them not change is the most common way to overload an MS/TP trunk.
- Counters and meter registers: trend logs, and never averaged on the way in. The reasons are in energy meter reset and rollover.
Mixing mechanisms is normal and worth documenting per point, because the mechanism determines how to interpret a gap. A gap in a polled series means the collector was down. A gap in a trend log series means the controller was down, or the buffer wrapped, which are different problems with different owners.
4. What to store alongside the value
A reading on its own is nearly useless eighteen months later. The fields that make it interpretable:
| Field | Why it matters later |
|---|---|
| Point identity, structurally | Device instance plus object type plus instance. Names change; this does not |
| Event time and ingestion time | Two separate columns. Conflating them is the subject of BACnet timestamp and clock synchronisation |
| Collection mechanism | Determines how to read a gap, and whether the series is evenly spaced |
| Engineering units as reported | Not as assumed. Units are a property of the object and should be captured, not inferred |
| Status and reliability flags | Whether the device believed its own reading. Almost always discarded, and the cheapest quality signal available |
| Out-of-service flag | A simulated value looks exactly like a measured one without it |
| Whether the row is raw or derived | So a downsampled average is never mistaken for a reading |
Status, reliability and out-of-service are the three most commonly dropped and the three that distinguish a data platform you can trust from one that confidently serves fiction. They cost a few bytes per row.
5. Where the data should land
Three plausible destinations, and the mistake is to let it land in all three by accident.
- The supervisory platform's own database. Convenient, usually adequate for operational lookback, rarely sized or structured for analysis, and tied to the platform's lifecycle. Replacing the head end then becomes a data migration as well as a software project.
- A dedicated time-series store or historian. The right home for anything feeding analysis. What one is and when it earns its place is covered in what is a BMS data historian, and the comparison against relying on controller buffers alone is in BMS trend logs versus external historians.
- A general data platform alongside other operational data, which suits organisations already running one. Patterns in data lakes and lakehouses for maintenance telemetry.
Whichever you choose, decide which copy is authoritative and write it down. Two stores holding the same points with different collection mechanisms will disagree, and the disagreement will be discovered by someone building a report who then trusts whichever answer they found first.
6. The failure modes to design against
- Silent buffer wrap. Covered above, and the most common. Detect it by checking that the oldest sample in each read is contiguous with the newest sample of the previous read; a jump means you lost the middle.
- Duplicate delivery on reconnection. A collector that re-reads a buffer without tracking its position will reinsert samples it already has. Handle it with an idempotent key on point plus event time rather than by hoping.
- Out-of-order arrival. Buffered data arriving after an outage carries old timestamps and will arrive after newer live data. A store that assumes monotonic arrival will either reject it or corrupt the series.
- Lapsed subscriptions. A subscription that stops being renewed produces a connection that looks healthy and delivers nothing. Detection belongs with the staleness checks in the connectivity loss playbook.
- Overloaded trunk. Collection that is too aggressive produces intermittent read failures which look like device faults.
- Collector restart amnesia. A collector that does not persist its read position will either re-read everything or skip to now, depending on how it was written. Both are bad and neither announces itself.
What is not covered here, and what governs instead
No buffer sizes, sampling intervals, COV increments or read frequencies are given, because they depend on your point count, trunk topology, device capability and what the data is for. Take them from the device documentation and the network design. Device capability in particular varies widely: not every controller implements trend log objects usefully, and the protocol implementation conformance statement for each device type is the authority on what is actually available. My own domain is the data model, the collection design and how this lands in maintenance and analytics systems rather than controls engineering, so the configuration of the controllers themselves is a conversation with whoever maintains them.
7. What to specify and what to ask for at handover
- The collection mechanism per point, recorded in the points map, not left to the gateway's default.
- Trend log configuration per logged point: buffer size, sampling behaviour, interval and full behaviour, with the resulting wrap time calculated.
- The collector's read frequency per log, with the margin against wrap time stated.
- Evidence of outage recovery: disconnect the collector for a period during commissioning, reconnect, and demonstrate that the gap filled in with device timestamps intact. This is a ten-minute test that proves the whole design and is almost never requested.
- Evidence of duplicate handling: force a re-read and confirm no duplicate rows appear.
- The protocol implementation conformance statement for each device type, so capability claims are documented rather than assumed.
These belong in the wider acceptance set described in the BACnet integration acceptance test checklist, and the contractual question of who is obliged to provide them is worth checking against your BMS service contract.
The idea to walk away with
Logging is not one thing. Polling, subscription and trend log reading produce different data with different resilience, and the choice determines whether an outage leaves a hole in your history or does not. Only the trend log has memory, so anything you will care about later should be collected that way where the devices support it.
Then store the metadata that makes a reading interpretable, decide which copy is authoritative, and prove the outage recovery during commissioning rather than discovering its absence during an investigation.
Final thoughts
A quick diagnostic for an existing integration: pick a point and find out, from documentation rather than assumption, which of the three mechanisms is collecting it. In a surprising number of systems nobody can answer, and the answer turns out to be polling for everything because that is what the gateway did out of the box.
If that is your situation, the cheapest improvement available is usually not more frequent polling. It is switching the points that feed analysis onto trend log collection, which costs some configuration and immediately makes your history survive the next network outage.
Disclosure
Alongside advisory work I also build a CMMS and CAFM platform, so I have a commercial interest in this category. Nothing above is a recommendation for it, and no vendor named here has paid for inclusion or had any editorial input. Weigh the analysis accordingly.
Gaps in your building data history?
Independent review of BACnet collection design: mechanism per point, trend log sizing against read frequency, outage recovery, duplicate handling and where the authoritative copy lives. 22+ years across CMMS, CAFM, EAM and ERP implementations.
Book a conversationRelated reading: BACnet objects, device instances and addressing, What is a BMS data historian, BACnet polling schedules, COV subscription recovery, Timestamps and clock synchronisation, Store-and-forward buffering.
Muhammad Abbas
CMMS / CAFM Manager & Independent Advisor · 22+ years across enterprise CMMS, EAM, CAFM and ERP implementations in utilities, oil and gas, manufacturing, government and facility operations.
Work with me