Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Porirua City NZ #2360

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,7 @@ If your service provider is not listed, feel free to open a [source request issu
- [Hamilton City Council](/doc/source/hcc_govt_nz.md) / fightthelandfill.co.nz
- [Horowhenua District Council](/doc/source/horowhenua_govt_nz.md) / horowhenua.govt.nz
- [Hutt City Council](/doc/source/toogoodtowaste_co_nz.md) / toogoodtowaste.co.nz
- [Porirua City](/doc/source/poriruacity_govt_nz.md) / poriruacity.govt.nz
- [Tauranga City Council](/doc/source/tauranga_govt_nz.md) / tauranga.govt.nz
- [Waipa District Council](/doc/source/waipa_nz.md) / waipadc.govt.nz
- [Wellington City Council](/doc/source/wellington_govt_nz.md) / wellington.govt.nz
Expand Down
5 changes: 5 additions & 0 deletions custom_components/waste_collection_schedule/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -6275,6 +6275,11 @@
"module": "toogoodtowaste_co_nz",
"default_params": {}
},
{
"title": "Porirua City",
"module": "poriruacity_govt_nz",
"default_params": {}
},
{
"title": "Tauranga City Council",
"module": "tauranga_govt_nz",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import json
import re
from datetime import date, datetime, timedelta

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

TITLE = "Porirua City"
DESCRIPTION = "Source for Porirua City."
URL = "https://poriruacity.govt.nz/"
TEST_CASES = {
"6 Ration Lane, Whitby, Porirua City 5024": {
"address": "6 Ration Lane, Whitby, Porirua City 5024"
},
"104 Main Road, Titahi Bay, Porirua City 5022": {
"address": "104 Main Road, Titahi Bay, Porirua City 5022"
},
}


ICON_MAP = {
"rubbish": "mdi:trash-can",
"glass": "mdi:bottle-soda",
"mixed": "mdi:recycle",
}


JS_URL = "https://storage.googleapis.com/pcc-wagtail-static-v4/pccapp/dist/assets/index.js?v=62120874e6b54e6e83ef020a2d376392"

ZONES_REGEX = re.compile(r"const\s?Xs\s?=\s?\{.*?\};", re.DOTALL)
COLLECTIONS_MAP_REGEX = re.compile(r"collections:\s?\{(\w+:\s?\[.*?\],?)+\}", re.DOTALL)


class Source:
def __init__(self, address: str):
self._address: str = address

@staticmethod
def get_js_infos() -> tuple[dict[str, list[str]], dict[str, list[str]]]:
r = requests.get(JS_URL)
zones_js_match = ZONES_REGEX.search(r.text)
if not zones_js_match:
raise Exception(
"Zones not found probably due to a change in the websites javascript"
)
zones_js = zones_js_match.group(0)
# const Xs={zone1:[new Date(2022,7,22),new Date(2022,7,23),new Date(2022,7,24),new Date(2022,7,25),new Date(2022,7,26)],zone2:[new Date(2022,7,8),new Date(2022,7,9),new Date(2022,7,10),new Date(2022,7,11),new Date(2022,7,12)],zone3:[new Date(2022,7,1),new Date(2022,7,2),new Date(2022,7,3),new Date(2022,7,4),new Date(2022,7,5)],zone4:[new Date(2022,7,15),new Date(2022,7,16),new Date(2022,7,17),new Date(2022,7,18),new Date(2022,7,19)]};
zones_js = zones_js.replace("const Xs=", "").replace(";", "")
# replace new Date(2022,7,22) with "2022-08-22"
zones_js = re.sub(
r"new Date\((\d{4}),(\d{1,2}),(\d{1,2})\)",
lambda m: f'"{m.group(1)}-{str(int(m.group(2)) + 1).zfill(2)}-{m.group(3).zfill(2)}"',
zones_js,
)
# replace zone1 with "zone1"
zones_js = re.sub(r"zone(\d+)", r'"zone\1"', zones_js)
ZONES: dict[str, list[str]] = json.loads(zones_js)
collections_map_reg_result = COLLECTIONS_MAP_REGEX.search(r.text)
if not collections_map_reg_result:
raise Exception(
"Collections map not found probably due to a change in the websites javascript"
)
collections_map_str = (
collections_map_reg_result.group(0).replace("collections:", "").strip()
)

# repalce glass with "glass"
collections_map_str = re.sub(r"(\w+):", r'"\1":', collections_map_str)
COLLECTIONS_MAP: dict[str, list[str]] = json.loads(collections_map_str)
return ZONES, COLLECTIONS_MAP

def fetch(self) -> list[Collection]:
ZONES, COLLECTIONS_MAP = self.get_js_infos()
url = "https://maps.poriruacity.govt.nz/server/rest/services/Property/PropertyAdminExternal/MapServer/5/query"
params: dict[str, str | int] = {
"where": f"lower(address) = '{self._address.lower()}'",
"f": "pjson",
"outFields": "Address,OBJECTID,Collection_Day,Collection_Zone",
"returnGeometry": "false",
"resultRecordCount": 20,
"orderByFields": "Address",
}

r = requests.get(url, params=params)

data = r.json()
if "features" not in data or not data["features"]:
raise Exception(f"Address {self._address} not found")

feature = data["features"][0]
properties = feature["attributes"]

today = date.today()

col_day = properties["Collection_Day"]
col_zone = properties["Collection_Zone"].replace(" ", "").lower()

next_col_day = None
for i in range(1, 8, 1):
if (today + timedelta(days=i)).strftime("%A") == col_day:
next_col_day = today + timedelta(days=i)
break
if not next_col_day:
raise Exception(f"Collection day {col_day} not found")

z = ZONES[col_zone][next_col_day.weekday()]

z_date = datetime.strptime(z, "%Y-%m-%d")

next_days = (
next_col_day,
next_col_day + timedelta(days=7),
next_col_day + timedelta(days=14),
)

qs = ["glass", "rubbish", "mixed", "rubbish"]
entries: list[Collection] = []
for d in next_days:
d_time = datetime(d.year, d.month, d.day)
unix_time = int(d_time.timestamp() * 1000)
z_date_unix_time = int(z_date.timestamp() * 1000)
js_r = int(round((unix_time - z_date_unix_time) / 864e5) // 7)
js_i = abs(js_r) % 4
map_idx = qs[js_i]
relevant_types = COLLECTIONS_MAP[map_idx]
for col_type in relevant_types:
entries.append(Collection(d, col_type, ICON_MAP.get(col_type)))

return entries
35 changes: 35 additions & 0 deletions doc/source/poriruacity_govt_nz.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Porirua City

Support for schedules provided by [Porirua City](https://poriruacity.govt.nz/), serving Porirua City, Newzeeland.

## Configuration via configuration.yaml

```yaml
waste_collection_schedule:
sources:
- name: poriruacity_govt_nz
args:
address: ADDRESS

```

### Configuration Variables

**address**
*(String) (required)*
Should exactly match the address as shown in the web search result.

## Example

```yaml
waste_collection_schedule:
sources:
- name: poriruacity_govt_nz
args:
address: 6 Ration Lane, Whitby, Porirua City 5024

```

## How to get the source argument

Visit <https://poriruacity.govt.nz/services/rubbish-and-recycling/recycling-calendar/> and search for your location, then copy the exact address from the search result.
2 changes: 1 addition & 1 deletion info.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Waste collection schedules from service provider web sites are updated daily, de
| Lithuania | Kauno švara, Telšių keliai |
| Luxembourg | Esch-sur-Alzette |
| Netherlands | ACV Group, Alpen an den Rijn, Area Afval, Avalex, Avri, Bar Afvalbeheer, Circulus, Cyclus NV, Dar, Den Haag, GAD, Gemeente Almere, Gemeente Berkelland, Gemeente Cranendonck, Gemeente Hellendoorn, Gemeente Lingewaard, Gemeente Meppel, Gemeente Middelburg + Vlissingen, Gemeente Peel en Maas, Gemeente Schouwen-Duiveland, Gemeente Sudwest-Fryslan, Gemeente Venray, Gemeente Voorschoten, Gemeente Waalre, Gemeente Westland, HVC Groep, Meerlanden, Mijn Blink, PreZero, Purmerend, RAD BV, Reinis, Spaarnelanden, Twente Milieu, Waardlanden, Ximmio, ZRD, Ôffalkalinder van Noardeast-Fryslân & Dantumadiel |
| New Zealand | Auckland Council, Christchurch City Council, Dunedin District Council, Gore, Invercargill & Southland, Hamilton City Council, Horowhenua District Council, Hutt City Council, Tauranga City Council, Waipa District Council, Wellington City Council |
| New Zealand | Auckland Council, Christchurch City Council, Dunedin District Council, Gore, Invercargill & Southland, Hamilton City Council, Horowhenua District Council, Hutt City Council, Porirua City, Tauranga City Council, Waipa District Council, Wellington City Council |
| Norway | BIR (Bergensområdets Interkommunale Renovasjonsselskap), IRiS, Min Renovasjon, Movar IKS, Oslo Kommune, ReMidt Orkland muni, Sandnes Kommune, Stavanger Kommune, Trondheim |
| Poland | Bydgoszcz Pronatura, Ecoharmonogram, Gmina Miękinia, Koziegłowy/Objezierze/Oborniki, Poznań, Warsaw, Wrocław |
| Slovenia | Moji odpadki, Ljubljana |
Expand Down
Loading