import os from datetime import datetime from typing import Dict, List from flask import Blueprint from babel.dates import format_date from dashboard_leaf.logic import Helpers from dashboard_leaf.logic.service.ServiceManager import ServiceManager from dashboard_leaf.logic.service.services.IcsService import CalendarEvent from dashboard_leaf.logic.tile.Tile import Tile class GarbageContainerScheduleTile(Tile): DATE_FORMAT = 'E dd.MM' ICON_BY_GARBAGE_TYPE = { 'Papier': 'garbage_paper', 'Papiertonnen': 'garbage_paper', 'Gelbe Tonne': 'garbage_plastic', 'Gelbe Säcke': 'garbage_plastic', 'Bioabfall': 'garbage_bio', 'Restabfall': 'garbage_waste', 'Restmülltonnen': 'garbage_waste' } EXAMPLE_SETTINGS = { "path": "path/to/my/calendar.ics", "garbageType": "Papier" or "Gelbe Tonne" or "Bioabfall" or "Restabfall", "notificationViaPushbullet": { "enable": False, "daysBeforeEvent": 1, "hour": 10, "pushbulletToken": None } } def __init__(self, uniqueName: str, settings: Dict, intervalInSeconds: int): super().__init__(uniqueName, settings, intervalInSeconds) self._lastNotificationDate = None def fetch(self, pageName: str) -> Dict: icsService = ServiceManager.get_instance().get_service_by_type_name('IcsService') cacheKey = f'{pageName}_{self._uniqueName}' events = icsService.get_data(cacheKey, self._intervalInSeconds, self._settings)['events'] eventsForGarbageType = [x for x in events if self._settings['garbageType'] in x.summary] eventsForGarbageType.sort(key=lambda event: event.start) nextEvent = self.__find_next_date(eventsForGarbageType) nextEventDate = '--.--.' remainingDays = '' if nextEvent: nextEventDate = nextEvent.start if isinstance(nextEventDate, datetime): remainingDays = nextEventDate - self._get_current_date_time() else: remainingDays = nextEventDate - self._get_current_date_time().date() remainingDays = remainingDays.days nextEventDate = format_date(nextEventDate, self.DATE_FORMAT, 'de') iconName = self.ICON_BY_GARBAGE_TYPE[self._settings['garbageType']] self._send_notification(remainingDays, nextEventDate) return { 'nextEventDate': nextEventDate, 'iconFileName': f'{iconName}.png', 'remainingDays': remainingDays } def _get_current_date_time(self) -> datetime: return datetime.now() def __find_next_date(self, events: List[CalendarEvent]) -> CalendarEvent or None: now = self._get_current_date_time().date() for event in events: if event.start < now: continue return event return None def _send_notification(self, remainingDays: int, nextEventDate: str): notificationSettings = self._settings['notificationViaPushbullet'] if not notificationSettings['enable']: self._lastNotificationDate = None return if remainingDays != notificationSettings['daysBeforeEvent']: self._lastNotificationDate = None return now = self._get_current_date_time() if now.hour < notificationSettings['hour']: self._lastNotificationDate = None return if self._is_already_notified(now): return self._lastNotificationDate = now.date() title = 'DashboardLeaf - Garbage Schedule Notification' description = f'"{self._settings["garbageType"]}" will be collected in {remainingDays} days ({nextEventDate})' Helpers.send_notification_via_pushbullet(notificationSettings['pushbulletToken'], title, description) def _is_already_notified(self, now: datetime) -> bool: if self._lastNotificationDate is None: return False return self._lastNotificationDate == now.date() def render(self, data: Dict) -> str: return Tile.render_template(os.path.dirname(__file__), __class__.__name__, data=data) def construct_blueprint(self, pageName: str, *args, **kwargs): return Blueprint(f'{pageName}_{__class__.__name__}_{self.get_uniqueName()}', __name__)