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

Copy Markdown View Source

The Accumulator object provides a standardised representation for pulse-counting measurement devices such as utility meters (electricity, water, gas, etc.). Pulses are accumulated into the readonly present_value using the prescale (pulses per unit) and scale factors so the exposed value matches the meter's register as closely as possible, including proper rollover behaviour at max_present_value (defaults to 32-bit unsigned max). Additional properties expose the instantaneous pulse_rate over a configurable limit_monitoring_interval, allow presetting the counter via value_set, and record change timestamps.

The object supports COV reporting on the present value. When intrinsic_reporting: true is passed to create/4, the UNSIGNED_RANGE event algorithm and associated high/low limit properties are activated for alarming on count thresholds.

Object Description (ASHRAE 135)

The Accumulator object type defines a standardized object whose properties represent the externally visible characteristics of a device that indicates measurements made by counting pulses.

Accumulator objects that support intrinsic reporting shall apply the UNSIGNED_RANGE event algorithm.

Behaviour and Operation

Accumulator objects are pulse totalizer / measurement objects. The present_value (a non-negative integer) is maintained by the local application or pulse counting hardware/driver. The application is responsible for incrementing the count (or writing the accumulated total) as pulses arrive, applying the prescale and scale factors so that the value matches the engineering units expected by the meter register as closely as possible. Rollover occurs at max_present_value (normally 2^32-1; the default is set in the struct but can be overridden at creation to higher values).

The object also exposes pulse_rate (when intrinsic or limit monitoring is active), value_change_time / value_before_change for detecting manual presets, and value_set which the local logic can use to preset the counter. The optional logging_record / logging_object pair supports atomic snapshot acquisition by a local logger (see Developer notes).

present_value is declared readonly in the object definition; writes normally come only from the local pulse source. out_of_service allows the input pulses to be ignored while a test total is forced. No priority array is present.

When intrinsic_reporting: true, UNSIGNED_RANGE high/low limit alarming on the accumulated count becomes available.

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

The object definition (via ObjectsMacro) provides the struct, create/update_property etc., type safety, defaults, implicit relationships, validators, and readonly/protected annotations (the latter are hints; your device server read/write handlers must enforce BACnet-side write protection for readonly properties and inputs).

Special / live properties and expected developer behaviour

These are the properties that are not just passive configuration or simple data. The object struct + macro provide storage, type checks, some implicit side effects, and advisory flags. You (device server / driver / app author) must implement the live semantics and keep them consistent with the real world / hardware. Always use update_property/3 (or helpers) to change them; direct map updates bypass logic.

  • present_value: The current accumulated total, after applying prescale + scale and rollover at max_present_value. This is the primary "live" input property (analog to other input objects' present_value). Dev must: From your pulse counting hardware/driver/polling task, call update_property(obj, :present_value, new_total) on pulse arrival or periodic batch. Handle rollover yourself or let the update do it if within max. This drives COV, intrinsic events (UNSIGNED_RANGE), status, etc.

  • out_of_service: When true, pulses are ignored; PV can be forced for testing/commissioning. Dev must: Suspend normal pulse processing / driver updates while true. Allow (in your write handler) writes to present_value / value_set only when true. Resume on false.

  • reliability (with implicit reliability_evaluation_inhibit): Current fault status (no_fault_detected, over_range, etc.). Dev must: Update it based on your pulse source health (e.g. comms loss to remote counter, sensor error). When changed, re-eval events if intrinsic.

  • value_set: The "preset" input. Writing here is how you (or a client when allowed) set a new total (e.g. after meter replacement). Dev must: Your code around update_property/3 should treat a write to value_set as a preset: snapshot the old present_value into value_before_change, set value_change_time to now, then apply the new value to present_value (or let subsequent logic). The change properties are side-effect outputs for observers to detect manual presets. Note: server write protection applies similar to present_value when !out_of_service.

  • value_change_time / value_before_change (readonly): Timestamp and prior value for the last preset. Dev must: Populate them (as described for value_set) so that clients and your own logic can detect when/how the accumulator was manually adjusted.

  • logging_record + logging_object: Support for atomic historical sampling by a co-resident logger (e.g. Trend Log in same device). Dev must (the key acquire-on-read contract): If logging_object is set, when that object (or any reader) reads logging_record, your read path must:

    1. Capture a stable, atomic snapshot from the underlying pulse/accumulated state (per spec: not mid-increment of PV vs accumulated_value).
    2. Build %AccumulatorRecord{timestamp: now, present_value: ..., accumulated_value: ..., ...}.
    3. Append the new record to the logging_record property and update_property/3.
    4. Return the fresh value. Before first acquire (or if never), use wildcard timestamp + zeros + status :starting. See BACnet.Protocol.AccumulatorRecord for the struct. This is analogous to present_value maintenance but triggered by reads instead of pulses.
  • pulse_rate + limit_monitoring_interval (intrinsic related): pulse_rate is the count of pulses in the recent interval. Dev must: Depending on implementation, either maintain pulse_rate yourself (from hardware) or ensure the limit monitoring logic (your event engine) has what it needs. The object links it via implicit to the interval.

  • Intrinsic properties (high_limit, low_limit, ... + full event set when enabled): Dev must: After any present_value or reliability update, your event processing code must re-run the UNSIGNED_RANGE algorithm using the limits on this object, update event_state/timestamps etc., and emit notifications via the notification_class if transitions require it. The object stores state; you drive the machine.

  • cov_increment: Affects when COV notifications are sent for present_value changes.

General: After any update_property/3 that returns :ok, store the returned object (it may have had computed/side effects). Your write handlers must respect readonly (use get_readonly_properties/0) and out_of_service rules for conformance.

Creation and initialisation: Use create/4. Required properties in the map include at minimum :units, :scale, :prescale (and :max_present_value if you want something other than the 32-bit max default). If intrinsic_reporting: true is passed in opts, the limit fields (high_limit, low_limit, pulse_rate, limit_monitoring_interval) plus the full intrinsic set (event_enable, etc.) become active and non-nil.

Maintaining present_value at runtime: Your sensor/pulse driver or I/O polling task MUST keep the value up to date by calling update_property(obj, :present_value, new_count) (or the equivalent in your device server abstraction) whenever a pulse arrives or a batch is processed. Direct struct mutation (%{obj | present_value: val}) bypasses validators, implicit relationships, the type's inhibit_object_check, and any side-effect logic. After a successful update the returned object should be stored back in your object database / registry.

Write protection for inputs (critical for BACnet conformance): Unlike commandable output/value objects (where the library itself protects :present_value in update_property/3 and set_priority/3 unless out_of_service), input-style objects like Accumulator provide no automatic protection. The device server layer (your WriteProperty / WritePropertyMultiple handler, or the code that receives BACnet writes) is responsible for rejecting attempts to write :present_value (or :value_set) when out_of_service == false. Typical error is {:error, :write_access_denied} or a BACnet error constructed from it. Local application code (your driver) is allowed to "write" via the internal path. See the macro documentation in BACnet.Protocol.ObjectsMacro for the exact note on input objects.

out_of_service semantics: Setting it true (via network write or local) signals that pulses should be ignored; you can then force a synthetic total by writing :present_value (now allowed) for testing, simulation, or commissioning. The pulse_rate / limit logic should typically be suspended. When you set it back to false, the physical source resumes.

Presets and change tracking: To preset the accumulator (e.g. after a meter replacement), write the desired total to :value_set. Your driver should monitor the side-effect properties (value_change_time, value_before_change) that the object populates on such updates.

Logging_Record and Logging_Object (special acquire-on-read properties): These optional properties enable atomic historical sampling by a co-located logger (commonly a Trend Log in the same device) without the logger needing direct access to the pulse hardware or risking inconsistent reads of present_value vs. the internal accumulated total.

logging_object (when present) identifies the logger object that will "acquire" records from this accumulator. Its presence changes the required behaviour of logging_record.

logging_record holds the most recently acquired atomic sample. Each BACnet.Protocol.AccumulatorRecord carries a timestamp, the present_value and accumulated_value at sample time, plus an accumulator_status.

Per ASHRAE 135: the values must be acquired and returned "atomically". If logging_object is set and no acquisition has occurred yet, the record must use a fully-wildcard timestamp, zero for the two value fields, and status :starting. Acquisition must occur when the underlying system is in a stable state (example from the spec: not between a PV pulse increment and the corresponding accumulated-value update).

What the developer must do (analogous to maintaining present_value): The library never auto-populates logging_record; it is entirely your responsibility (your pulse driver, meter interface, or a logging coordinator). Exactly as you drive present_value from the physical source via update_property/3, you must supply fresh records to logging_record via the same call when acquisition is triggered.

  • Network writes to logging_record (and usually logging_object only by privileged local logic) must be rejected by your device server's WriteProperty handler using the readonly annotation (get_readonly_properties/0) or explicit checks. Internal/driver code may write.
  • On every read of logging_record (BACnet ReadProperty or internal read by the logger that owns logging_object): your read path must trigger acquisition of a stable snapshot from the real counter, build the AccumulatorRecord, update_property(obj, :logging_record, [record]), then return the value. This is the key "special property" contract.
  • Because acquisition logic is instance- and hardware-specific, most implementors handle the special case for accumulator+logging_record centrally in their property read dispatcher rather than (or in addition to) wiring an annotation on the field definition.

After acquisition the just-captured record stays visible to subsequent reads until the next acquisition. This lets a local Trend Log treat the accumulator's logging_record as a "sample source" that always yields a consistent point-in-time total when read.

Intrinsic / event processing: When intrinsic is enabled the object carries the full event state machine fields. After you update :present_value (or :reliability), your event engine (or the code that calls into event detection) must re-evaluate the UNSIGNED_RANGE algorithm using the high/low/deadband params present on the object, update :event_state, manage :event_timestamps etc., and emit ConfirmedEventNotification / Unconfirmed... via the referenced notification_class when transitions occur. The object itself does not auto-emit; that is a server responsibility.

Remote objects: If _metadata.remote_object is set (populated by BACnet.Protocol.ObjectsUtility when reading from a remote device), all mutation operations (update_property, add_property, set_priority, etc.) will be rejected by the generated code. You can only read remote accumulators.

Reliability and status: Your driver must keep :reliability current (e.g. :no_fault_detected, :over_range, :communication_failure for a remote pulse source). The status_flags.fault (and in_alarm, out_of_service) bits are automatically kept in sync by the object based on reliability, event_state and out_of_service. The overridden bit is a local matter.

See the generated moduledoc tables for which fields are readonly, required, have init_funs, validators, or implicit_relationships.

Intrinsic Reporting

When intrinsic_reporting: true is passed to create/4, the UNSIGNED_RANGE event algorithm and related properties become active.

Examples

Creating an Accumulator:

iex> {:ok, acc} = BACnet.Protocol.ObjectTypes.Accumulator.create(200, "Energy", %{units: :kilowatt_hours, scale: 10, prescale: %BACnet.Protocol.Prescale{multiplier: 1, modulo_divide: 1}}); acc.object_name
"Energy"

See Also



The following part has been automatically generated.

Click to expand This module defines a BACnet object of the type `accumulator`. The following properties are defined: | Property | Revision | Required | Readonly | Protected | Intrinsic | |----------|----------|----------|----------|-----------|-----------| | acked_transitions | | | X | | X | | description | | | | | | | device_type | | | | | | | event_algorithm_inhibit | | | | | X | | event_algorithm_inhibit_ref | | | | | X | | event_detection_enable | | | | | X | | event_enable | | | | | X | | event_message_texts | | | X | | X | | event_message_texts_config | | | | | X | | event_state | | X | | | | | event_timestamps | | | X | | X | | high_limit | | | | | X | | limit_enable | | | | | X | | limit_monitoring_interval | | | | | X | | logging_object | | | | | | | logging_record | | | X | | | | low_limit | | | | | X | | max_present_value | | X | | | | | notification_class | | | | | X | | notify_type | | | | | X | | object_instance | | X | X | | | | object_name | | X | X | | | | out_of_service | | X | | | | | prescale | | X | | | | | present_value | | X | X | | | | profile_location | 19 | | | | | | profile_name | | | | | | | pulse_rate | | | | | X | | reliability | | | | | | | reliability_evaluation_inhibit | | | | | | | scale | | X | | | | | status_flags | | X | X | | | | tags | 19 | | | | | | time_delay | | | | | X | | time_delay_normal | | | | | X | | units | | X | | | | | value_before_change | | | X | | | | value_change_time | | | X | | | | value_set | | | | | | The following properties have additional semantics: | Property | Has Default | Has Init | Implicit Relationships | Validators | Annotations | |----------|-------------|----------|------------------------|------------|-------------| | event_algorithm_inhibit_ref | | | event_algorithm_inhibit | | | | high_limit | X | | | | | | limit_monitoring_interval | X | | | | | | low_limit | X | | | | | | max_present_value | X | | | | | | present_value | X | | | | | | profile_location | | | | Fun | `revision: 19` | | pulse_rate | | | limit_monitoring_interval | | | | reliability | | | reliability_evaluation_inhibit | | | | scale | | | | | `decoder: {:fn, [line: 295, column: 18], [{:->, [line: 295, column: 58], [[{:=, [line: 295, column: 47], [{:%, [line: 295, column: 21], [{:__aliases__, [line: 295, column: 22], [:Encoding]}, {:%{}, [line: 295, column: 30], [extras: {:extras, [line: 295, column: 39], nil}]}]}, {:encoding, [line: 295, column: 49], nil}]}], {:case, [line: 296, column: 11], [{{:., [line: 296, column: 23], [{:__aliases__, [line: 296, column: 16], [:Keyword]}, :fetch]}, [line: 296, column: 24], [{:extras, [line: 296, column: 30], nil}, :tag_number]}, [do: [{:->, [line: 297, column: 22], [[ok: 0], {:with, [line: 298, column: 15], [{:<-, ...}, ...]}]}, ...]]]}]}]}, ...` | | tags | | | | | `revision: 19` | | units | X | | | | | | value_before_change | X | | value_change_time | | | | value_change_time | | X | | | | The following table shows the default values and/or init functions: | Property | Default Value | Init Function | |----------|---------------|---------------| | high_limit | `0` | | | limit_monitoring_interval | `1` | | | low_limit | `0` | | | max_present_value | `4294967295` | | | present_value | `0` | | | units | `:no_units` | | | value_before_change | `0` | | | value_change_time | | `BACnet.Protocol.ObjectsMacro.get_default_bacnet_datetime/0` |

Summary

Types

Common object options for creation - all are optional.

Options accepted when creating or configuring an Accumulator object.

Available property names for this object.

The structure for property errors.

t()

Represents an Accumulator 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 object has Intrinsic Reporting enabled.

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 Accumulator object.

property_name()

@type property_name() ::
  :acked_transitions
  | :description
  | :device_type
  | :event_algorithm_inhibit
  | :event_algorithm_inhibit_ref
  | :event_detection_enable
  | :event_enable
  | :event_message_texts
  | :event_message_texts_config
  | :event_state
  | :event_timestamps
  | :high_limit
  | :limit_enable
  | :limit_monitoring_interval
  | :logging_object
  | :logging_record
  | :low_limit
  | :max_present_value
  | :notification_class
  | :notify_type
  | :object_instance
  | :object_name
  | :out_of_service
  | :prescale
  | :present_value
  | :profile_location
  | :profile_name
  | :pulse_rate
  | :reliability
  | :reliability_evaluation_inhibit
  | :scale
  | :status_flags
  | :tags
  | :time_delay
  | :time_delay_normal
  | :units
  | :value_before_change
  | :value_change_time
  | :value_set

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.Accumulator{
  _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,
  device_type: String.t() | nil,
  event_algorithm_inhibit: boolean() | nil,
  event_algorithm_inhibit_ref: BACnet.Protocol.ObjectPropertyRef.t() | nil,
  event_detection_enable: boolean() | nil,
  event_enable: BACnet.Protocol.EventTransitionBits.t() | nil,
  event_message_texts: BACnet.Protocol.EventMessageTexts.t() | nil,
  event_message_texts_config: BACnet.Protocol.EventMessageTexts.t() | nil,
  event_state:
    BACnet.Protocol.Constants.event_state()
    | (reserved_or_vendor_extension :: non_neg_integer()),
  event_timestamps: BACnet.Protocol.EventTimestamps.t() | nil,
  high_limit: non_neg_integer() | nil,
  limit_enable: BACnet.Protocol.LimitEnable.t() | nil,
  limit_monitoring_interval: non_neg_integer() | nil,
  logging_object: BACnet.Protocol.ObjectIdentifier.t() | nil,
  logging_record: [BACnet.Protocol.AccumulatorRecord.t()] | nil,
  low_limit: non_neg_integer() | nil,
  max_present_value: non_neg_integer(),
  notification_class: non_neg_integer() | nil,
  notify_type:
    BACnet.Protocol.Constants.notify_type()
    | (reserved_or_vendor_extension :: non_neg_integer())
    | nil,
  object_instance: non_neg_integer(),
  object_name: String.t(),
  out_of_service: boolean(),
  prescale: BACnet.Protocol.Prescale.t(),
  present_value: non_neg_integer(),
  profile_location: String.t() | nil,
  profile_name: String.t() | nil,
  pulse_rate: non_neg_integer() | nil,
  reliability:
    BACnet.Protocol.Constants.reliability()
    | (reserved_or_vendor_extension :: non_neg_integer())
    | nil,
  reliability_evaluation_inhibit: boolean() | nil,
  scale: float() | integer(),
  status_flags: BACnet.Protocol.StatusFlags.t(),
  tags: BACnet.Protocol.BACnetArray.t(BACnet.Protocol.NameValue.t()) | nil,
  time_delay: non_neg_integer() | nil,
  time_delay_normal: non_neg_integer() | nil,
  units:
    BACnet.Protocol.Constants.engineering_unit()
    | (reserved_or_vendor_extension :: non_neg_integer()),
  value_before_change: non_neg_integer() | nil,
  value_change_time: BACnet.Protocol.BACnetDateTime.t() | nil,
  value_set: non_neg_integer() | nil
}

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

The max_present_value property defaults to 2^32-1 and can be manually set to a higher value, if desired and/or needed.

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.

intrinsic_reporting?(object)

@spec intrinsic_reporting?(t()) :: boolean()

Checks if the given object has Intrinsic Reporting enabled.

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.