Skip to content

Commit

Permalink
Add edpevent and merge SSAM and Uppsalavatten (mampfes#2281)
Browse files Browse the repository at this point in the history
* Add edpevent and merge SSAM and Uppsalavatten

This follows a discussion on pull request mampfes#2261

* Revert "Add edpevent and merge SSAM and Uppsalavatten"

This reverts commit 4e3b88e.

* Add support for doc generator for edpevent multiple sources

* Add edpevent source

This is a multi source for all that use edpevent.
As of this commit that includes:
- Boden
- Uppsala Vatten
- SSAM
- Skellefteå

* Deprecate SSAM and Uppsala Vatten

* reformatting

---------

Co-authored-by: 5ila5 <[email protected]>
  • Loading branch information
morotsgurka and 5ila5 authored Jul 17, 2024
1 parent 4b7ef1e commit 8a5a7cb
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 177 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,8 @@ Waste collection schedules in the following formats and countries are supported.
<summary>Sweden</summary>

- [Affärsverken](/doc/source/affarsverken_se.md) / affarsverken.se
- [Boden](/doc/source/edpevent_se.md) / boden.se
- [EDPEvent - Multi Source](/doc/source/edpevent_se.md) / edpevent.se
- [Gästrike Återvinnare](/doc/source/gastrikeatervinnare_se.md) / gastrikeatervinnare.se
- [Jönköping - June Avfall & Miljö](/doc/source/juneavfall_se.md) / juneavfall.se
- [Landskrona - Svalövs Renhållning](/doc/source/lsr_nu.md) / lsr.nu
Expand All @@ -1214,9 +1216,12 @@ Waste collection schedules in the following formats and countries are supported.
- [Region Gotland](/doc/source/gotland_se.md) / gotland.se
- [Ronneby Miljöteknik](/doc/source/miljoteknik_se.md) / fyrfackronneby.se
- [Samverkan Återvinning Miljö (SÅM)](/doc/source/samiljo_se.md) / samiljo.se
- [Skellefteå](/doc/source/edpevent_se.md) / skelleftea.se
- [SRV Återvinning](/doc/source/srvatervinning_se.md) / srvatervinning.se
- [SSAM](/doc/source/ssam_se.md) / ssam.se
- [SSAM Södra Smalånds Avfall & Miljö](/doc/source/edpevent_se.md) / ssam.se
- [Sysav Sophämntning](/doc/source/sysav_se.md) / sysav.se
- [Uppsala Vatten](/doc/source/edpevent_se.md) / uppsalavatten.se
- [Uppsala Vatten och Avfall AB](/doc/source/uppsalavatten_se.md) / uppsalavatten.se
- [VA Syd Sophämntning](/doc/source/vasyd_se.md) / vasyd.se
- [VIVAB Sophämtning](/doc/source/vivab_se.md) / vivab.se
Expand Down
33 changes: 33 additions & 0 deletions custom_components/waste_collection_schedule/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -6378,6 +6378,18 @@
"module": "affarsverken_se",
"default_params": {}
},
{
"title": "Boden",
"module": "edpevent_se",
"default_params": {
"service_provider": "boden"
}
},
{
"title": "EDPEvent - Multi Source",
"module": "edpevent_se",
"default_params": {}
},
{
"title": "G\u00e4strike \u00c5tervinnare",
"module": "gastrikeatervinnare_se",
Expand Down Expand Up @@ -6433,6 +6445,13 @@
"module": "samiljo_se",
"default_params": {}
},
{
"title": "Skellefte\u00e5",
"module": "edpevent_se",
"default_params": {
"service_provider": "skelleftea"
}
},
{
"title": "SRV \u00c5tervinning",
"module": "srvatervinning_se",
Expand All @@ -6443,11 +6462,25 @@
"module": "ssam_se",
"default_params": {}
},
{
"title": "SSAM S\u00f6dra Smal\u00e5nds Avfall & Milj\u00f6",
"module": "edpevent_se",
"default_params": {
"service_provider": "ssam"
}
},
{
"title": "Sysav Soph\u00e4mntning",
"module": "sysav_se",
"default_params": {}
},
{
"title": "Uppsala Vatten",
"module": "edpevent_se",
"default_params": {
"service_provider": "uppsalavatten"
}
},
{
"title": "Uppsala Vatten och Avfall AB",
"module": "uppsalavatten_se",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@
"postCode": "Post Code",
"zipCode": "Zip Code",
"garden_cutomer": "Garden Cutomer",
"app": "App"
"app": "App",
"service_provider": "Service Provider"
},
"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."
Expand Down Expand Up @@ -508,7 +509,8 @@
"postCode": "Post Code",
"zipCode": "Zip Code",
"garden_cutomer": "Garden Cutomer",
"app": "App"
"app": "App",
"service_provider": "Service Provider"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import json
import logging
from datetime import datetime

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

TITLE = "EDPEvent - Multi Source"
DESCRIPTION = "Source for all EDPEvent waste collection sources. This included multiple municipalities in Sweden."
URL = "https://www.edpevent.se"
TEST_CASES = {
"Boden - Bodens Kommun": {
"street_address": "KYRKGATAN 24",
"service_provider": "boden",
},
"Boden - Gymnasiet": {
"street_address": "IDROTTSGATAN 4",
"url": "https://edpmobile.boden.se/FutureWeb/SimpleWastePickup",
},
"Uppsalavatten - Test1": {
"street_address": "SADELVÄGEN 1",
"url": "https://futureweb.uppsalavatten.se/Uppsala/FutureWeb/SimpleWastePickup",
},
"Uppsalavatten - Test2": {
"street_address": "BJÖRKLINGE-GRÄNBY 33",
"service_provider": "uppsalavatten",
},
"Uppsalavatten - Test3": {
"street_address": "BJÖRKLINGE-GRÄNBY 20",
"service_provider": "uppsalavatten",
},
"SSAM - Home": {
"street_address": "Asteroidvägen 1, Växjö",
"service_provider": "ssam",
},
"SSAM - Slambrunn": {
"street_address": "Svanebro Ormesberga, Ör",
"service_provider": "ssam",
},
"Skelleftea - Test1": {
"street_address": "Frögatan 76 -150",
"service_provider": "skelleftea",
},
}

COUNTRY = "se"
_LOGGER = logging.getLogger(__name__)

# This maps the icon based on the waste type
ICON_MAP = {
"Brännbart": "mdi:trash-can",
"Matavfall tätt": "mdi:food",
"Deponi": "mdi:recycle",
"Restavfall": "mdi:trash-can",
"Matavfall": "mdi:food-apple",
"Slam": "",
"Trädgårdsavfall": "mdi:leaf",
}

# This can be used to rename the waste types to something more user friendly
WASTE_TYPE_REPLACEMENTS = {
"FNI1": "Kärl 1",
"FNI2": "Kärl 2",
}

MONTH_MAP = {
"Jan": 1,
"Feb": 2,
"Mar": 3,
"Apr": 4,
"Maj": 5,
"Jun": 6,
"Jul": 7,
"Aug": 8,
"Sep": 9,
"Okt": 10,
"Nov": 11,
"Dec": 12,
}

SERVICE_PROVIDERS = {
"skelleftea": {
"title": "Skellefteå",
"url": "https://skelleftea.se",
"api_url": "https://wwwtk2.skelleftea.se/FutureWeb/SimpleWastePickup",
},
"boden": {
"title": "Boden",
"url": "https://boden.se",
"api_url": "https://edpmobile.boden.se/FutureWeb/SimpleWastePickup",
},
"ssam": {
"title": "SSAM Södra Smalånds Avfall & Miljö",
"url": "https://ssam.se",
"api_url": "https://edpfuture.ssam.se/FutureWeb/SimpleWastePickup",
},
"uppsalavatten": {
"title": "Uppsala Vatten",
"url": "https://uppsalavatten.se",
"api_url": "https://futureweb.uppsalavatten.se/Uppsala/FutureWeb/SimpleWastePickup",
},
}

EXTRA_INFO = [
{
"title": data["title"],
"url": data["url"],
"default_params": {"service_provider": provider},
}
for provider, data in SERVICE_PROVIDERS.items()
]


class Source:
def __init__(
self,
street_address: str,
service_provider: str | None = None,
url: str | None = None,
):
self._street_address = street_address
self._url = url
# Check if the user provided a url
if url is None:
# Raise an exception if the user did not provide a service provider (or url)
if service_provider is None:
raise ValueError("You must provide either a service provider or a url")
# Get the api url using the service provider
self._url = SERVICE_PROVIDERS.get(service_provider.lower(), {}).get(
"api_url"
)
if self._url is None:
raise ValueError(
f"Unknown service provider: {service_provider}, use one of {[x for x in SERVICE_PROVIDERS.keys()]}"
)
# Remove trailing slash from the url if present
if self._url.endswith("/"):
self._url = self._url[:-1]

def fetch(self):
params = {"searchText": self._street_address}
# Use the street address to find the full street address with the building ID
searchUrl = self._url + "/SearchAdress"
# Search for the address
response = requests.post(searchUrl, params=params, timeout=30)

address_data = json.loads(response.text)
address = None
# Make sure the response is valid and contains data
if address_data and len(address_data) > 0:
# Check if the request was successful
if address_data["Succeeded"]:
# The request can be successful but still not return any buildings at the specified address
if len(address_data["Buildings"]) > 0:
address = address_data["Buildings"][0]
else:
raise Exception(
f"No returned building address for: {self._street_address}"
)
else:
raise Exception(
f"The server failed to fetch the building data for: {self._street_address}"
)

# Raise exception if all the above checks failed
if not address:
raise Exception(
f"Failed to find building address for: {self._street_address}"
)

# Use the address we got to get the waste collection schedule
params = {"address": address}
getUrl = self._url + "/GetWastePickupSchedule"
# Get the waste collection schedule
response = requests.get(getUrl, params=params, timeout=30)

data = json.loads(response.text)

entries = []
for item in data["RhServices"]:
waste_type = ""
next_pickup = item["NextWastePickup"]
try:
if "v" in next_pickup:
date_parts = next_pickup.split()
month = MONTH_MAP[date_parts[1]]
date_joined = "-".join([date_parts[0], str(month), date_parts[2]])
next_pickup_date = datetime.strptime(
date_joined, "v%W-%m-%Y"
).date()
elif not next_pickup:
continue
else:
next_pickup_date = datetime.strptime(next_pickup, "%Y-%m-%d").date()
except ValueError:
# In some cases the date is just a month, so parse this as the
# first of the month to at least get something close
try:
next_pickup_date = datetime.strptime(next_pickup, "%b %Y").date()
except ValueError as month_parse_error:
_LOGGER.warning(
"Failed to parse date %s, %s,",
next_pickup,
str(month_parse_error),
)
continue

waste_type_prefix = item["WasteType"]
if item["WasteType"] in WASTE_TYPE_REPLACEMENTS:
waste_type_prefix = WASTE_TYPE_REPLACEMENTS[item["WasteType"]]
waste_type = (
waste_type_prefix
+ ", "
+ item["BinType"]["ContainerType"]
+ " "
+ str(item["BinType"]["Size"])
+ item["BinType"]["Unit"]
)
# Get the icon for the waste type, default to help icon if not found
icon = ICON_MAP.get(item["WasteType"], "mdi:help")

found = found = any(
x.date == next_pickup_date and x.type == waste_type for x in entries
)
if not found:
entries.append(
Collection(date=next_pickup_date, t=waste_type, icon=icon)
)
return entries
Loading

0 comments on commit 8a5a7cb

Please sign in to comment.