Current section
Files
Jump to
Current section
Files
lib/bacnet/protocol/alarm_summary.ex
defmodule BACnet.Protocol.AlarmSummary do
@moduledoc """
An Alarm Summary entry is the data structure returned by the Get Alarm Summary
confirmed service. It gives a client a compact, point-in-time list of every object
inside a device that is currently in an alarm or fault condition and that the client
is permitted to observe.
Each summary contains three pieces of information: the Object Identifier of the
alarming object, its current Event State (which may be FAULT or one of the alarm
states such as HIGH_LIMIT or LIFE_SAFETY_ALARM), and the Acknowledged Transitions
bit string. The acknowledged transitions bits are crucial for operator interfaces
because they indicate which state changes still require human acknowledgment before
the alarm can be considered fully cleared from the operator's perspective.
Although Get Alarm Summary is one of the older summary services in BACnet, it is
still widely supported for backward compatibility. Newer implementations are
encouraged to use the more capable Get Event Information service, which returns
timestamps, notification class, and other context. The Alarm Summary structure
itself remains useful whenever a very small encoding is required.
"""
# TODO: Throw argument error in encode if not valid
alias BACnet.Protocol.ApplicationTags
alias BACnet.Protocol.Constants
alias BACnet.Protocol.EventTransitionBits
alias BACnet.Protocol.ObjectIdentifier
@typedoc """
Represents a single entry in the response of a Get Alarm Summary service.
"""
@type t :: %__MODULE__{
object_identifier: ObjectIdentifier.t(),
alarm_state: Constants.event_state(),
acknowledged_transitions: EventTransitionBits.t()
}
@fields [:object_identifier, :alarm_state, :acknowledged_transitions]
@enforce_keys @fields
defstruct @fields
@doc """
Encodes a BACnet alarm summary into BACnet application tags encoding.
"""
@spec encode(t(), Keyword.t()) ::
{:ok, ApplicationTags.encoding_list()} | {:error, term()}
def encode(
%__MODULE__{
object_identifier: %ObjectIdentifier{},
acknowledged_transitions: %EventTransitionBits{}
} = summary,
_opts \\ []
) do
with {:ok, state} <-
Constants.by_name_with_reason(
:event_state,
summary.alarm_state,
{:unknown_state, summary.alarm_state}
) do
params = [
{:object_identifier, summary.object_identifier},
{:enumerated, state},
EventTransitionBits.to_bitstring(summary.acknowledged_transitions)
]
{:ok, params}
end
end
@doc """
Parses a BACnet alarm summary from BACnet application tags encoding.
"""
@spec parse(ApplicationTags.encoding_list()) ::
{:ok, {t(), rest :: ApplicationTags.encoding_list()}}
| {:error, term()}
def parse(tags) when is_list(tags) do
case tags do
[
{:object_identifier, obj},
{:enumerated, event_state},
{:bitstring, {offnormal, fault, normal}}
| rest
] ->
with {:ok, alarm_state} <-
Constants.by_value_with_reason(
:event_state,
event_state,
{:unknown_state, event_state}
) do
summary = %__MODULE__{
object_identifier: obj,
alarm_state: alarm_state,
acknowledged_transitions: %EventTransitionBits{
to_offnormal: offnormal,
to_fault: fault,
to_normal: normal
}
}
{:ok, {summary, rest}}
end
_else ->
{:error, :invalid_tags}
end
end
@doc """
Validates whether the given alarm summary is in form valid.
It only validates the struct is valid as per type specification.
"""
@spec valid?(t()) :: boolean()
def valid?(
%__MODULE__{
object_identifier: %ObjectIdentifier{} = obj_ref,
alarm_state: state,
acknowledged_transitions: %EventTransitionBits{} = bits
} = _t
) do
ObjectIdentifier.valid?(obj_ref) and Constants.has_by_name(:event_state, state) and
EventTransitionBits.valid?(bits)
end
def valid?(%__MODULE__{} = _t), do: false
end