第4章 IoTを体験しよう

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

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

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

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

クライアントサイドアプリケーションは、Rubyのコンソール(CLI)アプリケーションとして実装されています。実装を簡単にするために、Ruby用ライブラリの一般的な配布形式である、gem[7]をいくつか使用しています。データのアップロードはREST API(HTTP POST)で行うため、rest-clientを使用します。また、サーバーからのPush通知にはPusher[8]を使用しているため、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アプリケーション開発フレームワークが、クライアントからのリクエストがあるたびに、プロセス(ないしはスレッド)を生成する構成になっていたため、接続が重複すると、サーバーのメモリを使い切ってしまう事が一因です[9]

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コマンドを使用し、下記のように実行することでも、データをアップロードすることができます[10]。自分でクライアントアプリを実装する際の参考としてください。

[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シリアル変換アダプタのスライドスイッチを次のように外側になるようにしてください。[11]

スライドスイッチの設定

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


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

U-Boot 2014.04-at2 (Jun 12 2016 - 17:46:27)

CPU:   Freescale i.MX7D rev1.1 at 792 MHz
CPU:   Temperature: can't get valid data!
Reset cause: POR
I2C:   ready
DRAM:  512 MiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
SF: Detected N25Q64 with page size 256 Bytes, erase size 4 KiB, total 8 MiB
In:    serial
Out:   serial
Err:   serial
Found PFUZE300! deviceid 0x30, revid 0x11
Board Type: Armadillo-IoT G3(0a000000)
Revison: 0002
S/N: 2000
DRAM: 00001d05
XTAL: 00
Net:   FEC0
=>

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


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

=> boot
mmc1(part 0) is current device
mmc1(part 0) is current device
reading boot.scr
** Unable to read file boot.scr **
reading uImage
9301216 bytes read in 1560 ms (5.7 MiB/s)
Booting from mmc ...
reading armadillo_iotg_g3.dtb
52708 bytes read in 26 ms (1.9 MiB/s)
## Booting kernel from Legacy Image at 80800000 ...
   Image Name:   Linux-3.14.38-at2
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    9301152 Bytes = 8.9 MiB
   Load Address: 80008000
   Entry Point:  80008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 83000000
   Booting using the fdt blob at 0x83000000
   Loading Kernel Image ... OK
   Using Device Tree in place at 83000000, end 8300fde3

Starting kernel ...

Booting Linux on physical CPU 0x0
Linux version 3.14.38-at2 (ohsawa@pc-sienta) (gcc version 4.6.3 (Debian 4.6.3-14atmark1) ) #383 SMP PREEMPT Sun Jun 12 14:33:00 JST 2016
CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: Atmark-Techno Armadillo-IoT Gateway G3 Board
cma: CMA: reserved 320 MiB at 8c000000
Memory policy: Data cache writealloc
PERCPU: Embedded 8 pages/cpu @8bb35000 s8256 r8192 d16320 u32768
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
Kernel command line: console=ttymxc4,115200 root=/dev/mmcblk2p2 rootwait rw
PID hash table entries: 2048 (order: 1, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 172316K/524288K available (8487K kernel code, 504K rwdata, 6948K rodata, 2540K init, 440K bss, 351972K reserved, 0K highmem)
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    vmalloc : 0xa0800000 - 0xff000000   (1512 MB)
    lowmem  : 0x80000000 - 0xa0000000   ( 512 MB)
    pkmap   : 0x7fe00000 - 0x80000000   (   2 MB)
    modules : 0x7f000000 - 0x7fe00000   (  14 MB)
      .text : 0x80008000 - 0x80f1af20   (15436 kB)
      .init : 0x80f1b000 - 0x81196040   (2541 kB)
      .data : 0x81198000 - 0x81216360   ( 505 kB)
       .bss : 0x8121636c - 0x81284724   ( 441 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
Preemptible hierarchical RCU implementation.
        RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
NR_IRQS:16 nr_irqs:16 16
Switching to timer-based delay loop
sched_clock: 32 bits at 3000kHz, resolution 333ns, wraps every 1431655765682ns
Architected cp15 timer(s) running at 8.00MHz (phys).
sched_clock: 56 bits at 8MHz, resolution 125ns, wraps every 2147483648000ns
Ignoring duplicate/late registration of read_current_timer delay
Console: colour dummy device 80x30

(省略)

Debian GNU/Linux 8 armadillo-iotg ttymxc4

armadillo-iotg login:
     

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


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

Debian GNU/Linux 8 armadillo-iotg ttymxc4

armadillo-iotg login: root
Password:
root@armadillo-iotg ~# 

図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システムと同様、ネットワークインターフェースの設定はNetworkManagerが管理します。NetworkManagerは標準でeth0(LANのネットワークインターフェース)が自動でupし、DHCPでネットワーク設定を取得するようになっています。

もし、固定IPに設定したい場合など、ネットワーク設定を変更したい場合は、NetworkManagerのツール(nmtui, nmcli)を用いて設定するか、NetworkManagerの設定ファイル(connection-file)を編集することで行えます。本章ではユーザーフレンドリーなnmtuiを用いてネットワーク設定を行います。

手順4.1 nmtuiを使用しネットワーク設定を変更する

  1. nmtuiを起動する

    起動したnmtui

    図4.7 起動したnmtui


  2. Connection (Wired connection 1) を選択する

    Connection選択画面

    図4.8 Connection選択画面


  3. 固定IP(IPアドレス: 192.0.2.100/32、デフォルトゲートウェイ: 192.0.2.1、DNSサーバー:192.0.2.2)に設定する場合の設定例を下記に示します。ネットワーク設定入力後、<OK> を選択し設定を保存してください。

    ここでのポイントは以下の3つです。

    • IPv4 CONFIGURATION の Show を選択し入力項目を表示させる

    • IPv4 CONFIGURATION の <Automatic> を <Manual> に変更する

    • Addresses, Gateway, DNS servers をそれぞれ入力する

    固定IPの設定例

    図4.9 固定IPの設定例


  4. Connection選択画面に戻った後、<Quit> からnmtuiを終了させてください。

  5. ネットワーク設定を反映させるために、動作中のConnectionを一度Deactivateします。

    nmtui-connectを実行すると、Connectionの一覧が表示されます。Wired connection 1上でEnterを押下しConnectionをDeactivateしてください。 ConnectionがDeactivateになると、Connection名の左の*(アスタリスク)が消えます。

    ConnectionをDeactivateする

    図4.10 ConnectionをDeactivateする


  6. 再びWired connection 1上でEnterを押下しConnectionをActivateしてください。これで先ほど設定したネットワーク設定が反映されました。 ConnectionがActivateになると、Connection名の左の*(アスタリスク)が表示されます。

    ConnectionをActivateする

    図4.11 ConnectionをActivateする


4.3.2. 時刻を設定する

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

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

[armadillo ~]# ntpdate ntp.nict.jp
[armadillo ~]# date
Thu Mar 3 11:29:36 JST 2016

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


[注記]
[armadillo ~]# sed -i -e '/exit 0/i ntpdate ntp.nict.jp' /etc/rc.local

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


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 ~]# curl -kO https://armadillo-iot-sample.herokuapp.com/client/Gemfile
[armadillo ~]# bundle install --path vendor/bundle
[armadillo ~]# bundle exec 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 ~]# bundle exec ruby sample.rb --config config.json --interval 1 --times 5

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


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

[armadillo ~]# bundle exec 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 ~]# bundle exec 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)


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

サンプルアプリケーション トップページ

図4.18 サンプルアプリケーション トップページ


データが存在する場所には、ピンが立っています。ピンをクリックすると、UIDが表示されますので、自分のUIDと一致していたら「こちら」をクリックし、パーソナルページに移動してください。もし、自分のUIDを持つピンが見当たらなかったら、地図を広域表示にして探してください。詳細ページはクライアントサイドサンプルアプリケーションの実行ログの「personal page」と表示されている行のURLから直接アクセスすることもできます。

サンプルアプリケーション ピンの確認

図4.19 サンプルアプリケーション ピンの確認


[注記]ピンが見つからない

地図上のピンは、最新のデータがある位置を示しています。後から他の人がアップロードしたデータがたまたま同じ位置になってしまった場合、上書きされてしまいます。その場合は、再度クライアントサイドアプリケーションを実行して別の位置にピンを立てるか、パーソナルページに直接アクセスしてください。

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

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

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


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

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


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

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

[armadillo ~]# bundle exec 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.22 サンプルアプリケーション実行例(LED制御)




[6] PDS6-JにはGPS機能が無いため、GPSデータはダミーデータを送信します。

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

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

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

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

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

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

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