Skip to content

Commit

Permalink
Fix stevenage gov uk (#2217)
Browse files Browse the repository at this point in the history
* Fix the stevenage_gov_uk source

* Update documentation

* reformatting + ./update_docu_links.py + add findmyaddress.co.uk link in md file

---------

Co-authored-by: Adam Prickett <adam.prickett@ampersa.co.uk>
Co-authored-by: 5ila5 <5ila5@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 4, 2024
1 parent 9739594 commit 41aa829
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 98 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ Waste collection schedules in the following formats and countries are supported.
- [South Tyneside Council](/doc/source/southtyneside_gov_uk.md) / southtyneside.gov.uk
- [Southampton City Council](/doc/source/southampton_gov_uk.md) / southampton.gov.uk
- [Stafford Borough Council](/doc/source/staffordbc_gov_uk.md) / staffordbc.gov.uk
- [Stevenage Borough Council](/doc/source/stevenage_gov_uk.md) / stevenage.gov.uk
- [Stevenage](/doc/source/stevenage_gov_uk.md) / stevenage.gov.uk
- [Stirling.gov.uk](/doc/source/stirling_uk.md) / stirling.gov.uk
- [Stockport Council](/doc/source/stockport_gov_uk.md) / stockport.gov.uk
- [Stockton-on-Tees Borough Council](/doc/source/stockton_gov_uk.md) / stockton.gov.uk
Expand Down
7 changes: 6 additions & 1 deletion custom_components/waste_collection_schedule/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -5108,6 +5108,11 @@
"module": "lund_se",
"default_params": {}
},
{
"title": "Norrtalje Vatten & Avfall",
"module": "nvaa_se",
"default_params": {}
},
{
"title": "North / Middle Bohusl\u00e4n - Rambo AB",
"module": "rambo_se",
Expand Down Expand Up @@ -6256,7 +6261,7 @@
"default_params": {}
},
{
"title": "Stevenage Borough Council",
"title": "Stevenage",
"module": "stevenage_gov_uk",
"default_params": {}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,108 +1,110 @@
import json
import requests
import urllib3
from datetime import datetime
import datetime
import time

import requests
from waste_collection_schedule import Collection # type: ignore[attr-defined]

# With verify=True the POST fails due to a SSLCertVerificationError.
# Using verify=False works, but is not ideal. The following links may provide a better way of dealing with this:
# https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
# https://urllib3.readthedocs.io/en/1.26.x/user-guide.html#ssl
# This line suppresses the InsecureRequestWarning when using verify=False
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


TITLE = "Stevenage Borough Council"
DESCRIPTION = "Source for stevenage.gov.uk services for Stevenage, UK."
URL = "https://stevenage.gov.uk"
TITLE = "Stevenage"
DESCRIPTION = "Source for Stevenage."
URL = "https://www.stevenage.gov.uk/"
TEST_CASES = {
"Coopers Close schedule": {"road": "Coopers Close", "postcode": "SG2 9TL"},
"Wansbeck Close schedule": {"road": "Wansbeck Close", "postcode": "SG1 6AA"},
"Chepstow Close schedule": {"road": "Chepstow Close", "postcode": "SG1 5TT"},
"Chepstow Close": {"uprn": "100080879233"},
"Rectory Lane": {"uprn": "100081137566"},
"Neptune Gate": {"uprn": "200000585910"},
}

SEARCH_URLS = {
"round_search": "https://services.stevenage.gov.uk/~?a=find&v=1&p=P1&c=P1_C33_&act=P1_A43_",
"collection_search": "https://services.stevenage.gov.uk/~?a=find&v=1&p=P1&c=P1_C37_&act=P1_A64_",
}
ICON_MAP = {
"REFUSE": "mdi:trash-can",
"RECYCLING": "mdi:recycle",
"general waste": "mdi:trash-can",
"recycling": "mdi:recycle",
}
COLLECTIONS = {"Rubbish", "Recycling"}

SESSION_URL = "https://stevenage-self.achieveservice.com/authapi/isauthenticated?uri=https%3A%2F%2Fstevenage-self.achieveservice.com%2Fen%2Fservice%2FCheck_your_household_bin_collection_days&hostname=stevenage-self.achieveservice.com&withCredentials=true"
TOKEN_URL = (
"https://stevenage-self.achieveservice.com/apibroker/runLookup?id=5e55337a540d4"
)
API_URL = "https://stevenage-self.achieveservice.com/apibroker/runLookup"


class Source:
def __init__(self, road, postcode):
self._road = road
self._postcode = postcode
def __init__(self, uprn):
self._uprn = str(uprn)

def fetch(self):
data = {
"formValues": {
"Section 1": {
"token": {"value": ""},
"LLPGUPRN": {
"value": self._uprn,
},
"MinimumDateLookAhead": {
"value": time.strftime("%Y-%m-%d"),
},
"MaximumDateLookAhead": {
"value": str(int(time.strftime("%Y")) + 1)
+ time.strftime("-%m-%d"),
},
}
}
}

s = requests.Session()

# Get Round ID and Round Code
# Don't fully understand significance of all of the fields, but API borks if they are not present
roundData = {
"data": {
"fields": ["P1_C31_", "P1_C31_", "P1_C105_", "P1_C105_"],
"rows": [[self._road, self._road, self._postcode, self._postcode]],
},
"sequence": 1,
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0",
"X-Requested-With": "XMLHttpRequest",
"Referer": "https://stevenage-self.achieveservice.com/fillform/?iframe_id=fillform-frame-1&db_id=",
}
s = requests.session()
r = s.get(SESSION_URL)
r.raise_for_status()
session_data = r.json()
sid = session_data["auth-session"]

headers = {"Content-type": "application/json", "Accept": "text/plain"}
roundRequest = s.post(
SEARCH_URLS["round_search"], data=json.dumps(roundData), headers=headers, verify=False
)
roundJson = json.loads(roundRequest.text)
t = s.get(TOKEN_URL)
t.raise_for_status()
token_data = t.json()
data["formValues"]["Section 1"]["token"]["value"] = token_data["integration"][
"transformed"
]["rows_data"]["0"]["token"]

# Get collection info
collectionData = {
"data": {
"fields": [
"P1_C37_.selectedRowData.id",
"P1_C37_.selectedRowData.roundCode",
],
"rows": [[roundJson["rows"][0][0], roundJson["rows"][0][2]]],
},
"sequence": 1,
"childQueries": [
{
"data": {
"fields": ["P1_C37_.selectedRowData.id"],
"rows": [[roundJson["rows"][0][0]]],
},
"index": 0,
}
],
params = {
"id": "64ba8cee353e6",
"repeat_against": "",
"noRetry": "false",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AF-Renderer::Self",
# unix_timestamp
"_": str(int(time.time() * 1000)),
"sid": sid,
}

collectionRequest = s.post(
SEARCH_URLS["collection_search"],
data=json.dumps(collectionData),
headers=headers,verify=False
)
collectionJson = json.loads(collectionRequest.text)
r = s.post(API_URL, json=data, headers=headers, params=params)
r.raise_for_status()
data = r.json()
rows_data = data["integration"]["transformed"]["rows_data"]
if not isinstance(rows_data, dict):
raise ValueError("Invalid data returned from API")

entries = []
for collection in collectionJson["rows"]:
if collection[2] == "Recycling collection":
entries.append(
Collection(
date=datetime.strptime(collection[1], "%d/%m/%Y").date(),
t="Recycling",
icon=ICON_MAP.get("RECYCLING"),
)
)
elif collection[2] == "Refuse collection":
entries.append(
Collection(
date=datetime.strptime(collection[1], "%d/%m/%Y").date(),
t="Refuse",
icon=ICON_MAP.get("REFUSE"),
)
for key in rows_data:
value = rows_data[key]
bin_type = value["bintype"].strip()

try:
date = datetime.datetime.strptime(
value["collectiondate"], "%A %d %B %Y"
).date()
except ValueError:
continue

entries.append(
Collection(
date=date,
t=bin_type,
icon=ICON_MAP.get(bin_type.lower()),
)
)

return entries
24 changes: 13 additions & 11 deletions doc/source/stevenage_gov_uk.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Stevenage Borough Council

Support for schedules provided by [Stevenage Borough Council](https://www.stevenage.gov.uk/waste-and-recycling/your-bin-collections).
Support for schedules provided by [Stevenage Borough Council](https://stevenage-self.achieveservice.com/service/my_bin_collection_schedule).

## Configuration via configuration.yaml

Expand All @@ -9,21 +9,24 @@ waste_collection_schedule:
sources:
- name: stevenage_gov_uk
args:
postcode: POST_CODE
road: ROAD
uprn: UPRN
```
### Configuration Variables
**postcode**
**uprn**
*(string) (required)*
Postcode of property. This is required. Stevenage Borough Council API does not support UKPRN. Single space between 1st and 2nd part of postcode is optional.
Unique property reference. This is required. To obtain this value, visit https://stevenage-self.achieveservice.com/service/my_bin_collection_schedule, enter your postcode and Inspect the Select address field. The value of the option associated with your address is your uprn.
**road**
*(string) (required)*
Name of road property is in. This is required.
For example, the UPRN in this example for 100 High Street is **200000586516**
```html
<option value="">Select...</option>
<option class="lookup-option" value="100080885553">10 High Street, Stevenage</option>
<option class="lookup-option" value="200000586516">100 High Street, Stevenage</option>
<option class="lookup-option" value="100081247651">101 High Street, Stevenage</option>
...
```

## Example

Expand All @@ -32,6 +35,5 @@ waste_collection_schedule:
sources:
- name: stevenage_gov_uk
args:
postcode: SG2 9TL
road: Coopers Close
uprn: 100080879233
```
Loading

0 comments on commit 41aa829

Please sign in to comment.