ASHRAE 135 Annex Q.8 defines a BACnet URI scheme, in cases where a URI is needed to refer to data that is accessible using BACnet services.
A BACnet URI is used to refer to BACnet objects,
similar to BACnet.Protocol.DeviceObjectPropertyRef.
The format looks like this:
bacnet://<device>/<object>[/<property>[/<index>]]
Where angle brackets indicate variable text and square brackets indicate optionality.
The <device> segment is the device instance number in decimal.
A <device> identifier of .this means 'this device' so that it can be used in static files
that do not need to be changed when the device identifier changes.
The <object> identifier is in the form <type>,<instance> where <type> is either
a decimal number or BACnet.Protocol.Constants.object_type/0,
and <instance> is a decimal number.
The <property> identifier is either a decimal number or
BACnet.Protocol.Constants.property_identifier/0.
If it is omitted, it defaults to :present_value except for BACnet File objects,
where absence of <property> refers to the entire content of the file accessed with Stream Access.
In that special case, property is set to nil.
The <index> is the decimal number for the index of an array property.
Summary
Functions
Encodes a BACnetURI struct into a BACnet URI string.
Parses a BACnet URI string into a BACnetURI struct.
Returns true if the BACnetURI struct contains valid data according to
the BACnet URI scheme rules (Annex Q.8).
Returns true if the given BACnet URI string is valid.
Types
@type encode_opt() :: {:always_decimal, boolean()}
Available options for encode/2.
The always_decimal option will force the function to
always use decimal numbers in the URI output for better compatibility.
Otherwise it will by default try to use the Clause 21 definition text,
where possible.
@type t() :: %BACnet.Protocol.BACnetURI{ device_identifier: BACnet.Protocol.ObjectIdentifier.t() | nil, object_identifier: BACnet.Protocol.ObjectIdentifier.t(), property_array_index: non_neg_integer() | nil, property_identifier: BACnet.Protocol.Constants.property_identifier() | non_neg_integer() | nil }
Represents a BACnet URI.
Functions
@spec encode(t(), [encode_opt()]) :: {:ok, String.t()} | {:error, term()}
Encodes a BACnetURI struct into a BACnet URI string.
When the property is nil (for File objects), the property segment is omitted.
Otherwise the property is always included.
This function will use Clause 21 text for the URI encoding where possible and fallback to use the decimal number where necessary. It can be configured to always use the decimal number for better compability. If the object type or property identifier is a number, it will also be encoded as a number. It will not be converted to text.
Examples
Local object:
iex> object = %BACnet.Protocol.ObjectIdentifier{type: :analog_output, instance: 5}
iex> BACnetURI.encode(%BACnetURI{
...> device_identifier: nil, object_identifier: object,
...> property_identifier: :present_value, property_array_index: nil
...> })
{:ok, "bacnet://.this/analog-output,5/present-value"}
iex> BACnetURI.encode(%BACnetURI{
...> device_identifier: nil, object_identifier: object,
...> property_identifier: :present_value, property_array_index: nil
...> }, always_decimal: true)
{:ok, "bacnet://.this/1,5/85"}Remote object with array index:
iex> device = %BACnet.Protocol.ObjectIdentifier{type: :device, instance: 114705}
iex> object = %BACnet.Protocol.ObjectIdentifier{type: :binary_output, instance: 15555}
iex> BACnetURI.encode(%BACnetURI{
...> device_identifier: device, object_identifier: object,
...> property_identifier: :priority_array, property_array_index: 16
...> }, always_decimal: true)
{:ok, "bacnet://114705/4,15555/87/16"}
Parses a BACnet URI string into a BACnetURI struct.
Returns {:ok, uri} on success or {:error, reason} on failure.
This function is more permissive than the specification,
as in allows different casing and _ for object types
and property identifiers. Not only analog-value is allowed,
but also Analog_Value or analog_value.
Examples
Local object:
iex> BACnetURI.parse("bacnet://.this/1,5/85")
{:ok, %BACnetURI{
device_identifier: nil,
object_identifier: %BACnet.Protocol.ObjectIdentifier{type: :analog_output, instance: 5},
property_identifier: :present_value,
property_array_index: nil
}}
iex> BACnetURI.parse("bacnet://.this/analog-output,5")
{:ok, %BACnetURI{
device_identifier: nil,
object_identifier: %BACnet.Protocol.ObjectIdentifier{type: :analog_output, instance: 5},
property_identifier: :present_value,
property_array_index: nil
}}Remote object with array index:
iex> BACnetURI.parse("bacnet://114705/4,15555/priority-array/16")
{:ok, %BACnetURI{
device_identifier: %BACnet.Protocol.ObjectIdentifier{type: :device, instance: 114705},
object_identifier: %BACnet.Protocol.ObjectIdentifier{type: :binary_output, instance: 15555},
property_identifier: :priority_array,
property_array_index: 16
}}
Returns true if the BACnetURI struct contains valid data according to
the BACnet URI scheme rules (Annex Q.8).
Returns true if the given BACnet URI string is valid.
This function will attempt to parse the string and then validate it.