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:
- The class definition for
AnyAtomic— to confirm it really is the CHOICE you think it is, and what accessor methods it exposes. - The signature of the method that returns the wrapped primitive (often called
get_value()in older bacpypes; verify in the installed source for your bacpypes3 release). - A working pattern for converting an
AnyAtomicback to a native Python value so you can store it, log it, or compare it.
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:
- Schedule object — the
valuefield of everyTimeValuein aDailySchedule, and theSchedule_Defaultproperty itself. - Exception_Schedule — each
SpecialEventcontains alistOfTimeValues, and thevaluefield of eachTimeValueinside is anAnyAtomic. - Other places that need a generic atomic carrier — specific service parameters and a few constructed types that intentionally defer the primitive choice to the writer.
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:
- PyPI project page — pypi.org/project/bacpypes3/. The page links to the source repository for the currently published release. Always cross-check the version installed against the version you are reading.
- Installed package under site-packages — after
pip install bacpypes3,AnyAtomicis defined in thebacpypes3.constructeddatamodule (the atomic primitives it wraps — Real, Unsigned, Enumerated, and so on — live inbacpypes3.primitivedata). Openconstructeddata.pyin your editor and search forclass AnyAtomic; that is the definitive source for the version you have. - Project documentation — whatever Read the Docs build or README is linked from PyPI. Documentation tends to lag the source; treat it as a guide, not as the truth.
- ASHRAE 135 — for the protocol-level definition of BACnetAnyAtomic and the full list of atomic primitive types. The Python class is a translation; the spec is normative.
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:
- Read the property. Use the bacpypes3 application API to issue
ReadPropertyagainst the target object and property. The library returns a Python object whose type matches the property's declared type — for aWeekly_Schedule, an array-like sequence ofDailyScheduleentries, each containing a list ofTimeValueentries. - Drill down to the AnyAtomic. For each
TimeValue, thevalueattribute is theAnyAtomicwrapper. Confirm its class withtype(tv.value).__name__if you are unsure — you should seeAnyAtomic(or whatever name the installed version uses) rather than a primitive. - Extract the wrapped primitive. Inspect the installed
AnyAtomicclass for the accessor it exposes. Across bacpypes3 history this has been some combination of: aget_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. - 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 nativefloatorbool, either callfloat()/bool()on it or read its underlying value attribute. The dual-inheritance pattern used by primitives likeReal(Atomic, float)meansfloat()coercion is usually clean — see the entry on whyRealinherits fromAtomicandfloatfor 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
- Assuming
get_value()exists by that exact name. The legacy bacpypes library exposed a method literally namedget_value()onAnyAtomic. bacpypes3 may keep, rename, or replace it depending on release. Search the installed source fordef get_valuebefore relying on the name. - Confusing bacpypes (legacy) with bacpypes3. Both packages are installable from PyPI and have overlapping class names. The legacy
bacpypesis synchronous;bacpypes3is asyncio-native. Import paths and constructor signatures differ. Runpip list | grep bacpypesto confirm which one is in your environment. - Treating
AnyAtomicas if it were itself a primitive. Passing anAnyAtomicinto code that expects aRealor afloatwill not auto-unwrap. Always extract first. - Putting a constructed type inside an AnyAtomic. The CHOICE is restricted to atomic primitives by design. Attempting to wrap a
ObjectIdentifier, aBACnetAddress, or any SEQUENCE will fail encoding. If you are tempted to do this, the Schedule mechanism is not the right tool — rethink the design. - Mixed primitive types within a single Schedule. The spec permits a
Weekly_SchedulewhoseTimeValueentries hold different atomic types, but most controllers reject schedules whoseAnyAtomicvalues do not match the declared type of the target referenced inList_Of_Object_Property_References. Keep all values in a schedule the same primitive type unless you have a specific reason not to. - Forgetting that the wire tag drives decoding. If a peer device sends a value tagged as
Integerwhen your code expectsReal, theAnyAtomicyou receive has itsintegermember set, not itsrealmember. Defensive code checks which member is populated rather than assuming.
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:
- You are on an older bacpypes3 release. Upgrade in a virtualenv, re-read the source, and confirm the accessor in the newer version. Pin the version in your
requirements.txtonce you find one that works. - The peer device sent something unexpected. Capture the response in Wireshark, decode it as BACnet, and read the application tag on the value field. If the tag does not match what the property's declared type implies, the controller is sending non-conformant data and the bacpypes3 decoder has done the right thing by refusing to guess.
- You are hitting a real library bug. File an issue on the bacpypes3 repository (linked from PyPI) with the exact version, a minimal reproducible example, and the captured BACnet response. Do this last, after ruling out the first two.
Related KB Entries
- bacpypes3 DailySchedule, TimeValue, AnyAtomic: Source and Usage — companion entry covering the constructed types that contain
AnyAtomicvalues, with a Schedule-object focus. - BACpypes3: Custom BACnet Applications in Python — broader walkthrough of building applications on bacpypes3, including the application/device structure that issues the
ReadPropertyin the first place.
Source Attribution
- bacpypes3 on PyPI — the canonical project page; links to the source repository for the currently published release.
- bacpypes documentation (Read the Docs) — documents the legacy bacpypes API, useful as a starting point for understanding the original
get_value()naming that bacpypes3 inherited from. - ASHRAE Standard 135 — BACnet, A Data Communication Protocol for Building Automation and Control Networks. Normative reference for the BACnetAnyAtomic CHOICE and the full list of atomic primitive types.
- ASHRAE 135 standard listing — where to obtain the current published version of the BACnet standard.
Additional testing and field validation by SiteConduit.
Was this article helpful?
Related Articles
Why bacpypes3 Defines class TimeValue(Sequence)
Tools & Librariesbacpypes3 class Any: The Open BACnet Value Container
Tools & Librariesbacpypes3 Time Class: Why It's a Tuple of (Hour, Minute, Second, Hundredth)
Niagara / TridiumTridium Upgrade: Niagara Version Upgrade and Migration Guide
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.