個人的なメモを記していくためのページです。
120GBのポータブルHDD。売り場では値札のPOPも無しに一番下の棚に隠すように並んでいた。(←気のせい)なお同容量の他の製品は(税込で)1万円ちょっと位。
スイッチングハブが壊れた。ハブってなぜか壊れる。2002年7月購入だからまぁしょうがない。明日新しいのを買ってこなくては。CG-SW08TXRが適当な候補。
ってもう実現されてそう。Energy Harvesting Technologyの応用で。(参考: 熱や振動から電力を生成 ハーベスタ技術は離陸するか)
自宅の玄箱で次のようなスクリプトを定期的に実行するようにします。
1 #!/bin/sh 2 3 4 LOC=44132 5 6 cd $HOME/public_html/amedas/ || exit 7 8 HOUR=`date +%H` 9 10 case $HOUR in 11 00) 12 wget -q -N http://www.jma.go.jp/jp/amedas_h/yesterday-${LOC}.html 13 perl update-amedas.pl yesterday-${LOC}.html | sh 14 ;; 15 *) 16 wget -q -N http://www.jma.go.jp/jp/amedas_h/today-${LOC}.html 17 perl update-amedas.pl today-${LOC}.html | sh 18 ;; 19 esac 20 21 sh ./make-graph-2.sh ${LOC} 22 scp foo.png ${HOST}:${WWW_PATH}/qmd/files/amedas-${LOC}.pngこのスクリプトは以下のことをします。
23 * * * * /home/tito/public_html/amedas/fetch-amedas.sh >/dev/null 2>&1update-amedas.plは以下のperlスクリプトです。表中の最近のデータを取得しrrdtoolのコマンドラインを生成します。生成されたコマンドはfetch-amedas.sh でパイプラインでつながったシェルに渡され実行されています。しかしこれはセキュリティ的に問題が発生しやすいのでperlで適当なモジュールを使ってrrdtoolを起動するべきでしょう。一応以下のスクリプト中でもデータのサニタイズ等に気は使ったつもりですが。
1 #!/usr/local/bin/perl 2 3 use utf8; 4 5 use strict; 6 use Data::Dumper; 7 use HTML::TreeBuilder; 8 9 use Time::Local; 10 11 binmode STDOUT, ":encoding(euc-jp)"; 12 binmode STDERR, ":encoding(euc-jp)"; 13 14 our %wd; 15 our $location_code; 16 our( $year,$month,$day, $location, $location_yomi); 17 our $hour; 18 our $last_hour; 19 our $time_0 ; 20 our @dp_hour; 21 22 23 my $i = 0; 24 foreach ("北", "北北東", "北東", "東北東", 25 "東", "東南東", "南東", "南南東", 26 "南", "南南西", "南西", "西南西", 27 "西", "西北西", "北西", "北北西"){ 28 $wd{$_}=$i++; 29 utf8::encode( $wd{$_}); 30 } 31 32 33 foreach my $file (grep( -f $_, @ARGV)) { 34 ($location_code) = $file=~ /-([0-9]+).html/; 35 36 37 open FH, "<:encoding(Shift_JIS)", $file || die; 38 my @c = <FH>; 39 my $contents = join('', @c); 40 close(FH); 41 my $h = HTML::TreeBuilder->new; 42 utf8::encode( $contents ); 43 $h->parse($contents); 44 45 my @title = $h->look_down( "_tag", "table", 46 "id", "tbl_title" ); 47 my @tr = $title[0]->look_down( "_tag", "tr" ); 48 49 my $title=$tr[1]->as_text(); 50 utf8::decode($title); 51 ( $year,$month,$day, $location, $location_yomi) = 52 $title =~ /(.*)年(.*)月(.*)日 (.*)\((.*)\)/; 53 $hour=0; 54 $time_0 = timelocal( 0,0,0, $day, $month-1, $year ); 55 56 57 my @table = $h->look_down( "_tag", "table", 58 "id", "tbl_list"); 59 60 @tr = $table[0]->look_down( "_tag", "tr" ); 61 62 my @dp= $tr[0]->look_down( "_tag", "td" ); 63 my @dp_name = (); 64 foreach (@dp){ 65 my $cc = $_->as_text(); 66 utf8::decode( $cc ); 67 push( @dp_name, $cc ); 68 } 69 70 $hour =0; 71 @dp_hour=(); 72 73 foreach my $j( @tr[2..$#tr] ){ 74 my @td = $j->look_down( "_tag", "td" ); 75 76 my $i = 0; 77 $hour = $td[0]->as_text(); 78 $hour =~ y/^0-9//; 79 80 $dp_hour[ $hour ]={}; 81 my $dp_count=0; 82 foreach (@td){ 83 my $c = $_->as_text(); 84 $c =~ s/\x{00a0}//; 85 if( $c ne ""){ 86 $dp_hour[$hour]->{ $dp_name[ $i ] } = $c; 87 $dp_count++; 88 } 89 $i++; 90 # print " $c"; 91 } 92 if( $dp_count > 1){ 93 $last_hour = $hour; 94 # rrd_update( $last_hour ); 95 96 } 97 # print "\n"; 98 99 } 100 rrd_update( $last_hour ); 101 102 103 $h = $h->delete(); # nuke it! 104 } 105 exit; 106 107 sub sanitize 108 { 109 my($v) = @_; 110 $v =~ y/0-9.//cd; 111 return $v; 112 } 113 114 sub rrd_update 115 { 116 117 my($last_hour) = @_; 118 print STDERR "$year-$month-${day}T${last_hour}:00:00 $location($location_yomi) $location_code\n"; 119 120 my $d = $dp_hour[ $last_hour ]; 121 my $cmd; 122 $cmd = "rrdtool update $location_code.rrd "; 123 $cmd .= join( ':', 124 sprintf("%d",$time_0+$last_hour*3600), 125 &sanitize($d->{気温}), 126 &sanitize($d->{降水量}), 127 $wd{$d->{風向}}, 128 &sanitize($d->{風速}), 129 &sanitize($d->{日照時間}), 130 &sanitize($d->{積雪深}), 131 &sanitize($d->{湿度}), 132 &sanitize($d->{気圧})); 133 134 print "$cmd\n"; 135 136 $cmd = "rrdtool update $location_code-y.rrd "; 137 $cmd .= join( ':', 138 sprintf("%d",$time_0+$last_hour*3600+24*3600 ), 139 &sanitize($d->{気温}), 140 &sanitize($d->{降水量}), 141 $wd{$d->{風向}}, 142 &sanitize($d->{風速}), 143 &sanitize($d->{日照時間}), 144 &sanitize($d->{積雪深}), 145 &sanitize($d->{湿度}), 146 &sanitize($d->{気圧})); 147 148 print "$cmd\n"; 149 150 151 } 152 153 154 __END__
ところどころ utf8::decode、utf8::encodeが入っているのが魔法的ですが私もよく判っていません。別の環境ではこれが無くても動作しました。(入れると動かない)
amedasによって得られるデータの種類は地点によって違います。気象台がある地点以外では種類が少なく降水量しかなかったりします。一応他の地点でも使えるようにデータの種類も表中から得るようにしています。
rrdupdateサブルーチンではrrdtool update行を2行出力していますがこれは一つのグラフに今日のデータと一日前のデータと両方を出すためのトリックです。(RRDtoolの使い方のp.52) 例えば 44132.rrd と 44132-y.rrd というデータベースを用意して 44132-y.rrdには時間をずらしてデータを入れます。
グラフを生成するスクリプトです。rrdtool graphを呼び出しているだけです。
1 #!/bin/sh 2 3 LOC=$1 4 5 cat <<EOF | rrdtool -; 6 graph foo.png \ 7 -s `date +%s -d '1 day ago'` \ 8 -e `date +%s` \ 9 -a PNG \ 10 DEF:temp=${LOC}.rrd:temp:AVERAGE \ 11 GPRINT:temp:LAST:"temp %3.1lf\r" \ 12 DEF:rh=${LOC}.rrd:rh:AVERAGE \ 13 CDEF:rh1=rh,100,/,10,* \ 14 GPRINT:rh:LAST:"rh %3.1lf\r" \ 15 DEF:tempy=${LOC}-y.rrd:temp:AVERAGE LINE1:tempy#ff8888:"temp-y" \ 16 LINE1:temp#ff0000:temp \ 17 DEF:rhy=${LOC}-y.rrd:rh:AVERAGE \ 18 CDEF:rh2=rhy,100,/,10,* LINE1:rh2#88ccff:"rh-y" \ 19 LINE1:rh1#0033cc:rh \ 20 --width=400 --height=120 \ 21 --title "Tokyo Temp/RH (derive from AMEDAS)" 22 EOF
rrdtoolのデータベースを作るスクリプト。 以上のスクリプトのためには1地点について二つのrrdファイルが必要です。
$ ./createrrd 44132 $ ./createrrd 44132-y
1 rrdtool create $1.rrd --step 3600 \ 2 --start 1195189900 \ 3 DS:temp:GAUGE:7000:-50:50 \ 4 DS:prec:GAUGE:7000:0:100 \ 5 DS:wd:ABSOLUTE:7000:U:U \ 6 DS:ws:GAUGE:7000:0:30 \ 7 DS:dl:GAUGE:7000:0:1 \ 8 DS:sg:GAUGE:7000:0:U \ 9 DS:rh:GAUGE:7000:0:100 \ 10 DS:ap:GAUGE:7000:900:1100 \ 11 RRA:AVERAGE:0.5:1:48 \ 12 RRA:AVERAGE:0.5:24:30 \ 13 RRA:MIN:0.5:12:63 \ 14 RRA:MAX:0.5:12:63 \ 15 RRA:LAST:0.5:1:48
debianならば rrdtool と libhtml-tree-perl をaptやaptitude でインストールします。手動でインストールする場合は perl のモジュールは HTML::TreeBuilder です。 rrdtoolも最新版だと グラフィックスがcairoベースできれいになってたりするので そちらを入れてもよいでしょう。debian sargeのパッケージでは1.0.49ですが別マシンではrrdtool-1.2.99908020600を入れて使っています。その場合のグラフはこんな感じです。