# Title: CARIAD-Routing GUI # Author: Johannes Ziegmann # Mail: johannes.ziegmann@cariad.technology # Date: 10.12.2021 # Description: CARIAD-Routing GUI for showing the request details graphically distributed on map import sys import os import requests import config as cfg import time import gmplot import datetime from PyQt5 import QtCore, QtWidgets from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtWebEngineWidgets import QWebEngineView # Creating the main window class App(QMainWindow): def __init__(self): super().__init__() self.title = 'CARIAD Routing' self.setWindowTitle(self.title) self.setGeometry(250, 250, 1050, 1000) self.tab_widget = MyTabWidget(self) self.setCentralWidget(self.tab_widget) self.show() # Creating tab widgets class MyTabWidget(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) self.layout = QVBoxLayout(self) # Initialize tab screen self.tabs = QTabWidget() self.tab1 = QWidget() self.tab2 = QWidget() self.tab1UI() self.tab2UI() # Add tabs to widget self.layout.addWidget(self.tabs) self.setLayout(self.layout) def tab1UI(self): self.tabs.addTab(self.tab1, "Map") self.pushButton_setStart = QPushButton() self.pushButton_setStart.setGeometry(QtCore.QRect(10, 10, 250, 30)) self.pushButton_setStart.setFixedSize(250,30) self.pushButton_setStart.setObjectName("pushButton_setStart") self.pushButton_setStart.clicked.connect(self.setStart) self.pushButton_setStart.setText("set ccp") self.pushButton_setDestination = QPushButton() self.pushButton_setDestination.setGeometry(QtCore.QRect(10, 50, 250, 30)) self.pushButton_setDestination.setFixedSize(250,30) self.pushButton_setDestination.setObjectName("pushButton_setDestination") self.pushButton_setDestination.clicked.connect(self.setDestination) self.pushButton_setDestination.setText("set Destination") self.label_map = QWebEngineView(self.tab1)#(ui.centralwidget) self.label_map.setGeometry(QtCore.QRect(10, 90, 1010, 860)) local_url = QUrl.fromLocalFile(os.path.abspath("./figures/map.html")) self.label_map.load(local_url) self.label_map.setWindowTitle('QWebEngineView') self.label_map.show() self.label_map.setZoomFactor(1.4) hbox = QHBoxLayout() vbox = QVBoxLayout() vbox.addWidget(self.pushButton_setStart) vbox.addWidget(self.pushButton_setDestination) vbox.addWidget(self.label_map) self.tab1.setLayout(vbox) def tab2UI(self): self.tabs.addTab(self.tab2, "Vehicle") self.textEdit_vehicle = QTextEdit() self.textEdit_vehicle.setGeometry(QtCore.QRect(20, 10, 200, 30)) self.textEdit_vehicle.setFixedSize(200,30) self.textEdit_vehicle.setObjectName("textEdit_vehicle") self.textEdit_vehicle.setPlaceholderText('not editable') self.textEdit_vehicle.setReadOnly(True) self.textEdit_vehicleData = QTextEdit() self.textEdit_vehicleData.setGeometry(QtCore.QRect(20, 50, 200, 30)) self.textEdit_vehicleData.setFixedSize(200,30) self.textEdit_vehicleData.setObjectName("textEdit_vehicleData") self.textEdit_vehicleData.setPlaceholderText('Vehicle Data (model ID)') self.textEdit_vehicleData.setText('M1J') self.textEdit_consumptionData = QTextEdit() self.textEdit_consumptionData.setGeometry(QtCore.QRect(20, 90, 200, 30)) self.textEdit_consumptionData.setFixedSize(200,30) self.textEdit_consumptionData.setObjectName("textEdit_consumptionData") self.textEdit_consumptionData.setPlaceholderText('Vehicle Data (model code)') self.textEdit_consumptionData.setText('GEN') self.pushButton_showVehicles = QPushButton() self.pushButton_showVehicles.setGeometry(QtCore.QRect(260, 10, 200, 30)) self.pushButton_showVehicles.setFixedSize(200,30) self.pushButton_showVehicles.setObjectName("pushButton_calculateRoute") self.pushButton_showVehicles.clicked.connect(self.showVehicle) self.pushButton_showVehicles.setText("show vehicles") self.pushButton_showVehicleData = QPushButton() self.pushButton_showVehicleData.setGeometry(QtCore.QRect(260, 50, 200, 30)) self.pushButton_showVehicleData.setFixedSize(200,30) self.pushButton_showVehicleData.setObjectName("pushButton_showVehicleData") self.pushButton_showVehicleData.clicked.connect(self.showVehicleData) self.pushButton_showVehicleData.setText("show vehicle data") self.pushButton_showConsumptionData = QPushButton() self.pushButton_showConsumptionData.setGeometry(QtCore.QRect(260, 90, 200, 30)) self.pushButton_showConsumptionData.setFixedSize(200,30) self.pushButton_showConsumptionData.setObjectName("pushButton_showConsumptionData") self.pushButton_showConsumptionData.clicked.connect(self.showConsumptionData) self.pushButton_showConsumptionData.setText("show vehicles") self.pushButton_clear_label_showVhicleData = QPushButton() self.pushButton_clear_label_showVhicleData.setFixedSize(106,106) self.pushButton_clear_label_showVhicleData.setObjectName("pushButton_clear_label_showVhicleData") self.pushButton_clear_label_showVhicleData.clicked.connect(self.clear_label_showVhicleData) self.pushButton_clear_label_showVhicleData.setText("clear") self.label_showVehicleData = QTextBrowser() self.label_showVehicleData.setObjectName("label_showVehicleData") #self.label_showVehicleData.setText("response time [s]:") hbox = QHBoxLayout() vbox = QVBoxLayout() vbox.addWidget(self.textEdit_vehicle) vbox.addWidget(self.textEdit_vehicleData) vbox.addWidget(self.textEdit_consumptionData) hbox.addLayout(vbox) vbox = QVBoxLayout() vbox.addWidget(self.pushButton_showVehicles) vbox.addWidget(self.pushButton_showVehicleData) vbox.addWidget(self.pushButton_showConsumptionData) hbox.addLayout(vbox) hbox.addWidget(self.pushButton_clear_label_showVhicleData) hbox.addStretch(0) vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(self.label_showVehicleData) self.tab2.setLayout(vbox) def clear_label_showVhicleData(self): self.label_showVehicleData.clear() def showVehicle(self): try: # updateBearerToken url = "https://oidc.car-cloud.org/auth/realms/OEM/protocol/openid-connect/token" par = { "grant_type" : "client_credentials", "client_id":"etron-rp", "client_secret":"e7b479bf-df6e-4513-9565-0283d5873f50", } start = time.perf_counter() response = requests.post(url,data=par,timeout=300).json() request_time_token = time.perf_counter() - start print('time get token: %s sec'%str(round(request_time_token,3))) ac_token = response['access_token'] url_cs = "https://cariad-routing.tui.car-cloud.org/vehicles" print(url_cs) head = { 'Authorization': 'Bearer ' + ac_token } start = time.perf_counter() response = requests.get(url_cs,headers=head,timeout=300) request_time = round(time.perf_counter() - start,3) #print('DateTime: %s\nReqest time: %s\nRespones URL: %s\nResponse: %s\n#######################\n\n'%(str(datetime.datetime.now()),str(request_time),str(response.url),str(response))) self.label_showVehicleData.append('### show vehicle ###') self.label_showVehicleData.append('DateTime: '+str(datetime.datetime.now())) self.label_showVehicleData.append('Reqest time: '+str(request_time)) self.label_showVehicleData.append('Respones URL: '+str(response.url)) try: self.label_showVehicleData.append('Response: '+str(response.json())) except: print('ERROR: sevice not reachable') self.label_showVehicleData.append('Response: '+str(response)) self.label_showVehicleData.append('############################################') except Exception as e: print("ERROR : "+str(e)) def showVehicleData(self): try: # updateBearerToken url = "https://oidc.car-cloud.org/auth/realms/OEM/protocol/openid-connect/token" par = { "grant_type" : "client_credentials", "client_id":"etron-rp", "client_secret":"e7b479bf-df6e-4513-9565-0283d5873f50", } start = time.perf_counter() response = requests.post(url,data=par,timeout=300).json() request_time_token = time.perf_counter() - start print('time get token: %s sec'%str(round(request_time_token,3))) ac_token = response['access_token'] url_cs = "https://cariad-routing.tui.car-cloud.org/vehicleData?" print(url_cs) parameter = { "modelId":(self.textEdit_vehicleData.toPlainText()), } head = { 'Authorization': 'Bearer ' + ac_token } start = time.perf_counter() response = requests.get(url_cs,params=parameter,headers=head,timeout=300) request_time = round(time.perf_counter() - start,3) #print('DateTime: %s\nReqest time: %s\nRespones URL: %s\nResponse: %s\n#######################\n\n'%(str(datetime.datetime.now()),str(request_time),str(response.url),str(response))) self.label_showVehicleData.append('### show vehicle data ###') self.label_showVehicleData.append('DateTime: '+str(datetime.datetime.now())) self.label_showVehicleData.append('Reqest time: '+str(request_time)) self.label_showVehicleData.append('Respones URL: '+str(response.url)) try: self.label_showVehicleData.append('Response: '+str(response.json())) except: print('ERROR: sevice not reachable') self.label_showVehicleData.append('Response: '+str(response)) self.label_showVehicleData.append('############################################') except Exception as e: print("ERROR : "+str(e)) def showConsumptionData(self): try: # updateBearerToken url = "https://oidc.car-cloud.org/auth/realms/OEM/protocol/openid-connect/token" par = { "grant_type" : "client_credentials", "client_id":"etron-rp", "client_secret":"e7b479bf-df6e-4513-9565-0283d5873f50", } start = time.perf_counter() response = requests.post(url,data=par,timeout=300).json() request_time_token = time.perf_counter() - start print('time get token: %s sec'%str(round(request_time_token,3))) ac_token = response['access_token'] url_cs = "https://cariad-routing.tui.car-cloud.org/consumptionData?" print(url_cs) parameter = { "modelcode":(self.textEdit_consumptionData.toPlainText()), } head = { 'Authorization': 'Bearer ' + ac_token } start = time.perf_counter() response = requests.get(url_cs,params=parameter,headers=head,timeout=300) request_time = round(time.perf_counter() - start,3) #print('DateTime: %s\nReqest time: %s\nRespones URL: %s\nResponse: %s\n#######################\n\n'%(str(datetime.datetime.now()),str(request_time),str(response.url),str(response))) self.label_showVehicleData.append('### show vehicle consumption data ###') self.label_showVehicleData.append('DateTime: '+str(datetime.datetime.now())) self.label_showVehicleData.append('Reqest time: '+str(request_time)) self.label_showVehicleData.append('Respones URL: '+str(response.url)) try: self.label_showVehicleData.append('Response: '+str(response.json())) except: print('ERROR: sevice not reachable') self.label_showVehicleData.append('Response: '+str(response)) self.label_showVehicleData.append('############################################') except Exception as e: print("ERROR : "+str(e)) def setStart(self): try: url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + str(self.textEdit_from.toPlainText()) + '.json' parameters = {'access_token':cfg.conf['key_MapBox']} lat_s,lng_s = requests.get(url,params=parameters,timeout=300).json()['features'][0]['center'] url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + str(self.textEdit_to.toPlainText()) + '.json' parameters = {'access_token':cfg.conf['key_MapBox']} lat_d,lng_d = requests.get(url,params=parameters,timeout=300).json()['features'][0]['center'] ############################# ### CariadRouting (LDEVR) ### ############################# # updateBearerToken url = "https://oidc.car-cloud.org/auth/realms/OEM/protocol/openid-connect/token" par = { "grant_type" : "client_credentials", "client_id":"etron-rp", "client_secret":"e7b479bf-df6e-4513-9565-0283d5873f50", } start = time.perf_counter() response = requests.post(url,data=par,timeout=300).json() request_time_token = time.perf_counter() - start print('time get token: %s sec'%str(round(request_time_token,3))) ac_token = response['access_token'] parameter = { "vin":int(self.textEdit_VIN.toPlainText()), "latStart":lng_s, "longStart":lat_s, "latDestination":lng_d, "longDestination":lat_d, } #url_cs = "https://cariad-routing.tui.car-cloud.org/calculateRoute?" url_cs = self.combo_box_url.currentText() print(url_cs) head = { 'Authorization': 'Bearer ' + ac_token } start = time.perf_counter() response = requests.get(url_cs,params=parameter,headers=head,timeout=300) request_time = round(time.perf_counter() - start,3) print(response.url) response = response.json() #print(response) # ToDo change + get from vehicle par={'maxChargeInkWh':92, 'currentChargeInkWh':9, 'minChargeAtDestinationInkWh':4.2, 'minChargeAtChargingStopsInkWh':5, } #add the CARIAD Routing request time self.textBrowser_responseTime.append(str(request_time)) try: lat = [] lng = [] lat_ch = [] lng_ch = [] time_ch = [] # charging time arrival_energy = [] target_energy = [] charging_power = [] facility_info = [] leg_distance = [] chargingPark_name = [] ch_info_type = [] for i in range(len(response['routes'][0]['legs'])): boundary = response['routes'][0]['legs'][i]['points'] lat_ch.append(response['routes'][0]['legs'][i]['points'][-1]['latitude']) lng_ch.append(response['routes'][0]['legs'][i]['points'][-1]['longitude']) try: time_ch.append(response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingTimeInSeconds']/60) arrival_energy.append(response['routes'][0]['legs'][i]['summary']['remainingChargeAtArrivalInkWh']) target_energy.append(response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['targetChargeInkWh']) charging_power.append((response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['targetChargeInkWh'] -response['routes'][0]['legs'][i]['summary']['remainingChargeAtArrivalInkWh']) /(response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingTimeInSeconds']/3600)) leg_distance.append(response['routes'][0]['legs'][i]['summary']['lengthInMeters']) chargingPark_name.append(response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingParkName']) try: ch_info_type.append("" % ( response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingConnectionInfo']['chargingVoltageInV'], response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingConnectionInfo']['chargingCurrentInA'], response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingConnectionInfo']['chargingCurrentType'], response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingConnectionInfo']['chargingPowerInkW'], response['routes'][0]['legs'][i]['summary']['chargingInformationAtEndOfLeg']['chargingConnectionInfo']['chargingPlugType'] ) ) except: ch_info_type.append("") pass except: pass for d in boundary: lat.append(d['latitude']) lng.append(d['longitude']) # delete destination point lat_ch=lat_ch[:-1] lng_ch=lng_ch[:-1] time_r = request_time # s distance = response['routes'][0]['summary']['lengthInMeters']/1000 # km travel_time = response['routes'][0]['summary']['travelTimeInSeconds']/60 # min traffic_time = response['routes'][0]['summary']['trafficDelayInSeconds']/60 # min charging_time = response['routes'][0]['summary']['totalChargingTimeInSeconds']/60 # min charging_stops = len(lat_ch) # amount of charging stops arrival_energy_g = response['routes'][0]['summary']['remainingChargeAtArrivalInkWh'] total_energy = response['routes'][0]['summary']['batteryConsumptionInkWh'] if len(lat_ch)==0: lat_ch = 0 lng_ch = 0 Tab=[] Tab.append([lat,lng,lat_ch,lng_ch,time_r,distance,travel_time,traffic_time,charging_time,charging_stops,time_ch,arrival_energy,target_energy,charging_power,facility_info,'CARIAD Routing',arrival_energy_g,total_energy,leg_distance,chargingPark_name,ch_info_type]) ### Google Plot ### apikey = cfg.conf['key_Google'] # (your API key here) # GoogleMapPlotter return Map object # Pass the center latitude and center longitude gmap = gmplot.GoogleMapPlotter((lng_s+lng_d)/2, (lat_s+lat_d)/2, 7, apikey=apikey) color = ['#B22222','#1E90FF','#C0C0C0','#008000','#BDB76B','#FF8C00','#7FFFD4','#807673','#B22222','#B22222','#1E90FF','#C0C0C0','#008000','#BDB76B','#FF8C00','#7FFFD4','#807673','#B22222','#B22222','#1E90FF','#C0C0C0','#008000','#BDB76B','#FF8C00','#7FFFD4','#807673','#B22222'] for i in range(len(Tab)): if Tab[i] != 'No Route Found': gmap.plot( (Tab[i][0]), (Tab[i][1]), color=color[i], edge_width=12-2*i, label=('%s Routing' % Tab[i][15]), alpha=1-(i/10) ) if Tab[i][3] != 0: acc_d = 0 for j in range(len(Tab[i][2])): # iterate through charging stations acc_d = acc_d+Tab[i][18][j]/1000 gmap.marker( (Tab[i][2][j]), (Tab[i][3][j]), color=color[i], label=('%d'%(j+1)), info_window=('
' + '
' + "
" + '

' + ('%d - %s Charging' % (j+1,Tab[i][15])) + '

' + '
' + ("charging time %.2f [min]
arrival energy %.2f [kWh] (%.2f %%)
target energy %.2f [kWh] (%.2f %%)
calculated power %.2f kW
Distance of the leg %.2f [km]
Acc distance of legs %.2f [km]
Charging Name: %s
Charging Info:
%s" % (Tab[i][10][j],Tab[i][11][j],Tab[i][11][j]/par['maxChargeInkWh']*100,Tab[i][12][j],Tab[i][12][j]/par['maxChargeInkWh']*100,Tab[i][13][j],Tab[i][18][j]/1000,acc_d,Tab[i][19][j],Tab[i][20][j])) + "
" + "
"), marker=True, title=('%d - %s charging' % (j+1,Tab[i][15])), ) gmap.marker( lng_s, lat_s, label='S', info_window=('
' + '
' + "
" + '

' + ('%s Start Point' % (Tab[i][15])) + '

' + '
' + ("start energy %.2f [kWh] (%.2f %%)
max. Energy %.2f [kWh]
Setting: min. charge at Destination %.2f [kWh] (%.2f %%)
Setting: min. charge at Charging Stops %.2f [kWh] (%.2f %%) " % (par['currentChargeInkWh'],par['currentChargeInkWh']/par['maxChargeInkWh']*100,par['maxChargeInkWh'],par['minChargeAtDestinationInkWh'],par['minChargeAtDestinationInkWh']/par['maxChargeInkWh']*100,par['minChargeAtChargingStopsInkWh'],par['minChargeAtChargingStopsInkWh']/par['maxChargeInkWh']*100)) + "
" + "
"), ) gmap.marker( lng_d, lat_d, label='D', info_window=('
' + '
' + "
" + '

' + ('%s Destination Point' % (Tab[i][15])) + '

' + '
' + ("arrival energy %.2f [kWh] (%.2f %%)
total amount of energy %.2f [kWh] (%.2f %%)
charging stopps %.0f [-]
summary of charging time %.2f [min]
traffic delay time %.2f [min]
travel time %.2f [min]
total distance %.2f [km]
response time %.2f[s]" % (Tab[i][16],Tab[i][16]/par['maxChargeInkWh']*100,Tab[i][17],Tab[i][17]/par['maxChargeInkWh']*100,Tab[i][9],Tab[i][8],Tab[i][7],Tab[i][6],Tab[i][5],Tab[i][4])) + "
" + "
"), ) gmap.draw("figures/Routing_onMap.html") local_url = QUrl.fromLocalFile(os.path.abspath("./figures/Routing_onMap.html")) self.label_map.load(local_url) self.label_map.setZoomFactor(1.25) except: print(response) local_url = QUrl.fromLocalFile(os.path.abspath("./figures/error.html")) self.label_map.load(local_url) msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(str(response)) msg.setWindowTitle("Warning MessageBox") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) retval = msg.exec_() except Exception as e: print("Bad Input") print("ERROR : "+str(e)) local_url = QUrl.fromLocalFile(os.path.abspath("./figures/error.html")) self.label_map.load(local_url) def setDestination(self): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText('!RangeOnMap (360 Range) coming soon!') msg.setWindowTitle("Warning MessageBox") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) retval = msg.exec_() if __name__ == '__main__': app = QApplication(sys.argv) app.setStyleSheet('QMainWindow{border: 2px solid gray;}') ex = App() sys.exit(app.exec_())