MacでのBluetoothホストコントロールデバイスの優先順位の変更
毎回ググるのでメモ。
OSX は USBのドングルとかBluetoothホストコントローラとかをつけたときの挙動を、ファームウェアの NVRAM ってところに bluetoothHostControllerSwitchBehavior
というキーで値を設定してあげることによって以下の3種類のうちから決めることができる。
never
: 外付けのホストコントローラにスイッチせず、つねにビルドインコントローラを使うalways
: ビルドインコントローラからdetachして外付けのホストコントローラにスイッチするdefault
: 外付けホストコントローラがApple以外のときはビルドインからdetachして外付けデバイスを使う
デフォルトはもちろん default
。
で、 BT4LE に対応したドングルを持っていれば、BT4積んでない昔の MacBook なんかでも CoreBluetooth つかったり開発したりできる。
さらに、あえてここで never
を設定して外付けのホストコントローラを使わない設定にすると、 余っている外付けホストコントローラを iOS Simulator から利用することができる。
この設定を変えるには nvram
ってコマンドを使う:
$ sudo nvram bluetoothHostControllerSwitchBehavior="never"
とかでOK。
詳しくは
Technical Note TN2295: Testing Core Bluetooth Applications in the iOS Simulator
参照。
コマンドラインでネットワーク設定のネットワーク環境のところを変える
ネットワーク周りの設定は networksetup
コマンドでいろいろできるみたいで、 man をみるとどうも環境設定でできることはほとんどここからもできる模様。
んで、ネットワーク環境というのは
-listlocations
List all network locations.
-getcurrentlocation
Display the name of the current set.
-createlocation location [populate]
Create a set with the user-defined-name name and optionally populate it with the default services.
-deletelocation location
Delete the set.
-switchtolocation location
Make the specified set the current set.
この辺が該当するようだ、切り替えるだけなら
$ networksetup -switchtolocation Hoge
で OK。
バッテリーのこり60秒で通知の話
僕のトークでなんか気になった人がいるとのことなので僕の使っているスクリプトを置いておきますね。
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use Cocoa::BatteryInfo;
use Cocoa::EventLoop;
use Cocoa::Growl ':all';
growl_register(
app => 'Battery Notifier',
notifications => ['NotifyLastOneMinite', 'NotifyTimeRemaining'],
);
Cocoa::BatteryInfo::time_remaining_handler {
my $sec = Cocoa::BatteryInfo->time_remaining_estimate;
return unless $sec =~ /\d/;
if ($sec <= 60) {
growl_notify(
name => 'NotifyLastOneMinite',
title => 'バッテリー切れまで',
description => sprintf '残り %d 秒', $sec,
);
}
else {
my $time;
if ($sec >= 60*60) {
$time = sprintf '%d 時間 %d 分 %d 秒',
int($sec / (60*60)), int(($sec % (60*60)) / 60), $sec % 60;
}
elsif ($sec > 60) {
$time = sprintf '%d 分 %d 秒',
int($sec / 60), $sec % 60;
}
else {
$time = sprintf '%d 秒', $sec;
}
growl_notify(
name => 'NotifyTimeRemaining',
title => 'バッテリー切れまで',
description => sprintf '残り %s', $time,
);
}
};
Cocoa::EventLoop->run;
これを LaunchAgent でログイン時に自動で立ち上がるようにしております。
で、これをうごかしているとバッテリー残り時間が変化したタイミングで Growl 通知が来るのですが、 普通は NotifyTimeRemaining
という通知が来ます。もしそのときに残りが60秒いないだったらその代わりに NotifyLastOneMinite
という通知が来ます。
毎回通知されるのはうざいので僕は NotifyTimeRemaining
というほうは Growl の設定でオフにしています。
で、だいたい使っている感覚としては60秒でまず通知が来て、 その後もういちど、残り0秒という通知がきて、その直後にハイバネートする、というような感じのようです。
Cocoa::BatteryInfo has been released!
本日二回ほどバッテリー切れで黒い画面をみて、「システムのバッテリー残量警告でるのはやすぎなんだよなーもっとぎりぎりの残量通知が欲しいよなー」、とか思いつつバッテリー周りのAPIドキュメントを眺めていたら気がついたらCPANモジュールができていた…。
Cocoa::BatteryInfo - Getting battery informations on your Mac - metacpan.org
単純なバッテリー情報の取得の他にも、 Cocoa::EventLoop
との合わせ技で OS からのバッテリー関連通知を受け取るという機能もあるので残量監視スクリプトなど作るのに最適です。
というとネタモジュールな感じだけど、ノートブックのインターナルバッテリー以外にも OS X Server に接続している UPS の情報などもとれたりしますのでわりとそっち系では実用モジュールなのではないかと思われる。
OSX のコマンドラインから、wi-fi の情報をつかって位置情報を得る
を見て、面白そうだと思ったのでそのMac版。MacでコマンドラインからWiFiスポットをスキャンするのは、
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s
でいけます。ってことで、
use strict;
use warnings;
use utf8;
use 5.012;
use JSON;
use LWP::UserAgent;
my @addresses = do {
my @lines = split /\n/, qx{/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s};
shift @lines;
my @r;
push @r, (split /\s+/, $_)[2] for @lines;
@r;
};
my $query = encode_json({
version => '1.1.0',
host => 'maps.google.com',
request_address => JSON::true,
address_language => 'ja_JP',
wifi_towers => [
map +{
mac_address => $_,
signal_strength => 8,
age => 0,
}, @addresses,
],
});
my $ua = LWP::UserAgent->new;
my $res = $ua->post('http://www.google.com/loc/json', Content => $query);
$res->is_success or die $res->status_line;
use YAML;
warn Dump decode_json($res->content);
ってな感じでOKです!
Basic認証対応のMac用Gyazoクライアントを作った
今頃なにを言っているのかという感じだが、Basic認証ごしにGyazoクローンに画像アップロードしたいという要求があったので、ちょろっと書いてみた。
Downloads からバイナリも落とせるようにしておいた。
初回起動、もしくはOption押しながらの起動で設定画面が出るので、適当に情報を入力して閉じたら、あとは普通のGyazoクライアントと同じように使える。
誰かいかしたアイコンつくってください。
Time Machine で case-sensitive なバックアップを case-insensitive で復元する
都市伝説だと思われていた Diablo3 がなんと発売された。
発売日が決まってからというもの同僚が執拗に誘ってくるので、しょうがないのでインストールすることにしたが、 どうも Diablo3 は case-sensitive (大文字小文字を区別) なファイルシステムにインストールできないらしい。
ディスクイメージ内にインストールすることで回避できないか、とかいろいろやってみたがうまくいかないので Time Machine 復元を利用して無理矢理ファイルシステムを変更した。
手順は以下を参考にした。
joshua stein: restoring case-sensitive hfs+ volumes with time machine
OS X インストーラで起動して、希望のファイルシステムに初期化したあと、rsync で自前でバックアップをコピー、っていう手法。
インストーラに rsync は含まれていないんだけど、バックアップデータが rsync をもっているからそこのを使う、ってのはなかなか面白い。
この記事にもあるようにバックアップを rsync したあと、インストーラの /dev
も別途 rsync しないとシステムは起動しないので注意が必要。
あと大文字小文字違いのファイルを持っている場合、それらが失われる覚悟も必要。
というわけで無事に遊べるようになった。
OS X 10.7.3 から LaunchAgents の WatchPaths の仕様が変わったようだ
前から ~/Library/LaunchAgents
にユーザー権限でおいた agent から root 所有のファイルを監視していたのだが、10.7.3 にアップデートしてからそれらが全く動かなくなってしまった。
しょうがないので /Library/LaunchAgents
に移動し、 root でうごかすようにしたら再び動き出した。
監視してる root 所有のファイルはもちろん一般ユーザーでも読み込み可能な権限になっているのにこの制限は嫌だなぁ。
追記@
隣の席の人は同じものが全く問題なく動いているとのこと…。僕の環境が悪いのか…。
skype-cli
昨日のコードを元に、skype-cli
というコマンドラインツールを書いた。
Skype の Desktop API っていうのはマシン上で起動している Skype と通信することで、Skypeの機能にアクセスするAPIで、プラットフォーム毎に通信手段はことなるが、つながってしまったあとの通信内容はテキストベースのプロトコルとなっている。
なので、このテキストプロトコルをtelnet感覚で標準入出力でアクセスできるツールを作ってみたという感じ。
これを子プロセスで実行することで、nodeやEmacsなどからも簡単にSkype APIがたたける、はず。
なんだけど、実際にnodeで以下のようなコードを書いてみてもうまく動かない。
var child_process = require("child_process");
var skype = child_process.spawn("./skype-cli");
skype.stdout.setEncoding("utf8");
skype.stdout.on("data", function (data) {
console.log("stdout: %s", data);
});
skype.stderr.setEncoding("utf8");
skype.stderr.on("data", function (data) {
console.log("stderr: %s", data);
});
process.stdin.resume();
process.stdin.setEncoding("utf8");
process.stdin.pipe(skype.stdin, { end: false });
skype.on("exit", function (code) { process.exit(code) });
なーんでか。
Cocoa::Skype とか
Cocoa:: なんちゃらでほしいものを聞いていたときにも挙がっていた Cocoa::Skype だけど、その昔Skype4COMを使った記憶があって、SkypeAPI のバインディング書くのはめんどそうな印象だったのだが、 今日 Skype.framework のヘッダファイルみたら、
#import <Cocoa/Cocoa.h>
@protocol SkypeAPIDelegate;
@interface SkypeAPI : NSObject
{
}
+ (BOOL)isSkypeRunning;
+ (BOOL)isSkypeAvailable; // You can only connect and send commands when this method returns YES.
// For example, when Skype is running, but user is logged out, then it returns NO.
+ (void)setSkypeDelegate:(NSObject<SkypeAPIDelegate>*)aDelegate;
+ (NSObject<SkypeAPIDelegate>*)skypeDelegate;
+ (void)removeSkypeDelegate;
+ (void)connect;
+ (void)disconnect;
+ (void)sendSkypeCommand:(NSString*)aCommandString;
@end
// delegate protocol
@protocol SkypeAPIDelegate
- (NSString*)clientApplicationName;
@end
// delegate informal protocol
@interface NSObject (SkypeAPIDelegateInformalProtocol)
- (void)skypeNotificationReceived:(NSString*)aNotificationString;
- (void)skypeAttachResponse:(unsigned)aAttachResponseCode; // 0 - failed, 1 - success
- (void)skypeBecameAvailable:(NSNotification*)aNotification;
- (void)skypeBecameUnavailable:(NSNotification*)aNotification;
@end
と想像以上に短く、これならすぐバインディング書けそうだなーということで気分転換もかねてPerlバインディングをつくってみた。
使い方は付属の example を参照のこと。 Skype.framework の機能は全部つけてある。 Perl サイドのメソッド名とかはまだ変更するかもしれない。暇なときにドキュメントつけてリリースしよう。