mirror of
https://github.com/sascha-hemi/hacs_waste_collection_schedule.git
synced 2026-03-21 04:06:03 +01:00
add source multiple to combine multiple sources to one Entity (#1810)
* add source multiple to combine multiple sources to one Entity * typo --------- Co-authored-by: 5ila5 <5ila5@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,8 @@ Waste collection schedules in the following formats and countries are supported.
|
||||
|
||||
- [Generic ICS / iCal File](/doc/source/ics.md)
|
||||
- [User Specified](/doc/source/static.md)
|
||||
- [Multiple Sources Wrapper](/doc/source/multiple.md)
|
||||
|
||||
</details>
|
||||
|
||||
<!--Begin of country section-->
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
URL = None
|
||||
TITLE = "Multiple Sources"
|
||||
DESCRIPTION = "Source wrapper for multiple waste collection schedules."
|
||||
|
||||
TEST_CASES = {
|
||||
"two static": {
|
||||
"static": [
|
||||
{"type": "Dates only", "dates": ["2022-01-01", "2022-01-01"]},
|
||||
{
|
||||
"type": "First day of month",
|
||||
"frequency": "MONTHLY",
|
||||
"interval": 1,
|
||||
"start": "2022-01-01",
|
||||
"until": "2022-12-31",
|
||||
},
|
||||
],
|
||||
},
|
||||
"multiple ics": {
|
||||
"ics": [
|
||||
{
|
||||
"url": "https://servicebetrieb.koblenz.de/abfallwirtschaft/entsorgungstermine-digital/entsorgungstermine-2023-digital/altstadt-2023.ics?cid=2ui7"
|
||||
},
|
||||
{
|
||||
"url": "https://recollect.a.ssl.fastly.net/api/places/BCCDF30E-578B-11E4-AD38-5839C200407A/services/208/events.en.ics",
|
||||
"split_at": "\\, (?:and )?|(?: and )",
|
||||
},
|
||||
]
|
||||
},
|
||||
"static and ics": {
|
||||
"static": {"type": "Dates only", "dates": ["2022-01-01", "2022-01-01"]},
|
||||
"ics": {
|
||||
"url": "https://sperrmuell.erlensee.de/?type=reminder",
|
||||
"method": "POST",
|
||||
"params": {
|
||||
"street": 8,
|
||||
"eventType[]": [27, 23, 19, 20, 21, 24, 22, 25, 26],
|
||||
"timeframe": 23,
|
||||
"download": "ical",
|
||||
},
|
||||
},
|
||||
},
|
||||
"multiple different sources": {
|
||||
"lund_se": {"street_address": "Lokföraregatan 7, LUND (19120)"},
|
||||
"meinawb_de": {
|
||||
"city": "Oberzissen",
|
||||
"street": "Lindenstrasse",
|
||||
"house_number": "1",
|
||||
},
|
||||
"jumomind_de": {
|
||||
"service_id": "mymuell",
|
||||
"city": "Bad Wünnenberg-Bleiwäsche",
|
||||
},
|
||||
},
|
||||
"multiple different with two static": {
|
||||
"lund_se": {"street_address": "Lokföraregatan 7, LUND (19120)"},
|
||||
"nawma_sa_gov_au": {
|
||||
"street_number": "128",
|
||||
"street_name": "Bridge Road",
|
||||
"suburb": "Pooraka",
|
||||
},
|
||||
"static": [
|
||||
{"type": "Dates only", "dates": ["2024-01-01", "2024-01-24"]},
|
||||
{
|
||||
"type": "First day of month",
|
||||
"frequency": "MONTHLY",
|
||||
"interval": 1,
|
||||
"start": "2022-01-01",
|
||||
"until": "2022-12-31",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_source(source: str, args: dict | list[dict]) -> list:
|
||||
if isinstance(args, list):
|
||||
return [
|
||||
getattr(
|
||||
importlib.import_module(f"waste_collection_schedule.source.{source}"),
|
||||
"Source",
|
||||
)(**arg)
|
||||
for arg in args
|
||||
]
|
||||
return [
|
||||
getattr(
|
||||
importlib.import_module(f"waste_collection_schedule.source.{source}"),
|
||||
"Source",
|
||||
)(**args)
|
||||
]
|
||||
|
||||
|
||||
def check_source_type(data):
|
||||
"""Check if the type of 'data' matches either 'dict[str, dict]' or 'dict[str, list[dict]]'."""
|
||||
if isinstance(data, dict):
|
||||
# Check if all keys are strings
|
||||
if all(isinstance(key, str) for key in data.keys()):
|
||||
# Check if all values are either dictionaries or lists of dictionaries
|
||||
if all(
|
||||
isinstance(value, dict)
|
||||
or (
|
||||
isinstance(value, list)
|
||||
and all(isinstance(value2, dict) for value2 in value)
|
||||
)
|
||||
for value in data.values()
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Source:
|
||||
def __init__(self, **sources: dict[str, dict] | dict[str, list[dict]]):
|
||||
# test for correct source format
|
||||
|
||||
if not check_source_type(sources):
|
||||
raise ValueError(
|
||||
f"Invalid source format provided should be a list of dictionaries or a list of list of dictionaries but is {type(sources)}, please take a look at the examples"
|
||||
)
|
||||
self._sources: list = []
|
||||
for source, args in sources.items():
|
||||
self._sources += get_source(source, args)
|
||||
|
||||
def fetch(self):
|
||||
dates = []
|
||||
fails = 0
|
||||
for source in self._sources:
|
||||
try:
|
||||
dates.extend(source.fetch())
|
||||
except Exception as e:
|
||||
fails += 1
|
||||
LOGGER.error(f"Error fetching dates from source {source}: {e}")
|
||||
|
||||
if fails == len(self._sources):
|
||||
raise RuntimeError("Failed to fetch dates from all sources")
|
||||
return dates
|
||||
@@ -38,6 +38,8 @@ To use Waste Collection Schedules, additional entries need to be made in your `c
|
||||
|
||||
If you have to fetch data from multiple service providers, you have to add multiple sources. You can also add the same service provider multiple times. This only makes sense if you use it with different arguments, e.g. you are looking to display waste collection schedules for multiple districts served by the same provider.
|
||||
|
||||
If you prefer to combine the data into one calendar entity, you can use the [multiple](/doc/source/multiple.md) wrapper source.
|
||||
|
||||
2. Configuring sensor(s)
|
||||
|
||||
Sensors are used to visualize the retrieved information, e.g. waste type, next collection date, or number of days to next collection. The sensor state (which can be shown in a Lovelace/Mushroom cards) can be customized using templates. For example, you can display the collection type only, or the next collection date, or a combination of all available information.
|
||||
@@ -162,6 +164,8 @@ Examples:
|
||||
|
||||
## Combine Data from multiple Sources
|
||||
|
||||
### Combine Sensor Data
|
||||
|
||||
To combine data from multiple sources into one sensor, just add the source indexes like that:
|
||||
|
||||
```yaml
|
||||
@@ -172,6 +176,10 @@ To combine data from multiple sources into one sensor, just add the source index
|
||||
- 1
|
||||
```
|
||||
|
||||
### Combine Source Data
|
||||
|
||||
If you prefer to combine the data into one calendar entity, you can use the [multiple](/doc/source/multiple.md) wrapper source.
|
||||
|
||||
## HomeAssistant Service to manually trigger update
|
||||
|
||||
If you want to trigger a manual update of the sources, you can call the service:
|
||||
|
||||
141
doc/source/multiple.md
Normal file
141
doc/source/multiple.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# Multiple Source Wrapper
|
||||
|
||||
Wrapper Source to include multiple sources in one calendar.
|
||||
|
||||
This wrapper is meant for configurations where you want to include multiple sources in one calendar entity. If you want to have multiple calendars, you should simply pass multiple sources to the `sources` parameter in the configuration.
|
||||
|
||||
This is just a wrapper class for other sources for further information see the documentation of the sources you want to include.
|
||||
|
||||
## Configuration via configuration.yaml
|
||||
|
||||
```yaml
|
||||
waste_collection_schedule:
|
||||
sources:
|
||||
- name: multiple
|
||||
args:
|
||||
- SOURCE_NAME: SOURCE_ARGS
|
||||
- SOURCE_NAME: SOURCE_ARGS
|
||||
...
|
||||
# or (can be mixed)
|
||||
- SOURCE_NAME:
|
||||
- SOURCE_ARGS
|
||||
- SOURCE_ARGS
|
||||
...
|
||||
```
|
||||
|
||||
### Configuration Variables
|
||||
|
||||
**SOURCE_NAME**
|
||||
*(string) (required)*
|
||||
|
||||
The name of the source to include.
|
||||
|
||||
**SOURCE_ARGS**
|
||||
*(dict) (required)*
|
||||
|
||||
A dictionary of arguments for the source.
|
||||
|
||||
## Examples
|
||||
|
||||
### Two static sources
|
||||
|
||||
```yaml
|
||||
waste_collection_schedule:
|
||||
sources:
|
||||
- name: multiple
|
||||
args:
|
||||
- static:
|
||||
- type: "Dates only"
|
||||
dates:
|
||||
- "2022-01-01"
|
||||
- "2022-01-01"
|
||||
- type: "First day of month"
|
||||
frequency: "MONTHLY"
|
||||
interval: 1
|
||||
start: "2022-01-01"
|
||||
until: "2022-12-31"
|
||||
```
|
||||
|
||||
### Two ics sources
|
||||
|
||||
```yaml
|
||||
waste_collection_schedule:
|
||||
sources:
|
||||
- name: multiple
|
||||
args:
|
||||
- ics:
|
||||
- url: "https://servicebetrieb.koblenz.de/abfallwirtschaft/entsorgungstermine-digital/entsorgungstermine-2023-digital/altstadt-2023.ics?cid=2ui7"
|
||||
- url: "https://recollect.a.ssl.fastly.net/api/places/BCCDF30E-578B-11E4-AD38-5839C200407A/services/208/events.en.ics"
|
||||
split_at: "\\, (?:and )?|(?: and )"
|
||||
```
|
||||
|
||||
### One Static and ics source each
|
||||
|
||||
```yaml
|
||||
waste_collection_schedule:
|
||||
sources:
|
||||
- name: multiple
|
||||
- static:
|
||||
type: "Dates only"
|
||||
dates:
|
||||
- "2022-01-01"
|
||||
- "2022-01-01"
|
||||
- ics:
|
||||
url: "https://sperrmuell.erlensee.de/?type=reminder"
|
||||
method: "POST"
|
||||
params:
|
||||
street: 8
|
||||
eventType[]:
|
||||
- 27
|
||||
- 23
|
||||
- 19
|
||||
- 20
|
||||
- 21
|
||||
- 24
|
||||
- 22
|
||||
- 25
|
||||
- 26
|
||||
timeframe: 23
|
||||
download: "ical"
|
||||
```
|
||||
|
||||
### Three "normal" sources
|
||||
|
||||
```yaml
|
||||
waste_collection_schedule:
|
||||
sources:
|
||||
- name: multiple
|
||||
- lund_se:
|
||||
street_address: "Lokföraregatan 7, LUND (19120)"
|
||||
- meinawb_de:
|
||||
city: "Oberzissen"
|
||||
street: "Lindenstrasse"
|
||||
house_number: "1"
|
||||
- jumomind_de:
|
||||
service_id: "mymuell"
|
||||
city: "Bad Wünnenberg-Bleiwäsche"
|
||||
```
|
||||
|
||||
### Two "normal" sources with two static sources
|
||||
|
||||
```yaml
|
||||
waste_collection_schedule:
|
||||
sources:
|
||||
- name: multiple
|
||||
- lund_se:
|
||||
street_address: "Lokföraregatan 7, LUND (19120)"
|
||||
- nawma_sa_gov_au:
|
||||
street_number: "128"
|
||||
street_name: "Bridge Road"
|
||||
suburb: "Pooraka"
|
||||
- static:
|
||||
- type: "Dates only"
|
||||
dates:
|
||||
- "2024-01-01"
|
||||
- "2024-01-24"
|
||||
- type: "First day of month"
|
||||
frequency: "MONTHLY"
|
||||
interval: 1
|
||||
start: "2022-01-01"
|
||||
until: "2022-12-31"
|
||||
```
|
||||
@@ -11,7 +11,12 @@ import yaml
|
||||
SECRET_FILENAME = "secrets.yaml"
|
||||
SECRET_REGEX = re.compile(r"!secret\s(\w+)")
|
||||
|
||||
BLACK_LIST = {"/doc/source/ics.md", "/doc/source/static.md", "/doc/source/example.md"}
|
||||
BLACK_LIST = {
|
||||
"/doc/source/ics.md",
|
||||
"/doc/source/static.md",
|
||||
"/doc/source/multiple.md",
|
||||
"/doc/source/example.md",
|
||||
}
|
||||
|
||||
START_COUNTRY_SECTION = "<!--Begin of country section-->"
|
||||
END_COUNTRY_SECTION = "<!--End of country section-->"
|
||||
|
||||
Reference in New Issue
Block a user