Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Bug]: sources: abfallnavi_de service: nds get only Data for 2024 not 2023
### I Have A Problem With:

A specific source

### What's Your Problem


I haven't received any data for this year for ~1 weeks, only for 2024.

I think after the data for 2024 has been released, the integration will only fetch data from 2024 and not longer from 2023.

Data for 2023 is still available: https://abfallnavi.de/nds/
![image](https://github.com/mampfes/hacs_waste_collection_schedule/assets/100964266/3dc83b5b-36ab-45ec-b51e-2b9527fdbb72)


### Source (if relevant)

abfallnavi_de

### Logs

```Shell
didn't find somsthing waste_collection_schedule relatet
```


### Relevant Configuration

```YAML
waste_collection_schedule:
  sources:
    - name: abfallnavi_de
      args:
        service: nds
        ort: !secret ort
        strasse: !secret strasse
      customize:
        - type: "Gelbe Wertstoffbehälter -2 wö.-"
          alias: Gelbetonne
        - type: "Restabfall -2 wö.-"
          alias: Restabfall 
        - type: "Restabfall -4 wö.-"
          show: false
        - type: "Bioabfall -2 wö.-"
          alias: Bioabfall 
        - type: "Altpapier -4 wö.-"
          alias: Altpapier 
      calendar_title: "Abfallkalender"
```


### Checklist Source Error

- [X] Use the example parameters for your source (often available in the documentation) (don't forget to restart Home Assistant after changing the configuration)
- [X] Checked that the website of your service provider is still working
- [X] Tested my attributes on the service provider website (if possible)
- [X] I have tested with the latest version of the integration (master) (for HACS in the 3 dot menu of the integration click on "Redownload" and choose master as version)

### Checklist Sensor Error

- [x] Checked in the Home Assistant Calendar tab if the event names match the types names (if types argument is used)

### Required

- [X] I have searched past (closed AND opened) issues to see if this bug has already been reported, and it hasn't been.
- [X] I understand that people give their precious time for free, and thus I've done my very best to make this problem as easy as possible to investigate.


Discussion:
I cannot reproduce this issue 

this config returns dates for 2023 and 2024

```yaml
# waste_collection_schedule source configuration
waste_collection_schedule:
  sources:
    - name: abfallnavi_de
      args:
        service: nds
        ort: Norderstedt
        strasse: Adenauerplatz
```

The source should use the same method to get the dates as the website.

are there any events for 2023 in the calendar (Error in sensor config)? (maybe they changed the names for the 2023 events? or something)

# Workaround

If you cannot fix this an need a fast workaround:

use the [ICS source](https://github.com/mampfes/hacs_waste_collection_schedule/blob/master/doc/source/ics.md) with the link of the `Export-ICS` button (you can replace the year with %y so that it will work the next year as well:

e.g:

```yaml
waste_collection_schedule:
  sources:
    - name: ics
      args:
        url: https://abfallkalender.regioit.de/kalender-nds/downloadfile.jsp?format=ics&jahr=%y&ort=Norderstedt&strasse=425890&fraktion=0&fraktion=1&fraktion=2&fraktion=3&fraktion=4&fraktion=5&fraktion=6
        regex: "(.*) -[24] wö.-" # Remove  -4 wö.- and  -2 wö.-

```


Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/service/AbfallnaviDe.py b/custom_components/waste_collection_schedule/waste_collection_schedule/service/AbfallnaviDe.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/service/AbfallnaviDe.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/service/AbfallnaviDe.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
-import datetime
 import json
+from datetime import datetime
 
 import requests
 
@@ -168,10 +168,13 @@ def get_streets(self, city_id):
             result[street["id"]] = street["name"]
         return result
 
-    def get_street_id(self, city_id, street):
-        """Return id for given street string."""
+    def get_street_ids(self, city_id, street):
+        """Return ids for given street string.
+
+        may return multiple on change of id (may occur on year change)
+        """
         streets = self.get_streets(city_id)
-        return self._find_in_inverted_dict(streets, street)
+        return [id for id, name in streets.items() if name == street]
 
     def get_house_numbers(self, street_id):
         """Return all house numbers of a street."""
@@ -208,7 +211,7 @@ def _get_dates(self, target, id, waste_types=None):
 
         entries = []
         for r in results:
-            date = datetime.datetime.strptime(r["datum"], "%Y-%m-%d").date()
+            date = datetime.strptime(r["datum"], "%Y-%m-%d").date()
             fraktion = waste_types[r["bezirk"]["fraktionId"]]
             entries.append([date, fraktion])
         return entries
@@ -227,19 +230,22 @@ def get_dates(self, city, street, house_number=None):
             raise Exception(f"No id found for city: {city}")
 
         # find street_id
-        street_id = self.get_street_id(city_id, street)
-        if street_id is None:
+        street_ids = self.get_street_ids(city_id, street)
+        if street_ids == []:
             raise Exception(f"No id found for street: {street}")
 
-        # find house_number_id (which is optional: not all house number do have an id)
-        house_number_id = self.get_house_number_id(street_id, house_number)
-
-        # return dates for specific house number of street if house number
-        # doesn't have an own id
-        if house_number_id is not None:
-            return self.get_dates_by_house_number_id(house_number_id)
-        else:
-            return self.get_dates_by_street_id(street_id)
+        dates = []
+        for street_id in street_ids:
+            # find house_number_id (which is optional: not all house number do have an id)
+            house_number_id = self.get_house_number_id(street_id, house_number)
+
+            # return dates for specific house number of street if house number
+            # doesn't have an own id
+            if house_number_id is not None:
+                dates += self.get_dates_by_house_number_id(house_number_id)
+            else:
+                dates += self.get_dates_by_street_id(street_id)
+        return dates
 
     def _find_in_inverted_dict(self, mydict, value):
         inverted_dict = dict(map(reversed, mydict.items()))
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/abfallnavi_de.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/abfallnavi_de.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/abfallnavi_de.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/abfallnavi_de.py
@@ -1,6 +1,8 @@
 from waste_collection_schedule import Collection  # type: ignore[attr-defined]
-from waste_collection_schedule.service.AbfallnaviDe import (SERVICE_DOMAINS,
-                                                            AbfallnaviDe)
+from waste_collection_schedule.service.AbfallnaviDe import (
+    SERVICE_DOMAINS,
+    AbfallnaviDe,
+)
 
 TITLE = "AbfallNavi (RegioIT.de)"
 DESCRIPTION = (
@@ -31,15 +33,24 @@ def EXTRA_INFO():
         "strasse": "Am Sportplatz",
         "hausnummer": "2",
     },
+    "nds Norderstedt Adenauerplatz": {
+        "service": "nds",
+        "ort": "Norderstedt",
+        "strasse": "Distelweg",
+    },
 }
 
 
 class Source:
-    def __init__(self, service: str, ort: str, strasse: str, hausnummer: str | int | None = None):
+    def __init__(
+        self, service: str, ort: str, strasse: str, hausnummer: str | int | None = None
+    ):
         self._api = AbfallnaviDe(service)
         self._ort = ort
         self._strasse = strasse
-        self._hausnummer = str(hausnummer) if isinstance(hausnummer, int) else hausnummer
+        self._hausnummer = (
+            str(hausnummer) if isinstance(hausnummer, int) else hausnummer
+        )
 
     def fetch(self):
         dates = self._api.get_dates(self._ort, self._strasse, self._hausnummer)
@@ -47,4 +58,5 @@ def fetch(self):
         entries = []
         for d in dates:
             entries.append(Collection(d[0], d[1]))
-        return entries
+
+        return sorted(entries, key=lambda e: e.date)


Test patch: