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

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

タグ:nodejs

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 にデータを送信するサンプルとして使ってくださいませ。

たまに子供や初心者を相手にプログラミングを教えてみせたりする際に 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 接続はこんな感じで実現できるようです。

IBM Watson の比較的新しい API の1つである Watson Data Kit を使ってみました。ちなみにこのブログエントリを書いている 2018/Apr/28 の時点ではこの API はベータ版扱いとなっており、無料で利用できますが、ライトプランから利用することはできないようです。

この API は収集・解析済みのデータにアクセスすることができる API です。具体的にはある地点(緯度&経度)と調査半径(マイル)を指定すると、そのエリア内に含まれる観光名所やアトラクションをまとめて教えてくれる、というものです。特別に明記されているわけではないのですが、使っている限りでの印象として、現時点ではどうやら USA のデータ中心に提供されているようです。

使ってみるには IBM Cloud のダッシュボードから、「アプリケーション・サービス」カテゴリ内にある "Watson Data Kits" を選びます。 「Watson」カテゴリではなく「アプリケーション・サービス」カテゴリ内にあることに注意が必要です:
2018042800


そしてプランを選択してサービスを作成します。現時点では利用制限のない Free plan (無料)のみが提供されているようです:
2018042802


Watson Data Kit サービス作成後、サービス資格情報メニューから資格情報を(必要であれば作成した上で)参照します。この中の apikey と書かれている値と、instance-id と書かれている値が後で必要になります:
2018042803


これらの値を使って、以下のような Node.js のアプリケーションを作ってみました。(apikey) 部分と (instance-id) 部分を上記で取得した値に書き換えると動くようになる、と思います。また以下の例では米国ニューヨーク辺りの位置(北緯 40.73061 度、西経 73.935242 度)と、そこからの半径 5 マイル内のアトラクション( /attractions)を検索し、名称(name)と説明(description)を表示しています:

var request = require( 'request' );

var settings = {
  apikey: '(apikey)',
  instance_id: '(instance id)'
};

// NY
var lat = 40.73061;
var lng = -73.935242;

var radius = 5;  //. 半径 5 マイル

//. アクセストークン取得
var options = {
  url: 'https://iam.bluemix.net/identity/token',
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  form: { grant_type: 'urn:ibm:params:oauth:grant-type:apikey', apikey: settings.apikey },
  json: true
};
request( options, ( err, res, body ) => {
  if( err ){
    console.log( err );
  }else{
    var access_token = body.access_token; //. アクセストークン値

    //. アクセストークンを使って、/attractions API を実行する
    var access_headers = {
      'Authorization': 'Bearer ' + access_token,
      'Instance-ID': settings.instance_id
    };
    var access_options = {
      method: 'GET',
      hostname: 'wck-2.us-south.containers.mybluemix.net',
      port: null,
      uri: settings.apiurl + '/travel/v1/attractions?location=' + lat + ',' + lng + '&radius_miles=' + radius,
      headers: access_headers
    };
    request( access_options, ( err1, res1, body1 ) => {
      if( err1 ){
        console.log( err1 );
      }else{
        body1 = JSON.parse( body1 );
        body1.results.forEach( function( attraction ){
          console.log( attraction.name );
          console.log( ' ' + attraction.description );
        });
      }
    });
  }
});


上記を実行するためにまず apikey 値を使ってアクセストークンを取得し、取得したアクセストークンと instance-id 値を使って /attractions API を実行しています。この辺りの詳しい情報はチュートリアルを参照ください:

https://console.bluemix.net/docs/services/watson-data-kits/index.html#getting-started-tutorial


これを実行するとこんな感じになりました。青字部分が名称(name)で、黒地が説明(description)です:
$ node attractions.js
Calvary Cemetery
 Calvary Cemetery is a Roman Catholic cemetery in Maspeth and Woodside, Queens, in New York City, New York, United States. With about 3 million burials, it has the largest number of interments of any cemetery in the United States; it is also one of the oldest cemeteries in the United States. It covers 365 acres and is owned by the Roman Catholic Archdiocese of New York and managed by the Trustees of St. Patrick's Cathedral.
Calvary Cemetery is divided into four sections, spread across the neighborhoods of Maspeth and Woodside. The oldest, First Calvary, is also called "Old Calvary." The Second, Third and Fourth sections are all considered part of "New Calvary."
* First Calvary Cemetery is located between the Long Island Expressway and Review Avenue. The cemetery's offices are located here, at 49?02 Laurel Hill Boulevard.
* Second Calvary Cemetery is located on the west side of 58th Street between Queens Boulevard and the Brooklyn?Queens Expressway.
* Third Calvary Cemetery is located on the west side of 58th Street between the Long Island Expressway and the Brooklyn?Queens Expressway.
* Fourth Calvary Cemetery is located on the west side of 58th Street between the Long Island Expressway and 55th Avenue.
McCarren Park
 McCarren Park is a public park in Brooklyn, New York City. It is located in Greenpoint, Brooklyn and is bordered by Nassau Avenue, Bayard Street, Lorimer Street and North 12th Street. It is operated by the New York City Department of Parks and Recreation. Opened in 1906 and originally named Greenpoint Park, the park was renamed McCarren Park in 1909 after State Senator Patrick H. McCarren who began work as a cooper at Williamsburg sugar refineries and eventually became the Democratic boss of Brooklyn. The park is a popular destination for recreational softball, volleyball, soccer, handball, and other games. It is also used for sunbathing and dog-walking. In late 2004, the park's track was resurfaced and has been a popular destination for running enthusiasts.
Events on the baseball fields of McCarren Park include members of the punk and indie communities gathering to participate in league-controlled kickball tournaments. For several years, the baseball fields have hosted tournament play for the Hasidim; weekend afternoons provide T-ball and softball games for organized area youth groups; Latino families and friends often utilize the fields to play soccer and volleyball into the late hours of the night. Since June 2003, McCarren Park has hosted SummerScreen in McCarren Park, and The Renegade Craft Fair, a DIY event. The fair attracts artists and creative types, featuring a wide range of merchandise such as reconstructed clothing, comic books, tote bags and other handmade goods.
Pulaski Bridge
 The Pulaski Bridge in New York City connects Long Island City in Queens to Greenpoint in Brooklyn over Newtown Creek. It was named after Polish military commander and American Revolutionary War fighter Kazimierz Pu?aski because of the large Polish-American population in Greenpoint. It connects 11th Street in Queens to McGuinness Boulevard (formerly Oakland Street) in Brooklyn.
5 Pointz
 5 Pointz: The Institute of Higher Burnin' or 5Pointz Aerosol Art Center, Inc., mainly referred to as simply 5 Pointz or 5Pointz, was an American mural space at 45?46 Davis Street in Long Island City, Queens, New York City. When it opened in 1892, it housed the Neptune Meter factory, which built water meters.
   :
   :

位置情報サービスに対して、その周辺のアトラクションやキーワードとなる付加情報を加えることができるようになる、面白い API だと感じました。



JavaScript で JSON 配列をソートする、意外と簡単な方法があります。具体例として、例えば以下のような JSON 配列: myArray があったときに、
var myArray = [
 { id: 1, name: "鈴木", age: 30 },
 { id: 2, name: "田中", age: 29 },
 { id: 3, name: "佐藤", age: 35 },
   :
];

この JSON 配列を age 要素の小さい順にソートしたいという場合にどうやるか、というケースを紹介します。


まず、JavaScript の配列には sort 関数が標準で用意されています。直感的にこんな感じで使えます:
var array1 = [ 30, 29, 35 ];
array1.sort();                  //. => array1 = [ 29, 30, 35 ];

注意点として sort() 実行後の返り値がソート結果になるのではなく、実行すると array1 そのものが書き換えられる、という点に注意が必要です。

sort() 関数には比較関数をパラメータで指定して、比較方法を指定することもできます。例えば以下の例では比較関数 compare を「小さい順に並べる」ような内容にしているので、sort() 実行後に小さい順にソートされます(要するに普通の sort() と同じ結果になります):
//. 比較関数
function compare( a, b ){ var r = 0; if( a < b ){ r = -1; } else if( a > b ){ r = 1; } return r; }
var array2 = [ 30, 29, 35 ]; array2.sort( compare ); //. => array2 = [ 29, 30, 35 ];

比較関数はパラメータ a と b の大小関係をその返り値によって定義します:
・返り値が 0 より小さい場合、a < b(aはbよりも前に来る)
・返り値が 0 より大きい場合、a > b(aはbよりも後ろに来る)
・返り値が 0 の場合、a = b(aとbの位置関係は変わらない)

したがって、compare 関数の返り値の符号を逆にすると「大きい順に並べる」という比較関数を指定したことになり、sort() 実行後に大きい順にソートされます:
//. 比較関数
function compare( a, b ){ var r = 0; if( a < b ){ r = -1; } else if( a > b ){ r = 1; } return ( -1 * r ); } var array3 = [ 30, 29, 35 ]; array3.sort( compare ); //. => array3 = [ 35, 30, 29 ];

上記 JSON 配列のソートもこの比較関数を使った sort() の応用で可能になります。具体的には以下のように age 要素で大小比較するような比較関数を用意します:
//. 比較関数
function compare( a, b ){ var r = 0; if( a.age < b.age ){ r = -1; } else if( a.age > b.age ){ r = 1; } return r; }
var myArray = [ { id: 1, name: "鈴木", age: 30 }, { id: 2, name: "田中", age: 29 }, { id: 3, name: "佐藤", age: 35 }, : ]; myArray.sort( compare );

これだけ。応用も簡単にできそうで超便利。


このページのトップヘ