261 lines
8.5 KiB
Python
261 lines
8.5 KiB
Python
"""ics Calendar for Home Assistant."""
|
|
|
|
import logging
|
|
|
|
import homeassistant.helpers.config_validation as cv
|
|
import voluptuous as vol
|
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
|
from homeassistant.const import (
|
|
CONF_EXCLUDE,
|
|
CONF_INCLUDE,
|
|
CONF_NAME,
|
|
CONF_PASSWORD,
|
|
CONF_PREFIX,
|
|
CONF_URL,
|
|
CONF_USERNAME,
|
|
Platform,
|
|
)
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers import discovery
|
|
from homeassistant.helpers.issue_registry import (
|
|
IssueSeverity,
|
|
async_create_issue,
|
|
)
|
|
from homeassistant.helpers.typing import ConfigType
|
|
|
|
from .const import (
|
|
CONF_ACCEPT_HEADER,
|
|
CONF_ADV_CONNECT_OPTS,
|
|
CONF_CALENDARS,
|
|
CONF_CONNECTION_TIMEOUT,
|
|
CONF_DAYS,
|
|
CONF_DOWNLOAD_INTERVAL,
|
|
CONF_INCLUDE_ALL_DAY,
|
|
CONF_OFFSET_HOURS,
|
|
CONF_PARSER,
|
|
CONF_REQUIRES_AUTH,
|
|
CONF_SET_TIMEOUT,
|
|
CONF_SUMMARY_DEFAULT,
|
|
CONF_SUMMARY_DEFAULT_DEFAULT,
|
|
CONF_USER_AGENT,
|
|
DOMAIN,
|
|
)
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
PLATFORMS: list[Platform] = [Platform.CALENDAR]
|
|
|
|
CONFIG_SCHEMA = vol.Schema(
|
|
{
|
|
DOMAIN: vol.Schema(
|
|
{
|
|
# pylint: disable=no-value-for-parameter
|
|
vol.Optional(CONF_CALENDARS, default=[]): vol.All(
|
|
cv.ensure_list,
|
|
vol.Schema(
|
|
[
|
|
vol.Schema(
|
|
{
|
|
vol.Required(CONF_URL): vol.Url(),
|
|
vol.Required(CONF_NAME): cv.string,
|
|
vol.Optional(
|
|
CONF_INCLUDE_ALL_DAY, default=False
|
|
): cv.boolean,
|
|
vol.Optional(
|
|
CONF_USERNAME, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_PASSWORD, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_PARSER, default="rie"
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_PREFIX, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_DAYS, default=1
|
|
): cv.positive_int,
|
|
vol.Optional(
|
|
CONF_DOWNLOAD_INTERVAL, default=15
|
|
): cv.positive_int,
|
|
vol.Optional(
|
|
CONF_USER_AGENT, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_EXCLUDE, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_INCLUDE, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_OFFSET_HOURS, default=0
|
|
): int,
|
|
vol.Optional(
|
|
CONF_ACCEPT_HEADER, default=""
|
|
): cv.string,
|
|
vol.Optional(
|
|
CONF_CONNECTION_TIMEOUT, default=300
|
|
): cv.positive_float,
|
|
vol.Optional(
|
|
CONF_SUMMARY_DEFAULT,
|
|
default=CONF_SUMMARY_DEFAULT_DEFAULT,
|
|
): cv.string,
|
|
}
|
|
)
|
|
]
|
|
),
|
|
)
|
|
}
|
|
)
|
|
},
|
|
extra=vol.ALLOW_EXTRA,
|
|
)
|
|
|
|
STORAGE_KEY = DOMAIN
|
|
STORAGE_VERSION_MAJOR = 1
|
|
STORAGE_VERSION_MINOR = 0
|
|
|
|
|
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|
"""Set up calendars."""
|
|
_LOGGER.debug("Setting up ics_calendar component")
|
|
hass.data.setdefault(DOMAIN, {})
|
|
|
|
if DOMAIN in config and config[DOMAIN]:
|
|
_LOGGER.debug("discovery.load_platform called")
|
|
discovery.load_platform(
|
|
hass=hass,
|
|
component=PLATFORMS[0],
|
|
platform=DOMAIN,
|
|
discovered=config[DOMAIN],
|
|
hass_config=config,
|
|
)
|
|
async_create_issue(
|
|
hass,
|
|
DOMAIN,
|
|
"deprecated_yaml_configuration",
|
|
is_fixable=False,
|
|
issue_domain=DOMAIN,
|
|
severity=IssueSeverity.WARNING,
|
|
translation_key="YAML_Warning",
|
|
)
|
|
_LOGGER.warning(
|
|
"YAML configuration of ics_calendar is deprecated and will be "
|
|
"removed in ics_calendar v5.0.0. Your configuration items have "
|
|
"been imported. Please remove them from your configuration.yaml "
|
|
"file."
|
|
)
|
|
|
|
config_entry = _async_find_matching_config_entry(hass)
|
|
if not config_entry:
|
|
if config[DOMAIN].get("calendars"):
|
|
for calendar in config[DOMAIN].get("calendars"):
|
|
hass.async_create_task(
|
|
hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": SOURCE_IMPORT},
|
|
data=dict(calendar),
|
|
)
|
|
)
|
|
return True
|
|
|
|
# update entry with any changes
|
|
if config[DOMAIN].get("calendars"):
|
|
for calendar in config[DOMAIN].get("calendars"):
|
|
hass.config_entries.async_update_entry(
|
|
config_entry, data=dict(calendar)
|
|
)
|
|
|
|
return True
|
|
|
|
|
|
@callback
|
|
def _async_find_matching_config_entry(hass):
|
|
for entry in hass.config_entries.async_entries(DOMAIN):
|
|
if entry.source == SOURCE_IMPORT:
|
|
return entry
|
|
return None
|
|
|
|
|
|
async def async_migrate_entry(hass, entry: ConfigEntry):
|
|
"""Migrate old config entry."""
|
|
# Don't downgrade entries
|
|
if entry.version > STORAGE_VERSION_MAJOR:
|
|
return False
|
|
|
|
if entry.version == STORAGE_VERSION_MAJOR:
|
|
new_data = {**entry.data}
|
|
|
|
hass.config_entries.async_update_entry(
|
|
entry,
|
|
data=new_data,
|
|
minor_version=STORAGE_VERSION_MINOR,
|
|
version=STORAGE_VERSION_MAJOR,
|
|
)
|
|
|
|
return True
|
|
|
|
|
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
"""Implement async_setup_entry."""
|
|
full_data: dict = add_missing_defaults(entry)
|
|
hass.config_entries.async_update_entry(entry=entry, data=full_data)
|
|
|
|
hass.data.setdefault(DOMAIN, {})
|
|
hass.data[DOMAIN][entry.entry_id] = full_data
|
|
await hass.config_entries.async_forward_entry_setups(entry, ["calendar"])
|
|
return True
|
|
|
|
|
|
def add_missing_defaults(
|
|
entry: ConfigEntry,
|
|
) -> dict:
|
|
"""Initialize missing data."""
|
|
data = {
|
|
CONF_NAME: "",
|
|
CONF_URL: "",
|
|
CONF_ADV_CONNECT_OPTS: False,
|
|
CONF_SET_TIMEOUT: False,
|
|
CONF_REQUIRES_AUTH: False,
|
|
CONF_INCLUDE_ALL_DAY: False,
|
|
CONF_REQUIRES_AUTH: False,
|
|
CONF_USERNAME: "",
|
|
CONF_PASSWORD: "",
|
|
CONF_PARSER: "rie",
|
|
CONF_PREFIX: "",
|
|
CONF_DAYS: 1,
|
|
CONF_DOWNLOAD_INTERVAL: 15,
|
|
CONF_USER_AGENT: "",
|
|
CONF_EXCLUDE: "",
|
|
CONF_INCLUDE: "",
|
|
CONF_OFFSET_HOURS: 0,
|
|
CONF_ACCEPT_HEADER: "",
|
|
CONF_CONNECTION_TIMEOUT: 300.0,
|
|
CONF_SUMMARY_DEFAULT: CONF_SUMMARY_DEFAULT_DEFAULT,
|
|
}
|
|
data.update(entry.data)
|
|
|
|
if CONF_USERNAME in entry.data or CONF_PASSWORD in entry.data:
|
|
data[CONF_REQUIRES_AUTH] = True
|
|
if (
|
|
CONF_USER_AGENT in entry.data
|
|
or CONF_ACCEPT_HEADER in entry.data
|
|
or CONF_CONNECTION_TIMEOUT in entry.data
|
|
):
|
|
data[CONF_ADV_CONNECT_OPTS] = True
|
|
if CONF_CONNECTION_TIMEOUT in entry.data:
|
|
data[CONF_SET_TIMEOUT] = True
|
|
|
|
return data
|
|
|
|
|
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
"""Unload entry."""
|
|
unload_ok = await hass.config_entries.async_unload_platforms(
|
|
entry, PLATFORMS
|
|
)
|
|
if unload_ok:
|
|
hass.data[DOMAIN].pop(entry.entry_id)
|
|
|
|
return unload_ok
|