Masatoshi Nishiguchi's Blog

Masatoshi Nishiguchi's Blog

Elixir "poncho" project with Nerves firmware and Phoenix LiveView UI

Today I learned how to make a poncho project with the Nerves firmware and Phoenix LiveView UI and how it generally works.

My dev environment

MacOS BigSur 11.4
MacBook Pro (13-inch, 2018, Four Thunderbolt 3 Ports)

erlang 23.3.1
elixir 1.12.0-otp-23
node 12.13.0

export MIX_TARGET=rpi0

How-to (A)

The easiest way to do it is just clone the Nerves Project's official example hello_phoenix. The Nerves core team and the community keep the example up-to-date. It should just work.

Clone the example project

cd some/location
git clone git@github.com:nerves-project/nerves_examples.git
cd nerves_examples/hello_phoenix

then follow the instructions in the README.

How-to (B)

I was curious how I could create something similar from scratch so I did. Here is my secret recipe I ended up with.

Create a base project

cd some/location

# Decide on the project name
MY_PROJECT_NAME=hello_poncho

# Create the project directory and move into it
mkdir $MY_PROJECT_NAME && cd $MY_PROJECT_NAME

# Create README.md
echo "Copied from https://github.com/nerves-project/nerves_examples/tree/main/hello_phoenix\n\n$(curl -L https://raw.githubusercontent.com/nerves-project/nerves_examples/main/hello_phoenix/README.md)" > README.md

# Initialize Git
git init && git add . && git commit -m "Initial commit"

# Create Nerves firmware subproject
mix archive.install hex nerves_bootstrap
mix nerves.new "$MY_PROJECT_NAME"_firmware
git add . && git commit -m "Create Nerves firmware subproject"

# Create Phoenix LiveView UI subproject
mix archive.install hex phx_new
mix phx.new "$MY_PROJECT_NAME"_ui --no-ecto --live
git add . && git commit -m "Create Phoenix LiveView UI subproject"

Add to the Firmware subproject the UI subproject as a dependency

# hello_poncho_firmware/mix.exs

{:hello_poncho_ui, path: "../hello_poncho_ui", targets: @all_targets, env: Mix.env()},

Set up WiFi in the Firmware subproject

# hello_poncho_firmware/config/target.exs

{"wlan0",
  %{
    type: VintageNetWiFi,
    vintage_net_wifi: %{
      networks: [
        %{
          key_mgmt: :wpa_psk,
          ssid: System.get_env("WIFI_SSID"),
          psk: System.get_env("WIFI_PSK")
        }
      ]
    },
    ipv4: %{method: :dhcp}
  }}

Configure web server in the Firmware subproject

# hello_poncho_firmware/config/target.exs

# When we deploy to a device, we use the "prod" configuration:
import_config "../../hello_poncho_ui/config/config.exs"
import_config "../../hello_poncho_ui/config/prod.exs"

config :hello_poncho_ui, HelloPonchoUiWeb.Endpoint,
  # Nerves root filesystem is read-only, so disable the code reloader
  code_reloader: false,
  http: [port: 80],
  # Use compile-time Mix config instead of runtime environment variables
  load_from_system_env: false,
  # Start the server since we're running in a release instead of through `mix`
  server: true,
  url: [host: "nerves.local", port: 80]

Build the firmware and burn (or upload) it

Follow the instructions in Nerves official Hello Phoenix example.

Final Thoughts

At first, the poncho project looked scary to me, but it is actually pretty simple concept. The Nerves firmware combined with the Phoenix LiveView is so powerful that I may consider using this pattern for all my Nerves projects. Phoenix comes with LiveDashboard, which is cool. Now that I know how to implement it, it is time to do some experiments.

That's it! Here are some resources I read and found helpful.

Resources

Troubleshooting

  • Sometimes I have an issue resolving dependencies for some reason, then I run mix deps.clean --all.
 
Share this