Encoding

ASN.1 Basic Encoding Rules (BER) implementation for BACnet tag-length-value encoding, primitive type serialization, and APDU framing. Most users interact with encoding indirectly through the service and type layers.

ASN.1 tag-length-value encoding and decoding.

Tags

BACnet tag encoding and decoding per ASHRAE 135-2016 Clause 20.2.1.

class bac_py.encoding.tags.TagClass(*values)[source]

Bases: IntEnum

Tag class indicating application or context-specific encoding.

BACnet uses two tag classes per Clause 20.2.1.1:

  • APPLICATION tags identify the datatype (Null, Boolean, etc.).

  • CONTEXT tags identify a field within a constructed type.

APPLICATION = 0
CONTEXT = 1
class bac_py.encoding.tags.Tag(number, cls, length, is_opening=False, is_closing=False)[source]

Bases: object

A decoded BACnet tag header per Clause 20.2.1.

Represents the tag number, class, data length, and opening/closing status extracted from the tag octets.

Parameters:
number: int

Tag number: datatype for application tags, field index for context tags.

cls: TagClass

Tag class (application or context-specific).

length: int

Content length in bytes, or the raw L/V/T value for application booleans.

is_opening: bool

Whether this is a context-specific opening tag (L/V/T = 6).

is_closing: bool

Whether this is a context-specific closing tag (L/V/T = 7).

property is_boolean_true: bool

Check if this is an APPLICATION boolean tag with value True.

Per Clause 20.2.3, APPLICATION-tagged booleans encode the value in the tag’s L/V/T field with no contents octets. The length field here stores the raw L/V/T value, so a nonzero value means True.

bac_py.encoding.tags.encode_tag(tag_number, cls, length)[source]

Encode a tag header per Clause 20.2.1.

For APPLICATION class tags, the tag number identifies the datatype (0=Null, 1=Boolean, …, 12=ObjectIdentifier). For CONTEXT class tags, the tag number is a context-specific field identifier (0-254).

Parameters:
  • tag_number (int) – Tag number (0-254).

  • cls (TagClass) – Tag class (APPLICATION or CONTEXT).

  • length (int) – Data length in bytes.

Return type:

bytes

Returns:

Encoded tag header bytes.

Raises:

ValueError – If tag_number or length is out of range.

bac_py.encoding.tags.encode_opening_tag(tag_number)[source]

Encode a context-specific opening tag.

Parameters:

tag_number (int) – Context tag number.

Return type:

bytes

Returns:

Encoded opening tag bytes.

bac_py.encoding.tags.encode_closing_tag(tag_number)[source]

Encode a context-specific closing tag.

Parameters:

tag_number (int) – Context tag number.

Return type:

bytes

Returns:

Encoded closing tag bytes.

bac_py.encoding.tags.as_memoryview(data)[source]

Ensure data is a memoryview for efficient zero-copy slicing.

Parameters:

data (bytes | memoryview) – Input bytes or memoryview.

Return type:

memoryview

Returns:

A memoryview wrapping data.

bac_py.encoding.tags.decode_tag(buf, offset)[source]

Decode a tag from buf starting at offset.

Parses the initial tag octet, optional extended tag number, and optional extended length fields per Clause 20.2.1.

Parameters:
  • buf (memoryview | bytes) – Buffer to decode from.

  • offset (int) – Starting byte offset in buf.

Return type:

tuple[Tag, int]

Returns:

Tuple of (decoded Tag, new offset past the tag header).

Raises:

ValueError – If offset is beyond the buffer length.

bac_py.encoding.tags.extract_context_value(data, offset, tag_number)[source]

Extract raw bytes enclosed by a context opening/closing tag pair.

Reads from offset (which should point just past the opening tag) through the matching closing tag, handling nested opening/closing tags.

Parameters:
  • data (memoryview | bytes) – Buffer to read from.

  • offset (int) – Position immediately after the opening tag.

  • tag_number (int) – The context tag number of the enclosing pair.

Return type:

tuple[bytes, int]

Returns:

Tuple of (enclosed raw bytes, offset past the closing tag).

Raises:

ValueError – If the matching closing tag is not found or nesting depth exceeds _MAX_CONTEXT_NESTING_DEPTH.

bac_py.encoding.tags.decode_optional_context(data, offset, tag_number, decode_fn)[source]

Try to decode an optional context-tagged field.

Peeks at the next tag; if it matches the expected context tag number, decodes the value using decode_fn and advances the offset. Otherwise returns (None, offset) unchanged.

Parameters:
  • data (memoryview) – Buffer to decode from (must already be a memoryview).

  • offset (int) – Current position in the buffer.

  • tag_number (int) – Expected context tag number.

  • decode_fn (Callable[[memoryview | bytes], TypeVar(T)]) – Callable to decode the tag’s content bytes.

Return type:

tuple[TypeVar(T) | None, int]

Returns:

Tuple of (decoded value or None, new offset).

Primitive Encoding

BACnet primitive type encoding/decoding per ASHRAE 135-2016 Clause 20.2.

bac_py.encoding.primitives.encode_unsigned(value)[source]

Encode an unsigned integer using the minimum number of octets, big-endian.

BACnet unsigned integers are at most 4 bytes (0..4,294,967,295).

Parameters:

value (int) – Non-negative integer to encode (0–4,294,967,295).

Return type:

bytes

Returns:

Big-endian encoded bytes (1–4 bytes).

Raises:

ValueError – If value is negative or exceeds the 4-byte maximum.

bac_py.encoding.primitives.decode_unsigned(data)[source]

Decode an unsigned integer from big-endian bytes.

Parameters:

data (memoryview | bytes) – One or more bytes encoding a big-endian unsigned integer.

Return type:

int

Returns:

The decoded non-negative integer.

bac_py.encoding.primitives.encode_unsigned64(value)[source]

Encode an unsigned integer using the minimum number of octets, up to 8 bytes.

Used for BACnet Unsigned64 fields such as audit log sequence numbers.

Parameters:

value (int) – Non-negative integer to encode (0–18,446,744,073,709,551,615).

Return type:

bytes

Returns:

Big-endian encoded bytes (1–8 bytes).

Raises:

ValueError – If value is negative or exceeds the 8-byte maximum.

bac_py.encoding.primitives.decode_unsigned64(data)[source]

Decode an unsigned integer from big-endian bytes (up to 8 bytes).

Parameters:

data (memoryview | bytes) – One or more bytes encoding a big-endian unsigned integer.

Return type:

int

Returns:

The decoded non-negative integer.

bac_py.encoding.primitives.encode_signed(value)[source]

Encode a signed integer using minimum octets, two’s complement, big-endian.

BACnet signed integers are at most 4 bytes (-2,147,483,648..2,147,483,647).

Parameters:

value (int) – Signed integer to encode (-2,147,483,648..2,147,483,647).

Return type:

bytes

Returns:

Two’s-complement big-endian encoded bytes (1–4 bytes).

Raises:

ValueError – If value is outside the 4-byte signed range.

bac_py.encoding.primitives.decode_signed(data)[source]

Decode a signed integer from two’s-complement big-endian bytes.

Parameters:

data (memoryview | bytes) – One or more bytes encoding a two’s-complement big-endian signed integer.

Return type:

int

Returns:

The decoded signed integer.

bac_py.encoding.primitives.encode_real(value)[source]

Encode an IEEE-754 single-precision (32-bit) float.

Parameters:

value (float) – Floating-point value to encode.

Return type:

bytes

Returns:

4 bytes in big-endian IEEE-754 single-precision format.

bac_py.encoding.primitives.decode_real(data)[source]

Decode an IEEE-754 single-precision (32-bit) float.

Parameters:

data (memoryview | bytes) – At least 4 bytes of big-endian IEEE-754 single-precision data.

Return type:

float

Returns:

The decoded floating-point value.

Raises:

ValueError – If data contains fewer than 4 bytes.

bac_py.encoding.primitives.encode_double(value)[source]

Encode an IEEE-754 double-precision (64-bit) float.

Parameters:

value (float) – Floating-point value to encode.

Return type:

bytes

Returns:

8 bytes in big-endian IEEE-754 double-precision format.

bac_py.encoding.primitives.decode_double(data)[source]

Decode an IEEE-754 double-precision (64-bit) float.

Parameters:

data (memoryview | bytes) – At least 8 bytes of big-endian IEEE-754 double-precision data.

Return type:

float

Returns:

The decoded floating-point value.

Raises:

ValueError – If data contains fewer than 8 bytes.

bac_py.encoding.primitives.decode_octet_string(data)[source]

Decode an octet string by copying the raw bytes.

Parameters:

data (memoryview | bytes) – Raw octet-string content bytes.

Return type:

bytes

Returns:

A copy of the input as a bytes object.

bac_py.encoding.primitives.encode_character_string(value, charset=0)[source]

Encode a character string with a leading charset byte.

Parameters:
  • value (str) – The string to encode.

  • charset (int (default: 0)) – Character set identifier (default 0x00 = UTF-8).

Return type:

bytes

Returns:

Encoded bytes with leading charset byte.

Raises:

ValueError – If charset is not a supported BACnet character set.

bac_py.encoding.primitives.decode_character_string(data)[source]

Decode a character string from contents octets.

The first byte is the character set identifier. Unknown charsets fall back to latin-1 decoding with a warning log rather than raising, to preserve data from devices using non-standard charsets.

Parameters:

data (memoryview | bytes) – Contents octets with leading charset byte.

Return type:

str

Returns:

The decoded Python string.

Raises:

ValueError – If data is empty.

bac_py.encoding.primitives.encode_enumerated(value)[source]

Encode an enumerated value (same encoding as unsigned).

Parameters:

value (int) – Enumerated value to encode.

Return type:

bytes

Returns:

Big-endian encoded bytes.

bac_py.encoding.primitives.decode_enumerated(data)[source]

Decode an enumerated value (same encoding as unsigned).

Parameters:

data (memoryview | bytes) – Big-endian encoded bytes.

Return type:

int

Returns:

The decoded enumerated value as an integer.

bac_py.encoding.primitives.encode_bit_string(value)[source]

Encode a bit string with a leading unused-bits count byte.

Parameters:

value (BitString) – The BitString to encode.

Return type:

bytes

Returns:

Encoded bytes with leading unused-bits count followed by the bit data.

bac_py.encoding.primitives.decode_bit_string(data)[source]

Decode a bit string from contents octets.

Parameters:

data (memoryview | bytes) – Contents octets with leading unused-bits count byte.

Return type:

BitString

Returns:

The decoded BitString.

Raises:

ValueError – If data is empty.

bac_py.encoding.primitives.encode_date(date)[source]

Encode a BACnetDate to 4 bytes: year-1900, month, day, day-of-week.

Valid years are 1900–2155 or 0xFF (unspecified).

Parameters:

date (BACnetDate) – The BACnetDate to encode.

Return type:

bytes

Returns:

4 bytes representing the encoded date.

Raises:

ValueError – If the year is outside the valid range.

bac_py.encoding.primitives.decode_date(data)[source]

Decode a BACnetDate from 4 bytes.

Parameters:

data (memoryview | bytes) – At least 4 bytes of encoded date data.

Return type:

BACnetDate

Returns:

The decoded BACnetDate.

Raises:

ValueError – If data contains fewer than 4 bytes.

bac_py.encoding.primitives.encode_time(time)[source]

Encode a BACnetTime to 4 bytes: hour, minute, second, hundredth.

Parameters:

time (BACnetTime) – The BACnetTime to encode.

Return type:

bytes

Returns:

4 bytes representing the encoded time.

bac_py.encoding.primitives.decode_time(data)[source]

Decode a BACnetTime from 4 bytes.

Parameters:

data (memoryview | bytes) – At least 4 bytes of encoded time data.

Return type:

BACnetTime

Returns:

The decoded BACnetTime.

Raises:

ValueError – If data contains fewer than 4 bytes.

bac_py.encoding.primitives.encode_object_identifier(obj_type, instance)[source]

Encode a BACnet object identifier to 4 bytes.

Object type is a 10-bit field (0–1023). Instance is a 22-bit field (0–4,194,303). Delegates to ObjectIdentifier for encoding.

Parameters:
  • obj_type (int) – Object type number (0–1023).

  • instance (int) – Instance number (0–4,194,303).

Return type:

bytes

Returns:

4 bytes encoding the object identifier.

bac_py.encoding.primitives.decode_object_identifier(data)[source]

Decode a BACnet object identifier from 4 bytes.

Parameters:

data (memoryview | bytes) – At least 4 bytes of encoded object identifier data.

Return type:

tuple[int, int]

Returns:

Tuple of (object_type, instance_number).

Raises:

ValueError – If data contains fewer than 4 bytes.

bac_py.encoding.primitives.encode_boolean(value)[source]

Encode a boolean value as a single contents octet.

For context-tagged booleans. Application-tagged booleans encode the value in the tag itself.

Parameters:

value (bool) – The boolean value to encode.

Return type:

bytes

Returns:

A single byte (0x01 for True, 0x00 for False).

bac_py.encoding.primitives.decode_boolean(data)[source]

Decode a boolean value from a single contents octet.

Parameters:

data (memoryview | bytes) – At least 1 byte; the first byte is interpreted as the boolean value.

Return type:

bool

Returns:

True if the first byte is non-zero, False otherwise.

Raises:

ValueError – If data is empty.

bac_py.encoding.primitives.encode_application_tagged(tag_number, data)[source]

Encode data with an application tag.

Parameters:
  • tag_number (int) – Application tag number identifying the data type.

  • data (bytes) – Encoded content bytes to wrap with the tag.

Return type:

bytes

Returns:

Application-tagged encoded bytes.

bac_py.encoding.primitives.encode_context_tagged(tag_number, data)[source]

Encode data with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • data (bytes) – Encoded content bytes to wrap with the tag.

Return type:

bytes

Returns:

Context-tagged encoded bytes.

bac_py.encoding.primitives.encode_application_null()[source]

Encode an application-tagged Null.

Return type:

bytes

Returns:

Application-tagged Null encoding (tag only, no content).

bac_py.encoding.primitives.encode_application_boolean(value)[source]

Encode an application-tagged Boolean.

Per Clause 20.2.3, the value is encoded in the L/V/T bits of the tag with no contents octet.

Parameters:

value (bool) – The boolean value to encode.

Return type:

bytes

Returns:

Application-tagged Boolean encoding.

bac_py.encoding.primitives.encode_application_unsigned(value)[source]

Encode an application-tagged Unsigned Integer.

Parameters:

value (int) – Non-negative integer to encode.

Return type:

bytes

Returns:

Application-tagged Unsigned Integer encoding.

bac_py.encoding.primitives.encode_application_signed(value)[source]

Encode an application-tagged Signed Integer.

Parameters:

value (int) – Signed integer to encode.

Return type:

bytes

Returns:

Application-tagged Signed Integer encoding.

bac_py.encoding.primitives.encode_application_real(value)[source]

Encode an application-tagged Real.

Parameters:

value (float) – Floating-point value to encode.

Return type:

bytes

Returns:

Application-tagged Real encoding.

bac_py.encoding.primitives.encode_application_double(value)[source]

Encode an application-tagged Double.

Parameters:

value (float) – Floating-point value to encode.

Return type:

bytes

Returns:

Application-tagged Double encoding.

bac_py.encoding.primitives.encode_application_octet_string(value)[source]

Encode an application-tagged Octet String.

Parameters:

value (bytes) – Raw bytes to encode.

Return type:

bytes

Returns:

Application-tagged Octet String encoding.

bac_py.encoding.primitives.encode_application_character_string(value)[source]

Encode an application-tagged Character String.

Parameters:

value (str) – String to encode (UTF-8 by default).

Return type:

bytes

Returns:

Application-tagged Character String encoding.

bac_py.encoding.primitives.encode_application_enumerated(value)[source]

Encode an application-tagged Enumerated.

Parameters:

value (int) – Enumerated value to encode.

Return type:

bytes

Returns:

Application-tagged Enumerated encoding.

bac_py.encoding.primitives.encode_application_date(date)[source]

Encode an application-tagged Date.

Parameters:

date (BACnetDate) – The BACnetDate to encode.

Return type:

bytes

Returns:

Application-tagged Date encoding.

bac_py.encoding.primitives.encode_application_time(time)[source]

Encode an application-tagged Time.

Parameters:

time (BACnetTime) – The BACnetTime to encode.

Return type:

bytes

Returns:

Application-tagged Time encoding.

bac_py.encoding.primitives.encode_application_object_id(obj_type, instance)[source]

Encode an application-tagged Object Identifier.

Parameters:
  • obj_type (int) – Object type number.

  • instance (int) – Instance number.

Return type:

bytes

Returns:

Application-tagged Object Identifier encoding.

bac_py.encoding.primitives.encode_context_object_id(tag_number, obj_id)[source]

Encode an ObjectIdentifier with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • obj_id (ObjectIdentifier) – The ObjectIdentifier to encode.

Return type:

bytes

Returns:

Context-tagged Object Identifier encoding.

bac_py.encoding.primitives.encode_context_unsigned(tag_number, value)[source]

Encode an unsigned integer with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (int) – Non-negative integer to encode.

Return type:

bytes

Returns:

Context-tagged unsigned integer encoding.

bac_py.encoding.primitives.encode_context_signed(tag_number, value)[source]

Encode a signed integer with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (int) – Signed integer to encode.

Return type:

bytes

Returns:

Context-tagged signed integer encoding.

bac_py.encoding.primitives.encode_context_enumerated(tag_number, value)[source]

Encode an enumerated value with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (int) – Enumerated value to encode.

Return type:

bytes

Returns:

Context-tagged enumerated encoding.

bac_py.encoding.primitives.encode_context_boolean(tag_number, value)[source]

Encode a boolean with a context-specific tag.

Context-tagged booleans use a 1-byte contents octet, unlike application-tagged booleans which encode the value in the tag LVT.

Parameters:
  • tag_number (int) – Context tag number.

  • value (bool) – The boolean value to encode.

Return type:

bytes

Returns:

Context-tagged boolean encoding.

bac_py.encoding.primitives.encode_context_real(tag_number, value)[source]

Encode a Real with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (float) – Floating-point value to encode.

Return type:

bytes

Returns:

Context-tagged Real encoding.

bac_py.encoding.primitives.encode_context_octet_string(tag_number, value)[source]

Encode an octet string with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (bytes) – Raw bytes to encode.

Return type:

bytes

Returns:

Context-tagged octet string encoding.

bac_py.encoding.primitives.encode_context_bit_string(tag_number, value)[source]

Encode a bit string with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (BitString) – The BitString to encode.

Return type:

bytes

Returns:

Context-tagged bit string encoding.

bac_py.encoding.primitives.encode_context_date(tag_number, value)[source]

Encode a date with a context-specific tag.

Parameters:
  • tag_number (int) – Context tag number.

  • value (BACnetDate) – The BACnetDate to encode.

Return type:

bytes

Returns:

Context-tagged date encoding.

bac_py.encoding.primitives.encode_application_bit_string(value)[source]

Encode an application-tagged Bit String.

Parameters:

value (BitString) – The BitString to encode.

Return type:

bytes

Returns:

Application-tagged Bit String encoding.

bac_py.encoding.primitives.decode_application_value(data)[source]

Decode application-tagged bytes to a native Python value.

Inspects the application tag number and dispatches to the appropriate decoder. Returns native Python types:

Tag 0 (Null) -> None Tag 1 (Boolean) -> bool Tag 2 (Unsigned) -> int Tag 3 (Signed) -> int Tag 4 (Real) -> float Tag 5 (Double) -> float Tag 6 (Octet String) -> bytes Tag 7 (Character String) -> str Tag 8 (Bit String) -> BitString Tag 9 (Enumerated) -> int Tag 10 (Date) -> BACnetDate Tag 11 (Time) -> BACnetTime Tag 12 (Object Id) -> ObjectIdentifier

Parameters:

data (bytes | memoryview) – Application-tagged encoded bytes.

Return type:

object

Returns:

Decoded Python value.

Raises:

ValueError – If the tag is not application-class or is unrecognised.

Example:

from bac_py.encoding.primitives import (
    decode_application_value,
    encode_application_real,
)

encoded = encode_application_real(72.5)
value = decode_application_value(encoded)  # -> 72.5
bac_py.encoding.primitives.decode_all_application_values(data)[source]

Decode all application-tagged values from concatenated bytes.

Iterates through the buffer, decoding each application-tagged element and collecting them into a list.

Parameters:

data (bytes | memoryview) – Concatenated application-tagged encoded bytes.

Return type:

list[object]

Returns:

List of decoded Python values.

Raises:

ValueError – If a non-application tag is encountered or the number of decoded values exceeds _MAX_DECODED_VALUES.

bac_py.encoding.primitives.decode_and_unwrap(data)[source]

Decode application-tagged bytes and unwrap single-element lists.

Convenience wrapper around decode_all_application_values() that returns a single value directly when the data contains exactly one application-tagged element, None for empty data, or the full list for multiple elements.

Parameters:

data (bytes | memoryview) – Concatenated application-tagged encoded bytes.

Return type:

object

Returns:

None if data decodes to zero elements, the single decoded value if exactly one element, or a list of decoded values if multiple elements.

bac_py.encoding.primitives.encode_property_value(value, *, int_as_real=False)[source]

Encode a Python value to application-tagged bytes.

Handles the common types stored in BACnet object properties, including both primitive and constructed BACnet types.

Parameters:
  • value (object) – The value to encode.

  • int_as_real (bool (default: False)) – If True, encode plain int values as Real instead of Unsigned (used for analog object types where Present_Value is Real).

Return type:

bytes

Returns:

Application-tagged encoded bytes.

Raises:

TypeError – If the value type is not supported.

APDU Encoding

APDU encoding and decoding per ASHRAE 135-2016 Clause 20.1.

class bac_py.encoding.apdu.ConfirmedRequestPDU(segmented, more_follows, segmented_response_accepted, max_segments, max_apdu_length, invoke_id, sequence_number, proposed_window_size, service_choice, service_request)[source]

Bases: object

BACnet Confirmed-Request PDU (Clause 20.1.2).

Parameters:
  • segmented (bool)

  • more_follows (bool)

  • segmented_response_accepted (bool)

  • max_segments (int | None)

  • max_apdu_length (int)

  • invoke_id (int)

  • sequence_number (int | None)

  • proposed_window_size (int | None)

  • service_choice (int)

  • service_request (bytes)

segmented: bool

Whether this PDU is a segment of a larger message.

more_follows: bool

Whether more segments follow this one.

segmented_response_accepted: bool

Whether the sender can accept a segmented response.

max_segments: int | None

Maximum number of segments the sender can accept, or None for unspecified.

max_apdu_length: int

Maximum APDU length in bytes the sender can accept.

invoke_id: int

Invoke ID for matching requests to responses (0-255).

sequence_number: int | None

Segment sequence number, or None if not segmented.

proposed_window_size: int | None

Proposed window size for segmentation, or None if not segmented.

service_choice: int

Confirmed service choice number.

service_request: bytes

Encoded service request parameters.

class bac_py.encoding.apdu.UnconfirmedRequestPDU(service_choice, service_request)[source]

Bases: object

BACnet Unconfirmed-Request PDU (Clause 20.1.3).

Parameters:
  • service_choice (int)

  • service_request (bytes)

service_choice: int

Unconfirmed service choice number.

service_request: bytes

Encoded service request parameters.

class bac_py.encoding.apdu.SimpleAckPDU(invoke_id, service_choice)[source]

Bases: object

BACnet SimpleACK PDU (Clause 20.1.4).

Parameters:
  • invoke_id (int)

  • service_choice (int)

invoke_id: int

Invoke ID of the confirmed request being acknowledged.

service_choice: int

Service choice of the confirmed request being acknowledged.

class bac_py.encoding.apdu.ComplexAckPDU(segmented, more_follows, invoke_id, sequence_number, proposed_window_size, service_choice, service_ack)[source]

Bases: object

BACnet ComplexACK PDU (Clause 20.1.5).

Parameters:
  • segmented (bool)

  • more_follows (bool)

  • invoke_id (int)

  • sequence_number (int | None)

  • proposed_window_size (int | None)

  • service_choice (int)

  • service_ack (bytes)

segmented: bool

Whether this PDU is a segment of a larger response.

more_follows: bool

Whether more segments follow this one.

invoke_id: int

Invoke ID of the confirmed request being acknowledged.

sequence_number: int | None

Segment sequence number, or None if not segmented.

proposed_window_size: int | None

Proposed window size for segmentation, or None if not segmented.

service_choice: int

Service choice of the confirmed request being acknowledged.

service_ack: bytes

Encoded service response parameters.

class bac_py.encoding.apdu.SegmentAckPDU(negative_ack, sent_by_server, invoke_id, sequence_number, actual_window_size)[source]

Bases: object

BACnet SegmentACK PDU (Clause 20.1.6).

Parameters:
  • negative_ack (bool)

  • sent_by_server (bool)

  • invoke_id (int)

  • sequence_number (int)

  • actual_window_size (int)

negative_ack: bool

Whether this is a negative acknowledgement (requesting retransmission).

sent_by_server: bool

Whether the server (not the client) sent this SegmentACK.

invoke_id: int

Invoke ID of the segmented transaction.

sequence_number: int

Sequence number of the last segment received.

actual_window_size: int

Actual window size the sender can accept.

class bac_py.encoding.apdu.ErrorPDU(invoke_id, service_choice, error_class, error_code, error_data=b'')[source]

Bases: object

BACnet Error PDU (Clause 20.1.7).

Represents the error response with error-class, error-code, and optional trailing error data for extended error types (e.g. ChangeList-Error, CreateObject-Error).

Parameters:
invoke_id: int

Invoke ID of the confirmed request that caused the error.

service_choice: int

Service choice of the confirmed request that caused the error.

error_class: ErrorClass

Error class categorising the error (e.g. object, property, resource).

error_code: ErrorCode

Specific error code within the error class.

error_data: bytes

Optional trailing bytes for extended error types.

class bac_py.encoding.apdu.RejectPDU(invoke_id, reject_reason)[source]

Bases: object

BACnet Reject PDU (Clause 20.1.8).

Parameters:
invoke_id: int

Invoke ID of the confirmed request being rejected.

reject_reason: RejectReason

Reason the request was rejected.

class bac_py.encoding.apdu.AbortPDU(sent_by_server, invoke_id, abort_reason)[source]

Bases: object

BACnet Abort PDU (Clause 20.1.9).

Parameters:
sent_by_server: bool

Whether the server (not the client) initiated the abort.

invoke_id: int

Invoke ID of the transaction being aborted.

abort_reason: AbortReason

Reason the transaction was aborted.

bac_py.encoding.apdu.encode_apdu(pdu)[source]

Encode an APDU dataclass to wire-format bytes.

Dispatches to the appropriate encoder based on the PDU type.

Parameters:

pdu (ConfirmedRequestPDU | UnconfirmedRequestPDU | SimpleAckPDU | ComplexAckPDU | SegmentAckPDU | ErrorPDU | RejectPDU | AbortPDU) – The PDU dataclass instance to encode.

Return type:

bytes

Returns:

Encoded APDU bytes ready for transmission.

Raises:

TypeError – If pdu is not a recognised PDU type.

bac_py.encoding.apdu.decode_apdu(data)[source]

Decode an APDU from raw bytes.

Inspects the PDU type nibble in the first byte and dispatches to the appropriate decoder.

Parameters:

data (memoryview | bytes) – Raw APDU bytes.

Return type:

ConfirmedRequestPDU | UnconfirmedRequestPDU | SimpleAckPDU | ComplexAckPDU | SegmentAckPDU | ErrorPDU | RejectPDU | AbortPDU

Returns:

Decoded PDU dataclass instance.

Raises:
  • ValueError – If data is too short to decode.

  • TypeError – If the PDU type is not recognised.