core/homeassistant/components/caldav/calendar.py

177 lines
6.0 KiB
Python
Raw Normal View History

"""Support for WebDav Calendar."""
from __future__ import annotations
from datetime import datetime
import logging
import caldav
import voluptuous as vol
from homeassistant.components.calendar import (
2019-07-31 19:25:30 +00:00
ENTITY_ID_FORMAT,
PLATFORM_SCHEMA,
CalendarEntity,
CalendarEvent,
2019-07-31 19:25:30 +00:00
is_offset_reached,
)
from homeassistant.const import (
2019-07-31 19:25:30 +00:00
CONF_NAME,
CONF_PASSWORD,
CONF_URL,
CONF_USERNAME,
CONF_VERIFY_SSL,
)
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .coordinator import CalDavUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
2019-07-31 19:25:30 +00:00
CONF_CALENDARS = "calendars"
CONF_CUSTOM_CALENDARS = "custom_calendars"
CONF_CALENDAR = "calendar"
CONF_SEARCH = "search"
CONF_DAYS = "days"
2019-07-31 19:25:30 +00:00
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_URL): vol.Url(),
vol.Optional(CONF_CALENDARS, default=[]): vol.All(cv.ensure_list, [cv.string]),
vol.Inclusive(CONF_USERNAME, "authentication"): cv.string,
vol.Inclusive(CONF_PASSWORD, "authentication"): cv.string,
vol.Optional(CONF_CUSTOM_CALENDARS, default=[]): vol.All(
cv.ensure_list,
[
vol.Schema(
{
vol.Required(CONF_CALENDAR): cv.string,
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_SEARCH): cv.string,
}
)
],
),
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
vol.Optional(CONF_DAYS, default=1): cv.positive_int,
2019-07-31 19:25:30 +00:00
}
)
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
disc_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the WebDav Calendar platform."""
url = config[CONF_URL]
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
days = config[CONF_DAYS]
client = caldav.DAVClient(
2019-07-31 19:25:30 +00:00
url, None, username, password, ssl_verify_cert=config[CONF_VERIFY_SSL]
)
calendars = client.principal().calendars()
calendar_devices = []
2023-08-13 16:58:55 +00:00
device_id: str | None
for calendar in list(calendars):
# If a calendar name was given in the configuration,
# ignore all the others
2019-07-31 19:25:30 +00:00
if config[CONF_CALENDARS] and calendar.name not in config[CONF_CALENDARS]:
_LOGGER.debug("Ignoring calendar '%s'", calendar.name)
continue
# Create additional calendars based on custom filtering rules
for cust_calendar in config[CONF_CUSTOM_CALENDARS]:
# Check that the base calendar matches
if cust_calendar[CONF_CALENDAR] != calendar.name:
continue
name = cust_calendar[CONF_NAME]
device_id = f"{cust_calendar[CONF_CALENDAR]} {cust_calendar[CONF_NAME]}"
2019-07-31 19:25:30 +00:00
entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass)
coordinator = CalDavUpdateCoordinator(
hass,
calendar=calendar,
days=days,
include_all_day=True,
search=cust_calendar[CONF_SEARCH],
2019-07-31 19:25:30 +00:00
)
calendar_devices.append(WebDavCalendarEntity(name, entity_id, coordinator))
# Create a default calendar if there was no custom one for all calendars
# that support events.
if not config[CONF_CUSTOM_CALENDARS]:
if (
supported_components := calendar.get_supported_components()
) and "VEVENT" not in supported_components:
_LOGGER.debug(
"Ignoring calendar '%s' (components=%s)",
calendar.name,
supported_components,
)
continue
name = calendar.name
device_id = calendar.name
2019-07-31 19:25:30 +00:00
entity_id = generate_entity_id(ENTITY_ID_FORMAT, device_id, hass=hass)
coordinator = CalDavUpdateCoordinator(
hass,
calendar=calendar,
days=days,
include_all_day=False,
search=None,
)
calendar_devices.append(WebDavCalendarEntity(name, entity_id, coordinator))
add_entities(calendar_devices, True)
class WebDavCalendarEntity(CoordinatorEntity[CalDavUpdateCoordinator], CalendarEntity):
"""A device for getting the next Task from a WebDav Calendar."""
def __init__(self, name, entity_id, coordinator):
"""Create the WebDav Calendar Event Device."""
super().__init__(coordinator)
self.entity_id = entity_id
self._event: CalendarEvent | None = None
self._attr_name = name
@property
def event(self) -> CalendarEvent | None:
"""Return the next upcoming event."""
return self._event
2022-08-19 11:02:46 +00:00
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
) -> list[CalendarEvent]:
"""Get all events in a specific time frame."""
return await self.coordinator.async_get_events(hass, start_date, end_date)
@callback
def _handle_coordinator_update(self) -> None:
"""Update event data."""
self._event = self.coordinator.data
self._attr_extra_state_attributes = {
"offset_reached": is_offset_reached(
self._event.start_datetime_local, self.coordinator.offset
)
if self._event
else False
}
super()._handle_coordinator_update()
async def async_added_to_hass(self) -> None:
"""When entity is added to hass update state from existing coordinator data."""
await super().async_added_to_hass()
self._handle_coordinator_update()