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

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

2015/06

IBM Bluemix 上で CakePHP を動かす」。実はこれ、自分が Bluemix に携わるようになった直後くらいから挑戦しては跳ね返されて、少し環境が変わってはまた挑戦して挫折して・・・を繰り返してきたテーマでした。実は意外と難しいんです。

が、先日のランタイムアップデートで PHP ランタイムの環境も変わり、その後の環境であればなんとか動せることが分かりました。その手順を紹介します。


まずは Bluemix に PHP ランタイムと MySQL データベースを用意します。その辺りの手順はこちらのエントリを参照してください。このエントリでは WordPress の導入方法を紹介していますが、そこまで行う必要はなく、PHP ランタイムと MySQL データベースサービスを作成して、接続情報の環境変数を確認して、cf ツールをインストールするところまでを参考にしてください:
IBM Bluemix 上に WordPress 環境を構築する(2015/06/28)


では改めて Bluemix 上に構築した PHP + MySQL 環境上に CakePHP と、データベース管理目的で phpMyAdmin をインストールしてみましょう。


まずは専用の空フォルダを1つ用意します。この例では C:\tmp\cake というフォルダを新たに作りました。このフォルダが PHP サーバーのドキュメントルートになるイメージです:
2015062900


次に CakePHP のコードを入手します。公式ページに移動し、2.x 系の最新バージョンをダウンロードします(3.x でも動くかもしれませんが未検証です)。この図では 2.6.7 が最新バージョンになっており、ダウンロードするファイルは cakephp-2.6.7.zip というものでした:
2015062901


この zip ファイルを展開して、特定のフォルダに保存します。この例では C:\tmp\cake フォルダに cakephp というフォルダ名で保存しています:
2015062902


次に CakePHP の設定ファイルをこの環境に合わせて2ファイル変更します。まずは app\Config\core.php ファイルをテキストエディタで開き、以下の2箇所を変更して保存します:
/**
 * A random string used in security hashing methods. Security.salt を適当な文字列に変更
 */
	Configure::write('Security.salt', 'ABCDabcd1234');

/**
 * A random numeric string (digits only) used to encrypt/decrypt strings. Security.cipherSeed を適当な数値文字列に変更
 */
	Configure::write('Security.cipherSeed', '1234567890');

続いて app\Config\database.php.default を app\Config\database.php にリネームし、更に以下の箇所を変更して保存します:
class DATABASE_CONFIG {

  public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => '(接続情報の host の値)',
    'port' => '(接続情報の port の値)',
    'login' => '(接続情報の username の値)',
    'password' => '(接続情報の password の値)',
    'database' => '(接続情報の name の値)',
    'prefix' => '',
    //'encoding' => 'utf8',
  );
: :

(補足)
この後 cf コマンドでデプロイする場合の CakePHP 側の作業はここまでですが、IDS(IBM DevOps Services) を使ってデプロイする場合は、更にもう1ファイルの変更が必要です。

CakePHP の zip ファイルを展開したフォルダ直下に .gitignore というファイルがあります。この中で /app/Config/database.php ファイルが指定されています。このままだと(リネーム後の) database.php の存在が認識されないため、.gitignore を編集して、この一行の先頭に # を入れコメント行扱いにしてください:
# User specific & automatically generated files #
#################################################
#/app/Config/database.php
/app/tmp
/lib/Cake/Console/Templates/skel/tmp/
  :
  :
(補足終わり)


これで CakePHP の準備ができました。このままデプロイすれば CakePHP 環境としては使えるのですが、MySQL データベースの管理が不便なので、phpMyAdmin 環境も合わせて用意することにします。

まずは phpMyAdmin のコードを入手します。公式ページにアクセスし、最新版モジュール(この図では 4.4.10 でファイル名は phpMyAdmin-4.4.10-all-languages.zip)をダウンロードします:
2015062903


この zip ファイルを展開して、上記で CakePHP を保存したのと同じフォルダに保存します。この例では展開先フォルダを phpMyAdmin としています:
2015062904


次に phpMyAdmin の設定ファイルをこの環境に合わせて変更します。展開先フォルダ直下の config.sample.inc.php を config.inc.php にリネームしてからテキストエディタで開き、以下を変更して保存します('port'の方は一行丸ごと追加してください)。:
  :
  :
$cfg['Servers'][$i]['host'] = '(接続情報の host の値)';
$cfg['Servers'][$i]['port'] = '(接続情報の port の値)';  # この行は追加
  :
  :


これで phpMyAdmin の設定も完了しました。最後に Bluemix 上の PHP ランタイムで mbstring や MySQL, PDO を有効にするための設定を追加します。 CakePHP や phpMyAdmin を保存したフォルダ(ドキュメントルートにするフォルダ)に .bp-config というフォルダを作ります:
2015062905


そしてこの .bp-config フォルダの中に options.json というテキストファイルを以下の内容で新規に作成して保存します:
{
  "PHP_EXTENSIONS": [ "bz2", "zlib", "curl", "mcrypt", "mbstring", "mysql", "pdo", "pdo_mysql" ]
}
2015062906


更に、ドキュメントルート直下に composer.json というファイルを以下の({} だけの)内容で作成します:
{}
2015062907


これで全ての準備が整いました。ではこのフォルダ(cakephp や phpMyAdmin, .bp-config のあるフォルダ)をカレントフォルダにして、Bluemix 上の PHP アプリケーションに cf ツールでプッシュします:
> cd c:\tmp\cake (目的のフォルダ)

> cf login -a https://api.ng.bluemix.net/ -u (Bluemix のログインID)

※データセンターが英国を使っている場合は https://api.eu-gb.bluemix.net を指定する

(パスワード入力を求められるので指定)

> cf push (Bluemix で作成時に指定したアプリ名)

cf push コマンドが成功すると Bluemix 上に CakePHP および phpMyAdmin の環境ができているはずです:

(CakePHP 環境)
2015062908

(phpMyAdmin 環境)
2015062909


念願の CakePHP on Bluemix 環境の作り方が分かりました!

IBM Bluemix 上に WordPress 環境を構築する方法の 2015/06/28 版を紹介します。

具体的な内容紹介の前に少し補足を。実は同様の内容を過去2回ほど紹介したことがありました:
IBM Bluemix 上で WordPress 環境を構築する(2014/06/28)
IBM Bluemix で無料の WordPress 環境を構築する(2015/02/21)

前者は自分で必要なサービスを選んで組み合わせていく、という今回の内容に近い方法です。ただ残念ながら IBM Bluemix の環境が変わり、この時に紹介した方法では現在は正しく構築できないことが分かっています。そんなこともあって今回、新しい方法を紹介しようと思いました。

後者の方法は IBM Bluemix のボイラープレートと呼ばれるテンプレート機能を使う方法で、こちらは現在でも使えます。ただこの方法で提供される MySQL データベースは ClearDB の無料プランで、その容量は 5MB しかありません。本格的に使うにはさすがに不十分だと思っています。

という背景もあって、
 ・2015/06/28 現在でも有効に使えて、
 ・そこそこな容量の MySQL データベースを持つ
WordPress 環境を Bluemix 上に構築する方法を紹介します。おおまかな流れとしては上記前者の方法に近いのですが、ちょっとした追加設定を行うことになります。


まず、最初は普通に Bluemix 上に PHP サーバーと MySQL データベースサーバーを用意してバインドします。最初は PHP サーバーを作ります。ダッシュボードから「アプリの作成」:
2015062801


アプリサーバーの種類として「PHP」を選択:
2015062802


アプリサーバーの名前(ホスト名の一部になる名前)を指定して「完了」:
2015062803


これで PHP サーバーは完成です。続いて MySQL サーバーを追加してバインドします。「サービスまたは API の追加」を選択:
2015062804


「データ管理」カテゴリを選択します。ClearDB の MySQL を選択してもいいのですがデフォルトで与えられる容量が少ないので画面下部の「Bluemix Labs Catelog」をクリックしてオープンソース版の MySQL を探します:
2015062805


オープンソースデータベースの一覧が表示されるので、ここから「MySQL」を選択:
2015062806


プランの選択肢から好きなプランを選びます(画面では 500MB まで使えるプランを選択しています)。アプリに自分が先程作った PHP アプリの名称が表示されていることを確認して「作成」:
2015062807


これで Bluemix 上に PHP アプリサーバーと MySQL データベースサーバーが1つずつ作成されました。MySQL データベースに接続するための情報はメニューの「環境変数」を選択すると表示されます:
2015062808


おそらくこのような JSON テキストが表示されます。この情報は後で WordPress の設定内容として必要になるので保存しておくか、メモしておきます:

#オープンソース版 MySQL サービスを選択した場合、ポート番号がデフォルトの 3306 ではなく、3307 になる点に注意
{
   "mysql-5.5": [
      {
         "name": "mysql-n7",
         "label": "mysql-5.5",
         "plan": "300",
         "credentials": {
            "name": "(データベース名)",
            "hostname": "(MySQL サーバーのIPアドレス)",
            "host": "(MySQL サーバーのIPアドレス)",
            "port": 3307,
            "user": "(MySQL サーバーのユーザー名)",
            "username": "(MySQL サーバーのユーザー名)",
            "password": "(MySQL サーバーのパスワード)",
            "uri": "mysql://(MySQL サーバーのユーザー名):(MySQL サーバーのパスワード)@(MySQL サーバーのIPアドレス):3307/(データベース名)"
         }
      }
   ]
}

ではこの環境を使って WordPress 環境を構築します。

まずは cf ツールをインストールします。こちらのサイトから自分の環境にあった cf コマンドラインツールをダウンロードしてインストールしておきます:
cloudfoundry/cli


次に WordPress をダウンロードします。WordPress の(日本語)公式ページから最新版の WordPress モジュールの zip ファイルをダウンロードします(2015/06/28 時点では wordpress-4.2.2-ja.zip が最新でした。以下このファイルを使う前提で紹介します):
2015062801


ダウンロードしたファイルを展開して、ローカルディスク内の任意のフォルダ(例えば c:\tmp\wordpress)内に保存します:
2015062802


まずは WordPress に必要なフォルダを作成します。モジュールを展開したフォルダの wp-content フォルダに以下のサブフォルダを追加で作成します:
 - upgrade
 - uploads
2015062803


また、モジュール展開フォルダ内にある wp-config-sample.php ファイルを wp-config.php にリネームします:
2015062804


加えて、リネーム後の wp-config.php ファイルをテキストエディタで開き、先程メモした接続情報を使って以下の様な内容に書き換えます(最終行の FS_METHOD の行は丸々追加):
  :
  :
// ** MySQL 設定 - この情報はホスティング先から入手してください。 ** //
/** WordPress のためのデータベース名 */
define('DB_NAME', '(MySQL サーバーのデータベース名)');

/** MySQL データベースのユーザー名 */
define('DB_USER', '(MySQL サーバーのユーザー名)');

/** MySQL データベースのパスワード */
define('DB_PASSWORD', '(MySQL サーバーのパスワード)');

/** MySQL のホスト名 */
define('DB_HOST', '(MySQL サーバーのIPアドレス):3307');


/** データベースのテーブルを作成する際のデータベースの文字セット */
define('DB_CHARSET', 'utf8');

/** データベースの照合順序 (ほとんどの場合変更する必要はありません) */
define('DB_COLLATE', '');

define('FS_METHOD','direct');
  :
  :

実は今まではこれだけの設定で WordPress が使えたのですが、現在はこれだけだと使えなくなっています。理由は PHP ランタイム側に変更が加わり、デフォルト状態では MySQL や mbstring モジュールが無効にされており、その結果 WordPress の環境条件が満たされずにエラーとなってしまうようです。

このエラーを回避するため、ドキュメントルート直下に .bp-config というフォルダを作り、その下に options.json というテキストファイル(つまり .bp-config/options.json)を以下の内容で作成します。このファイルを作っておくと、PHP ランタイムに MySQL や mbstring のモジュールが組み込まれ、利用可能になり、上述のエラーを回避することができるようになります:
{
      "PHP_EXTENSIONS": [ "bz2", "zlib", "curl", "mcrypt", "mbstring", "mysql", "pdo", "pdo_mysql" ]
 }
2015062805


(2015/06/30 追記)
これだけだと足りませんでした。この後の cf push コマンドを成功させるには更に1ファイルがドキュメントルート直下に必要でした。

ドキュメントルート直下に composer.json というファイルを用意し、その中身を {} だけで作成します:
{}
(2015/06/30 追記終わり)


ではローカルマシンに作ったこの WordPress 環境を Bluemix 上の PHP サーバーにプッシュします。プッシュの作業には上述の作業でインストールした cf ツールを使います。コマンドラインやコンソールを起動後、以下のようなコマンドを指定します:
> cd (WordPress のフォルダ)

> cf login -a https://api.ng.bluemix.net/ -u (Bluemix のログインID)

※データセンターが英国を使っている場合は https://api.eu-gb.bluemix.net を指定する

(パスワード入力を求められるので指定) > cf push (Bluemix で作成時に指定したアプリ名)


プッシュが正しく終了すると WordPress モジュールが PHP サーバーのドキュメントルートに送られ、ウェブから WordPress が利用できるようになります:
2015062806



というわけで、PHP のビルドパック内の mbstring や MySQL モジュールを有効にすることで WordPress が使えるようにする、という例の紹介でした。
 

東芝の(いい意味で)変態な SD カード "FlashAir" 。実は以前のブログエントリでは以前のバージョンの FlashAir のこんなハックを紹介したことがありました:


比較的最近のモデルでは lua 言語によるスクリプト処理が可能になったり、「ファイルが FlashAir カードに追加された」などのイベントをハンドリングして処理を実行したり、といったことも可能になり、ますます変態チックな度合いが上がっているようです:



で、せっかく lua スクリプトが使えるようになったのであれば、このカードの中のファイルを(例えば FlashAir カードにファイルが追加されたタイミングなどで)サーバーにアップロードして、サーバー側ではアップロードされた画像ファイルになんらかの(例えば「保存する」などの)処理を実行する、という一連のスクリプトも記述できるのではないか、と考えました。

サーバー側の処理はアップロードされたファイルを取り出して・・・という内容になると思うので、一般的なファイルアップロード処理を行うことになります。

一方、クライアント(FlashAir カード)側の処理は、やることは簡単なのですが、何しろ普段名前を聞くくらいでしか知らなかった lua という軽量言語を触ったことがありませんでした。加えて、ちょっと特殊な言語のようで結局、未だにデバッグ方法を理解していません(苦笑)。 FlashAir も変態でしたが、lua は lua でまたどM向けプログラミング言語というか・・・ 「変態」とか「どM」とか、IT とは異なる世界の話をしている気分になってきます。 (^^;

まあ、でもなんとかファイルアップロードができることを確認したスクリプトが作れました。もしかしたら私以外の変態な皆様の役に立つかもしれないと思って公開することにします(赤字はコメントなので実際には不要、というか残したままだと正しく動きません):
boundary = "1234567890" 適当な文字列
contenttype = "multipart/form-data; boundary=" .. boundary
fname = "sample.png" 転送するファイル名
fpath = "/DCIM/100__TSB/" .. fname 転送するファイルのフルパス
mes = "--" ..  boundary .. "\r\n"
  .."Content-Disposition: form-data; name=\"file\"; filename=\""..fname.."\"\r\n"
  .."Content-Type: image/png\r\n\r\n"
  .."\r\n"
  .."--" .. boundary .. "--\r\n"

blen = lfs.attributes(fpath,"size") + string.len(mes) - 17
b, c, h = fa.request{url = "http://xx.xx.xx.xx/up.php", http://xx.xx.xx.xx/up.php というアップローダーに転送
  method = "POST",
  headers = {["Content-Length"] = tostring(blen),
  ["Content-Type"] = contenttype},
  file = fpath,
  body = mes
}

#だいたい lua のコメントってどう書くのかと??

この例では FlashAir 内の /DCIM/100__TSB/sample.png というファイルを http://xx.xx.xx.xx/up.php というアップローダーに転送することを想定した、マルチパートにすらしていないシンプルなスクリプトです。固定の同じファイルだけを送信するような内容になっていますが、これは実際にはファイル名のパラメータ渡しなどで対応できないかな、と思ってます。

受け取る側の up.php は例えばこんな感じで:
<?php
$name = $_FILES["file"]["name"]; // ファイル名
$mimetype = $_FILES["file"]["type"]; // Content-Type
$filesize = $_FILES["file"]["size"]; // ファイルサイズ
$tmpname = $_FILES["file"]["tmp_name"]; // 一時ファイル名(ここに実体がある)

$filename = "/var/www/html/imgs/" . $name; $result = @move_uploaded_file( $tmpname, $filename ); // 一時ファイルを Document Root 以下に移動するだけ echo( $result ); ?>

こちらはある意味で「一般的な」 PHP アップローダーの中身です。 $_FILES 変数に入った情報を元にファイル名やサイズ、そしてファイルの実体を取り出しています。この例では単純にアップロードされたファイルをドキュメントルート以下に移動するだけの内容です。これが http://xx.xx.xx.xx/up.php という URL でアクセスできる PHP サーバー上に用意されている、という想定です。
2015062401


この PHP では単純にアップロードされたファイルをドキュメントルート以下に置き直しているだけですが、その画像を使って PHP で更に別の処理を行う、なんてことももちろんできます。また PHP である必要もなく、ごく一般的な HTTP ファイルアップローダーの仕組みが用意されていればよい、という認識で大丈夫です。


これら2つのファイルを FlashAir および PHP サーバー側にそれぞれ用意しておくことで FlashAir からのファイルアップロードが実現できました。後はこれを HTTP 経由で呼び出すか、あるいは FlashAir の SD カードにファイルが追加されたタイミングで実行する、などの方法で lua を動かして使うことになります。



参考にしたのはこの辺りです:
- FlashAir Developers : チュートリアル
- FlashAir Developers : API ガイド
おまけ程度のツール置き場 - FlashAirをいじってわかったこと。


#いやあ、しかし lua は難しいというか、、、資料が少ないのも原因なんだろうけど・・・
 

ABC朝日放送様主催のハードウェアハッカソン「ABCハッカソン」が6月20日深夜に放送されました。関東地方ではニコ生と Youtube でサイマル放送され、ネットで試聴することができました:

新世紀発明バトル ABCハッカソン~ひらめきで世界を変えろ!~



ハッカソンをテーマとしたドキュメンタリー番組です。そのハッカソンも一般的な「ソフトウェアハッカソン」ではなく「ハードウェア(+ソフトウェア)ハッカソン」です。しかもテーマは「1万人規模のイベントを盛り上げるガジェットを作る」というもの。なかなかにハードル高そうなハッカソンですが、ハードウェアのハッカソン自体が珍しいこともあって、どんなものが生まれるのか興味津津でした。

私も現地で IBM Bluemix のサポート要員として参加していたこのイベントの結果を、初回放送が終わったこともあり(多少のネタバレが許されるという判断で)、自分なりの視点で情報を少し補足しながら説明したいと思います。なお、以下の内容には一部私の推測も含まれていることと、会社としての見解ではないことをご了承ください。


最優秀賞を獲得した「レコチョク’s」チームが取り組んだのは、音楽イベントでアーティストと目が合えば、それを教えてくれるデバイス "目、あいましたよね?" の開発でした。自分の好きなアーティストやアイドルのコンサートに行って、「今一瞬こっちを向いてくれたような・・・??」と(都合よく)解釈することもできますが、その事実を客観的に知らせてくれるサービスです。

具体的には株式会社ジェイアイエヌ様が開発したスマートメガネ JINS MEME を使ったものです。アーティストがこのメガネを装着してステージ上を動きまわる間、その視線の方向をほぼリアルタイムに計算してサーバーに送ります。一方、観客は専用のデバイスを持っていると想定し、(スマートフォンを通じて)送られてくるデータによって、アーティストの視線の方向に自分がいるかどうかを知ることができる(いたと判断したら、そのデバイスが反応する)、というものでした。 今回のハッカソンでは開発期間の問題もあり、スマートフォンがその通知を受けることができる、というものの実現を目指されていたようです。

この仕組み、JINS MEME からの情報量や更新頻度にもよるとは思いますが、観客が数人(デバイスが数台)であれば、MEME からの情報を http でウェブサーバーに送り、デバイスが(1秒おきなどで)定期的に Web サーバーを見に行く、という普通の(?)アルゴリズムで実現できるかもしれません。

ただ実用化を考えると問題もあります。まず http のような重いプロトコルで実装してしまうと、デバイスの電池消費の問題に直面します。そのデバイスはコンサートイベントの間中動き続けてもらわないといけないため、あまり電気を使うような実装方法は避けたい、という背景があります。また電池の問題はともかく、1万人規模のファン(1万台規模のセンサー)が定期的に Web サーバーに対して1秒おきレベルの頻度でアクセスを繰り返す、というのは、重い http プロトコルではサーバーの負担が大きく、すぐにパフォーマンスの限界が来てしまう、という現実的な問題もあります。「目があったかどうか」というリアルタイム性が重視されるこの処理はネットワークにも演算処理にもパフォーマンスが求められる厳しい要求仕様が隠れていることになります。アイデアの実用化を考えると、これらの問題点をどうやって解決するか?という問題を解決する目処が見込める必要があるのでした。


実は IBM Bluemix にはその答が用意されています。Bluemix が提供している IoT アプリ開発環境である Node-RED フローエディタや、そのインフラとなる Internet of Things Foundation サービスは軽量な MQTT プロトコルを使ってセンサーデータを集めます(集めるための手段やサーバーも提供しています)。プロトコルを軽量にすることでセンサー側の電池消費量を抑え、ネットワーク負担も減らし、その結果処理自体を軽く実装することが可能になります:
2015062302


また Node-RED フローエディタはセンサーデータのワークフローを視覚化された環境で作っていくと実際に動くものが作れる、という特徴を持っています:
2015062301


これらの Bluemix に用意された機能やサービスを使うことで、サービスやデバイスの開発者の余分な負担や心配を減らすことができ、生産性の高い開発が実現できるようになります。同時に多くの実績を持った実現性の高いインフラ環境が提供されていることで、開発者のメリットだけでなく、運用者やベンチャーキャピタルに対するメッセージにもなります。「パフォーマンスが厳しくなってきたから途中からインフラを変える」のは、言うほど簡単ではないし、この辺りをきちんと事前にアセスしておくことも大変だと思っています。そういった部分をプロにアウトソースできる IBM Bluemix はデバイスアプリケーション開発に適していると思っています。


今回はレコチョク’sチームの皆さんに Bluemix を採用いただくことができ、我々もその実現に向けて限られた時間の中でしたがご支援ができました。レコチョク’sチームへは企業賞である IBM 賞も贈呈させていただきましたが、結果として斬新なアイデアとその実現性の高さが評価された上で最優秀賞に選ばれたのだと思っています。改めてレコチョク’sの皆さん、おめでとうございました。

なお、このハッカソンでは最優秀賞のレコチョク’s以外にも、優秀賞を取った "五感王" の「ごったがえし」チーム、サイボウズ賞 "FLUERIR" の「チーム共犯者」にも IBM Bluemix を採用していただきました。 我々もハッカソン前には「ハードウェアのハッカソンで、果たして何チームが Bluemix を採用してくれるのだろう?もしゼロだったら・・」と不安を抱えての大阪入りでした。結果的として3つのチームに採用いただき、最終的にはいずれの3チームも何らかの評価を得る結果になりました。IBM としても非常に嬉しい結果になりました。


このイベントにはアイデアソンの段階から参加させていただき、普段思いつかないような多くのアイデアを目の当たりにする機会があり、とても刺激的でした。また IBM 同様にスポンサーとして参加した企業の皆様との交流機会もあり、得るものがとても多い3日間であったと思っています。


スマホで操作するテトリスを作ってみました。「スマホで操作」の意味がわかりにくいかもしれませんが、スマホの画面上でフリックしたりするわけではなく、スマホをリモートコントローラーとして振ったり傾けたりして操作する、という意味です。

実現する上で Phone Sensor サービスを使いました:
http://phonesensor.mybluemix.net/

ロジックとしてはこんな感じです。まずスマホでは JavaScript でスマホのジャイロ情報を取得し、Phone Sensor サービスを使ってその情報を MQTT ブローカーに送ります。そして IBM Bluemix の Node-RED フローエディタを使って、その MQTT ブローカーに送られたジャイロデータを取り出して、WebSocket に送り続ける、というサーバーサイド処理を記述します。最後にゲームを HTML5 で作り、そのコントロール部分を WebSocket に送られてくるスマホのジャイロデータを元にして操作するよう記述します:
2015061900


ちょっとだけアピールしておくと、MQTT ブローカーを挟んでゲーム画面部分(テトリス)とコントロール部分(Phone Sensor)が独立して分離している点が特徴です。この特徴があるので、例えば同じコントロールの仕組みを使いながら画面はもっと大きな街中のビジョンに投影してもいいし、あるいはコントロール部分を別のデバイスにしたり、別の方法(例えば温度が上がったら右、下がったら左、のよう)に変更することも容易です。


実際の使い方はこんな感じです。まず IBM Bluemix にアクセスして Node-RED プロジェクトを作成します。この辺りの手続き等の詳細はこちらを参照ください:
Bluemix の Node-RED サービスで IoT アプリを作る(1/2)


ただプロジェクト作成において気をつけていただく点が何箇所かあります。まずボイラープレートを選ぶ際の選択肢です。Node-RED を使うアプリケーションプロジェクトをボイラープレートから作成する場合、"Internet of Things Foundation Starter" か "Node RED Starter" かのいずれかを選択することになるのですが、ここでは "Node RED Starter" のボイラープレートを選択してください:
2015061901


そしてアプリケーション名を指定して Node-RED Starter ボイラープレートからアプリケーションを「作成」します。ここではアプリケーション名に "dotnsf-nodered" と入力しています:
2015061902


作成後(ステージング中でも構いません)、左メニューの「コーディングの開始」を選択すると、作成した Node-RED アプリケーションのカスタマイズ方法を紹介する内容が画面右側に表示されます:
2015061903


ここを下にスクロールして "Customizing your Node-RED instance" と書かれた所に実際のカスタマイズ手順が紹介されています(この紹介が IoT Foundation Stater ボイラープレートにはありません)。ここで紹介されている2つの手順を行う必要があります。具体的には cf ツールのインストールと、スターターコードのダウンロードです:
2015061904


cf ツールは既にダウンロード&インストール済みであれば行う必要はありません。まだ cf ツールをインストールしたことがない場合はガイドに従って自分の環境にあったインストール用バイナリをダウンロードし、インストールしてください:
2015061907


一方、スターターコードは必ず必要になるため、ダウンロードのボタンをクリックします:
2015061908


自分が付けたプロジェクト名.zip という名前の zip ファイルのダウンロードが始まります。これを保存します:
2015061905


保存した zip ファイルを展開するとこんな内容になっています。これらはこの後ですぐに使うことになるので、適当なフォルダ(例えば /tmp/dotnsf-nodered)に展開しておきます:
2015061906



次にゲームを用意します。今回はオープンソースで公開されている HTML5 ベースのテトリスゲームを使うことにします。こちらを参考にさせていただきました:
http://coderecipe.jp/recipe/iHjJBJx9Si/

上記サイトで紹介されている6つのファイルをダウンロード/作成します。作成後、index.html だけは tetris.html とファイル名を変えておきます:
- index.html → tetris.html とリネーム
- style.css
- tetris.js
- render.js
- controller.js
- pop.ogg(効果音ファイル)

この6つのファイルを先程ダウンロード&展開した zip ファイルの展開先の、public フォルダに全てコピーします。このフォルダにはもともと css フォルダ、images フォルダと index.html ファイルが存在しているはずなので、6つのファイルをコピーした後はこのようなファイル構成になります:
2015061901


tetris.html ファイルを少し編集します。上記サイトでは pop.ogg ファイルを sound フォルダに、*.js ファイルを js フォルダに入れる想定で記述されています。そのような構成に作り変えてもいいのですが、tetris.html ファイルを変えて対応することにしました。tetris.html 内の <body> 部分を以下のように(同じフォルダ上のファイルを参照するように)書き換えます。また body タグの onload 属性に connect() を指定して、このファイルが読み込まれたタイミングで JavaScript の connect() 関数が実行されるよう指定します(青字部分を変更):
<!DOCTYPE html>
<html>
    <head>
        <title>HTML5 Tetris</title>
        <link rel='stylesheet' href='style.css' />
    </head>
    <body onload="connect()">
        <audio id="clearsound" src="./pop.ogg" preload="auto"></audio>
        <canvas width='300' height='600'></canvas>
        <script src='./tetris.js'></script>
        <script src='./controller.js'></script>
        <script src='./render.js'></script>
    </body>
</html>

そして controller.js も変更します。このファイルが入力キーによるゲームのコントロールを行う部分を担当しており、変更後はキー入力ではなく、WebSocket から取得するデータの内容によっていずれかのキーが押された時と同じ処理をするように変更します(青字部分を追加):
/* もとのキーボードによるコントール操作部分をすべてコメントアウトして無効にする
 キーボードを入力した時に一番最初に呼び出される処理
document.body.onkeydown = function( e ) {
  // キーに名前をセットする
  var keys = {
    37: 'left',
    39: 'right',
    40: 'down',
    38: 'rotate'
  };

  if ( typeof keys[ e.keyCode ] != 'undefined' ) {
    // セットされたキーの場合はtetris.jsに記述された処理を呼び出す
    keyPress( keys[ e.keyCode ] );
    // 描画処理を行う
    render();
  }
};
*/

// 無効にした部分を WebSocket からの入力に従って実行するように追加
var socket;
var th = 5; //. しきい値
var wsUrl = 'ws://' + location.hostname + '/ws/sensor';
function connect(){ // この処理が tetris.html のロード直後に呼ばれる
  socket = new WebSocket(wsUrl);
  socket.onmessage = function(e) {
    var sensorData = JSON.parse(e.data);

    if( sensorData.LR >= 50 ){ 
      // デバイスを右に50度傾けたら右方向キーが押されたとみなす
      keyPress( 'right' );
      render();
    }else if( sensorData.LR <= -50 ){
      // デバイスを左に50度傾けたら左方向キーが押されたとみなす
      keyPress( 'left' );
      render();
    }else if( sensorData.FB >= 50 || sensorData.FB <= -50 ){
      // デバイスを前後に50度傾けたら回転キーが押されたとみなす
      keyPress( 'rotate' );
      render();

      // 下に押されたとみなすキーは定義しない
    }
  }
}

// キーボードが押された時に呼び出される関数
function keyPress( key ) {
  :

これだけでゲームの改良は完成です。基本的にはキー操作部分を変更しただけです。ではこのゲーム部分を追加/変更したアプリケーションをデプロイします。

シェルやコマンドプロンプトを開き、zip ファイルを展開したディレクトリ(public フォルダが見えているディレクトリ)に移動してから Bluemix にログインし、アプリケーションをプッシュ(デプロイ)します:
# cd /tmp/dotnsf-nodered (カレントディレクトリを変更)

# cf login -a https://api.ng.bluemix.net/ (米国データセンターの場合)
# cf login -a https://api.eu-gb.bluemix.net/ (英国データセンターの場合)

# cf push dotnsf-nodered (作成したプロジェクト名を指定してプッシュ)


ゲームアプリのプッシュが完了すれば、後はセンサーデータを WebSocket に送る Node-RED 側を定義するだけです。

Node-RED のフローエディタを開き、中に何も記述されていない状態を作ります。何か書かれている場合は全て削除します。そして右上のハンバーガーメニューから Import > Clipboard を選択します:
2015061901



クリップボード画面が表示されます:
2015061902


この中に以下の内容をクリップボードにコピー&ペーストして OK ボタンをクリックします:
[
 {
  "id":"298b5c83.185f3c",
  "type":"websocket-listener",
  "path":"/ws/sensor",
  "wholemsg":"false"
 },
 {
  "id":"5bcc699c.5ca31",
  "type":"ibmiot in",
  "authentication":"quickstart",
  "apiKey":"",
  "inputType":"evt",
  "deviceId":"434444964396",
  "applicationId":"",
  "deviceType":"+",
  "eventType":"+",
  "commandType":"",
  "format":"json",
  "name":"Phone Sensor",
  "service":"quickstart",
  "allDevices":"",
  "allApplications":"",
  "allDeviceTypes":true,
  "allEvents":true,
  "allCommands":"",
  "allFormats":"",
  "x":82,
  "y":263,
  "z":"4fdac9e9.134208",
  "wires":[
   ["ed5efd2.39d978"]
  ]
 },
 {
  "id":"b4dded1e.e1a35",
  "type":"debug",
  "name":"",
  "active":false,
  "console":"false",
  "complete":"false",
  "x":537,
  "y":109,
  "z":"4fdac9e9.134208",
  "wires":[]
 },
 {
  "id":"ed5efd2.39d978",
  "type":"function",
  "name":"ペイロードデータ",
  "func":"\nreturn {payload:msg.payload.d};",
  "outputs":1,
  "valid":true,
  "x":220,
  "y":189,
  "z":"4fdac9e9.134208",
  "wires":[
   [
    "b4dded1e.e1a35",
    "771cdce9.22bb1c"
   ]
  ]
 },
 {
  "id":"f611f711.bd56d",
  "type":"debug",
  "name":"",
  "active":false,
  "console":"false",
  "complete":"false",
  "x":556,
  "y":192,
  "z":"4fdac9e9.134208",
  "wires":[]
 },
 {
  "id":"771cdce9.22bb1c",
  "type":"function",
  "name":"整形",
  "func":"\nreturn {payload:{\n    AX: msg.payload.accelX,\n    AY: msg.payload.accelY,\n    AZ: msg.payload.accelZ,\n    RX: msg.payload.rotationX,\n    RY: msg.payload.rotationY,\n    RZ: msg.payload.rotationZ,\n    LR: msg.payload.tiltLR,\n    FB: msg.payload.tiltFB\n}};",
  "outputs":1,
  "valid":true,
  "x":350,
  "y":240,
  "z":"4fdac9e9.134208",
  "wires":[
   [
    "f611f711.bd56d",
    "f7300e6c.db39"
   ]
  ]
 },
 {
  "id":"f7300e6c.db39",
  "type":"websocket out",
  "name":"",
  "server":"298b5c83.185f3c",
  "client":"",
  "x":533,
  "y":243,
  "z":"4fdac9e9.134208",
  "wires":[]
 }
]

こんな感じのフローがインポートされるはずです。内容は非常にシンプルで、Phone Sensor から送られてくるスマホの動きや傾きの情報を扱いやすいように整形した上で、 /ws/sensor というパスへ WebSocket で一方的に送っているだけです。2つほど無効なデバッグノードを使ってますが、興味ある方は有効にして送られてくるデータを確認してみてください:
2015061903


次にコントローラーとして使うスマホのブラウザで上記 Phone Sensor サイトにアクセスします。そこで以下の様な画面が表示されるので、赤枠部分に表示される数字文字列(=デバイスID この例だと 434367967328)をメモしておきます。なお、このページは(デバイスの動きを検知して情報を送信する目的で使うため)ゲームを終えるまで閉じないでください:
2015061603


先程の Node-RED エディタ画面に戻って "Phone Sensor" と書かれたノードをダブルクリックします:
2015061904


先程の Phone Sensor ページでメモしたデバイス ID を Device Id 欄に入力して OK ボタンをクリック:
2015061905


最後のフローエディタ右上の "Deploy" ボタンをクリックしてアプリケーションを有効にします。これで Node-RED 側の準備も完了です:
2015061906


では実際にゲームを動かしてみます。PC など、コントローラーとするスマホ以外の環境から http://(プロジェクトのサーバー)/tetris.html にアクセスします。テトリスのゲームがはじまり、ブロックが落ちてくるはずです:
2015061901


コントローラーとして使うスマホ(http://phonesensor.mybluemix.net/ を開いているはずです)を左右に傾けるとブロックは左右に、前後に傾けるとブロックは回転するはずです。上手く操作して遊んでみてください:
2015061902



なお、現状ではかなり雑な操作ロジックにしているので、必ずしも操作しやすいわけではないです(苦笑)。このあたり、controller.js を変更することでもう少し使いやすくしたり、あるいは別の動作(振る、とか)をブロックの操作に変えたりもできるはずです。是非挑戦してみてください。

(プレイ動画)



 

このページのトップヘ