Nerves上で動作するLivebookをデバイスとMacとで同期する
課題
fhunleth/nerves_livebook: Livebook for Nervesをデバイス上で動かして、livebookでセンサーを触るコードを書いたとします。その結果をリポジトリ管理しようと思っても、livebookのファイル(.livemd
)ファイルはデバイス上にあるので、デバイスから手元のマシンに持ってくる必要があります。また、一度ずつ持ってくるのも面倒なので自動的に同期したい気持ちになりますね。
解決策
そこで、SSHFSを使って手元のMacのディレクトリとNervesデバイス上のディレクトリとを同期するとよいでしょう。
Nerves Livebookの準備
まずはfhunleth/nerves_livebook: Livebook for Nervesをgit clone
して、手元でビルドしたファームウェアをデバイスに適用できる状態を作ってください。
合わせて、@mnishiguchiさんによる以下の変更を参考に、config/target.exs
にSSH用の設定をたしておく必要があります。
WIP: dev · mnishiguchi/nerves_livebook@fa0ca2e
diffは以下の通り(rpi3を使っていて、WIFI経由で通信できる設定もいれてあります)。
diff --git a/config/rpi3.exs b/config/rpi3.exs
index c3049d8..7343ac8 100644
--- a/config/rpi3.exs
+++ b/config/rpi3.exs
@@ -6,5 +6,18 @@ config :vintage_net,
regulatory_domain: "US",
config: [
{"eth0", %{type: VintageNetEthernet, ipv4: %{method: :dhcp}}},
- {"wlan0", %{type: VintageNetWiFi}}
+ {"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}
+ }}
]
diff --git a/config/target.exs b/config/target.exs![](https://storage.googleapis.com/zenn-user-upload/4058f17150a3242e77c8116c.png)
index 4bab7c1..00aee5b 100644
--- a/config/target.exs
+++ b/config/target.exs
@@ -47,7 +47,24 @@ config :nerves, :erlinit,
# * See https://hexdocs.pm/nerves_ssh/readme.html for general SSH configuration
# * See https://hexdocs.pm/ssh_subsystem_fwup/readme.html for firmware updates
+keys =
+ [
+ Path.join([System.user_home!(), ".ssh", "id_rsa.pub"]),
+ Path.join([System.user_home!(), ".ssh", "id_ecdsa.pub"]),
+ Path.join([System.user_home!(), ".ssh", "id_ed25519.pub"])
+ ]
+ |> Enum.filter(&File.exists?/1)
+
+if keys == [],
+ do:
+ Mix.raise("""
+ No SSH public keys found in ~/.ssh. An ssh authorized key is needed to
+ log into the Nerves device and update firmware on it using ssh.
+ See your project's config.exs for this error message.
+ """)
+
config :nerves_ssh,
+ authorized_keys: Enum.map(keys, &File.read!/1),
user_passwords: [{"livebook", "nerves"}, {"root", "nerves"}],
daemon_option_overrides: [
{:auth_method_kb_interactive_data,
これでファームウェアをビルドしてSDカードに焼きます。
$ mix deps.get
$ mix firmware.burn
ファームウェア焼いたSDカードをデバイスに挿して、起動します。
$ ssh nerves.local
デバイスが起動して、SSHできるようになったらOKです。
Livebookを置くリポジトリの準備
自分で作ったLivebookを管理するリポジトリを作っておきましょう。ディレクトリ構成は、こんな感じになりました。
- Nerves Livebookのクローン先:/Users/antipop/src/github.com/fhunleth/nerves_livebook
- 自分のLivebookを置くローカルリポジトリ:/Users/antipop/src/github.com/kentaro/my_nerves_livebooks
以下、適宜ご自身の環境に読み替えてください。
同期するディレクトリの準備
http://nerves.local/ にアクセスするとLivebookのページが開けます。自分のLivebookを置くディレクトリを作成するために、画面右上のNew notebook
ボタンからファイルを作成します。そして、ページ右下に表示されるボタンから以下のポップアップを開きファイルを適当な名前で保存すると、デフォルトで/data/livebooks/notebooks
というディレクトリも作成されます。
こうしてできたディレクトリを、手元のMacのディレクトリと同期します。
環境
- macOS Big Sur
- MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
- 2.3 GHz クアッドコアIntel Core i7
SSHFSの準備
macMacとSSHFSをhomebrew経由でインストールします。
$ brew install macfuse
$ brew install gromgit/fuse/sshfs-mac
sshfs
の実行
fhunleth/nerves_livebook: Livebook for Nervesをgit clone
してきたディレクトリで、以下のようにしてsshfsを実行します。
$ sshfs nerves.local:/data/livebooks ./priv
mount_macfuse: the file system is not available (1)
初回起動時はセキュリティの関係で失敗します。
実行を許可すると、再起動が必要です。
Nerves Livebookでセンサーデータを扱う準備
せっかくNerves Livebookを使うので、何かセンサーデータを取得してみたいですよね。そこで、CO2濃度を取得できるMH-Z19というセンサーをElixirから扱えるkentaro/mh_z19_exを使ってみることにしましょう。
以下のようにして依存モジュールを追加します。
diff --git a/mix.exs b/mix.exs
index 316355a..9151cbd 100644
--- a/mix.exs
+++ b/mix.exs
@@ -54,7 +54,7 @@ defmodule NervesLivebook.MixProject do
{:kino, "~> 0.2.1"},
# Dependencies for all targets except :host
- {:circuits_uart, "~> 1.3", targets: @all_targets},
+ {:circuits_uart, "~> 1.3", targets: @all_targets, override: true},
{:circuits_gpio, "~> 0.4", targets: @all_targets},
{:circuits_i2c, "~> 0.3", targets: @all_targets},
{:circuits_spi, "~> 0.1", targets: @all_targets},
@@ -74,7 +74,10 @@ defmodule NervesLivebook.MixProject do
{:nerves_system_bbb, "~> 2.10", runtime: false, targets: :bbb},
{:nerves_system_osd32mp1, "~> 0.6", runtime: false, targets: :osd32mp1},
{:nerves_system_x86_64, "~> 1.15", runtime: false, targets: :x86_64},
- {:nerves_system_npi_imx6ull, "~> 0.2", runtime: false, targets: :npi_imx6ull}
+ {:nerves_system_npi_imx6ull, "~> 0.2", runtime: false, targets: :npi_imx6ull},
+
+ # Dependencies for Pratipad.Device
+ {:mh_z19, "~> 0.1.0"}
]
end
上記でcircuits_uart
の設定をいじっている箇所は、mh_z19
の依存とバッティングしてエラーになったので上書きするようにしました。
センサーの実装については解説しません。mh-z19 · PyPIに図解されていますので、ご覧ください。
ファームウェアをビルドしてデバイスに適用しておきます。
$ mix deps.get
$ mix firmware
$ mix upload
sshfsでデバイス上のLivebookのディレクトリをマウント
以下のようにして、デバイス上のディレクトリを手元のMacのLivebookを管理するローカルリポジトリにマウントします。
$ sshfs nerves.local:/data/livebooks/notebook ../../kentaro/my_nerves_livebooks/
これでうまくいくはずだったのだが、ちゃんとマウントできない……。
ああそうか!NervesのSSHはiexシェルにつながるから、普通にやっちゃそりゃだめか。いやでも、Embedded Elixirだと普通にできてるからなあ。
SFTPならできるんだよな〜。気を取り直して、そっちでいくか。
デバイス上の、自分が作成したlivebookが置かれているディレクトリに含まれる.livemd
ファイルを手元のMacに全部持ってくるために、以下のような内容でsync-my-livebooks
としてファイルを作っておく。
cd /data/livebooks/notebook
get *
Livebookを管理したいリポジトリから以下のコマンドを実行する。パスワードの入力を求められるので、表示されている通りnerves
を入力する。
$ sftp livebook@nerves.local < sync-my-livebooks
Nerves Livebook
https://github.com/fhunleth/nerves_livebook
ssh livebook@nerves.local # Use password "nerves"
Password:
そうすると、sync-my-livebooks
の内容がSFTPコマンドとして実行され、デバイス上のlivebookのファイルを手元に取得できる。あとはこれをgit commit
してやればよい。