diff --git a/goportparking.py b/goportparking.py index 3531567..4f41615 100644 --- a/goportparking.py +++ b/goportparking.py @@ -4,11 +4,15 @@ from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By +from selenium.common.exceptions import NoSuchElementException import hassapi as hass import traceback import adbase as ad +JS_WAIT = 1 +WEB_WAIT = 5 + class GoPortParkingController(hass.Hass): def initialize(self): chrome_options = Options() @@ -35,8 +39,6 @@ def filter_quick_buy_button(x): return False self.listen_event(self.book_daily, "call_service", domain="button", service="press", service_data=filter_quick_buy_button) self.run_daily(self.reset_state, '3:00:00') - self.listen_state(self.parking_pass_email_cb, self.args['parking_pass_email_sensor'], attribute='subject') - self.pending_plates = [] def terminate(self): try: @@ -44,17 +46,6 @@ def terminate(self): except Exception: self.log(f"failed to terminate properly: {traceback.format_exc()}") - def parking_pass_email_cb(self, entity, attr, old, new, kwargs): - if len(self.pending_plates) > 0: - plate = self.pending_plates.pop() - entity_id = f"button.quick_buy_daily_{plate}" - entity = self.get_entity(entity_id) - if new not in ['RPP Approved', 'Payment Processed']: - self.log(f"Unexpected email from RPP email: {new}") - entity.set_state(state='error', attributes={'detail': 'Unexpected email from parking: {new}'}) - else: - entity.set_state(state='successfully_purchased', attributes={'detail': 'Purchase successfully completed.'}) - def reset_state(self, kwargs): for plate in self.args['plates']: entity_id = f"button.quick_buy_daily_{plate}" @@ -74,7 +65,7 @@ def book_daily(self, event_name, data, kwargs): self.get_entity(entity).set_state(state='opening_portal', attributes={'detail': 'Opening portal'}) self.log(f"buying daily: navigating to login") self.driver.get("https://goportparking.org/rppportal/login.xhtml") - time.sleep(5) + time.sleep(WEB_WAIT) self.log(f"buying daily: logging in") username = self.driver.find_element(By.ID, "username") username.clear() @@ -84,20 +75,36 @@ def book_daily(self, event_name, data, kwargs): password.send_keys(self.args['password']) self.driver.find_element(By.ID, "login").click() self.get_entity(entity).set_state(state='logging_in', attributes={'detail': 'Logging in...'}) - time.sleep(5) + time.sleep(WEB_WAIT) if self.driver.current_url != 'https://goportparking.org/rppportal/index.xhtml': self.log(f"Login seems to have failed") self.get_entity(entity).set_state(state='login_failed', attributes={'detail': 'Login failed'}) return self.log(f"buying daily: activating quick-buy (on url {self.driver.current_url})") self.get_entity(entity).set_state(state='purchasing_daily', attributes={'detail': 'Purchasing daily pass...'}) - quick_buy = self.driver.find_element(By.PARTIAL_LINK_TEXT, plate) + try: + quick_buy = self.driver.find_element(By.PARTIAL_LINK_TEXT, plate) + except NoSuchElementException: + drop_down = self.driver.find_element(By.CLASS_NAME, 'caret') + drop_down.click() + time.sleep(JS_WAIT) + quick_buy = self.driver.find_element(By.PARTIAL_LINK_TEXT, plate) quick_buy.click() - time.sleep(5) + time.sleep(WEB_WAIT) self.log(f"buying daily: confirming quick-buy") self.get_entity(entity).set_state(state='confirming_purchase', attributes={'detail': 'Confirming purchase...'}) quick_buy_confirm = self.driver.find_element(By.XPATH, "//span[@id='quickBuyConfirmPanel']//input[@Value='Yes']") quick_buy_confirm.click() print(f"bought the daily pass (confirm={quick_buy_confirm})") - self.pending_plates.append(plate) + + time.sleep(WEB_WAIT) + try: + xpath = f'//div[contains(@class, "panel") and .//h3[contains(text(), "Your RPPs")] and .//li[contains(@class, "active") and ./a[contains(text(), "Current RPPs")]] and .//td[./span[contains(text(), "Plate")] and ./span[contains(text(), "{plate}") and contains(@class, "text-success")]]]' + self.log(f"Find element by xpath {xpath}") + self.driver.find_element(By.XPATH, xpath) + self.log(f"Found active parking pass on RPP portal for {plate}") + self.get_entity(entity).set_state(state='successfully_purchased', attributes={'detail': 'Purchase successfully completed.'}) + except NoSuchElementException as nse: + self.log(f"Unexpected state from RPP portal for {plate}: {nse}") + self.get_entity(entity).set_state(state='error', attributes={'detail': 'No active parking passes, check the website.'}) diff --git a/lights.py b/lights.py index 4c66ad9..95f71ed 100644 --- a/lights.py +++ b/lights.py @@ -263,7 +263,7 @@ def match(service_data): @ad.app_lock def service_snoop(self, event_name, data, kwargs): - if data['domain'] != 'light' and data['domain'] != 'button' and data['domain'] != 'input_boolean': + if 'domain' not in data or data['domain'] != 'light' and data['domain'] != 'button' and data['domain'] != 'input_boolean': return #print(f"service snooped {data}") endogenous = data['metadata']['context']['user_id'] == self.user_id