これまでNervesで頑張っていたのは、Nerves起動時にNode.connect()
したかったからなのでした。ようやくできるようになりました\(^o^)/
これは「Nervesのネットワーク設定をmix firmware
する時に指定できるようにした」の続編になります。
更新情報
こちらの記事のほうが新しいので興味があればぜひ。
やりたいこと
Nerves起動時にOSXにNode.connect()
して、接続できるようにしたい。
環境
Nervesプロジェクト名
- Exineris001
ハードウェア
- Mac OSX
- NervesをRaspberryPi 3で稼働
ネットワーク
-
Mac OSX
- 有線LAN→メンテナンス用、固定IPアドレス(192.168.5.100/24)
- 無線LAN→インターネット接続用、DHCP(本記事では192.168.46.6)
-
ラズパイ
- 有線LAN(eth0)→メンテナンス用、固定IPアドレス(192.168.5/24の範囲)
- 無線LAN(wlan0)→インターネット接続用、DHCP(192.168.46/24から自動割当)
- 192.168.5.240(default)は後述
こんな風に書きました
mix.exs
お約束でdefp deps
に必要なライブラリを記載して、def release
にあらかじめ決めておきたいCookieを記載しました。
-
defp deps
に必要なライブラリを記載 -
def release
にあらかじめ決めておきたいCookieを記載
defp deps do
[
(略)
{:nerves_network, "~> 0.5", targets: @all_targets},
{:nerves_firmware_ssh, "~> 0.3", targets: @all_targets},
{:ex_string_util, "~> 0.1.0"}
]
end
def release do
[
cookie: "comecomeeverybody" # セットしたいCookieを設定
]
end
config/target.exs
:nerves_init_gadget
やIPアドレス等のネットワークの設定はconfig/network.exs
にまとめて記載するようにしました。SSHの鍵の登録を別途する場合はここで登録します。
(参考) NervesのSSH環境を整えた 〜upload.shを使ってファームウェア更新も〜
-
:nerves_init_gadget
をコメントアウト -
import_config("network.exs")
を記載して、IPアドレス等のネットワーク設定を別ファイルに分離
# config :nerves_init_gadget,
# ifname: "usb0",
# address_method: :dhcpd,
# mdns_domain: "nerves.local",
# node_name: node_name,
# node_host: :mdns_domain
import_config("network.exs")
config/network.exs
ここで無線(wlan0)と有線(eth0)のネットワーク設定をおこないます。
:nerves_config_gadget
に記載しているnode_name@node_host
という名前でNodeが起動します。
import Config
settings = [
networks: [
[ssid: "SSIDを記載", psk: "PSKを記載", key_mgmt: :"WPA-PSK", priority: 0,
ipv4_address_method: :dhcp,
nameservers: ["8.8.8.8", "8.8.4.4"]
]
]
]
config :nerves_network, default: [
wlan0: settings,
eth0: [
ipv4_address_method: :static,
ipv4_address: "192.168.5.55",
ipv4_subnet_mask: "255.255.255.0"
]
]
config :nerves_init_gadget,
ifname: "wlan0",
address_method: :dhcp,
node_name: "exineris001",
node_host: :ip
lib/exineris001/application.ex
アプリケーション起動時の引数として、OSXのノード名@ホスト名(kazumambp@192.168.46.6
)を渡すようにしました。
ホスト名といいつつIPアドレスを記載しています。ここ、DNSサーバたてて解決できるかどうかが次の課題かなぁと思ってるところです。
def children(_target) do
{Exineris001.Bootexineris, ["kazumambp@192.168.46.6"]} # OSXのWiFiのIPアドレス
end
lib/exineris001/bootexineris.ex
Nervesとしては以下の順で処理がすすむのですべての項目がクリア(今回は:true(trueでも同じ)
)にならないとNode.connect()
しないようにしました。
- wlan0インターフェース作成 →
is_wlan0_ready()
で確認 - WiFi設定を有効化後、DHCPでIPアドレス取得 →
is_ipv4_ready()
で確認 - nodeの設定 →
is_nodeconn_ready()
で確認
※ExStringUtil.is_ip!()
はIPアドレスのチェックがかなりかなり甘いので注意して使うことが必要です。
defmodule Exineris001.Bootexineris do
use GenServer
require Logger
def start_link(node \\ []) do
GenServer.start_link(__MODULE__, node, name: __MODULE__)
end
def init(node) do
conn = do_nodeconn(node)
{:ok, conn}
end
def do_nodeconn(node) do
nodeconn_status = get_nodeconn_status()
case nodeconn_status do
[:true, :true, :true] ->
conn = Node.connect(:"#{node}")
case conn do
:true -> Logger.info("===== conn => #{conn} =====")
_ -> do_nodeconn(node)
end
[_, _, _] ->
do_nodeconn(node)
end
end
def get_nodeconn_status() do
[is_nodeconn_ready(), is_ipv4_ready(), is_wlan0_ready()]
end
def is_nodeconn_ready() do
node = Node.self()
case node do
:nonode@nohost -> :false
_ -> :true
end
end
def is_ipv4_ready() do
case Nerves.NetworkInterface.settings("wlan0") do
{:ok, list} -> Map.get(list, :ipv4_address) |> ExStringUtil.is_ip!() # return: true or false
{_, _} -> :false
end
end
def is_wlan0_ready() do
wlan0 = Nerves.NetworkInterface.interfaces() |> Enum.find(& &1 == "wlan0")
case wlan0 do
"wlan0" -> :true
_ -> :false
end
end
end
実行→確認
準備として、OSXのターミナルから名前とCookieを指定してプロセスを起動しておきます。
Nerves起動前はNode.list()
しても空のリストが返ってきますが、Nervesを起動するとConnectしているNodeのリストが返ってきます。
- OSXのターミナルから名前とCookieを指定してプロセスを起動
- Nerves起動前は
Node.list()
しても空のリストとなる - Nerves起動後は接続先のリストが返ってくる
$ mix deps.get
$ mix firmware
$ ./upload.sh 192.168.5.55
$ iex --name kazumambp@192.168.46.5 --cookie comecomeeverybody
iex(kazumambp@192.168.46.5)> Node.list()
[]
<<< ここでNerves起動 >>>
iex(kazumambp@192.168.46.5)> Node.list()
[:"exineris001@192.168.46.6"]
iex(exineris001@192.168.46.6)> Node.list()
[:"kazumambp@192.168.46.5"]
まとめ
Nerves起動時にNode.connect()
できるようになりました!
感想:ながかったー
足跡
- Elixirのバージョン管理環境をasdfを使って作った
- Nervesのネットワーク環境を整えた
- NervesのSSH環境を整えた 〜upload.shを使ってファームウェア更新も〜
- Nervesのnode_nameとnode_hostとcookieを設定した
- NervesでShellに落ちた
- Nervesのネットワーク設定を
mix firmware
する時に指定できるようにした
@kikuyuta さんが はじめてNerves(0) ElixirによるIoTフレームワークNervesがとにかく動くようになるためのリンク集 に色々とまとめてくれてるのでこちらもどうぞ。