From 0fa0126dbc09a29c443b7314ec932a35d04429ea Mon Sep 17 00:00:00 2001 From: Christopher Teutsch Date: Thu, 16 May 2019 14:11:29 +0200 Subject: [PATCH] Integration with a SQL database, human-readable output of departures --- monitor.py | 122 +++++++++++++++++++++++++++++++++++------------ requirements.txt | 3 +- 2 files changed, 94 insertions(+), 31 deletions(-) diff --git a/monitor.py b/monitor.py index 37c596b..a702d38 100755 --- a/monitor.py +++ b/monitor.py @@ -6,6 +6,23 @@ from pprint import pprint, pformat import datetime import pause import sys +import mysql.connector + +TABLE = """ +CREATE TABLE IF NOT EXISTS vrr ( +line_code varchar(9) not null, +direction_code varchar(1) not null, +station_id int not null, +orig_datetime datetime not null, +status enum('on_time', 'early', 'late', 'cancelled', 'no_data') not null, +delay_value int default null, +primary key (line_code, direction_code, station_id, orig_datetime)); +""" + +# CONFIGURATION +USE_MODES = [] +USE_STATION_ID = 20021002 +USE_LINES = [] class MOT: @@ -30,16 +47,8 @@ lines_filter = [ ] -def t(s: str) -> str: - """ - Encode a string to be used as a station identifier. - :param s: a string to encode - :return: the encoded string - """ - return s.replace(' ', '+') - - -def make_request_data(station_id: int, result_count: int = 8, modes: List = MOT.ALL_MODES, lines: List[str] = ALL_LINES) -> dict: +def make_request_data(station_id: int, result_count: int = 8, modes: List = MOT.ALL_MODES, + lines: List[str] = ALL_LINES) -> dict: """ Prepare a request data dictionary to put into get_data() :param station_id: an EFA station ID @@ -81,7 +90,7 @@ def make_request_data(station_id: int, result_count: int = 8, modes: List = MOT. if lines is ALL_LINES: request_data['useAllLines'] = 1 else: - lines_dictarr = [{'data': t(v)} for v in lines] + lines_dictarr = [{'data': v.replace(' ', '+')} for v in lines] request_data['linesFilter'] = json.dumps(lines_dictarr) request_data['useAllLines'] = 0 @@ -116,9 +125,12 @@ def is_early(trip: dict) -> bool: return False -# Pretty-print the reply data. -"""print("Data:") -pprint(reply_data)""" +def is_on_time(trip: dict) -> bool: + return int(trip['delay']) == 0 + + +def has_realtime(trip: dict) -> bool: + return trip['delay'] != '' def fixup_data(d: dict) -> dict: @@ -129,13 +141,20 @@ def fixup_data(d: dict) -> dict: def print_trip(trip: dict) -> None: - trip_part = "The {}:{} {} (???:{}: :{}) service to {} ".format(trip['orgHour'], trip['orgMinute'], trip['lineNumber'], trip['lineCode'], trip['directionCode'], trip['direction']) - if is_cancelled(trip): - print(trip_part + "is cancelled.") - elif is_late(trip): - print(trip_part + "is {} minutes late.".format(trip['delay'])) - elif is_early(trip): - print(trip_part + "is {} minutes early.".format(-trip['delay'])) + trip_part = "The {}:{} {} (???:{}: :{}) service to {} ".format(trip['orgHour'], trip['orgMinute'], + trip['lineNumber'], trip['lineCode'], + trip['directionCode'], trip['direction']) + if has_realtime(trip): + if is_cancelled(trip): + print(trip_part + "is cancelled.") + elif is_late(trip): + print(trip_part + "is {} minutes late.".format(trip['delay'])) + elif is_early(trip): + print(trip_part + "is {} minutes early.".format(-trip['delay'])) + elif is_on_time(trip): + print(trip_part + "is on time.") + else: + print(trip_part + "has no real-time data.") def get_next_refresh(data: dict): @@ -147,37 +166,80 @@ def get_next_refresh(data: dict): times.sort() for time in times: if (datetime.datetime.fromtimestamp(time) - datetime.datetime.now()) > datetime.timedelta(seconds=30): - if (datetime.datetime.fromtimestamp(time)-datetime.datetime.now()) > datetime.timedelta(minutes=5): - return (datetime.datetime.now()+datetime.timedelta(minutes=5)).timestamp() + if (datetime.datetime.fromtimestamp(time) - datetime.datetime.now()) > datetime.timedelta(minutes=5): + return (datetime.datetime.now() + datetime.timedelta(minutes=5)).timestamp() return time return (datetime.datetime.now() + datetime.timedelta(seconds=60)).timestamp() -def update(): +def _make_delay_value_for_sql(value: str or int or None) -> int or None: + if value == '': + value = None + else: + value = int(value) + return value + + +def _make_status_value_for_sql(trip: dict) -> str: + if not has_realtime(trip): + status = 'no_data' + else: + if is_late(trip): + status = 'late' + elif is_cancelled(trip): + status = 'cancelled' + elif is_early(trip): + status = 'early' + elif is_on_time(trip): + status = 'on_time' + else: + raise ValueError("unknown delay value") + return status + + +def update(station_id: int): reply_data = get_data( make_request_data( - 20021002, + station_id, 8, lines=lines_filter ) ) - reply_data = fixup_data(reply_data) for trip in reply_data['departureData']: print_trip(trip) return reply_data -def wait(): - data = update() +def wait(cxn: mysql.connector.MySQLConnection, station_id: int): + lines_filter = [ + 'rbg:70070: :H', # U70 -> Düsseldorf Hbf + 'rbg:70070: :R', # U70 -> Krefeld Rheinstr + 'rbg:70076: :H', # U76 -> Düsseldorf Hbf + 'rbg:70076: :R', # U76 -> Krefeld Rheinstr + ] + cur = cxn.cursor() while True: + data = update(station_id) + for t in data['departureData']: + cur.execute('REPLACE INTO vrr ' + '(line_code, direction_code, station_id, orig_datetime, status, delay_value)' + ' VALUES (%s, %s, %s, ' + 'from_unixtime(%s), %s, %s)', + (t['lineCode'], t['directionCode'], station_id, + t['orgFullTime'], _make_status_value_for_sql(t), _make_delay_value_for_sql(t['delay']) + )) + cxn.commit() next_refresh = get_next_refresh(data) print("Sleeping until " + datetime.datetime.fromtimestamp(next_refresh).isoformat(), file=sys.stderr) pause.until(next_refresh) - data = update() def main(): - wait() + cxn = mysql.connector.connect(user='vrr', password='vrr', host='127.0.0.1', database='vrr') + cursor = cxn.cursor() + cursor.execute(TABLE) + + wait(cxn, USE_STATION_ID) main() diff --git a/requirements.txt b/requirements.txt index 8310781..7f4dce5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ requests -pause \ No newline at end of file +pause +mysql-connector-python \ No newline at end of file