2022-03-10 21:51:55 +01:00
import tkinter
import threading
2022-03-10 14:59:19 +01:00
from selenium import webdriver
from selenium . webdriver . chrome . service import Service
from webdriver_manager . chrome import ChromeDriverManager
from selenium . webdriver . common . by import By
2022-03-10 21:51:55 +01:00
from selenium . webdriver . common . keys import Keys
2022-03-10 14:59:19 +01:00
from PIL import Image
2022-03-11 21:39:01 +01:00
import os
2022-03-11 22:18:02 +01:00
import qrcode
2022-03-10 21:51:55 +01:00
from tkinter import filedialog
2022-03-10 14:59:19 +01:00
import time
2022-11-07 09:58:57 +01:00
import datetime
from dateutil . relativedelta import relativedelta
2022-03-19 11:23:37 +01:00
from selenium . webdriver . common . action_chains import ActionChains
2022-11-07 09:58:57 +01:00
import json
import requests
2022-03-10 14:59:19 +01:00
2022-11-05 14:26:59 +01:00
DropDownLabels = [ " Street: " , " Number: " , " Postal code: " , " City: " , " Sonnendach URL: " , " Suitability " , " Image Filename Map: " , " Image Filename Production: " , " Image Filename qrcode: " , " PV Production 50 " , " PV Production 75 " , " PV Production 100 " , " Value Electricity production " , " Roof area " ]
2022-03-11 18:51:14 +01:00
file_split_char = " , "
2022-03-11 17:47:01 +01:00
OptionList = [ ]
2022-03-10 21:51:55 +01:00
exit = False
stopThread = False
filename_adresslist = " "
adresslist = " "
step = 0
2022-07-27 13:45:26 +02:00
service = Service ( ChromeDriverManager ( ) . install ( ) )
driver = webdriver . Chrome ( service = service )
2022-03-10 21:51:55 +01:00
driver . minimize_window ( )
outputtext = " Welcome to application Sonnendach \n "
2022-03-11 18:51:14 +01:00
columnIndexes = [ ]
2022-03-11 17:47:01 +01:00
2022-03-10 21:51:55 +01:00
2022-03-11 20:44:21 +01:00
2022-07-27 18:08:24 +02:00
def search_adresses ( adress_list , filename_adresslist , driver , mainText ) :
2022-03-11 17:47:01 +01:00
global file_split_char
global stopThread
2022-03-11 18:51:14 +01:00
global columnIndexes
2022-07-27 18:08:24 +02:00
global outputtext
2022-11-07 09:58:57 +01:00
global checkBoxCreateImages
2022-03-11 18:51:14 +01:00
2022-07-27 13:45:26 +02:00
#Create Direcotrys to save screenshots and qrcodes if they don't exist yet.
2022-03-11 21:39:01 +01:00
if ( not os . path . exists ( " screenshots " ) ) :
os . makedirs ( " screenshots " , exist_ok = False )
2022-03-11 22:18:02 +01:00
if ( not os . path . exists ( " qrcodes " ) ) :
os . makedirs ( " qrcodes " , exist_ok = False )
2022-03-11 17:47:01 +01:00
2022-11-07 09:58:57 +01:00
startTime = datetime . datetime . now ( )
2022-11-05 14:26:59 +01:00
address_count = len ( adress_list )
2022-07-27 13:45:26 +02:00
#Search for each adress in the list and create screenshots and qrcodes
2022-11-05 14:26:59 +01:00
for i in range ( address_count ) :
2022-03-10 14:59:19 +01:00
line = adress_list [ i ]
adress = line . split ( file_split_char )
2022-07-27 17:30:05 +02:00
if ( ( line != adress_list [ 0 ] ) & ( adress [ columnIndexes [ 4 ] ] == " " ) & ( len ( adress [ columnIndexes [ 0 ] ] ) > 0 ) & ( len ( adress [ columnIndexes [ 1 ] ] ) > 0 ) & ( len ( adress [ columnIndexes [ 2 ] ] ) > 0 ) & ( len ( adress [ columnIndexes [ 3 ] ] ) > 0 ) ) :
2022-03-11 18:51:14 +01:00
search_string = adress [ columnIndexes [ 0 ] ] + " " + adress [ columnIndexes [ 1 ] ] + " " + adress [ columnIndexes [ 2 ] ] + " " + adress [ columnIndexes [ 3 ] ]
2022-11-05 14:26:59 +01:00
2022-11-07 09:58:57 +01:00
if ( createImages . get ( ) > 0 ) :
search_bar = driver . find_element ( By . ID , " searchTypeahead1 " )
search_bar . send_keys ( Keys . CONTROL + " a " )
search_bar . send_keys ( Keys . DELETE )
search_bar . send_keys ( search_string )
driver . implicitly_wait ( 10 )
time . sleep ( 0.7 )
found = False
suggestions = driver . find_elements ( By . XPATH , " //div[@class= ' tt-suggestion tt-selectable ' ] " )
for suggestion in suggestions :
if ( suggestion . text == search_string ) :
found = True
suggestion . click ( )
driver . implicitly_wait ( 10 )
break
if ( found ) :
time . sleep ( 0.7 )
url = driver . current_url
suitability = driver . find_element ( By . ID , " eignung " ) . text
pv_Production50 = driver . find_element ( By . ID , " pv50 " ) . text . replace ( " ' " , " " )
pv_Production75 = driver . find_element ( By . ID , " pv75 " ) . text . replace ( " ' " , " " )
pv_Production100 = driver . find_element ( By . ID , " pv100 " ) . text . replace ( " ' " , " " )
value_electricity_production = driver . find_elements ( By . XPATH , " //h2[@id= ' TitelSolarstrom ' ]//strong " ) [ 2 ] . text . replace ( " ' " , " " ) . replace ( " Franken " , " " )
roof_area = driver . find_element ( By . ID , " areaOutput " ) . text
time . sleep ( 2 )
2022-11-05 14:26:59 +01:00
image_filename = suitability + " - " + search_string
image_folder_map = " screenshots/ "
image_filename_map = image_filename + " map " + " .png "
image_folder_production = " screenshots/ "
image_filename_production = image_filename + " production " + " .png "
image_folder_qrcode = " qrcodes/ "
image_filename_qrcode = image_filename + " qrcode " + " .png "
# Create QR-Code
qr = qrcode . QRCode ( version = 1 , box_size = 10 , border = 5 )
qr . add_data ( url )
qr . make ( fit = True )
qr . make_image ( fill = ' black ' , back_color = ' white ' ) . save ( image_folder_qrcode + image_filename_qrcode )
# Create Screenshot of Map
actions = ActionChains ( driver )
try :
driver . execute_script ( """ var l = document.getElementsByClassName( " ol-zoom ol-unselectable ol-control " )[0];
l . parentNode . removeChild ( l ) ; """ )
except :
pass
mapElement = driver . find_element ( By . XPATH ,
" //div[@id= ' map ' ]//div[@class= ' ol-viewport ' ] " )
location = mapElement . location
size = mapElement . size
2022-07-27 17:30:05 +02:00
x = location [ " x " ]
y = location [ " y " ]
w = x + size [ " width " ]
h = size [ " height " ]
area = ( x , 0 , w , h )
driver . execute_script ( " window.scrollTo(0, " + str ( y ) + " ) " )
2022-03-19 11:23:37 +01:00
time . sleep ( 1 )
2022-11-05 14:26:59 +01:00
driver . save_screenshot ( image_folder_map + image_filename_map )
2022-03-19 11:23:37 +01:00
time . sleep ( 0.2 )
2022-11-05 14:26:59 +01:00
Image . open ( image_folder_map + image_filename_map ) . crop ( area ) . save (
image_folder_map + image_filename_map )
# Create Screenshot of Chart
try :
chartElement = driver . find_elements ( By . XPATH , " //div[@id= ' chart ' ]//* " ) [ 0 ]
location = chartElement . location
size = chartElement . size
x = location [ " x " ]
y = location [ " y " ]
w = x + size [ " width " ]
h = size [ " height " ]
area = ( x , 0 , w , h )
driver . execute_script ( " window.scrollTo(0, " + str ( y ) + " ) " )
time . sleep ( 1 )
driver . save_screenshot ( image_folder_production + image_filename_production )
time . sleep ( 0.2 )
Image . open ( image_folder_production + image_filename_production ) . crop ( area ) . save (
image_folder_production + image_filename_production )
except :
image_filename_production = " not-found "
2022-11-07 09:58:57 +01:00
print ( " saved Address: " + search_string )
2022-11-05 14:26:59 +01:00
else :
2022-11-07 09:58:57 +01:00
url = " not-found "
suitability = " not-found "
image_filename_map = " not-found "
image_filename_production = " not-found "
image_filename_qrcode = " not-found "
pv_Production50 = " not-found "
pv_Production75 = " not-found "
pv_Production100 = " not-found "
value_electricity_production = " not-found "
roof_area = " not-found "
print ( " not found: " + search_string )
else : # If no images must be created
try :
# Address to coordinates
params = {
" type " : " locations " ,
" searchText " : search_string ,
" lang " : " de " }
locationsResponse = requests . get ( ' https://api3.geo.admin.ch/rest/services/api/SearchServer ' ,
params = params )
locations = json . loads ( locationsResponse . content . decode ( ) )
firstLocation = locations [ ' results ' ] [ 0 ] [ ' attrs ' ]
# you need the coordinates from other services, once you have them
coordinates = ( firstLocation [ ' y ' ] , firstLocation [ ' x ' ] ) # example coordinates
coordinates_str = ' , ' . join ( map ( str , coordinates ) )
tolerance = 1
# this is wrong, bbox should be computed using tolerance and pixel size, but there are no problems for the
# purpose of this exercise
bbox = ( coordinates [ 0 ] - tolerance , coordinates [ 1 ] - tolerance , coordinates [ 0 ] + tolerance ,
coordinates [ 1 ] + tolerance )
bbox_str = ' , ' . join ( map ( str , bbox ) )
params = {
" geometryType " : " esriGeometryPoint " ,
" returnGeometry " : " true " ,
" layers " : " all:ch.bfe.solarenergie-eignung-daecher " ,
" geometry " : coordinates_str ,
" mapExtent " : bbox_str ,
" imageDisplay " : " 1391,1070,96 " ,
" tolerance " : tolerance ,
" order " : " distance " ,
" lang " : " de " ,
}
# retrieve one roof and the building_id associated
response_one_roof = requests . get ( ' https://api3.geo.admin.ch/rest/services/api/MapServer/identify ' ,
params = params )
response_one_roof_decoded = json . loads ( response_one_roof . content . decode ( ) )
results = ( response_one_roof_decoded [ ' results ' ] )
# for result in results:
# print(result)
building_id = ( response_one_roof_decoded ) [ ' results ' ] [ 0 ] [ ' attributes ' ] [ ' building_id ' ]
# use the building_id of previous request to get all roofs associated with this building_id
params = {
' layer ' : ' ch.bfe.solarenergie-eignung-daecher ' ,
' searchField ' : ' building_id ' ,
' contains ' : ' false ' ,
' searchText ' : str ( building_id ) ,
' returnGeometry ' : ' false '
}
response_all_roofs = requests . get ( ' https://api3.geo.admin.ch/rest/services/api/MapServer/find ' ,
params = params )
response_all_roofs_decoded = json . loads ( response_all_roofs . content . decode ( ) ) [ ' results ' ]
best_roof = response_all_roofs_decoded [ 0 ] # TODO: Find best roof
for roof in response_all_roofs_decoded :
if ( float ( roof [ ' attributes ' ] [ ' flaeche ' ] ) > float ( best_roof [ ' attributes ' ] [ ' flaeche ' ] ) ) :
best_roof = roof
url = " https://www.uvek-gis.admin.ch/BFE/sonnendach/index.html?featureId= " + str ( best_roof [ ' featureId ' ] ) + " &lang=de "
suitability = str ( best_roof [ ' attributes ' ] [ ' klasse ' ] )
image_filename_map = " not-created "
image_filename_production = " not-created "
image_filename_qrcode = " not-created "
pv_Production100 = str ( float ( best_roof [ ' attributes ' ] [ ' gstrahlung ' ] ) * 0.2 * 0.8 )
pv_Production75 = str ( float ( pv_Production100 ) * 0.75 )
pv_Production50 = str ( float ( pv_Production100 ) * 0.5 )
value_electricity_production = str ( best_roof [ ' attributes ' ] [ ' finanzertrag ' ] )
roof_area = str ( best_roof [ ' attributes ' ] [ ' flaeche ' ] )
print ( " saved Address: " + search_string )
except :
url = " not-found "
suitability = " not-found "
image_filename_map = " not-found "
image_filename_production = " not-found "
image_filename_qrcode = " not-found "
pv_Production50 = " not-found "
pv_Production75 = " not-found "
pv_Production100 = " not-found "
value_electricity_production = " not-found "
roof_area = " not-found "
print ( " Address " + str ( i ) + " of " + str ( address_count ) )
timediff = relativedelta ( datetime . datetime . now ( ) , startTime )
print ( " Process is running since %d years %d months %d days %d hours %d minutes %d seconds " % ( timediff . years , timediff . months , timediff . days , timediff . hours , timediff . minutes , timediff . seconds ) )
2022-03-19 11:23:37 +01:00
#Write back into file
adress [ columnIndexes [ 4 ] ] = url
2022-07-27 17:46:27 +02:00
adress [ columnIndexes [ 5 ] ] = suitability
2022-03-19 11:23:37 +01:00
adress [ columnIndexes [ 6 ] ] = image_filename_map
adress [ columnIndexes [ 7 ] ] = image_filename_production
adress [ columnIndexes [ 8 ] ] = image_filename_qrcode
adress [ columnIndexes [ 9 ] ] = pv_Production50
adress [ columnIndexes [ 10 ] ] = pv_Production75
adress [ columnIndexes [ 11 ] ] = pv_Production100
adress [ columnIndexes [ 12 ] ] = value_electricity_production
2022-11-05 14:26:59 +01:00
adress [ columnIndexes [ 13 ] ] = roof_area
2022-11-04 10:21:51 +01:00
adress_file = open ( filename_adresslist , " w " , encoding = " utf-8 " )
2022-03-19 11:23:37 +01:00
new_line_string = " "
for j in adress :
new_line_string = new_line_string + j + file_split_char
adress_list [ i ] = new_line_string
new_adress_list = " "
for j in adress_list :
new_adress_list = new_adress_list + ( j ) + " \n "
adress_file . write ( new_adress_list )
adress_file . close ( )
2022-03-10 21:51:55 +01:00
if ( stopThread == True ) :
2022-07-27 18:08:24 +02:00
print ( " closing Thread " )
return
2022-03-10 21:51:55 +01:00
2022-07-27 18:08:24 +02:00
outputtext = outputtext + " Reached end of list. \n Press Exit to close the application. " + " \n "
mainText . config ( text = outputtext )
2022-07-27 17:30:05 +02:00
print ( " closing Thread " )
2022-07-27 18:08:24 +02:00
return
2022-03-10 21:51:55 +01:00
def read_adresslist ( filename_adresslist ) :
returnvalues = [ ]
try :
2022-11-04 10:21:51 +01:00
adress_file = open ( filename_adresslist , " r " , encoding = " utf-8 " )
2022-03-10 21:51:55 +01:00
adress_list = adress_file . read ( ) . splitlines ( )
adress_file . close ( )
returnvalues . append ( True )
returnvalues . append ( adress_list )
except :
returnvalues . append ( False )
return returnvalues
2022-03-11 17:47:01 +01:00
def createFrameFileColums ( headers ) :
global OptionList
2022-03-11 18:51:14 +01:00
global DropDownLabels
2022-03-11 17:47:01 +01:00
for header in headers :
OptionList . append ( header )
2022-03-11 17:56:48 +01:00
desctext = tkinter . Label ( frameFileColums , text = " Please select Headers of Columns " )
2022-03-11 17:47:01 +01:00
desctext . grid ( row = 1 , column = 1 , padx = 10 , pady = 3 )
frameFileColums1 = tkinter . Frame ( frameFileColums )
frameFileColums1 . grid ( row = 2 , column = 1 , padx = 10 , pady = 3 )
2022-03-11 18:51:14 +01:00
for i in range ( len ( DropDownLabels ) ) :
exec ( " text " + str ( i + 1 ) + " = tkinter.Label(frameFileColums1, text= \" " + DropDownLabels [ i ] + " \" ) " )
exec ( " text " + str ( i + 1 ) + " .grid(row= " + str ( i + 1 ) + " , column=1, padx=10, pady=3) " )
exec ( " dropdown " + str ( i + 1 ) + " = tkinter.OptionMenu(frameFileColums1, variablesDropdown[ " + str ( i ) + " ], *OptionList) " )
exec ( " dropdown " + str ( i + 1 ) + " .grid(row= " + str ( i + 1 ) + " , column=2, padx=10, pady=3) " )
2022-03-11 17:47:01 +01:00
2022-03-11 18:51:14 +01:00
def getColumnIndex ( ) :
2022-03-11 17:47:01 +01:00
global OptionList
2022-03-11 18:51:14 +01:00
global columnIndexes
for j in range ( len ( DropDownLabels ) ) :
for i in range ( len ( OptionList ) ) :
if ( OptionList [ i ] == variablesDropdown [ j ] . get ( ) ) :
columnIndexes . append ( i )
2022-03-11 17:47:01 +01:00
2022-03-10 21:51:55 +01:00
def command ( ) :
global exit
global stopThread
global adresslist
global step
global driver
global filename_adresslist
global outputtext
global thread_search_adresses
2022-03-11 17:47:01 +01:00
global file_split_char
2022-03-10 21:51:55 +01:00
if ( exit ) :
2022-03-11 17:47:01 +01:00
print ( " Command Exit received " )
2022-03-10 21:51:55 +01:00
stopThread = True
2022-03-10 22:07:48 +01:00
try :
thread_search_adresses . join ( )
except :
pass
2022-03-11 17:47:01 +01:00
print ( " Thread is closed " )
2022-03-10 21:51:55 +01:00
root . quit ( )
2022-03-11 17:47:01 +01:00
print ( " Application is closed " )
2022-03-10 21:51:55 +01:00
driver . quit ( )
2022-03-11 17:47:01 +01:00
print ( " Webdriver is closed " )
2022-03-10 21:51:55 +01:00
elif ( step == 0 ) :
#Schritt 1
filename_adresslist = filedialog . askopenfilename ( )
2022-03-11 17:47:01 +01:00
outputtext = outputtext + " Searching File " + filename_adresslist + " \n "
mainText . config ( text = outputtext )
2022-03-10 21:51:55 +01:00
adress_list_result = read_adresslist ( filename_adresslist )
2022-11-07 09:58:57 +01:00
if ( adress_list_result [ 0 ] ) :
2022-03-10 21:51:55 +01:00
adresslist = adress_list_result [ 1 ]
2022-03-11 17:47:01 +01:00
outputtext = outputtext + " File " + filename_adresslist + " found. " + " \n "
mainText . config ( text = outputtext )
button1 . config ( text = " read file " )
createFrameFileColums ( adresslist [ 0 ] . split ( file_split_char ) )
frameFileColums . grid ( row = 2 , column = 1 )
2022-03-10 21:51:55 +01:00
step + = 1
else :
2022-03-11 17:47:01 +01:00
outputtext = outputtext + " File " + filename_adresslist + " not found. " + " \n "
mainText . config ( text = outputtext )
2022-03-10 21:51:55 +01:00
exit = True
button1 . grid_remove ( )
2022-03-11 17:47:01 +01:00
elif ( step == 1 ) :
2022-03-11 18:51:14 +01:00
# TODO: check if dropdowns are selected
getColumnIndex ( )
2022-03-11 17:47:01 +01:00
outputtext = outputtext + " Reading File " + filename_adresslist + " done. " + " \n "
mainText . config ( text = outputtext )
frameFileColums . grid_remove ( )
button1 . config ( text = " open Webbrowser " )
step + = 1
elif ( step == 2 ) :
2022-03-10 21:51:55 +01:00
# Schritt 2
outputtext = outputtext + " Website is opening " + " \n "
2022-03-11 17:47:01 +01:00
mainText . config ( text = outputtext )
2022-03-10 21:51:55 +01:00
try :
driver . maximize_window ( )
driver . get ( " https://www.uvek-gis.admin.ch/BFE/sonnendach/ " )
driver . implicitly_wait ( 20 )
outputtext = outputtext + " opening website was done. \n Prepare the browser window to create screenshots. " + " \n "
2022-03-11 17:47:01 +01:00
mainText . config ( text = outputtext )
2022-03-10 21:51:55 +01:00
button1 . config ( text = " start process " )
step + = 1
except :
outputtext = outputtext + " opening website failed " + " \n "
2022-03-11 17:47:01 +01:00
mainText . config ( text = outputtext )
2022-03-10 21:51:55 +01:00
exit = True
button1 . grid_remove ( )
2022-03-11 17:47:01 +01:00
elif ( step == 3 ) :
2022-07-27 18:08:24 +02:00
thread_search_adresses = threading . Thread ( target = search_adresses , args = ( adresslist , filename_adresslist , driver , mainText ) )
2022-03-10 21:51:55 +01:00
thread_search_adresses . start ( )
2022-03-11 17:47:01 +01:00
print ( " Thread started " )
2022-07-27 20:39:10 +02:00
outputtext = outputtext + " process has started. " + " \n "
2022-03-11 17:47:01 +01:00
mainText . config ( text = outputtext )
2022-03-10 21:51:55 +01:00
button1 . grid_remove ( )
exit = True
def command_exit ( ) :
2022-03-10 22:07:48 +01:00
global exit
2022-03-10 21:51:55 +01:00
exit = True
command ( )
root = tkinter . Tk ( )
2022-03-15 08:14:51 +01:00
root . protocol ( " WM_DELETE_WINDOW " , command_exit )
2022-03-10 21:51:55 +01:00
root . wm_title ( " Sonnendach " )
2022-03-11 17:47:01 +01:00
mainText = tkinter . Label ( root , text = outputtext , width = 80 )
mainText . grid ( row = 1 , column = 1 , padx = 10 , pady = 3 )
frameFileColums = tkinter . Frame ( root )
2022-03-11 18:51:14 +01:00
variablesDropdown = [ ]
for i in range ( len ( DropDownLabels ) ) :
variablesDropdown . append ( tkinter . StringVar ( root ) )
2022-03-11 17:47:01 +01:00
frameButtons = tkinter . Frame ( root )
frameButtons . grid ( row = 3 , column = 1 )
2022-11-07 09:58:57 +01:00
createImages = tkinter . IntVar ( )
checkBoxCreateImages = tkinter . Checkbutton ( frameButtons , text = " create images " , variable = createImages )
checkBoxCreateImages . grid ( )
2022-03-11 17:47:01 +01:00
button1 = tkinter . Button ( frameButtons , text = " Select Adresslist file " , command = command , width = 20 , height = 2 , bg = " #FCCA03 " )
button1 . grid ( row = 3 , column = 1 , padx = 10 , pady = 3 )
button2 = tkinter . Button ( frameButtons , text = " EXIT " , command = command_exit , width = 20 , height = 2 , bg = " #FCCA03 " )
button2 . grid ( row = 3 , column = 2 , padx = 10 , pady = 3 )
2022-03-10 21:51:55 +01:00
root . mainloop ( )