VOOZH about

URL: https://qiita.com/torifukukaiou/items/dfe1577004f36b8b77d7

⇱ Nerves Livebook Firmwareを使って温度・湿度のグラフをかいてみる #Elixir - Qiita


👁 Image
13

Go to list of users who liked

6

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 3 years have passed since last update.

@torifukukaiou(Awesome YAMAUCHI)Team Coffeein👁 Image
fukuoka.ex:福岡Elixirコミュ

Nerves Livebook Firmwareを使って温度・湿度のグラフをかいてみる

13
Last updated at Posted at 2021-08-07

はじめに

👁 output.gif

必要なもの

👁 スクリーンショット 2021-08-07 12.13.34.png

  • 私はRaspberry Pi 4を使いました
  • Prerequisitesに書いてあるターゲットをお持ちの方はぜひお試しください!
  • 温度・湿度の測定には手先が不器用ですからな私でもIoTを楽しめるSeeedさんの製品を使いました
    • Raspberry Pi用Grove Base Hat
    • Grove AHT20 I2C温度および湿度センサー 工業用グレード
      • この記事では、私が持っているセンサーを使います
      • そのほかのセンサーでもこの記事を参考に楽しめるとおもいます
        • センサーから値を読み込むElixirのプログラムを作っていただく必要はあります
      • そんなの無いよう〜 という方のために、この記事でつかったRaspberry Pi 4さえあれば楽しめる手順は後ほど書いておきます
  • 私の開発マシンはmacOS Catalina 10.15.7です
  • Windowsでも大丈夫なはずです (すみません。試してはいません)

準備

①ファームウェアを焼き込むツールをインストールします

②ファームウェアをダウンロードします

③ファームウェアをmicroSDカードに焼き込みます

  • 開発マシンにmicroSDカードをさして以下のコマンドを実行します

LANケーブルでネットワークに接続する場合

$ fwup nerves_livebook_rpi4.fw
Use 15.84 GB memory card found at /dev/rdisk2? [y/N] y

Wi-Fiでネットワークに接続する場合

$ sudo NERVES_WIFI_SSID='access_point' NERVES_WIFI_PASSPHRASE='passphrase' fwup nerves_livebook_rpi4.fw

④こんがり焼き上がったmicroSDカードをターゲットに差し込んで電源ON

  • 10秒から30秒程度、👁 :coffee:
    でも飲んでお待ちください
  • ping nerves.localで反応があることを確かめたら、ブラウザでhttp://nerves.localにアクセスしてみてください
  • こんな画面がでてきましたら、Passwordには迷わずnervesと叩き込んでください!

👁 スクリーンショット 2021-08-07 12.34.25.png

温度・湿度のグラフを書いてみる

Livebook v0.2 is out! I have recorded a video with our latest features: https://t.co/jvbL5lNrjX

After the initial announcement, we have added user profiles, notebook importing, inputs, charts, and interactive widgets with Kino!

Thread 👇 with a TL;DW [1/6] #MyElixirStatus

— José Valim (@josevalim) June 17, 2021
  • Elixirの作者であるJosé Valimさんの解説動画をとても参考にしています
  • nervesでAuthenticateすると以下のような画面に遷移します

👁 スクリーンショット 2021-08-07 12.37.18.png

  • 右上のNew notebookでノートブックをつくります
  • あとはポチポチやっていく感じです
  • タイトルのデフォルト値はUntitled notebookです
    • そのままでもよいです
    • 名前は大事なので、temperature-humidityとでもつけておきましょう

👁 スクリーンショット 2021-08-07 12.46.30.png

グラフをかく

defmodule Aht20.Reader do
 alias Circuits.I2C

 @i2c_bus "i2c-1"
 @i2c_addr 0x38
 @initialization_command <<0xBE, 0x08, 0x00>>
 @trigger_measurement_command <<0xAC, 0x33, 0x00>>
 @two_pow_20 :math.pow(2, 20)

 def read do
 {:ok, ref} = I2C.open(@i2c_bus)

 I2C.write(ref, @i2c_addr, @initialization_command)
 Process.sleep(10)

 I2C.write(ref, @i2c_addr, @trigger_measurement_command)
 Process.sleep(80)

 ret = I2C.read(ref, @i2c_addr, 7)

 I2C.close(ref)

 value(ret)
 end

 defp value({:ok, val}), do: {:ok, convert(val)}

 defp value(_), do: :error

 defp convert(<<_, raw_humi::20, raw_temp::20, _>>) do
 humi = Float.round(raw_humi * 100 / @two_pow_20, 1)
 temp = Float.round(raw_temp * 200 / @two_pow_20 - 50.0, 1)

 {temp, humi}
 end
end
  • いきなり長いですね
  • センサーごとにデータシートを読み解きながら、値を読み取るプログラムをつくる必要があります
  • もしかしたらライブラリとして公開されているものがあるかもしれません
  • Elixirがはじめての方にはもしかしたら見慣れないものが多いかもしれませんが、なんとなく感じてください
  • 以下のコミュニティがきっと優しくSlackで相談にのってくれるでしょう!

👁 スクリーンショット 2021-08-07 15.53.41.png

  • 続いて+ Elixirを押して
Aht20.Reader.read()
  • と入力します
  • すぐ上に> Evaluateというボタンがありますので迷わずおしてみます

👁 スクリーンショット 2021-08-07 15.56.56.png

  • 温度・湿度が読み取れました
    • この例では気温 28.2℃、湿度 46.4%です
  • あとは定期的に値を取得してグラフ表示してみます
  • + Elixirを押して以下のプログラムを入力してください
  • https://www.youtube.com/watch?v=MOTEgF-wIEI にて、José Valimさんが説明されているプログラムを参考にしています
alias VegaLite, as: Vl

layers = 
 for {layer, color} <- [temp: :red, humi: :blue] do
 Vl.new()
 |> Vl.mark(:line)
 |> Vl.encode_field(:x, "iteration", type: :quantitative)
 |> Vl.encode_field(:y, Atom.to_string(layer), type: :quantitative, title: "℃, %")
 |> Vl.encode(:color, value: color, datum: Atom.to_string(layer))
 end

widget = Vl.new(width: 500, height: 200)
 |> Vl.layers(layers)
 |> Kino.VegaLite.new()
  • 一度、+ Elixirを押してプログラムを分けてください
Kino.VegaLite.periodically(widget, 200, 0, fn i ->
 {:ok, {temp, humi}} = Aht20.Reader.read()
 point = %{temp: temp, humi: humi, iteration: i}
 
 Kino.VegaLite.push(widget, point, window: 1000)
 {:cont, i + 1}
end)
  • evaluateを迷わず押すと、こんなグラフが表示されるとおもいます
  • センサーを水に近づけることで湿度があがっています
    • なにもしないとまっすぐにしかならないので演出です

👁 output.gif

👁 :tada:
👁 :tada:
👁 :tada:
👁 :tada:

おまけ メモリ使用量でグラフをかく

  • センサーをお持ちではない方でもお手軽に試せる方法を書いておきます
Mix.install([
 {:vega_lite, "~> 0.1.0"},
 {:kino, "~> 0.2.0"}
])

alias VegaLite, as: Vl

memory = [
 total: :red,
 processes: :yellow,
 atom: :green,
 binary: :pink,
 code: :orange,
 ets: :blue
]

layers = 
 for {layer, color} <- memory do
 Vl.new()
 |> Vl.mark(:line)
 |> Vl.encode_field(:x, "iteration", type: :quantitative)
 |> Vl.encode_field(:y, Atom.to_string(layer), type: :quantitative, title: "Memory usage (MB)")
 |> Vl.encode(:color, value: color, datum: Atom.to_string(layer))
 end

widget = Vl.new(width: 500, height: 200)
 |> Vl.layers(layers)
 |> Kino.VegaLite.new()
Kino.VegaLite.periodically(widget, 200, 0, fn i ->
 point =
 :erlang.memory()
 |> Enum.map(fn {type, bytes} -> {type, bytes / 1_000_000} end)
 |> Map.new()
 |> Map.put(:iteration, i)
 
 Kino.VegaLite.push(widget, point, window: 1000)
 {:cont, i + 1}
end)

for i <- 1..1_000_000 do
 :"atom#{i}"
end

おまけ Lチカ

👁 output.gif

しまった👁 :bangbang:
👁 :bangbang:
👁 :bangbang:

SORACOM Air for セルラーのSIMを使ったデータ通信

$ mkdir livebook_project
$ cd livebook_project
$ git clone https://github.com/fhunleth/nerves_livebook.git
$ git clone https://github.com/nerves-project/nerves_system_rpi4.git custom_rpi4 -b v1.16.1
  • Nerves Systemのバージョンは、nerves_livebook/mix.lockに記録されているバージョンにあわせておくのが吉です

custom_rpi4

livebook_project/custom_rpi4/mix.exs
-defmodule NervesSystemRpi4.MixProject do
+defmodule CustomRpi4.MixProject do
 use Mix.Project
 
- @github_organization "nerves-project"
- @app :nerves_system_rpi4
+ @github_organization "TORIFUKUKaiou"
+ @app :custom_rpi4
livebook_project/custom_rpi4/linux-5.4.defconfig
CONFIG_PPP=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_DEFLATE=m
CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=m
CONFIG_PPP_MULTILINK=y
CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
CONFIG_USB_NET_CDC_NCM=m
CONFIG_USB_NET_HUAWEI_CDC_NCM=m
CONFIG_USB_NET_QMI_WWAN=m
CONFIG_USB_SERIAL_OPTION=m

livebook_project/custom_rpi4/nerves_defconfig
BR2_PACKAGE_USB_MODESWITCH=y
BR2_PACKAGE_PPPD=y
BR2_PACKAGE_PPPD_FILTER=y
BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES="${NERVES_DEFCONFIG_DIR}/busybox.fragment"
livebook_project/custom_rpi4/busybox.fragment
CONFIG_MKNOD=y
CONFIG_WC=y

nerves_livebook

  • 続いてnerves_livebookのほうをカスタマイズします
livebook_project/nerves_livebook/mix.exs
diff --git a/mix.exs b/mix.exs
index 0ca7bbb..558b54d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -13,7 +13,8 @@ defmodule NervesLivebook.MixProject do
 :bbb,
 :osd32mp1,
 :x86_64,
- :npi_imx6ull
+ :npi_imx6ull,
+ :custom_rpi4
 ]
 
 def project do
@@ -76,7 +77,8 @@ defmodule NervesLivebook.MixProject do
 {:nerves_system_bbb, "~> 2.10", runtime: false, targets: :bbb},
 {:nerves_system_osd32mp1, "~> 0.6", runtime: false, targets: :osd32mp1},
 {:nerves_system_x86_64, "~> 1.15", runtime: false, targets: :x86_64},
- {:nerves_system_npi_imx6ull, "~> 0.2", runtime: false, targets: :npi_imx6ull}
+ {:nerves_system_npi_imx6ull, "~> 0.2", runtime: false, targets: :npi_imx6ull},
+ {:custom_rpi4, path: "../custom_rpi4", runtime: false, targets: :custom_rpi4, nerves: [compile: true]},
+ {:elixircom, "~> 0.2.0", targets: @all_targets}
 ]
 end
livebook_project/nerves_livebook/rootfs_overlay/etc/chatscripts/soracom
# This chatfile was generated by pppconfig 2.3.18.
# Please do not delete any of the comments. Pppconfig needs them.
# 
# ispauth CHAP
# abortstring
ABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED
# modeminit
'' ATZ
'' ATH
# ispnumber
OK-AT-OK "ATDT*99***1#"
# ispconnect
CONNECT \d\c
# prelogin

# ispname
# isppassword
# postlogin

# end of pppconfig stuff
livebook_project/nerves_livebook/rootfs_overlay/etc/ppp/chap-secrets
# Secrets for authentication using CHAP
# client server secret IP addresses


sora * sora
"sora@soracom.io" * "sora"
"sora@soracom.io" * "sora"
livebook_project/nerves_livebook/rootfs_overlay/etc/ppp/peers/soracom
# This optionfile was generated by pppconfig 2.3.18. 
# 
#
hide-password 
noauth
connect "/usr/sbin/chat -v -f /etc/chatscripts/soracom"
debug
/dev/ttyUSB2
115200
defaultroute
noipdefault 
user "sora@soracom.io"

ipparam soracom
livebook_project/nerves_livebook/config/custom_rpi4.exs
import Config

# Configure the network using vintage_net
# See https://github.com/nerves-networking/vintage_net for more information
config :vintage_net,
 regulatory_domain: "US",
 config: [
 {"usb0", %{type: VintageNetDirect}},
 {"eth0", %{type: VintageNetEthernet, ipv4: %{method: :dhcp}}},
 {"wlan0", %{type: VintageNetWiFi}}
 ]

ビルド

  • Nerves SystemのビルドでDockerを使いますので、Dockerを起動しておきます
    • mix firmwareの中で自動的にいい感じにやってくれるので起動さえしておけばよいです
$ cd livebook_project/nerves_livebook
$ export MIX_TARGET=custom_rpi4
$ mix deps.get
$ mix firmware
  • mix firmwareはマシンスペックやネットワーク環境などに依存するとおもいますが、けっこう時間がかかります
  • 👁 :coffee:
    でも飲んで待ちましょう
  • ちなみに私の場合は、1時間弱かかりました

焼く

$ cd _build/custom_rpi4_dev/nerves/images/
$ sudo NERVES_WIFI_SSID='access_point' NERVES_WIFI_PASSPHRASE='passphrase' fwup nerves_livebook.fw

実行

$ ssh livebook@nerves.local

iex> lsusb()
Bus 001 Device 004: ID 1004:618f NTT DOCOMO, INC. docomo L02C
...

iex> Elixircom.run("/dev/ttyUSB2")

入力するATコマンド

AT+COPS=1,2,"44010"
OK # 端末から返される
~.

New Notebook でElixirのプログラムを書く

defmodule CellularSample do
 use Toolshed

 def connect do
 cmd("mknod /dev/ppp c 108 0")
 cmd("pon soracom")
 end

 def update_route do
 cmd("ip rou delete default")
 cmd("ip rou add default via #{ip_address()} dev ppp0")
 end

 # ifconfigしてIP Addressを取得している感じです
 defp ip_address do
 {:ok, list} = :inet.getifaddrs()

 Enum.filter(list, fn {type, _} -> type == 'ppp0' end)
 |> Enum.at(0)
 |> elem(1)
 |> Enum.at(1)
 |> elem(1)
 |> Tuple.to_list()
 |> Enum.join(".")
 end
end

CellularSample.connect()
CellularSample.update_route()
iex> ping "pong.soracom.io" 
Press enter to stop
Response from pong.soracom.io (100.127.100.127): time=69.427ms
Response from pong.soracom.io (100.127.100.127): time=66.683ms
Response from pong.soracom.io (100.127.100.127): time=77.495ms
  • 一応できてはいますが、本当はCustom modemsにあるようにモデムモジュールを作るのが推奨されています

Wrapping Up 👁 :lgtm:
👁 :lgtm:
👁 :lgtm:
👁 :lgtm:

俺、ディ、Discovery 2021が終わったら Nervesに取り組むんだ!

— 松下享平(Max)@ソラコム/IoTのエバンジェリスト (@ma2shita) June 5, 2021
13

Go to list of users who liked

6
0

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13

Go to list of users who liked

6