ずっとやりたかったけど、面倒で見送っていたことができた。スマフォなどのケーブルが何本も(充電用とPC接続用、他にデジカメ用も)あって見苦しいし、注意しないと間違えるのが嫌になったのだ。しかも、スマフォをPCに繋いでも、いちいち画面で画像転送(PTP)を選ぶ必要がある※のも、イライラを増していた。

※検索すると、この選択は開発者ツールを使えば固定できるようなのだが、なぜか、再起動か何かのたびにリセットされて、いつも選ぶ羽目になっていた。AQUOSの仕様なのだろうか?

やりたかったのは以下のようなことだ。

  • スマフォをPCに繋がなくても、操作なしで自動的にPCに画像が取り込まれる。
  • USBで繋いだ時と全く同じように取り込まれる。
    • 新規画像(例: 前回の取り込み以降に撮影されたもの)画像だけが取り込まれる。
    • 画像は年月日ごとのディレクトリ(例: 2019/2019_01-03/2019_03_04)に仕訳けされる。
    • 画像のファイル名にはカメラ(スマフォ)・トップディレクトリ(例: DCIM/102SHARP)固有のIDが追加される(例: DSC_0301_2345987612.JPG)。
      • カメラ間・カメラ内のファイル名の競合を防ぐため。
    • ファイルの更新時刻が撮影時刻になる。
      • PNGなど、タグのないファイルでも並び順を揃えたいので。
    • 新しい画像であることを示すタグ(例: Subject="New")が付く。
      • ファイルを自動で仕訳けするために画像の場所が分散するので、あちこち探さなくても一目で新規画像を分かるようにするため。

そして、なぜか数日前(調べたら、3/2からだった。簡単にできそうなアイデア(後述の、マウントしてtarコマンドでコピー)が浮かんだので始めたのだった。本当に、「寝食を忘れて」熱中・集中していたので、結構疲れた)からやる気が出て実装し、以下のような感じで動くようになった。

  • スマフォをPCに繋がなくても、スマフォのアイコン(実体はウィジェット)を押すとPCに画像が取り込まれる。
  • USBで繋いだ時と全く同じように取り込まれる。

上に書いたように、操作なしにしたかったのだが、いくつかの問題があるので、今は保留している。 (→ その後改良して、概ね操作なしでできるようになった。: 3/9 12:09)

  • 使っているサーバソフト(SSHDroid)の仕様なのか、画面offの状態では、そのサーバが停止(スリープ?)するために、PCから接続できない。接続していても、画面offになってしばらくすると切れる。
    • → サーバを起動するために画面をonにするのなら、ロック解除してアイコンを押すのはそれほど手間ではない。
  • 仮に常時接続できるようにしても、定期的にPCから新規画像のチェックをするのは効率が悪い(画像が増えることはそれほど頻繁でないので)。頻繁にチェックすると電池を食うし、チェック間隔を長くすると不便だ。
    • → 画像が増えたら、スマフォがPCに通知するようにすれば良さそう。[今後の課題]

なお、PCからも取り込みを開始することができるのだが(最初はそうした)、上記のように、取り込み前に自分でスマフォの画面をonにする必要があるから余り便利でないことに気付き、スマフォから開始できるようにした。

スマフォとPCの画面が写った動画でないと全くおもしろくない(さすがに撮影する気は起こらないw)のだが、以下のように、スマフォのエクスポート(あるいはアップロード・同期)アイコンを押すと、PCで取り込みプログラムが起動し、取り込みウインドウに取り込みの経過が表示され、新規画像が取り込まれる。自画自賛だが、なかなか便利だ。例えば、スマフォで撮影したらアイコンを押すだけでPCに入れられるのはすごくいい(今までだったら、ケーブルを繋ぐかDropboxに入れるなど、結構面倒だった)。今気付いたが、家の中ならどこにいても転送できるはずだ(それに価値があるかは別としてw)。

こういうアプリなり仕組みは既にあるが、いろいろ探してもどうも僕の要望には今ひとつ合わないので(同様な理由でUSBでの取り込みプログラムも自分で作ったので、まず合いようがない)、自分で作った。あと、今はスマフォからクラウドに直接自動的にアップロードするのが主流だが、やっぱり使いにくいし、モバイルデータ量も増大するかも知れないし、そもそも、提供者の都合で仕様が変わったり有料になったり終了になる可能性があるので、なるべく使わないことにしている。

と、さらっと書いたが、中ではなかなかいろいろなことをやっているので、以下に細かい話を書く。

スマフォからの画像取り込み

基本的には、今までのUSB(PTP)での画像取り込みプログラム(の枠とでもいうもの)を使っている。ただ、今回のネットワーク対応ためにかなり追加・変更した箇所がある。

転送の仕組みは、最初は、sshfsなどでPCからスマフォのファイルシステムをマウントし、ファイル一覧を取得し、新規ファイルを抽出してtarコマンドでコピーすることを考えたが、rsyncコマンドの方が便利そうだったので、それを使うことにした。特に、rsyncはマウント不要(自動でスマフォ側のプログラムを起動する)なのが良かった。

スマフォのファイルシステムは大きく、毎回スキャンするのは得策でないから、PCでは新規ファイルの抽出はせず、取り込み済みファイル一覧から除外ファイル一覧を作ってrsyncに指定することにした。実際には、スマフォ内でrsyncによるスキャンは行われるが、PCからNW経由でやるよりは良さそうだ。除外ファイルサイズが大きくなって重くなるのが気になるが、今のところ、デジカメも含む全ファイル一覧(画像数: 8千以上)でさえ300KB未満なので、大きな問題はなさそうだ。

画像取り込みの開始

前述のとおり、最初はPCのプログラムで取り込みを開始するようにしたが、その前にスマフォの画面をonにする必要があって不便なので、スマフォのアイコンで開始できるようにした。

そうするにはいろいろな方法が考えられるが、手軽に作るためにAutomagicを使うことにした。Automagicで可能なのは、Wake on LANパケットの送信、HTTPアクセス、FTPアクセスなどだった。Wake on LANは手軽でいいのだが、ユーザのデータが送れないので、HTTPにしてみた。

なお、AutomagicからOSのコマンドを実行することもでき、ncコマンドもあるのだが、UDPの送信ができない(セキュリティの制限か、エラーになる)ので、諦めた。あと、そもそも、Automagicから実行できるコマンドのパスがシェルとは違っているために実行できない問題もあった。

これだけのためにPCでHTTPサーバを動かすのはもったいないので、socatコマンドで擬似的なHTTPサーバを作って待ち受けることにした。「サーバ」といってもまったく大したことはなく、「のようなもの」だ。基本的なコマンドは以下のような感じで、たった1行(長いので折り返した)で済むものだ。

echo -e "HTTP/1.0 200 OK\r\n\r\nHello!" |
  socat -d TCP-LISTEN:2345,reuseaddr - | hexdump -C

AutomagicからPCのTCPポート2345にアクセスすると(URLの例: http://192.168.1.2:2345)、PCでその要求がダンプされる(→ 要求が来たことが分かる)。また、スマフォ(Automagic)には"Hello!"という文字列が返るので、PCからの応答も分かる。

あと、ものすごく簡単な不正アクセス対策として、Automagicから要求を出す時に、ヘッダに「何か」(普通はない情報、合言葉のようなもの)を追加すると、何もしないよりはよい。そもそも、外部からのアクセスはルータで遮断されるので、外部からPCへのHTTPアクセスは来ない前提だし、PCはデスクトップなので持ち歩かないから、今はこれでいいと思う。それから、Wake on LANは間違って宅内の他の機器から出る可能性があり、ブロードキャストなので宛先で受信制限ができず、上記のようにユーザのデータは送れなくて正当性のチェックができないという点でも、HTTPの方が少し良さそうだ。

スマフォの個体の識別

前述のように、画像のファイル名にはカメラ(スマフォ)・トップディレクトリ固有のIDを追加する。そのIDは、カメラ情報(メーカー、機種、SN)から生成するのだが、当然、NW経由ではそれらは取得できない(スマフォのコマンドを使うとできるかも知れないが、仕組みを特定のOS・機種に依存させたくないので、止めた)。

そこで、スマフォのMACアドレス(HWアドレス)を使うことにした。MACアドレスはその個体に固有で変わることがないので、IDとしては良い。ただ、USBで取り込んだ時とネットワーク経由の時でIDが異なると、別の接続では取り込み済みファイル一覧が異なるため、新規ファイルが異なって、重複して取り込まれてしまうので、画像取り込み開始プログラムで、MACアドレスからUSB(PTP)で取得・生成したIDを検索して(今はプログラム中に書いている)、それを取り込みプログラムに指定するようにした。そうすれば、同じ取り込み済みファイル一覧が参照される。

MACアドレスは、次のように取得する。スマフォからのHTTPアクセスの場合、アクセスを受けたsocatは環境変数SOCAT_PEERADDRにスマフォのIPアドレスを格納するので、要求が来たらコマンドを実行するようにし、その中でIPアドレスを取得し、その後、arpコマンドでIPアドレスに対応するMACアドレスを取得するようにした。次はそのコマンド例である(まだsocatには理解できていないことがあるため、綺麗ではない。なぜか、最後の";"は必要である)。

tmp_file=/tmp/iimg-rss.d
http_resp_line='HTTP/1.0 200 OK\r\n\r\nAccepted.'
socat -T 0.7 TCP-LISTEN:2345,reuseaddr 
  SYSTEM:"/bin/echo -n -e \"\\\"${http_resp_line}\\\"; 
  (date +\"Date:\ %Y/%m/%d\ %H:%M:%S\"; 
  echo \"PeerAddr: \${SOCAT_PEERADDR}\"; 
  echo; cat ) > $tmp_file; "

スマフォから要求が来た場合、一時ファイル/tmp/iimg-rss.d中に、要求が来た時刻(Date)、スマフォのIPアドレス(PeerAddr)、要求の内容が格納されるので、適宜処理すれば良い(上述の正当性チェック用トークンも要求の内容として格納されている)。なお、これを受信した場合、スマフォには"Accepted."という文字列が返る(今はそのチェックはしていない)。

見つかった問題

実装中や試している時に見付かった問題と対処を以下に書く。

  • rsyncの除外・含めるファイル指定の謎
    • 対象ファイルの指定はなかなかの謎で、うまく使えるようにするのがとても大変だった。指定順序がかなり重要らしい。(→ 参考ページ)
  • オーディオファイル(例: MP3)、動画にはタグが付けられない。
    • exiftoolがMP3などの書き込みには対応していないうえに、タグの仕組みが異なるので、画像と同じようには処理できない。
    • → 取り込み後に画像管理アプリXnViewMPに認識させるために、新規画像一覧を指定してXnViewMPを起動しているので、取り込み時にタグが付けられなかったファイルがある場合には、そのウインドウを閉じないようにして新規ファイルが分かるようにした。
  • 時々SSHDroidが停まる。
    • Wi-Fiの鍵更新時に一瞬Wi-Fiが切れるために、SSHDroidが終了するようだ。
    • → 先日できたWi-Fiの自動再接続プログラムで、画面がoffの場合には(onの時はすぐに繋がるから、問題ないはず)SSHDroidを再起動するようにして、解決するか試している。 → 今のところ大丈夫なようだ。
  • ディレクトリ名の問題
    • rsyncと従来の取り込みプログラム間の想定の違いやAndroidで画像のあるディレクトリはDCIMだけでないなどの細かい問題があったので、逐次対応した。
  • 変なファイル名
    • 一部のファイル名に、想定外の"["や"]"が入っているものがあって、「ゲー」っとなったが、PHPにescapeshellarg()というすごい関数があることを知って、何とかなった。
  • 余計なファイル(Android下のキャッシュなど)の除外
    • 上述のrsyncの除外パターンに指定して、なんとか除外できるようになった。
  • tarはエラーをうまく返さない?
    • 普通に使う分にはちゃんと返すのだろうが、パイプで繋げた場合にはエラー状態が消滅してしまって、失敗がちゃんと分からなくて不便だった。これは、rsyncに換えた最初の理由である。

その他

今、以下のようなことを思った・思っている。

  • 転送がすごく速い。
    • USB(PTP, gphoto2)での時よりずっとキビキビしていて、速くて気分がいい。今は転送ファイル数が少ないだけかも知れないが、rsyncの処理が高速な気もする。
  • 外からの帰宅時に自動取得できると便利かも。※
    • AutomagicでWi-Fiの接続イベントが取れるので、その時にエクスポート開始すればできそうだ。これを作れば、帰宅してすこし経てば自動的に取り込まれているので、ロック解除してアイコンを押す手間すら省けて、なかなか良さそうだ。が、帰宅時にPCが起動していない可能性もあるので、そううまくは行かないことに、今気付いた。 → 外部サーバを使うといいかも知れない(大げさになってしまうが)。
  • スマフォの物理ボタンを押したら転送開始できると便利。
    • が、使えるボタンが少な過ぎて無理(音量しか使えない)。
  • デジカメでもこうしたいが、無理かも。
    • 仮にWi-Fi付きモデルだとしても、rsyncが動くとは思えない(別のファイル共有が使えれば、それに対応させれば、可能性はある)。
  • Automagicはすごく便利! もっとしゃぶり尽くしたいw
  • そして、こんな芸当(というか、Linuxでは当たり前だが)はiPhoneではまず無理だっ! (ネイティブアプリを作ればできるかも知れないけど、そんな面倒なことはしたくない)

※ その後、帰宅後の転送を操作なしにできるように、Wi-Fi接続時に自動的に画像転送を開始するようにした。PCが起動していない可能性については、開始前にpingでPCが起動しているかを確認するようにした。また、Wi-Fiの接続が安定するのを待つため、少し(例: 3分間)待つようにした。

更に、スマフォが電源に接続された時も、同様に自動で転送開始するようにした。この場合は無駄な転送になる可能性があるが、電池は消費しないので、大きな問題ではない。

なお、自動的に転送を開始する場合は、エラーがあった時以外はPCの画面に画像取り込みウインドウを出さないようにした。なるべくPCの操作を邪魔されたくないからである。これは、上記トークンと同様に、スマフォからの転送開始要求のHTTPヘッダに取り込みの動作モードを指定することで実現した。 (3/5 8:58)

その後、アイドル中(画面消灯後、約3分経過以降)はSSHDroidが停まっている(アプリがdoze状態?)ためにPCからのrsyncでのアクセスが失敗することが分かった。いろいろ試したところ、直接的にアプリを起こすことはできなかったが、画面を点灯させるとSSHDroidも動き出すことが分かったので、自動転送開始の契機がWi-Fiの接続時の場合には(電源接続時はスマフォ全体のスリープが解除されてSSHDroidも動き出すので、必要はない)、短く(1秒程度)点灯させてから転送開始するようにした。消費電力の増加が気になるので、しばらく様子を見たい。 (3/6 9:43, 13:35)

Wi-Fi接続時に自動転送したいのは帰宅時なので、長時間(例: 10分以上)Wi-Fiが切断された後に接続した時だけ転送を開始するようにして、長時間アイドル中のWi-Fi鍵の更新時に無駄に画面点灯と空の転送が実行されて電池が減るのを防ぐようにしてみた。

ソフトというのは、最初は単純なものでも、こうしていろいろ工夫・調整すると複雑になってしまう。そういうのの成れの果てがWindowsのようなものだ。なかなか加減が難しい。。。 (3/6 14:14)

更に、自動転送の場合、スマフォ内に前回PCが取り込んだ(PCに転送した)ファイルより新しいものがある時だけ転送開始要求するようにした。これで、無駄に画面が点くことはまずなくなるだろう。ただ、新規ファイルの検索と画面点灯とどちらの電池消費量が多いかは不明だ(点灯させるとスマフォ全体が起動するから、そっちの方が多いとは思うが)。

PCへの要求を送るのにHTTPを使うようにしたおかげで、スマフォからPCへの命令(前回転送したなかで最新のファイル名を取得する)を追加できたのは良かった。

これで、この件に関しては概ね気が済んだ。ただ、想定が狂って、転送開始要求の前に、前回転送した最新のファイルを取得する必要があるために転送回数が増えてしまったのは、ちょっと気に入らない。本当に必要なのか、もう少し考えてみたい。

当然ながら、プログラムは更に複雑になってしまった。 (3/7 11:53)

 

(18:52 若干加筆; 19:49 題を変更; 20:28 若干加筆; 23:42 2番目のsocatの例が誤っていたので修正)

  •   0
  •   0

2件のコメント

  1. naoki:

    これは凄く便利そうです!

    自分の為だけに特化してるのが、また尖ってて格好いいです。

    憧れるなあ。

    •   0
    •   0
  2. れんと:

    ●ありがとうございます。我ながら、本当に便利です。ただ、しばらくは突然不具合が出てデバッグになりそうですがw

    LinuxやAndroidはこういうのができるからいいんです。

    あと、PCにしてもスマフォにしても、今までいろいろいじくりまくっているのを、いつか寿命の時などに別の機種に移せるのか、結構不安です(爆)

    •   1
    •   0

コメントを書く

名前    

メール 

URL