(レポート) MBL303: IoT デバイス向けのモバイルアプリとモバイルアプリ向けの IoT アプリの構築 #reinvent

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

IoT デバイス向けのモバイルアプリとモバイルアプリ向けの IoT アプリの構築

この記事は re:Invent 2015 のセッション「MBL303 - Build Mobile Apps for IoT Devices and IoT Apps for Mobile Devices」のレポートです。


スピーカーは次のお二人です。実際の IoT デバイスとモバイルアプリを使ったデモも行われた、現地で参加してこそ楽しめるセッションでした。

  • Michael Garcia - Solutions Architect, Amazon Web Services
  • Tara Walker - Technical Evangelist, Amazon Web Services, Amazon Web Services

iot-device-photo-6

アジェンダ

  • デモ
  • モバイルと IoT の利用シナリオについて
  • AWS IoT SDK と API について
  • AWS ToT を使ったアーキテクチャ

デモ

まずはじめに、AWS IoT を活用例としてのシステム「A.S.F.A (Autonomous system for agriculture)」のデモが行われました。A.S.F.A は、スマホアプリや PC (Web アプリ)から自宅の植物を管理することができるシステムです。

iot-mobile01

ペルソナとして、人形のキャラクター「ジョージ」が登場。ジョージは外出中には植物の状態は分かりませんでしたが、A.S.F.A を使うことで水が足りないかどうか見ることができたり、もちろん自宅でもデータを見ることができたりします。家族など複数人で管理することも想定できます。

A.S.F.A は小さな箱。そこから湿度センサーを植物の鉢の土壌に繋ぎます。

iot-device-photo-2

モバイルアプリでは、シンプルなメニューから「Connect to Device」を選択すると、家の中の通信可能な Bluetooth デバイスが一覧で表示されます。デバイスを選択すると、数秒でセットアップ完了。Wi-Fi のパスワードを入力すると IoT デバイスに送信され、Wi-Fi に接続できるようになります。

iot-device-photo-3

インターネットに接続された IoT デバイスは、湿度などの情報を AWS IoT に送信できるようになります。

iot-device-photo-4

モバイルアプリでは、湿度や温度などの情報をサブスクライブすることができます。サブスクライブすると、リアルタイムでデータが飛んできます。

iot-device-photo-5

ジョージが外出したらどうする?モバイルアプリから水のコントロールが遠隔でできます。モバイルアプリからの Topic への Publish が AWS IoT の Device Shadow を使って IoT デバイスに送信され、ポンプから水が送られます。

iot-device-photo-7

が、ポンプがうまく設置されておらず、水が暴発していましたw

iot-device-photo-8

植物の状態を、ダッシュボードとして家族に共有したい。そのような場面を想定し、Web アプリによるデータの閲覧も可能。

iot-device-photo-9

ダッシュボードの閲覧は、Amazon アカウントで認証。

iot-device-photo-10

ログイン後、植物の状態が閲覧可能。

iot-device-photo-11

先ほどモバイルアプリから操作した、ポンプから水を送る機能も付いています。

iot-device-photo-12

かわいい(?)花の絵が表示されており、健康状態によって変わる。センサーを外すと辛そうな顔になる。

iot-device-photo-13

状態の変化はグラフで確認することができます。

iot-device-photo-14

ポンプから水を送ったという情報は、メールなどで受信可能。

iot-device-photo-15

ということで、ジョージは引き続きバケーションを楽しめます。

モバイルからの利用シナリオ

簡単なセットアップ

モバイルからのセットアップは、ほとんど魔法のように簡単です。簡単だと、信頼できる接続が行えるか心配されますがそれも問題ありません。これにより、高いエンゲージメントが得られます。

iot-mobile03

A.S.F.A の本体である IoT デバイス は Intel Edison でした。IoT デバイスは Wi-Fi に接続して AWS IoT に繋がりますが、肝心の Wi-Fi 接続についてはモバイルアプリからセットアップします。モバイルアプリに Wi-Fi の接続情報 (どこのSSIDか、パスワードは何か) を入力し、そのデータを IoT デバイスに Bluetooth 経由で送信します。IoT デバイスはその情報を使って Wi-Fi に接続します。

データの送信

Node.js を使用。プライベートキー、認証情報をファイルから読み込みます。

// Certificates for secure communications
var KEY = fs.readFileSync(pathToPrivateKey);
var CERT = fs.readFileSync(pathToCert);
var TRUSTED_CA_LIST = [fs.readFileSync(pathToROOTCA)];

これらの情報を使いつつ、AWS IoT のエンドポイント (MQTT broker) に接続します。なお、AWS IoT との接続には TSL 1.2 (Latest version) を使って行われます。

// Set connections parameters
var options = {
  port: 8883,
  host: <AWS IoT Endpoint>,
  protocol: 'mqtts',
  ca: TRUSTED_CA_LIST,
  key: KEY,
  cert: CERT,
  secureProtocol: 'TLSv1_2_method',
  protocolId: 'MQIsdp',
  clientId: ’Edison’,
  protocolVersion: 3
};

// Connect to the MQTT broker
var client = mqtt.connect(options);

この時点ではまだサブスクライブ、パブリッシュは行っていません。それぞれ、次のように行います。

client.on('connect', function () {
  // Do stuff here when connection is established
});
client.on('message', function (topic, message) {
  // Do stuff here when a message is received
});

// Subscribe to an MQTT topic
client.subscribe(topic);

// Publish data on MQTT topic
client.publish(topic, JSON.stringify(myMsg));

Bluetooth 接続

IoT デバイスの Bluetooth 接続は、まず IoT デバイスがペリフェラルとなりアドバタイズを開始します。モバイルがセントラルとなり IoT デバイスを見つけることができます。BLE のライブラリは、例えば bleno などを使います。on にしてから startAdvertising でアドバタイズ開始です。受け取ったデータ (Wi-Fi 接続情報) は updateWPASupplicant に渡すことで、Wi-Fi に接続を試みます。

// Bluetooth Low Energy Library
var bleno = require('bleno');

// When starting up
bleno.on('stateChange', function(state) {
  if (state === 'poweredOn') {
    bleno.startAdvertising('ASFA device', ['f00df00ddffb48d2b060d0f5a71096e0']);
  }
});

// Reads data and update WiFi configuration
BLEConnectCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
  updateWPASupplicant(JSON.parse(data));
  callback(this.RESULT_SUCCESS);
};

モバイルアプリ(Android) 側はセントラルとなります。BluetoothManager を使って IoT デバイスを探して writeCharacteristic でデータを書き込みます。ちなみに知見ですが、4.x 系は Buggy なのでご注意を。。5 系からのほうが安心して使えますね。

// Initializes a Bluetooth adapter on Android
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

// Automatically connects to the device upon successful start-up initialization.
mBluetoothLeService.connect(mDeviceAddress);

// Write data
characteristic.setValue(this.chunks[0].toString());
mBluetoothGatt.writeCharacteristic(characteristic);

システムのモニタリング

複数のユーザーが正しい認証情報でアクセスすることが可能なツールを構想。

iot-mobile04

AWS IoT の Rule の設定によって、IoT デバイスから送信されたデータを DynamoDB に格納することが可能です。まずはこれによって永続化を実現します。もちろん、Kinesis を使う方法でも実現可能です。

iot-mobile05

Web アプリであるダッシュボードは、Cognito を利用したユーザーの認証を実現。認証したユーザーは AWS リソースにアクセス可能になるため、先ほどの DynamoDB テーブル内のデータを取得することが可能になります。これで、サーバーレスな Web アプリケーションが構築できます。このアーキテクチャは、もちろんモバイルアプリにも使えます。

iot-mobile06

サーバーレスで構築した Web アプリケーションは、S3 の静的 Web サイトホスティングを利用。AWS SDK for JavaScript で AWS サービスの API をコールします。ダッシュボードでは、3秒おきにデータがレポーティングされるように実装。さらに、PC からだけではなくモバイルからも開くことができる(レスポンシブデザイン対応済み!)。このページはネイティブアプリにも Web ビューとして組み込まれています。

iot-device-photo-16

Rule は次のように設定します。IoT から送信されたデータをすべて DynamoDB テーブルのアイテムとして書き込んでいます。レンジキーをタイムスタンプにしているので、ダッシュボードからデータを取得するとき、日時による範囲指定が可能になっています。

{
  "sql": "SELECT * FROM 'things/data'", "ruleDisabled": false,
  "actions": [
    {
      "dynamoDB": {
        "roleArn": "arn:aws:iam::xxxxxxxxxxx:role/iot-role",
        "tableName": "thingsData”,
        "hashKeyField": "topic", 
        "hashKeyValue": "things/data", 
        "rangeKeyField": "timestamp", 
        "rangeKeyValue": "${devicetimestamp}"
      }
    }
  ]
}

接続したオブジェクトの制御

IoT デバイスの制御は Device Shadow を使うことで実現できます。Device Shadow を使うと、さまざまなデータ通信技術に対応可能です。常にオンラインである必要もなく、良いネットワーク接続がない場合はバッテリー消費を軽減できます。また、デバイスの状態の遠隔でのモニタリング、管理も可能です。

iot-mobile07

iot-mobile08

例として A.S.F.A では、モバイルアプリ(など)から AWS IoT の Device Shadow に向けて HTTPS でポンプの状態の書き込みを送信します。そのデータは MQTTS で通信されている IoT デバイスにダイレクトに送信され、データを受けたときにどうするかロジックを実装することにより、制御可能になります。Device Shadow で定義できる状態は desiredreported の2つがありますが、この場合は desire を使います。

{
  "state":{
    "desired":{
      "pump":"1"
    } 
  }
}

MQTT トピックをサブスクライブしていると、次のデータが IoT デバイスで受け取れます。

{
  "state":{
    "pump":"1"
  }, 
  "version":"3", 
  "metadata":{
    "color":<time-stamp> 
  }
}

こうして変更された内容は reported として Device Shadow に送信されます。そこから Rule を作り込み、例えば SNS のモバイルプッシュを使ってモバイルアプリに変更完了通知を送ることができます。もちろん、通知先はメールとかでもOKです。

iot-mobile09

MQTT トピックには reported としてデータが送信されます。

{
  "state":{
    "reported":{
      "pump":"1"
    }
  }
}

SNS に Publish したいのであれば、次のような Rule を設定します。targetArn でトピックを指定しているので、このトピックのサブスクリプションを増やしていけば複数人、複数端末に一斉に送信できます。

{
  "sql": "SELECT * FROM '$aws/things/Edison/shadow/update/delta' WHERE state.desired.pump = 1 AND state.reported.pump = 1",
  "ruleDisabled": false,
  "actions": [
    {
      "sns": {
        "roleArn": "arn:aws:iam::xxxxxxxxxxx:role/iot-role",
        "targetArn": "arn:aws:sns:us-east-1:xxxxxxxxxxx:ReInventDemo"
      }
    }
  ]
}

自動制御システム

Rule を使うことで、自律したシステムを構築可能です。入り組んだ処理を自動化したり、ユーザーによりフィットするような外部サービスを使うこともできます。

iot-mobile10

Twilio を使った例。Rule で Lambda のファンクションが Invoke されるようにし、ファンクションの中で Twilio の API を呼び出せば、電話による通知も可能です。

iot-mobile11

次のような Rule にすると、ある値が一定値を超えたら Lambda ファンクションを Invoke するようなきめ細かい設定ができます。

{
  "sql": "SELECT * FROM 'things/data' WHERE humidity < 20", 
  "ruleDisabled": false,
  "actions": [
    {
      "lambda": {
        "functionArn": "arn:aws:lambda:us-east- 1:xxxxxxxxxxx:function:pumpAlert"
      }
    }
  ]
}

AWS IoT SDK

IoT デバイス側に組み込む SDK は、現在 C と JavaScript で提供されています。

AWS IoT Device C SDK

Intel Edison などを使う場合は、C SDK を使います。IoT デバイスの情報をモバイルなどに通知したり、Lambda を使ってサービスを連係したり、データを蓄積して機械学習したりといった、さまざまなことができます。

// Libraries
#include "mqtt_interface.h"
#include "iot_version.h"

// Connecting to MQTT broker
MQTTConnectParams connectParams;
connectParams.MQTTVersion = MQTT_3_1_1;
connectParams.pClientID = "CSDK-test-device";
connectParams.pHostURL = HostAddress;
connectParams.port = port; iot_mqtt_connect(connectParams);

// Subscribing to a topic
MQTTSubscribeParams subParams;
subParams.mHandler = MQTTcallbackHandler;
subParams.pTopic = "sdkTest/sub";
subParams.qos = qos;
iot_mqtt_subscribe(subParams);

AWS IoT SDK for JavaScript

AWS IoT SDK for JavaScript では、もろもろの設定をサービスモデル(JSON ファイル)として外出しすることができます。ソースコードの使い回しができそうですね。

// Enable AWS SDK for JavaScript support using a service model file
var myService = new AWS.Service({
  apiConfig: require('./path/to/service-model.json'),
  endpoint: "service endpoint"
});

// Initialize SDK
var aws = require('aws-sdk');
var iot = new aws.Service({
  apiConfig: require('./iot-service-model.json'),
  endpoint: "iot.us-east-1.amazonaws.com"
});
var iotData = new aws.Service({
  apiConfig: require('./iot-data-service-model.json'),
  endpoint: "data.iot.us-east-1.amazonaws.com" 
});

// Publish message on MQTT topic
var params = { 
  "topic" : "foo/bar", 
  "payload" : "hello world"
};
iotData.publish(params, function(err, data) { 
  console.log(err, data);
});

MQTT on Android with Paho

AWS IoT の SDK ではないですが、例えば Android から AWS IoT の MQTT broker とデータの送受信が可能です。Android の MQTT クライアントライブラリは、Paho を使うのがポピュラーです。認証情報は BKS(Bouncy Castle 形式) を使用します。

// Use TLS1.2 to connect to AWS IoT
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
mqttConnectOptions.setSocketFactory(sslContext.getSocketFactory());

// Use Android MQTT Paho Library to establish connection
mqttConnectOptions.setCleanSession(true);
mqttConnectOptions.setConnectionTimeout(AWSIoTConstants.IoTTimeout);
mqttConnectOptions.setKeepAliveInterval(AWSIoTConstants.IoTKeepalive);
if (AWSIoTConstants.lastWillTestament != "" 
    && AWSIoTConstants.LastWillTopic != null) {
    mqttConnectOptions.setWill(
        AWSIoTConstants.LastWillTopic, 
        AWSIoTConstants.lastWillTestament.getBytes(), 
        AWSIoTConstants.IoTQoS, true);
}
try {
    connectionListener.setMQTTClient(mqttClient,mqttConnectOptions); 
    mqttClient.connect(mqttConnectOptions, null, connectionListener); 
    instance = this;
} catch (Exception e) {
    e.printStackTrace();
}

Cognito の IAM ポリシー

Cognito の IAM ポリシーでは、変数として cognito-identity.amazonaws.com:amrcognito-identity.amazonaws.com:audcognito-identity.amazonaws.com:sub が利用できます。これを使って Allow するリソースをきめ細かく制御できます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow", "Action": [
        "iot:Publish"
      ],
      "Resource": [
        "arn:aws:iot:us-east-1:420622145616:topic/foo/bar/${cognito-identity.amazonaws.com:aud}"
      ],
      "Condition": {
        "ForAnyValue:StringLike": {
          "cognito-identity.amazonaws.com:amr": "graph.facebook.com"
        }
      }
    }
  ]
}

AWS IoT CLI and Web Console

AWS IoT のサービスは CLI または Web Console から操作可能です。

AWS IoT を利用した共通アーキテクチャ

AWS IoT を使う場合に有用なアーキテクチャの紹介です。

スマホをハブとして利用

  • 非常に少ないリソースでコストを削減
  • Cognito を利用したセキュアなデータ送信
  • スマホの Wi-Fi または 4G を通信として使用

iot-mobile12

ビルドの自動化 / モバイルアプリでの制御

  • IoT デバイスから情報を受け、何かしらを動的に自動化
    • ex. 緊急ボタンが押されたらドアを開き支援を要求する など
  • Rule を使ってモバイルアプリから IoT / ファクトリの制御

iot-mobile13

複雑なメトリクスの表示

  • Lambda を活用してデータを加工し DynamoDB へ格納

iot-mobile14

ユーザーの好みの学習

  • IoT デバイス、スマホアプリ、Web ダッシュボードから AWS IoT にデータを送信
  • Kinesis 経由で S3 に格納
  • S3 のデータを元に Machine Learning で機械学習

iot-mobile15

まとめ

ホームオートメーション的なソリューションとしての AWS IoT の活用例でした。植物育てるとき、このシステム普通に欲しいですね!モバイルアプリとの密な連係も取れていて、実用面が考えられていて大変勉強になりました。

モバイルアプリも絡めた AWS IoT の活用方法は、Rule を使うことでかなり広がります。Lambda までいければあとはアイデア次第でどこまでも広がりますね。A.S.F.A と同じものを作ってみるのも面白そうですが、他の用途としても使ってみたいなぁと思いました。あと Shadow を使って IoT デバイスの状態を変えるというのも、深く考えていくと面白いソリューションが生まれそうですね。

IoT デバイスがあればそこまで時間もかからないと思いますので、この例を参考に作ってみてはいかがでしょうか。新時代のDIYですね!