DEV Community

Masatoshi Nishiguchi
Masatoshi Nishiguchi

Posted on • Updated on

Connect Nerves devices forming an Erlang cluster

I want to enable my Nerves devices to talk to each other using Distributed Erlang. Here is my memo.

Preparation

About Nerves

If you are not familiar with Nerves, this conference talk by a Nerves co-author Frank Hunleth will introduce it to you.

Find hostname or IP address for each device

Normally when shelling into a Nerves device, we will see IP address and host name printed by nerves_motd.

DNS Bridge configuration

According to mdns_lite - DNS Bridge configuration documentation, we need to let Erlang/OTP's built-in DNS resolver know about mDNS. Underjord's YouTube video explaining DNS Bridge configuration was helpful.

Start Erlang nodes

  • nerves_pack - Erlang distribution documentation explains about how to form an Erlang cluster.
  • Let's say we have a device with host name nerves-mn00.local and anoter with host name nerves-mn02.local.
  • Alternatively IP addresses can be used instead of host names
  • Make sure that the same Erlang magic cookie is used
 ssh nerves-mn00.local

# make sure the epmd OS process is running by calling epmd -daemon
iex> System.cmd("epmd", ["-daemon"])

# start a node.
iex> Node.start(:"nerves@nerves-mn00.local")

# check current node. `node/0` does the same.
iex(nerves@nerves-mn00.local)> Node.self()

# configure the magic cookie to form this cluster.
iex(nerves@nerves-mn00.local)> Node.set_cookie(:securecookie)
Enter fullscreen mode Exit fullscreen mode
 ssh nerves-mn02.local

iex> System.cmd("epmd", ["-daemon"])
iex> Node.start(:"nerves@nerves-mn02.local")
iex(nerves@nerves-mn02.local)> Node.set_cookie(:securecookie)
Enter fullscreen mode Exit fullscreen mode

Connect a node to another

  • Let's connect nerves-mn02.local to nerves-mn00.local
iex(nerves@nerves-mn02.local)> Node.connect(:"nerves@nerves-mn00.local")
true

iex(nerves@nerves-mn02.local)> Node.list()
[:"nerves@nerves-mn00.local"]
Enter fullscreen mode Exit fullscreen mode

Invoke a function in another node

  • From nerves-mn02.local invoke a function that is defined in nerves-mn00.local using Node.spawn/2 or something similar
  • Let's access to the other device and peek into its firmware infomation by invoking Toolshed.Nerves.uname/0 that is normally available in our Nerves IEx shell.
Node.spawn(
  # the node name we want to invoke a function in
  :"nerves@nerves-mn00.local",
  # the function we want to invoke
  fn -> Toolshed.Nerves.uname() end
)
Enter fullscreen mode Exit fullscreen mode
iex(nerves@nerves-mn02.local)> Node.spawn(:"nerves@nerves-mn00.local", fn -> Toolshed.Nerves.uname() end)
Nerves nerves-mn00 hello_nerves 0.1.0 (240d82e1-1e6c-5800-0ef9-63cba9efc212) arm
#PID<51667.6840.0>
Enter fullscreen mode Exit fullscreen mode

Yay, we were able to at least do something in another device through the Distributed Erlang. Isn't it cool?

I put together what I learned as kantan_cluster Elixir package. It allows us to form an Erlang cluster automatically. Please take a look if you like.

Resources

Discussion (0)