From 0dcaa45bc846439694c33306ebea67a4dee03a62 Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Fri, 27 Dec 2024 22:01:54 +0100 Subject: [PATCH 1/9] add support for kcm (klikogroep / klikocontainermanager) --- README.md | 1 + .../afvalwijzer/collector/klikogroep.py | 97 +++++++++++++++++++ .../afvalwijzer/collector/main_collector.py | 16 ++- .../afvalwijzer/common/main_functions.py | 3 +- custom_components/afvalwijzer/config_flow.py | 4 + custom_components/afvalwijzer/const/const.py | 10 ++ custom_components/afvalwijzer/sensor.py | 10 ++ .../afvalwijzer/sensor_provider.py | 4 +- .../afvalwijzer/translations/en.json | 2 + .../afvalwijzer/translations/nl.json | 2 + 10 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 custom_components/afvalwijzer/collector/klikogroep.py diff --git a/README.md b/README.md index b022aee..18aa9ec 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ _Component to integrate with the following providers/communities. Be aware that | rad (ximmio) | | westland (ximmio) | | woerden (ximmio) | +| oudeijsselstreek (klikogroep, needs user / pass) | This custom component dynamically creates sensor.afvalwijzer\_\* items. For me personally the items created are gft, restafval, papier, pmd and kerstbomen. Look in the states overview in the developer tools in Home Assistant what the sensor names for your region are and modify where necessary. diff --git a/custom_components/afvalwijzer/collector/klikogroep.py b/custom_components/afvalwijzer/collector/klikogroep.py new file mode 100644 index 0000000..23a01ec --- /dev/null +++ b/custom_components/afvalwijzer/collector/klikogroep.py @@ -0,0 +1,97 @@ +from ..const.const import _LOGGER, SENSOR_COLLECTORS_KLIKOGROEP +from ..common.main_functions import _waste_type_rename +from datetime import datetime, timedelta +import requests +from urllib3.exceptions import InsecureRequestWarning + +requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + + +def get_waste_data_raw(provider, postal_code, street_number, suffix, username, password): + try: + suffix = suffix.strip().upper() + + if provider not in SENSOR_COLLECTORS_KLIKOGROEP: + raise ValueError(f"Invalid provider: {provider} for KLIKOGROEP, please verify") + + url = SENSOR_COLLECTORS_KLIKOGROEP[provider]['url'] + app = SENSOR_COLLECTORS_KLIKOGROEP[provider]['app'] + + headers = { + 'Content-Type': 'application/json', + 'Referer': url, + } + + ########################################################################## + # First request: login and get token + ########################################################################## + data = { + "cardNumber": username, + "password": password, + "clientName": provider, + "app": app, + } + + try: + raw_response = requests.post(url="{}/loginWithPassword".format(url), timeout=60, headers=headers, json=data) + raw_response.raise_for_status() + except requests.exceptions.RequestException as err: + raise ValueError(err) from err + + try: + response = raw_response.json() + except ValueError as err: + raise ValueError(f"Invalid and/or no data received from {url}") from err + + if 'success' not in response or not response['success']: + _LOGGER.error('Login failed. Check card number (username) and / or password!') + return + + token = response["token"] + + ########################################################################## + # Second request: get the dates + ########################################################################## + data = { + "token": token, + "clientName": provider, + "app": app, + } + + response = requests.post(url="{}/getMyWasteCalendar".format(url), timeout=60, headers=headers, json=data).json() + + if not response: + _LOGGER.error("Fetching WasteCalendar failed!") + return [] + + waste_data_raw = [] + waste_type_mapping = {} + for waste_type in response['fractions']: + waste_type_mapping[waste_type['id']] = _waste_type_rename(waste_type['name'].lower()) + + for pickup_date in response["dates"]: + num_pickup = len(response["dates"][pickup_date][0]) + for idx in range(0, num_pickup): + pick_up = response["dates"][pickup_date][0][idx] + if pick_up != 0: + waste_data_raw.append({ + "type": waste_type_mapping[pick_up], + "date": pickup_date, + }) + + ########################################################################## + # Third request: invalidate token / close session + ########################################################################## + data = { + "token": token, + "clientName": provider, + "app": app, + } + + response = requests.post(url="{}/logout".format(url), timeout=60, headers=headers, json=data).json() + # We really don't care about the result, honestly. + + except requests.exceptions.RequestException as err: + raise ValueError(err) from err + + return waste_data_raw diff --git a/custom_components/afvalwijzer/collector/main_collector.py b/custom_components/afvalwijzer/collector/main_collector.py index 6085bdd..ea0ea7b 100644 --- a/custom_components/afvalwijzer/collector/main_collector.py +++ b/custom_components/afvalwijzer/collector/main_collector.py @@ -7,6 +7,7 @@ SENSOR_COLLECTORS_CIRCULUS, SENSOR_COLLECTORS_DEAFVALAPP, SENSOR_COLLECTORS_ICALENDAR, + SENSOR_COLLECTORS_KLIKOGROEP, SENSOR_COLLECTORS_OPZET, SENSOR_COLLECTORS_RD4, SENSOR_COLLECTORS_ROVA, @@ -14,7 +15,7 @@ ) try: - from . import afvalalert, burgerportaal, circulus, deafvalapp, icalendar, mijnafvalwijzer, opzet, rd4, rova, rwm, ximmio + from . import afvalalert, burgerportaal, circulus, deafvalapp, icalendar, klikogroep, mijnafvalwijzer, opzet, rd4, rova, rwm, ximmio except ImportError as err: _LOGGER.error(f"Import error {err.args}") @@ -26,6 +27,8 @@ def __init__( postal_code, street_number, suffix, + username, + password, exclude_pickup_today, date_isoformat, exclude_list, @@ -36,6 +39,8 @@ def __init__( self.postal_code = str(postal_code).strip().upper() self.street_number = str(street_number).strip() self.suffix = str(suffix).strip().lower() + self.username = str(username).strip().lower() + self.password = str(password).strip() # Handle boolean and string parameters correctly self.exclude_pickup_today = str(exclude_pickup_today).lower() if isinstance( @@ -89,6 +94,15 @@ def __init__( self.street_number, self.suffix, ) + elif provider in SENSOR_COLLECTORS_KLIKOGROEP.keys(): + waste_data_raw = klikogroep.get_waste_data_raw( + self.provider, + self.postal_code, + self.street_number, + self.suffix, + self.username, + self.password, + ) elif provider in SENSOR_COLLECTORS_OPZET.keys(): waste_data_raw = opzet.get_waste_data_raw( self.provider, diff --git a/custom_components/afvalwijzer/common/main_functions.py b/custom_components/afvalwijzer/common/main_functions.py index 868bb18..7645d67 100644 --- a/custom_components/afvalwijzer/common/main_functions.py +++ b/custom_components/afvalwijzer/common/main_functions.py @@ -11,6 +11,7 @@ def _waste_type_rename(item_name): "gft & etensresten": "gft", "glass": "glas", "gft afval": "gft", + "gft+e": "gft", "green": "gft", "groene container": "gft", "groente": "gft", @@ -26,6 +27,7 @@ def _waste_type_rename(item_name): "packages": "pmd", "pap": "papier", "paper": "papier", + "pbd": "pmd", "pdb": "pmd", "papier en karton": "papier", "papierinzameling": "papier", @@ -35,7 +37,6 @@ def _waste_type_rename(item_name): "plastic, blik & drinkpakken": "pmd", "plastic, blik & drinkpakken arnhem": "pmd", "plastic, blik & drinkpakken overbetuwe": "pmd", - "pmd": "pmd", "pmdrest": "pmd-restafval", "pmd-zak": "pmd", "pruning_waste": "snoeiafval", diff --git a/custom_components/afvalwijzer/config_flow.py b/custom_components/afvalwijzer/config_flow.py index 97480b4..f172190 100644 --- a/custom_components/afvalwijzer/config_flow.py +++ b/custom_components/afvalwijzer/config_flow.py @@ -9,6 +9,8 @@ CONF_POSTAL_CODE, CONF_STREET_NUMBER, CONF_SUFFIX, + CONF_USERNAME, + CONF_PASSWORD, CONF_EXCLUDE_PICKUP_TODAY, CONF_DATE_ISOFORMAT, CONF_DEFAULT_LABEL, @@ -20,6 +22,8 @@ vol.Required(CONF_POSTAL_CODE): cv.string, vol.Required(CONF_STREET_NUMBER): cv.string, vol.Optional(CONF_SUFFIX, default=""): cv.string, + vol.Optional(CONF_USERNAME, default=""): cv.string, + vol.Optional(CONF_PASSWORD, default=""): cv.string, vol.Optional(CONF_EXCLUDE_PICKUP_TODAY, default=True): cv.boolean, vol.Optional(CONF_DATE_ISOFORMAT, default=False): cv.boolean, vol.Optional(CONF_DEFAULT_LABEL, default="geen"): cv.string, diff --git a/custom_components/afvalwijzer/const/const.py b/custom_components/afvalwijzer/const/const.py index 5cc0f26..5944b05 100644 --- a/custom_components/afvalwijzer/const/const.py +++ b/custom_components/afvalwijzer/const/const.py @@ -59,6 +59,13 @@ "veldhoven": "https://www.veldhoven.nl/afvalkalender/{5}/{1}-{2}.ics", } +SENSOR_COLLECTORS_KLIKOGROEP = { + "oudeijsselstreek": { + "url": "https://cp-oudeijsselstreek.klikocontainermanager.com/MyKliko", + "app": "cp-oudeijsselstreek.kcm.com" + } +} + SENSOR_COLLECTORS_AFVALWIJZER = [ "mijnafvalwijzer", "afvalstoffendienstkalender", @@ -74,6 +81,7 @@ "woerden": "https://wasteprod2api.ximmio.com", } + SENSOR_COLLECTORS_XIMMIO_IDS = { "acv": "f8e2844a-095e-48f9-9f98-71fceb51d2c3", "almere": "53d8db94-7945-42fd-9742-9bbc71dbe4c1", @@ -128,6 +136,8 @@ CONF_POSTAL_CODE = "postal_code" CONF_STREET_NUMBER = "street_number" CONF_SUFFIX = "suffix" +CONF_USERNAME = "username" +CONF_PASSWORD = "password" CONF_DATE_FORMAT = "date_format" CONF_EXCLUDE_PICKUP_TODAY = "exclude_pickup_today" CONF_DEFAULT_LABEL = "default_label" diff --git a/custom_components/afvalwijzer/sensor.py b/custom_components/afvalwijzer/sensor.py index 25e5252..2065ddf 100644 --- a/custom_components/afvalwijzer/sensor.py +++ b/custom_components/afvalwijzer/sensor.py @@ -21,6 +21,8 @@ CONF_POSTAL_CODE, CONF_STREET_NUMBER, CONF_SUFFIX, + CONF_USERNAME, + CONF_PASSWORD, SCAN_INTERVAL, ) from .sensor_custom import CustomSensor @@ -33,6 +35,8 @@ vol.Required(CONF_POSTAL_CODE): cv.string, vol.Required(CONF_STREET_NUMBER): cv.string, vol.Optional(CONF_SUFFIX, default=""): cv.string, + vol.Optional(CONF_USERNAME, default=""): cv.string, + vol.Optional(CONF_PASSWORD, default=""): cv.string, vol.Optional(CONF_EXCLUDE_PICKUP_TODAY, default=True): cv.boolean, vol.Optional(CONF_DATE_ISOFORMAT, default=False): cv.boolean, vol.Optional(CONF_EXCLUDE_LIST, default=""): cv.string, @@ -63,6 +67,8 @@ async def _setup_sensors(hass, config, async_add_entities): postal_code = config.get(CONF_POSTAL_CODE) street_number = config.get(CONF_STREET_NUMBER) suffix = config.get(CONF_SUFFIX, "") + username = config.get(CONF_USERNAME, "") + password = config.get(CONF_PASSWORD, "") exclude_pickup_today = config.get(CONF_EXCLUDE_PICKUP_TODAY, True) date_isoformat = config.get(CONF_DATE_ISOFORMAT, False) exclude_list = config.get(CONF_EXCLUDE_LIST, "") @@ -125,6 +131,8 @@ def update(self): postal_code = self.config.get(CONF_POSTAL_CODE) street_number = self.config.get(CONF_STREET_NUMBER) suffix = self.config.get(CONF_SUFFIX) + username = self.config.get(CONF_USERNAME) + password = self.config.get(CONF_PASSWORD) exclude_pickup_today = self.config.get(CONF_EXCLUDE_PICKUP_TODAY) date_isoformat = self.config.get(CONF_DATE_ISOFORMAT) default_label = self.config.get(CONF_DEFAULT_LABEL) @@ -136,6 +144,8 @@ def update(self): postal_code, street_number, suffix, + username, + password, exclude_pickup_today, date_isoformat, exclude_list, diff --git a/custom_components/afvalwijzer/sensor_provider.py b/custom_components/afvalwijzer/sensor_provider.py index f7e6ec0..fdd0ecc 100644 --- a/custom_components/afvalwijzer/sensor_provider.py +++ b/custom_components/afvalwijzer/sensor_provider.py @@ -17,6 +17,8 @@ CONF_POSTAL_CODE, CONF_STREET_NUMBER, CONF_SUFFIX, + CONF_USERNAME, + CONF_PASSWORD, CONF_DATE_ISOFORMAT, SENSOR_ICON, SENSOR_PREFIX, @@ -48,7 +50,7 @@ def __init__(self, hass, waste_type, fetch_data, config): self._state = self._default_label self._icon = SENSOR_ICON self._unique_id = hashlib.sha1( - f"{waste_type}{config.get(CONF_ID)}{config.get(CONF_POSTAL_CODE)}{config.get(CONF_STREET_NUMBER)}{config.get(CONF_SUFFIX, '')}".encode( + f"{waste_type}{config.get(CONF_ID)}{config.get(CONF_POSTAL_CODE)}{config.get(CONF_STREET_NUMBER)}{config.get(CONF_SUFFIX, '')}{config.get(CONF_USERNAME, '')}{config.get(CONF_PASSWORD, '')}".encode( "utf-8" ) ).hexdigest() diff --git a/custom_components/afvalwijzer/translations/en.json b/custom_components/afvalwijzer/translations/en.json index 1cfb78a..a32a594 100644 --- a/custom_components/afvalwijzer/translations/en.json +++ b/custom_components/afvalwijzer/translations/en.json @@ -9,6 +9,8 @@ "postal_code": "Postal code (e.g., 1234AB)", "street_number": "Street number", "suffix": "Address suffix", + "username": "Provider username", + "password": "Provider password", "exclude_pickup_today": "Exclude today's pickup", "date_isoformat": "Use ISO date format", "default_label": "Default label when no data is available", diff --git a/custom_components/afvalwijzer/translations/nl.json b/custom_components/afvalwijzer/translations/nl.json index d6de13a..a4ba1db 100644 --- a/custom_components/afvalwijzer/translations/nl.json +++ b/custom_components/afvalwijzer/translations/nl.json @@ -9,6 +9,8 @@ "postal_code": "Postcode (bijv. 1234AB)", "street_number": "Huisnummer", "suffix": "Huisnummer toevoeging", + "username": "Provider gebruikersnaam", + "password": "Provider wachtwoord", "exclude_pickup_today": "Sluit ophalen van vandaag uit", "date_isoformat": "Gebruik ISO-datumformaat", "default_label": "Standaard label bij geen datum bekend", From d33eb66c0e0e070e30685f5b8b648107b527a1eb Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Fri, 27 Dec 2024 22:44:42 +0100 Subject: [PATCH 2/9] allow spaces pre- and post-fixing passwords --- custom_components/afvalwijzer/collector/main_collector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/afvalwijzer/collector/main_collector.py b/custom_components/afvalwijzer/collector/main_collector.py index ea0ea7b..0a9f63a 100644 --- a/custom_components/afvalwijzer/collector/main_collector.py +++ b/custom_components/afvalwijzer/collector/main_collector.py @@ -40,7 +40,7 @@ def __init__( self.street_number = str(street_number).strip() self.suffix = str(suffix).strip().lower() self.username = str(username).strip().lower() - self.password = str(password).strip() + self.password = str(password) # Handle boolean and string parameters correctly self.exclude_pickup_today = str(exclude_pickup_today).lower() if isinstance( From b64eb13d151b850ef72080b5491bbd3c766003c8 Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Fri, 27 Dec 2024 22:44:55 +0100 Subject: [PATCH 3/9] suffix not used in this collector --- custom_components/afvalwijzer/collector/klikogroep.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/afvalwijzer/collector/klikogroep.py b/custom_components/afvalwijzer/collector/klikogroep.py index 23a01ec..e7063e2 100644 --- a/custom_components/afvalwijzer/collector/klikogroep.py +++ b/custom_components/afvalwijzer/collector/klikogroep.py @@ -9,8 +9,6 @@ def get_waste_data_raw(provider, postal_code, street_number, suffix, username, password): try: - suffix = suffix.strip().upper() - if provider not in SENSOR_COLLECTORS_KLIKOGROEP: raise ValueError(f"Invalid provider: {provider} for KLIKOGROEP, please verify") From ad8f8d56a25da9c1aed5d251ef92498498ed74f8 Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Fri, 27 Dec 2024 22:46:36 +0100 Subject: [PATCH 4/9] remove extraneous empty line --- custom_components/afvalwijzer/const/const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/afvalwijzer/const/const.py b/custom_components/afvalwijzer/const/const.py index 5944b05..26c8d58 100644 --- a/custom_components/afvalwijzer/const/const.py +++ b/custom_components/afvalwijzer/const/const.py @@ -81,7 +81,6 @@ "woerden": "https://wasteprod2api.ximmio.com", } - SENSOR_COLLECTORS_XIMMIO_IDS = { "acv": "f8e2844a-095e-48f9-9f98-71fceb51d2c3", "almere": "53d8db94-7945-42fd-9742-9bbc71dbe4c1", From 8414831ccd90b4ebd47f32c0cc7468c4eeebe3ef Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Fri, 27 Dec 2024 22:48:25 +0100 Subject: [PATCH 5/9] test is useless here, done in main_collector.py --- custom_components/afvalwijzer/collector/klikogroep.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom_components/afvalwijzer/collector/klikogroep.py b/custom_components/afvalwijzer/collector/klikogroep.py index e7063e2..38dc74c 100644 --- a/custom_components/afvalwijzer/collector/klikogroep.py +++ b/custom_components/afvalwijzer/collector/klikogroep.py @@ -9,9 +9,6 @@ def get_waste_data_raw(provider, postal_code, street_number, suffix, username, password): try: - if provider not in SENSOR_COLLECTORS_KLIKOGROEP: - raise ValueError(f"Invalid provider: {provider} for KLIKOGROEP, please verify") - url = SENSOR_COLLECTORS_KLIKOGROEP[provider]['url'] app = SENSOR_COLLECTORS_KLIKOGROEP[provider]['app'] From af1d8e3c28464e4ec5cf49271f2169f6f05a8ed9 Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Fri, 27 Dec 2024 22:54:50 +0100 Subject: [PATCH 6/9] add user/pass to readme examples --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 18aa9ec..f271666 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,8 @@ Here's an example of my own Home Asisstant config: https://github.com/xirixiz/ho postal_code: 1234AB # (required, default = '') street_number: 5 # (required, default = '') suffix: '' # (optional, default = '') + username: '' # (optional, default = '') + password: '' # (optional, default = '') exclude_pickup_today: true # (optional, default = true) to take or not to take Today into account in the next pickup. date_isoformat: false # (optional, default = false) show the date in full isoformat if desired. Example: "2024-01-14T08:40:33.993521" default_label: geen # (optional, default = geen) label if no date found From 931cde30dba699a9d52a085dd2264f17ed69f425 Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Sat, 28 Dec 2024 08:39:35 +0100 Subject: [PATCH 7/9] import datetime unnecessary in this collector --- custom_components/afvalwijzer/collector/klikogroep.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/afvalwijzer/collector/klikogroep.py b/custom_components/afvalwijzer/collector/klikogroep.py index 38dc74c..1852eef 100644 --- a/custom_components/afvalwijzer/collector/klikogroep.py +++ b/custom_components/afvalwijzer/collector/klikogroep.py @@ -1,6 +1,5 @@ from ..const.const import _LOGGER, SENSOR_COLLECTORS_KLIKOGROEP from ..common.main_functions import _waste_type_rename -from datetime import datetime, timedelta import requests from urllib3.exceptions import InsecureRequestWarning From a7697dd46449523441b3fc00fb03871daf85bf7b Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Sat, 28 Dec 2024 08:53:02 +0100 Subject: [PATCH 8/9] collector only uses provider, user and pass args --- custom_components/afvalwijzer/collector/klikogroep.py | 2 +- custom_components/afvalwijzer/collector/main_collector.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/custom_components/afvalwijzer/collector/klikogroep.py b/custom_components/afvalwijzer/collector/klikogroep.py index 1852eef..d733261 100644 --- a/custom_components/afvalwijzer/collector/klikogroep.py +++ b/custom_components/afvalwijzer/collector/klikogroep.py @@ -6,7 +6,7 @@ requests.packages.urllib3.disable_warnings(InsecureRequestWarning) -def get_waste_data_raw(provider, postal_code, street_number, suffix, username, password): +def get_waste_data_raw(provider, username, password): try: url = SENSOR_COLLECTORS_KLIKOGROEP[provider]['url'] app = SENSOR_COLLECTORS_KLIKOGROEP[provider]['app'] diff --git a/custom_components/afvalwijzer/collector/main_collector.py b/custom_components/afvalwijzer/collector/main_collector.py index 0a9f63a..d268534 100644 --- a/custom_components/afvalwijzer/collector/main_collector.py +++ b/custom_components/afvalwijzer/collector/main_collector.py @@ -97,9 +97,6 @@ def __init__( elif provider in SENSOR_COLLECTORS_KLIKOGROEP.keys(): waste_data_raw = klikogroep.get_waste_data_raw( self.provider, - self.postal_code, - self.street_number, - self.suffix, self.username, self.password, ) From 06cdb88d268ed08f1f3c3f8bc1966f1a6dcdb122 Mon Sep 17 00:00:00 2001 From: Sander Smeenk Date: Sat, 28 Dec 2024 09:19:27 +0100 Subject: [PATCH 9/9] flake8 / style code improvements --- .../afvalwijzer/collector/klikogroep.py | 155 +++++++++--------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/custom_components/afvalwijzer/collector/klikogroep.py b/custom_components/afvalwijzer/collector/klikogroep.py index d733261..edfe390 100644 --- a/custom_components/afvalwijzer/collector/klikogroep.py +++ b/custom_components/afvalwijzer/collector/klikogroep.py @@ -1,91 +1,92 @@ from ..const.const import _LOGGER, SENSOR_COLLECTORS_KLIKOGROEP from ..common.main_functions import _waste_type_rename + import requests from urllib3.exceptions import InsecureRequestWarning - requests.packages.urllib3.disable_warnings(InsecureRequestWarning) def get_waste_data_raw(provider, username, password): + url = SENSOR_COLLECTORS_KLIKOGROEP[provider]['url'] + app = SENSOR_COLLECTORS_KLIKOGROEP[provider]['app'] + + headers = { + 'Content-Type': 'application/json', + 'Referer': url, + } + + ########################################################################## + # First request: login and get token + ########################################################################## + data = { + "cardNumber": username, + "password": password, + "clientName": provider, + "app": app, + } + + try: + raw_response = requests.post(url="{}/loginWithPassword".format(url), timeout=60, headers=headers, json=data) + raw_response.raise_for_status() + except requests.exceptions.RequestException as err: + raise ValueError(err) from err + try: - url = SENSOR_COLLECTORS_KLIKOGROEP[provider]['url'] - app = SENSOR_COLLECTORS_KLIKOGROEP[provider]['app'] - - headers = { - 'Content-Type': 'application/json', - 'Referer': url, - } - - ########################################################################## - # First request: login and get token - ########################################################################## - data = { - "cardNumber": username, - "password": password, - "clientName": provider, - "app": app, - } - - try: - raw_response = requests.post(url="{}/loginWithPassword".format(url), timeout=60, headers=headers, json=data) - raw_response.raise_for_status() - except requests.exceptions.RequestException as err: - raise ValueError(err) from err - - try: - response = raw_response.json() - except ValueError as err: - raise ValueError(f"Invalid and/or no data received from {url}") from err - - if 'success' not in response or not response['success']: - _LOGGER.error('Login failed. Check card number (username) and / or password!') - return - - token = response["token"] - - ########################################################################## - # Second request: get the dates - ########################################################################## - data = { - "token": token, - "clientName": provider, - "app": app, - } - - response = requests.post(url="{}/getMyWasteCalendar".format(url), timeout=60, headers=headers, json=data).json() - - if not response: - _LOGGER.error("Fetching WasteCalendar failed!") - return [] - - waste_data_raw = [] - waste_type_mapping = {} - for waste_type in response['fractions']: - waste_type_mapping[waste_type['id']] = _waste_type_rename(waste_type['name'].lower()) - - for pickup_date in response["dates"]: - num_pickup = len(response["dates"][pickup_date][0]) - for idx in range(0, num_pickup): - pick_up = response["dates"][pickup_date][0][idx] - if pick_up != 0: - waste_data_raw.append({ - "type": waste_type_mapping[pick_up], - "date": pickup_date, - }) - - ########################################################################## - # Third request: invalidate token / close session - ########################################################################## - data = { - "token": token, - "clientName": provider, - "app": app, - } - - response = requests.post(url="{}/logout".format(url), timeout=60, headers=headers, json=data).json() - # We really don't care about the result, honestly. + response = raw_response.json() + except ValueError as err: + raise ValueError(f"Invalid and/or no data received from {url}/loginWithPassword") from err + if 'success' not in response or not response['success']: + _LOGGER.error('Login failed. Check card number (username) and / or password!') + return + + token = response["token"] + + ########################################################################## + # Second request: get the dates + ########################################################################## + data = { + "token": token, + "clientName": provider, + "app": app, + } + + try: + raw_response = requests.post(url="{}/getMyWasteCalendar".format(url), timeout=60, headers=headers, json=data) + raw_response.raise_for_status() except requests.exceptions.RequestException as err: raise ValueError(err) from err + try: + response = raw_response.json() + except ValueError as err: + raise ValueError(f"Invalid and/or no data received from {url}/getMyWasteCalendar") from err + + waste_data_raw = [] + waste_type_mapping = {} + for waste_type in response['fractions']: + waste_type_mapping[waste_type['id']] = _waste_type_rename(waste_type['name'].lower()) + + for pickup_date in response["dates"]: + num_pickup = len(response["dates"][pickup_date][0]) + for idx in range(0, num_pickup): + pick_up = response["dates"][pickup_date][0][idx] + if pick_up != 0: + waste_data_raw.append({ + "type": waste_type_mapping[pick_up], + "date": pickup_date, + }) + + ########################################################################## + # Third request: invalidate token / close session + ########################################################################## + data = { + "token": token, + "clientName": provider, + "app": app, + } + + response = requests.post(url="{}/logout".format(url), timeout=60, headers=headers, json=data).json() + # We really don't care about this result, honestly. + return waste_data_raw