Skip to content
Branch: master
Find file History
Type Name Latest commit message Commit time
Failed to load latest commit information.
config Default to usb0 for hello_network to match the others Feb 21, 2019
lib Format code with mix format (#72) Feb 13, 2018
rel Synchronize various files with latest template Oct 24, 2018
rootfs_overlay/etc Replace Nerves.Runtime.Helpers with Toolshed Jun 5, 2019
.formatter.exs Update hello_network example. Mar 17, 2018
.gitignore Synchronize various files with latest template Oct 24, 2018 Consistently assume rpi0 target by default Feb 21, 2019
mix.exs Update for Elixir 1.8 and Nerves 1.4 Feb 21, 2019

Hello Network

This example shows how to connect your Nerves device to the network using wired or wireless Ethernet. By default, the configuration assumes that you'll be connecting using the USB gadget interface usb0, but you can change the :ifname option in config/config.exs to choose another interface (such as "wlan0" for WiFi or "eth00" for wired Ethernet). The targets with built-in WiFi hardware (such as rpi3 and rpi0 on a Zero W) will work with their built in-WiFi, but you can also use a variety of popular USB WiFi dongles on other targets.

How to Use the Code in this Repository

  1. Specify your target with the MIX_TARGET environment variable
  2. Get dependencies with mix deps.get
  3. Create firmware with mix firmware
  4. Burn firmware to an SD card with mix firmware.burn
  5. Connect a monitor to the HDMI port on the board
  6. Insert the SD card into your target board and power it on
  7. After about 5 seconds, you should see messages on the console
export MIX_TARGET=rpi0
mix deps.get
mix firmware
mix firmware.burn

How to Use the WiFi and Wired Interfaces

Configure the application settings to use the WiFi interface ("wlan0") or wired interface ("eth0") instead of the USB gadget Ethernet interface ("usb0"). Also be sure to switch from :dhcpd (DHCP server mode) to :dhcp (DHCP client mode) as appropriate for the interface.

# config/config.exs

# ...

config :nerves_init_gadget,
  mdns_domain: "hello_network.local",
  node_name: node_name,
  node_host: :mdns_domain,
  # ifname: "usb0",
  # address_method: :dhcpd

  # To use wired Ethernet:
  # ifname: "eth0",
  # address_method: :dhcp

  # To use WiFi:
  ifname: "wlan0",
  address_method: :dhcp

# Configure wireless settings

key_mgmt = System.get_env("NERVES_NETWORK_KEY_MGMT") || "WPA-PSK"

config :nerves_network, :default,
  wlan0: [
    ssid: System.get_env("NERVES_NETWORK_SSID"),
    psk: System.get_env("NERVES_NETWORK_PSK"),
    key_mgmt: String.to_atom(key_mgmt)

# ...

Specify your WiFi settings using the NERVES_NETWORK_SSID and NERVES_NETWORK_PSK environmental variables during the firmware build process:

Note: NERVES_NETWORK_SSID and NERVES_NETWORK_PSK are both case-sensitive.

export NERVES_NETWORK_SSID=my_accesspoint_name
export NERVES_NETWORK_PSK=secret
export MIX_TARGET=rpi0
mix deps.get
mix firmware
mix firmware.burn

WiFi Troubleshooting Tips

If you cannot get a network connection, but you can get to the IEx prompt, you can check the interface status:

iex> Nerves.Network.status("wlan0")
  domain: "",
  ifname: "wlan0",
  index: 3,
  ipv4_address: "",
  ipv4_broadcast: "",
  ipv4_gateway: "",
  ipv4_subnet_mask: "",
  is_up: true,

If it does not have an IP address listed or is_up is false, that confirms that your interface is not connecting properly.

An incorrect WiFi password would normally generate a log message like:

00:00:21.986 [info]  WiFiManager(wlan0): ignoring event: {:error, :psk, :FAIL}

Checking the status would show the operstate is down:

iex> Nerves.Network.status("wlan0")
  ifname: "wlan0",
  is_up: true,
  operstate: :down,

To rule out configuration issues, you can try setting up the connection manually and watch the log messages that get generated.

Note: The key_mgmt setting must be an atom. This is done for you when using config.exs, but you need to be sure to do it yourself when testing manually.

iex> Nerves.Network.setup("wlan0", [ssid: "Good-Network", psk: "good-pass", key_mgmt: :"WPA-PSK"])
00:00:42.132 [info]  Register Nerves.WpaSupplicant "wlan0"
00:00:42.135 [info]  Nerves.WpaSupplicant: sending 'REMOVE_NETWORK all'
00:00:42.148 [info]  Nerves.WpaSupplicant: sending 'ADD_NETWORK'
00:00:42.167 [info]  Nerves.WpaSupplicant: sending 'SET_NETWORK 0 key_mgmt WPA-PSK'
00:00:42.177 [info]  Nerves.WpaSupplicant: sending 'SET_NETWORK 0 psk "goodpass"'
00:00:42.197 [info]  Nerves.WpaSupplicant: sending 'SET_NETWORK 0 ssid "Good-Network"'
00:00:42.353 [info]  Nerves.WpaSupplicant: sending 'SELECT_NETWORK 0'
00:00:43.141 [info]  WiFiManager(wlan0) wpa_supplicant wifi_connected

If your network isn't hidden, you can try to scan and see if you can see it:

iex> Nerves.Network.scan("wlan0")
    ssid: "Good-Network",

Testing DNS Name Resolution

There is a HelloNetwork.test_dns function that you can call in the IEx console to check that your Nerves device indeed has successfully established network connectivity and that DNS name resolution works. The expected output when DNS resolution is available is something like this:

iex(1)> HelloNetwork.test_dns()
 {:hostent, '', [], :inet, 4,
  [{192, 30, 252, 154}, {192, 30, 252, 153}]}}

Using Erlang Distribution

One of the exciting features that Erlang and Elixir provide out of the box is called Erlang Distribution. This gives you the ability to easily make a connection between multiple running instances of the Erlang VM, called "nodes."

Once you have your device running this nerves_network example project, you can use Erlang Distribution to connect to it using from your development host by starting an iex session using the appropriate "cookie" that matches the one configured on your device:

iex --name host@ --cookie chocolatechip

This cookie is set in your project's rel/vm.args file, so you can look there to verify that you have the correct cookie or change the cookie that will be set in your project's firmware.

Your iex prompt should look like this when you are running with distribution:


Then, you can connect to the target node:

iex(host@> Node.connect(:"hello_network@hello_network.local")

Note that the entire node name is an atom, due to the : in front of the string. You can verify and configure what this node name will be by looking for the node_name and mdns_domain settings in your nerves_init_gadget configuration.

# hello_network/config/config.exs

# ...

# Setting the node_name will enable Erlang Distribution.
# Only enable this for prod if you understand the risks.
node_name = if Mix.env() != :prod, do: "hello_network"

config :nerves_init_gadget,
  node_name: node_name,
  mdns_domain: "hello_network.local"

# ...

There is also a short-cut way to start an iex session and automatically connect to a remote node (split over multiple lines with backslashes just to make it easier to read):

iex --name host@ \
    --cookie chocolatechip \
    --remsh hello_network@hello_network.local

Once connected, you can verify the list of nodes that are connected to the node running on your host machine.

iex(host@> Node.list

Then you can have some fun by passing messages between the nodes as described in the Elixir documentation.

Learn More

You can’t perform that action at this time.