Skip to content

Commit

Permalink
Added support for Royal Borough Of Greenwich (mampfes#3277)
Browse files Browse the repository at this point in the history
  • Loading branch information
timocov committed Dec 26, 2024
1 parent db06cd0 commit a1552fc
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,7 @@ If your service provider is not listed, feel free to open a [source request issu
- [Rochdale Borough Council](/doc/source/rochdale_gov_uk.md) / rochdale.gov.uk
- [Rotherham](/doc/source/apps_imactivate_com.md) / rotherham.gov.uk
- [Rotherham Metropolitan Borough Council](/doc/source/rotherham_gov_uk.md) / rotherham.gov.uk
- [Royal Borough Of Greenwich](/doc/source/royalgreenwich_gov_uk.md) / royalgreenwich.gov.uk
- [Runnymede Borough Council](/doc/source/runnymede_gov_uk.md) / runnymede.gov.uk
- [Rushcliffe Brough Council](/doc/source/rushcliffe_gov_uk.md) / rushcliffe.gov.uk
- [Rushmoor Borough Council](/doc/source/rushmoor_gov_uk.md) / rushmoor.gov.uk
Expand Down
6 changes: 6 additions & 0 deletions custom_components/waste_collection_schedule/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -13786,6 +13786,12 @@
"default_params": {},
"id": "rotherham_gov_uk"
},
{
"title": "Royal Borough Of Greenwich",
"module": "royalgreenwich_gov_uk",
"default_params": {},
"id": "royalgreenwich_gov_uk"
},
{
"title": "Runnymede Borough Council",
"module": "runnymede_gov_uk",
Expand Down
24 changes: 24 additions & 0 deletions custom_components/waste_collection_schedule/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -15648,6 +15648,30 @@
"uprn": "Eine einfache Möglichkeit, Ihre Unique Property Reference Number (UPRN) zu finden, besteht darin, auf https://www.findmyaddress.co.uk/ zu gehen und Ihre Adressdaten einzugeben."
}
},
"args_royalgreenwich_gov_uk": {
"title": "Quelle konfigurieren",
"description": "Konfiguriere deinen Service Provider. Mehr details: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/royalgreenwich_gov_uk.md",
"data": {
"calendar_title": "Kalender Titel",
"address": "Addresse",
"house": "Haus",
"post_code": "PLZ"
},
"data_description": {
"calendar_title": "Ein lesbarerer oder benutzerfreundlicherer Name für den Müllkalender. Wenn nichts angegeben wird, wird der Name der Quelle verwendet."
}
},
"reconfigure_royalgreenwich_gov_uk": {
"title": "Quelle Neu Konfigurieren",
"description": "Konfiguriere deinen Service Provider. Mehr details: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/royalgreenwich_gov_uk.md",
"data": {
"calendar_title": "Kalender Titel",
"address": "Addresse",
"house": "Haus",
"post_code": "PLZ"
},
"data_description": {}
},
"args_runnymede_gov_uk": {
"title": "Quelle konfigurieren",
"description": "Konfiguriere deinen Service Provider. Mehr details: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/runnymede_gov_uk.md",
Expand Down
24 changes: 24 additions & 0 deletions custom_components/waste_collection_schedule/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15671,6 +15671,30 @@
"uprn": "An easy way to discover your Unique Property Reference Number (UPRN) is by going to https://www.findmyaddress.co.uk/ and entering in your address details."
}
},
"args_royalgreenwich_gov_uk": {
"title": "Configure Source",
"description": "Configure your service provider. More details: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/royalgreenwich_gov_uk.md.",
"data": {
"calendar_title": "Calendar Title",
"address": "Address",
"house": "House",
"post_code": "Postcode"
},
"data_description": {
"calendar_title": "A more readable, or user-friendly, name for the waste calendar. If nothing is provided, the name returned by the source will be used."
}
},
"reconfigure_royalgreenwich_gov_uk": {
"title": "Reconfigure Source",
"description": "Configure your service provider. More details: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/royalgreenwich_gov_uk.md.",
"data": {
"calendar_title": "Calendar Title",
"address": "Address",
"house": "House",
"post_code": "Postcode"
},
"data_description": {}
},
"args_runnymede_gov_uk": {
"title": "Configure Source",
"description": "Configure your service provider. More details: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/runnymede_gov_uk.md.",
Expand Down
24 changes: 24 additions & 0 deletions custom_components/waste_collection_schedule/translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -15630,6 +15630,30 @@
"uprn": "Un modo facile per scoprire il tuo Numero di Riferimento Proprietà Unica (UPRN) è andare su https://www.findmyaddress.co.uk/ e inserire i dettagli del tuo indirizzo."
}
},
"args_royalgreenwich_gov_uk": {
"title": "Configurazione Sorgente",
"description": "Compila i campi per ottenere le informazioni sul tuo servizio di raccolta. Maggiori informazioni: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/royalgreenwich_gov_uk.md.",
"data": {
"calendar_title": "Nome Calendario",
"address": "Address",
"house": "Casa",
"post_code": "Codice Postale CAP"
},
"data_description": {
"calendar_title": "Puoi cambiare il nome del calendario della raccolta dei rifiuti, altrimenti di default verra' utilizzato il nome del tuo fornitore di servizi."
}
},
"reconfigure_royalgreenwich_gov_uk": {
"title": "Riconfigurazione Sorgente",
"description": "Compila i campi per ottenere le informazioni sul tuo servizio di raccolta. Per maggiori informazioni: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/royalgreenwich_gov_uk.md.",
"data": {
"calendar_title": "Nome Calendario",
"address": "Address",
"house": "Casa",
"post_code": "Codice Postale CAP"
},
"data_description": {}
},
"args_runnymede_gov_uk": {
"title": "Configurazione Sorgente",
"description": "Compila i campi per ottenere le informazioni sul tuo servizio di raccolta. Maggiori informazioni: https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/runnymede_gov_uk.md.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import re
import datetime

import requests
from bs4 import BeautifulSoup, Tag
from dateutil import parser
from typing import Optional
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.exceptions import SourceArgAmbiguousWithSuggestions, SourceArgumentNotFound

TITLE = "Royal Borough Of Greenwich"
DESCRIPTION = "Source for services from the Royal Borough Of Greenwich"
URL = "https://www.royalgreenwich.gov.uk/"
TEST_CASES = {
"address": {"address": "25 - Tizzard Grove - London - SE3 9DH"},
"houseNumber": {"post_code": "SE9 5AW", "house": "11"},
"alternativeWeek": {"address": "32 - Glenlyon Road - London - SE9 1AJ"}
}

ADDRESS_SEARCH_URL = "https://www.royalgreenwich.gov.uk/site/custom_scripts/apps/waste-collection/new2023/source.php"


DAYS = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"]
ICON_MAP = {
"recycling": "mdi:recycle",
"garden": "mdi:leaf",
"food": "mdi:food-apple",
}


class InsufficientDataError(Exception):
pass


class Source:
def __init__(
self,
post_code: Optional[str] = None,
house: Optional[str] = None,
address: Optional[str] = None
):
self._post_code = post_code
self._house = house
self._address = address

def _find_address(self) -> str:
term_list = [self._post_code]
if self._house:
term_list.append(self._house)

s = requests.Session()
search_term = " ".join(term_list)
r = s.get(ADDRESS_SEARCH_URL, params={"term": search_term})
r.raise_for_status()

addresses = r.json()

if len(addresses) > 1:
raise SourceArgAmbiguousWithSuggestions("house", self._house, addresses)

if len(addresses) == 0:
raise SourceArgumentNotFound("house", self._house)

return addresses[0]

def _get_black_top_bin_next_collection_date(self, week_name: str, this_week_collection_date: datetime.datetime) -> datetime.datetime:
s = requests.Session()
r = s.get(
"https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/2436/black_top_bin_collections"
)
r.raise_for_status()

soup = BeautifulSoup(r.text, "html.parser")

black_top_bin_schedule_table = soup.find("table")
if not isinstance(black_top_bin_schedule_table, Tag):
raise Exception("Could not find address form")

headers = black_top_bin_schedule_table.find_all("th")
week_column_index = list(map(lambda h: h.text, headers)).index(week_name)
if week_column_index < 0:
raise Exception("Cannot find black top bin collection weeks")

# e.g. Monday 1 January to Friday 5 January
first_week_dates_range_str: str = black_top_bin_schedule_table.find("tbody").find("tr").find_all('td')[week_column_index].text

first_week_date = parser.parse(first_week_dates_range_str.split(" to ")[0]).date()

# we assume that this "first_week_date" is always Monday (as per schedule)
first_week_collection_date = first_week_date + datetime.timedelta(this_week_collection_date.isoweekday() - 1)
return this_week_collection_date + datetime.timedelta(weeks=1) if (this_week_collection_date - first_week_collection_date).days % 14 else this_week_collection_date

def fetch(self) -> list[Collection]:
if not self._address:
self._address = self._find_address()

s = requests.Session()

r = s.get(
"https://www.royalgreenwich.gov.uk/site/custom_scripts/repo/apps/waste-collection/new2023/ajax-response-uprn.php",
params={ "address": self._address }
)
r.raise_for_status()

# even if address is part of the borough it doesn't mean they will provide data for it
# e.g. for flats they explicitly mentioned to contact management company instead
# so in this case address can be found in previous steps, but there is no data for it and this error is returned
if r.text == "ADDRESS_NOT_FOUND":
raise Exception(f"No data found for address '{self._address}'")

data = r.json()

collection_day = data["Day"]
black_top_bin_week = data["Frequency"]

today = datetime.date.today()
collection_day_index = DAYS.index(collection_day.upper()) + 1
this_week_collection_date = today + datetime.timedelta(
(collection_day_index - today.isoweekday()) % 7
)

next_food_collection_date = self._get_black_top_bin_next_collection_date(black_top_bin_week, this_week_collection_date)

weeks_to_generate = 10

recycling_collections = [
Collection(
date=this_week_collection_date + datetime.timedelta(weeks=i),
t="recycling",
icon=ICON_MAP.get("recycling"),
) for i in range(weeks_to_generate)
]

garden_collections = [
Collection(
date=this_week_collection_date + datetime.timedelta(weeks=i),
t="garden",
icon=ICON_MAP.get("garden"),
) for i in range(weeks_to_generate)
]

food_collections = [
Collection(
date=next_food_collection_date + datetime.timedelta(weeks=i * 2),
t="food",
icon=ICON_MAP.get("food"),
) for i in range(int(weeks_to_generate / 2))
]

return recycling_collections + garden_collections + food_collections
61 changes: 61 additions & 0 deletions doc/source/royalgreenwich_gov_uk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Royal Borough Of Greenwich

Support for schedules provided by the [Royal Borough Of Greenwich](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day).

## Configuration via configuration.yaml

```yaml
waste_collection_schedule:
sources:
- name: royalgreenwich_gov_uk
args:
post_code: POST_CODE
house: HOUSE_NUMBER
address: FULL_ADDRESS
```
### Configuration Variables
**address**
*(string) (optional)*
This is required if you do not supply any other options. (Using this removes the need to do an address look up web request)
**house**
*(string) (optional)*
This is required if you supply a Postcode.
**post_code**
*(string) (optional)*
This is required if you do not supply an Address. Single space between 1st and 2nd part of postcode is optional.
#### How to find your `FULL_ADDRESS`

An easy way to discover your full address is:

1. Go to <https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day>
1. Find your property and click "Search" button
1. First bold text in the message below the search bar (right after "At" and before ":") is your address, use it as-is.

## Example using FULL_ADDRESS

```yaml
waste_collection_schedule:
sources:
- name: royalgreenwich_gov_uk
args:
address: "32 - Glenlyon Road - London - SE9 1AJ"
```

## Example using Address lookup

```yaml
waste_collection_schedule:
sources:
- name: royalgreenwich_gov_uk
args:
post_code: "SE9 5AW"
number: "11"
```
Loading

0 comments on commit a1552fc

Please sign in to comment.