Nerves合同ハンズオンのコード解説＋うまみ


# はじめに
この記事は、[#NervesJP Advent Calendar 2022](https://qiita.com/advent-calendar/2022/nervesjp) の22日目「だった」ものです。

標準入力になんど「すいません」と入力したことか。
えっ、今日は白ひげの赤い還暦姿のおじいちゃんが帰宅する日ですか。そうですか。

さて本題
順調にいけば一昨日だった20日目に@nishiuchikazuma さんが投稿してくれた[Nerves合同ハンズオンの裏側](https://qiita.com/nishiuchikazuma/items/e92188aee93e6869ad18)の、アンサー的な記事になります。

それでは

2022年10月22日（土）にNervesJPとkochi.ex合同でNervesハンズオンする回！で使用したコードの簡単な解説を書いていきます。

# 資料一覧
ハンズオン用Repository github:[b5g-ex/nerves_livebook](https://github.com/b5g-ex/nerves_livebook)
[演習_Nervesハンズオン_基本編](https://docs.google.com/presentation/d/10nthQ7-Z4b9kE01X1oyKf8KPkYujWKiXA1089puMvxM/edit#slide=id.g145ee8131ba_0_45)
[演習_Nervesハンズオン_応用編](https://docs.google.com/presentation/d/1NgLImDiGsWEyUjKAAejtJA4ryPhK2cf299GMVtJrOfs/edit#slide=id.g147ef7291cb_2_67)

# 運営側の準備編
### 機材を必要なセット分用意する。
今回のハンズオンは全てLivebook上で完結するため、参加者の環境にはElixirのコンパイル環境は不要ですが、Rpi4と有線NWで接続する点だけ注意が必要です。

- Raspberry Pi4
- Grove Base HAT
- Grove I2C温湿度センサ AHT20
- Grove LED
- Grove Button
- 電源、マイクロSD

![演習_Nervesハンズオン_基本編　#NervesJP #kochi.ex #B5G.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295240/d05a8f5c-2066-0b4c-bb33-343ccf8564cc.png)

### プログラム
プログラムは、github:[nerves_livebook](https://github.com/livebook-dev/nerves_livebook)のRepositoryをcloneし、ネットワークを設定し、ハンズオン用のソースコードを突っ込む以上です。いやーかんたん。まじかよ。
※ハンズオン用Repository github:[b5g-ex/nerves_livebook](https://github.com/b5g-ex/nerves_livebook)は上記全て済みの状態です。

#### ネットワークの設定
今回のTARGETはrpi4なので、/config/rpi4.exs を編集します。
rpi4.exsはtarget.exsでimportされています

```Elixir:config/rpi4.exs 
# 有線NWの設定を追加
import Config

# Configure the network using vintage_net
# See https://github.com/nerves-networking/vintage_net for more information
config :vintage_net,
  config: [
    {"usb0", %{type: VintageNetDirect}},
    #　↓↓ここから
    {"eth0",
     %{
       type: VintageNetEthernet,
       ipv4: %{
         method: :static,
         address: "192.168.5.55",
         netmask: "255.255.255.0"
       }
    #ここまで↑↑
     }},
    {"wlan0", %{type: VintageNetWiFi}}
  ]

config :nerves_livebook, :delux_config, indicators: %{default: %{green: "led0"}}
```

#### ソースコード
lib/jssst/sensor/配下に2つのファイルを配置しています。
- aht20.exs　：　ハンズオン用の本体コード
- const_nerves.ex　：　i2cのアドレス等を定数にしたファイル、aht20.exsで読込

#### burnする。
以上、とても簡単。

# ハンズオン編
### ここからは、ハンズオンの基本編、応用編の「うまみ」を簡単にまとめてみます。

## 基本編のうまみ
### Livebookに簡単ログイン
![演習_Nervesハンズオン_基本編　#NervesJP #kochi.ex #B5G (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295240/9c70b190-9d03-22b2-8043-455738a75058.png)

### LivebookからLチカ
![演習_Nervesハンズオン_基本編　#NervesJP #kochi.ex #B5G (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295240/32957c03-9dc4-60c5-fe1e-dc4769eaebdf.png)

### LivebookでGenSrver
基本編では、GenServerを利用して、イベントドリブンによるLチカまで行っています。

```Elixir:Livebook
defmodule ButtonServer do
  use GenServer
  require Logger
  alias Circuits.GPIO

  # GPIOの番号
  @button 5
  @led 16

  # GenServerではstart_linkの後は暗黙的にinitが呼ばれます。
  def start_link(_) do
    GenServer.start_link(__MODULE__, [])
  end

  def init(_) do
    # button(入力)とled(出力)が接続されたgpioをそれぞれopneします。
    {:ok, button} = GPIO.open(@button, :input, pull_mode: :pullup)
    {:ok, led} = GPIO.open(@led, :output)

    # buttonに対して、set_interruptsすることで、押した時、離した時の
    # 両方(:both)のイベントが発生した時に、handle_infoにメッセージが飛んできます。
    GPIO.set_interrupts(button, :both)
    
    # Elixirの関数には必ず戻り値が必要です
    # 第2戻り値のstateに、openしたbuttonとledを入れておきます。
    {:ok, %{button: button, led: led}}
  end

  # 飛んできたメッセージをhandle_infoでひっかけます。
  # :circuits_gpio　をパターンマッチしています。
　# @button　buttonのgpio番号でパターンマッチしています。
  def handle_info({:circuits_gpio, @button, _timestamp, value}, state) do
 
    # stateにはopenしたbuttonとledが入っています。
    # ledのvalueにbuttonのvalueを出力します。
    # 押したときのvalue：1
    # 話したときのvalue：0
    GPIO.write(state.led, value)
    Logger.debug("Button is #{value}")

    {:noreply, state}
  end
end

```

## 応用編のうまみ
### Livebookで温湿度測定
準備編で用意したソースコードを利用しています。
![演習_Nervesハンズオン_応用編　#JSSST #B5G.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295240/132a0c8f-d5c6-0c25-a324-750fcfb0dcca.png)

### バイナリーデータをビット長でパターンマッチ
aht20.exsの中では、温湿度センサーから取得したバイナリデータをビット長でパターンマッチし変数に格納しています。
```Elixir:lib/jssst/sensor/aht20.ex 
〜
defp convert(src) do
    # バイナリデータ部をビット長でパターンマッチ
    # <<0:state, 1:humi1, 2:humi2, 3:humi3/temp1, 4:temp2, 5:temp3, 6:crc>>
    <<_state::8, raw_humi::20, raw_temp::20, _crc::8>> = src

    # 湿度に換算する計算（データシートの換算方法に準じた）
    humi = Float.round(raw_humi / @two_pow_20 * 100.0, 1)

    # 温度に換算する計算（データシートの換算方法に準じた）
    temp = Float.round(raw_temp / @two_pow_20 * 200.0 - 50.0, 1)

    # 温度と湿度をタプルにして返す
    {temp, humi}
  end
```

### Livebookで温湿度をグラフ表示
![演習_Nervesハンズオン_応用編　#JSSST #B5G (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295240/1c280ca5-31bd-d3c3-2b75-68fe185e2e8c.png)

# まとめ
以上、kochi.exとNerves.jpで共催したハンズオンの解説でした。

### この構成のうまみ まとめ
- Livebookの準備がとても簡単
- 参加者の環境にElixirのコンパイル環境が不要
- 機材とPCさえあれば誰でも簡単に横展開できそう

これでやっと年末を迎えられそうです。
あぁ今日はクリスマスなんですね。そうですね。
奥様がとてもクリスマスモードなので、イベントカレンダーはこのくらいにしておきます。

皆様よいお年を。