Mercurial > lbo > hg > geohub
changeset 55:1cbade934726
Add IC/ICE train collection script.
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Thu, 03 Dec 2020 22:34:25 +0100 |
parents | 2d6770d7e8cf |
children | e47f25aef153 |
files | examples/track_ICE/README.md examples/track_ICE/collect.py |
diffstat | 2 files changed, 121 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/track_ICE/README.md Thu Dec 03 22:34:25 2020 +0100 @@ -0,0 +1,62 @@ +# `track_ICE` + +The German IC (InterCity) and ICE (InterCityExpress) trains have -- mostly -- +on-board Wi-Fi with entertainment and internet uplink. + +As any good nerd, we are not interested in some fringe German TV shows. We find +that to implement the live map on the website, DB has thankfully built a little +API: + +* `GET https://iceportal.de/api1/rs/status` + * Returns a JSON object. For example, in the last car of an ICE2: + +```json +{ + "connection": true, + "servicelevel": "AVAILABLE_SERVICE", + "internet": "HIGH", + "speed": 159, + "gpsStatus": "VALID", + "tzn": "Tz208", + "series": "807", + "latitude": 52.601715, + "longitude": 12.369854, + "serverTime": 1605641662281, + "wagonClass": "SECOND", + "navigationChange": "2020-11-17-16-04-20", + "trainType": "ICE" +} + +``` + +or a middle car of a doubledecker IC2: + +```json +{ + "connection": true, + "servicelevel": "AVAILABLE_SERVICE", + "internet": "MIDDLE", + "speed": 72, + "gpsStatus": "VALID", + "tzn": "ICD2871", + "series": "100", + "latitude": 50.96594, + "longitude": 7.019422, + "serverTime": 1606577933620, + "wagonClass": "SECOND", + "navigationChange": "2020-11-28-06-25-31", + "trainType": "IC" +} +``` + +We can now directly store and evaluate position and speed. And because we are +interested in the speed and internet quality of our train to evaluate at home, +let's send them as metadata along the coordinates. + +The enclosed python script does just that. Once run, it will + +* Fetch the current train data at a regular interval (5 seconds) +* Log it to a file consisting of JSON objects separated by newlines +* Send it to a configured URL. + +Run it with `--help` to obtain more info.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/track_ICE/collect.py Thu Dec 03 22:34:25 2020 +0100 @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# Collect speed data from a driving ICE/IC train. + +import requests + +import argparse +import json +import sys +import time + +def fetch_current(api): + return requests.get(api).json() + +def format_server_time(servertime): + return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(servertime/1000)) + +def send_point(args, info): + geohub_url = args.geohub.format(HOST=args.geohub_host, CLIENT=args.client or info.get('tzn', 'TRAIN'), SECRET=args.secret, PROTOCOL=args.geohub_scheme) + additional = '&lat={lat}&longitude={long}&spd={spd}&time={ts}'.format( + lat=info['latitude'], long=info['longitude'], spd=info['speed'], ts=format_server_time(info['serverTime'])) + url = geohub_url + additional + requests.post(url, json=info) + +def parse_args(): + parser = argparse.ArgumentParser(description='Fetch and send train data') + parser.add_argument('--api', default='https://iceportal.de/api1/rs/status', help='Location of train API') + parser.add_argument('--client', default='', help='Client name. By default, this will be the `tzn` (train number) of the current train.') + parser.add_argument('--secret', default='', help='Secret. This protects your current location; to share it, you have to share the secret. By default, the points will be made public on your GeoHub instance.') + parser.add_argument('--interval', default=5, help='Poll interval') + parser.add_argument('--outfile', default='traindata.jsonlines', help='Where to write the JSON data received from the train.') + parser.add_argument('--geohub_host', default='example.com', help='Host of your GeoHub. Use this if the URL --geohub works for you.') + parser.add_argument('--geohub_scheme', default='https', help='Protocol scheme of the GeoHub instance. Use this if you do not want to specify the entire --geohub URL') + parser.add_argument('--geohub', default='{PROTOCOL}://{HOST}/geo/{CLIENT}/log?secret={SECRET}', help='Base URL of Geohub instance. {PROTOCOL}, {CLIENT}, {HOST}, and {SECRET} will be replaced by the --geohub_scheme, --client, --geohub_host, and --secret values, respectively. This string must end in the URL query parameter section, ready to take more parameters.') + + return parser.parse_args() + +def run(args): + info = fetch_current(args.api) + if not info: + print('Empty info received!') + return + tzn = info['tzn'] + print('Running in train:', tzn) + + with open(args.outfile, 'w') as outfile: + while True: + send_point(args, info) + outfile.write(json.dumps(info)) + outfile.write('\n') + time.sleep(args.interval) + +def main(): + args = parse_args() + run(args) + + +if __name__ == '__main__': + main()