User Interfaces

Phoenix Web Interfaces

Phoenix makes an excellent companion to Nerves applications by offering an easy-to-use, powerful framework to create user interfaces in parallel with Nerves device code. The easiest way to handle this is to lay out your application as an Umbrella.

First, generate a new umbrella app, called nervy in this case:

$ mix new nervy --umbrella

Next, create your sub-applications for Nerves and for Phoenix:

$ cd nervy/apps
$ mix nerves.new fw
$ mix phoenix.new ui --no-ecto --no-brunch

Now, add the Phoenix ui app and the nerves_networking library to the fw app as dependencies:

# nervy/apps/fw/mix.exs

...
defp deps do
  [{:ui, in_umbrella: true},
   {:nerves_networking, "~> 0.6.0"}]
end
...

In order to start networking when fw boots, add a worker that sets up networking. This example sets up the networking using DHCP. For more network settings, check the nerves_networking project.

# nervy/apps/fw/lib/fw/application.ex

...
# add networking
children = [
  worker(Task, [fn -> Nerves.Networking.setup :eth0, [mode: "dhcp"] end], restart: :transient)
]
...

In order to build the ui Phoenix application into the nerves fw app, you need to add some configuration to your firmware config:

# nervy/apps/fw/config/config.exs

use Mix.Config

config :ui, Ui.Endpoint,
  http: [port: 80],
  url: [host: "localhost", port: 80],
  secret_key_base: "#############################",
  root: Path.dirname(__DIR__),
  server: true,
  render_errors: [accepts: ~w(html json)],
  pubsub: [name: Nerves.PubSub],
  code_reload: false

config :logger, level: :debug

By default, the main config loads the application configs in an unordered way: import_config "../apps/*/config/config.exs. This can cause problems if the ui config is applied last: we loose the overrides we just added in the previous step. You need to force the order in which the config files get imported:

# nervy/config/config.exs

use Mix.Config

# By default, the umbrella project as well as each child
# application will require this configuration file, ensuring
# they all use the same configuration. While one could
# configure all applications here, we prefer to delegate
# back to each application for organization purposes.
import_config "../apps/ui/config/config.exs"
import_config "../apps/fw/config/config.exs"

There you have it! A Phoenix web application ready to run on your Nerves device. By separating the Phoenix application from the Nerves application, you could easily distribute the development between team members and continue to leverage the features we have all come to love from Phoenix, like live code reloading.

When developing your UI, you can simply run the phoenix server from the UI application:

$ cd nervy/apps/ui
$ mix phoenix.server

When it’s time to create your firmware:

$ cd nervy/apps/fw
$ export MIX_TARGET=rpi3
$ mix deps.get
$ mix firmware
$ mix firmware.burn