ElixirでIoT#2.2：関数型言語からGroveモジュールを使ってみた

この記事は[「fukuoka.ex(その2) Elixir Advent Calendar 2017」](https://adventar.org/calendars/2871)の25日目，および
[「Raspberry Pi Advent Calendar 2017」](https://qiita.com/advent-calendar/2017/raspberry-pi)の20日目です．


昨日は，@twinbeeさんの
「[Google DatalabコンテナにElixirを入れてTensorflexを動かそう](https://qiita.com/twinbee/items/4a1b4178fc870386f7f8)」でした．

本記事では，ラズパイのGrovePi+に接続した各種Groveを関数型言語Elixirから扱える[GrovePiライブラリ](https://github.com/adkron/grovepi)を紹介します．


:camping: :camping: :camping:　<b>お知らせ！新たなElixir Advent Calendar、来週6/18(月)から始まります</b>　:camping: :camping: :camping:

fukuoka.exアドバイザーズのざっきーさん率いる山崎研究室、通称「ザキ研」の有志と、fukuoka.exアドバイザーズ／キャスト数名が、合同で新たな季節外れのElixir Advent Calendarを始めます:star2:

来週6/18（月）からスタートで、[「季節外れのfukuoka.ex(その2) Elixir Advent Calender」](https://adventar.org/calendars/2871)で連載途中だったシリーズも、[「fukuoka.ex x ザキ研 Advent Calendar」](https://adventar.org/calendars/2873)で、続きが見れます:gem:

どうぞ、来週6/18（月）以降の新たなカレンダーをお楽しみに！:rocket:

[![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/f4fe0296-4ad0-4d81-1328-07e5613e98f0.png)](https://adventar.org/calendars/2873)


# はじめに

どうもこんにちは．
[fukuoka.ex](https://fukuokaex.connpass.com/)という福岡のElixir/PhoenixコミュニティにてIoT芸を披露している者です．
巷を賑わせている新しめの関数型言語である**ElixirでIoTできるんじゃね！？**と喧伝しております．

[これまでの連載記事](qiita.com/takasehideki/items/8f43f1853ce88cbbe82e)はこちら．
　|> [ElixirでIoT#1.0：IoTボードへのLinux環境の準備](https://qiita.com/takasehideki/items/9e3db412a40659233384)
　|> [ElixirでIoT#1.1：IoTボードへのElixir環境の構築とEEloTツールキットの紹介](https://qiita.com/takasehideki/items/fc570ae92a895caed213)
　|> [ElixirでIoT#1.2：いろいろ分かるベンチマークを整備してみる](https://qiita.com/takasehideki/items/e1dcb4058c7d0b51d554)
　|> [ElixirでIoT#1.3：IoTボードで動いた！Phoenixが立った！性能評価と考察](https://qiita.com/takasehideki/items/0aa644639f81c2ad0bbc)
　|> [ElixirでIoT#2.1：Nervesって何者？ラズパイでLチカできんの！？](https://qiita.com/takasehideki/items/94820516ec95b85bae32)

Elixirユーザの皆さまにはいろいろそこそこ反響をいただいて感謝の限りです．
ラズパイユーザな皆さまにも，**ラズパイでElixir使えるよ！？**ということを知っていただきたく，やはり季節外れですが[「Raspberry Pi Advent Calendar 2017」](https://qiita.com/advent-calendar/2017/raspberry-pi)の空き日に投下しております．
なお，ラズパイカレンダーに前回投下した記事はこちらです．
　|> [ElixirでIoT#1.1.1：ラズパイへのErlang/Elixir環境の構築](https://qiita.com/takasehideki/items/210f8a7172807d0c9e5b)


今回は，Elixirから各種Groveを扱える[GrovePiライブラリ](https://github.com/adkron/grovepi)を紹介します．


## Elixirとは？

`RaspberryPi`タグで来た方への説明です．

Elixirは2012年に登場した新しい関数型言語です．ErlangのVM上で走ります．[次に来る大物Web言語](https://qiita.com/HirofumiTamori/items/0dfdbada30c7d8f183fd)と言われています．

Elixirには以下の特徴があります．

- 読み書きしやすく，生産性が高い．
- 並行処理（並列処理）のプログラミングが簡単に実現できる．
- 分散システム対応／スケールしやすい．
- 軽量で耐障害性が高い．

**あれっ？これってIoTでも使えるんじゃね！？？**

## Groveとは？

`Elixir`や`Erlang`のタグで来た方への説明です．

[Grove](https://www.seeedstudio.com/grove.html)は，各種センサなどのIoTデバイスを画一パッケージ化したモジュール群です．中国深センにある気鋭のスタートアップであるSeeed社が開発・販売しています．
入出力ピンが4ピンのGroveコネクタで統一されており，簡単に付け替えできるのが特徴です．また，Arduinoやラズパイに96Boardsなどの主要なIoTボードに適合する各種シールドも提供されています．このため，様々なIoTシステムの開発をラピッドに試すことができます:bullettrain_side::bullettrain_side::bullettrain_side:

## Elixirのラズパイ／Groveへの対応状況

Elixir界隈では，[前回の記事](https://qiita.com/takasehideki/items/94820516ec95b85bae32)でも紹介したとおり，[Nerves](https://nerves-project.org)というプロジェクトにてラズパイへの対応が進んでいます．
Grove対応は，[Nerves.Grove](https://hexdocs.pm/nerves_grove/readme.html)というライブラリが提供されており，[GitHubでもソースが公開](https://github.com/bendiken/nerves_grove)されています．最初はこれを使おうかと思ったのですが，ドキュメントやサンプルアプリが乏しく，扱い方がよく分かりませんでした．開発が2016年8月で止まっているのも気がかりです．

今回は，上記のNerves.Groveを発展させてGrovePiに対応した下記のライブラリを使いました．

- [adkron/GrovePi: Use the GrovePi in Elixir](https://github.com/adkron/grovepi)

GrovePi+とGrovePi Zeroに対応していて，[`examples/`](https://github.com/adkron/grovepi/tree/master/examples)以下に幾つかサンプルも提供されていて分かりやすいです．Groveモジュールの対応状況は[HexDocs](https://hexdocs.pm/grovepi/api-reference.html)をご参照ください．

GrovePiライブラリでは，Erlang VMのNIF経由でラズパイのGPIO,I2C,SPIの各種デバドラにアクセスできる[elixir_ale](https://github.com/fhunleth/elixir_ale)が使われています．

# 用意した環境

筆者が試してみた環境をまとめてみます．

- ボード：[Raspberry Pi 3 Model B](https://www.raspberrypi.org/products/raspberry-pi-3-model-b/)
- カーネル：[Raspbian Stretch with Desktop 4.9](https://www.raspberrypi.org/downloads/raspbian/)と[Ubuntu MATE 16.04](https://ubuntu-mate.org/raspberry-pi/)
- Groveシールド：[GrovePi+](https://www.seeedstudio.com/GrovePi%2B-p-2241.html)
- Elixirバージョン：Elixir 1.6.5 (compiled with OTP 20)
    - Erlang/OTP 20 [erts-9.3] [source] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

今回の記事では，以下のGroveモジュールを使いました．

- [Button](http://wiki.seeedstudio.com/Grove-Button/)
- [Buzzer](http://wiki.seeedstudio.com/Grove-Buzzer/)
- [Rotary Angle Sensor](http://wiki.seeedstudio.com/Grove-Rotary_Angle_Sensor/)
- [LED Socket Kit](http://wiki.seeedstudio.com/Grove-LED_Socket_Kit/)
- [LCD RGB Backlight](http://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/)

![IMG_9936.JPG](https://qiita-image-store.s3.amazonaws.com/0/240349/988e6524-7fff-c6b6-0a35-2c87f7f8188f.jpeg)


# GrovePi+の環境構築

まずは[こちら](https://www.dexterindustries.com/GrovePi/get-started-with-the-grovepi/setting-software/)を参考にして，GrovePi+を使えるように環境をインストールします．
インストール後は再起動が必要です．

```shell-session
$ sudo curl -kL dexterindustries.com/update_grovepi | bash
$ sudo reboot
```

再起動後にGrovePi+をラズパイに刺して，`i2cdetect`コマンドで正常にシールド接続が検出できることを確認してください．

```shell-session
 sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- 04 -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                   
```

# GrovePiライブラリの使用方法

それではGrovePiライブラリを使っていきましょう．
まずはmixプロジェクトの作成ですが，この辺りはいつものElixirと同じです．

```shell-session
$ mix new grovepi_test 
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/grovepi_test.ex
* creating test
* creating test/test_helper.exs
* creating test/grovepi_test_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd grovepi_test
    mix test

Run "mix help" for more commands.
$ cd grovepi_test/
```

`mix.exs`にGrovePiライブラリを使うための依存関係を書いてやります．
releaseタグじゃなく最新の`master`ブランチを明示的に指定してやらないと動かないサンプルがありました．

```mix.exs
  defp deps do
    [{:grovepi, github: "adkron/grovepi", branch: "master"}]
  end
```

あとは，`lib/grovepi_test.ex`にプログラミングしていくだけです．

コンパイルと実行はこんな感じです．
elixir_aleの都合で`MIX_ENV=prod`を明示指定する必要があるようです．

```shell-session
$ mix deps.get
$ MIX_ENV=prod mix compile
$ MIX_ENV=prod iex -S mix
```

# [`examples/`](https://github.com/adkron/grovepi/tree/master/examples)の紹介

最後に，GitHubに挙がっているexamplesを使ってみたので紹介します．
とりま`git clone`して移動しましょう．

```shell-session
$ git clone https://github.com/adkron/grovepi
$ cd grovepi/examples
$ ls
alarm  demo_pivotpi  demo_rgblcd  
home_weather_display  led_fade
```

## alarm

GrovePi+のA0にButtonを，D3にBuzzerを接続します．
ボタンを押したら`Alert!!!!`と表示されて1秒間ブザーが鳴ります．Buzzer音がすっごく大きいので，周りの方々をビックリさせないようにご注意ください:rage::rage::rage:
（Buzzerに養生テープ等を貼り付けとくと音量が抑制できます）

```shell-session
＄ cd alarm/
$ mix deps.get
$ MIX_ENV=prod mix compile
$ MIX_ENV=prod iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.6.5) - press Ctrl+C to exit (type h() ENTER for help)
# ボタンを押したら，，，？？
iex(1)> Alert!!!!
```

ちなみに，コネクタの配置は`lib/alarm.ex`の6-7行目で変更できます．

```lib/alarm.ex
  # Pick ports that work on both the GrovePi+ and GrovePi Zero
  @button_pin 14 # Port A0
  @buzzer_pin 3  # Port D3
```

## demo_pivotpi

シリアルモータを制御できる[PivotPi](https://www.dexterindustries.com/pivotpi/)用のサンプルです．
手元に持っていなかったんでカッツアイ．

## demo_rbglcd

LCDモジュールを使ったサンプルです．今回の[LCD RGB Backlight](http://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/)は，名前の通りRBGのバックライトが付いています．
GrovePi+のI2C-1に接続します．

```shell-session
$ cd demo_rgblcd/
$ mix deps.get
$ MIX_ENV=prod mix compile
$ MIX_ENV=prod iex -S mix
```

LCDの表示を制御するデモが幾つか用意されています．
無限ループで動きますので，その都度Erlangを終了させる必要があります．

```shell-session
iex(1)> DemoRGBLCD.autoscroll()
%GrovePi.RGBLCD.Config{display_control: 12, entry_mode: 6, function: 56}
0
1
2
3
4
5
6
7
8
9
%GrovePi.RGBLCD.Config{display_control: 12, entry_mode: 7, function: 56}
0
1
2
3
4
5
6
7

BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
```

実際に動いている様子です．0-9の数字が右から左へ受け流されます．


![lcd_autoscroll.gif](https://qiita-image-store.s3.amazonaws.com/0/240349/d0d185c5-063a-51a0-6109-e135c41d4db9.gif)



```shell-session
iex(4)> DemoRGBLCD.colors()
```

バックライトがRGBWで点灯します．
動画だともっと綺麗なんですが，GIFだとコレが限界ですかね．

![lcd_rgb.gif](https://qiita-image-store.s3.amazonaws.com/0/240349/68c42fdb-6b72-726d-2082-ccd6ca0201b9.gif)

その他のデモの解説はさらっといきますかね．

```shell-session
iex(3)> DemoRGBLCD.blink()
  # Say "Hello World!" and toggles cursor blinking on and off every 3000ms
iex(4)> DemoRGBLCD.cursor()
  # Say "Hello World!" and toggles the cursor on and off every 1500ms
iex(5)> DemoRGBLCD.display()
  # Toggles the display on and off every 1500ms
iex(6)> DemoRGBLCD.text_direction()
  # Demonstrates text direction both ways
iex(7)> DemoRGBLCD.set_cursor()
  # Demonstrates moving the cursor to the second line
```

## home_weather_display

温湿度センサ（[Temperature&Humidity Sensor](http://wiki.seeedstudio.com/Grove-TemperatureAndHumidity_Sensor/)）の値をLCDに表示します．

ただこれはなぜかNerves環境下で動作するクロス開発のアプリになっています．使用されているNervesや他ツールのバージョンが古いようで，最新環境を構築している筆者の母艦Macではコンパイルすらできませんでした．
そのうちセルフ開発で扱えるように本サンプルを作り変えたいと思っています．

## led_fade

GrovePi+のA2にRotary Angle Sensorを，D3にLED Socketを接続します．
ロータリの角度に応じてLEDの点灯量が変化します．

```shell-session
$ cd led_fade/
$ mix deps.get
$ MIX_ENV=prod mix compile
$ MIX_ENV=prod iex -S mix
```

実際の動作はこんな感じ．
細かくて分かりにくい上に汚い指ですみません，，，

![led_fade.gif](https://qiita-image-store.s3.amazonaws.com/0/240349/bb22dcae-644e-d29a-bcb5-2fc217cbdadc.gif)

ラズパイはデジタルピンしか出ていないのですが，Groveを使用することでアナログ制御も簡単に実現できるようになります．


# まとめ

- ElixirでGrove使えるよ！IoTラピッドプロトタイピングできちゃうよ！！
- Groveモジュールを扱えるGrovePiライブラリとそのサンプルを紹介しました

# お知らせ

:alarm_clock::alarm_clock::alarm_clock::alarm_clock:<b>　満員御礼！Elixir MeetUpを6月末に開催します　</b>:alarm_clock::alarm_clock::alarm_clock::alarm_clock:
<font color="red"><b>※応募多数により、増枠しました</b></font>
[<b>「fukuoka.ex#11：DB／データサイエンスにコネクトするElixir」</b>](https://fukuokaex.connpass.com/event/87241)を6/22(金) 19時に開催します．


[![image.png](https://connpass-tokyo.s3.amazonaws.com/thumbs/cb/13/cb130a03343bc310b07244c308b940db.png)](https://fukuokaex.connpass.com/event/87241)


私も**「ElixirでIoTやってみた」**芸を披露する予定です．
実は今回の記事は，このfukuoka.ex#11に向けたネタ仕込みの先出しだったりするのです．
温湿度センサをセルフで扱えるようにして，環境データをセンシングしてさくっとWeb表示できたらおもろいかな？と思っていたりしています．

そして，ネタ仕込みの開発状況は下記のGitHubで逐次公開していきます．

- https://github.com/takasehideki/fukuokaex11

まだ今回のサンプルを移しただけなのですが，，，ちゃんと準備が進んでいるのかリポジトリをWatchしてたら面白いかもしれませんｗ

どうぞfukuoka.ex#11での発表にご期待ください！！