Skip to content

Commit

Permalink
fix elmbridge_gov_uk
Browse files Browse the repository at this point in the history
  • Loading branch information
5ila5 committed Sep 27, 2024
1 parent e5fb057 commit 286b931
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 141 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import logging
from datetime import datetime, timedelta
from datetime import datetime
from typing import TypedDict

import requests
from bs4 import BeautifulSoup
from dateutil.parser import parse
from waste_collection_schedule import Collection

TITLE = "Elmbridge Borough Council"
Expand All @@ -16,107 +16,95 @@
"Test_005": {"uprn": 100062372553},
}

API_URLS = {
"session": "https://emaps.elmbridge.gov.uk/myElmbridge.aspx",
"search": "https://emaps.elmbridge.gov.uk/myElmbridge.aspx?action=SetAddress&UniqueId={}",
"schedule": "https://emaps.elmbridge.gov.uk/myElmbridge.aspx?tab=0#Refuse_&_Recycling",
}

OFFSETS = {
"Monday": 0,
"Tuesday": 1,
"Wednesday": 2,
"Thursday": 3,
"Friday": 4,
"Saturday": 5,
"Sunday": 6,
}
BASE_URL = "https://elmbridge-self.achieveservice.com"
INTIAL_URL = f"{BASE_URL}/service/Your_bin_collection_days"
AUTH_URL = f"{BASE_URL}/authapi/isauthenticated"
AUTH_TEST = f"{BASE_URL}/apibroker/domain/elmbridge-self.achieveservice.com"
API_URL = f"{BASE_URL}/apibroker/runLookup"

ICON_MAP = {
"REFUSE": "mdi:trash-can",
"RECYCLING": "mdi:recycle",
"FOOD": "mdi:food",
"GARDEN": "mdi:leaf",
}

HEADERS = {
"user-agent": "Mozilla/5.0",
ICON_MAP = {
"Domestic Waste": "mdi:trash-can",
"Domestic Recycling": "mdi:recycle",
"Food Waste": "mdi:food",
"Textiles and Small WEEE": "mdi:tshirt-crew",
}


_LOGGER = logging.getLogger(__name__)
class CollectionResult(TypedDict):
Date: str
Service1: str
Service2: str
Service3: str


class Source:
def __init__(self, uprn: str = None):
self._uprn = str(uprn)

def fetch(self):
# API's do not return the year, nor the date of the collection.
# They return a list of dates for the beginning of a week, and the day of the week the collection is on.
# This script assumes the week-commencing dates are for the current year.
# This'll cause problems in December as upcoming January collections will have been assigned dates in the past.
# Some clunky logic can deal with this:
# If a date in less than 1 month in the past, it doesn't matter as the collection will have recently occurred.
# If a date is more than 1 month in the past, assume it's an incorrectly assigned date and increment the year by 1.
# Once that's been done, offset the week-commencing dates to match day of the week each waste collection type is scheduled.
# If you have a better way of doing this, feel free to update via a Pull Request!

# Get current date and year in format consistent with API result
today = datetime.now()
today = today.replace(hour=0, minute=0, second=0, microsecond=0)
year = today.year

s = requests.Session()

r0 = s.get(API_URLS["session"], headers=HEADERS)
r0.raise_for_status()
r1 = s.get(API_URLS["search"].format(self._uprn), headers=HEADERS)
r1.raise_for_status()
r2 = s.get(API_URLS["schedule"], headers=HEADERS)
r2.raise_for_status()

responseContent = r2.content
soup = BeautifulSoup(responseContent, "html.parser")
def __init__(self, uprn: str | int):
self._uprn = str(uprn).strip()
self._session = requests.Session()

def _init_session(self) -> str:
self._session = requests.Session()
r = self._session.get(INTIAL_URL)
r.raise_for_status()
params: dict[str, str | int] = {
"uri": r.url,
"hostname": "elmbridge-self.achieveservice.com",
"withCredentials": "true",
}
r = self._session.get(AUTH_URL, params=params)
r.raise_for_status()
data = r.json()
session_key = data["auth-session"]

params = {
"sid": session_key,
"_": int(datetime.now().timestamp() * 1000),
}
r = self._session.get(AUTH_TEST, params=params)
r.raise_for_status()

return session_key

def get_collections(self, session_key: str) -> list[Collection]:
params: dict[str, int | str] = {
"id": "663b557cdaece",
"repeat_against": "",
"noRetry": "false",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AF-Renderer::Self",
"_": int(datetime.now().timestamp() * 1000),
"sid": session_key,
}
payload = {
"formValues": {
"Section 1": {
"UPRN": {"value": self._uprn},
}
}
}
r = self._session.post(API_URL, params=params, json=payload)
r.raise_for_status()
return list(r.json()["integration"]["transformed"]["rows_data"].values())

def fetch(self) -> list[Collection]:
session_key = self._init_session()
collections = self.get_collections(session_key)

entries = []

notice = soup.find("div", {"class": "atPanelContent atFirst atAlt0"})
notices = notice.text.replace(
"\nRefuse and recycling collection days\n", ""
).split(".")
notices.pop(-1) # Remove superfluous element
frame = soup.find("div", {"class": "atPanelContent atAlt1 atLast"})
table = frame.find("table")

for tr in table.find_all("tr"):
row = []
for td in tr.find_all("td"):
row.append(td.text.strip())
row.pop(1) # removes superfluous element
dt = row[0] + " " + str(year)
dt = datetime.strptime(dt, "%d %b %Y")

# Amend year, if necessary
if (dt - today) < timedelta(days=-31):
dt = dt.replace(year=dt.year + 1)
row[0] = dt

# Separate out same-day waste collections
wastetypes = row[1].split(" + ")

# Sort out date offsets for each collection type
for waste in wastetypes:
for day, offset in OFFSETS.items():
for sentence in notices:
if (waste in sentence) and (day in sentence):
new_date = row[0] + timedelta(days=offset)
entries.append(
Collection(
date=new_date.date(),
t=waste + " bin",
icon=ICON_MAP.get(waste.upper()),
)
)
for collection in collections:
date = parse(collection["Date"], dayfirst=True).date()
for service in [
collection["Service1"],
collection["Service2"],
collection["Service3"],
]:
if not service:
continue
service = service.removesuffix(" Collection Service")
icon = ICON_MAP.get(service)
entries.append(Collection(date=date, t=service, icon=icon))

return entries
48 changes: 1 addition & 47 deletions doc/source/elmbridge_gov_uk.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Elmbridge Borough Council

Support for schedules provided by [Elmbridge Borough Council](https://emaps.elmbridge.gov.uk/myElmbridge.aspx?tab=0#Refuse_&_Recycling), serving Elmbridge, UK.
Support for schedules provided by [Elmbridge Borough Council](http://elmbridge-self.achieveservice.com/service/Your_bin_collection_days), serving Elmbridge, UK.

## Configuration via configuration.yaml

Expand Down Expand Up @@ -33,49 +33,3 @@ waste_collection_schedule:
## How to find your `UPRN`

An easy way to find your Unique Property Reference Number (UPRN) is by going to https://www.findmyaddress.co.uk/ and entering in your address details.

#### Notes:
The Elmbridge web site does not show a list of collection dates. It describes the day of the week your waste collection(s) happen on, and lists the start date of the weeks this applies to. The format also differs depending on your collection schedule, for example:


```
Refuse and recycling collection days
Your collection day for refuse is Wednesday in the weeks indicated below.
Your collection day for recycling is Wednesday in the weeks indicated below.
Your collection day for garden waste (if you subscribe) is Tuesday in the weeks indicated below.
Recycling and garden waste collections for weeks commencing Monday
10 Oct - refuse + garden
17 Oct - refuse + recycling
24 Oct - refuse + garden
31 Oct - refuse + recycling
```

```
Refuse and recycling collection days
Your collection day for refuse and food waste or, recycling and food waste is Tuesday in the weeks indicated below.
Your collection day for garden waste (if you subscribe) is Tuesday in the weeks indicated below.
Recycling and garden waste collections for weeks commencing Monday
10 Oct - refuse + food + garden
17 Oct - recycling + food
24 Oct - refuse + food + garden
31 Oct - recycling + food
```

Trying to convert all this into a schedule of dates for each specific waste collections is a bit fiddly. By way of explanaion of what the the script tries to do:
* It assumes the week-commencing dates are for the current year.
* This'll cause problems in December as upcoming January collections will have been assigned dates in the past.
* Some clunky logic can deal with this:
* If a date in less than 1 month in the past, it doesn't matter as the collection will have recently occurred.
* If a date is more than 1 month in the past, assume it's an incorrectly assigned date and increments the year by 1.
* Once that's been done, offset the week-commencing dates to match day of the week indicated for each waste collection type.

So, plenty of scope for things to go wrong!

If you have a better way of doing this, feel free to update all the elmbridge_gov_uk files via a pull request!

0 comments on commit 286b931

Please sign in to comment.