iPhoneのバッテリー残量を取得

iPhoneのバッテリーがかなりヘタってちょっと使うとすぐに電源が落ちてしまうようになってしまったので、自分で交換してみました。やり方を紹介したページを見つつ、バッテリー\2000 + 工具セット \1000 で無事交換成功し、日中そこそこ使っても丸一日持つようになりました。



DIGIFORCE 交換用PSEバッテリー iPhone6用 1810mAh LPB-DIGI6

DIGIFORCE 交換用PSEバッテリー iPhone6用 1810mAh LPB-DIGI6


さて、バッテリーの寿命を良くする方法として、80〜90%ほど充電されたら繋ぎっぱなしにせずに充電をやめると良いという説があるようです。真偽のほどは定かではありませんし、大きな効果があるならそういった機能が実装されているでしょうから、おそらくいちいち気にするほどの効果はないのでしょう。とはいえ、意識しなくとも自動的に充電が止まってくれるのならそうしてみても良いかな?という気になったので、やり方を考えてみました。


まず、iPhoneのバッテリー残量を取得する方法ですが、なんらかのアプリを使えないでしょうか? しかしiOSの場合、アプリがバックグラウンドで定期的に処理をするのは、アクセサリへのアクセスや、音楽再生や位置情報を使用するアプリに限られており、電池監視のためにはトリッキーなことをする必要があるので候補から外しました。


次に考えられるのはUSB越しで取得する方法です*1。最近のLinuxデスクトップ(Fedora 25で確認)にiPhoneをUSB接続すると、upowerコマンドでiPhoneのバッテリー値を取得できます。下記はiPadの場合ですが、まず一覧で名前を確認し、

$ upower -e
/org/freedesktop/UPower/devices/computer_3_1
/org/freedesktop/UPower/devices/mouse_0003o046Do1024x000A
/org/freedesktop/UPower/devices/keyboard_0003o046Do2011x000B
/org/freedesktop/UPower/devices/DisplayDevice

それっぽいデバイスを指定すると、

$ upower -i /org/freedesktop/UPower/devices/computer_3_1
  native-path:          /sys/devices/pci0000:00/0000:00:14.0/usb3/3-1
  vendor:               Apple_Inc.
  model:                iPad
  serial:               *****************************************
  power supply:         no
  updated:              20161231221652(14 seconds ago)
  has history:          yes
  has statistics:       no
  computer
    warning-level:       none
    percentage:          100%
    icon-name:          'battery-full-charged-symbolic'

という感じで情報が出力されるので、このpercentageを見るというのが一つの方法です。GUIで設定(gnome-control-center)→電源 で残量を確認できるのもこの情報を表示しています。


これを見て、80%を超えたらUSBの電源をOFFにする方法が取れるでしょう。LinuxからのUSBの電源制御には、最近だと以下のハブが使えるそうです。
LinuxからUSB HUBの電源のON/OFFを制御してみる - memoメモ


ただ欠点として、USBから切断してしまうとそれ以降の情報は取れないので、充電完了後に使用していると電池が減っていってしまうということになります*2


別のやり方として、iTunesをインストール済みのMacまたはWindowsであれば、libimobiledeviceを導入することで、Wi-Fi経由でも電池残量などの情報が取得できます。たまたまWiFiで電源をON/OFFできるコンセントを作ってあったので、全てWiFi越しでやれるということもあり、今回はこの方法を試してみました。


まず、libimobiledeviceを導入します。Macであればbrewで一発です。とはいえiOS10のせいか、HEADでないとうまく動作しませんでした。

$ brew install --HEAD libimobiledevice

これで、
idevice_id -l コマンドでUSBまたはWiFiで繋がっているiOSバイスのシリアルを調べておき、ideviceinfoでバッテリー情報を取得します。

$ ideviceinfo -u ****************(idevice_idで表示されたシリアル) -q com.apple.mobile.battery
BatteryCurrentCapacity: 100
BatteryIsCharging: false
ExternalChargeCapable: true
ExternalConnected: true
FullyCharged: false
GasGaugeCapability: true
HasBattery: true

BatteryCurrentCapacityが%単位でのバッテリー残量です。
rubyであれば

$IDEVICEINFO_CMD = '/usr/local/bin/ideviceinfo'

def get_batt(device_id)
  result = `#{$IDEVICEINFO_CMD} -u #{device_id} -q com.apple.mobile.battery`
  if result =~ /BatteryCurrentCapacity:\s*(\d+)/
    return $1.to_i
  end
  nil
end

というような関数でバッテリー残量を取得できるようになります。


ただし,iPhoneがスリープ状態になっている場合、WiFiには90〜300秒に一度、数秒間しか接続されないようで、この瞬間しか情報がとれません。とりあえず、2秒に一度くらいポーリングをかけることにします*3。また、それでもかなり長いことWiFiに接続してこないこともあるようなので、そのような場合には一度充電をOFF→ON(またはON→OFF)することで、iPhoneをウェイクアップさせれば情報がとれます*4


この結果を見て、80%以上で充電停止、80%未満で再開するようにします。また、充電中にMacがスリープしてしまうと充電されっぱなしになるので、充電中はcaffeinateコマンドでスリープを抑制しています。全体的にはこんなスクリプトになりました。


30%充電の状態からこのスクリプトを動かしながら充電を試して見た結果、こんな感じになりました。運悪く80%になるわずか手前でWiFi接続が切れたらしく、80%を3%ほど超えたところで充電が止まりました。



そのままiPhoneを使っていると、79〜80%で維持されるように充電がON/OFFされます。



でもこれ結局充放電してるわけで、バッテリーに優しい気はしない。。まあ、あくまで実験ということで。

*1:Bluetooth LEのBattery Serviceを使ってとれないか試したのですが、いざ取得しようとすると認証を要求されてしまい失敗しました。

*2:定期的に再接続して充電残量をチェックすればいいかも

*3:本当はlibimobiledeviceから接続イベントを取れれば良いのですが、ポーリングでも大した負荷ではないのて今回は適当に済ませてしまいました。

*4:この時、いちいち接続音やバイブレータが鳴りますが…

SLコマンド on touch bar

新しいMacBook Proのtouch barで走るSLコマンドを作りました。
(touch barシュミレータでしか動作確認してませんが。)


https://raw.githubusercontent.com/NeoCat/sl_on_touchbar/master/sample.png



オリジナルのようにオプション(-a, -l, -F)には対応していません。


ソース(Swift)は以下。ビルド済みのバイナリも入ってます。
https://github.com/NeoCat/sl_on_touchbar


追記: 新しいmacOSでは、開発元が確認できないので開けない、というエラーが出ますが、一度 中にある「sl_on_touchbar」というappをctrlクリックして開くを選択すると、エラーダイアログに「開く」というボタンが現れますので、これをクリックすると以降は普通に開けるようになります。


なおビルドとシミュレータの動作にはmacOS Sierra 10.12.2 beta (16C41b)以降、XCode 8.2 beta以降が必要です。


slが走っている間はウィンドウのフォーカスが奪われるので、実質何も操作できなくなります。端末しか占拠しない普通のSLコマンド以上にうざいです。


これは、touch barに何か出すにはアプリケーションのウィンドウを手前に出している必要があるため。
普通のSLコマンドのような使用感を得るために、UIElement=YESにしてDockアイコンが出ないようにしたアプリケーションを起動してサイズ0×0のウィンドウをこっそり開くことで、touch barへの描画権を得ています。こいつが常に手前に出るせいでフォーカスが奪われるというわけです。

SL画像の差し替え [11/16追記]

「長い列車写真」の情報をコメントでいただいたので、touch barにこの写真を流せるようにしました。
slコマンドの引数か、環境変数 SL_IMAGE のいずれかに写真ファイル(高さを60ピクセルにしてください)へのパスを設定しておくと、そのファイルの画像が使われます。

参考: https://github.com/avatsaev/touchbar_nyancat

keyhacでNICOLA配列を実現する

macOS Sierraにアップデートしたところ、キー配列をカスタマイズするKarabinerが利用できなくなってしまいました。


Karabinerは非常に様々なカスタマイズに対応していたため、不便な思いをしている人も多そう。
私はNICOLA配列(いわゆる親指シフト入力)で日本語を入力するのにKarabinerを使っていたのですが、これができなくなっていました。
親指シフトは同時押し(シフトキーを押しながら文字キーを押すだけでなく、文字キーを押してからシフトキーを押し下げても良い)が特徴のため、単純なキーの置き換えだけができるツールでは再現ができません。

そんな折、以下のページでkeyhacという、Pythonで高度にキー配列をカスタマイズできるツールを知りました。


macOS SierraでKarabinerが動かなくて困っている人に贈る代替ソフトウェア


Keyhac - Pythonによる柔軟なキーカスタマイズツール - craftware


これならというわけで、JIS配列キーボード/ローマ字設定の環境向けにNICOLA配列を実現する設定を書いてみました。設定といっても普通にPythonのプログラムです。この記事も、これでNICOLA配列にした状態で書いています。

設定の仕方

keyhacを起動し、メニューバーに表示されたアイコンメニューから"設定の編集"を選ぶと、TextEditで設定ファイルが開きます。そこに、本記事末尾のコードをコピペして上書きします。デフォルトの設定はいろんな機能のサンプルが入っていて意図しない動作になったりするので消すか無効化したほうがいいでしょう。
なお、TextEditは勝手にクォート("")を“”などと置き換えてしまうので、編集→自動置換→スマート引用符の設定は切ってから編集したほうがいいでしょう。
シフトキーの設定は SHIFT_KEY = ["左親指シフトキー", "右親指シフトキー"] のように書きます。キーの名称は、keyhacのメニューから"端末を表示"し、同じくメニューから"内部ログ ON"にしてタイプしてみれば確認できます。
設定を書いたら保存して、再度メニューから"設定のリロード"を選べば準備完了です。

使い方

かなキーを押すとNICOLA配列が有効化され、英数キーを押すと無効化されます。
親指シフトキーは同時押しが可能です。具体的には、親指シフトキーの押下前後40ms以内に文字キーが押されると一回だけ効くようになっています。文字キーの後でシフトキーを押下した場合に対応するため、文字キー単体で入力された場合は最大40msだけキーダウンが遅延されます(キーアップするか親指シフトキーが押されれば直ちに入力されます)。この判定時間はSHIFT_MSとSHIFT_DURATIONを両方とも変更することで、個々人の好みに合わせて調整が可能です。
一応これでそれなりに機能しているようですが、文字キー → 親指シフトキー → 文字キー と高速打鍵すると意図しない方の文字にシフトが効いたりすることも稀にあるため、まだ改善の余地があるかもしれません*1

さらなるカスタマイズ…

キー配列は TABLE という辞書を編集することでカスタマイズが可能です。各文字に対して/(スラッシュ)区切りで'シフトなし/左親指シフト/右親指シフト'という順にローマ字表記、または""でくくったキー名を書くようになっています。頑張ればorz配列等にも対応できるはずです。

この設定は下記のNICOLA-J配列を参考にしてますが、"[", "]", "^", "\" キーはそのままにしてあります。
http://nicola.sunicom.co.jp/image/nicola-j-implementation-sample.png


なおドキュメントはメニューのヘルプで見られますが、delayedCall などの一部の低レベルの機能は載っていないので、そういう細かい部分はkeyhacやその下位ライブラリのpyauto, ctkitのソースを見る必要があるかもしれません。

GitHub - crftwr/keyhac: python based key customization utility
GitHub - crftwr/pyauto: windows low-level feature library
GitHub - crftwr/ckit: craftware's base library

*1:文字キーを離す前に親指シフトキーを押した場合、どう判定するべきかが難しいところ。近い方の文字キーにすべきなのかもしれませんが、これを実現するには入力をタイマーで遅延させる必要があり、かなり複雑なことになりそう……。

HTTPS接続がCan't verify SSL peersというエラーになるときは

久しぶりにMacでとあるPerlスクリプトを実行したら OAuth::Lite::Consumer が特にエラーも出さずに失敗してしまった。


いろいろ試しているうちに、下記のようなスクリプトを実行すると

% perl -MLWP::UserAgent -e 'print LWP::UserAgent->new()->get("https://www.google.com/")->as_string'

500 Can't verify SSL peers without knowing which Certificate Authorities to trust
Content-Type: text/plain
Client-Date: Wed, 06 May 2015 04:47:19 GMT
Client-Warning: Internal response

Can't verify SSL peers without knowing which Certificate Authorities to trust

This problem can be fixed by either setting the PERL_LWP_SSL_CA_FILE
envirionment variable or by installing the Mozilla::CA module.

To disable verification of SSL peers set the PERL_LWP_SSL_VERIFY_HOSTNAME
envirionment variable to 0.  If you do this you can't be sure that you
communicate with the expected peer.

とか言われた。これは信頼出来るCAを見つけられなくてSSL接続先を検証できなかったため(そのまんま)。


OAuth::Lite::Consumer も接続先がHTTPSだったため、内部的にこのエラーで接続ができずに(タチの悪いことに無言で)失敗していた。


Macの場合、CAはKeychainで管理されているので、PERL_LWP_SSL_CA_FILE を設定するといった方法は使えない。ホスト認証を止める(PERL_LWP_SSL_VERIFY_HOSTNAME=0にする)のはいやなので、上記メッセージの通り

% sudo cpan install Mozilla::CA

Mozilla::CAを導入すれば、Mozillaが提供するCA Bundleを勝手に取得してくれ解決する。

MouseCapeでIBeamカーソルを見やすくする

Mac OS X 10.9くらいから、Iビームのマウスポインタが暗い背景で非常に見にくくなってしまいました。ターミナル等で背景色を黒っぽい色にしていると、テキストを選択しようとした時などにマウスポインタがどこにあるかわからず、非常に不便です。


MouseCapeというマウスポインタをカスタマイズすることができるソフトを使うことで、Iビームの周囲に白いハイライトを足すことで、見易さを改善できました。


作成したcape(カスタマイズされたカーソル集)はGitHubにあります。使い方はcapeファイルをダウンロードしてImportし、取り込まれた「Enhanced IBeam」をダブルクリックして適用するだけです。


https://github.com/NeoCat/enhanced-ibeam


他にもさまざまなcapeが公開されているので、自分好みに置き換えてみるのも楽しいかもしれません。
capeを右クリックしてEditを選び、ポインタの種類を選択してアイコンをFinderにoptionドラッグすると、pngファイルを取り出せます。pngファイルを別のcapeのアイコンにドロップすれば、特定のポインタだけを入れ替えることもできます。

Xcodeでは別の対処が必要

XcodeはOSとは別にカーソルを持っているようで、Mousecapeでは置換されないようです。下記を使えば同様の対処が可能です。

https://github.com/egold/better-xcode-ibeam-cursor

MacのPreviewで画像ベースのPDFファイルサイズを小さくする

スキャナ等で取り込んだJPEGファイルをPDF変換する際、Previewで単純に形式をPDFにして保存すると、とんでもなくファイルサイズが大きくなって驚くことがあります(1MBのJPEGファイルが10MB超になるとか)。


システム標準でReduce File SizeというQuartzフィルタが用意されており、これを保存する際に選択しておくとファイルサイズを縮小してくれるのですが、こいつは非常に強力に圧縮をかけてくれるため、画質がひどいことになります(主に最大512×512ピクセルに縮小していることが原因かと)。


こんなときは、もとのJPEG程度のファイルサイズにしてくれるQuartzフィルタを用意してあげると良いです。

具体的には、 http://neocat.jp/Reduce%20File%20Size%20Slightly.qfilter をダウンロードして /Library/Filters/Reduce File Size Slightly.qfilter に保存します。そして、変換したい画像ファイルを「プレビュー」開いて、「ファイル」→「書き出す…」を選択、フォーマットをPDFにした後、Quartzフィルタから「Reduce File Size Slightly」を選んで保存すればOKです。


やってることはPDF内の画像をJPEG圧縮してるだけ。要はReduce File Size*1から画像縮小とかのよけいな処理を取り除いたものです。

*1:フィルタのファイルは /System/Library/Filters/Reduce File Size.qfilter にあります。

JavaScriptでMacに歌ってもらう

最近のChrome, SafariJavaScriptには音声合成APIが入っています。
使い方は簡単で、JavaScriptコンソール等で

var msg = new SpeechSynthesisUtterance('こんにちは!');
msg.lang = "ja-JP"; // 言語指定
window.speechSynthesis.speak(msg);

のようにするだけで喋ってくれます。


音声エンジンを変えることも可能です。使える音声の一覧を

var voices = speechSynthesis.getVoices();

で取得すると、voicesに音声オブジェクトのリストが返ってくるので、この中のlangやnameを見て使いたいものを

msg.voice = voices[3];

などとSpeechSynthesisUtteranceオブジェクトのvoice属性に指定すればOKです。


MacだとOSの音声合成エンジンを呼び出すことができます。Mac1984年から脈々とMacInTalkという音声合成エンジンを受け継いできており、Mac OS Xになっても昔のVoiceがまだ利用できます。その中には、MacInTalk 3で収録された、歌を歌ってくれるという遊び心あふれるVoiceも未だに入っています。当時はこれを33MHzの68030とかで合成していたんですよね。そんなVoiceがJavaScriptで呼び出せるなんて、ちょっと感慨深いものがあります。というわけでやってみない手はありません。

さっそく動かしてみる

MacJavaScriptで歌わせるサンプル: http://jsfiddle.net/ApvvB/7/


上記のページで、Bells, Cellos, Pipe Organ, Good News, Bad Newsのボタンを押すと、それぞれのVoiceでラララーと歌ってくれます。
defaultは0番のボイスで読み上げ、stopは歌うのを停止させるボタンです。


rate,pitch,volumeのスライダーを動かすと、早さ、音程、音量を変えられます。が、rateは歌には効かないようでした。

Mac OS XSafari, Chromeで動作を確認できました。


ChromeはonLoadの中でvoicesを取得しようとすると、なぜか空のリストが返ってくるので、ボタンをクリックされたタイミングで取得するよう注意が必要でした。

おまけ

ちなみに、端末上で

say -v Bells 'have a nice day'

などとしても、歌わせることが可能です。