We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ZAS Abfallwirtschaft
I'm trying to integrate the ZAS Abfallwirtschaft ICS. But i can't seem to get it to work.
Is there anything i need to configure specifically?

The Website is
https://www.za-sws.de/abfallkalender.cfm

And the generated ICS is
https://online-portal.za-sws.de/WasteManagementSuedwestsachsen/WasteManagementServiceServlet?ApplicationName=Calendar&SubmitAction=sync&StandortID=52554001&AboID=33626&Fra=R;P;B;W;L;C;S
_(The adress used is a random one, not mine of course)_

My configuration looks like this:

```
waste_collection_schedule:
  sources:
    - name: ics
      args:
        url: https://online-portal.za-sws.de/WasteManagementSuedwestsachsen/WasteManagementServiceServlet?ApplicationName=Calendar&SubmitAction=sync&StandortID=52554001&AboID=33626&Fra=R;P;B;W;L;C;S
        customize:
        - type: Restmuelltonne 02-woechentl.
          alias: Restmüll
          icon: mdi:trash-can
        - type: Biotonnenwaesche
          alias: Biotonnenwäsche
          show: false
          icon: mdi:flower-outline
        - type: Papiertonne 04-woechentl.
          alias: Papiertonne
          icon: mdi:trash-can-outline
        - type: LVP
          alias: Gelbe Tonne
          icon: mdi:recycle
```

Thanks in advance.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py`
Content:
```
1 import datetime
2 import logging
3 from pathlib import Path
4 
5 import requests
6 from waste_collection_schedule import Collection  # type: ignore[attr-defined]
7 from waste_collection_schedule.service.ICS import ICS
8 from waste_collection_schedule.service.ICS_v1 import ICS_v1
9 
10 TITLE = "ICS"
11 DESCRIPTION = "Source for ICS based schedules."
12 URL = None
13 TEST_CASES = {
14     "Dortmund, Dudenstr. 5": {
15         "url": "https://www.edg.de/ical/kalender.ics?Strasse=Dudenstr.&Hausnummer=5&Erinnerung=-1&Abfallart=1,2,3,4"
16     },
17     "Leipzig, Sandgrubenweg 27": {
18         "url": "https://stadtreinigung-leipzig.de/wir-kommen-zu-ihnen/abfallkalender/ical.ics?position_nos=38296&name=Sandgrubenweg%2027"
19     },
20     "Ludwigsburg": {
21         "url": "https://www.avl-ludwigsburg.de/fileadmin/Files/Abfallkalender/ICS/Privat/Privat_{%Y}_Ossweil.ics"
22     },
23     "Esslingen, Bahnhof": {
24         "url": "https://api.abfall.io/?kh=DaA02103019b46345f1998698563DaAd&t=ics&s=1a862df26f6943997cef90233877a4fe"
25     },
26     "Test File": {
27         # Path is used here to allow to call the Source from any location.
28         # This is not required in a yaml configuration!
29         "file": str(Path(__file__).resolve().parents[1].joinpath("test/test.ics"))
30     },
31     "Test File (recurring)": {
32         # Path is used here to allow to call the Source from any location.
33         # This is not required in a yaml configuration!
34         "file": str(Path(__file__).resolve().parents[1].joinpath("test/recurring.ics"))
35     },
36     "München, Bahnstr. 11": {
37         "url": "https://www.awm-muenchen.de/entsorgen/abfuhrkalender?tx_awmabfuhrkalender_abfuhrkalender%5Bhausnummer%5D=11&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BB%5D=1%2F2%3BU&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BP%5D=1%2F2%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BR%5D=001%3BU&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=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bpapier%5D=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Brestmuell%5D=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstrasse%5D=bahnstr.&tx_awmabfuhrkalender_abfuhrkalender%5Byear%5D={%Y}",
38         "version": 1,
39     },
40     "Buxtehude, Am Berg": {
41         "url": "https://abfall.landkreis-stade.de/api_v2/collection_dates/1/ort/10/strasse/90/hausnummern/1/abfallarten/R02-R04-B02-D04-D12-P04-R12-R14-W0-R22-R24-R31/kalender.ics"
42     },
43     #    "Hausmüllinfo: ASR Chemnitz": {
44     #        "url": "https://asc.hausmuell.info/ics/ics.php",
45     #        "method": "POST",
46     #        "params": {
47     #            "hidden_id_egebiet": 439087,
48     #            "input_ort": "Chemnitz",
49     #            "input_str": "Straße der Nationen",
50     #            "input_hnr": 2,
51     #            "hidden_send_btn": "ics",
52     #            # "hiddenYear": 2021,
53     #            "hidden_id_ort": 10,
54     #            "hidden_id_ortsteil": 0,
55     #            "hidden_id_str": 17814,
56     #            "hidden_id_hnr": 5538100,
57     #            "hidden_kalenderart": "privat",
58     #            "showBinsBio": "on",
59     #            "showBinsRest": "on",
60     #            "showBinsRest_rc": "on",
61     #            "showBinsPapier": "on",
62     #            "showBinsOrganic": "on",
63     #            "showBinsXmas": "on",
64     #            "showBinsDsd": "on",
65     #            "showBinsProb": "on",
66     #        },
67     #        "year_field": "hiddenYear",
68     #    },
69     "Abfall Zollernalbkreis, Ebingen": {
70         "url": "https://www.abfallkalender-zak.de",
71         "params": {
72             "city": "2,3,4",
73             "street": "3",
74             "types[]": [
75                 "restmuell",
76                 "gelbersack",
77                 "papiertonne",
78                 "biomuell",
79                 "gruenabfall",
80                 "schadstoffsammlung",
81                 "altpapiersammlung",
82                 "schrottsammlung",
83                 "weihnachtsbaeume",
84                 "elektrosammlung",
85             ],
86             "go_ics": "Download",
87         },
88         "year_field": "year",
89     },
90     "Detmold": {
91         "url": "https://abfuhrkalender.detmold.de/icsmaker.php",
92         "method": "GET",
93         "params": {"strid": 338},
94         "year_field": "year",
95     },
96     "EAW Rheingau Taunus": {
97         "url": "https://www.eaw-rheingau-taunus.de/abfallkalender/calendar.ics?streetid=1429",
98         "split_at": ",",
99     },
100     "Recollect, Ottawa": {
101         "url": "https://recollect.a.ssl.fastly.net/api/places/BCCDF30E-578B-11E4-AD38-5839C200407A/services/208/events.en.ics",
102         "split_at": "\\, [and ]*",
103     },
104     "Frankfurt am Main, Achenbachstrasse 3": {
105         "url": "https://www.fes-frankfurt.de/abfallkalender/QWNoZW5iYWNoc3RyLnwzfDYwNTk2.ics"
106     },
107     "Erlensee, Am Haspel": {
108         "url": "https://sperrmuell.erlensee.de/?type=reminder",
109         "method": "POST",
110         "params": {
111             "street": 8,
112             "eventType[]": [27, 23, 19, 20, 21, 24, 22, 25, 26],
113             "timeframe": 23,
114             "download": "ical",
115         },
116     },
117 }
118 
119 
120 HEADERS = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
121 _LOGGER = logging.getLogger(__name__)
122 
123 
124 class Source:
125     def __init__(
126         self,
127         url=None,
128         file=None,
129         offset=None,
130         params=None,
131         year_field=None,
132         method="GET",
133         split_at=None,
134         version=2,
135     ):
136         self._url = url
137         self._file = file
138         if bool(self._url is not None) == bool(self._file is not None):
139             raise RuntimeError("Specify either url or file")
140         if version == 1:
141             self._ics = ICS_v1(offset=offset, split_at=split_at)
142         else:
143             self._ics = ICS(offset=offset, split_at=split_at)
144         self._params = params
145         self._year_field = year_field  # replace this field in params with current year
146         self._method = method  # The method to send the params
147 
148     def fetch(self):
149         if self._url is not None:
150             if "{%Y}" in self._url or self._year_field is not None:
151                 # url contains wildcard or params contains year field
152                 now = datetime.datetime.now()
153 
154                 # replace year in url
155                 url = self._url.replace("{%Y}", str(now.year))
156 
157                 # replace year in params
158                 if self._year_field is not None:
159                     if self._params is None:
160                         raise RuntimeError("year_field specified without params")
161                     self._params[self._year_field] = str(now.year)
162 
163                 entries = self.fetch_url(url, self._params)
164 
165                 if now.month == 12:
166                     # also get data for next year if we are already in december
167                     url = self._url.replace("{%Y}", str(now.year + 1))
168                     if self._year_field is not None:
169                         self._params[self._year_field] = str(now.year + 1)
170 
171                     try:
172                         entries.extend(self.fetch_url(url, self._params))
173                     except Exception:
174                         # ignore if fetch for next year fails
175                         pass
176                 return entries
177             else:
178                 return self.fetch_url(self._url, self._params)
179         elif self._file is not None:
180             return self.fetch_file(self._file)
181 
182     def fetch_url(self, url, params=None):
183         # get ics file
184         if self._method == "GET":
185             r = requests.get(url, params=params, headers=HEADERS)
186         elif self._method == "POST":
187             r = requests.post(url, data=params, headers=HEADERS)
188         else:
189             raise RuntimeError(
190                 "Error: unknown method to fetch URL, use GET or POST; got {self._method}"
191             )
192         r.encoding = "utf-8"  # requests doesn't guess the encoding correctly
193 
194         # check the return code
195         if not r.ok:
196             _LOGGER.error(
197                 "Error: the response is not ok; need code 200, but got code %s"
198                 % r.status_code
199             )
200             return []
201 
202         return self._convert(r.text)
203 
204     def fetch_file(self, file):
205         f = open(file)
206         return self._convert(f.read())
207 
208     def _convert(self, data):
209         dates = self._ics.convert(data)
210 
211         entries = []
212         for d in dates:
213             entries.append(Collection(d[0], d[1]))
214         return entries
215
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py
@@ -132,6 +132,7 @@
         method="GET",
         split_at=None,
         version=2,
+        verify_ssl=True,
     ):
         self._url = url
         self._file = file
@@ -144,6 +145,7 @@
         self._params = params
         self._year_field = year_field  # replace this field in params with current year
         self._method = method  # The method to send the params
+        self._verify_ssl = verify_ssl
 
     def fetch(self):
         if self._url is not None:
@@ -182,9 +184,13 @@
     def fetch_url(self, url, params=None):
         # get ics file
         if self._method == "GET":
-            r = requests.get(url, params=params, headers=HEADERS)
+            r = requests.get(
+                url, params=params, headers=HEADERS, verify=self._verify_ssl
+            )
         elif self._method == "POST":
-            r = requests.post(url, data=params, headers=HEADERS)
+            r = requests.post(
+                url, data=params, headers=HEADERS, verify=self._verify_ssl
+            )
         else:
             raise RuntimeError(
                 "Error: unknown method to fetch URL, use GET or POST; got {self._method}"

{"golden_diff": "diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py\n--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py\n+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py\n@@ -132,6 +132,7 @@\n         method=\"GET\",\n         split_at=None,\n         version=2,\n+        verify_ssl=True,\n     ):\n         self._url = url\n         self._file = file\n@@ -144,6 +145,7 @@\n         self._params = params\n         self._year_field = year_field  # replace this field in params with current year\n         self._method = method  # The method to send the params\n+        self._verify_ssl = verify_ssl\n \n     def fetch(self):\n         if self._url is not None:\n@@ -182,9 +184,13 @@\n     def fetch_url(self, url, params=None):\n         # get ics file\n         if self._method == \"GET\":\n-            r = requests.get(url, params=params, headers=HEADERS)\n+            r = requests.get(\n+                url, params=params, headers=HEADERS, verify=self._verify_ssl\n+            )\n         elif self._method == \"POST\":\n-            r = requests.post(url, data=params, headers=HEADERS)\n+            r = requests.post(\n+                url, data=params, headers=HEADERS, verify=self._verify_ssl\n+            )\n         else:\n             raise RuntimeError(\n                 \"Error: unknown method to fetch URL, use GET or POST; got {self._method}\"\n", "issue": "ZAS Abfallwirtschaft\nI'm trying to integrate the ZAS Abfallwirtschaft ICS. But i can't seem to get it to work.\r\nIs there anything i need to configure specifically?\r\n\r\nThe Website is\r\nhttps://www.za-sws.de/abfallkalender.cfm\r\n\r\nAnd the generated ICS is\r\nhttps://online-portal.za-sws.de/WasteManagementSuedwestsachsen/WasteManagementServiceServlet?ApplicationName=Calendar&SubmitAction=sync&StandortID=52554001&AboID=33626&Fra=R;P;B;W;L;C;S\r\n_(The adress used is a random one, not mine of course)_\r\n\r\nMy configuration looks like this:\r\n\r\n```\r\nwaste_collection_schedule:\r\n  sources:\r\n    - name: ics\r\n      args:\r\n        url: https://online-portal.za-sws.de/WasteManagementSuedwestsachsen/WasteManagementServiceServlet?ApplicationName=Calendar&SubmitAction=sync&StandortID=52554001&AboID=33626&Fra=R;P;B;W;L;C;S\r\n        customize:\r\n        - type: Restmuelltonne 02-woechentl.\r\n          alias: Restm\u00fcll\r\n          icon: mdi:trash-can\r\n        - type: Biotonnenwaesche\r\n          alias: Biotonnenw\u00e4sche\r\n          show: false\r\n          icon: mdi:flower-outline\r\n        - type: Papiertonne 04-woechentl.\r\n          alias: Papiertonne\r\n          icon: mdi:trash-can-outline\r\n        - type: LVP\r\n          alias: Gelbe Tonne\r\n          icon: mdi:recycle\r\n```\r\n\r\nThanks in advance.\n", "before_files": [{"content": "import datetime\nimport logging\nfrom pathlib import Path\n\nimport requests\nfrom waste_collection_schedule import Collection  # type: ignore[attr-defined]\nfrom waste_collection_schedule.service.ICS import ICS\nfrom waste_collection_schedule.service.ICS_v1 import ICS_v1\n\nTITLE = \"ICS\"\nDESCRIPTION = \"Source for ICS based schedules.\"\nURL = None\nTEST_CASES = {\n    \"Dortmund, Dudenstr. 5\": {\n        \"url\": \"https://www.edg.de/ical/kalender.ics?Strasse=Dudenstr.&Hausnummer=5&Erinnerung=-1&Abfallart=1,2,3,4\"\n    },\n    \"Leipzig, Sandgrubenweg 27\": {\n        \"url\": \"https://stadtreinigung-leipzig.de/wir-kommen-zu-ihnen/abfallkalender/ical.ics?position_nos=38296&name=Sandgrubenweg%2027\"\n    },\n    \"Ludwigsburg\": {\n        \"url\": \"https://www.avl-ludwigsburg.de/fileadmin/Files/Abfallkalender/ICS/Privat/Privat_{%Y}_Ossweil.ics\"\n    },\n    \"Esslingen, Bahnhof\": {\n        \"url\": \"https://api.abfall.io/?kh=DaA02103019b46345f1998698563DaAd&t=ics&s=1a862df26f6943997cef90233877a4fe\"\n    },\n    \"Test File\": {\n        # Path is used here to allow to call the Source from any location.\n        # This is not required in a yaml configuration!\n        \"file\": str(Path(__file__).resolve().parents[1].joinpath(\"test/test.ics\"))\n    },\n    \"Test File (recurring)\": {\n        # Path is used here to allow to call the Source from any location.\n        # This is not required in a yaml configuration!\n        \"file\": str(Path(__file__).resolve().parents[1].joinpath(\"test/recurring.ics\"))\n    },\n    \"M\u00fcnchen, Bahnstr. 11\": {\n        \"url\": \"https://www.awm-muenchen.de/entsorgen/abfuhrkalender?tx_awmabfuhrkalender_abfuhrkalender%5Bhausnummer%5D=11&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BB%5D=1%2F2%3BU&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BP%5D=1%2F2%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BR%5D=001%3BU&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=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bpapier%5D=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Brestmuell%5D=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstrasse%5D=bahnstr.&tx_awmabfuhrkalender_abfuhrkalender%5Byear%5D={%Y}\",\n        \"version\": 1,\n    },\n    \"Buxtehude, Am Berg\": {\n        \"url\": \"https://abfall.landkreis-stade.de/api_v2/collection_dates/1/ort/10/strasse/90/hausnummern/1/abfallarten/R02-R04-B02-D04-D12-P04-R12-R14-W0-R22-R24-R31/kalender.ics\"\n    },\n    #    \"Hausm\u00fcllinfo: ASR Chemnitz\": {\n    #        \"url\": \"https://asc.hausmuell.info/ics/ics.php\",\n    #        \"method\": \"POST\",\n    #        \"params\": {\n    #            \"hidden_id_egebiet\": 439087,\n    #            \"input_ort\": \"Chemnitz\",\n    #            \"input_str\": \"Stra\u00dfe der Nationen\",\n    #            \"input_hnr\": 2,\n    #            \"hidden_send_btn\": \"ics\",\n    #            # \"hiddenYear\": 2021,\n    #            \"hidden_id_ort\": 10,\n    #            \"hidden_id_ortsteil\": 0,\n    #            \"hidden_id_str\": 17814,\n    #            \"hidden_id_hnr\": 5538100,\n    #            \"hidden_kalenderart\": \"privat\",\n    #            \"showBinsBio\": \"on\",\n    #            \"showBinsRest\": \"on\",\n    #            \"showBinsRest_rc\": \"on\",\n    #            \"showBinsPapier\": \"on\",\n    #            \"showBinsOrganic\": \"on\",\n    #            \"showBinsXmas\": \"on\",\n    #            \"showBinsDsd\": \"on\",\n    #            \"showBinsProb\": \"on\",\n    #        },\n    #        \"year_field\": \"hiddenYear\",\n    #    },\n    \"Abfall Zollernalbkreis, Ebingen\": {\n        \"url\": \"https://www.abfallkalender-zak.de\",\n        \"params\": {\n            \"city\": \"2,3,4\",\n            \"street\": \"3\",\n            \"types[]\": [\n                \"restmuell\",\n                \"gelbersack\",\n                \"papiertonne\",\n                \"biomuell\",\n                \"gruenabfall\",\n                \"schadstoffsammlung\",\n                \"altpapiersammlung\",\n                \"schrottsammlung\",\n                \"weihnachtsbaeume\",\n                \"elektrosammlung\",\n            ],\n            \"go_ics\": \"Download\",\n        },\n        \"year_field\": \"year\",\n    },\n    \"Detmold\": {\n        \"url\": \"https://abfuhrkalender.detmold.de/icsmaker.php\",\n        \"method\": \"GET\",\n        \"params\": {\"strid\": 338},\n        \"year_field\": \"year\",\n    },\n    \"EAW Rheingau Taunus\": {\n        \"url\": \"https://www.eaw-rheingau-taunus.de/abfallkalender/calendar.ics?streetid=1429\",\n        \"split_at\": \",\",\n    },\n    \"Recollect, Ottawa\": {\n        \"url\": \"https://recollect.a.ssl.fastly.net/api/places/BCCDF30E-578B-11E4-AD38-5839C200407A/services/208/events.en.ics\",\n        \"split_at\": \"\\\\, [and ]*\",\n    },\n    \"Frankfurt am Main, Achenbachstrasse 3\": {\n        \"url\": \"https://www.fes-frankfurt.de/abfallkalender/QWNoZW5iYWNoc3RyLnwzfDYwNTk2.ics\"\n    },\n    \"Erlensee, Am Haspel\": {\n        \"url\": \"https://sperrmuell.erlensee.de/?type=reminder\",\n        \"method\": \"POST\",\n        \"params\": {\n            \"street\": 8,\n            \"eventType[]\": [27, 23, 19, 20, 21, 24, 22, 25, 26],\n            \"timeframe\": 23,\n            \"download\": \"ical\",\n        },\n    },\n}\n\n\nHEADERS = {\"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}\n_LOGGER = logging.getLogger(__name__)\n\n\nclass Source:\n    def __init__(\n        self,\n        url=None,\n        file=None,\n        offset=None,\n        params=None,\n        year_field=None,\n        method=\"GET\",\n        split_at=None,\n        version=2,\n    ):\n        self._url = url\n        self._file = file\n        if bool(self._url is not None) == bool(self._file is not None):\n            raise RuntimeError(\"Specify either url or file\")\n        if version == 1:\n            self._ics = ICS_v1(offset=offset, split_at=split_at)\n        else:\n            self._ics = ICS(offset=offset, split_at=split_at)\n        self._params = params\n        self._year_field = year_field  # replace this field in params with current year\n        self._method = method  # The method to send the params\n\n    def fetch(self):\n        if self._url is not None:\n            if \"{%Y}\" in self._url or self._year_field is not None:\n                # url contains wildcard or params contains year field\n                now = datetime.datetime.now()\n\n                # replace year in url\n                url = self._url.replace(\"{%Y}\", str(now.year))\n\n                # replace year in params\n                if self._year_field is not None:\n                    if self._params is None:\n                        raise RuntimeError(\"year_field specified without params\")\n                    self._params[self._year_field] = str(now.year)\n\n                entries = self.fetch_url(url, self._params)\n\n                if now.month == 12:\n                    # also get data for next year if we are already in december\n                    url = self._url.replace(\"{%Y}\", str(now.year + 1))\n                    if self._year_field is not None:\n                        self._params[self._year_field] = str(now.year + 1)\n\n                    try:\n                        entries.extend(self.fetch_url(url, self._params))\n                    except Exception:\n                        # ignore if fetch for next year fails\n                        pass\n                return entries\n            else:\n                return self.fetch_url(self._url, self._params)\n        elif self._file is not None:\n            return self.fetch_file(self._file)\n\n    def fetch_url(self, url, params=None):\n        # get ics file\n        if self._method == \"GET\":\n            r = requests.get(url, params=params, headers=HEADERS)\n        elif self._method == \"POST\":\n            r = requests.post(url, data=params, headers=HEADERS)\n        else:\n            raise RuntimeError(\n                \"Error: unknown method to fetch URL, use GET or POST; got {self._method}\"\n            )\n        r.encoding = \"utf-8\"  # requests doesn't guess the encoding correctly\n\n        # check the return code\n        if not r.ok:\n            _LOGGER.error(\n                \"Error: the response is not ok; need code 200, but got code %s\"\n                % r.status_code\n            )\n            return []\n\n        return self._convert(r.text)\n\n    def fetch_file(self, file):\n        f = open(file)\n        return self._convert(f.read())\n\n    def _convert(self, data):\n        dates = self._ics.convert(data)\n\n        entries = []\n        for d in dates:\n            entries.append(Collection(d[0], d[1]))\n        return entries\n", "path": "custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py"}], "after_files": [{"content": "import datetime\nimport logging\nfrom pathlib import Path\n\nimport requests\nfrom waste_collection_schedule import Collection  # type: ignore[attr-defined]\nfrom waste_collection_schedule.service.ICS import ICS\nfrom waste_collection_schedule.service.ICS_v1 import ICS_v1\n\nTITLE = \"ICS\"\nDESCRIPTION = \"Source for ICS based schedules.\"\nURL = None\nTEST_CASES = {\n    \"Dortmund, Dudenstr. 5\": {\n        \"url\": \"https://www.edg.de/ical/kalender.ics?Strasse=Dudenstr.&Hausnummer=5&Erinnerung=-1&Abfallart=1,2,3,4\"\n    },\n    \"Leipzig, Sandgrubenweg 27\": {\n        \"url\": \"https://stadtreinigung-leipzig.de/wir-kommen-zu-ihnen/abfallkalender/ical.ics?position_nos=38296&name=Sandgrubenweg%2027\"\n    },\n    \"Ludwigsburg\": {\n        \"url\": \"https://www.avl-ludwigsburg.de/fileadmin/Files/Abfallkalender/ICS/Privat/Privat_{%Y}_Ossweil.ics\"\n    },\n    \"Esslingen, Bahnhof\": {\n        \"url\": \"https://api.abfall.io/?kh=DaA02103019b46345f1998698563DaAd&t=ics&s=1a862df26f6943997cef90233877a4fe\"\n    },\n    \"Test File\": {\n        # Path is used here to allow to call the Source from any location.\n        # This is not required in a yaml configuration!\n        \"file\": str(Path(__file__).resolve().parents[1].joinpath(\"test/test.ics\"))\n    },\n    \"Test File (recurring)\": {\n        # Path is used here to allow to call the Source from any location.\n        # This is not required in a yaml configuration!\n        \"file\": str(Path(__file__).resolve().parents[1].joinpath(\"test/recurring.ics\"))\n    },\n    \"M\u00fcnchen, Bahnstr. 11\": {\n        \"url\": \"https://www.awm-muenchen.de/entsorgen/abfuhrkalender?tx_awmabfuhrkalender_abfuhrkalender%5Bhausnummer%5D=11&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BB%5D=1%2F2%3BU&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BP%5D=1%2F2%3BG&tx_awmabfuhrkalender_abfuhrkalender%5Bleerungszyklus%5D%5BR%5D=001%3BU&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=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Bpapier%5D=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstellplatz%5D%5Brestmuell%5D=70024507&tx_awmabfuhrkalender_abfuhrkalender%5Bstrasse%5D=bahnstr.&tx_awmabfuhrkalender_abfuhrkalender%5Byear%5D={%Y}\",\n        \"version\": 1,\n    },\n    \"Buxtehude, Am Berg\": {\n        \"url\": \"https://abfall.landkreis-stade.de/api_v2/collection_dates/1/ort/10/strasse/90/hausnummern/1/abfallarten/R02-R04-B02-D04-D12-P04-R12-R14-W0-R22-R24-R31/kalender.ics\"\n    },\n    #    \"Hausm\u00fcllinfo: ASR Chemnitz\": {\n    #        \"url\": \"https://asc.hausmuell.info/ics/ics.php\",\n    #        \"method\": \"POST\",\n    #        \"params\": {\n    #            \"hidden_id_egebiet\": 439087,\n    #            \"input_ort\": \"Chemnitz\",\n    #            \"input_str\": \"Stra\u00dfe der Nationen\",\n    #            \"input_hnr\": 2,\n    #            \"hidden_send_btn\": \"ics\",\n    #            # \"hiddenYear\": 2021,\n    #            \"hidden_id_ort\": 10,\n    #            \"hidden_id_ortsteil\": 0,\n    #            \"hidden_id_str\": 17814,\n    #            \"hidden_id_hnr\": 5538100,\n    #            \"hidden_kalenderart\": \"privat\",\n    #            \"showBinsBio\": \"on\",\n    #            \"showBinsRest\": \"on\",\n    #            \"showBinsRest_rc\": \"on\",\n    #            \"showBinsPapier\": \"on\",\n    #            \"showBinsOrganic\": \"on\",\n    #            \"showBinsXmas\": \"on\",\n    #            \"showBinsDsd\": \"on\",\n    #            \"showBinsProb\": \"on\",\n    #        },\n    #        \"year_field\": \"hiddenYear\",\n    #    },\n    \"Abfall Zollernalbkreis, Ebingen\": {\n        \"url\": \"https://www.abfallkalender-zak.de\",\n        \"params\": {\n            \"city\": \"2,3,4\",\n            \"street\": \"3\",\n            \"types[]\": [\n                \"restmuell\",\n                \"gelbersack\",\n                \"papiertonne\",\n                \"biomuell\",\n                \"gruenabfall\",\n                \"schadstoffsammlung\",\n                \"altpapiersammlung\",\n                \"schrottsammlung\",\n                \"weihnachtsbaeume\",\n                \"elektrosammlung\",\n            ],\n            \"go_ics\": \"Download\",\n        },\n        \"year_field\": \"year\",\n    },\n    \"Detmold\": {\n        \"url\": \"https://abfuhrkalender.detmold.de/icsmaker.php\",\n        \"method\": \"GET\",\n        \"params\": {\"strid\": 338},\n        \"year_field\": \"year\",\n    },\n    \"EAW Rheingau Taunus\": {\n        \"url\": \"https://www.eaw-rheingau-taunus.de/abfallkalender/calendar.ics?streetid=1429\",\n        \"split_at\": \",\",\n    },\n    \"Recollect, Ottawa\": {\n        \"url\": \"https://recollect.a.ssl.fastly.net/api/places/BCCDF30E-578B-11E4-AD38-5839C200407A/services/208/events.en.ics\",\n        \"split_at\": \"\\\\, [and ]*\",\n    },\n    \"Frankfurt am Main, Achenbachstrasse 3\": {\n        \"url\": \"https://www.fes-frankfurt.de/abfallkalender/QWNoZW5iYWNoc3RyLnwzfDYwNTk2.ics\"\n    },\n    \"Erlensee, Am Haspel\": {\n        \"url\": \"https://sperrmuell.erlensee.de/?type=reminder\",\n        \"method\": \"POST\",\n        \"params\": {\n            \"street\": 8,\n            \"eventType[]\": [27, 23, 19, 20, 21, 24, 22, 25, 26],\n            \"timeframe\": 23,\n            \"download\": \"ical\",\n        },\n    },\n}\n\n\nHEADERS = {\"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}\n_LOGGER = logging.getLogger(__name__)\n\n\nclass Source:\n    def __init__(\n        self,\n        url=None,\n        file=None,\n        offset=None,\n        params=None,\n        year_field=None,\n        method=\"GET\",\n        split_at=None,\n        version=2,\n        verify_ssl=True,\n    ):\n        self._url = url\n        self._file = file\n        if bool(self._url is not None) == bool(self._file is not None):\n            raise RuntimeError(\"Specify either url or file\")\n        if version == 1:\n            self._ics = ICS_v1(offset=offset, split_at=split_at)\n        else:\n            self._ics = ICS(offset=offset, split_at=split_at)\n        self._params = params\n        self._year_field = year_field  # replace this field in params with current year\n        self._method = method  # The method to send the params\n        self._verify_ssl = verify_ssl\n\n    def fetch(self):\n        if self._url is not None:\n            if \"{%Y}\" in self._url or self._year_field is not None:\n                # url contains wildcard or params contains year field\n                now = datetime.datetime.now()\n\n                # replace year in url\n                url = self._url.replace(\"{%Y}\", str(now.year))\n\n                # replace year in params\n                if self._year_field is not None:\n                    if self._params is None:\n                        raise RuntimeError(\"year_field specified without params\")\n                    self._params[self._year_field] = str(now.year)\n\n                entries = self.fetch_url(url, self._params)\n\n                if now.month == 12:\n                    # also get data for next year if we are already in december\n                    url = self._url.replace(\"{%Y}\", str(now.year + 1))\n                    if self._year_field is not None:\n                        self._params[self._year_field] = str(now.year + 1)\n\n                    try:\n                        entries.extend(self.fetch_url(url, self._params))\n                    except Exception:\n                        # ignore if fetch for next year fails\n                        pass\n                return entries\n            else:\n                return self.fetch_url(self._url, self._params)\n        elif self._file is not None:\n            return self.fetch_file(self._file)\n\n    def fetch_url(self, url, params=None):\n        # get ics file\n        if self._method == \"GET\":\n            r = requests.get(\n                url, params=params, headers=HEADERS, verify=self._verify_ssl\n            )\n        elif self._method == \"POST\":\n            r = requests.post(\n                url, data=params, headers=HEADERS, verify=self._verify_ssl\n            )\n        else:\n            raise RuntimeError(\n                \"Error: unknown method to fetch URL, use GET or POST; got {self._method}\"\n            )\n        r.encoding = \"utf-8\"  # requests doesn't guess the encoding correctly\n\n        # check the return code\n        if not r.ok:\n            _LOGGER.error(\n                \"Error: the response is not ok; need code 200, but got code %s\"\n                % r.status_code\n            )\n            return []\n\n        return self._convert(r.text)\n\n    def fetch_file(self, file):\n        f = open(file)\n        return self._convert(f.read())\n\n    def _convert(self, data):\n        dates = self._ics.convert(data)\n\n        entries = []\n        for d in dates:\n            entries.append(Collection(d[0], d[1]))\n        return entries\n", "path": "custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py"}]}