仙石浩明の日記

2019年12月10日

学習リモコンの赤外線波形データを変換してみた 〜 Nature Remo で取得した波形データを PC-OP-RS1 用に変換

人感センサ (人の動きを感知するセンサ) 付であることに魅力を感じて IoT な学習リモコン Nature Remo を買ったら、 人の動きをトリガーにした IFTTT との連携ができないばかりか、 センサの感度もあまりよくなかった。 仕方ないので人感センサを新たに買ってみた

人感センサとしての感度は、 だんぜんこの +Style ORIGINAL スマートセンサー(人感) PS-SMT-W01 のほうがいい。 IFTTT と連携できないので他の IoT 機器との連携を考えている場合は注意が必要だが、 私は IFTTT をショートカットするので無問題。 思わず買い増ししてしまった。

Nature Remo から人感センサを引き算したら、 残りは「学習リモコン」ということになるが、 そこで思い出したのが 13年前に買ったパソコン用学習リモコン PC-OP-RS1。 いま流行りの IoT では無いが、 サーバが置いてある部屋で使うのであれば IoT である必要はなく、 むしろ PC-OP-RS1 のように (ネットを介さず) USB で直接コントロールできるほうが、 赤外線を発射するまでの遅延が少なくてすむ。

学習リモコン PC-OP-RS1 と人感センサ PS-SMT-W01 を組合わせれば Nature Remo は不要? と思ったので押し入れの中から PC-OP-RS1 を発掘した。 ところが、 家電のリモコンの赤外線を学習させようと、 PC-OP-RS1 の受光部に向けて赤外線を発射しても、 PC-OP-RS1 側では何も受け取っていない様子。 10年くらい使ってなかったから赤外線受光素子が劣化してしまったのか?

赤外線の受光はできないものの、 発光は可能みたい。 13年前に書いた Perl スクリプトを使って Nature Remo に向けて赤外線を発射してみると、 ちゃんと Nature Remo で波形データを生成できた。 ということは、 波形データさえ用意できれば今でも使えそう。

ただし、 13年前に PC-OP-RS1 を買ったときは、 波形データのフォーマットを知らなくても使えたので、 単に PC-OP-RS1 が出力した波形データを 16進数の羅列として perl スクリプトに取り込んだだけ。 当時書いた「日記」からスクリプト (の冒頭部分) を引用:

#!/usr/bin/perl
use strict;
use warnings;
use Device::SerialPort;
use Getopt::Std;

my %Ir;
$Ir{'vPower'} = [
    pack("H*", "ffffffffffffffffffffff0700000000007ef0831ff8c00f7e00003f00800ffc00003f00801f00c00700f00300f8c10f7c00003f00801f00e00700f0831f00c00f7ee0033ff8c10ffc00003ff00100fc00007e00001f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
    ];
$Ir{'aPower'} = [
    pack("H*", "ffffffff0f00000080ff000000fc030000f01fc07f000000fe01fc070000e03f000000ff01fe030000f01f000080ff00fe010000f80fe03f000000ff000000fc07f01fc03f000000ff01fc07f80fe03f807f00ff01fc03f80f0000c07f00ff00fe03f80fe01fc07f00ffffffff07000000c03f000000ff010000f80fe01f000000ff00fe030000f01f0000807f00ff010000f80f0000c03f80ff000000fc07f00f0000c07f000000fe03f807f01f000080ff00fe01fc07f00fe03f80ff00fe01fc070000e03f807f00ff01fc03f80fe03f80ffffffff01000000f01f0000000000000000000000000000000000feffff"),
    ];

 ...以下略 ...

スクリプト中 「vPower」 はビデオテープレコーダ (VTR) の電源をオン/オフする赤外線のデータ。 「aPower」 は (おそらく) エアコンのオン/オフ。 後に続く 16進数の羅列が赤外線の波形データ。 どちらの家電もすでに無く (VTR なんてすでに死語?)、 そのリモコンも捨ててしまった。 なのでこのスクリプトが (今でも) ちゃんと機能するかは確認のすべがない。

とりあえず vPower の 16進数を 2進数で表示してみる:

senri:~ $ perl -e 'print unpack("b*", pack("H*", "ffffffffffffffffffffff0700000000007ef0831ff8c00f7e00003f00800ffc00003f00801f00c00700f00300f8c10f7c00003f00801f00e00700f0831f00c00f7ee0033ff8c10ffc00003ff00100fc00007e00001f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))."\n"'
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000001111110000011111100000111111000000111110000001111110000011111100000000000000000111111000000000000000001111100000011111100000000000000001111110000000000000000011111100000000000000000111110000000000000000011111100000000000000000111111000001111110000001111100000000000000000111111000000000000000001111110000000000000000111111000000000000000001111110000011111100000000000000000111111000001111110000001111100000011111100000111111000001111110000001111110000000000000000111111000000111110000000000000000011111100000000000000000111111000000000000000001111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

おお、 (なんとなく ^^;) 赤外線の波形データっぽい。 2進数で表示すると、 最初の 91個の「1」と続く 46個の「0」の連続を除けば、 「1」は 5〜6個続くのに対し、 「0」は 5〜6個か、15〜17個続く。 これは赤外線リモコンの通信フォーマットにおける 1T (5〜6個) および 3T (15〜17個) の区間に対応するのだろう。 ということは T (変調単位) は 2進数 5.5個くらいに対応する、 つまり 2進数 1個は 100μ秒くらいなのだろう。

ちなみに unpack("B*", ...) (descending bit order) も試してみたのだが、 「"b*"」(ascending bit order) のほうが赤外線の波形データっぽかったので、 「"b*"」と仮定して作業を進めた。 とりあえず 2進数に変換してみる、みたいな試行錯誤を 1行スクリプトでサクっと書けてしまえるのは perl ならでは。 さいきんあまり人気がない perl だが、 この手の試行錯誤をするときには今でも一番ではなかろうか?

いっぽう Nature Remo の赤外線波形データはこんな感じ:

senri:~ $ curl -i -X GET "http://Remo-XXXXXX.local/messages" -H "Accept: application/json" -H "X-Requested-With: curl" -H "Expect: "
HTTP/1.0 200 OK
Server: Remo/1.0.77-g808448c
Content-Type: application/json

{"format":"us","freq":37,"data":[3357,1717,385,1305,377,468,386,460,386,460,387,459,383,463,385,462,382,463,383,463,383,462,384,465,381,465,379,1306,386,463,382,460,385,465,381,467,381,459,385,462,384,462,377,1312,386,1309,384,459,387,462,382,460,386,460,385,461,385,462,385,1306,385,461,384,1307,384,461,386,1306,402,1291,399,1291,382,1307,388,456,404,1290,401,443,403,1287,407,440,402,445,401,443,386,462,400,445,384,463,382,464,381,464,384,1306,401,1292,383,1302,409,1285,402,1289,383,1309,383,1306,387,1304,379,1312,407,1285,402,443,405,441,386,460,403,443,385,460,404,442,385,464,403,440,404,1289,405,1285,404,1282,388,1304,409,1282,390,1301,406,441,386,1306,407,436,410,441,401,440,406,443,385,1304,407,1284,404,1287,405,441,386,1305,408,1287,404,1285,385,1304,407,441,383,462,389,40199,3376,1697,384,1306,407,441,402,442,407,440,384,465,400,443,405,442,383,460,385,464,384,461,401,445,402,441,404,1291,400,446,384,461,400,446,381,463,383,466,399,444,402,444,383,1304,407,1287,401,444,384,460,404,442,407,439,406,442,403,441,404,1287,386,460,403,1289,400,445,403,1287,407,1282,409,1285,385,1307,400,444,405,1285,404,442,404,1289,402,442,405,441,401,444,386,459,404,442,405,441,403,443,404,442,407,1286,405,1288,398,1286,406,1285,409,1283,404,1287,407,1286,401,1294,406,1284,401,1288,401,446,381,462,402,445,401,444,402,444,384,462,383,466,398,442,407,1286,401,1288,403,1288,404,1288,403,1288,401,1290,407,439,404,1284,406,441,404,441,409,436,408,439,407,1285,406,1285,403,1289,400,446,402,1288,403,1287,405,1284,404,1286,409,437,406,444,404,39760,3379,1697,402,1288,404,442,405,441,401,444,407,439,406,441,401,446,402,441,407,439,402,445,406,441,401,443,401,1290,405,437,404,446,405,441,402,441,402,442,406,441,403,441,404,1290,402,1290,400,446,404,439,407,439,406,439,404,442,404,442,406,1288,401,442,402,1290,385,462,401,1289,401,1290,404,1288,399,1288,404,441,386,1306,402,446,402,1287,403,446,401,442,402,444,401,445,404,441,402,444,402,444,402,446,400,1290,398,1290,402,1287,385,1309,404,1287,400,1289,403,1292,401,1283,390,1302,387,1304,404,445,384,460,408,436,405,442,385,462,402,443,404,441,404,442,385,1306,404,1287,402,1292,383,1307,401,1289,404,1290,400,443,405,1282,388,461,406,439,404,446,384,461,383,1303,404,1289,385,1303,405,442,404,1288,405,1286,404,1287,402,1290,403,442,406,440,405]}

Nature Remo に向けて赤外線を発射した後、 http でアクセスすれば JSON 形式で波形データを返してくれる。 で、この波形データの意味は? と思う間もなく答が見つかってしまった。 つまんない。

data配列の各要素は、赤外線ONの期間、OFFの期間、ONの期間、OFFの期間、、、、を表している。 厳密には、これは38kHzの変調をデコードしたあとの結果である。実際にはONの期間は38kHzの変調信号になっている。

ぱっと見 400前後の数値が多いなぁと思ったが、 1T 区間に対応するわけね、納得。 ざっと見た感じ 「赤外線ONの期間」 のほうが 「OFFの期間」 より短めになっている感じがしたので、 前者は 85 で割り算し、 後者は 115 で割り算してみた。 この「商」(割り算した結果) の個数だけ 2進数の 1 と 0 を並べ、 16進数に変換すればオシマイ。

Nature Remo 形式から PC-OP-RS1 形式への変換スクリプト:

#!/usr/bin/perl
use strict;
use warnings;

my @data = (3357,1717,385,1305,377,468,386,460,386,460,387,459,383,463,385,462,382,463,383,463,383,462,384,465,381,465,379,1306,386,463,382,460,385,465,381,467,381,459,385,462,384,462,377,1312,386,1309,384,459,387,462,382,460,386,460,385,461,385,462,385,1306,385,461,384,1307,384,461,386,1306,402,1291,399,1291,382,1307,388,456,404,1290,401,443,403,1287,407,440,402,445,401,443,386,462,400,445,384,463,382,464,381,464,384,1306,401,1292,383,1302,409,1285,402,1289,383,1309,383,1306,387,1304,379,1312,407,1285,402,443,405,441,386,460,403,443,385,460,404,442,385,464,403,440,404,1289,405,1285,404,1282,388,1304,409,1282,390,1301,406,441,386,1306,407,436,410,441,401,440,406,443,385,1304,407,1284,404,1287,405,441,386,1305,408,1287,404,1285,385,1304,407,441,383,462,389,40199,3376,1697,384,1306,407,441,402,442,407,440,384,465,400,443,405,442,383,460,385,464,384,461,401,445,402,441,404,1291,400,446,384,461,400,446,381,463,383,466,399,444,402,444,383,1304,407,1287,401,444,384,460,404,442,407,439,406,442,403,441,404,1287,386,460,403,1289,400,445,403,1287,407,1282,409,1285,385,1307,400,444,405,1285,404,442,404,1289,402,442,405,441,401,444,386,459,404,442,405,441,403,443,404,442,407,1286,405,1288,398,1286,406,1285,409,1283,404,1287,407,1286,401,1294,406,1284,401,1288,401,446,381,462,402,445,401,444,402,444,384,462,383,466,398,442,407,1286,401,1288,403,1288,404,1288,403,1288,401,1290,407,439,404,1284,406,441,404,441,409,436,408,439,407,1285,406,1285,403,1289,400,446,402,1288,403,1287,405,1284,404,1286,409,437,406,444,404,39760,3379,1697,402,1288,404,442,405,441,401,444,407,439,406,441,401,446,402,441,407,439,402,445,406,441,401,443,401,1290,405,437,404,446,405,441,402,441,402,442,406,441,403,441,404,1290,402,1290,400,446,404,439,407,439,406,439,404,442,404,442,406,1288,401,442,402,1290,385,462,401,1289,401,1290,404,1288,399,1288,404,441,386,1306,402,446,402,1287,403,446,401,442,402,444,401,445,404,441,402,444,402,444,402,446,400,1290,398,1290,402,1287,385,1309,404,1287,400,1289,403,1292,401,1283,390,1302,387,1304,404,445,384,460,408,436,405,442,385,462,402,443,404,441,404,442,385,1306,404,1287,402,1292,383,1307,401,1289,404,1290,400,443,405,1282,388,461,406,439,404,446,384,461,383,1303,404,1289,385,1303,405,442,404,1288,405,1286,404,1287,402,1290,403,442,406,440,405);
my $str = "";
my $bit = 1;
for my $d (@data) {
    if ($bit) {
	$str .= $bit x ($d / 85);
	$bit = 0;
    } else {
	$str .= $bit x ($d / 115);
	$bit = 1;
    }
}
$str = unpack("H*", pack("b*", $str)). "\n";
print "$str\n";

1行スクリプトに書けなくもないが、 まあ無理に 1行にしなくても、 このくらいならソッコーで書ける。 やっぱり perl が一番 :-)。

実行してみると ↓ こんな感じ。 波形データを PC-OP-RS1 形式に変換して初めて気付いたが、 80個以上の 0 が連なる区間 (2進数だと 320個以上、つまり 32ミリ秒以上の空白) があり、 3つの波形データに分けられることが分かる。

senri:~ $ ./irconv.pl
ffffffff7f00e001f0f0f0f07878787878787878003c3c3c3c3c1e1e1e000f80c7c3c3c3c3c303e0e101f0f00078003c001e008f07c0e301f0783c1e1e0f0f0f0f8007c003e001f00078003c001e000f8007c0e3f1f078783c3c1e000f8007c003e001f000783c001e8fc7e301f00078003c1e000f8007c003e0f1f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0ffffffff0f003c001e8fc7c3e3f1f0f0f0783c001e0f8f8787c7e301f000783c3c1e8fc703e0e101f078003c001e000f80c703e0f100783c1e8fc7e3f178003c001e000f8007c003e001f00078003c001e0f8fc7e3e1e1f10078003c001e000f8007c0e301f0783c1e0f8007c003e0f10078003c001e008fc703000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8ffffffff03000f80c7e3f1783c1e8fc7e3f100783c1e8fc7e3f10078003c1e8fc7e3f100783c001e1e000f8007c003e0f100783c001e8fc7e3f1783c1e000f8007c003e001f00078003c001e000f80c7c3e3f1f0783c1e000f8007c003e001f000783c001e1e8f8707c003e001f078003c001e000f80c7e301

というわけで、 上記「変換スクリプト」をちょこっと書き直して、 赤外線信号が表現しているデータを表示するようにしてみる。 NECフォーマットでも、 家製協(AEHA, 家電製品協会)フォーマットでも、 赤外線OFFの期間が 1T のとき「0」で、 3T のとき「1」だから、 赤外線ONの期間は無視して、 赤外線OFFの期間が 1000以上の時は 1 で、以下なら 0、 そして 3000以上なら信号の切れ目。

Nature Remo 形式から家製協(AEHA)フォーマットへの変換スクリプト:

#!/usr/bin/perl
use strict;
use warnings;

my @data = (3357,1717,385,1305,377,468,386,460,386,460,387,459,383,463,385,462,382,463,383,463,383,462,384,465,381,465,379,1306,386,463,382,460,385,465,381,467,381,459,385,462,384,462,377,1312,386,1309,384,459,387,462,382,460,386,460,385,461,385,462,385,1306,385,461,384,1307,384,461,386,1306,402,1291,399,1291,382,1307,388,456,404,1290,401,443,403,1287,407,440,402,445,401,443,386,462,400,445,384,463,382,464,381,464,384,1306,401,1292,383,1302,409,1285,402,1289,383,1309,383,1306,387,1304,379,1312,407,1285,402,443,405,441,386,460,403,443,385,460,404,442,385,464,403,440,404,1289,405,1285,404,1282,388,1304,409,1282,390,1301,406,441,386,1306,407,436,410,441,401,440,406,443,385,1304,407,1284,404,1287,405,441,386,1305,408,1287,404,1285,385,1304,407,441,383,462,389,40199,3376,1697,384,1306,407,441,402,442,407,440,384,465,400,443,405,442,383,460,385,464,384,461,401,445,402,441,404,1291,400,446,384,461,400,446,381,463,383,466,399,444,402,444,383,1304,407,1287,401,444,384,460,404,442,407,439,406,442,403,441,404,1287,386,460,403,1289,400,445,403,1287,407,1282,409,1285,385,1307,400,444,405,1285,404,442,404,1289,402,442,405,441,401,444,386,459,404,442,405,441,403,443,404,442,407,1286,405,1288,398,1286,406,1285,409,1283,404,1287,407,1286,401,1294,406,1284,401,1288,401,446,381,462,402,445,401,444,402,444,384,462,383,466,398,442,407,1286,401,1288,403,1288,404,1288,403,1288,401,1290,407,439,404,1284,406,441,404,441,409,436,408,439,407,1285,406,1285,403,1289,400,446,402,1288,403,1287,405,1284,404,1286,409,437,406,444,404,39760,3379,1697,402,1288,404,442,405,441,401,444,407,439,406,441,401,446,402,441,407,439,402,445,406,441,401,443,401,1290,405,437,404,446,405,441,402,441,402,442,406,441,403,441,404,1290,402,1290,400,446,404,439,407,439,406,439,404,442,404,442,406,1288,401,442,402,1290,385,462,401,1289,401,1290,404,1288,399,1288,404,441,386,1306,402,446,402,1287,403,446,401,442,402,444,401,445,404,441,402,444,402,444,402,446,400,1290,398,1290,402,1287,385,1309,404,1287,400,1289,403,1292,401,1283,390,1302,387,1304,404,445,384,460,408,436,405,442,385,462,402,443,404,441,404,442,385,1306,404,1287,402,1292,383,1307,401,1289,404,1290,400,443,405,1282,388,461,406,439,404,446,384,461,383,1303,404,1289,385,1303,405,442,404,1288,405,1286,404,1287,402,1290,403,442,406,440,405);
my $str = "";
my $bit = 1;
my $skip = 2;
for my $d (@data) {
    next if $skip-- > 0;
    if ($bit) {
	$bit = 0;
    } else {
	if ($d > 3000) {
	    print unpack("h*", pack("b*", $str)). "\n";
	    $str = "";
	    $skip = 2;
	} elsif ($d > 1000) {
	    $str .= "1";
	} else {
	    $str .= "0";
	}
	$bit = 1;
    }
}
print unpack("h*", pack("b*", $str)). "\n"; 

実行結果を以下に示す。 3つの波形は同じデータ 「10010305fa00ff30cf2cd3」(低 nybble が先) の繰り返しだった。 前掲した PC-OP-RS1 形式への変換スクリプトで得た波形データは 454バイトもあったが、 3つの波形が同じなら最初の 1波形 124バイトだけでよいことになる。 PC-OP-RS1 は一度に送ることができる赤外線データが 240バイトという制限があるので、 1波形のみ送ることにした。

senri:~ $ ./iraeha.pl
10010305fa00ff30cf2cd3
10010305fa00ff30cf2cd3
10010305fa00ff30cf2cd3

以下は、 PC-OP-RS1 で赤外線の送信を行うスクリプト。 -d オプションで PC-OP-RS1 のデバイスを指定する。 受光部分が壊れてしまったので、赤外線を学習する機能はない。 前述したような方法 (Nature Remo 等の学習リモコンで元データを生成して変換) で赤外線の波形データを作成し、 連想配列 %Ir に設定する。

緊張しながらこのスクリプトを実行 「./pc-op-rs1 -d /dev/PC-OP-RS1 off」 すると...
みごと 日立LED照明器具 LEC-AHS810K が消灯した。 ということは日立製作所のメーカ識別コードが 0x1001 ってこと? どこかに家製協のメーカ識別コード (カスタマーコード) の一覧って無いだろうか? ちなみに「全灯」ボタンは「10010305fa00ff20df2cd3」だった。

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Std;
use Device::SerialPort;

my %Ir;
$Ir{'on'} = pack("H480", "ffffffff7f00e001f0f0783c1e8fc7e3f1783c001e1e8fc7e3f178003c001e1e8fc7e3f100783c001e1e000f8007c003e0e101f0f00078783c1e8fc7e3f10078003c001e000f8007c003e001f078003c1e0f8fc7c303e0e101f00078003c001e000f80c703e0e1e1f1f00078003c001e1e000f8007c003e0e1f1");
$Ir{'off'} = pack("H480", "ffffffff7f00e001f0f0f0f07878787878787878003c3c3c3c3c1e1e1e000f80c7c3c3c3c3c303e0e101f0f00078003c001e008f07c0e301f0783c1e1e0f0f0f0f8007c003e001f00078003c001e000f8007c0e3f1f078783c3c1e000f8007c003e001f000783c001e8fc7e301f00078003c1e000f8007c003e0f1f0");

our ($opt_v, $opt_d, $opt_c);
getopts("vd:c:") || help();
defined $opt_d || die "option -d is needed\n";

my $port = new Device::SerialPort($opt_d) || help();
$port->user_msg(1);
$port->error_msg(1);
$port->baudrate(115200);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
$port->handshake("none");
$port->read_const_time(100); # 0.1 sec
$port->read_char_time(5);
send_ir($port, "\x69");
recv_ir($port, 1, 3);

my $ch = 1;
if ($opt_c) {
    if ($opt_c =~ /^[1-4]$/) {
	$ch = $opt_c;
    } else {
	help();
    }
}

while ($_ = shift @ARGV) {
    defined $Ir{$_} || help();
    send_ir($port, "\x74")
	&& recv_ir($port, 1, 3) eq "\x59"
	&& send_ir($port, pack("C", 0x30+$ch))
	&& recv_ir($port, 1, 3) eq "\x59"
	&& send_ir($port, $Ir{$_})
	&& recv_ir($port, 1, 3) eq "\x45"
	&& next;
    die;
}
$port->close;
exit 0;


sub send_ir {
    my ($port, $data) = @_;
    $port->write($data);
    print STDERR "send: ", unpack("H*", $data), "\n" if $opt_v;
}

sub recv_ir {
    my ($port, $len, $timeout) = @_;
    my $i = 0;
    my $j = 0;
    my $data;
    while ($i < $len) {
	my ($l, $d) = $port->read(1);
	if ($l > 0) {
	    $data .= $d;
	    $i += $l;
	    $j = 0;
	} else {
	    $j++;
	    if ($timeout > 0 && $j > $timeout) {
		print STDERR "TIMEOUT to read $len byte\n";
		return "";
	    }
	}
    }
    print STDERR "recv: ", unpack("H*", $data), "\n" if $opt_v;
    return $data;
}

sub help {
    print STDERR <<EOF;
Usage: pc-op-rs1 [opt] <com>...
opt:   -d <dev>   device (MUST)
       -c <ch>    channel (1..4)
       -v         verbose
EOF
    print "com: ", join(" ", sort keys %Ir), "\n";
    exit 1;
}
2019年11月28日

IFTTT に登録できないのでお蔵入りになってた Eco Plugs RC-028W & CT-065W が、UDP パケットを送るだけでコントロールできた!

IoT 機器の多くが、 専用のスマホアプリだけでなく Googleアシスタントや Amazonアレクサからコントロールできる。 しかし、 いちいち音声でコントロールするのはメンドクサイ (なぜ音声以外の方法でもコントロールできるようにしないのか?)。 出かけるときに毎回 「行ってきま〜す」 などと Googleアシスタントに呼び掛けるのは、 いかがなものかと思う。 外出を勝手に検知して家電を適切にコントロール (例えば電気ポットの電源を切る) してくれるほうがずっといい。

IoT 機器を IFTTT に登録すると、 自前のプログラムからコントロールできるようになる。 IoT 機器は Googleアシスタントでコントロールするより、 自前のプログラムでコントロールするに限る。 例えば自宅の Wi-Fi LAN にスマホが繋がっているかプログラムで監視し、 繋がってるスマホがいなくなったら留守になったと判断して、 自動的に電気ポットの電源を切れば、 電気ポットのコンセントを抜いたかどうか出先で心配せずに済む。 あるいはコンセントを抜くのを忘れて寝てしまい、 翌朝電気ポットのお湯が熱いままなのを見て愕然とするより (先月の電気使用量が 600kWh だったので驚いた)、 部屋が暗いときは自動的に電源が切れている方がいい (これはプログラムを書かなくても IFTTT だけで実現できる)。

というわけで持ってる IoT 機器を片っ端から IFTTT に登録したのだけど、 IFTTT に登録できない IoT 機器も残念ながら若干ある。 いまどき IFTTT に登録できない IoT 機器に何の意味があるのだろう? (今なら絶対に買わない) と思うのだけど、 IFTTT の便利さを知る前に買ってしまったのだから後悔先に立たず。 IFTTT の便利さを知ってからは、 お蔵入りになっていた。

Eco Plugs もそんな「使えない」IoT 機器の一つ。 当時としては安価だった (今ならもっと安い) ので Walmart で購入してしまった。 Googleアシスタントや Amazonアレクサには登録できるのに、 肝心の IFTTT に登録できない。

といって通信プロトコルを解析しようにも、 いまどきの IoT 機器はクラウド (ベンダが運用するサーバ) と https で通信するので調べる取っ掛かりがない。 最後の手段、 分解するしかないのか?

ところがググっていると、 Eco Plugs は平文で通信しているという投稿を見つけた。 Eco Plugs はクラウドに登録しなくても、 同一 LAN セグメントならスマホアプリでコントロールできるが、 同一 LAN 内では平文の UDP パケットを飛ばしているらしい。

ありがたいことに Eco Plugs をコントロールする JavaScript プログラムが GitHub に公開されていた。 JavaScript は文法もロクに知らない (^^; のだけど、 見よう見まねで perl で書き直してみる:

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Std;
use IO::Socket::INET;
our ($opt_v);
(getopts('v') && @ARGV == 3) || &help;
my ($ip, $id, $on) = @ARGV;

my $state = 0x0100;
$state = 0x0101 if $on eq "on";
my $buf = pack("H260", 0);
# Byte 0:3 - Command 0x16000500 = Write, 0x17000500 = Read
substr($buf, 0, 4) = pack("N", 0x16000500);
# Byte 4:7 - Command sequence num - looks random
substr($buf, 4, 4) = pack("N", rand(0xffffffff));
# Byte 8:9 - Not sure what this field is - 0x0200 = Write, 0x0000 = Read
substr($buf, 8, 2) = pack("n", 0x0200);
# Byte 16:31 - ECO Plugs ID ASCII Encoded - <ECO-xxxxxxxx>
substr($buf, 16, 16) = $id;
# Byte 116:119 - The current epoch time in Little Endian
substr($buf, 116, 4) = pack("L", time());
# Byte 124:127 - Not sure what this field is - this value works, but i've seen others 0xCDB8422A
substr($buf, 124, 4) = pack("N", 0xCDB8422A);
# Byte 128:129 - Power state (only for writes)
substr($buf, 128, 2) = pack("n", $state);

my $sock = IO::Socket::INET->new(PeerAddr => $ip, PeerPort => 80,
    Proto => 'udp', Timeout => 1) || die;
my $flags;
print unpack("H*", $buf) . "\n" if $opt_v;
print $sock $buf;
$sock->recv($buf, 1024, $flags);
print unpack("H*", $buf) . "\n" if $opt_v;

# Byte 10:14 - ASCII encoded FW Version - Set in readback only?
my $fwver = substr($buf, 10, 5);
# Byte 48:79 - ECO Plugs name as set in app
my $name = substr($buf, 48, 32);
$name =~ s/\0*$//;
printf("%s (ver %s)\n", $name, $fwver);

sub help {
    print <<EOF;
Usage: ecoplugs <opt> <IP> <ID> <on/off>
opt:   -v           ; verbose
EOF
    exit 1;
} 

長さ 130 バイトの UDP パケット (変数 $buf) を作って Eco Plugs へ送信している (print $sock $buf;) だけなので、 いたってシンプル。 ユーザ認証もないので LAN 内なら誰でもコントロールできる。

Eco Plugs の IP アドレス (第1引数) と、 Eco Plugs の ID 「ECO-XXXXXXXX」(第2引数, XXXXXXXX は MACアドレスの第3〜6オクテット, ただし 16進数の A〜F は大文字限定)、 および「on」あるいは「off」の 3引数を付けて、 この perl プログラムを実行すると、 該当 Eco Plugs をオン/オフし、 Eco Plugs の名前 (スマホアプリで設定できる。以下の例では 「potplug」) と、 ファームウェアのバージョン (以下の例では 「1.6.3」) を表示する。

senri:~ $ ecoplugs -v 192.168.15.123 ECO-01234567 on
16000500940c163b020000000000000045434f2d303132333435363700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a625df5d00000000cdb8422a0101
160005000000163b0000312e362e330045434f2d30313233343536370000000000000000000000000000000000000000706f74706c7567000000000000000000000000000000000000000000000000003031323334353637000000000000000000000000000000000000000000000000a8e23b7ea625df5d00000000cdb8422a
potplug (ver 1.6.3) 

「-v」オプションを付けた場合、 最初に表示される行が Eco Plugs へ送った長さ 130バイトの UDP パケット (260桁の 16進数)、 2行目が Eco Plugs から返ってきた長さ 128バイトの UDP パケット (256桁の 16進数)。 第1引数で指定した IP アドレスが Eco Plugs のものでなかった場合、 あるいは第2引数で指定した ID が間違っている場合など、 応答が返ってこない時は待ち続ける。 ID の 16進数において A〜F が小文字だと応答しないので注意。

Eco PlugsRC-028W (屋外用) および CT-065W (屋内用) で動作を確認したが、 おそらく同シリーズの他の機器でも使えるだろう。 Woods の WiON (スマホアプリが Eco Plugs そっくり) でも使えるらしい。

More...
2019年11月19日

IoT な人感センサをトリガーとした照明の点灯/消灯を IFTTT を使って行っていたけど反応が遅いので IFTTT をショートカットしてみた

さいきん流行りの IoT 機器。 多くの家電がネットからコントロールできるようになった。 IFTTT を使うと、 そういった機器を手軽に連携できるので便利。 IoT 機器同士だけでなく、 (私が管理する) WWW サーバを IFTTT がアクセスするように設定したり、 あるいは逆に私のサーバが IFTTT をアクセスする (トリガーを送る) こともできるので、 思いのままに IoT 機器を制御できる。

例えば、 人感センサで照明を点灯/消灯させる場合、 防犯用ライトなら人の動きを感知したときだけ点灯し、 人の動きが無くなれば速やかに消灯する、 といった単純なルールで充分だが、 部屋の照明となると人の動きが無くなったからと言ってすぐに消されては困る。 部屋を退出したことを確認してから消灯して欲しいし、 時間帯、あるいは在宅/不在時に応じて (さらにはその時々の天気に応じて)、 適切な点灯/消灯制御を行いたい。

つまり、 部屋の外にも人感センサを設置し、 部屋の中で人の動きが検知できなくなった後、 部屋の外で人の動きを検知すれば、 部屋を出ていったと判断し部屋の照明を消灯する。 さらに、 特定のスマホが LAN (家庭内 Wi-Fi) に接続していないときは不在とみなし、 部屋の外で人の動きを検知しただけでは照明を点灯しないけど、 そのスマホが LAN に接続した直後は帰宅したとみなし、 夜間であれば人の動きを検知したら速やかに点灯するなど。 私自身のサーバ (以下、「自サーバ」と略記) を IFTTT と連携させれば、 いくらでも複雑な制御ルールを設定できる。

IFTTT (IF This Then That) は、 その名の通り特定の条件 (This) が満たされたとき特定の動作 (That) を行わせることができる。 IoT 機器の多くは IFTTT との連携をサポートしているので、 例えば「This」として、 「人感センサが人の動きを検知」を設定し、 「That」として、 「照明をオン」を設定すれば、 単純な防犯用ライトが実現できる。

この連携に自サーバを絡めるには、 「This」および「That」を自サーバと結び付ければ良い。 それには IFTTT の 「webhooks」を用いる。

「This」は、 IFTTT の特定の URL をアクセスするだけ。 例えばこんな感じ:

senri:~ $ curl https://maker.ifttt.com/trigger/light_on/with/key/dD-v7GCx46LnWaF1AD9nwSUeA_N1ALvDHKS57cP1_Md
Congratulations! You've fired the light_on event

「light_on」の部分は任意に定めることができる。 「with/key/」以降の部分はユーザごとに IFTTT が割当てる認証用キー。 このキーが他人に漏れると勝手に操作されてしまうので適切な管理が必要。 そして、 「https://maker.ifttt.com/trigger/light_on/with/key/... へのアクセスがあった」(This) ならば、 「照明をオン」(That) を行う、 というルールを設定することで、 自サーバから照明を点灯させることが可能になる。

いっぽう 「That」 は、 IFTTT に自サーバをアクセスさせる。 例えば 「https://www.gcd.org/ifttt へ POST メソッドでアクセス」させる。 POST の body として json データを送るよう設定することができて、

{"magic": "0svikYKbcsxDbkty", "type": "Motion detected", "CreatedAt": "{{CreatedAt}}", "DeviceName": "{{DeviceName}}"}

などと設定する。 「"magic": "0svikYKbcsxDbkty"」は認証用。 https://www.gcd.org/ifttt は誰でもアクセスできるので、 "magic" の文字列が一致しないリクエストは無視する。 「"type"」は 「This」の機器の種類 (この例では人感センサ) を伝えるために設定。 「{{CreatedAt}}」と 「{{DeviceName}}」は、 「This」の機器が IFTTT へ送信したデータ。 例えば人感センサが検知 (This) すると IFTTT が次のようなアクセスを www.gcd.org へ行ってくれる (That)。

POST /ifttt HTTP/1.1
Content-type: application/json
host: www.gcd.org
content-length: 134
x-newrelic-id: ZW1uPtmAO9tRDSFGGvmp
x-newrelic-transaction: VGhpcyBpcyBmYWtlIHgtbmV3cmVsaWMtdHJhbnNhY3Rpb24uCg==
Connection: close

{"magic": "0svikYKbcsxDbkty",
 "type": "Motion detected",
 "CreatedAt": "November 19, 2019 at 09:15AM",
 "DeviceName": "廊下センサ"
}

この IFTTT からのアクセスを受信することで、 人感センサが人の動きを検知したことを自サーバが知ることができる。 そして自サーバにおいて様々な条件を加味した後、 前述した 「https://maker.ifttt.com/trigger/light_on/with/key/...」 へアクセスすれば照明を点灯することができる。

以上で、 IoT の連携に自サーバを絡ませることができるようになった。 ところがこの方法は、いかんせん遅い。 人感センサ ⇒ IFTTT ⇒ 自サーバ ⇒ IFTTT ⇒ 照明 などと IFTTT とのやりとりを 2度も行うため、 人の動きを検知してから照明が点灯するまで 6秒ほどかかってしまう。 部屋に入るまで 6秒も待てないので、 暗いままの部屋に入る羽目になる。 なお、 点灯するのは素早さが肝要だが、 消灯するのは数秒程度の遅れなら全く問題にならない。

More...
Filed under: システム構築・運用,ハードウェアの認識と制御 — hiroaki_sengoku @ 15:58
2019年9月4日

UEFI ブートでキーボードが無いと GRUB がハングするバグを修正してみた

遅ればせながら手元の PC を MBR ブートから UEFI ブートに切り替えた。 ハードディスクの最初の 512バイト MBR (Master Boot Record) を読み込んで起動するのが MBR ブート。 Windows だと 2TB 超のディスクは MBR ブートできない (Linux ならブート可能)。 2TB では手狭になってきたのが切り替えを決意した理由だが、 ついでに Linux 専用マシンも PC のファームウェアが対応しているものは UEFI ブートに切り替えた。

UEFI (Unified Extensible Firmware Interface) だと、 普通の FAT32 ボリュームにブートローダのファイルを置いておくだけなので、 わざわざ MBR を書き換えたりするより簡単だし分かりやすい。 PC が起動しなくなった、などのトラブルはよくあるが、 トラブル発生時は気が急くし時間的余裕がないことも多いので、 トラブル時の作業は簡単であればあるほど、 分かりやすければ分かりやすいほど好ましい。

UEFI ブートに切り替えて 1ヶ月ほど経ったある日、 CPU を換装するために落としていた PC の電源を入れたら GRUB のメニュー画面でフリーズしたので私も凍り付いた。 CPU の性能をむやみに上げると、マザーボードとのミスマッチが起りがち。 せっかく買った新しい CPU が問題を起こしたのかと思った。 電源ボタンを長押しして強制的に電源を落とす。

BIOS 設定を確認するためにキーボードをつないで再度電源を入れてみる。 設定に何の問題もない。 続いて GRUB を立ち上げる。問題無く立ち上がる。 Linux を起動する。問題無い。 さっきのフリーズは何だったのだろう?

この時は因果関係に気付かなかったが、 キーボードをつないでいないと GRUB 2.04 (および最新版の 2.05 も) がメニュー画面のカウントダウンでハングする (最初の秒を表示したまま止まる)。 PC を再起動するときは、たいていキーボードをつないでいるので正常に起動し、 この症状は見たことがなかった。

実はこの時も、 なぜキーボードをつないでいなかったかというと明確な理由はない。 CPU 換装後の動作確認なのだからキーボードをつないでおくべきだと思うのだけど、 たまたまつなぐのを忘れていただけかも。 Web で 「headless GRUB hang bug UEFI without keyboard」 などを検索しても似た症例がほとんど見つからないのは、 キーボードをつながずに起動させる人がほとんどいないから?

とはいえ、 何台もあるサーバそれぞれにキーボードをつないでいては邪魔である。 意図して再起動するときはキーボードをつなぐなり KVM スイッチ (Keyboards, Video monitors, Mice Switch) を切り替えてキーボードが効く状態にするのが通常だが、 トラブルや Watchdog タイマーで勝手に再起動したとき、 あるいは遠隔から再起動させたときに、 立ち上がらずにフリーズしてしまったら非常に困る。 不測の再起動に備えて、 急遽テンキーをつないでおくことにした。

GRUB がキー入力を検知する状態であれば、 画面表示の有無自体は関係なくハングする。 逆に言うと、 GRUB がキー入力を検知しなければ、 例えば grub.cfg でキー入力を読む命令が無ければ (menuentry 等が無ければ) ハングしない。 例えば grub.cfg が次のように特定の Linux を起動するだけなら、 正常に起動できる。

insmod all_video
insmod part_gpt
insmod search_label
search --no-floppy --label --set=root /
linux /boot/linuz-4.19.69-x86_64 root=LABEL=/ resume=LABEL=swap ro
initrd /boot/initz-4.19.69-x86_64
boot

もちろんこれでは GRUB を使う意味がないが、 少なくとも問題が GRUB のキー入力関連にあることが分かった。 同じ PC、同じ GRUB でも、 UEFI ブートではなく MBR ブートなら、 キーボードをつながなくてもハングしない (MBR ブート専用の USB メモリを作って確認した。末尾の「おまけ」参照)。 また、UEFI ブートであっても UEFI ファームウェアによってはハングしない場合もあると思われる (未確認)。 が、少なくとも私の PRIMERGY MX130 S2 では確実に再現する。

というわけで、 問題の所在はおおむね絞り込めたので、 GRUB のソースコードを読み始めた。 並行して facebook に、 ことの顛末を書込んだ

すると野中尚道さんから grub-core/tem/efi/console.c が怪しそう、 とのヒントを頂いた。 ありがたい! なにぶん EFI のソースコードを読むのは初めてなので、 この時点ではまだ流れを追いきれていなかった。 efi/console.c の grub_console_getkey まわりを重点的に読んでみる。

grub-core/tem/efi/console.cのget_keyで key_exとkey_conを呼び分けている処理が失敗しているような気がします。 key_exの方はオプション機能なので実装有無を確認してるのですが

なるほど確かに grub_console_getkey_ex は、 grub_efi_open_protocol の返り値が NULL で無いとき (key_ex の実装が有るとき) に限り呼び出されているが、 grub_console_getkey_con には対応するものがない。 key_con は必ず実装されているから確認不要? でも、キーボードをつないでいない場合はどうなる? key_ex の有無を確認するコード:

text_input_ex_guid = GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
	...
text_input = grub_efi_open_protocol(grub_efi_system_table->console_in_handler,
				    &text_input_ex_guid,
				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);

をマネして、 key_con の有無を確認するコードをでっち上げてみる。 単に 「_EX_」 の部分を取り除いただけだが、 キーボードをつないでいるか否かを正しく検出しているようだ。

text_input_guid = GRUB_EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
text_input = grub_efi_open_protocol(grub_efi_system_table->console_in_handler,
				    &text_input_guid,
				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);

あとはキーボードの有無に応じて grub_efi_console_input_init の返り値を変えるだけ。 grub_efi_console_input_init が 1 (非ゼロ?) を返せば、 GRUB は grub_console_getkey を呼ばなくなるようだ。

以上をまとめると、 次のようなパッチになった:

diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
index 4840cc5..f2be32f 100644
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -207,7 +207,12 @@ grub_efi_console_input_init (struct grub_term_input *term)
 				      GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
   term->data = (void *)text_input;
 
-  return 0;
+  if (text_input) return 0;
+  grub_efi_guid_t text_input_guid = GRUB_EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
+  text_input = grub_efi_open_protocol(grub_efi_system_table->console_in_handler,
+				      &text_input_guid,
+				      GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+  return text_input == NULL;
 }
 
 static int

わずか 6行だが、 これで GRUB がハングしなくなった。

More...
Filed under: システム構築・運用,プログラミングと開発環境 — hiroaki_sengoku @ 21:21
2019年8月26日

Windows 10 上の VMware Workstation Player のゲストOS でタグVLAN を使ってみる

Windows 上の仮想化ソフトウェアの定番 VMware Workstation Player で、 タグVLAN (tagged VLAN, IEEE 802.1Q) を使うことはできないと今まで思い込んでいたが、 レジストリエディタ (regedt32.exe) でレコードを一つ追加するだけで使えるようになった。 ググっても Windows 上のゲストOS でタグVLAN を使う話は見かけないのでメモしておく。

私の自宅内LAN はタグVLAN を利用している。 つまり物理的な配線は一本のイーサケーブルで、 複数のネットワーク (宅内LAN, DMZ, 対外セグメントなど) を同居させている。 タグVLAN はオフィス等で使われることが多いが、 美観上の理由からケーブルを何本も這わすわけにはいかない家庭内LAN においてこそ、 タグVLAN は有用と思う。

Linux OS などタグVLAN 対応の OS が走るマシンへは、 タグが付いたままのパケットを流し、 Windows OS などタグVLAN に非対応な OS が走るマシンへは、 スマートスイッチでタグを取り除いた (通常の) パケットを流している。

ところが、 マシンによっては Linux と Windows の両方の OS を走らせることがある (いわゆるデュアルブート)。 OS を切り替えるたびにスマートスイッチの設定を変更するのは面倒なので、 そういうマシンには Linux と Windows の両方がアクセスするネットワーク (つまり自宅内LAN) のパケットはタグ無しで流しつつ、 Linux のみがアクセスするネットワーク (DMZ や対外セグメント) のパケットはタグ付で流すことになる。

Windows が立ち上がってるときもタグ付パケットが届くが無視される。 Linux が立ち上がっているときはタグ付、タグ無し両方のパケットを受け取る。

さいきんは PC のメモリも大きくなり、 普段は Windows を使うマシンでも、 VMware Workstation Player (以下 VMware と略記) などの仮想化ソフトウェアを使って Linux をゲストOS として走らせておくことが増えてきた。 デュアルブートよりも同時に走らせておくほうが便利に決まってる。 となってくると、 ゲストOS でもタグVLAN を使いたくなるのが人情というもの。

ゲストOS でタグVLAN が扱えると、 本来 DMZ へ置くべきようなサーバ (WWW サーバとか) をゲストOS 上で動かすことが可能になる。 また、 ゲストOS でも自宅内LAN とインターネットとの両方のネットワークへアクセスできるわけで、 ルータの役割を担わせてもよい。 いずれにしても仮想マシンの応用範囲が一気に広がる。

しかし VMware を使って起動した仮想マシン上では、 (仮想)ネットワークインタフェースにタグ付パケットが上がってこないので、 ゲストOS でタグ付パケットを拾うことができない。 VMware がタグVLAN に対応していないのだろうと諦めていた。 まあタダで利用させてもらってるソフトウェアだし、 対応してなくても仕方がないなぁと。

ところが、 実は VMware 自体はタグVLAN に対応しているらしい。 Windows 10 がタグ付パケットを落としているから、 VMware までパケットが届かないということらしい。 細かく言えば Windows 10 が悪いというよりは、 ネットワークインターフェース (以下 NIC と略記) のドライバがタグ付パケットを落としているらしい。

私が使ってる Windows 10 では NIC が 「Broadcom NetLink (TM) Gigabit Ethernet」 と表示されるので、 「windows10 broadcom capture vlan」 あたりのキーワードで検索していたら、 Windows 上でタグ付パケットをキャプチャする方法について書かれたページを見つけた。

なお google では同じキーワードを使って検索しても、 このページを見つけ出すことはできなかった。 ニッチなものを見つけたい場合に、 google 検索が全く役に立たなくなったのは、 google がモバイル検索にシフトし始めた頃だったろうか? 探しているページが全く見つけられないので、 最近は google 検索を使わなくなってしまった。 google お得意の AI で賢く検索するより、 バカ正直にキーワード検索してくれたほうが (少なくとも私にとっては) 役に立つ。 Stay Foolish !

この見つけたページには、 Windows 上のパケットキャプチャソフトウェア Wireshark でタグ付パケットを見る方法が書かれている:

Display VLAN tags in Wireshark on laptops with Broadcom B57 chipsets から引用:

In order to make these tags visible to Wireshark, specialized drivers or specific NICs that support VLAN tags are usually needed. In the case of the Broadcom B57 chipset in some Dell Latitude laptops, the NIC itself supports VLAN tags (display only, it cannot actively tag outgoing traffic) with a small registry modification and a specific driver.

(意訳) Wireshark でタグ付パケットを見るには、 NIC ドライバがタグVLAN に対応している必要がある。 Broadcom B57 チップセット自体はタグVLAN に対応しているので、 ドライバのレジストリをいじればタグ付パケットを見ることができるようになる。 ただし見るだけでタグ付パケットを送信することはできない。

このページには 「送信できない」 と書いてあるが、 後述するようにゲストOS からタグ付パケットを送信できている。 Wireshark と VMware とでは違うのかも?

レジストリをいじるには、 まず NIC ドライバのインスタンスを見つけなければならない。 このページでは 「TxCoalescingTicks」 を検索せよと説いている。 Broadcom B57 チップセットのドライバのインスタンスであれば、 この名前のレコードを必ず持っているからだろう。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{クラスID}\番号 を見つけたら、 このインスタンスに 「PreserveVlanInfoInRxPacket」 という名前で文字列値 「1」 を追加すればよい。

ちなみに、 「tx coalesce ticks」 を WWW で検索すると Broadcom 関連のページばかりが出てくる。 Broadcom 製 NIC 特有の機能なのかも? Linux の BCM5700 用ドライバ にも tx_coalesce_ticks というパラメータがあるようだ。

というわけで、 Broadcom 製 NIC でタグ付パケットを落とさないようにする方法は以下のようになる:

VLAN capture setup から引用:

  1. Run the Registry Editor (regedt32).
  2. Search for "TxCoalescingTicks" and ensure this is the only instance that you have.
  3. Right-click on the instance number (eg. 0008) and add a new string value.
  4. Enter "PreserveVlanInfoInRxPacket" and give it the value "1".

意訳:

  1. レジストリエディタ regedt32 を起動する
  2. 「TxCoalescingTicks」 を検索する。 見つけたインスタンスが (Backup 用のインスタンスを除いて) 唯一であることを確認する。
  3. 見つけたインスタンス番号 (例えば 0008) を右クリックし、 「新規 文字列値」 を追加する。
  4. 「PreserveVlanInfoInRxPacket」 を入力し、 その値を 「1」 とする。

Intel 製 NIC の場合も、 ドライバのレジストリをいじることで、 タグ付パケットを落とさないようにできるらしい。

レジストリをいじった後は、 再起動すれば NIC ドライバがタグ付パケットを捨てずに受け取るようになっている。 ドライバが捨てなければ、 タグ付パケットは Windows OS から VMware に渡され、 ゲストOS まで届く。 逆にゲストOS から発せられたタグ付パケットは、 Windows OS から NIC へ送られ、 ネットワークへ送出される。 つまりゲストOS がタグVLAN を扱えるようになった。

Filed under: システム構築・運用 — hiroaki_sengoku @ 09:06
2018年4月12日

NETGEAR のスマートスイッチ GS108E/GS116E のポートごとの通信量を取得して Cacti でグラフ化してみた 〜 通信量を見ることができない Wi-Fi中継機への対処法 〜

たまたま買った Wi-Fiアクセスポイント (以下 Wi-Fi AP と略記) が、 SNMP 非対応なのはもちろん、 Web管理画面でさえ通信量を見ることができなかったので、 この Wi-Fi AP を接続しているスイッチ (ネットワークハブ) NETGEAR GS108E (と GS116E) のポートの通信量を取得して Cacti (最近の流行りは Grafana ?) で可視化してみた。 Wi-Fi そのものの通信量ではないが、 Wi-Fi AP とスイッチとの間の通信量を測ることができる。

買ったのは NETGEAR WiFi中継機/802.11ac wave2 Nighthawk X4 EX7300-100JPS (以下 EX7300 と略記)。 たまたま amazon で税込5,980円 (送料無料) で売っていて、 中継機 (ワイヤレスエクステンダー) としてだけでなくアクセスポイントとしても使えるとのことなので (NETGEAR製ということもあって) 衝動買い。 もともとルータの機能は必要ないし、 コンセント直挿しで場所を取らないので、 リビング用としてちょうどいいかなと思った次第。

さいきん Wi-Fi中継機が流行りらしく、 各社からお手頃価格で多数の製品が発売されている。 コンセント直挿しで場所を取らないので家庭向きと言えるが、 残念なことにアクセスポイントとして使える製品は (NETGEAR や TP-Link などのごく一部の例外を除くと) ほとんど無い。
中継機も (広義の) アクセスポイントと言えるが、 親機 (Wi-Fiルータ) と無線でつながるのが中継機で、 有線でつながるのが (狭義の) アクセスポイント。 あたりまえだが、 有線でつなぐことができる (家庭内でケーブルを配線できる) なら、 有線のほうがいいに決まってる。
ちなみに私が初めて Wi-Fi中継機を使ったのは 10年前なので、 いまさら流行って少々戸惑いを覚える。

EX7300 は、 たった 6000円なのに性能的には悪くない。 ルータ機能が不要ならお買得と思う。 ノートPC Lavie HZ を Wi-Fi で EX7300 につないで iperf3 を走らせて測定してみたら 530Mbps くらい出ている。

C:\Users\sengoku>c:\bin\iperf3.exe -c esaka -P 5
Connecting to host esaka, port 5201
[  4] local 192.168.18.147 port 50119 connected to 192.168.18.20 port 5201
[  6] local 192.168.18.147 port 50120 connected to 192.168.18.20 port 5201
[  8] local 192.168.18.147 port 50121 connected to 192.168.18.20 port 5201
[ 10] local 192.168.18.147 port 50122 connected to 192.168.18.20 port 5201
[ 12] local 192.168.18.147 port 50123 connected to 192.168.18.20 port 5201
[ ID] Interval           Transfer     Bandwidth
[  4]   0.00-1.00   sec  13.4 MBytes   112 Mbits/sec
[  6]   0.00-1.00   sec  13.2 MBytes   111 Mbits/sec
	...

[SUM]   9.00-10.01  sec  63.9 MBytes   533 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth
[  4]   0.00-10.01  sec   130 MBytes   109 Mbits/sec                  sender
[  4]   0.00-10.01  sec   130 MBytes   109 Mbits/sec                  receiver
[  6]   0.00-10.01  sec   128 MBytes   108 Mbits/sec                  sender
[  6]   0.00-10.01  sec   128 MBytes   108 Mbits/sec                  receiver
[  8]   0.00-10.01  sec   128 MBytes   107 Mbits/sec                  sender
[  8]   0.00-10.01  sec   128 MBytes   107 Mbits/sec                  receiver
[ 10]   0.00-10.01  sec   126 MBytes   106 Mbits/sec                  sender
[ 10]   0.00-10.01  sec   126 MBytes   106 Mbits/sec                  receiver
[ 12]   0.00-10.01  sec   124 MBytes   104 Mbits/sec                  sender
[ 12]   0.00-10.01  sec   124 MBytes   104 Mbits/sec                  receiver
[SUM]   0.00-10.01  sec   636 MBytes   534 Mbits/sec                  sender
[SUM]   0.00-10.01  sec   636 MBytes   534 Mbits/sec                  receiver

iperf Done.

たまたま手元にあった TP-Link WiFi 無線LAN ルーター Archer C3150 11ac にも Wi-Fi でつないで同様に iperf3 を走らせて比較してみたら、 ほとんど差がない。 同等と言ってもいいレベル。 値段は 3倍くらい違うのだから、 EX7300 をブッチぎって欲しかった。

しかもこの Archer C3150 は OpenVPN を使ってると腐るバグがあるように感じる (いちど電源を切らないと復旧しない)。 ヘンテコな付加機能よりも安定性こそ一番重要なのではないか? ついでに言うと勝手に外部と通信しているのが気持ち悪い。 値段が高い Wi-Fiルータにはもうちょっと頑張ってもらいたいところ。

もちろん、 このノートPC を無線LAN ではなく有線LAN につなげば 940Mbps くらいは出るので、 ノートPC の性能がボトルネックになっているわけではない。 というか Wi-Fi のパフォーマンスは周囲の電波状況に強く影響され (もちろん空いてるチャンネルを使っている)、 有線側の状況はほとんど関係がない。 電波暗室とかで測定すれば、 EX7300 と Archer C3150 の差が開くのかもしれないが、 実用上は無意味。

性能でも安定性でも申し分のない EX7300 ではあるが、 残念なことに Web管理画面を隅から隅まで調べてみても通信量を見る方法がない。 どんな安物 Wi-Fiルータ (or Wi-Fi AP) でも、 通信量 (パケット数とか) を表示させる方法はあるものだと思っていたが、 中継機は Wi-Fiルータとは製品コンセプトが違うのかも?

通信量を見ることができない通信機器があるとは思っていなかったので、 意表を突かれた感じ。 今後 Wi-Fi AP を買う際は注意したい。 やっぱり (ルータ機能が必要なくても) 素直に Wi-Fiルータを買うべきなのかも。 ほんとうは (ルータ機能がない) アクセスポイント専用機が欲しいのだけど...

幸い、 この EX7300 を接続しているスイッチ NETGEAR GS108E が「スマート」で、 スイッチの各ポートごとの通信量 (≒ Wi-Fi AP の通信量) を GS108E/GS116E 付属の Windows アプリ ProSafe Plus で見ることができる。

Web アプリではなく Windows アプリなので、 表示された通信量の数値を Web スクレイピングなどのお手軽な方法で取り込むことはできないが、 google で検索したら ProSafe Plus と同等のことができる Python プログラムが見つかった。 6年前に開発が終了しているが、 このスイッチを買ったのも 6年前なので無問題。

さっそくダウンロードして (ざっと内容を確認したのち) 走らせてみる:

senri $ git clone https://github.com/Z3po/Netgearizer.git ↵
Cloning into 'Netgearizer'...
remote: Counting objects: 88, done.        
remote: Total 88 (delta 0), reused 0 (delta 0), pack-reused 88        
Unpacking objects: 100% (88/88), done.
Checking connectivity... done.
senri $ Netgearizer/netgearizer.py ↵
please select one of the following switches with "selectSwitch $NR"
--> 0: 192.168.18.239
Information: 
switch-name: living
switch-dhcp: disabled
switch-type: GS108Ev2
switch-ip: 192.168.18.239
switch-mac: 4c:60:de:69:01:23
switch-firmware: 1.00.06
switch-netmask: 255.255.255.0
switch-gateway: 192.168.18.1
(Cmd) 

スイッチは 3つ (GS116E と GS108E 2台) あるのに、 なぜか 1つ (リビングに設置した GS108E) しか表示されない。 selectSwitch コマンドでスイッチを選択し (選択肢は 1つしか無いが)、 getPortStatistics コマンドでポートごとの通信量を表示できるようだ。

実行してみる:

(Cmd) selectSwitch 0 ↵
(Cmd) getPortStatistics ↵
switch-port-statistics: 
 -> Port 01: 
   >> send: 2664610542955
   >> receive: 5993649462240
   >> crcerrors: 0
 -> Port 02: 
   >> send: 6062498001
   >> receive: 328715447216
   >> crcerrors: 0
 -> Port 03: 
   >> send: 183424114643
   >> receive: 8723285000144
   >> crcerrors: 0
 -> Port 04: 
   >> send: 39935317815
   >> receive: 26550837425456
   >> crcerrors: 0
 -> Port 05: 
   >> send: 137960667631
   >> receive: 790398362288
   >> crcerrors: 0
 -> Port 06: 
   >> send: 3948410207
   >> receive: 1156872131840
   >> crcerrors: 0
 -> Port 07: 
   >> send: 2789623
   >> receive: 20875141728
   >> crcerrors: 0
 -> Port 08: 
   >> send: 1989939088
   >> receive: 2852348890112
   >> crcerrors: 0
(Cmd) 

一見、 正しく動いているように見えるが、 「send:」に表示されている数値は (ProSafe Plus で見たときの) 受信バイト数で、 「receive:」に表示されている数値は送信バイト数を 16倍した値になっている。

受信と送信が入れ替わっているのはご愛敬だが、 16倍になっているのは... netgearizer.py (Python で書かれたスクリプト) を読んでみると、 単純なバグだった。 次のパッチをあてると正常に動作した:

--- netgearizer.py.org	2018-04-07 22:04:42.292912972 +0900
+++ netgearizer.py	2018-04-09 11:34:50.124297214 +0900
@@ -284,5 +284,5 @@
             for port in hexvalue:
-                sendstats = self.__convertFromHex(port[2:18],'cipher')
-                receivestats = self.__convertFromHex(port[19:35],'cipher')
-                crcerrors = self.__convertFromHex(port[36:53],'cipher')
+                receivestats = self.__convertFromHex(port[2:18],'cipher')
+                sendstats = self.__convertFromHex(port[18:34],'cipher')
+                crcerrors = self.__convertFromHex(port[82:98],'cipher')
                 result.append(( 'Port ' + str(port[:2]), (('send', sendstats), ('receive', receivestats), ('crcerrors', crcerrors))))
@@ -345,15 +345,16 @@
                 for key in self.switches.keys():
                     self.switchList.append(key)
                     print '--> ' + str(counter) + ': ' + key
                     print 'Information: '
                     self.selectedSwitch = key
                     self.__printResult(True)
                     self.selectedSwitch = None
-                    return True
+                    counter += 1
+                return True
             else:
                 print 'please select one of the switches you get with getSwitches first.'
                 return False
 
         if 'ERROR' in resultdict:
             found = None
             for key in  self.switchattributes.keys():

送信バイト数が 16倍になるのは、 部分文字列の切り出しで「port[18:34]」 (変数「port」の文字列の 18文字目から 34文字目まで切り出す) とすべきところを、 「port[19:35]」 としてしまっていたため。 変数「port」には、 スイッチから受信したデータを 16進数に変換した文字列が格納されている。 1文字ずれて切り出したため、 16倍 (16進数で 1桁ぶん) になっていた。

16進数で 16文字つまり 64bit だが、 ProSafe Plus で表示される GS116E の送受信バイト数が小さすぎると思っていたら、 GS116E はバイト数が 32bit (4GiB) でラップアラウンドしているようだ。 つまり上位 32bit は常にゼロ。ポートによっては毎日ラップアラウンドしている。
GS108Ev2 は 40bit (1TiB) を超えるバイト数になっているポートもあるので、 どこでラップアラウンドするか確認できるまで、 まだだいぶかかりそう。 仮に 1ヶ月で 1TiB くらいの通信量だとすると、 もし 48bit (256TiB) が上限なら 20年もかかってしまう。
もし 64bit 全部使ってカウントしているなら、 上限は 16EiB (エクスビバイト) ということになり、 140万年くらいかかってしまう。 ちょっとのコスト増を惜しんでラップアラウンドするより、 64bit きっちり使って半永久にラップアラウンドしないほうがいい。

実は、 私は今まで Python でプログラミングしたことが無い。 文法もろくに知らなかったのだけど、 部分文字列を切り出す際の Python の位置の指定方法は独特だと思う。 このプログラムの作者も Python は慣れていなくて、 うっかりこのようなバグを作り込んでしまった (前の行で 18文字目まで切り出したので、 その次は 19文字目からとしたくなる気持ちは分かる) のではないか?

さらに興味深いのが、 3つあるはずのスイッチが 1つしか見つからなかったバグ。 なんと、 「return True」文のインデント (字下げ) が間違っていただけ。 インデントでブロックを表わす Python ならではのバグ?

インデントが一段階深かったので、 「return True」文が forループの中に入ってしまい、 必ずループが 1回だけで終了してしまっていた。 だからスイッチを 1つ見つけてすぐループを終了していた。 「return True」文の前の空白を削除してループの外へ出したら、 正しく 3つのスイッチを見つけるようになった。 空白の有無で挙動が変わってしまうのは、 やっぱり気持ち悪い。

この netgearizer.py は対話的にコマンドを入力するソフトウェアだが、 通信量を自動計測する際には使いにくいので、 対話せず通信量を取得するだけのプログラムに書き換えた。 不要な機能をばっさり削除したので、 プログラムの行数が半分以下の 317行になった。 この改変版は、

http://www.gcd.org/sengoku/docs/netgearizer.py

からダウンロードできる。 わずかな改変とはいえ、 なにぶん私が初めて書く Python プログラムなので、 変なところがあったらご指摘頂けると幸い。

この改変版を実行する (引数としてインタフェースを指定する) と、 以下のように LAN 内 (同一セグメント内) の全ての NETGEAR スマートスイッチ (GS116E, GS108E, GS105E など) の、 各ポートの受信バイト数、送信バイト数、エラー数を表示する。

senri:~ $ netgearizer.py eth0 ↵
IP:   192.168.18.239
MAC:  4c:60:de:69:01:23
Type: GS108Ev2
switch-port-statistics: 
 Port01 rx:2673873720246 tx:375671471563 err:0
 Port02 rx:6410023533 tx:21992185424 err:0
 Port03 rx:183424114643 tx:545205312509 err:0
 Port04 rx:40052812544 tx:1664344574414 err:1
 Port05 rx:138616484625 tx:52251007903 err:0
 Port06 rx:3954090302 tx:72431873899 err:0
 Port07 rx:2802623 tx:1308888305 err:0
 Port08 rx:1989939088 tx:178271805632 err:0
IP:   192.168.18.237
MAC:  4c:60:de:69:04:56
Type: GS108Ev2
switch-port-statistics: 
 Port01 rx:786331851 tx:1283347 err:0
 Port02 rx:0 tx:0 err:0
 Port03 rx:0 tx:0 err:0
 Port04 rx:0 tx:0 err:0
 Port05 rx:0 tx:0 err:0
 Port06 rx:474556 tx:875905 err:0
 Port07 rx:0 tx:0 err:0
 Port08 rx:0 tx:0 err:0
IP:   192.168.18.236
MAC:  84:1b:5e:90:81:72
Type: GS116E
switch-port-statistics: 
 Port01 rx:2245190893 tx:3192491053 err:0
 Port02 rx:2079058908 tx:4030809209 err:0
 Port03 rx:0 tx:0 err:0
 Port04 rx:2815311290 tx:1592352771 err:0
 Port05 rx:3838533539 tx:2573311206 err:0
 Port06 rx:1441584273 tx:1249733039 err:0
 Port07 rx:747795050 tx:97733030 err:0
 Port08 rx:889171012 tx:559797414 err:0
 Port09 rx:3757714660 tx:749158734 err:0
 Port0a rx:3210386057 tx:2724670950 err:0
 Port0b rx:441710237 tx:2183781562 err:0
 Port0c rx:0 tx:0 err:0
 Port0d rx:4837745 tx:252496639 err:0
 Port0e rx:2058650283 tx:3610878767 err:0
 Port0f rx:1435416601 tx:403439849 err:0
 Port10 rx:0 tx:0 err:0
senri:~ $ 

私の自宅の LAN ではタグVLAN を使っているため、 以上のコマンドを実行している Linux マシン「senri」の eth0 インタフェースには IP アドレスを割当てていないが、 問題なく動作している。 しかも、 この Linux マシンは GS116E の Port04 に接続していて、 2台の GS108E には GS116E 経由で間接的に繋がっているのだけど、 GS108E の通信量も取得できている。 Windows アプリの ProSafe Plus だと、 スイッチに直接繋げないと管理できないことがある。

改変版 netgearizer.py で取得した送受信バイト数を Cacti (最近の流行りは Prometheus とか Fluentd ?) に読み込ませて EX7300 の通信量をグラフ化すると、 こんな感じ:

In がスイッチのポートの送信バイト数、 つまりスイッチから EX7300 が受信したバイト数、 すなわち Wi-Fi 子機 (スマホなど) がダウンロードした合計。

Out がスイッチのポートの受信バイト数、 つまりスイッチへ EX7300 が送信したバイト数、 すなわち Wi-Fi 子機がアップロードした合計。

実は ProSafe Plus のもう一つの Python 実装である ProSafeLinux も試してみたのだが、 IP アドレスを割当てていないインタフェースを受付けないので、 先に netgearizer.py の書き換えを試みた次第。

ProSafeLinux のほうが (active ではないにせよ) 今でも開発が続いているし、 前述したようなバグも無いようなので、 試してみるべきだとは思うが、 プログラムの行数が netgearizer.py の倍以上 (私が作った改変版の 5倍以上) もある。 通信量の取得といった単純な目的であれば、 短い方がいい。

Filed under: システム構築・運用 — hiroaki_sengoku @ 10:10
2018年3月8日

配当金領収証の上限は 100万円、複数枚でも簡易書留で送付できるらしい 〜 祝 KLab(株) 初配当 (特別配当 9円) 〜

株式の配当金って、 (特に手続きしなければ) 郵便為替 (正確に言うと、 株式会社ゆうちょ銀行が発行する配当金領収証) を利用することがほとんどだと思いますが、 金額が大きくなっても郵便為替を使うのかなぁ? と日頃からギモンに思っていました。

「領収証」って名称ですが、為替証書の一種です。 株主届出印を押印して郵便局へ持っていくと換金できます (身分証明書の提示が必要)。

そんなある日、 KLab株式会社から 「定時株主総会招集ご通知」 と題する簡易書留郵便が届きました。

「ご通知」 を簡易書留で?
不審に思いつつ受け取って開封すると...
3枚の配当金領収証が出てきました。(@_@)

「配当金領収証」の上限って 100万円なんですね、初めて知りました。 配当金の額面は 255万円余り (税引き前は 320万円余り) なのに、 簡易書留 (5万円が上限) で送れるとは、 ちょっとビックリ。

送金できる金額は、 配当金領収証1通につき100万円までです。 100万円を超える送金は、 配当金領収証を発行することで行えますが、 追加する配当金領収証の枚数に応じた料金がかかります。

もっと金額が大きくなると、どうなるんだろう?

その企業の役職員の場合や、法人株主宛の場合は、 さすがに郵便為替ということはないと思うのですが、 個人株主宛の場合は、 どんなに高額でも (事前に手続きしない限り) 郵便為替を使うんですかねぇ?

- o -

18年前の 2000年7月末、 (株)ケイ・ラボラトリー (当時の社名) への出資金として 300万円を振り込みました。

シティバンク銀行 (現 SMBC信託銀行PRESTIA) 虎ノ門支店で、 虎の子の 300万円をおろしたものの、 目と鼻の先にある東京三菱銀行 (現 三菱東京UFJ銀行) 虎ノ門支店まで現金を持っていくのが怖くて (引ったくりに遭ったらどうしよう?)、 840円もの振込手数料を払って振り込んだのが思い出されます。

1年後にどうなってるか分からない会社 (実際、かなり危うい時期が何度かありました) にポンと 300万円もの大金を投じた当時の私 (← 株式会社日立製作所から転職したばかりの 33歳でお金持ってません) もビックリですが、 それから 18年たって、 出資した額以上の配当金 (税引き前 320万円余り) を出せる会社に成長したのもビックリです。

今回の配当金の総額は 3億3500万円だそうですが、 創業当時の資本金が 3億円でした。

正確に言うと創業時の私の出資分に対する今回の配当金は 162万円 (税引き後は 129万円ほど) です。 創業時 1株 5万円だったので、 私が出資した 300万円は 60株になったのですが、 2004年10月30日に 1株が 2株に分割、 2011年4月21日に 1株が 300株に分割、 2012年1月31日に 1株が 5株に分割しました。 つまり、 創業時の 1株が 3000株になったので、 私の 60株は現在の 18万株になったわけです。 今回の特別配当は 1株あたり 9円ですから、 9円 * 18万株=162万円ですね。

もっとも、 創業当時とは全く異なる事業の会社になってしまいましたが、 全く異なる会社に脱皮できたからこそ今の成長があるのでしょう。

初の配当おめでとうございます。 そして、 ありがとうございました。 株主の一人として、また創業者の一人として御礼申し上げます。

Filed under: 元CTO の日記 — hiroaki_sengoku @ 23:04
2017年8月11日

ZenFone3 で撮影した写真ファイル内の、位置情報が壊れている Exif データを修復するコードを書いてみた

昨年発表された ASUS のハイエンド スマホ ZenFone 3 Deluxe ZS570KL の購入時の OS は Android 6.0 Marshmallow だが、 この OS (UL-Z016-WW-4.12.40.1698) の標準のカメラ アプリには、 撮影した写真の位置情報が他のアプリで参照できないというバグがあった。

つまり、 カメラの設定で 「場所サービス」 を 「オン」 にすると、 撮影した場所 (GPS などの位置情報) を写真ファイルに付加する (Exif データ) が、 この位置情報に問題があって、 他のアプリで写真を見ても位置情報が表示されない。 例えば撮影した写真を Google フォトへアップロードしても、 撮影場所が表示されない

browsed with Gallery Application

この写真を Google フォトからダウンロードしてみれば、 Exif データ内に位置情報が保持されていることが分かるし、 アプリによってはこの位置情報を参照できるものもある。

例えば OS 標準の 「ギャラリー」 アプリで見ると、 位置情報が正しく保持されているように見える。 例えば、 御成町の交差点で撮影したこの写真を 「ギャラリー」 で見ると (右図 ⇒ ZenFone のスクリーンショット)、 場所が 「鎌倉市, 御成町」 と正しく表示される。

位置情報を正しく表示できるアプリがある以上、 バグではなく仕様 (Exif のバージョンの違い?) の可能性もある。 このとき私は、 この写真の位置情報を参照できないアプリは、 アプリ側にも問題があるのだろうと思ってしまった。 おそらく開発元でも同様の理由で、 このバグが見逃されてしまったのだろう。

More...
Filed under: Android,プログラミングと開発環境 — hiroaki_sengoku @ 22:09
2017年7月26日

カナダで Project Fi を使ってみた 〜 現地でプリペイドSIMを買うより安いし、同時に複数のスマホで使える

昨年に続いて今年も、 日本の梅雨 (と夏の暑さ) から逃れるべく バンクーバーに滞在した昨年の滞在では fido, WIND, Virgin のプリペイド SIM を買ったが、 今年 1月に米国を訪れたとき Project Fi を契約したので、 Project Fi の SIM をバンクーバーでも使ってみた。

Project Fi は米国外で使っても (米国内で使う場合と同じく) データ通信が $10/GB (1MB あたり 1セント) という、 リーズナブルかつシンプルな料金体系。 カナダだと、 何故かキャリアのプリペイド SIM を買うより安くつく。 カナダでは Telus や Bell の通信設備を使ってローミングサービスしているようだが、 Telus や Bell のプリペイド SIM よりも料金が安いのは何故なのか?

バンクーバーのいたるところにキャリアの店舗があるので、 適当に入ってみた店で、 「いま Google の Project Fi を使っているのですが、 Project Fi より安くなるプランありますか?」と (もちろん英語で) 聞いてみたら、 「Project Fi みたいに安いプランはありません!」 と即答されてしまった。(^^;

しかも、 Project Fi の大きな特徴として、 追加料金無しで Data-only SIM を 9枚まで追加できる。 妻のスマホに Data-only SIM を入れておけば、 Project Fi 一契約だけで (私と妻、二人分の) 用が足りてしまう。 Data-only SIM を 9枚入手すれば、 10人で共有できる?

なお、 Project Fi の (通話可能な) SIM は、 Pixel や Nexus に入れて使うことが推奨されているが、 ふつうのスマホに入れても通話やデータ通信が可能。 私はバンクーバー滞在中ずっと、 ZenFone 3 Deluxe (ZS570KL) に入れていた。 もちろん Pixel も持ってはいるのだが、 ZenFone のほうがメモリが多く、 また root 権限を取得済なのでいろいろ使い勝手が良い。

もちろん、 いくら安くても通信速度が遅ければ意味がないので、 その時は現地でプリペイド SIM を買うつもりでバンクーバーを訪れたのだが、 Project Fi でもしっかり LTE の電波をつかんでくれた。 昨年使った fido や Virgin のプリペイド SIM と比べてなんら遜色がない (WIND は 3G のみ)。 結局 27日間のバンクーバー滞在で、 一度も現地 SIM を買おうという気にはならなかった。

Project Fi のページで確認すると、 7月の 24日間のデータ通信量が 7.36GB (私が 2.62GB、妻が 4.75GB) だった。 ホテルの Wi-Fi が使い物にならないほど遅かったので、 ホテルに居るときまで Project Fi を使うことになり、 ふだん日本で 1ヶ月に使うデータ通信量より多くなってしまった。

最近のアプリ (特に facebook, twitter, Instagram など) は、 画像や動画をストレスなくどんどん表示するために、 勝手にどんどん通信するのでいかがなものかと思う (私はこの手の通信しまくりアプリは一切インストールしない)。 滞在したホテルは 「無料 Wi-Fi 完備」 をうたっていたが、 宿泊客がこの手の通信しまくりアプリを使うためか、 夕方以降は全くといっていいほど通信できなくなってしまっていた。

日ごとのデータ通信量は次のような感じ:

Project Fi Current cycle

日によってばらつきが大きいが、 平均 300MB くらい。 二人分なのでこんなもの? 7.364GB で $73.64 (約 8250円)。 国際電話の通話料が 21分間で $4.20 (約 470円)。 さらに Project Fi の基本料金 $20 と税金等 ($6 くらい?) がかかる。 まだ請求が来ていない (〆日は 8月2日) が、 合計 $104 くらい?

Project Fi で、 カナダから米国の toll free 番号に電話できるのか? と思いつつ 1-888 から始まる電話番号に電話したら繋がったので、 てっきり無料通話かと思って安心して長電話してしまった。 有料なら繋がらないで欲しい (>_<)。 繋がらなければ、 米国外からかけるときに使えるコレクトコール番号を使ったのに。
1分あたり 20セントという国際電話料金は、 ケータイの通話料の感覚からすると安いが、 Google Voice の感覚からすると高い。 ZenFone 3 に Project Fi の SIM を入れて通話したのだが、 Pixel (あるいは Nexus 5X) に入れて通話すれば無料だったのかも?
少なくともハングアウトで発信していれば無料だった。

昨年のバンクーバー滞在は 14日間と今年の半分の日数だったが、 fido の SIM に CA$89.60 (約 7900円)、 Virgin の SIM に CA$72.79 (約 6400円)、 WIND (現 Freedom Mobile) の SIM に CA$72.80 (約 6400円) 支払った。 もし今回 Project Fi がなくて昨年と同様にプリペイド SIM を買っていたら、 昨年の倍、4万円近くかかってしまったかもしれない。

カナダでは、 どのキャリアも 1GB 程度使おうとすると、CA$70 以上かかってしまう。 各キャリア横並びの料金で、 格安SIM 登場前の日本みたいな感じ。 キャリア間の競争がないのかも? どの月額プランを選ぶかでデータ通信の課金レートが変わってくるので、 最適な月額プランを選ぶのが難しい。

これに対し Project Fi は、 どんなに使っても 1MB あたり 1セントの単一課金レートなので分かりやすいし、 課金レートだけ比較すると、 カナダのどのキャリアよりも安い (例えば比較的安価な Virgin でも 2¢/MB)。

ただし Project Fi はプリペイド SIM ではなくポストペイ SIM なので、 米国に住所がないと契約が難しいかも? 私の場合はホテルの住所で契約することができた。 私は米国の銀行が発行したクレジットカードで払っているが、 日本のクレジットカードで契約できるかどうかは不明。

また、ポストペイなので当然だが、 使わなくても毎月基本料金 ($20 と税金等が $3 ほど) がかかる。 日本でもローミングサービスが利用できるが、 日本だと 1¢/MB という課金レートは (格安 SIM と比べると) 安いとは言えず、 常用には向かない。

日本に居るときは基本料金が無駄になるなぁ、 $23 というのは無駄に払う額としては安くないなぁ、 と思いつつ (今年 1月に) 契約したのだが、 実は Project Fi の契約は一時停止できる。

一時停止中は、 データ通信ができないのはもちろん、 通話の着信もできなくなるが、 いまどき通話なんてできなくても困らない。 Google Voice の番号は他にも持ってるし。 :-)

というわけで今年 3月1日に一時停止した。 停止/再開は Project Fi の Web ページからいつでも可能。 3ヶ月後に自動で再開してしまうが、 その直後に停止すれば基本料金はほとんどかからない。 3ヶ月後の 5月30日に自動再開したが、 6月4日に停止し、 バンクーバーを訪れる直前 6月27日に再開し、 日本に帰国してから停止した。 自動再開した直後に停止することさえ忘れなければ (自動再開を知らせるメールが届くので見落とさなければ大丈夫)、 使っていない期間の基本料金をほぼゼロにできる。

More...
Filed under: Android,SIM — hiroaki_sengoku @ 21:48
2017年4月19日

ZenFone3 Deluxe を Nougat 7.0 にしたらデータ通信できなくなった 〜 アンロックして Android 6 に戻す 〜

Nexus 5X が突然壊れて以来、 私はメインのスマホとして ZenFone 3 Deluxe ZS570KL を使っている。 購入時の OS は Android 6.0 Marshmallow だったが、 今年 3月にシステム更新のお知らせが表示されたので、 更新を行なったら Android 7.0 Nougat WW-5.14.44.1898 になった (3月26日)。

ところが!

この更新によって通話もデータ通信もできなくなってしまった。 LTE ネットワークへ接続できなくなっていて、 アンテナ・ピクトも表示されない (バツ印が付く)。 最初 SIM の接触不良を疑ったのだが、 SIM を入れ直しても接続できないまま。

更新作業は Wi-Fi のあるところ (自宅) で行なうわけで、 (モバイル) データ通信できなくても Wi-Fi でデータ通信できるから気付きにくい。 まさか更新で通話やデータ通信ができなくなってしまっているとは思わないので、 翌日 (3月27日) も気付かずに出かけてしまい、 出先でデータ通信できないことに初めて気付いて往生した。 出かける前に気付いていれば、 昔のスマホ (Nexus 5X とか) に SIM を入れ替えて使うこともできただろうに。

LTE で接続できないなら、 W-CDMA で接続してみてはどうだろう?と思ったので、 設定メニューで 「モバイルネットワーク」 を選び、 「有線ネットワークタイプ」 を 「2G/3G/4G」 から 「2G/3G」 へ変更 (つまり LTE 接続を抑制) してみた。 すると無事 3G (W-CDMA) ネットワークへ接続して (アンテナ・ピクトが表示されて) 通話ができるようになった。 しかし 3G でもデータ通信はできない。

もちろん、 SIM を別のスマホに入れると何の問題もなく通話もデータ通信もできるので、 SIM や設定の問題ではなく、 Nougat な ZS570KL の問題。

この時点では ZS570KL の root 権限を取得していなかった (まだブートローダをアンロックしていなかった) ので、 できることは限られている。 仕方ないので、 設定メニューの 「バックアップとリセット」 で 「データの初期化」 を行なってみると、 LTE へ接続できるようになった (3月28日)。

Android のバージョンを上げるたびに初期化を強要されてはかなわないと思いつつも、 いちおうこれで一件落着なのだが、 せっかく初期化したのだから、 この機会に (自分流にカスタマイズする前に) ブートローダをアンロックすることにした。

昨年 9月11日に発売開始した ZS570KL だが、 アンロックの方法を ASUS が公開したのは半年近くが経過した 2月16日になってから。 アンロックツール ZS570KL_UnlockTool_V1.1.zip が ASUS の Driver & Tools ページからダウンロードできる。

ASUS UnlockTool

アンロックを行なうとデータの初期化が行なわれてしまうので、 アンロックするならカスタマイズする前の方がいい。 本当は購入直後にアンロックするのが一番なのであるが、 当時はアンロックツールが (少なくとも公式には) 公開されていなかったので、 いままでアンロックせずに使い続けてきた次第。

ASUS のページからダウンロードした zip ファイルを展開して得られた UnlockTool-9.0.0.29_ZS570KL.apk を ZS570KL へインストールして実行すると、 警告画面 (→ 右図) が表示される。

アンロック (ロック解除) すると一切の保証が無くなるだけでなく、 ソフトウェアのアップデートも受けることができなくなると書いてある。 もちろん、 同ページから最新のソフトウェアをダウンロードすること自体は (ロック解除とは関係なく) 可能なので、 ここで言う 「ソフトウェアのアップデート」 とは、 あくまで自動で行なわれる更新のことだろう。

「押してデバイスのロック解除を行う」 を押すと、 再起動と初期化が行なわれる。 これでブートローダがアンロックされ、 ボリューム大ボタンを押しながら電源を入れると、 ブートローダ・モードへ入ることができる。

Nexus 等のブートローダ・モードは、 起動する OS を選べたりするが、 ZS570KL のブートローダ・モードは、 通常の起動画面 (ASUS ロゴ) と変わらず、 ブートローダ・モードに入ってるか外見上は区別できないので注意が必要。 ZS570KL と USB ケーブルでつないだ PC 上で fastboot コマンドを実行することで、 任意のブート・イメージ (TWRP など) を起動したり、 フラッシュメモリへ書込んだりすることが可能。

きちんと動作する ZS570KL 用の TWRP がちょうど公開されていた (3月19日, これ以前のバージョンは画面が逆になるなど、いろいろ不具合があった) ので、 ZS570KL をブートローダ・モードにした上で、 fastboot コマンドを使って起動してみる:

$ fastboot boot twrp-3.1.0-0-Z016D-20170319-N.img 
downloading 'boot.img'...
OKAY [  0.777s]
booting...
OKAY [  0.394s]
finished. total time: 1.171s
$ 

ちょっと使ってみた限りでは、 問題無く使えるようだ。 早く TWRP 公式ページからダウンロードできるようになることを望む。 TWRP を ZS570KL の recovery パーティションへ書込んでおくと、 ボリューム小ボタンを押しながら電源を入れることで、 (PC とつながなくても) TWRP を起動できる。

$ fastboot flash recovery twrp-3.1.0-0-Z016D-20170319-N.img 
target reported max download size of 536870912 bytes
sending 'recovery' (19980 KB)...
OKAY [  0.777s]
writing 'recovery'...
OKAY [  0.021s]
finished. total time: 0.797s
$ 

アンロックしたらついでに root 権限も取得したくなるのが人情なので、 SuperSU v2.79 SuperSU-v2.79-201612051815.zip を TWRP からインストールした。

と、 ここまでは順調だったが、 ある日 (4月4日) 出先で唐突にデータ通信できなくなった。 外出中にデータ通信できなくなると往生する (前述したように 3月27日に体験済み) ので、 こんなこともあろうかと ZS570KL には普段使っている IIJmio の nano SIM の他に、 非常用として Aeon Mobile の micro SIM も入れていた。 電話の着信は両方の SIM で可能 (DSDS, Dual SIM Dual Standby) で、 電話の発信とデータ通信は、 どちらの SIM で行なうか選ぶ方式。 データ通信を Aeon Mobile へ切り替えると、 無事データ通信できた。

なぜ Aeon Mobile ではデータ通信できるのに、 IIJmio ではできないのだろう? と思いつつも、 IIJmio でもアンテナ・ピクトは表示されるし、 IIJmio の電話番号に着信できるので、 そのまま使い続けた。

もちろん、 Aeon Mobile なら他の SIM でもデータ通信できるのか?とか、 micro/nano どちらの SIM トレイに入れるかでデータ通信の可否が変わるのか?とか、 いろいろ確認したいことはあり、 その都度いろんな実験をしている。 が、結論から言えばいずれも直接の関係は無さそうだった。 わざわざ他キャリアから Aeon Mobile へ MNP して新たに nano SIM を作ってみたがデータ通信できなかったし、 IIJmio や mineo の nano SIM にゲタを履かせて micro SIM トレイに入れてもデータ通信できるようにはならなかったし、 nano SIM トレイでも例えば香港3 の nano SIM なら (ローミングで) データ通信できた。

そんなある日 (4月13日)、 IIJmio の電話番号へ電話がかかってきたので出たら、 音声が互いに聞こえなかった。 驚いて Aeon Mobile で通話実験したら、 Aeon Mobile でも着信/発信ともに音声が聞こえなくなっていた。

少なくとも 4月11日までは普通に通話できていたので、 2日間の間に何があったか思い出そうとしたが全く心当たりがなかった。 ある日突然、通話できなくなるなんてことが起きると大変困る。

# 4月21日追記: TWRP で DSP をリストアすると発症するらしい。
# 音声が聞こえない症状については Nougat への更新とは無関係だった。

データ通信ができないのはモバイル・ルータを持ち歩くことで対処できるが、 通話ができないのでは話にならない。 直ちに ZS570KL の使用を中止し、 IIJmio SIM を Pixel に入れて Pixel を持ち歩くことにした。 Pixel は Band 19 をサポートしていないので docomo (の MVNO) では使いにくく、 (日本では) あまり使っていなかった。

というわけで ZS570KL の使用を中止したので、 さらに思いきった実験ができるようになった。 手始めに再度初期化してみることにした。 今回は root 権限を取得済なので、 バックアップ/リストアが手軽にできる。 初期化してデータ通信が復活すれば、 徐々に設定を変えていくことで原因の切り分けも可能だろう。

ところが!

初期化したのに IIJmio のデータ通信は復活しなかった (4月14日)。 通話も着信/発信はできるけど音声が伝わらない。 ZS570KL 単体の問題ではなくて、 LTE ネットワークとの相性も関係あるのか? ますます何が原因なのか分からなくなってしまった。

初期化ではなく Nougat をクリーン・インストールすれば、 通話もデータ通信も元通りできるようになるのかもしれない。 しかしいつ同じ症状が再発しないとも限らない。 突然データ通信できなくなったり、 音声が聞こえなくなったりするようでは安心して使えない。 しかもこの Nougat にはメニューボタンが使えないという (私にとっては) 重大なバグもある (本来は 「ASUS カスタマイズ設定」 でマルチタスクボタンの長押しでメニューを表示するように設定できるはずだが、 この Nougat では機能しない)。

通話やデータ通信ができなくなるのはおそらくバグだろうし、 メニューボタンのほうは明らかにバグ。 ついでに言うと、 カメラが EXIF に記録する位置情報が壊れていて、 他のソフト (Googleフォトを含む) で位置情報が認識できないというバグもある。 そのうち修正版が公開されるのだろうと思っていたが、 Android 7 Nougat WW-5.14.44.1898 が公開されてから一ヶ月がたつのに何も発表されない。 ASUS はバグを認識していないのか?

# 4月19日追記: WW-5.14.44.2096 が公開された。が、症状は変わらず (>_<)

事ここに至っては Nougat の使用を諦め、 Android 6 Marshmallow に戻すしかないと決断した。 といっても、 バージョンを戻す方法は (ASUS 公式には) 提供されていない。 が、 アンロックした ZS570KL であれば、 フラッシュメモリに直接書込めるので、 Marshmallow のイメージを書込めばよい。 つまりクリーン・インストール。

このブログを書いていて (いまごろ orz) 気付いたが、 上記 TWRP のダウンロードページ に、 「Downgrade_to_4.12.40.1698」 というディレクトリがあった。 Android 6 に戻したいという (私と同様な) 人が多いのだろう。

まず ASUS の Driver & Tools ページから Marshmallow の最後のバージョン WW-4.12.40.1698 の zip アーカイブをダウンロード。これを展開する:

senri:~/ZS570KL $ unzip UL-Z016-WW-4.12.40.1698-user.zip
Archive:  UL-Z016-WW-4.12.40.1698-user.zip
signed by SignApk
 extracting: system.patch.dat        
  inflating: META-INF/com/android/metadata  
  inflating: META-INF/com/google/android/update-binary  
  inflating: META-INF/com/google/android/updater-script  
  inflating: boot.img                
  inflating: file_contexts           
  inflating: firmware-update/NON-HLOS.bin  
  inflating: firmware-update/adspso.bin  
  inflating: firmware-update/cmnlib.mbn  
  inflating: firmware-update/cmnlib64.mbn  
  inflating: firmware-update/devcfg.mbn  
  inflating: firmware-update/emmc_appsboot.mbn  
  inflating: firmware-update/hyp.mbn  
  inflating: firmware-update/keymaster.mbn  
  inflating: firmware-update/mdtp.img  
  inflating: firmware-update/pmic.elf  
  inflating: firmware-update/rpm.mbn  
  inflating: firmware-update/tz.mbn  
  inflating: firmware-update/xbl.elf  
  inflating: logs/version            
  inflating: system.new.dat          
  inflating: system.transfer.list    
  inflating: META-INF/com/android/otacert  
  inflating: META-INF/MANIFEST.MF    
  inflating: META-INF/CERT.SF        
  inflating: META-INF/CERT.RSA       
senri:~/ZS570KL $ 

zip アーカイブの中の boot.img が android のブート・イメージ。 このファイルの中に、 Linux カーネルと initramfs が含まれている。 これを boot パーティションへ書込む:

senri:~/ZS570KL $ fastboot flash boot boot.img
target reported max download size of 536870912 bytes
sending 'boot' (13305 KB)...
OKAY [  0.524s]
writing 'boot'...
OKAY [  0.021s]
finished. total time: 0.545s
senri:~/ZS570KL $ 

zip アーカイブの中の firmware-update ディレクトリ下の 13個のファイルが、 ブートローダ等のファームウェア。

拡張子が *.bin のファイル (2個) はファイルシステムのイメージ。 NON-HLOS.bin は /firmware ディレクトリに、 adspso.bin は /dsp ディレクトリに、 それぞれ読み取り専用でマウントされる。 どちらも AMSS モデム関連のディレクトリ。 NON-HLOS.bin は modem パーティションへ、 adspso.bin は dsp パーティションへ、 それぞれ書込む:

senri:~/ZS570KL $ fastboot flash modem firmware-update/NON-HLOS.bin
target reported max download size of 536870912 bytes
sending 'modem' (81916 KB)...
OKAY [  3.166s]
writing 'modem'...
OKAY [  1.895s]
finished. total time: 5.060s
senri:~/ZS570KL $ fastboot flash dsp firmware-update/adspso.bin
target reported max download size of 536870912 bytes
sending 'dsp' (16384 KB)...
OKAY [  0.652s]
writing 'dsp'...
OKAY [  0.401s]
finished. total time: 1.053s
senri:~/ZS570KL $ 

拡張子 *.mbn は multi-boot binary ファイル (8個) で、 ARM の ELF (Executable and Linkable Format) オブジェクト。 keymaster.mbn と cmnlib.mbn は 32bit の共通ライブラリで、 keymaster は証明書の暗号鍵を管理する。 cmnlib64.mbn は 64bit の共通ライブラリ。

rpm.mbn と emmc_appsboot.mbn は 32bit ARM の ELF 実行ファイル。 rpm は 「resources & power manager」 を意味し、 プライマリ・ブートローダの役割を果たす。 emmc_appsboot はセカンダリ・ブートローダで、 このブートローダが android のカーネルを起動する。

残りの devcfg.mbn, hyp.mbn, tz.mbn は 64bit ARM の ELF 実行ファイル。 機能の詳細は分からないが、 devcfg は device config、 hyp は hypervisor、 tz は trust zone のことだと思われる。

詳細不明なファイルが多いが (^^; 以上 8個の *.mbn ファイルを、 それぞれ対応するパーティションへ (emmc_appsboot.mbn は aboot パーティションへ、 それ以外はファイル名と同じ名称のパーティションへ) 書込む:

senri:~/ZS570KL $ fastboot flash cmnlib firmware-update/cmnlib.mbn
target reported max download size of 536870912 bytes
sending 'cmnlib' (200 KB)...
OKAY [  0.029s]
writing 'cmnlib'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.060s
senri:~/ZS570KL $ fastboot flash cmnlib64 firmware-update/cmnlib64.mbn
target reported max download size of 536870912 bytes
sending 'cmnlib64' (254 KB)...
OKAY [  0.030s]
writing 'cmnlib64'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.061s
senri:~/ZS570KL $ fastboot flash devcfg firmware-update/devcfg.mbn
target reported max download size of 536870912 bytes
sending 'devcfg' (39 KB)...
OKAY [  0.040s]
writing 'devcfg'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.070s
senri:~/ZS570KL $ fastboot flash aboot firmware-update/emmc_appsboot.mbn
target reported max download size of 536870912 bytes
sending 'aboot' (749 KB)...
OKAY [  0.047s]
writing 'aboot'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.077s
senri:~/ZS570KL $ fastboot flash hyp firmware-update/hyp.mbn
target reported max download size of 536870912 bytes
sending 'hyp' (257 KB)...
OKAY [  0.038s]
writing 'hyp'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.069s
senri:~/ZS570KL $ fastboot flash keymaster firmware-update/keymaster.mbn
target reported max download size of 536870912 bytes
sending 'keymaster' (220 KB)...
OKAY [  0.032s]
writing 'keymaster'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.062s
senri:~/ZS570KL $ fastboot flash rpm firmware-update/rpm.mbn
target reported max download size of 536870912 bytes
sending 'rpm' (224 KB)...
OKAY [  0.039s]
writing 'rpm'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.069s
senri:~/ZS570KL $ fastboot flash tz firmware-update/tz.mbn
target reported max download size of 536870912 bytes
sending 'tz' (1600 KB)...
OKAY [  0.084s]
writing 'tz'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.114s
senri:~/ZS570KL $ 

拡張子 *.elf は 64bit ARM の ELF 実行ファイル (2個)。 *.mbn との違いは不明 (誰か教えて!)。 pmic.elf は power management IC のこと? xbl.elf は eXtended bootloader のことだろう。 それぞれ対応する同名のパーティションへ書込む:

senri:~/ZS570KL $ fastboot flash pmic firmware-update/pmic.elf
target reported max download size of 536870912 bytes
sending 'pmic' (41 KB)...
OKAY [  0.040s]
writing 'pmic'...
(bootloader) partition_need_check.
OKAY [  0.030s]
finished. total time: 0.070s
senri:~/ZS570KL $ fastboot flash xbl firmware-update/xbl.elf
target reported max download size of 536870912 bytes
sending 'xbl' (1780 KB)...
OKAY [  0.090s]
writing 'xbl'...
(bootloader) partition_need_check.
OKAY [  0.034s]
finished. total time: 0.124s
senri:~/ZS570KL $ 

mdtp.img は Mobile Device Theft Prevention のこと? ファイルの形式すら不明だが、 mdtp パーティションへ書込む:

senri:~/ZS570KL $ fastboot flash mdtp firmware-update/mdtp.img
target reported max download size of 536870912 bytes
sending 'mdtp' (8086 KB)...
OKAY [  0.324s]
writing 'mdtp'...
OKAY [  0.218s]
finished. total time: 0.542s
senri:~/ZS570KL $ 

以上で zip アーカイブの中の firmware-update ディレクトリ下の 13個のファイルの書き込みが完了した。

そして、 zip アーカイブの中の system.new.dat と system.transfer.list が、 android を起動したときに /system にマウントされる ext4 ファイルシステムのイメージ。 つまり Android OS の本体。 3.6GB ほどあり、 zip アーカイブの中の他のファイルと比べてケタ違いに大きい。

一般にファイルシステムのイメージは、 データが無い部分が散在する 「疎なファイル」(sparse file) になる。 フラッシュメモリに書込むときに、 データが無い 「0」 ばかりのブロックを書込むのは効率が悪いので、 「0」 なブロックを飛ばしたデータのファイル system.new.dat と、 そのデータをフラッシュメモリのどこへ書込むか指定するファイル system.transfer.list に分かれている。

残念なことに fastboot コマンドは system.transfer.list を扱えないので、 あらかじめ system.new.dat と system.transfer.list から ext4 ファイルシステムのイメージを作成しておいて fastboot コマンドに与える必要がある。 sdat2img コマンドを使うと、 system.new.dat と system.transfer.list から、 (疎な) イメージ system.img を作成できる:

senri:~/ZS570KL $ sdat2img system.transfer.list system.new.dat system.img
sdat2img binary - version: 1.0

Android Marshmallow 6.0 detected!

Copying 32770 blocks into position 0...
Copying 2 blocks into position 33009...
Copying 32016 blocks into position 33519...
Copying 2 blocks into position 65536...
Copying 32257 blocks into position 66046...
Copying 2 blocks into position 98304...
Copying 2 blocks into position 98545...
Copying 32016 blocks into position 99055...
Copying 2 blocks into position 131072...
Copying 32257 blocks into position 131582...
Copying 2 blocks into position 163840...
Copying 2 blocks into position 164081...
Copying 32016 blocks into position 164591...
Copying 2 blocks into position 196608...
Copying 32257 blocks into position 197118...
Copying 2 blocks into position 229376...
Copying 2 blocks into position 229617...
Copying 32016 blocks into position 230127...
Copying 2 blocks into position 262144...
Copying 32257 blocks into position 262654...
Copying 2 blocks into position 294912...
Copying 2 blocks into position 295153...
Copying 32016 blocks into position 295663...
Copying 2 blocks into position 327680...
Copying 32257 blocks into position 328190...
Copying 2 blocks into position 360448...
Copying 32257 blocks into position 360958...
Copying 2 blocks into position 393216...
Copying 32257 blocks into position 393726...
Copying 2 blocks into position 425984...
Copying 32257 blocks into position 426494...
Copying 2 blocks into position 458752...
Copying 32257 blocks into position 459262...
Copying 2 blocks into position 491520...
Copying 32257 blocks into position 492030...
Copying 2 blocks into position 524288...
Copying 32257 blocks into position 524798...
Copying 2 blocks into position 557056...
Copying 32257 blocks into position 557566...
Copying 2 blocks into position 589824...
Copying 32257 blocks into position 590334...
Copying 2 blocks into position 622592...
Copying 32257 blocks into position 623102...
Copying 2 blocks into position 655360...
Copying 32257 blocks into position 655870...
Copying 2 blocks into position 688128...
Copying 32257 blocks into position 688638...
Copying 2 blocks into position 720896...
Copying 32257 blocks into position 721406...
Copying 2 blocks into position 753664...
Copying 32257 blocks into position 754174...
Copying 2 blocks into position 786432...
Copying 32257 blocks into position 786942...
Copying 2 blocks into position 819200...
Copying 2 blocks into position 819441...
Copying 32016 blocks into position 819951...
Copying 2 blocks into position 851968...
Copying 32250 blocks into position 852478...
Copying 2 blocks into position 884736...
Copying 2 blocks into position 884977...
Copying 32016 blocks into position 885487...
Copying 2 blocks into position 917504...
Copying 2820 blocks into position 918014...
Copying 2 blocks into position 950272...
Copying 24508 blocks into position 950782...
Copying 7689 blocks into position 975291...
Skipping command zero...
Skipping command erase...
Done! Output image: ~/ZS570KL/system.img
senri:~/ZS570KL $ 

そして、作成した (疎な) system.img を system パーティションへ書込む。 fastboot コマンドは、 与えられた system.img が疎なファイルであることを認識し、 まず system パーティション全体を erase した後、 必要なブロックのみを ZS570KL へ転送して書込んでいる:

senri:~/ZS570KL $ fastboot flash system system.img
target reported max download size of 536870912 bytes
Invalid sparse file format at header magi
erasing 'system'...
OKAY [  0.002s]
sending sparse 'system' (513215 KB)...
OKAY [ 20.270s]
writing 'system'...
OKAY [  4.815s]
sending sparse 'system' (524224 KB)...
OKAY [ 20.871s]
writing 'system'...
OKAY [  5.201s]
sending sparse 'system' (523318 KB)...
OKAY [ 20.565s]
writing 'system'...
OKAY [  4.793s]
sending sparse 'system' (486869 KB)...
OKAY [ 19.371s]
writing 'system'...
OKAY [  4.688s]
sending sparse 'system' (513436 KB)...
OKAY [ 20.188s]
writing 'system'...
OKAY [  4.710s]
sending sparse 'system' (512989 KB)...
OKAY [ 20.225s]
writing 'system'...
OKAY [  4.705s]
sending sparse 'system' (506575 KB)...
OKAY [ 20.021s]
writing 'system'...
OKAY [ 22.541s]
sending sparse 'system' (67808 KB)...
OKAY [  2.684s]
writing 'system'...
OKAY [  0.475s]
finished. total time: 196.124s
senri:~/ZS570KL $ 

「header magi」 とは何ぞ? 東方より来たりし三賢者? と思ったら、 「header magic」 と表示しようとしてるのだけど、 fastboot コマンドの内部のバッファの大きさが 1 バイト足らなくて、 1 文字欠けてしまったらしい (まあ magic の語源は magi なので当たらずとも遠からじだが)。 system/core/libsparse/sparse_read.c を見ると、

static void verbose_error(bool verbose, int err, const char *fmt, ...)
{
	char *s = "";
	char *at = "";

…… (中略) ……

		size = vsnprintf(NULL, 0, fmt, argp);

…… (中略) ……

		at = malloc(size + 1);

…… (中略) ……

		vsnprintf(at, size, fmt, argp);

…… (中略) ……

		if (err == -EINVAL) {
			sparse_print_verbose("Invalid sparse file format%s%s\n", s, at);

…… (中略) ……

struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
{

…… (中略) ……

	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
		verbose_error(verbose, -EINVAL, "header magic");
		return NULL;
	}

などと書いてある。 せっかくメッセージの長さを調べて、 ちゃんと 1 バイト大きい (size + 1) バッファを確保しているのに、 vsnprintf の第2引数に (size + 1 ではなく) size を与えているために、 最後の 1 文字が欠けてしまうというバグ (>_<) どうしてこんな単純なバグが放置されているのか?

system/core/libsparse/sparse_format.h によると、 「sparse file format」 というファイル形式があって、 その magic (フォーマット識別子) は 0xed26ff3a であるらしい。 それなら何故 system.new.dat と system.transfer.list というファイル形式を使っているのだろう? sparse file format にすれば 1つのファイルで済むように思われるのだが...

max download size (前述の例だと 536870912 bytes) を超えるファイルを書込もうとすると、 fastboot はそのファイルが 「sparse file format」 であることを期待して、 magic が違うと 「Invalid sparse file format at header magic」 と表示する。

この場合、 通常のファイルとして読み込み直して、 内部で 「sparse file format」 へ変換するコード (sparse_read.c) になっている。 この場合、 そのファイルが疎か否かは関係なく、 単に 1ブロックが全て同じ値かどうか調べているので、 (疎でない) 通常のファイルを与えた場合も、 必要なブロックのみを転送して書込む仕様になっていた。

以上で、 Android 6.0 Marshmallow WW-4.12.40.1698 のクリーン・インストールが完了した (4月14日)。 数日間使っているが、全く何の問題も起きていない。 3月27日に問題が発覚してから 19日間、 さんざん苦しめられていたのが嘘のようだ。 もっと早く Marshmallow へ戻せばよかった。 OS のメジャーバージョンを上げるときは、 元に戻す方法を確認してからにすべきと改めて痛感した。

More...
Filed under: Android — hiroaki_sengoku @ 11:04
2016年8月3日

カナダで fido と WIND と Virgin のプリペイド SIM カードを買ってみた

8年ぶりのバンクーバー。 前回来た (2008年5月) 後にバンクーバーオリンピック (2010年) があって、 街がいろいろ変わってた。 オリンピックが終わっても不動産バブルはドンドン膨らみ続け、 巨大なビルがドンドン建てられている (が、テナントは入らず既にバブル崩壊状態?)。

でも、 それに負けず劣らず大きく変わったのがネット環境。 2008年5月当時はスマホがまだ一般的でなく (iPhone 3G の発表は 2008年6月)、 通信手段と言えばモデムだけ。 ホテルの部屋に LAN は無く、 公衆無線LAN も部屋には届かず、 かろうじていくつかのカフェで Wi-Fi が利用できたので、 わざわざカフェまで行ってネットにアクセスしていた (2008年なので Advanced W-ZERO3[es] で)。 滞在中ほとんどネットにアクセスできなかった (しかもホテルでさえネット無し!) なんて、 今から思うと考えられない。

ちなみに 2008年当時でも、 ワイキキなら多くのホテルは部屋まで LAN が来ていたし、 ホテルの部屋から公衆無線LAN でネットにアクセスすることもできた。 2008年くらいにもなるとモデムを使う羽目に陥ったことは皆無だったはず。 米国のホテルでモデムを使ったのは 2005年くらいが最後だったと思う。

8年前に泊まったホテルも、 今回のホテルも、 ロブソン通 (Robson St) に面していてすぐ近く。 8年前と違うのは周囲にケータイ屋が溢れている点。 ホテルを出てちょっと歩き回ってみるだけで、 fido, WIND, Virgin, Telus, Bell, Rogers など、 ほとんど全てのキャリアのお店を見つけることができた。 ホテルから歩いて最初に見つけた fido に入ってみる。

Fido Solutions

Fido Solutions は Rogers の子会社。 fido という名前の有名な犬がイタリアにいたらしい。 空襲の犠牲となった主人を14年間待ち続けたイタリアの忠犬フィド (イタリア語だと 「フィド」 だけど、 英語では 「ファイド」 と読むようだ)。 この犬にちなんで fido のロゴには犬小屋が描かれている。

fido のプリペイドSIM には、 月額 (By the Month) プラン ($15.75, $25.75, $30, $35, $45, $55, $60, $70) と従量 (By the Minute) プランと一日 (By the Day) プランがある。 もちろん 「$」 はカナダドル、以下同様。 月額プランのうち $15.75 〜 $35 のプランと、 一日プランは通話&SMS のためのプラン (例えば $35 の月額プランは 500分の通話が含まれていて SMS は無制限に使える) で、 データ通信に関しては従量プランと同じ。 したがってデータ通信がメインで SMS は使わない人 (= 私) にとっては、 $15.75 〜 $35 の月額プランや一日プランは (従量プランと比べて) メリットが無く、 従量プランあるいは $45 以上の月額プランが選択肢となる。

従量プラン$15.75$45$55$60$70
ローカル通話40¢/分30¢/分含300分含500分無制限無制限
長距離通話80¢/分70¢/分45¢/分45¢/分無制限無制限
夜間通話放題無し無し5pm-7am5pm-7am全日全日
国内SMS30¢/通無制限無制限無制限無制限無制限
国際SMS35¢/通無制限無制限無制限無制限無制限
データ通信要アドオン要アドオン400MB
5¢/MB
750MB
5¢/MB
1GB
2¢/MB
2GB
2¢/MB

もちろん「¢」はカナダセント、以下同様。 従量プランにはデータ通信が含まれていないので、 アドオンとして以下のデータパッケージを追加することが必須。 $45 以上の月額プランではこのアドオンを追加することはできない。

データ量月額料金超過料金
100MB$1015¢/MB
500MB$205¢/MB
1GB$305¢/MB

2週間の滞在で 1GB くらいは通信するだろうから、 選択肢としては $60 の月額プランか、 従量プランに 1GB のアドオンを追加するか、 の二択。 前者だと 1カナダドル=約80円なので 4800円くらい。 米国とかと比べると 1G で 5000円近くというのは割高感がある。 後者はそもそも 40¢〜80¢/分という通話料が高すぎ。 迷った末に $60 の月額プランを選んだ。

ところが、 支払う段階になってさらに 「Minimum Refill Amount Required $10.00」 が必要と言われる。 しかも消費税 12% が加わって、 しめて $78.40 (約 6300円)。 う〜ん、 これで 1GB しか使えないというのは高いなぁ。 「Refill Amount」 って言ってるけど、 残高 (balance) には加算されない。 預り金 (デポジット) みたいなもの? SIM 代と言ってくれたほうがスッキリするなぁ。

従量プランだと通話 1分 40¢ も課金される。 滞在中に残高を気にしながら電話するのはちょっとなぁ (残高が足らなくなってきたら refill しなきゃならない)、 と思ったので月額プランを選んでしまったのだけど、 多くても一日 5回くらいしか電話しなかったので、 2週間の滞在で合計 50分もいくかどうか。 最初に $20 くらい refill しておけば充分だった。 私の場合、 長距離通話の必要はないし、 SMS もほとんど使わない (ハングアウト等のチャットアプリを使えば済む)。

従量プランでデータ通信する場合は、 アドオンとしてデータパッケージを購入する。 1GB が $30 なので、 通話料が $20 とすれば合計で $50、 つまり従量プランのほうが $10 ほど安くなる。 滞在期間が短い場合や、 通話をあまりしない場合は、 従量プランを選択すべき。

SIM を Nexus 5X に入れてアクティベートしてもらうと、 無事 LTE が使えた。 fido は Rogers の通信設備を利用しているので LTE は Rogers と同じ Band 4 (1700/2100 MHz) と Band 7 (2600 MHz) そして現在展開中の Band 12 (700 MHz, Band 17 を内包する) が利用できる。 3G は Band II (1900 MHz) と Band V (850 MHz)。 いずれも Nexus 5X はサポートしている。

2週間の滞在で通信量を 1GB に収めようとするとかなり節約しなければならない。 Wi-Fi が使えるところでは Wi-Fi を使い、 ホテルでは Nexus 5 を Wi-Fi ルータとして使い (後述)、 できるだけデータ通信量を節約したのだけど、 ほとんど初めての土地 (8年前に来たけどほとんど忘れてた) だとどうしても Google Maps を見ることが多くなりがちで、 1日 100MB くらいは使ってしまう。 10日目くらいで通信量が 1GB を超えてしまった。

月額 $60 のプランだと、 1GB を超えたぶんは 1MB につき 2¢課金される。 仮に 1日に 100MB 使えば $2 になる。 たかが $2 と思うかもしれないが、 月額プランは残高ゼロのままで使えるのがメリットなのに、 課金が発生すると refill しなければならず面倒。

というわけで、 せっかく月額プランにしたのに、 結局 refill することになってしまった。 残高を気にして refill することになるなら、 最初から 40¢/分の通話料を払う従量プランにすればよかった。 なお、 従量プランに 1GB のデータパッケージを購入した場合は、 1GB を超えたぶんは 1MB につき 5¢課金されるので、 (1MB につき 2¢の) 月額プランより 2.5倍高く、 月額プランの意味がないとまでは言えない。

クレジットカード払いで (オンライン) refill する場合は、 カナダの住所でないとダメ。 というのも、 クレジットカード会社に登録している住所を入力する必要があるのだけど、 国名が 「Canada」 固定で変更できない (州もカナダの州から選ぶ選択式だし、 郵便番号はカナダ式でないとエラーになる)。 ところが、 クレジットカード会社に (その) 住所で認証を求めるらしい。 クレジットカード会社の判断次第というところもあるけど、 多くのクレジットカード会社は住所が異なっていると承認しない。

INTERAC Online を使う方法もあるらしいが、 Scotia Bank, RBC (Royal Bank), TD (Bank of Canada), BMO (Bank of Montreal) のいずれかに口座がないとダメ。

結局のところカナダ在住者でないかぎり refill カードを買うしかない、 ということのようだ。 これは fido に限らず他のキャリアでも同じ。 日本からの旅行者が refill カードを買うしかない、 というのは分からなくもないが、 お隣の米国から来た人でさえそうだというのだから、 いかがなものかと思う。 SIM の有効期限が切れてしまうから一刻も早く refill したいが、 それには何百キロも走ってカナダへ行ってくるしかない、 なんて笑えない話も米国にはあるようだ。

refill カードは買った日から 30日間しか有効でない (未確認) ので、 買いだめしておくわけにもいかない。 国によっては、 買ってから一年くらいは (何年も?) 有効な refill カードもあるのに、 カナダのキャリアはどうしてこう融通が効かないのだろう? ちなみに米国のキャリアも、 クレジットカード払いで refill する場合は SSN が必要だったりするので非居住者にはハードルが高いが、 幸いキャリア以外から refill カードを買うことができる (支払は PayPal が利用できる)。

More...
Filed under: SIM — hiroaki_sengoku @ 11:55
2015年11月24日

自分戦略 〜 なぜ成功できないのか?

昨年に続き、 今年も立命館大学で 2, 3回生の学生さん達に講義する機会を頂きました。 就職を目前にした学生さんが自分の進路を考えるにあたって、 社会人の話を聞いて参考にしようという趣旨のカリキュラムのようです。 私は 8人目、 ちょうど真ん中あたりだそうです。

「社会人の話」 というと実際にどのような仕事をしているかとかの、 会社視点の話が多くなりがちだと思いますし、 学生さん達もそういう話を期待していると思うのですが、 あいにく私は現在は働いていません (^^;)。 会社を辞めたのは 2011年ですが、 それまでの 11年間も取締役だったので、 いわゆるサラリーマン的な働きかたをしていたのは 15年以上も昔 (前世紀!) の話で、 すでに忘却の彼方です。

こんな状況で仕事の話はできるわけはなく、 ならばいっそと、 会社視点の話はヤメにして会社と対峙する一個人の視点からお話ししました。 会社で研究者・技術者としてバリバリ専門的な仕事をしている人たちの話とは毛色が違いすぎて、 戸惑っている学生さん達も多かったようですが (40代で働いていない、 というのは学生さんにとってそれなりのインパクトがあるようです)、 学生さん達がこれからの人生を考える上で多少なりとも参考になれば幸いです。

これから社会人になろうとする学生さん達がまずやるのは 「自分探し」 「自己分析」 で、 さらに自分のこれからの人生を切り拓くための戦略を考えたりするそうです。 「自分戦略」 をググると、 「自分のやりたいことを明確にし、それを実現するための手段を練ること」 などと出てきます。

私が学生の時、 自己分析したり戦略を練ったりしてたかなぁ? ぜんぜん思い出せません。 コンピュータにのめり込んでコンピュータを自作してしまったり、 授業そっちのけでソフトウェア開発のアルバイトに没頭したりした記憶はあるのですが、 将来のことなど考えたことは無かったように思います。

私が新卒で就職したのはバブル崩壊真っ只中の 1992年です。 就職氷河期 (1993年〜) に入る直前にギリギリ滑り込みました。 その後の世代と比べれば恵まれた時代だったのでしょう。 とはいえ、 就職でラクをしたぶん昨今ではバブル世代と揶揄されて、 厳しい社会人生活を余儀なくされている人も多いようですが。

そんな中で私が今でもラクできているのは何故なのか? 振り返ってみると、 将来のことを考えなかった割に、 実はとても 「戦略的」 な人生を歩んできたように思います。 「結果論」 とか 「後講釈」 のように見えるかもしれませんが (^^;)、 私の実例を 「単に運が良かっただけ」 と切り捨てるか、 「自分戦略」 として参考にすべき点があるか、 判断は読者のみなさんにお任せします。

私と違って、 いまの学生さん達は 「自己分析」 とかに余念がなく、 それはとても結構なことだと思うのですが、 「自分のやりたいこと」 ってそんなに明確ですか? 「なりたい自分」 と 「やりたいこと」 を混同してませんか? 私にとって 「研究者」 は 「なりたい」 職業でしたが、 研究は 「やりたいこと」 ではありませんでした。 (アルバイトの経験を除けば) まだ働いたこともないのに、 これからどんな仕事をしていきたいのか明確なはずはないと思うのです。 自己分析をすればするほど分からなくなる、 あたりが関の山じゃないでしょうか?

で、 実際の会社選びとなると、 (学生さん達の間で) 人気がある企業とか、 初任給 (or 平均給与) が高くて福利厚生がよい企業とか、 職場環境がよい企業とか、 ブラック企業は何としても避けなければとか、 「自分戦略」 というお題目とは裏腹に、 えらく近視眼的で、 自分の将来どころか数年先すら見通せていないのが現状ではないでしょうか?

自分戦略?

・ 「自分のやりたいことを明確にし、
   それを実現するための手段を練ること」
・ やりたいこと?
  - 将来も、やりたいことが変わらないのか?
  - 何が向いているかも定かでないのに
・ やりたいことをやって、その後は?
  - 体力が衰えて同じようには働けなくなる
・ とりあえず給料の高い会社へ就職
  - 福利厚生・職場環境がいいところ?
  - 社会貢献できるところ?
・ 将来どころか数年先すら見通せていない
3

初任給が高くてもその後の昇給ペースが遅ければ意味がないし、 平均が高くても自分の給料が平均以下なら意味がないし、 平均が低くても自分の給料が高ければ問題無いわけです。 職場環境だって、 会社の中での立場が変われば変わってきます。 新卒入社一年目の社員から見れば快適な職場環境が中堅社員から見ると最悪だったり、 極端な話、 誰が自分の上司になるかで大きく変わることもあります。

そもそも、 現在の 「やりたいこと」 を一生続けたいですか? みなさんが今から 10年前、小学生だった時に 「やりたい」 と思っていたことが、 今でも 「やりたいこと」 なのか考えてみれば明らかでしょう。 今から 10年後には、 今とは全然違うことが 「やりたい」 と思っているかもしれません。

「やりたいこと」 を一生続ける?

・ やってみたら実際は違った
  - プログラミングじゃなくてニーズの汲み上げ
  - 経験を積むと嗜好は変わる / 体力は落ちる
・ そもそも幸せな人生とは?
  - ネガティブにならないこと
  - ネガティブの根本にはいつもお金の問題
  - お金の召使いになってはいけない
・ 年功序列の崩壊
  - 「やりたいこと」 だけでは老後破綻一直線
  - みんなが年金を頼ると国家破綻一直線
5

それなら、 今 「やりたいこと」 よりも、 「やりたい」 ことを見つけた時に、 それを 「やれる」 自由度こそが重要ではないでしょうか?

社会人を何年もやっていれば、 予想できない偶発的なことがいろいろ起きます。 その中には自分のキャリアを大きく左右するような事象もあることでしょう。 その偶発的な事象を 「計画的に導くこと」 で、 自分のキャリアを良いものにしていこうという考え方が、 ジョン・D・クランボルツの 「計画的偶発性理論」 です。

成功者を見ると、 「あの人は運が良かった (だけ)」 と思ってしまい、 運に恵まれない自分は決して同じようにはなれないと、 諦めてしまう人が多いのだと思いますが、 運が良くてもその運を活かせなければ成功できません。 「運に恵まれない」 のではなく、 せっかく訪れたチャンスに気付いてないだけかもしれませんよ? 「チャンスは備えあるところに訪れる」 のです。

人生には分岐点が沢山あります。 たとえ八方塞がりに思えるドツボな状況に陥ってしまっていても、 その後の分岐点で最適な選択さえできれば、 ピンチが逆にチャンスになったりします。 ただしそれは、 分岐点に選択肢の幅が十分にあればの話です。

ところが大多数の人はこの 「選択肢」 を進んで捨ててしまいます。 「やりたいこと」 があっても、 いろいろ言い訳 (「時間がない」 「お金がない」 「自分の今の実力ではムリ」 等々...) して挑戦を躊躇います。 ぐずぐずしているうちに歳をとり、 選択肢がどんどん狭まっていくわけです。 なにごともやってみなきゃわからないと思うのですが、 やるまえから 「どうせダメに決まってる」 と諦めてしまっていては選択肢は広がらず、 成功を遠ざけてしまいます

また、 実際やってみてダメだったとしても、 果敢に挑戦することによって新たな選択肢が現れてきます。 まさに失敗は成功の元ですね。 「運が良い人」 というのはそうやって 「運を引き寄せる」 のです。

(戦略1)
選択肢を減らさない

・ 「自分のやりたいこと」 って明確じゃない
  - 「自分探し」 は時間の無駄
  - いろいろ学ぶと興味が持てることが変わってくる
  - やりたいことは手当たり次第やってみるべき
・ リスクを取らないリスク
  - 「みんなと同じ」 はリスク最大
  - 歳をとるごと選択肢は容赦なく減っていく
・ 別の道へ変更する選択肢は残しておく
  - 最悪の事態を常に想定する
・ 計画的偶発性理論
  - チャンスは備えあるところに訪れる
6

選択肢を減らさないようにして (戦略1) 運を引き寄せることができたら、 次に必要になるのが運を活かす能力です。 多くの業界において一番重要な能力は 「論理的に考える力」 でしょう。 ところが現代の学校教育は、 この 「考える力」 を伸ばす点においてあまり有効ではないようです。

より正確に言うと、 考える材料をたくさん提供している点においては有効なのですが、 それはあくまで元々考える習慣を持っていた学生さんに対してのみ言えることであって、 義務教育の課程で考える習慣を身につけることができなかった学生さんは、 高等教育において、 ますます考えなくなってしまうという悪循環に陥っています。

極めつけは、 会社選びで 「自分の気持ちを大切に」 などと言う人ですね。 自分の将来という一番合理的に考えなければならない時に、 それも高等教育をちゃんと受けた人が、 「自分の気持ち」 すなわち感情を優先するなんてアリエナイと思うのですが、 いったん考えなくなってしまった人たちは、 自分の気持ちに従うことをオカシイとは思えなくなってしまうようです。

誰でも (どんなに地頭のいい人でも) 一人では考える力を伸ばすことはできません。 なぜなら 「考えたつもり」 に陥って、 そこで思考停止してしまうからです。 自分の考えを他人に話したり書いたりして、 他人から何らかの反応 (批判とか) を受け取って初めて考えるきっかけが生まれるのです。 自分の考えを文章にしてみるだけでも、 自分がどのくらい考えているか (あるいは考えていないか) 分かる場合もあるでしょう。

たとえば、 「答がある問題を解いているだけでは考える力を伸ばせない」 と言ったりしますが、 なぜ 「答がある問題」 じゃダメなのか考えたことはありますか? 「現実の社会は答が無い問題ばかりだから」 という説明で満足してしまっていたとしたら要注意です。 現実社会の問題に答が無いからと言って、 答がある問題を解く練習が役に立たないことにはならないですよね? 中途半端な説明で満足してしまっているのは、 「分かったつもり」 そのものです。

だから、 授業を聞いているだけではダメなんです。 分かっているつもりで聞いていても、 いざそれを自分の言葉で表現しようとしたら、 ぜんぜん言葉が出てこないなんてことがよくあります。 学校教育で考える力が伸びない理由がここにあります (もともと考える力があった人は教えなくても伸びるのでここでは除外して考えます)。 言いたいことがあれば先生の話を遮ってでも発言し、 自分が 「考えたつもり」 に陥っていないか常に確認する必要があります。

幸い、何を言っても許されるのが学生の特権です。 社会人だとキャリアに終止符を打ってしまいかねない発言すら、 学生なら 「若いから」 ということで許されてしまいます。 どうかこの特権をフルに活用して、 「自分の考えを発言する」 習慣を、 学生のうちに身につけてください

はじめに

・ ぜひ、この場でしかできないことを
  - 聞くだけなら、私のブログを読むだけで充分
・ 分からないことはすぐ質問
  - あとでググればいいやなどと思わないように
・ 言いたいことがあればすぐ発言
  - うまく言おうとしないこと
  - 最初は誰だって下手くそ。場数を踏んで上手くなる
・ 空気を読んではいけない
  - こんな発言したら浮く?とか考えていてはダメ
1

ハワード・ガードナーの多重知能理論によれば、 人間は進化の過程で

  1. 言語的知能
  2. 論理数学的知能
  3. 音楽的知能
  4. 身体運動的知能
  5. 空間的知能
  6. 対人的知能
  7. 内省的知能
  8. 博物的知能

の8つの知能を発達させてきたとされます。

このうち、科学技術とりわけ IT 技術の進歩により 2, 4, 8 の知能はどんどん重要ではなくなりつつあります。 あと 10年ほどで大半の職業が消えるとか言われていますね。 また、現代社会においては (特定の職種を除けば) 3, 5 は、 さほど重要とは言えないでしょう。

残るは 1, 6, 7 ですが、 なかでも他の知能を伸ばすメタ知能ともいえる 「7. 内省的知能」 が一番重要でしょう。 すなわち、自分自身の 「心」 を理解してコントロールする能力です。 7 の能力を他者に対して発揮すれば 6 になりますし、 1 が重要なのは主に 6 のためですから、結局 7 が一番重要ということになります。

現代社会では何かというと 「自分の気持ち」 を重視する傾向 (自分の気持ち至上主義) がありますが、 自分の気持ちのままに生きれば、 内省する機会は失われてしまいます。 知能は繰り返し発揮することにより伸びるものですから、 内省する機会があまりなければ、 内省的知能が未発達のまま成長してしまうことになります。

(戦略2)
合理的に考える

・ 「お気持ち」 至上主義
  - 「いまのお気持ちは?」
  - 自分の気持ちを大切にしていてはダメ
・ もっと頭を使おう!
  - 使えば使うほど頭はよくなる
  - 授業を聞いているだけではダメ
・ 金融リテラシー = 「恐怖と欲望」 のコントロール
  - 内省的知能
失敗は成功の元
  - 成功できないのは 「失敗」 が少なすぎるから
  - リスクを負わなければ失敗も無い
7

運を引き寄せ (戦略1)、 運を活かす能力を磨いたら (戦略2)、 最後に必要になるのが 「敵」 を知ることです。 これから社会に出ていく学生さんが、 当の社会のことを知らなければ出だしから躓くのは必至です。

残念なことに、ここでも学校教育はあまり有効ではありません。 先生がたは社会の矛盾点・問題点を追求することがお好きなようです。 もちろん批判的精神は重要ですし、 社会のあるべき姿を論じ、 学問の力で社会をよりよい形へ変革していくことは大学の使命とも言えるでしょう。

しかし学生さんはその 「社会」 の中でこれから生き抜かなければならないのです。 すでに 「エスタブリッシュメント」 な先生がたなら、 社会を批判しているだけでも周囲から一目おかれますが、 体制の後ろ楯もなく、 何の権力も持たない学生さんがいきなり社会を批判したって、 返り討ちに遭うだけです。 学生さんに今必要なのは、 理想社会の戯言ではなく、 現実の矛盾だらけ欠陥だらけの社会が実際にどう動いているか、 そして丸腰でそういう社会に飛込んで生き抜く方法です。

言うまでもなく現代社会は資本主義社会です。 お金の仕組みを知らずに社会に出ていくことは、 カモがネギをしょって出ていくようなものだと思うのですが、 どうして先生がたはそれを止めようとしないのでしょう? 特にウブな理系の学生さんは、 「優れた技術は高い給料で報われるべき」 などと考え、 社会に出ても自身の技術を磨くことばかりに夢中になってしまいます。 こういう勘違いは実に悲劇的だと思うのですが...

仮にも最高学府で学んでいる学生さん達が、 「努力は報われる」 などといったような素朴な労働観をいまだに持っていることに、 あらためて驚かされます。 製造業 (あるいは農林漁業) が産業の中心だった時代ならば、 労働者一人一人の 「努力」 が生産量の多寡に反映したこともあったでしょう。 労働者にとっても自らの努力の結果が目に見えるので、 努力の方向を間違えることはありません。 生産量が多い労働者の稼ぎが増えるのは合理的ですし、 周囲の納得感を得ることも難しくありません。

しかし今や企業の利益は数多くの労働者の連係プレーによって生み出されています。 技術者だけではお金にはなりません。 努力の結果がすぐに利益の増大という形で見えることは稀で、 あさっての方向の努力をしてしまうことも珍しくありません。 誰がどのくらい利益に貢献しているかなんて (合理的に) 測定することは不可能でしょう。 誰もが納得する利益配分なんて、 それこそ人月で測るくらいしか無いのが実状です。

努力の方向がズレていて残業ばかりしている (傍目には一生懸命努力しているように見える) 人と、 的確な判断のもと効率的に仕事を進めて短時間で仕事を終える (傍目にはあまり努力していないように見える) 人と、 どちらを評価すべきでしょうか? もちろん後者の方が会社に貢献しているのですが、 前者を冷遇すると納得感が失われて社内に不満が溜ります。

つまり、 資本主義が言うように、 給料は労働の対価ではなく、 単に労働力の再生産 (つまり労働者が次の日も納得して働いてくれること) に必要な 「コスト」 に過ぎません。 労働者の技術の優劣と、給料の高低との間に、直接の関係はありません。 もちろんモチベーション向上のために関連性を 「演出」 することはありますが、 結局のところ給料は多くの人が納得する 「相場感」 で決まってくるのです。 努力が報われないなんて、 そんな社会は間違っている!と思いたい気持ちは重々分かりますが、 実際の社会はそういう仕組みなのですから否定したところで始まりません。

努力を認めてもらいたければ、 「努力は報われるべきだ」 なんて受け身なことを言ってないで、 戦略的にアピールして昇給を勝ち取るべきです。 その際、 「労働力を売らない自由」 (後述) があると昇給交渉をより有利に進めることができるでしょう。

(戦略3)
(社会に出る前に) 社会を理解する

・ 学校では社会の問題点ばかりを学ぶ
  - 社会を変えようとする人ばかり量産している
  - 学問の力で社会を変革する、それは大事だけど…
・ 現実の社会=お金の仕組み
  - お金の仕組みを理解しないと搾取される人生に
  - 社会を知らない学生さんは 「カモネギ」
・ みんなの勘違い
  - 優れた技術には高い給料で報いるべき?
  - 給料は労働の対価ではない!
  - 搾取 ≠ ブラック企業
・ 労働分配率が上がっても消費へ回してしまう
  - 搾取され続け、一生 (嫌々) 働き続ける羽目に
8

学生さんにとって、 とりわけ喫緊の課題は資本主義社会における 「搾取」 の構造です。 現代における 「搾取」 を正しく理解しない限り、 搾取の餌食になってしまいます。 社会を変革するどころか、 その遥か手前で力尽きてしまうことでしょう。

搾取というとすぐブラック企業を思い浮かべる人が多いと思いますが、 ブラックのレッテルを貼られた企業の業績があっと言う間に悪化したように、 給料を安く抑えようとする手法 (サービス残業とか名ばかり管理職とか) は現代社会においてはあまり賢いやり方とは言えません。 本当の、そして最も警戒すべきは、 搾取と気付かれないだけでなく、 むしろ進んで搾取されることを多くの人が望むような搾取です。

資本主義社会において労働者の立場が弱いのは、 自身の労働力を売らない自由が無い (辞めると生活できなくなる) からです。 通常の売買契約でも売り手が (安い価格でも) 売らざるを得ない (閉店時間間際の生鮮食料品売場とかが該当しますね) のであれば (足元を見られて) 損をするように、 労働力を売らないという選択肢が無ければ、 労働条件に不満があっても受け入れざるを得ません。

したがって、 半年くらいは働かなくても生活できる程度の貯金 (数百万円?) さえあれば、 労働者の立場は劇的に改善するはずです。 しかも、 昨今は給料を安く抑えようとすると、 すぐ 「ブラック」 のレッテルを貼られてしまいますから、 給料が生活費ギリギリということはあまり無く、 本来ならば貯金にまわす余裕があるはずです。

ところが、 給料が上がっても同じくらい支出も増えてしまってほとんど貯金できない、 という人がほとんどのようです。 給料半年分どころか、100万円の貯金すら無い人が多いとか。 いったい何にそんなにお金を使っているのでしょうか? 初任給が 300万円/年だった人が 400万円/年に昇給して、 何年たっても 100万円すら貯金できないというのは意味不明です。

お金をついつい使ってしまう人に是非考えてほしいのは、 資本主義の世の中では、 いかに消費者にお金を使ってもらうか必死に考えている人が大勢いるってことです。 ほとんど全ての場合において、 お金を使いたいと自発的に消費者が思っているのではなくて、 お金を使わせたいとあの手この手で誘惑している人がいて、 消費者はまんまとその策略に乗せられてしまっているだけなのです。

お金を使う決断をする前に、 はたしてその金額が自分の身の丈に合っているか考えてみるべきでしょう。 給料が少なかったときはお金を使わずに我慢できていたことであれば、 それは決して必需品ではありませんよね? 知能が先天的なものか後天的なものか本当のところはよく分かりませんが、 たとえ先天的なものが支配的であったとしても、 マシュマロを我慢する自制心は鍛えるべきだと思います。 「子どもでも大人でも自制心を育むことは可能」なのですから。

支出を増やしてしまうこと以上に問題なのが借金することです。 年収の 5倍もの借金をかかえて、 借金を返すためだけに働いているような人もたくさんいます。 まさに銀行の 「奴隷」 ですね。 なぜ身の丈を大きく超えるような金額の住宅を買わせようとするのでしょうか? 言うまでもなく巨額のローンを組ませて銀行が儲けるためです。

労働者が生み出した剰余価値を奪うことによって、 労働者を労働者階級に固定化することを搾取と定義するなら、 こうした貯金させない社会の仕組みこそが現代の搾取と呼ぶにふさわしいと思います。

(戦略3)
お金の仕組み

・ 給料とは労働力の再生産のためのコスト
  - 「努力は報われる」 はプロパガンダ
  - 報われるのはリスクを負った人のみ
・ 生産者になる前に一人前の消費者に
  - 小学生のころから消費の仕方を学ぶ
  - 時給アルバイトは時間の切り売り。生産ではない
・ 消費の誘惑に満ち満ちている = 搾取の構造
  - なぜ銀行は住宅ローンを勧めるのか?
  - なぜ保険会社は保険を勧めるのか?
・ 資本主義=労働者から生産手段を分離
  - 生産手段 (知能) を取り戻せ!
9

以上 3点が、 私が意識せずに実践していた 「自分戦略」 です。 意識していなかったくらいですから大したこととは思っていなかったのですが、 ネット時代になって貯蓄額の世帯分布などを手軽に参照できるようになった昨今、 私と同じくらいの給料をもらっていたはずの人たちにおいても、 大した貯金があるわけではないことを知り、 驚いている次第です。

最初の 100万円を貯めるだけでも労働者としての立場は格段に向上するわけで、 強くなった立場を背景に給料交渉を有利に進めて自身の労働力の価格をつり上げ、 加速度的に貯蓄額を増やしていけば、 労働者階級を脱出する (= 働かなくても当面の生活には困らないし、 やりたい仕事を選べる) ことも現実的な目標となるはずです。 それなのに、 なぜ大多数の人が同様の戦略をとることができないのでしょうか?

「戦略1」 (選択肢を減らさない) は、 自分の適性を知るための戦略です。 世の中は 「自己分析」 が流行りですが、 ちゃんとしたコンサルタントとかに相談するならともかく、 素人の学生さんが一人でやってマトモな分析ができるはずはありませんよね?

「自分のことは自分が一番分かっている」 という思い込みが、 「戦略1」 を実践する障害になっているのではないでしょうか? 実際は、 自己評価より他人からの評価のほうが正しかったりするわけです。 こと自分のことになると、 心理的な防衛本能が働いて真実の姿が見えにくくなります。 自分のことを知るには、 あれこれ考えるより、 やりたいと思うことを実地にやってみるべきです。 とことんやってみれば自分の能力の限界がどのあたりにあるかも、 見えてくることでしょう。

「戦略2」 (合理的に考える) は、 自分の知能を向上させるための戦略です。 小学校から大学まで 16年 (大学院までいけば 18年も!) 学ぶのに、 考える機会がほとんど無いことに驚かされます。 学んでばかりいるから考える機会が失われているのかもしれません。 まさに 「学びて思わざれば則ち罔し」 ですね。

「考える」 という言葉は誰もが気軽に使いますが、 実際のところどこまで考えているでしょうか? ほとんどの場合、 考えているのではなくて悩んでいるだけだったりします。 自分の考えを主張している時ですら、 他の人の意見の受け売りに過ぎなかったりしますし、 そもそも 「自分の考え」 を表明する機会ってほとんど無いように思います。 facebook だって、 「今どんな気持ち?」 ですし。 ふつーに生活している限り、 気持ちを聞かれることはあっても、 考えを聞かれることは皆無ではないでしょうか?

映画 「マーガレット・サッチャー 鉄の女の涙」 で、 「あなたの本当のお気持ちは?」 と聞かれたときのサッチャーの答がふるってます:

なに
私の気持ちってどういうことかしら
最近は考えより気持ちね
どんな気持ち
なんだか気持ち悪いわ
すみません我々の気持ちとしては
これは今の時代の大きな問題ですよ
人々は感情にばかり左右されて
考えやアイディアなんかはどうでもよくなって
本当に面白いのは
考えとかアイディアなのに
私が何を考えているか聞いて

このあと、 例の有名な 「自分の考えが言葉になる、言葉が行動になる、行動が...」 が続くのですが、 そこでは 「考え」 と 「気持ち」 が混同されていて、 私は何だか気持ち悪く感じます。 前段 (上記引用部分) と 後段 (自分の考えが言葉になる...) は、 同じ人の言葉とは思えません。 まあ、後段は 「父の口癖だった」 のかもしれませんが。

斯くして考える習慣がある人はどんどん知能を向上させていき、 習慣が無い人はどんどん差を付けられていく、 という二極化が進んでしまっているのでしょう。 経済的な格差ばかり注目される昨今ですが、 本当の格差は 「知能」 の格差であって、 経済的な格差はその派生物に過ぎません。

そして 「戦略3」 (社会を理解する) は、 金融リテラシーを身につけるための戦略です。 社会に関する誤った常識が、 社会の本質を理解する妨げになります。 お金を使わせたいと誘惑する側が、 誤った知識を広めようとしているのも、 妨げになっていますね。

誤った知識とは、 例えば 「賃貸より購入の方が良い」 といったようなものです。 その 「知識」 を広めようとしている人 (マンション開発業者とか不動産屋とか銀行とか) が、 その知識が広まることで利益を得ているならば疑ってかかるべきでしょう。 「毎月家賃を払い続けても永遠に家は自分のものにならないが、 ローンなら完済すれば家が自分のものになる」 などと言われて騙されてしまう人が沢山います。

家賃を払う人には安い家に引っ越して負担を減らす自由がありますが、 ローンを抱えている人には負担を軽減する自由はありません。 つまり選択肢を減らしてしまっているわけです。 したがって、 「購入 VS 賃貸」 という比較はナンセンスです。

「戦略3」 を実践する最大の障害が、 お金にまつわる感情です。 ほとんどの人が、 「お金がなくなる恐怖」 と 「お金がもっと欲しいという欲望」 の二つの感情に支配されていて、 お金について合理的に考える余裕が無くなっています。 これでは金融リテラシーを身につけることはできません。

「お金になんか興味はない」 「仕事が好きだから働いているんだ」 と言う人もいますが、 そういう人は今の仕事が好きでなくなったら、 働くのを辞めるのでしょうか? 辞めても生活に不自由しないのであれば問題ありませんが、 多くの人はそうではないはずです。 つまり 「興味がない」のではなくて、 お金について本当は考えなければならないのに、 それを直視できていないだけです。 心理学で言うところの 「否認」 ですね。 「仕事が好きだから働いているんだ」 は 「合理化」 (防衛機制の一つ) でしょう。

なぜ戦略的に動けないか?

・ 戦略1 ⇒ 自分の適性を知る
  - 自分のことは (他人のことより) 知るのが困難
  - 心理的な防衛機制が働く
・ 戦略2 ⇒ 論理的に考える力を鍛える
  - 直観や気持ちを優先してしまう
  - 自分の考えを発表する機会が皆無
・ 戦略3 ⇒ 社会の本質を見抜く
  - 「常識」 に囚われてしまう
  - 大人たちが 「カモネギ」 を狙ってる
10

以上のように、 この 3点の戦略には、 それぞれ実践を難しくしている要因がありそうです。 ではなぜ私は実践できたのか?

やりたいことは先送りにせず、 とことんやってみる性格だったのが大きいように思います。 当時は計画的偶発性理論など知らなかったのですが、 何かやりたいと思うより先に行動していました。 やりたいと意識しないうちに、 気が付くと既にやっているみたいな感じで。 また、 知らないことを見つけるとすぐ首を突っ込んでいました。 コンピュータ分野に限らず、 数学、物理学、哲学、社会学、果てはテニスに至るまで、 自分に向いてるかどうかなんて考えずに、 やれるところまでやってみる、 ということを繰り返していました。 戦略1 (選択肢を減らさない) ですね。

中学校 (1979年) の部活動でマイコン部 (当時 PC は 「マイコン」 と呼ばれていました) に入ったのですが、 そのオリエンテーションで BASICっていう言語を使ってプログラミングをするという話を聞いて、 その日のうちに都心の一番大きい本屋へ出かけていって、 当時一冊しかなかった BASIC の入門書 「BASICで広がる世界」 (CQ出版社, 1979年発行) を買って一気に読み、 次の日にはもうプログラムを書き始めていたほどです。

子供のころから好奇心旺盛だった私ですが、 実を言うと考えることは不得手でした。 小学生の時はよく 「分かったつもり」 に陥っていました。 学校のテストで答案によくデタラメを書いたものです。 しかもデタラメを書いているという意識はなく、 自分は分かっていると思い込んで、 正しい答を書いているつもりだったのです。 中学一年生のとき数学のテストで赤点 (30点未満) をとったこともあります。

ところが中学生になって、 とても優秀な同級生が現れたのです。 彼は、一を聞けば十を理解する。 あまりに早く 「分かった」 というので、 信じられずに残りの九を説明しようとすると、 先回りして答えられてしまったほど。 そんな彼が 「分からない」 を連発する。 つまり 「分かった」 と言うのも早いが、 「分からない」 と言うのもとても早かったのです。

そんな彼を見て、 私は 「分からない」 と言えるのはカッコイイことなんだと思うようになりました。 なんとかして自分も、 「分からない」 と言えるようになりたい、 と思ったのでした。 いま思えば、 これが私の人生の転機だったのかもしれません。 戦略2 (合理的に考える) ですね。

以来、 考えるのが好きになり、 大学受験に失敗したのをいいことに、 浪人中の一年間に弁証法とか資本論とかの難しそうな本 (といっても初学者向けの教科書ですが) を手当たり次第に読みまくりました。 難しそうなテーマであればあるほどチャレンジしたくなったのです。 これが資本主義についてもっと知りたいと思うきっかけになりました。 戦略3 (社会を理解する) ですね。 実はこの時、 人文系の本を読みすぎたせいで、 文系へ転向しようかと思ったほどです。 プログラミングの方が好きだったので思い止まり、 結局一年目と同じ情報工学科を再び受験したのですが。

今から思うと、 お金を稼ぐ前に社会の勉強を始めたのは幸いでした。 浪人中はお金が無かったので、 消費したいという欲求が全く起きなかったし、 資本主義について学び始めた後は、 「搾取の構造」 を理解したので消費の誘惑に負けなくなったのです。 収入が増えても消費は増えなかったので、 収入の増分を丸々貯金することができました。 もし現役で大学に合格していたら、 順序が逆になって、 勉強を始める前にアルバイトでお金を手にして、 搾取の罠にはまっていたかもしれません。

いっぽう、 大学生のときパソコン通信や JUNET を知って (1989年)、 これを駆使すれば個人でも有名になれると思ってからは、 どうやって自分を売り込めばいいか考えるようになりました。 企業にとってブランドが最重要であるように、 個人にとってもブランドが資産になると考えたのです。 合理的に考えれば当たり前のことですよね。

もちろん最初は何をすれば自分を売り込めるのか見当もつかなかったのですが、 いろいろ試行錯誤しているうちに、 それなりに注目を集めることもできるようになり、 初めて書いたオープンソース・ソフトウェアである stone は、 そこそこ有名になりました。 私は 「stone の開発者」 として多くのかたに覚えていただけるようになったのです。 stone は私にとって最大の 「資産」 (収入をもたらす源) と言っても過言ではないでしょう。 無料で配布しているソフトウェアが最大の資産ってのが面白いですね。

浪人生の時に資本論をかじったこともあって、 大学生になってアルバイトで数十万円の貯金ができると、 すぐ株の売買を始めました (当時はオンライン取引というとファミコン・トレードだけで、 電話をかけて口頭で売買注文を出したり、 証券会社の窓口で注文したりしていました)。 当時 NTT が株式を公開 (1987年2月9日) したり、 ブラック・マンデー (1987年10月19日) が起ったりと、 世間的に株が注目を集めていたのも、 株の売買を始めようと思ったきっかけの一つだったのでしょう。

もちろん単位株での売買で大した金額ではなかったのですが、 学生にとっては大金です。 損を出すまいと必死になって経済の勉強をしました。 「お金がなくなる恐怖」 が勉強の原動力になったのです。 経済に対する理解が深まれば会社の経営に興味が湧いてくるのは必然で、 2000年に KLab(株) (設立当時の社名は (株)ケイ・ラボラトリー) 会社設立の計画を聞いたとき、 迷わず飛び付きました。

仮に起業が頓挫しても数年くらいは生活に困らない程度の貯金がありましたし、 当時も技術者は不足していましたから、 ここがダメでも再チャレンジの余地は充分あるだろうと思っていたので、 大企業の正社員という安定した 「地位」 を捨ててベンチャーに飛込むことに、 何の躊躇いもありませんでした。 まさに、 備えがあったからこそチャンスが訪れたのです。

私の自分戦略

・ やりたいことは先送りにせず、とことんやってみる
  - 中学1年の時以来、パソコンにのめり込む
  - 大学に入ってパソコンを 「自作」
  - 大学院生の時、個人事業主としてソフトウェア開発
  - 日立に就職後、本業そっちのけでネットインフラ整備
・ 自分ブランド
  - 大学で JUNET を知って (1989年) 以来、試行錯誤
  - stone の開発・発表 (1995年~)
・ 金融リテラシー
  - 小学生の時から株に興味を持ち、大学生の時から売買
  - 「金持ち父さん 貧乏父さん」 (2000年)
11

それはベンチャーと技術者との出会いでした。 それまでベンチャーを興そうという人と技術者とでは興味の対象が異なり、 両者の出会いはかなり稀な事象でした。 2000年当時は、 創業メンバに アイディアマン, 技術者, マーケッタ という多様な顔触れが揃うベンチャーは珍しかったのです。 この会社が現在に至るまで発展し続けているのは、 創業メンバの多様性にこそあったのだと思います。 この偶然の出会いを 「単に運が良かっただけ」 と思うか、 それとも 「戦略的に計画された偶発的事象」 ととらえるか、 判断は読者のみなさんにお任せします。

Filed under: 元CTO の日記,自己啓発 — hiroaki_sengoku @ 09:36
2015年10月6日

米国 BYOD プリペイド SIM の GoSmart を使ってみた 〜 $35 で 30日間 かけ放題、4G データ 2.5GB 〜

私は米国 AT&T のプリペイド SIM を (毎年 refill して) 維持している。 日本に居るときは料金プランを月額料金が無料で従量制の 「10¢ / minute」プランにして残高が減るのを防ぎ、 訪米する直前に 「$60 Monthly」プランに切り替えて、 $60 で 30日間 4GB までのデータ通信ができるようにしている (通話・SMS は無制限)。

ところが今回初めて 30日間を超えて 35日間米国に滞在したので、 最後の 5日間ほどデータ通信ができなくなってしまった (通話は 「10¢ / minute」プランでもできる)。 もちろん、 二ヶ月続けて 「$60 Monthly」 を契約すればデータ通信できるのだけど、 たった 5日間のために $60 も払うのはモッタイナイ。 そこで、 最近米国で流行っている BYOD (Bring Your Own Device) SIM を買ってみることにした。

BYOD SIM を買ってから気付いたが、 訪米の 20日ほど前に AT&T の 「$45 Monthly」プラン (1.5GB までのデータ通信が可能) を契約し米国滞在中に (一度だけ) 自動更新すれば、 未使用データ通信量は一度だけ Rollover されるので、 二ヶ月分の計 3GB が利用できて、 二ヶ月分の料金 $90 で済む。
BYOD SIM で 500MB 以上のデータ通信を行なおうとすると月単位の料金プランを契約する必要があって、 最低でも (SIM 代金と月額料金の合計で) $40 くらいはかかるので、 AT&T 「$60 Monthly」 + BYOD で合計 $100 になってしまう。 AT&T 「$45 Monthly」 + BYOD なら合計 $85 だが、 1.5GB + BYOD だとちょっと心許無く、 $5 の差なら AT&T の 「$45 Monthly」* 2ヶ月 3GB のほうが好ましい。
とはいえ、 一度 BYOD SIM を使ってみたかったということで... (^^;)

(注) 後述するように BYOD SIM は今まさに価格競争が起きている。 近いうちに (現時点ですでに?) 結論は変わってくるかもしれない。 すなわち、プリペイド SIM は refill して維持するよりも、 訪米ごとに使い捨てたほうがいい、ということになってしまうかも? (もちろん、訪米頻度に依存する)

日本では BYOD は、 「企業における私物端末の持ち込み」 という意味に限定されて使われているが、 米国だと持ち込み先は 「企業」 に限らず、 「年間契約が不要なプリペイド・プランへ自分の端末を持ち込む」 という意味にも使われているらしい。

もちろん米国では何年も前から、 プリペイド SIM を単体で購入し、 (日本から持ち込んだ) SIM ロック・フリー スマホに入れて使うことはできた。 でも、 AT&T や T-Mobile などのショップで (英語を喋って) 購入する必要があり、 英語がニガテだとハードルが高い。 しかも ID (身分証明) が必要 (私の場合、 米国発行のクレジットカードを提示したらそれ以上は求められなかったが、 適当なものが無ければパスポートが必要かも?)。

それが昨今の BYOD SIM だと、 スーパーマーケットで日用品を買うのと同じような感覚で買えてしまう。 英語を喋る必要もなく、 単に商品棚から SIM を手にとって買物カゴに放り込み、 レジでお金を払うだけ。 まさにバナナを買うのと同じ感覚でプリペイド SIM が買えてしまう。 従来のプリペイド SIM のように refill して維持してもいいが、 これだけ手軽に買えるなら訪米ごとに使い捨てでもいい。

ただし、 Walmart などの (万引き防止策に熱心な?) スーパーマーケットだと、 (万引きされやすい) 一部の商品は什器 (商品棚) に固定されていて、 店員に (英語で) 頼まないと手に取ることすらできない。 気軽に商品を手に取れてこそのスーパーマーケットだと思うのだけど、 商品を引っくり返して裏面の説明を読むためだけに、 わざわざ店員を呼ぶのはいかにも億劫。 お客の買う気を減退させてどうする?と思うのだけど、 それだけ万引き被害が甚大ということなのかなぁ? そもそも SIM などの商品はギフトカードとかと同様、 レジで有効化しないと使用できないはずなので、 万引きの対象にならないんじゃなかったのか? とか思ったり (SIM にも 「Not active until scanned at register」 と書いてある)。

BYOD SIMs at Target

幸い、私が GoSmart BYOD SIM を買った TARGET (パッケージには $39.95 と書いてあるのに、 なぜか 4セント高い値段で売っていた) では、 どの SIM も自由に手にとって見ることができたので、 裏面の説明をじっくり読んで、 比較検討してから買うことができた (もちろん、TARGET で扱ってる SIM だけでなく、 Longs Drugs など他の店で扱ってる SIM も比較検討した)。

とはいえ、 裏面の説明には肝心なことが書いてない。 買って本当に誰でも (非居住者でも) SIM の activate 手続きを WWW だけで完結できるのか? activate 手続きの途中で身分証明 (SSN の入力とか) や (米国発行の) クレジットカードの提示を求められたりしないのか? 追加費用が発生したりしないのか? activate するには使用するケータイの IMEI を登録する必要があると聞くけど、 その登録したケータイ以外のケータイでも使えるのか? など不安の種は尽きない (→ 全部杞憂だった, 後述)。 まあ SIM 自体は $5 もしないので ($39.95 のパッケージに $35 の refill カードが含まれているので、 SIM 単体だと差し引き $4.95)、 ダメでもいいやくらいの気持ちで買ってみた。

GoSmart というのは T-Mobile の低価格プリペイド用ブランド。 速度を 3G に抑えることで料金を安くしているらしい。 この SIM は、 activate してから 30日間、 2.5GB まで 3G 速度でデータ通信できる。 私のケータイは日本で買った北米以外の地域向けの Nexus5 (LG-D821) で、 どのみち T-Mobile では 4G 通信できないので 3G で充分。

パッケージ表面に 「UNLIMITED 4G LTE FACEBOOK ACCESS, AT NO EXTRA CHARGE」 と書いてある。 LTE で接続しているときも 3G 速度に抑えるが、 facebook をアクセスするときは速度を制限しない、ということ? 3G で接続したときはどうなるんだろう? (→ 速くなった, 後述)

GoSmart SIM は、 TARGET の他、 ドンキホーテや街中のケータイ・ショップなどでも売っていて、 最近販売に力を入れ始めているように見える。 なお、 $35/月プランで 2.5GB のデータ通信が可能になったのは今年の一月末からで、 以前は 500MB だったらしい。

開封して説明書を読むと、 SIM の activate に必要なのは以下の 6点:

  • SIM Card Serial #:
  • Phone Serial # / IMEI #:
  • Area Code for Your Phone Number:
  • ZIP Code:
  • Pick a Security PIN (4 digits):
  • Refill Code:

「SIM Card Serial #」 は ICCID (IC Card IDentifier) のこと。 同梱されている SIM の表面に印字してある 19桁の数字。 「ICCD は最長 19桁」 だとする解説が日本語で書かれた WWW ページに多いが AT&T の SIM は 20桁だし、 正しくは最長 22桁らしい。

「Phone Serial # / IMEI #」 はケータイで 「*#06#」 をダイヤルすれば表示される。 どのケータイの IMEI (International Mobile Equipment Identity) を入力すべきか悩ましいところ。 私の常用スマホ Nexus5 には (この時点では) AT&T SIM が入っていたので、 それをいったん抜いて GoSmart SIM と入れ替えるのはメンドクサイ。 とりあえず遊んでる予備機 Galaxy Mega 5.8 Duos に GoSmart SIM を入れて Galaxy Mega の IMEI を登録したいところなのだけど、 もしここで登録した IMEI のケータイと GoSmart SIM が紐づいてしまって、 そのケータイ以外では使えなくなってしまうのだとしたら、 AT&T SIM の 「$60 Monthly」 プランの期限が切れた後の 5日間、 Nexus5 で通信できなくて Galaxy Mega の使用を強いられるのは困る。

まあ、 注意書きも無いのに勝手に紐づくなんてことは無いだろうと思いつつも、 万一に備えて (一時的に) Nexus5 の SIM を GoSmart に入れ替えることにした (AT&T SIM は Galaxy Mega へ)。

「Area Code for Your Phone Number」 で好きな地域の電話番号の局番を入力すれば、 その地域の電話番号を割当ててもらえる、 ということなのだろう。 ハワイ州なら 「808」。 日本だと携帯電話の電話番号は 「090」や「080」等で、 固定電話の局番とは別になっているが、 米国だと固定電話と同じ局番になる。

なぜここで 「ZIP Code」(郵便番号) を登録する必要があるのか分からないのだけど、 「Please enter your ZIP code so we can determine what area codes are available」 と言ってくるので、 入力した ZIP の地域の局番しか選べないのかもしれない。 素直に泊っているホテルの ZIP を入力したので、 別の州の ZIP を入力するとどうなってたかは不明。

「PIN」 は適当な 4桁の暗証番号を登録すれば良い。 カスタマーサポートに電話するとき、 本人認証するために用いるらしい。

GoSmart Refill Card

「Refill Code」 は同梱されている Refill カードの下方のマスク部分を削ると出てくる 10桁の数字。 ちなみに、 この 「マスク部分」 を 「スクラッチ」 と呼んでる WWW ページをやたら目にするのだけど、 どこからそんな誤用が広まったのだろう? 「スクラッチを削る」 って文を見ると頭痛が痛い (>_<)。

以上 6点の準備ができたので、 www.gosmartmobile.com をアクセスして、 「ACTIVATE ACCOUNT」 をクリック。 あとは準備した 6点を入力していくだけ。 名前や住所も聞かれるが入力が必須な項目ではない。 ところが、 以下 2点が必須入力項目:

  • Email
  • Alternate phone number

必須なら、 説明書に書いておくべきだと思うのだけど... 「Email」 は、(誰でも持っているだろうから) まあ良いとして、 「Alternate phone number」 は日本のケータイ番号でも構わないのだろうか? 私は Google Voice の番号を持っているので、 それを入力したのだけど、 GoSmart が米国での最初の電話番号になる人はどうすればよいのだろう? ここで入力した番号に電話がかかってくる様子もないので、 ホテルの電話番号でも入力しておけば良い?

説明書に、 「When asked to select a plan YOU MUST CHOOSE THE $35 UNLIMITED TALK, TEXT & HIGH-SPEED WEB PLAN without any additional features.」 と書いてあるので、 「Unlimited Talk, Text & Web + up to 2.5GB of 3G Web」プランを選ぶ。 WWW ページの文字列を説明書と一致させておいたほうが良いのではないかと思ったり...

最後に 「Refill Code」 を入力して無事 activate 完了。 さっそく SIM を Nexus5 へ入れてみる。 APN は 「fast.t-mobile.com」 のままでデータ通信できるみたい。 でも、びっくりするくらい遅い。 測ってみると 1Mbps も出ていない。 こんなんで (AT&T SIM の 「$60 Monthly」 プランの期限が切れた後の) 5日間を耐えられるのかなぁ? 同じ 3G でも AT&T SIM なら (同じ Nexus5 で) 5Mbps 以上出るのに。 ただ、 看板通り facebook へのアクセスだけは速い。 「UNLIMITED 4G LTE FACEBOOK ACCESS」 というのは LTE じゃない 3G 接続時も適用されるらしい。

ところが実際に使い始めてみると、 意外なほど遅さは気にならなかった。 画像など大量のデータを送受信するのは、 実は facebook がほとんどだった、ということなのか...orz ただし、 AT&T と比べて 3G が圏外になる頻度が高いのは、 (GoSmart に限らず) T-Mobile の不便なところ。 ちょっと郊外へ出かけるとすぐ 2G になるのはもちろん、 市街地でも建物の奥に入ると電波が弱くなり、 2G に落ちることもしばしば。

More...
Filed under: Hawaii,SIM — hiroaki_sengoku @ 07:00
2014年10月27日

シンガポール SingTel 3G プリペイド SIM を 4G へアップグレードしてみた

SingTel 3G Prepaid SIM

2012年2月にシンガポールで買ったプリペイド SIM カード
当時シンガポールでは LTE (4G) サービスが始まっていなかったが、 その後 2013年に SingTel と M1 は、 プリペイドでも LTE が使えるようになった。 ところが、 この SingTel の古い 3G プリペイド SIM カードでは LTE を利用することができず、 4G プリペイド SIM へアップグレードする必要がある。

もちろん、 わざわざアップグレードしなくても、 コンビニ等で新規に 4G プリペイド SIM カードを買えばよいのだが、 私の場合この古い 3G プリペイド SIM カードの残高が S$140 (約 12,000円) ほどあったのと、 この SIM の番号へ日本から電話連絡してもらう予定があったのとで、 古い SIM を使い続ける必要があった。

元々 S$28 のプリペイド SIM なのに、 なぜ S$140 も残高があるかというと、 この SIM をはじめほとんどのプリペイド SIM は、 一定期間以上チャージしないと無効になってしまうから。 この SIM の場合 S$20 チャージすると、 その時点から 180日間有効なので、 半年ごとに S$20 チャージし続けると、 5回チャージする (計 S$100) ことで、 購入から 2年半以上経った現在でも (同じ電話番号のままで) 使い続けることができている。

街中 (というかショッピングモール内) を歩いていて見かけた SingTel shop で、 4G SIM へのアップグレードの方法を店員に尋ねたら、 アップグレードは、 SingTel shop ComCentre (31 Exeter Road) でのみ可能とのこと。 Google Maps で調べると、 MRT (地下鉄) の Somerset 駅 (NS23) の南側に聳え立つ ComCentre (SingTel の本社ビル) の隣らしい。 近くなので行ってみた。

店内に入ると、 順番を待つ客でごった返していた。 (順番待ちの) 発券機があったので画面にタッチすると、 「Enter your NRIC/FIN」 と表示され、 番号を入力しないと先に進めない。 たかが順番待ちに、 NRIC (National Registration Identity Card) や FIN (Foreign Identification Number) を入力させるとは、 さすが管理国家 (>_<)。 もちろん一観光客 (ビザ無し) である私はどちらも持っていない。

通りがかったスタッフに 「4G SIM へアップグレードしたいんだけど?」 と (もちろん英語で) 聞くと、 「今日は特別な日 (たまたまこの日は Deepavali というヒンドゥー教のお正月) だから激混みで 2時間待ちだけどそれでもいいのか?」 と脅される。 待つなら発券機で番号札を取れと言うので、 「私は resident じゃないので NRIC を持ってない」 と言うと、 ポストペイ SIM かプリペイド SIM か聞いてきて、 「プリペイド SIM なら、向こうの Cashier へ行け」 と言われた。

SingTel ComCentre Cashier

へ? Cashier ? 順番待ちせずにアップグレードできるということなのかなぁ? Cashier って、 ケータイケースとかの、 お金を出すだけですぐ買えるような単純なものを買うところのように見えるんだけど... (後ろにケータイケースとか並べてるし)

Cashier 前に並んでいる人たちは、 ケータイ用のアクセサリ等を買うために並んでいるか、 あるいは既に相談カウンターで手続きが済んでいて、 お金を払う最終段階で Cashier に並んでいるように見える。 Cashier でアップグレードの手続きができるとは、 ちょっと信じがたい... それに、 Cashier には 10人ぐらい並んでいて、 Cashier といえどそこそこ待つ必要があるように見える (実際 10分かかった)。 待った挙げ句、 やっぱり番号札を取って順番を待てという結末になったら嫌だなぁと思いつつ、 ダメ元で並んでみた。

で、 順番が回ってきて、 Cashier のレジ係に 「4G へアップグレードしたいんだけど...」 と伝えると、 レジ係がメモ紙を出して、 「ケータイの電話番号を書け」 と言う。 お、 本当にここでアップグレードできるのか? いま使ってる 3G SIM の 8桁の電話番号を渡された紙に書くと、 レジ係が 「Mr. Hiroaki Sengoku, パスポートはいま持ってるか?」 と聞く。

う、 プリペイド SIM の電話番号だけで名前が分かるのか! と驚いたけど、 よく考えたら SIM を買ったとき (2012年) にパスポートを提示したのだから当たり前。 でも、 レジ係が簡単に SIM 使用者の身元を照会できてしまうのはいかがなものか? もし私が (間違えたフリして) 他人の番号を書いたら、 使用者の名前を聞けてしまう? 管理国家とはこういうことなのか?

パスポートを見せると、 「S$38 をチャージする形になるが構わないか?」 と聞かれた。 つまり、 いま S$38 (約 3200円) を払う必要があるが、 それはプリペイド SIM にチャージされ、 通話やデータ通信する料金として使うことができて、 アップグレード自体は無料ということ。 「もちろん」 と答えて、 S$38 を (クレジットカードで) 支払う。 すると、 間髪をいれず手元の Nexus5 (3G SIM が入ってる) に、 チャージ完了を知らせる SMS が届く:

From: 74445
Date: 2014-10-22 13:32

You have successfully topped up $38.00. New MAIN bal: $152.32, Expiry: 20/04/2015.Visit www.singtel.com/hi (no data charges!) or dial *363 to buy data plans or transfer airtime locally/overseas via hi!Share using your MAIN account bal.

新しい 4G SIM の代金として払った S$38 なのに、 アップグレードする前の古い 3G SIM に S$38 がチャージされるのは、 ちょっと変な感じ。

SingTel ComCentre Cashier

そして遂に、 新しい 4G プリペイド SIM カードをゲット。 Cashier の順番が回ってきてからここまで 3分もたっていない。 街中で新規に S$38 のプリペイド SIM を買うのとほとんど同じ。 古い 3G SIM の残高と電話番号を引き継げる。 新しい SIM はケータイ網に登録されるまで 15分ほどかかるとのこと。

店内の椅子に腰掛けて、 Nexus5 から古い 3G SIM を取り出す。 そして、 いま買ったばかりの 4G SIM を入れると、 まだ登録が済んでいないらしく圏外表示。 15分待ってもアンテナ表示が立たないので、 Nexus5 を再起動したらアンテナと 「LTE」 の文字が表示された。 ちなみに古い 3G SIM の返却は求められなかったし、 Cashier では Nexus5 に入れたままだったので提示すらしていない。

シンガポールは、 一人 3枚までしかプリペイド SIM を持てず、 一つのパスポートで 3枚のプリペイド SIM を買ってしまうと、 たとえ紛失したとしても 3枚の SIM が有効である限り、 それ以上 SIM を買うことはできないと聞く。 しかしながら、 4G へのアップグレードの際に古い SIM を持参する必要が無かったことを考えると、 例えば SIM のサイズを nano に変更するなどの理由があれば (無くても?)、 新しい SIM を 3枚制限の枠内で発行してもらうことが可能なのではないか? 紛失して有効期限満了まで待てない時など、 試してみる価値はありそう。

なお、 新しい 4G プリペイド SIM カード表面に、 「FREE 1GB DATA」 と書いてある通り、 7日間 1GB までのデータ通信が無料になるが、 私の場合は古い 3G SIM において既に 「7-Day $25 Ultimate 14GB Plan」 を購入済みだったので、 この 「FREE 1GB DATA」 は使われることなく無駄になってしまった (1週間以内の短期滞在なので)。 「7-Day $25 Ultimate 14GB Plan」 の 7日間が過ぎるか、 あるいは 14GB を使いきれば、 「FREE 1GB DATA」 も使えるのだろう。

Filed under: SIM — hiroaki_sengoku @ 18:19
2014年10月14日

お金と自由 〜 なぜ貯められないのか?

先日、 立命館大学で 2, 3回生の学生さん達に講義する機会を頂きました。 せっかくの機会なので、 大学ではまず教わることが無いであろう 「お金」 の話をしました。 学生さん達が社会人になる前に、 是非ともお金について考えてみてもらいたいと常々思っていたからです。

お金も時間も足らないはずがない
(中略)
何でお金がなくなるんだろうって、そっちも不思議なんですよ。 日立ってそんな高い給料じゃないと思うんですけど、 入社当時、お金ってそんなに必要じゃなかったから、 あの安月給でもお金が貯まって仕方なかったんです。 お金が貯まらないって人は、 好きじゃないことにお金を使っているんじゃないの? って思いますね。
例えばですね、 すごく不思議だったから今でも覚えているんですけど、 同期入社の人が、入社早々、みんな車を新車で買ったんですよ。 もちろん好きだったら、買ってもいいと思いますよ。 レーサーを目指しているとか、 峠を攻めたいとかっていう人は買ったらいいと思うんです。
でもそんなに好きでもなくて、たまにしか車を使わないような人でも、 みんな車を買ったんで、不思議だなと思いましたね。 私に言わせるとありえないんですけど。 みなさん、好きでもないことにばっかりお金を使っているんじゃないですかね。

自由な時間は学生さんの方が持っていて、 お金は社会人の方が持っているという違いがありますが、 どちらも無駄遣いする習慣を身につけてしまうと、 一生取り返しがつかないように思うので、 ぜひとも人生これからの学生さん達に伝えたいと思っていました。

多くの人が、 学生時代は月に 10万円以下の生活費で暮らしていたにもかかわらず、 社会人になって急に毎月 20万円以上の 「大金」 を手にし、 いままでやらなかった (できなかった) 消費活動に走り、 お金があればあるだけ使ってしまうという悪い習慣に、 あっと言う間に染まってしまいます。 ひとたびこの悪習に取り憑かれると、 給料が上がっても、 上がったぶんだけ消費が増え、 いつになっても金銭面での余裕ができず、 何をするにもお金がネックになって、 お金に振り回される人生を送ってしまいます。 まさに 「お金は悪い主人である」 の典型ですね。

良い召使い or 悪い主人

・ 良い召使い
  - お金は自由を得るための手段
  - お金をどう使うか主体的に考える
  - チャレンジするための強力な道具
・ 悪い主人 (充分なお金が無いと...)
  - お金は生活の手段
  - 使い方を考えるまでもなく出費がかさむ
  - お金のために働く, お金に振り回される
  - お金を失う恐怖で、チャレンジができない
  - お金の不安がストレスに

日頃ストレスを感じると回答した人に、 その理由を尋ねると、 約 40% の人が 「収入や家計に関すること」 と回答しているそうです。 ストレスの原因としては他に、 「人間関係」 「健康状態」 「子育て」 なども挙げられていますが、 例えば、 職場の人間関係にストレスを感じていても辞められないのは、 転職したくても収入が不安定になるのが怖くて踏みきれないことが多かったりするわけで、 様々なストレスの遠因がお金 (が足らないこと) にあると言っても過言ではありません。

当座の生活に困らない程度の充分な蓄えさえあれば、 ストレスの多くは感じずに済み、 お金に振り回されるのではなく、 お金を 「良い召使い」 として使えるようになります。

そんなこと言ったって、 安月給なんだから貯められないのは仕方がない、 って声が聞こえてきそうですが...

充分なお金ってどのくらい?

・ 年収 300万円なら年 100万円以上貯金
  - 独身なら生活費は月 10万円程度で済むはず
・ 30歳までに 500万円
  - 100万円/年 * 5年
・ 40歳までに 4000万円
  - 350万円/年 * 10年
  - 年収 700万円以上あれば誰にでも貯められる
・ もちろん、やりたいことにはお金を使うべき
  - でも、昨今はお金をかけずに何でもできてしまう

独身で扶養家族を持たない人であれば、 学生時代と同程度の生活費で暮らすことが本来は可能なはずです。 しかも学費を払う必要がないのですから、 正社員であれば初年度においても 100万円以上貯めることは簡単なはずです。 その後、昇給もあるでしょうから、 30歳までに 500万円貯めるのは (正社員であれば) 誰にでもできることでしょう。

私は日立の安月給で 30歳までに 1000万円ほど貯めました。 寮費が月 2000円、 朝夕食は寮の食堂で昼食は社内食堂で食べ、 会社にいないときは寮に併設のコートでテニスをしている、 というほとんどお金を使わない生活をしていたからですが (^^)。

なお、 「お金を貯める」 「貯金」 は、 普通は銀行預金のことを意味しますが、 ここでは貯金してまとまった資産をつくり、 それを元手に投資することまで含むものとします。

その後、 給料が増えても生活レベルをあまり上げずに生活費を年間 200万円程度に抑えれば、 増えたぶんは丸々貯金できるはずです。 もし年収が 700万円以上あれば、 40歳までに 4000万円貯めることも決して難しくないはずです (私は 1億円近く貯めました ^^)。 貯金が 4000万円もあれば、 どれだけ生活にゆとりができるでしょうか。 ストレスの多くは感じずに済むのではないでしょうか。

ところが、 この程度の貯金すら、 ほとんどの人にとっては難しいようです。

なぜ貯められない?

・ お金に関する間違った常識
  - 持ち家は一生の財産 (ローンなら負債)
  - 生命保険は社会人の常識
  - お金は使ってなんぼ (うまく投資できればの話)
  - 「お金に働いてもらう」信仰 (貯めるのが先)
・ お金に余裕があると使ってしまう習慣
  - お金を使うことに慣れてしまう
  - 初任給から一ヶ月間が運命の分かれ道
・ 貯めるメリットが分かってない
  - そんなに貯めて何に使うの?

多くの人は貯金するどころか逆にローンという莫大な借金を抱えてしまいます。 家賃を払う人には安い家に引っ越して負担を減らす自由がありますが、 ローンを抱えている人には負担を軽減する自由はありません。 したがって、 「購入 VS 賃貸」 という比較はナンセンスです。 それなのに、 なぜ家賃を払うより 「お得」 と称して高額のローンを組ませるのでしょうか? もちろん、 銀行が儲けるためです。

扶養家族を持たない新卒社員に、 なぜ生命保険が必要なのでしょうか? 高額療養費制度により高額な医療費を支払ったときは払い戻しが受けられるのに、 なぜ医療保険が必要なのでしょうか? もちろん、 保険会社が儲けるためです。

銀行や保険会社以外も、 「お金は使ってこそ価値がある」 「若いときこそお金は自己投資すべき」 などと、 あの手この手でお金を使わせようとします。 でも、 まだ何の経験もない新卒社員に、 お金の有効な使い方が分かれば苦労はしません。 新卒社員にお金を使わせようと躍起になっている人たちが、 真に有効なお金の使い方を新卒社員に教えるでしょうか? もちろん彼らが教えるわけはなく、 教える義理もありません。 彼らが関心があるのは彼ら自身の儲けだけです。

お金を使わせようとする人以外にも、 「お金に働いてもらおう」 「投資に成功する方法」 など、 「儲かる」投資方法を伝授しようとする人もたくさんいます。 彼らがもし真に儲かる投資方法を知っているなら、 わざわざ他人に教えるのではなく自分で大儲けすればいいのにと思いますが、 わざわざ本を書いたり講演したりして、 わずかばかりの印税や講演料を稼いでいるわけです。 変だと思いませんか?

そういう本や講演にいちいちお金を使っていては彼らの思うツボです。 お金を払う前に、 著者あるいは講演者がどれほどの個人資産を持っているというのか、 調べてみるべきでしょう。 決して、 お金が勝手に働いてくれるわけではありません。 自分の頭で考えて汗をかいて有効な投資先を見つけ出し、 あるいは自分で創り出し、 リスクを取って投資し、 その報酬としてリターンを得るのです。

お金はいったん使ってしまうと歯止めが効きません。 使えば使うほど、 財布の紐は緩くなります。 近頃流行りのソーシャルゲームは、 いかにユーザに最初の 100円を払ってもらうかが腕の見せどころです。 いったん 100円を払ってしまったユーザは、 次の 1000円を払うのに躊躇しません。

世界中の大人達が寄ってたかってウブな若者にお金を使わせようと知恵を絞る中、 お金を使うのを我慢するのは至難の業ですが、 さらに周囲の同僚からも、 「ケチ」 だの 「そんなに貯めてどうするんだ?」 などと、 冷たい視線を浴びることになります。 ほとんどの人が、 お金を貯めるメリットを理解していないのだから仕方ありません。

お金を貯めるメリット?

・ お金を「良い召使い」として使える
  - お金 (生活) のためでなく自己実現のために働ける
  - お金の不安という最悪のストレスから解放される
・ お金 (定期収入) を失う恐怖を克服できる
  - 転職に踏み切れる, 何度でも勝負できる
・ 資本家と対等の立場に立てる
  - 自身の労働を売らない自由 (給料交渉では超重要)
階層の壁を越えるチャンス
  - (詐欺ではない本物の) うまい投資話に乗れる
  - まずは最低でも 1000万円。それ以下では相手にされない

労働者は自身の労働力を売らない自由が無い (辞めると生活できなくなる) ばっかりに、 資本家 (会社) との交渉において立場が弱くなってしまい、 (たとえ労働三法の庇護の下でも) 不利な条件を渋々飲まされるわけで、 「辞める自由」ってのは非常に重要だと思います。

また、 お金 (定期収入) を失う恐怖を克服して、 勝負する自由や、 お金を (生活のためでなく) 自己実現のために使う自由も重要でしょう。 ところが、私が 「お金を貯める最大のメリットは、 自由が得られること」 と話しても、 学生さん達にはイマイチ響かなかったように見えました。

お金を貯めるメリットが分からないというよりは、 自由の価値が分からない、 ということなのかも? と講義を終えてから思い当たりました。 (もし次の機会があれば) 今度はお金だけでなく自由の重要性についてもっと話してみようと思います。

(資本主義における) 給料が 「労働の再生産コスト」 に収斂するのは、 労働者に自由がないからであって、 もし労働者が自由を獲得すれば、 労働者が実際に産み出した 「(使用)価値」 に近いところまで給料が上がることが期待できます。 「労働の再生産コスト」 と同程度の給料でできるのは現状維持だけですが、 それより給料が高ければ 「剰余価値」 が労働者の側に蓄積し、 労働者階級から脱出する道が見えてきます。

階級格差は固定されたものではなく、 一労働者からスタートしても、 階層の壁を越えて資本家側に移ることは充分現実的であり、 お金を貯めれば貯めるほど、 その難度は下がります。 お金を貯めて 「壁越え」 に挑戦する人が増えることを願って止みません。 それこそが閉塞感を打ち破り、 活気に満ちた社会を取り戻す唯一の方法だと思うからです。

成功者を妬んで引きずり降ろそうと足の引っ張り合いをするのではなく、 成功者を正当に評価して後に続く人を増やすことこそが、 真の 「トリクルダウン」 (trickle-down) であり、 社会の成長エンジンになりうるのだと思います。

More...
Filed under: 自己啓発 — hiroaki_sengoku @ 00:00
Older Posts »