summaryrefslogtreecommitdiffstats
path: root/ampel
diff options
context:
space:
mode:
authormakefu <github@syntax-fehler.de>2017-12-06 13:52:53 +0100
committermakefu <github@syntax-fehler.de>2017-12-06 13:52:53 +0100
commit6bfcd8a348962f0357372f4e74c286f93e6eec26 (patch)
tree00d97bfb8a716afc118a35f7bb7097456bf46511 /ampel
parent8727451b41b057d36e76cecdb543015c0f50b304 (diff)
setup.py: init
Diffstat (limited to 'ampel')
-rw-r--r--ampel/__init__.py0
-rwxr-xr-xampel/ampel.py141
-rwxr-xr-xampel/fade.py78
-rwxr-xr-xampel/google-muell.py111
-rwxr-xr-xampel/muell.py62
-rw-r--r--ampel/vvs_efa/README.md61
-rw-r--r--ampel/vvs_efa/VVS_EFA.py358
-rw-r--r--ampel/vvs_efa/__init__.py0
8 files changed, 811 insertions, 0 deletions
diff --git a/ampel/__init__.py b/ampel/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ampel/__init__.py
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
--- /dev/null
+++ b/ampel/vvs_efa/__init__.py