Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: Please add source "West Suffolk Council" schedule (UK)
### Municipality / Region

West Suffolk, UK

### Collection Calendar Webpage

https://www.westsuffolk.gov.uk/bins/when-are-my-bins-emptied.cfm

### Example Address

Flat, The Flying Shuttle, Three Counties Way, Withersfield, CB9 7FB

### Collection Data Format

As html on a webpage

### Additional Information

**Website has a separate link to a place where postcode must be entered (https://maps.westsuffolk.gov.uk/MyWestSuffolk.aspx).**

The link is in the text "When are my bins emptied?
Your bins are emptied on alternate weeks. When there is a public holiday, the collection days will be revised. To see when your bins are emptied, use our [Find my nearest](https://maps.westsuffolk.gov.uk/MyWestSuffolk.aspx) service and enter your postcode into the Search for a location box and select your address. Your bin collection information will be displayed."


**The bin schedule for the next few days is shown in a panel, with a title, and further links. note that garden refuse (brown bin) may not be shown if the resident has not paid for the service, as in this example:**
---------------------------------------------------------------------------------------
_copy-paste of the web text_

[Waste and recycling](https://maps.westsuffolk.gov.uk/MyWestSuffolk.aspx#Waste_and_recycling)
Bin collection days
Please leave your bin out for collection by 6:15am.

Your [collection day](http://www.westsuffolk.gov.uk/bins/my-bin-hasnt-been-emptied.cfm) will change on weeks with bank holidays.


Your next bin collection days are:

Black bin: Saturday 6th January
Blue bin: Saturday 30th December
Your [garden waste collection](https://www.westsuffolk.gov.uk/gardenwaste) is an optional subscription service.

[Report a missed bin](http://www.westsuffolk.gov.uk/bins/my-bin-hasnt-been-emptied.cfm)



---------------------------------------------------------------------------------------------------
**Example including the brown bin:**
_copy-paste of the text_

Bin collection days
Please leave your bin out for collection by 6:15am.

Your [collection day](http://www.westsuffolk.gov.uk/bins/my-bin-hasnt-been-emptied.cfm) will change on weeks with bank holidays.


Your next bin collection days are:

Black bin: Saturday 6th January
Blue bin: Saturday 30th December
Brown bin: Thursday 11th January
Your [garden waste collection](https://www.westsuffolk.gov.uk/gardenwaste) is an optional subscription service.

[Report a missed bin](http://www.westsuffolk.gov.uk/bins/my-bin-hasnt-been-emptied.cfm)


-------------------------------------------------------------------------------------------------------
**Screenshot:**

![waste collection dates](https://github.com/mampfes/hacs_waste_collection_schedule/assets/105645866/ebaa0d6d-74a7-4e9f-8017-fd4eec1ec528)



Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/westsuffolk_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/westsuffolk_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/westsuffolk_gov_uk.py
@@ -0,0 +1,64 @@
+import re
+
+import requests
+from bs4 import BeautifulSoup, Tag
+from dateutil import parser
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "West Suffolk Council"
+DESCRIPTION = "Source for West Suffolk Council."
+URL = "https://westsuffolk.gov.uk/"
+TEST_CASES = {
+    "Flat, The Flying Shuttle, Three Counties Way, Withersfield, CB9 7FB": {
+        "uprn": 10090739388
+    },
+    "Haere Mai, The Street, Troston, IP31 1EW": {"uprn": "100091387226"},
+}
+
+
+ICON_MAP = {
+    "Black bin": "mdi:trash-can",
+    "Brown bin": "mdi:leaf",
+    "Blue bin": "mdi:recycle",
+}
+
+
+API_URL = "https://maps.westsuffolk.gov.uk/MyWestSuffolk.aspx"
+
+
+class Source:
+    def __init__(self, uprn: str | int):
+        self._uprn: str | int = uprn
+
+    def fetch(self):
+        session = requests.session()
+        args = {"UniqueId": self._uprn, "action": "SetAddress"}
+
+        # get json file
+        r = session.get(API_URL, params=args)
+        r.raise_for_status()
+        soup = BeautifulSoup(r.text, "html.parser")
+        collections_div = soup.find(
+            "", text=re.compile(r"Your next bin collection days", re.IGNORECASE)
+        ).find_next_sibling("div", class_="atPanelData")
+
+        bin_type = None
+        entries = []
+
+        for collection in collections_div.contents:
+            if isinstance(collection, Tag):
+                if collection.name == "strong":
+                    bin_type = " ".join(
+                        a.strip()
+                        for a in collection.text.strip().strip(":").split("\n")
+                    )
+                continue
+
+            collection = collection.strip()
+            date_str = collection.strip()
+            # date: Saturday 30th December
+            coll_date = parser.parse(date_str).date()
+            entries.append(
+                Collection(date=coll_date, t=bin_type, icon=ICON_MAP.get(bin_type))
+            )
+        return entries


Test patch: