Protocols and data

BACnet COV vs polling, and data freshness

How BACnet change-of-value (COV) subscriptions differ from polling: COV increments, subscription lifetimes, network load, and how to know that a value is still fresh.

A BACnet client gets a value in one of two ways. Polling reads it on the client's schedule, with ReadProperty or ReadPropertyMultiple. Change of value (COV) asks the device to send a notification when the value changes by at least a set amount. The choice decides the network load, how fast a change arrives and what it means when nothing arrives.

This guide is part of the BACnet and building protocols series.

How COV works

A client sends SubscribeCOV to one object in the device. The request names a subscriber process identifier, chooses confirmed or unconfirmed notifications, and gives a lifetime in seconds. The device then sends a notification with Present_Value and Status_Flags:

  • once when the subscription is accepted, so that the client has a first value;
  • for an analog object, when Present_Value has changed by at least its COV_Increment since the last notification;
  • for a binary or multi-state object, on every change of state;
  • when Status_Flags change, for example when the point goes into alarm or out of service.

Take an increment of 0.5 °C and a last notified value of 20.0 °C. Readings of 20.2 °C and 20.4 °C send nothing. A reading of 20.6 °C sends a notification, although each step was only 0.2 °C, because the device compares with the last notified value and not with the previous reading. Slow drift is therefore reported once it adds up to the increment. A change smaller than the increment is never reported, so the client can hold a value almost 0.5 °C away from the true value for as long as the room stays there.

SubscribeCOVProperty subscribes to one property and lets the client set its own increment. Use it to watch a property other than Present_Value, such as High_Limit, or to override the object's COV_Increment without writing to the controller.

The increment also sets the load. If a controller scans a noisy analog input once a second and the increment is 0.01, it can send a notification every second to every subscriber: 3,600 an hour from one point. Newman's account of the Cornell campus network lists an increment set too small among the controller faults that Cornell contains by letting each building network see only its own traffic and the central system.

Confirmed and unconfirmed notifications

A confirmed notification needs an acknowledgement from the client. If none arrives within the device's APDU timeout, the device resends it, up to its retry count. An unconfirmed notification is sent once and is never retried. If a router drops it, or the client is busy, the change is lost and neither end knows.

Use confirmed notifications for alarms and plant status. The acknowledgements cost one short message per change. Unconfirmed notifications suit high-rate analog points where the next change replaces the lost one, but only with a check read (see What silence means).

Lifetime and renewal

The lifetime is how long the device keeps the subscription without a renewal. The client renews it by sending the same SubscribeCOV again before it ends. In a client, the lifetime is normally a setting. In Beckhoff's TF8020 it is Subscriptions Lifetime in the Settings dialog.

Renew at half the lifetime. A 600 s subscription renewed every 300 s survives one lost renewal. The BACnet Testing Laboratories (BTL) guidelines require every COV server to accept any lifetime from 1 to 28,800 s (8 hours), so values in that range will not be rejected (clauses 7.24 and 7.25).

A lifetime of 0 means an indefinite subscription. Do not use it. BTL clause 7.6 gives the reasons: the device need not keep its subscription list through a reset or power loss, a replaced controller starts with an empty list, and a subscription from a client that has been removed holds its slot forever. SubscribeCOVProperty does not allow a lifetime of 0.

Subscription slots are finite. The standard requires a COV server to support only five concurrent subscriptions (BTL clause 7.7, citing clauses K.1.12 and K.1.13 of ASHRAE 135). The open-source BACnet Stack reserves 128 by default. When the table is full, a subscription request fails with an error; in BACnet Stack the error class is RESOURCES and the code is NO_SPACE_TO_ADD_LIST_ELEMENT. The Device object's Active_COV_Subscriptions property lists the subscriptions that the device holds. Read it during commissioning to see how many slots the supervisor and other clients already use.

A failed subscription must not fail silently. BTL clause 7.7 says to fall back to polling for that point, or to tell the operator, or both.

Polling and COV side by side

PollingCOV
Who starts each messageThe client, on its scheduleThe device, when the value changes
Traffic for a steady valueOne request and reply every intervalRenewals only, for example one exchange every 300 s
Time for a change to arriveUp to one polling interval, plus the readThe device's COV scan cycle plus transit; on MS/TP, also the wait for the token
Small changesSeen at each pollHidden until they add up to the increment
Support neededReadProperty, which every BACnet device must executeSubscribeCOV in the device and in the client
Resources in the deviceNone heldOne subscription slot per point per client; five is the required minimum
After a device restartThe next poll worksSubscriptions may be lost; they return at the next renewal
Evidence that data is freshThe timestamp of each successful readThe last renewal, the last notification and a check read

Polling budget on MS/TP

On BACnet/IP, polling a few hundred points once a minute is a small load. On MS/TP it needs arithmetic. MS/TP sends 10 bits per octet. A ReadProperty request for the Present_Value of an Analog Input is about 23 octets in its MS/TP frame, and the reply carrying a REAL is about 29 octets. At 38,400 bit/s, that is about 14 ms for one point, before the turnaround gaps, the reply delay of the answering controller and the token passing round every other master.

Work out the reads per second before you choose an interval. 300 points every 60 s is 5 reads a second, about 70 ms of each second on the wire. 300 points every 5 s is 60 reads a second, about 0.8 s of each second, which leaves no room for the controllers' own traffic. ReadPropertyMultiple carries several points in one exchange where the device supports it, and cuts the overhead per point. The BACnet/IP vs MS/TP guide explains the token cycle and baud rates.

What silence means

With polling, a failed read is visible: the request times out. With COV, silence has two meanings. The value may not have changed, or the subscription may have gone because the device restarted, the lifetime ran out or a notification was lost. A steady value and a dead subscription look the same.

Record three timestamps for each COV point:

  1. Last change: when the value last changed.
  2. Last message: when a notification or a successful read last arrived.
  3. Last renewal: when a SubscribeCOV for the point was last acknowledged.

Read each COV point every 15 minutes as a check. If the read differs from the last notified value by at least the increment, a notification was lost: resubscribe and raise a fault. Mark the point stale when the last renewal is older than the lifetime, or the last message is older than the check interval plus one minute. For a 600 s lifetime and a 15 minute check, that is 600 s and 960 s. The stale data guide explains how to show and handle values that are no longer fresh.

Polling needs the same care in a different form. A scheduler that runs every minute does not prove that a valid value arrives every minute. Measure the time between successful reads.

Choose per point

PointUsual choice
Energy and power for analysis, every 1 to 15 minutesPoll at the analysis interval, aligned to the clock
Room temperatures for comfort reportingPoll every 5 minutes, or COV with an increment of 0.2 to 0.5 °C
Plant status and alarms that must arrive within secondsCOV with confirmed notifications, a 600 s lifetime renewed every 300 s, and a 15 minute check read
Many points on an MS/TP busPoll only the points you need, with ReadPropertyMultiple where supported, or read them from the building management system (BMS) supervisor on BACnet/IP

Test the choice on site, with the client's log and the controller's own trend side by side:

  1. Leave the point steady for 30 minutes. Pass: renewals are acknowledged every 300 s, no notifications arrive, and the check reads match the last value.
  2. Make a change smaller than the increment. Pass: no notification, and the next check read shows the new value.
  3. Make a change larger than the increment. Pass: one notification. Record the delay from the change to its arrival; that is the latency the site will see.
  4. Restart the controller. Pass: notifications resume within one renewal interval, and the point shows stale if they do not.
  5. Restart the client. Pass: it subscribes again before it marks any point fresh.
  6. Read Active_COV_Subscriptions. Pass: the device holds the expected subscriptions and has free slots.

Polling with Edge

Edge on the ZGW-20 Gateway reads BACnet/IP by polling Present_Value. It does not subscribe to COV. Each point runs on a clock-aligned schedule, such as every 60 or 300 seconds, or in live mode, which also reads once a minute. Each successful read carries its own timestamp. A failed read records no new value, so a stopped controller shows as a gap. Edge does not connect to MS/TP directly; reach MS/TP controllers through a BACnet/IP router or the BMS supervisor. Poll energy and slow environmental points this way, and leave alarms that must arrive within seconds to the BMS.

Common questions

What is COV in BACnet?

Change of value. A client subscribes to an object, and the device sends a notification when the present value changes by at least the COV increment since the last notification, or when the status flags change. It replaces repeated polling for points that change rarely.

What is a COV increment?

The minimum change in the present value of an analog object that triggers a COV notification. With an increment of 0.5 °C and a last notified value of 20.0 °C, readings of 20.2 and 20.4 °C send nothing; a reading of 20.5 °C or more sends a notification. Binary and multi-state objects notify on every change of state.

How long should a COV subscription last?

Use a finite lifetime and renew at about half of it, for example a 600 s lifetime renewed every 300 s. BTL requires COV servers to accept any lifetime from 1 to 28,800 s. A lifetime of 0 means indefinite, and the BTL guidelines tell clients not to use it.

Is COV better than polling?

It reduces traffic for points that change rarely, and it reports state changes quickly. It needs support in both the device and the client, uses a subscription slot in the device, and needs renewal and a check read. Polling is simpler and gives a timestamp at every interval.