from tpmcqr_service import redis_client from tpmcqr_service.models.gtfs import QRDev, Lineas, Shapes, Paraderos, Trips, Stops, find_shape_position import time import pickle import math import xxhash def parada_ruta_expediciones(redis_id, parada_id, lineacode): info_linea = dict() paradadb = obtiene_datos_parada(parada_id) if not paradadb: info_linea['debug'] = 'Invalid QR' return 400, info_linea if not paradadb.vigente: info_linea['debug'] = 'Parada sin servicios' info_linea['vigente'] = False return 400, info_linea lineadb = obtiene_datos_linea(lineacode) if not lineadb: info_linea['debug'] = 'Invalid Lineas' return 400, info_linea info_linea['vigente'] = True rt_linea = pickle.loads(redis_client.get(lineadb.id_linea)) if len(rt_linea['servicios']) == 0: info_linea['debug'] = 'No data' info_linea['servicios'] = 0 return 400, info_linea rt_ppus = pickle.loads(redis_client.get('ppus')) for key in ['stop_name', 'stop_lat', 'stop_lon']: info_linea[key] = getattr(paradadb, key) for key in ['route_short_name', 'route_long_name', 'route_color', 'route_text_color', 'lur']: info_linea[key] = rt_linea[key] shape, paradas = obtiene_shape_paradas(rt_linea['id_shape'], rt_ppus[rt_linea['servicios'][0][1]]['id_trip']) info_linea['route_shape'] = shape info_linea['route_stops'] = paradas parada_pos, parada_distance = find_shape_position(rt_linea['id_shape'], paradadb.stop_lat, paradadb.stop_lon) info_linea['servicios'] = [] info_linea['recientes'] = [] expediciones_enruta = [] expediciones_pasadas = [] for item in rt_linea['servicios']: if item[0] < parada_distance: expediciones_enruta.append(item) else: expediciones_pasadas.append(item) if len(expediciones_enruta) > 0: expedicion = expediciones_enruta.pop(-1) expedicion_pos = expedicion[4] trip_shape = [{'lat': expedicion[2], 'lon': expedicion[3]}] if expedicion_pos != parada_pos: trip_shape += shape[expedicion_pos:parada_pos-1] trip_shape += [{'lat': info_linea['stop_lat'], 'lon': info_linea['stop_lon']}] info_linea['servicios'].append( {'ppu': expedicion[1], 'trip_shape': trip_shape} ) if len(expediciones_enruta) > 0: expedicion = expediciones_enruta.pop(-1) expedicion_pos = expedicion[4] trip_shape = [{'lat': expedicion[2], 'lon': expedicion[3]}] if expedicion_pos != parada_pos: trip_shape += shape[expedicion_pos:parada_pos-1] trip_shape += [{'lat': info_linea['stop_lat'], 'lon': info_linea['stop_lon']}] info_linea['servicios'].append( {'ppu': expedicion[1], 'trip_shape': trip_shape} ) if len(expediciones_pasadas) > 0: expedicion = expediciones_pasadas.pop(0) expedicion_pos = expedicion[4] trip_shape = [{'lat': info_linea['stop_lat'], 'lon': info_linea['stop_lon']}] if expedicion_pos != parada_pos: trip_shape += shape[parada_pos:expedicion_pos-1] trip_shape += [{'lat': expedicion[2], 'lon': expedicion[3]}] info_linea['recientes'].append( {'ppu': expedicion[1], 'trip_shape': trip_shape} ) if len(expediciones_pasadas) > 0: expedicion = expediciones_pasadas.pop(0) expedicion_pos = expedicion[4] trip_shape = [{'lat': info_linea['stop_lat'], 'lon': info_linea['stop_lon']}] if expedicion_pos != parada_pos: trip_shape += shape[parada_pos:expedicion_pos-1] trip_shape += [{'lat': expedicion[2], 'lon': expedicion[3]}] info_linea['recientes'].append( {'ppu': expedicion[1], 'trip_shape': trip_shape} ) return 200, info_linea def calcula_distancias_parada(redis_id, parada_id): salida_parada = dict() paradadb = obtiene_datos_parada(parada_id) if not paradadb: salida_parada['stop_name'] = 'Parada no Existe' salida_parada['debug'] = 'Parada no Existe' return 400, salida_parada salida_parada['lineas'] = [] if not paradadb.vigente: salida_parada['stop_name'] = paradadb.stop_name salida_parada['debug'] = 'Parada sin servicios' salida_parada['vigente'] = False return 200, salida_parada salida_parada['vigente'] = True for key in ['stop_name', 'stop_lat', 'stop_lon']: salida_parada[key] = getattr(paradadb, key) for id_linea in obtiene_lineas_parada(paradadb.id_paradero): rt_linea = pickle.loads(redis_client.get(id_linea)) info_linea = dict() for key in ['route_short_name', 'lur_code', 'route_long_name', 'route_color', 'route_text_color', 'lur', 'ilinea']: info_linea[key] = rt_linea[key] info_linea['servicios'] = [] info_linea['recientes'] = [] if 'id_shape' in rt_linea: parada_pos, parada_distance = find_shape_position(rt_linea['id_shape'], salida_parada['stop_lat'], salida_parada['stop_lon']) expediciones_enruta = [] expediciones_pasadas = [] estimator = 'estimator' for expedicion in rt_linea['servicios']: trip_info = estima_llegada(parada_distance, expedicion) if trip_info[estimator] > 0: expediciones_enruta.append(trip_info) else: expediciones_pasadas.append(trip_info) expediciones_enruta.sort(key=lambda x: x[estimator]) expediciones_pasadas.sort(key=lambda x: x[estimator]) if len(expediciones_enruta) > 0: info_linea['servicios'].append( expediciones_enruta.pop(0) ) if len(expediciones_enruta) > 0: info_linea['servicios'].append( expediciones_enruta.pop(0) ) if len(expediciones_pasadas) > 0: info_linea['recientes'].append( expediciones_pasadas.pop(-1) ) if len(expediciones_pasadas) > 0: info_linea['recientes'].append( expediciones_pasadas.pop(-1) ) salida_parada['lineas'].append(info_linea) return 200, salida_parada def estima_llegada(parada_distance, expedicion): ts = int(time.time()) data_keys = ['trip_traveled', 'bus_id', 'trip_lat', 'trip_lon', 'trip_pos', 'ts'] trip_info = dict(zip(data_keys, expedicion)) trip_info['bus_id'] = xxhash.xxh32(trip_info['bus_id'], seed=int(parada_distance)).hexdigest() trip_info['drift'] = int(trip_info['ts']) - ts trip_info['trip_distance'] = parada_distance - int(trip_info['trip_traveled']) estimator = int(trip_info['trip_distance'] / 5) # 18 Km/h promedio -> 5 m/s trip_info['old_estimator'] = estimator trip_info['forward_correction'] = trip_info['drift'] * 5 # distancia avanzada desde el timestamp original (estimación de avance) trip_info['forward_inference'] = 60 * 5 # forward position a minute to predict position estimator = int((trip_info['trip_distance'] + trip_info['forward_correction'] - trip_info['forward_inference']) / 5) trip_info['estimator'] = estimator if estimator > 1570: # 26:10 minutos trip_info['trip_estimator'] = 'En 25-30 minutos' elif estimator > 1260: # #21 minutos trip_info['trip_estimator'] = 'En 20-25 minutos' elif estimator > 950: #15:50 minutos trip_info['trip_estimator'] = 'En 15-20 minutos' elif estimator > 640: #10:40 minutos trip_info['trip_estimator'] = 'En 10-15 minutos' elif estimator > 330: # 5:30 trip_info['trip_estimator'] = 'En 5-10 minutos' elif estimator > 200: # 3:20 sec trip_info['trip_estimator'] = 'En 3 minutos' elif estimator > 70: # trip_info['trip_estimator'] = 'Llegando' elif estimator > 0: # trip_info['trip_estimator'] = 'En Parada' elif estimator > -60: # trip_info['trip_estimator'] = 'Avanzando' else: # salida = math.ceil(-estimator/60) trip_info['trip_estimator'] = 'Hace {} minutos'.format(salida) return trip_info def obtiene_shape_paradas(id_shape, id_trip): shape = [] paradas = [] for item in Shapes.query.filter(Shapes.id_shape==id_shape).order_by(Shapes.shape_pt_sequence.asc()).all(): shape.append({'lat': item.shape_pt_lat, 'lon': item.shape_pt_lon}) for item in Paraderos.query.join(Stops).filter(Stops.id_trip==id_trip).distinct(Paraderos.id_paradero).order_by(Paraderos.id_paradero.asc(), Stops.stop_sequence.asc()).all(): paradas.append({'name': item.stop_name, 'lat': item.stop_lat, 'lon': item.stop_lon}) return shape, paradas def obtiene_datos_parada(QRCode): devdb = QRDev.query.filter(QRDev.id_dispositivo==QRCode).one_or_none() if not devdb: return None paradadb = Paraderos.query.filter(Paraderos.id_paradero==devdb.id_paradero).one_or_none() return paradadb def obtiene_datos_linea(codigo_linea): parada = Lineas.query.filter(Lineas.route_short_name==codigo_linea).one_or_none() if parada is None: return None return parada def obtiene_lineas_parada(id_paradero): lineas = [] for linea in Trips.query.join(Stops).filter(Stops.id_paradero == id_paradero).distinct(Trips.id_linea).all(): lineas.append(linea.id_linea) return lineas