File size: 5,900 Bytes
63ec258
 
 
 
 
 
 
 
 
 
187a965
63ec258
 
 
 
 
 
 
 
e5f444f
 
5baa807
 
 
 
e5f444f
63ec258
 
5baa807
 
 
e5f444f
 
 
5baa807
63ec258
 
e5f444f
63ec258
e5f444f
 
cb47347
 
 
e5f444f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3ae3815
e5f444f
 
63ec258
 
 
 
 
 
 
 
cb47347
 
 
 
63ec258
 
cb47347
 
187a965
 
cc1b4c0
 
 
63ec258
cc1b4c0
63ec258
 
cb47347
 
63ec258
cb47347
cc1b4c0
 
 
 
 
63ec258
 
 
 
 
 
cb47347
63ec258
 
 
 
 
 
 
 
7b96044
 
63ec258
 
247bc50
 
 
63ec258
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e5f444f
 
 
 
 
63ec258
 
 
cb47347
63ec258
cb47347
 
 
 
 
63ec258
 
 
cb47347
 
 
 
 
7b96044
cc1b4c0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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
    """
    # https://developer.tomtom.com/geocoding-api/documentation/geocode
    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_geo(lat=lats, lon=lons)
    # fig.update_geos(fitbounds="locations")

    fig = px.line_mapbox(
        lat=lats, lon=lons, zoom=12, height=600, color_discrete_sequence=["red"]
    )

    fig.update_layout(
        mapbox_style="open-street-map",
        # mapbox_zoom=12,
    )
    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

    # origin = "49.631997,6.171029"
    # destination = "49.586745,6.140002"

    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'.
    """
    # https://developer.tomtom.com/routing-api/documentation/routing/calculate-route
    # https://developer.tomtom.com/routing-api/documentation/routing/guidance-instructions
    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,
    )

    # Parse JSON from the response
    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"]
    # Convert string to datetime object
    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, lon, city = check_city_coordinates(lat_depart,lon_depart,city_depart)
    lat_dest, lon_dest = find_coordinates(destination)
    print(f"lat_dest: {lat_dest}, lon_dest: {lon_dest}")

    # Extract the latitude and longitude of the vehicle
    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"],
    )

    # Calculate distance in kilometers (1 meter = 0.001 kilometers)
    distance_km = distance * 0.001
    # Calculate travel time in minutes (1 second = 1/60 minutes)
    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 ""
        )

    # Extract and display the arrival hour in HH:MM format
    arrival_hour_display = arrival_time.strftime("%H:%M")

    # return the distance and time
    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}."
    # raw_response["routes"][0]["legs"][0]["points"]