def validate_secure_url(config): url_ = config[CONF_URL] if config.get(CONF_VERIFY_SSL) and not isinstance(url_, Lambda) \ and url_.lower().startswith('https:'): raise cv.Invalid( 'Currently ESPHome doesn\'t support SSL verification. ' 'Set \'verify_ssl: false\' to make insecure HTTPS requests.') return config
def validate_secure_url(config): url_ = config[CONF_URL] if (config.get(CONF_VERIFY_SSL) and not isinstance(url_, Lambda) and url_.lower().startswith("https:")): raise cv.Invalid( "Currently ESPHome doesn't support SSL verification. " "Set 'verify_ssl: false' to make insecure HTTPS requests.") return config
def validate_count_mode(value): rising_edge = value[CONF_RISING_EDGE] falling_edge = value[CONF_FALLING_EDGE] if rising_edge == "DISABLE" and falling_edge == "DISABLE": raise cv.Invalid( "Can't set both count modes to DISABLE! This means no counting occurs at " "all!") return value
def validate_full_update_every_only_type_a(value): if CONF_FULL_UPDATE_EVERY not in value: return value if MODELS[value[CONF_MODEL]][0] != "a": raise cv.Invalid( "The 'full_update_every' option is only available for models " "'1.54in', '2.13in', '2.90in', and '2.90inV2'.") return value
def validate_send_first_at(value): send_first_at = value.get(CONF_SEND_FIRST_AT) send_every = value[CONF_SEND_EVERY] if send_first_at is not None and send_first_at > send_every: raise cv.Invalid( "send_first_at must be smaller than or equal to send_every! {} <= {}" "".format(send_first_at, send_every)) return value
def _parse_cron_part(part, min_value, max_value, special_mapping): if part in ('*', '?'): return set(range(min_value, max_value + 1)) if '/' in part: data = part.split('/') if len(data) > 2: raise cv.Invalid( "Can't have more than two '/' in one time expression, got {}". format(part)) offset, repeat = data offset_n = 0 if offset: offset_n = _parse_cron_int( offset, special_mapping, "Offset for '/' time expression must be an integer, got {}") try: repeat_n = int(repeat) except ValueError: raise cv.Invalid( "Repeat for '/' time expression must be an integer, got {}". format(repeat)) return set(range(offset_n, max_value + 1, repeat_n)) if '-' in part: data = part.split('-') if len(data) > 2: raise cv.Invalid( "Can't have more than two '-' in range time expression '{}'". format(part)) begin, end = data begin_n = _parse_cron_int( begin, special_mapping, "Number for time range must be integer, " "got {}") end_n = _parse_cron_int( end, special_mapping, "Number for time range must be integer, " "got {}") if end_n < begin_n: return set(range(end_n, max_value + 1)) | set( range(min_value, begin_n + 1)) return set(range(begin_n, end_n + 1)) return { _parse_cron_int( part, special_mapping, "Number for time expression must be an " "integer, got {}") }
def validate_raw_data(value): if isinstance(value, text_type): return value.encode('utf-8') if isinstance(value, str): return value if isinstance(value, list): return cv.Schema([cv.hex_uint8_t])(value) raise cv.Invalid("data must either be a string wrapped in quotes or a list of bytes")
def validate_invert_esp32(config): if (CORE.is_esp32 and CONF_TX_PIN in config and CONF_RX_PIN in config and config[CONF_TX_PIN][CONF_INVERTED] != config[CONF_RX_PIN][CONF_INVERTED]): raise cv.Invalid( "Different invert values for TX and RX pin are not (yet) supported for ESP32." ) return config
def validate_pin_number(value): valid_pins = [0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 37, 38, 39] if value[CONF_NUMBER] not in valid_pins: raise cv.Invalid( "Only pins {} support wakeup" "".format(", ".join(str(x) for x in valid_pins)) ) return value
def final_validate(config): has_sta = bool(config.get(CONF_NETWORKS, True)) has_ap = CONF_AP in config has_improv = "esp32_improv" in fv.full_config.get() if (not has_sta) and (not has_ap) and (not has_improv): raise cv.Invalid( "Please specify at least an SSID or an Access Point to create." )
def validator(value): if isinstance(value, list): for v in value: if not isinstance(v, int): raise cv.Invalid( f"Expected integer for {v} '{name}', got {type(v)}") if v < min_value or v > max_value: raise cv.Invalid( f"{name} {v} is out of range (min={min_value} max={max_value})." ) return list(sorted(value)) value = cv.string(value) values = set() for part in value.split(","): values |= _parse_cron_part(part, min_value, max_value, special_mapping) return validator(list(values))
def final_validate(config): has_sta = bool(config.get(CONF_NETWORKS, True)) has_ap = CONF_AP in config has_improv = "esp32_improv" in fv.full_config.get() has_improv_serial = "improv_serial" in fv.full_config.get() if not (has_sta or has_ap or has_improv or has_improv_serial): raise cv.Invalid( "Please specify at least an SSID or an Access Point to create.")
def _spi_extra_validate(config): if CORE.is_esp32: return if config[CONF_DATA_PIN] != 13 and config[CONF_CLOCK_PIN] != 14: raise cv.Invalid( "SPI only supports pins GPIO13 for data and GPIO14 for clock on ESP8266" )
def validate_tariff_time(value): value = cv.string_strict(value) parts = value.split("-") if len(parts) != 2: raise cv.Invalid("Time period should be HH:MM-HH:MM format") time_period(parts[0]) time_period(parts[1]) return value
def validate_min_max_value(config): if CONF_MIN_VALUE in config and CONF_MAX_VALUE in config: min_val = config[CONF_MIN_VALUE] max_val = config[CONF_MAX_VALUE] if min_val >= max_val: raise cv.Invalid("Max value {} must be smaller than min value {}" "".format(max_val, min_val)) return config
def validate_pin_number(value): valid_pins = WAKEUP_PINS.get(get_esp32_variant(), WAKEUP_PINS[VARIANT_ESP32]) if value[CONF_NUMBER] not in valid_pins: raise cv.Invalid( f"Only pins {', '.join(str(x) for x in valid_pins)} support wakeup" ) return value
def _parse_cron_int(value, special_mapping, message): special_mapping = special_mapping or {} if isinstance(value, str) and value in special_mapping: return special_mapping[value] try: return int(value) except ValueError: raise cv.Invalid(message.format(value))
def create_service_key(value): value = cv.string_strict(value) parts = value.split(':') if len(parts) != 8: raise cv.Invalid( "Service Key must consist of 8 : (colon) separated parts") parts_int = [] if any(len(part) != 2 for part in parts): raise cv.Invalid("Service Key must be format XX:XX:XX:XX:XX:XX:XX:XX") for part in parts: try: parts_int.append(int(part, 8)) except ValueError as error: raise cv.Invalid( "Service Key parts must be hexadecimal values from 00 to FF" ) from error return ServiceKey(*parts_int)
def validate_color_temperature_channels(value): if (value[CONF_COLD_WHITE_COLOR_TEMPERATURE] >= value[CONF_WARM_WHITE_COLOR_TEMPERATURE]): raise cv.Invalid( "Color temperature of the cold white channel must be colder than that of the warm white channel.", path=[CONF_COLD_WHITE_COLOR_TEMPERATURE], ) return value
def check_max_runs(value): if CONF_MAX_RUNS not in value: return value if value[CONF_MODE] not in [CONF_QUEUED, CONF_PARALLEL]: raise cv.Invalid( "The option 'max_runs' is only valid in 'queue' and 'parallel' mode.", path=[CONF_MAX_RUNS]) return value
def validator(value): if opt in device: raise cv.Invalid( f"The uart {opt} is used both by {name} and {device[opt]}, " f"but can only be used by one. Please create a new uart bus for {name}." ) device[opt] = name return value
def parse_multi_click_timing_str(value): if not isinstance(value, string_types): return value parts = value.lower().split(' ') if len(parts) != 5: raise cv.Invalid( "Multi click timing grammar consists of exactly 5 words, not {}" "".format(len(parts))) try: state = cv.boolean(parts[0]) except cv.Invalid: raise cv.Invalid(u"First word must either be ON or OFF, not {}".format( parts[0])) if parts[1] != 'for': raise cv.Invalid(u"Second word must be 'for', got {}".format(parts[1])) if parts[2] == 'at': if parts[3] == 'least': key = CONF_MIN_LENGTH elif parts[3] == 'most': key = CONF_MAX_LENGTH else: raise cv.Invalid( u"Third word after at must either be 'least' or 'most', got {}" u"".format(parts[3])) try: length = cv.positive_time_period_milliseconds(parts[4]) except cv.Invalid as err: raise cv.Invalid( u"Multi Click Grammar Parsing length failed: {}".format(err)) return {CONF_STATE: state, key: str(length)} if parts[3] != 'to': raise cv.Invalid("Multi click grammar: 4th word must be 'to'") try: min_length = cv.positive_time_period_milliseconds(parts[2]) except cv.Invalid as err: raise cv.Invalid( u"Multi Click Grammar Parsing minimum length failed: {}".format( err)) try: max_length = cv.positive_time_period_milliseconds(parts[4]) except cv.Invalid as err: raise cv.Invalid( u"Multi Click Grammar Parsing minimum length failed: {}".format( err)) return { CONF_STATE: state, CONF_MIN_LENGTH: str(min_length), CONF_MAX_LENGTH: str(max_length) }
def validate_calibrate_polynomial(config): if config[CONF_DEGREE] >= len(config[CONF_DATAPOINTS]): raise cv.Invalid( "Degree is too high! Maximum possible degree with given datapoints is " "{}".format(len(config[CONF_DATAPOINTS]) - 1), [CONF_DEGREE], ) return config
def _validate_key(value): value = cv.string_strict(value) parts = [value[i:i + 2] for i in range(0, len(value), 2)] if len(parts) != 16: raise cv.Invalid( "Decryption key must consist of 16 hexadecimal numbers") parts_int = [] if any(len(part) != 2 for part in parts): raise cv.Invalid("Decryption key must be format XX") for part in parts: try: parts_int.append(int(part, 16)) except ValueError: # pylint: disable=raise-missing-from raise cv.Invalid("Decryption key must be hex values from 00 to FF") return "".join(f"{part:02X}" for part in parts_int)
def validate_url(value): value = cv.string(value) try: parsed = list(urlparse.urlparse(value)) except Exception as err: raise cv.Invalid("Invalid URL") from err if not parsed[0] or not parsed[1]: raise cv.Invalid("URL must have a URL scheme and host") if parsed[0] not in ["http", "https"]: raise cv.Invalid("Scheme must be http or https") if not parsed[2]: parsed[2] = "/" return urlparse.urlunparse(parsed)
def validate_pcf8574_gpio_mode(value): value = cv.string(value) if value.upper() == "INPUT_PULLUP": raise cv.Invalid( "INPUT_PULLUP mode has been removed in 1.14 and been combined into " "INPUT mode (they were the same thing). Please use INPUT instead." ) return cv.enum(PCF8674_GPIO_MODES, upper=True)(value)
def validate_internal_filter(value): value = cv.positive_time_period_microseconds(value) if CORE.is_esp32: if value.total_microseconds > 13: raise cv.Invalid("Maximum internal filter value for ESP32 is 13us") return value return value
def validate_rc_switch_code(value): if not isinstance(value, (str, str)): raise cv.Invalid("All RCSwitch codes must be in quotes ('')") for c in value: if c not in ("0", "1"): raise cv.Invalid( "Invalid RCSwitch code character '{}'. Only '0' and '1' are allowed" "".format(c) ) if len(value) > 64: raise cv.Invalid( "Maximum length for RCSwitch codes is 64, code '{}' has length {}" "".format(value, len(value)) ) if not value: raise cv.Invalid("RCSwitch code must not be empty") return value
def validate_uid(value): value = cv.string_strict(value) for x in value.split("-"): if len(x) != 2: raise cv.Invalid( "Each part (separated by '-') of the UID must be two characters " "long.") try: x = int(x, 16) except ValueError as err: raise cv.Invalid( "Valid characters for parts of a UID are 0123456789ABCDEF." ) from err if x < 0 or x > 255: raise cv.Invalid( "Valid values for UID parts (separated by '-') are 00 to FF") return value
def validate_url(value): value = cv.string(value) try: parsed = list(urlparse.urlparse(value)) except Exception: raise cv.Invalid('Invalid URL') if not parsed[0] or not parsed[1]: raise cv.Invalid('URL must have a URL scheme and host') if parsed[0] not in ['http', 'https']: raise cv.Invalid('Scheme must be http or https') if not parsed[2]: parsed[2] = '/' return urlparse.urlunparse(parsed)