Source code for bac_py.services.private_transfer
"""Private transfer services per ASHRAE 135-2016 Clause 16.2-16.3.
ConfirmedPrivateTransfer (Clause 16.2), UnconfirmedPrivateTransfer (Clause 16.3).
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Self
from bac_py.encoding.primitives import (
decode_unsigned,
encode_context_tagged,
encode_unsigned,
)
from bac_py.encoding.tags import (
as_memoryview,
decode_tag,
encode_closing_tag,
encode_opening_tag,
extract_context_value,
)
[docs]
@dataclass(frozen=True, slots=True)
class ConfirmedPrivateTransferRequest:
"""ConfirmedPrivateTransfer-Request (Clause 16.2.1.1).
::
ConfirmedPrivateTransfer-Request ::= SEQUENCE {
vendorID [0] Unsigned,
serviceNumber [1] Unsigned,
serviceParameters [2] ABSTRACT-SYNTAX.&TYPE OPTIONAL
}
"""
vendor_id: int
service_number: int
service_parameters: bytes | None = None
[docs]
def encode(self) -> bytes:
"""Encode ConfirmedPrivateTransfer-Request service parameters.
:returns: Encoded service request bytes.
"""
buf = bytearray()
buf.extend(encode_context_tagged(0, encode_unsigned(self.vendor_id)))
buf.extend(encode_context_tagged(1, encode_unsigned(self.service_number)))
if self.service_parameters is not None:
buf.extend(encode_opening_tag(2))
buf.extend(self.service_parameters)
buf.extend(encode_closing_tag(2))
return bytes(buf)
[docs]
@classmethod
def decode(cls, data: memoryview | bytes) -> Self:
"""Decode ConfirmedPrivateTransfer-Request from service request bytes.
:param data: Raw service request bytes.
:returns: Decoded request instance.
"""
data = as_memoryview(data)
offset = 0
# [0] vendorID
tag, offset = decode_tag(data, offset)
vendor_id = decode_unsigned(data[offset : offset + tag.length])
offset += tag.length
# [1] serviceNumber
tag, offset = decode_tag(data, offset)
service_number = decode_unsigned(data[offset : offset + tag.length])
offset += tag.length
# [2] serviceParameters (optional)
service_parameters = None
if offset < len(data):
tag, new_offset = decode_tag(data, offset)
if tag.is_opening and tag.number == 2:
service_parameters, offset = extract_context_value(data, new_offset, 2)
return cls(
vendor_id=vendor_id,
service_number=service_number,
service_parameters=service_parameters,
)
[docs]
@dataclass(frozen=True, slots=True)
class ConfirmedPrivateTransferACK:
"""ConfirmedPrivateTransfer-ACK (Clause 16.2.1.2).
Uses the same wire format as the request, but the context-2
tagged block carries vendor-defined *result* data rather than
request *service-parameters*.
"""
vendor_id: int
service_number: int
result_block: bytes | None = None
[docs]
def encode(self) -> bytes:
"""Encode ConfirmedPrivateTransfer-ACK service parameters.
:returns: Encoded service ACK bytes.
"""
buf = bytearray()
buf.extend(encode_context_tagged(0, encode_unsigned(self.vendor_id)))
buf.extend(encode_context_tagged(1, encode_unsigned(self.service_number)))
if self.result_block is not None:
buf.extend(encode_opening_tag(2))
buf.extend(self.result_block)
buf.extend(encode_closing_tag(2))
return bytes(buf)
[docs]
@classmethod
def decode(cls, data: memoryview | bytes) -> ConfirmedPrivateTransferACK:
"""Decode ConfirmedPrivateTransfer-ACK from service ACK bytes.
:param data: Raw service ACK bytes.
:returns: Decoded :class:`ConfirmedPrivateTransferACK`.
"""
data = as_memoryview(data)
offset = 0
tag, offset = decode_tag(data, offset)
vendor_id = decode_unsigned(data[offset : offset + tag.length])
offset += tag.length
tag, offset = decode_tag(data, offset)
service_number = decode_unsigned(data[offset : offset + tag.length])
offset += tag.length
result_block = None
if offset < len(data):
tag, new_offset = decode_tag(data, offset)
if tag.is_opening and tag.number == 2:
result_block, offset = extract_context_value(data, new_offset, 2)
return cls(
vendor_id=vendor_id,
service_number=service_number,
result_block=result_block,
)
[docs]
@dataclass(frozen=True, slots=True)
class UnconfirmedPrivateTransferRequest(ConfirmedPrivateTransferRequest):
"""UnconfirmedPrivateTransfer-Request (Clause 16.3.1.1).
Same structure as ConfirmedPrivateTransfer-Request.
"""