mail@mabbaz.com Abu Dhabi, UAE

BMS · Storage Rules · Reporting

Late and Out-of-Order BACnet Readings: Storage and Reporting Rules

Readings do not always arrive in the order they happened. Buffered data lands hours late, a reconnected controller delivers yesterday, a replay overlaps what you already have. The gateway side of this is a buffering question; this is the other half, what the store and the reports must do when the past arrives after the present.

Muhammad Abbas October 27, 2026 ~12 min read

Most building data platforms are built on the quiet assumption that readings arrive roughly when they happen and roughly in order. For a well-connected single building that holds most of the time. Add a wide-area link, a gateway that buffers, controllers with their own trend logs, and the assumption fails regularly, and the failures are not loud. They show up as a monthly total that changes after the month closed, or a chart that gains data where it previously had a gap, and nobody can explain either.

The message up front: separate event time from ingestion time, key rows on point plus event time so a replay cannot duplicate, define a late-arrival window beyond which data is accepted but flagged, and decide explicitly what happens to aggregates and reports that were already computed over a period that has just gained readings. The last of those is the decision most often skipped, and it is the one that produces figures which change retrospectively with no explanation attached.

1. Why readings arrive late

  • Gateway buffering and replay. The designed case: an outage ends and the backlog arrives carrying its original timestamps. The mechanism is in store-and-forward buffering for BMS gateways.
  • Controller trend log collection. Reading a device buffer periodically means every batch is late by design, by up to the collection interval. Covered in BACnet data logging.
  • Reconnection after a device restart, where a controller delivers what it recorded while unreachable.
  • Clock error. A device whose clock is behind produces readings that look late and are not, which is why the diagnosis depends on the drift monitoring in timestamps and clock synchronisation.
  • Deliberate backfill. A manual import correcting a historical gap, which is late by months rather than minutes.

Only the fourth is a fault. The rest are normal operation, which is why rejecting late data is the wrong instinct.

2. Two times, two different questions

The whole subject reduces to holding both and knowing which to use.

  • Event time is when the condition existed in the building. Every question about the building uses this: consumption in March, the temperature at the moment of the alarm, the trend across a shift.
  • Ingestion time is when your system learned about it. Every question about your systems uses this: whether collection is keeping up, how much lateness is normal, when a figure could first have been computed.

Store both on every row. A platform holding one timestamp cannot answer the other kind of question and cannot detect lateness at all, which means it also cannot detect clock drift, buffer replay or stalled collection.

Lateness is a measurable property, so measure it

The difference between ingestion and event time, trended per point, tells you what normal looks like for each collection path. A polled point should sit near zero. A trend-log point should sit near its collection interval. Once you know the normal distribution, an outlier is meaningful: a jump means a buffer replayed, a steady drift means a clock is wrong, and a growing lag means collection is falling behind. None of this requires new instrumentation, only the second timestamp, and it converts a class of invisible problems into a single chart.

3. Accepting a replay without duplicating it

A gateway that is unsure what it delivered will re-send, which is correct behaviour. The receiver has to absorb that harmlessly.

  • Key rows on point identity plus event time. Structural point identity, not the name, for the reasons in BACnet objects and addressing. A re-sent reading then collapses onto the existing row instead of adding one.
  • Decide what happens on a conflicting value for the same key. Two different values claiming the same point at the same instant means something is wrong: a clock problem, a double collection path, or a scaling change. Overwriting silently discards the evidence. Keeping both needs somewhere to put the second. Flagging the conflict is usually right.
  • Do not key on arrival order or on a sequence number alone, because a replay restarts the sequence and the arrival order is exactly what is unreliable.
  • Make the ingest path genuinely idempotent, not merely usually. A retry after a partial failure is the normal case, not the exception.

The related but distinct problem of the same physical reading arriving by two different paths is handled separately in handling duplicate sensor readings.

4. The late-arrival window

A window is a declared expectation about how late data can legitimately be, and it exists to make lateness classifiable rather than to reject anything.

Lateness Treatment Why
Within the normal range for that pathAccept silentlyThis is how the collection mechanism works. Alarming on it trains people to ignore the alarm
Beyond normal, inside the windowAccept, record the lateness, recompute affected aggregatesA buffer replayed. Expected occasionally, and the aggregates are now stale
Beyond the windowAccept and flag; do not rejectCould be a long outage or a clock error. Rejecting loses real data to protect a convention
Future-datedAccept and flag as suspectImpossible by definition, so it is a clock error rather than lateness

The principle throughout is accept and flag rather than reject, the same discipline applied to quality in BACnet data quality flags. A rejected reading is unrecoverable and leaves a gap indistinguishable from never-collected.

5. Aggregates computed over a period that has changed

This is the consequence everybody discovers late. An hourly average, a daily total or a monthly consumption figure computed before the backlog arrived was computed from incomplete data and is now wrong.

  • Treat derived values as derived, not as records. An aggregate is a cached computation over a period, and it needs a recorded dependency on that period so it can be invalidated.
  • Recompute on late arrival, rather than waiting for somebody to notice. Any period that gains readings has its aggregates rebuilt.
  • Version the published figure. If a monthly total has already been reported and then changes, both values and the reason need to exist. A figure that silently changes destroys confidence faster than one that was wrong and was corrected.
  • Decide a closing point. At some stage a period must be declared final, after which late data is recorded but the published figure does not move. Without that, nothing is ever stable enough to report on.
  • Carry completeness alongside the figure, so a reader can see what proportion of the period it covers, which is the qualification argued for in BMS data completeness KPIs.

The closing point is a policy decision rather than a technical one, and it is worth making deliberately: too early and figures are built on incomplete data, too late and nothing can be reported promptly.

6. Alerting on conditions that have already passed

A backlog can contain an alarm condition that arose during the outage and has since cleared. What to do with it is a genuine judgement.

  • Do not raise it as a live alert. Notifying somebody about a condition that resolved hours ago wastes a response and erodes trust in the alerting.
  • Do record it as an occurrence. It happened, and it belongs in the history and in any recurrence counting, per converting repeated faults into one case.
  • Review the backlog explicitly after a long outage, as a task rather than a hope, because this is where something significant occasionally sits unexamined.
  • Treat a condition still active on arrival differently. That is a live problem you have only just learned about, and it should alert normally.

7. What to require of a platform

  • Accepts writes with event times earlier than existing rows, without rejecting or reordering them. Test this before purchase; several platforms do not.
  • Stores event time and ingestion time separately on every row.
  • Idempotent on point plus event time, demonstrated by a forced replay producing no duplicates.
  • Invalidates and recomputes aggregates when a period gains data.
  • Exposes lateness as a queryable property, so the measurement in section 2 is possible at all.

These belong in the acceptance set in the BACnet integration acceptance test checklist, and the disconnect-and-reconnect test proves most of them in ten minutes.

Limits

No window durations or closing periods are given, because they follow from your own collection mechanisms and outage history and from what your reporting cycle requires, which is the measurement described in section 2 rather than a general figure. Platform behaviour on late and out-of-order writes also varies considerably between products and versions, so the platform's own current documentation governs rather than any general description, and it is worth testing rather than reading. Where a reported figure carries a contractual or regulatory obligation, the rules on restating it are set by that obligation and not by a data policy. This is written from the data model and reporting side, which is my own domain.

The idea to walk away with

Late data is normal, not exceptional, and a platform that treats it as an error will either lose real readings or silently corrupt the ordering. The shape of the solution is small: two timestamps, an idempotent key on point plus event time, acceptance with flagging rather than rejection, and aggregates that know which period they depend on so they can be rebuilt.

The part that needs a human decision rather than a design is when a period closes. Make that explicitly, because the alternative is figures that quietly change after they have been presented.

Final thoughts

If you store both timestamps already, plot the difference between them per point for a month. The distribution tells you how your collection actually behaves, which is usually not what the design document says.

If you store only one, that is the finding: you cannot currently tell a buffered replay from a clock error from collection falling behind, and all three are producing effects somebody has probably already noticed and attributed to something else.

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.

Figures that change after the month closed?

Independent review of how your platform handles late and out-of-order readings: timestamp model, idempotency, late-arrival policy, aggregate invalidation and when a period should close. 22+ years across CMMS, CAFM, EAM and ERP implementations.

Book a conversation

Related reading: Store-and-forward buffering, Handling duplicate sensor readings, Timestamps and clock synchronisation, BMS data completeness KPIs, BACnet data logging, BACnet data quality flags.

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
MAbbaz.com
© MAbbaz.com