From 622230410e2a74983826d6bfcfbd5f63728edba6 Mon Sep 17 00:00:00 2001 From: mampfes Date: Tue, 5 May 2020 16:42:22 +0200 Subject: [PATCH] add source for Berliner Stadtreinigungsbetriebe / bsr.de --- README.md | 1 + .../package/source/bsr_de.py | 111 ++++++++++++++++++ .../package/wizard/bsr_de.py | 72 ++++++++++++ doc/source/bsr_de.md | 41 +++++++ info.md | 13 +- 5 files changed, 232 insertions(+), 6 deletions(-) create mode 100644 custom_components/waste_collection_schedule/package/source/bsr_de.py create mode 100755 custom_components/waste_collection_schedule/package/wizard/bsr_de.py create mode 100644 doc/source/bsr_de.md diff --git a/README.md b/README.md index 7ec765ee..c2bb12a3 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Currently the following service providers are supported: - [AbfallNavi / RegioIT.de](./doc/source/regioit_de.md) - [AbfallPlus.de / Abfall.IO](./doc/source/abfall_io.md) - [AWBKoeln.de](./doc/source/awbkoeln_de.md) +- [BSR.de / Berliner Stadtreinigungsbetriebe](./doc/source/bsr_de.md) - [Generic ICS File](./doc/source/ics.md) - [Jumomind.de](./doc/source/jumomind_de.md) - [Stadtreinigung.Hamburg](./doc/source/stadtreinigung_hamburg.md) diff --git a/custom_components/waste_collection_schedule/package/source/bsr_de.py b/custom_components/waste_collection_schedule/package/source/bsr_de.py new file mode 100644 index 00000000..945ad8e8 --- /dev/null +++ b/custom_components/waste_collection_schedule/package/source/bsr_de.py @@ -0,0 +1,111 @@ +import requests +import datetime +import icalendar +from collections import OrderedDict +import urllib.parse + +from ..helpers import CollectionAppointment + +DESCRIPTION = "Source for Berliner Stadtreinigungsbetriebe" +URL = "bsr.de" +TEST_CASES = OrderedDict( + [ + ( + "Bahnhofstr., 12159 Berlin (Tempelhof-Schöneberg)", + { + "abf_strasse": "Bahnhofstr., 12159 Berlin (Tempelhof-Schöneberg)", + "abf_hausnr": 1, + }, + ), + ( + "Am Ried, 13467 Berlin (Reinickendorf)", + { + "abf_strasse": "Am Ried, 13467 Berlin (Reinickendorf)", + "abf_hausnr": "11G", + }, + ) + ] +) + + +def myquote(s): + # bsr uses strange quoting + return urllib.parse.quote(s, safe=",()") + + +class Source: + def __init__(self, abf_strasse, abf_hausnr): + self._abf_strasse = abf_strasse + self._abf_hausnr = abf_hausnr + + def fetch(self): + # get cookie + r = requests.get("https://www.bsr.de/abfuhrkalender-20520.php") + cookies = r.cookies + + # get street name only (without PLZ) + street = self._abf_strasse.split(",")[0] + + # start search using string name (without PLZ) + args = {"script": "dynamic_search", "step": 1, "q": street} + r = requests.get( + "https://www.bsr.de/abfuhrkalender_ajax.php", params=args, cookies=cookies + ) + + # retrieve house number list + args = {"script": "dynamic_search", "step": 2, "q": self._abf_strasse} + r = requests.get( + "https://www.bsr.de/abfuhrkalender_ajax.php", params=args, cookies=cookies + ) + + args = { + "abf_strasse": street, + "abf_hausnr": self._abf_hausnr, + "tab_control": "Jahr", + "abf_config_weihnachtsbaeume": "", + "abf_config_restmuell": "on", + "abf_config_biogut": "on", + "abf_config_wertstoffe": "on", + "abf_config_laubtonne": "on", +# "abf_selectmonth": "5 2020", +# "abf_datepicker": "28.04.2020", +# "listitems":7, + } + r = requests.post( + "https://www.bsr.de/abfuhrkalender_ajax.php?script=dynamic_kalender_ajax", data=args, cookies=cookies + ) + + args = { + "script": "dynamic_iCal_ajax", + "abf_strasse": self._abf_strasse, + "abf_hausnr": self._abf_hausnr, + "tab_control": "Jahr", + "abf_config_weihnachtsbaeume": "", + "abf_config_restmuell": "on", + "abf_config_biogut": "on", + "abf_config_wertstoffe": "on", + "abf_config_laubtonne": "on", +# "abf_selectmonth": "5 2020", +# "listitems":7, + } + + # create url using private url encoding + encoded = map(lambda key: f"{key}={myquote(str(args[key]))}", args.keys()) + url = "https://www.bsr.de/abfuhrkalender_ajax.php?" + "&".join(encoded) + r = requests.get(url, cookies=cookies) + + # parse ics file + calender = icalendar.Calendar.from_ical(r.text) + + entries = [] + for e in calender.walk(): + if e.name == "VEVENT": + dtstart = None + if type(e.get("dtstart").dt) == datetime.date: + dtstart = e.get("dtstart").dt + elif type(e.get("dtstart").dt) == datetime.datetime: + dtstart = e.get("dtstart").dt.date() + summary = str(e.get("summary")) + entries.append(CollectionAppointment(dtstart, summary)) + + return entries diff --git a/custom_components/waste_collection_schedule/package/wizard/bsr_de.py b/custom_components/waste_collection_schedule/package/wizard/bsr_de.py new file mode 100755 index 00000000..ad9ae86f --- /dev/null +++ b/custom_components/waste_collection_schedule/package/wizard/bsr_de.py @@ -0,0 +1,72 @@ +#!/usr/bin/python3 + +import inquirer +import requests +import json + + +def main(): + # get cookies + r = requests.get("https://www.bsr.de/abfuhrkalender-20520.php") + cookies = r.cookies + + while True: + questions = [inquirer.Text("q", message="Enter search string for street")] + answers = inquirer.prompt(questions) + + args = {"script": "dynamic_search", "step": 1, "q": answers["q"]} + + r = requests.get( + "https://www.bsr.de/abfuhrkalender_ajax.php", params=args, cookies=cookies + ) + + data = json.loads(r.text) + if ( + len(data) == 1 and data[0]["value"] == "Keine Adresse gefunden" + ): # {'value': 'Keine Adresse gefunden'} + print("Search returned no result. Please try again.") + else: + break + + street_choices = [] + for d in data: + street_choices.append(d["value"]) + + # select street + questions = [ + inquirer.List("abf_strasse", choices=street_choices, message="Select street") + ] + answers = inquirer.prompt(questions) + + # retrieve house number list + args = {"script": "dynamic_search", "step": 2, "q": answers["abf_strasse"]} + + r = requests.get( + "https://www.bsr.de/abfuhrkalender_ajax.php", params=args, cookies=cookies + ) + + # select house number + data = json.loads(r.text) + house_number_choices = [] + for d in data.values(): + house_number_choices.append((d["FullStreet"], d["HouseNo"])) + + questions = [ + inquirer.List( + "abf_hausnr", choices=house_number_choices, message="Select house number" + ) + ] + answers.update(inquirer.prompt(questions)) + + print("Copy the following statements into your configuration.yaml:\n") + print("# waste_collection_schedule source configuration") + print("waste_collection_schedule:") + print(" sources:") + print(" - name: bsr_de") + print(" args:") + for key, value in answers.items(): + print(f" {key}: {value}") + + +if __name__ == "__main__": + main() diff --git a/doc/source/bsr_de.md b/doc/source/bsr_de.md new file mode 100644 index 00000000..5ec9eaf4 --- /dev/null +++ b/doc/source/bsr_de.md @@ -0,0 +1,41 @@ +# Stadtreinigung.Hamburg + +Add support for schedules provided by `Berliner Stadtreinigungsbetriebe`. + +## Configuration via configuration.yaml + +```yaml +waste_collection_schedule: + sources: + - name: bsr_de + args: + abf_strasse: STRASSE + abf_hausnr: HAUSNR +``` + +### Configuration Variables + +**abf_strasse**
+*(string) (required)* + +**abf_hausnr**
+*(string) (required)* + +## Example + +```yaml +waste_collection_schedule: + sources: + - name: bsr_de + args: + abf_strasse: "Bahnhofstr., 12159 Berlin (Tempelhof-Schöneberg)" + abf_hausnr: 1 +``` + +## How to get the source arguments + +There is a script with an interactive command line interface which generates the required source configuration: + +[https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/custom_components/waste_collection_schedule/package/wizard/bsr_de.py](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/custom_components/waste_collection_schedule/package/wizard/bsr_de.py). + +Just run this script from a shell and answer the questions. diff --git a/info.md b/info.md index f60fa5f9..21366c63 100644 --- a/info.md +++ b/info.md @@ -28,10 +28,11 @@ Alternative details view showing the list of appointment types and their next ev Currently the following service providers are supported: -- Abfall_Kreis_Tuebingen.de -- AbfallNavi / RegioIT.de -- AbfallPlus.de / Abfall.IO -- AWBKoeln.de +- [Abfall_Kreis_Tuebingen.de]([Abfall_Kreis_Tuebingen.de) +- [AbfallNavi by RegioIT.de](RegioIT.de) +- [AbfallPlus.de](AbfallPlus.de) / [Abfall.IO](Abfall.IO) +- [AWBKoeln.de](AWBKoeln.de) +- [BSR.de / Berliner Stadtreinigungsbetriebe](bsr.de) - Generic ICS File -- Jumomind.de -- Stadtreinigung.Hamburg +- [Jumomind.de](Jumomind.de) +- [Stadtreinigung.Hamburg](Stadtreinigung.Hamburg)