package GPS::Garmin::Connect; use warnings; use strict; use LWP::UserAgent; use HTML::Form; use JSON; use Error; =head1 NAME GPS::Garmin::Connect - Allows simple fetching of activities from http://connect.garmin.com =head1 VERSION Version 0.01 =cut our $VERSION = '0.01'; =head1 SYNOPSIS This module is a simple helper to fetch and parse activities from http://connect.garmin.com use GPS::Garmin::Connect; my $connect = GPS::Garmin::Connect->new(); my $json = $connect->fetchdata( $username, $password ); my $activities = $connect->parse( $json ); foreach my $activity (@$activities) { print "My activity $activity->{activity} - HR: $activity->{heartrate}\n"; } =head1 FUNCTIONS =head2 new =cut sub new { my $self = shift; return bless { _loginurl => 'http://connect.garmin.com/signin', }, $self; } =head2 fetchdata $connect->fetchdata( $username, $password ); Logins into connect.garmin.com and fetches all activities and returns a JSON string which can be parsed using L. =cut sub fetchdata { my ($pkg, $username, $password) = @_; my $loginurl = $pkg->{_loginurl}; my $ua = LWP::UserAgent->new(); $ua->cookie_jar( { } ); push @{ $ua->requests_redirectable }, 'POST'; # Fetch login form to get a session id .. my $loginformreq = HTTP::Request->new(GET => $loginurl); my $loginformres = $ua->request($loginformreq); throw Error::Simple('Error while requesting login form: ' . $loginformres->status_line) unless $loginformres->is_success; my $loginform = HTML::Form->parse($loginformres->content, $loginurl); $loginform->value( 'login:loginUsernameField' => $username ); $loginform->value( 'login:password' => $password ); # Send login request .. my $loginres = $ua->request($loginform->click); if ($loginres->is_success) { # we successfully logged in (probably) } else { throw Error::Simple("Error while trying to log in: ".$loginres->status_line); } # We can now retrieve our activity ... my $req = HTTP::Request->new(GET => 'http://connect.garmin.com/proxy/activity-search-service-1.0/json/activities?_dc=1220170621856&start=0&limit=50'); my $res = $ua->request($req); if ($res->is_success) { return $res->content; } else { throw Error::Simple("error while requesting activities (".$res->status_line.")"); } } =head2 parse method responsible for parsing the json data and returning a simplified array ref of hash refs: $VAR1 = [ { 'begindate' => '2009-02-17', 'distance' => 3156, 'name' => 'Untitled', 'heartrate' => 162, 'duration' => 1980, 'activity' => 'Untitled', 'activityid' => '2194739', 'id' => '2194739', 'type' => 'Uncategorized', 'begin' => 'Tue, Feb 17 \'09 08:27 AM' }, { 'begindate' => '2009-02-17', 'distance' => 2200, 'name' => 'Untitled', 'heartrate' => 157, 'duration' => 1500, 'activity' => 'Untitled', 'activityid' => '2194738', 'id' => '2194738', 'type' => 'Uncategorized', 'begin' => 'Tue, Feb 17 \'09 08:02 AM' }, =cut sub parse { my ($pkg, $content) = @_; my $json = JSON->new(); my $results = $json->decode($content); my $activities = $results->{results}->{activities}; my $simpleactivities = []; foreach my $activity (@$activities) { my $a = $activity->{activity}; # convert it to something more "userfriendly" my $hr = undef; if ($a->{weightedMeanHeartRate}) { $hr = int($a->{weightedMeanHeartRate}->{value}); } my $durstr = $a->{sumDuration}->{display}; my ($hrs, $min, $sec) = split(/:/,$durstr); my $duration = (($hrs * 60) + $min) * 60 + $sec; my $ac = { 'id' => $a->{activityId}, 'activityid' => $a->{activityId}, 'activity' => $a->{activityName}->{value}, 'name' => $a->{activityName}->{value}, 'type' => $a->{activityType}->{display}, 'distance' => int($a->{sumDistance}->{value}*1000),#sprintf("%.2f",$a->{sumDistance}->{value}), 'duration' => $duration, 'begin' => $a->{beginTimestamp}->{display}, 'begindate' => $a->{beginTimestamp}->{value}, 'heartrate' => $hr, }; push(@$simpleactivities, $ac); } return $simpleactivities; } =head1 AUTHOR Herbert Poul, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc GPS::Garmin::Connect You can also look for information at: =over 4 =item * RT: CPAN's request tracker L =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =item * Search CPAN L =back =head1 ACKNOWLEDGEMENTS =head1 COPYRIGHT & LICENSE Copyright 2009 Herbert Poul, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # End of GPS::Garmin::Connect