データ通信用SIM(3G SIM)って、ちゃんと選べば月300円ぐらいのものもあって、すごく安くなりましたよね。こうなったら、Wi-Fiの代わりに3G SIMで常時接続しちゃっても、問題ないですよね?
ということで、Raspberry Pi A+ や Raspberry Pi Zero に USB接続の3Gモデムを繋いで、インターネットと常に接続されているマシンを作ります。
他のQiitaにある同様の3Gモデム接続設定と比べた新規性:
-
wvdial
というダイアラーを使う作例が多いですが、今回pppconfig
を使った時の不具合と解消方法が判明したので、Linuxで一般的な標準パッケージppp
に含まれている、古式ゆかしいpon
poff
によるPPP接続をします。 - 作例で利用が多い、
SORACOM Air
って値段高くないですか……Raspberry PiはSSLを喋れるんだから、SORACOMの付加機能のSORACOM Beam
とか使わずに安い定額SIMでいいんじゃないですか……
ざっくり概要
設定とか入る前にざっくりした説明しておきます
なにができるの?
これができます
- Raspberry PiにUSB-3Gモデムを挿すと、docomoの電波で自動的にインターネットにつながります。
- \プラグアンドプレイ!/
- ↑「プラグアンドプレイ」って今日日聞かねえな
- スタバでRaspberry Pi使った開発が捗る
- ↑スタバで仕事しているふりの人ってほんとに捗っているんですかね……
- ↑五反田のスタバはLet'snoteのが多い
- ↑法人用Let'snoteの修理は大阪なのでアキバの例の場所じゃ直せないこれ豆な
- ↑五反田のスタバはLet'snoteのが多い
- ↑スタバで仕事しているふりの人ってほんとに捗っているんですかね……
- \プラグアンドプレイ!/
- Raspberry PiにUSB-3Gモデムを挿したまま電源が投入されると、自動でインターネットにリンクアップします。
- Raspberry PiがIoT機器になるよ!
- ↑リソースリッチなIoT機器だなおい
- SSL/TLS通信まで平気で使える
- ↑来いやNSA
- AWS IoTがサンプルプログラムのまま使える
- ↑プログラマが怠惰になるよ! 怠惰 is 美徳
- リモートで遠隔地設置の Raspberry Pi のプログラムまで直せちゃう
- ↑べんりやないの……
- Raspberry PiがIoT機器になるよ!
できないこと
- スタバでネットサーフィン
- ↑「ネットサーフィン」って今日日聞かねえな
- HDMIモニタもスタバに持ち込もう
- ↑スタバのない地域だってあるんですよ!
- ↑サーセン
- ↑スタバのない地域だってあるんですよ!
- docomoの電波がないところで接続
- ↑そんな地域あるんかな
- ↑あるんだなこれが
- ↑出張で行かされた(泣)
- ↑サーセン
- ↑出張で行かされた(泣)
- ↑あるんだなこれが
- ↑docomoがないならWi-Fi使えばいいじゃない
- ↑だからRaspberry PiはWi-Fi無モデルのが多い
- ↑つことはUSBドングルだけでネットに繋がるの? ステキやん
- ↑だからRaspberry PiはWi-Fi無モデルのが多い
- ↑そんな地域あるんかな
- USB挿したら音が出る
- ↑スピーカーさえあれば
- ピ↑ボ↓
- ↑おっさん乙
- ピ↑ボ↓
- ↑スピーカーさえあれば
- Raspberry PiでモバイルHTTPサーバ
- ↑3G SIMで払い出されるIPがプライベートIPだったり
- ↑RasPiから外部ホストへトンネル掘れているってことは、あとはわかるよな?
- ↑その外部ホストとやらでHTTPサービスしたほうが早いのでは?
- ↑RasPiから外部ホストへトンネル掘れているってことは、あとはわかるよな?
- ↑3G SIMで払い出されるIPがプライベートIPだったり
ていうかんじです。
動作確認は?
今回のテストにあたり、
- Raspberry Pi A+ 256MB
- Raspberry Pi A+ 512MB
- Raspberry Pi Zero カメラ端子なし版
- Raspberry Pi Zero カメラ端子あり版
- Raspberry Pi 3 B+
にNOOBSでインストールした Raspbian Jessie(2016-05-27)で動作確認をしております。
必要3G-USBモデム・3G SIM
- 3G-USBモデムは ABIT AK-020(¥6000)
- 3G SIM は ロケットモバイル神プラン(¥298/月)
を使います。
3G SIMに関しては、自分が調達できるものに合わせて適宜読み替えてください。
Raspberry Piのシステムファイルには、機材固有の設定をします。今回はロケットモバイル/AK-020専用設定となります。
つくるまえに
- 本稿では、Raspberry Piがインターネットに接続可能になっている状態からセットアップしていきますので、Raspberry PiにRaspbian Jessieをセットアップする作業、Raspberry Pi を有線もしくはWi-Fiでインターネットにつなぐ作業は予め完了しておいてください。
- 説明の際、
pi@raspberrypi:~ $
と書いている場所は、コンソールが表示するプロンプトですので、入力しないでください。 -
RaspberryPiのコンソールへコピペ
と書いているところは、ブラウザ上でクリップボードにコピーしておいて、コンソール上にペーストするとファイルが生成されたりコマンドが実行されるようになっています。最後の行は改行がコピーできていないので、自分でEnterキーを入れてあげてください。
設定
実際に操作を順番に追って設定していきます。
① Raspbianにpiユーザでログイン
以下の方法のいずれかで、Raspberry Piへコンソールアクセスします。
- Raspberry PiのGUIで、
LXTerminal
を起動 - Raspberry PiをDHCP制御下の有線LANにつないで、他のホストからSSH接続して
pi
ユーザーでログイン - Raspberry PiでWi-Fiを使えるようにして、無線LANのネットワークに参加させ、ネットワーク内の他のホストからSSH接続して
pi
ユーザーでログイン - Raspberry PiのGPIOに出ているUARTにシリアル接続
② 3G-USBモデム AK-020を挿入した時のLinuxの挙動を調整
先人達の努力により、
- 3G-USBモデムを接続すると最初はCDとして認識され、
Eject
すると本来の通信デバイスとして認識される - Linux側でUSBの認識制御をする
usb_modeswitch
があって、特定のUSBデバイスが認識されたらeject
するまでできちゃう -
udev
により、デバイスの認識とそれに対するふるまいを設定できる -
Systemd
と統合されているためデバイスの認識に合わせて、Systemd
へメッセージを送ることができる
ということがわかっています。
今回使用する3G-USBモデム、AK-020用の特別設定を準備します。
cat << 'EOS' | sudo tee /etc/udev/rules.d/40-ak-020.rules
ACTION=="add",\
ATTRS{idVendor}=="15eb",\
ATTRS{idProduct}=="a403",\
RUN+="/usr/sbin/usb_modeswitch --std-eject --default-vendor 0x15eb --default-product 0xa403 --target-vendor 0x15eb --target-product 0x7d0e"
ACTION=="add",\
ATTRS{idVendor}=="15eb",\
ATTRS{idProduct}=="7d0e",\
RUN+="/sbin/modprobe usbserial vendor=0x15eb product=0x7d0e"
ATTRS{../idVendor}=="15eb",\
ATTRS{../idProduct}=="7d0e",\
ATTRS{bNumEndpoints}=="03",\
ATTRS{bInterfaceNumber}=="02",\
SYMLINK+="ttyAK020",\
ENV{SYSTEMD_WANTS}+="ifup@wwan0.service"
EOS
sudo reboot
これで、Raspberry PiのUSBポートにAK-020を差し込むと、
- 最初に認識されるCD-ROMデバイスが自動でマウント解除され、
- 次に認識されるUSBシリアルデバイスにドライバをあてがい、
- USBシリアルデバイスを
/dev/ttyAK020
にリンクします。 - あと、(あれば)ネットワークインタフェース
wwan0
をupします。
実際にAK-020をRaspberry Piにつなぐ前と、つないだ後で比較してみます。
$ ls /dev/tty*
/dev/tty /dev/tty21 /dev/tty35 /dev/tty49 /dev/tty62
/dev/tty0 /dev/tty22 /dev/tty36 /dev/tty5 /dev/tty63
/dev/tty1 /dev/tty23 /dev/tty37 /dev/tty50 /dev/tty7
/dev/tty10 /dev/tty24 /dev/tty38 /dev/tty51 /dev/tty8
/dev/tty11 /dev/tty25 /dev/tty39 /dev/tty52 /dev/tty9
/dev/tty12 /dev/tty26 /dev/tty4 /dev/tty53 /dev/ttyAMA0
/dev/tty13 /dev/tty27 /dev/tty40 /dev/tty54 /dev/ttyS0
/dev/tty14 /dev/tty28 /dev/tty41 /dev/tty55 /dev/ttyprintk
/dev/tty15 /dev/tty29 /dev/tty42 /dev/tty56
/dev/tty16 /dev/tty3 /dev/tty43 /dev/tty57
/dev/tty17 /dev/tty30 /dev/tty44 /dev/tty58
/dev/tty18 /dev/tty31 /dev/tty45 /dev/tty59
/dev/tty19 /dev/tty32 /dev/tty46 /dev/tty6
/dev/tty2 /dev/tty33 /dev/tty47 /dev/tty60
/dev/tty20 /dev/tty34 /dev/tty48 /dev/tty61
$ ls /dev/tty*
/dev/tty /dev/tty21 /dev/tty35 /dev/tty49 /dev/tty62
/dev/tty0 /dev/tty22 /dev/tty36 /dev/tty5 /dev/tty63
/dev/tty1 /dev/tty23 /dev/tty37 /dev/tty50 /dev/tty7
/dev/tty10 /dev/tty24 /dev/tty38 /dev/tty51 /dev/tty8
/dev/tty11 /dev/tty25 /dev/tty39 /dev/tty52 /dev/tty9
/dev/tty12 /dev/tty26 /dev/tty4 /dev/tty53 /dev/ttyAK020
/dev/tty13 /dev/tty27 /dev/tty40 /dev/tty54 /dev/ttyAMA0
/dev/tty14 /dev/tty28 /dev/tty41 /dev/tty55 /dev/ttyS0
/dev/tty15 /dev/tty29 /dev/tty42 /dev/tty56 /dev/ttyUSB0
/dev/tty16 /dev/tty3 /dev/tty43 /dev/tty57 /dev/ttyUSB1
/dev/tty17 /dev/tty30 /dev/tty44 /dev/tty58 /dev/ttyUSB2
/dev/tty18 /dev/tty31 /dev/tty45 /dev/tty59 /dev/ttyUSB3
/dev/tty19 /dev/tty32 /dev/tty46 /dev/tty6 /dev/ttyprintk
/dev/tty2 /dev/tty33 /dev/tty47 /dev/tty60
/dev/tty20 /dev/tty34 /dev/tty48 /dev/tty61
後の工程で使うため、AK-020は接続したままにしておきます。
③ USB-3GモデムにAPN設定を入れる
今回利用したUSB-3Gモデム・AK-020は実質APN設定をUSB-3Gモデムに記憶させておく必要が無いです。なのでこの工程飛ばす
④ RaspbianにPPP設定を作る
ppp 設定用対話型プログラムの pppconfig
をインストール。
sudo apt-get -y install pppconfig
pppconfig
を起動する。これは、ロケットモバイルとAK-020用の接続設定となります。
sudo pppconfig rokemoba_ak-020
以下の設定を順番に設定する。モーダルインタフェースとなっているから、1項目ごとに入力していくので注意。
Configure Nameservers(DNS):Dynamic
Authentication Method:PAP
User Name:roke@moba
Password:rokemoba
Speed:460800
Pulse or Tone:Tone
Phone Number:*99#
Choose Modem Config Method:No
Manually Select Modem Port:/dev/ttyAK020
Finishedで設定ファイルの書き出しを行い、そのあと、Quitして終了。
Authentication Method(認証メソッド)ですが、pppconfig 2.3.18
のバージョンには、認証メソッドに CHAP
を選んでも、パスワードが /etc/ppp/chap-secrets
に記録されない不具合があるので1、認証メソッドを PAP
にします。
PPP接続時、デフォルトルートをPPP側に置き換える設定
-
persist
:接続維持 -
replacedefaultroute
:PPP接続時にデフォルトルートを自動で置き換える設定。
実質的にこれによって3Gモデムでインターネット接続ができることになる。
cat << EOS | sudo tee -a /etc/ppp/peers/rokemoba_ak-020
persist
replacedefaultroute
EOS
書き換え後は以下のようになります。
# This optionfile was generated by pppconfig 2.3.18.
#
#
hide-password
noauth
connect "/usr/sbin/chat -v -f /etc/chatscripts/rokemoba_ak-020"
debug
/dev/ttyAK020
460800
defaultroute
noipdefault
user "roke@moba"
remotename rokemoba_ak-020
ipparam rokemoba_ak-020
usepeerdns
persist
replacedefaultroute
APN設定・PPP接続用チャットスクリプトの修正
PPP接続時に、モデムとコマンドシーケンスを送受信しますが、それの制御をするチャットスクリプトを調整します。
3G SIMのAPNの設定もこちらになります。
sudo sed -i -e "s/'' ATZ/'' ATH\n\
OK AT+CFUN=1\n\
OK ATZ\n\
OK 'ATQ0 V1 E1 S0=0 \&C1 \&D2'\n\
OK AT+CGDCONT=1,\"IP\",\"4gn.jp\"\
/" /etc/chatscripts/rokemoba_ak-020
書き換え後は以下のようになります。
# 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
'' ATH
OK AT+CFUN=1
OK ATZ
OK 'ATQ0 V1 E1 S0=0 &C1 &D2'
OK AT+CGDCONT=1,"IP","4gn.jp"
# ispnumber
OK-AT-OK "ATDT*99#"
# ispconnect
CONNECT \d\c
# prelogin
# ispname
# isppassword
# postlogin
# end of pppconfig stuff
⑤ PPP接続テスト
AK-020は接続したままにしてありますので、この状態でPPP接続のテストをします。
sudo pon rokemoba_ak-020
AK-020のランプが、接続後待機状態の緑点灯⇒赤点灯⇒緑点滅(2Hz)になると、PPP接続完了です。
curl inet-ip.info
で、ロケットモバイル(nuro)のホストIPが割りあげられていることを確認してください。
pi@raspberrypi:~ $ curl inet-ip.info
118.241.248.164
pi@raspberrypi:~ $ host `curl inet-ip.info`
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 16 100 16 0 0 9 0 0:00:01 0:00:01 --:--:-- 9
164.248.241.118.in-addr.arpa domain name pointer mp76f1f8a4.ap.nuro.jp.
pi@raspberrypi:~ $
確認が終わったら、PPP接続を切断します。
sudo poff rokemoba_ak-020
3G-USBモデムのランプの緑点滅が、緑点灯になり、PPP接続が終了しました。
⑥ PPP接続用ネットワークインタフェースを作る
電源投入後、または3G-USBモデムをUSBポートに挿したタイミングで自動でPPP接続したいので、設定を作ります。
Raspberry Piに仮想のネットワークインタフェース wwan0
を用意し、PPP接続と紐づけます。
cat << 'EOS' | sudo tee -a /etc/network/interfaces
allow-hotplug wwan0
iface wwan0 inet ppp
provider rokemoba_ak-020
EOS
書き換え後は以下の通り。
# interfaces(5) file used by ifup(8) and ifdown(8)
# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
auto lo
iface lo inet loopback
iface eth0 inet manual
allow-hotplug wlan0
iface wlan0 inet manual
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
allow-hotplug wlan1
iface wlan1 inet manual
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
allow-hotplug wwan0
iface wwan0 inet ppp
provider rokemoba_ak-020
なお、Raspbian Jessieの Systemd
では、/etc/network/interface
に書かれたネットワークインタフェースは Systemd
における .service
タイプの Unit として認識されるようです。
⑦ ネットワークインタフェースのリンクアップテスト
ネットワークインタフェースがシステム上にブリングアップしてきたときにちゃんとPPP接続ができるかテストをしていきます。ケースは3通りです。
- 手動でネットワークインタフェースを
ifup
してみる - 3G-USBモデムをUSBポートに挿入してみる
- 3G-USBモデムをUSBポートに挿入したままRaspberry Piを再起動してみる
手動でネットワークインタフェースをifup/ifdownして接続テスト
wwan0
ネットワークインタフェースを ifup
することで、PPP接続が開始します。
sudo ifup wwan0
3G-USBモデムの緑ランプが2Hz点滅するとPPP接続済み。
wwan0
ネットワークインタフェースを ifdown
することで、PPP接続が終了します。
sudo ifdown wwan0
3G-USBモデムの緑ランプが点灯(待機状態)に切り替わります。
3G-USBモデムをUSBポートに挿入してリンクアップするかテスト
まだ3G-USBモデムがUSBポートに刺さったままだと思いますので、いったん抜きます。2
少し待ってから(10秒くらい)、もう一度USBポートに挿してみると、数十秒から2分ぐらいまでの間で自動で接続開始します(3G-USBモデムの緑ランプが2Hz点滅するとPPP接続済み)。
Raspberry Piを再起動して自動でリンクアップするかテスト
3G-USBモデムをUSBポートに挿した状態のままにして、Raspberry Piを再起動します。
sudo reboot
Raspberry Piブートアップの途中で、3G-USBモデムがリンクアップするはずです。
おめでとう! 君のRaspberry Piは3G回線という翼を得たのだ!
⑧ 一巻の終わり
PPP接続開始の時点で、デフォルトゲートウェイが3G側に切り替わり、Raspberry Piから外に出る接続は3G経由となりますが、3G SIMに割り当てられるIPアドレスがプライベートIPアドレスだったりします。
ということは、Raspberry Piの内部から外のインターネット側へは通信できますが、インターネット側からRaspberry Piの内部には入って行けません。そのような必要があるのなら、せっかくのLinuxなのですから、Raspbery PiからどこかのVPSなど自分所有ホストへSSHトンネルを掘るなどするとよいですね。
おまけ
この仕組み、なんに使おうかなー
Raspberry Piから外部ホストへSSHトンネルを掘る
3G-USBモデムだけが刺さったRaspberry Piに、別ホストからリモートログインできるようにするため、Raspberry Piから、3G-USBモデムを通じインターネット上のほかのホストにSSH接続し、トンネルを掘ります。
遠隔地に置きっぱなしのRaspberry Piがあったとして、そのRaspberry Piが遠隔地から手元のホストにトンネルを自力で掘ってくれるので、自分が遠隔地に行かなくともRaspberry Pi側から掘られ済みのトンネルを通じてリモートログインできるのはとっても便利なような気がします。
見方を変えると、インターネットからRaspberry Piに入れるようになるUSBドングル、とも言えますね。
sudo apt-get -y install autossh
cat << "EOS" | sudo tee /etc/ppp/ip-up.d/10ssh-tunnel
#!/bin/sh
# This script is called with the following arguments:
# Arg Name Example
# $1 Interface name ppp0
# $2 The tty /dev/ttyS1
# $3 The link speed 38400
# $4 Local IP number 12.34.56.78
# $5 Peer IP number 12.34.56.99
# $6 Optional ``ipparam'' value foo
if [ "$2" = "/dev/ttyL05A" \
-o "$2" = "/dev/ttyAK020" \
]; then
# ppp0 の txqueuelen が 3 なので、大きくする
/sbin/ifconfig $1 txqueuelen 128
# root権限で動いているため、ほかのユーザで実行したい場合は
# su <user> -c "echo hoge" 的なことをする
#
# autossh でトンネルを掘る場合は、トンネルの出口の sshd の
# 設定で、ClientAliveInterval 10/ ClientAliveCountMax 3
# などの 回線が死んだらsshも自然に死ぬようにしておく必要が
# あります(送り側のautosshでsshのセッションを張りなおしても、
# 受け側の古いsshdが死なずに居座るとListen出来ないので)。
su pi -c \
'/usr/bin/autossh \
-N -f -M 0 \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=3 \
-o ExitOnForwardFailure=yes \
-o StrictHostKeyChecking=no \
-R 10022:localhost:22 \
-i /home/pi/.ssh/id_rsa \
-l remotehostuser \
example.com'
fi
exit
EOS
sudo chmod 755 /etc/ppp/ip-up.d/10ssh-tunnel
/etc/ppp/ip-up.d/
の中に実行権限をつけたスクリプトを置いておくと、PPPで接続確立後に実行されますので、 autossh
によるSSHトンネルを掘る例です。
これをすると、3G電波だけでインターネットにつながっている Raspberry Pi
に外部ホストからリモートログインが実現できます。
slogin pi@localhost -p 10022 -o StrictHostKeyChecking=no
応用
GPSを搭載して、node.js
を使って AWS IoT
に JSON
をPubして、 DynamoDB
に現在位置をダダ記録するのはどうでしょう。
参考文献
- Raspberry Pi A+ (Raspbian wheezy) でAK-020を使ってSORACOMに自動接続する - Qiita
- Raspberry PiでUSBモデム挿入時にSORACOMへ自動接続する - Qiita
- Rasoberry Pi + SORACOM Air SIM ( L-02C , AK-020 ) の wvdial.conf 設定情報 - Qiita
- AK-020 を Raspbian で使う(とりあえず版) - Qiita
- Raspberry PI+docomo L-05A+SORACOM AirでUSBモデム自動起動 - Qiita
- L-02C でインターネット接続する方法: Linuxist の Debian-Ubuntu 拾い食い日記
脚注
-
なお、PPP接続のための別のパッケージ
wvdial
でCHAP
認証で設定すると、正しく/etc/ppp/chap-secrets
にパスワードが設定されるため、以降CHAP
で設定していたpppconfig
で作った接続設定でもつながるようになります。Raspbianでの接続例はwvdial
での例ばかりなのはおそらくこれのせい。 ↩ -
3G-USBモデムが通信中に、いきなりUSBポートから抜いても、PPP接続は正常にクローズ・終了処理されますが、通信路が急になくなるので、アプリケーションレベルで不具合が出ることがあります(TCP通信であれば、FINパケットなしで通信が途絶するので通信路クローズのタイミングは実装と設定による)。 ↩