Engineering

Reading a BMS you did not commission

Point names that lie, intervals that are not what they claim, cumulative registers that roll over, and meters that stopped two years ago. A first-week field guide.

· 13 min read · All articles

Tags: BMS · BACnet · Modbus · data integration · submetering · data quality · metering · timezones · Project Haystack · Brick Schema

Every integration begins the same way: someone gives you access to a historian with several thousand points and a spreadsheet that describes what they are. The spreadsheet was accurate at commissioning. Commissioning was in 2016.

Since then the chiller has been replaced, two floors re-tenanted, a panel added, a gateway swapped, and the person who knew how it was wired has left. That is the normal condition of a building, and any method assuming otherwise produces numbers that look fine and are not.

What follows is what we check, in the order that finds problems fastest, with the query or test for each. We read; we never write — nothing here touches a setpoint, a schedule or an output, and nor does any part of our platform.

1. What has actually reported in the last 30 days

Not what exists in the point list — what has produced a value recently. In every portfolio we have onboarded, a meaningful fraction of declared points are dead: decommissioned equipment never removed from the schedule, gateways replaced without the old points retired, sensors that failed unnoticed because nothing was reading them.

SELECT p.point_id,
       MAX(r.ts)                        AS last_seen,
       COUNT(r.value)                   AS values_30d
FROM points p
LEFT JOIN readings r
       ON r.point_id = p.point_id
      AND r.ts >= now() - interval '30 days'
GROUP BY p.point_id
ORDER BY last_seen NULLS FIRST;

NULLS FIRST matters: points that never reported are the ones you most need at the top. Three buckets come out — never, stopped, live — and the middle one is the dangerous one, because it has history, so it charts, and the chart just ends.

That number is the denominator for everything else. "Zero data quality problems" across a list where a third of the points are dead is not a clean bill of health; it is a report about an empty set. Any sweep reporting zero problems must also report how many things it examined and how it knows that is all of them.

2. The declared interval versus the observed interval

A point declares itself as one-minute. Check the timestamps and consecutive readings are five minutes apart. Everything computed from that point is now wrong by a factor of five, and it will not look wrong — it will look like a building with unremarkable consumption. We have seen exactly this from a weather station declaring a one-minute cadence for a device that samples every five: the declaration came from the integration's configuration file, and the device never agreed to it.

Derive the interval from the data, not the metadata. Take the modal difference between consecutive timestamps over a recent window and compare it to the claim:

WITH gaps AS (
  SELECT point_id,
         EXTRACT(epoch FROM ts - lag(ts) OVER (PARTITION BY point_id ORDER BY ts)) AS dt
  FROM readings
  WHERE ts >= now() - interval '7 days'
)
SELECT point_id,
       mode() WITHIN GROUP (ORDER BY dt)     AS modal_seconds,
       percentile_cont(0.95) WITHIN GROUP (ORDER BY dt) AS p95_seconds,
       COUNT(*) FILTER (WHERE dt = 0)        AS duplicate_stamps
FROM gaps
WHERE dt IS NOT NULL
GROUP BY point_id;

Use the mode, not the mean: one long outage drags a mean anywhere. Carry p95 too — a point whose mode is 900 seconds and whose p95 is 3,600 is not a fifteen-minute point with a few gaps. And count zero-second differences: duplicate timestamps are common where two collectors write to one historian, and each double-counts in a SUM. Where data and metadata disagree, the data wins and the metadata is a defect to be filed.

3. Duplicated buildings

The same site appears twice under slightly different names because two integrations were set up eighteen months apart by different people. Both are live, both ingesting. Portfolio totals double-count, and per-building figures are each about half of reality.

Embarrassing to find, far worse to miss. Compare profiles rather than names: resample to hourly, take the correlation matrix across sites, and look at pairs above 0.98 of similar magnitude. Different buildings in one climate correlate on weather, but not that strongly, and not with peaks matching to the quarter hour. The same test finds one meter exposed under two names in a single site.

4. Whether submeters sum to the main

The most informative check on a whole-connection site. Sum every submeter and compare to the main incomer interval by interval, not month by month — a monthly comparison hides a residual that goes negative in the afternoon and positive at night.

  • Sum exceeds the main: double-counting — a nested submeter, a point duplicated under two names, or two meters stamping the same interval differently.
  • Sum well below the main: unmetered load. Normal, but you must know its size, because any claim about "total metered consumption" is short by it.
  • Sum tracks the main: rare and valuable, and you can attribute consumption with confidence.

Whatever the answer, it belongs in any report built on those meters. An allocation that assumes complete submetering when 30% of load is unmetered is a fabrication with a chart around it.

5. Point names that lie

Naming conventions decay. Patterns to expect:

  • A point named for equipment that was replaced by different equipment, keeping the old tag.
  • _kW and _kWh suffixes used interchangeably — power and energy are not the same quantity and the unit error is a factor of the interval length.
  • Cumulative registers presented as interval consumption, so every value is the total since installation and the "consumption" chart only ever rises.
  • Sign conventions inverted on export meters, so generation appears as consumption.
  • A point re-pointed at different equipment without being renamed, so its history is two things joined at a date nobody recorded.

The defence is a plausibility check per point before it is trusted: is the magnitude consistent with the equipment it names, and does its daily profile look like the thing it claims to be?

6. Telling power from energy, from the data alone

You cannot trust the suffix, so derive the quantity — four tests, fastest first.

  1. Monotonicity. Sort a week of values by time. If the series never decreases it is a cumulative register, not interval consumption. One query, and it changes everything downstream.
  2. Interval scaling. Take one day at two grains. If moving from fifteen minutes to hourly means summing four values to get a sensible figure, you have interval energy; if it means averaging them, you have power. Backwards on a fifteen-minute point inflates every total by four — large enough to notice, small enough to rationalise.
  3. Nameplate. A 400 kW chiller cannot draw 1,600 kW. An hourly figure above connected load means you summed something you should have averaged.
  4. Shape. Power falls as well as rises. Interval energy is non-negative and scales with the interval. A cumulative register has autocorrelation near one at every lag and a daily range that is a tiny fraction of its level.

Record the answer as a property of the point, with its evidence and date. Held as data, a classification can be re-derived and contradicted by a later run; held as prose, it will be wrong in two years and nothing will notice.

7. Cumulative registers and rollover

Most electricity meters expose a cumulative energy register, and consumption is the difference between successive reads — fine until the register wraps. Modbus registers are sixteen bits, so one counting whole kilowatt hours holds 0 to 65,535. On a site averaging 250 kW that is 65,536 / 250 = 262 hours: it wraps roughly every eleven days, forever.

Take a read of 65,500 followed by 120. Naive differencing gives −65,380 kWh. Three things happen next, and two are wrong:

  • The negative is passed through and the chart has a −65 MWh spike. Annoying, but visible, which makes it the best of the three.
  • The negative is clamped to zero and the interval is silently lost — a series short by one interval every eleven days, with nothing recording it.
  • The difference is taken modulo the register span: (120 − 65,500) mod 65,536 = 156 kWh. Right, and safe only if at most one wrap occurred between reads — polling interval times maximum load must stay below the span. Hourly polling here is safe; a monthly read of a 1 kWh-resolution register on a 250 kW site is fundamentally ambiguous.

Two traps sit alongside. A 32-bit value carried in two 16-bit registers has no agreed word order, and reading the words the wrong way round turns 1,234,567 kWh into 3,599,171,602 — obvious. The subtle version is scaling: a register reporting in 0.1 kWh units read as whole kWh makes a building exactly ten times too large, and nothing but an invoice catches it. A replaced meter also resets to zero, which looks like a rollover except that the step is arbitrary and the modulo correction invents a number. Flag resets for a human; never repair them automatically.

8. What the protocol actually gives you

BACnet

BACnet is maintained by ASHRAE's SSPC 135 committee as ANSI/ASHRAE Standard 135, current edition 135-2024. It is richly self-describing, so the device will tell you things the point list will not — if the historian kept them.

The committee's own paper, The Language of BACnet, notes that on an Analog Input object "some of the properties — such as Description, Device_Type and Units — are set during installation". That is the problem in miniature: Units is a required property whose value is a human's installation-time claim — metadata with the authority of a protocol field and the reliability of a spreadsheet.

What is worth harvesting, and what most historians throw away:

  • Status_Flags (In_Alarm, Fault, Overridden, Out_Of_Service) and Reliability, which runs from No_Fault_Detected through specific fault conditions. These are the protocol's native way of saying this value is not a measurement. A historian that stores Present_Value and discards them has converted a declared non-measurement into a reading — the same defect as coalescing a null to zero, committed one layer earlier.

Two cautions. The paper counts 123 standard properties, but BACnet "does allow vendors to add proprietary Properties" and proprietary objects, which "may not be understood or accessible by equipment from other manufacturers"; assume every site has some. Second, BACnet supports change-of-value reporting, where a device notifies subscribers when a value moves by more than an increment rather than being polled. A COV-driven historian has no fixed cadence, so section 2's interval test returns a mode that means nothing — and for those points a missing reading means "unchanged", not "missing". Getting that backwards inverts your data quality report.

Modbus

Modbus is the opposite: small, old, widely implemented and almost entirely undescriptive. No units property, no status flag, no object model — just numbered registers and a device profile in a PDF somewhere. Everything BACnet asserts badly, Modbus does not assert.

What bites: which table a value lives in, since holding and input registers are separate address spaces and vendors disagree about which to use; whether documented addresses are zero- or one-based, an off-by-one returning a plausible neighbouring value rather than an error; the scaling factor, usually documented and often documented wrongly; and the unit identifier when several devices sit behind one gateway, where a wrong id happily returns another meter's data. None of these produce an exception. They produce a number — which is why every Modbus point is checked against nameplate and invoice before anything is computed from it.

9. Time, and the errors you will never see as anomalies

Store everything in UTC, present in local time, and be explicit about which you are doing at every boundary. Use the IANA time zone database rather than fixed offsets, and record which release an analysis used: tzdata is revised several times a year as authorities change offsets and daylight-saving rules, so a re-run months later can bucket local time differently. The failure modes, in the order they cost money:

  • DST boundaries. A query for "last month" built on naive local timestamps includes 23 or 25 hours in one of its days across a transition. Annual totals are off by an hour of consumption and nobody ever finds it.
  • Occupancy schedules against a UTC series. "Occupied hours" is inherently a local-time concept. An office running 08:00–18:00 in Kuala Lumpur is 00:00–10:00 UTC. Bucket in UTC and the occupied window lands on the small hours: the afternoon cooling peak is reported as out-of-hours load, and the overnight base load disappears into "occupied". This breaks worst in a tropical portfolio with no DST at all, because a fixed offset error is perfectly stable. It never spikes, never looks like an anomaly, and is simply wrong every day in the same direction.
  • Stamp convention. Does a timestamp mark the start or the end of its interval? Both are in use, sometimes within one site, and a half-interval shift biases every boundary — shoulder hours, occupancy edges, tariff windows. Do not ask; prove it from a known step change, such as large plant starting at a scheduled time.
  • Device clock drift. A controller twenty minutes out files its readings in the wrong bucket. BACnet has a TimeSynchronization service many installations never use, and reference clocks are a solved problem — the NIST Time and Frequency Division distributes exactly this — but never assume a plant-room controller has reached one. Detect drift by cross-correlating against a daylight-driven or co-located series and looking for a consistent lag.

10. What a meter's accuracy class actually promises

"Class 1" gets used as though it means the meter is accurate to 1% on your wall. It does not. IEC 62053-21:2020 covers static watt-hour meters of classes 0.5, 1 and 2, and its scope says it "applies to their type tests only"; IEC 62053-22:2020 does the same for transformer-operated meters of classes 0.1S, 0.2S and 0.5S. A class is a limit demonstrated by a sample of that model, under reference conditions, in a laboratory — not a warranty about one installed unit, at a particular load, years later.

  • A transformer-operated meter's accuracy is that of a chain. The current transformer carries its own class under IEC 61869-2, and CT error grows at the bottom of the range — an oversized CT at a few per cent of rating is the commonest reason a metered figure and an invoice disagree.
  • Reference conditions are not plant-room conditions: temperature, harmonics and power factor all sit outside the laboratory envelope in a switchroom.
  • If the saving you mean to claim is of the same order as the chain's uncertainty, it is not measurable at that boundary and no analysis fixes it. Move the boundary, or say so — the question IPMVP makes you ask, and the subject of what a defensible savings claim requires.

11. Quantifying unmetered load, and what to do about it

Unmetered load is not a defect; pretending it is zero is. Compute it as a series — residual(t) = main(t) − SUM(submeter_i(t)) — and read the series, not its total.

  • Ever negative? A physically impossible residual means double-counting, a nested submeter, or clock skew. Fix that before interpreting anything else.
  • Flat? A missing base load: lifts, pumps, external lighting, a landlord's supply. With a weekday profile, tenant load behind a landlord meter.
  • Tracks the weather? Unmetered cooling — the case that matters most, because cooling is where the savings usually are.

Then state it. Report the residual as its own line — "unallocated, 28% of supply" — and never distribute it pro rata across the metered circuits, which is the commonest way a plausible allocation chart becomes fiction. If the measure you are verifying sits inside the unmetered portion, the honest boundary is the whole-facility meter. And if meters are to be added, the residual says where.

12. Why standardised tagging exists, and what to do without it

Everything above is the cost of buildings whose data has no shared vocabulary. Three efforts address that.

  • Project Haystack standardises semantic data models for equipment data, on the premise that "pragmatic use of naming conventions and taxonomies can make it more cost effective to analyze, visualize, and derive value from our operational data". A point carries tags for its function — "sensor, command, or setpoint" — for whether it supports a current value, historisation or writing, and for its unit.
  • Brick is "an open-source effort to standardize semantic descriptions of the physical, logical and virtual assets in buildings and the relationships between them". Where Haystack leans on tags, Brick leans on an explicit graph, which is what answers "which meter is upstream of this one" — the question section 4 keeps asking.
  • ASHRAE Standard 223P lets users "create semantic models that describe the many entities in their buildings that are relevant to advanced features and applications such as fault detection and diagnostics, demand flexibility, and real time optimization". Tooling comes from Open223, which states plainly that its tools "are neither developed nor endorsed by ASHRAE"; the standard sits with ASHRAE.

Almost no building you inherit will have any of them, so you will build the mapping yourself. Store it as data, not as a spreadsheet or naming rules in code. Keep the original point name immutable, and record every derived assertion — this is energy not power, this is the main incomer, this meter is downstream of that one — as a row with its evidence and date. Held that way, a mapping can be re-derived when the plant changes, contradicted by new data, and audited when a number is challenged. A naming convention can do none of that, which is how we all got here.

Twelve checks, one week

Those twelve run in that order for a reason: each sets the denominator for the next. None of it is glamorous, and all of it is cheaper now than after a customer has reported a number to a regulator. It also settles the question that matters most at the start — whether a portfolio's existing infrastructure is already enough to verify savings from, which, more often than owners expect, it is. See how we connect, what we do with monitoring you already have, and the rules those numbers must satisfy.

Sources

  1. BACnet — the standard maintained by ASHRAE SSPC 135
  2. The Language of BACnet — Objects, Properties and Services (BACnet.org)
  3. Modbus Organization
  4. Project Haystack
  5. Project Haystack — the point definition and its tags
  6. Brick Schema
  7. Open223 — tooling for ASHRAE Standard 223P
  8. ASHRAE Standard 223P — user documentation (Open223)
  9. ASHRAE — Standards and Guidelines
  10. IANA Time Zone Database
  11. NIST — Time and Frequency Division
  12. IEC 62053-21:2020 — static meters for AC active energy, classes 0.5, 1 and 2
  13. IEC 62053-22:2020 — static meters for AC active energy, classes 0.1S, 0.2S and 0.5S
  14. IEC 61869-2:2012 — instrument transformers, additional requirements for current transformers
  15. Efficiency Valuation Organization — IPMVP

External links open in a new tab. Standards and regulations change; where this article describes a threshold or an obligation, check the source for the current text before relying on it.

Apply this to your own estate

Send us what you already measure — meters, BMS points, or nothing but bills — and we will tell you what can be verified from it today.