BACnet.Stack.ForeignDevice (bacstack v0.1.0-dev.1)

Copy Markdown View Source

The Foreign Device module is a server process that takes care of registering the application (client/transport) as a Foreign Device in a BACnet/IPv4 Broadcast Management Device (BBMD).

It will automatically renew the registration in the BBMD, as long as this Foreign Device process is alive. The default Time-To-Live (TTL) is a development value and should always be overwritten in a production environment to lessen network traffic caused by Foreign Device registration.

It also allows to read the BBMD's Broadcast Distribution Table, Foreign Device Table and distribute Unconfirmed Service Request APDUs through it.

If registration in the BBMD fails, it will automatically retry to register in the BBMD at a later point in time (10 seconds). Currently this value can not be changed and is hardcoded.

For each BBMD (client/transport) one Foreign Device process is required. This allows to register in many BBMDs as Foreign Device.

BACnet Specification References

The registration, renewal and table-read behaviour follows Annex J.5.2. The TTL value supplied in the Register-Foreign-Device message (J.2.6) plus the 30-second grace period (J.5.2.3) determines how long the remote BBMD will keep the registration. Distribute-Broadcast-To-Network (J.2.10) is the mechanism used by distribute/2.

See Also

Summary

Types

Represents a BACnet.Stack.Client process. It will be used to retrieve the transport module, transport and portal through the BACnet.Stack.Client API.

Represents a server process of the Foreign Device module.

Valid start options. For a description of each, see start_link/1.

List of start options.

Functions

Returns a specification to start this module under a supervisor.

Distributes the given APDU as broadcast through the BBMD. Only unconfirmed service requests can be sent as broadcast.

Get the status of Foreign Device registration.

Reads the Broadcast Distribution Table of the BBMD.

Reads the Foreign Device Table of the BBMD.

Explicitely renews the Foreign Device Registration in the BBMD.

Sends a Who-Is APDU to the BBMD for local broadcast.

Starts and links the BACnet Foreign Device.

Stops and shuts down the Foreign Device.

Writes the Broadcast Distribution Table of the BBMD.

Types

client()

@type client() :: BACnet.Stack.Client.server()

Represents a BACnet.Stack.Client process. It will be used to retrieve the transport module, transport and portal through the BACnet.Stack.Client API.

server()

@type server() :: GenServer.server()

Represents a server process of the Foreign Device module.

start_option()

@type start_option() ::
  {:bbmd, {:inet.ip4_address(), port :: 1..65535}}
  | {:client, client()}
  | {:reply_rfd, boolean()}
  | {:ttl, pos_integer()}
  | GenServer.option()

Valid start options. For a description of each, see start_link/1.

start_options()

@type start_options() :: [start_option()]

List of start options.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

distribute_broadcast(server, apdu, opts \\ [])

@spec distribute_broadcast(
  server(),
  BACnet.Protocol.APDU.UnconfirmedServiceRequest.t(),
  Keyword.t()
) ::
  :ok | {:error, BACnet.Protocol.BvlcResult.t()} | {:error, term()}

Distributes the given APDU as broadcast through the BBMD. Only unconfirmed service requests can be sent as broadcast.

It will spawn a new Task to temporarily subscribe for BACnet.Stack.Client notifications to receive BVLL/BVLC messages.

It uses BACnet.Stack.Client to send the APDU, all opts will be given to BACnet.Stack.Client.send/4, in addition, the following are available for this function only:

  • receive_timeout: non_neg_integer() - Optional. The timeout to use to await BVLL/BVLC NAK response from the BBMD. Defaults to 1_000.

get_status(server)

@spec get_status(server()) :: :registered | :waiting_for_ack | :uninitialized

Get the status of Foreign Device registration.

read_broadcast_distribution_table(server, opts \\ [])

@spec read_broadcast_distribution_table(server(), Keyword.t()) ::
  {:ok, [BACnet.Protocol.BroadcastDistributionTableEntry.t()]}
  | {:error, BACnet.Protocol.BvlcResult.t()}
  | {:error, term()}

Reads the Broadcast Distribution Table of the BBMD.

This function will only read the BBMD address from the Foreign Device server, all communication to the BBMD is done in the caller process using a Task. The new Task will temporarily subscribe for BACnet.Stack.Client notifications to be able to process BVLL/BVLC messages.

The following options are available:

  • timeout: non_neg_integer() | :infinity - Optional. The timeout to use for waiting for the BBMD reply.

read_foreign_device_table(server, opts \\ [])

@spec read_foreign_device_table(server(), Keyword.t()) ::
  {:ok, [BACnet.Protocol.ForeignDeviceTableEntry.t()]}
  | {:error, BACnet.Protocol.BvlcResult.t()}
  | {:error, term()}

Reads the Foreign Device Table of the BBMD.

This function will only read the BBMD address from the Foreign Device server, all communication to the BBMD is done in the caller process using a Task. The new Task will temporarily subscribe for BACnet.Stack.Client notifications to be able to process BVLL/BVLC messages.

The following options are available:

  • timeout: non_neg_integer() | :infinity - Optional. The timeout to use for waiting for the BBMD reply.

renew(server)

@spec renew(server()) :: :ok

Explicitely renews the Foreign Device Registration in the BBMD.

This function returns :ok almost immediately, without waiting for a response from the BBMD.

send_whois(server, timeout \\ 5000, opts \\ [])

@spec send_whois(server(), non_neg_integer(), Keyword.t()) ::
  {:ok, [BACnet.Protocol.Services.IAm.t()]} | {:error, term()}

Sends a Who-Is APDU to the BBMD for local broadcast.

It uses distribute_broadcast/3 to do the broadcast and then collects the incoming BACnet.Protocol.Services.IAm messages. This function will always spawn a new Task to send and collect messages.

It accepts the same options as BACnet.Stack.ClientHelper.who_is/3, except apdu_destination and no_subscribe.

start_link(opts)

@spec start_link(start_options()) :: GenServer.on_start()

Starts and links the BACnet Foreign Device.

The following options are available, in addition to GenServer.options/0:

  • bbmd: {:inet.ip4_address(), 1..65_535} - Required. The BBMD address to register itself as Foreign Device with.
  • client: client() - Required. The client & transport information.
  • reply_rfd: boolean() - Optional. Enables replying to Register-Foreign-Device packets from other BACnet clients. Defaults to true. If multiple BACnet.Stack.ForeignDevice processes are running on the same client/transport, all except for one MUST have this option disabled.
  • ttl: pos_integer() - Optional. The time in seconds until the Foreign Device Registration expires. Defaults to 60.

stop(server)

@spec stop(server()) :: :ok

Stops and shuts down the Foreign Device.

If a registration is active, it will try to delete it in the BBMD.

write_broadcast_distribution_table(server, bdt, opts \\ [])

@spec write_broadcast_distribution_table(
  server(),
  [BACnet.Protocol.BroadcastDistributionTableEntry.t()],
  Keyword.t()
) :: :ok | {:error, BACnet.Protocol.BvlcResult.t()} | {:error, term()}

Writes the Broadcast Distribution Table of the BBMD.

This function will only read the BBMD address from the Foreign Device server, all communication to the BBMD is done in the caller process using a Task. The new Task will temporarily subscribe for BACnet.Stack.Client notifications to be able to process BVLL/BVLC messages.

Since the response from the BBMD is a generic success message, without any other information, you MUST make sure that this is the ONLY BVLL command that gets executed concurrently. Otherwise this or any other concurrent BVLL command MAY receive a false positive response instead of a negative response that would be the actual response to the BVLL command.

The following options are available:

  • timeout: non_neg_integer() | :infinity - Optional. The timeout to use for waiting for the BBMD reply.