tdtp_parada_v2/tpmcqr_service/api/utils.py

243 lines
9.2 KiB
Python
Raw Normal View History

2025-02-03 02:36:54 -03:00
2025-02-03 03:46:09 -03:00
from tpmcqr_service import redis_client
2025-02-06 14:32:25 -03:00
from tpmcqr_service.models.gtfs import QRDev, Lineas, Shapes, Paraderos, Trips, Stops, find_shape_position
2025-02-03 02:36:54 -03:00
import time
2025-02-03 04:13:30 -03:00
import pickle
2025-02-03 04:19:01 -03:00
import math
2025-02-27 17:30:54 -03:00
import xxhash
2025-02-03 02:36:54 -03:00
2025-02-06 14:21:52 -03:00
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
2025-02-21 13:58:01 -03:00
if not paradadb.vigente:
info_linea['debug'] = 'Parada sin servicios'
info_linea['vigente'] = False
return 400, info_linea
2025-02-06 14:21:52 -03:00
lineadb = obtiene_datos_linea(lineacode)
if not lineadb:
info_linea['debug'] = 'Invalid Lineas'
return 400, info_linea
2025-02-21 13:58:01 -03:00
info_linea['vigente'] = True
2025-02-06 14:21:52 -03:00
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
2025-02-06 14:28:01 -03:00
parada_pos, parada_distance = find_shape_position(rt_linea['id_shape'], paradadb.stop_lat, paradadb.stop_lon)
2025-02-06 14:21:52 -03:00
info_linea['servicios'] = []
info_linea['recientes'] = []
2025-02-06 14:43:14 -03:00
expediciones_enruta = []
expediciones_pasadas = []
2025-02-06 14:21:52 -03:00
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:
2025-02-06 14:43:14 -03:00
expedicion = expediciones_pasadas.pop(0)
2025-02-06 14:21:52 -03:00
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:
2025-02-06 14:43:14 -03:00
expedicion = expediciones_pasadas.pop(0)
2025-02-06 14:21:52 -03:00
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} )
2025-02-06 14:44:30 -03:00
return 200, info_linea
2025-02-06 14:21:52 -03:00
2025-02-03 02:36:54 -03:00
def calcula_distancias_parada(redis_id, parada_id):
salida_parada = dict()
2025-02-06 14:29:21 -03:00
paradadb = obtiene_datos_parada(parada_id)
2025-02-03 02:36:54 -03:00
if not paradadb:
2025-02-23 16:49:15 -03:00
salida_parada['stop_name'] = 'Parada no Existe'
2025-02-21 13:58:01 -03:00
salida_parada['debug'] = 'Parada no Existe'
return 400, salida_parada
2025-02-23 16:49:15 -03:00
salida_parada['lineas'] = []
2025-02-21 13:58:01 -03:00
if not paradadb.vigente:
2025-02-24 11:49:09 -03:00
salida_parada['stop_name'] = paradadb.stop_name
2025-02-21 13:58:01 -03:00
salida_parada['debug'] = 'Parada sin servicios'
salida_parada['vigente'] = False
2025-02-24 11:50:38 -03:00
return 200, salida_parada
2025-02-03 02:36:54 -03:00
2025-02-21 13:58:01 -03:00
salida_parada['vigente'] = True
2025-02-03 02:36:54 -03:00
for key in ['stop_name', 'stop_lat', 'stop_lon']:
salida_parada[key] = getattr(paradadb, key)
2025-02-06 14:30:52 -03:00
for id_linea in obtiene_lineas_parada(paradadb.id_paradero):
2025-02-03 02:36:54 -03:00
rt_linea = pickle.loads(redis_client.get(id_linea))
info_linea = dict()
2025-02-21 14:04:25 -03:00
for key in ['route_short_name', 'lur_code', 'route_long_name', 'route_color', 'route_text_color', 'lur', 'ilinea']:
2025-02-03 02:36:54 -03:00
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 = []
2025-02-23 16:50:44 -03:00
estimator = 'estimator'
2025-02-23 16:49:15 -03:00
for expedicion in rt_linea['servicios']:
trip_info = estima_llegada(parada_distance, expedicion)
if trip_info[estimator] > 0:
expediciones_enruta.append(trip_info)
2025-02-03 02:36:54 -03:00
else:
2025-02-23 16:49:15 -03:00
expediciones_pasadas.append(trip_info)
expediciones_enruta.sort(key=lambda x: x[estimator])
expediciones_pasadas.sort(key=lambda x: x[estimator])
2025-02-03 02:36:54 -03:00
if len(expediciones_enruta) > 0:
2025-02-23 16:55:32 -03:00
info_linea['servicios'].append( expediciones_enruta.pop(0) )
2025-02-03 02:36:54 -03:00
if len(expediciones_enruta) > 0:
2025-02-23 16:55:32 -03:00
info_linea['servicios'].append( expediciones_enruta.pop(0) )
2025-02-03 02:36:54 -03:00
if len(expediciones_pasadas) > 0:
2025-02-23 16:55:32 -03:00
info_linea['recientes'].append( expediciones_pasadas.pop(-1) )
2025-02-03 02:36:54 -03:00
if len(expediciones_pasadas) > 0:
2025-02-23 16:55:32 -03:00
info_linea['recientes'].append( expediciones_pasadas.pop(-1) )
2025-02-03 02:36:54 -03:00
salida_parada['lineas'].append(info_linea)
return 200, salida_parada
def estima_llegada(parada_distance, expedicion):
ts = int(time.time())
2025-02-27 17:36:28 -03:00
data_keys = ['trip_traveled', 'bus_id', 'trip_lat', 'trip_lon', 'trip_pos', 'ts']
2025-02-03 03:16:05 -03:00
trip_info = dict(zip(data_keys, expedicion))
2025-02-27 17:41:34 -03:00
trip_info['bus_id'] = xxhash.xxh32(trip_info['bus_id'], seed=int(parada_distance)).hexdigest()
2025-02-27 17:36:28 -03:00
2025-02-03 02:36:54 -03:00
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
2025-02-23 16:49:15 -03:00
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
2025-02-03 02:36:54 -03:00
if estimator > 1570: # 26:10 minutos
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En 25-30 minutos'
2025-02-03 02:36:54 -03:00
elif estimator > 1260: # #21 minutos
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En 20-25 minutos'
2025-02-03 02:36:54 -03:00
elif estimator > 950: #15:50 minutos
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En 15-20 minutos'
2025-02-03 02:36:54 -03:00
elif estimator > 640: #10:40 minutos
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En 10-15 minutos'
2025-02-03 02:36:54 -03:00
elif estimator > 330: # 5:30
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En 5-10 minutos'
2025-02-03 02:36:54 -03:00
elif estimator > 200: # 3:20 sec
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En 3 minutos'
2025-02-03 02:36:54 -03:00
elif estimator > 70: #
trip_info['trip_estimator'] = 'Llegando'
elif estimator > 0: #
2025-02-23 16:49:15 -03:00
trip_info['trip_estimator'] = 'En Parada'
elif estimator > -60: #
trip_info['trip_estimator'] = 'Avanzando'
2025-02-03 02:36:54 -03:00
else: #
2025-02-03 05:04:17 -03:00
salida = math.ceil(-estimator/60)
2025-02-03 02:36:54 -03:00
trip_info['trip_estimator'] = 'Hace {} minutos'.format(salida)
2025-02-03 04:52:51 -03:00
return trip_info
2025-02-06 14:21:52 -03:00
def obtiene_shape_paradas(id_shape, id_trip):
shape = []
paradas = []
2025-02-06 14:34:25 -03:00
for item in Shapes.query.filter(Shapes.id_shape==id_shape).order_by(Shapes.shape_pt_sequence.asc()).all():
2025-02-06 14:21:52 -03:00
shape.append({'lat': item.shape_pt_lat, 'lon': item.shape_pt_lon})
2025-02-06 14:40:11 -03:00
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():
2025-02-06 14:21:52 -03:00
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
2025-02-03 02:36:54 -03:00
2025-02-06 14:21:52 -03:00
def obtiene_datos_linea(codigo_linea):
2025-02-06 14:33:26 -03:00
parada = Lineas.query.filter(Lineas.route_short_name==codigo_linea).one_or_none()
2025-02-03 02:36:54 -03:00
if parada is None:
return None
return parada
def obtiene_lineas_parada(id_paradero):
lineas = []
2025-02-03 04:10:35 -03:00
for linea in Trips.query.join(Stops).filter(Stops.id_paradero == id_paradero).distinct(Trips.id_linea).all():
2025-02-03 02:36:54 -03:00
lineas.append(linea.id_linea)
return lineas