"""BACnet Loop object per ASHRAE 135-2020 Clause 12.17."""
from __future__ import annotations
from typing import Any, ClassVar
from bac_py.objects.base import (
BACnetObject,
PropertyAccess,
PropertyDefinition,
register_object_type,
standard_properties,
status_properties,
)
from bac_py.types.constructed import BACnetObjectPropertyReference
from bac_py.types.enums import (
Action,
EngineeringUnits,
EventType,
ObjectType,
PropertyIdentifier,
)
[docs]
@register_object_type
class LoopObject(BACnetObject):
"""BACnet Loop object (Clause 12.17).
Represents a PID control loop. Present_Value is the manipulated
variable output. The control algorithm parameters (P, I, D
constants) define the loop behavior.
"""
OBJECT_TYPE: ClassVar[ObjectType] = ObjectType.LOOP
INTRINSIC_EVENT_ALGORITHM: ClassVar[EventType | None] = EventType.FLOATING_LIMIT
PROPERTY_DEFINITIONS: ClassVar[dict[PropertyIdentifier, PropertyDefinition]] = {
**standard_properties(),
PropertyIdentifier.PRESENT_VALUE: PropertyDefinition(
PropertyIdentifier.PRESENT_VALUE,
float,
PropertyAccess.READ_WRITE,
required=True,
default=0.0,
),
**status_properties(),
PropertyIdentifier.CONTROLLED_VARIABLE_REFERENCE: PropertyDefinition(
PropertyIdentifier.CONTROLLED_VARIABLE_REFERENCE,
BACnetObjectPropertyReference,
PropertyAccess.READ_WRITE,
required=True,
),
PropertyIdentifier.CONTROLLED_VARIABLE_VALUE: PropertyDefinition(
PropertyIdentifier.CONTROLLED_VARIABLE_VALUE,
float,
PropertyAccess.READ_ONLY,
required=True,
default=0.0,
),
PropertyIdentifier.CONTROLLED_VARIABLE_UNITS: PropertyDefinition(
PropertyIdentifier.CONTROLLED_VARIABLE_UNITS,
EngineeringUnits,
PropertyAccess.READ_ONLY,
required=True,
default=EngineeringUnits.NO_UNITS,
),
PropertyIdentifier.MANIPULATED_VARIABLE_REFERENCE: PropertyDefinition(
PropertyIdentifier.MANIPULATED_VARIABLE_REFERENCE,
BACnetObjectPropertyReference,
PropertyAccess.READ_WRITE,
required=True,
),
PropertyIdentifier.SETPOINT_REFERENCE: PropertyDefinition(
PropertyIdentifier.SETPOINT_REFERENCE,
BACnetObjectPropertyReference,
PropertyAccess.READ_WRITE,
required=True,
),
PropertyIdentifier.SETPOINT: PropertyDefinition(
PropertyIdentifier.SETPOINT,
float,
PropertyAccess.READ_WRITE,
required=True,
default=0.0,
),
PropertyIdentifier.ACTION: PropertyDefinition(
PropertyIdentifier.ACTION,
Action,
PropertyAccess.READ_WRITE,
required=True,
default=Action.DIRECT,
),
PropertyIdentifier.PROPORTIONAL_CONSTANT: PropertyDefinition(
PropertyIdentifier.PROPORTIONAL_CONSTANT,
float,
PropertyAccess.READ_WRITE,
required=False,
default=0.0,
),
PropertyIdentifier.PROPORTIONAL_CONSTANT_UNITS: PropertyDefinition(
PropertyIdentifier.PROPORTIONAL_CONSTANT_UNITS,
EngineeringUnits,
PropertyAccess.READ_ONLY,
required=False,
default=EngineeringUnits.NO_UNITS,
),
PropertyIdentifier.INTEGRAL_CONSTANT: PropertyDefinition(
PropertyIdentifier.INTEGRAL_CONSTANT,
float,
PropertyAccess.READ_WRITE,
required=False,
default=0.0,
),
PropertyIdentifier.INTEGRAL_CONSTANT_UNITS: PropertyDefinition(
PropertyIdentifier.INTEGRAL_CONSTANT_UNITS,
EngineeringUnits,
PropertyAccess.READ_ONLY,
required=False,
default=EngineeringUnits.NO_UNITS,
),
PropertyIdentifier.DERIVATIVE_CONSTANT: PropertyDefinition(
PropertyIdentifier.DERIVATIVE_CONSTANT,
float,
PropertyAccess.READ_WRITE,
required=False,
default=0.0,
),
PropertyIdentifier.DERIVATIVE_CONSTANT_UNITS: PropertyDefinition(
PropertyIdentifier.DERIVATIVE_CONSTANT_UNITS,
EngineeringUnits,
PropertyAccess.READ_ONLY,
required=False,
default=EngineeringUnits.NO_UNITS,
),
PropertyIdentifier.MAXIMUM_OUTPUT: PropertyDefinition(
PropertyIdentifier.MAXIMUM_OUTPUT,
float,
PropertyAccess.READ_WRITE,
required=False,
default=100.0,
),
PropertyIdentifier.MINIMUM_OUTPUT: PropertyDefinition(
PropertyIdentifier.MINIMUM_OUTPUT,
float,
PropertyAccess.READ_WRITE,
required=False,
default=0.0,
),
PropertyIdentifier.PRIORITY_FOR_WRITING: PropertyDefinition(
PropertyIdentifier.PRIORITY_FOR_WRITING,
int,
PropertyAccess.READ_WRITE,
required=True,
default=16,
),
PropertyIdentifier.UPDATE_INTERVAL: PropertyDefinition(
PropertyIdentifier.UPDATE_INTERVAL,
int,
PropertyAccess.READ_WRITE,
required=False,
default=100,
),
PropertyIdentifier.OUTPUT_UNITS: PropertyDefinition(
PropertyIdentifier.OUTPUT_UNITS,
EngineeringUnits,
PropertyAccess.READ_WRITE,
required=True,
default=EngineeringUnits.NO_UNITS,
),
PropertyIdentifier.BIAS: PropertyDefinition(
PropertyIdentifier.BIAS,
float,
PropertyAccess.READ_WRITE,
required=False,
),
PropertyIdentifier.COV_INCREMENT: PropertyDefinition(
PropertyIdentifier.COV_INCREMENT,
float,
PropertyAccess.READ_WRITE,
required=False,
),
PropertyIdentifier.ERROR_LIMIT: PropertyDefinition(
PropertyIdentifier.ERROR_LIMIT,
float,
PropertyAccess.READ_WRITE,
required=False,
),
PropertyIdentifier.DEADBAND: PropertyDefinition(
PropertyIdentifier.DEADBAND,
float,
PropertyAccess.READ_WRITE,
required=False,
),
PropertyIdentifier.NOTIFICATION_CLASS: PropertyDefinition(
PropertyIdentifier.NOTIFICATION_CLASS,
int,
PropertyAccess.READ_WRITE,
required=False,
),
PropertyIdentifier.EVENT_ENABLE: PropertyDefinition(
PropertyIdentifier.EVENT_ENABLE,
list,
PropertyAccess.READ_WRITE,
required=False,
),
PropertyIdentifier.TIME_DELAY: PropertyDefinition(
PropertyIdentifier.TIME_DELAY,
int,
PropertyAccess.READ_WRITE,
required=False,
),
}
def __init__(self, instance_number: int, **initial_properties: Any) -> None:
super().__init__(instance_number, **initial_properties)
self._init_status_flags()
# Object property references default to empty if not provided
self._set_default(PropertyIdentifier.CONTROLLED_VARIABLE_REFERENCE, None)
self._set_default(PropertyIdentifier.MANIPULATED_VARIABLE_REFERENCE, None)
self._set_default(PropertyIdentifier.SETPOINT_REFERENCE, None)