diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py index 9a3c153a03..4d595f11d1 100644 --- a/esphome/components/cover/__init__.py +++ b/esphome/components/cover/__init__.py @@ -1,18 +1,24 @@ import voluptuous as vol -from esphome.automation import ACTION_REGISTRY, maybe_simple_id +from esphome.automation import ACTION_REGISTRY, maybe_simple_id, Condition from esphome.components import mqtt from esphome.components.mqtt import setup_mqtt_component import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_INTERNAL, CONF_MQTT_ID +from esphome.const import CONF_ID, CONF_INTERNAL, CONF_MQTT_ID, CONF_DEVICE_CLASS, CONF_STATE, \ + CONF_POSITION, CONF_TILT, CONF_STOP from esphome.core import CORE -from esphome.cpp_generator import Pvariable, add, get_variable -from esphome.cpp_types import Action, Nameable, esphome_ns +from esphome.cpp_generator import Pvariable, add, get_variable, templatable +from esphome.cpp_types import Action, Nameable, esphome_ns, App PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ }) +DEVICE_CLASSES = [ + '', 'awning', 'blind', 'curtain', 'damper', 'door', 'garage', + 'shade', 'shutter', 'window' +] + cover_ns = esphome_ns.namespace('cover') Cover = cover_ns.class_('Cover', Nameable) @@ -32,10 +38,14 @@ COVER_STATES = { OpenAction = cover_ns.class_('OpenAction', Action) CloseAction = cover_ns.class_('CloseAction', Action) StopAction = cover_ns.class_('StopAction', Action) +ControlAction = cover_ns.class_('ControlAction', Action) +CoverIsOpenCondition = cover_ns.class_('CoverIsOpenCondition', Condition) +CoverIsClosedCondition = cover_ns.class_('CoverIsClosedCondition', Condition) COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(Cover), cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTCoverComponent), + vol.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True), }) COVER_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(COVER_SCHEMA.schema) @@ -44,6 +54,8 @@ COVER_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(COVER_SCHEMA.schema) def setup_cover_core_(cover_var, config): if CONF_INTERNAL in config: add(cover_var.set_internal(config[CONF_INTERNAL])) + if CONF_DEVICE_CLASS in config: + add(cover_var.set_device_class(config[CONF_DEVICE_CLASS])) setup_mqtt_component(cover_var.Pget_mqtt(), config) @@ -51,6 +63,13 @@ def setup_cover(cover_obj, config): CORE.add_job(setup_cover_core_, cover_obj, config) +def register_cover(var, config): + if not CORE.has_id(config[CONF_ID]): + var = Pvariable(config[CONF_ID], var, has_side_effects=True) + add(App.register_cover(var)) + CORE.add_job(setup_cover_core_, var, config) + + BUILD_FLAGS = '-DUSE_COVER' CONF_COVER_OPEN = 'cover.open' @@ -96,3 +115,40 @@ def cover_stop_to_code(config, action_id, template_arg, args): rhs = var.make_stop_action(template_arg) type = StopAction.template(template_arg) yield Pvariable(action_id, rhs, type=type) + + +CONF_COVER_CONTROL = 'cover.control' +COVER_CONTROL_ACTION_SCHEMA = cv.Schema({ + vol.Required(CONF_ID): cv.use_variable_id(Cover), + vol.Optional(CONF_STOP): cv.templatable(cv.boolean), + vol.Exclusive(CONF_STATE, 'pos'): cv.templatable(cv.one_of(*COVER_STATES)), + vol.Exclusive(CONF_POSITION, 'pos'): cv.templatable(cv.percentage), + vol.Optional(CONF_TILT): cv.templatable(cv.percentage), +}) + + +@ACTION_REGISTRY.register(CONF_COVER_CONTROL, COVER_CONTROL_ACTION_SCHEMA) +def cover_control_to_code(config, action_id, template_arg, args): + for var in get_variable(config[CONF_ID]): + yield None + type = StopAction.template(template_arg) + rhs = type.new(var) + action = Pvariable(action_id, rhs, type=type) + if CONF_STOP in config: + for template_ in templatable(config[CONF_STOP], args, bool): + yield None + add(action.set_stop(template_)) + if CONF_STATE in config: + for template_ in templatable(config[CONF_STATE], args, float, + to_exp=COVER_STATES): + yield None + add(action.set_position(template_)) + if CONF_POSITION in config: + for template_ in templatable(config[CONF_POSITION], args, float): + yield None + add(action.set_position(template_)) + if CONF_TILT in config: + for template_ in templatable(config[CONF_TILT], args, float): + yield None + add(action.set_tilt(template_)) + yield action diff --git a/esphome/components/cover/endstop.py b/esphome/components/cover/endstop.py new file mode 100644 index 0000000000..982d178a87 --- /dev/null +++ b/esphome/components/cover/endstop.py @@ -0,0 +1,57 @@ +import voluptuous as vol + +from esphome import automation +from esphome.components import binary_sensor, cover +import esphome.config_validation as cv +from esphome.const import CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, \ + CONF_CLOSE_ENDSTOP, CONF_ID, CONF_NAME, CONF_OPEN_ACTION, CONF_OPEN_DURATION, \ + CONF_OPEN_ENDSTOP, CONF_STOP_ACTION, CONF_MAX_DURATION +from esphome.cpp_generator import Pvariable, add, get_variable +from esphome.cpp_helpers import setup_component +from esphome.cpp_types import App + +EndstopCover = cover.cover_ns.class_('EndstopCover', cover.Cover) + +PLATFORM_SCHEMA = cv.nameable(cover.COVER_PLATFORM_SCHEMA.extend({ + cv.GenerateID(): cv.declare_variable_id(EndstopCover), + vol.Required(CONF_STOP_ACTION): automation.validate_automation(single=True), + + vol.Required(CONF_OPEN_ENDSTOP): cv.use_variable_id(binary_sensor.BinarySensor), + vol.Required(CONF_OPEN_ACTION): automation.validate_automation(single=True), + vol.Required(CONF_OPEN_DURATION): cv.positive_time_period_milliseconds, + + vol.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True), + vol.Required(CONF_CLOSE_ENDSTOP): cv.use_variable_id(binary_sensor.BinarySensor), + vol.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds, + vol.Optional(CONF_MAX_DURATION): cv.positive_time_period_milliseconds, +}).extend(cv.COMPONENT_SCHEMA.schema)) + + +def to_code(config): + rhs = App.register_component(EndstopCover.new(config[CONF_NAME])) + var = Pvariable(config[CONF_ID], rhs) + cover.register_cover(var, config) + setup_component(var, config) + + automation.build_automations(var.get_stop_trigger(), [], + config[CONF_STOP_ACTION]) + + for bin in get_variable(config[CONF_OPEN_ENDSTOP]): + yield + add(var.set_open_endstop(bin)) + add(var.set_open_duration(config[CONF_OPEN_DURATION])) + automation.build_automations(var.get_open_trigger(), [], + config[CONF_OPEN_ACTION]) + + for bin in get_variable(config[CONF_CLOSE_ENDSTOP]): + yield + add(var.set_close_endstop(bin)) + add(var.set_close_duration(config[CONF_CLOSE_DURATION])) + automation.build_automations(var.get_close_trigger(), [], + config[CONF_CLOSE_ACTION]) + + if CONF_MAX_DURATION in config: + add(var.set_max_duration(config[CONF_MAX_DURATION])) + + +BUILD_FLAGS = '-DUSE_ENDSTOP_COVER' diff --git a/esphome/components/cover/template.py b/esphome/components/cover/template.py index a7e2c19d39..708ee297a9 100644 --- a/esphome/components/cover/template.py +++ b/esphome/components/cover/template.py @@ -9,7 +9,6 @@ from esphome.const import CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_ID, CONF_L from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable from esphome.cpp_helpers import setup_component from esphome.cpp_types import Action, App, optional -from esphome.py_compat import string_types TemplateCover = cover.cover_ns.class_('TemplateCover', cover.Cover) CoverPublishAction = cover.cover_ns.class_('CoverPublishAction', Action) @@ -69,11 +68,8 @@ def cover_template_publish_to_code(config, action_id, template_arg, args): rhs = var.make_cover_publish_action(template_arg) type = CoverPublishAction.template(template_arg) action = Pvariable(action_id, rhs, type=type) - state = config[CONF_STATE] - if isinstance(state, string_types): - template_ = cover.COVER_STATES[state] - else: - for template_ in templatable(state, args, cover.CoverState): - yield None + for template_ in templatable(config[CONF_STATE], args, cover.CoverState, + to_exp=cover.COVER_STATES): + yield None add(action.set_state(template_)) yield action diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 540964980a..a82ecdceef 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -8,7 +8,8 @@ from esphome.const import CONF_ALPHA, CONF_BLUE, CONF_BRIGHTNESS, CONF_COLORS, \ CONF_COLOR_TEMPERATURE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_DURATION, CONF_EFFECT, \ CONF_EFFECTS, CONF_EFFECT_ID, CONF_FLASH_LENGTH, CONF_GAMMA_CORRECT, CONF_GREEN, CONF_ID, \ CONF_INTERNAL, CONF_LAMBDA, CONF_MQTT_ID, CONF_NAME, CONF_NUM_LEDS, CONF_RANDOM, CONF_RED, \ - CONF_SPEED, CONF_STATE, CONF_TRANSITION_LENGTH, CONF_UPDATE_INTERVAL, CONF_WHITE, CONF_WIDTH + CONF_SPEED, CONF_STATE, CONF_TRANSITION_LENGTH, CONF_UPDATE_INTERVAL, CONF_WHITE, CONF_WIDTH, \ + CONF_COLOR_CORRECT from esphome.core import CORE from esphome.cpp_generator import Pvariable, StructInitializer, add, get_variable, process_lambda, \ templatable @@ -249,7 +250,24 @@ LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTJSONLightComponent), }) -LIGHT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(LIGHT_SCHEMA.schema) +BINARY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend({ + vol.Optional(CONF_EFFECTS): validate_effects(BINARY_EFFECTS), +}) + +BRIGHTNESS_ONLY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend({ + vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, + vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, + vol.Optional(CONF_EFFECTS): validate_effects(MONOCHROMATIC_EFFECTS), +}) + +RGB_LIGHT_SCHEMA = BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({ + vol.Optional(CONF_EFFECTS): validate_effects(RGB_EFFECTS), +}) + +ADDRESSABLE_LIGHT_SCHEMA = RGB_LIGHT_SCHEMA.extend({ + vol.Optional(CONF_EFFECTS): validate_effects(ADDRESSABLE_EFFECTS), + vol.Optional(CONF_COLOR_CORRECT): vol.All([cv.percentage], vol.Length(min=3, max=4)), +}) def build_effect(full_config): @@ -386,6 +404,9 @@ def setup_light_core_(light_var, config): if effects: add(light_var.add_effects(effects)) + if CONF_COLOR_CORRECT in config: + add(light_var.set_correction(*config[CONF_COLOR_CORRECT])) + setup_mqtt_component(light_var.Pget_mqtt(), config) diff --git a/esphome/components/light/binary.py b/esphome/components/light/binary.py index 522a4f082c..a1dc1c20a4 100644 --- a/esphome/components/light/binary.py +++ b/esphome/components/light/binary.py @@ -7,11 +7,10 @@ from esphome.cpp_generator import get_variable, variable from esphome.cpp_helpers import setup_component from esphome.cpp_types import App -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight), vol.Required(CONF_OUTPUT): cv.use_variable_id(output.BinaryOutput), - vol.Optional(CONF_EFFECTS): light.validate_effects(light.BINARY_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema)) +}).extend(light.BINARY_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema)) def to_code(config): diff --git a/esphome/components/light/cwww.py b/esphome/components/light/cwww.py index 19447fdcab..70ae917182 100644 --- a/esphome/components/light/cwww.py +++ b/esphome/components/light/cwww.py @@ -11,17 +11,14 @@ from esphome.cpp_generator import get_variable, variable from esphome.cpp_helpers import setup_component from esphome.cpp_types import App -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight), vol.Required(CONF_COLD_WHITE): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_WARM_WHITE): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): validate_color_temperature, vol.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): validate_color_temperature, - - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, - vol.Optional(CONF_EFFECTS): light.validate_effects(light.MONOCHROMATIC_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema), validate_cold_white_colder) +}).extend(light.BRIGHTNESS_ONLY_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema), + validate_cold_white_colder) def to_code(config): diff --git a/esphome/components/light/fastled_clockless.py b/esphome/components/light/fastled_clockless.py index df872a6428..2187a0b6fb 100644 --- a/esphome/components/light/fastled_clockless.py +++ b/esphome/components/light/fastled_clockless.py @@ -56,7 +56,7 @@ def validate(value): MakeFastLEDLight = Application.struct('MakeFastLEDLight') -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(light.AddressableLightState), cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeFastLEDLight), @@ -67,12 +67,8 @@ PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, vol.Optional(CONF_RGB_ORDER): cv.one_of(*RGB_ORDERS, upper=True), - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_COLOR_CORRECT): vol.All([cv.percentage], vol.Length(min=3, max=3)), - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent), - vol.Optional(CONF_EFFECTS): light.validate_effects(light.ADDRESSABLE_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema), validate) +}).extend(light.RGB_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema), validate) def to_code(config): @@ -95,10 +91,6 @@ def to_code(config): yield add(fast_led.set_power_supply(power_supply)) - if CONF_COLOR_CORRECT in config: - r, g, b = config[CONF_COLOR_CORRECT] - add(fast_led.set_correction(r, g, b)) - light.setup_light(make.Pstate, config) setup_component(fast_led, config) diff --git a/esphome/components/light/fastled_spi.py b/esphome/components/light/fastled_spi.py index 5abfce21cd..ae830d2e4d 100644 --- a/esphome/components/light/fastled_spi.py +++ b/esphome/components/light/fastled_spi.py @@ -33,7 +33,7 @@ RGB_ORDERS = [ MakeFastLEDLight = Application.struct('MakeFastLEDLight') -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(light.AddressableLightState), cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeFastLEDLight), @@ -45,12 +45,9 @@ PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ vol.Optional(CONF_RGB_ORDER): cv.one_of(*RGB_ORDERS, upper=True), vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_COLOR_CORRECT): vol.All([cv.percentage], vol.Length(min=3, max=3)), - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent), vol.Optional(CONF_EFFECTS): light.validate_effects(light.ADDRESSABLE_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema)) +}).extend(light.ADDRESSABLE_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema)) def to_code(config): @@ -75,10 +72,6 @@ def to_code(config): yield add(fast_led.set_power_supply(power_supply)) - if CONF_COLOR_CORRECT in config: - r, g, b = config[CONF_COLOR_CORRECT] - add(fast_led.set_correction(r, g, b)) - light.setup_light(make.Pstate, config) setup_component(fast_led, config) diff --git a/esphome/components/light/monochromatic.py b/esphome/components/light/monochromatic.py index ca819dd2c8..338be37e22 100644 --- a/esphome/components/light/monochromatic.py +++ b/esphome/components/light/monochromatic.py @@ -2,19 +2,15 @@ import voluptuous as vol from esphome.components import light, output import esphome.config_validation as cv -from esphome.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, \ - CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT +from esphome.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT from esphome.cpp_generator import get_variable, variable from esphome.cpp_helpers import setup_component from esphome.cpp_types import App -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight), vol.Required(CONF_OUTPUT): cv.use_variable_id(output.FloatOutput), - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, - vol.Optional(CONF_EFFECTS): light.validate_effects(light.MONOCHROMATIC_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema)) +}).extend(light.BRIGHTNESS_ONLY_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema)) def to_code(config): diff --git a/esphome/components/light/neopixelbus.py b/esphome/components/light/neopixelbus.py index be8bc9052a..9ace51c118 100644 --- a/esphome/components/light/neopixelbus.py +++ b/esphome/components/light/neopixelbus.py @@ -130,7 +130,7 @@ def validate(config): MakeNeoPixelBusLight = Application.struct('MakeNeoPixelBusLight') -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(light.AddressableLightState), cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeNeoPixelBusLight), @@ -143,12 +143,9 @@ PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int, - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_COLOR_CORRECT): vol.All([cv.percentage], vol.Length(min=3, max=4)), - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent), - vol.Optional(CONF_EFFECTS): light.validate_effects(light.ADDRESSABLE_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema), validate, validate_method_pin) +}).extend(light.ADDRESSABLE_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema), + validate, validate_method_pin) def to_code(config): @@ -178,9 +175,6 @@ def to_code(config): yield add(output.set_power_supply(power_supply)) - if CONF_COLOR_CORRECT in config: - add(output.set_correction(*config[CONF_COLOR_CORRECT])) - light.setup_light(make.Pstate, config) setup_component(output, config) diff --git a/esphome/components/light/partition.py b/esphome/components/light/partition.py index 61587492d8..30f8d054a0 100644 --- a/esphome/components/light/partition.py +++ b/esphome/components/light/partition.py @@ -20,7 +20,7 @@ def validate_from_to(value): return value -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(light.AddressableLightState), cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakePartitionLight), @@ -29,11 +29,7 @@ PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ vol.Required(CONF_FROM): cv.positive_int, vol.Required(CONF_TO): cv.positive_int, }, validate_from_to), vol.Length(min=1)), - - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, - vol.Optional(CONF_EFFECTS): light.validate_effects(light.ADDRESSABLE_EFFECTS), -})) +}).extend(light.ADDRESSABLE_LIGHT_SCHEMA)) def to_code(config): diff --git a/esphome/components/light/rgb.py b/esphome/components/light/rgb.py index 77791fdefd..355469a4bd 100644 --- a/esphome/components/light/rgb.py +++ b/esphome/components/light/rgb.py @@ -8,15 +8,12 @@ from esphome.cpp_generator import get_variable, variable from esphome.cpp_helpers import setup_component from esphome.cpp_types import App -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight), vol.Required(CONF_RED): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_GREEN): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_BLUE): cv.use_variable_id(output.FloatOutput), - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, - vol.Optional(CONF_EFFECTS): light.validate_effects(light.RGB_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema)) +}).extend(light.RGB_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema)) def to_code(config): diff --git a/esphome/components/light/rgbw.py b/esphome/components/light/rgbw.py index d421322eb1..4c035f738a 100644 --- a/esphome/components/light/rgbw.py +++ b/esphome/components/light/rgbw.py @@ -2,22 +2,18 @@ import voluptuous as vol from esphome.components import light, output import esphome.config_validation as cv -from esphome.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, \ - CONF_GAMMA_CORRECT, CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE +from esphome.const import CONF_BLUE, CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE from esphome.cpp_generator import get_variable, variable from esphome.cpp_helpers import setup_component from esphome.cpp_types import App -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight), vol.Required(CONF_RED): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_GREEN): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_BLUE): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_WHITE): cv.use_variable_id(output.FloatOutput), - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, - vol.Optional(CONF_EFFECTS): light.validate_effects(light.RGB_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema)) +}).extend(light.RGB_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema)) def to_code(config): diff --git a/esphome/components/light/rgbww.py b/esphome/components/light/rgbww.py index 5af68cb74d..71c786b396 100644 --- a/esphome/components/light/rgbww.py +++ b/esphome/components/light/rgbww.py @@ -30,7 +30,7 @@ def validate_cold_white_colder(value): return value -PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = cv.nameable(light.PLATFORM_SCHEMA.extend({ cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight), vol.Required(CONF_RED): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_GREEN): cv.use_variable_id(output.FloatOutput), @@ -39,11 +39,7 @@ PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({ vol.Required(CONF_WARM_WHITE): cv.use_variable_id(output.FloatOutput), vol.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): validate_color_temperature, vol.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): validate_color_temperature, - - vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, - vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, - vol.Optional(CONF_EFFECTS): light.validate_effects(light.RGB_EFFECTS), -}).extend(cv.COMPONENT_SCHEMA.schema), validate_cold_white_colder) +}).extend(light.RGB_LIGHT_SCHEMA).extend(cv.COMPONENT_SCHEMA.schema), validate_cold_white_colder) def to_code(config): diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 3d7371c03d..75fe0dda6b 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -242,9 +242,10 @@ def setup_sensor(sensor_obj, config): def register_sensor(var, config): - sensor_var = Pvariable(config[CONF_ID], var, has_side_effects=True) - add(App.register_sensor(sensor_var)) - CORE.add_job(setup_sensor_core_, sensor_var, config) + if not CORE.has_id(config[CONF_ID]): + var = Pvariable(config[CONF_ID], var, has_side_effects=True) + add(App.register_sensor(var)) + CORE.add_job(setup_sensor_core_, var, config) BUILD_FLAGS = '-DUSE_SENSOR' diff --git a/esphome/const.py b/esphome/const.py index c86469acc3..8b4c44a55a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -266,6 +266,9 @@ CONF_INTERNAL = 'internal' CONF_BUILD_PATH = 'build_path' CONF_PLATFORMIO_OPTIONS = 'platformio_options' CONF_REBOOT_TIMEOUT = 'reboot_timeout' +CONF_STOP = 'stop' +CONF_POSITION = 'position' +CONF_TILT = 'tilt' CONF_INVERT = 'invert' CONF_DELAYED_ON = 'delayed_on' CONF_DELAYED_OFF = 'delayed_off' @@ -299,6 +302,11 @@ CONF_COLOR_TEMPERATURE = 'color_temperature' CONF_BATTERY_LEVEL = 'battery_level' CONF_MOISTURE = 'moisture' CONF_CONDUCTIVITY = 'conductivity' +CONF_OPEN_ENDSTOP = 'open_endstop' +CONF_OPEN_DURATION = 'open_duration' +CONF_CLOSE_ENDSTOP = 'close_endstop' +CONF_CLOSE_DURATION = 'close_duration' +CONF_MAX_DURATION = 'max_duration' CONF_RC_SWITCH_RAW = 'rc_switch_raw' CONF_RC_SWITCH_TYPE_A = 'rc_switch_type_a' CONF_RC_SWITCH_TYPE_B = 'rc_switch_type_b' diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index f2f2f058ff..11a1cf0811 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -1,14 +1,13 @@ from collections import OrderedDict import math -from esphome.core import CORE, HexInt, Lambda, TimePeriod, TimePeriodMicroseconds, \ - TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes -from esphome.helpers import cpp_string_escape, indent_all_but_first_and_last - # pylint: disable=unused-import, wrong-import-order -from typing import Any, Generator, List, Optional, Tuple, Union # noqa -from esphome.core import ID # noqa -from esphome.py_compat import text_type, string_types, integer_types +from typing import Any, Generator, List, Optional, Tuple, Type, Union, Dict, Callable # noqa + +from esphome.core import CORE, HexInt, ID, Lambda, TimePeriod, TimePeriodMicroseconds, \ + TimePeriodMilliseconds, TimePeriodMinutes, TimePeriodSeconds # noqa +from esphome.helpers import cpp_string_escape, indent_all_but_first_and_last +from esphome.py_compat import integer_types, string_types, text_type class Expression(object): @@ -30,7 +29,8 @@ class Expression(object): return self.required -SafeExpType = Union[Expression, bool, str, text_type, int, float, TimePeriod] +SafeExpType = Union[Expression, bool, str, text_type, int, float, TimePeriod, + Type[bool], Type[int], Type[float]] class RawExpression(Expression): @@ -190,7 +190,7 @@ class LambdaExpression(Expression): self.parameters = parameters self.requires.append(self.parameters) self.capture = capture - self.return_type = return_type + self.return_type = safe_exp(return_type) if return_type is not None: self.requires.append(return_type) for i in range(1, len(parts), 3): @@ -271,6 +271,8 @@ def safe_exp( obj # type: Union[Expression, bool, str, unicode, int, long, float, TimePeriod, list] ): # type: (...) -> Expression + from esphome.cpp_types import bool_, float_, int32 + if isinstance(obj, Expression): return obj if isinstance(obj, bool): @@ -293,6 +295,12 @@ def safe_exp( return IntLiteral(int(obj.total_minutes)) if isinstance(obj, (tuple, list)): return ArrayInitializer(*[safe_exp(o) for o in obj]) + if obj is bool: + return bool_ + if obj is int: + return int32 + if obj is float: + return float_ raise ValueError(u"Object is not an expression", obj) @@ -425,15 +433,21 @@ def process_lambda(value, # type: Lambda def templatable(value, # type: Any - args, # type: List[Tuple[Expression, str]] - output_type # type: Optional[Expression] + args, # type: List[Tuple[SafeExpType, str]] + output_type, # type: Optional[SafeExpType], + to_exp=None # type: Optional[Any] ): if isinstance(value, Lambda): for lambda_ in process_lambda(value, args, return_type=output_type): yield None yield lambda_ else: - yield value + if to_exp is None: + yield value + elif isinstance(to_exp, dict): + yield to_exp[value] + else: + yield to_exp(value) class MockObj(Expression):