From c442d437fc431d91e26d10613869546a020b5955 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sun, 22 Jan 2023 15:31:15 +0100 Subject: [PATCH 01/12] Added support for waste event start and event time. --- .../waste_collection_schedule/calendar.py | 7 ++++++ .../waste_collection_schedule/collection.py | 18 ++++++++++++- .../waste_collection_schedule/source_shell.py | 25 ++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index f76abaa79..981cb0107 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -116,6 +116,13 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" + if collection.start_hours_before is not None and collection.end_hours_after is not None: + return CalendarEvent( + summary=collection.type, + start=collection.date + timedelta(hours=collection.start_hours_before), + end=collection.date + timedelta(hours=collection.end_hours_after), + ) + return CalendarEvent( summary=collection.type, start=collection.date, diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py index 16f2b9105..f08b3ab17 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py @@ -9,7 +9,7 @@ def __init__( icon: Optional[str] = None, picture: Optional[str] = None, ): - dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture) + dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture, start_hours_before=None, end_hours_after=None) self._date = date # store date also as python date object @property @@ -34,6 +34,22 @@ def picture(self): def set_picture(self, picture: str): self["picture"] = picture + @property + def start_hours_before(self): + return self["start_hours_before"] + + @property + def start_hours_before(self, hours: int): + self["start_hours_before"] = hours + + @property + def end_hours_after(self): + return self["end_hours_after"] + + @property + def end_hours_after(self, hours: int): + self["end_hours_after"] = hours + class Collection(CollectionBase): def __init__( diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py index 6f53c5d1a..65f252e00 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py @@ -21,6 +21,8 @@ def __init__( picture=None, use_dedicated_calendar=False, dedicated_calendar_title=None, + start_hours_before=None, + end_hours_after=None, ): self._waste_type = waste_type self._alias = alias @@ -29,6 +31,8 @@ def __init__( self._picture = picture self._use_dedicated_calendar = use_dedicated_calendar self._dedicated_calendar_title = dedicated_calendar_title + self._start_hours_before = start_hours_before + self._end_hours_after = end_hours_after @property def waste_type(self): @@ -58,8 +62,16 @@ def use_dedicated_calendar(self): def dedicated_calendar_title(self): return self._dedicated_calendar_title + @property + def start_hours_before(self): + return self._start_hours_before + + @property + def end_hours_after(self): + return self._end_hours_after + def __repr__(self): - return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}}}" + return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}, start_hours_before={self._start_hours_before}, end_hours_after={self._end_hours_after}}}" def filter_function(entry: Collection, customize: Dict[str, Customize]): @@ -82,6 +94,14 @@ def customize_function(entry: Collection, customize: Dict[str, Customize]): return entry +def start_end_time_function(entry: Collection, customize: Dict[str, Customize]): + if customize.start_hours_before is not None: + entry.start_hours_before(customize.start_hours_before) + if customize.end_hours_after is not None: + entry.end_hours_after(customize.end_hours_after) + return entry + + class SourceShell: def __init__( self, @@ -149,6 +169,9 @@ def fetch(self): # customize fetched entries entries = map(lambda x: customize_function(x, self._customize), entries) + # add optional start and end time to a waster event + entries = map(lambda x: start_end_time_function(x, self._customize), entries) + self._entries = list(entries) def get_dedicated_calendar_types(self): From c79f6a2f7546831eccee26c88974e71dd6ab03f9 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sun, 22 Jan 2023 15:49:13 +0100 Subject: [PATCH 02/12] Added new config fields to schema. --- custom_components/waste_collection_schedule/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py index 91af47789..e83b37f03 100644 --- a/custom_components/waste_collection_schedule/__init__.py +++ b/custom_components/waste_collection_schedule/__init__.py @@ -40,6 +40,8 @@ CONF_PICTURE = "picture" CONF_USE_DEDICATED_CALENDAR = "use_dedicated_calendar" CONF_DEDICATED_CALENDAR_TITLE = "dedicated_calendar_title" +CONF_START_HOURS_BEFORE = "start_hours_before" +CONF_END_HOURS_AFTER = "end_hours_after" CUSTOMIZE_CONFIG = vol.Schema( { @@ -50,6 +52,8 @@ vol.Optional(CONF_PICTURE): cv.string, vol.Optional(CONF_USE_DEDICATED_CALENDAR): cv.boolean, vol.Optional(CONF_DEDICATED_CALENDAR_TITLE): cv.string, + vol.Optional(CONF_START_HOURS_BEFORE): cv.string, + vol.Optional(CONF_END_HOURS_AFTER): cv.string, } ) From d34ad3fde2ff76b95c5008e490075588afaf50ab Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sun, 22 Jan 2023 16:39:44 +0100 Subject: [PATCH 03/12] Fixed in event time customization. --- .../waste_collection_schedule/__init__.py | 2 ++ .../waste_collection_schedule/calendar.py | 7 ++++--- .../waste_collection_schedule/collection.py | 10 ++++------ .../waste_collection_schedule/source_shell.py | 16 +++++++++------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py index e83b37f03..07d80be03 100644 --- a/custom_components/waste_collection_schedule/__init__.py +++ b/custom_components/waste_collection_schedule/__init__.py @@ -110,6 +110,8 @@ async def async_setup(hass: HomeAssistant, config: dict): picture=c.get(CONF_PICTURE), use_dedicated_calendar=c.get(CONF_USE_DEDICATED_CALENDAR, False), dedicated_calendar_title=c.get(CONF_DEDICATED_CALENDAR_TITLE, False), + start_hours_before=c.get(CONF_START_HOURS_BEFORE, None), + end_hours_after=c.get(CONF_END_HOURS_AFTER, None), ) await hass.async_add_executor_job( api.add_source_shell, diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index 981cb0107..ce2229457 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -1,7 +1,7 @@ """Calendar platform support for Waste Collection Schedule.""" import logging -from datetime import datetime, timedelta +from datetime import datetime, timedelta, time from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.core import HomeAssistant @@ -117,10 +117,11 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" if collection.start_hours_before is not None and collection.end_hours_after is not None: + event_date_time = datetime.combine(collection.date, time(hour=0, minute=0, second=0)) return CalendarEvent( summary=collection.type, - start=collection.date + timedelta(hours=collection.start_hours_before), - end=collection.date + timedelta(hours=collection.end_hours_after), + start=event_date_time - timedelta(hours=collection.start_hours_before), + end=event_date_time + timedelta(hours=collection.end_hours_after), ) return CalendarEvent( diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py index f08b3ab17..b49bcd496 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py @@ -38,17 +38,15 @@ def set_picture(self, picture: str): def start_hours_before(self): return self["start_hours_before"] - @property - def start_hours_before(self, hours: int): - self["start_hours_before"] = hours + def set_start_hours_before(self, hours: int): + self["start_hours_before"] = int(hours) @property def end_hours_after(self): return self["end_hours_after"] - @property - def end_hours_after(self, hours: int): - self["end_hours_after"] = hours + def set_end_hours_after(self, hours: int): + self["end_hours_after"] = int(hours) class Collection(CollectionBase): diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py index 65f252e00..a98755b68 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py @@ -95,10 +95,12 @@ def customize_function(entry: Collection, customize: Dict[str, Customize]): def start_end_time_function(entry: Collection, customize: Dict[str, Customize]): - if customize.start_hours_before is not None: - entry.start_hours_before(customize.start_hours_before) - if customize.end_hours_after is not None: - entry.end_hours_after(customize.end_hours_after) + c = customize.get(entry.type) + if c is not None: + if c.start_hours_before is not None: + entry.set_start_hours_before(c.start_hours_before) + if c.end_hours_after is not None: + entry.set_end_hours_after(c.end_hours_after) return entry @@ -166,12 +168,12 @@ def fetch(self): # filter hidden entries entries = filter(lambda x: filter_function(x, self._customize), entries) - # customize fetched entries - entries = map(lambda x: customize_function(x, self._customize), entries) - # add optional start and end time to a waster event entries = map(lambda x: start_end_time_function(x, self._customize), entries) + # customize fetched entries + entries = map(lambda x: customize_function(x, self._customize), entries) + self._entries = list(entries) def get_dedicated_calendar_types(self): From 6230af40a9852bf1dc3e229c07f4ef22101b8e0b Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Tue, 24 Jan 2023 11:23:07 +0100 Subject: [PATCH 04/12] Renamed/simplied waste event time config. --- .../waste_collection_schedule/__init__.py | 12 ++++---- .../waste_collection_schedule/calendar.py | 6 ++-- .../waste_collection_schedule/collection.py | 18 ++++++------ .../waste_collection_schedule/source_shell.py | 28 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py index 07d80be03..49c7a3893 100644 --- a/custom_components/waste_collection_schedule/__init__.py +++ b/custom_components/waste_collection_schedule/__init__.py @@ -40,8 +40,8 @@ CONF_PICTURE = "picture" CONF_USE_DEDICATED_CALENDAR = "use_dedicated_calendar" CONF_DEDICATED_CALENDAR_TITLE = "dedicated_calendar_title" -CONF_START_HOURS_BEFORE = "start_hours_before" -CONF_END_HOURS_AFTER = "end_hours_after" +CONF_START_HOUR = "start_hour" +CONF_END_HOUR = "end_hour" CUSTOMIZE_CONFIG = vol.Schema( { @@ -52,8 +52,8 @@ vol.Optional(CONF_PICTURE): cv.string, vol.Optional(CONF_USE_DEDICATED_CALENDAR): cv.boolean, vol.Optional(CONF_DEDICATED_CALENDAR_TITLE): cv.string, - vol.Optional(CONF_START_HOURS_BEFORE): cv.string, - vol.Optional(CONF_END_HOURS_AFTER): cv.string, + vol.Optional(CONF_START_HOUR): cv.string, + vol.Optional(CONF_END_HOUR): cv.string, } ) @@ -110,8 +110,8 @@ async def async_setup(hass: HomeAssistant, config: dict): picture=c.get(CONF_PICTURE), use_dedicated_calendar=c.get(CONF_USE_DEDICATED_CALENDAR, False), dedicated_calendar_title=c.get(CONF_DEDICATED_CALENDAR_TITLE, False), - start_hours_before=c.get(CONF_START_HOURS_BEFORE, None), - end_hours_after=c.get(CONF_END_HOURS_AFTER, None), + start_hour=c.get(CONF_START_HOUR, None), + end_hour=c.get(CONF_END_HOUR, None), ) await hass.async_add_executor_job( api.add_source_shell, diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index ce2229457..da3abc45d 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -116,12 +116,12 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" - if collection.start_hours_before is not None and collection.end_hours_after is not None: + if collection.start_hour is not None and collection.end_hour is not None: event_date_time = datetime.combine(collection.date, time(hour=0, minute=0, second=0)) return CalendarEvent( summary=collection.type, - start=event_date_time - timedelta(hours=collection.start_hours_before), - end=event_date_time + timedelta(hours=collection.end_hours_after), + start=event_date_time + timedelta(hours=collection.start_hour), + end=event_date_time + timedelta(hours=collection.end_hour), ) return CalendarEvent( diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py index b49bcd496..f5f9c00b9 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py @@ -9,7 +9,7 @@ def __init__( icon: Optional[str] = None, picture: Optional[str] = None, ): - dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture, start_hours_before=None, end_hours_after=None) + dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture, start_hour=None, end_hour=None) self._date = date # store date also as python date object @property @@ -35,18 +35,18 @@ def set_picture(self, picture: str): self["picture"] = picture @property - def start_hours_before(self): - return self["start_hours_before"] + def start_hour(self): + return self["start_hour"] - def set_start_hours_before(self, hours: int): - self["start_hours_before"] = int(hours) + def set_start_hour(self, hours: int): + self["start_hour"] = int(hours) @property - def end_hours_after(self): - return self["end_hours_after"] + def end_hour(self): + return self["end_hour"] - def set_end_hours_after(self, hours: int): - self["end_hours_after"] = int(hours) + def set_end_hour(self, hours: int): + self["end_hour"] = int(hours) class Collection(CollectionBase): diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py index a98755b68..a4660bf33 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py @@ -21,8 +21,8 @@ def __init__( picture=None, use_dedicated_calendar=False, dedicated_calendar_title=None, - start_hours_before=None, - end_hours_after=None, + start_hour=None, + end_hour=None, ): self._waste_type = waste_type self._alias = alias @@ -31,8 +31,8 @@ def __init__( self._picture = picture self._use_dedicated_calendar = use_dedicated_calendar self._dedicated_calendar_title = dedicated_calendar_title - self._start_hours_before = start_hours_before - self._end_hours_after = end_hours_after + self._start_hour = start_hour + self._end_hour = end_hour @property def waste_type(self): @@ -63,15 +63,15 @@ def dedicated_calendar_title(self): return self._dedicated_calendar_title @property - def start_hours_before(self): - return self._start_hours_before + def start_hour(self): + return self._start_hour @property - def end_hours_after(self): - return self._end_hours_after + def end_hour(self): + return self._end_hour def __repr__(self): - return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}, start_hours_before={self._start_hours_before}, end_hours_after={self._end_hours_after}}}" + return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}, start_hour={self._start_hour}, end_hour={self._end_hour}}}" def filter_function(entry: Collection, customize: Dict[str, Customize]): @@ -97,10 +97,10 @@ def customize_function(entry: Collection, customize: Dict[str, Customize]): def start_end_time_function(entry: Collection, customize: Dict[str, Customize]): c = customize.get(entry.type) if c is not None: - if c.start_hours_before is not None: - entry.set_start_hours_before(c.start_hours_before) - if c.end_hours_after is not None: - entry.set_end_hours_after(c.end_hours_after) + if c.start_hour is not None: + entry.set_start_hour(c.start_hour) + if c.end_hour is not None: + entry.set_end_hour(c.end_hour) return entry @@ -168,7 +168,7 @@ def fetch(self): # filter hidden entries entries = filter(lambda x: filter_function(x, self._customize), entries) - # add optional start and end time to a waster event + # add optional start and end time to a waste event entries = map(lambda x: start_end_time_function(x, self._customize), entries) # customize fetched entries From f93d87aca4ffc284c354acd504f0e3e99f005d10 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Fri, 24 Feb 2023 12:39:58 +0100 Subject: [PATCH 05/12] Reverted to their manifest.json file. --- .../waste_collection_schedule/manifest.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/custom_components/waste_collection_schedule/manifest.json b/custom_components/waste_collection_schedule/manifest.json index 2574940ef..a2159e617 100644 --- a/custom_components/waste_collection_schedule/manifest.json +++ b/custom_components/waste_collection_schedule/manifest.json @@ -1,11 +1,12 @@ { "domain": "waste_collection_schedule", "name": "waste_collection_schedule", - "codeowners": ["@mampfes"], - "dependencies": [], "documentation": "https://github.com/mampfes/hacs_waste_collection_schedule#readme", - "integration_type": "hub", + "requirements": ["icalendar", "recurring_ical_events", "icalevents", "bs4"], + "dependencies": [], + "codeowners": ["@mampfes"], "iot_class": "cloud_polling", - "requirements": ["icalendar", "recurring_ical_events", "icalevents", "beautifulsoup4", "lxml"], - "version": "1.49.0" + "version": "1.34.0", + "integration_type": "hub", + "loggers": ["custom_components.waste_collection_schedule"] } From aa7037f859ec83105b1af5ee4db049ed807de1e3 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sat, 29 Apr 2023 22:31:57 +0200 Subject: [PATCH 06/12] Added timezone to calendar events as this is required since HA 2023.4.x --- .../waste_collection_schedule/calendar.py | 15 +++++++++++++-- .../waste_collection_schedule/manifest.json | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index da3abc45d..8fc8d999c 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -1,10 +1,11 @@ """Calendar platform support for Waste Collection Schedule.""" import logging -from datetime import datetime, timedelta, time +from datetime import datetime, timedelta, time, tzinfo from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.core import HomeAssistant +from homeassistant.util import dt as dt_util # fmt: off from custom_components.waste_collection_schedule.waste_collection_schedule.collection_aggregator import \ @@ -27,6 +28,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= api = discovery_info["api"] + tz = dt_util.get_time_zone(hass.config.time_zone) if hass.config.time_zone is not None else None + for shell in api.shells: dedicated_calendar_types = shell.get_dedicated_calendar_types() for type in dedicated_calendar_types: @@ -37,6 +40,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= name=shell.get_calendar_title_for_type(type), include_types={shell.get_collection_type_name(type)}, unique_id=calc_unique_calendar_id(shell, type), + timezone=tz ) ) @@ -50,6 +54,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= for type in dedicated_calendar_types }, unique_id=calc_unique_calendar_id(shell), + timezone=tz ) ) @@ -65,6 +70,7 @@ def __init__( aggregator, name, unique_id: str, + timezone: tzinfo, include_types=None, exclude_types=None, ): @@ -75,6 +81,7 @@ def __init__( self._exclude_types = exclude_types self._unique_id = unique_id self._attr_unique_id = unique_id + self._timezone = timezone if timezone is not None else dt_util.DEFAULT_TIME_ZONE @property def name(self): @@ -117,7 +124,11 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" if collection.start_hour is not None and collection.end_hour is not None: - event_date_time = datetime.combine(collection.date, time(hour=0, minute=0, second=0)) + event_date_time = datetime.combine( + collection.date, + time(hour=0, minute=0, second=0), + self._timezone + ) return CalendarEvent( summary=collection.type, start=event_date_time + timedelta(hours=collection.start_hour), diff --git a/custom_components/waste_collection_schedule/manifest.json b/custom_components/waste_collection_schedule/manifest.json index a2159e617..4332fb88f 100644 --- a/custom_components/waste_collection_schedule/manifest.json +++ b/custom_components/waste_collection_schedule/manifest.json @@ -6,7 +6,7 @@ "dependencies": [], "codeowners": ["@mampfes"], "iot_class": "cloud_polling", - "version": "1.34.0", + "version": "1.34.1", "integration_type": "hub", "loggers": ["custom_components.waste_collection_schedule"] } From 3f19d4c6c8e3abddd1dff1cff0ce9a838d11a44c Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sun, 22 Jan 2023 15:31:15 +0100 Subject: [PATCH 07/12] Added support for waste event start and event time. --- .../waste_collection_schedule/calendar.py | 7 ++++++ .../waste_collection_schedule/collection.py | 18 ++++++++++++- .../waste_collection_schedule/source_shell.py | 25 ++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index f76abaa79..981cb0107 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -116,6 +116,13 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" + if collection.start_hours_before is not None and collection.end_hours_after is not None: + return CalendarEvent( + summary=collection.type, + start=collection.date + timedelta(hours=collection.start_hours_before), + end=collection.date + timedelta(hours=collection.end_hours_after), + ) + return CalendarEvent( summary=collection.type, start=collection.date, diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py index 16f2b9105..f08b3ab17 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py @@ -9,7 +9,7 @@ def __init__( icon: Optional[str] = None, picture: Optional[str] = None, ): - dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture) + dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture, start_hours_before=None, end_hours_after=None) self._date = date # store date also as python date object @property @@ -34,6 +34,22 @@ def picture(self): def set_picture(self, picture: str): self["picture"] = picture + @property + def start_hours_before(self): + return self["start_hours_before"] + + @property + def start_hours_before(self, hours: int): + self["start_hours_before"] = hours + + @property + def end_hours_after(self): + return self["end_hours_after"] + + @property + def end_hours_after(self, hours: int): + self["end_hours_after"] = hours + class Collection(CollectionBase): def __init__( diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py index 6f53c5d1a..65f252e00 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py @@ -21,6 +21,8 @@ def __init__( picture=None, use_dedicated_calendar=False, dedicated_calendar_title=None, + start_hours_before=None, + end_hours_after=None, ): self._waste_type = waste_type self._alias = alias @@ -29,6 +31,8 @@ def __init__( self._picture = picture self._use_dedicated_calendar = use_dedicated_calendar self._dedicated_calendar_title = dedicated_calendar_title + self._start_hours_before = start_hours_before + self._end_hours_after = end_hours_after @property def waste_type(self): @@ -58,8 +62,16 @@ def use_dedicated_calendar(self): def dedicated_calendar_title(self): return self._dedicated_calendar_title + @property + def start_hours_before(self): + return self._start_hours_before + + @property + def end_hours_after(self): + return self._end_hours_after + def __repr__(self): - return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}}}" + return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}, start_hours_before={self._start_hours_before}, end_hours_after={self._end_hours_after}}}" def filter_function(entry: Collection, customize: Dict[str, Customize]): @@ -82,6 +94,14 @@ def customize_function(entry: Collection, customize: Dict[str, Customize]): return entry +def start_end_time_function(entry: Collection, customize: Dict[str, Customize]): + if customize.start_hours_before is not None: + entry.start_hours_before(customize.start_hours_before) + if customize.end_hours_after is not None: + entry.end_hours_after(customize.end_hours_after) + return entry + + class SourceShell: def __init__( self, @@ -149,6 +169,9 @@ def fetch(self): # customize fetched entries entries = map(lambda x: customize_function(x, self._customize), entries) + # add optional start and end time to a waster event + entries = map(lambda x: start_end_time_function(x, self._customize), entries) + self._entries = list(entries) def get_dedicated_calendar_types(self): From ed2fd27626341657e284518c0269c5a8f1daab6f Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sun, 22 Jan 2023 15:49:13 +0100 Subject: [PATCH 08/12] Added new config fields to schema. --- custom_components/waste_collection_schedule/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py index 91af47789..e83b37f03 100644 --- a/custom_components/waste_collection_schedule/__init__.py +++ b/custom_components/waste_collection_schedule/__init__.py @@ -40,6 +40,8 @@ CONF_PICTURE = "picture" CONF_USE_DEDICATED_CALENDAR = "use_dedicated_calendar" CONF_DEDICATED_CALENDAR_TITLE = "dedicated_calendar_title" +CONF_START_HOURS_BEFORE = "start_hours_before" +CONF_END_HOURS_AFTER = "end_hours_after" CUSTOMIZE_CONFIG = vol.Schema( { @@ -50,6 +52,8 @@ vol.Optional(CONF_PICTURE): cv.string, vol.Optional(CONF_USE_DEDICATED_CALENDAR): cv.boolean, vol.Optional(CONF_DEDICATED_CALENDAR_TITLE): cv.string, + vol.Optional(CONF_START_HOURS_BEFORE): cv.string, + vol.Optional(CONF_END_HOURS_AFTER): cv.string, } ) From 6cd7a9c3869067678d486e301f10b53546ce59f9 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sun, 22 Jan 2023 16:39:44 +0100 Subject: [PATCH 09/12] Fixed in event time customization. --- .../waste_collection_schedule/__init__.py | 2 ++ .../waste_collection_schedule/calendar.py | 7 ++++--- .../waste_collection_schedule/collection.py | 10 ++++------ .../waste_collection_schedule/source_shell.py | 16 +++++++++------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py index e83b37f03..07d80be03 100644 --- a/custom_components/waste_collection_schedule/__init__.py +++ b/custom_components/waste_collection_schedule/__init__.py @@ -110,6 +110,8 @@ async def async_setup(hass: HomeAssistant, config: dict): picture=c.get(CONF_PICTURE), use_dedicated_calendar=c.get(CONF_USE_DEDICATED_CALENDAR, False), dedicated_calendar_title=c.get(CONF_DEDICATED_CALENDAR_TITLE, False), + start_hours_before=c.get(CONF_START_HOURS_BEFORE, None), + end_hours_after=c.get(CONF_END_HOURS_AFTER, None), ) await hass.async_add_executor_job( api.add_source_shell, diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index 981cb0107..ce2229457 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -1,7 +1,7 @@ """Calendar platform support for Waste Collection Schedule.""" import logging -from datetime import datetime, timedelta +from datetime import datetime, timedelta, time from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.core import HomeAssistant @@ -117,10 +117,11 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" if collection.start_hours_before is not None and collection.end_hours_after is not None: + event_date_time = datetime.combine(collection.date, time(hour=0, minute=0, second=0)) return CalendarEvent( summary=collection.type, - start=collection.date + timedelta(hours=collection.start_hours_before), - end=collection.date + timedelta(hours=collection.end_hours_after), + start=event_date_time - timedelta(hours=collection.start_hours_before), + end=event_date_time + timedelta(hours=collection.end_hours_after), ) return CalendarEvent( diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py index f08b3ab17..b49bcd496 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py @@ -38,17 +38,15 @@ def set_picture(self, picture: str): def start_hours_before(self): return self["start_hours_before"] - @property - def start_hours_before(self, hours: int): - self["start_hours_before"] = hours + def set_start_hours_before(self, hours: int): + self["start_hours_before"] = int(hours) @property def end_hours_after(self): return self["end_hours_after"] - @property - def end_hours_after(self, hours: int): - self["end_hours_after"] = hours + def set_end_hours_after(self, hours: int): + self["end_hours_after"] = int(hours) class Collection(CollectionBase): diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py index 65f252e00..a98755b68 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py @@ -95,10 +95,12 @@ def customize_function(entry: Collection, customize: Dict[str, Customize]): def start_end_time_function(entry: Collection, customize: Dict[str, Customize]): - if customize.start_hours_before is not None: - entry.start_hours_before(customize.start_hours_before) - if customize.end_hours_after is not None: - entry.end_hours_after(customize.end_hours_after) + c = customize.get(entry.type) + if c is not None: + if c.start_hours_before is not None: + entry.set_start_hours_before(c.start_hours_before) + if c.end_hours_after is not None: + entry.set_end_hours_after(c.end_hours_after) return entry @@ -166,12 +168,12 @@ def fetch(self): # filter hidden entries entries = filter(lambda x: filter_function(x, self._customize), entries) - # customize fetched entries - entries = map(lambda x: customize_function(x, self._customize), entries) - # add optional start and end time to a waster event entries = map(lambda x: start_end_time_function(x, self._customize), entries) + # customize fetched entries + entries = map(lambda x: customize_function(x, self._customize), entries) + self._entries = list(entries) def get_dedicated_calendar_types(self): From 71c68ece4289a7ba14b777a10bedd28fe594191e Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Tue, 24 Jan 2023 11:23:07 +0100 Subject: [PATCH 10/12] Renamed/simplied waste event time config. --- .../waste_collection_schedule/__init__.py | 12 ++++---- .../waste_collection_schedule/calendar.py | 6 ++-- .../waste_collection_schedule/collection.py | 18 ++++++------ .../waste_collection_schedule/source_shell.py | 28 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/custom_components/waste_collection_schedule/__init__.py b/custom_components/waste_collection_schedule/__init__.py index 07d80be03..49c7a3893 100644 --- a/custom_components/waste_collection_schedule/__init__.py +++ b/custom_components/waste_collection_schedule/__init__.py @@ -40,8 +40,8 @@ CONF_PICTURE = "picture" CONF_USE_DEDICATED_CALENDAR = "use_dedicated_calendar" CONF_DEDICATED_CALENDAR_TITLE = "dedicated_calendar_title" -CONF_START_HOURS_BEFORE = "start_hours_before" -CONF_END_HOURS_AFTER = "end_hours_after" +CONF_START_HOUR = "start_hour" +CONF_END_HOUR = "end_hour" CUSTOMIZE_CONFIG = vol.Schema( { @@ -52,8 +52,8 @@ vol.Optional(CONF_PICTURE): cv.string, vol.Optional(CONF_USE_DEDICATED_CALENDAR): cv.boolean, vol.Optional(CONF_DEDICATED_CALENDAR_TITLE): cv.string, - vol.Optional(CONF_START_HOURS_BEFORE): cv.string, - vol.Optional(CONF_END_HOURS_AFTER): cv.string, + vol.Optional(CONF_START_HOUR): cv.string, + vol.Optional(CONF_END_HOUR): cv.string, } ) @@ -110,8 +110,8 @@ async def async_setup(hass: HomeAssistant, config: dict): picture=c.get(CONF_PICTURE), use_dedicated_calendar=c.get(CONF_USE_DEDICATED_CALENDAR, False), dedicated_calendar_title=c.get(CONF_DEDICATED_CALENDAR_TITLE, False), - start_hours_before=c.get(CONF_START_HOURS_BEFORE, None), - end_hours_after=c.get(CONF_END_HOURS_AFTER, None), + start_hour=c.get(CONF_START_HOUR, None), + end_hour=c.get(CONF_END_HOUR, None), ) await hass.async_add_executor_job( api.add_source_shell, diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index ce2229457..da3abc45d 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -116,12 +116,12 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" - if collection.start_hours_before is not None and collection.end_hours_after is not None: + if collection.start_hour is not None and collection.end_hour is not None: event_date_time = datetime.combine(collection.date, time(hour=0, minute=0, second=0)) return CalendarEvent( summary=collection.type, - start=event_date_time - timedelta(hours=collection.start_hours_before), - end=event_date_time + timedelta(hours=collection.end_hours_after), + start=event_date_time + timedelta(hours=collection.start_hour), + end=event_date_time + timedelta(hours=collection.end_hour), ) return CalendarEvent( diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py index b49bcd496..f5f9c00b9 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/collection.py @@ -9,7 +9,7 @@ def __init__( icon: Optional[str] = None, picture: Optional[str] = None, ): - dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture, start_hours_before=None, end_hours_after=None) + dict.__init__(self, date=date.isoformat(), icon=icon, picture=picture, start_hour=None, end_hour=None) self._date = date # store date also as python date object @property @@ -35,18 +35,18 @@ def set_picture(self, picture: str): self["picture"] = picture @property - def start_hours_before(self): - return self["start_hours_before"] + def start_hour(self): + return self["start_hour"] - def set_start_hours_before(self, hours: int): - self["start_hours_before"] = int(hours) + def set_start_hour(self, hours: int): + self["start_hour"] = int(hours) @property - def end_hours_after(self): - return self["end_hours_after"] + def end_hour(self): + return self["end_hour"] - def set_end_hours_after(self, hours: int): - self["end_hours_after"] = int(hours) + def set_end_hour(self, hours: int): + self["end_hour"] = int(hours) class Collection(CollectionBase): diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py index a98755b68..a4660bf33 100644 --- a/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py +++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py @@ -21,8 +21,8 @@ def __init__( picture=None, use_dedicated_calendar=False, dedicated_calendar_title=None, - start_hours_before=None, - end_hours_after=None, + start_hour=None, + end_hour=None, ): self._waste_type = waste_type self._alias = alias @@ -31,8 +31,8 @@ def __init__( self._picture = picture self._use_dedicated_calendar = use_dedicated_calendar self._dedicated_calendar_title = dedicated_calendar_title - self._start_hours_before = start_hours_before - self._end_hours_after = end_hours_after + self._start_hour = start_hour + self._end_hour = end_hour @property def waste_type(self): @@ -63,15 +63,15 @@ def dedicated_calendar_title(self): return self._dedicated_calendar_title @property - def start_hours_before(self): - return self._start_hours_before + def start_hour(self): + return self._start_hour @property - def end_hours_after(self): - return self._end_hours_after + def end_hour(self): + return self._end_hour def __repr__(self): - return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}, start_hours_before={self._start_hours_before}, end_hours_after={self._end_hours_after}}}" + return f"Customize{{waste_type={self._waste_type}, alias={self._alias}, show={self._show}, icon={self._icon}, picture={self._picture}, start_hour={self._start_hour}, end_hour={self._end_hour}}}" def filter_function(entry: Collection, customize: Dict[str, Customize]): @@ -97,10 +97,10 @@ def customize_function(entry: Collection, customize: Dict[str, Customize]): def start_end_time_function(entry: Collection, customize: Dict[str, Customize]): c = customize.get(entry.type) if c is not None: - if c.start_hours_before is not None: - entry.set_start_hours_before(c.start_hours_before) - if c.end_hours_after is not None: - entry.set_end_hours_after(c.end_hours_after) + if c.start_hour is not None: + entry.set_start_hour(c.start_hour) + if c.end_hour is not None: + entry.set_end_hour(c.end_hour) return entry @@ -168,7 +168,7 @@ def fetch(self): # filter hidden entries entries = filter(lambda x: filter_function(x, self._customize), entries) - # add optional start and end time to a waster event + # add optional start and end time to a waste event entries = map(lambda x: start_end_time_function(x, self._customize), entries) # customize fetched entries From f05bf5f714a687d5001468cef9bc50d444ba4103 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Fri, 24 Feb 2023 12:39:58 +0100 Subject: [PATCH 11/12] Reset manifest.json to their version. --- .../waste_collection_schedule/manifest.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/custom_components/waste_collection_schedule/manifest.json b/custom_components/waste_collection_schedule/manifest.json index 2574940ef..a2159e617 100644 --- a/custom_components/waste_collection_schedule/manifest.json +++ b/custom_components/waste_collection_schedule/manifest.json @@ -1,11 +1,12 @@ { "domain": "waste_collection_schedule", "name": "waste_collection_schedule", - "codeowners": ["@mampfes"], - "dependencies": [], "documentation": "https://github.com/mampfes/hacs_waste_collection_schedule#readme", - "integration_type": "hub", + "requirements": ["icalendar", "recurring_ical_events", "icalevents", "bs4"], + "dependencies": [], + "codeowners": ["@mampfes"], "iot_class": "cloud_polling", - "requirements": ["icalendar", "recurring_ical_events", "icalevents", "beautifulsoup4", "lxml"], - "version": "1.49.0" + "version": "1.34.0", + "integration_type": "hub", + "loggers": ["custom_components.waste_collection_schedule"] } From 78c6ecb92b800406fb77f45928e3f850fdcce740 Mon Sep 17 00:00:00 2001 From: Sander Peterse Date: Sat, 29 Apr 2023 22:31:57 +0200 Subject: [PATCH 12/12] Added timezone to calendar events as this is required since HA 2023.4.x --- .../waste_collection_schedule/calendar.py | 15 +++++++++++++-- .../waste_collection_schedule/manifest.json | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/custom_components/waste_collection_schedule/calendar.py b/custom_components/waste_collection_schedule/calendar.py index da3abc45d..8fc8d999c 100644 --- a/custom_components/waste_collection_schedule/calendar.py +++ b/custom_components/waste_collection_schedule/calendar.py @@ -1,10 +1,11 @@ """Calendar platform support for Waste Collection Schedule.""" import logging -from datetime import datetime, timedelta, time +from datetime import datetime, timedelta, time, tzinfo from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.core import HomeAssistant +from homeassistant.util import dt as dt_util # fmt: off from custom_components.waste_collection_schedule.waste_collection_schedule.collection_aggregator import \ @@ -27,6 +28,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= api = discovery_info["api"] + tz = dt_util.get_time_zone(hass.config.time_zone) if hass.config.time_zone is not None else None + for shell in api.shells: dedicated_calendar_types = shell.get_dedicated_calendar_types() for type in dedicated_calendar_types: @@ -37,6 +40,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= name=shell.get_calendar_title_for_type(type), include_types={shell.get_collection_type_name(type)}, unique_id=calc_unique_calendar_id(shell, type), + timezone=tz ) ) @@ -50,6 +54,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= for type in dedicated_calendar_types }, unique_id=calc_unique_calendar_id(shell), + timezone=tz ) ) @@ -65,6 +70,7 @@ def __init__( aggregator, name, unique_id: str, + timezone: tzinfo, include_types=None, exclude_types=None, ): @@ -75,6 +81,7 @@ def __init__( self._exclude_types = exclude_types self._unique_id = unique_id self._attr_unique_id = unique_id + self._timezone = timezone if timezone is not None else dt_util.DEFAULT_TIME_ZONE @property def name(self): @@ -117,7 +124,11 @@ async def async_get_events( def _convert(self, collection) -> CalendarEvent: """Convert an collection into a Home Assistant calendar event.""" if collection.start_hour is not None and collection.end_hour is not None: - event_date_time = datetime.combine(collection.date, time(hour=0, minute=0, second=0)) + event_date_time = datetime.combine( + collection.date, + time(hour=0, minute=0, second=0), + self._timezone + ) return CalendarEvent( summary=collection.type, start=event_date_time + timedelta(hours=collection.start_hour), diff --git a/custom_components/waste_collection_schedule/manifest.json b/custom_components/waste_collection_schedule/manifest.json index a2159e617..4332fb88f 100644 --- a/custom_components/waste_collection_schedule/manifest.json +++ b/custom_components/waste_collection_schedule/manifest.json @@ -6,7 +6,7 @@ "dependencies": [], "codeowners": ["@mampfes"], "iot_class": "cloud_polling", - "version": "1.34.0", + "version": "1.34.1", "integration_type": "hub", "loggers": ["custom_components.waste_collection_schedule"] }