2014年 01月 20日

Angular JS でビューを伴う Service ってどう書けばいいんですか

続きをかきました。

[tech] Angular JS で View を伴う Service 的なことをしたいとき、あるいは Directive に Controller をつけたいとき。 | Tue, Jan 21. 2014 - 氾濫原

よくわからなかったので以下のようにしましたが、まっとうな方法には思えないので正しいやりかたをおしえていただきたく申し上げます……

  • factory で空のオブジェクトをかえしとく
  • view に紐付けた controller で factory で作ったオブジェクトを初期化する
  • 作った Service を依存に加えて使う

一応、controller 間は直接依存しない (Service を mock にさしかえれば動く) のでユニットテストは書けると思うけど、よくわかりません……

myApp.factory('DialogService', function () { return { } });
myApp.controller('DialogControl', function ($scope, $q, DigalogService) {
	DialogService.open = function (title, message) {
		$scope.deferred = $q.defer();
		$scope.show = true;
		return $scope.deferred.promise;
	};

	$scope.close = function () {
		$scope.show = false;
		$scope.deferred = null;
	};

	$scope.ok = function () {
		$scope.deferred.resolve(true);
	};
});


// User
myApp.controller('FooController', function ($scope, DialogService) {
	DialogService.open('foo', 'bar').then(function () {
		...
	});
});

そもそも "View independent business logic: Services" と書いてあるので、定義からして Service はビューを持ってはいけないようです。

じゃあビューを伴う Service 的なものはどうやって書くんですか

Raspberry Pi を中心にやってみようとしているところ

Raspberry Pi せっかくあるので、一応作りたい目標をもっていろいろ試してみてる。現時点での思惑を書いておく。

概要

無線機の周辺を拡張して、PCと連携しやすくしたり便利にしたり、というのが目的。具体的には

  • 無線機の Wi-Fi 化
    • API サーバになってLAN内のコンピュータから無線機の情報を取得・設定する
  • アンテナ切替情報の取得・設定
  • そのたもろもろ

全体

  • Raspberry Pi
    • I2C バス
      • アンテナ切替コントローラー (AVR)
      • センサー計 (温度など)
    • シリアルポート
      • 無線機コントロール (RS-232C 変換)
  • WebSocket サーバー
    • 周辺機器の中央集権サーバー
      • 無線機コントローラー
      • アンテナ情報
      • センサーなど

ある程度拡張性を持たせつつこれらを収めたい。無線機の近くで使うので、ある程度ノイズ対策が必要かもしれない。

ブロックごとの設計

電源部
  • アンテナ切り替えリレー用に 12V (最大 400mA 程度) が必要
  • Raspberry Pi が 5V 700mA が必要
  • ほか周辺機器分はそんなに食うものがないので、かなり余裕を持っても 5V 500mA ぐらいあればよさそう
    • Raspberry Pi の GPIO が 3.3V で接続機器もあわせたいので 3.3V も必要

12V が必要なので、ACアダプタとして 12V を使い、降圧して 5V, 3.3V を作りたい。

  • 12V 500mA (6W)
  • 5V 1A (5W)
  • 3.3V 500mA (1.65W)

ぐらい確保できたら十分そう。PC用の電源だと、100Vから直接これらの電圧を全部調達できるけど、コストはともかくオーバースペックでデカすぎる。

12V 2A ぐらいのACアダプタ (24W) から 5V はスイッチングである程度高容量を高効率でとりだして、3.3V は 5V からリニアレギュレーターで安定化させる感じにする。

http://akizukidenshi.com/catalog/g/gM-02038/

5V 3A のスイッチングDC/DCコンバーターで、変換効率は最低でも73%。

  • アダプタ: 12V 2A
    • 12V 500mA
    • 12V 1.5A (18W) -> 5V 2.6A (18 * 0.73 = 13.14W)
      • 5V 1A
      • 3.3V 500mA を 5V からリニアレギュレーターで作ろうとすると、電圧差はそのまま熱になるので ( (5 - 3.3) * 0.5 = 0.85W が無駄になる)、単に 5V 500mA を消費すると考えることができる。
アンテナ切替コントローラー

ATmega168P をつかって実装。TWI (I2C) がついてるので簡単。内蔵8 M クロックで動作させて、アンテナのリレーのコントールをI2C経由及びボタンで行い、LED でどのアンテナが有効かを表示する。

リレーは2〜6つほどを同時に駆動する必要があり、この時最大で 400mA ほど流れる。かなり余裕があり、3.3V でも十分スイッチできるパワーMOS-FET でスイッチングする。

電源は I2C を Raspberry Pi と直接繋げたいので 3.3V 供給

センサー類

基本的に I2C 対応、3.3V 品なので、そのままバスに繋ぐだけ。ごちゃごちゃやりたいのでブレッドボードを内蔵してそこに差す

RS-232 変換

無線機とのインターフェイスのために RS-232 変換をする。

2014年 01月 17日

Raspberry Pi / BeagleBoard Black / Intel Galileo / Arduino の違いのメモ

いろいろでてきてる。

Raspberry Pi

Type AType B があり、Type A はイーサネットポートと組込みUSBハブがなくメモリが少ない分少しだけ安い。

BeagleBoard Black

本体は Raspberry Pi と同じぐらいの価格だけど、

  • CPU がより高速
  • オンボードなフラッシュメモリがある (SDカードもつけれる)
  • 消費電力がより低い
  • GPIO が多い

という特徴がある。内蔵フラッシュメモリがあるので、(それにおさまるなら) SDカードがいらない分、Raspberry Pi よりコスト面でも有利。一方で欠点は

  • 入手性
    • Raspbery Pi はかなり安定して手に入る感じだけど、BeagleBoard Black はそうでもない感じ
  • 情報源
    • やはりちょっと少ない

Intel Galileo

価格的に上であげたものの1.2〜1.5倍ぐらいする。現時点ではまだ日本未発売。1月中旬らしいのでそろそろかな。2A のAC アダプタとケーブルが一部付属っぽいので、(それらが必要な人なら) そんなに割高とはいえないかもしれない。

Linux が動いてるけど、Arduino 互換を謳ってる。ピン互換があって Arduino 用にでまわっているシールドがつかえるのと、開発環境も Arduino のものが使える。

気になるのは

  • グラフィック出力がない (HDMI とか)
  • 消費電力 (詳しいスペックがわからないけど、2A のアダプタが付属ってことは結構あるのかな)

Arduino

Arduino は AVR というマイコンを使って動いているので、Linux は載っていない。本当にローレベルなことしかできないし、CPU クロックも20MHz程度。2000円〜3000円ぐらいで買えるみたいだけど、できることと、実装方法の苦楽の差を考えると Raspberry Pi や BeagleBoard Black のほうが圧倒的にコストパフォーマンスは高い。

個人の見解のまとめ

最初に手をとるなら Raspberry Pi がよさそう。もっと要求がでてきたら BeagleBoard Black がよさそう。Intel Galileo はなんともいえない。

さらに別の回路を複雑に繋げたり、役割分担をさせたくなったら、Arduino 的なものを導入してもよさそう。

しかし AVR 使うなら、普通にチップ買えば1個あたり50円〜300円程度 (チップによる) なので、個人的にはそのほうがいいと思う。ただ、Arduino はオールインワンな感じの開発環境がキモなので、それが欲しいなら Arduino はいいかもしれない。(自分で互換のブートローダーを書きこんでもいいけど)

2014年 01月 16日

関連エントリー (画像)

2014年 01月 15日

Raspberry Pi の SD カードを Mac でバックアップ

特筆するほど難しいことはないけど書いておく。基本的に dd を使う方法が最速だと思うけど、dd コマンドはうっかり使うと死ぬ感じなので、こういうことは GUI で行いたい。なので、ディスクユーティリティを使用してバックアップを作る。

SD カードをさしこむとディスクユーティリティにでてくるので、各パーティションをアンマウントして (boot だけ自動でマウントされるはず)、カード (この例では 32.02GB APPLE SD Card...) を選択して、ツールバーの「新規イメージ」を選択する。

新規イメージでは、デフォルトで「圧縮」が選択されているはずなので、そのまま適当なディレクトリに保存する。

するとコピーがはじまる。基本、SDカードそのものの読み出し速度に律速される。手元のカード (Class 10) の場合、25MB/sec ぐらいで読み出されて、圧縮で 8〜16MB/sec で書き込みがある。32GB だと、32 * 1024 / 25 / 60 で、22分ほどかかる。最終的に 18GB になった。

Mac では Linux で使われる extN には対応していないので、Raspberry Pi の ext4 のパーティションはマウントできない。コピー中、パーティションのタイプ自体は認識されているけど、ext2 として認識されている。

圧縮された .dmg ができるので、復元 (あるいはクローン) もディスクユーティリティを使う必要がある (Mac 上でマウントして復元、または hdiutil convert してから)。dd + gzip だとどこの環境でも簡単に復元可能なので、どっちもどっちかなという感じ。

2014年 01月 14日

関連エントリー (画像)

node.js で Perl における Test::TCP または Ruby における Glint

Perl には Test::TCP というのがあって、テスト中、空いてるポートで何かしらのサーバーを起動して使うということができます。Ruby においては Glint というライブラリがあって、同じことができます。

node.js の場合、node-test-tcp というのがあって、node の net.Server で動くサーバに関しては簡単に同じことができます。が、memcached とか外部プロセスを起動させようとするとちょっと困るのと、done() を呼ばないと終了しないので、何かいい方法はないかなと思ったので書いてみました。

test-tcp だとカブるので glint のほうの名前を仮りています。

つかいかた

glint(
	function (port) {
		// ここは外部プロセスで実行される
		// ただし文字列化して関数が渡されるので外のスコープの変数は使えない。
		// node.js の exec, execFile はいわゆる exec ではないので1つプロセスが余分にできる。我慢するしかない。
		console.log('starting memcached with port: ' + port);
		require('child_process').execFile('memcached', ['-p', port]);
	},

	function (error, server) {
		if (error) throw error;

		// server は起動が確認済み
		// server.port でポート番号がとれる。
		// server.kill() でこのプロセスだけ殺せる

		console.log(server);
		var s = net.connect(server.port, function () {
			s.write("version\r\n");
		});
		s.on('data', function (data) {
			console.log(data.toString('UTF-8'));
			s.end();
		});

		// この関数を抜けても exit されるまで server は (明示的にkillしない限り) kill されない
	}
);

しくみ

他のモジュールとやってることは一緒なのですが、node.js だと面倒な点がいくつかあります

  • fork / exec はいわゆる *nix の fork/exec ではない
  • オブジェクトファイナライザ的な仕組みがない
    • 特定のオブジェクトが破棄されるタイミングで処理を行うことができない

node の fork / exec (execFile) は *nix の fork / exec とは全く違うので、細かいプロセスの制御ができません。特に exec 単体相当はないので、現在のプロセス自体を置き換えるということができません。そんなわけで1つ別プロセスを経由している関係で、無駄に1プロセスを消費しています。

オブジェクトのファイナライザがないので、node-glint では process.on('exit') で起動したサーバを終了しています。ただし、普通に外部プロセスを起動すると、そのプロセスの終了を待つ挙動になり、exit されません。が、spawn() のオプションに detach: true を指定した上で、unref() を呼んであげることで、外部プロセスの終了に関わらず起動元の node プロセスを exit させることができます。

まとめ

一応形にはなりましたが、細かい挙動の検証がめんどうなので npm にあげてません。特に現在の実装はシグナルまわりのハンドリングがいい加減です。node マスターの皆様におかれましては、よりよい方法をご教示頂ければと思う所存です。