Discovery

This tutorial will cover the following topics:

Content

Local Discovery Server

The Local Discovery Server (LDS) provides the necessary infrastructure to publicly expose the OPC UA Servers available on a given computer.

OPC UA Servers will periodically connect to the LDS and Register themselves as being available. This periodic activity means that the list of available OPC UA servers is always current and means that an OPC UA client can immediately connect to any of them.

Server

Assuming that an OPC UA Server has been created and configured as shown in Lifecycle tutorial.

LDS Configuration

To spawn an LDS server, follow these steps.

alias OpcUA.Server

{:ok, lds_pid} = Server.start_link()

:ok = Server.set_default_config(lds_pid)

application_uri = "urn:opex62541.test.local_discovery_server"
:ok = Server.set_lds_config(lds_pid, application_uri)

Note: LDS Servers only supports the Discovery Services. Therefore, it cannot be used in combination with any other capability.

Registration

The LDS maintains a list of available servers which servers may use to announce their existence to clients. Any other server can register with this server using discovery_register/2 function as shown below:

alias OpcUA.Server

{:ok, server_pid} = Server.start_link()

:ok = Server.set_default_config(server_pid)

application_uri = "urn:opex62541.test.local_register_server"
:ok = Server.discovery_register(server_pid,
        application_uri: application_uri,
        server_name: "TestRegister",
        endpoint: "opc.tcp://localhost:4840"
      )

The endpoint option represents the LDS endpoint, and the server_name is how the registered server will be visible in the network.

The discovery_unregister can be used to delete the desired server from the LDS server.

:ok = Server.discovery_unregister(server_pid)

Client

Clients may request a list of all available servers from the discovery server (LDS) and then use the GetEndpoints service to get the connection information from a server.

Assuming you have an LDS server with a registered server

alias OpcUA.Server

#LDS Server
{:ok, lds_pid} = Server.start_link()
:ok = Server.set_port(lds_pid, 4050)
:ok = Server.set_lds_config(lds_pid, "urn:opex62541.test.local_discovery_server")
:ok = Server.start(lds_pid)

#Normal OPC UA Server
{:ok, s_pid} = Server.start_link()
:ok = Server.set_port(s_pid, 4048)

:ok = Server.discovery_register(s_pid,
        application_uri: "urn:opex62541.test.local_register_server",
        server_name: "testRegister",
        endpoint: "opc.tcp://localhost:4050"
      )
:ok = Server.start(s_pid)

# Registration time
Process.sleep(1500)

Scanning Network

To discover all OPC UA Server in the network, you can use find_servers_on_network/2,

alias OpcUA.Client

{:ok, c_pid} = Client.start_link()
:ok = Client.set_config(c_pid)

# LDS Server url
url = "opc.tcp://localhost:4050/"

Client.find_servers_on_network(c_pid, url)

# this response may change depending on your computer
{:ok,
 [
   %{
     "capabilities" => ["LDS"],
     "discovery_url" => "opc.tcp://localhost:4050",
     "record_id" => 0,
     "server_name" => "LDS-localhost"
   },
   %{
     "capabilities" => ["NA"],
     "discovery_url" => "opc.tcp://localhost:4048",
     "record_id" => 1,
     "server_name" => "testRegister-localhost"
   }
 ]}

If you require more detailed information, you can use the find_server/2 function.

Client.find_servers(c_pid, url)

# this response may change depending on your computer
{:ok,
  [
    %{
      "discovery_url" => ["opc.tcp://localhost:4050/"],
      "name" => "open62541-based OPC UA Application",
      "product_uri" => "http://open62541.org",
      "application_uri" => "urn:opex62541.test.local_discovery_server",
      "server" => "urn:opex62541.test.local_discovery_server",
      "type" => "discovery_server"
    },
    %{
      "application_uri" => "urn:opex62541.test.local_register_server",
      "discovery_url" => [
        "opc.tcp://localhost:4048/",
        "opc.tcp://localhost:4048/"
      ],
      "name" => "open62541-based OPC UA Application",
      "product_uri" => "http://open62541.org",
      "server" => "urn:opex62541.test.local_register_server",
      "type" => "server"
    }
  ]}

Finally, to get the server endpoints, you can use the get_endpoints/2 function.


url = "opc.tcp://localhost:4048"
Client.get_endpoints(c_pid, url)

# this response may change depending on your computer
{:ok,
  [
    %{
      "endpoint_url" => "opc.tcp://localhost:4048",
      "security_level" => 1,
      "security_mode" => "none",
      "security_profile_uri" => "http://opcfoundation.org/UA/SecurityPolicy#None",
      "transport_profile_uri" =>
        "http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"
    }
  ]}