def _single_validate(typ, value, key): """Validate a single element.""" # if required argument if value is None: raise vol.Invalid(f"Missing required option '{key}'") # parse extend data from type match = RE_SCHEMA_ELEMENT.match(typ) # prepare range range_args = {} for group_name in ('i_min', 'i_max', 'f_min', 'f_max'): group_value = match.group(group_name) if group_value: range_args[group_name[2:]] = float(group_value) if typ.startswith(V_STR): return str(value) elif typ.startswith(V_INT): return vol.All(vol.Coerce(int), vol.Range(**range_args))(value) elif typ.startswith(V_FLOAT): return vol.All(vol.Coerce(float), vol.Range(**range_args))(value) elif typ.startswith(V_BOOL): return vol.Boolean()(value) elif typ.startswith(V_EMAIL): return vol.Email()(value) elif typ.startswith(V_URL): return vol.Url()(value) elif typ.startswith(V_PORT): return NETWORK_PORT(value) elif typ.startswith(V_MATCH): return vol.Match(match.group('match'))(str(value)) raise vol.Invalid(f"Fatal error for {key} type {typ}")
def _single_validate(typ, value, key): """Validate a single element.""" try: # if required argument if value is None: raise vol.Invalid("Missing required option '{}'.".format(key)) if typ == V_STR: return str(value) elif typ == V_INT: return int(value) elif typ == V_FLOAT: return float(value) elif typ == V_BOOL: return vol.Boolean()(value) elif typ == V_EMAIL: return vol.Email()(value) elif typ == V_URL: return vol.Url()(value) elif typ == V_PORT: return NETWORK_PORT(value) raise vol.Invalid("Fatal error for {} type {}".format(key, typ)) except ValueError: raise vol.Invalid("Type {} error for '{}' on {}.".format( typ, value, key)) from None
def url(value: Any) -> str: """Validate an URL.""" url_in = str(value) if urlparse(url_in).scheme in ['http', 'https']: return vol.Schema(vol.Url())(url_in) raise vol.Invalid('invalid url')
def url(value: Any) -> str: """Validate an URL.""" url_in = str(value) if urlparse(url_in).scheme in ["http", "https"]: return cast(str, vol.Schema(vol.Url())(url_in)) raise vol.Invalid("invalid url")
def url(value: Any, **kwargs) -> str: """Validate an URL.""" url_in = str(value) if urlparse(url_in).scheme in ["http", "https"]: return vol.Schema(vol.Url())(url_in) raise AssertionError("Invalid url")
def get_schema(self): repos = GitHubRepoConfig().get_schema() return { v.Required("url"): v.Url(str), v.Required("username"): v.All(str, v.Length(min=1)), v.Required("password"): v.All(str, v.Length(min=1)), v.Required("repos"): [repos] }
def url(url_in, protocols=None): if protocols is None: protocols = ["http", "https", "sftp", "ftp"] if urlparse(url_in).scheme in protocols: try: return vol.Schema(vol.Url())(url_in) except: pass raise vol.Invalid("Invalid URL.")
def validate_repository(repository): """Validate a valide repository.""" data = RE_REPOSITORY.match(repository) if not data: raise vol.Invalid("No valid repository format!") # Validate URL # pylint: disable=no-value-for-parameter vol.Url()(data.group('url')) return repository
def validate_repository(repository: str) -> str: """Validate a valid repository.""" if repository in [StoreType.CORE.value, StoreType.LOCAL.value]: return repository data = RE_REPOSITORY.match(repository) if not data: raise vol.Invalid("No valid repository format!") from None # Validate URL # pylint: disable=no-value-for-parameter vol.Url()(data.group("url")) return repository
def url(value): """Validate an URL.""" url_in = str(value) if IP_PATTERN.match(value): return value + ':80' if IP_PORT_PATTERN.match(value): return value if urlparse(url_in).scheme in ['http', 'https']: return vol.Schema(vol.Url())(url_in) raise vol.Invalid('invalid url')
def _single_validate(coresys: CoreSys, typ: str, value: Any, key: str): """Validate a single element.""" # if required argument if value is None: raise vol.Invalid(f"Missing required option '{key}'") # Lookup secret if str(value).startswith("!secret "): secret: str = value.partition(" ")[2] value = coresys.secrets.get(secret) if value is None: raise vol.Invalid(f"Unknown secret {secret}") # parse extend data from type match = RE_SCHEMA_ELEMENT.match(typ) if not match: raise vol.Invalid(f"Unknown type {typ}") # prepare range range_args = {} for group_name in _SCHEMA_LENGTH_PARTS: group_value = match.group(group_name) if group_value: range_args[group_name[2:]] = float(group_value) if typ.startswith(V_STR) or typ.startswith(V_PASSWORD): return vol.All(str(value), vol.Range(**range_args))(value) elif typ.startswith(V_INT): return vol.All(vol.Coerce(int), vol.Range(**range_args))(value) elif typ.startswith(V_FLOAT): return vol.All(vol.Coerce(float), vol.Range(**range_args))(value) elif typ.startswith(V_BOOL): return vol.Boolean()(value) elif typ.startswith(V_EMAIL): return vol.Email()(value) elif typ.startswith(V_URL): return vol.Url()(value) elif typ.startswith(V_PORT): return network_port(value) elif typ.startswith(V_MATCH): return vol.Match(match.group("match"))(str(value)) elif typ.startswith(V_LIST): return vol.In(match.group("list").split("|"))(str(value)) raise vol.Invalid(f"Fatal error for {key} type {typ}")
'http://w3.org' """ try: parsed = urlparse.urlparse(v) if not parsed.path or parsed.netloc or parsed.scheme: raise UrlInvalid("must have only a URL path") return parsed except Exception: raise ValueError KEY_SCHEMA = vol.Schema( vol.All( { vol.Optional(CONF_URL, default=''): vol.Any(None, '', vol.Url()), vol.Optional(CONF_PARTURL, default=''): vol.Any(None, '', UrlPath()), vol.Optional(CONF_METHOD, default=''): vol.In(('', 'GET', 'POSTFORM', 'POSTJSON', 'POSTBIN')), vol.Optional(CONF_TIMEOUT, default=0): vol.All(int, vol.Range(min=0)), vol.Optional(CONF_PARAMS, default={}): cv.schema_with_slug_keys(PARAMS_SCHEMA) }, conf_validator_url_or_part)) PLATFORM_SCHEMA = vol.Schema( vol.All( PLATFORM_SCHEMA.extend( { vol.Required(CONF_NAME):
"""Support for launching a web browser on the host machine.""" import voluptuous as vol ATTR_URL = "url" ATTR_URL_DEFAULT = "https://www.google.com" DOMAIN = "browser" SERVICE_BROWSE_URL = "browse_url" SERVICE_BROWSE_URL_SCHEMA = vol.Schema( { # pylint: disable=no-value-for-parameter vol.Required(ATTR_URL, default=ATTR_URL_DEFAULT): vol.Url() } ) def setup(hass, config): """Listen for browse_url events.""" import webbrowser hass.services.register( DOMAIN, SERVICE_BROWSE_URL, lambda service: webbrowser.open(service.data[ATTR_URL]), schema=SERVICE_BROWSE_URL_SCHEMA, ) return True
For more details about this component, please refer to the documentation at https://home-assistant.io/components/feedreader/ """ from datetime import datetime from logging import getLogger import voluptuous as vol from homeassistant.const import EVENT_HOMEASSISTANT_START from homeassistant.helpers.event import track_utc_time_change REQUIREMENTS = ['feedparser==5.2.1'] _LOGGER = getLogger(__name__) DOMAIN = "feedreader" EVENT_FEEDREADER = "feedreader" # pylint: disable=no-value-for-parameter CONFIG_SCHEMA = vol.Schema({DOMAIN: { 'urls': [vol.Url()], }}, extra=vol.ALLOW_EXTRA) MAX_ENTRIES = 20 # pylint: disable=too-few-public-methods class FeedManager(object): """Abstraction over feedparser module.""" def __init__(self, url, hass): """Initialize the FeedManager object, poll every hour.""" self._url = url self._feed = None self._hass = hass self._firstrun = True # Initialize last entry timestamp as epoch time
vol.Optional("vid"): vol.All(str, verify_uppercase), vol.Optional("pid"): vol.All(str, verify_uppercase), vol.Optional("serial_number"): vol.All(str, verify_lowercase), vol.Optional("manufacturer"): vol.All(str, verify_lowercase), vol.Optional("description"): vol.All(str, verify_lowercase), vol.Optional("known_devices"): [str], }) ], vol.Required("documentation"): vol.All( vol.Url(), documentation_url # pylint: disable=no-value-for-parameter ), vol.Optional("issue_tracker"): vol.Url(), # pylint: disable=no-value-for-parameter vol.Optional("quality_scale"): vol.In(SUPPORTED_QUALITY_SCALES), vol.Optional("requirements"): [str], vol.Optional("dependencies"): [str], vol.Optional("after_dependencies"): [str], vol.Required("codeowners"): [str], vol.Optional("disabled"): str, vol.Optional("iot_class"): vol.In(SUPPORTED_IOT_CLASSES), })
{vol.Optional(CONF_ENTITY_CONFIG): {cv.entity_id: GOOGLE_ENTITY_SCHEMA}} ) # pylint: disable=no-value-for-parameter CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( { vol.Optional(CONF_MODE, default=DEFAULT_MODE): vol.In( [MODE_DEV, MODE_PROD] ), vol.Optional(CONF_COGNITO_CLIENT_ID): str, vol.Optional(CONF_USER_POOL_ID): str, vol.Optional(CONF_REGION): str, vol.Optional(CONF_RELAYER): str, vol.Optional(CONF_SUBSCRIPTION_INFO_URL): vol.Url(), vol.Optional(CONF_CLOUDHOOK_CREATE_URL): vol.Url(), vol.Optional(CONF_REMOTE_API_URL): vol.Url(), vol.Optional(CONF_ACME_DIRECTORY_SERVER): vol.Url(), vol.Optional(CONF_ALEXA): ALEXA_SCHEMA, vol.Optional(CONF_GOOGLE_ACTIONS): GACTIONS_SCHEMA, vol.Optional(CONF_ALEXA_ACCESS_TOKEN_URL): vol.Url(), vol.Optional(CONF_GOOGLE_ACTIONS_REPORT_STATE_URL): vol.Url(), vol.Optional(CONF_ACCOUNT_LINK_URL): vol.Url(), vol.Optional(CONF_VOICE_API_URL): vol.Url(), } ) }, extra=vol.ALLOW_EXTRA, )
CONF_RELATIVE_URL_REGEX = r'\A/' CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema({ cv.slug: { # pylint: disable=no-value-for-parameter vol.Optional(CONF_TITLE): cv.string, vol.Optional(CONF_ICON): cv.icon, vol.Required(CONF_URL): vol.Any( vol.Match(CONF_RELATIVE_URL_REGEX, msg=CONF_RELATIVE_URL_ERROR_MSG), vol.Url()), } }) }, extra=vol.ALLOW_EXTRA) @asyncio.coroutine def setup(hass, config): """Set up the iFrame frontend panels.""" for url_path, info in config[DOMAIN].items(): yield from hass.components.frontend.async_register_built_in_panel( 'iframe', info.get(CONF_TITLE), info.get(CONF_ICON), url_path, {'url': info[CONF_URL]}) return True
ATTR_JWT = 'jwt' # The number of days after the moment a notification is sent that a JWT # is valid. JWT_VALID_DAYS = 7 KEYS_SCHEMA = vol.All(dict, vol.Schema({ vol.Required(ATTR_AUTH): cv.string, vol.Required(ATTR_P256DH): cv.string })) SUBSCRIPTION_SCHEMA = vol.All(dict, vol.Schema({ # pylint: disable=no-value-for-parameter vol.Required(ATTR_ENDPOINT): vol.Url(), vol.Required(ATTR_KEYS): KEYS_SCHEMA })) REGISTER_SCHEMA = vol.Schema({ vol.Required(ATTR_SUBSCRIPTION): SUBSCRIPTION_SCHEMA, vol.Required(ATTR_BROWSER): vol.In(['chrome', 'firefox']) }) CALLBACK_EVENT_PAYLOAD_SCHEMA = vol.Schema({ vol.Required(ATTR_TAG): cv.string, vol.Required(ATTR_TYPE): vol.In(['received', 'clicked', 'closed']), vol.Required(ATTR_TARGET): cv.string, vol.Optional(ATTR_ACTION): cv.string, vol.Optional(ATTR_DATA): dict, })
def _single_validate(self, typ: str, value: Any, key: str): """Validate a single element.""" # if required argument if value is None: raise vol.Invalid( f"Missing required option '{key}' in {self._name} ({self._slug})" ) from None # Lookup secret if str(value).startswith("!secret "): secret: str = value.partition(" ")[2] value = self.sys_homeassistant.secrets.get(secret) if value is None: raise vol.Invalid( f"Unknown secret '{secret}' in {self._name} ({self._slug})" ) from None # parse extend data from type match = RE_SCHEMA_ELEMENT.match(typ) if not match: raise vol.Invalid( f"Unknown type '{typ}' in {self._name} ({self._slug})" ) from None # prepare range range_args = {} for group_name in _SCHEMA_LENGTH_PARTS: group_value = match.group(group_name) if group_value: range_args[group_name[2:]] = float(group_value) if typ.startswith(_STR) or typ.startswith(_PASSWORD): if typ.startswith(_PASSWORD) and value: self.pwned.add(hashlib.sha1(str(value).encode()).hexdigest()) return vol.All(str(value), vol.Range(**range_args))(value) elif typ.startswith(_INT): return vol.All(vol.Coerce(int), vol.Range(**range_args))(value) elif typ.startswith(_FLOAT): return vol.All(vol.Coerce(float), vol.Range(**range_args))(value) elif typ.startswith(_BOOL): return vol.Boolean()(value) elif typ.startswith(_EMAIL): return vol.Email()(value) elif typ.startswith(_URL): return vol.Url()(value) elif typ.startswith(_PORT): return network_port(value) elif typ.startswith(_MATCH): return vol.Match(match.group("match"))(str(value)) elif typ.startswith(_LIST): return vol.In(match.group("list").split("|"))(str(value)) elif typ.startswith(_DEVICE): try: device = self.sys_hardware.get_by_path(Path(value)) except HardwareNotFound: raise vol.Invalid( f"Device '{value}' does not exist in {self._name} ({self._slug})" ) from None # Have filter if match.group("filter"): str_filter = match.group("filter") device_filter = _create_device_filter(str_filter) if device not in self.sys_hardware.filter_devices( **device_filter): raise vol.Invalid( f"Device '{value}' don't match the filter {str_filter}! in {self._name} ({self._slug})" ) # Device valid self.devices.add(device) return str(device.path) raise vol.Invalid( f"Fatal error for option '{key}' with type '{typ}' in {self._name} ({self._slug})" ) from None
return value MANIFEST_SCHEMA = vol.Schema( { vol.Required("domain"): str, vol.Required("name"): str, vol.Optional("config_flow"): bool, vol.Optional("zeroconf"): [str], vol.Optional("ssdp"): vol.Schema( vol.All([vol.All(vol.Schema({}, extra=vol.ALLOW_EXTRA), vol.Length(min=1))]) ), vol.Optional("homekit"): vol.Schema({vol.Optional("models"): [str]}), vol.Required("documentation"): vol.All( vol.Url(), documentation_url # pylint: disable=no-value-for-parameter ), vol.Optional("quality_scale"): vol.In(SUPPORTED_QUALITY_SCALES), vol.Optional("requirements"): [str], vol.Optional("dependencies"): [str], vol.Optional("after_dependencies"): [str], vol.Required("codeowners"): [str], vol.Optional("logo"): vol.Url(), # pylint: disable=no-value-for-parameter vol.Optional("icon"): vol.Url(), # pylint: disable=no-value-for-parameter } ) def validate_manifest(integration: Integration): """Validate manifest.""" try:
vol.Optional("ssdp"): vol.Schema( vol.All([vol.All(vol.Schema({}, extra=vol.ALLOW_EXTRA), vol.Length(min=1))]) ), vol.Optional("homekit"): vol.Schema({vol.Optional("models"): [str]}), vol.Optional("dhcp"): [ vol.Schema( { vol.Optional("macaddress"): vol.All( str, verify_uppercase, verify_wildcard ), vol.Optional("hostname"): vol.All(str, verify_lowercase), } ) ], vol.Required("documentation"): vol.All( vol.Url(), documentation_url # pylint: disable=no-value-for-parameter ), vol.Optional( "issue_tracker" ): vol.Url(), # pylint: disable=no-value-for-parameter vol.Optional("quality_scale"): vol.In(SUPPORTED_QUALITY_SCALES), vol.Optional("requirements"): [str], vol.Optional("dependencies"): [str], vol.Optional("after_dependencies"): [str], vol.Required("codeowners"): [str], vol.Optional("disabled"): str, vol.Optional("iot_class"): vol.In(SUPPORTED_IOT_CLASSES), } ) CUSTOM_INTEGRATION_MANIFEST_SCHEMA = MANIFEST_SCHEMA.extend(
from .const import ( ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_BETA_CHANNEL, ATTR_TIMEZONE, ATTR_ADDONS_CUSTOM_LIST, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, ATTR_PASSWORD, ATTR_HOMEASSISTANT, ATTR_HASSIO, ATTR_BOOT, ATTR_LAST_BOOT, ATTR_SSL, ATTR_PORT, ATTR_WATCHDOG, ATTR_WAIT_BOOT, ATTR_UUID, ATTR_STARTUP_TIME) NETWORK_PORT = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)) ALSA_CHANNEL = vol.Match(r"\d+,\d+") WAIT_BOOT = vol.All(vol.Coerce(int), vol.Range(min=1, max=60)) DOCKER_IMAGE = vol.Match(r"^[\w{}]+/[\-\w{}]+$") # pylint: disable=no-value-for-parameter REPOSITORIES = vol.All([vol.Url()], vol.Unique()) def validate_timezone(timezone): """Validate voluptuous timezone.""" try: pytz.timezone(timezone) except pytz.exceptions.UnknownTimeZoneError: raise vol.Invalid( "Invalid time zone passed in. Valid options can be found here: " "http://en.wikipedia.org/wiki/List_of_tz_database_time_zones") \ from None return timezone
# pylint: disable=no-value-for-parameter SCHEMA_ADDON_CONFIG = vol.Schema( { vol.Required(ATTR_NAME): vol.Coerce(str), vol.Required(ATTR_VERSION): vol.Coerce(str), vol.Required(ATTR_SLUG): vol.Coerce(str), vol.Required(ATTR_DESCRIPTON): vol.Coerce(str), vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)], vol.Optional(ATTR_MACHINE): [vol.In(MACHINE_ALL)], vol.Optional(ATTR_URL): vol.Url(), vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.In(STARTUP_ALL)), vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]), vol.Optional(ATTR_INIT, default=True): vol.Boolean(), vol.Optional(ATTR_ADVANCED, default=False): vol.Boolean(), vol.Optional(ATTR_STAGE, default=AddonStages.STABLE): vol.Coerce(AddonStages), vol.Optional(ATTR_PORTS): DOCKER_PORTS, vol.Optional(ATTR_PORTS_DESCRIPTION): DOCKER_PORTS_DESCRIPTION, vol.Optional(ATTR_WEBUI):
SECURITY_INITIALIZE = 'security_initialize' SECURITY_TOTP = 'security_totp' SECURITY_PASSWORD = '******' SECURITY_SESSIONS = 'security_sessions' # pylint: disable=no-value-for-parameter SCHEMA_CONFIG = vol.Schema({ vol.Optional(UPSTREAM_BETA, default=False): vol.Boolean(), vol.Optional(API_ENDPOINT): vol.Coerce(str), vol.Optional(TIMEZONE, default='UTC'): validate_timezone, vol.Optional(HOMEASSISTANT_LAST): vol.Coerce(str), vol.Optional(HOMEASSISTANT_DEVICES, default=[]): [vol.Coerce(str)], vol.Optional(HASSIO_LAST): vol.Coerce(str), vol.Optional(ADDONS_CUSTOM_LIST, default=[]): [vol.Url()], vol.Optional(SECURITY_INITIALIZE, default=False): vol.Boolean(), vol.Optional(SECURITY_TOTP): vol.Coerce(str), vol.Optional(SECURITY_PASSWORD): vol.Coerce(str), vol.Optional(SECURITY_SESSIONS, default={}): {vol.Coerce(str): vol.Coerce(str)}, }, extra=vol.REMOVE_EXTRA) class Config(object): """Hold all config data.""" def __init__(self, config_file): """Initialize config object.""" self._file = config_file self._data = {}
from .util import api_process, api_process_raw, api_validate from ..const import (ATTR_ADDONS, ATTR_VERSION, ATTR_LAST_VERSION, ATTR_BETA_CHANNEL, ATTR_ARCH, HASSIO_VERSION, ATTR_ADDONS_REPOSITORIES, ATTR_LOGO, ATTR_REPOSITORY, ATTR_DESCRIPTON, ATTR_NAME, ATTR_SLUG, ATTR_INSTALLED, ATTR_TIMEZONE, ATTR_STATE, CONTENT_TYPE_BINARY) from ..validate import validate_timezone _LOGGER = logging.getLogger(__name__) SCHEMA_OPTIONS = vol.Schema({ # pylint: disable=no-value-for-parameter vol.Optional(ATTR_BETA_CHANNEL): vol.Boolean(), vol.Optional(ATTR_ADDONS_REPOSITORIES): [vol.Url()], vol.Optional(ATTR_TIMEZONE): validate_timezone, }) SCHEMA_VERSION = vol.Schema({ vol.Optional(ATTR_VERSION): vol.Coerce(str), }) class APISupervisor(object): """Handle rest api for supervisor functions.""" def __init__(self, config, loop, supervisor, snapshots, addons, host_control, updater): """Initialize supervisor rest api part.""" self.config = config
REMOVE_HANDLER_URL = '' CONF_TRUSTED_NETWORKS = 'trusted_networks' DEFAULT_TRUSTED_NETWORKS = [ ip_network('149.154.167.197/32'), ip_network('149.154.167.198/31'), ip_network('149.154.167.200/29'), ip_network('149.154.167.208/28'), ip_network('149.154.167.224/29'), ip_network('149.154.167.232/31') ] # pylint: disable=no-value-for-parameter PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_URL): vol.Url(), vol.Optional(CONF_TRUSTED_NETWORKS, default=DEFAULT_TRUSTED_NETWORKS): vol.All(cv.ensure_list, [ip_network]) }) @asyncio.coroutine def async_setup_platform(hass, config): """Set up the Telegram webhooks platform.""" import telegram bot = telegram.Bot(config[CONF_API_KEY]) current_status = yield from hass.async_add_job(bot.getWebhookInfo) base_url = config.get(CONF_URL, hass.config.api.base_url) # Some logging of Bot current status:
ARCH_ALL = [ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64, ARCH_I386] # pylint: disable=no-value-for-parameter SCHEMA_ADDON_CONFIG = vol.Schema( { vol.Required(ATTR_NAME): vol.Coerce(str), vol.Required(ATTR_VERSION): vol.Coerce(str), vol.Required(ATTR_SLUG): vol.Coerce(str), vol.Required(ATTR_DESCRIPTON): vol.Coerce(str), vol.Optional(ATTR_URL): vol.Url(), vol.Optional(ATTR_ARCH, default=ARCH_ALL): [vol.In(ARCH_ALL)], vol.Required(ATTR_STARTUP): vol.In( [STARTUP_BEFORE, STARTUP_AFTER, STARTUP_ONCE, STARTUP_INITIALIZE]), vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]), vol.Optional(ATTR_PORTS): dict, vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")], vol.Optional(ATTR_MAP, default=[]): [vol.Match(MAP_VOLUME)], vol.Optional(ATTR_ENVIRONMENT): { vol.Match(r"\w*"): vol.Coerce(str) }, vol.Required(ATTR_OPTIONS): dict,
from homeassistant.util import Throttle, dt _LOGGER = logging.getLogger(__name__) CONF_CALENDARS = "calendars" CONF_CUSTOM_CALENDARS = "custom_calendars" CONF_CALENDAR = "calendar" CONF_SEARCH = "search" CONF_DAYS = "days" OFFSET = "!!" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { # pylint: disable=no-value-for-parameter 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_MOMENTARY): vol.All(vol.Coerce(int), vol.Range(min=10)), vol.Optional(CONF_PAUSE): vol.All(vol.Coerce(int), vol.Range(min=10)), vol.Optional(CONF_REPEAT): vol.All(vol.Coerce(int), vol.Range(min=-1)), } ), cv.has_at_least_one_key(CONF_PIN, CONF_ZONE), ) # pylint: disable=no-value-for-parameter CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( { vol.Required(CONF_ACCESS_TOKEN): cv.string, vol.Optional(CONF_API_HOST): vol.Url(), vol.Required(CONF_DEVICES): [ { vol.Required(CONF_ID): cv.matches_regex("[0-9a-f]{12}"), vol.Optional(CONF_BINARY_SENSORS): vol.All( cv.ensure_list, [_BINARY_SENSOR_SCHEMA] ), vol.Optional(CONF_SENSORS): vol.All( cv.ensure_list, [_SENSOR_SCHEMA] ), vol.Optional(CONF_SWITCHES): vol.All( cv.ensure_list, [_SWITCH_SCHEMA] ), vol.Optional(CONF_HOST): cv.string, vol.Optional(CONF_PORT): cv.port, vol.Optional(CONF_BLINK, default=True): cv.boolean,
fields = v.Schema([{ 'name': str, 'type': v.Any('url', 'short_text', 'long_text', 'number', 'boolean', 'enum'), v.Optional('required', True): bool, v.Optional('min_length'): int, v.Optional('max_length'): int, v.Optional('min_digit'): v.Coerce(float), v.Optional('max_digit'): v.Coerce(float), v.Optional('choices'): [str] }], required=True) details = v.Schema( { 'field_name': str, 'type': v.Any('url', 'short_text', 'long_text', 'number', 'boolean', 'enum'), 'value': v.Any(int, str, bool, v.Url()) }, required=True)