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

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

2018年05月

IBM Cloud から提供されている IoT サービスである IBM Watson IoT Platform (の QuickStart)にメッセージをパブリッシュする Node.js のサンプルアプリケーション(とソースコード)を作って公開しました:
https://github.com/dotnsf/mqtt_pub_ibmiot

2018051501


主要なソースコードは app.js だけですが、内部的に MQTT.js ライブラリを使っています:
2018051500


主な挙動としては settings.js で指定された内容に併せて、1秒(デフォルト)ごとに0から1つずつ増えるカウンタ値、タイムスタンプ値、実行したマシンの CPU 稼働率、12回周期のサイン値およびコサイン値、そしてランダムな値が JSON で IBM Watson IoT Platform の QuickStart に送られます。その際のデバイス ID 値は settings.js 内で指定されていればその値が、されていなければ動的に生成されるようにしました。


IBM Cloud 環境で Node-RED ランタイムを作ると動作を確認しやすく、またそのためカスタマイズの勘所が分かりやすいと思っています。以下、この環境での動作確認方法を紹介します。

まずはこのサンプルを動かす前提として Node.js がインストールされたマシンが必要です。Windows/MacOS/Linux/Raspberry Pi などなど、Node.js をインストール可能なマシンで導入を済ませていると仮定して以下を続けます。

次に上記リポジトリから git clone またはダウンロード&展開して、アプリケーションのソースコードを手元に用意します:
$ git clone https://github.com/dotnsf/mqtt_pub_ibmiot
$ cd mqtt_pub_ibmiot

必要に応じてテキストエディタで settings.js の中身を編集します。とはいえ、変える必要がありそうなのは exports.interval の値(メッセージデータを送信する時間間隔(ミリ秒)。デフォルト値は 1000 なので1秒ごとにメッセージを送信する)と、exports.deviceId の値(後で指定するデバイス ID。デフォルトは空文字列なので、後で自動生成された値になります)くらいです。なお、settings.js の値は変えなくても動きます。


※もし exports.deviceId の値を編集する場合は、("test" のような簡単な単語ではなく)他の人が使わないようなユニークな値になるよう指定してください。exports.deviceId の値をデフォルトのから文字列のままにする場合は、実行時ごとにデバイス ID を生成するので、この値は実行ごとに変わることに留意してください。


ではアプリケーションの動作に必要なライブラリをインストールします:
$ npm install

そして実行します:
$ node app

実行が成功して IBM Watson IoT Platform に接続すると、"client#connect: " という文字列に続いてデバイス ID が画面に表示されます(以下の例では 5d7436e992d0)。この値は settings.js で指定した場合はその値が、指定しなかった場合は自動生成された値が表示されます。この後で使うのでメモしておきます:
2018051502


※なお、メッセージを送信しているアプリケーションの終了方法は特に用意していないので、終了する場合は Ctrl+C で強制終了してください。


これでサンプルアプリケーションが IBM Watson IoT Platform に接続し、exports.interval で指定した値の間隔でメッセージデータを送信し続けている状態になりました。

最後にこの送信データを Node-RED で確認してみます。IBM Cloud で Node-RED ランタイムを作成し、IBM IoT のインプットノード(右側にジョイントのあるノード)と、debug アウトプットノードをキャンバスに配置して接続します:
2018051503


↑IBM Watson IoT Platform サーバーにメッセージが送られてきたらその payload の内容をデバッグタブに表示する、というシンプルなフローです。


IBM IoT インプットノードをダブルクリックし、Authentication が Quickstart になっていることを確認した上で、Device Id 欄に先程確認した実行中アプリケーションのデバイス ID を指定します。そして「完了」してから、このアプリケーションを「デプロイ」します:
2018051504


すると、Node-RED 画面右のデバッグタブに(デフォルトであれば)1秒おきにメッセージが追加されていく様子が確認できるはずです:
2018051505


メッセージの1つを選んで展開してみると、元のアプリケーションから送信されたカウント値(count)、タイムスタンプ値(timestamp)、CPU稼働率(cpu)、サイン値(sin)、コサイン値(cos)、そして乱数値(random)が確認できます。つまり Node.js を使って動かしたアプリケーションから MQTT 経由で実際にデータが送信されていて、その内容を Node-RED と IBM IoT インプットノードを使って取り出して確認できたことになります:
2018051506


送信データをカスタマイズしたり、別の値を送信したい場合は app.js をカスタマイズして、publish 時に送信する data 変数の中身を変える(必要な値を取得して、この中に JSON で入れる)ということになります。こちらはシンプルなのでなんとなく理解できるんじゃないかな・・・と期待しています。


また Node-RED の場合であれば node-red-dashboard と組み合わせることで、ここで取得した値を簡単にチャート化することもできます。例えば Gauge ノードと Chart ノードを使って CPU 負荷とサインカーブをこんな感じで・・・
2018051600


IBM Watson IoT Platform の Quickstart にデータを送信するサンプルとして使ってくださいませ。

今月(2018年5月)から GitHub ページがカスタムドメインでも HTTPS 対応された、という発表がありました:
Custom domains on GitHub Pages gain support for HTTPS

2018051001


というわけで、自分が取得しているドメインを使って試してみました。以下、GitHub ページの紹介と、その手順を含めた報告です。


GitHub ページとは?

GitHub ページとは GitHub の仕組みを使った静的ウェブサイトのホスティングサービスです。GitHub アカウントを持っていれば、誰でも簡単にウェブサイトを作って公開することができるので、非常に便利です。


GitHub ページの作り方

index.html 一枚だけの非常にシンプルな例で紹介します。まずは普通に Github でリポジトリを作成し、GitHub ページ(ウェブサイト)に含めたい HTML ファイルその他をまとめてプッシュし、公開します:
2018051002


この時点で、同リポジトリが GitHub で普通に公開されている状態になりました:
https://github.com/dotnsf/githubpagessample


(今回、公開する index.html ファイルの中身)
https://raw.githubusercontent.com/dotnsf/githubpagessample/master/index.html


次にこのリポジトリを GitHub ページとして公開します。リポジトリのページから "Settings" メニューを選択します:
2018051003


少しスクロールして GitHub Pages の設定欄を表示し、Source が None になっている所を "master branch" に変更して "Save" します。これでこのリポジトリのマスターブランチが Github Pages として公開されることになります:
2018051004


"Save" が成功すると画面内に GitHub Pages として参照する場合の URL が表示されます。一般的にはここは https://(ログイン名).github.io/(リポジトリ名)/ となります:
2018051005


この URL にアクセスしてみると、先程のリポジトリのマスターブランチが HTTP サーバーのドキュメントルートとして扱われる感じになり、index.html ファイルが表示されます。またこの画面からもわかるように、このページは HTTPS 対応しています:
2018051102


以上、ここまでが GitHub ページの説明です。


カスタムドメインで GitHub ページを使ってみる

今回の更新で、上記の GitHub ページがカスタムドメインでも HTTPS 対応されるようになりました。この点を確認したいので、まずは GitHub ページをカスタムドメイン対応してみます。

そのためには GoDaddyお名前.comなどのドメイン業者でドメインを取得しておく必要があります。ここはどうしても無料というわけにはいかず、ドメインの種類にもよりますが、1年間 $10 程度かかってしまうことを理解した上で取得してください。ちなみに自分は(B'z ファンでもないのに) welove.bz というドメインを GoDaddy で取得しているので、このドメインを使って GitHub ページをカスタムドメイン対応する手順を以下に紹介します。

最初に、対象ドメインの DNS 設定を変更する必要があります。このページの "Configuring A records with your DNS provider" という項目によると、ホスト名の A レコードの IP アドレスを以下のように設定する必要があるようです:
2018051103


A レコードの IP アドレスを複数設定できる場合はこの4つの IP アドレスを設定します。僕が使っている GoDaddy では1つしか設定できないようだったので、一番上のアドレスに指定しました:
2018051104


この部分は同様の作業をドメイン業者の用意したツールを使って設定してください。 なおこの作業について、詳しくは GitHub のドキュメントも参照ください:
https://help.github.com/articles/setting-up-an-apex-domain/


この作業の後で、GitHub の該当リポジトリに CNAME という名前のファイルを1つ追加します。CNAME ファイルの中身にはカスタムドメイン名だけを記載します:
2018051105


このファイルをリポジトリに add して commit して push します:
2018051106

2018051107


最後に再びリポジトリの settings 画面を確認して、GitHub ページのカスタムドメインが設定されている(されていない場合は、ドメイン名を入力して "Save")ことを確認します。これで GitHub ページのカスタムドメイン設定ができました:
2018051108


この状態で http://(カスタムドメイン名) にアクセスすると、先程まで ***.github.io ドメインで動いていた GitHub ページが表示されます:
2018051101


これで GitHub ページのカスタムドメイン化が完了しました。



カスタムドメイン GitHub ページの HTTPS 対応

やっと本題です(苦笑)。ここまでの作業で GitHub ページがカスタムドメインで利用できるようになりました。今回の目的は「このページを HTTPS 対応にする」ことです。

そのための設定はリポジトリの settings で、カスタムドメインを指定した下に "Enforce HTTPS" というフィールドがあるので、ここにチェックを入れるだけ・・・
2018051101



・・・なのですが、まだ証明書が有効になっていないようです(チェックできない)。こうなると作業としてできることはないので、ひたすら待つ必要があります。

ちなみに、この状態で無理やり HTTPS を指定して https://(カスタムドメイン名)/ にアクセスすると「安全な接続ではない」と言われます。ここから例外を承認して・・・ということもできないわけではないですが、せっかくなのでしばらく待ちましょう:
2018051102


しばらく待つとこの部分のメッセージが変わり、"Enforce HTTPS" がチェック可能になります:
2018051103


チェックするとこのような画面になり、このリポジトリの GitHub ページは強制的に(HTTP でリクエストしても)HTTPS でアクセスされるようになります:
2018051104


実際にアクセスしてみました。ちゃんと HTTPS に転送されています:
スクリーンショット 2018-05-11 15.38.40


HTTPS のインフォメーションを確認しても(オレオレ証明書とかではなく)"Secure Connection" になっていることが確認できます:
スクリーンショット 2018-05-11 15.39.12



(おまけ)
ではこの証明書は誰がどうやって発行しているのだろう? と疑問に思ったのですが、"Verified by: Let's Encrypt" だそうです。なるほどね・・・:
スクリーンショット 2018-05-11 15.38.58


めでたし、めでたし。
ところでこの welove.bz ドメイン、なんかいい使いみちないかな? (^^;


IBM Cloud から提供されているコグニティブエンジン IBM Watson を使って、
 1. MNIST の手書き数字サンプルデータを学習させて、
 2. 実際に手書き数字データを送信して、認識させる
という、「学習」と「問い合わせ」のコグニティブエンジン一連の作業を再現させてみます(した)。


今回紹介する一連の作業では、IBM Cloud の以下のサービスを連動させて使います:
 ・IBM Watson Studio
 ・IBM Machine Learning
 ・IBM Cloud Storage
 ・SDK for Node.js ランタイム(上記2のサンプルをクラウド上で稼働させる場合)

以下で紹介する手順は IBM Cloud の無料版であるライトアカウントを使っても同様に動かすことができるようにしているので、興味ある方は是非挑戦してみてください。


1. MNIST の手書き数字サンプルデータを学習させる

人工知能とか機械学習とかを勉強していると、そのチュートリアルとして "MNIST" (Modified National Institute of Standards and Technology)を目にする機会があると思っています。機械学習のサンプルとして手書きで描かれた数字の画像データと、そのラベル(何の数字を描いた画像なのか、の答)が大量にサンプルデータとして公開されており、機械学習を説明する際の様々な場面で使われています:
2018050800


今回、この MNIST データを IBM Watson StudioIBM Watson Machine Learning を使って学習させ、かつ問い合わせ用の REST API を用意します。

・・・と、偉そうに書いていますが、この部分の手順については私の尊敬する大先輩・石田剛さんが Qiita 上でわかりやすく紹介していただいています。今回の学習部分についてはこの内容をそっくりそのまま使わせていただくことにします(石田さん、了承ありがとうございます):
Watson Studioのディープラーニング機能(DLaaS)を使ってみた 

2018050801

↑この作業で MNIST の手書き画像を IBM Watson Machine Learning を使って学習させ、その問い合わせ API を REST API で作成する、という所までが完了します。


2. 手書き数字データを送信して、認識させる

マウスやタッチ操作で画面に手書き数字を描き、その内容を 1. の作業で用意した REST API にポストして何の数字と認識するか、を確認できるようなアプリケーションを作成します。

・・・というか、しました(笑):
2018050804


PC またはスマホでこちらのサイトにアクセスすると体験できるようにしています:
https://dotnsf-fingerwrite-mnist.us-east.mybluemix.net/


フロントエンドはもともと以前に「イラツイ」という手描きイラスト付きツイートサービスを作った際のものを丸パク応用し、問い合わせ API を呼び出すバックエンド部分はデプロイしたモデルの Implementation タブ内にある JavaScript の Code Snippets を参考に作りました。この Code Snippents は各種言語のサンプル(アクセストークンを取得してエンドポイントにリクエストするサンプル)が用意されていて、とても便利です:
2018050809


アプリケーションの使い方はマウスまたは指でキャンパス部分に数字を描いて、"fingerwrite" ボタンを押すと、その描いた数字データを上記 1. で作成した REST API を使って識別し、最も可能性が高い、と判断された数値とその確率が表示される、というものです:
2018050805


PC 画面の場合に限りますが、デバッグコンソールを表示した状態で上記を実行すると、可能性が最も高いと思われた結果だけでなく、全ての数値ごとの確率を確認することもできます:
2018050806

↑常に「2」の確率が高くなってる気がする。。原因は学習の調整不足だろうか??それともデータを渡すフロントエンド側??(2018/May/09 ピクセル毎のデータを取り出すロジックに不具合があったので、修正しました)


なお、この 2. のサンプルアプリは Node.js のソースコードを公開しているので、興味ある方は自分でも同様のサイトを作成してみてください:
https://github.com/dotnsf/fingerwrite-mnist

2018050807


このソースコードから動かす場合、事前に settings.js ファイルを編集しておく必要があります:
2018050808


まず上の3つ、 exports.wml_url, exports.wml_username, exports.wml_password の3つの変数の値は 1. で MNIST データを学習した際に使った IBM Watson Machine Learning サービスのサービス資格情報を確認して、その中の url, username, password の値をそれぞれコピー&ペーストしてください(最初の exports.wml_url だけはおそらくデフォルトで url の値になっていると思います。異なっていた場合のみ編集してください):
2018050803


また一番下の exports.ws_endpoint の値は同様に 1. で使った IBM Watson Studio の Web サービスのエンドポイント(学習モデルをデプロイした時に作成した Web サービス画面の Implementation タブから確認できる Scoring End-point の値)をそのまま指定します:
2018050802


ここまでの準備ができた上でアプリケーションを実行します。ローカル環境で動かす場合は普通に npm install して node app で起動します:
$ npm install
$ node app

IBM Cloud (の SDK for Node.js)を使って動かす場合は、cf ツールbx ツールを使って、そのまま cf push で公開されます:
$ cf push (appname)


今回紹介した方法では IBM Watson Studio と IBM Watson Machine Learning を使って画像データを学習させ、その学習結果に対して REST API で問い合わせをする、という機械学習の一連の流れを体験できます。また学習データ(とモデリング)を変更することで、異なる内容の学習をさせる応用もできますし、学習した内容に問い合わせを行う API も自動生成されるので、フロントエンドの開発も非常に楽でした。
 

たまに子供や初心者を相手にプログラミングを教えてみせたりする際に Scratch を使っています:
Screenshot from 2018-05-04 15-28-23


MIT メディアラボが開発した GUI によるプログラミング開発言語および実行環境です。プログラムをエディタでガリガリと記述するような、いわゆる「コーディング」に相当する作業があまり必要なく、GUI を中心とした見た目に対する処理や変更をイベント単位に足していきながら少しずつ動くものを作っていくものです。そのためユーザーが完成形をイメージしながら作っていくことができ、コーディングそのものに不慣れな人がプログラミングを理解するのに向いていると思っています。

この Scratch は良くも悪くも GUI 中心の作業になるため、他の環境との連携が難しい(というか、そもそもどういう外部インターフェースが用意されているのかわかっていなかった)という印象を持っていました。Scratch の閉じた世界の中では初心者にも簡単でわかりやすい、という面があるのと同時に、Scratch 以外の環境とは繋がりにくいと思っていました。

で、なんかインターフェースが公開されてないかなあ・・・ と思って探していたら、この Scratch の国内第一人者でもある石原さんが書かれた一連のブログを見つけました:
Scratch(スクラッチ)を外部のプログラムなどとつなぐ「遠隔センサー接続」を解説する(その1)


↑このブログで書かれている内容は Scratch 1.4 の「遠隔センサーを有効に設定」して 42001 番ポートを開放した上で、TCP/IP のメッセージングによる連携を Ruby で行う、というものです。基本的にはほぼ同じ内容を Node.js で実装してみようと思い、調べた結果をまとめました。


なお、石原さんは「まちくえすと」の開発などで活躍されていてご存知の方もいらっしゃると思いますが、拙作マンホールマップiOS アプリ版の開発に尽力いただいたご縁もあり、そのお付き合いの中で Scratch のことも教えていただきました。僕にとっては「Scratch の先生」でもあります。石原さん、このブログとても助かりました。ありがとうございます!



まず、以下の作業を行う前提として、Scratch はローカルインストール可能なバージョン 1.4 を使う必要があります。公式サイトからオンライン版であるバージョン 2.0 以降を利用することも可能ですが、以下で紹介する Node.js 連携は Scratch 1.4 をローカルインストールして使う想定で記載しています。各種 OS 向けの Scratch 1.4 はこちらからダウンロードして導入してください(以下、Ubuntu 16.04 環境に Scratch 1.4 を導入した前提で記述します):
https://scratch.mit.edu/scratch_1.4/



まず最初に、Scrach を外部連携するためのポート開放を行います。Scratch 1.4 を起動し、「調べる」カテゴリ内「●●センサーの値」と書かれたブロックを右クリックして、「遠隔センサー接続を有効にする」を選択します:
Screenshot from 2018-05-04 15-29-09


すると「遠隔センサー接続が有効になりました」という確認ダイアログが表示されます:
Screenshot from 2018-05-04 15-29-39



この作業後、Scratch は 42001 番ポートで接続できるようになっています。つまり僕の以前のブログで紹介したような TCP/IP プログラミングによって Scratch との TCP/IP 接続が可能になっているのでした。試しに以下のような Node.js プログラム(scratch01.js)を書いて実行してみます(以前のブログで書いたものよりも更に簡略化し、最小限必要な内容だけにしています):
var net = require( 'net' );

//. 接続先 IP アドレスとポート番号
var host = '127.0.0.1';
var port = 42001;

//. 接続
var client = new net.Socket();
client.connect( port, host, function(){
  console.log( '接続: ' + host + ':' + port );
});

//. サーバーからメッセージを受信したら、その内容を表示する
client.on( 'data', function( data ){
  console.log( '' + data );
});

↑このプログラムを実行すると、127.0.0.1(自分自身)の 42001 番ポートに TCP/IP 接続し、接続先から何かメッセージが送られてくるとそのメッセージ内容を文字列化してそのまま表示する、というものです。これをまず node コマンドを使って実行しておきます:
$ node scratch01.js

これで 42001 番ポートに接続し、メッセージの受信待ち状態になりました。


そして Scratch 側からはこの(42001 番ポートの)接続先に対してメッセージを送信してみます。この処理を行うには「制御」カテゴリ内「●●を送る」ブロックを使います:
Screenshot from 2018-05-04 15-40-55


同ブロックを右クリックして「新規」を選択し、メッセージの名前を任意に指定します。以下の例ではメッセージの名前に Hello と指定してます:
Screenshot from 2018-05-04 15-42-14


するとブロックの表示内容が「Hello を送る」と切り替わります。この状態で同ブロックを何度かマウスでクリックします(クリックするたびにこのブロックが処理を実行します):
Screenshot from 2018-05-04 15-42-41


すると先に実行していた Node.js プログラムのコンソール画面に(最初の制御文字に続いて) 
broadcast "Hello"
という文字行がクリックするたびに表示されます:
Screenshot from 2018-05-04 15-46-59


この結果から Scratch の「●●を送る」ブロックを1回実行すると
broadcast "(指定したメッセージ)"

という文字列が送信される、ということが分かりました。これで Scratch から Node.js のプログラムにメッセージを送信し、Node.js プログラム側でその内容を受信することができました。


この応用で逆に Node.js から Scratch にメッセージを送ることもできます。例えば scratch02.js を以下の内容で作成します(接続後に 'broadcast "a"' というメッセージを Scratch に送信する、という内容です):
//. scratch02.js
var net = require( 'net' );
var host = '127.0.0.1';
var port = 42001;

var client = new net.Socket();
client.connect( port, host, function(){
  console.log( '接続: ' + host + ':' + port );

  var msg = 'broadcast "a"';
  var len = msg.length;
  var buf = pack( len );
  client.write( buf + msg );  //. msg の内容を Scratch へ送信
});

//. 4バイトのバイト列(Buffer)に変換
function pack( n ){
  var m1 = n % 256;
  n = Math.floor( n / 256 );
  var m2 = n % 256;
  n = Math.floor( n / 256 );
  var m3 = n % 256;
  var m4 = Math.floor( n / 256 );

  return new Buffer( [ m4, m3, m2, m1 ] );
}



そして Scratch 側では 'broadcast "a"' というメッセージを受け取ったら何らかの処理がスタートする、というプログラムを書いておきます(下の例ではスプライト1の猫のキャラクターが画面内を歩き始める処理がスタートする、という内容にしています):
Screenshot from 2018-05-05 15-54-06


この状態で scratch02.js を実行すると、TCP/IP 通信によって Scratch に接続し、broadcast "a" というメッセージが送られ、Scratch のスプライト1のキャラクターが壁に跳ね返りながら動き回る処理がスタートします(特に止める方法を用意していないので、止めるには画面右上の赤丸部分をクリックしてください):
Screenshot from 2018-05-05 16-02-12


これで Scratch から Nodejs にメッセージを送ったり、逆に Node.js から Scratch にメッセージを送る、ということが実現できました。

 

Node.js はサーバーサイドで動く JavaScript ということもあって、Express などを使ってサーバーサイドのアプリケーションランタイムとして利用することが多いと思っています。

が、必ずしもサーバーサイド開発言語にのみに使えるということはなく、クライアント側のアプリケーションを記述・実行することも可能です。そんな一例として(HTTP よりも汎用的な)TCP/IP を使ったクライアントアプリケーションを作るサンプルを紹介します。

以下は 127.0.0.1 の 42001 番ポートで待ち受けるサーバーに対して、クライアントとして接続したり、メッセージを送信したり、受信したり、切断したときの挙動を実装しています:

var net = require( 'net' );

//. 接続先 IP アドレスとポート番号
var host = '127.0.0.1';
var port = 42001;

//. 接続 var client = new net.Socket(); client.connect( port, host, function(){ console.log( '接続: ' + host + ':' + port ); //. サーバーへメッセージを送信 client.write( 'ハロー' ); }); //. サーバーからメッセージを受信したら、その内容を表示する client.on( 'data', function( data ){ console.log( data ); }); //. 接続が切断されたら、その旨をメッセージで表示する client.on( 'close', function(){ console.log( '切断' ); })

実際の挙動としてはサーバーへメッセージを送る必要があるのかないのか、サーバーからメッセージを受信することがあるのかないのか、・・・といったサーバー側の挙動も考慮してクライアント側を作ることになりますが、特定のポートに対する TCP/IP 接続はこんな感じで実現できるようです。

このページのトップヘ