NEC Aterm WR9500N[HPモデル] PA-WR9500N-HP - NEC

NEC

5.0 / 5.0

評判の良いこれを買った。セットアップはあまり迷うところもなく終わった。

ただ、USB ディスク共有だけなんかおかしくて、smb://192.168.0.1/Hitachi-1 みたいな感じで、全部指定して接続をかけないと失敗する (Mac OS X)

  1. トップ
  2. tech
  3. 無線ルーターを変えた

初回はうまくいったけど、時間が経ってからもう一度やろうとしたらうまくいかなくなった。Mac の smb 接続が不安定になったりとかいろいろした結果、以下のような状態っぽいことがわかった (推測)

  • スパースバンドルのサイズが大きいとディレクトリエントリが多くなる
  • ルーターがメモリサイズ的にそのサイズのエントリを扱えなくなる
  • 死ぬ

なので、小さいスパースバンドルにするかなんとかしたらうまくいくかもしれないけど、もう諦めた…… 時間の無駄だった。

初回うまくいったのはよくわからない。Mac 側になんらかの形でエントリのキャッシュがあったのかもしれない。なんでもいいけど…

買ってから気付いたけど、USB ポートがついていて、USB HDD を繋いで SMB 共有ができるようになっていた。

せっかくなので、今まで有線USBでバックアップしていたのを、無線経由でバックアップするように変えた。

Time Machine をオフに

まず既存 Time Machine を OFF にする。

現状のバックアップディスクをバックアップ

HDDを新しく買ってくるならこんなことしなくていいんだけど、買いたくないので、一旦現状のバックアップディスクを、別にディスクに .dmg としてバックアップした。

バックアップディスクとなるスパースバンドルファイルをつくる

ディスクユーティリティでスパースバンドルファイルをつくる

  • サイズはとりあえずデフォルトのまま
    • 手元のディスク容量よりも大きいサイズには作れないため
  • フォーマットは Mac OS 拡張 (ジャーナリング)
  • イメージフォーマットはスパースバンドル・ディスクイメージ

作成したらアンマウントして、NASに繋げるディスクにコピーする。最初のバックアップまでは USB で直接繋いで作業する。

コピーしてからもう一度そのイメージをディスクユーティリティで開いて、「イメージのサイズを変更」を行い、2TB ほど容量を確保する。

バックアップをスパースバンドルイメージに復元

スパースバンドルファイルに対して、既存のバックアップの dmg を復元する。死ぬほど時間がかる。

NAS に繋げてバックアップ開始

ディスクをNASに繋げ、共有フォルダを開き、イメージをマウントする。

イメージをマウントして、マウント済みディレクトリに対し、以下のコマンドを実行。GUI を使わないので強制的に設定できる。

sudo tmutil setdestination /Volumes/Time\ Machine 

これでバックアップを再開するとネットワーク経由でバックアップが開始される。履歴も引き継がれ、差分バックアップになる。

NEC Aterm WR9500N[HPモデル] PA-WR9500N-HP - NEC

NEC

5.0 / 5.0

  1. トップ
  2. tech
  3. NEC Aterm WR9500N で Time Capsule 的バックアップ (履歴引き継ぎ)

追記:最近別のアダプタに変えました 500 Can't connect to lowreal.net:443 (certificate verify failed)

 -

3.0 / 5.0

アダプタは WLI-UC-GNM というやつをつけているんだけれど、ping が平均 100ms ぐらい (1ms〜250ms ばらつきがある) で、速度も 300kB/sec (2.4Mbps) ぐらいしかでない状態だった。

SSH して作業をしているので、ちょいちょいひっかかってストレスがかかるのと、奇妙な感じなので直したくていろいろ調べていたけど、ようやく解決したので記録しておく。

解決法

先に解決方法を書くと、/etc/network/interfaces に以下を書けばいいだけだった。

wireless-power off 

経緯

いろいろググってみると、ドライバに対してオプションをわたしたりとかしている例がでてくるけど、別のチップの話なのでそのまま適用できない感じだった。ただ、パワーマネジメントまわりでよくないことが起こることがある、みたいなのはこの時点で頭に入った。

iwconfig の出力を眺めると、以下のように Power Management:on になっていた。なので、iwconfig 側から Power Management を off にできないか調べたら解決方法にあるようなオプションがあることがわかった。

$ iwconfig
wlan0     IEEE 802.11bgn  ESSID:"SNEG"  
          Mode:Managed  Frequency:2.462 GHz  Access Point: XX:XX:XX:XX:AE:CE   
          Bit Rate=43.3 Mb/s   Tx-Power=20 dBm   
          Retry  long limit:7   RTS thr:off   Fragment thr:off
          Power Management:on
          Link Quality=63/70  Signal level=-47 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:41   Missed beacon:0

lo        no wireless extensions.

eth0      no wireless extensions.

オプションを適用させると、Power Management:off になり、ping は平均36ms程度まで、速度は 3MB/sec (24Mbps) まで改善した。数msぐらいまで短かくてもいいと思うけど、だいぶ改善してストレスが減ったのでとりあえずよしとする。

  1. トップ
  2. raspberrypi
  3. Raspberry Pi + Wi-Fi アダプタが異常に遅い問題を解決
  1. トップ
  2. tech
  3. Raspberry Pi + Wi-Fi アダプタが異常に遅い問題を解決

Raspberry Pi の実測電流値が気になったので安定化電源に繋いで適当に計ってみた。

アナログで読んだのでだいたい。USB Wi-Fi は指したまま起動。ほかのイーサネットポートやHDMIポートには何も指していない。

  1. 起動直後 約400mA (2W)
  2. USB Wi-Fi がチカチカしはじめてから 約500mA (2.5W)
  3. ruby -e 'loop {}' (CPU 99%) 約600mA (3W)

自分で接続した周辺機器をオン (AVR + RS232ドライバ + 気圧計 + I2C文字液晶) にすると、約650mA だけど、ほぼLEDだと思う。

スペック上、このモデルは 700mA 使うことになってるけど、意外と少なかった。CPU 全力 + HDMI + イーサネットポートとかだと 700mA になるのかな?

700mA (3.5W) で1年起動させっぱなしで、電気料金が高くとも 30円/kWh だとすると、(3.5 * 24 * 265) / 1000 * 25 ≒ 668円ぐらい。

  1. トップ
  2. raspberrypi
  3. Raspberry Pi の実測消費電力 (電流量)
  1. トップ
  2. tech
  3. Raspberry Pi の実測消費電力 (電流量)

GPIO ピンからとれる電源は普通に電源回路直結なので、Raspberry Pi 自体が起動していようがしていまいが、電源ケーブルさえ接続されていれば供給されています。まぁこれはいいんですが、Raspberry Pi 本体が起動していないとき、もっというとそれらを扱うデーモンが起動していないときに電源供給されてもエコじゃないので、なんとかしました。

回路図

ちょっと余計な線がありますが、キモは FET だけです。伸びてる GND と VCC を周辺回路に繋ぐと、GPIO 25 (22pinから出てる) の論理によってオン・オフします。

手元では 2SK2796L を使ってます (3.3V で直接駆動できるので)

コード側

単に GPIO 25 ピンのハイ・ローを切り替えるだけです。Ruby の場合以下のように

#!/usr/bin/env ruby
# coding: utf-8
 
module GPIO
	def self.export(pin)
		File.open("/sys/class/gpio/export", "w") do |f|
			f.write(pin)
		end
	end
 
	def self.unexport(pin)
		File.open("/sys/class/gpio/unexport", "w") do |f|
			f.write(pin)
		end
	end
 
	def self.direction(pin, direction)
		[:in, :out].include?(direction) or raise "direction must be :in or :out"
		File.open("/sys/class/gpio/gpio#{pin}/direction", "w") do |f|
			f.write(direction)
		end
	end
 
	def self.read(pin)
		File.open("/sys/class/gpio/gpio#{pin}/value", "r") do |f|
			f.read.to_i
		end
	end
 
	def self.write(pin, val)
		File.open("/sys/class/gpio/gpio#{pin}/value", "w") do |f|
			f.write(val ? "1" : "0")
		end
	end
end
 
GPIO.export(25)
GPIO.direction(25, :out)
GPIO.write(25, true)
at_exit do
    GPIO.write(25, false)
end
sleep 3 # 周辺機器が安定するまで適当な時間

...

at_exit でローにするようにしてるだけです。

備考

回路図だとわかりにくい感じだけど、これは GND 側のスイッチ (ローサイドスイッチ) で、VCC は繋がりっぱなしなので、Raspberry Pi 以外の他の電源を回路に接続するとよくないかもしれないです。

ぜんぜんよくわからないんですが、こういう回路はハイサイドにしたほうが安全なのかな。応答速度はあまり必要ではないし……

  1. トップ
  2. raspberrypi
  3. Raspberry Pi のローレベル周辺機器の電源を特定プロセスが動いているときだけオンにする
  1. トップ
  2. tech
  3. Raspberry Pi のローレベル周辺機器の電源を特定プロセスが動いているときだけオンにする

AngularJS には ngResource という拡張があって、サーバに対する API 経由の CRUD 的操作を JavaScript のオブジェクトとしてラッピングできる。具体的には例えば

var Entry = $resource('/entry/:id');
var entry = Entry.get({ id : 0 }, function () {
    entry.title = "yuno";
    entry.$save(); // XHR (async)
});

とかできる。ちょっとかっこいいけど、既存APIで使おうとすると、些細なフォーマットの違いで案の定使えなかったりする。どうしても使ってみたいけど、サーバサイドAPIの仕様まで変えたくない場合、若干無理矢理な方法である程度なら対応させることができる。

サーバサイドの仕様

前提として以下のような仕様だとする

エントリリスト取得

GET /api/entries

# Response
{
  "ok" : true,
  "has_more" : true,
  "entries" : [ ... ]
}

データの新規作成

POST /api/entries
Content-Type: application/x-www-form-urlencoded

title=xxx&body=yyy

# Response
{
  "ok": true
  "entry" : { ... }
}

データの編集

PUT /api/entries?id=0
Content-Type: application/x-www-form-urlencoded

title=xxx&body=yyy

# Response
{
  "ok": true
  "entry" : { ... }
}

ngResource での対応

いくつかハマりポイントがある

  • AngularJS は POST 時のデフォルト Content-Type が application/json
  • ngResource は直接配列のJSONが返ってくることを前提にしている
    • そして付属するデータをうまく返す方法がない

いろいろやってみると以下のようになった。

var Entry = $resource('/api/entries', { id : '@id' }, {
	'query':  {
		method:'GET',
		isArray: true,
		transformResponse : function (data, headers) {
			data = angular.fromJson(data);
			if (!data.ok) throw "API failed";
			Entry.hasMore = data.has_more;
			return data.entries;
		}
	},
	'save':  {
		method:'POST',
		transformResponse : function (data, headers) {
			data = angular.fromJson(data);
			if (!data.ok) throw "API failed";
			return data.entry;
		},
		transformRequest: function (data, headers) {
			var ret = '';
			for (var key in data) if (data.hasOwnProperty(key)) {
				var val = data[key];
				ret += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
			}
			return ret;
		},
		headers : {
			'Content-Type' : 'application/x-www-form-urlencoded'
		}
	},

	'update' : {
		method: 'PUT',
		transformResponse : function (data, headers) {
			data = angular.fromJson(data);
			if (!data.ok) throw "API failed";
			return data.entry;
		},
		transformRequest: function (data, headers) {
			var ret = '';
			for (var key in data) if (data.hasOwnProperty(key)) {
				var val = data[key];
				ret += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
			}
			return ret;
		},
		headers : {
			'Content-Type' : 'application/x-www-form-urlencoded'
		}
	}
});
  • 自力で transformResponse, transformRequest で ngResource が要求しているフォーマットに変更してやる
  • リストに付随するデータはスタティックに持たせてしまう (リクエスト直後に読み出すことを想定)
  • 自力で application/x-www-form-urlencoded なリクエストを作ってやる
  • 冗長に書いてるけど PUT と POST はメソッドが違うだけ

これを使う場合、

var entries = Entry.query(function () {
    $scope.hasMore = Entry.hasMore;
});

...

var entry = entries[0];

entry.title = "FooBar";
entry.$update();

みたいになる。だいぶアホっぽいし、この部分のコードがカオスになるけど、一応使えるようにはなる。

もっといい方法があったら教えてください……

  1. トップ
  2. angularjs
  3. AngularJS の ngResource を既存APIの仕様にあわせる
  1. トップ
  2. tech
  3. AngularJS の ngResource を既存APIの仕様にあわせる