Repository navigation
Conversation
Doncaster retired its Compass waste portal. The endpoint the scraper called, /Compass/PremiseDetail/GetCollectionsForCalendar, now 302s to an ASP.NET error page that is served with HTTP 200, so the status-code guard passed and json.loads raised JSONDecodeError. /Compass/Entity/Launch/D3/ renders "Nothing To Display". The council's bins page now links to a Netcall Liberty Create app at doncaster-wasterecycling.oncreate.app, which is JS-rendered and searched by postcode and property, so the scraper drives it with Selenium. BREAKING CHANGE: the inputs change from uprn to postcode + house_number. The app's only entry point requires a postcode, and its address links carry a per-session Liberty Create record id rather than a UPRN, so a UPRN cannot be used to reach a property. Existing Home Assistant users must reconfigure the integration after the release that carries this. Collections are read from the calendar widget's data-params, which holds the whole published event list, so every month is returned rather than only the one the FullCalendar grid has drawn; the rendered grid is kept as a fallback. Targets #2256, diagnosed by @Smokinloads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2282 +/- ##
==========================================
+ Coverage 80.97% 82.47% +1.49%
==========================================
Files 16 34 +18
Lines 1619 2596 +977
==========================================
+ Hits 1311 2141 +830
- Misses 308 455 +147 ☔ View full report in Codecov by Harness. |
The fixture was 3 Sandown Gardens, a dwelling, which input.json must not carry. Doncaster's app only holds data for properties on a domestic round, so finding a non-residential one that still returns collections took a sweep of 174 postcodes plus 125 named-property checks: schools, libraries, nurseries, community centres, scout huts, clubs, miners' welfare and churches all return "no collection information available". Two registered nursing homes do return collections. The Laurels Nursing Home, High Street, Norton, DN6 9EU returns 15 (Refuse and Recycling, weekly alternating), and its address is published in the CQC register, so it is a business premises rather than anyone's home. Also drops the residential street names from the unit test fixtures, which are just as public as input.json, in favour of the new address and hypothetical numbers on the same street. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Cherry-picked into #2277 unchanged ( Nothing wrong with the work — Thanks for checking the fixture properly and swapping it. The Laurels Nursing Home is a registered business at a named premises rather than a private household, which is what input.json needs. Re-verified independently: live test passes, 15 collections. One observation, not a request: two of those 15 dates are in the past. That's harmless, because the integration's |
Every existing Doncaster user must reconfigure the integration after the release that carries this. The council's replacement app has no UPRN route at all (evidence below), so there was no way to keep the old input.
Why the rewrite
DoncasterCouncil.pycalledhttps://www.doncaster.gov.uk/Compass/PremiseDetail/GetCollectionsForCalendarwith a UPRN and epochStart/Endparams. Verified live from a UK residential connection on 2026-10-15:/Themes/DMBC.Theme2/Static/Error.html?aspxerrorpath=..., an ASP.NET error page served with HTTP 200. The scraper'sif response.status_code != 200guard therefore passed andjson.loadsdied withJSONDecodeError: Expecting value: line 1 column 1 (char 0)— exactly the Home Assistant failure in Doncaster: setup fails with JSON decoding error; council lookup now uses OnCreate #2256.https://www.doncaster.gov.uk/Compass/Entity/Launch/D3/renders "Nothing To Display".https://doncaster-wasterecycling.oncreate.app/w/webpage/bin-query, a Netcall Liberty Create app. A plain GET returns a 35 KB JS shell with an empty<title>and no form inputs, so it needs Selenium.Why the UPRN could not be kept
I checked specifically for a UPRN route before accepting a breaking change:
bin-queryformaddress-collections?uprn=100050768956address-collections?id=58989without a tokenidin the results linkswebpage_tokenHMAC andauthvalue that cannot be derived client-side.So postcode + property is the only way in, and
uprnis replaced bypostcode+house_number, matchingSevenoaksDistrictCouncil, which drives the same platform.How the new scraper works
bin-query, fills Postcode and Property Number or Name, submits.Three things about this platform are worth knowing, and the code is shaped around all three:
num_data_rows: 25,pagination_bottom: "dynamic"in the widget's own settings), so the property box has to be filled rather than relying on a postcode-only search. Because that box is a plain substring match against the council's record, the scraper falls back to a postcode-only search when the property text finds nothing, then matches locally.Rear Of 23 ...alongside23 ..., so neither a naive substring test nor "first result wins" is safe.data-params. Parsing that attribute returns every published date with no month-by-month clicking. The rendered grid (td.fc-daygrid-day[data-date]plus.fc-event-title) is kept as a fallback.The form fields are located through the
forattribute of their visible labels, because Liberty Create generates the input ids from internal page references (payload[PAG0000624GBSLB1][PWG0002347GBSLB1]...) that change whenever the council rebuilds the app.No User-Agent is forced on the driver (
create_webdriver(..., None, ...)). This app has no bot management of its own, and a hardcoded string would claim an OS and Chrome version that the browser's own JavaScript then contradicts.input.json
uprn100050768956postcodeDN6 9EUhouse_numberThe Laurels Nursing Homeurlbin-querypageweb_driverhttp://selenium:4444(the class callscreate_webdriver)wiki_noteThe test address is non-residential, but it took some finding
Doncaster's app only holds data for properties on a domestic collection round, and almost everything institutional in the borough is on trade waste and returns "There is no collection information available for this address". Confirmed against the live site for schools, academies, pre-schools and day nurseries, branch libraries, a community centre, a scout and guide association, a cricket club, a social club and institute, a miners' welfare recreation ground, an air cadet centre, a children's centre, an assembly hall, a leisure centre, the Civic Offices, and a supermarket — all empty.
Finding one that works took a sweep of 174 postcodes (prioritising village parishes, where community buildings are likeliest to be on a domestic round) plus 125 individual named-property checks. Two registered nursing homes do return collections:
The Laurels is a CQC-registered care business whose address is published in the CQC register and the usual care-home directories, so it is a business premises rather than anyone's home, and the property name says so in the fixture itself. The second commit also drops the residential street names from the unit test fixtures — those are just as public as input.json — in favour of this address and hypothetical numbers on the same street.
If a nursing home is still the wrong call, the honest alternative is that there may be no suitable address at all: nothing institutional in the borough that I could find is on a domestic round.
Test plan
Run from a UK residential connection with Chrome 154 installed, not from a sandbox.
Verified:
pytest uk_bin_collection/tests/step_defs/ -k Doncaster --local_browser True -q— 1 passed, 8.9 s. Re-run after the fixture change.collect_data.py DoncasterCouncil <url> -s -p "DN6 9EU" -n "The Laurels Nursing Home"returns 15 collections (Refuse, Recycling), 06/10/2026 to 12/01/2027, matching the live page in a browser. This exercises the house-name lookup path, not just a number.pytest uk_bin_collection/tests custom_components/uk_bin_collection/tests --ignore=uk_bin_collection/tests/step_defs/ -q— 364 passed, 0 failed (339 before this change, plus 25 new). The playbook's known sandbox-only failures (test_check_postcode_valid,test_check_postcode_invalid,test_create_webdriver_local) pass here because this machine has network.black --checkclean on both changed Python files.web_driver-vs-create_webdriverconsistency: Doncaster is consistent. That check flags 14 pre-existing mismatches on master (Bexley, Bromley, Chelmsford, East Riding, Epping Forest, Kingston upon Thames, North Warwickshire, Peterborough, Rugby, South Holland, Stirling, Windsor and Maidenhead, Wirral, Wokingham), all untouched here.uk_bin_collection/tests/test_doncaster_council.pycovering several waste types with dates, a subscribed service whose dates have run out (seasonal garden waste), duplicate and unreadable events, the "no collection information" error, a page with no calendar at all, the grid fallback, address matching, and the driver being closed on both success and timeout.Not verified:
tests/check_selenium_url_in_input.json.pyreads input.json from the GitHub API, so locally it checks nothing; I ran an offline equivalent instead.config_flow.py(house_number→ requirednumber,web_driver→ optional Selenium URL).oncreate.app— playbook §4 notes CI IPs are blocked by many council sites.Credit
Diagnosed by @Smokinloads in #2256, who had already identified the migration to OnCreate, the HTTP 200 error page and the exact failure mode before any of this work started. This PR is their diagnosis implemented.
Targets #2256rather thanFixes— the live test passes for the project's test address, but it would be good to have the reporter confirm it works for their own property, since they are the one who has to reconfigure.Not done here
Not merged and not released — that is the maintainer's call.
docs/MAINTAINER_PLAYBOOK.mdis deliberately untouched to avoid conflicting with the concurrent Fylde retirement PR, andwiki/Councils.mdis left to theDeploy - Wikiworkflow.🤖 Generated with Claude Code
Summary by CodeRabbit