Base and Device

Base Object Model

BACnet object base classes per ASHRAE 135-2016 Clause 12.

class bac_py.objects.base.PropertyAccess(*values)[source]

Bases: IntEnum

Property access mode.

READ_ONLY = 0
READ_WRITE = 1
class bac_py.objects.base.PropertyDefinition(identifier, datatype, access, required, default=None)[source]

Bases: object

Metadata for a single BACnet property.

Parameters:
identifier: PropertyIdentifier

The PropertyIdentifier for this property.

datatype: type

Expected Python type for the property value.

access: PropertyAccess

Read-only or read-write access mode.

required: bool

Whether the property is required by the BACnet standard.

default: Any

Default value assigned on object creation, or None.

bac_py.objects.base.standard_properties()[source]

Return properties common to all BACnet objects (Clause 12.1).

Includes the required Object_Identifier/Object_Name/Object_Type triad, the optional Description, and the required Property_List.

Return type:

dict[PropertyIdentifier, PropertyDefinition]

Returns:

Mapping of PropertyIdentifier to PropertyDefinition.

bac_py.objects.base.status_properties(*, event_state_required=True, reliability_required=False, reliability_default=None, include_out_of_service=True)[source]

Return status monitoring properties shared by most objects (Clause 12).

Includes Status_Flags, Event_State, Reliability, and optionally Out_Of_Service. Keyword arguments allow per-object-type overrides.

Parameters:
  • event_state_required (bool (default: True)) – Whether Event_State is required.

  • reliability_required (bool (default: False)) – Whether Reliability is required.

  • reliability_default (Reliability | None (default: None)) – Default value for Reliability, or None.

  • include_out_of_service (bool (default: True)) – Whether to include the Out_Of_Service property.

Return type:

dict[PropertyIdentifier, PropertyDefinition]

Returns:

Mapping of PropertyIdentifier to PropertyDefinition.

bac_py.objects.base.commandable_properties(value_type, default, *, required=True)[source]

Return properties for commandable objects (Clause 19).

Parameters:
  • value_type (type) – Type of the Relinquish_Default value.

  • default (Any) – Default value for Relinquish_Default.

  • required (bool (default: True)) – Whether commandable properties are required (True for Output objects, False for optionally commandable Values).

Return type:

dict[PropertyIdentifier, PropertyDefinition]

Returns:

Mapping of PropertyIdentifier to PropertyDefinition.

bac_py.objects.base.intrinsic_reporting_properties(*, include_limit=False)[source]

Return optional intrinsic reporting properties (Clause 12, Clause 13).

These properties enable alarm/event reporting without a separate EventEnrollment object. All are optional – objects opt in by merging this dict into their PROPERTY_DEFINITIONS.

Parameters:

include_limit (bool (default: False)) – If True, include analog-specific limit detection properties (High_Limit, Low_Limit, Deadband, Limit_Enable).

Return type:

dict[PropertyIdentifier, PropertyDefinition]

Returns:

Mapping of PropertyIdentifier to PropertyDefinition.

class bac_py.objects.base.BACnetObject(instance_number, **initial_properties)[source]

Bases: object

Base class for all BACnet objects.

Each subclass defines its property schema via class-level PROPERTY_DEFINITIONS. Properties are stored in a dict and accessed via typed read/write methods.

Parameters:
  • instance_number (int)

  • initial_properties (Any)

OBJECT_TYPE: ClassVar[ObjectType]
PROPERTY_DEFINITIONS: ClassVar[dict[PropertyIdentifier, PropertyDefinition]]
INTRINSIC_EVENT_ALGORITHM: ClassVar[EventType | None] = None

Event algorithm for intrinsic reporting, or None if not supported.

property object_identifier: ObjectIdentifier

The ObjectIdentifier for this object.

read_property(prop_id, array_index=None)[source]

Read a property value.

Parameters:
  • prop_id (PropertyIdentifier) – Property identifier to read.

  • array_index (int | None (default: None)) – Optional array index for array properties.

Return type:

Any

Returns:

The property value.

Raises:

BACnetError – If the property is unknown or array_index is invalid.

write_property(prop_id, value, priority=None, array_index=None)[source]

Write a property value.

Parameters:
  • prop_id (PropertyIdentifier) – Property identifier to write.

  • value (Any) – Value to write.

  • priority (int | None (default: None)) – Optional priority for commandable properties (1-16).

  • array_index (int | None (default: None)) – Optional array index for array properties.

Raises:

BACnetError – If the property is unknown, read-only, or priority / array_index is invalid.

Return type:

None

async async_write_property(prop_id, value, priority=None, array_index=None)[source]

Write a property value with concurrency protection.

Uses an asyncio.Lock to serialize writes to this object.

Parameters:
  • prop_id (PropertyIdentifier) – Property identifier to write.

  • value (Any) – Value to write.

  • priority (int | None (default: None)) – Optional priority for commandable properties (1-16).

  • array_index (int | None (default: None)) – Optional array index for array properties.

Return type:

None

class bac_py.objects.base.ObjectDatabase[source]

Bases: object

Container for all BACnet objects in a device.

Enforces Object_Name uniqueness per Clause 12.1.5.

add(obj)[source]

Add an object to the database.

Parameters:

obj (BACnetObject) – The BACnetObject to register.

Raises:

BACnetError – If an object with the same identifier or name already exists.

Return type:

None

remove(object_id)[source]

Remove an object from the database.

Parameters:

object_id (ObjectIdentifier) – Identifier of the object to remove.

Raises:

BACnetError – If the object does not exist or is a Device object.

Return type:

None

validate_name_unique(name, exclude=None)[source]

Check that a name is unique within the database.

Parameters:
  • name (str) – The object name to check.

  • exclude (ObjectIdentifier | None (default: None)) – Object identifier to exclude (for rename operations).

Raises:

BACnetError – If name is already in use by another object.

Return type:

None

register_change_callback(object_id, prop_id, callback)[source]

Register a callback fired when a property value changes.

The callback receives (prop_id, old_value, new_value) after a successful write that changes the value.

Parameters:
Return type:

None

unregister_change_callback(object_id, prop_id, callback)[source]

Remove a previously registered change callback.

Parameters:
Return type:

None

get(object_id)[source]

Retrieve an object by its identifier.

Parameters:

object_id (ObjectIdentifier) – The ObjectIdentifier to look up.

Return type:

BACnetObject | None

Returns:

The BACnetObject, or None if not found.

get_objects_of_type(obj_type)[source]

Retrieve all objects matching a given type.

Parameters:

obj_type (ObjectType) – The ObjectType to filter by.

Return type:

list[BACnetObject]

Returns:

List of matching BACnetObject instances.

property object_list: list[ObjectIdentifier]

List of all ObjectIdentifier values in the database.

values()[source]

Iterate over all BACnetObject instances in the database.

Return type:

Iterator[BACnetObject]

bac_py.objects.base.register_object_type(cls)[source]

Class decorator to register a BACnetObject subclass in the factory.

Parameters:

cls (type[BACnetObject]) – The BACnetObject subclass to register.

Return type:

type[BACnetObject]

Returns:

The same class, unmodified.

bac_py.objects.base.create_object(object_type, instance_number, **properties)[source]

Create a BACnetObject by type using the registry.

Parameters:
  • object_type (ObjectType) – BACnet object type.

  • instance_number (int) – Instance number for the new object.

  • properties (Any) – Initial property values.

Return type:

BACnetObject

Returns:

New BACnetObject instance.

Raises:

BACnetError – If the object type is not registered.

Device Object

BACnet Device object per ASHRAE 135-2020 Clause 12.11.

class bac_py.objects.device.DeviceObject(instance_number, **initial_properties)[source]

Bases: BACnetObject

BACnet Device object (Clause 12.11).

Every BACnet device must have exactly one Device object.

Parameters:
  • instance_number (int)

  • initial_properties (Any)

OBJECT_TYPE: ClassVar[ObjectType] = 8
PROPERTY_DEFINITIONS: ClassVar[dict[PropertyIdentifier, PropertyDefinition]] = {PropertyIdentifier.APDU_SEGMENT_TIMEOUT: PropertyDefinition(identifier=<PropertyIdentifier.APDU_SEGMENT_TIMEOUT: 10>, datatype=<class 'int'>, access=<PropertyAccess.READ_WRITE: 1>, required=True, default=2000), PropertyIdentifier.APDU_TIMEOUT: PropertyDefinition(identifier=<PropertyIdentifier.APDU_TIMEOUT: 11>, datatype=<class 'int'>, access=<PropertyAccess.READ_WRITE: 1>, required=True, default=6000), PropertyIdentifier.APPLICATION_SOFTWARE_VERSION: PropertyDefinition(identifier=<PropertyIdentifier.APPLICATION_SOFTWARE_VERSION: 12>, datatype=<class 'str'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.DESCRIPTION: PropertyDefinition(identifier=<PropertyIdentifier.DESCRIPTION: 28>, datatype=<class 'str'>, access=<PropertyAccess.READ_WRITE: 1>, required=False, default=None), PropertyIdentifier.DEVICE_ADDRESS_BINDING: PropertyDefinition(identifier=<PropertyIdentifier.DEVICE_ADDRESS_BINDING: 30>, datatype=<class 'list'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=[]), PropertyIdentifier.FIRMWARE_REVISION: PropertyDefinition(identifier=<PropertyIdentifier.FIRMWARE_REVISION: 44>, datatype=<class 'str'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.MAX_APDU_LENGTH_ACCEPTED: PropertyDefinition(identifier=<PropertyIdentifier.MAX_APDU_LENGTH_ACCEPTED: 62>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=1476), PropertyIdentifier.MODEL_NAME: PropertyDefinition(identifier=<PropertyIdentifier.MODEL_NAME: 70>, datatype=<class 'str'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.NUMBER_OF_APDU_RETRIES: PropertyDefinition(identifier=<PropertyIdentifier.NUMBER_OF_APDU_RETRIES: 73>, datatype=<class 'int'>, access=<PropertyAccess.READ_WRITE: 1>, required=True, default=3), PropertyIdentifier.OBJECT_IDENTIFIER: PropertyDefinition(identifier=<PropertyIdentifier.OBJECT_IDENTIFIER: 75>, datatype=<class 'bac_py.types.primitives.ObjectIdentifier'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.OBJECT_LIST: PropertyDefinition(identifier=<PropertyIdentifier.OBJECT_LIST: 76>, datatype=<class 'list'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.OBJECT_NAME: PropertyDefinition(identifier=<PropertyIdentifier.OBJECT_NAME: 77>, datatype=<class 'str'>, access=<PropertyAccess.READ_WRITE: 1>, required=True, default=None), PropertyIdentifier.OBJECT_TYPE: PropertyDefinition(identifier=<PropertyIdentifier.OBJECT_TYPE: 79>, datatype=<enum 'ObjectType'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.PROTOCOL_OBJECT_TYPES_SUPPORTED: PropertyDefinition(identifier=<PropertyIdentifier.PROTOCOL_OBJECT_TYPES_SUPPORTED: 96>, datatype=<class 'bac_py.types.primitives.BitString'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED: PropertyDefinition(identifier=<PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED: 97>, datatype=<class 'bac_py.types.primitives.BitString'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.PROTOCOL_VERSION: PropertyDefinition(identifier=<PropertyIdentifier.PROTOCOL_VERSION: 98>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=1), PropertyIdentifier.SEGMENTATION_SUPPORTED: PropertyDefinition(identifier=<PropertyIdentifier.SEGMENTATION_SUPPORTED: 107>, datatype=<enum 'Segmentation'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=<Segmentation.BOTH: 0>), PropertyIdentifier.SYSTEM_STATUS: PropertyDefinition(identifier=<PropertyIdentifier.SYSTEM_STATUS: 112>, datatype=<enum 'DeviceStatus'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=<DeviceStatus.OPERATIONAL: 0>), PropertyIdentifier.VENDOR_IDENTIFIER: PropertyDefinition(identifier=<PropertyIdentifier.VENDOR_IDENTIFIER: 120>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.VENDOR_NAME: PropertyDefinition(identifier=<PropertyIdentifier.VENDOR_NAME: 121>, datatype=<class 'str'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.PROTOCOL_REVISION: PropertyDefinition(identifier=<PropertyIdentifier.PROTOCOL_REVISION: 139>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=22), PropertyIdentifier.ACTIVE_COV_SUBSCRIPTIONS: PropertyDefinition(identifier=<PropertyIdentifier.ACTIVE_COV_SUBSCRIPTIONS: 152>, datatype=<class 'list'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=None), PropertyIdentifier.BACKUP_FAILURE_TIMEOUT: PropertyDefinition(identifier=<PropertyIdentifier.BACKUP_FAILURE_TIMEOUT: 153>, datatype=<class 'int'>, access=<PropertyAccess.READ_WRITE: 1>, required=False, default=300), PropertyIdentifier.CONFIGURATION_FILES: PropertyDefinition(identifier=<PropertyIdentifier.CONFIGURATION_FILES: 154>, datatype=<class 'list'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=None), PropertyIdentifier.DATABASE_REVISION: PropertyDefinition(identifier=<PropertyIdentifier.DATABASE_REVISION: 155>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=0), PropertyIdentifier.LAST_RESTORE_TIME: PropertyDefinition(identifier=<PropertyIdentifier.LAST_RESTORE_TIME: 157>, datatype=<class 'object'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=None), PropertyIdentifier.MAX_SEGMENTS_ACCEPTED: PropertyDefinition(identifier=<PropertyIdentifier.MAX_SEGMENTS_ACCEPTED: 167>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=64), PropertyIdentifier.PROFILE_NAME: PropertyDefinition(identifier=<PropertyIdentifier.PROFILE_NAME: 168>, datatype=<class 'str'>, access=<PropertyAccess.READ_WRITE: 1>, required=False, default=None), PropertyIdentifier.BACKUP_AND_RESTORE_STATE: PropertyDefinition(identifier=<PropertyIdentifier.BACKUP_AND_RESTORE_STATE: 338>, datatype=<enum 'BackupAndRestoreState'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=<BackupAndRestoreState.IDLE: 0>), PropertyIdentifier.BACKUP_PREPARATION_TIME: PropertyDefinition(identifier=<PropertyIdentifier.BACKUP_PREPARATION_TIME: 339>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=None), PropertyIdentifier.RESTORE_COMPLETION_TIME: PropertyDefinition(identifier=<PropertyIdentifier.RESTORE_COMPLETION_TIME: 340>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=None), PropertyIdentifier.RESTORE_PREPARATION_TIME: PropertyDefinition(identifier=<PropertyIdentifier.RESTORE_PREPARATION_TIME: 341>, datatype=<class 'int'>, access=<PropertyAccess.READ_ONLY: 0>, required=False, default=None), PropertyIdentifier.PROPERTY_LIST: PropertyDefinition(identifier=<PropertyIdentifier.PROPERTY_LIST: 371>, datatype=<class 'list'>, access=<PropertyAccess.READ_ONLY: 0>, required=True, default=None), PropertyIdentifier.PROFILE_LOCATION: PropertyDefinition(identifier=<PropertyIdentifier.PROFILE_LOCATION: 485>, datatype=<class 'str'>, access=<PropertyAccess.READ_WRITE: 1>, required=False, default=None), PropertyIdentifier.TAGS: PropertyDefinition(identifier=<PropertyIdentifier.TAGS: 486>, datatype=<class 'list'>, access=<PropertyAccess.READ_WRITE: 1>, required=False, default=None)}
read_property(prop_id, array_index=None)[source]

Read property with virtual Object_List from database (Clause 12.11.19).

Return type:

Any

Parameters: