第4章 IoTを体験しよう

Armadillo-IoTを使い、データをクラウド上のサーバーにアップロードするサンプルアプリケーションを動かし、IoTの基本部分を体験してみましょう。

4.1. サンプルアプリケーションの概要

サンプルアプリケーションは、Armadillo-IoT上で動作するクライアントサイドアプリケーションとクラウドプラットフォーム上で動作するサーバーサイドWebアプリケーションの2つのアプリケーションから構成されています。サンプルアプリケーションは、Armadillo-IoT(クライアント)からデータをサーバーにアップロードする機能と、サーバーからクライアントに対して操作指示(Push通知)を行う機能の二つを備えています。

クライアントからサーバーへのデータアップロードの例として、Armadillo-IoTが本体の状態監視用に内蔵している温度センサの値をアップロードします[7]。また、サーバーからのPush通知の例として、ブラウザに表示されたボタンをクリックすると、その状態(ONまたはOFF)をArmadillo-IoTに通知します。

クライアントサイドアプリケーションは、Rubyのコンソール(CLI)アプリケーションとして実装されています。実装を簡単にするために、Ruby用ライブラリの一般的な配布形式である、gem[8]をいくつか使用しています。データのアップロードはREST API(HTTP POST)で行うため、rest-clientを使用します。また、サーバーからのPush通知にはPusher[9]を使用しているため、pusher-clientを使用します。

サーバーサイドWebアプリケーションは、クラウドアプリケーション開発プラットフォームのHeroku上で動作しています。Node.jsで実装されており、クライアントサイドアプリケーションからのデータを受信するとデータベース(PostgreSQL)に格納します。格納したデータは、Webブラウザからリアルタイムに変化を確認できるようになっています。また、ブラウザ上に表示されたボタンをクリックすると、それがクライアント(Armadillo-IoT)への操作指示として、Push通知されるようになっています。

サンプルアプリケーションの構成

図4.1 サンプルアプリケーションの構成


[ティップ]REST API

REST(REpresentational State Transfer)は、WebアプリケーションのAPIに関するアーキテクチャスタイル(設計思想)の一つです。

ネットワーク上のリソースに対し一意のURIを割り当て、リソースに対する操作をHTTP GET(取得)/POST(新規作成)/PUT(更新)/DELETE(削除)で行います。RESTの原則に従いAPIを設計すると、クライアントからのリクエストをステートレスにできるため、サーバー側の実装をスケールアウトしやすいと言われています。サンプルアプリケーションでは、時々刻々と変化する温度センサデータのアップロードは、常にリソース(温度データの時系列情報)の新規作成となるためHTTP POSTで行っています。

なお、厳密にはREST原則に従っていないAPIもREST APIと称することが多くなっているため、原則に忠実に従って設計されたAPIのことを、RESTful APIということもあります。

[ティップ]Heroku

Heroku(ヘロク)は、Webアプリケーションの開発、公開が簡単に行えるクラウド上のプラットフォームです。

一昔前のWebアプリケーション開発現場では、まず開発環境にLinuxやApache、MySQL、PHP(LAMP)をインストールして開発を行い、開発がうまくいったら公開用のサーバーを購入するなり、レンタルサーバーを借りるなりして、また色々インストールして、一般公開するためにドメインを購入して、というようにアプリケーションの実装以外に多くの付随する作業が必要でした。

Herokuを使うと、1. Herokuアカウントを作成する、2. アプリケーションを実装する(アプリケーションの実行に必要なサーバーやデータベースの設定は、Herokuのツールが面倒を見てくれるので、開発者は何を使うか指定するだけです)、3. サーバーに「push」する、という単純なステップで、アプリケーションを一般公開できます。また、サーバーで使用するCPUの数やメモリサイズ、データベース容量を動的に変更できるなど、急にアクセスが増えた場合でも、簡単にスケールアウトできるような仕掛けがなされています。

また、Webアプリケーションを開発する際に必要となる様々な機能が「アドオン」として用意されており、それらを活用することで、アプリケーションの本質的な部分に開発リソースを集中することができます。サンプルアプリケーションでは、データベースとしてPostgreSQLを、Push通知を行うためにPusherのアドオンを使用しています。

課金体系としてフリーミアムモデルを採用しており、一定時間までは無料で使用することができます。このことも、利用の敷居を下げる一因になっています。サンプルプログラムも無料枠の範囲内で運用しています。

[ティップ]Node.js

Node.jsは、javascriptで構成されたサーバーサイドアプリケーションの開発フレームワークです。わざわざサーバーサイドと謳っているのは、Node.js登場以前は、javascriptはクライアント(ここではWebブラウザのことを意味します)上で動作するプログラムに使用することが一般的であったためです。

Node.jsが登場した背景には、10,000台のクライアントが一斉にWebアプリケーションにアクセスすると急激に性能が劣化する、いわゆるC10K問題と呼ばれる課題がありました。これは、それまでのWebアプリケーション開発フレームワークが、クライアントからのリクエストがあるたびに、プロセス(ないしはスレッド)を生成する構成になっていたため、接続が重複すると、サーバーのメモリを使い切ってしまう事が一因です[10]

Node.jsでは、非同期I/Oを活用し一つのプロセスで全てのリクエストを処理することで、この課題の解決を試みています。Webアプリケーションのサーバーサイドロジックが単純な場合、サーバーサイドアプリケーションはほとんどの時間、I/O待ちをしていることになります(CPU boundではなく、I/O boundな状態)。非同期I/Oを使うと、その間も他の処理ができるため、一つのプロセスで複数のリクエストを捌くことができるようになります。

例えば、APIをRESTfulにしておくと、HTTP POST(新規作成)リクエストは、クライアントから受けとったデータを(ほとんど何も処理せずに)DBに書き込むだけになり、HTTP GET(取得)はDBからデータを取得してレスポンスを返すだけになるため、I/O boundな状態となります。このようなアプリケーションの場合、Node.jsのアプローチは非常にうまくスケールします。サンプルアプリケーションはまさにこのような状況なため、Node.jsを使って実装しています。

反対に、Node.jsでは数値計算などが必要でCPU処理が長くなるアプリケーションには適しません。また、非同期I/Oを活用することで、必然的にイベント駆動型のプログラミングスタイルが強制されるため、複雑なロジックが必要なアプリケーションでは、それに応じてコードも複雑化しがちです。どのようなアプリケーションにも適しているわけではない点には注意が必要です。

4.1.1. サンプルアプリケーションのAPI

クライアントから https://armadillo-iot-sample.herokuapp.com/api/series というURIに対して、下記の内容でHTTP POSTリクエストを発行すると、データが格納されます。

表4.1 POST時のQUERYパラメータ

パラメータ名
uidUIDcharacter varing(制限付き可変長文字列) 255文字
latitude緯度double precision(8byte 浮動小数点)
longitude経度double precision(8byte 浮動小数点)
value摂氏温度real(4byte 浮動小数点)
created_at温度取得時刻timestamp without time zone(日付と時刻両方、時間帯なし)
tokenトークンID("12345")文字列

uidは、重複しない値であれば何でも構いません。クライアントサイドサンプルアプリケーションでは、MACアドレスから「:」を抜いた文字列を使用します。サンプルアプリケーションは、実装の簡単な例を示すことを目的としているため、誰でもデータをアップロードし、閲覧することができます。tokenは、Armadillo-IoTのことを全く知らない人が、簡単にデータをアップロードできないようするための簡易的な仕掛けとして使用します。

データアップロードは単純なHTTP POSTリクエストですので、例えばcurlコマンドを使用し、下記のように実行することでも、データをアップロードすることができます[11]。自分でクライアントアプリを実装する際の参考としてください。

[armadillo ~]# curl -d "uid=00110cxxxxxx&latitude=35.681382&longitude=139.766084&value=25.00&created_at=$(date "+%Y-%m-%d %H:%M:%S")&token=12345" http://armadillo-iot-sample.herokuapp.com/api/series

図4.2 curlを利用してPOSTする例


サーバーからのPush通知は、下記のパラメータで行われます。

表4.2 Push通知パラメータ

パラメータ名
チャンネル文字列UID
イベント文字列"button"
データJSON文字列{"value": "on"} か {"value": "off"}

4.2. 電源投入から起動まで

Armadillo-IoTに電源を投入する前に、USBシリアル変換アダプタのスライドスイッチを次のように外側になるようにしてください。[12]

スライドスイッチの設定

図4.3 スライドスイッチの設定


Armadillo-IoTに電源を接続すると、シリアル通信ソフトウェアには次のように表示されます。

Hermit-At v3.5.0 (armadillo-iotg-std) compiled at 20:38:28, Jun 12 2015
hermit> 

図4.4 電源を投入直後のログ


Linuxシステムを起動するには、次のように "boot"コマンドを実行してください。コマンドを実行するとブートローダーがLinuxシステムを起動させます。シリアル通信ソフトウェアにはLinuxの起動ログが表示されます。

Hermit-At v3.5.0 (armadillo-iotg-std) compiled at 20:38:28, Jun 12 2015
hermit> boot
Uncompressing  kernel.....................................................done.
Uncompressing ramdisk..........................................................
..........................................................................done.
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpu
Initializing cgroup subsys cpuacct
Linux version 3.14-at1 (atmark@atde5) (gcc version 4.6.3 (Debian4.6.3-14atmark1)
 ) #1 PREEMPT Sat Jun 13 10:48:43 JST 2015
CPU: ARM926EJ-S [41069264] revision 4 (ARMv5TEJ), cr=00053177
CPU: VIVT data cache, VIVT instruction cache
Machine: Armadillo-410
    :
    : (割愛)
    :
atmark-dist v1.41.0 (AtmarkTechno/Armadillo-IoTG-Std)
Linux 3.14-at1 [armv5tejl arch]

armadillo-iotg login:

図4.5 bootコマンドでLinuxを起動


[注記]

Linuxシステムの起動後に表示される次のメッセージは、エラーメッセージではありません。

random: nonblocking pool is initialized

このメッセージは、/dev/urandomが内部的に使用するプール領域の初期化完了を示します。

ここでは、rootユーザーでログインします。デフォルトのパスワードは、"root"となっています。

atmark-dist v1.41.0 (AtmarkTechno/Armadillo-IoTG-Std)
Linux 3.14-at1 [armv5tejl arch]

armadillo-iotg login: root
Password:
[root@armadillo-iotg (ttymxc1) ~]# 

図4.6 rootユーザーでログイン


4.3. 初期設定

クライアントサイドサンプルアプリケーションを動作させるためには、次の項目を設定する必要があります。

  • ネットワーク

  • 時刻

4.3.1. ネットワークを設定する

Armadillo-IoTは、WAN用インターフェースとして、LAN、無線LAN、及びモバイル通信(3G)を備えています。ここでは、LANを使ってネットワークに接続する設定方法について説明します。無線LAN、3Gの設定方法や、LANの設定方法の詳細については、製品マニュアルを参照してください。

4.3.1.1. LANを設定する

Armadillo-IoTでは、通常のLinuxシステムと同様、ネットワークインターフェースの設定は/etc/network/interfacesに記述します。Armadillo-IoTの出荷時の設定では、eth0(LANのネットワークインターフェース)が自動でupし、DHCPでネットワーク設定を取得するようになっています。

# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)

auto lo eth0
iface lo inet loopback
iface eth0 inet dhcp
iface umts0 inet dhcp
        pre-up 3g-connect
        post-down 3g-disconnect
    

図4.7 出荷状態のネットワーク設定


[ティップ]

出荷時期によっては下記のように3g-monitorの記述がある場合があります。

# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)

auto lo eth0
iface lo inet loopback
iface eth0 inet dhcp
iface umts0 inet dhcp
        pre-up 3g-connect
        post-up 3g-monitor start
        pre-down 3g-monitor stop
        post-down 3g-disconnect
    

また、v20160527より古いユーザーランドイメージを使用している場合は、3Gインタフェース切断検知と再接続を行うスクリプト(3g-recover)が追加されていないため、 3g-monitorの行は消さないでください。

もし、固定IPに設定したい場合など、ネットワーク設定を変更したい場合、一度ネットワークインターフェースをdownしてから、設定を変更してください。

[armadillo ~]# ifdown eth0
[armadillo ~]# vi /etc/network/interfaces

図4.8 ネットワークインターフェースをdownし設定を変更する


固定IP(IPアドレス: 192.0.2.100、デフォルトゲートウェイ: 192.0.2.1、サブネットマスク: 255.255.255.0)に設定する場合の記述例を下記に示します。

# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)

auto lo eth0
iface lo inet loopback
iface eth0 inet static
netmask 255.255.255.0
gateway 192.0.2.1
address 192.0.2.100
iface umts0 inet dhcp
        pre-up 3g-connect
        post-down 3g-disconnect
    

図4.9 固定IPの設定例


変更した設定は、ifupコマンドで反映されます。

[armadillo ~]# ifup eth0

図4.10 ネットワークインターフェースをupし設定変更を反映する


DNSサーバーの指定は/etc/resolv.confに記述します。DNSサーバーのIPアドレスを192.0.2.2に設定する場合の記述例を下記に示します。

nameserver 192.0.2.2

図4.11 DNSサーバーの設定例


[ティップ]

DHCP を利用している場合には、DHCP サーバーが DNS サーバーを通知する場合があります。この場合、/etc/resolv.confは自動的に更新されます。

なお、この設定は再起動すると消えてしまいます 。これに限らず、Armadillo-IoTではルートファイルシステムのファイルに加えた変更は再起動すると全て元通りとなります。これは、Armadillo-IoTのユーザーランドがRAMDISK上にあるためです。これは、再起動すると必ず同じ状態で起動するという意味で組み込み機器としては必要な機能なのですが、毎回起動するたびに設定するのも面倒です。そのため、設定ファイル類だけはフラッシュメモリに永続的に保存できるようになっています。

それを行うためのコマンドが、flatfsdです。flatfsd -s-sオプションを付けて実行することで、/etc/configディレクトリにあるファイルを、フラッシュメモリに保存します。実は/etc/network/interfaces/etc/resolv.confは、/etc/config以下のファイルへのシンボリックリンクとなっています。そのため、/etc/network/interfacesなどに対して行った変更は、flatfsd -sコマンドを実行することで、フラッシュメモリに保存されます。保存されたファイルは起動時に自動で復元されるようになっているため、次回起動時は変更したネットワーク設定が行われるようになります。変更を消したくない場合は、flatfsd -sコマンドを実行することを忘れないでください。

4.3.2. 時刻を設定する

サンプルアプリケーションで使用するデータの取得時刻には、クライアント側のシステムタイムを利用します。時刻が大幅にずれている場合には混乱を招く場合があるため、時刻を設定します。

ここでは、NTPクライアントを利用してシステムタイムをタイムサーバー[13]と同期させます。ntpclientコマンドで時刻を設定し、dateコマンドで時刻が設定されたことを確認してください。

[armadillo ~]# ntpclient -h ntp.nict.jp -s
[armadillo ~]# date
Tue Jun 2 12:34:57 JST 2015

図4.12 ntpclientを利用した時刻の設定


[注記]起動時に自動で時刻設定を行う

時刻設定のように起動するたびに毎回行う操作は、起動時に自動で行うように設定できます。Armadillo-IoTでは、/etc/config/rc.localがinitスクリプトの最後に実行されるようになっていますので、これを編集しntpclientコマンドを実行するように記述することで、起動時に自動で時刻設定されるようになります。

/etc/config/rc.localファイルに対する変更も、そのままでは再起動すると消えてしまいますのでflatfsd -sコマンドでフラッシュメモリに保存するのを忘れないでください。

[armadillo ~]# echo "ntpclient -h ntp.nict.jp -s" >> /etc/config/rc.local
[armadillo ~]# flatfsd -s

図4.13 起動時に自動で時刻設定を行う


[注記]時刻の保持

Armadillo-IoTでは、システムタイムをリアルタイムクロック(カレンダー時計)に保持することができます。リアルタイムクロックのバックアップ用電池を取り付けることで、電源を切っても時刻を保持し続けるようになります。この場合、起動するたびに時刻設定をする必要は無くなります。詳しくは、製品マニュアルを参照してください。

4.4. サンプルアプリケーションの実行

クライアントサイドサンプルアプリケーションを実行すると、デフォルトで設定されたURIに対してデータをアップロードし、サーバーからのPush通知に応じてコマンドを実行します。表4.1「POST時のQUERYパラメータ」で示したQUERYパラメータのうち、「latitude」、「longitude」については、東京周辺を指すようにランダムに生成されます。

クライアントサイドのサンプルアプリケーションと設定ファイルは、それぞれ http://armadillo-iot-sample.herokuapp.com/client/sample.rb と http://armadillo-iot-sample.herokuapp.com/client/config.json から取得します。

[armadillo ~]# curl -kO https://armadillo-iot-sample.herokuapp.com/client/sample.rb
[armadillo ~]# curl -kO https://armadillo-iot-sample.herokuapp.com/client/config.json
[armadillo ~]# ruby sample.rb --config config.json
I, [2015-06-03T12:29:56.164923 #1108]  INFO -- : uid: 00110cxxxxxx
I, [2015-06-03T12:29:56.167375 #1108]  INFO -- : top page: http://armadillo-iot-sample.herokuapp.com
I, [2015-06-03T12:29:56.168886 #1108]  INFO -- : personal page: http://armadillo-iot-sample.herokuapp.com/cockpit?uid=00110cxxxxxx
I, [2015-06-03T12:29:56.170631 #1108]  INFO -- : Searching GPS...
I, [2015-06-03T12:30:01.224029 #1108]  INFO -- : 0: 2015-06-03 12:30:01
I, [2015-06-03T12:30:06.736723 #1108]  INFO -- : 1: 2015-06-03 12:30:06
I, [2015-06-03T12:30:12.169770 #1108]  INFO -- : 2: 2015-06-03 12:30:12
I, [2015-06-03T12:30:17.612970 #1108]  INFO -- : 3: 2015-06-03 12:30:17
I, [2015-06-03T12:30:23.085313 #1108]  INFO -- : 4: 2015-06-03 12:30:23
I, [2015-06-03T12:30:28.519343 #1108]  INFO -- : 5: 2015-06-03 12:30:28
I, [2015-06-03T12:30:33.959218 #1108]  INFO -- : 6: 2015-06-03 12:30:33
I, [2015-06-03T12:30:39.420082 #1108]  INFO -- : 7: 2015-06-03 12:30:39
I, [2015-06-03T12:30:44.860059 #1108]  INFO -- : 8: 2015-06-03 12:30:44
I, [2015-06-03T12:30:50.329457 #1108]  INFO -- : 9: 2015-06-03 12:30:50

図4.14 サンプルアプリケーション実行例


デフォルトでは、5秒間隔で10回データ送信を行います。--intervalオプションを指定することで送信間隔を、--timesオプションを指定することで送信回数を指定できます。(-1を指定すると、無制限にデータをアップロードし続けます。)

[armadillo ~]# ruby sample.rb --config config.json --interval 1 --times 5

図4.15 オプションの指定例(1秒間隔で5回送信)


その他のオプションについては、helpを参照してください。

[armadillo ~]# ruby sample.rb --help
Usage: iotg_sample [options]
    -p, --config=path                Config file path (default: config.json)
    -d, --debug                      Enable debug message
    -t, --times=TIMES                Number of repeat times, -1 means infinite loop (default: 10)
    -i, --interval=INTERVAL          Interval between sending a message (default: 5[sec])
    -c, --command=COMMAND            Command which execute push notification (default: echo $value)

図4.16 サンプルアプリケーションのhelp


4.5. Webブラウザでデータを確認

アップロードしたデータが反映されているか、Webブラウザで確認してみましょう。確認用URLは、クライアントサイドサンプルアプリケーション実行時のログに表示されています。

[armadillo ~]# ruby sample.rb --config config.json
I, [2015-06-03T12:29:56.164923 #1108]  INFO -- : uid: 00110cxxxxxx
I, [2015-06-03T12:29:56.167375 #1108]  INFO -- : top page: http://armadillo-iot-sample.herokuapp.com
I, [2015-06-03T12:29:56.168886 #1108]  INFO -- : personal page: http://armadillo-iot-sample.herokuapp.com/cockpit?uid=00110cxxxxxx

図4.17 サンプルアプリケーション実行例(確認用URL)


「personal page」と表示されている行のURL (http://armadillo-iot-sample.herokuapp.com/cockpit?uid=00110cxxxxxx) にアクセスすると、サンプルアプリケーション パーソナルページが表示されます。Basic認証が掛かっていますので、ユーザー名「username」、パスワード「password」でログインしてください。

パーソナルページには、現在の温度データを表示するメーター(左上)と、Armadillo-IoTへの操作指示を行うボタン(右上)、時系列を表示するグラフ領域(下)があります。

サンプルアプリケーション パーソナルページ(上側)

図4.18 サンプルアプリケーション パーソナルページ(上側)


サンプルアプリケーション パーソナルページ(下側)

図4.19 サンプルアプリケーション パーソナルページ(下側)


クライアントから温度データがアップロードされると、メーターの表示がリアルタイムに変化することを確認してください。また、グラフ領域上の日付ボックスでデータを表示したい日を選択すると、その日の温度変化が時系列グラフとして表示されます。

また、ボタンをクリックすると、クライアントにPush通知を行います。クライアントサイドサンプルアプリケーションのデフォルト設定では、シリアル通信ソフトウェアに"on"または"off"と表示するだけです。--commandでPush通知を受けたときに実行するコマンドを指定できます。value変数に"on"または"off"が格納されてコマンドが実行されます。ボタンの状態に応じてLED[14]を点灯/消灯する場合の実行例を下記に示します。

[armadillo ~]# ruby sample.rb --config config.json --command 'if [ $value = "on" ]; then echo 1 > \
/sys/class/leds/led3/brightness; else echo 0 > /sys/class/leds/led3/brightness; fi'

図4.20 サンプルアプリケーション実行例(LED制御)


[警告]

top page (http://armadillo-iot-sample.herokuapp.com) の地図アプリケーションは現在サービスを終了しています。



[7] GPSデータもアップロードしますが、開発セットにはGPS用アンテナが同梱されていないため、ダミーデータを使います。

[8] https://www.ruby-lang.org/ja/libraries/ 参照。

[9] Pusher Ltd.が提供するWebsocket技術を使用したサーバーからクライアントへのPush通知サービス。

[10] 一つのプロセスあたり約2MB必要となる場合、8GBのメモリを積んだサーバーでも同時に捌けるリクエストは4,000個が限界という計算になります。

[11] そのまま実行すると、「00110cxxxxxx」というuidでデータが作成されてしまいます。uidは適当に変えて実行してください。

[12] スライドスイッチ機能の詳細については、製品マニュアルに記載されています。

[13] コマンドライン中で使用しているタイムサーバは一例です。

[14] LEDについての詳細な情報は、製品マニュアルに記載されています。