« Edisonの電池駆動無線カメラの実現へ | トップページ | Edison進展せず。電子工作に「ときめか」ない »

2015年5月18日 (月)

EdisonでIPアドレスを変数化した動画サーバーが動いた

 Edisonの無線動画サーバーソフトは、ウェブでいくつか紹介されている。そのうちnodeを使ったこのサーバーは軽くて具合が良いのだがWindowsでは動かない。ローカルネットの中のホスト名を拾い上げる機能(Avahi)をこのサーバーが使っているからである。Windowsのためには生IPアドレスをクライアント用のソースコード(index.html)にハードコーディングしてやる必要がある。

 EdisonはWiFiでネットとつながっており、IPアドレスは勝手に設定されるので、このままでは運用性が極めて悪い。iTuneのソフトをインストールすればWindowsでも動くようだが、このためだけにクライアント側をいじるというのは、どうも本末転倒で、元プロのソフト開発者としては受け入れがたい解決手段である。

Node

 そこでnodeの勉強も兼ねて、自分のIPアドレスが変わってもストリーミングサーバーが動くように、このサーバーのソフト改修にこのところ熱中していた。久しぶりのPCプログラミングである。ここは電子工作のブログで、PCのソフト開発はなるべくやらないはずだったのだが、行きがかりで止まらなくなってしまった。

 悪戦苦闘していたが、このほど、まがりながら、当面の目的を果たしたので、そのご報告とともに修正方法を紹介することにする。オリジナルはMITライセンスなので、改訂したソースの公開は問題ないと認識している。ただし、オリジナル同様、完全な無保証、無責任であることはご承知置き願いたい。

Linuxでのnodeとexpressのインストール(4/24/2015)
 久しぶりの大物、node.js(正式名)である。これまでのウェブプログラミングの概念を破る革新的な手法ということで、少し勉強してみる気になった。ただ、node.jsは近年、分派活動(io.jsというらしい)が始まったりして、ちょっと先行きが不透明だったが、つい先日統合されるというニュースが飛び込んできた。ウェブサイトにはおびただしい量のnodeの紹介ページが存在する。

 Edisonのサーバーがnodeの中のHTTPサーバー用のモジュールexpressを使っているので、まずはWindowsでnodeとexpressの学習を続けていた。その結果、概要がつかめてきたので、いよいよ、本題のEdisonサーバーの改修に移ることにする。

 Edisonの石はIntel AtomでOSはLinux(Yocto Linux)である。ここのエディター環境は貧弱(viしかない)なので、この上で開発やテストを続けて行くのはつらい。このためPCのLinux(Ubuntu14.04)にもnodeをインストールし、こちらで動作を確認していくことにした。

 nodeのLinuxでの導入ツールはapt-getである。この環境は強力で、Windowsに比べれば嘘のように簡単だった。あっと言う間にすべてのモジュールがインストールされた(node,express,npm)。動作を確認する。expressも問題なく動く。

Screen20150427

 うまくいったのは、Linuxの環境(nodeの生まれ故郷)ということもあるがnodeに慣れてきたということもあるだろう。薄紙をはがすように、expressの構造も見えてきた。レンダリングのツールはejs(enbedded java script、組み込みjs)を選ぶ。

 ejsを選んだ理由は、HTMLに近く可読性が高いことによる。jadeなど省力を狙ったものは別言語のようで扱いにくい。それにしても、nodeでの付加すべきパッケージはやたらと種類が多い。しかも、バージョンの変化が激しく、各所でバージョン違いでのトラブルが発生する。しかし経験を積んできたので事前に必ず確認するようにし失敗は少なくなった。

 Windowsで懲りたので、Linuxでは少し計画的に作業を進めることにする。結構道のりが遠い。下手をするとまた脱線する。少し細かいが、以下のステップで行くことにした。

1. Linux(Ubuntu)でNodeのインストールとテスト。

2.  同        expressのインストールとテスト。

3.  同        ejsのインストール。ここまでは済んでいる。

4. 外部コマンド(ifconfig )によるIPアドレスの取得。これはWindows(ipconfig)ではnodeで実現できている。ウェブにたくさん記事がある(ここやここ)ので簡単だった。Linuxでのテストはここで済ませる。

5. ejsを使ってクライアントファイルをレンダリングし、所定のIPアドレスに変更する部分の開発。ここまではUbuntuでやる。

6. Edisonにnodeの上記スクリプトファイルの持ち込み。

7. Edisonでのサーバーテスト。いきなり動画サーバーを動かさないで別サーバーでテストする。

8. Edisonでの動画ストリーミングのテスト

Linuxでのnodeの勉強は順調(4/25/2015)
 PC Linuxでnodeを復習する。久しぶりのLinux環境である。Linuxも昔に比べると格段に進歩している。ブラウザー(Firefox)も明らかにWindowsより早い。USBメモリなど周辺のI/O機器も何もせずに認識する。特にサウンド関係が全く手づかずで動いたのには感動した。YouTubeでクラシックを聴きながら作業する。快適だ。

 少しづつnodeとjs(JavaScript)が見えてくる。ただ、無料で読ませて貰ってケチをつけるのは少々気が引けるが、どの入門サイトも、サンプルコードの中の変数名やプロパティ、さらにオブジェクトにどうして同じような名前を付けるのだろう。

 オブジェクト指向言語の変数や関数は、ピリオドなどでいくらでも派生できるので、同じ名前をつけると致命的に混乱する。しかも、この変数名が予約語なのか、一般の変数なのかの区別は、すべてモジュールの原典にまで戻らないと分からない。解読するのに一苦労である。

 海外のものでも、fooとかbarという名前がやたらと使われ混乱することおびただしい。経験者には自明のことなのかもしれないが、初心者にとっては、どの部分がオブジェクトで、どれが変数で、どれがプロパティなのかはわからない。

//foo.js
exports.foo = 'foo';
//main.js
var foo = require('./foo')
console.log(foo.foo); // 'foo'

こういうサンプルを見せられて、いらいらしないで読み下せる人がいたらお目にかかりたい。

 こんな悪態をつきながら、少しづつサーバーの機能を増やしていく。お手本にしたのはこれ。このサイトは少しづつ、実例付きで、相当高度なところまで案内してくれるので嬉しい。このサイトのコードを参考に、テーブル表記や、POSTによるデータ入力、ejsによるフィルタリングなどの初歩的なことができるようになった。

LinuxでもIPアドレスの抽出は成功。grepの正規表現にはまる(4/28/2015)
 IPアドレスの抽出は、Windowsのnodeですでに成功している。nodeでの外部コマンド出力については、以下のサイトが親切だった(前に紹介したところと同じ)。
http://yosuke-furukawa.hatenablog.com/entry/2014/07/26/145814

 今のところ、コマンドの出力文字列から、IPアドレスを抜き出す方法は、grepを2回使っている。まず、該当アドレスの行を抜出し、それをさらにIPアドレスだけに絞り込む方法である。

IPアドレスを抽出する正規表現: [0-9]+(\\.+[0-9]+){3}   (\は不要な環境もある)

 これを何とか一段で出来ないか、色々サイトを漁って調べているが、プログラムでも書かない限り無理なようだ。しかし、久しぶりのこういうパズルのような開発は面白い。正規表現は奥が深い。

 Windowsでは、grepのバージョンを上げる必要があったが、さすが本家のLinuxである。Linuxでは何の問題もなく成功した。ただ、Edisonではコマンド出力のフォーマットがUbuntuとまた違うので気を付けないといけない。

 grepも方言が多い。Windowsでは成功してもLinuxで動くとはかぎらない。しかも、UbuntuとEdisonではOSが違うのでifconfigの出力も違い、別のやり方が必要である。エスケープ\のタイミングが微妙である。[^ ](ブランクでない文字)という表現に気が付くまで迷走した。今のところEdisonでは以下のコマンドで抽出に成功している。

ifconfig wlan0 | egrep -o 'addr[^ ]+' | egrep -o '[0-9]+(.[0-9]+){3}'

正規表現に慣れない方のために、少し説明しておくと、ifconfigの出力メッセージが以下の通りなので、
wlan0   Link encap:Ethernet  HWaddr fc:c2:de:3c:c4:23
   inet addr:192.168.1.13 Bcast:0.0.0.0 Mask:255.255.255.0
   UP BROADCAST ........(以下略)

 まず、addrから始まり、ブランクで終わる文字列を残す。つまり、addr:192.168.1.13が残る。次に、数字の0から9だけで構成される1つ以上(カギかっこのあとの+)の文字と.のあと同様に一つ以上の数値の組み合わせが3個ある文字列を抽出すると、addr:がとれて、めでたく、192.168.0.13となるわけである。

Edison_ipaddr

Edisonのサーバーはejsを使っていなかった(4/29/2015)
 いよいよ、Edisonのnodeストリーミングサーバーの解析に入る。久しぶりにEdisonを立ち上げて様子を見る。ここのexpressはV4であった。ウェブ上の資料はV3が多い。ソースは最新のテクニックを駆使しているようなので、理解するのに時間がかかる。

 そのうちEdisonのサーバーソースは、ejsを使っていないことがわかる。勘違いしていた。しかし、IPアドレスの埋め込みは必要なので、ejsは使わなければならない。Edisonのソースコードをさらに真面目に調べ始める。いや、この前のmjpg-streamerほどではないが複雑な構造だ。

require関数(と呼ぶのか)の新しい形に戸惑う。

require(パス名).serveIndex(app,function(){ });

というステートメントが理解できない。いったいこれは何だ。

 調べた結果、serveIndexという関数が、別のところで定義したプライベートな関数で、その定義場所が前のrequireのパスであるらしい。このステートメントでexportされた当該関数を実行している。やれやれ。

 node(というよりjs)が難しいのは、こんな感じで、ある名前が、オブジェクトなのか、プロパティなのか、メソッドなのか、また、既に出来ているモジュールの予約された変数なのか、それともプライベートな変数定義なのかは、一つ一つ調べていく以外に、分からないことにある。

 ディレクトリ構造が変わってもソースが動くように、かなり抽象化したコーディングになっているようで、とても複雑だ。結局、サーバーの構造を変えることはあきらめた。姑息な手段だが、このサーバーの中はそのままにしておき、クライアント側のディレクトリに用意されているindex.htmlだけを換えることにする。

 ファイルアクセスが発生するが、立ち上がりの時の一回限りだ。幸いnodeは、ファイルをアクセスするモジュールは完備している。サーバーの開始直後に、直接ejsのレンダリングで書き換えて入れ替える。

Node expressのインストール不調の原因解明(5/3/2015)

 Edisonのnodeサーバーの解析で壁にぶつかっているころ、思わぬところで別の進展があった。Windowsでnodeのexpressが入らない原因が判明したのだ。何かゴミが入っているのだろうと推測していたが、そのゴミが見つかった。

 たまたま別の調べものをしていて、Winでのnodeのワークディレクトリ直下に.npmrcというファイルを見つけた。その内容は、prefix=C\;\Users\NODE\Nodist\binというテキストである。この文字列は、これまでさんざん頭を悩ましてきた幻のC;ディレクトリチェーンと一致する。

 いつもはこの下のプロジェクト単位のディレクトリで作業していたので気付かなかった。これを誰が作ったのかはわからないが、このいかにもプリファレンスファイル臭い名前は間違いなくインストール時に悪さをしている元凶に違いない。

 これを消してもういちど、npmでexpressをインストールする。大当たりであった。変なディレクトリも作られず、順調にインストールが完了した。expressのコマンドはどうだ。よーし、ちゃんと動く。

 これでWin7のexpressは所定のところにインストールされコマンドとして働くようになった。めでたし、めでたしである。ささいなことだけれど、こういうトラブルが解決したときの爽快感は何ものにも代えがたい

あともう少しだが、うまく整形されない(5/9/2015)
  IPアドレスの抽出に成功したので、残るは、index.htmlの書き換えである。これも思わぬところで新しい手法が見つかった。ejsを使った置換を考えていたのだが、もっと簡単な方法があった。jsのreplaceメソッドを使う方法である。お世話になったこのサイトの最初の講義のところで紹介されていた。

 nodeのfsモジュールを使ってプロトタイプのindex.htmlファイルの内容を文字列に読み込み、 str = str.replace('/置換される文字列/g', IPアドレス); とやると、IPアドレスが、置換される文字列(@などを使った他にない文字列)のところに置き換わる。gはglobalの略でマッチするすべてを変換する。

 こういうところはjsは便利である。変換したあとこのstrをfsで書き出す。造作のない作業だ。早速Windows版でテストしてみた。見事に、該当の場所がIPアドレスに換わった。良いぞ。おや、最後のところで改行され(0x0A)、行が折り返されている。Windowsだから改行が残るのだろうか。もしかすると、HTMLの中の改行は無視されるので問題ないかも。

 まあ、あれこれ考えるより、この外部コマンドの末尾の改行をとってしまえば良いはずだ。というので、ウェブでまた「末尾の改行文字をとる」「java script」などで検索するとすぐ解決法が見つかった。同じreplaceメソッドで、replace('/\n/g','')という正規表現である。

 ところが、こいつがエラーになるのである。fsで読んだファイルの文字列はうまくいくのに、外部コマンドの出力は文字列ではないとはねられる。わけがわからない。文字列オブジェクトを新規に定義して、そこにコマンド出力を移し替えてもだめである。

 これはWindowsだけの現象ではないかと淡い期待を抱いて、Edisonにコードを持ち込み、実際に動かしてみた。危惧した通りEdisonでもindex.htmlファイルの中のIPアドレスは折り返された。さらに一縷の望みを抱いて動画サーバーを動かしてみる。残念、画像は表示されない。悔しい。あともう少しなのに。

ちょっとしたきっかけで遂に成功。いやあ難しいもんだ(5/12/2015)
 この問題もちょっとしたことで解決した。ええー、こんなところにしかけがあったとは、というやつである。外部コマンドをjsで出す、execsync関数の解説ページを見ていた時のことである。外部コマンドの出力を文字列オブジェクトへ収容するステートメントで、冒頭に""という空白文字をつけ加えていることに気付いた。

 str = “” + execsync(“ifconfig wlan0 | grep ...

ふーむ、これはいったい何のためだ。こちらでは無駄なステートメントとしてこの部分は消してしまっていた。電撃が走る。むむむ、これは匂うぞ。

 外部コマンドの出力は文字列でなないと怒られている。文字列オブジェクトを新たに定義し、そこへ放り込んでもだめだったので論理性はないが、もしかすると、これが文字列にするおまじないなのかもしれない。

 だめもとである。この部分を加えてテストしてみる。ヤッホー、大当たりだ。改行文字を除くreplaceメソッドがエラーなしに正常終了した。焦る手で、index.htmlでもテストする。よーし、IPアドレスは折り返さずに表示される。

 喜び勇んでEdisonを立ち上げ、ソースコードを修正する。やった、やりました。外部コマンドから収集したIPアドレスが認識され、Edisonの動画サーバーが見事にWindowsでもストリーミングを開始した。JavaSciriptは型には全くうるさくないと聞いていたが、結構、気難しいことがわかった。

 現在の変更は、オリジナルの複雑なディレクトリ構造とは無関係に、本来、サーバーなどを置く場所にプロトタイプのindex.htmlを収容し、現在のクライアントディレクトリにあるindex.htmlを書き換えるという武骨な方法だが、とにかくこれでEdisonのIP環境がどう変化しても自分でアドレスを拾って正しく稼働する。

 公開は迷ったが、とりあえず、変更した分だけのソースリストをご紹介することにする。このソースの変更と、index.htmlの少しの変更、外部コマンド実行の関数、execsyncsのインストールが必要である。これについては公開したフォルダーのreadme.txtを参照されたい。オリジナルはMITライセンスなので、ライセンスファイルも同梱されている。

ここに、上記のソースファイルなどを入れたディレクトリーを圧縮したzipファイルを置きます。適当な場所に解凍して、中のreadme.txtを読んでください。

「Edison_server_js.zip」をダウンロード

|

« Edisonの電池駆動無線カメラの実現へ | トップページ | Edison進展せず。電子工作に「ときめか」ない »

Edison」カテゴリの記事

Node」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック


この記事へのトラックバック一覧です: EdisonでIPアドレスを変数化した動画サーバーが動いた:

« Edisonの電池駆動無線カメラの実現へ | トップページ | Edison進展せず。電子工作に「ときめか」ない »