2017-11-18 16:38:59 +01:00
|
|
|
'''
|
2018-07-20 15:43:31 +02:00
|
|
|
Fourni les informations sur les arrêts
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
|
|
|
|
2017-11-21 21:07:08 +01:00
|
|
|
from libs import get_data_from_json, hms2seconds
|
2017-11-18 16:38:59 +01:00
|
|
|
from time import time
|
2021-08-27 11:53:29 +02:00
|
|
|
from urllib.parse import quote
|
|
|
|
from re import search
|
2017-11-18 16:38:59 +01:00
|
|
|
|
2021-08-14 08:50:57 +02:00
|
|
|
search_stop_url = 'https://ws.infotbm.com/ws/1.0/get-schedule/%s'
|
|
|
|
stop_info_url = 'https://ws.infotbm.com/ws/1.0/network/stoparea-informations/%s'
|
2018-07-20 15:43:31 +02:00
|
|
|
stop_schedule_url = 'https://ws.infotbm.com/ws/1.0/get-realtime-pass/%d/%s'
|
2017-11-18 16:38:59 +01:00
|
|
|
|
2021-09-18 09:01:23 +02:00
|
|
|
line_types = (
|
|
|
|
'Tram',
|
|
|
|
'Corol',
|
|
|
|
'Lianes',
|
|
|
|
'Ligne',
|
|
|
|
'Bus Relais',
|
2021-09-18 09:26:10 +02:00
|
|
|
'Citéis',
|
2021-09-18 09:01:23 +02:00
|
|
|
)
|
2021-09-18 09:26:10 +02:00
|
|
|
line_translate = {
|
|
|
|
'Tram A': 'A',
|
|
|
|
'Tram B': 'B',
|
|
|
|
'Tram C': 'C',
|
|
|
|
'Tram D': 'D',
|
|
|
|
'TBNight': '58',
|
|
|
|
'BAT3': '69',
|
|
|
|
}
|
2021-09-18 09:01:23 +02:00
|
|
|
|
2017-11-18 16:38:59 +01:00
|
|
|
|
2021-08-27 11:53:29 +02:00
|
|
|
def search_stop_by_name (keyword):
|
2021-08-14 08:50:57 +02:00
|
|
|
'''
|
|
|
|
Recherche la référence d'un nom d'arrêt
|
2021-08-27 11:53:29 +02:00
|
|
|
|
|
|
|
Format des données retournées par le site
|
|
|
|
[
|
|
|
|
{
|
|
|
|
id: str, nommé ref par la suite
|
|
|
|
name: str
|
|
|
|
type: str, mais je ne gère que "stop_area"
|
|
|
|
city: str
|
|
|
|
},
|
|
|
|
]
|
2021-08-14 08:50:57 +02:00
|
|
|
'''
|
2021-08-27 11:53:29 +02:00
|
|
|
d = get_data_from_json (search_stop_url % quote (keyword))
|
2021-08-14 08:50:57 +02:00
|
|
|
r = []
|
|
|
|
for i in d:
|
2021-08-27 11:53:29 +02:00
|
|
|
if i ['type'] == 'stop_area':
|
|
|
|
r.append ({
|
|
|
|
'name': i ['name'],
|
|
|
|
'city': i ['city'],
|
|
|
|
'ref': i ['id'],
|
|
|
|
})
|
|
|
|
return (r)
|
|
|
|
|
|
|
|
|
|
|
|
def show_stops_from_ref (ref):
|
|
|
|
'''
|
|
|
|
Affiche la liste des arrêts d'une référence donnée par search_stop_name
|
|
|
|
|
|
|
|
Format des données retournées par le site
|
|
|
|
{
|
|
|
|
id: str, contenu de la variable ref donnée
|
|
|
|
name: str
|
|
|
|
latitude: str, convertible en float
|
|
|
|
longitude: str, convertible en float
|
|
|
|
city: str
|
|
|
|
hasWheelchairBoarding: bool, accessibilité en fauteuil roulant
|
|
|
|
stopPoints: [
|
|
|
|
id: str
|
|
|
|
name: str, encore le nom
|
|
|
|
routes: [
|
|
|
|
{
|
|
|
|
id: str
|
|
|
|
name: str, nom du terminus
|
|
|
|
line: {
|
|
|
|
name: str, nom pour les humains
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
d = get_data_from_json (stop_info_url % quote (ref))
|
|
|
|
r = {
|
|
|
|
'ref': d ['id'],
|
|
|
|
'name': d ['name'],
|
|
|
|
'latitude': float (d ['latitude']),
|
|
|
|
'longitude': float (d ['longitude']),
|
|
|
|
'city': d ['city'],
|
|
|
|
'stop_points': [],
|
|
|
|
}
|
|
|
|
for i in d ['stopPoints']:
|
|
|
|
s = {
|
2021-08-14 08:50:57 +02:00
|
|
|
'name': i ['name'],
|
2021-08-27 11:53:29 +02:00
|
|
|
'routes': [],
|
|
|
|
}
|
|
|
|
s ['id'] = int (search ('[0-9]+$', i ['id']).group ())
|
|
|
|
for j in i ['routes']:
|
|
|
|
rte = {
|
|
|
|
'terminus': j ['name'],
|
|
|
|
'line_human': j ['line'] ['name'],
|
|
|
|
}
|
2021-09-18 09:26:10 +02:00
|
|
|
add = False
|
|
|
|
if rte ['line_human'] in line_translate:
|
|
|
|
line_id = line_translate [rte ['line_human']]
|
|
|
|
add = True
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
line_id = search ('[0-9]+$', rte ['line_human']).group ()
|
|
|
|
except AttributeError:
|
|
|
|
continue
|
2021-08-27 11:53:29 +02:00
|
|
|
line_id = '%02d' % int (line_id)
|
2021-09-18 09:26:10 +02:00
|
|
|
for i in line_types:
|
|
|
|
if rte ['line_human'] [0:len (i)] == i:
|
|
|
|
add = True
|
|
|
|
break
|
|
|
|
if add:
|
2021-09-18 09:01:23 +02:00
|
|
|
rte ['line_id'] = line_id
|
|
|
|
s ['routes'].append (rte)
|
2021-09-18 09:28:11 +02:00
|
|
|
if s ['routes'] != []:
|
|
|
|
r ['stop_points'].append (s)
|
2021-08-14 08:50:57 +02:00
|
|
|
return (r)
|
|
|
|
|
|
|
|
|
2021-08-27 11:53:29 +02:00
|
|
|
class StopRoute ():
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
2018-07-20 15:43:31 +02:00
|
|
|
Récupère les informations sur un arrêt
|
2017-11-18 16:38:59 +01:00
|
|
|
|
2018-07-20 15:43:31 +02:00
|
|
|
Format des données retournées pas le site
|
|
|
|
{
|
|
|
|
destinations: {
|
|
|
|
<destination_stop_id>: [
|
2017-11-18 16:38:59 +01:00
|
|
|
{
|
2018-07-20 15:43:31 +02:00
|
|
|
destination_name: str
|
|
|
|
realtime: 1 si suivi, 0 sinon
|
|
|
|
vehicle_id: str
|
|
|
|
vehicle_lattitude: float
|
|
|
|
vehicle_longitude: float
|
|
|
|
waittime: HH:MM:SS
|
2021-08-27 11:53:29 +02:00
|
|
|
waittime_text: str, lisible pas un humain
|
2017-11-18 16:38:59 +01:00
|
|
|
},
|
2018-07-20 15:43:31 +02:00
|
|
|
]
|
2017-11-18 16:38:59 +01:00
|
|
|
}
|
2018-07-20 15:43:31 +02:00
|
|
|
}
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
|
|
|
|
2018-07-20 15:43:31 +02:00
|
|
|
def __init__ (self, number, line, autoupdate_at_creation = True, autoupdate = False, autoupdate_delay = -1):
|
2017-11-18 16:38:59 +01:00
|
|
|
self.number = number
|
2018-07-20 15:43:31 +02:00
|
|
|
self.line = line
|
2017-11-18 16:38:59 +01:00
|
|
|
self.last_update = 0
|
|
|
|
self.data = None
|
|
|
|
if autoupdate_at_creation:
|
|
|
|
self.update ()
|
|
|
|
|
|
|
|
def update (self, auto = False):
|
|
|
|
'''
|
2018-07-20 15:43:31 +02:00
|
|
|
Met à jour les données
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
2021-09-18 09:01:23 +02:00
|
|
|
d = get_data_from_json (stop_schedule_url % (self.number, self.line))
|
|
|
|
if 'destinations' in d:
|
|
|
|
d = d ['destinations']
|
|
|
|
else:
|
|
|
|
return ()
|
2017-11-21 21:07:08 +01:00
|
|
|
self.last_update = time ()
|
2018-07-20 15:43:31 +02:00
|
|
|
if type (d) == dict:
|
2017-11-21 21:07:08 +01:00
|
|
|
self.data = []
|
|
|
|
# let's simplify the data
|
|
|
|
for i in d:
|
2018-07-20 15:43:31 +02:00
|
|
|
for j in d [i]:
|
2017-11-21 21:07:08 +01:00
|
|
|
loc = None
|
|
|
|
try:
|
|
|
|
loc = (float (j ['vehicle_lattitude']), float (j ['vehicle_longitude']))
|
|
|
|
except TypeError:
|
|
|
|
pass
|
2018-07-20 15:43:31 +02:00
|
|
|
vehicle = {
|
2017-11-21 21:07:08 +01:00
|
|
|
'id': j ['vehicle_id'],
|
|
|
|
'destination': j ['destination_name'],
|
|
|
|
'realtime': j ['realtime'] == '1',
|
|
|
|
'location': loc,
|
|
|
|
'wait_time': hms2seconds (j ['waittime']),
|
2021-08-27 11:53:29 +02:00
|
|
|
'wait_time_human': j ['waittime_text'],
|
2017-11-21 21:07:08 +01:00
|
|
|
'arrival': int (self.last_update + hms2seconds (j ['waittime'])),
|
2018-07-20 15:43:31 +02:00
|
|
|
}
|
|
|
|
self.data.append (vehicle)
|
2021-08-29 12:42:04 +02:00
|
|
|
self.data = sorted (self.data, key = lambda item: item ['arrival'])
|
2017-11-18 16:38:59 +01:00
|
|
|
else:
|
2017-11-21 21:07:08 +01:00
|
|
|
self.last_update = 0
|
2017-11-18 16:38:59 +01:00
|
|
|
|
|
|
|
def data_age (self):
|
|
|
|
'''
|
2018-07-20 15:43:31 +02:00
|
|
|
Retourne l'âge des données
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
|
|
|
return (time () - self.last_update)
|
|
|
|
|
2018-07-20 15:43:31 +02:00
|
|
|
def get_line (self):
|
2017-11-18 16:38:59 +01:00
|
|
|
class Line ():
|
|
|
|
'''
|
2018-07-20 15:43:31 +02:00
|
|
|
Information sur la ligne déservie à un arrêt
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
|
|
|
def __init__ (self, data):
|
2018-07-20 15:43:31 +02:00
|
|
|
self.ve = data
|
2017-11-18 16:38:59 +01:00
|
|
|
|
|
|
|
def vehicles (self):
|
2021-08-27 11:53:29 +02:00
|
|
|
if self.ve is not None:
|
|
|
|
return (list (range (0, len (self.ve))))
|
|
|
|
return ([])
|
2017-11-18 16:38:59 +01:00
|
|
|
|
|
|
|
def get_vehicle (self, vehicle):
|
|
|
|
class Vehicle ():
|
|
|
|
'''
|
2018-07-20 15:43:31 +02:00
|
|
|
Information sur un passage de véhicule
|
2017-11-18 16:38:59 +01:00
|
|
|
'''
|
|
|
|
def __init__ (self, data):
|
2017-11-21 21:07:08 +01:00
|
|
|
self.id = data ['id']
|
|
|
|
self.location = data ['location']
|
|
|
|
self.destination = data ['destination']
|
|
|
|
self.is_realtime = data ['realtime']
|
|
|
|
self.wait_time = data ['wait_time']
|
2021-08-27 11:53:29 +02:00
|
|
|
self.wait_time_text = data ['wait_time_human']
|
2018-01-27 16:02:36 +01:00
|
|
|
self.arrival = data ['arrival']
|
2017-11-18 16:38:59 +01:00
|
|
|
|
2017-11-21 21:07:08 +01:00
|
|
|
return (Vehicle (self.ve [vehicle]))
|
2017-11-18 16:38:59 +01:00
|
|
|
|
2018-07-20 15:43:31 +02:00
|
|
|
return (Line (self.data))
|
2017-11-18 16:38:59 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2018-01-27 16:02:36 +01:00
|
|
|
from datetime import datetime
|
2021-09-18 09:01:23 +02:00
|
|
|
for word in ('Gravière', 'Gare Saint Jean', 'Quinconces', 'Zorbut'):
|
2021-08-27 11:53:29 +02:00
|
|
|
print (word + ':')
|
|
|
|
for area in search_stop_by_name (word):
|
|
|
|
print ('\t' + area ['name'] + ' (' + area ['city'] + '):')
|
|
|
|
for stop in show_stops_from_ref (area ['ref']) ['stop_points']:
|
|
|
|
print ('\t\t' + stop ['name'] + ' (' + str (stop ['id']) + '):')
|
|
|
|
for route in stop ['routes']:
|
|
|
|
print ('\t\t\t' + route ['line_human'] + ' terminus ' + route ['terminus'] + ':')
|
|
|
|
sr = StopRoute (stop ['id'], route ['line_id'])
|
|
|
|
line = sr.get_line ()
|
|
|
|
for vehicle in line.vehicles ():
|
|
|
|
v = line.get_vehicle (vehicle)
|
|
|
|
if v.is_realtime:
|
|
|
|
print ('\t\t\t\t' + str (v.wait_time) + ' (' + datetime.fromtimestamp (v.arrival).strftime ('%H:%M') + ') → ' + v.destination)
|
|
|
|
else:
|
|
|
|
print ('\t\t\t\t~' + str (v.wait_time) + ' (' + datetime.fromtimestamp (v.arrival).strftime ('%H:%M') + ') → ' + v.destination)
|