Unified Endpoint で SORACOM の複数サービスにデータを送る

 先日 2/14 にソラコムさんの if-up2019 IoT Technology Conference に参加してきました。

if-up2019.soracom.jp

 ソラコムさんはイベントに合わせていつも新発表をされますが、今回の新発表の一つとして Unified Endpoint が発表されました。

blog.soracom.jp

 こちらは独立した新サービスではなく新機能ということで、すでに Public Beta として使えるようになっていたので早速試してみました。

機能概要

 Unified Endpoint を簡単に説明すると、 SORACOM の複数のサービスへのデータ送信を一つのURLでまとめて受け取れるようにしたものです。 SORACOM では今までに Beam, Funnel, Harvest といったサービスが提供されていて、クラウドサービスとのデータ連携や可視化が便利にできるようになっていましたが、送信先URLはそれぞれ違っています。なので後から送信先サービスを変更する場合、例えば Beam で自前のサーバに送っていたけど Funnel で AWS IoT に連携するようにする、といった場合にはデバイス上の実装に含まれているURL指定を変更する必要がありました。

 これが Unified Endpoint を利用することにより、デバイスの実装では常に Unified Endpoint の URL にデータを送っていれば、ユーザーコンソールの設定だけで送信先サービスを変更できるようになります。もちろん送信内容はあらかじめ汎用性を考慮しておく必要はありますが、設置済みデバイスの実装に手を入れずに送信先を変更できるというのはとても便利なのではないかと思います。

設定

 今回は Raspberry Pi を SORACOM Air でセルラーネットワークに接続し、温度と湿度のデータを JSON で SORACOM Harvest と SORACOM Funnel 経由で AWS IoT に送信してみます。 AWS IoT に接続するにはデバイスの認証が必要ですが、今回の認証は以前下記の記事で試した SORACOM Krypton での認証を使用します。

blog.akanumahiroaki.com

 それではそれぞれのサービスの設定を行なっていきます。まず Unified Endpoint は有効にするための設定は特に必要なく、自動的に使用されます。レスポンスの形式を変更する場合はユーザコンソールのSimグループの設定画面から設定変更を行います。今回はデフォルトの Auto 設定のまま使用してみます。

f:id:akanuma-hiroaki:20190216154948p:plain

 Harvest の設定は ON/OFF の切り替えのみですので、ユーザコンソールから ON にします。

f:id:akanuma-hiroaki:20190216155126p:plain

 Funnel から AWS IoT への転送設定は、 Funnel の利用を ON にして、転送先サービスで AWS IoT を選択します。転送先 URL には AWS IoT のエンドポイントに MQTT のトピックス名を組み合わせて指定し、認証情報は Krypton で設定した認証情報を指定します。

f:id:akanuma-hiroaki:20190216160208p:plain

 これで設定は一通り完了です。データ送信については今回は擬似的に温度と湿度データを生成して送信する Ruby スクリプトを実装してデータを送信してみます。送信先の URL には Unified Endpoint の URL を指定し、30秒ごとにデータを送信してみます。

require 'bundler/setup'
require 'httpclient'
require 'logger'

UNIFIED_ENDPOINT = 'http://uni.soracom.io'
LOG_FILE = 'env_monitor.log'

class ENV_MONITOR
  def initialize(interval)
    @interval = interval
    @http_client = HTTPClient.new
    @logger = Logger.new(LOG_FILE)
    @temperature_range = 20.0..25.0
    @humidity_range = 40..60
  end

  def execute
    loop do
      temperature = Random.rand(@temperature_range)
      humidity = Random.rand(@humidity_range)
      payload = '{"temperature": "%.1f", "humidity": "%.1f"}' % [temperature, humidity]
      res = @http_client.post(UNIFIED_ENDPOINT, payload, 'Content-Type' => 'application/json')
      @logger.info("PAYLOAD: #{payload} / Response: #{res.status}")
      @logger.info(res.body)

      sleep(@interval)
    end
  end
end

if __FILE__ == $PROGRAM_NAME
  monitor = ENV_MONITOR.new(30)
  monitor.execute
end

動作確認

 それでは SORACOM Air でネットワーク接続した上でスクリプトを動かして動作を確認してみます。スクリプトを動かすと下記のようにログに出力されます。今回は Unified Endpoint のレスポンスの設定を Auto にしていますので、レスポンスの detail には Funnel と Harvest それぞれからの statusCode が含まれます。 Funnel からは 204、 Harvest からは 201 が返って来ていますので、それぞれへのデータ送信は成功しているようです。

I, [2019-02-16T06:34:37.185769 #23241]  INFO -- : PAYLOAD: {"temperature": "20.8", "humidity": "58.0"} / Response: 200
I, [2019-02-16T06:34:37.186107 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:35:09.495921 #23241]  INFO -- : PAYLOAD: {"temperature": "25.0", "humidity": "41.0"} / Response: 200
I, [2019-02-16T06:35:09.496257 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:35:43.716117 #23241]  INFO -- : PAYLOAD: {"temperature": "20.1", "humidity": "52.0"} / Response: 200
I, [2019-02-16T06:35:43.716453 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:36:15.356277 #23241]  INFO -- : PAYLOAD: {"temperature": "23.3", "humidity": "47.0"} / Response: 200
I, [2019-02-16T06:36:15.356612 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:36:49.526506 #23241]  INFO -- : PAYLOAD: {"temperature": "20.4", "humidity": "52.0"} / Response: 200
I, [2019-02-16T06:36:49.526851 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:37:21.146493 #23241]  INFO -- : PAYLOAD: {"temperature": "23.7", "humidity": "47.0"} / Response: 200
I, [2019-02-16T06:37:21.146824 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:37:58.956850 #23241]  INFO -- : PAYLOAD: {"temperature": "22.3", "humidity": "59.0"} / Response: 200
I, [2019-02-16T06:37:58.957189 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:38:30.626827 #23241]  INFO -- : PAYLOAD: {"temperature": "21.2", "humidity": "50.0"} / Response: 200
I, [2019-02-16T06:38:30.627169 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:39:03.247368 #23241]  INFO -- : PAYLOAD: {"temperature": "21.7", "humidity": "59.0"} / Response: 200
I, [2019-02-16T06:39:03.247702 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}
I, [2019-02-16T06:39:34.887067 #23241]  INFO -- : PAYLOAD: {"temperature": "22.1", "humidity": "55.0"} / Response: 200
I, [2019-02-16T06:39:34.887410 #23241]  INFO -- : {"result":"ok","detail":{"SoracomFunnel":{"statusCode":204},"SoracomHarvest":{"statusCode":201}}}

 レスポンスのフォーマットについては下記公式ドキュメントに詳しく書かれていますのでご参照ください。

Unified Endpoint : 機能の説明 | 開発者ガイド | SORACOM Developers

 Harvest の画面でも送信されたデータが確認できます。

f:id:akanuma-hiroaki:20190216160003p:plain

まとめ

 Unified Endpoint から転送可能なのは Beam, Funnel, Harvest の3つですが、 Beam に転送できるということは実質的には何処へでも転送できるということになりますので、実装時にはとりあえず Unified Endpoint 宛に JSON でデータを送るようにしておけば、後からの変更はかなり柔軟にできるのではないでしょうか。認証でも Krypton 等を組み合わせることができますし、様々な処理をデバイスからクラウド側へオフロードできるようになって、どんどん便利になってきました。プロトタイプ段階からこういったサービスを活用してアーキテクチャを考えていくことが重要になってきますね。