|
from datetime import datetime |
|
import requests |
|
from .common import config, vehicle |
|
|
|
|
|
def find_coordinates(address): |
|
""" |
|
Find the coordinates of a specific address. |
|
:param address (string): Required. The address |
|
""" |
|
|
|
url = f"https://api.tomtom.com/search/2/geocode/{address}.json?key={config.TOMTOM_API_KEY}" |
|
response = requests.get(url) |
|
data = response.json() |
|
lat = data["results"][0]["position"]["lat"] |
|
lon = data["results"][0]["position"]["lon"] |
|
return lat, lon |
|
|
|
|
|
def plot_route(points): |
|
import plotly.express as px |
|
|
|
lats = [] |
|
lons = [] |
|
|
|
for point in points: |
|
lats.append(point["latitude"]) |
|
lons.append(point["longitude"]) |
|
|
|
|
|
|
|
fig = px.line_mapbox( |
|
lat=lats, lon=lons, zoom=12, height=600, color_discrete_sequence=["red"] |
|
) |
|
|
|
fig.update_layout( |
|
mapbox_style="open-street-map", |
|
|
|
) |
|
fig.update_geos(fitbounds="locations") |
|
fig.update_layout(margin={"r": 20, "t": 20, "l": 20, "b": 20}) |
|
return fig |
|
|
|
|
|
def calculate_route(origin, destination): |
|
"""This function is called when the origin or destination is updated in the GUI. It calculates the route between the origin and destination.""" |
|
print(f"calculate_route(origin: {origin}, destination: {destination})") |
|
origin_coords = find_coordinates(origin) |
|
destination_coords = find_coordinates(destination) |
|
|
|
orig_coords_str = ",".join(map(str, origin_coords)) |
|
dest_coords_str = ",".join(map(str, destination_coords)) |
|
print(f"origin_coords: {origin_coords}, destination_coords: {destination_coords}") |
|
|
|
vehicle.destination = destination |
|
vehicle.location_coordinates = origin_coords |
|
vehicle.location = origin |
|
|
|
|
|
|
|
|
|
url = f"https://api.tomtom.com/routing/1/calculateRoute/{orig_coords_str}:{dest_coords_str}/json?key={config.TOMTOM_API_KEY}" |
|
response = requests.get(url) |
|
data = response.json() |
|
points = data["routes"][0]["legs"][0]["points"] |
|
|
|
return plot_route(points), vehicle.model_dump_json(), points |
|
|
|
|
|
def find_route_tomtom( |
|
lat_depart="0", |
|
lon_depart="0", |
|
lat_dest="0", |
|
lon_dest="0", |
|
depart_datetime="", |
|
**kwargs, |
|
): |
|
""" |
|
Return the distance and the estimated time to go to a specific destination from the current place, at a specified depart time. |
|
:param lat_depart (string): latitude of depart |
|
:param lon_depart (string): longitude of depart |
|
:param lat_dest (string): latitude of destination |
|
:param lon_dest (string): longitude of destination |
|
:param depart_time (string): departure hour, in the format '08:00:20'. |
|
""" |
|
|
|
|
|
url = f"https://api.tomtom.com/routing/1/calculateRoute/{lat_depart},{lon_depart}:{lat_dest},{lon_dest}/json?key={config.TOMTOM_API_KEY}&departAt={depart_datetime}" |
|
|
|
print(f"Calling TomTom API: {url}") |
|
r = requests.get( |
|
url, |
|
timeout=5, |
|
) |
|
|
|
|
|
response = r.json() |
|
|
|
try: |
|
result = response["routes"][0]["summary"] |
|
except KeyError: |
|
print(f"Failed to find a route: {response}") |
|
return "Failed to find a route", response |
|
|
|
distance_m = result["lengthInMeters"] |
|
duration_s = result["travelTimeInSeconds"] |
|
arrival_time = result["arrivalTime"] |
|
|
|
arrival_time = datetime.fromisoformat(arrival_time) |
|
|
|
return { |
|
"distance_m": distance_m, |
|
"duration_s": duration_s, |
|
"arrival_time": arrival_time, |
|
}, response |
|
|
|
|
|
def find_route(destination=""): |
|
"""This function finds a route to a destination and returns the distance and the estimated time to go to a specific destination\ |
|
from the current location. |
|
:param destination (string): Required. The destination |
|
""" |
|
if not destination: |
|
destination = vehicle.destination |
|
|
|
|
|
lat_dest, lon_dest = find_coordinates(destination) |
|
print(f"lat_dest: {lat_dest}, lon_dest: {lon_dest}") |
|
|
|
|
|
vehicle_coordinates = getattr(vehicle, "location_coordinates") |
|
lat_depart, lon_depart = vehicle_coordinates |
|
print(f"lat_depart: {lat_depart}, lon_depart: {lon_depart}") |
|
|
|
date = getattr(vehicle, "date") |
|
time = getattr(vehicle, "time") |
|
departure_time = f"{date}T{time}" |
|
|
|
trip_info, raw_response = find_route_tomtom( |
|
lat_depart, lon_depart, lat_dest, lon_dest, departure_time |
|
) |
|
|
|
distance, duration, arrival_time = ( |
|
trip_info["distance_m"], |
|
trip_info["duration_s"], |
|
trip_info["arrival_time"], |
|
) |
|
|
|
|
|
distance_km = distance * 0.001 |
|
|
|
time_minutes = duration / 60 |
|
if time_minutes < 60: |
|
time_display = f"{time_minutes:.0f} minutes" |
|
else: |
|
hours = int(time_minutes / 60) |
|
minutes = int(time_minutes % 60) |
|
time_display = f"{hours} hours" + ( |
|
f" and {minutes} minutes" if minutes > 0 else "" |
|
) |
|
|
|
|
|
arrival_hour_display = arrival_time.strftime("%H:%M") |
|
|
|
|
|
return f"The route to {destination} is {distance_km:.2f} km which takes {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display}." |
|
|
|
|