summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerf Null <derf@finalrewind.org>2023-04-07 14:49:32 +0200
committerDerf Null <derf@finalrewind.org>2023-04-07 14:49:32 +0200
commit915bad108d838716c17ac605d13d59624b2bc539 (patch)
tree2157b0a02a17359c98e18978e0a1b705771b81ba
parent809f1910da538bffb0e671eb3965f28d5e60237a (diff)
add geoSearch mode
-rwxr-xr-xbin/hafas-m21
-rw-r--r--lib/Travel/Status/DE/HAFAS.pm145
2 files changed, 139 insertions, 27 deletions
diff --git a/bin/hafas-m b/bin/hafas-m
index 2b6c2d0..53f232b 100755
--- a/bin/hafas-m
+++ b/bin/hafas-m
@@ -59,7 +59,14 @@ my %opt = (
service => $service,
);
-if ( $opt{station} =~ m{[|]} ) {
+if ( $opt{station} =~ m{ ^ (?<lat> [0-9.]+ ) : (?<lon> [0-9].+ ) $ }x ) {
+ $opt{geoSearch} = {
+ lat => $+{lat},
+ lon => $+{lon},
+ };
+ delete $opt{station};
+}
+elsif ( $opt{station} =~ m{[|]} ) {
$opt{journey} = { id => $opt{station} };
delete $opt{station};
}
@@ -234,7 +241,17 @@ if ( my $err = $status->errstr ) {
exit 2;
}
-if ( $opt{journey} ) {
+if ( $opt{geoSearch} ) {
+ for my $result ( $status->results ) {
+ printf(
+ "%5.1f km %8d %s\n",
+ $result->{distance_m} * 1e-3,
+ $result->{eva}, $result->{name}
+ );
+ }
+ exit 0;
+}
+elsif ( $opt{journey} ) {
my $result = $status->result;
printf( "%s → %s", $result->name, $result->route_end );
diff --git a/lib/Travel/Status/DE/HAFAS.pm b/lib/Travel/Status/DE/HAFAS.pm
index da6eb47..9bf33f1 100644
--- a/lib/Travel/Status/DE/HAFAS.pm
+++ b/lib/Travel/Status/DE/HAFAS.pm
@@ -192,8 +192,8 @@ sub new {
$ua->env_proxy;
}
- if ( not $conf{station} and not $conf{journey} ) {
- confess('station or journey must be specified');
+ if ( not( $conf{station} or $conf{journey} or $conf{geoSearch} ) ) {
+ confess('station / journey / geoSearch must be specified');
}
if ( not defined $service ) {
@@ -238,6 +238,37 @@ sub new {
%{ $hafas_instance{$service}{request} }
};
}
+ elsif ( $conf{geoSearch} ) {
+ $req = {
+ svcReqL => [
+ {
+ cfg => { polyEnc => 'GPA' },
+ meth => 'LocGeoPos',
+ req => {
+ ring => {
+ cCrd => {
+ x => int( $conf{geoSearch}{lon} * 1e6 ),
+ y => int( $conf{geoSearch}{lat} * 1e6 ),
+ },
+ maxDist => -1,
+ minDist => 0,
+ },
+ locFltrL => [
+ {
+ type => "PROD",
+ mode => "INC",
+ value => $self->mot_mask
+ }
+ ],
+ getPOIs => \0,
+ getStops => \1,
+ maxLoc => 10,
+ }
+ }
+ ],
+ %{ $hafas_instance{$service}{request} }
+ };
+ }
else {
my $date = ( $conf{datetime} // $now )->strftime('%Y%m%d');
my $time = ( $conf{datetime} // $now )->strftime('%H%M%S');
@@ -340,6 +371,9 @@ sub new {
if ( $conf{journey} ) {
$self->parse_journey;
}
+ elsif ( $conf{geoSearch} ) {
+ $self->parse_geosearch;
+ }
else {
$self->parse_board;
}
@@ -366,6 +400,9 @@ sub new_p {
if ( $conf{journey} ) {
$self->parse_journey;
}
+ elsif ( $conf{geoSearch} ) {
+ $self->parse_geosearch;
+ }
else {
$self->parse_board;
}
@@ -575,6 +612,35 @@ sub add_message {
return $message;
}
+sub parse_geosearch {
+ my ($self) = @_;
+
+ $self->{results} = [];
+
+ if ( $self->{errstr} ) {
+ return $self;
+ }
+
+ my @refLocL = @{ $self->{raw_json}{svcResL}[0]{res}{common}{locL} // [] };
+ my @locL = @{ $self->{raw_json}{svcResL}[0]{res}{locL} // [] };
+
+ for my $loc (@locL) {
+ push(
+ @{ $self->{results} },
+ {
+ eva => 0 + $loc->{extId},
+ name => $loc->{name},
+ lat => $loc->{crd}{x} * 1e-6,
+ lon => $loc->{crd}{y} * 1e-6,
+ weight => $loc->{wt},
+ distance_m => $loc->{dist},
+ }
+ );
+ }
+
+ return $self;
+}
+
sub parse_journey {
my ($self) = @_;
@@ -603,6 +669,8 @@ sub parse_journey {
polyline => \@polyline,
hafas => $self,
);
+
+ return $self;
}
sub parse_board {
@@ -810,8 +878,9 @@ version 4.08
Travel::Status::DE::HAFAS is an interface to HAFAS-based
arrival/departure monitors using the mgate.exe interface.
-It can report departures/arrivals at a specific station, or provide details
-about a specific journey. It supports non-blocking operation via promises.
+It can report departures/arrivals at a specific station, search for stations,
+or provide details about a specific journey. It supports non-blocking operation
+via promises.
=head1 METHODS
@@ -819,11 +888,11 @@ about a specific journey. It supports non-blocking operation via promises.
=item my $status = Travel::Status::DE::HAFAS->new(I<%opt>)
-Requests departures/arrivals/journey as specified by I<opt> and returns a new
+Requests item(s) as specified by I<opt> and returns a new
Travel::Status::DE::HAFAS element with the results. Dies if the wrong
I<opt> were passed.
-I<opt> must contain either a B<station> or a B<journey> flag:
+I<opt> must contain either a B<station>, a B<geoSearch>, or a B<journey> flag:
=over
@@ -834,6 +903,11 @@ Request station board (arrivals or departures) for I<station>, e.g. "Essen HBf"
EVA ID (e.g. 8000080 for Dortmund Hbf).
Results are available via C<< $status->results >>.
+=item B<geoSearch> => B<{> B<lat> => I<latitude>, B<lon> => I<longitude> B<}>
+
+Search for stations near I<latitude>, I<longitude>.
+Results are available via C<< $status->results >>.
+
=item B<journey> => B<{> B<id> => I<tripid> [, B<name> => I<line> ] B<}>
Request details about the journey identified by I<tripid> and I<line>.
@@ -841,14 +915,16 @@ The result is available via C<< $status->result >>.
=back
-The following optional flags may be set:
+The following optional flags may be set.
+Values in brackets indicate flags that are only relevant in certain request
+modes, e.g. geoSearch or journey.
=over
-=item B<arrivals> => I<bool>
+=item B<arrivals> => I<bool> (station)
Request arrivals (if I<bool> is true) rather than departures (if I<bool> is
-false or B<arrivals> is not specified). Only relevant in station board mode.
+false or B<arrivals> is not specified).
=item B<cache> => I<Cache::File object>
@@ -856,41 +932,37 @@ Store HAFAS replies in the provided cache object. This module works with
real-time data, so the object should be configured for an expiry of one to two
minutes.
-=item B<datetime> => I<DateTime object>
+=item B<datetime> => I<DateTime object> (station)
-Date and time to report for. Defaults to now. Only relevant in station board mode.
+Date and time to report for. Defaults to now.
-=item B<excluded_mots> => [I<mot1>, I<mot2>, ...]
+=item B<excluded_mots> => [I<mot1>, I<mot2>, ...] (geoSearch, station)
By default, all modes of transport (trains, trams, buses etc.) are returned.
If this option is set, all modes appearing in I<mot1>, I<mot2>, ... will
be excluded. The supported modes depend on B<service>, use
B<get_services> or B<get_service> to get the supported values.
-Only relevant in station board mode.
-=item B<exclusive_mots> => [I<mot1>, I<mot2>, ...]
+=item B<exclusive_mots> => [I<mot1>, I<mot2>, ...] (geoSearch, station)
If this option is set, only the modes of transport appearing in I<mot1>,
I<mot2>, ... will be returned. The supported modes depend on B<service>, use
B<get_services> or B<get_service> to get the supported values.
-Only relevant in station board mode.
-=item B<lookahead> => I<int>
+=item B<lookahead> => I<int> (station)
Request arrivals/departures that occur up to I<int> minutes after the specified datetime.
Default: -1 (do not limit results by time).
-Only relevant in station board mode.
=item B<lwp_options> => I<\%hashref>
Passed on to C<< LWP::UserAgent->new >>. Defaults to C<< { timeout => 10 } >>,
pass an empty hashref to call the LWP::UserAgent constructor without arguments.
-=item B<results> => I<count>
+=item B<results> => I<count> (geoSearch, station)
Request up to I<count> results.
Default: 30.
-Only relevant in station board mode.
=item B<service> => I<service>
@@ -898,10 +970,9 @@ Request results from I<service>, defaults to "DB".
See B<get_services> (and C<< hafas-m --list >>) for a list of supported
services.
-=item B<with_polyline> => I<bool>
+=item B<with_polyline> => I<bool> (journey)
Request a polyline (series of geo-coordinates) indicating the train's route.
-Only relevant in journey mode.
=back
@@ -936,18 +1007,42 @@ as string. If no backend error occurred, returns undef.
In case of an error in the HTTP request or HAFAS backend, returns a string
describing it. If no error occurred, returns undef.
-=item $status->results
+=item $status->results (geoSearch)
+
+Returns a list of stations. Each list element is a hash ref with the following
+keys.
+
+=over
+
+=item * eva (identifier / EVA code)
+
+=item * name
+
+=item * lat (latitude)
+
+=item * lon (longitude)
+
+=item * distance_m (distance from requested coordinates, in meters)
+
+=item * weight (relevance / importance of result, unknown metric)
+
+=back
+
+If no matching results were found or the parser / http request failed, returns
+an empty list.
+
+=item $status->results (station)
Returns a list of arrivals/departures. Each list element is a
-Travel::Status::DE::HAFAS::Journey(3pm) object. Unavailable in journey mode.
+Travel::Status::DE::HAFAS::Journey(3pm) object.
If no matching results were found or the parser / http request failed, returns
undef.
-=item $status->result
+=item $status->result (journey)
Returns a single Travel::Status::DE::HAFAS::Journey(3pm) object that describes
-the requested journey. Unavailable in station board mode.
+the requested journey.
If no result was found or the parser / http request failed, returns undef.