まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

2015年09月

以前に東芝 FlashAir 内の特定ファイルをウェブサーバーにアップロードする、という lua スクリプトを作って紹介したことがありました:

一応、このスクリプトは動くのですが、残念なことに固定ファイルしかアップロードできませんでした。理想を言えば「FlashAir に最後に作成されたファイル」を調べることができれば、LUA_SD_EVENT イベントをフックして、「新しいファイルが追加されたら、そのファイルをアップロードする」ということができるようになるのですが、このブログエントリを記述した頃はまだそこまで lua を分かっていませんでした。

で、今乗ってる電車の目的地までしばらく時間がある時間と気持ちに余裕ができたので、FlashAir の特定ディレクトリ内で最も最近作成されたファイルを調べるスクリプトを作ってみました(赤字はコメントです):
last_filepath = ""
max_mod = 0
fpath = "/DCIM/100__TSB" 目的のフォルダ
for filename in lfs.dir(fpath) do 目的フォルダ内の全ファイルを探す
  filepath = fpath .. "/" .. filename
  mod = lfs.attributes( filepath, "modification" ) ファイルの最終更新日時
  if mod > max_mod then 更新日時が最新(最大)のファイルを探す
    max_mod = mod
    last_filepath = filepath
  end
end

   :
(この時点で last_filepath に最新ファイルのパスが格納されている) :

このスクリプトは FlashAir 内の \DCIM\100__TSB というフォルダの中を調べて最も作成日時(実際には更新日時)が新しいファイルを探して last_filepath という変数にそのファイルのファイルパスを代入する、という処理を実行しています。

というわけで、このスクリプトを使って上述リンク先の前回作成した lua スクリプトを改良して、「FlashAir の \DCIM\100__TSB フォルダ内に新しいファイルが作られたらウェブサーバーにアップロードする」という lua スクリプトを作ってみました:
last_fname = ""
last_fpath = ""
max_mod = 0
fpath = "/DCIM/100__TSB"
for filename in lfs.dir(fpath) do
  filepath = fpath .. "/" .. filename
  mod = lfs.attributes( filepath, "modification" )
  if mod > max_mod then
    max_mod = mod
    last_fname = filename
    last_fpath = filepath
  end
end

boundary = "1234567890"
contenttype = "multipart/form-data; boundary=" .. boundary
mes = "--" ..  boundary .. "\r\n"
  .."Content-Disposition: form-data; name=\"file\"; filename=\""..last_fname.."\"\r\n"
  .."Content-Type: image/png\r\n\r\n"
  .."\r\n"
  .."--" .. boundary .. "--\r\n"

blen = lfs.attributes(last_fpath,"size") + string.len(mes) - 17
b, c, h = fa.request{url = "http://XX.XX.XX.XX/up.php",
  method = "POST",
  headers = {["Content-Length"] = tostring(blen),
  ["Content-Type"] = contenttype},
  file = fpath,
  body = mes
}


これを FlashAir の \lua\upload.lua という名前で作成し、\SD_WLAN\config ファイルに以下の1行を追加すると、FlashAir の \DCIM\100__TSB フォルダに新しいファイルができる度にそのファイルはウェブサーバーにアップロードされる、という処理が実現できるようになります:
LUA_SD_EVENT=/lua/upload.lua


そしてウェブサーバー(XX.XX.XX.XX)側のドキュメントルートに up.php というアップロードの受け口となるモジュールが用意されていればこれでアップロードできます。こちらのサンプルは上述の前回リンクの中で紹介しているサンプルのようなものになります(サンプルは PHP です)。


Lua のファイルシステム API についてはこちらのリファレンスを参照してください:
http://keplerproject.github.io/luafilesystem/manual.html#reference
 

IoT アプリ開発をする上で避けて通れないのが MQTT(Message Queuing Telemetry Transport) プロトコルです。デバイスやセンサーなどのマシン間接続(いわゆる "M2M")用に IBM を中心に提唱された軽量プロトコルで、Node-RED や IBM IoT Foundation Quickstart などでも使われています。

そして、この MQTT をアプリケーション実装する上で便利なライブラリPaho です。これも元々は IBM が開発したものをオープンソースとして Eclipse Foundation に寄贈し、現在は Eclipse プロジェクトの1つとして公開されています:

http://www.eclipse.org/paho/
paho_logo_400


この Paho ライブラリを使うことで MQTT の詳しいプロトコル仕様を理解することなく、MQTT アプリケーションを開発することが可能になります。プログラミング言語としても C/Java/Java Script/Python など、多くの言語に対応しており、PC やスマホ、組込機器など、多くのデバイスで利用することができるようになっています。

そして、この Paho の Java ライブラリを使って、実際に IBM IoT Foundation Quickstart の MQTT ブローカー( quickstart.messaging.internetofthings.ibmcloud.com:1883 )に接続して、MQTT パブリッシュ処理を行うサンプルを作ってみた時の様子をこちらで紹介しています:
QuickStart MQTT ブローカーに Java からパブリッシュする

QuickStart は IBM が公開している MQTT ブローカー(サーバー)で、認証なしであれば誰でも使うことができます。また上記リンク先でも紹介していますが、ここにパブリッシュされたメッセージは IBM BluemixNodeRED アプリケーションを使って簡単に取得したり、データベースに格納したり、データフローを定義することができるようになります。


IoT アプリ開発者にとって、この Paho は慣れておくことが必須のライブラリだと思いました。


IBM Bluemix が提供するサービスの1つに "API Management" と呼ばれるものがあります:
2015090901


このサービスは少し特殊なものです。これ単体で何かのサービス機能を提供するものではなく、特定の組織やグループ向けに Bluemix 上で使える独自 API サービスを生成するためのサービスです。また、この API Management サービスを使って提供される API サービスに関しては、名前のとおりに利用状況を把握したり、利用制限をしたり、といった API の管理機能も利用できるようになります。


少し前に API を Bluemix の公式なサービスとして登録するための手順をこのブログで紹介しました:
API を Bluemix のサービスとして登録するには?

ここで紹介した内容はあくまで公式な Bluemix サービスとして、世界中の全 Bluemix ユーザーを対象に公開する API を登録するための手順を紹介しました。技術的な要件はもちろんですが、無料枠の準備なども含めて営業的なハードルもある内容であると思っています。

一方、今回紹介するこの API Management サービスを使った場合、特定の Bluemix ユーザーだけが対象になりますが、そのユーザーに対して、Bluemix 上の(いわば)プライベートサービスを公開して管理する、ということを目的としています。何のセキュリティもない素の REST API に認証機能を追加したり、利用制限をかけたり、利用状況を監視したりする、といったことを実現します。


ではこの API Management サービスを実際に使って独自 API を Bluemix 開発者向けにサービス提供し、Bluemix 上のアプリケーションから利用し、その利用状況を確認するまでの手順を以下に紹介します。API Management ではおおまかに2段階の手順を行う必要があります:
(1) API の定義
(2) API を公開する条件の設定


まず最初に、この API Management を利用して管理/公開する独自 API を用意します。開発者の方で、既に自分の API をお持ちであればそれを使っていただいても構いません。ここでは以下の公開された為替情報 API を使って一連の流れを紹介することにします:
http://fx.mybluemix.net/

2015090905


上記 URL にブラウザでアクセスするとわかるのですが、ほぼリアルタイムに20種類の為替情報が JSON フォーマットで得ることができる、という俺製の REST API です。ドメインを見ればわかるように Bluemix 上で(Liberty Java の 256MB メモリ1インスタンスで)動いているサービスですが、ここで登録するサービスは Bluemix の外のサービスでも構いません。

で、前提としては「この API を作ったけどまだ未公開で、これを Bluemix ユーザー向け API として公開/提供したい」とします。つまり上記 URL はサービスとしてはできていて、ここにアクセスすれば API としては動くんだけど、まだ管理できないから公開はしていない(誰もこの URL を知らない、或いは認証をかけている)状態であるとします。この API を Bluemix の API Management サービスを使って Bluemix の管理下で運用できるように公開する、というのが今回の目的です。


では、まずは Bluemix にログインして、この API Management サービスを追加します。ダッシュボードの「サービスまたは API の使用」をクリックします:
2015090901


サービスの一覧が表示されるので、「統合」カテゴリ内の "API Management" サービスをクリックします:
2015090902


API Management サービスの説明が表示されます。このサービスは特定のランタイムにバインドして使うものではなく、サービス単体で利用します。そのまま「使用」をクリックして、サービスインスタンスを作成します:
2015090903


サービスインスタンスが生成されると API Management 入門の画面が表示されます(ダッシュボードから作成済みの API Management サービスを選択してもこの画面になります)。この中の "API MANAGER に移動" ボタンをクリックして、サービス管理画面に移動します:
2015090904


サービス管理画面の初期状態の画面がこちらです。まだ API を1つも登録していないので何も表示されていませんが、登録 API があると、この画面から利用状況を確認することができるようになります:
2015090905


では早速先程の為替情報 API をここに新規登録してみます。画面左のメニュー上から3番目の API マークをクリックし、API ページ内の "+API" と書かれた箇所から「作成」を選択します:
2015090906


まずは API そのものの情報を指定します。「タイトル」と「基本パス」は必須入力です。「基本パス」とは、この後登録する API のベースとなる共通 URL パスです。ここでは "/fx" と指定しているので、実際に呼び出す API のエンドポイントは "/fx/****(?a=x&b=Y&...)" という形式になります。最後に「追加」ボタンをクリックします:
2015090907

(注 このタイトルは半角英数字で入力してください。日本語は使えますが、公開時に問題が発生します)



新規に API が追加され、指定した内容が画面に表示されます。続いて具体的な API エンドポイントを追加します。画面下部の「操作」タブから「+操作」をクリックします:
2015090901


今回は最新の為替情報を表示する API 1つを追加します。この例ではパスに "/status" と指定していますが、上記でベースパスとして "/fx" を指定しているので、この API は "/fx/status" というパスで呼び出すことになります。また今回の例では GET メソッドで情報を取り出すだけの API を用意するので、POST メソッドは不要です。POST の×印をクリックして POST メソッドを削除します(GET メソッドだけを残します)。最後に「追加」ボタンをクリックします:
2015090902


"/status" GET メソッドが追加されました。ではこの "/status" GET メソッドの具体的な内容を定義するため、編集ボタンをクリックします:
2015090903


"/status" の具体的な内容を定義する画面が表示されます。今回は http://fx.mybluemix.net/ を単純に呼び出した結果をこのメソッドの結果として定義するようにします。このような場合は「実装」タブの「プロキシー」を選択し、プロキシー URL に "http://fx.mybluemix.net/" を指定します。最後に画面右上の「保存」ボタンをクリックして、この変更内容を保存します:
2015090904


これで API の定義は完成しました。API Management サービスを使って API を公開するには、API 利用者が参照できるような公開プランを定義する必要があります。続いてこの API のための公開プランを作成します。メニューの上から2番目の「プラン」セクションを選択し、「+プラン」をクリックします:
2015090905


新規プランの作成ダイアログが表示されます。API のタイトル(この例では "FX")等を指定して「追加」ボタンをクリックします:
2015090906


"FX" プランが作成できました。このプランの中で許可するエンドポイントを追加するため、画面下部の「+操作」をクリックします:
2015090907


「操作の追加」ダイアログが表示されます。今回は "/status" GET メソッド1つだけしか用意していないので1つしか表示されませんが、このプランで公開したい操作にチェックを入れて「追加」ボタンをクリックします:
2015090908


"FX" プラン内に "/status" GET メソッドが追加されました。このまま使ってもいいのですが、折角なので管理っぽい機能を1つ追加してみましょう。このまま使うと利用制限なしに使えてしまいますが、1分間に利用できる呼び出し回数に制限を付けてみます。"/status" GET メソッド行のレート制限変更ボタンをクリックします:
2015090901


「レート制限」ダイアログが表示されます。ここで1分間に呼び出せる回数として "10" を指定して「適用」をクリックします:
2015090902


指定した内容にレート制限が変更されたことを確認します。これで "/status" GET メソッドには1分間に 10 回しか呼び出せない制約が付けられたことになります:
2015090903


ここまでの内容を Bluemix ユーザー向けに公開しますが、公開対象を変更する画面についても確認しておきます。画面左のメニュー上から5番目の「開発者」を選択します。デフォルト状態では自分と同じ Bluemix 組織に属しているユーザーに対してのみ、この API が公開されるような設定になっている点を確認します。他の組織や他のユーザーにこの API を公開する場合は、この画面から開発者を追加します:
2015090904


では、改めて今回作成した API を Bluemix ユーザーに公開します。画面左メニューから「プラン」を選び、公開するプラン(今回の例では "FX" )をクリックします:
2015090905


まずこのサービスを Sandbox 環境にステージングします。画面上部の「ステージ」ボタンをクリックします:
2015090906


ステージングに成功したことを確認します:
2015090907


続いて画面左メニューから「管理」画面を選び、ステージング状態になったサービスの歯車アイコンから「公開」を選択します:
2015090908


公開範囲を指定するダイアログが表示されるので、内容を確認して「公開」ボタンをクリックします:
2015090901


しばらく待つと「公開済み」ステータスに変更されます。これで定義した API が Bluemix 利用者(の自分と同じ組織に属しているユーザー)に公開されました:
2015090902


この状態で一度 Bluemix からログアウトして、ログインし直します:
2015090903


Bluemix に再ログインすると API Management で追加された FX サービスが「カスタムAPI」カテゴリに追加されている(見えるようになっている)はずです:
2015090901


もちろん、Bluemix 上に作ったランタイムのサービスとして追加することも可能です。試しに追加してみます:
2015090902


このカスタム API サービスを追加したランタイムの環境変数を見ると、この API を使うためのクレデンシャル情報を取得することができます:
2015090903


この内容は以下の様な内容になっています、この "credentials" として書かれた3つの内容は後で使うのでメモしておきます:
  :
  :
    "credentials": {
            "client_id": "(client_id の値)",
            "client_secret": "(client_secret の値)",
            "url": "(url の値)"
    }
  :
  :

この情報を使うと、目的の API にアクセスすることができます。例えば "/status" の情報にアクセスするにはウェブブラウザを使って、上記 "credentials" 情報に含まれる情報を使った以下の URL にアクセスしてみます:
  ("url" の値)/status?client_id=(client_id の値)&client_secret=(client_secret の値)

(パラメータとして client_id と client_secret の値を指定して呼び出す)
2015090904


当初の目的通りに、期待通りの API が、API Management サービスの管理下で(本来の URL を公開することなく)作成/実行できました。この API を使ったアプリケーションを開発して Bluemix 上で動かす、ということも可能ですが、制限を加えているので1分間に10回しか呼びさせないようになっているはずです。

また、Bluemix の API Management サービスのポータル画面を確認すると、この API の利用状況を確認することもできます:
2015090906


以上が API Management サービスの使い方についてひと通りの実践を紹介した形になります。既存の(或いはこれから作成する)ウェブサービスを管理して Bluemix サービスに統合するためのサービス、という位置付けであることがお分かりいただけるでしょうか?

興味ある方は是非実際にご自身でウェブサービス API を作って、上記の手順を試していただきたいと思います。自分が作った API の利用制限や認証、利用状況監視などを外付けで実現できるというのはなんとも不思議な気分です。 自分でウェブサービスを作るような立場でない方も、本エントリで紹介している為替 API を使って試してみていただいても構いません。ただ 256 MB メモリ×1インスタンスの比較的貧弱なサーバーで動かしているサービスなので、ご利用はお手柔らかに。。



Node-RED フローエディタの出現などもあって MQTT プロトコルに新たな可能性を感じています。

MQTT といえば「IoT のプロトコル」というイメージを持っている人もいると思います。必ずしも間違いではないと思っていますが、こんな軽量で便利なプロトコルを IoT のためだけに使うのはもったいないかな、、、とも感じるようになりました。それを実感するためにちょっとしたアプリを作ってみました、という内容です。


今回紹介するための例として選んだのが投資相場情報です。個人的にもたしなむ程度には投資をやってますが、デイトレードするようなタイプの投資家からすると、リアルタイムにより近い情報が提供されるのであれば有用なはずです。ただ IoT と投資を結びつけて考えることはあまりないですよね。でも IBM IoT Foundation や Node-RED と組み合わせて投資を考えるとどうなるでしょうか?

まず、ためしに外国為替の価格情報を表示するような、こんなウェブサービスを作ってみました:
http://fx.mybluemix.net/

↑上記 URL にアクセスすると、そのタイミングでの20種類の為替情報を JSON フォーマットで返してくれます。週末とかでない限り、為替相場は24時間変化し続けます。これ自体はごく一般的な REST のウェブサービスです。(ドメインを見ればわかりますが)これは Bluemix 上で動いていますが、このサービスがどこで動いているかは関係ありません:
2015090701


この仕組をこのまま(必要な時にこの URL にアクセスして取得する形で)使うこともできますが、MQTT を使うとプッシュのような仕組みを実現することもできるようになります。別途 MQTT パブリッシャーのアプリケーションを用意して、例えば1分おきに最新の為替状況を取り出して、MQTT ブローカーへパブリッシュする、という方法です。特にパブリッシュ先の MQTT ブローカーを IBM IoT Foundation の QuickStart(quickstart.messaging.internetofthings.ibmcloud.com:1883) に指定すると、Bluemix 上の Node-RED の QuickStart からも参照できるようになるので、Node-RED を使って簡単に為替情報を取り出すことができるようになります。また取り出したデータをデータベースに格納したり、取り出した数値を元にデータフローを記述して実行することは Node-RED の機能を使って簡単に実現することができるようになります:
2015090702


実際に QuickStart の MQTT ブローカーに対してメッセージをパブリッシュするアプリケーションを Java で開発する場合の詳細はこちらを参照ください:
QuickStart MQTT ブローカーに Java からパブリッシュする


今回のアプリでは ClientID(Node-RED の QuickStart で言うところの deviceId)に "net.mybluemix.fx.mqtt.publish" という文字列を指定して quickstart.messaging.internetofthings.ibmcloud.com:1883 にパブリッシュしています。なので、Node-RED 側でも同じ deviceId を指定すれば取り出せるようになる、というものです:
2015090703


実際にこのアプリを作って、ローカルホストで動かしてみました(MQTT パブリッシャーはローカルホストだろうが、プライベートネットワーク内だろうが、MQTT ブローカーに接続できる環境下であれば動きます)。同時に Bluemix 上の Node-RED では MQTT パブリッシャーと同じ deviceId を指定して QuickStart からデータを取り出してみます:
2015090704


とりあえずは普通に Debug アウトプットノードだけを足してデプロイすると・・・
2015090705


為替情報が(この例では)30秒おきに Debug タブに表示されるようになりました!期待通りに動いてます。
2015090706


この結果を WebSocket にも送るように改良してみます:
2015090707


WebSocket に送られてくるデータを視覚化するような HTML を用意するとこんな感じ。MQTT から送られてくる為替データを元にリアルタイム為替チャートが簡単にできちゃいました:
2015090708


後は為替を売買する(業者の)API があれば、これと組み合わせて実際に売買するシステムが作れちゃいそうです。もちろん為替である必要はなく、株式でも同様のデータが取得できて、同様の売買 API があれば同じような仕組みを作ることもできそうですね。

なお、WebSocket 経由で取得したデータの視覚化方法についてはこのページの情報を参考にしています。具体的には Google Visualization API を使っています:
Node-REDを使ってセンサーデータをWebSocketで出力する


MQTT はデバイスデータやセンサーデータを扱うだけでなく、色んな応用ができそうです。アイデア勝負の世界になりそうな感じですね。


(2015/Sep/11 追記)
この中で紹介している Quickstart MQTT ブローカーに為替情報をパブリッシュする Java アプリケーションのソースコードを GitHub で公開します:
https://github.com/dotnsf/FxQuickstart



このページのトップヘ