def _has_all_unique_hosts(value): """Validate that each hub configured has a unique host.""" hosts = [device[CONF_HOST] for device in value] schema = vol.Schema(vol.Unique()) schema(hosts) return value
from ..exceptions import APIError from ..snapshots.validate import ALL_FOLDERS from .utils import api_process, api_validate _LOGGER: logging.Logger = logging.getLogger(__name__) RE_SLUGIFY_NAME = re.compile(r"[^A-Za-z0-9]+") # pylint: disable=no-value-for-parameter SCHEMA_RESTORE_PARTIAL = vol.Schema({ vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)), vol.Optional(ATTR_HOMEASSISTANT): vol.Boolean(), vol.Optional(ATTR_ADDONS): vol.All([vol.Coerce(str)], vol.Unique()), vol.Optional(ATTR_FOLDERS): vol.All([vol.In(ALL_FOLDERS)], vol.Unique()), }) SCHEMA_RESTORE_FULL = vol.Schema( {vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str))}) SCHEMA_SNAPSHOT_FULL = vol.Schema({ vol.Optional(ATTR_NAME): vol.Coerce(str), vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)), }) SCHEMA_SNAPSHOT_PARTIAL = SCHEMA_SNAPSHOT_FULL.extend({
# pylint: disable=no-value-for-parameter _SCHEMA_ADDON_CONFIG = vol.Schema( { vol.Required(ATTR_NAME): str, vol.Required(ATTR_VERSION): version_tag, vol.Required(ATTR_SLUG): str, vol.Required(ATTR_DESCRIPTON): str, vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)], vol.Optional(ATTR_MACHINE): vol.All([vol.Match(RE_MACHINE)], vol.Unique()), vol.Optional(ATTR_URL): vol.Url(), vol.Optional(ATTR_STARTUP, default=AddonStartup.APPLICATION): vol.Coerce(AddonStartup), vol.Optional(ATTR_BOOT, default=AddonBoot.AUTO): vol.Coerce(AddonBoot), vol.Optional(ATTR_INIT, default=True): vol.Boolean(), vol.Optional(ATTR_ADVANCED, default=False): vol.Boolean(), vol.Optional(ATTR_STAGE, default=AddonStage.STABLE): vol.Coerce(AddonStage), vol.Optional(ATTR_PORTS): docker_ports, vol.Optional(ATTR_PORTS_DESCRIPTION):
def validate_repository(repository: str) -> str: """Validate a valid 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 # pylint: disable=no-value-for-parameter repositories = vol.All([validate_repository], vol.Unique()) DOCKER_PORTS = vol.Schema({ vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): vol.Maybe(network_port) }) DOCKER_PORTS_DESCRIPTION = vol.Schema({ vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): vol.Coerce(str) }) # pylint: disable=no-value-for-parameter SCHEMA_HASS_CONFIG = vol.Schema( { vol.Optional(ATTR_UUID, default=lambda: uuid.uuid4().hex):
"maxMP": ST("max Mana", "mdi:auto-fix", "MP", ["stats", "maxMP"]), "exp": ST("EXP", "mdi:star", "EXP", ["stats", "exp"]), "toNextLevel": ST("Next Lvl", "mdi:star", "EXP", ["stats", "toNextLevel"]), "lvl": ST("Lvl", "mdi:arrow-up-bold-circle-outline", "Lvl", ["stats", "lvl"]), "gp": ST("Gold", "mdi:coin", "Gold", ["stats", "gp"]), "class": ST("Class", "mdi:sword", "", ["stats", "class"]), } INSTANCE_SCHEMA = vol.Schema( { vol.Optional(CONF_URL, default=DEFAULT_URL): cv.url, vol.Optional(CONF_NAME): cv.string, vol.Required(CONF_API_USER): cv.string, vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_SENSORS, default=list(SENSORS_TYPES)): vol.All( cv.ensure_list, vol.Unique(), [vol.In(list(SENSORS_TYPES))] ), } ) has_unique_values = vol.Schema(vol.Unique()) # pylint: disable=invalid-name # because we want a handy alias def has_all_unique_users(value): """Validate that all API users are unique.""" api_users = [user[CONF_API_USER] for user in value] has_unique_values(api_users) return value
vol.Optional(ATTR_SSL, default=False): vol.Boolean(), vol.Optional(ATTR_PORT, default=8123): NETWORK_PORT, vol.Optional(ATTR_PASSWORD): vol.Maybe(vol.Coerce(str)), vol.Optional(ATTR_REFRESH_TOKEN): vol.Maybe(vol.Coerce(str)), vol.Optional(ATTR_WATCHDOG, default=True): vol.Boolean(), vol.Optional(ATTR_WAIT_BOOT, default=600): vol.All(vol.Coerce(int), vol.Range(min=60)), }, extra=vol.REMOVE_EXTRA), vol.Optional(ATTR_FOLDERS, default=list): vol.All([vol.In(ALL_FOLDERS)], vol.Unique()), vol.Optional(ATTR_ADDONS, default=list): vol.All([ vol.Schema( { vol.Required(ATTR_SLUG): vol.Coerce(str), vol.Required(ATTR_NAME): vol.Coerce(str), vol.Required(ATTR_VERSION): vol.Coerce(str), vol.Optional(ATTR_SIZE, default=0): vol.Coerce(float), }, extra=vol.REMOVE_EXTRA) ], unique_addons), vol.Optional(ATTR_REPOSITORIES, default=list): REPOSITORIES, }, extra=vol.ALLOW_EXTRA)
ATTR_PASSWORD, ATTR_PROTECTED, CONTENT_TYPE_TAR, ) from ..coresys import CoreSysAttributes from ..exceptions import APIError _LOGGER: logging.Logger = logging.getLogger(__name__) # pylint: disable=no-value-for-parameter SCHEMA_RESTORE_PARTIAL = vol.Schema( { vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)), vol.Optional(ATTR_HOMEASSISTANT): vol.Boolean(), vol.Optional(ATTR_ADDONS): vol.All([vol.Coerce(str)], vol.Unique()), vol.Optional(ATTR_FOLDERS): vol.All([vol.In(ALL_FOLDERS)], vol.Unique()), } ) SCHEMA_RESTORE_FULL = vol.Schema( {vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str))} ) SCHEMA_SNAPSHOT_FULL = vol.Schema( { vol.Optional(ATTR_NAME): vol.Coerce(str), vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)), } )
cv.port, vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION): vol.All(vol.In(AUTHENTICATION_LIST)), vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION): vol.All(vol.In(RESOLUTION_LIST)), vol.Optional(CONF_STREAM_SOURCE, default=STREAM_SOURCE_LIST[0]): vol.All(vol.In(STREAM_SOURCE_LIST)), vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string, vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period, vol.Optional(CONF_BINARY_SENSORS): vol.All( cv.ensure_list, [vol.In(BINARY_SENSOR_KEYS)], vol.Unique(), check_binary_sensors, ), vol.Optional(CONF_SWITCHES): vol.All(cv.ensure_list, [vol.In(SWITCH_KEYS)], vol.Unique()), vol.Optional(CONF_SENSORS): vol.All(cv.ensure_list, [vol.In(SENSOR_KEYS)], vol.Unique()), vol.Optional(CONF_CONTROL_LIGHT, default=True): cv.boolean, }) CONFIG_SCHEMA = vol.Schema( {DOMAIN: vol.All(cv.ensure_list, [AMCREST_SCHEMA], _has_unique_names)}, extra=vol.ALLOW_EXTRA, )
CONDITION_TYPE_AND, CONDITION_TYPE_OR, ] ), vol.Optional(ATTR_TRACK_CONDITIONS): cv.boolean, vol.Required(ATTR_ACTIONS): vol.All( cv.ensure_list, vol.Length(min=1), [ACTION_SCHEMA] ), } ) ADD_SCHEDULE_SCHEMA = vol.Schema( { vol.Optional(ATTR_WEEKDAYS, default=[DAY_TYPE_DAILY]): vol.All( cv.ensure_list, vol.Unique(), vol.Length(min=1), [ vol.In( WEEKDAYS + [ DAY_TYPE_WORKDAY, DAY_TYPE_WEEKEND, DAY_TYPE_DAILY, ] ) ], ), vol.Optional(ATTR_START_DATE, default=None): validate_date, vol.Optional(ATTR_END_DATE, default=None): validate_date, vol.Required(ATTR_TIMESLOTS): vol.All(
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION): vol.All(vol.In(AUTHENTICATION_LIST)), vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION): vol.All(vol.In(RESOLUTION_LIST)), vol.Optional(CONF_STREAM_SOURCE, default=STREAM_SOURCE_LIST[0]): vol.All(vol.In(STREAM_SOURCE_LIST)), vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string, vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period, vol.Optional(CONF_BINARY_SENSORS): vol.All(cv.ensure_list, [vol.In(BINARY_SENSORS)], vol.Unique(), check_binary_sensors), vol.Optional(CONF_SENSORS): vol.All(cv.ensure_list, [vol.In(SENSORS)], vol.Unique()), vol.Optional(CONF_CONTROL_LIGHT, default=True): cv.boolean, }) CONFIG_SCHEMA = vol.Schema( {DOMAIN: vol.All(cv.ensure_list, [AMCREST_SCHEMA], _has_unique_names)}, extra=vol.ALLOW_EXTRA, ) class AmcrestChecker(Http): """amcrest.Http wrapper for catching errors."""
def _all_unique_names(value): """Validate that all entities have a unique profile name.""" hosts = [device[CONF_NAME] for device in value] schema = vol.Schema(vol.Unique()) schema(hosts) return value
vol.Required(CONF_SOURCE_SENSOR): cv.entity_id, vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_METER_TYPE): vol.In(METER_TYPES), vol.Optional(CONF_METER_OFFSET, default=DEFAULT_OFFSET): vol.All(cv.time_period, cv.positive_timedelta, max_28_days), vol.Optional(CONF_METER_DELTA_VALUES, default=False): cv.boolean, vol.Optional(CONF_METER_NET_CONSUMPTION, default=False): cv.boolean, vol.Optional(CONF_TARIFFS, default=[]): vol.All(cv.ensure_list, vol.Unique(), [cv.string]), vol.Optional(CONF_CRON_PATTERN): validate_cron_pattern, }, period_or_cron, )) CONFIG_SCHEMA = vol.Schema( {DOMAIN: vol.Schema({cv.slug: METER_CONFIG_SCHEMA})}, extra=vol.ALLOW_EXTRA) async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up an Utility Meter.""" hass.data[DATA_LEGACY_COMPONENT] = EntityComponent(_LOGGER, DOMAIN, hass)
def _unique(options: Any) -> Any: try: return vol.Unique()(options) except vol.Invalid as exc: raise HomeAssistantError("Duplicate options are not allowed") from exc
from .sensor import WITHINGS_MEASUREMENTS_MAP DOMAIN = const.DOMAIN CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema({ vol.Required(const.CLIENT_ID): vol.All(cv.string, vol.Length(min=1)), vol.Required(const.CLIENT_SECRET): vol.All(cv.string, vol.Length(min=1)), vol.Optional(const.BASE_URL): cv.url, vol.Required(const.PROFILES): vol.All(cv.ensure_list, vol.Unique(), vol.Length(min=1), [vol.All(cv.string, vol.Length(min=1))]), vol.Optional(const.MEASURES, default=list(WITHINGS_MEASUREMENTS_MAP)): vol.All( cv.ensure_list, vol.Unique(), vol.Length(min=1), [vol.All(cv.string, vol.In(list(WITHINGS_MEASUREMENTS_MAP)))]), }) }, extra=vol.ALLOW_EXTRA, ) async def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up the Withings component.""" conf = config.get(DOMAIN)
def validate_repository(repository): """Validate a valid 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 # pylint: disable=no-value-for-parameter REPOSITORIES = vol.All([validate_repository], vol.Unique()) DOCKER_PORTS = vol.Schema({ vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): vol.Maybe(NETWORK_PORT) }) DOCKER_PORTS_DESCRIPTION = vol.Schema({ vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): vol.Coerce(str) }) # pylint: disable=no-value-for-parameter SCHEMA_HASS_CONFIG = vol.Schema( { vol.Optional(ATTR_UUID, default=lambda: uuid.uuid4().hex):
def has_all_unique_names(value): """Validate that printers have an unique name.""" names = [util_slugify(printer["name"]) for printer in value] vol.Schema(vol.Unique())(names) return value
def ensure_unique_hosts(value: dict[Any, Any]) -> dict[Any, Any]: """Validate that all configs have a unique host.""" vol.Schema(vol.Unique("duplicate host entries found"))( [entry[CONF_HOST] for entry in value]) return value
def _has_unique_names(devices: list[dict[str, Any]]) -> list[dict[str, Any]]: names = [device[CONF_NAME] for device in devices] vol.Schema(vol.Unique())(names) return devices
_LOGGER = logging.getLogger(__name__) INSTANCE_SCHEMA = vol.All( cv.deprecated(CONF_SENSORS), vol.Schema({ vol.Optional(CONF_URL, default=DEFAULT_URL): cv.url, vol.Optional(CONF_NAME): cv.string, vol.Required(CONF_API_USER): cv.string, vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_SENSORS, default=list(SENSORS_TYPES)): vol.All(cv.ensure_list, vol.Unique(), [vol.In(list(SENSORS_TYPES))]), }), ) has_unique_values = vol.Schema(vol.Unique()) # because we want a handy alias def has_all_unique_users(value): """Validate that all API users are unique.""" api_users = [user[CONF_API_USER] for user in value] has_unique_values(api_users) return value def has_all_unique_users_names(value):
def has_all_unique_cities(value): """Validate that all cities are unique.""" cities = [location[CONF_CITY] for location in value] vol.Schema(vol.Unique())(cities) return value
def has_all_unique_files(value: list[dict]) -> list[dict]: """Validate that all persistence files are unique and set if any is set.""" persistence_files = [gateway[CONF_PERSISTENCE_FILE] for gateway in value] schema = vol.Schema(vol.Unique()) schema(persistence_files) return value
def ensure_unique_hosts(value): """Validate that all configs have a unique host.""" vol.Schema(vol.Unique("duplicate host entries found"))( [socket.gethostbyname(entry[CONF_HOST]) for entry in value]) return value
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
vol.Optional("conditions"): vol.All(cv.ensure_list, vol.Length(min=1), [CONDITION_SCHEMA]), vol.Optional("condition_type"): vol.In([ CONDITION_TYPE_AND, CONDITION_TYPE_OR, ]), vol.Required("actions"): vol.All(cv.ensure_list, vol.Length(min=1), [ACTION_SCHEMA]), }) SCHEDULE_SCHEMA = vol.Schema({ vol.Required("weekdays"): vol.All( cv.ensure_list, vol.Unique(), vol.Length(min=1), [ vol.In([ "mon", "tue", "wed", "thu", "fri", "sat", "sun", DAY_TYPE_WORKDAY, DAY_TYPE_WEEKEND, DAY_TYPE_DAILY, ]) ],
vol.Inclusive(ATTR_IMAGE, "custom_hass"): DOCKER_IMAGE, vol.Inclusive(ATTR_LAST_VERSION, "custom_hass"): vol.Coerce(str), vol.Optional(ATTR_BOOT, default=True): vol.Boolean(), vol.Optional(ATTR_SSL, default=False): vol.Boolean(), vol.Optional(ATTR_PORT, default=8123): NETWORK_PORT, vol.Optional(ATTR_PASSWORD): vol.Maybe(vol.Coerce(str)), vol.Optional(ATTR_REFRESH_TOKEN): vol.Maybe(vol.Coerce(str)), vol.Optional(ATTR_WATCHDOG, default=True): vol.Boolean(), vol.Optional(ATTR_WAIT_BOOT, default=600): vol.All( vol.Coerce(int), vol.Range(min=60) ), }, extra=vol.REMOVE_EXTRA, ), vol.Optional(ATTR_FOLDERS, default=list): vol.All( [vol.In(ALL_FOLDERS)], vol.Unique() ), vol.Optional(ATTR_ADDONS, default=list): vol.All( [ vol.Schema( { vol.Required(ATTR_SLUG): vol.Coerce(str), vol.Required(ATTR_NAME): vol.Coerce(str), vol.Required(ATTR_VERSION): vol.Coerce(str), vol.Optional(ATTR_SIZE, default=0): vol.Coerce(float), }, extra=vol.REMOVE_EXTRA, ) ], unique_addons, ),
def _has_unique_names(devices): names = [device[CONF_NAME] for device in devices] vol.Schema(vol.Unique())(names) return devices
vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION): vol.All( vol.In(AUTHENTICATION_LIST) ), vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION): vol.All( vol.In(RESOLUTION_LIST) ), vol.Optional(CONF_STREAM_SOURCE, default=STREAM_SOURCE_LIST[0]): vol.All( vol.In(STREAM_SOURCE_LIST) ), vol.Optional(CONF_FFMPEG_ARGUMENTS, default=DEFAULT_ARGUMENTS): cv.string, vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period, vol.Optional(CONF_BINARY_SENSORS): vol.All( cv.ensure_list, [vol.In(BINARY_SENSORS)], vol.Unique(), check_binary_sensors ), vol.Optional(CONF_SENSORS): vol.All( cv.ensure_list, [vol.In(SENSORS)], vol.Unique() ), vol.Optional(CONF_CONTROL_LIGHT, default=True): cv.boolean, } ) CONFIG_SCHEMA = vol.Schema( {DOMAIN: vol.All(cv.ensure_list, [AMCREST_SCHEMA], _has_unique_names)}, extra=vol.ALLOW_EXTRA, ) class AmcrestChecker(Http):