end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転します

perlでyahoo電気予報を取得し、メール送信

昨日?、yahoo japanから東京地方?の使用電気量を予想するページが、web apiと共に公開されました。

http://setsuden.yahoo.co.jp/denkiyoho/

企業の場合、「インターネットに手軽に接続できないので、電気予報をメールで送って欲しい」という方も多いと思います。

なので、
yahoo apiからその日の使用電力量を取得し、メール送信(smtp auth)するperl scriptを書いてみました。

メッセージ内容

表示内容は、好みが分かれるので、シンプルにしています

Yahoo 電気予報 at:2011-04-28 12:25

usage capacity
04-28 11H -> 32,420,000 / 40,000,000 kW (81%)
04-28 12H -> 30,280,000 / 40,000,000 kW (75%)
04-28 13H -> 31,750,000 / 40,000,000 kW (79%)
04-28 14H -> 31,810,000 / 40,000,000 kW (79%)
04-28 15H -> 31,640,000 / 40,000,000 kW (79%)
04-28 16H -> 32,010,000 / 40,000,000 kW (80%)
04-28 17H -> 31,830,000 / 40,000,000 kW (79%)
04-28 18H -> 32,960,000 / 40,000,000 kW (82%)
04-28 19H -> 32,550,000 / 40,000,000 kW (81%)
04-28 20H -> 31,390,000 / 40,000,000 kW (78%)
04-28 21H -> 30,080,000 / 40,000,000 kW (75%)
04-28 22H -> 29,060,000 / 40,000,000 kW (72%)
04-28 23H -> 27,210,000 / 40,000,000 kW (68%)
04-29 00H -> 25,320,000 / 40,000,000 kW (63%)
04-29 01H -> 24,330,000 / 35,000,000 kW (69%)
04-29 02H -> 23,860,000 / 35,000,000 kW (68%)
04-29 03H -> 23,520,000 / 35,000,000 kW (67%)
04-29 04H -> 23,200,000 / 35,000,000 kW (66%)
04-29 05H -> 23,060,000 / 35,000,000 kW (65%)
04-29 06H -> 23,880,000 / 35,000,000 kW (68%)
04-29 07H -> 25,270,000 / 35,000,000 kW (72%)
04-29 08H -> 27,280,000 / 35,000,000 kW (77%)
04-29 09H -> 28,660,000 / 35,000,000 kW (81%)
04-29 10H -> 29,100,000 / 35,000,000 kW (83%)

refer to http://setsuden.yahoo.co.jp/denkiyoho/

perl script

#!/usr/local/bin/perl
use strict;
use utf8;
use Encode;
use HTTP::Request::Common;
use JSON qw/decode_json/;
use LWP::UserAgent;
use Authen::SASL;
use MIME::Base64;
use Net::SMTP;
use Data::Dumper;

my $YAHOO_API_URL =
    'http://setsuden.yahooapis.jp/v1/Setsuden/electricPowerForecast';

#yahoo apiのアプリケーションIDは次のurlで取得できます(要yahoo login)
# https://e.developer.yahoo.co.jp/dashboard/
my $YAHOO_API_OPT =
    {appid =>'ないしょ',
     output =>  'json',
     area=>     'tokyo',
     results=>  24,
    };
my $YAHOO_PAGE_URL = 'http://setsuden.yahoo.co.jp/denkiyoho/';

my $HTTP_REQEST_COND =
    {timeout =>         10,
     max_retry =>       5,
     sleep =>           60 };
my $MSG_TITLE_HEAD = 'Yahoo 電気予報';
my $MAIL =
    {mailfrom =>        'xxxx@hogehoge.jp',
     mailto =>          ['yyyy@hogehoge.jp','zzzz@hogehoge.jp'],
     smtp_host=>        'hogehoge.jp',
     smtp_port=>        '587',          #smtp auth
     smtp_timeout=>     20,
     user_id=>          'xxxx',     #smtp auth user
     user_passwd=>      'ないしょ',     #smtp auth user passwd
    };

main();
exit(0);

sub main {
    my $forcast = get_pow_forecast();
    return undef unless $forcast;

    my ($title,$msg_body) = conv_forecast2txt($forcast);
    send_mail($title,$msg_body);
}

#取得した電気予報(perl object)をテキスト形式に変換
sub conv_forecast2txt {
    my ($forcast) = @_;

    my $update_str = '';
    if ($forcast->{ElectricPowerForecasts}->{UpdateTime} =~
        /^(\d+)\D(\d+)\D(\d+)\D(\d+)\D(\d+)/o){
        $update_str = "$1-$2-$3 $4:$5";
    }
    my $title = "$MSG_TITLE_HEAD  at:$update_str";

    my $msg_body =<<EOF;
$title

              usage        capacity
EOF
    my $forcast_hours =
        $forcast->{ElectricPowerForecasts}->{Forecast};
    for my $hour_info ( @$forcast_hours ){
        $msg_body .= substr($hour_info->{Date},5);
        $msg_body .= sprintf(" %02dH -> ",$hour_info->{Hour});

        my $usage_str = split_int_num($hour_info->{Usage}->{'$'});
        my $capa_str =  split_int_num($hour_info->{Capacity}->{'$'});
        $msg_body .= "$usage_str / $capa_str $hour_info->{Capacity}->{'@unit'}";

        my $ratio =
            int($hour_info->{Usage}->{'$'}/$hour_info->{Capacity}->{'$'} *100);
        $msg_body .= " ($ratio%)";
        $msg_body .= '!!!' if $ratio >= 90;
        $msg_body .= "\n";
    }

    $msg_body .= "\n refer to $YAHOO_PAGE_URL\n";

    return $title, $msg_body;
}

#整数を3桁毎に「,」で区切ります
sub split_int_num {
    my ($int) = @_;
    $int =~ s/([+-]?\d)(?=(\d{3})+(?!\d))/$1,/go;
    return $int;
}

#yahoo apiで電気予報を取得
sub get_pow_forecast {
    my $ua = LWP::UserAgent->new();
    $ua->timeout($HTTP_REQEST_COND->{timeout});

    my @api_args;
    for my $arg_key ( keys %$YAHOO_API_OPT ){
        push(@api_args,"$arg_key=$YAHOO_API_OPT->{$arg_key}");
    }
    my $req_url = $YAHOO_API_URL .'?'.join('&',@api_args);
    my $req = HTTP::Request->new(GET=>$req_url);

    my $i = 0;
    while( $i++ < $HTTP_REQEST_COND->{max_retry} ){
        my $res = $ua->request($req);
        return decode_json($res->content) if($res->is_success);
        print STDERR $res->status_line;
        sleep($HTTP_REQEST_COND->{sleep});
    }
    return undef;
}


sub send_mail {
    my ($subject,$message) = @_;

    my $from =  $MAIL->{mailfrom};
    my $mailto_str = join(',', @{$MAIL->{mailto}});
    $subject = encode('iso-2022-jp',$subject);

    #メールのヘッダーを構築
    my $header = << "MAILHEADER";
From: $from
Subject: $subject
Mime-Version: 1.0
Content-Type: text/plain; charset = "ISO-2022-JP"
Content-Transfer-Encoding: 7bit
MAILHEADER

    $message = encode('iso-2022-jp',$message);

    my $smtp = Net::SMTP->new($MAIL->{smtp_host},
                              Hello=>$MAIL->{smtp_host},
                              Port=> $MAIL->{smtp_port},
                              Timeout=>$MAIL->{smtp_timeout},
#                             Debug=>1
                             );
    unless($smtp){
        print STDERR "can't connect smtp server:$MAIL->{smtp_host}\n";
        return undef;
    }
    unless ($smtp->auth($MAIL->{user_id},$MAIL->{user_passwd}) ){
        print STDERR "can't login smtp server:$MAIL->{smtp_host}\n";
        return undef;
    }

    $smtp->mail($from);
    $smtp->to(@{$MAIL->{mailto}});
    $smtp->data();
    $smtp->datasend("$header\n");
    $smtp->datasend("$message\n");
    $smtp->dataend();
    $smtp->quit;
    return 1;
}