def validate(config): if CONF_PASSWORD in config and CONF_SSID not in config: raise vol.Invalid("Cannot have WiFi password without SSID!") if CONF_SSID in config: network = {CONF_SSID: config.pop(CONF_SSID)} if CONF_PASSWORD in config: network[CONF_PASSWORD] = config.pop(CONF_PASSWORD) if CONF_NETWORKS in config: raise vol.Invalid("You cannot use the 'ssid:' option together with 'networks:'. Please " "copy your network into the 'networks:' key") config[CONF_NETWORKS] = cv.ensure_list(WIFI_NETWORK_STA)(network) if (CONF_NETWORKS not in config) and (CONF_AP not in config): raise vol.Invalid("Please specify at least an SSID or an Access Point " "to create.") if config.get(CONF_FAST_CONNECT, False): networks = config.get(CONF_NETWORKS, []) if not networks: raise vol.Invalid("At least one network required for fast_connect!") if len(networks) != 1: raise vol.Invalid("Fast connect can only be used with one network!") if CONF_USE_ADDRESS not in config: if CONF_MANUAL_IP in config: use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP]) else: use_address = CORE.name + config[CONF_DOMAIN] config[CONF_USE_ADDRESS] = use_address return config
def validate_recursive_condition(value): is_list = isinstance(value, list) value = cv.ensure_list()(value)[:] for i, item in enumerate(value): path = [i] if is_list else [] item = copy.deepcopy(item) if not isinstance(item, dict): raise vol.Invalid(u"Condition must consist of key-value mapping! Got {}".format(item), path) key = next((x for x in item if x != CONF_CONDITION_ID), None) if key is None: raise vol.Invalid(u"Key missing from action! Got {}".format(item), path) if key not in CONDITION_REGISTRY: raise vol.Invalid(u"Unable to find condition with the name '{}', is the " u"component loaded?".format(key), path + [key]) item.setdefault(CONF_CONDITION_ID, None) key2 = next((x for x in item if x not in (CONF_CONDITION_ID, key)), None) if key2 is not None: raise vol.Invalid(u"Cannot have two conditions in one item. Key '{}' overrides '{}'! " u"Did you forget to indent the block inside the condition?" u"".format(key, key2), path) validator = CONDITION_REGISTRY[key][0] try: condition = validator(item[key]) except vol.Invalid as err: err.prepend(path) raise err value[i] = { CONF_CONDITION_ID: cv.declare_variable_id(Condition)(item[CONF_CONDITION_ID]), key: condition, } return value
def _validate(config): if CONF_PASSWORD in config and CONF_SSID not in config: raise cv.Invalid("Cannot have WiFi password without SSID!") if CONF_SSID in config: # Automatically move single network to 'networks' section config = config.copy() network = {CONF_SSID: config.pop(CONF_SSID)} if CONF_PASSWORD in config: network[CONF_PASSWORD] = config.pop(CONF_PASSWORD) if CONF_EAP in config: network[CONF_EAP] = config.pop(CONF_EAP) if CONF_NETWORKS in config: raise cv.Invalid( "You cannot use the 'ssid:' option together with 'networks:'. Please " "copy your network into the 'networks:' key" ) config[CONF_NETWORKS] = cv.ensure_list(WIFI_NETWORK_STA)(network) if (CONF_NETWORKS not in config) and (CONF_AP not in config): config = config.copy() config[CONF_NETWORKS] = [] if config.get(CONF_FAST_CONNECT, False): networks = config.get(CONF_NETWORKS, []) if not networks: raise cv.Invalid("At least one network required for fast_connect!") if len(networks) != 1: raise cv.Invalid("Fast connect can only be used with one network!") if CONF_USE_ADDRESS not in config: use_address = CORE.name + config[CONF_DOMAIN] if CONF_MANUAL_IP in config: use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP]) elif CONF_NETWORKS in config: ips = set( str(net[CONF_MANUAL_IP][CONF_STATIC_IP]) for net in config[CONF_NETWORKS] if CONF_MANUAL_IP in net ) if len(ips) > 1: raise cv.Invalid( "Must specify use_address when using multiple static IP addresses." ) if len(ips) == 1: use_address = next(iter(ips)) config[CONF_USE_ADDRESS] = use_address return config
def _relocate_fields_to_subfolder(config, subfolder, subschema): fields = [k.schema for k in subschema.schema.keys()] fields.remove(CONF_ID) if subfolder in config: # Ensure no ambiguous fields in base of config for f in fields: if f in config: raise cv.Invalid("You cannot use the '" + str(f) + "' field when already using 'traces:'. " "Please move it into 'traces:' entry.") else: # Copy over all fields to subfolder: trace = {} for f in fields: if f in config: trace[f] = config.pop(f) config[subfolder] = cv.ensure_list(subschema)(trace) return config
cv.declare_variable_id(StartupTrigger), vol.Optional(CONF_PRIORITY): cv.float_, }), vol.Optional(CONF_ON_SHUTDOWN): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ShutdownTrigger), }), vol.Optional(CONF_ON_LOOP): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(LoopTrigger), }), vol.Optional(CONF_INCLUDES): cv.ensure_list(cv.file_), vol.Optional(CONF_LIBRARIES): cv.ensure_list(cv.string_strict), vol.Optional('esphomelib_version'): cv.invalid("The esphomelib_version has been renamed to " "esphome_core_version in 1.11.0"), }) def preload_core_config(config): if 'esphomeyaml' in config: _LOGGER.warning( "The esphomeyaml section has been renamed to esphome in 1.11.0. " "Please replace 'esphomeyaml:' in your configuration with 'esphome:'." ) config[CONF_ESPHOME] = config.pop('esphomeyaml')
from esphome.const import CONF_ID, CONF_OUTPUTS, CONF_TYPE from esphome.cpp_generator import Pvariable, get_variable from esphome.cpp_helpers import setup_component BinaryCopyOutput = output.output_ns.class_('BinaryCopyOutput', output.BinaryOutput) FloatCopyOutput = output.output_ns.class_('FloatCopyOutput', output.FloatOutput) BINARY_SCHEMA = output.PLATFORM_SCHEMA.extend({ vol.Required(CONF_ID): cv.declare_variable_id(BinaryCopyOutput), vol.Required(CONF_TYPE): 'binary', vol.Required(CONF_OUTPUTS): cv.ensure_list(cv.use_variable_id(output.BinaryOutput)), }) FLOAT_SCHEMA = output.PLATFORM_SCHEMA.extend({ vol.Required(CONF_ID): cv.declare_variable_id(FloatCopyOutput), vol.Required(CONF_TYPE): 'float', vol.Required(CONF_OUTPUTS): cv.ensure_list(cv.use_variable_id(output.FloatOutput)), }) def validate_copy_output(value): if not isinstance(value, dict): raise vol.Invalid("Value must be dict")
cv.Schema({ cv.GenerateID(): cv.declare_id(ModbusController), cv.Optional(CONF_COMMAND_THROTTLE, default="0ms"): cv.positive_time_period_milliseconds, }).extend(cv.polling_component_schema("60s")).extend( modbus.modbus_device_schema(0x01))) ModbusItemBaseSchema = cv.Schema( { cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController), cv.Optional(CONF_ADDRESS): cv.positive_int, cv.Optional(CONF_CUSTOM_COMMAND): cv.ensure_list(cv.hex_uint8_t), cv.Exclusive( CONF_OFFSET, "offset", f"{CONF_OFFSET} and {CONF_BYTE_OFFSET} can't be used together", ): cv.positive_int, cv.Exclusive( CONF_BYTE_OFFSET, "offset", f"{CONF_OFFSET} and {CONF_BYTE_OFFSET} can't be used together", ): cv.positive_int, cv.Optional(CONF_BITMASK, default=0xFFFFFFFF): cv.hex_uint32_t, cv.Optional(CONF_SKIP_UPDATES, default=0):
], ): cv.All( cv.ensure_list( cv.Schema({ cv.Optional(CONF_STATE, default=True): cv.boolean, cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage, cv.Optional(CONF_RED, default=1.0): cv.percentage, cv.Optional(CONF_GREEN, default=1.0): cv.percentage, cv.Optional(CONF_BLUE, default=1.0): cv.percentage, cv.Optional(CONF_WHITE, default=1.0): cv.percentage, cv.Required(CONF_DURATION): cv.positive_time_period_milliseconds, }), cv.has_at_least_one_key( CONF_STATE, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, ), ), cv.Length(min=2), ), },
import esphome.config_validation as cv from esphome.components import text_sensor from esphome.const import CONF_ID, CONF_LAMBDA, CONF_TEXT_SENSORS from .. import custom_ns CustomTextSensorConstructor = custom_ns.class_('CustomTextSensorConstructor') CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(CustomTextSensorConstructor), cv.Required(CONF_LAMBDA): cv.returning_lambda, cv.Required(CONF_TEXT_SENSORS): cv.ensure_list( text_sensor.TEXT_SENSOR_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), })), }) def to_code(config): template_ = yield cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.std_vector.template( text_sensor.TextSensorPtr)) rhs = CustomTextSensorConstructor(template_) var = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_TEXT_SENSORS]): text = cg.Pvariable(conf[CONF_ID], var.get_text_sensor(i))
SensorMapType = binary_sensor_map_ns.enum('SensorMapType') CONF_GROUP = 'group' SENSOR_MAP_TYPES = { CONF_GROUP: SensorMapType.BINARY_SENSOR_MAP_TYPE_GROUP, } entry = { cv.Required(CONF_BINARY_SENSOR): cv.use_id(binary_sensor.BinarySensor), cv.Required(CONF_VALUE): cv.float_, } CONFIG_SCHEMA = cv.typed_schema({ CONF_GROUP: sensor.sensor_schema(UNIT_EMPTY, ICON_CHECK_CIRCLE_OUTLINE, 0).extend({ cv.GenerateID(): cv.declare_id(BinarySensorMap), cv.Required(CONF_CHANNELS): cv.All(cv.ensure_list(entry), cv.Length(min=1)), }), }, lower=True) def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) yield sensor.register_sensor(var, config) constant = SENSOR_MAP_TYPES[config[CONF_TYPE]] cg.add(var.set_sensor_type(constant)) for ch in config[CONF_CHANNELS]: input_var = yield cg.get_variable(ch[CONF_BINARY_SENSOR]) cg.add(var.add_channel(input_var, ch[CONF_VALUE]))
cv.GenerateID(): cv.declare_id(i2c.I2CDevice) }).extend(i2c.i2c_device_schema(None)) CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(HT16K33AlphaDisplay), cv.Optional(CONF_SCROLL, default=False): cv.boolean, cv.Optional(CONF_SCROLL_SPEED, default='250ms'): cv.positive_time_period_milliseconds, cv.Optional(CONF_SCROLL_DWELL, default='2s'): cv.positive_time_period_milliseconds, cv.Optional(CONF_SCROLL_DELAY, default='3'): cv.float_range(min=1), cv.Optional(CONF_SECONDARY_DISPLAYS): cv.ensure_list(CONFIG_SECONDARY), }).extend(cv.polling_component_schema('1s')).extend( i2c.i2c_device_schema(0x70)) def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) yield display.register_display(var, config) yield i2c.register_i2c_device(var, config) if CONF_LAMBDA in config: lambda_ = yield cg.process_lambda( config[CONF_LAMBDA], [(HT16K33AlphaDisplay.operator('ref'), 'it')], return_type=cg.void) cg.add(var.set_writer(lambda_))
return SOURCE_SCHEMA(conf) SOURCE_SCHEMA = cv.Any( validate_source_shorthand, cv.typed_schema({ TYPE_GIT: cv.Schema(GIT_SCHEMA), TYPE_LOCAL: cv.Schema(LOCAL_SCHEMA), }), ) CONFIG_SCHEMA = cv.ensure_list({ cv.Required(CONF_SOURCE): SOURCE_SCHEMA, cv.Optional(CONF_REFRESH, default="1d"): cv.All(cv.string, cv.source_refresh), cv.Optional(CONF_COMPONENTS, default="all"): cv.Any("all", cv.ensure_list(cv.string)), }) async def to_code(config): pass def _process_git_config(config: dict, refresh) -> str: repo_dir = git.clone_or_update( url=config[CONF_URL], ref=config.get(CONF_REF), refresh=refresh, domain=DOMAIN,
import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import cover from esphome.const import CONF_ID, CONF_LAMBDA from .. import custom_ns CustomCoverConstructor = custom_ns.class_('CustomCoverConstructor') CONF_COVERS = 'covers' CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(CustomCoverConstructor), cv.Required(CONF_LAMBDA): cv.returning_lambda, cv.Required(CONF_COVERS): cv.ensure_list(cover.COVER_SCHEMA), }) def to_code(config): template_ = yield cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.std_vector.template( cover.Cover.operator('ptr'))) rhs = CustomCoverConstructor(template_) custom = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_COVERS]): rhs = custom.Pget_cover(i) yield cover.register_cover(rhs, conf)
FILTER_KEYS = [CONF_OFFSET, CONF_MULTIPLY, CONF_FILTER_OUT, CONF_FILTER_NAN, CONF_SLIDING_WINDOW_MOVING_AVERAGE, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_LAMBDA, CONF_THROTTLE, CONF_DELTA, CONF_UNIQUE, CONF_HEARTBEAT, CONF_DEBOUNCE, CONF_OR] FILTERS_SCHEMA = cv.ensure_list({ vol.Optional(CONF_OFFSET): cv.float_, vol.Optional(CONF_MULTIPLY): cv.float_, vol.Optional(CONF_FILTER_OUT): cv.float_, vol.Optional(CONF_FILTER_NAN): None, vol.Optional(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.All(vol.Schema({ vol.Optional(CONF_WINDOW_SIZE, default=15): cv.positive_not_null_int, vol.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int, vol.Optional(CONF_SEND_FIRST_AT): cv.positive_not_null_int, }), validate_send_first_at), vol.Optional(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({ vol.Optional(CONF_ALPHA, default=0.1): cv.positive_float, vol.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int, }), vol.Optional(CONF_LAMBDA): cv.lambda_, vol.Optional(CONF_THROTTLE): cv.positive_time_period_milliseconds, vol.Optional(CONF_DELTA): cv.float_, vol.Optional(CONF_UNIQUE): None, vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEBOUNCE): cv.positive_time_period_milliseconds, vol.Optional(CONF_OR): validate_recursive_filter, }, cv.has_exactly_one_key(*FILTER_KEYS)) # Base sensor_ns = esphome_ns.namespace('sensor') Sensor = sensor_ns.class_('Sensor', Nameable) SensorPtr = Sensor.operator('ptr')
if CONF_INITIAL_OPTION in config: if config[CONF_INITIAL_OPTION] not in config[CONF_OPTIONS]: raise cv.Invalid( f"initial_option '{config[CONF_INITIAL_OPTION]}' is not a valid option [{', '.join(config[CONF_OPTIONS])}]" ) else: config[CONF_INITIAL_OPTION] = config[CONF_OPTIONS][0] return config CONFIG_SCHEMA = cv.All( select.SELECT_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(TemplateSelect), cv.Required(CONF_OPTIONS): cv.All(cv.ensure_list(cv.string_strict), cv.Length(min=1)), cv.Optional(CONF_LAMBDA): cv.returning_lambda, cv.Optional(CONF_OPTIMISTIC): cv.boolean, cv.Optional(CONF_SET_ACTION): automation.validate_automation(single=True), cv.Optional(CONF_INITIAL_OPTION): cv.string_strict, cv.Optional(CONF_RESTORE_VALUE): cv.boolean, }).extend(cv.polling_component_schema("60s")), validate_initial_value_in_options, )
cv.declare_id(DeepSleepComponent), cv.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds, cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, cv.Optional(CONF_WAKEUP_PIN): cv.All(cv.only_on_esp32, pins.internal_gpio_input_pin_schema, validate_pin_number), cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All(cv.only_on_esp32, cv.enum(WAKEUP_PIN_MODES), upper=True), cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All( cv.only_on_esp32, cv.Schema({ cv.Required(CONF_PINS): cv.ensure_list(pins.shorthand_input_pin, validate_pin_number), cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True), })), cv.Optional(CONF_RUN_CYCLES): cv.invalid("The run_cycles option has been removed in 1.11.0 as " "it was essentially the same as a run_duration of 0s." "Please use run_duration now.") }).extend(cv.COMPONENT_SCHEMA) def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) if CONF_SLEEP_DURATION in config:
cv.declare_id(StartupTrigger), cv.Optional(CONF_PRIORITY, default=600.0): cv.float_, }), cv.Optional(CONF_ON_SHUTDOWN): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ShutdownTrigger), }), cv.Optional(CONF_ON_LOOP): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LoopTrigger), }), cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(valid_include), cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict), cv.Optional('esphome_core_version'): cv.invalid("The esphome_core_version option has been " "removed in 1.13 - the esphome core source " "files are now bundled with ESPHome.") }) PRELOAD_CONFIG_SCHEMA = cv.Schema( { cv.Required(CONF_NAME): cv.valid_name, cv.Required(CONF_PLATFORM): validate_platform, }, extra=cv.ALLOW_EXTRA)
from esphome.components import time as time_ import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import CONF_ID, CONF_SERVERS DEPENDENCIES = ['network'] sntp_ns = cg.esphome_ns.namespace('sntp') SNTPComponent = sntp_ns.class_('SNTPComponent', time_.RealTimeClock) DEFAULT_SERVERS = ["0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org"] CONFIG_SCHEMA = time_.TIME_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(SNTPComponent), cv.Optional(CONF_SERVERS, default=DEFAULT_SERVERS): cv.All(cv.ensure_list(cv.domain), cv.Length(min=1, max=3)), }).extend(cv.COMPONENT_SCHEMA) def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) servers = config[CONF_SERVERS] servers += [''] * (3 - len(servers)) cg.add(var.set_servers(*servers)) yield cg.register_component(var, config) yield time_.register_time(var, config)
CONF_TAG_NAME = "tag_name" TELEINFO_TAG_SCHEMA = cv.Schema({ cv.Required(CONF_TAG_NAME): cv.string, cv.Required(CONF_SENSOR): sensor.sensor_schema(UNIT_WATT_HOURS, ICON_EMPTY, 0, DEVICE_CLASS_POWER), }) CONF_TAGS = "tags" CONF_HISTORICAL_MODE = "historical_mode" CONFIG_SCHEMA = (cv.Schema({ cv.GenerateID(): cv.declare_id(TeleInfo), cv.Optional(CONF_HISTORICAL_MODE, default=False): cv.boolean, cv.Optional(CONF_TAGS): cv.ensure_list(TELEINFO_TAG_SCHEMA), }).extend(cv.polling_component_schema("60s")).extend(uart.UART_DEVICE_SCHEMA)) def to_code(config): var = cg.new_Pvariable(config[CONF_ID], config[CONF_HISTORICAL_MODE]) yield cg.register_component(var, config) yield uart.register_uart_device(var, config) if CONF_TAGS in config: for tag in config[CONF_TAGS]: sens = yield sensor.new_sensor(tag[CONF_SENSOR]) cg.add(var.register_teleinfo_sensor(tag[CONF_TAG_NAME], sens))
CONF_TIME_OFF = "time_off" CONF_TIME_ON = "time_on" DEFAULT_DELAY = "1s" DEFAULT_TIME_OFF = "100ms" DEFAULT_TIME_ON = "900ms" @FILTER_REGISTRY.register( "autorepeat", AutorepeatFilter, cv.All( cv.ensure_list({ cv.Optional(CONF_DELAY, default=DEFAULT_DELAY): cv.positive_time_period_milliseconds, cv.Optional(CONF_TIME_OFF, default=DEFAULT_TIME_OFF): cv.positive_time_period_milliseconds, cv.Optional(CONF_TIME_ON, default=DEFAULT_TIME_ON): cv.positive_time_period_milliseconds, }), ), ) async def autorepeat_filter_to_code(config, filter_id): timings = [] if len(config) > 0: for conf in config: timings.append( (conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON])) else: timings.append(( cv.time_period_str_unit(DEFAULT_DELAY).total_milliseconds, cv.time_period_str_unit(DEFAULT_TIME_OFF).total_milliseconds, cv.time_period_str_unit(DEFAULT_TIME_ON).total_milliseconds,
cv.Optional(CONF_PASSWORD, default=''): cv.string, cv.Optional(CONF_CLIENT_ID): cv.string, cv.Optional(CONF_DISCOVERY, default=True): cv.Any(cv.boolean, cv.one_of("CLEAN", upper=True)), cv.Optional(CONF_DISCOVERY_RETAIN, default=True): cv.boolean, cv.Optional(CONF_DISCOVERY_PREFIX, default="homeassistant"): cv.publish_topic, cv.Optional(CONF_BIRTH_MESSAGE): MQTT_MESSAGE_SCHEMA, cv.Optional(CONF_WILL_MESSAGE): MQTT_MESSAGE_SCHEMA, cv.Optional(CONF_SHUTDOWN_MESSAGE): MQTT_MESSAGE_SCHEMA, cv.Optional(CONF_TOPIC_PREFIX, default=lambda: CORE.name): cv.publish_topic, cv.Optional(CONF_LOG_TOPIC): cv.Any(None, MQTT_MESSAGE_BASE.extend({ cv.Optional(CONF_LEVEL): logger.is_log_level, }), validate_message_just_topic), cv.Optional(CONF_SSL_FINGERPRINTS): cv.All(cv.only_on_esp8266, cv.ensure_list(validate_fingerprint)), cv.Optional(CONF_KEEPALIVE, default='15s'): cv.positive_time_period_seconds, cv.Optional(CONF_REBOOT_TIMEOUT, default='5min'): cv.positive_time_period_milliseconds, cv.Optional(CONF_ON_MESSAGE): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MQTTMessageTrigger), cv.Required(CONF_TOPIC): cv.subscribe_topic, cv.Optional(CONF_QOS, default=0): cv.mqtt_qos, cv.Optional(CONF_PAYLOAD): cv.string_strict, }), cv.Optional(CONF_ON_JSON_MESSAGE): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MQTTJsonMessageTrigger), cv.Required(CONF_TOPIC): cv.subscribe_topic, cv.Optional(CONF_QOS, default=0): cv.mqtt_qos, }), }), validate_config)
matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X) if len(matches) != len(value[CONF_ARGS]): raise cv.Invalid( u"Found {} printf-patterns ({}), but {} args were given!" u"".format(len(matches), u', '.join(matches), len(value[CONF_ARGS]))) return value CONF_LOGGER_LOG = 'logger.log' LOGGER_LOG_ACTION_SCHEMA = cv.All( maybe_simple_message({ cv.Required(CONF_FORMAT): cv.string, cv.Optional(CONF_ARGS, default=list): cv.ensure_list(cv.lambda_), cv.Optional(CONF_LEVEL, default="DEBUG"): cv.one_of(*LOG_LEVEL_TO_ESP_LOG, upper=True), cv.Optional(CONF_TAG, default="main"): cv.string, }), validate_printf) @automation.register_action(CONF_LOGGER_LOG, LambdaAction, LOGGER_LOG_ACTION_SCHEMA) def logger_log_action_to_code(config, action_id, template_arg, args): esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]] args_ = [cg.RawExpression(text_type(x)) for x in config[CONF_ARGS]] text = text_type( cg.statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args_)))
import esphome.config_validation as cv from esphome.components import switch from esphome.const import CONF_ID, CONF_LAMBDA, CONF_SWITCHES from .. import custom_ns CustomSwitchConstructor = custom_ns.class_("CustomSwitchConstructor") CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(CustomSwitchConstructor), cv.Required(CONF_LAMBDA): cv.returning_lambda, cv.Required(CONF_SWITCHES): cv.ensure_list( switch.SWITCH_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(switch.Switch), })), }) def to_code(config): template_ = yield cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.std_vector.template( switch.SwitchPtr)) rhs = CustomSwitchConstructor(template_) var = cg.variable(config[CONF_ID], rhs) for i, conf in enumerate(config[CONF_SWITCHES]): switch_ = cg.Pvariable(conf[CONF_ID], var.get_switch(i)) yield switch.register_switch(switch_, conf)
cv.All(cv.only_on_esp32, WAKEUP_CAUSES_SCHEMA), cv.positive_time_period_milliseconds, ), cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, cv.Optional(CONF_WAKEUP_PIN): cv.All(cv.only_on_esp32, pins.internal_gpio_input_pin_schema, validate_pin_number), cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All(cv.only_on_esp32, cv.enum(WAKEUP_PIN_MODES), upper=True), cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All( cv.only_on_esp32, cv.Schema({ cv.Required(CONF_PINS): cv.ensure_list(pins.internal_gpio_input_pin_schema, validate_pin_number), cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True), }), ), cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean), }).extend(cv.COMPONENT_SCHEMA) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) if CONF_SLEEP_DURATION in config: cg.add(var.set_sleep_duration(config[CONF_SLEEP_DURATION]))
if CONF_MANUAL_IP in config: use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP]) else: use_address = CORE.name + config[CONF_DOMAIN] config[CONF_USE_ADDRESS] = use_address return config CONF_OUTPUT_POWER = "output_power" CONFIG_SCHEMA = cv.All( cv.Schema({ cv.GenerateID(): cv.declare_id(WiFiComponent), cv.Optional(CONF_NETWORKS): cv.ensure_list(WIFI_NETWORK_STA), cv.Optional(CONF_SSID): cv.ssid, cv.Optional(CONF_PASSWORD): validate_password, cv.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA, cv.Optional(CONF_EAP): EAP_AUTH_SCHEMA, cv.Optional(CONF_AP): WIFI_NETWORK_AP, cv.Optional(CONF_ENABLE_MDNS, default=True): cv.boolean, cv.Optional(CONF_DOMAIN, default=".local"): cv.domain_name, cv.Optional(CONF_REBOOT_TIMEOUT, default="15min"):
tca9548a_ns = cg.esphome_ns.namespace("tca9548a") TCA9548AComponent = tca9548a_ns.class_("TCA9548AComponent", cg.Component, i2c.I2CDevice) TCA9548AChannel = tca9548a_ns.class_("TCA9548AChannel", i2c.I2CBus) MULTI_CONF = True CONF_BUS_ID = "bus_id" CONFIG_SCHEMA = (cv.Schema({ cv.GenerateID(): cv.declare_id(TCA9548AComponent), cv.Optional(CONF_SCAN): cv.invalid("This option has been removed"), cv.Optional(CONF_CHANNELS, default=[]): cv.ensure_list({ cv.Required(CONF_BUS_ID): cv.declare_id(TCA9548AChannel), cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7), }), }).extend(i2c.i2c_device_schema(0x70)).extend(cv.COMPONENT_SCHEMA)) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await i2c.register_i2c_device(var, config) for conf in config[CONF_CHANNELS]: chan = cg.new_Pvariable(conf[CONF_BUS_ID]) cg.add(chan.set_parent(var)) cg.add(chan.set_channel(conf[CONF_CHANNEL]))
MQTT_MESSAGE_SCHEMA, vol.Optional(CONF_WILL_MESSAGE): MQTT_MESSAGE_SCHEMA, vol.Optional(CONF_SHUTDOWN_MESSAGE): MQTT_MESSAGE_SCHEMA, vol.Optional(CONF_TOPIC_PREFIX): cv.publish_topic, vol.Optional(CONF_LOG_TOPIC): vol.Any( None, MQTT_MESSAGE_BASE.extend({ vol.Optional(CONF_LEVEL): logger.is_log_level, }), validate_message_just_topic), vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266, cv.ensure_list(validate_fingerprint)), vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds, vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds, vol.Optional(CONF_ON_MESSAGE): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger), vol.Required(CONF_TOPIC): cv.subscribe_topic, vol.Optional(CONF_QOS): cv.mqtt_qos, vol.Optional(CONF_PAYLOAD): cv.string_strict, }),
} entry = { cv.Required(CONF_BINARY_SENSOR): cv.use_id(binary_sensor.BinarySensor), cv.Required(CONF_VALUE): cv.float_, } CONFIG_SCHEMA = cv.typed_schema( { CONF_GROUP: sensor.sensor_schema(UNIT_EMPTY, ICON_CHECK_CIRCLE_OUTLINE, 0, DEVICE_CLASS_EMPTY).extend({ cv.GenerateID(): cv.declare_id(BinarySensorMap), cv.Required(CONF_CHANNELS): cv.All(cv.ensure_list(entry), cv.Length(min=1)), }), }, lower=True, ) async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await sensor.register_sensor(var, config) constant = SENSOR_MAP_TYPES[config[CONF_TYPE]] cg.add(var.set_sensor_type(constant))
GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_OFF, 'RESTORE_DEFAULT_ON': GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_ON, 'ALWAYS_OFF': GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_OFF, 'ALWAYS_ON': GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_ON, } CONF_INTERLOCK_WAIT_TIME = 'interlock_wait_time' CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(GPIOSwitch), cv.Required(CONF_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_RESTORE_MODE, default='RESTORE_DEFAULT_OFF'): cv.enum(RESTORE_MODES, upper=True, space='_'), cv.Optional(CONF_INTERLOCK): cv.ensure_list(cv.use_id(switch.Switch)), cv.Optional(CONF_INTERLOCK_WAIT_TIME, default='0ms'): cv.positive_time_period_milliseconds, }).extend(cv.COMPONENT_SCHEMA) def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) yield switch.register_switch(var, config) pin = yield cg.gpio_pin_expression(config[CONF_PIN]) cg.add(var.set_pin(pin)) cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
await cg.register_component(var, {}) return var def validate_not_all_from_same(config): if all(conf[CONF_FROM] == config[0][CONF_FROM] for conf in config): raise cv.Invalid( "The 'from' values of the calibrate_linear filter cannot all point " "to the same value! Please add more values to the filter.") return config @FILTER_REGISTRY.register( "calibrate_linear", CalibrateLinearFilter, cv.All(cv.ensure_list(validate_datapoint), cv.Length(min=2), validate_not_all_from_same), ) async def calibrate_linear_filter_to_code(config, filter_id): x = [conf[CONF_FROM] for conf in config] y = [conf[CONF_TO] for conf in config] k, b = fit_linear(x, y) return cg.new_Pvariable(filter_id, k, b) CONF_DATAPOINTS = "datapoints" CONF_DEGREE = "degree" def validate_calibrate_polynomial(config): if config[CONF_DEGREE] >= len(config[CONF_DATAPOINTS]):