mirror of
https://github.com/sascha-hemi/hacs_waste_collection_schedule.git
synced 2026-03-21 04:06:03 +01:00
Add new source AWM München (#1768)
* Add new source AWM München * fstring + typehint + comment fix --------- Co-authored-by: 5ila5 <5ila5@users.noreply.github.com>
This commit is contained in:
@@ -563,7 +563,6 @@ Waste collection schedules in the following formats and countries are supported.
|
|||||||
- [Abfallwirtschaftsbetrieb Landkreis Aurich](/doc/source/c_trace_de.md) / mkw-grossefehn.de
|
- [Abfallwirtschaftsbetrieb Landkreis Aurich](/doc/source/c_trace_de.md) / mkw-grossefehn.de
|
||||||
- [Abfallwirtschaftsbetrieb Landkreis Karlsruhe](/doc/ics/awb_landkreis_karlsruhe_de.md) / awb-landkreis-karlsruhe.de
|
- [Abfallwirtschaftsbetrieb Landkreis Karlsruhe](/doc/ics/awb_landkreis_karlsruhe_de.md) / awb-landkreis-karlsruhe.de
|
||||||
- [Abfallwirtschaftsbetrieb LK Mainz-Bingen](/doc/source/awb_mainz_bingen_de.md) / awb-mainz-bingen.de
|
- [Abfallwirtschaftsbetrieb LK Mainz-Bingen](/doc/source/awb_mainz_bingen_de.md) / awb-mainz-bingen.de
|
||||||
- [Abfallwirtschaftsbetrieb München](/doc/ics/awm_muenchen_de.md) / awm-muenchen.de
|
|
||||||
- [Abfallwirtschaftsbetriebe Münster](/doc/source/muellmax_de.md) / stadt-muenster.de
|
- [Abfallwirtschaftsbetriebe Münster](/doc/source/muellmax_de.md) / stadt-muenster.de
|
||||||
- [Abfallwirtschaftsgesellschaft Landkreis Schaumburg](/doc/ics/aws_shg_de.md) / aws-shg.de
|
- [Abfallwirtschaftsgesellschaft Landkreis Schaumburg](/doc/ics/aws_shg_de.md) / aws-shg.de
|
||||||
- [Abfallwirtschaftsverband Kreis Groß-Gerau](/doc/source/c_trace_de.md) / awv-gg.de
|
- [Abfallwirtschaftsverband Kreis Groß-Gerau](/doc/source/c_trace_de.md) / awv-gg.de
|
||||||
@@ -602,6 +601,7 @@ Waste collection schedules in the following formats and countries are supported.
|
|||||||
- [AWISTA Düsseldorf](/doc/source/muellmax_de.md) / awista.de
|
- [AWISTA Düsseldorf](/doc/source/muellmax_de.md) / awista.de
|
||||||
- [Awista Starnberg](/doc/ics/awista_starnberg_de.md) / awista-starnberg.de
|
- [Awista Starnberg](/doc/ics/awista_starnberg_de.md) / awista-starnberg.de
|
||||||
- [AWL Neuss](/doc/source/awlneuss_de.md) / buergerportal.awl-neuss.de
|
- [AWL Neuss](/doc/source/awlneuss_de.md) / buergerportal.awl-neuss.de
|
||||||
|
- [AWM München](/doc/source/awm_muenchen_de.md) / awm-muenchen.de
|
||||||
- [Bad Arolsen (MyMuell App)](/doc/source/jumomind_de.md) / mymuell.de
|
- [Bad Arolsen (MyMuell App)](/doc/source/jumomind_de.md) / mymuell.de
|
||||||
- [Bad Homburg vdH](/doc/source/jumomind_de.md) / bad-homburg.de
|
- [Bad Homburg vdH](/doc/source/jumomind_de.md) / bad-homburg.de
|
||||||
- [Bad Kissingen](/doc/source/app_abfallplus_de.md) / Abfall+ App: abfallappbk
|
- [Bad Kissingen](/doc/source/app_abfallplus_de.md) / Abfall+ App: abfallappbk
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
import urllib.parse
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from waste_collection_schedule import Collection # type: ignore[attr-defined]
|
||||||
|
from waste_collection_schedule.service.ICS import ICS
|
||||||
|
|
||||||
|
TITLE = "AWM München"
|
||||||
|
DESCRIPTION = "Source for AWM München."
|
||||||
|
URL = "https://www.awm-muenchen.de"
|
||||||
|
TEST_CASES = {
|
||||||
|
"Waltenbergerstr. 1": {
|
||||||
|
"street": "Waltenbergerstr.",
|
||||||
|
"house_number": "1",
|
||||||
|
},
|
||||||
|
"Geretsrieder Str. 10a": {
|
||||||
|
"street": "Geretsrieder Str.",
|
||||||
|
"house_number": "10a",
|
||||||
|
},
|
||||||
|
"Neureutherstr. 8": {
|
||||||
|
"street": "Neureutherstr.",
|
||||||
|
"house_number": "8",
|
||||||
|
"r_collect_cycle": "1/2;G",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ICON_MAP = {
|
||||||
|
"Restmülltonne": "mdi:delete",
|
||||||
|
"Biotonne": "mdi:leaf",
|
||||||
|
"Papiertonne": "mdi:newspaper",
|
||||||
|
"Wertstofftonne": "mdi:recycle",
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_URL = "https://www.awm-muenchen.de"
|
||||||
|
|
||||||
|
|
||||||
|
# Parser for HTML input (hidden) text
|
||||||
|
class HiddenInputParser(HTMLParser):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._args = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def args(self):
|
||||||
|
return self._args
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
if tag == "input":
|
||||||
|
d = dict(attrs)
|
||||||
|
if str(d["type"]).lower() == "hidden":
|
||||||
|
self._args[d["name"]] = d["value"] if "value" in d else ""
|
||||||
|
|
||||||
|
|
||||||
|
class Source:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
street: str,
|
||||||
|
house_number: str,
|
||||||
|
r_collect_cycle="",
|
||||||
|
b_collect_cycle="",
|
||||||
|
p_collect_cycle="",
|
||||||
|
):
|
||||||
|
self._street = street
|
||||||
|
self._hnr = house_number
|
||||||
|
self._ics = ICS()
|
||||||
|
self._r_collect_cycle = r_collect_cycle
|
||||||
|
self._b_collect_cycle = b_collect_cycle
|
||||||
|
self._p_collect_cycle = p_collect_cycle
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
s = requests.session()
|
||||||
|
|
||||||
|
# special request header is required, server backend checks for Origin
|
||||||
|
headers = {
|
||||||
|
"Origin": "https://www.awm-muenchen.de",
|
||||||
|
}
|
||||||
|
s.headers.update(headers)
|
||||||
|
|
||||||
|
# request default page
|
||||||
|
r = s.get(f"{BASE_URL}/entsorgen/abfuhrkalender")
|
||||||
|
r.raise_for_status()
|
||||||
|
r.encoding = "utf-8"
|
||||||
|
|
||||||
|
step1_action_url, args = self._get_html_form_infos(r.text, "abfuhrkalender")
|
||||||
|
|
||||||
|
# add the address information
|
||||||
|
args["tx_awmabfuhrkalender_abfuhrkalender[strasse]"] = self._street
|
||||||
|
args["tx_awmabfuhrkalender_abfuhrkalender[hausnummer]"] = self._hnr
|
||||||
|
args["tx_awmabfuhrkalender_abfuhrkalender[section]"] = "address"
|
||||||
|
args["tx_awmabfuhrkalender_abfuhrkalender[submitAbfuhrkalender]"] = "true"
|
||||||
|
|
||||||
|
# ready for step 1 - we post the address
|
||||||
|
r = s.post(
|
||||||
|
step1_action_url,
|
||||||
|
data=args,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
# result is the result page or the collection cycle select page
|
||||||
|
ics_action_url = ""
|
||||||
|
page_soup = BeautifulSoup(r.text, "html.parser")
|
||||||
|
if download_link := page_soup.find("a", {"class": "downloadics"}):
|
||||||
|
ics_action_url = download_link.get("href")
|
||||||
|
else:
|
||||||
|
action_url, args = self._get_html_form_infos(r.text, "abfuhrkalender")
|
||||||
|
|
||||||
|
error_message = ""
|
||||||
|
|
||||||
|
for key in ("B", "P", "R"):
|
||||||
|
if (
|
||||||
|
f"tx_awmabfuhrkalender_abfuhrkalender[leerungszyklus][{key}]"
|
||||||
|
not in args
|
||||||
|
):
|
||||||
|
if self.__getattribute__(f"_{key.lower()}_collect_cycle") == "":
|
||||||
|
cycle_options = {}
|
||||||
|
cycle_options = page_soup.find(
|
||||||
|
"form", id="abfuhrkalender"
|
||||||
|
).find_all("option")
|
||||||
|
|
||||||
|
error_message += f"Optional parameter {key.lower()}_collect_cycle required. Possible values: "
|
||||||
|
for option in cycle_options:
|
||||||
|
error_message += f"{option.get('value')} ({option.text}) "
|
||||||
|
else:
|
||||||
|
args[
|
||||||
|
f"tx_awmabfuhrkalender_abfuhrkalender[leerungszyklus][{key}]"
|
||||||
|
] = self.__getattribute__(f"_{key.lower()}_collect_cycle")
|
||||||
|
|
||||||
|
if error_message:
|
||||||
|
raise ValueError(error_message)
|
||||||
|
|
||||||
|
r = s.post(
|
||||||
|
action_url,
|
||||||
|
data=args,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
page_soup = BeautifulSoup(r.text, "html.parser")
|
||||||
|
if download_link := page_soup.find("a", {"class": "downloadics"}):
|
||||||
|
ics_action_url = download_link.get("href")
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown error getting ics link with cycle options.")
|
||||||
|
|
||||||
|
# Download the ics.file
|
||||||
|
r = s.get(f"{URL}{urllib.parse.unquote(ics_action_url)}")
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
dates = self._ics.convert(r.text)
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for d in dates:
|
||||||
|
bin_type = d[1].split(",")[0].strip()
|
||||||
|
|
||||||
|
entries.append(Collection(d[0], bin_type, ICON_MAP.get(bin_type)))
|
||||||
|
|
||||||
|
return entries
|
||||||
|
|
||||||
|
def _get_html_form_infos(self, html: str, form_name: str) -> Tuple[str, dict]:
|
||||||
|
"""Return a tuple with form action url and hidden form fields."""
|
||||||
|
# collect the url where we post to
|
||||||
|
page_soup = BeautifulSoup(html, "html.parser")
|
||||||
|
form_soup = page_soup.find("form", id=form_name)
|
||||||
|
action_url = f"{URL}{urllib.parse.unquote(form_soup.get('action'))}"
|
||||||
|
|
||||||
|
# collect the hidden input fields
|
||||||
|
parser = HiddenInputParser()
|
||||||
|
parser.feed(page_soup.find("form", id=form_name).decode_contents())
|
||||||
|
|
||||||
|
return action_url, parser.args
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# Abfallwirtschaftsbetrieb München
|
|
||||||
|
|
||||||
Abfallwirtschaftsbetrieb München is supported by the generic [ICS](/doc/source/ics.md) source. For all available configuration options, please refer to the source description.
|
|
||||||
|
|
||||||
|
|
||||||
## How to get the configuration arguments
|
|
||||||
|
|
||||||
- Goto <https://www.awm-muenchen.de/entsorgen/abfuhrkalender> and select your location.
|
|
||||||
- Right-click on `Download ICS-Datei 20xx für Ihren Kalender` link and copy link address.
|
|
||||||
- Replace the `url` in the example configuration with this link.
|
|
||||||
- Replace the year in the url with `{%Y}`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Adolaweg 1
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
waste_collection_schedule:
|
|
||||||
sources:
|
|
||||||
- name: ics
|
|
||||||
args:
|
|
||||||
regex: (.*), .*
|
|
||||||
url: https://www.awm-muenchen.de/entsorgen/abfuhrkalender?tx_awmabfuhrkalender_abfuhrkalender%5Bhausnummer%5D=1&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BB%5D=1%2F2%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BP%5D=1%2F2%3BU&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BR%5D=001%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bsection%5D=ics&tx_awmabfuhrkalender_abfuhrkalender%5Bsinglestandplatz%5D=false&tx_awmabfuhrkalender_abfuhrkalender%5Bstandplatzwahl%5D=true&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bbio%5D=70082516&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bpapier%5D=70082516&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Brestmuell%5D=70082516&tx_awmabfuhrkalender_abfuhrkalender%5Bstrasse%5D=Adaloweg&tx_awmabfuhrkalender_abfuhrkalender%5Byear%5D={%Y}&cHash=e346bec0e7fdb173ae2d0e8650ecd980
|
|
||||||
```
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
title: Abfallwirtschaftsbetrieb München
|
|
||||||
url: https://www.awm-muenchen.de
|
|
||||||
howto: |
|
|
||||||
- Goto <https://www.awm-muenchen.de/entsorgen/abfuhrkalender> and select your location.
|
|
||||||
- Right-click on `Download ICS-Datei 20xx für Ihren Kalender` link and copy link address.
|
|
||||||
- Replace the `url` in the example configuration with this link.
|
|
||||||
- Replace the year in the url with `{%Y}`.
|
|
||||||
test_cases:
|
|
||||||
Adolaweg 1:
|
|
||||||
url: "https://www.awm-muenchen.de/entsorgen/abfuhrkalender?tx_awmabfuhrkalender_abfuhrkalender%5Bhausnummer%5D=1&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BB%5D=1%2F2%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BP%5D=1%2F2%3BU&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BR%5D=001%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bsection%5D=ics&tx_awmabfuhrkalender_abfuhrkalender%5Bsinglestandplatz%5D=false&tx_awmabfuhrkalender_abfuhrkalender%5Bstandplatzwahl%5D=true&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bbio%5D=70082516&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bpapier%5D=70082516&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Brestmuell%5D=70082516&tx_awmabfuhrkalender_abfuhrkalender%5Bstrasse%5D=Adaloweg&tx_awmabfuhrkalender_abfuhrkalender%5Byear%5D={%Y}&cHash=e346bec0e7fdb173ae2d0e8650ecd980"
|
|
||||||
regex: "(.*), .*"
|
|
||||||
85
doc/source/awm_muenchen_de.md
Normal file
85
doc/source/awm_muenchen_de.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# Abfallwirtschaftsbetrieb München
|
||||||
|
|
||||||
|
Support for schedules provided by [Abfallwirtschaftsbetrieb München](https://www.awm-muenchen.de/), Germany.
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration via configuration.yaml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
waste_collection_schedule:
|
||||||
|
sources:
|
||||||
|
- name: awm_muenchen_de
|
||||||
|
args:
|
||||||
|
street: STREET
|
||||||
|
house_number: HNR
|
||||||
|
b_collect_cycle: COLLECTION CYCLE ID
|
||||||
|
p_collect_cycle: COLLECTION CYCLE ID
|
||||||
|
r_collect_cycle: COLLECTION CYCLE ID
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Variables
|
||||||
|
|
||||||
|
**street**
|
||||||
|
*(string) (required)*
|
||||||
|
|
||||||
|
**house_number**
|
||||||
|
*(string) (required)*
|
||||||
|
|
||||||
|
**b_collect_cycle**
|
||||||
|
*(string) (optional) (default: "")*
|
||||||
|
|
||||||
|
**p_collect_cycle**
|
||||||
|
*(string) (optional) (default: "")*
|
||||||
|
|
||||||
|
**r_collect_cycle**
|
||||||
|
*(string) (optional) (default: "")*
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
waste_collection_schedule:
|
||||||
|
sources:
|
||||||
|
- name: awm_muenchen_de
|
||||||
|
args:
|
||||||
|
street: "Waltenbergerstr."
|
||||||
|
house_number: "1"
|
||||||
|
- name: awm_muenchen_de
|
||||||
|
args:
|
||||||
|
street: "Neureutherstr."
|
||||||
|
house_number: "8"
|
||||||
|
r_collect_cycle: "1/2;G"
|
||||||
|
```
|
||||||
|
|
||||||
|
Some addresses have different bin collection cycles (ex: weekly, bi-weekly). For these addresses the optional parameters are required.
|
||||||
|
|
||||||
|
## How to get the optional configuration arguments
|
||||||
|
|
||||||
|
- Setup the component without the optional parameter and restart Home Assistant
|
||||||
|
- Check the Home Assistant log for entries from this component.
|
||||||
|
- The available options are listed in the error message.
|
||||||
|
- Adjust the configuration and restart Home Assistant.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Waltenbergerstr. 1
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
waste_collection_schedule:
|
||||||
|
sources:
|
||||||
|
- name: awm_muenchen_de
|
||||||
|
args:
|
||||||
|
street: "Waltenbergerstr."
|
||||||
|
house_number: "1"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Neureutherstr. 8 with an collection cycle option
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
waste_collection_schedule:
|
||||||
|
sources:
|
||||||
|
- name: awm_muenchen_de
|
||||||
|
args:
|
||||||
|
street: "Neureutherstr."
|
||||||
|
house_number: "8"
|
||||||
|
r_collect_cycle: "1/2;G"
|
||||||
|
```
|
||||||
@@ -159,7 +159,6 @@ This source has been successfully tested with the following service providers:
|
|||||||
- [Abfallwirtschaft Sonneberg](/doc/ics/abfallwirtschaft_sonneberg_de.md) / abfallwirtschaft-sonneberg.de
|
- [Abfallwirtschaft Sonneberg](/doc/ics/abfallwirtschaft_sonneberg_de.md) / abfallwirtschaft-sonneberg.de
|
||||||
- [Abfallwirtschaftsbetrieb Ilm-Kreis](/doc/ics/ilm_kreis_de.md) / ilm-kreis.de
|
- [Abfallwirtschaftsbetrieb Ilm-Kreis](/doc/ics/ilm_kreis_de.md) / ilm-kreis.de
|
||||||
- [Abfallwirtschaftsbetrieb Landkreis Karlsruhe](/doc/ics/awb_landkreis_karlsruhe_de.md) / awb-landkreis-karlsruhe.de
|
- [Abfallwirtschaftsbetrieb Landkreis Karlsruhe](/doc/ics/awb_landkreis_karlsruhe_de.md) / awb-landkreis-karlsruhe.de
|
||||||
- [Abfallwirtschaftsbetrieb München](/doc/ics/awm_muenchen_de.md) / awm-muenchen.de
|
|
||||||
- [Abfallwirtschaftsgesellschaft Landkreis Schaumburg](/doc/ics/aws_shg_de.md) / aws-shg.de
|
- [Abfallwirtschaftsgesellschaft Landkreis Schaumburg](/doc/ics/aws_shg_de.md) / aws-shg.de
|
||||||
- [ALBA Braunschweig](/doc/ics/alba_bs_de.md) / alba-bs.de
|
- [ALBA Braunschweig](/doc/ics/alba_bs_de.md) / alba-bs.de
|
||||||
- [Altmarkkreis Salzwedel](/doc/ics/abfall_app_net.md) / altmarkkreis-salzwedel.de
|
- [Altmarkkreis Salzwedel](/doc/ics/abfall_app_net.md) / altmarkkreis-salzwedel.de
|
||||||
|
|||||||
Reference in New Issue
Block a user