Closed10

Nerves上で動作するLivebookをデバイスとMacとで同期する

栗林健太郎栗林健太郎

課題

fhunleth/nerves_livebook: Livebook for Nervesをデバイス上で動かして、livebookでセンサーを触るコードを書いたとします。その結果をリポジトリ管理しようと思っても、livebookのファイル(.livemd)ファイルはデバイス上にあるので、デバイスから手元のマシンに持ってくる必要があります。また、一度ずつ持ってくるのも面倒なので自動的に同期したい気持ちになりますね。

解決策

そこで、SSHFSを使って手元のMacのディレクトリとNervesデバイス上のディレクトリとを同期するとよいでしょう。

栗林健太郎栗林健太郎

Nerves Livebookの準備

まずはfhunleth/nerves_livebook: Livebook for Nervesgit 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 Nervesgit 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だと普通にできてるからなあ。

栗林健太郎栗林健太郎

デバイス上の、自分が作成した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してやればよい。

このスクラップは2021/07/27にクローズされました