From 6bfcd8a348962f0357372f4e74c286f93e6eec26 Mon Sep 17 00:00:00 2001 From: makefu Date: Wed, 6 Dec 2017 13:52:53 +0100 Subject: setup.py: init --- ampel/__init__.py | 0 ampel/ampel.py | 141 ++++++++++++++++++ ampel/fade.py | 78 ++++++++++ ampel/google-muell.py | 111 ++++++++++++++ ampel/muell.py | 62 ++++++++ ampel/vvs_efa/README.md | 61 ++++++++ ampel/vvs_efa/VVS_EFA.py | 358 ++++++++++++++++++++++++++++++++++++++++++++++ ampel/vvs_efa/__init__.py | 0 8 files changed, 811 insertions(+) create mode 100644 ampel/__init__.py create mode 100755 ampel/ampel.py create mode 100755 ampel/fade.py create mode 100755 ampel/google-muell.py create mode 100755 ampel/muell.py create mode 100644 ampel/vvs_efa/README.md create mode 100644 ampel/vvs_efa/VVS_EFA.py create mode 100644 ampel/vvs_efa/__init__.py (limited to 'ampel') diff --git a/ampel/__init__.py b/ampel/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ampel/ampel.py b/ampel/ampel.py new file mode 100755 index 0000000..effec24 --- /dev/null +++ b/ampel/ampel.py @@ -0,0 +1,141 @@ +#! /usr/bin/env python3 +#! nix-shell -i python3 -p python3 python35Packages.docopt python35Packages.paho-mqtt +""" usage: ampel [options] NUMLEDS + + --mqtt-server=HOST path to mqtt server [Default: 192.168.8.11] + --influx-server=HOST path to influxdb server [Default: 192.168.8.11] + --no-mqtt disable mqtt connections for debugging + --no-influx disable sending stats to influxdb + +NUMLEDS is the number of leds to output data for (--add-empty does not count in here) + +13 22 24 26 28 +|-----------|----|----|----| +BLUE GR YEL RED BLUE + EEN LOW +""" +from docopt import docopt +from influxdb import InfluxDBClient +from ampel.fade import calc_chain +import time +from time import sleep +import json +import sys +from datetime import datetime, timedelta +import requests +import logging as log +log.basicConfig(level=log.INFO) + +import paho.mqtt.client as mqtt + +thalesplatz = "5003035" +ditzingen = "5007000" + +red = timedelta(minutes=2) +orange = timedelta(minutes=3) +yellow = timedelta(minutes=4) +green = timedelta(minutes=6) +maxtime = timedelta(minutes=15) + + +def fetch_data(): + from datetime import datetime as dt + from vvs_efa import VVS_EFA + efa = VVS_EFA.EFA() + now = dt.now() + conns = efa.get_next_connections( + "Ditzingen Thalesplatz", + "Hauptbahnhof (tief)", + now, + True) + for dep in conns: + if now < dep.time_of_departure: + return dep.time_of_departure + + +def main(): + args = docopt(__doc__) + db = "telegraf" + numleds = int(args['NUMLEDS']) + mqtt_server = args["--mqtt-server"] + influx_server = args["--influx-server"] + no_mqtt = args["--no-mqtt"] + no_influx = args["--no-influx"] + + t = fetch_data() + if not no_mqtt: + log.info("Starting MQTT") + mq = mqtt.Client() + mq.connect(mqtt_server,1883,60) + mq.loop_start() + pub = lambda topic,data: mq.publish(topic,data) + else: + pub = lambda topic,data: log.info("topic: {}\ndata: {}".format(topic,data)) + if not no_influx: + log.info("preparing influxdb") + client = InfluxDBClient(host=influx_server, port=8086, database=db) + msg = { + "measurement": "seconds_to_bus", + "tags": { + "": "thalesplatz" + }, + "time": "2009-11-10T23:00:00Z", + "fields": { + "value": 0.64 + } + } + + sendstat = lambda secs: client.write_points([ { + "measurement": "seconds_to_bus", + "tags": { "station": "thalesplatz" }, + "fields": { "value": secs } }]) + else: + log.info("No influx") + sendstat = lambda secs: log.info("stat {} -> {} secs".format(datetime.now().replace(microsecond=0).isoformat(),secs)) + + val = 0.0 + step = 0.01 + oldstate = state = None + while True: + ret = [] + now = datetime.now() + + + if now > t: + t = fetch_data() + + delta = t - now + sendstat(delta.seconds + delta.days*86400) + deltastr = str(delta).split('.', 2)[0] + + if not ( (t - maxtime) < now < t): + log.info("Bus too far away - {}".format(deltastr)) + ret = calc_chain(3,val) + ret.insert(0,[0,0,0]) + pub("/leds/nodemcu-switcher/set",json.dumps(ret)) + val += step % 1 + else: + log.info("{}:{:02d} -> {}:{:02d} delta: {}".format( + now.hour,now.minute,t.hour,t.minute,deltastr)) + if (t-red) < now < t: + state = "red" + ret = [[255,0,0]] * 4 + elif (t-orange) < now < t: + state = "orange" + ret = [[255,128,0]] * 4 + elif (t-yellow) < now < t: + state = "yellow" + ret = [[255,255,0]] * 4 + elif (t-green) < now < t: + state = "green" + ret = [[0,255,0]] * 4 + else: + state = "blue" + ret = [[0,0,255]] * 4 + if oldstate != state: + oldstate = state + pub("/leds/nodemcu-switcher/set",json.dumps(ret)) + sleep(1) + +if __name__ == "__main__": + main() diff --git a/ampel/fade.py b/ampel/fade.py new file mode 100755 index 0000000..8aea815 --- /dev/null +++ b/ampel/fade.py @@ -0,0 +1,78 @@ +#! /usr/bin/env python3 +#! nix-shell -i python3 -p python3 python35Packages.docopt +""" usage: run [options] NUMLEDS (loop [--skip-unchanged] [STEP] [DELAY]|single STARTVAL) + + --add-empty essentially add a single empty led in front, does not count into NUMLEDS + + --mode=TYPE mode of fading (Default: chain) + --output=TYPE output type, either json or raw (Default: json) + --skip-unchanged if the value in the loop is unchanged, skip the output + +running with loop this script essentially becomes a generator which outputs the +next value each "DELAY" +single returns a single output with STARTVAL as starting point for the first led + +NUMLEDS is the number of leds to output data for (--add-empty does not count in here) +STEP defaults to 0.01 +DELAY defaults to 1 second + +""" +from docopt import docopt +import time +from colorsys import hsv_to_rgb +import json +import sys + +def calc_chain(numleds,val): + divisor = 1.0 / numleds + ret = [] + for i in range(numleds): + v = float(divisor * i + val) % 1 + r,g,b = hsv_to_rgb(v,0.9,1) + ret.append([int(r*255), + int(g*255), + int(b*255)]) + return ret + +def calc_single(numleds,val): + ret = [] + for i in range(numleds): + r,g,b = hsv_to_rgb(val,1,1) + ret.append([int(r*255), + int(g*255), + int(b*255)]) + return ret + +def main(): + args = docopt(__doc__) + numleds = int(args['NUMLEDS']) + mode = args['--mode'] + step = float(args['STEP'] or 0.01) + delay = float(args['DELAY'] or 1) + val = float(args['STARTVAL'] or 0) + last = [] + while True: + if mode == "chain": + ret = calc_chain(numleds,val) + elif mode == "single": + ret = calc_single(numleds,val) + + if args['--add-empty']: + ret.insert(0,[0,0,0]) + + # early serialization makes comparsion easy + ret = json.dumps(ret) + if not (args['--skip-unchanged'] and last == ret): + last = ret + print(ret) + sys.stdout.flush() + if args['single']: + break + else: + val += step % 1 + time.sleep(delay) + + + +if __name__ == "__main__": + main() diff --git a/ampel/google-muell.py b/ampel/google-muell.py new file mode 100755 index 0000000..b3652cb --- /dev/null +++ b/ampel/google-muell.py @@ -0,0 +1,111 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python3 -p python3 python36Packages.docopt python36Packages.requests2 python36Packages.google_api_python_client python36Packages.dateutil +""" usage: google-muell [options] + + --esp=HOST esp8266 ip [Default: 192.168.1.23] + --client-secrets=FILE Path to client secrets file (from application) [Default: licht-kalender-secrets.json] + --credential-path=PATH Path to newly generated (or existing) credentials [Default: licht-creds.json] + --sleepval=SEC seconds to sleep [Default: 900] + +you can create the client-secrets by creating a new google application, create +oauth2 token and download it ( url here) + +""" +from docopt import docopt +from fade import calc_chain +import time +from time import sleep +import json +import sys +from datetime import datetime, timedelta +import requests + +import httplib2 +from dateutil.parser import parse +from apiclient import discovery +from oauth2client import client +from oauth2client import tools +from oauth2client.file import Storage +SCOPES = 'https://www.googleapis.com/auth/calendar.readonly' +APPLICATION_NAME = 'licht-kalender-client' + +colormap = { + "8": [ 128,128,128 ], # grey + "9": [ 0,0,0 ], # blue + "11": [ 0,0,0 ],# true red + "4": [ 0,0,0 ], # light red + "3": [ 0,0,0 ], # purple + } + +def get_creds(secrets_file,credential_path): + ''' + provide a cred_dir where the credentials would be stored to + ''' + import argparse + flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() + + store = Storage(credential_path) + credentials = store.get() + if not credentials or credentials.invalid: + flow = client.flow_from_clientsecrets(secrets_file, SCOPES) + flow.user_agent = APPLICATION_NAME + credentials = tools.run_flow(flow, store, flags) + print('Storing new credentials to ' + credential_path) + else: + print('Using existing valid credentials ' + credential_path) + + return credentials + +def next_date(credentials): + http = credentials.authorize(httplib2.Http()) + service = discovery.build('calendar', 'v3', http=http) + + #page_token = None + #while True: + # calendar_list = service.calendarList().list( + # pageToken=page_token).execute() + # for calendar_list_entry in calendar_list['items']: + # print("{} - {}".format(calendar_list_entry['id'],calendar_list_entry['summary'])) + # page_token = calendar_list.get('nextPageToken') + # if not page_token: + # break + + + now = datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time + print('Getting the upcoming 10 events') + eventsResult = service.events().list( + calendarId='o56ig681gla2a5vupm4vgiv7tc@group.calendar.google.com', timeMin=now, maxResults=10, singleEvents=True, + orderBy='startTime').execute() + events = eventsResult.get('items', []) + for event in events: + start = parse(event['start'].get('dateTime', event['start'].get('date'))) + if 'dateTime' in event['end']: + end = parse(event['end']['dateTime']) + else: + end = parse(event['end']['date']) + timedelta(days=1) - timedelta(seconds=1) + + if start < datetime.now() < end: + print("event is active now") + print(start,end, event) + + + pass + + +def to_payload(arr): + return {"r":arr[0],"g":arr[1],"b":arr[2]} + +def main(): + args = docopt(__doc__) + client_secrets = args['--client-secrets'] + sleepval = float(args["--sleepval"]) + esp = args["--esp"] + cred_path = args["--credential-path"] + creds = get_creds(client_secrets,cred_path) + while True: + t = next_date(creds) + requests.get("http://{}/color".format(esp),params=to_payload(t)) + sleep(sleepval) + +if __name__ == "__main__": + main() diff --git a/ampel/muell.py b/ampel/muell.py new file mode 100755 index 0000000..3b84f02 --- /dev/null +++ b/ampel/muell.py @@ -0,0 +1,62 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python3 -p python3 python35Packages.docopt python35Packages.requests2 +""" usage: ampel [options] TIMEFILE + + --esp=HOST esp8266 ip [Default: 192.168.1.23] + --sleepval=SEC seconds to sleep [Default: 900] + +TIMEFILE refers to a json file which contains all the dates where the bus +drives + +""" +from docopt import docopt +from fade import calc_chain +import time +from time import sleep +import json +import sys +from datetime import datetime, timedelta +import requests + +# time before the day +timebefore = timedelta(hours=24) + +colors = { + "gelber_sack": [ 255,255,0 ], + "orchis": [ 45, 255, 0 ], + "papiermuell": [ 0,0,255 ], + "restmuell": [ 0, 255, 15 ], + "kehrwoche": [ 226, 96, 255 ], + "fallback": [ 66, 220, 244] +} + +def next_date(now,db): + # now = datetime.now() + for e in db: #times are sorted + name = list(e.keys())[0] + times = e[name] + for time in times: + y,m,d = [ int(i) for i in time.split("-") ] + t = datetime.now().replace(year=y,month=m,day=d, + hour=9,minute=0,second=0,microsecond=0) + if (t - timebefore) < now < t: + return name + return "fallback" + +def to_payload(arr): + return {"r":arr[0],"g":arr[1],"b":arr[2]} + +def main(): + args = docopt(__doc__) + times = json.load(open(args['TIMEFILE'])) + sleepval = float(args["--sleepval"]) + esp = args["--esp"] + while True: + now = datetime.now() + t = next_date(now,times) + print(t) + requests.get("http://{}/color".format(esp),params=to_payload(colors[t])) + sleep(sleepval) + +if __name__ == "__main__": + main() diff --git a/ampel/vvs_efa/README.md b/ampel/vvs_efa/README.md new file mode 100644 index 0000000..0dae508 --- /dev/null +++ b/ampel/vvs_efa/README.md @@ -0,0 +1,61 @@ +##VVS API Wrapper + +This was created for easy access to the VVS EFA (Elektronische Fahrplanauskunft) in Python. + +### Example + +```python +# coding: utf-8 +import datetime as dt +from vvs_efa import VVS_EFA + +vvs_efa = VVS_EFA.EFA() +connections = vvs_efa.get_next_connections("Stadtbibliothek", "Feuersee", dt.datetime(2015, 7, 7, 7, 20), True) + + +print connections[0].origin.name +print connections[0].destination.name +print connections[0].time_of_departure.strftime("%d.%m.%Y - %H:%M") + " - " + connections[0].time_of_arrival.strftime("%d.%m.%Y - %H:%M") +print str(connections[0].fare) + "€ / " + str(connections[0].zones) + " Zone(n)" +print "" +for leg in connections[0].legs: + print leg.time_of_departure.strftime("%H:%M") + " - " + leg.time_of_arrival.strftime("%H:%M") + ": " + print leg.origin.name + " - " + leg.destination.name + " ("+ leg.line + ")" + "\n" + + +charlottenplatz = VVS_EFA.Stop("Charlottenplatz") +charlottenplatz_departures = charlottenplatz.get_next_connections(dt.datetime(2015, 7, 9, 18, 10), True) + +print charlottenplatz_departures[0].stop_id +print charlottenplatz_departures[0].stop_name +print charlottenplatz_departures[0].scheduled_datetime.strftime("%d.%m.%Y - %H:%M") +print charlottenplatz_departures[0].realtime_datetime.strftime("%d.%m.%Y - %H:%M") +print charlottenplatz_departures[0].serving_line.key +print charlottenplatz_departures[0].serving_line.number +print charlottenplatz_departures[0].serving_line.direction +print charlottenplatz_departures[0].serving_line.direction_from +print charlottenplatz_departures[0].serving_line.line_type + +``` + +results in: + +``` +Stuttgart, Stadtbibliothek +Stuttgart, Feuersee +06.07.2015 - 07:20 - 06.07.2015 - 07:31 +2.3€ / 2 Zone(n) +07:20 - 07:22: Stadtbibliothek - Hauptbf (A.-Klett-Pl.) (U12) +07:24 - 07:28: Hauptbf (Arnulf-Klett-Platz) - Stuttgart Hauptbahnhof (tief) () +07:28 - 07:31: Stuttgart Hauptbahnhof (tief) - Feuersee (S6) + +5006075 +Charlottenplatz +09.07.2015 - 18:05 +09.07.2015 - 18:11 +143 +43 +Feuersee +Killesberg +Bus +``` diff --git a/ampel/vvs_efa/VVS_EFA.py b/ampel/vvs_efa/VVS_EFA.py new file mode 100644 index 0000000..3a3ca3d --- /dev/null +++ b/ampel/vvs_efa/VVS_EFA.py @@ -0,0 +1,358 @@ +# coding: utf-8 + +import datetime as dt +import requests +import pytz +class EFA(object): + + def __init__(self): + + pass + + @classmethod + def convert_name_to_id(cls, name, mobile=False): + if name.strip() != "": #check if string is empty -> return None + if mobile: + request_url = "http://m.vvs.de/jqm/controller/XSLT_STOPFINDER_REQUEST" + parameters = {} + parameters["name_sf"] = name + parameters["language"] = "de" + parameters["stateless"] = "1" + parameters["locationServerActive"] = "1" + parameters["anyObjFilter_sf"] = "0" + parameters["anyMaxSizeHitList"] = "500" + parameters["outputFormat"] = "JSON" + parameters["SpEncId"] = "0" + parameters["type_sf"] = "any" + parameters["anySigWhenPerfectNoOtherMatches"] = "1" + parameters["convertAddressesITKernel2LocationServer"] = "1" + parameters["convertCoord2LocationServer"] = "1" + parameters["convertCrossingsITKernel2LocationServer"] = "1" + parameters["convertStopsPTKernel2LocationServer"] = "1" + parameters["convertPOIsITKernel2LocationServer"] = "1" + parameters["tryToFindLocalityStops"] = "1" + parameters["w_objPrefAl"] = "12" + parameters["w_regPrefAm"] = "1" + + else: + request_url = "http://www2.vvs.de/vvs/XSLT_STOPFINDER_REQUEST" + parameters = {} + parameters["suggest_macro"] = "vvs" + parameters["name_sf"] = name + + req = requests.post(request_url, parameters) + + points = req.json()["stopFinder"]["points"] + + + best_point_index = 0 + + if len(points) > 1: + for index, point in enumerate(points): + if point["best"] == "1": + best_point_index = index + break + + return points[best_point_index]["stateless"] + + elif len(points) == 1: + return points["point"]["stateless"] #if one point found (no array to iterate!) -> directly return + + else: + return None #no points found -> return None + + else: + return None + + + def get_next_connections(self, origin, destination, datetime, departure, search_by_name = True): + + """Get connections for parameter set: + origin: name of origin + destination: name of destination + time: datetime object of departure/arrival + departure: boolean --> true: time of departure; false: time of arrival + search_by_name: boolean --> true: search by name; false: search by id""" + + if search_by_name: + id_origin = self.convert_name_to_id(origin) + id_destination = self.convert_name_to_id(destination) + if id_origin == None: + raise TypeError('Origin not valid or not found.') + if id_destination == None: + raise TypeError('Destination not valid or not found.') + + else: + id_origin = origin + id_destination = destination + + request_url = "http://m.vvs.de/jqm/controller/XSLT_TRIP_REQUEST2" + + parameters = {} + + #parameters["genC"] = "1" + #parameters["itOptionsActive"] = "1" + #parameters["locationServerActive"] = "1" + #parameters["ptOptionsActive"] = "1" + parameters["stateless"] = "1" + parameters["name_origin"] = id_origin + parameters["name_destination"] = id_destination + parameters["type_destination"] = "any" + parameters["type_origin"] = "any" + parameters["use_realtime"] = "1" + parameters["itdTime"] = datetime.strftime("%H%M") #"2105" + parameters["date"] = datetime.strftime("%Y%m%d") #"20141216" + + if departure: + parameters["itdTripDateTimeDepArr"] = "dep" + else: + parameters["itdTripDateTimeDepArr"] = "arr" + + parameters["routeType"] = "LEASTTIME" + parameters["changeSpeed"] = "normal" + + #parameters["includedMeans"] = "checkbox" #does only work when inclMOT_x set + #parameters["inclMOT_0"] = "1" + #parameters["inclMOT_1"] = "1" + #parameters["inclMOT_2"] = "1" + #parameters["inclMOT_3"] = "1" + #parameters["inclMOT_4"] = "1" + #parameters["inclMOT_5"] = "1" + #parameters["inclMOT_6"] = "1" + #parameters["inclMOT_7"] = "1" + #parameters["inclMOT_8"] = "1" + #parameters["inclMOT_9"] = "1" + #parameters["inclMOT_10"] = "1" + #parameters["inclMOT_11"] = "1" + #parameters["inclMOT_12"] = "1" + #parameters["inclMOT_13"] = "1" + #parameters["inclMOT_14"] = "1" + #parameters["inclMOT_15"] = "1" + #parameters["inclMOT_16"] = "1" + #parameters["inclMOT_17"] = "1" + + parameters["outputFormat"] = "JSON" + + #parameters["SpEncId"] = "0" + #parameters["anySigWhenPerfectNoOtherMatches"] = "1" + #parameters["convertStopsPTKernel2LocationServer"] = "1" + #parameters["convertPOIsITKernel2LocationServer"] = "1" + #parameters["verifyAnyLocViaLocServer"] = "1" + #parameters["w_objPrefAl"] = "12" + #parameters["w_regPrefAm"] = "1" + #parameters["calcOneDirection"] = "1" #if not set, first trip is last trip before date/time for departure, else first trip after date/time + #parameters["searchLimitMinutes"] = "360" + + + req = requests.post(request_url, parameters) + + data = req.json() + trips = data["trips"] + trip_objs = [] + + if trips != None: + for trip in trips: + #Trip attributes + #trip_duration = trip["duration"] + trip_fare = float(trip["itdFare"]["fares"]["fare"]["fareAdult"]) + trip_zones = abs(int(trip["itdFare"]["tariffZones"]["tariffZone"]["toPR"]) - int(trip["itdFare"]["tariffZones"]["tariffZone"]["fromPR"])) + trip_origin = Location(name = data["origin"]["points"]["point"]["name"], loc_id = data["origin"]["points"]["point"]["stateless"], loc_type = data["origin"]["points"]["point"]["anyType"]) + trip_destination = Location(name = data["destination"]["points"]["point"]["name"], loc_id = data["destination"]["points"]["point"]["stateless"], loc_type = data["destination"]["points"]["point"]["anyType"]) + + #print "Dauer: %s \nPreis: %s\n" % (trip_duration, trip_fare) + + trip_legs = [] + for leg in trip["legs"]: + origin = Location(name=leg["points"][0]["name"], loc_id=leg["points"][0]["ref"]["id"]) + destination = Location(name=leg["points"][1]["name"], loc_id=leg["points"][1]["ref"]["id"]) + + origin_realtime_date = leg["points"][0]["dateTime"]["rtDate"] #17.12.2014 + origin_realtime_time = leg["points"][0]["dateTime"]["rtTime"] #16:35 + + destination_realtime_date = leg["points"][1]["dateTime"]["rtDate"] + destination_realtime_time = leg["points"][1]["dateTime"]["rtTime"] + berlin = pytz.timezone('Europe/Berlin') + origin_departure_real_datetime = berlin.localize( + dt.datetime.strptime(origin_realtime_date + "-" + + origin_realtime_time, + "%d.%m.%Y-%H:%M")).replace(tzinfo=None) + destination_arrival_real_datetime = berlin.localize( + dt.datetime.strptime(destination_realtime_date + "-" + + destination_realtime_time, + "%d.%m.%Y-%H:%M")).replace(tzinfo=None) + + duration = leg["timeMinute"] + mode = leg["mode"]["product"] + line = leg["mode"]["number"] + direction = leg["mode"]["destination"] + + l = Leg(origin, destination, origin_departure_real_datetime, destination_arrival_real_datetime, mode, line, direction) + + trip_legs.append(l) + + #print "%s-%s: (%s min)\n %s - %s" %(origin_departure_real_time, destination_arrival_real_time, duration, origin, destination) + + + trip_time_of_departure = trip_legs[0].time_of_departure + trip_time_of_arrival = trip_legs[-1].time_of_arrival + + trip_obj = Trip(trip_origin, trip_destination, trip_time_of_departure, trip_time_of_arrival, trip_legs, trip_fare, trip_zones) + trip_objs.append(trip_obj) + + else: + raise ValueError("No trips found") + + + return trip_objs + + +class Trip(object): + + def __init__(self, origin, destination, time_of_departure, time_of_arrival, legs, fare, zones): + """origin: location object of origin + destination: location object of destination + time_of_departure: datetime object of trip departure time / date + time_of_arrival: datetime object of trip arrival time / date + legs: list of Leg objects + fare: fare of trip (float) + zones: number of zones travelled (int)""" + + self.origin = origin + self.destination = destination + self.time_of_departure = time_of_departure + self.time_of_arrival = time_of_arrival + self.legs = legs + self.fare = fare + self.zones = zones + + + +class Leg(object): + + def __init__(self, origin, destination, time_of_departure, time_of_arrival, mode, line, direction): + """origin: leg origin (station / address / etc.) + destination: leg destination (station / address / etc.) + time_of_departure: departure datetime object + time_of_arrival: arrival datetime object + mode: mode of transportation (U-Bahn / S-Bahn / Bus / Walking) + line: U-Bahn / S-Bahn / Bus Line + direction: ulitmate destination of U-Bahn / S-Bahn / Bus Line""" + + self.origin = origin + self.destination = destination + self.time_of_departure = time_of_departure + self.time_of_arrival = time_of_arrival + self.mode = mode + self.line = line + self.direction = direction + + +class Location(object): + + def __init__(self, name, loc_id, loc_type="any"): + """type: type of location (station / address / etc.) + name: full name of location + id: id of location""" + + self.loc_type = loc_type + self.name = name + self.loc_id = loc_id + + +class Stop(object): + + def __init__(self, name): + self.id = VVS_EFA.convert_name_to_id(name) + if self.id == None: + raise TypeError("Station could not be found.") + + def get_next_connections(self, datetime, departure, limit=20): + + """datetime: datetime object of time & date + departure: boolean, true -> time of departure, false --> time of arrival + limit: int, limit of results fetched, default: 20""" + + if self.id != None: + + parameters = {} + + parameters["deleteAssignedStops_dm"] = "1" + parameters["itOptionsActive"] = "1" + parameters["limit"] = str(limit) + parameters["locationServerActive"] = "1" + parameters["mode"] = "direct" + parameters["name_dm"] = self.id + parameters["ptOptionsActive"] = "1" + parameters["stateless"] = "1" + parameters["type_dm"] = "stop" + parameters["useAllStops"] = "1" + parameters["useRealtime"] = "1" + parameters["itdTime"] = datetime.strftime("%H%M") + parameters["itdDate"] = datetime.strftime("%Y%m%d") + + if departure: + parameters["itdTripDateTimeDepArr"] = "dep" + else: + parameters["itdTripDateTimeDepArr"] = "arr" + + parameters["outputFormat"] = "JSON" + parameters["SpEncId"] = "0" + parameters["anySigWhenPerfectNoOtherMatches"] = "1" + parameters["convertStopsPTKernel2LocationServer"] = "1" + parameters["convertPOIsITKernel2LocationServer"] = "1" + parameters["verifyAnyLocViaLocServer"] = "1" + parameters["w_objPrefAl"] = "12" + parameters["w_regPrefAm"] = "1" + + request_url = "http://m.vvs.de/jqm/controller/XSLT_DM_REQUEST" + req = requests.post(request_url, parameters) + data = req.json() + + departure_list = data["departureList"] + connections = [] + for list_entry in departure_list: + serving_line_data = list_entry["servingLine"] + serving_line = ServingLine(serving_line_data["key"], serving_line_data["number"], serving_line_data["direction"], + serving_line_data["directionFrom"], serving_line_data["name"]) + + stop_id = list_entry["stopID"] + stop_name = list_entry["stopName"] + scheduled_datetime = dt.datetime(int(list_entry["dateTime"]["year"]), int(list_entry["dateTime"]["month"]), + int(list_entry["dateTime"]["day"]), int(list_entry["dateTime"]["hour"]), int(list_entry["dateTime"]["minute"])) + + try: #check if realtime info available + realtime_datetime = dt.datetime(int(list_entry["realDateTime"]["year"]), int(list_entry["realDateTime"]["month"]), + int(list_entry["realDateTime"]["day"]), int(list_entry["realDateTime"]["hour"]), int(list_entry["realDateTime"]["minute"])) + + except: #if not: return None for realtime_datetime + realtime_datetime = None + + connection = Connection(stop_id, stop_name, scheduled_datetime, realtime_datetime, serving_line) + connections.append(connection) + + return connections + + else: + return None + + + +class Connection(object): + """docstring for Connection""" + def __init__(self, stop_id, stop_name, scheduled_datetime, realtime_datetime, serving_line): + """realtime_datetime: datetime object of projected departure/arrival. None if not available""" + self.stop_id = stop_id + self.stop_name = stop_name + self.scheduled_datetime = scheduled_datetime + self.realtime_datetime = realtime_datetime + self.serving_line = serving_line + + +class ServingLine(object): + """docstring for ServingLine""" + def __init__(self, key, number, direction, direction_from, line_type): + self.key = key + self.number = number + self.direction = direction + self.direction_from = direction_from + self.line_type = line_type diff --git a/ampel/vvs_efa/__init__.py b/ampel/vvs_efa/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3