"""BIBB (BACnet Interoperability Building Block) conformance matrix.
Auto-detects which BIBBs are supported by introspecting registered
service handlers per ASHRAE 135-2020 Annex K.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
from bac_py.types.enums import ConfirmedServiceChoice, UnconfirmedServiceChoice
if TYPE_CHECKING:
from bac_py.services.base import ServiceRegistry
[docs]
@dataclass(frozen=True, slots=True)
class BIBBDefinition:
"""A BIBB definition with required services."""
name: str
"""BIBB identifier (e.g. 'DS-RP-B')."""
description: str
"""Human-readable description."""
confirmed_services: frozenset[ConfirmedServiceChoice] = field(default_factory=frozenset)
"""Confirmed services required for this BIBB."""
unconfirmed_services: frozenset[UnconfirmedServiceChoice] = field(default_factory=frozenset)
"""Unconfirmed services required for this BIBB."""
role: str = "A"
"""'A' = client/initiator, 'B' = server/responder."""
# BIBB definitions per Annex K
_BIBB_DEFINITIONS: list[BIBBDefinition] = [
# --- Data Sharing ---
BIBBDefinition(
name="DS-RP-A",
description="Data Sharing - ReadProperty - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.READ_PROPERTY}),
role="A",
),
BIBBDefinition(
name="DS-RP-B",
description="Data Sharing - ReadProperty - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.READ_PROPERTY}),
role="B",
),
BIBBDefinition(
name="DS-RPM-A",
description="Data Sharing - ReadPropertyMultiple - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE}),
role="A",
),
BIBBDefinition(
name="DS-RPM-B",
description="Data Sharing - ReadPropertyMultiple - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE}),
role="B",
),
BIBBDefinition(
name="DS-WP-A",
description="Data Sharing - WriteProperty - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.WRITE_PROPERTY}),
role="A",
),
BIBBDefinition(
name="DS-WP-B",
description="Data Sharing - WriteProperty - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.WRITE_PROPERTY}),
role="B",
),
BIBBDefinition(
name="DS-WPM-A",
description="Data Sharing - WritePropertyMultiple - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.WRITE_PROPERTY_MULTIPLE}),
role="A",
),
BIBBDefinition(
name="DS-WPM-B",
description="Data Sharing - WritePropertyMultiple - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.WRITE_PROPERTY_MULTIPLE}),
role="B",
),
BIBBDefinition(
name="DS-COV-A",
description="Data Sharing - COV - A (Client/Subscriber)",
confirmed_services=frozenset({ConfirmedServiceChoice.SUBSCRIBE_COV}),
role="A",
),
BIBBDefinition(
name="DS-COV-B",
description="Data Sharing - COV - B (Server/Notifier)",
confirmed_services=frozenset({ConfirmedServiceChoice.SUBSCRIBE_COV}),
role="B",
),
# --- Alarm and Event ---
BIBBDefinition(
name="AE-N-A",
description="Alarm & Event - Notification - A (Client/Notification Source)",
confirmed_services=frozenset({ConfirmedServiceChoice.CONFIRMED_EVENT_NOTIFICATION}),
unconfirmed_services=frozenset({UnconfirmedServiceChoice.UNCONFIRMED_EVENT_NOTIFICATION}),
role="A",
),
BIBBDefinition(
name="AE-N-B",
description="Alarm & Event - Notification - B (Server/Notification Sink)",
confirmed_services=frozenset({ConfirmedServiceChoice.CONFIRMED_EVENT_NOTIFICATION}),
unconfirmed_services=frozenset({UnconfirmedServiceChoice.UNCONFIRMED_EVENT_NOTIFICATION}),
role="B",
),
BIBBDefinition(
name="AE-ACK-A",
description="Alarm & Event - Acknowledgment - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.ACKNOWLEDGE_ALARM}),
role="A",
),
BIBBDefinition(
name="AE-ACK-B",
description="Alarm & Event - Acknowledgment - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.ACKNOWLEDGE_ALARM}),
role="B",
),
BIBBDefinition(
name="AE-INFO-A",
description="Alarm & Event - GetEventInformation - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.GET_EVENT_INFORMATION}),
role="A",
),
BIBBDefinition(
name="AE-INFO-B",
description="Alarm & Event - GetEventInformation - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.GET_EVENT_INFORMATION}),
role="B",
),
BIBBDefinition(
name="AE-ASUM-A",
description="Alarm & Event - GetAlarmSummary - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.GET_ALARM_SUMMARY}),
role="A",
),
BIBBDefinition(
name="AE-ASUM-B",
description="Alarm & Event - GetAlarmSummary - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.GET_ALARM_SUMMARY}),
role="B",
),
BIBBDefinition(
name="AE-ESUM-A",
description="Alarm & Event - GetEnrollmentSummary - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.GET_ENROLLMENT_SUMMARY}),
role="A",
),
BIBBDefinition(
name="AE-ESUM-B",
description="Alarm & Event - GetEnrollmentSummary - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.GET_ENROLLMENT_SUMMARY}),
role="B",
),
# --- Device Management ---
BIBBDefinition(
name="DM-DDB-A",
description="Device Management - Dynamic Device Binding - A (Client)",
unconfirmed_services=frozenset(
{UnconfirmedServiceChoice.WHO_IS, UnconfirmedServiceChoice.I_AM}
),
role="A",
),
BIBBDefinition(
name="DM-DDB-B",
description="Device Management - Dynamic Device Binding - B (Server)",
unconfirmed_services=frozenset(
{UnconfirmedServiceChoice.WHO_IS, UnconfirmedServiceChoice.I_AM}
),
role="B",
),
BIBBDefinition(
name="DM-DOB-A",
description="Device Management - Dynamic Object Binding - A (Client)",
unconfirmed_services=frozenset(
{UnconfirmedServiceChoice.WHO_HAS, UnconfirmedServiceChoice.I_HAVE}
),
role="A",
),
BIBBDefinition(
name="DM-DOB-B",
description="Device Management - Dynamic Object Binding - B (Server)",
unconfirmed_services=frozenset(
{UnconfirmedServiceChoice.WHO_HAS, UnconfirmedServiceChoice.I_HAVE}
),
role="B",
),
BIBBDefinition(
name="DM-DCC-A",
description="Device Management - DeviceCommunicationControl - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.DEVICE_COMMUNICATION_CONTROL}),
role="A",
),
BIBBDefinition(
name="DM-DCC-B",
description="Device Management - DeviceCommunicationControl - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.DEVICE_COMMUNICATION_CONTROL}),
role="B",
),
BIBBDefinition(
name="DM-RD-A",
description="Device Management - ReinitializeDevice - A (Client)",
confirmed_services=frozenset({ConfirmedServiceChoice.REINITIALIZE_DEVICE}),
role="A",
),
BIBBDefinition(
name="DM-RD-B",
description="Device Management - ReinitializeDevice - B (Server)",
confirmed_services=frozenset({ConfirmedServiceChoice.REINITIALIZE_DEVICE}),
role="B",
),
BIBBDefinition(
name="DM-TS-A",
description="Device Management - TimeSynchronization - A (Client)",
unconfirmed_services=frozenset({UnconfirmedServiceChoice.TIME_SYNCHRONIZATION}),
role="A",
),
BIBBDefinition(
name="DM-TS-B",
description="Device Management - TimeSynchronization - B (Server)",
unconfirmed_services=frozenset({UnconfirmedServiceChoice.TIME_SYNCHRONIZATION}),
role="B",
),
BIBBDefinition(
name="DM-UTC-A",
description="Device Management - UTCTimeSynchronization - A (Client)",
unconfirmed_services=frozenset({UnconfirmedServiceChoice.UTC_TIME_SYNCHRONIZATION}),
role="A",
),
BIBBDefinition(
name="DM-UTC-B",
description="Device Management - UTCTimeSynchronization - B (Server)",
unconfirmed_services=frozenset({UnconfirmedServiceChoice.UTC_TIME_SYNCHRONIZATION}),
role="B",
),
# --- File Access ---
BIBBDefinition(
name="DM-BR-A",
description="Device Management - Backup/Restore - A (Client)",
confirmed_services=frozenset(
{
ConfirmedServiceChoice.REINITIALIZE_DEVICE,
ConfirmedServiceChoice.ATOMIC_READ_FILE,
ConfirmedServiceChoice.ATOMIC_WRITE_FILE,
ConfirmedServiceChoice.READ_PROPERTY,
}
),
role="A",
),
BIBBDefinition(
name="DM-BR-B",
description="Device Management - Backup/Restore - B (Server)",
confirmed_services=frozenset(
{
ConfirmedServiceChoice.REINITIALIZE_DEVICE,
ConfirmedServiceChoice.ATOMIC_READ_FILE,
ConfirmedServiceChoice.ATOMIC_WRITE_FILE,
ConfirmedServiceChoice.READ_PROPERTY,
}
),
role="B",
),
# --- Object Access ---
BIBBDefinition(
name="DM-OCD-A",
description="Device Management - Object Creation/Deletion - A (Client)",
confirmed_services=frozenset(
{
ConfirmedServiceChoice.CREATE_OBJECT,
ConfirmedServiceChoice.DELETE_OBJECT,
}
),
role="A",
),
BIBBDefinition(
name="DM-OCD-B",
description="Device Management - Object Creation/Deletion - B (Server)",
confirmed_services=frozenset(
{
ConfirmedServiceChoice.CREATE_OBJECT,
ConfirmedServiceChoice.DELETE_OBJECT,
}
),
role="B",
),
BIBBDefinition(
name="DM-LM-A",
description="Device Management - List Manipulation - A (Client)",
confirmed_services=frozenset(
{
ConfirmedServiceChoice.ADD_LIST_ELEMENT,
ConfirmedServiceChoice.REMOVE_LIST_ELEMENT,
}
),
role="A",
),
BIBBDefinition(
name="DM-LM-B",
description="Device Management - List Manipulation - B (Server)",
confirmed_services=frozenset(
{
ConfirmedServiceChoice.ADD_LIST_ELEMENT,
ConfirmedServiceChoice.REMOVE_LIST_ELEMENT,
}
),
role="B",
),
]
[docs]
class BIBBMatrix:
"""Determine which BIBBs are supported by a BACnet application.
The matrix checks registered service handlers against the
requirements for each BIBB definition.
"""
def __init__(self, registry: ServiceRegistry) -> None:
self._registry = registry
[docs]
def supported_bibbs(self) -> list[BIBBDefinition]:
"""Return all BIBBs for which required services are registered."""
result: list[BIBBDefinition] = []
for bibb in _BIBB_DEFINITIONS:
if self._is_supported(bibb):
result.append(bibb)
return result
[docs]
def supported_bibb_names(self) -> list[str]:
"""Return names of all supported BIBBs."""
return [b.name for b in self.supported_bibbs()]
[docs]
def generate_matrix(self) -> dict[str, dict[str, str | bool]]:
"""Generate a matrix dict mapping BIBB name → info."""
matrix: dict[str, dict[str, str | bool]] = {}
for bibb in _BIBB_DEFINITIONS:
matrix[bibb.name] = {
"description": bibb.description,
"role": bibb.role,
"supported": self._is_supported(bibb),
}
return matrix
def _is_supported(self, bibb: BIBBDefinition) -> bool:
"""Check if all services required by a BIBB are registered.
For 'B' (server) role, checks that the service handler exists
in the registry. For 'A' (client) role, we assume the client
can initiate any service, so A-role BIBBs are always supported.
"""
if bibb.role == "A":
return True
# B-role: check server handlers
return all(
self._registry.has_confirmed_handler(svc.value) for svc in bibb.confirmed_services
) and all(
self._registry.has_unconfirmed_handler(svc.value) for svc in bibb.unconfirmed_services
)