BACnet COV (Change of Value) subscribes a client to receive push notifications whenever an object's value changes by at least its COV_Increment, while polling has the client repeatedly read values on a fixed schedule. Use COV when you need fast change detection across many slow-changing points and the device supports it reliably; use polling when you need predictable bandwidth, synchronized multi-point reads, or the device's COV implementation is incomplete. At most real sites the right answer is a hybrid — COV for the bulk of points, polling as a heartbeat or fallback on anything safety-critical.
When This Decision Shows Up
You hit the COV-vs-polling question whenever you build a new integration: a supervisory station pulling points from field controllers, an analytics platform ingesting trend data, an IoT gateway forwarding values to the cloud. The default in most engineering tools is “poll everything every 60 seconds.” That works until one of the following starts to bite:
- The point list grew. A campus with 12,000 BACnet points polled at 60-second intervals generates 200 reads per second on average — not catastrophic on BACnet/IP, but enough to saturate an MS/TP trunk shared with token traffic.
- Detection latency matters. A binary status (fan failure, smoke detector, freeze stat) only changes a few times a day, but when it does change you want to know in seconds, not whenever the next poll happens to hit it.
- You're paying for cellular or LTE backhaul. Polling generates traffic whether anything changed or not. COV only spends bytes when the underlying value moves.
- The supervisor is logging trends. If you only need to record values when they change, polling every minute writes 60 redundant samples per hour per point. COV-based trending writes a sample only when a real change occurred.
How COV and Polling Actually Work
Polling is the simpler model. A client (your JACE, supervisor, or script) issues a ReadProperty or ReadPropertyMultiple request, the device returns the current value, the client moves on to the next point. Repeat on a fixed interval. Bandwidth and CPU load are deterministic: number of points × polling rate × bytes per read. Worst-case detection latency is one poll interval. If the device is offline, you get an error and try again next cycle.
COV (Change of Value) inverts the flow. The client sends a SubscribeCOV or SubscribeCOVProperty request once, specifying a process identifier, a target object, an issue-confirmed flag, and a subscription lifetime in seconds. The device then sends a COVNotification back — either confirmed (which the client must acknowledge) or unconfirmed (fire-and-forget) — whenever the monitored property changes by more than the object's COV_Increment (for analog values) or whenever it transitions (for binary values). When the subscription lifetime runs out, the device stops sending notifications. The client must re-issue the subscription before that happens.
Both services are defined in ASHRAE Standard 135. The exact set of subscription services a device supports depends on the protocol revision and the BIBBs (BACnet Interoperability Building Blocks) the vendor declared on the PICS. Real-world support breaks down roughly as follows:
SubscribeCOV— Subscribes to thePresent_ValueandStatus_Flagsof an object. Almost universally supported on devices that claim COV at all.SubscribeCOVProperty— Subscribes to an arbitrary property of an object, including specifying a different COV increment from the object default. Less universally supported.SubscribeCOVPropertyMultiple— Subscribes to multiple properties across multiple objects in a single request. Added later in the standard's evolution; support is spottier on older firmware, common on modern supervisory controllers.
Choosing Between COV and Polling
The decision usually isn't global — it's per-point-class. Use this rough framework:
- Binary inputs / status / alarms → COV. A fan-status point or freeze stat only flips a handful of times a day. Polling it wastes bandwidth and adds detection latency. COV is the right shape.
- Slow-changing analog values (space temperature, humidity, CO2) → COV with a sensible
COV_Increment. Set the increment to the smallest change you actually care about (0.5 °F, 1 % RH, 20 ppm CO2). Anything smaller is noise. - Fast-changing analog values (flow rates, kW, VFD speed feedback) → mixed. If the value oscillates by more than your COV increment several times per second, COV will flood the network. Either widen the increment or fall back to polling at whatever rate the value actually needs to be sampled at.
- Multi-point synchronized reads (energy bills, performance audits) → polling with
ReadPropertyMultiple. COV gives you each point's update independently, which makes it hard to compute “total kW at exactly 09:00:00” from the stream. A scheduledReadPropertyMultiplegrabs a synchronized snapshot. - Safety-critical or trip-circuit points → COV plus polling. Subscribe for fast detection, and also poll on a longer interval as a liveness check. If the device dies or the subscription silently expires, the next polled read fails and you know something is wrong.
Tuning COV_Increment and Subscription Lifetime
Two parameters determine whether COV behaves well: the COV_Increment on the object, and the subscription Lifetime the client requests.
COV_Increment defines the minimum absolute change in Present_Value required to trigger a notification. Set it too low and a noisy sensor will flood the trunk; set it too high and you'll miss real changes. A few starting points that work in practice:
- Zone temperature: 0.5 °F (0.25 °C)
- Relative humidity: 1 %RH
- CO2: 20 ppm
- Static pressure: 0.05 in. w.c.
- VFD speed feedback: 1 %
Lifetime is the subscription duration in seconds the client requests. A lifetime of zero means “subscribe indefinitely” in some implementations, but many devices interpret this differently or cap it internally. A safer pattern is a finite lifetime (for example, 300 seconds) that the client renews on a shorter interval (every 240 seconds). If the client crashes, the device will drop the subscription naturally; if the device restarts, the client will re-establish it on the next renewal. Most supervisory platforms handle this automatically — verify your specific BACnet driver actually renews, because some don't.
Common Pitfalls
- Assuming every device supports COV. The PICS document is the authoritative answer. Older MS/TP field controllers, low-end gateways, and certain Modbus-to-BACnet bridges either don't implement COV at all or implement only the simplest
SubscribeCOVvariant. If you subscribe and never see a notification, check the PICS before assuming the device is broken. - Setting
COV_Incrementtoo aggressively on noisy sensors. A duct static pressure sensor that fluctuates ±0.1 in. w.c. on its own, with aCOV_Incrementof 0.05, will issue notifications constantly. On a shared MS/TP trunk that one point can starve everyone else of token time. Tune the increment to actual sensor noise, not to a marketing-grade resolution number. - Forgetting that confirmed COV blocks. Confirmed notifications require an ACK before the device considers them delivered. If the client is slow or offline, the device may queue retries, exhaust its application-layer timer, and stop notifying altogether. Use unconfirmed COV for non-critical points; reserve confirmed for points where you can't afford to miss a transition.
- Silent subscription expiration. The most common failure mode of a COV-only integration is the subscription quietly lapses (because the client's renewal logic broke, the device rebooted and lost subscription state, or a router on the path dropped a renewal packet) and values appear frozen. There's no error — the value just stops updating. A heartbeat poll every few minutes catches this; pure COV doesn't.
- COV storms during equipment cycling. When a chiller starts, dozens of analog points can move through their increment in a few seconds. On BACnet/IP this is usually fine. On MS/TP, where the trunk only carries one frame per token rotation, a COV storm can collapse trunk responsiveness for tens of seconds. Plan for this when sizing trunks. See our BACnet MS/TP wiring best practices guide for the bandwidth math on a typical 38.4 or 76.8 kbps trunk.
- Treating COV as a substitute for trend logs. COV is a real-time push to one client. If that client misses notifications — due to restart, network blip, or subscription lapse — the data is gone. For historical archival, use Trend Log objects in the device itself; see BACnet trending and trend log export. The device buffers samples locally and you read them out on whatever schedule you like.
Verifying COV Behavior in the Field
When something feels wrong, the fastest way to confirm what's actually happening on the wire is a packet capture. On BACnet/IP, capture on the interface carrying UDP 47808 and look for SubscribeCOV requests from the client, the corresponding SimpleACK from the device, and the subsequent UnconfirmedCOVNotification or ConfirmedCOVNotification messages flowing back. If you see the subscribe and ACK but no notifications, either the value really isn't changing enough to cross the increment, or the device's COV implementation is broken.
In Wireshark, the BACnet dissector decodes COV service requests and notifications directly — filter for the BACnet protocol and look at the service column. Avoid copying obscure filter expressions from forums; either use the protocol filter and read the decoded packets, or build a filter from the dissector tree by right-clicking a known-good field and selecting “Apply as Filter.”
When to Escalate
Reach out to the device vendor or your integrator (rather than continuing to tune) when:
- The PICS claims COV support but you can subscribe successfully and never receive notifications for points whose values are clearly changing on the live system.
- Subscriptions are accepted but the device sends a single notification and then goes silent, even though more changes happened.
- The device refuses subscriptions with an error response (the BACnet error class and error code in the response narrow the cause — record both before escalating).
- You're seeing
ConfirmedCOVNotificationretries from the device with no apparent delivery problem on the network — the client's BACnet stack may not be ACK'ing correctly. - You need
SubscribeCOVPropertyMultiplefor performance reasons and the device's PICS doesn't list it. There's no client-side workaround beyond falling back to polling or many single-property subscriptions.
For Python automation that needs to test COV behavior directly, both bacpypes3 and BAC0 support subscription and notification handling — their respective READMEs and API documentation on PyPI are the canonical references for the current release's API surface.
Source Attribution
The technical guidance in this entry is informed by the following sources:
- ASHRAE Standard 135 — BACnet—A Data Communication Protocol for Building Automation and Control Networks. The normative reference for
SubscribeCOV,SubscribeCOVProperty,SubscribeCOVPropertyMultiple, theCOV_Incrementproperty, and confirmed vs. unconfirmed notification semantics. - bacpypes3 documentation — Open-source Python BACnet stack with subscribe and notification handlers; the source code and examples in the package are useful for understanding how a working client implements COV state.
- BAC0 documentation — Higher-level Python BACnet library built on bacpypes; documents COV subscription patterns at the application level.
- Wireshark BACnet APDU dissector reference — The canonical source for verified BACnet display-filter field names.
Additional testing and field validation by SiteConduit.
Was this article helpful?
Related Articles
Need to do this remotely? SiteConduit provides Layer 2 access that preserves BACnet broadcasts — no BBMD needed for remote sessions. Join the waitlist.
SiteConduit Technical Team
Idea Networks Inc.
SiteConduit builds managed remote access for building automation. Our knowledge base is maintained by BAS professionals with hands-on experience deploying and troubleshooting BACnet, Niagara, Modbus, and Facility Explorer systems.