bacpypes3 AnyAtomic and get_value(): Source and Usage

Tools & Librariesbacpypes3AnyAtomicget_valueprimitivedata
June 7, 2026|8 min read

In bacpypes3, AnyAtomic is the Python representation of the ASHRAE 135 BACnetAnyAtomic CHOICE — a wrapper that can hold any of the atomic primitive types (Null, Boolean, Unsigned, Integer, Real, Double, OctetString, CharacterString, BitString, Enumerated, Date, Time). When you read a property whose declared type is AnyAtomic (most commonly a TimeValue.value field inside a Schedule's Weekly_Schedule), you receive an AnyAtomic instance and need to extract the wrapped primitive before you can use it. The authoritative source for the class definition — and for whatever accessor your installed release exposes (often called get_value() or similar) — lives in the bacpypes3 package on PyPI; the fastest way to read it is to open the installed module under your site-packages and search for the AnyAtomic class.

Scenario: You Have an AnyAtomic and You Need the Value Out

You are writing a Python service against bacpypes3 — a small supervisor, an analytics extractor, a test harness — and you have called ReadProperty on something whose declared type is BACnetAnyAtomic. The most common case is reading a Schedule object's Weekly_Schedule: each TimeValue entry contains a value field typed as AnyAtomic. You print the response and see something like <AnyAtomic ...> or a nested object; you cannot pass it directly to your downstream code, because that code expects a Python float, bool, or int.

You search for "bacpypes3 anyatomic get_value source" because you want one or more of the following:

This entry walks through each of those, with the standing caveat that bacpypes3 has evolved across releases and the installed package on your machine is the only definitive reference for your environment.

What AnyAtomic Is at the Protocol Level

ASHRAE Standard 135 defines BACnetAnyAtomic as a CHOICE restricted to the BACnet atomic primitive types. Atomic, in BACnet terms, means a value that fits in a single application tag — no constructed SEQUENCEs, no object identifier references, no arrays. The standard uses BACnetAnyAtomic wherever a field needs to hold "any atomic value, encoded with its own tag" — the receiver inspects the application tag on the wire to learn which primitive it actually is.

The places you most commonly see BACnetAnyAtomic in the spec:

Because the choice is determined at write time, an AnyAtomic read off the wire arrives already "tagged" with whichever primitive it actually is. The bacpypes3 decoder uses that tag to populate the corresponding member of the CHOICE; your job in Python is to look at which member is set and pull the value out.

Where the Class Definition Lives

bacpypes3 is the Python 3 / asyncio rewrite of the original bacpypes library. For the canonical source:

Constructor signatures and accessor method names have changed across bacpypes3 releases during its asyncio rewrite. A snippet from a Stack Overflow answer or a blog post written against an older release may reference methods that no longer exist or have been renamed. The file on disk under your site-packages directory is the only reference that is guaranteed to match your runtime.

Pattern for Reading the Value Out

The pattern that works across recent bacpypes3 releases:

  1. Read the property. Use the bacpypes3 application API to issue ReadProperty against the target object and property. The library returns a Python object whose type matches the property's declared type — for a Weekly_Schedule, an array-like sequence of DailySchedule entries, each containing a list of TimeValue entries.
  2. Drill down to the AnyAtomic. For each TimeValue, the value attribute is the AnyAtomic wrapper. Confirm its class with type(tv.value).__name__ if you are unsure — you should see AnyAtomic (or whatever name the installed version uses) rather than a primitive.
  3. Extract the wrapped primitive. Inspect the installed AnyAtomic class for the accessor it exposes. Across bacpypes3 history this has been some combination of: a get_value() method (a carry-over name from the original bacpypes), direct attribute access by primitive name (av.real, av.boolean, etc., where exactly one is set), or iteration over the CHOICE's elements. Use whichever pattern matches the class you actually have installed.
  4. Coerce to a native Python value. The extracted primitive is itself a bacpypes3 class (Real, Boolean, etc.) and not a raw Python value. To get a native float or bool, either call float() / bool() on it or read its underlying value attribute. The dual-inheritance pattern used by primitives like Real(Atomic, float) means float() coercion is usually clean — see the entry on why Real inherits from Atomic and float for the rationale.

Because the exact accessor name varies, prefer narrative pseudocode in your own documentation over copy-pasted snippets pinned to one release. The snippet that worked last year may quietly break after a pip install --upgrade bacpypes3.

Common Pitfalls

When to Escalate

If you can read the AnyAtomic wrapper but cannot find a clean way to extract its value in your installed bacpypes3, the situation is almost always one of three things:

Related KB Entries

Source Attribution

Additional testing and field validation by SiteConduit.

bacpypes3AnyAtomicget_valueprimitivedataBACnet types

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.

SC

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.