Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: Wollondilly Shire Council (NSW, Australia)
### Municipality / Region

Wollondilly Shire Council

### Collection Calendar Webpage

https://www.wollondilly.nsw.gov.au/waste-services/lookup-your-clean-up-details

### Example Address

87 Remembrance Driveway TAHMOOR NSW

### Collection Data Format

As html on a webpage, As documented API, Something different (add to additional information)

### Additional Information

Hi,
Thanks for taking the time to investigate this request.

WSC for this would be great.
The Shire has two means of getting the data, the first being through the web, and the second being through the Shire's publicly published dataset & documented API

Firstly, it would seem that when entering an address on WSC's collection calendar page (as above) calls are made to:
> https://yokqi4ofx1.execute-api.ap-southeast-2.amazonaws.com/Live/wcc_details_lookup

From there, 
> ?fields=xxxxxxx

is appended to the end of the URL when a valid address hit is found. "Fields" appears to relate to the Parcel number - I can't find anything on a rates notice that relates or links to a parcel number, and a quick look on SIXMaps doesn't point out anything obvious to me either.

For example, the address "87 Remembrance Driveway Tahmoor NSW" reaches out to:
> https://yokqi4ofx1.execute-api.ap-southeast-2.amazonaws.com/Live/wcc_details_lookup?fields=10029

When put into Postman, the Pretty view is as follows:

```json
[
    [
        {
            "name": "parcel_no",
            "caption": "parcel no",
            "value": "10029"
        },
        {
            "name": "Waste Service",
            "caption": "Waste Service",
            "value": "Commercial"
        },
        {
            "name": "Waste Pickup",
            "caption": "Waste Pickup",
            "value": "Thursday"
        },
        {
            "name": "WasteNextPickupType1",
            "caption": "WasteNextPickupType1",
            "value": "Thursday, 08 February 2024, Garbage and Recycling"
        },
        {
            "name": "WasteNextPickupType2",
            "caption": "WasteNextPickupType2",
            "value": "Thursday, 01 February 2024, Garbage and Garden Organics"
        },
        {
            "name": "Waste Run",
            "caption": "Waste Run",
            "value": "Run 2"
        },
        {
            "name": "Clean Up Zone",
            "caption": "Clean Up Zone",
            "value": "Commercial - no service entitlement"
        },
        {
            "name": "Last clean up date",
            "caption": "Last clean up date",
            "value": "Commercial - no service entitlement"
        },
        {
            "name": "Next clean up date",
            "caption": "Next clean up date",
            "value": "Commercial - no service entitlement"
        },
        {
            "name": "Future clean up date",
            "caption": "Future clean up date",
            "value": "Commercial - no service entitlement"
        }
    ]
]
```

The second is through a published dataset with a documented API, available here:
https://data.wollondilly.nsw.gov.au/explore/dataset/wasteweeklypickup/information/

I'm not much of a data person, however, if it helps, WSC (currently) have two waste collection cycles - one for Rubbish & Recycling, the other for Rubbish and Compost. These alternate weekly - so one week is R&R, the other is R&C, and then R&R again.



Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/wollondilly_nsw_gov_au.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/wollondilly_nsw_gov_au.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/wollondilly_nsw_gov_au.py
@@ -0,0 +1,60 @@
+from datetime import datetime
+
+import requests
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "Wollondilly Shire Council"
+DESCRIPTION = "Source for Wollondilly Shire Council."
+URL = "https://www.wollondilly.nsw.gov.au/"
+TEST_CASES = {
+    "87 Remembrance Driveway TAHMOOR NSW": {
+        "address": "87 Remembrance Driveway TAHMOOR NSW"
+    },
+    "Thirlmere Way THIRLMERE NSW": {"address": "Thirlmere Way THIRLMERE NSW"},
+}
+
+
+ICON_MAP = {
+    "garbage": "mdi:trash-can",
+    "garden organic": "mdi:leaf",
+    "recycling": "mdi:recycle",
+}
+
+
+ADDRESS_URL = "https://yokqi4ofx1.execute-api.ap-southeast-2.amazonaws.com/Live/wcc_address_lookup"
+INFO_URL = "https://yokqi4ofx1.execute-api.ap-southeast-2.amazonaws.com/Live/wcc_details_lookup"
+
+
+class Source:
+    def __init__(self, address: str):
+        self._address: str = address
+
+    def fetch(self):
+        args = {"fields": self._address}
+
+        r = requests.get(ADDRESS_URL, params=args)
+        r.raise_for_status()
+
+        data = r.json()
+        if len(data) == 0:
+            raise Exception("Address not found")
+
+        id = data[0][1]["value"]
+        args = {"fields": id}
+        r = requests.get(INFO_URL, params=args)
+        r.raise_for_status()
+
+        data = r.json()
+        entries = []
+        for collection in data[0]:
+            if "WasteNextPickup" not in collection["name"]:
+                continue
+            info_arr = collection["value"].split(", ")
+            date_str = info_arr[1]
+            collection_str = info_arr[2]
+            date = datetime.strptime(date_str, "%d %B %Y").date()
+            collection_types = collection_str.split(" and ")
+            for col_type in collection_types:
+                icon = ICON_MAP.get(col_type.lower())
+                entries.append(Collection(date=date, t=col_type, icon=icon))
+        return entries


Test patch: