NervesのファームウエアにPoncho projectsと呼ばれる手法を用いてPhoenixのUIを搭載したいと思います。
Poncho projectsとは
Ponchoプロジェクトのファイル構成は以下のようになります。
hello_poncho
├── README.md
├── hello_poncho_firmware
└── hello_poncho_ui
Elixir界隈ではPoncho projectsに似たようなものでUmbrella projectsがありますが、NervesではPoncho projectsが一般的には好まれるようです。理由は、Nervesではファームウエアが特別な存在だからと理解してます。
Umbrella projectsではすべての下位プロジェクトを同等に扱われます。
しかしながら、ファームウエアは他のElixirプロジェクトと異なり、ビルドツールであるため、ファームウエアをメインとして特別視した方が分かりやすいということだと思います。
ディレクトリー名は短くしてもよいのですが、個人的には後々の保全性を考えてあえて冗長なディレクトリー名を使うのが好みです。
MacOS BigSur 11.6
elixir 1.12.3-otp-24
erlang 24.1
nerves 1.7.11
phoenix 1.6.2
やりかた (A): hello_phoenix exampleをクローン
一番手軽なやり方は、Nerves公式のhello_phoenix exampleをクローンすることです。Nervesコアチームとコミュニティーにより定期的にアップデートされています。
万一なにか問題がみつかった場合は、プルリクエストで貢献する良い機会となると思います。
nerves_examplesをクローンして、hello_phoenix READMEの指示に従います。
git clone git@github.com:nerves-project/nerves_examples.git
cd nerves_examples/hello_phoenix
やりかた (B): From scratch
いちからhello_phoenix同様のものを作るのはそんなにむずかしいことではありません。
Nervesプロジェクトを作る
# プロジェクト名を決める
MY_PROJECT_NAME=hello_poncho
# プロジェクトのディレクトリーを作成して、その中に移動
mkdir $MY_PROJECT_NAME && cd $MY_PROJECT_NAME
# Nervesファームウエアのプロジェクトを新規作成
mix archive.install hex nerves_bootstrap
mix nerves.new "$MY_PROJECT_NAME"_firmware
# Phoenix UIのプロジェクトを新規作成
mix archive.install hex phx_new
mix phx.new "$MY_PROJECT_NAME"_ui --no-ecto --no-mailer
UIプロジェクトの設定
ひとつ大事なことは、Nervesでは開発環境でファームウエアをビルド・デプロイすることも多いと思いますので、(Phoenix 1.6から導入された)esbuildの設定に工夫が必要です。
ホストマシン(開発マシン)以外ではesbuildのランタイムが不要です。
defp deps do
[
{:phoenix, "~> 1.6.0"},
# ...
{:esbuild, "~> 0.2", runtime: Mix.env() == :dev && Mix.target() == :host},
# ...
]
end
参考までに、ターゲットマシン(ラズパイ等)でesbuildのランタイムが走るとこんな感じにファームウエアがクラッシュします。
UIプロジェクトをファームウエアプロジェクトの依存関係リストに追加
defp deps do
[
{:nerves, "~> 1.7", runtime: false},
# ...
{:hello_poncho_ui, path: "../hello_poncho_ui", targets: @all_targets, env: Mix.env()},
# ...
]
end
ファームウエアプロジェクトにてウエブサーバー関連の設定
一つ注意点は、UIプロジェクトに設定を記述してもそれはファームウエアのビルド時には読み込まれないことです。
ですので、UIの設定もファームウエア側に記述する必要があります。UIプロジェクトからimport
する手もありますが、個人的には必要な設定はすべてファームウエア側に記述する手法が気に入ってます。
# as of phoenix 1.6.2
config :hello_poncho_ui, MyAppUiWeb.Endpoint,
url: [host: "nerves.local"],
http: [port: 80],
cache_static_manifest: "priv/static/cache_manifest.json",
secret_key_base: "HEY05EB1dFVSu6KykKHuS4rQPQzSHv4F7mGVB/gnDLrIu75wE/ytBXy2TaL3A6RA",
live_view: [signing_salt: "AAAABjEyERMkxgDh"],
check_origin: false,
render_errors: [view: MyAppUiWeb.ErrorView, accepts: ~w(html json), layout: false],
pubsub_server: Ui.PubSub,
# Start the server since we're running in a release instead of through `mix`
server: true,
# Nerves root filesystem is read-only, so disable the code reloader
code_reloader: false
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
WiFiの設定 (任意)
USBガジェットモードを利用して、USB経由で通信する場合は不要です。
config :vintage_net,
regulatory_domain: "US",
config: [
{"usb0", %{type: VintageNetDirect}},
{"eth0",
%{
type: VintageNetEthernet,
ipv4: %{method: :dhcp}
}},
{"wlan0",
%{
type: VintageNetWiFi,
vintage_net_wifi: %{
networks: [
%{
key_mgmt: :wpa_psk,
# 環境変数経由で渡すか、直書きするかご自由に
ssid: System.get_env("NERVES_WIFI_SSID"),
psk: System.get_env("NERVES_WIFI_PSK")
}
]
},
ipv4: %{method: :dhcp}
}}
]
UIの開発
UIの開発に取り組むときは、hello_poncho/hello_poncho_ui
ディレクトリーに移動して、Phoenixのサーバーを起動します。
cd hello_poncho/hello_poncho_ui
iex -S mix phx.server
ファームウエアのビルド
まずはhello_poncho/hello_poncho_ui
ディレクトリーにてUIのアセットをビルドします。
cd hello_poncho/hello_poncho_ui
export MIX_TARGET=host
export MIX_ENV=dev
mix deps.get
# アセットをビルド
mix assets.deploy
そして hello_poncho/hello_poncho_firmware
ディレクトリーにてファームウエアをビルドします。
cd hello_poncho/hello_poncho_firmware
export MIX_TARGET=rpi0
export MIX_ENV=dev
mix deps.get
# ファームウエアをビルド
mix firmware
# ファームウエアをMicroSDカードに焼き上げる
mix firmware.burn
焼き上がったMicroSDカードをターゲットマシンに挿入し、電源オン。
以下のURLでPhoenixアプリにアクセスできるはずです。
http://nerves.local
以降、ファームウエアはネットワーク経由でもアップデート可能です。
mix firmware
mix upload nerves.local