はじめに
この記事は、#NervesJP Advent Calendar 2022 の22日目「だった」ものです。
標準入力になんど「すいません」と入力したことか。
えっ、今日は白ひげの赤い還暦姿のおじいちゃんが帰宅する日ですか。そうですか。
さて本題
順調にいけば一昨日だった20日目に@nishiuchikazuma さんが投稿してくれたNerves合同ハンズオンの裏側の、アンサー的な記事になります。
それでは
2022年10月22日(土)にNervesJPとkochi.ex合同でNervesハンズオンする回!で使用したコードの簡単な解説を書いていきます。
資料一覧
ハンズオン用Repository github:b5g-ex/nerves_livebook
演習_Nervesハンズオン_基本編
演習_Nervesハンズオン_応用編
運営側の準備編
機材を必要なセット分用意する。
今回のハンズオンは全てLivebook上で完結するため、参加者の環境にはElixirのコンパイル環境は不要ですが、Rpi4と有線NWで接続する点だけ注意が必要です。
- Raspberry Pi4
- Grove Base HAT
- Grove I2C温湿度センサ AHT20
- Grove LED
- Grove Button
- 電源、マイクロSD
プログラム
プログラムは、github:nerves_livebookのRepositoryをcloneし、ネットワークを設定し、ハンズオン用のソースコードを突っ込む以上です。いやーかんたん。まじかよ。
※ハンズオン用Repository github:b5g-ex/nerves_livebookは上記全て済みの状態です。
ネットワークの設定
今回のTARGETはrpi4なので、/config/rpi4.exs を編集します。
rpi4.exsはtarget.exsでimportされています
# 有線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に簡単ログイン
LivebookからLチカ
LivebookでGenSrver
基本編では、GenServerを利用して、イベントドリブンによるLチカまで行っています。
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で温湿度測定
バイナリーデータをビット長でパターンマッチ
aht20.exsの中では、温湿度センサーから取得したバイナリデータをビット長でパターンマッチし変数に格納しています。
〜
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で温湿度をグラフ表示
まとめ
以上、kochi.exとNerves.jpで共催したハンズオンの解説でした。
この構成のうまみ まとめ
- Livebookの準備がとても簡単
- 参加者の環境にElixirのコンパイル環境が不要
- 機材とPCさえあれば誰でも簡単に横展開できそう
これでやっと年末を迎えられそうです。
あぁ今日はクリスマスなんですね。そうですね。
奥様がとてもクリスマスモードなので、イベントカレンダーはこのくらいにしておきます。
皆様よいお年を。