評判の良いこれを買った。セットアップはあまり迷うところもなく終わった。
ただ、USB ディスク共有だけなんかおかしくて、smb://192.168.0.1/Hitachi-1 みたいな感じで、全部指定して接続をかけないと失敗する (Mac OS X)
評判の良いこれを買った。セットアップはあまり迷うところもなく終わった。
ただ、USB ディスク共有だけなんかおかしくて、smb://192.168.0.1/Hitachi-1 みたいな感じで、全部指定して接続をかけないと失敗する (Mac OS X)
初回はうまくいったけど、時間が経ってからもう一度やろうとしたらうまくいかなくなった。Mac の smb 接続が不安定になったりとかいろいろした結果、以下のような状態っぽいことがわかった (推測)
なので、小さいスパースバンドルにするかなんとかしたらうまくいくかもしれないけど、もう諦めた…… 時間の無駄だった。
初回うまくいったのはよくわからない。Mac 側になんらかの形でエントリのキャッシュがあったのかもしれない。なんでもいいけど…
買ってから気付いたけど、USB ポートがついていて、USB HDD を繋いで SMB 共有ができるようになっていた。
せっかくなので、今まで有線USBでバックアップしていたのを、無線経由でバックアップするように変えた。
まず既存 Time Machine を OFF にする。
HDDを新しく買ってくるならこんなことしなくていいんだけど、買いたくないので、一旦現状のバックアップディスクを、別にディスクに .dmg としてバックアップした。
ディスクユーティリティでスパースバンドルファイルをつくる
作成したらアンマウントして、NASに繋げるディスクにコピーする。最初のバックアップまでは USB で直接繋いで作業する。
コピーしてからもう一度そのイメージをディスクユーティリティで開いて、「イメージのサイズを変更」を行い、2TB ほど容量を確保する。
スパースバンドルファイルに対して、既存のバックアップの dmg を復元する。死ぬほど時間がかる。
ディスクをNASに繋げ、共有フォルダを開き、イメージをマウントする。
イメージをマウントして、マウント済みディレクトリに対し、以下のコマンドを実行。GUI を使わないので強制的に設定できる。
sudo tmutil setdestination /Volumes/Time\ Machine
これでバックアップを再開するとネットワーク経由でバックアップが開始される。履歴も引き継がれ、差分バックアップになる。
追記:最近別のアダプタに変えました 500 Can't connect to lowreal.net:443 (certificate verify failed)
アダプタは 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ぐらいまで短かくてもいいと思うけど、だいぶ改善してストレスが減ったのでとりあえずよしとする。
Raspberry Pi の実測電流値が気になったので安定化電源に繋いで適当に計ってみた。
アナログで読んだのでだいたい。USB Wi-Fi は指したまま起動。ほかのイーサネットポートやHDMIポートには何も指していない。
自分で接続した周辺機器をオン (AVR + RS232ドライバ + 気圧計 + I2C文字液晶) にすると、約650mA だけど、ほぼLEDだと思う。
スペック上、このモデルは 700mA 使うことになってるけど、意外と少なかった。CPU 全力 + HDMI + イーサネットポートとかだと 700mA になるのかな?
700mA (3.5W) で1年起動させっぱなしで、電気料金が高くとも 30円/kWh だとすると、(3.5 * 24 * 265) / 1000 * 25 ≒ 668円ぐらい。
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 以外の他の電源を回路に接続するとよくないかもしれないです。
ぜんぜんよくわからないんですが、こういう回路はハイサイドにしたほうが安全なのかな。応答速度はあまり必要ではないし……
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" : { ... } }
いくつかハマりポイントがある
いろいろやってみると以下のようになった。
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'
}
}
});
これを使う場合、
var entries = Entry.query(function () {
$scope.hasMore = Entry.hasMore;
});
...
var entry = entries[0];
entry.title = "FooBar";
entry.$update();
みたいになる。だいぶアホっぽいし、この部分のコードがカオスになるけど、一応使えるようにはなる。
もっといい方法があったら教えてください……