Skip to content

Commit

Permalink
Added support for Royal Borough Of Greenwich (mampfes#3278)
Browse files Browse the repository at this point in the history
* Added support for Royal Borough Of Greenwich (mampfes#3277)

* Added arguments description and how to get them to metainfo

* reformatting + fixing typehints

---------

Co-authored-by: 5ila5 <[email protected]>
  • Loading branch information
timocov and 5ila5 authored Dec 27, 2024
1 parent db06cd0 commit 1956979
Show file tree
Hide file tree
Showing 8 changed files with 338 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. \n\nUsing a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). Find the collection day and the first bold text in the message below the search bar (right after \"At\" and before \":\") is your address, use it as-is.\n\nMehr 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. \n\nUsing a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). Find the collection day and the first bold text in the message below the search bar (right after \"At\" and before \":\") is your address, use it as-is.\n\nMehr 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
31 changes: 31 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,37 @@
"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. \n\nUsing a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). Find the collection day and the first bold text in the message below the search bar (right after \"At\" and before \":\") is your address, use it as-is.\n\nMore 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.",
"address": "Full address",
"house": "House number or name",
"post_code": "Postcode"
}
},
"reconfigure_royalgreenwich_gov_uk": {
"title": "Reconfigure Source",
"description": "Configure your service provider. \n\nUsing a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). Find the collection day and the first bold text in the message below the search bar (right after \"At\" and before \":\") is your address, use it as-is.\n\nMore 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": {
"address": "Full address",
"house": "House number or name",
"post_code": "Postcode"
}
},
"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. \n\nUsing a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). Find the collection day and the first bold text in the message below the search bar (right after \"At\" and before \":\") is your address, use it as-is.\n\nMaggiori 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. \n\nUsing a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). Find the collection day and the first bold text in the message below the search bar (right after \"At\" and before \":\") is your address, use it as-is.\n\nPer 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,190 @@
import datetime
from typing import Optional

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

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",
}

# ### Arguments affecting the configuration GUI ####

HOW_TO_GET_ARGUMENTS_DESCRIPTION = { # Optional dictionary to describe how to get the arguments, will be shown in the GUI configuration form above the input fields, does not need to be translated in all languages
"en": "Using a browser, go to [royalgreenwich.gov.uk](https://www.royalgreenwich.gov.uk/info/200171/recycling_and_rubbish/100/find_your_bin_collection_day). "
'Find the collection day and the first bold text in the message below the search bar (right after "At" and before ":") is your address, use it as-is.'
}

PARAM_DESCRIPTIONS = { # Optional dict to describe the arguments, will be shown in the GUI configuration below the respective input field
"en": {
"post_code": "Postcode",
"house": "House number or name",
"address": "Full address",
}
}

# ### End of arguments affecting the configuration GUI ####


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:
if not self._post_code:
raise SourceArgumentRequired(
"post_code", "postcode is required if address is not provided"
)
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.date
) -> datetime.date:
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 1956979

Please sign in to comment.