package weather; use 5.018; use strict; use warnings; use utf8; use open qw (:std :utf8); use English qw ( -no_match_vars ); use Carp qw (carp cluck); use CHI; use CHI::Driver::BerkeleyDB; use DB_File; use Digest::MD5 qw (md5_base64); use File::Path qw (make_path); use Mojo::Log; use Mojo::UserAgent::Cached; use conf qw (loadConf); use util qw (trim urlencode); use version; our $VERSION = qw (1.0); use Exporter qw (import); our @EXPORT_OK = qw (weather); my $c = loadConf (); sub weather { my $city = shift; $city = trim $city; return 'Мне нужно ИМЯ города.' if ($city eq ''); return 'Длинновато для названия города.' if (length ($city) > 80); $city = ucfirst $city; my $w = __weather ($city); my $reply; if ($w) { if ($w->{temperature_min} == $w->{temperature_max}) { $reply = sprintf ( "Погода в городе %s, %s:\n%s, ветер %s %s м/c, температура %s°C, ощущается как %s°C, относительная влажность %s%%, давление %s мм.рт.с", $w->{name}, $w->{country}, ucfirst $w->{description}, $w->{wind_direction}, $w->{wind_speed}, $w->{temperature_min}, $w->{temperature_feelslike}, $w->{humidity}, $w->{pressure} ); } else { $reply = sprintf ( "Погода в городе %s, %s:\n%s, ветер %s %s м/c, температура %s-%s°C, ощущается как %s°C, относительная влажность %s%%, давление %s мм.рт.ст", $w->{name}, $w->{country}, ucfirst $w->{description}, $w->{wind_direction}, $w->{wind_speed}, $w->{temperature_min}, $w->{temperature_max}, $w->{temperature_feelslike}, $w->{humidity}, $w->{pressure} ); } } else { $reply = "Я не знаю, какая погода в $city"; } return $reply; } sub __weather { my $city = shift; $city = urlencode $city; my $appid = $c->{openweathermap}->{appid}; my $cachedir = $c->{openweathermap}->{cachedir}; my $now = time (); my $fc; my $w; my $r; # try 3 times and giveup for (1..3) { my $ua = Mojo::UserAgent::Cached->new; $ua->local_dir ($cachedir); $ua->cache_agent( CHI->new ( driver => 'BerkeleyDB', root_dir => $cachedir, namespace => __PACKAGE__, expires_in => '3 hours', expires_on_backend => 1, ) ); # just to make Mojo::UserAgent::Cached happy $ua->logger (Mojo::Log->new (path => '/dev/null', level => 'error')); $r = $ua->get (sprintf ('http://api.openweathermap.org/data/2.5/weather?q=%s&lang=ru&APPID=%s', $city, $appid))->result; if ($r->is_success) { last; } sleep 2; } # all 3 times can give error, so check it here if ($r->is_success) { $fc = eval { return $r->json; }; unless ($fc) { cluck "[WARN] openweathermap returns corrupted json: $EVAL_ERROR"; return undef; }; } else { cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message; return undef; } # TODO: check all of this for existence $w->{'name'} = $fc->{name}; $w->{'state'} = $fc->{state}; $w->{'country'} = $fc->{sys}->{country}; $w->{'longitude'} = $fc->{coord}->{lon}; $w->{'latitude'} = $fc->{coord}->{lat}; $w->{'temperature_min'} = int ($fc->{main}->{temp_min} - 273.15); $w->{'temperature_max'} = int ($fc->{main}->{temp_max} - 273.15); $w->{'temperature_feelslike'} = int ($fc->{main}->{feels_like} - 273.15); $w->{'humidity'} = $fc->{main}->{humidity}; $w->{'pressure'} = int ($fc->{main}->{pressure} * 0.75006375541921); $w->{'description'} = $fc->{weather}->[0]->{description}; $w->{'wind_speed'} = $fc->{wind}->{speed}; $w->{'wind_direction'} = 'разный'; my $dir = int ($fc->{wind}->{deg} + 0); if ($dir == 0) { $w->{'wind_direction'} = 'северный'; } elsif ($dir > 0 && $dir <= 30) { $w->{'wind_direction'} = 'северо-северо-восточный'; } elsif ($dir > 30 && $dir <= 60) { $w->{'wind_direction'} = 'северо-восточный'; } elsif ($dir > 60 && $dir < 90) { $w->{'wind_direction'} = 'восточно-северо-восточный'; } elsif ($dir == 90) { $w->{'wind_direction'} = 'восточный'; } elsif ($dir > 90 && $dir <= 120) { $w->{'wind_direction'} = 'восточно-юго-восточный'; } elsif ($dir > 120 && $dir <= 150) { $w->{'wind_direction'} = 'юговосточный'; } elsif ($dir > 150 && $dir < 180) { $w->{'wind_direction'} = 'юго-юго-восточный'; } elsif ($dir == 180) { $w->{'wind_direction'} = 'южный'; } elsif ($dir > 180 && $dir <= 210) { $w->{'wind_direction'} = 'юго-юго-западный'; } elsif ($dir > 210 && $dir <= 240) { $w->{'wind_direction'} = 'юго-западный'; } elsif ($dir > 240 && $dir < 270) { $w->{'wind_direction'} = 'западно-юго-западный'; } elsif ($dir == 270) { $w->{'wind_direction'} = 'западный'; } elsif ($dir > 270 && $dir <= 300) { $w->{'wind_direction'} = 'западно-северо-западный'; } elsif ($dir > 300 && $dir <= 330) { $w->{'wind_direction'} = 'северо-западный'; } elsif ($dir > 330 && $dir < 360) { $w->{'wind_direction'} = 'северо-северо-западный'; } elsif ($dir == 360) { $w->{'wind_direction'} = 'северный'; } return $w; } 1; # vim: set ft=perl noet ai ts=4 sw=4 sts=4: