diff --git a/Sonnendach.py b/Sonnendach.py index 66956dd..3d1f908 100644 --- a/Sonnendach.py +++ b/Sonnendach.py @@ -10,9 +10,12 @@ import os import qrcode from tkinter import filedialog import time +import datetime +from dateutil.relativedelta import relativedelta from selenium.webdriver.common.action_chains import ActionChains +import json +import requests -create_images = True 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"] file_split_char = "," OptionList = [] @@ -34,7 +37,7 @@ def search_adresses(adress_list, filename_adresslist, driver, mainText): global stopThread global columnIndexes global outputtext - + global checkBoxCreateImages #Create Direcotrys to save screenshots and qrcodes if they don't exist yet. if(not os.path.exists("screenshots")): @@ -42,41 +45,42 @@ def search_adresses(adress_list, filename_adresslist, driver, mainText): if (not os.path.exists("qrcodes")): os.makedirs("qrcodes", exist_ok=False) + startTime = datetime.datetime.now() address_count = len(adress_list) #Search for each adress in the list and create screenshots and qrcodes for i in range(address_count): line = adress_list[i] adress = line.split(file_split_char) 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)): - print(adress) search_string = adress[columnIndexes[0]] + " " + adress[columnIndexes[1]] + " " + adress[columnIndexes[2]] + " " + adress[columnIndexes[3]] - 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) - 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(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(2) - 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") - - if(create_images): + 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) image_filename = suitability + " - " + search_string image_folder_map = "screenshots/" image_filename_map = image_filename + " map" + ".png" @@ -135,27 +139,103 @@ def search_adresses(adress_list, filename_adresslist, driver, mainText): except: image_filename_production = "not-found" + print("saved Address: " + search_string) else: - image_filename_map = "not created" - image_filename_production = "not created" - image_filename_qrcode = "not created" + 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("saved Address: " + search_string) - print("Address " + str(i) + " of " + str(address_count)) - else: - 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'] - print("not found: " + search_string) + # 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)) #Write back into file @@ -254,7 +334,7 @@ def command(): outputtext = outputtext + "Searching File " + filename_adresslist + "\n" mainText.config(text=outputtext) adress_list_result = read_adresslist(filename_adresslist) - if(adress_list_result): + if(adress_list_result[0]): adresslist = adress_list_result[1] outputtext = outputtext + "File " + filename_adresslist + " found." + "\n" mainText.config(text=outputtext) @@ -323,6 +403,9 @@ for i in range(len(DropDownLabels)): frameButtons = tkinter.Frame(root) frameButtons.grid(row=3, column=1) +createImages = tkinter.IntVar() +checkBoxCreateImages = tkinter.Checkbutton(frameButtons, text="create images", variable=createImages) +checkBoxCreateImages.grid() 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") diff --git a/api-Test.py b/api-Test.py new file mode 100644 index 0000000..05d19d2 --- /dev/null +++ b/api-Test.py @@ -0,0 +1,57 @@ +#take a roof knowing the coordinates and use it to retrieve all the others "on the same building" +import json +import requests + +search_string = "Toggenburgstrasse 31 8245 Feuerthalen" + +#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['attributes']['building_id']) +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'] +for roof in response_all_roofs_decoded: + # print(roof['attributes'].keys()) + print("URL:", "https://www.uvek-gis.admin.ch/BFE/sonnendach/index.html?featureId=" + str(roof['featureId']) + "&lang=de", "Fläche:", roof['attributes']['flaeche'], "Eignung(1-5):", roof['attributes']['klasse'], "PV100:", float(roof['attributes']['gstrahlung']*0.2*0.8)) \ No newline at end of file