Node.js + Socket.IO + pm2でデーモン化とクラスタリング

Socket.IOをpm2でクラスタリングするには、ちょっと工夫が必要だったのでメモ

forever

Node.jsのデーモン化といえばforeverです。しかしクラスタリングしようとすると、Node.jsのコードをクラスタリング対応で書かないといけないのでやや面倒だったりします。今回、foreverよりも高機能なpm2を使ってクラスタリングを試してみました。

pm2

pm2はforeverと同じようにNode.jsをデーモン化するツールですが、モニタ機能やクラスタリング機能などかなり高機能になっています。

pm2のインストール

pm2はグローバルでインストールします。

$ npm install -g pm2

対応するNode.jsのバージョンは古いと動かないかもしれません。今回はv0.10.20(on Mac)で動作確認しました。動かすNode.jsアプリはこちらのSocket.IOのサンプルアプリです。このコードだとSocket.IOのバージョンが古いようなので、一旦npm uninstall socket.ioして、再度npm install socket.ioで再インストールしました。

pm2を使ってクラスタリング

$ pm2 start app.js -i max

として起動するとプロセスがCPUコア数分だけ起動し、クラスタリングされます。簡単ですね。起動リストを表示させるには

$ pm2 list

f:id:tomo_watanabe:20140131120059p:plain

プロセスが4つ起動されているのがわかります。この時にブラウザでアクセスして確認します。

f:id:tomo_watanabe:20140131120326p:plain

片方がxhr-pollingになってたりしますね。これリロードするとwebsocketになったり、xhr-pollingになったりなんとも不安定になります。

ログを表示するには

$ pm2 logs

f:id:tomo_watanabe:20140131120712p:plain

ところどころに警告がでています。

warn  - client not handshaken client should reconnect

調べてみるとSocket.IOの接続に起因するものでSocket.IO or WebSocket を AmazonELB でバランスする検証にありました。

つまり、 Socket.IO は接続確立までに 2 回リクエストを投げるということです。 そしてこの最初の要求と、 WS の接続要求は、「同じインスタンス」にアクセスする必要があります。 二つの接続がバランスされて別々のサーバに行くと、ハンドシェイクがエラーになり、リトライが発生します。 たまたま二回同じサーバにいけば、接続が確立できるので、バランスするサーバが増えるほど成功確率が減 り、確立までの時間が長くなります。

redisの導入

解決策としてredisをセッションキーストアとして利用する、ということのようです。今更だけどSocket.ioについてまとめてみる

redisのPub/Subを利用して、各プロセス間でセッション共有をするということです。

このサイトの記事のとおりなのですが、ひと通りメモ

redisのインストールと起動

$ brew install redis
$ redis-server /usr/local/etc/redis.conf &
[1] 3234
$ [3234] 31 Jan 11:29:03.112 * Max number of open files set to 10032
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 2.8.1 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in stand alone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 3234
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

[3234] 31 Jan 11:29:03.113 # Server started, Redis version 2.8.1
[3234] 31 Jan 11:29:03.113 * The server is now ready to accept connections on port 6379

redisのpub/sub機能

redisにはpublisher/subscriberという機能があって、いずれかのプロセスが受けた通知をredisに設定することで、他のプロセスに通知を行い共有できるということです。この機能を使うことでクラスタリングされたプロセス間でセッションの共有を行えます。

サーバアプリの書き換え

app.jsを以下のように書き換えます

var app = express()
    , server = http.createServer(app)
    , redis = require('socket.io/lib/stores/redis')  // socket.ioにredisがある
    , redisConf = { host: '127.0.0.1', port: 6379 }
    , io = require('socket.io').listen(server);

// storeタイプをredisに変更
io.set('store', new redis({
    redisPub: redisConf,
    redisSub: redisConf,
    redisClient: redisConf
}));

pm2でクラスタリング

再びpm2でクラスタリングを試してみます。

$ pm2 start app.js -i max

この時のアクセスログを見ると警告が無くなり、かつ正常にクラスタリングされているようです\(^o^)/

f:id:tomo_watanabe:20140131120626p:plain

モバイル版ChromeのSPDYプロキシはIPv6に対応

モバイル版のChrome正式にSPDYに対応しました。

たまたま実験してて気づいてたのですが、SPDYプロキシはIPv6に対応しているようです。

実験

グローバルなIPv6が振られているMac上でサーバアプリを起動して、IPv6でアクセスできるようにします。今回はNode.jsを使ったサーバアプリを起動しておきます。また、アクセスしてきたIPアドレスをログで表示できるようにしておきます。

IPv6でアクセスできるようにするには、Node.jsでlistenを下記のように書いておきます。

server.listen(3000, '::');

PC版Chromeでアクセス

IPv6指定でアクセスすると、このように接続されます。これはまあ普通です。

f:id:tomo_watanabe:20140120125629p:plain

Node.jsのログでIPアドレスを確認してみます。同じマシンからアクセスしてるので同じIPv6アドレスです。

f:id:tomo_watanabe:20140120130136p:plain

AndroidChromeでアクセス

AndroidChromeでSPDYをON(帯域幅の管理→データ使用量を節約)でアクセスしてみます。

f:id:tomo_watanabe:20140120130720p:plain

同じようにアクセスできました。この時のアクセスログを見てみると

f:id:tomo_watanabe:20140120130845p:plain

謎のIPv6アドレスからアクセスが来ていますね。これを調べてみます。

f:id:tomo_watanabe:20140120162437p:plain

どう見てもGoogleさんです。本当にry

ちなみにSPDYをOFF(データ使用量を節約しない)に設定すると

f:id:tomo_watanabe:20140120131721p:plain

このようにアドレス解決できません(今まではこうだった)

追試

IPv6アクセスの確認サイトである「The KAME project」にアクセスしてみます。 このサイトのIPv6アドレスは「2001:200:dff:fff1:216:3eff:feb1:44d7」です。

モバイル版ChromeでSPDY ONで「http://www.kame.net/」へアクセス(IPv4)と「http://[2001:200:dff:fff1:216:3eff:feb1:44d7]」(IPv6)へそれぞれアクセスしてみてください

亀が泳いでいればIPv6でアクセスしていることになります。IPv6アドレスでアクセスした場合には亀が泳いでいるのが確認できると思います。

f:id:tomo_watanabe:20140120133300p:plain

まとめ

Android端末で僕が契約しているdocomo XiのLTEでは端末にはIPv6は割り当てられず、IPv4アドレスしか振られません。なので普通にURLを入れるとIPv4でのアクセスになります。しかしIPv6アドレスを直打ちすることで、SPDYプロキシがIPv6へのアクセスを可能にしていることがわかりました。

ただし、PCからのアクセスだとWebScoketで接続できますが、SPDY経由だとxhr-pollingになるのでWebSocketのプロキシには対応していないようです...

追記:httpsアクセスはSPDYプロキシは通ってないようですね(まぁそうか)

Intel Galileoはじめの一歩

やっとIntel Galileoが来たので、とりあえず最初にやっておくことひと通り

f:id:tomo_watanabe:20140119182300j:plain

ファームウェアのアップデート

まずはファームウェアのアップデートをやっておかないとならないのですが、いきなりここでハマりました。3回くらいファームのアップロードをやってやっと成功。やり方がまずかったかもしれませんが、シリアルポートがハングアップすることがありました。

アップデートはなぜかGalileo用のArduino IDEから行います。まずはここからマシン環境にあったIntel Galileo Arduinoを落としてインストールします。いわゆる通常のArduino IDEは使用できないので注意です。Macの場合はドライバは必要ないようです。

起動したら設定を行う

Macの場合、どうやらここで「tty.XXX」ではなく、「cu.XXX」を選択しないとダメなようです。僕は最初「tty.XXX」を指定してやったらハングアップしました(^_^;)

f:id:tomo_watanabe:20140119181238p:plain

f:id:tomo_watanabe:20140119181248p:plain

さてファームウェアのアップデートを行います。ヘルプから「Firmware Update」を選択します。

f:id:tomo_watanabe:20140119181506p:plain

こんな感じで警告がでます。ACアダプタをちゃんと挿しておきましょう。

f:id:tomo_watanabe:20140119181610p:plain

OKを押すとファームウェアのアップデートが開始されます。

f:id:tomo_watanabe:20140119181712p:plain

途中5分くらい掛かるよ。というメッセージに変わり、終了すると終了メッセージが出ます(スクショ忘れ)ちなみに実際には5分以上掛かっていました。かつ、アクセスランプの点滅等が無いので、ほぼ進行状況が掴めないという優しくない仕様・・・

(僕は最初tty.XXXを選択していたためか、ここで10分ほど放置した結果、ハングアップしてると判断して電源引っこ抜きました・・・)

Lチカで動作確認

ファームウェアのアップデートが完了したら、サンプルのLチカを実行してみます。Arduinoのメニューから「Blink」を選択して、ビルド・ダウンロードするだけです。

f:id:tomo_watanabe:20140119182605p:plain

手前のグリーンのLEDがチカチカと点滅すればOKです

f:id:tomo_watanabe:20140119182451j:plain

まとめ

まずはここまでやっておけば、あとはArduinoで何かすれば普通にできそうです。とはいえ、ただのArduino互換で使うには勿体無いというか、これ一応Quarkの開発ボードなので、メインはLinux動かしてなにかやる方だと思いますが。しかしこのQuarkチップは熱持ちすぎですね。触ると数秒で手を離すレベルです。これではCES2014で発表したIntel Edisonは熱とか大丈夫なんでしょうか?この発熱だととてもIoT用のチップとしては使えない気が・・・(´ε`;)ウーン…

とりあえず次は手元にあるArduinoシールド動かしてみるかな...

BeagleBone Blackにcloud9をインストールする

UbuntuをインストールしたBeagleBone Blackにcloud9 IDEをインストールしてみます。

cloud9 IDEとは

BeagleBone Blackに標準インストールのAngstrom上にプリインストールされている、Node.jsを利用したブラウザIDE環境です。今回はUbuntuに入れ替えてあるので、ここにcloud9 IEDを追加でインストールします。

cloud9 IDEのインストール

cloud9 IDEはgitihubに公開されていますので、これをインストールすれば動くはずです。

Requirements:

  • NodeJS >= 0.6.16
  • NPM >= 1.1.16
  • libxml2-dev

となっていますが、すでにNode.jsは0.8.22をnodebrewを使ってインストール済みで、同時にNPMもインストールされているので、libxml2-devをインストールします。

$ sudo apt-get install libxml2-dev

次にcloud9をインストールします

$ git clone https://github.com/ajaxorg/cloud9.git
$ cd cloud9
$ npm install

cloud9 IDEの起動

cloud9はデフォルトで起動すると、localhostからしかアクセスできないので、外部からブラウザ経由でアクセスするためには。以下のように起動します。

$ bin/cloud9.sh -l 0.0.0.0
make: Nothing to be done for `worker'.
Linux ARM
connect plugin start
Connect server listening at http://0.0.0.0:3131
IDE SERVER PLUGIN:  auth
IDE SERVER PLUGIN:  git
IDE SERVER PLUGIN:  gittools
IDE SERVER PLUGIN:  hg
IDE SERVER PLUGIN:  npm
IDE SERVER PLUGIN:  filelist
IDE SERVER PLUGIN:  search
IDE SERVER PLUGIN:  revisions
IDE SERVER PLUGIN:  settings
IDE SERVER PLUGIN:  shell
IDE SERVER PLUGIN:  state
IDE SERVER PLUGIN:  watcher
IDE SERVER PLUGIN:  node-runtime
IDE SERVER PLUGIN:  npm-runtime
IDE SERVER PLUGIN:  python-runtime
IDE SERVER PLUGIN:  apache-runtime
IDE SERVER PLUGIN:  ruby-runtime
IDE SERVER PLUGIN:  php-runtime
Started '/home/ubuntu/cloud9/configs/default'!
IDE server initialized. Listening on 0.0.0.0:3131

ポートは3131で起動していますので、BeagleBone BlackのIPアドレスを調べてアクセスしてみましょう。

f:id:tomo_watanabe:20131228220414p:plain

LEDの点灯・消灯サンプル

clou9が起動したら、サンプルアプリを動かしてみましょう。「New File」で新規ファイルを作成します。led.jsとかファイル名を付けておきます。下記はBoneScriptを使って、LEDを制御するプログラムです。

/**
 * LED点灯、2秒後に消灯
 */
var b = require('bonescript');

// LEDの設定
b.pinMode('USR0', b.OUTPUT);
b.pinMode('USR1', b.OUTPUT);
b.pinMode('USR2', b.OUTPUT);
b.pinMode('USR3', b.OUTPUT);

// LEDをONに
b.digitalWrite('USR0', b.HIGH);
b.digitalWrite('USR1', b.HIGH);
b.digitalWrite('USR2', b.HIGH);
b.digitalWrite('USR3', b.HIGH);

// 2秒後にLEDをOFFに
setTimeout(function() {
    b.digitalWrite('USR0', b.LOW);
    b.digitalWrite('USR1', b.LOW);
    b.digitalWrite('USR2', b.LOW);
    b.digitalWrite('USR3', b.LOW);
}, 2000);

実行してみます。

Running Node Process
Your code is running at 'http://0.0.0.0:21479'.
Important: in your scripts, use 'process.env.PORT' as port and '0.0.0.0' as host.
fs.js:338
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                ^
Error: EACCES, permission denied '/sys/class/leds/beaglebone:green:usr0/trigger'
    at Object.fs.openSync (fs.js:338:18)
    at Object.fs.writeFileSync (fs.js:756:15)
    at Object.f.pinMode (/home/ubuntu/cloud9/node_modules/bonescript/index.js:132:20)
    at Object. (/home/ubuntu/cloud9/myScript/led1.js:7:3)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:492:10)
    at process.startup.processNextTick.process._tickCallback (node.js:245:9)

どうやら、LEDへのアクセス権が無いということで怒られてしまいました....cloud9をroot権限で実行してやらないと、デバイスへのアクセスは出来ないようです。

$ sudo bin/cloud9.sh 
make: Nothing to be done for `worker'.
Linux ARM
bin/cloud9.sh: 18: bin/cloud9.sh: node: not found

今度はnodeが無いと怒られてしまいました。nodebrewをubuntuユーザでインストールしたため、rootユーザにnodeがインストールされていません。これを回避するには

  • rootでnodeをインストール
  • rootでcloud9を起動し、ubuntuユーザのnodeパスを指定

のどちらかを選択することになりますが、今回はnodeがすでにインストールされているので後者の方法で起動します。cloud.shを下記のように書き換えます。

Linux*arm*)  echo "Linux ARM"
    /home/ubuntu/.nodebrew/current/bin/node server.js "$@" -a x-www-browser
    ;;

BeagleBone Blackは"Linux ARM"なので、ここの部分をnodebrewのcurrentのnodeが起動するように修正します。これでもう一度起動して、先ほどのプログラムを実行します。

$ sudo bin/cloud9.sh -l 0.0.0.0
make: Nothing to be done for `worker'.
Linux ARM
connect plugin start
Connect server listening at http://0.0.0.0:3131
IDE SERVER PLUGIN:  auth
IDE SERVER PLUGIN:  git
IDE SERVER PLUGIN:  gittools
IDE SERVER PLUGIN:  hg
IDE SERVER PLUGIN:  npm
IDE SERVER PLUGIN:  filelist
IDE SERVER PLUGIN:  search
IDE SERVER PLUGIN:  revisions
IDE SERVER PLUGIN:  settings
IDE SERVER PLUGIN:  shell
IDE SERVER PLUGIN:  state
IDE SERVER PLUGIN:  watcher
IDE SERVER PLUGIN:  node-runtime
IDE SERVER PLUGIN:  npm-runtime
IDE SERVER PLUGIN:  python-runtime
IDE SERVER PLUGIN:  apache-runtime
IDE SERVER PLUGIN:  ruby-runtime
IDE SERVER PLUGIN:  php-runtime
Started '/home/ubuntu/cloud9/configs/default'!
IDE server initialized. Listening on 0.0.0.0:3131

今度はLEDが一斉に点灯して、2秒後に消灯するように動くはずです。

おわりに

BoneScriptは簡単にLEDやGPIOを制御できる便利なライブラリです。以前BoneScriptのライブラリ構成を調べましたが、socket.ioやserialportも入ってると思ったのですが、これらはBoneScript配下で使用されるようで、自分で意識して扱う場合には別途インストールする必要があるようです。

cloud9 IDEはBeagelBone Black上でGPIO制御などの動作確認やプロトタイピングにはいいのですが、実際にNode.jsサーバを動かすといった場合には、いつものようexpressなどを使うのが良いと思われます。おそらくBoneScriptはそのまま使えるので、上手く利用できるでしょう。

ToCoStickのシリアル通信で受信プロンプトを無くす

前回のエントリで調べた、シリアル通信の受信データの部分を書き換えてみました。

開発環境について

ToCoNetSDKというのが無償にて提供されています。これをダウンロードして展開するとeclipseによる開発を行えます。今回はこのWindows版(eclipse同梱で楽そうだった)を使ってコードを修正しました。

ビルドの方法などは特に特別なことは無く、ToCoNetSDKのページのPDFに詳しい説明があるので省きます。

変更点

修正するプロジェクトは「App_Uart」です。gistにアップしてありますが、受信時にデータ以外の文字列の表示をしないようにコメントアウトしただけです。 (gistのタブが8設定で見づらい・・・変更効かない...)

そのままビルドをするとデバッグビルドになるので、Makefileデバッグフラグを無効してやる必要があります。詳細はgistの方を見て下さい。

ビルドで作成した.binファイルをTWE-Lite専用プログラマで書き込んでやります。

動作検証

手前が送信側、後ろ側が受信側になります。送信側は手を入れていないのでプロンプトが出ますが、受信側にはプロンプトが出なくなりました。

f:id:tomo_watanabe:20131224220848p:plain

補足:シリアル通信動作

動作検証の結果では、送信側はEnterキーでデータを確定しているのですが、受信側では改行などが入っていません。ちょっとコードを調べてみたのですが、入力の終了を検出する箇所は以下のようになっています。(Source/input_string.C)

if (u8Byte == 0x0d || u8Byte == 0x0a) {
    // enter、系列の終了
    bComplete = TRUE;
} else if ...

CRやLFは送信するわけではなく、送信データの終了フラグとして使われています。したがって、受信側にはCRもLFも送信されずに連続した文字列として受信されます。とはいえ、受信側としては受信バッファが空になるまで読みこめばいいので困ることは無いかと思いますし、必要なら送信時にデリミタを付加して受信側でデコードすればよいでしょう。

まとめ

とりあえず受信側を修正してみましたが、送信側も同じような要領で削除することはできるでしょう。ただ送信データにはそもそもプロンプトは含まれないので修正する意味はあまり無いかと思いますが。受信側の修正としては、起動時のメッセージなども修正して削除する。なども必要だと思いますが、起動後に一度受信バッファをクリアすれば実用上は問題は無いでしょう。

実際に使用するにはまだ修正する箇所があるような気もしますが、今のところ実運用する予定は無いのでここまで(^^;

一応今回作成したToCoStick動作用バイナリを置いておきます。動作上の保証はいたしません

ToCoStick(TWE-LITE-USB)を使ってみた

ToCoStickとはTWE-LiteをUSBドングルの形に収めたものです。 詳しくはToCoStick

ToCoStick

動作確認の方法

今回これを2台購入したので動作レポートしてみたいと思います。2台ということは当然ながら、やりたいことは2台のPC間をZigBeeで通信させることを行います。つまり「無線シリアル通信」を構築してみるのとほぼ同義です。TOCOSのHPにもかなりの情報はあるのですが、微妙にわかりづらいです(^^;

データ通信

初めにしておくこと

ToCoStickの初期設定では、下記のLEDやPWMを操作するファームウェアが焼いてあります。このファームは動作確認用なので書き換えちゃいます。USBドングルの形をしていますが、USBシリアルドライバとしてFTDIのシリアルドライバをインストールする必要があります。

IO

ファームウェアの書き換えには専用のソフトが用意されているので、そちらを利用しましょう。 TWE-Lite専用プログラマ

書き換えるファームウェアはApp_Uart (シリアル通信アプリ)です。これを使うとシリアル通信が使えるようになります。購入した2台ともシリアル通信アプリに書き換えます。

起動

USBに接続してTeraTermなどで該当のシリアルポートをオープンします。通信速度は115200です。僕の環境はMacなのでCoolTermを使っています。

シリアルポートをオープンしたら「+++」と入力すると「インタラクティブモード」に入ります。

.[2J.[H--- CONFIG/TWE UART APP V1-00-0/SID=0x81002816/LID=0x00 ---
 a: set Application ID (0x67720103)*
 i: set Device ID (--)*
 c: set Channels (18)*
 o: set Output Tx Power (3)*
 r: set Role (0x0)*
 b: set UART baud (38400)*
 p: set parity (N)*
 m: set uart mode (C)*
 h: set handle name []*
 C: set crypt mode (0)*
 K: set crypt key []*
---
 S: save Configuration
 R: reset to Defaults

デフォルトのDEVICE IDは未設定(=子機)、UARTモードは「C」なので、「C: チャットモード」となっています。もう一度「+++」と入力するとインタラクティブモードから抜けられます。

チャットモードでの動作テスト

ではデフォルトのチャットモードで動かしてみます。チャットモードは、Enterキーの入力でデータ送信が行われます。

今回同じマシンに2台繋いでいるので、こんな感じです。

f:id:tomo_watanabe:20131220231056p:plain

[810028A9:1] bbb  <--- 受信コード
81002816:1> ccc   <--- 送信コード
81002816:2>

送信元には「SID=0x81002816」が付いています。受信する方にも「SID=810028A9」というのが付いていることがわかります。このSIDではわかりにくいということで、これをハンドルネームとして変更できます。先のインタラクティブモードの「h」で名前を付けてみます。変更した後は「S」でセーブし忘れないようにしましょう。

f:id:tomo_watanabe:20131220231849p:plain

これで少しわかりやすくなりました。

ちょっと問題点が・・・

これで相手に無線シリアルでデータを送ることが出来るのですが、ちょっと問題があります。人間の目で見るにはデータはわかりやすいのですが、受信データを見てみると

[hoge:0] hoge->fuga

となっています。受信データ本体は「hoge->fuga」だけですので、余計な付加情報も受信データとして扱ってしまうことになります。1対1の通信で、ソフトで処理しようとすると、前半の部分は不必要であるばかりではなく、数字の部分がインクリメントされることになっています。0-255と変化するので、先頭から何バイト目からデータとして処理するのも面倒です。せめて000-255とかなら先頭バイトは変化しないのですが・・・

ぜひファームウェアで前半の部分が無い、送受信データのみのバージョンをリリースして欲しいと思います。※修正バージョン作ってみました)送信元を判別したければ、送信元が自分のハンドルネームを付けて送るなどの仕様を各自が実装すればそれで問題無いですね。

透過モードでの動作テスト

次は透過モードを試してみます。透過モードではEnterキーでの送信ではなく、1文字打つごとに送信するモードです。透過モードにするにはインタラクティブモードでUARTモードで「T」を設定します。

ここで気をつけなければいけないのは、透過モードの場合、必ず1台は「親機」にならないといけないので、どちらか一方の「Device ID」を121に設定する必要があります。

親機の設定

.[2J.[H--- CONFIG/TWE UART APP V1-00-0/SID=0x810028a9/LID=0x00 ---
 a: set Application ID (0x67720103) 
 i: set Device ID (121=0x79)  <-- 121を設定
 c: set Channels (18) 
 o: set Output Tx Power (3) 
 r: set Role (0x0) 
 b: set UART baud (38400) 
 p: set parity (N) 
 m: set uart mode (T)   <-- 透過モード
 h: set handle name [fuga] 
 C: set crypt mode (0) 
 K: set crypt key [] 
---
 S: save Configuration
 R: reset to Defaults

子機の設定

.[2J.[H--- CONFIG/TWE UART APP V1-00-0/SID=0x81002816/LID=0x65 ---
 a: set Application ID (0x67720103) 
 i: set Device ID (--) 
 c: set Channels (18) 
 o: set Output Tx Power (3) 
 r: set Role (0x0) 
 b: set UART baud (38400) 
 p: set parity (N) 
 m: set uart mode (T)   <-- 透過モード
 h: set handle name [hoge] 
 C: set crypt mode (0) 
 K: set crypt key [] 
---
 S: save Configuration
 R: reset to Defaults

これで設定すると下記のようになります。

f:id:tomo_watanabe:20131220233823p:plain

ローカルエコーが出なくなるので、送信元には送信表示がされませんが1文字ごとに送信されるようになります。

まとめ

というわけで簡単ではありますが、ToCoStickの動作確認をしてみました。ToCoStickをdebian/Ubuntuに挿してscreenコマンドでの動作も確認しています。これを使うとUSBシリアルを無線化できるようになるので、色々捗るパターンがありそうです\(^o^)/

もちろんToCoStick同士でなくて、ToCoStickとTWE-Lite DIPでも無線シリアル通信化が可能なので、TWE-Lite DIPに接続したセンサー類のデータを遠隔のPCのシリアルで受信して処理する。ということも簡単にできるのでデバッグにも使えそうです。

BeagleBone BlackのUbuntuにbonescriptをインストールする

デフォルトのAngstromではなく、Ubuntuの方にbonescript入れてやればいいよね?的な発想でインストール

Node.js v0.10.21でインストール

前々回にインストールしたv0.10.12でbonescriptをインストールしてみます

ubuntu@ubuntu-armhf:~$ npm install -g bonescript
npm http GET https://registry.npmjs.org/bonescript
npm http 304 https://registry.npmjs.org/bonescript

> bonescript@0.2.3 preinstall /home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/bonescript
> node-gyp clean || (exit 0); node-gyp configure build

make: Entering directory `/home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/bonescript/build'
  CXX(target) Release/obj.target/misc/misc.o
../misc.cpp:1:0: warning: "BUILDING_NODE_EXTENSION" redefined [enabled by default]

<--中略-->

make: *** [Release/obj.target/misc/misc.o] Error 1
make: Leaving directory `/home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/bonescript/build'
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:267:23)
gyp ERR! stack     at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (child_process.js:789:12)
gyp ERR! System Linux 3.8.13-bone30
gyp ERR! command "node" "/home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "configure" "build"
gyp ERR! cwd /home/ubuntu/.nodebrew/node/v0.10.21/lib/node_modules/bonescript
gyp ERR! node -v v0.10.21
gyp ERR! node-gyp -v v0.10.10
gyp ERR! not ok 
npm ERR! weird error 1
npm ERR! not ok code 0

おうふ・・・

bonescriptは対応Nodeバージョンがある

ググったところ、こんな情報を発見。Installing Ubuntu 13.10, Node.js, bonescript.js on BBB

I had to make some changes when installing node.js in order to get bonescript.js installed. Bonescript.js is only compatible with node.js v0.8 Github issue #53.

たしかにAngstromの場合v0.8.22でした。というわけで、v0.8.22をインストール。こういう時にnodebrewを使ってると便利ですね。

Node.js v0.8.22をインストール

ubuntu@ubuntu-armhf:~$ nodebrew install v0.8.22

-- ビルド約1時間--

ubuntu@ubuntu-armhf:~$ nodebrew ls
v0.8.22
v0.10.21

current: v0.10.21
ubuntu@ubuntu-armhf:~$ nodebrew use v0.8.22
use v0.8.22

あらためてbonescriptをインストール

ubuntu@ubuntu-armhf:~$ npm install -g bonescript

> serialport@1.0.6 install /home/ubuntu/.nodebrew/node/v0.8.22/lib/node_modules/bonescript/node_modules/serialport
> node-gyp rebuild

-- 中略 --
make: Entering directory `/home/ubuntu/.nodebrew/node/v0.8.22/lib/node_modules/bonescript/node_modules/serialport/build'
  CXX(target) Release/obj.target/serialport/src/serialport.o
  CXX(target) Release/obj.target/serialport/src/serialport_unix.o
  SOLINK_MODULE(target) Release/obj.target/serialport.node
  SOLINK_MODULE(target) Release/obj.target/serialport.node: Finished
  COPY Release/serialport.node
make: Leaving directory `/home/ubuntu/.nodebrew/node/v0.8.22/lib/node_modules/bonescript/node_modules/serialport/build'
bonescript@0.2.3 /home/ubuntu/.nodebrew/node/v0.8.22/lib/node_modules/bonescript
├── systemd@0.2.0
├── i2c@0.1.4 (bindings@1.1.1, repl@0.1.3, underscore@1.2.4, coffee-script@1.3.3)
├── winston@0.6.2 (cycle@1.0.3, stack-trace@0.0.7, eyes@0.1.8, colors@0.6.2, pkginfo@0.2.3, async@0.1.22, request@2.9.203)
├── express@3.1.0 (methods@0.0.1, fresh@0.1.0, cookie-signature@0.0.1, range-parser@0.0.4, debug@0.7.4, buffer-crc32@0.1.1, cookie@0.0.5, commander@0.6.1, mkdirp@0.3.3, send@0.1.0, connect@2.7.2)
├── socket.io@0.8.7 (policyfile@0.0.4, redis@0.6.7, socket.io-client@0.8.7)
└── serialport@1.0.6 (bindings@0.3.0, sf@0.1.3, async@0.1.18, optimist@0.3.7, node-gyp@0.6.2)

expressやらsocket.io, serialportなども同時にインストールされるようです。リストを取ってみます

ubuntu@ubuntu-armhf:~$ npm list -g
/home/ubuntu/.nodebrew/node/v0.8.22/lib
├─┬ bonescript@0.2.3
│ ├─┬ express@3.1.0
│ │ ├── buffer-crc32@0.1.1
│ │ ├── commander@0.6.1
│ │ ├─┬ connect@2.7.2
│ │ │ ├── bytes@0.1.0
│ │ │ ├── formidable@1.0.11
│ │ │ ├── pause@0.0.1
│ │ │ └── qs@0.5.1
│ │ ├── cookie@0.0.5
│ │ ├── cookie-signature@0.0.1
│ │ ├── debug@0.7.4
│ │ ├── fresh@0.1.0
│ │ ├── methods@0.0.1
│ │ ├── mkdirp@0.3.3
│ │ ├── range-parser@0.0.4
│ │ └─┬ send@0.1.0
│ │   └── mime@1.2.6
│ ├─┬ i2c@0.1.4
│ │ ├── bindings@1.1.1
│ │ ├── coffee-script@1.3.3
│ │ ├── repl@0.1.3
│ │ └── underscore@1.2.4
│ ├─┬ serialport@1.0.6
│ │ ├── async@0.1.18
│ │ ├── bindings@0.3.0
│ │ ├─┬ node-gyp@0.6.2
│ │ │ ├─┬ fstream@0.1.25
│ │ │ │ ├── graceful-fs@2.0.1
│ │ │ │ └── inherits@2.0.1
│ │ │ ├─┬ glob@3.2.7
│ │ │ │ └── inherits@2.0.1
│ │ │ ├── graceful-fs@1.2.3
│ │ │ ├─┬ minimatch@0.2.14
│ │ │ │ ├── lru-cache@2.5.0
│ │ │ │ └── sigmund@1.0.0
│ │ │ ├── mkdirp@0.3.5
│ │ │ ├─┬ nopt@2.1.2
│ │ │ │ └── abbrev@1.0.4
│ │ │ ├─┬ npmlog@0.0.6
│ │ │ │ └── ansi@0.2.1
│ │ │ ├── osenv@0.0.3
│ │ │ ├── request@2.9.203
│ │ │ ├── rimraf@2.2.5
│ │ │ ├── semver@1.1.4
│ │ │ ├─┬ tar@0.1.19
│ │ │ │ ├── block-stream@0.0.7
│ │ │ │ └── inherits@2.0.1
│ │ │ └── which@1.0.5
│ │ ├─┬ optimist@0.3.7
│ │ │ └── wordwrap@0.0.2
│ │ └── sf@0.1.3
│ ├─┬ socket.io@0.8.7
│ │ ├── policyfile@0.0.4
│ │ ├── redis@0.6.7
│ │ └─┬ socket.io-client@0.8.7
│ │   ├── uglify-js@1.0.6
│ │   ├── websocket-client@1.0.0
│ │   └── xmlhttprequest@1.2.2
│ ├── systemd@0.2.0
│ └─┬ winston@0.6.2
│   ├── async@0.1.22
│   ├── colors@0.6.2
│   ├── cycle@1.0.3
│   ├── eyes@0.1.8
│   ├── pkginfo@0.2.3
│   ├── request@2.9.203
│   └── stack-trace@0.0.7
└─┬ npm@1.2.14
  ├── abbrev@1.0.4
  ├── ansi@0.1.2
  ├── archy@0.0.2
  ├── block-stream@0.0.6
  ├── chmodr@0.1.0
  ├── chownr@0.0.1
  ├── fstream@0.1.22
  ├─┬ fstream-npm@0.1.3
  │ └── fstream-ignore@0.0.6
  ├── glob@3.1.21
  ├── graceful-fs@1.2.0
  ├── inherits@1.0.0
  ├── ini@1.1.0
  ├─┬ init-package-json@0.0.6
  │ └── promzard@0.2.0
  ├── lockfile@0.3.0
  ├── lru-cache@2.2.2
  ├─┬ minimatch@0.2.11
  │ └── sigmund@1.0.0
  ├── mkdirp@0.3.5
  ├── node-gyp@0.8.5
  ├── nopt@2.1.1
  ├─┬ npm-registry-client@0.2.18
  │ └── couch-login@0.1.15
  ├─┬ npmconf@0.0.23
  │ └─┬ config-chain@1.1.5
  │   └── proto-list@1.2.2
  ├── npmlog@0.0.2
  ├── once@1.1.1
  ├── opener@1.3.0
  ├── osenv@0.0.3
  ├─┬ read@1.0.4
  │ └── mute-stream@0.0.3
  ├── read-installed@0.1.1
  ├── read-package-json@0.2.2
  ├── request@2.9.203
  ├── retry@0.6.0
  ├── rimraf@2.1.4
  ├── semver@1.1.4
  ├── slide@1.1.3
  ├── tar@0.1.16
  ├── uid-number@0.0.3
  └── which@1.0.5

これでUbuntuでもbonescriptを使ったNodeアプリが書ける・・・はず>たぶん次回