ElixirでラズパイのLEDをチカ〜RaspbianOSインストールから〜


この記事は「#NervesJP Advent Calendar 2019」の9日目です。

昨日は @pojiro さんの「作って学ぶNerves、BBBでCO2計測」でした。

Nervesハンズオンを経験した結果、初心者には環境構築が厳しいと感じました。まずはElixir IoTの取っ掛かりとして、手軽なラズパイでElixirを使ってLEDをチカチカさせるまでをまとめようと思います。ひととおり手を動かした感想として、Nerves使った場合はRaspbianの設定が不要なのはいい点ではないかという印象を持ちました。

ざっくりまとめると

  • Mac OSXでRaspbian OSインストールとかんたんな設定
  • ラズパイにElixirインストール
  • ラズパイのLEDをチカチカ

Mac OSXでRaspbian OSインストールとかんたんな設定

Raspbian OSのインストールはいろいろなやり方があると思いますが、今回はMac OSXを使ってRaspbian OSをインストール(実際にはSDカードにOSイメージ書き込み)して、Wi-Fi設定とSSHでログインできるまでをおこないます。

Raspbian OSインストール

Mac OSXを使ってRaspbian OSをインストール(実際にはSDカードにOSイメージ書き込み)します。

Raspbian OSダウンロード

今回はRaspbian Buster with desktopをインストールすることにします。

公式サイトからダウンロードしてもいいですが、時間がかかりすぎるのでミラーサイトから2019-09-26-raspbian-buster.zipをダウンロードして、unzipします。

unzipしたディレクトリに2019-09-26-raspbian-buster.imgファイルができあがります。

SDカードにイメージを焼く

フォーマットしたSDカードを準備[^sd-formatter]して、OSXがSDカードをマウントしているディレクトリを確認します。
以下の場合は/dev/disk4ということが分かります。

% diskutil list
(いろいろ略)
/dev/disk4 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *32.2 GB    disk4
   1:             Windows_FAT_32 NO NAME                 32.2 GB    disk4s1

Downloadsなどunzipしたファイルのあるディレクトリに移動します。
SDカードをアンマウントして、ダウンロードしたRaspbian OSイメージをSDカードに書き込みます。

% cd Downloads
% diskutil unmountDisk /dev/disk4
% sudo dd bs=1m if=2019-09-26-raspbian-buster.img of=/dev/disk4

かんたんな設定(Wi-Fi設定、SSHできるまで)

SDカードをRaspberryPiに挿して起動します。
この時、HDMIモニター・USBキーボード・USBマウスを準備しているとスムーズです。

今回は、RaspberryPiのインターネット接続はWi-Fi、メンテナンス用として有線LANを使うこととします。
インストール後、初期画面に基本設定をする画面が起動するので自分の環境にあわせた設定とWi-Fiでインターネットにつながるようにします。その後、以下のコマンドを実行してSSH・I2Cの有効化とパッケージの更新を実行します。

% sudo raspi-config
5 Interfacing Options
P2 SSH
    Would you like the SSH server to be enabled? → <はい>
P5 I2C
    Would you like the ARM I2C interface to be enabled? → <はい>
% sudo apt-get update
% sudo apt-get upgrade ※時間かかる
% sudo reboot

メンテナンス用として有線LANのIPアドレスを設定します。
基本はDHCPでIPアドレスを自動取得という設定にして、IPアドレス取得失敗した場合に192.168.5.55/24になる設定をおこないます。

/etc/dhcpcd.confを編集します。インターネット接続はWi-Fiを使いたいのでstatic routersstatic domain_name_serversの行は削除かコメントアウトします。

% sudo vi /etc/dhcpcd.conf

profile static_eth0 ←そのまま
static ip_address=192.168.5.55/24 ←IPアドレスを修正
# static routers ←行を削除 or コメントアウト
# static domain_name_servers ←行を削除 or コメントアウト
inteface eth0 ←コメントアウトはずす
fallback static_eth0 ←コメントアウトはずす

補足

無線LANの設定は/etc/wpa_supplicantディレクトリにあるので必要に応じて設定します。

ラズパイにElixirインストール

注意
「aptでインストールしたElixir」と「asdfでインストールしたElixir」を共存させるととても面倒なことが起こると思うのでやめたほうがいいです。

aptでインストール(Elixir古いバージョンでていいから環境をお手軽に構築したい人向け)

Raspbianが提供しているパッケージ管理システムを使ってElixirをインストールします。
公式ドキュメントどおり実行します。

% echo "deb https://packages.erlang-solutions.com/debian buster contrib" | sudo tee /etc/apt/sources.list.d/erlang-solutions.list
% wget https://packages.erlang-solutions.com/debian/erlang_solutions.asc
% sudo apt-key add erlang_solutions.asc
% sudo apt update
% sudo apt install elixir

asdfでインストール(Elixirの最新バージョンを使いたい人向け)

Elixirのバージョンを切り替えて実行できるasdfを使ってElixirをインストールします。
基本的には公式ドキュメントどおり実行します。

% git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.7.5

<Bash on Linuxの場合>
% echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc
% echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc

<Fishの場合>
% echo 'source ~/.asdf/asdf.fish' >> ~/.config/fish/config.fish
% mkdir -p ~/.config/fish/completions; and cp ~/.asdf/completions/asdf.fish ~/.config/fish/completions

% sudo apt-get install automake autoconf libreadline-dev libncurses-dev libssl-dev libyaml-dev libxslt-dev libffi-dev libtool unixodbc-dev unzip curl libncurses5-dev

% asdf install erlang 22.1.5 ※すごい時間かかる!
% asdf install elixir 1.9.4

% asdf global erlang 22.1.5
% asdf global elixir 1.9.4

% iex -v
Erlang/OTP 22 [erts-10.5.3] [source] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

IEx 1.9.4 (compiled with Erlang/OTP 20)

ラズパイのLEDをチカチカ

ラズパイのボードについている緑色のLEDをチカチカさせるプログラムをElixirで作ります。

緑色のLEDは/sys/class/leds/led0/brightness1にすると光ります。root権限でなくても実行できるようにしたいので誰でも読み書き可能にしておきます。このパーミッションはラズパイを再起動すると元に戻ります。

% sudo chmod 666 /sys/class/leds/led0/brightness

iexを起動して以下の内容を入力します。
Led0chika.green(count, sleep_msec)のように実行するとcount回緑色のLEDをチカらせ、その間隔はsleep_msecとなります。

defmodule Led0chika do

  @green "/sys/class/leds/led0/"
  @brightness @green <> "brightness"
  @bright "1"
  @start 0

  def green(count, sleep_msec) do
    {:ok, file} = File.open(@brightness, [:write])
    start = @start
    finish = count
    green(start, finish, sleep_msec, file)
  end

  def green(start, finish, sleep_msec, file) when start == finish do
    chika(start, sleep_msec, file)
    File.close(file)
    IO.puts("finish!!!")
  end

  def green(start, finish, sleep_msec, file) when start != finish do
    chika(start, sleep_msec, file)
    green(start + 1, finish, sleep_msec, file)
  end

  defp chika(start, sleep_msec, file) do
    IO.puts(start)
    IO.binwrite(file, @bright)
    :timer.sleep(sleep_msec)
  end

end

入力が完了したら実行してみます。
以下の例では、1,000ミリ秒の間隔で10回緑のLEDをチカらせることとします。

iex(2)> Led0chika.green(10, 1_000)
0
1
2
3
4
5
6
7
8
9
10
finish!!!
:ok

緑色のLEDがチカチカしました!
動画がなくてスミマセン


明日は @torifukukaiou さんの「Nervesを使ってRaspberry Pi 2でLEDをチカチカさせる 〜クリスマスの飾り付けをしよう〜」です。

参考URL