はじめに
- Elixir 楽しんでいますか
- 先日、「SORACOM x Nerves できたとはいえるとぼくおもいます」を書きました
- こちらは、本当にやりたいことはできませんでした〜 という内容でした
- その後、進展がありましたので改めて書いておきます
- 本当にやりたかったことにだいぶ近づきました
- この記事は、2021/06/12(土) 00:00 〜 2021/06/14(月) 23:59開催のautoracex #32というElixirのもくもく会での成果です
この記事で書いていること
-
SORACOM Air for セルラーのSIMをセットしたL-02CをNervesがイゴいているRaspberry Pi 4に挿してセルラー通信を楽しみます
- nerves-project/nerves_system_rpi4をカスタマイズします
- 本当に、SORACOM Air for セルラーでセルラー通信していることを確かめるために、SORACOM Beamを使います
-
pon
コマンドやip route ...
コマンドなどを使って多少強引ではありますがセルラー通信ができるようになりました - たったの4ステップです!!!
SORACOM Beamとは
- https://soracom.jp/services/beam/ の説明、図を拝借させていただきました
- SORACOM Beam(以下、Beam)は、IoT デバイスにかかる暗号化等の高負荷処理や接続先の設定を、クラウドにオフロードできるサービスです。Beam を利用することによって、クラウドを介していつでも、どこからでも、簡単に IoT デバイスを管理することができます。大量のデバイスを直接設定する必要はありません。
- _お客さまのサーバー_は私の場合、Azure 仮想マシン上にPhoenixを使って自作したWebアプリケーションをイゴかします
- 設定はこんな感じです
- 転送先が、お客さまのサーバー です
- 公式ドキュメント → https://users.soracom.io/ja-jp/docs/beam/
① 準備
- この記事では割愛します
- いくつかリンクを示しておきます
公式
環境構築
Nervesアプリの開発の流れがよくわかる記事
WiFi設定
② SIMの購入・データ通信端末の購入
- SORACOM Air for セルラーの利用方法(個人・法人) を参考にSIMを購入します
- 私は、
plan-D
を選びました -
L-02Cに合うサイズは、標準1です
- L-02Cはなぜ買ったのかは忘れてしまいましたが発売当初に購入した記憶だけはあります
- SORACOM IoTストアで購入できるデータ通信端末でもよいとおもいます
- https://soracom.jp/store/5273/
- https://soracom.jp/store/5274/
- ただし、私は試しているわけではないのでNervesと組み合わせて使えるかどうかは保証できないです
- がんばればいけるとおもいます!
L-02Cがデフォルトでモデムモードになっているようにする
- 素のRaspberry Pi OSでは自動的にモデムモードとして認識されますが、Nervesの場合はCDROMとして認識されてしまいます
- 以前は素のRaspberry Pi OSでもデフォルトはCDROMとして認識していたようです
- もしRaspberry Pi OSのアップデート等でこのへんの動きが変わってしまった場合は、
eject
、usb_modeswitch
、lsusb
あたりでググると答えにたどりつけるとおもいます
- そこであらかじめ、素のRaspberry Pi OSでモデムモードとして認識されるように設定しておきました
$ cu -l /dev/ttyUSB2
ATZ
AT%USBMODEM=0
~.
- (たしかこんな感じだったはずです)
③ Customizing Your Own Nerves System
- を参考にカスタマイズしていきます
環境
- 私が使用した環境です
- macOS Catalina 10.15.7
- Elixir: 1.11.4-otp-23
- Erlang: 23.0.1
- Docker version 20.10.6, build 370c289
- Dockerをイゴかしておく必要があります
- のちほど行う
mix firmware
のときにNerves Systemのビルドで使われます - イゴかしておけば勝手に使われる感じです
フォルダ構成
soracom
├── custom_rpi4
└── cellular_sample
custom_rpi4
$ git clone https://github.com/nerves-project/nerves_system_rpi4.git custom_rpi4 -b v1.15.1
カスタマイズ
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
@source_url "https://github.com/#{@github_organization}/#{@app}"
@version Path.join(__DIR__, "VERSION")
|> File.read!()
- 以下は、https://github.com/nerves-networking/vintage_net_mobile#system-requirements を参考にカスタマイズします
-
ppp
等が使えるようになります
-
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
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"
busybox.fragment
CONFIG_MKNOD=y
CONFIG_WC=y
cellular_sample
- Nervesアプリです
$ mix nerves.new cellular_sample --target rpi4
ファイルの変更
mix.exs
defmodule CellularSample.MixProject do
@app :cellular_sample
@version "0.1.0"
- @all_targets [:rpi4]
+ @all_targets [:rpi4, :custom_rpi4]
def project do
[
@@ -41,7 +41,13 @@ defmodule CellularSample.MixProject do
{:nerves_pack, "~> 0.4.0", targets: @all_targets},
# Dependencies for specific targets
- {:nerves_system_rpi4, "~> 1.13", runtime: false, targets: :rpi4}
+ {:nerves_system_rpi4, "~> 1.13", runtime: false, targets: :rpi4},
+ {:custom_rpi4, path: "../custom_rpi4", runtime: false, targets: :custom_rpi4, nerves: [compile: true]},
+ {:elixircom, "~> 0.2.0"},
+ {:circuits_i2c, "~> 0.3.8"},
+ {:httpoison, "~> 1.8"},
+ {:jason, "~> 1.2"},
+ {:timex, "~> 3.7"}
]
end
セルラー通信のための設定ファイル
- 素のRaspberry Pi OSで動作するファイルをこさえるとよいです
- ググったり、
pppconfig
でひな形つくって、ググって変更したり地道にがんばる必要があります- 各行の意味はそれほど理解しているわけではありません
- L-02Cに関しては多くの先人の方々の記録があり、たいへん参考にさせてもらいました
- ありがとうございます!
- データ通信端末ごとに多少異なる部分があるとおもいます
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
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"
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
セルラー通信
lib/cellular_sample.ex
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
Grove AHT20 I2C温度および湿度センサー 工業用グレードで取得した値を、SORACOM Beamを経由して自分のサーバーに送り込む
- ここは通信するプログラムならなにでもいいです
-
ping 'soracom.jp'
でもいいとおもいます
-
-
SORACOM Beamと組み合わせたくて、過去にやったことある方法をつかいました
- 本題とはだいぶずれます
- 団長! いつでもどこでも温度・湿度が測れるのであります! (Elixir, SORACOM Air for セルラー)を参考にしてください
lib/cellular_sample/aht20.ex
defmodule CellularSample.Aht20 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 =
case I2C.read(ref, @i2c_addr, 7) do
{:ok, val} -> {:ok, val |> convert()}
{:error, :i2c_nak} -> {:error, "Sensor is not connected"}
_ -> {:error, "An error occurred"}
end
I2C.close(ref)
ret
end
defp convert(<<_, raw_humi::20, raw_temp::20, _>>) do
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
end
lib/cellular_sample/worker.ex
defmodule CellularSample.Worker do
require Logger
@url "http://beam.soracom.io:8888/"
@headers [{"Content-Type", "application/json"}]
def run do
{:ok, {temperature, humidity}} = CellularSample.Aht20.read()
inspect({temperature, humidity}) |> Logger.debug()
post(temperature, humidity)
end
defp post(temperature, humidity) do
time = Timex.now() |> Timex.to_unix()
json = Jason.encode!(%{value: %{temperature: temperature, humidity: humidity, time: time}})
HTTPoison.post(@url, json, @headers)
end
end
WiFi(オプション)
- sshでNervesの中に入って操作します
- LANケーブルで接続する場合は不要です
- https://hexdocs.pm/vintage_net/cookbook.html#wifi
ビルド
$ cd soracom/cellular_sample
$ export MIX_TARGET=custom_rpi4
$ mix deps.get
$ mix firmware
-
mix firmware
はNerves Systemのビルドも行われるのでかなり時間がかかります -
でも飲んで気長に待ちましょう
- マシンスペックやネットワーク環境によるとおもいますが、私は4時間くらいかかりました
- 時間がかかっていたのはダウンロードのところだとおもいます
- 夜は家のインターネットがおそいのです……
- マシンスペックやネットワーク環境によるとおもいますが、私は4時間くらいかかりました
- ビルドが終わったらmicroSDカードをPCに差し込んで
mix burn
です
④ Run
-
ssh nerves.local
等でNervesにログインします
iex> lsusb
Bus 001 Device 003: ID 1004:618f NTT DOCOMO, INC. docomo L02C
...
-
618f
がモデムモードです -
618f
になっていない場合には、ココを参照してください
iex> Elixircom.run("/dev/ttyUSB2")
AT+COPS=1,2,"44010"
- このATコマンドはおまじないです
-
44010
はドコモを表しています - 私の家の周辺ではこれを行っておくことでIPアドレスが割り当てられることが多くなったようにおもいます
-
- Ctl + Bで抜けます
iex> CellularSample.connect
# cmd("mknod /dev/ppp c 108 0")
# cmd("pon soracom")
# の実行と同じです
iex> CellularSample.update_route
# ifconfigでppp0のIPアドレスを確認して
# cmd("ip rou delete default")
# cmd("ip rou add default via #{ip_address} dev ppp0")
# の実行と同じです
iex> CellularSample.Worker.run
# AHT20から温度・湿度を取得して、SORACOM Beamを経由して自分自身のサーバーにデータが送られます
- こんな感じのセルラー通信が実現しました!
- ただし、L-02Cには無通信監視タイマーというものが満了すると通信状態が途切れてしまいます(青表示から白表示)
- 正確な時間はわかっていないのですが60秒くらいでしょうか
- 団長! いつでもどこでも温度・湿度が測れるのであります! (Elixir, SORACOM Air for セルラー)でやったときは、たしか10秒に1回くらいデータを送っていたのでこういうものがあることに気づかなかったのだとおもいます
- また24時間以上経つと不通になってしまうことがあるそうです(そんな記事を読みました)
- というような制限みたいなものはありますが、そのへんはさまざまなデータ端末で今後試してみたいとおもいます
進展したきっかけ
- 行き詰まりを感じて、その思いを吐露(SORACOM x Nerves できたとはいえるとぼくおもいます)したあと寝ました
- 翌朝ダメもとで、
RingLogger.attach
でログ出してみました - そうすると、
:os.cmd('pon soracom')
実行時に設定ファイルがみつからないというエラーログがでていまして、配置場所を間違えていたことにようやく気づきました
Wrapping Up
- 開発をするときにはログを出しておくの大事
- 寝るのも大事
- ElixirでIoTを楽しむ場合は、Nervesです
- ElixirでWebアプリケーションを楽しむ場合は、Phoenixです
- つぎはmodemつくって対応したいとおもいます
ソースコード
NervesJP
- ここでNervesJPの紹介です
- 月1回程度、ワイワイガヤガヤ オンラインで集まっています
- 次回は、2021/6/23(水) 19:30〜 NervesJP #18 テストどうやってやっていく回 です
- 愉快なfolksたちがあなたの参加を待っています
- れっつじょいな〜す
- https://join.slack.com/t/nerves-jp/shared_invite/enQtNzc0NTM1OTA5MzQ1LTg5NTAyYThiYzRlNDRmNDIwM2ZlZTJiZDc1MmE5NTFjYzA5OTE4ZTM5OWQxODFhZjY1NWJmZTc4NThkMjQ1Yjk
- ぜひぜひSlackにご参加ください
-
SIMの場合は小は大を兼ねます。ただしSIMアダプターでサイズをあわせるのはススメられてはいません。https://soracom.zendesk.com/hc/ja/articles/223454148-SIM-%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E5%A4%89%E6%9B%B4-%E5%86%8D%E7%99%BA%E8%A1%8C%E3%81%AF%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%81%8B- ↩