BACnet.Protocol.ObjectTypes.EventEnrollment (bacstack v0.1.0-dev.1)

Copy Markdown View Source

The Event Enrollment object is the primary mechanism for defining intrinsic or algorithmic event/alarm generation in BACnet. It references a single property (local or on a remote device via object_property_reference), applies a chosen event algorithm (CHANGE_OF_STATE, OUT_OF_RANGE, BUFFER_READY, etc.) together with optional fault algorithms, and, when the state changes, sends notifications to the recipients listed in the associated Notification Class.

The enrollment object itself never modifies the monitored property; it is a pure observer. It carries the full set of event configuration (event_enable, acked_transitions, event_priorities, event_message_texts, etc.) and can be enabled/disabled independently. This design allows any object (even those that do not support intrinsic reporting themselves) to participate in alarming by creating a separate Event Enrollment that watches it.

Object Description (ASHRAE 135)

The Event Enrollment object type defines a standardized object that represents and contains the information required for algorithmic reporting of events. For the general event concepts and algorithmic event reporting, see Clause 13.2.

Behaviour and Operation

Event Enrollment objects are the "watcher + algorithm engine". The device (local application or a background task) must periodically (or on change) evaluate the referenced property using the chosen event and fault algorithms (the parameters for which live in this object). When a transition occurs the enrollment generates BACnet.Protocol.Services.ConfirmedEventNotification or BACnet.Protocol.Services.UnconfirmedEventNotification messages to the recipients defined by the linked Notification Class.

The enrollment never modifies the monitored property. It only observes it (the reference may point to a remote object via the network). event_detection_enable, event_algorithm_inhibit, time delays, limit parameters, etc. all live here and control exactly when and how notifications are produced. The object is not commandable.

Developer Implementation Notes (geared to device server / application authors)

The generated code handles storage + basic mechanics (validation, implicit_relationships, readonly annotations as hints to your server, etc.). You must drive "special" live properties and side effects yourself, via update_property/3 (never direct mutation). Read notes below + generated tables for details.

Special / live properties and expected developer behaviour

  • object_property_reference: What to monitor (any object/prop, local or remote). Dev must: Your detection task periodically or on change reads the current value (and status_flags for some algos) of the referenced prop (do remote reads if needed) and feeds it + other params into the event algorithm (the params live on this enrollment).

  • event_parameters: The config for the configured algorithm. Dev must: Run the configured event algorithm.

  • event_state, acked_transitions, event_timestamps, event_message_texts, etc.: The event machine state. Dev must: After feeding a value and running the algorithm, update the state, timestamps, etc. on this object.

  • status_flags, reliability: Dev must: Update based on ability to read the reference or internal faults. in_alarm/fault/out_of_service bits are auto-managed (overridden is a local matter).

  • event_algorithm_inhibit*, reliability_evaluation_inhibit: Control. Dev must: Respect when inhibiting detection or reliability.

  • fault_type, fault_parameters: Optional fault detection on the reference. Dev must: Run the fault algorithm too if configured.

Your "event engine" (timer or change driven) owns the evaluation loop; the enrollment is the attachment point + parameters + state holder. See the "You run the detection engine" section below.

EventEnrollment is the most flexible way to attach alarming to any property, even on a completely different device, without modifying the source object.

You run the detection engine: Nothing in the enrollment object automatically wakes up and evaluates the algorithm. On a schedule appropriate for the algorithm (on every change for a CHANGE_OF_STATE, every time a new record is appended for BUFFER_READY, …) you must:

  1. Read the current value of the property described by object_property_reference (local object or full remote ref - you do the network read if necessary).
  2. Feed that value (plus any other required inputs such as status_flags for some algorithms) into the event algorithm whose parameters live on this event enrollment.
  3. Also run the optional fault algorithm if one is configured (fault_parameters).
  4. From the results decide whether event_state or reliability should change.
  5. If a transition that requires a notification occurred (and the corresponding bit in event_enable is set, the event_algorithm_inhibit is not active, etc.), look up the Notification Class referenced by this enrollment and emit the notification (using the priority and ack-required information from the class, the message texts from the enrollment, etc.).
  6. Update the enrollment's own event_state, event_timestamps, acked_transitions, reliability etc. via the normal update path.

The enrollment object is purely the configuration and current state of one particular alarm/fault detector.

The monitored property can be anywhere: Because the reference is a full BACnet.Protocol.DeviceObjectPropertyRef you can watch a sensor that lives on a different controller. Your detection task becomes a little distributed alarm engine.

FAULT_ algorithms run in parallel with the event algorithm. A fault transition (e.g. FAULT_STATUS_FLAGS) can move the object into a fault reliability even if the event state stays normal. Both can generate notifications.

event_algorithm_inhibit / event_algorithm_inhibit_ref: These let a different object (or a schedule, or a manual switch) temporarily suppress the alarming logic without clearing all the configuration. Your engine must check the inhibit flag (and follow the reference if present) on every evaluation.

Writing the enrollment from the wire: Almost everything on an EventEnrollment is writable (the reference, the algorithm parameters, the enable bits, the notification class, the message texts, the delays …). A configuration tool can completely repurpose an enrollment at runtime. Your detection engine simply uses whatever parameters are currently stored on the object.

Examples

Creating an Event Enrollment:

iex> {:ok, ee} = BACnet.Protocol.ObjectTypes.EventEnrollment.create(1100, "HighTempAlarm", %{notification_class: 1}); ee.object_name
"HighTempAlarm"

See Also



The following part has been automatically generated.

Click to expand This module defines a BACnet object of the type `event_enrollment`. The following properties are defined: | Property | Revision | Required | Readonly | Protected | Intrinsic | |----------|----------|----------|----------|-----------|-----------| | acked_transitions | | | X | | | | description | | | | | | | event_algorithm_inhibit | | | | | | | event_algorithm_inhibit_ref | | | | | | | event_detection_enable | | X | | | | | event_enable | | X | | | | | event_message_texts | | | X | | | | event_message_texts_config | | | | | | | event_parameters | | X | | | | | event_state | | X | | | | | event_timestamps | | | X | | | | event_type | | X | X | | | | fault_parameters | | | | | | | fault_type | | | X | | | | notification_class | | X | | | | | notify_type | | X | | | | | object_instance | | X | X | | | | object_name | | X | X | | | | object_property_reference | | X | | | | | profile_location | 19 | | | | | | profile_name | | | | | | | reliability | | | | | | | reliability_evaluation_inhibit | | | | | | | status_flags | | X | | | | | tags | 19 | | | | | | time_delay_normal | | | | | | The following properties have additional semantics: | Property | Has Default | Has Init | Implicit Relationships | Validators | Annotations | |----------|-------------|----------|------------------------|------------|-------------| | event_algorithm_inhibit | | | event_algorithm_inhibit_ref | | | | event_detection_enable | X | | | | | | event_enable | X | | | | | | event_parameters | X | | | | | | event_state | X | | | | | | event_type | X | | | | | | fault_parameters | | | fault_type | | | | notify_type | X | | | | | | object_property_reference | X | | | | | | profile_location | | | | Fun | `revision: 19` | | reliability | | | reliability_evaluation_inhibit | | | | tags | | | | | `revision: 19` | The following table shows the default values and/or init functions: | Property | Default Value | Init Function | |----------|---------------|---------------| | event_detection_enable | `true` | | | event_enable | `%BACnet.Protocol.EventTransitionBits{...}` | | | event_parameters | `%BACnet.Protocol.EventParameters.None{...}` | | | event_state | `:normal` | | | event_type | `:none` | | | notify_type | `:alarm` | | | object_property_reference | `%BACnet.Protocol.DeviceObjectPropertyRef{...}` | |

Summary

Types

Common object options for creation - all are optional.

Options accepted when creating or configuring an Event Enrollment object.

Available property names for this object.

The structure for property errors.

t()

Represents an Event Enrollment object. All keys should be treated as read-only, all updates should go only through update_property/3.

Functions

Adds an optional property to an object. Remote objects can not be mutated using this operation.

Creates a new object struct with the defined properties. Optional properties are not created when not given, only required, given and dependency properties are created. Properties with a value of nil are ignored.

Auto generated function to get the names of all properties this object supports.

Auto generated function to get the annotations for the given property name.

Auto generated function to get the list of annotations for each property.

Auto generated function to get the names of properties used for COV reporting.

Auto generated function to get the names of intrinsic properties.

Get the BACnet object identifier.

Auto generated function to get the names of optional properties.

Get the list of properties the object has.

Auto generated function to get a map of property name to type.

Get a property's value from an object.

Auto generated function to get the names of protected properties.

Auto generated function to get the names of readonly properties.

Auto generated function to get the names of required properties.

Checks if the given object has the given property.

Checks if the given property is writable.

Removes an optional property from an object. This function is idempotent. Remote objects can not be mutated using this operation.

Auto generated function to check whether the object type supports intrinsic reporting.

Updates a property of an object.

Types

common_object_opts()

@type common_object_opts() ::
  {:allow_numeric_constants, boolean()}
  | {:allow_unknown_properties, boolean()}
  | {:ignore_unknown_properties, boolean()}
  | {:revision, BACnet.Protocol.Constants.protocol_revision()}
  | {:skip_property_validation_remote_object, boolean() | :value}

Common object options for creation - all are optional.

  • allow_numeric_constants - Constants are atoms and thus unknown constants or vendor extensions are integers and thus are rejected. Enabling this option will allow integers (non_neg_integer()) for properties with a Constants.type() spec.
  • allow_unknown_properties - Properties that are unknown to the object implementation are usually rejected. With this option, unknown properties (numeric identifiers usually means we dont know them) are accepted and put into a separate map. This does mean we can not validate or write them. Types of the values can be anything at this point. While you can read unknown properties with atom or integer as property identifier, you can only remove numeric unknown property identifiers from an object. Property identifiers of type atom are only accepted, if it is a remote object (object implementation is only enforced if it is a local object). Numeric property identifiers are accepted regardless of remote object or not. For remote objects, this means you have to write "raw values" (usually Encoding structs).
  • ignore_unknown_properties - Properties that are unknown to the object implementation are usually rejected. With this option, unknown properties get ignored, as if they were not specified.
  • revision - The BACnet protocol revision to check required properties against. Optional properties are regardless of revision available. See BACnet.Protocol.Constants.protocol_revision/0 for the available revisions.
  • skip_property_validation_remote_object - Skips property validation for remote objects. Sometimes it is possible that the value is invalid as per BACnet specification (i.e. value 0 for a multistate object), but you still want those to be represented. Value true neither type nor value are validated. Value :value means the type is still validated and only the value validator is not run (if present). The property's validator_fun will also be skipped.

object_opts()

@type object_opts() :: common_object_opts()

Options accepted when creating or configuring an Event Enrollment object.

property_name()

@type property_name() ::
  :acked_transitions
  | :description
  | :event_algorithm_inhibit
  | :event_algorithm_inhibit_ref
  | :event_detection_enable
  | :event_enable
  | :event_message_texts
  | :event_message_texts_config
  | :event_parameters
  | :event_state
  | :event_timestamps
  | :event_type
  | :fault_parameters
  | :fault_type
  | :notification_class
  | :notify_type
  | :object_instance
  | :object_name
  | :object_property_reference
  | :profile_location
  | :profile_name
  | :reliability
  | :reliability_evaluation_inhibit
  | :status_flags
  | :tags
  | :time_delay_normal

Available property names for this object.

property_update_error()

@type property_update_error() ::
  {:error,
   {error :: atom(),
    property :: BACnet.Protocol.Constants.property_identifier()}}

The structure for property errors.

t()

@type t() :: %BACnet.Protocol.ObjectTypes.EventEnrollment{
  _metadata: internal_metadata(),
  _unknown_properties: %{
    optional(atom() | non_neg_integer()) =>
      term()
      | BACnet.Protocol.ApplicationTags.Encoding.t()
      | [BACnet.Protocol.ApplicationTags.Encoding.t()]
  },
  acked_transitions: BACnet.Protocol.EventTransitionBits.t() | nil,
  description: String.t() | nil,
  event_algorithm_inhibit: boolean() | nil,
  event_algorithm_inhibit_ref: BACnet.Protocol.ObjectPropertyRef.t() | nil,
  event_detection_enable: boolean(),
  event_enable: BACnet.Protocol.EventTransitionBits.t(),
  event_message_texts: BACnet.Protocol.EventMessageTexts.t() | nil,
  event_message_texts_config: BACnet.Protocol.EventMessageTexts.t() | nil,
  event_parameters: BACnet.Protocol.EventParameters.event_parameter(),
  event_state:
    BACnet.Protocol.Constants.event_state()
    | (reserved_or_vendor_extension :: non_neg_integer()),
  event_timestamps: BACnet.Protocol.EventTimestamps.t() | nil,
  event_type:
    BACnet.Protocol.Constants.event_type()
    | (reserved_or_vendor_extension :: non_neg_integer()),
  fault_parameters: BACnet.Protocol.FaultParameters.fault_parameter() | nil,
  fault_type:
    BACnet.Protocol.Constants.fault_type()
    | (reserved_or_vendor_extension :: non_neg_integer())
    | nil,
  notification_class: non_neg_integer(),
  notify_type:
    BACnet.Protocol.Constants.notify_type()
    | (reserved_or_vendor_extension :: non_neg_integer()),
  object_instance: non_neg_integer(),
  object_name: String.t(),
  object_property_reference: BACnet.Protocol.DeviceObjectPropertyRef.t(),
  profile_location: String.t() | nil,
  profile_name: String.t() | nil,
  reliability:
    BACnet.Protocol.Constants.reliability()
    | (reserved_or_vendor_extension :: non_neg_integer())
    | nil,
  reliability_evaluation_inhibit: boolean() | nil,
  status_flags: BACnet.Protocol.StatusFlags.t(),
  tags: BACnet.Protocol.BACnetArray.t(BACnet.Protocol.NameValue.t()) | nil,
  time_delay_normal: non_neg_integer() | nil
}

Represents an Event Enrollment object. All keys should be treated as read-only, all updates should go only through update_property/3.

Functions

add_property(object, property, value)

@spec add_property(t(), BACnet.Protocol.Constants.property_identifier(), term()) ::
  {:ok, t()} | property_update_error()

Adds an optional property to an object. Remote objects can not be mutated using this operation.

Please note that properties of services can not be dynamically added and instead the object must be newly created using create/4.

create(instance_number, object_name, properties \\ %{}, opts \\ [])

@spec create(
  non_neg_integer(),
  String.t(),
  %{optional(property_name() | atom() | non_neg_integer()) => term()},
  [object_opts() | internal_metadata()]
) :: {:ok, t()} | property_update_error()

Creates a new object struct with the defined properties. Optional properties are not created when not given, only required, given and dependency properties are created. Properties with a value of nil are ignored.

Only properties that are required for specific services (i.e. Intrinsic Reporting) are automatically created.

get_all_properties()

@spec get_all_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of all properties this object supports.

get_annotation(name)

@spec get_annotation(property_name()) :: [term()]

Auto generated function to get the annotations for the given property name.

get_annotations()

@spec get_annotations() :: [{name :: property_name(), values :: [term()]}]

Auto generated function to get the list of annotations for each property.

get_cov_properties()

@spec get_cov_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of properties used for COV reporting.

get_intrinsic_properties()

@spec get_intrinsic_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of intrinsic properties.

get_object_identifier(object)

@spec get_object_identifier(t()) :: BACnet.Protocol.ObjectIdentifier.t()

Get the BACnet object identifier.

get_optional_properties()

@spec get_optional_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of optional properties.

get_properties(object)

@spec get_properties(t()) :: [BACnet.Protocol.Constants.property_identifier()]

Get the list of properties the object has.

get_properties_type_map()

@spec get_properties_type_map() :: map()

Auto generated function to get a map of property name to type.

get_property(object, property)

Get a property's value from an object.

get_protected_properties()

@spec get_protected_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of protected properties.

Protected is an annotation and the object modules prevent writing to this property directly in code. The protected properties are either written on creation or updated automatically depending on other properties being written to. Some properties are only written once at creation and never updated.

get_readonly_properties()

@spec get_readonly_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of readonly properties.

Readonly is only an annotation that the property should be write protected on the BACnet side, there is no actual write protection in the object. This is a hint to the device server. If you need actual write protection, see protected.

get_required_properties()

@spec get_required_properties() :: [BACnet.Protocol.Constants.property_identifier()]

Auto generated function to get the names of required properties.

has_property?(object, property)

Checks if the given object has the given property.

See BACnet.Protocol.ObjectsUtility.has_property?/2 for implementation details.

property_writable?(object, property)

@spec property_writable?(t(), BACnet.Protocol.Constants.property_identifier()) ::
  boolean()

Checks if the given property is writable.

Check BACnet.Protocol.ObjectsUtility.property_writable?/2 for a basic run-down.

remove_property(object, property)

@spec remove_property(
  t(),
  BACnet.Protocol.Constants.property_identifier() | non_neg_integer()
) ::
  {:ok, t()} | property_update_error()

Removes an optional property from an object. This function is idempotent. Remote objects can not be mutated using this operation.

Please note that properties of services can not be dynamically removed and instead the object must be newly created using create/4. Required properties can not be removed.

supports_intrinsic()

@spec supports_intrinsic() :: boolean()

Auto generated function to check whether the object type supports intrinsic reporting.

update_property(object, property, value)

@spec update_property(t(), BACnet.Protocol.Constants.property_identifier(), term()) ::
  {:ok, t()} | property_update_error()

Updates a property of an object.