Nervesで湯婆婆を実装してみる

- この記事は[#NervesJP Advent Calendar 2020](https://qiita.com/advent-calendar/2020/nervesjp) の3日目です。
- 前日は、 @kentaro さんの[ウェブチカでElixir/Nervesに入門する（2020年12月版）](https://qiita.com/kentaro/items/e8df79aa93b9fe9a567e)です。
- すごくよい記事なのでオススメです！ :lgtm::lgtm::lgtm:
- どのくらいよい記事なのかと言うと、
    - @takasehideki 先生談: [ものっそい丁寧な解説記事！ これからNerves始める方もすでに慣れてる方も，この記事を写経するだけでめっちゃんこいろいろ学べます！！ #NervesJP](https://twitter.com/takasehideki/status/1333944825574432770)
- 前の記事の[おわりに](https://qiita.com/kentaro/items/e8df79aa93b9fe9a567e#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB)にあるようにたったの２週間での成果とのことです
- 私はなんとな〜くは1年以上[Nerves](https://www.nerves-project.org/)を触っています
- **当然**、**必然**といえばその通りなのですが、その2週間の間に**完全に完璧に一気に**追い抜かれた感:rocket::rocket::rocket:を感じています :fire: :lgtm::sweat_smile::lgtm::fire:
    - [6号艇(緑)からの強まくり](https://www.youtube.com/watch?v=Q4awCMwe0nE) ← こんな感じ
    - [6コースからの強まくり](https://www.youtube.com/watch?v=SDOfzi_392U) ← こんな感じ
    - [予告!] @kentaro さんが作られた[kentaro/mix_tasks_upload_hotswap](https://github.com/kentaro/mix_tasks_upload_hotswap)を試してみますという記事をご本人が参加していらっしゃるアドベントカレンダー(12/12)で書きます！

---

# はじめに :santa: :santa_tone1: :santa_tone2: 
- @Nemesis さんの[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)を拝見しまして、私は[Nerves](https://www.nerves-project.org/)でやってみようとおもいました
- 私はすでに以下の記事を書いてます
    - [Elixirで湯婆婆を実装してみる](https://qiita.com/torifukukaiou/items/daec6de40a54978dccc9)
    - [Phoenixで湯婆婆を実装してみる](https://qiita.com/torifukukaiou/items/43f50cb6abab40d4e7d1)
    - [【毎日自動更新】湯婆婆 LGTMランキング！](https://qiita.com/torifukukaiou/items/c8361231cdc56e493245)
- [Nerves](https://www.nerves-project.org/)は[Elixir](https://elixir-lang.org/)製のIoTフレームワークです
- [【毎日自動更新】湯婆婆 LGTMランキング！](https://qiita.com/torifukukaiou/items/c8361231cdc56e493245) は、[Nerves](https://www.nerves-project.org/)アプリとして作っておりまして、令和2年なのにいまだにRaspberry Pi 2しか持っていない私の虎の子のRaspberry Pi 2が定期的に自動更新をしています
- 下記を使っています
    - elixir: 1.10.4-otp-23
    - erlang: 23.0.1
    - nerves_bootstrap-1.10.0 
- えっ！？ Raspberry Piをもっていないですって〜
    - そんなあなたに素敵なイベントをご紹介します :rocket::rocket::rocket: 
    - [2020/12/27(日) 14:00〜 【オンライン】豪華プレゼント付！Elixir/Nerves(ナーブス)体験ハンズオン！](https://algyan.connpass.com/event/197306/)
    - [Seeed株式会社](https://www.seeed.co.jp/)様からプレゼント！
    - [Nerves始めたい方は必見。ハンズオンに際して、ラズパイとか必要な一式まで提供してくださるという神がかった企画……！ヤバ過ぎる……！！](https://twitter.com/kentaro/status/1333640114283577344)
    - もう参加枠埋まっている :tada::tada::tada: 

# 今年のごくワタクシ的[Nerves](https://www.nerves-project.org/)ニュース
- [Interface(インターフェース) 2021年 1 月号](https://interface.cqpub.co.jp/magazine/202101/)に @takasehideki 先生のお手伝いという形でいっしょに書かせていただいて、名乗るほどのものではない[名前](https://interface.cqpub.co.jp/wp-content/uploads/if2101_152.pdf)を載っけてもらいました！
    - [IoT向きモダン言語Elixirの研究 第7回　IoTシステム開発にトライ!(サンプル)](https://interface.cqpub.co.jp/wp-content/uploads/if2101_152.pdf)
- [TORIFUKUKaiou/hello_nerves](https://github.com/TORIFUKUKaiou/hello_nerves)
    - ごった煮プロジェクトにいろいろと煮込み続けています

# 0. 準備
- まずは[Elixir](https://elixir-lang.org/)をインストールしましょう
- 手前味噌な記事ですが[インストール](https://qiita.com/torifukukaiou/items/d04d0273749c41eb50af#0-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)などをご参照ください
    - `asdf`でのインストールがオススメです
- [Nerves](https://www.nerves-project.org/)を始めるにはもう少し準備が必要です
- 公式の[Installation](https://hexdocs.pm/nerves/installation.html#content)がわかりやすいです
    - 公式の[Installation](https://hexdocs.pm/nerves/installation.html#content)に書いていないこととしては、SSHの鍵を作るところが書かれていません
    - すでに`~/.ssh/id_rsa.pub`等がある場合はそれがそのまま使えます
    - そんなフォルダがそもそも無いよという場合は下記をご参照ください
        - [SSH公開鍵の作成](https://qiita.com/takasehideki/items/88dda57758051d45fcf9#ssh%E5%85%AC%E9%96%8B%E9%8D%B5%E3%81%AE%E4%BD%9C%E6%88%90)
- 日本語がお好みの方は下記の記事を参照するのがよいでしょう
    - [ElixirでIoT#4.1：Nerves開発環境の準備](https://qiita.com/takasehideki/items/88dda57758051d45fcf9)

# 1. プロジェクト作成

```
$ mix nerves.new yubaba
$ cd yubaba
$ export MIX_TARGET=rpi2
$ mix deps.get
```

- プロジェクトの雛形がつくられます
- いっぱいファイルができます
- [Elixir](https://elixir-lang.org/)がはじめての方はそんなものだと流してください
- 慣れるといつもの景色にみえてきます
- 私は`rpi2`を使っていますがその他のターゲットをお使いの方は、[Targets](https://hexdocs.pm/nerves/targets.html#content)から値(TAG)を選んでください


# 2. プログラムを書く

## Wi-Fi設定
- LANケーブルで接続する場合は、下記の変更は必要ではありません
- Wi-Fiで接続する場合には、下記を参考に、`"wlan0"`からはじまるタプル(`{...}`)のところにご利用のWi-Fi設定を書いてください
- [VintageNet Cookbook — WiFi](https://hexdocs.pm/vintage_net/cookbook.html#wifi)

```elixir:config/target.exs
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: "your_ssid",
             psk: "your_psk"
           }
         ]
       },
       ipv4: %{method: :dhcp}
     }}
  ]
```

## Yubabaモジュール

```elixir:lib/yubaba.ex
defmodule Yubaba do
  def main do
    name = IO.gets("契約書だよ。そこに名前を書きな。\n") |> String.trim()

    IO.puts("フン。#{name}というのかい。贅沢な名だねぇ。")
    new_name = String.codepoints(name) |> Enum.random()

    IO.puts("今からお前の名前は#{new_name}だ。いいかい、#{new_name}だよ。分かったら返事をするんだ、#{new_name}!!")
  end
end
```

- `|>` は[Pipe operator](https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2)と呼ばれるものでして、前の計算結果を次の関数の第一引数に入れて計算をしてくれます
- 入力文字列から一文字を選ぶ([名前を奪う](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2#%E5%90%8D%E5%89%8D%E3%82%92%E5%A5%AA%E3%81%86))ところは、[String.codepoints/1](https://hexdocs.pm/elixir/String.html#codepoints/1)関数で要素が1文字ずつのリストにして、そのリストの中から1要素を適当に選んでくれる[Enum.random/1](https://hexdocs.pm/elixir/Enum.html#random/1)関数を使うことで`new_name`を求めています
- `Module.function/1`なんていきなりさらっと書いていますが、`/`のうしろは引数の数です
    - [Elixir](https://elixir-lang.org/)界でよくみる表記方法です
- カンの良い方はお気づきの通り、[Elixirで湯婆婆を実装してみる](https://qiita.com/torifukukaiou/items/daec6de40a54978dccc9) で書いたコードと全く同じです
- IoTだからと書き方を変えないといけないということに出くわすことはほとんどありません(そこまで複雑なことをやったことがないという理由もあります)

# 3. 実行

```
$ mix firmware
```

- ↑このコマンドでファームウェアができます
- microSDカードをホスト(開発マシン)に差し込んでファームウェアをmicroSDカードにこんがり焼きます

```
$ mix burn
```

- こんがり焼き上がりましたら、Raspberry Pi 2に差し込んで電源ON !
- 少し待つと`ping nerves.local`が通るようになるとおもいます
- このまま実行してもよいのですが、[Elixirで湯婆婆を実装してみる](https://qiita.com/torifukukaiou/items/daec6de40a54978dccc9) と違うことをやってみましょう

![7-2_目覚ましアラーム_honeko入.jpg](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F131808%2F2b651c28-37c1-6de3-93dd-a5490bcceaf2.jpeg?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=3b66b0deb7b05ee6e844e45f765db666)

- (この記事ではいろいろと繋いでいるもののことは一切説明しておりません:relaxed:)


# 4. プログラムを書く(その2)
- `Yubaba.main/0`の呼び出しを`rootfs_overlay/etc/iex.exs`の末尾に追加します
- こうしておくことで`ssh`接続したときに、すぐに`湯婆婆`が動き(イゴキ)始めます

```elixir:rootfs_overlay/etc/iex.exs
# Add Toolshed helpers to the IEx session
use Toolshed

if RingLogger in Application.get_env(:logger, :backends, []) do
  IO.puts """
  RingLogger is collecting log messages from Elixir and Linux. To see the
  messages, either attach the current IEx session to the logger:

    RingLogger.attach

  or print the next messages in the log:

    RingLogger.next
  """
end

Yubaba.main # add
```

# 5. ファームウェアアップデート

```
$ mix firmware
```

- Raspberry Pi 2からmicroSDカードを抜いて、ホスト(開発マシン)に差し込んで`mix burn`で焼き直すこともできますが、もっと便利な方法をご紹介します

```
$ mix upload
```

- このコマンドを使うことで、Raspberry Pi 2からmicroSDカードを差し込んだままでファームウェアのアップデートができるのです！
- これは文字だけでは伝わりにくいのですがけっこう便利です

# 6. 実行

- いよいよ実行します
- `mix upload`後少し待って、`ping nerves.local`が通るようになったことを確認してください

```
$ ssh nerves.local                                                                                              
Interactive Elixir (1.10.4) - press Ctrl+C to exit (type h() ENTER for help)
Toolshed imported. Run h(Toolshed) for more info.
RingLogger is collecting log messages from Elixir and Linux. To see the
messages, either attach the current IEx session to the logger:

  RingLogger.attach

or print the next messages in the log:

  RingLogger.next

契約書だよ。そこに名前を書きな。
荻野千尋
フン。è»éåå°というのかい。贅沢な名だねぇ。
今からお前の名前はだ。いいかい、だよ。分かったら返事をするんだ、
```
- `ssh`したら湯婆婆から名前を聞かれます！
- :cry: 文字化けしました
- 気を取り直して

```
$ ssh nerves.local                                                                                              
Interactive Elixir (1.10.4) - press Ctrl+C to exit (type h() ENTER for help)
Toolshed imported. Run h(Toolshed) for more info.
RingLogger is collecting log messages from Elixir and Linux. To see the
messages, either attach the current IEx session to the logger:

  RingLogger.attach

or print the next messages in the log:

  RingLogger.next

契約書だよ。そこに名前を書きな。
abc
フン。abcというのかい。贅沢な名だねぇ。
今からお前の名前はbだ。いいかい、bだよ。分かったら返事をするんだ、b!!
```
- アスキー文字ならうまく行きました :tada::tada::tada: 

# Wrapping Up :lgtm: :qiita-fabicon: :lgtm:
- だいぶ気が早いですがアドベントカレンダーネタを書きました
- 文字化けのところはたぶん、Buildrootでしたっけ！？ それでサムシングをカスタマイズすると解決できるのだとおもいます
- 解決は他の方に任せるとしてこのへんで筆を置きます :santa: :santa_tone1: :santa_tone2: 
- Enjoy [Elixir](https://elixir-lang.org/) !!! :rocket::rocket::rocket: 
- 4日目は、@pojiroさんの[なぜ僕はNervesに期待するのか](https://qiita.com/pojiro/items/99a60dc8a4427b79ddc7) です。続けてお楽しみください。
    - 熱い記事！！！ :fire::fire::fire::rocket::rocket::rocket::rocket::rocket: