# 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("
- ch. voltage %d [V]
- ch. current %d [A]
- ch. type %s
- ch. power %d [kW]
- ch. PlugType %s
" % (
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_())