#!/usr/bin/perl # # This is a simple script which is designed to show the next 10 # departures from the given Tram Stop, by ID. # # This is used by my toy tram-display project: # # https://steve.fi/Hardware/helsinki-tram-times/ # # The ESP8266 could probably manage to do the job itself, # but parsing the output from this script (CSV) is significantly # simpler. # # (The ESP8266 has barely got the grunt to handle SSL requests # parsing simple JSON is possible, but I'm wary of memory allocations # and parsing larger objects.) # # Steve # -- # use strict; use warnings; use CGI; use JSON; use utf8; use LWP::UserAgent; # # Get the ID # my $cgi = new CGI; my $id = $cgi->param("id"); # # Ensure it was supplied and is solely numeric. # if ( !defined($id) || ( $id !~ /([0-9]+)/ ) ) { print "Content-type: text/plain\n\nMissing/Bogus ID\n"; exit(0); } # # Show the details. # printStop($id); # # All done # exit(0); sub printStop { my ($id) = (@_); # URL we hit my $uri = 'https://api.digitransit.fi/routing/v1/routers/hsl/index/graphql'; # GraphQL query-text. my $data = "{ stop(id: \"HSL:$id\") { name code desc stoptimesWithoutPatterns(numberOfDepartures:10){ scheduledArrival realtimeArrival realtime timepoint trip { route { id shortName longName } } } } }"; # POST with the correct content-type. my $req = HTTP::Request->new( 'POST', $uri ); $req->header( 'Content-Type' => 'application/graphql' ); $req->content($data); # Make the request. my $lwp = LWP::UserAgent->new; my $response = $lwp->request($req); # If we fail .. if ( !$response->is_success ) { print "Content-type: text/plain\n\n"; print "Failed: " . $response->status_line; exit(0); } # # Decode the response to JSON # my $json = JSON->new->allow_nonref; my $obj = $json->decode( $response->decoded_content() ); # # We assume success, output the header. # print "Content-type: text/plain; charset=UTF-8\n\n"; # # Now access the parts of the data we care about. # # This is horrid. # my $x = $obj->{ 'data' }; my $s = $x->{ 'stop' }; my $t = $s->{ 'stoptimesWithoutPatterns' }; # # For each departure show: # # Tram-Line [Two characters, always] # Time [HH:MM:SS] # Name [Could be non-ASCII.] # foreach my $a (@$t) { my $line = $a->{ 'trip' }{ 'route' }{ 'shortName' }; my $time = $a->{ 'realtimeArrival' } || $a->{ 'scheduledArrival' }; my $name = $a->{ 'trip' }->{ 'route' }->{ 'longName' }; # Simplify formattng on the receiving-side. $line = sprintf( "%2s", $line ); # Create HH:MM:SS from seconds-past-midnight. my $HMS = sprintf '%02d:%02d:%02d', $time / 3600, ( $time / 60 ) % 60, $time % 60; # Show the output. print "$line,$HMS,$name\n"; } }