bacpypes3 class Any: The Open BACnet Value Container

Tools & Librariesbacpypes3Anyconstructed dataABSTRACT-SYNTAX
June 21, 2026|8 min read

In bacpypes3, Any is the open value container that models BACnet's ABSTRACT-SYNTAX.&Type — the ASHRAE Standard 135 datatype used wherever a property or service parameter can hold a value whose concrete type is not fixed by the schema. Unlike AnyAtomic, which is restricted to a single primitive, plain Any can carry either an atomic value or a constructed one (Sequence, Array, or CHOICE). It stores the raw, application-tagged content and defers decoding until you cast it to a known type, which is why reading one back often hands you a wrapper object rather than a native Python value.

The Scenario

You are reading bacpypes3 source — or your IDE jumped to a definition — and you land on a class named Any. The name is deliberately broad, and that is exactly what makes it confusing: it does not correspond to a single BACnet datatype the way Real or Unsigned does. It is a placeholder for "whatever value belongs here, decided at runtime."

This usually surfaces in one of two ways. Either you read a property back and got an Any instance where you expected a plain number, string, or object identifier; or you are constructing a service request or a complex object and bacpypes3 wants an Any for a field you thought took a concrete type. Both lead to the same question: what does this container actually hold, and how do I get a typed value in or out of it?

What Any Represents in BACnet

BACnet's abstract syntax (ASHRAE Standard 135) defines an open datatype written as ABSTRACT-SYNTAX.&Type. It marks a position in the protocol where the encoder cannot know the datatype in advance — the actual type is whatever the application or context tag on the wire says it is, and the receiver interprets it using out-of-band knowledge such as the property's declared datatype.

The clearest example is property access itself. In the ReadProperty and WriteProperty services, the property value is carried in a parameter typed as the open ABSTRACT-SYNTAX.&Type, because a single service has to move an analog setpoint, a binary state, a character string, or a structured value depending on which property you addressed. The service encoding is fixed; the value it carries is not. That open slot is what bacpypes3's Any models.

You also meet the open type inside constructed datatypes — places where a SEQUENCE or CHOICE includes a member whose type depends on context rather than being pinned by the schema. Wherever the standard writes the open type, bacpypes3 needs a class that can hold encoded content first and resolve its concrete type later. That class is Any.

Any vs. AnyAtomic

The two names cause most of the confusion, so it is worth being precise. Any is the general open container: it can hold an atomic (primitive) value or a constructed value. AnyAtomic is the same idea narrowed to exactly one primitive — no Sequence, no Array, no nested CHOICE. That is why, in the library, the restricted form inherits from the general one. If you have been reading about the Schedule object's setpoints, that is the AnyAtomic case; the entry on why bacpypes3 defines class AnyAtomic(Any) covers that restriction in detail.

Practically: if the BACnet property you are working with allows a constructed value, you want Any. If the standard restricts the slot to a single primitive, you want AnyAtomic, and supplying a constructed value will be rejected. Check the property's datatype in Standard 135 rather than guessing — the choice between the two follows directly from what the standard permits in that position.

Getting a Value In and Out

Because Any holds tagged content rather than a decoded value, working with it is a two-step process: you put a typed value in, and you cast a typed value out. The original BACpypes line (the pre-3 library) exposed this as explicit cast-in and cast-out operations. bacpypes3 reworked the encoding layer substantially, so the accessor names and call patterns are not guaranteed to match older examples. Rather than copy a method name from a blog post, confirm what your installed release actually provides.

The reliable approach when you read a property back and got an Any is to tell bacpypes3 the datatype you expect, so it can resolve the open value to a concrete class for you. The concrete type comes from the property you addressed — the standard, or the device's PICS, tells you whether that property is a Real, an Enumerated, a structured type, and so on. Once you know the target type, you cast the Any to it and read the native value.

How to Find the Definition in Your Installed Release

Module paths and accessor names have moved between bacpypes3 releases, so verify against the exact version you have installed rather than trusting a path from a guide. Locate the package directory and grep for the class:

# Find where bacpypes3 is installed
python -c "import bacpypes3, os; print(os.path.dirname(bacpypes3.__file__))"

# Grep that directory for the class definition
grep -rn "class Any" /path/printed/above

You will find Any defined alongside the other constructed and open types rather than next to the simple primitives, with AnyAtomic nearby as a subclass. Confirm the inheritance and the available methods at runtime without reading the file:

import inspect
from bacpypes3.constructeddata import Any  # confirm this import against your release

print(inspect.getsourcefile(Any))
print(Any.__mro__)
print([m for m in dir(Any) if not m.startswith("__")])

Treat the import line as something to verify, not copy blindly — if it raises ImportError, the grep above gives you the correct module for your version. The dir() output is the authoritative list of cast and accessor methods for the code actually running on your machine, which beats any documented method name that may have changed.

Common Pitfalls

When to Escalate

If you have confirmed the class, the inheritance, and the cast methods but decoding still fails against a real device, the problem is usually the concrete type you are casting to or supplying, not Any itself. Capture the exchange and compare the application or context tag on the wire against what the device's PICS says the property carries; a mismatch there explains most failed casts.

When the class definition or accessors genuinely differ from what any guide describes, the source of truth is the bacpypes3 project. Check the issues and discussions on the bacpypes3 GitHub repository rather than guessing, since the maintainer documents behavior changes there. For wiring these types into a working client or server, see the bacpypes3 custom applications tutorial.

Source Attribution

The technical guidance in this entry is informed by the following sources:

Additional testing and field validation by SiteConduit.

bacpypes3Anyconstructed dataABSTRACT-SYNTAXBACnet 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.