あなたの天然記念物
ホーム更新雑談Perl鉄ゲタランドナーコースガイド自転車Linuxリンク経歴連絡先

FlashAirで快適なツイッターライフを (2015.03.04)

背景

電話だけのプリペイド携帯を使っていて、ネットはパソコンだけ、写真はデジカメで撮影、USBケーブルを接続して取り込んでいます。 写真付きでツイートしようとすると面倒なので手早くできないか模索していました。 2015.03.04 タスクスケジューラを利用して全自動ダウンロードに成功、 デジカメの電源オン→撮影→(デスクトップに自動ダウンロード)→デジカメの電源オフ という手順になりました。

FlashAir

そんな中、見つけたのがFlashAirです。メーカーのサイトがこちら。 FlashAir(TM) | 東芝 Pocket Media
FlashAirをメモリカードの代わりにデジカメの中に入れて写真を保存、FlashAirが無線LAN親機かつWebサーバとなって画像を配信できます。

FlashAirが無線LANの親機になっているなんて知らなかったよ。 パソコン側にUSB/無線LANの親子兼用機を追加して親機にしたら、どっちも親機で通信できなかったんだ。 気がつくまでに半日かかったよ。 ちなみに、子機に切り替える事も出来ましたけれど、親機として使っています。 パソコン環境で無線LAN使うのはこれが初めてで他は有線LANです。 LANは有線!(有線原理主義者の発言)

それからメーカー提供の設定ツールでFlashAirを設定する際は、パソコンにFlashAirをUSBカードリーダで接続することが必要にも関わらず、明示されていなくて試行錯誤してそうと分かるまでに半日かかったよ。

手早くするための工夫

メーカー提供のツールで設定した後でも「写真添付のツイートを素早く」に不便でしたので色々と工夫しました。 メーカーではAPIを公開していて自分なりのHTMLを用意できることがわかりました。
FlashAir Developers - ホーム

サンプルソースを元に修正していますので、著作権者のコピーライト表示を提示します(これリンクじゃダメなのかな?)。
FlashAir Developers - ライセンス - チュートリアル
Copyright (c) 2013, Toshiba Corporation. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  1. この設定はWIndows7で不要です。
    ネットとFlashAirを併用
    パソコンでネット用のLANとFlashAir用のLANはどちらか一方に切り替えて使う話ばかりだったので色々調べました。 これ、ネットをアクセスする際にFlashAir用に追加した無線LAN子機へアクセスしない工夫をするとOKですね。 DNSサーバへのアクセスをネット側へ誘導すると上手い事いくようです。 DNSサーバへのパケットを確実にゲートウエイに出すためにサブネットを32ビット全部にしました(苦笑)。
    通常は設定しておくデフォルトゲートウエイを削除しておく点が肝です【超重要】
    その代わりにコマンドプロンプトで次のコマンドを実行します
    route -p ADD ddd.ddd.ddd.ddd 255.255.255.255 ggg.ggg.ggg.ggg IF 0xlllll
    【説明】
    ddd.ddd.ddd.ddd DNSサーバのIPアドレス
    ggg.ggg.ggg.ggg ゲートウエイのIPアドレス
    0xlllll ネット用インタフェースの番号(route printで表示)
    
  2. 1の代わりにこちらの設定を使います。
    ネットワーク→プロパティ→アダプターの設定の変更→ネットワーク接続→詳細設定→詳細設定→アダプターとバインドを開く
    接続の順序をローカルエリア接続→ワイヤレスネットワーク接続に変更
    これで、①まず有線LAN(インターネット)、②上手く行かない時はFlashAir、という順番でアクセスします。
  3. デジカメから写真をダウンロードするタスクをタスクスケジューラに登録
    FlashAirに電源が入りワイヤレスネットワーク接続が確立されたイベントだけをカスタムフィルタで抽出してトリガにします。
    操作はPerlスクリプトを使って、ネットから画像をダウンロードするのと同じです。
    このスクリプトはダウンロード後に削除のCGIも起動してカメラ内の画像を削除します。
  4. 外部からの削除要求を許可
    \SD_WLAN\CONFIGに次の行を追加
    UPLOAD=1
  5. ページのベースを用意
    \SD_WLAN\List.htmを作成、中身はサンプルソースを元に修正
    <!doctype html>
    <html>
    	<head>
    		<title>FlashAir in CASIO EX-ZS6</title>
    
    		<meta charset="UTF-8">
    		<meta http-equiv="Pragma" content="no-cache">
    		<meta http-equiv="Cache-Control" content="no-cache">
    		<meta http-equiv="Expires" content="-1">
    
    		<script type="text/javascript" src="/SD_WLAN/js/jquery-2.0.3.min.js"></script>
    		<script type="text/javascript" src="/SD_WLAN/js/main.js"></script>
    		<script type="text/javascript">
    			wlansd = new Array();
    			<!--WLANSDJLST-->
    		</script>
    	</head>
    	<body>
    	FlashAir in CASIO EX-ZS6
    	<div id="list">
    	</div>
    	</body>
    </html>
    
  6. ライブラリを追加
    \SD_WLAN\js\jquery-2.0.3.min.jsを用意
    ダウンロードはjQueryから。※最新バージョンで良いと思います。
  7. HTMLを書き換えるJavaScriptを用意
    \SD_WLAN\js\main.jsを作成、中身はサンプルソースを元に修正
    // JavaScript Document
    // Judge the card is V1 or V2.
    function isV1(wlansd) {
    	if ( wlansd.length == undefined || wlansd.length == 0 ) {
    		// List is empty so the card version is not detectable. Assumes as V2.
    		return false;
    	} else if ( wlansd[0].length != undefined ) {
    		// Each row in the list is array. V1.
    		return true;
    	} else {
    		// Otherwise V2.
    		return false;
    	}
    }
    // Convert data format from V1 to V2.
    function convertFileList(wlansd) {
    	for (var i = 0; i < wlansd.length; i++) {
    		var elements = wlansd[i].split(",");
    		wlansd[i] = new Array();
    		wlansd[i]["r_uri"] = elements[0];
    		wlansd[i]["fname"] = elements[1];
    		wlansd[i]["fsize"] = Number(elements[2]);
    		wlansd[i]["attr"] = Number(elements[3]);
    		wlansd[i]["fdate"] = Number(elements[4]);
    		wlansd[i]["ftime"] = Number(elements[5]);
    	}
    }
    // Callback Function for sort()
    function cmptime(a, b) {
    	if( a["fdate"] == b["fdate"] ) {
    		return a["ftime"] - b["ftime"];
    	}else{
    		return a["fdate"] - b["fdate"];
    	}
    }
    
    // Show file list
    function showFileList(path) {
    	// Clear box.
    	$("#list").html('');
    
    	$.each(wlansd, function() {
    			var file = this;
    
    			var thumbnail = $('<img />').attr('src','../../thumbnail.cgi?'+file["r_uri"]+'/'+file["fname"]);
    
    			var filelink = $('<a></a>').attr('href',file["r_uri"]+'/'+file["fname"]);
    			filelink.append(thumbnail);
    
    			var deletelink = $('<a></a>').attr('href','../../upload.cgi?DEL='+file["r_uri"]+'/'+file["fname"]);
    			deletelink.append('delete');
    
    			var imagepack = $('<div></div>').attr('style', 'float:left; margin:10px;');
    			imagepack.append(filelink);
    			imagepack.append('<br />');
    			imagepack.append(deletelink);
    
    			$("#list").append(imagepack);
    	});
    }
    
    // Document Ready
    $(function() {
    	if ( isV1(wlansd) ) {
    		convertFileList(wlansd);
    	}
    	wlansd.sort(cmptime);
    	showFileList(location.pathname);
    });
    

タスクスケジューラのカスタムフィルター

この仕掛けの肝は、タスクスケジューラのトリガにあります。
イベントビューアでワイヤレスネットワーク接続が確立したイベントを探して、それだけを抽出するようにフィルタを考えました。
ですので、確立に伴う他のイベントや、接続が切れたイベントを拾わない工夫をしています。
イベントの名称等はパソコンによって異なる場合がありますのでイベントビューアで良く確かめてください。
特に接続名「flashair」は各自で決めた名前に合わせてください。
<QueryList>
  <Query Id="0" Path="Microsoft-Windows-NetworkProfile/Operational">
    <Select Path="Microsoft-Windows-NetworkProfile/Operational">*[System[Provider[@Name='Microsoft-Windows-NetworkProfile'] and (Level=4 or Level=0) and (band(Keywords,35184372088832)) and (EventID=10000)]][EventData [Data[@Name='Name']='flashair']]</Select>
  </Query>
</QueryList>

ダウンロードと削除のPerlスクリプト

タスクスケジューラが起動するスクリプトです。これはActivePerlで動かしています。
#!/usr/local/bin/perl -w

use utf8;
use strict;
use warnings;
use Encode;
use open IO => ":utf8";
use LWP::UserAgent;
use Image::ExifTool;

binmode STDOUT, ":encoding(cp932)";

$| = 1;

print "写真をダウンロード\n";

my $ua = LWP::UserAgent->new();
my $res;

my @photo;
do {
	print "接続を待機 ... ";
	do {
		$res = $ua->get("http://flashair/DCIM/101CASIO/");
		if (500 == $res->code) {
			sleep 3;
		}
	} while (500 == $res->code);
	print "接続確認\n";

	if ($res->is_success) {
		@photo = map /"fname":"([^"]*)"/, grep /wlansd\.push/, split "\n", $res->content;
	}
	if (!@photo) {
		print "撮影を待機 ... ";
		sleep 3;
		print "完了\n";
	}
} while (!@photo);


# Exifを削除するExifTool
my $exiftool = new Image::ExifTool;
$exiftool->SetNewValue("*");

for (@photo) {
	print "$_ ... ダウンロード ... ";
	my $download = Encode::encode "cp932", $ENV{USERPROFILE} . "\\Desktop\\$_";
	$res = $ua->get("http://flashair/DCIM/101CASIO/$_", ":content_file" => $download);
	my $code = $res->code;
	if (200 == $res->code) {
		print "exif削除 ... ";
		$exiftool->WriteInfo($download);

		print "カメラの画像を削除 ... ";

		$res = $ua->get("http://flashair/upload.cgi?DEL=/DCIM/101CASIO/$_");
		if (200 == $res->code) {
			print "完了\n";
		} else {
			print "失敗\n";
		}
	} else {
		print "失敗\n";
	}
}

exit;

操作が簡潔になりました

撮影からダウンロードまでの手順はこんな感じ。デジカメにFlashAirを入れて後はそのままです。 はいチーズ。 撮影しているうちにワイヤレスネットワーク接続が確立、それをトリガにPerlスクリプトが起動されます。
スクリプトが画像をデスクトップにダウンロード、ツイートに添付するためEXIF情報を削除、FlashAir内の写真の削除までやってくれます。
ダウンロードした写真はこちら。 皆さんも素敵なFlashAirライフを!

質問、その他

へご連絡ください。