diff --git a/README.md b/README.md
index bed4763e..cfbb99c9 100644
--- a/README.md
+++ b/README.md
@@ -190,7 +190,9 @@ Currently the following service providers are supported:
### United Kingdom
+- [Bracknell Forest Council - bracknell-forest.gov.uk](./doc/source/bracknell_forest_gov_uk.md)
- [Bradford Metropolitan District Council - bradford.gov.uk](./doc/source/bradford_gov_uk.md)
+- [Braintree District Council - bracknell-forest.gov.uk](./doc/source/braintree_gov_uk.md)
- [Cambridge City Council - cambridge.gov.uk](./doc/source/cambridge_gov_uk.md)
- [Canterbury City Council - canterbury.gov.uk](./doc/source/canterbury_gov_uk.md)
- [Cheshire East Council - cheshireeast.gov.uk](./doc/source/cheshire_east_gov_uk.md)
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/bracknell_forest_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/bracknell_forest_gov_uk.py
new file mode 100644
index 00000000..720bf7ac
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/bracknell_forest_gov_uk.py
@@ -0,0 +1,87 @@
+import json
+
+import requests
+from dateutil import parser
+from waste_collection_schedule import Collection
+
+TITLE = "bracknell-forest.gov.uk"
+DESCRIPTION = "Bracknell Forest Council, UK - Waste Collection"
+URL = "https://selfservice.mybfc.bracknell-forest.gov.uk"
+TEST_CASES = {
+ "44 Kennel Lane": {"house_number": "44", "post_code": "RG42 2HB"},
+ "28 Kennel Lane": {"house_number": "28", "post_code": "RG42 2HB"},
+ "32 Ashbourne": {"house_number": "32", "post_code": "RG12 8SG"},
+ "1 Acacia Avenue": {"house_number": "1", "post_code": "GU47 0RU"},
+}
+ICONS = {
+ "General Waste": "mdi:trash-can",
+ "Recycling": "mdi:recycle",
+ "Garden": "mdi:leaf",
+ "Food": "mdi:food-apple",
+}
+
+
+class Source:
+ def __init__(self, post_code: str, house_number: str):
+ self.params = {
+ "webpage_subpage_id": "PAG0000570FEFFB1",
+ "webpage_token": "390170046582b0e3d7ca68ef1d6b4829ccff0b1ae9c531047219c6f9b5295738",
+ "widget_action": "handle_event",
+ }
+ self.headers = {
+ "Accept": "application/json",
+ "X-Requested-With": "XMLHttpRequest",
+ }
+ self.data = {
+ "action_cell_id": "PCL0003988FEFFB1",
+ "action_page_id": "PAG0000570FEFFB1",
+ }
+ self.url = f"{URL}/w/webpage/waste-collection-days"
+ self.post_code = post_code
+ self.house_number = house_number
+
+ def fetch(self):
+ address_lookup = requests.post(
+ self.url,
+ params=self.params,
+ headers=self.headers,
+ data={
+ "code_action": "find_addresses",
+ "code_params": json.dumps({"search": self.post_code}),
+ }
+ | self.data,
+ )
+ address_lookup.raise_for_status()
+ addresses = address_lookup.json()["response"]["addresses"]["items"]
+ id = next(address for address in addresses if address["Description"].startswith(f"{self.house_number} "))["Id"]
+
+ collection_lookup = requests.post(
+ self.url,
+ params=self.params,
+ headers=self.headers,
+ data={
+ "code_action": "find_rounds",
+ "code_params": json.dumps({"addressId": id}),
+ }
+ | self.data,
+ )
+ collection_lookup.raise_for_status()
+ collections = collection_lookup.json()["response"]["collections"]
+ entries = []
+ for waste_type in ICONS.keys():
+ try:
+ entries.append(
+ Collection(
+ date=parser.parse(
+ next(collection for collection in collections if collection["round"] == waste_type)[
+ "firstDate"
+ ]["date"]
+ ).date(),
+ t=waste_type,
+ icon=ICONS[waste_type],
+ )
+ )
+ except (StopIteration, TypeError):
+ pass
+
+ return entries
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/braintree_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/braintree_gov_uk.py
new file mode 100644
index 00000000..b76826c9
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/braintree_gov_uk.py
@@ -0,0 +1,59 @@
+import requests
+from bs4 import BeautifulSoup
+from dateutil import parser
+from waste_collection_schedule import Collection
+
+TITLE = "braintree.gov.uk"
+DESCRIPTION = "Braintree District Council, UK - Waste Collection"
+URL = "https://www.braintree.gov.uk"
+TEST_CASES = {
+ "30 Boars Tye Road": {"house_number": "30", "post_code": "CM8 3QE"},
+ "64 Silver Street": {"house_number": "64", "post_code": "CM8 3QG"},
+ "18 St Mary's Road": {"house_number": "1", "post_code": "CM8 3PE"},
+ "20 Peel Crescent": {"house_number": "20", "post_code": "CM7 2RS"},
+}
+
+ICONS = {
+ "Grey Bin": "mdi:trash-can",
+ "Clear Sack": "mdi:recycle",
+ "Green Bin": "mdi:leaf",
+ "Food Bin": "mdi:food-apple",
+}
+
+
+class Source:
+ def __init__(self, post_code: str, house_number: str):
+ self.post_code = post_code
+ self.house_number = house_number
+ self.url = f"{URL}/xfp/form/554"
+ self.form_data = {
+ "qe15dda0155d237d1ea161004d1839e3369ed4831_0_0": (None, post_code),
+ "page": (None, 5730),
+ }
+
+ def fetch(self):
+ address_lookup = requests.post("https://www.braintree.gov.uk/xfp/form/554", files=self.form_data)
+ address_lookup.raise_for_status()
+ addresses = {}
+ for address in BeautifulSoup(address_lookup.text, "html.parser").find_all('option'):
+ if len(address['value']) == 12:
+ addresses[address['value']] = address.text.strip()
+ id = next(address for address in addresses if addresses[address].startswith(self.house_number))
+ self.form_data["qe15dda0155d237d1ea161004d1839e3369ed4831_1_0"] = (None, id)
+ self.form_data["next"] = (None, "Next")
+ collection_lookup = requests.post("https://www.braintree.gov.uk/xfp/form/554", files=self.form_data)
+ collection_lookup.raise_for_status()
+ entries = []
+ for results in BeautifulSoup(collection_lookup.text, "html.parser").find_all('div', class_="date_display"):
+ try:
+ collection_type, collection_date = results.text.strip().split("\n")
+ entries.append(
+ Collection(
+ date=parser.parse(collection_date).date(),
+ t=collection_type,
+ icon=ICONS[collection_type]
+ )
+ )
+ except (StopIteration, TypeError):
+ pass
+ return entries
diff --git a/doc/source/bracknell_forest_gov_uk.md b/doc/source/bracknell_forest_gov_uk.md
new file mode 100644
index 00000000..49ab4142
--- /dev/null
+++ b/doc/source/bracknell_forest_gov_uk.md
@@ -0,0 +1,33 @@
+# Bracknell Forest Council
+
+Support for schedules provided by [Bracknell Forest Council](https://selfservice.mybfc.bracknell-forest.gov.uk/w/webpage/waste-collection-days), serving Bracknell Forest, UK.
+
+## Configuration via configuration.yaml
+
+```yaml
+waste_collection_schedule:
+ sources:
+ - name: bracknell_forest_gov_uk
+ args:
+ post_code: Post Code
+ house_number: House Number
+```
+
+### Configuration Variables
+
+**post_code**
+*(string) (required)*
+
+**house_number**
+*(string) (required)*
+
+## Example
+
+```yaml
+waste_collection_schedule:
+ sources:
+ - name: bracknell_forest_gov_uk
+ args:
+ post_code: "RG42 2HB"
+ house_number: "44"
+```
diff --git a/doc/source/braintree_gov_uk.md b/doc/source/braintree_gov_uk.md
new file mode 100644
index 00000000..7854e6de
--- /dev/null
+++ b/doc/source/braintree_gov_uk.md
@@ -0,0 +1,33 @@
+# Bracknell Forest Council
+
+Support for schedules provided by [Braintree District Council](https://www.braintree.gov.uk/xfp/form/554), serving Braintree, UK.
+
+## Configuration via configuration.yaml
+
+```yaml
+waste_collection_schedule:
+ sources:
+ - name: braintree_gov_uk
+ args:
+ post_code: Post Code
+ house_number: House Number
+```
+
+### Configuration Variables
+
+**post_code**
+*(string) (required)*
+
+**house_number**
+*(string) (required)*
+
+## Example
+
+```yaml
+waste_collection_schedule:
+ sources:
+ - name: braintree_gov_uk
+ args:
+ post_code: "CM8 3QE"
+ house_number: "30"
+```
diff --git a/info.md b/info.md
index 0c67d925..14bd1295 100644
--- a/info.md
+++ b/info.md
@@ -175,7 +175,9 @@ Currently the following service providers are supported:
### United Kingdom
+- [Bracknell Forest Council - bracknell-forest.gov.uk](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/bracknell_forest_gov_uk.md)
- [Bradford Metropolitan District Council - bradford.gov.uk](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/bradford_gov_uk.md)
+- [Braintree District Council - bracknell-forest.gov.uk](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/braintree_gov_uk.md)
- [Cambridge City Council - cambridge.gov.uk](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/cambridge_gov_uk.md)
- [Canterbury City Council - canterbury.gov.uk](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/canterbury_gov_uk.md)
- [Cheshire East Council - cheshireeast.gov.uk](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/cheshire_east_gov_uk.md)