"""This module holds the vaious schemas""" from datetime import datetime, date import voluptuous as vol from homeassistant.helpers import config_validation as cv from homeassistant.const import ( CONF_ENTITY_ID, CONF_AFTER, CONF_BEFORE, CONF_NAME, CONF_WEEKDAY, CONF_REPEAT, CONF_DELAY, CONF_FOR, CONF_UNTIL, ) from .const import ( CONF_ALLOW_MANUAL, CONF_CLOCK, CONF_ENABLED, CONF_FINISH, CONF_FIXED, CONF_FUTURE_SPAN, CONF_HISTORY, CONF_HISTORY_REFRESH, CONF_HISTORY_SPAN, CONF_MAX_LOG_ENTRIES, CONF_MAXIMUM, CONF_MINIMUM, CONF_MODE, CONF_MONTH, CONF_DAY, CONF_ODD, CONF_EVEN, CONF_RENAME_ENTITIES, CONF_RESULTS, CONF_SHOW_LOG, CONF_AUTOPLAY, CONF_ANCHOR, CONF_SPAN, CONF_SYNC_SWITCHES, CONF_SEER, CONF_CONTROLLERS, CONF_SCHEDULES, CONF_ZONES, CONF_DURATION, CONF_SUN, CONF_TIME, CONF_PREAMBLE, CONF_POSTAMBLE, CONF_GRANULARITY, CONF_TESTING, CONF_SPEED, CONF_TIMES, CONF_START, CONF_END, MONTHS, CONF_SHOW, CONF_CONFIG, CONF_TIMELINE, CONF_CONTROLLER_ID, CONF_ZONE_ID, CONF_SEQUENCES, CONF_ALL_ZONES_CONFIG, CONF_REFRESH_INTERVAL, CONF_OUTPUT_EVENTS, CONF_CRON, CONF_EVERY_N_DAYS, CONF_START_N_DAYS, CONF_CHECK_BACK, CONF_RETRIES, CONF_RESYNC, CONF_STATE_ON, CONF_STATE_OFF, CONF_PERCENTAGE, CONF_ACTUAL, CONF_INCREASE, CONF_DECREASE, CONF_RESET, CONF_SEQUENCE_ID, CONF_STATES, CONF_SCHEDULE_ID, CONF_FROM, CONF_VOLUME, CONF_VOLUME_PRECISION, CONF_VOLUME_SCALE, CONF_FLOW_RATE_PRECISION, CONF_FLOW_RATE_SCALE, CONF_QUEUE, CONF_QUEUE_MANUAL, CONF_USER, CONF_TOGGLE, CONF_EXTENDED_CONFIG, ) IU_ID = r"^[a-z0-9]+(_[a-z0-9]+)*$" def _list_is_not_empty(value): if value is None or len(value) < 1: raise vol.Invalid("Must have at least one entry") return value def _parse_dd_mmm(value: str) -> date | None: """Convert a date string in dd mmm format to a date object.""" if isinstance(value, date): return value return datetime.strptime(value, "%d %b").date() USER_SCHEMA = vol.Schema( {}, extra=vol.ALLOW_EXTRA, ) SHOW_SCHEMA = vol.Schema( { vol.Optional(CONF_CONFIG, False): cv.boolean, vol.Optional(CONF_TIMELINE, False): cv.boolean, } ) SUN_SCHEMA = vol.Schema( { vol.Required(CONF_SUN): cv.sun_event, vol.Optional(CONF_BEFORE): cv.positive_time_period, vol.Optional(CONF_AFTER): cv.positive_time_period, } ) CRON_SCHEMA = vol.Schema( { vol.Required(CONF_CRON): cv.string, } ) EVERY_N_DAYS_SCHEMA = vol.Schema( { vol.Required(CONF_EVERY_N_DAYS): cv.positive_int, vol.Required(CONF_START_N_DAYS): cv.date, } ) time_event = vol.Any(cv.time, SUN_SCHEMA, CRON_SCHEMA) anchor_event = vol.Any(CONF_START, CONF_FINISH) month_event = vol.All(cv.ensure_list, [vol.In(MONTHS)]) day_number = vol.All(vol.Coerce(int), vol.Range(min=0, max=31)) day_event = vol.Any( CONF_ODD, CONF_EVEN, cv.ensure_list(day_number), EVERY_N_DAYS_SCHEMA ) SCHEDULE_SCHEMA = vol.Schema( { vol.Required(CONF_TIME): time_event, vol.Required(CONF_ANCHOR, default=CONF_START): anchor_event, vol.Required(CONF_DURATION): cv.positive_time_period, vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_SCHEDULE_ID): cv.matches_regex(IU_ID), vol.Optional(CONF_WEEKDAY): cv.weekdays, vol.Optional(CONF_MONTH): month_event, vol.Optional(CONF_DAY): day_event, vol.Optional(CONF_ENABLED): cv.boolean, vol.Inclusive(CONF_FROM, "span"): _parse_dd_mmm, vol.Inclusive(CONF_UNTIL, "span"): _parse_dd_mmm, } ) SEQUENCE_SCHEDULE_SCHEMA = vol.Schema( { vol.Required(CONF_TIME): time_event, vol.Required(CONF_ANCHOR, default=CONF_START): anchor_event, vol.Optional(CONF_DURATION): cv.positive_time_period, vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_SCHEDULE_ID): cv.matches_regex(IU_ID), vol.Optional(CONF_WEEKDAY): cv.weekdays, vol.Optional(CONF_MONTH): month_event, vol.Optional(CONF_DAY): day_event, vol.Optional(CONF_ENABLED): cv.boolean, vol.Inclusive(CONF_FROM, "span"): _parse_dd_mmm, vol.Inclusive(CONF_UNTIL, "span"): _parse_dd_mmm, } ) LOAD_SCHEDULE_SCHEMA = vol.Schema( { vol.Required(CONF_SCHEDULE_ID): cv.matches_regex(IU_ID), vol.Optional(CONF_TIME): time_event, vol.Optional(CONF_ANCHOR): anchor_event, vol.Optional(CONF_DURATION): cv.positive_time_period_template, vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_WEEKDAY): cv.weekdays, vol.Optional(CONF_MONTH): month_event, vol.Optional(CONF_DAY): day_event, vol.Optional(CONF_ENABLED): cv.boolean, vol.Inclusive(CONF_FROM, "span"): _parse_dd_mmm, vol.Inclusive(CONF_UNTIL, "span"): _parse_dd_mmm, } ) CHECK_BACK_SCHEMA = vol.All( cv.deprecated(CONF_STATE_ON), cv.deprecated(CONF_STATE_OFF), vol.Schema( { vol.Optional(CONF_STATES): vol.Any("none", "all", "on", "off"), vol.Optional(CONF_DELAY): cv.positive_int, vol.Optional(CONF_RETRIES): cv.positive_int, vol.Optional(CONF_RESYNC): cv.boolean, vol.Optional(CONF_STATE_ON): cv.string, # Deprecated vol.Optional(CONF_STATE_OFF): cv.string, # Deprecated vol.Optional(CONF_ENTITY_ID): cv.entity_id, vol.Optional(CONF_TOGGLE): cv.boolean, } ), ) VOLUME_SCHEMA = vol.Schema( { vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Optional(CONF_VOLUME_PRECISION): cv.positive_int, vol.Optional(CONF_VOLUME_SCALE): cv.positive_float, vol.Optional(CONF_FLOW_RATE_PRECISION): cv.positive_int, vol.Optional(CONF_FLOW_RATE_SCALE): cv.positive_float, } ) ZONE_SCHEMA = vol.Schema( { vol.Optional(CONF_SCHEDULES): vol.All(cv.ensure_list, [SCHEDULE_SCHEMA]), vol.Optional(CONF_ZONE_ID): cv.matches_regex(IU_ID), vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_ENABLED): cv.boolean, vol.Optional(CONF_ALLOW_MANUAL): cv.boolean, vol.Optional(CONF_MINIMUM): cv.positive_time_period, vol.Optional(CONF_MAXIMUM): cv.positive_time_period, vol.Optional(CONF_FUTURE_SPAN): cv.positive_int, vol.Optional(CONF_SHOW): vol.All(SHOW_SCHEMA), vol.Optional(CONF_CHECK_BACK): vol.All(CHECK_BACK_SCHEMA), vol.Optional(CONF_VOLUME): vol.All(VOLUME_SCHEMA), vol.Optional(CONF_DURATION): cv.positive_time_period_template, vol.Optional(CONF_USER): vol.All(USER_SCHEMA), } ) ALL_ZONES_SCHEMA = vol.Schema( { vol.Optional(CONF_SHOW): vol.All(SHOW_SCHEMA), vol.Optional(CONF_MINIMUM): cv.positive_time_period, vol.Optional(CONF_MAXIMUM): cv.positive_time_period, vol.Optional(CONF_FUTURE_SPAN): cv.positive_int, vol.Optional(CONF_ALLOW_MANUAL): cv.boolean, vol.Optional(CONF_CHECK_BACK): vol.All(CHECK_BACK_SCHEMA), vol.Optional(CONF_VOLUME): vol.All(VOLUME_SCHEMA), vol.Optional(CONF_DURATION): cv.positive_time_period_template, vol.Optional(CONF_USER): vol.All(USER_SCHEMA), } ) SEQUENCE_ZONE_SCHEMA = vol.Schema( { vol.Required(CONF_ZONE_ID): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_DELAY): cv.time_period, vol.Optional(CONF_DURATION): cv.positive_time_period, vol.Optional(CONF_REPEAT): cv.positive_int, vol.Optional(CONF_ENABLED): cv.boolean, vol.Optional(CONF_VOLUME): cv.positive_float, } ) SEQUENCE_SCHEMA = vol.Schema( { vol.Required(CONF_ZONES, default={}): vol.All( cv.ensure_list, [SEQUENCE_ZONE_SCHEMA], _list_is_not_empty ), vol.Optional(CONF_SCHEDULES): vol.All( cv.ensure_list, [SEQUENCE_SCHEDULE_SCHEMA] ), vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_DELAY): cv.time_period, vol.Optional(CONF_DURATION): cv.positive_time_period, vol.Optional(CONF_REPEAT): cv.positive_int, vol.Optional(CONF_ENABLED): cv.boolean, } ) CONTROLLER_SCHEMA = vol.Schema( { vol.Required(CONF_ZONES): vol.All( cv.ensure_list, [ZONE_SCHEMA], _list_is_not_empty ), vol.Optional(CONF_SEQUENCES): vol.All( cv.ensure_list, [SEQUENCE_SCHEMA], _list_is_not_empty ), vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_CONTROLLER_ID): cv.matches_regex(IU_ID), vol.Optional(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_PREAMBLE): cv.time_period, vol.Optional(CONF_POSTAMBLE): cv.time_period, vol.Optional(CONF_ENABLED): cv.boolean, vol.Optional(CONF_ALL_ZONES_CONFIG): vol.All(ALL_ZONES_SCHEMA), vol.Optional(CONF_QUEUE_MANUAL): cv.boolean, vol.Optional(CONF_CHECK_BACK): vol.All(CHECK_BACK_SCHEMA), vol.Optional(CONF_VOLUME): vol.All(VOLUME_SCHEMA), vol.Optional(CONF_USER): vol.All(USER_SCHEMA), } ) HISTORY_SCHEMA = vol.Schema( { vol.Optional(CONF_ENABLED): cv.boolean, vol.Optional(CONF_REFRESH_INTERVAL): cv.positive_int, vol.Optional(CONF_SPAN): cv.positive_int, } ) clock_mode = vol.Any(CONF_FIXED, CONF_SEER) CLOCK_SCHEMA = vol.Schema( { vol.Optional(CONF_MODE, default=CONF_SEER): clock_mode, vol.Optional(CONF_SHOW_LOG, default=False): cv.boolean, vol.Optional(CONF_MAX_LOG_ENTRIES): cv.positive_int, } ) TEST_RESULT_SCHEMA = vol.Schema( { vol.Required("t"): cv.datetime, vol.Required("c"): cv.positive_int, vol.Required("z"): cv.positive_int, vol.Required("s"): cv.boolean, } ) TEST_TIME_SCHEMA = vol.Schema( { vol.Required(CONF_START): cv.datetime, vol.Required(CONF_END): cv.datetime, vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_RESULTS): [TEST_RESULT_SCHEMA], } ) TEST_SCHEMA = vol.Schema( { vol.Optional(CONF_ENABLED): cv.boolean, vol.Optional(CONF_SPEED): cv.positive_float, vol.Optional(CONF_TIMES): [TEST_TIME_SCHEMA], vol.Optional(CONF_OUTPUT_EVENTS): cv.boolean, vol.Optional(CONF_SHOW_LOG): cv.boolean, vol.Optional(CONF_AUTOPLAY): cv.boolean, } ) IRRIGATION_SCHEMA = vol.Schema( { vol.Required(CONF_CONTROLLERS, default={}): vol.All( cv.ensure_list, [CONTROLLER_SCHEMA], _list_is_not_empty ), vol.Optional(CONF_GRANULARITY): cv.positive_int, vol.Optional(CONF_REFRESH_INTERVAL): cv.positive_int, vol.Optional(CONF_HISTORY_SPAN): cv.positive_int, vol.Optional(CONF_HISTORY_REFRESH): cv.positive_int, vol.Optional(CONF_SYNC_SWITCHES): cv.boolean, vol.Optional(CONF_RENAME_ENTITIES): cv.boolean, vol.Optional(CONF_TESTING): TEST_SCHEMA, vol.Optional(CONF_HISTORY): HISTORY_SCHEMA, vol.Optional(CONF_CLOCK): CLOCK_SCHEMA, vol.Optional(CONF_EXTENDED_CONFIG): cv.boolean, } ) positive_float_template = vol.Any(cv.positive_float, cv.template) ENTITY_SCHEMA = {vol.Required(CONF_ENTITY_ID): cv.entity_id} ENABLE_DISABLE_SCHEMA = { vol.Required(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_ZONES): cv.ensure_list, vol.Optional(CONF_SEQUENCE_ID): cv.positive_int, } TIME_ADJUST_SCHEMA = vol.All( vol.Schema( { vol.Required(CONF_ENTITY_ID): cv.entity_ids, vol.Exclusive( CONF_ACTUAL, "adjust_method" ): cv.positive_time_period_template, vol.Exclusive(CONF_PERCENTAGE, "adjust_method"): positive_float_template, vol.Exclusive( CONF_INCREASE, "adjust_method" ): cv.positive_time_period_template, vol.Exclusive( CONF_DECREASE, "adjust_method" ): cv.positive_time_period_template, vol.Exclusive(CONF_RESET, "adjust_method"): None, vol.Optional(CONF_MINIMUM): cv.positive_time_period_template, vol.Optional(CONF_MAXIMUM): cv.positive_time_period_template, vol.Optional(CONF_ZONES): cv.ensure_list, vol.Optional(CONF_SEQUENCE_ID): cv.positive_int, } ), cv.has_at_least_one_key( CONF_ACTUAL, CONF_PERCENTAGE, CONF_INCREASE, CONF_DECREASE, CONF_RESET ), ) MANUAL_RUN_SCHEMA = { vol.Required(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_TIME): cv.positive_time_period_template, vol.Optional(CONF_DELAY): cv.time_period, vol.Optional(CONF_QUEUE): cv.boolean, vol.Optional(CONF_ZONES): cv.ensure_list, vol.Optional(CONF_SEQUENCE_ID): cv.positive_int, } SUSPEND_SCHEMA = vol.All( vol.Schema( { vol.Required(CONF_ENTITY_ID): cv.entity_ids, vol.Exclusive(CONF_FOR, "time_method"): cv.positive_time_period_template, vol.Exclusive(CONF_UNTIL, "time_method"): cv.datetime, vol.Exclusive(CONF_RESET, "time_method"): None, vol.Optional(CONF_ZONES): cv.ensure_list, vol.Optional(CONF_SEQUENCE_ID): cv.positive_int, } ), cv.has_at_least_one_key(CONF_FOR, CONF_UNTIL, CONF_RESET), ) CANCEL_SCHEMA = { vol.Required(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_ZONES): cv.ensure_list, vol.Optional(CONF_SEQUENCE_ID): cv.positive_int, } PAUSE_RESUME_SCHEMA = { vol.Required(CONF_ENTITY_ID): cv.entity_ids, vol.Optional(CONF_SEQUENCE_ID): cv.positive_int, } RELOAD_SERVICE_SCHEMA = vol.Schema({})