diff --git a/esphomeyaml/__main__.py b/esphomeyaml/__main__.py index 55fe6f3aa1..c79da1971b 100644 --- a/esphomeyaml/__main__.py +++ b/esphomeyaml/__main__.py @@ -10,6 +10,7 @@ from esphomeyaml import core, mqtt, wizard, writer, yaml_util, const from esphomeyaml.config import core_to_code, get_component, iter_components, read_config from esphomeyaml.const import CONF_BAUD_RATE, CONF_ESPHOMEYAML, CONF_HOSTNAME, CONF_LOGGER, \ CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI +from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.helpers import AssignmentExpression, RawStatement, _EXPRESSIONS, add, add_task, \ color, get_variable, indent, quote, statement, Expression @@ -132,6 +133,8 @@ def write_cpp(config): if isinstance(exp, Expression) and not exp.required: continue if isinstance(exp, AssignmentExpression) and not exp.obj.required: + if not exp.has_side_effects(): + continue exp = exp.rhs all_code.append(unicode(statement(exp))) @@ -284,7 +287,11 @@ def main(): print(yaml_util.dump(config)) return 0 elif args.command == 'compile': - exit_code = write_cpp(config) + try: + exit_code = write_cpp(config) + except ESPHomeYAMLError as e: + _LOGGER.error(e) + return 1 if exit_code != 0: return exit_code exit_code = compile_program(config) diff --git a/esphomeyaml/automation.py b/esphomeyaml/automation.py new file mode 100644 index 0000000000..8ef802e520 --- /dev/null +++ b/esphomeyaml/automation.py @@ -0,0 +1,223 @@ +import voluptuous as vol + +import esphomeyaml.config_validation as cv +from esphomeyaml.const import CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, CONF_BLUE, \ + CONF_BRIGHTNESS, CONF_CONDITION_ID, CONF_DELAY, CONF_EFFECT, CONF_FLASH_LENGTH, CONF_GREEN, \ + CONF_ID, CONF_IF, CONF_LAMBDA, CONF_MAX, CONF_MIN, CONF_OR, CONF_PAYLOAD, CONF_QOS, \ + CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_THEN, CONF_TOPIC, CONF_TRANSITION_LENGTH, \ + CONF_TRIGGER_ID, CONF_WHITE +from esphomeyaml.core import ESPHomeYAMLError +from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, \ + bool_, esphomelib_ns, float_, get_variable, process_lambda, std_string, templatable, uint32, \ + uint8 + +CONF_MQTT_PUBLISH = 'mqtt.publish' +CONF_LIGHT_TOGGLE = 'light.toggle' +CONF_LIGHT_TURN_OFF = 'light.turn_off' +CONF_LIGHT_TURN_ON = 'light.turn_on' +CONF_SWITCH_TOGGLE = 'switch.toggle' +CONF_SWITCH_TURN_OFF = 'switch.turn_off' +CONF_SWITCH_TURN_ON = 'switch.turn_on' + +ACTION_KEYS = [CONF_DELAY, CONF_MQTT_PUBLISH, CONF_LIGHT_TOGGLE, CONF_LIGHT_TURN_OFF, + CONF_LIGHT_TURN_ON, CONF_SWITCH_TOGGLE, CONF_SWITCH_TURN_OFF, CONF_SWITCH_TURN_ON, + CONF_LAMBDA] + +ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({ + cv.GenerateID('action', CONF_ACTION_ID): cv.register_variable_id, + vol.Optional(CONF_DELAY): cv.positive_time_period_milliseconds, + vol.Optional(CONF_MQTT_PUBLISH): vol.Schema({ + vol.Required(CONF_TOPIC): cv.templatable(cv.publish_topic), + vol.Required(CONF_PAYLOAD): cv.templatable(cv.mqtt_payload), + vol.Optional(CONF_QOS): cv.templatable(cv.mqtt_qos), + vol.Optional(CONF_RETAIN): cv.templatable(cv.boolean), + }), + vol.Optional(CONF_LIGHT_TOGGLE): vol.Schema({ + vol.Required(CONF_ID): cv.variable_id, + vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), + }), + vol.Optional(CONF_LIGHT_TURN_OFF): vol.Schema({ + vol.Required(CONF_ID): cv.variable_id, + vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), + }), + vol.Optional(CONF_LIGHT_TURN_ON): vol.Schema({ + vol.Required(CONF_ID): cv.variable_id, + vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), + vol.Optional(CONF_FLASH_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), + vol.Optional(CONF_BRIGHTNESS): cv.templatable(cv.zero_to_one_float), + vol.Optional(CONF_RED): cv.templatable(cv.zero_to_one_float), + vol.Optional(CONF_GREEN): cv.templatable(cv.zero_to_one_float), + vol.Optional(CONF_BLUE): cv.templatable(cv.zero_to_one_float), + vol.Optional(CONF_WHITE): cv.templatable(cv.zero_to_one_float), + vol.Optional(CONF_EFFECT): cv.templatable(cv.string), + }), + vol.Optional(CONF_SWITCH_TOGGLE): vol.Schema({ + vol.Required(CONF_ID): cv.variable_id, + }), + vol.Optional(CONF_SWITCH_TURN_OFF): vol.Schema({ + vol.Required(CONF_ID): cv.variable_id, + }), + vol.Optional(CONF_SWITCH_TURN_ON): vol.Schema({ + vol.Required(CONF_ID): cv.variable_id, + }), + vol.Optional(CONF_LAMBDA): cv.lambda_, +}, cv.has_at_exactly_one_key(*ACTION_KEYS))]) + +# pylint: disable=invalid-name +DelayAction = esphomelib_ns.DelayAction +LambdaAction = esphomelib_ns.LambdaAction +Automation = esphomelib_ns.Automation + + +def validate_recursive_condition(value): + return CONDITIONS_SCHEMA(value) + + +CONDITION_KEYS = [CONF_AND, CONF_OR, CONF_RANGE, CONF_LAMBDA] + +CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({ + cv.GenerateID('condition', CONF_CONDITION_ID): cv.register_variable_id, + vol.Optional(CONF_AND): validate_recursive_condition, + vol.Optional(CONF_OR): validate_recursive_condition, + vol.Optional(CONF_RANGE): vol.All(vol.Schema({ + vol.Optional(CONF_MIN): vol.Coerce(float), + vol.Optional(CONF_MAX): vol.Coerce(float), + }), cv.has_at_least_one_key(CONF_MIN, CONF_MAX)), + vol.Optional(CONF_LAMBDA): cv.lambda_, +}), cv.has_at_exactly_one_key(*CONDITION_KEYS)]) + +# pylint: disable=invalid-name +AndCondition = esphomelib_ns.AndCondition +OrCondition = esphomelib_ns.OrCondition +RangeCondition = esphomelib_ns.RangeCondition +LambdaCondition = esphomelib_ns.LambdaCondition + +AUTOMATION_SCHEMA = vol.Schema({ + cv.GenerateID('trigger', CONF_TRIGGER_ID): cv.register_variable_id, + cv.GenerateID('automation', CONF_AUTOMATION_ID): cv.register_variable_id, + vol.Optional(CONF_IF): CONDITIONS_SCHEMA, + vol.Required(CONF_THEN): ACTIONS_SCHEMA, +}) + + +def build_condition(config, arg_type): + template_arg = TemplateArguments(arg_type) + if CONF_AND in config: + return AndCondition.new(template_arg, build_conditions(config[CONF_AND], template_arg)) + if CONF_OR in config: + return OrCondition.new(template_arg, build_conditions(config[CONF_OR], template_arg)) + if CONF_LAMBDA in config: + return LambdaCondition.new(template_arg, + process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')])) + if CONF_RANGE in config: + conf = config[CONF_RANGE] + rhs = RangeCondition.new(template_arg) + condition = Pvariable(RangeCondition.template(template_arg), config[CONF_CONDITION_ID], rhs) + if CONF_MIN in conf: + condition.set_min(templatable(conf[CONF_MIN], arg_type, float_)) + if CONF_MAX in conf: + condition.set_max(templatable(conf[CONF_MAX], arg_type, float_)) + return condition + raise ESPHomeYAMLError(u"Unsupported condition {}".format(config)) + + +def build_conditions(config, arg_type): + return ArrayInitializer(*[build_condition(x, arg_type) for x in config]) + + +def build_action(config, arg_type): + from esphomeyaml.components import light, mqtt, switch + + template_arg = TemplateArguments(arg_type) + if CONF_DELAY in config: + rhs = App.register_component(DelayAction.new(template_arg)) + action = Pvariable(DelayAction.template(template_arg), config[CONF_ACTION_ID], rhs) + add(action.set_delay(templatable(config[CONF_DELAY], arg_type, uint32))) + return action + elif CONF_LAMBDA in config: + rhs = LambdaAction.new(template_arg, process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')])) + return Pvariable(LambdaAction.template(template_arg), config[CONF_ACTION_ID], rhs) + elif CONF_MQTT_PUBLISH in config: + conf = config[CONF_MQTT_PUBLISH] + rhs = App.Pget_mqtt_client().Pmake_publish_action() + action = Pvariable(mqtt.MQTTPublishAction.template(template_arg), config[CONF_ACTION_ID], + rhs) + add(action.set_topic(templatable(conf[CONF_TOPIC], arg_type, std_string))) + add(action.set_payload(templatable(conf[CONF_PAYLOAD], arg_type, std_string))) + if CONF_QOS in conf: + add(action.set_qos(templatable(conf[CONF_QOS], arg_type, uint8))) + if CONF_RETAIN in conf: + add(action.set_retain(templatable(conf[CONF_RETAIN], arg_type, bool_))) + return action + elif CONF_LIGHT_TOGGLE in config: + conf = config[CONF_LIGHT_TOGGLE] + var = get_variable(conf[CONF_ID]) + rhs = var.make_toggle_action(template_arg) + action = Pvariable(light.ToggleAction.template(template_arg), config[CONF_ACTION_ID], rhs) + if CONF_TRANSITION_LENGTH in conf: + add(action.set_transition_length( + templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32) + )) + return action + elif CONF_LIGHT_TURN_OFF in config: + conf = config[CONF_LIGHT_TURN_OFF] + var = get_variable(conf[CONF_ID]) + rhs = var.make_turn_off_action(template_arg) + action = Pvariable(light.TurnOffAction.template(template_arg), config[CONF_ACTION_ID], rhs) + if CONF_TRANSITION_LENGTH in conf: + add(action.set_transition_length( + templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32) + )) + return action + elif CONF_LIGHT_TURN_ON in config: + conf = config[CONF_LIGHT_TURN_ON] + var = get_variable(conf[CONF_ID]) + rhs = var.make_turn_on_action(template_arg) + action = Pvariable(light.TurnOnAction.template(template_arg), config[CONF_ACTION_ID], rhs) + if CONF_TRANSITION_LENGTH in conf: + add(action.set_transition_length( + templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32) + )) + if CONF_FLASH_LENGTH in conf: + add(action.set_flash_length(templatable(conf[CONF_FLASH_LENGTH], arg_type, uint32))) + if CONF_BRIGHTNESS in conf: + add(action.set_brightness(templatable(conf[CONF_BRIGHTNESS], arg_type, float_))) + if CONF_RED in conf: + add(action.set_red(templatable(conf[CONF_RED], arg_type, float_))) + if CONF_GREEN in conf: + add(action.set_green(templatable(conf[CONF_GREEN], arg_type, float_))) + if CONF_BLUE in conf: + add(action.set_blue(templatable(conf[CONF_BLUE], arg_type, float_))) + if CONF_WHITE in conf: + add(action.set_white(templatable(conf[CONF_WHITE], arg_type, float_))) + if CONF_EFFECT in conf: + add(action.set_effect(templatable(conf[CONF_EFFECT], arg_type, std_string))) + return action + elif CONF_SWITCH_TOGGLE in config: + conf = config[CONF_SWITCH_TOGGLE] + var = get_variable(conf[CONF_ID]) + rhs = var.make_toggle_action(template_arg) + return Pvariable(switch.ToggleAction.template(arg_type), config[CONF_ACTION_ID], rhs) + elif CONF_SWITCH_TURN_OFF in config: + conf = config[CONF_SWITCH_TURN_OFF] + var = get_variable(conf[CONF_ID]) + rhs = var.make_turn_off_action(template_arg) + return Pvariable(switch.TurnOffAction.template(arg_type), config[CONF_ACTION_ID], rhs) + elif CONF_SWITCH_TURN_ON in config: + conf = config[CONF_SWITCH_TURN_ON] + var = get_variable(conf[CONF_ID]) + rhs = var.make_turn_on_action(template_arg) + return Pvariable(switch.TurnOnAction.template(arg_type), config[CONF_ACTION_ID], rhs) + raise ESPHomeYAMLError(u"Unsupported action {}".format(config)) + + +def build_actions(config, arg_type): + return ArrayInitializer(*[build_action(x, arg_type) for x in config]) + + +def build_automation(trigger, arg_type, config): + rhs = App.make_automation(trigger) + obj = Pvariable(Automation.template(arg_type), config[CONF_AUTOMATION_ID], rhs) + if CONF_IF in config: + add(obj.add_conditions(build_conditions(config[CONF_IF], arg_type))) + add(obj.add_actions(build_actions(config[CONF_THEN], arg_type))) diff --git a/esphomeyaml/components/ads1115.py b/esphomeyaml/components/ads1115.py index 4d5b1740c5..878ffe2373 100644 --- a/esphomeyaml/components/ads1115.py +++ b/esphomeyaml/components/ads1115.py @@ -1,12 +1,13 @@ import voluptuous as vol import esphomeyaml.config_validation as cv +from esphomeyaml.components import sensor from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_RATE from esphomeyaml.helpers import App, Pvariable DEPENDENCIES = ['i2c'] -ADS1115_COMPONENT_CLASS = 'sensor::ADS1115Component' +ADS1115Component = sensor.sensor_ns.ADS1115Component RATE_REMOVE_MESSAGE = """The rate option has been removed in 1.5.0 and is no longer required.""" @@ -23,7 +24,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [ADS1115_SCHEMA]) def to_code(config): for conf in config: rhs = App.make_ads1115_component(conf[CONF_ADDRESS]) - Pvariable(ADS1115_COMPONENT_CLASS, conf[CONF_ID], rhs) + Pvariable(ADS1115Component, conf[CONF_ID], rhs) BUILD_FLAGS = '-DUSE_ADS1115_SENSOR' diff --git a/esphomeyaml/components/binary_sensor/__init__.py b/esphomeyaml/components/binary_sensor/__init__.py index bcb396077d..138e273c80 100644 --- a/esphomeyaml/components/binary_sensor/__init__.py +++ b/esphomeyaml/components/binary_sensor/__init__.py @@ -1,8 +1,11 @@ import voluptuous as vol import esphomeyaml.config_validation as cv -from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_INVERTED, CONF_MQTT_ID -from esphomeyaml.helpers import add, setup_mqtt_component, App, Pvariable +from esphomeyaml import automation +from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INVERTED, CONF_MAX_LENGTH, \ + CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, CONF_ON_PRESS, \ + CONF_ON_RELEASE, CONF_TRIGGER_ID +from esphomeyaml.helpers import App, NoArg, Pvariable, add, esphomelib_ns, setup_mqtt_component DEVICE_CLASSES = [ '', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas', @@ -11,39 +14,82 @@ DEVICE_CLASSES = [ 'sound', 'vibration', 'window' ] -DEVICE_CLASSES_MSG = "Unknown device class. Must be one of {}".format(', '.join(DEVICE_CLASSES)) - PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_INVERTED): cv.boolean, - vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower, - vol.Any(*DEVICE_CLASSES, msg=DEVICE_CLASSES_MSG)), -}) - -MQTT_BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({ }) -MQTT_BINARY_SENSOR_ID_SCHEMA = MQTT_BINARY_SENSOR_SCHEMA.extend({ +binary_sensor_ns = esphomelib_ns.namespace('binary_sensor') +PressTrigger = binary_sensor_ns.PressTrigger +ReleaseTrigger = binary_sensor_ns.ReleaseTrigger +ClickTrigger = binary_sensor_ns.ClickTrigger +DoubleClickTrigger = binary_sensor_ns.DoubleClickTrigger +BinarySensor = binary_sensor_ns.BinarySensor +MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent + +BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({ cv.GenerateID('mqtt_binary_sensor', CONF_MQTT_ID): cv.register_variable_id, + cv.GenerateID('binary_sensor'): cv.register_variable_id, + vol.Optional(CONF_INVERTED): cv.boolean, + vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower, cv.one_of(DEVICE_CLASSES)), + vol.Optional(CONF_ON_PRESS): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), + vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), + vol.Optional(CONF_ON_CLICK): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ + vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds, + vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds, + })]), + vol.Optional(CONF_ON_DOUBLE_CLICK): + vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ + vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds, + vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds, + })]), }) -def setup_binary_sensor(obj, config): +def setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config): if CONF_DEVICE_CLASS in config: - add(obj.set_device_class(config[CONF_DEVICE_CLASS])) + add(binary_sensor_var.set_device_class(config[CONF_DEVICE_CLASS])) if CONF_INVERTED in config: - add(obj.set_inverted(config[CONF_INVERTED])) + add(binary_sensor_var.set_inverted(config[CONF_INVERTED])) + + for conf in config.get(CONF_ON_PRESS, []): + rhs = binary_sensor_var.make_press_trigger() + trigger = Pvariable(PressTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, NoArg, conf) + + for conf in config.get(CONF_ON_RELEASE, []): + rhs = binary_sensor_var.make_release_trigger() + trigger = Pvariable(ReleaseTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, NoArg, conf) + + for conf in config.get(CONF_ON_CLICK, []): + rhs = binary_sensor_var.make_release_trigger(conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH]) + trigger = Pvariable(ClickTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, NoArg, conf) + + for conf in config.get(CONF_ON_DOUBLE_CLICK, []): + rhs = binary_sensor_var.make_double_click_trigger(conf[CONF_MIN_LENGTH], + conf[CONF_MAX_LENGTH]) + trigger = Pvariable(DoubleClickTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, NoArg, conf) + + setup_mqtt_component(mqtt_var, config) -def setup_mqtt_binary_sensor(obj, config): - setup_mqtt_component(obj, config) +def setup_binary_sensor(binary_sensor_obj, mqtt_obj, config): + binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], binary_sensor_obj, + has_side_effects=False) + mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], mqtt_obj, + has_side_effects=False) + setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config) def register_binary_sensor(var, config): - setup_binary_sensor(var, config) - rhs = App.register_binary_sensor(var) - mqtt_sensor = Pvariable('binary_sensor::MQTTBinarySensorComponent', config[CONF_MQTT_ID], rhs) - setup_mqtt_binary_sensor(mqtt_sensor, config) + binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], var, + has_side_effects=True) + rhs = App.register_binary_sensor(binary_sensor_var) + mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], rhs, + has_side_effects=True) + setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config) BUILD_FLAGS = '-DUSE_BINARY_SENSOR' diff --git a/esphomeyaml/components/binary_sensor/esp32_ble.py b/esphomeyaml/components/binary_sensor/esp32_ble.py index f0019d3354..0f58c05fad 100644 --- a/esphomeyaml/components/binary_sensor/esp32_ble.py +++ b/esphomeyaml/components/binary_sensor/esp32_ble.py @@ -2,9 +2,10 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import binary_sensor -from esphomeyaml.const import CONF_ID, CONF_MAC_ADDRESS, CONF_NAME, ESP_PLATFORM_ESP32 +from esphomeyaml.components.esp32_ble import ESP32BLETracker +from esphomeyaml.const import CONF_MAC_ADDRESS, CONF_NAME, ESP_PLATFORM_ESP32 from esphomeyaml.core import HexInt, MACAddress -from esphomeyaml.helpers import ArrayInitializer, Pvariable, get_variable +from esphomeyaml.helpers import ArrayInitializer, get_variable ESP_PLATFORMS = [ESP_PLATFORM_ESP32] DEPENDENCIES = ['esp32_ble'] @@ -28,17 +29,15 @@ def validate_mac(value): PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('esp32_ble_device'): cv.register_variable_id, vol.Required(CONF_MAC_ADDRESS): validate_mac, -}).extend(binary_sensor.MQTT_BINARY_SENSOR_ID_SCHEMA.schema) +}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) def to_code(config): - hub = get_variable(None, type='ESP32BLETracker') + hub = get_variable(None, type=ESP32BLETracker) addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts] rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False)) - device = Pvariable('ESP32BLEDevice', config[CONF_ID], rhs) - binary_sensor.register_binary_sensor(device, config) + binary_sensor.register_binary_sensor(rhs, config) BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER' diff --git a/esphomeyaml/components/binary_sensor/esp32_touch.py b/esphomeyaml/components/binary_sensor/esp32_touch.py index f69dd271a6..321aef22ac 100644 --- a/esphomeyaml/components/binary_sensor/esp32_touch.py +++ b/esphomeyaml/components/binary_sensor/esp32_touch.py @@ -2,8 +2,9 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import binary_sensor -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_PIN, CONF_THRESHOLD, ESP_PLATFORM_ESP32 -from esphomeyaml.helpers import Pvariable, RawExpression, get_variable +from esphomeyaml.components.esp32_touch import ESP32TouchComponent +from esphomeyaml.const import CONF_NAME, CONF_PIN, CONF_THRESHOLD, ESP_PLATFORM_ESP32 +from esphomeyaml.helpers import get_variable, global_ns from esphomeyaml.pins import validate_gpio_pin ESP_PLATFORMS = [ESP_PLATFORM_ESP32] @@ -11,16 +12,16 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP32] DEPENDENCIES = ['esp32_touch'] TOUCH_PADS = { - 4: 'TOUCH_PAD_NUM0', - 0: 'TOUCH_PAD_NUM1', - 2: 'TOUCH_PAD_NUM2', - 15: 'TOUCH_PAD_NUM3', - 13: 'TOUCH_PAD_NUM4', - 12: 'TOUCH_PAD_NUM5', - 14: 'TOUCH_PAD_NUM6', - 27: 'TOUCH_PAD_NUM7', - 33: 'TOUCH_PAD_NUM8', - 32: 'TOUCH_PAD_NUM9', + 4: global_ns.TOUCH_PAD_NUM0, + 0: global_ns.TOUCH_PAD_NUM1, + 2: global_ns.TOUCH_PAD_NUM2, + 15: global_ns.TOUCH_PAD_NUM3, + 13: global_ns.TOUCH_PAD_NUM4, + 12: global_ns.TOUCH_PAD_NUM5, + 14: global_ns.TOUCH_PAD_NUM6, + 27: global_ns.TOUCH_PAD_NUM7, + 33: global_ns.TOUCH_PAD_NUM8, + 32: global_ns.TOUCH_PAD_NUM9, } @@ -32,18 +33,16 @@ def validate_touch_pad(value): PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('esp32_touch_pad'): cv.register_variable_id, vol.Required(CONF_PIN): validate_touch_pad, vol.Required(CONF_THRESHOLD): cv.uint16_t, -}).extend(binary_sensor.MQTT_BINARY_SENSOR_ID_SCHEMA.schema) +}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) def to_code(config): - hub = get_variable(None, type='binary_sensor::ESP32TouchComponent') - touch_pad = RawExpression(TOUCH_PADS[config[CONF_PIN]]) + hub = get_variable(None, type=ESP32TouchComponent) + touch_pad = TOUCH_PADS[config[CONF_PIN]] rhs = hub.make_touch_pad(config[CONF_NAME], touch_pad, config[CONF_THRESHOLD]) - device = Pvariable('ESP32TouchBinarySensor', config[CONF_ID], rhs) - binary_sensor.register_binary_sensor(device, config) + binary_sensor.register_binary_sensor(rhs, config) BUILD_FLAGS = '-DUSE_ESP32_TOUCH_BINARY_SENSOR' diff --git a/esphomeyaml/components/binary_sensor/gpio.py b/esphomeyaml/components/binary_sensor/gpio.py index 04e5b9a6f3..3da3bde169 100644 --- a/esphomeyaml/components/binary_sensor/gpio.py +++ b/esphomeyaml/components/binary_sensor/gpio.py @@ -3,23 +3,22 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import binary_sensor -from esphomeyaml.const import CONF_ID, CONF_INVERTED, CONF_NAME, CONF_PIN -from esphomeyaml.helpers import App, add, variable, gpio_input_pin_expression +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN +from esphomeyaml.helpers import App, gpio_input_pin_expression, variable, Application PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('gpio_binary_sensor'): cv.register_variable_id, + cv.GenerateID('gpio_binary_sensor', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_PIN): pins.GPIO_INPUT_PIN_SCHEMA -}).extend(binary_sensor.MQTT_BINARY_SENSOR_SCHEMA.schema) +}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) + +MakeGPIOBinarySensor = Application.MakeGPIOBinarySensor def to_code(config): rhs = App.make_gpio_binary_sensor(config[CONF_NAME], gpio_input_pin_expression(config[CONF_PIN])) - gpio = variable('Application::MakeGPIOBinarySensor', config[CONF_ID], rhs) - if CONF_INVERTED in config: - add(gpio.Pgpio.set_inverted(config[CONF_INVERTED])) - binary_sensor.setup_binary_sensor(gpio.Pgpio, config) - binary_sensor.setup_mqtt_binary_sensor(gpio.Pmqtt, config) + gpio = variable(MakeGPIOBinarySensor, config[CONF_MAKE_ID], rhs) + binary_sensor.setup_binary_sensor(gpio.Pgpio, gpio.Pmqtt, config) BUILD_FLAGS = '-DUSE_GPIO_BINARY_SENSOR' diff --git a/esphomeyaml/components/binary_sensor/status.py b/esphomeyaml/components/binary_sensor/status.py index 5a48e1e674..e3c94ec4e6 100644 --- a/esphomeyaml/components/binary_sensor/status.py +++ b/esphomeyaml/components/binary_sensor/status.py @@ -1,20 +1,21 @@ import esphomeyaml.config_validation as cv from esphomeyaml.components import binary_sensor -from esphomeyaml.const import CONF_ID, CONF_NAME -from esphomeyaml.helpers import App, variable +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME +from esphomeyaml.helpers import App, Application, variable DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('status_binary_sensor'): cv.register_variable_id, -}).extend(binary_sensor.MQTT_BINARY_SENSOR_SCHEMA.schema) + cv.GenerateID('status_binary_sensor', CONF_MAKE_ID): cv.register_variable_id, +}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) + +MakeStatusBinarySensor = Application.MakeStatusBinarySensor def to_code(config): rhs = App.make_status_binary_sensor(config[CONF_NAME]) - status = variable('Application::MakeStatusBinarySensor', config[CONF_ID], rhs) - binary_sensor.setup_binary_sensor(status.Pstatus, config) - binary_sensor.setup_mqtt_binary_sensor(status.Pmqtt, config) + status = variable(MakeStatusBinarySensor, config[CONF_MAKE_ID], rhs) + binary_sensor.setup_binary_sensor(status.Pstatus, status.Pmqtt, config) BUILD_FLAGS = '-DUSE_STATUS_BINARY_SENSOR' diff --git a/esphomeyaml/components/binary_sensor/template.py b/esphomeyaml/components/binary_sensor/template.py new file mode 100644 index 0000000000..70c556ac04 --- /dev/null +++ b/esphomeyaml/components/binary_sensor/template.py @@ -0,0 +1,23 @@ +import voluptuous as vol + +import esphomeyaml.config_validation as cv +from esphomeyaml.components import binary_sensor +from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME +from esphomeyaml.helpers import App, Application, process_lambda, variable + +PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ + cv.GenerateID('template_binary_sensor', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_LAMBDA): cv.lambda_, +}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) + +MakeTemplateBinarySensor = Application.MakeTemplateBinarySensor + + +def to_code(config): + template_ = process_lambda(config[CONF_LAMBDA], []) + rhs = App.make_template_binary_sensor(config[CONF_NAME], template_) + make = variable(MakeTemplateBinarySensor, config[CONF_MAKE_ID], rhs) + binary_sensor.setup_binary_sensor(make.Ptemplate_, make.Pmqtt, config) + + +BUILD_FLAGS = '-DUSE_TEMPLATE_BINARY_SENSOR' diff --git a/esphomeyaml/components/cover/__init__.py b/esphomeyaml/components/cover/__init__.py new file mode 100644 index 0000000000..2a80a88911 --- /dev/null +++ b/esphomeyaml/components/cover/__init__.py @@ -0,0 +1,33 @@ +import esphomeyaml.config_validation as cv +from esphomeyaml.const import CONF_ID, CONF_MQTT_ID +from esphomeyaml.helpers import Pvariable, esphomelib_ns, setup_mqtt_component + +PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ + +}) + +COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ + cv.GenerateID('cover'): cv.register_variable_id, + cv.GenerateID('mqtt_cover', CONF_MQTT_ID): cv.register_variable_id, +}) + +cover_ns = esphomelib_ns.namespace('cover') +Cover = cover_ns.Cover +MQTTCoverComponent = cover_ns.MQTTCoverComponent +CoverState = cover_ns.CoverState +COVER_OPEN = cover_ns.COVER_OPEN +COVER_CLOSED = cover_ns.COVER_CLOSED + + +def setup_cover_core_(cover_var, mqtt_var, config): + setup_mqtt_component(mqtt_var, config) + + +def setup_cover(cover_obj, mqtt_obj, config): + cover_var = Pvariable(Cover, config[CONF_ID], cover_obj, has_side_effects=False) + mqtt_var = Pvariable(MQTTCoverComponent, config[CONF_MQTT_ID], mqtt_obj, + has_side_effects=False) + setup_cover_core_(cover_var, mqtt_var, config) + + +BUILD_FLAGS = '-DUSE_COVER' diff --git a/esphomeyaml/components/cover/template.py b/esphomeyaml/components/cover/template.py new file mode 100644 index 0000000000..eb31153e69 --- /dev/null +++ b/esphomeyaml/components/cover/template.py @@ -0,0 +1,39 @@ +import voluptuous as vol + +import esphomeyaml.config_validation as cv +from esphomeyaml import automation +from esphomeyaml.components import cover +from esphomeyaml.const import CONF_CLOSE_ACTION, CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, \ + CONF_OPEN_ACTION, CONF_STOP_ACTION +from esphomeyaml.helpers import App, Application, NoArg, add, process_lambda, variable + +PLATFORM_SCHEMA = cover.PLATFORM_SCHEMA.extend({ + cv.GenerateID('template_cover', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_LAMBDA): cv.lambda_, + vol.Optional(CONF_OPEN_ACTION): automation.ACTIONS_SCHEMA, + vol.Optional(CONF_CLOSE_ACTION): automation.ACTIONS_SCHEMA, + vol.Optional(CONF_STOP_ACTION): automation.ACTIONS_SCHEMA, +}).extend(cover.COVER_SCHEMA.schema) + +MakeTemplateCover = Application.MakeTemplateCover + + +def to_code(config): + template_ = process_lambda(config[CONF_LAMBDA], []) + rhs = App.make_template_cover(config[CONF_NAME], template_) + make = variable(MakeTemplateCover, config[CONF_MAKE_ID], rhs) + + if CONF_OPEN_ACTION in config: + actions = automation.build_actions(config[CONF_OPEN_ACTION], NoArg) + add(make.Ptemplate_.add_open_actions(actions)) + if CONF_CLOSE_ACTION in config: + actions = automation.build_actions(config[CONF_CLOSE_ACTION], NoArg) + add(make.Ptemplate_.add_close_actions(actions)) + if CONF_STOP_ACTION in config: + actions = automation.build_actions(config[CONF_STOP_ACTION], NoArg) + add(make.Ptemplate_.add_stop_actions(actions)) + + cover.setup_cover(make.Ptemplate_, make.Pmqtt, config) + + +BUILD_FLAGS = '-DUSE_TEMPLATE_COVER' diff --git a/esphomeyaml/components/dallas.py b/esphomeyaml/components/dallas.py index c4732aa253..27e5b10e56 100644 --- a/esphomeyaml/components/dallas.py +++ b/esphomeyaml/components/dallas.py @@ -2,10 +2,11 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins +from esphomeyaml.components import sensor from esphomeyaml.const import CONF_ID, CONF_PIN, CONF_UPDATE_INTERVAL from esphomeyaml.helpers import App, Pvariable -DALLAS_COMPONENT_CLASS = 'sensor::DallasComponent' +DallasComponent = sensor.sensor_ns.DallasComponent CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ cv.GenerateID('dallas'): cv.register_variable_id, @@ -17,7 +18,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ def to_code(config): for conf in config: rhs = App.make_dallas_component(conf[CONF_PIN], conf.get(CONF_UPDATE_INTERVAL)) - Pvariable(DALLAS_COMPONENT_CLASS, conf[CONF_ID], rhs) + Pvariable(DallasComponent, conf[CONF_ID], rhs) BUILD_FLAGS = '-DUSE_DALLAS_SENSOR' diff --git a/esphomeyaml/components/deep_sleep.py b/esphomeyaml/components/deep_sleep.py index 1818897e4e..52687d9b2d 100644 --- a/esphomeyaml/components/deep_sleep.py +++ b/esphomeyaml/components/deep_sleep.py @@ -3,7 +3,7 @@ import voluptuous as vol from esphomeyaml import config_validation as cv, pins from esphomeyaml.const import CONF_ID, CONF_NUMBER, CONF_RUN_CYCLES, CONF_RUN_DURATION, \ CONF_SLEEP_DURATION, CONF_WAKEUP_PIN -from esphomeyaml.helpers import App, Pvariable, add, gpio_input_pin_expression +from esphomeyaml.helpers import App, Pvariable, add, gpio_input_pin_expression, esphomelib_ns def validate_pin_number(value): @@ -23,10 +23,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds, }) +DeepSleepComponent = esphomelib_ns.DeepSleepComponent + def to_code(config): rhs = App.make_deep_sleep_component() - deep_sleep = Pvariable('DeepSleepComponent', config[CONF_ID], rhs) + deep_sleep = Pvariable(DeepSleepComponent, config[CONF_ID], rhs) if CONF_SLEEP_DURATION in config: add(deep_sleep.set_sleep_duration(config[CONF_SLEEP_DURATION])) if CONF_WAKEUP_PIN in config: diff --git a/esphomeyaml/components/esp32_ble.py b/esphomeyaml/components/esp32_ble.py index 29de179553..5a2620117b 100644 --- a/esphomeyaml/components/esp32_ble.py +++ b/esphomeyaml/components/esp32_ble.py @@ -2,7 +2,7 @@ import voluptuous as vol from esphomeyaml import config_validation as cv from esphomeyaml.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32 -from esphomeyaml.helpers import App, Pvariable, add +from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns ESP_PLATFORMS = [ESP_PLATFORM_ESP32] @@ -11,10 +11,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds, }) +ESP32BLETracker = esphomelib_ns.ESP32BLETracker + def to_code(config): rhs = App.make_esp32_ble_tracker() - ble = Pvariable('ESP32BLETracker', config[CONF_ID], rhs) + ble = Pvariable(ESP32BLETracker, config[CONF_ID], rhs) if CONF_SCAN_INTERVAL in config: add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL])) diff --git a/esphomeyaml/components/esp32_touch.py b/esphomeyaml/components/esp32_touch.py index 3d5b6790b5..b77c0d0126 100644 --- a/esphomeyaml/components/esp32_touch.py +++ b/esphomeyaml/components/esp32_touch.py @@ -1,11 +1,12 @@ import voluptuous as vol from esphomeyaml import config_validation as cv +from esphomeyaml.components import binary_sensor from esphomeyaml.const import CONF_ID, CONF_SETUP_MODE, CONF_IIR_FILTER, \ CONF_SLEEP_DURATION, CONF_MEASUREMENT_DURATION, CONF_LOW_VOLTAGE_REFERENCE, \ CONF_HIGH_VOLTAGE_REFERENCE, CONF_VOLTAGE_ATTENUATION, ESP_PLATFORM_ESP32 from esphomeyaml.core import TimePeriod -from esphomeyaml.helpers import App, Pvariable, add +from esphomeyaml.helpers import App, Pvariable, add, global_ns ESP_PLATFORMS = [ESP_PLATFORM_ESP32] @@ -17,29 +18,27 @@ def validate_voltage(values): value = cv.string(value) if not value.endswith('V'): value += 'V' - if value not in values: - raise vol.Invalid('Must be one of {}'.format(values)) - return value + return cv.one_of(values)(value) return validator LOW_VOLTAGE_REFERENCE = { - '0.5V': 'TOUCH_LVOLT_0V5', - '0.6V': 'TOUCH_LVOLT_0V6', - '0.7V': 'TOUCH_LVOLT_0V7', - '0.8V': 'TOUCH_LVOLT_0V8', + '0.5V': global_ns.TOUCH_LVOLT_0V5, + '0.6V': global_ns.TOUCH_LVOLT_0V6, + '0.7V': global_ns.TOUCH_LVOLT_0V7, + '0.8V': global_ns.TOUCH_LVOLT_0V8, } HIGH_VOLTAGE_REFERENCE = { - '2.4V': 'TOUCH_HVOLT_2V4', - '2.5V': 'TOUCH_HVOLT_2V5', - '2.6V': 'TOUCH_HVOLT_2V6', - '2.7V': 'TOUCH_HVOLT_2V7', + '2.4V': global_ns.TOUCH_HVOLT_2V4, + '2.5V': global_ns.TOUCH_HVOLT_2V5, + '2.6V': global_ns.TOUCH_HVOLT_2V6, + '2.7V': global_ns.TOUCH_HVOLT_2V7, } VOLTAGE_ATTENUATION = { - '1.5V': 'TOUCH_HVOLT_ATTEN_1V5', - '1V': 'TOUCH_HVOLT_ATTEN_1V', - '0.5V': 'TOUCH_HVOLT_ATTEN_0V5', - '0V': 'TOUCH_HVOLT_ATTEN_0V', + '1.5V': global_ns.TOUCH_HVOLT_ATTEN_1V5, + '1V': global_ns.TOUCH_HVOLT_ATTEN_1V, + '0.5V': global_ns.TOUCH_HVOLT_ATTEN_0V5, + '0V': global_ns.TOUCH_HVOLT_ATTEN_0V, } CONFIG_SCHEMA = vol.Schema({ @@ -55,10 +54,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_VOLTAGE_ATTENUATION): validate_voltage(VOLTAGE_ATTENUATION), }) +ESP32TouchComponent = binary_sensor.binary_sensor_ns.ESP32TouchComponent + def to_code(config): rhs = App.make_esp32_touch_component() - touch = Pvariable('binary_sensor::ESP32TouchComponent', config[CONF_ID], rhs) + touch = Pvariable(ESP32TouchComponent, config[CONF_ID], rhs) if CONF_SETUP_MODE in config: add(touch.set_setup_mode(config[CONF_SETUP_MODE])) if CONF_IIR_FILTER in config: diff --git a/esphomeyaml/components/fan/__init__.py b/esphomeyaml/components/fan/__init__.py index ef25200267..18b302178c 100644 --- a/esphomeyaml/components/fan/__init__.py +++ b/esphomeyaml/components/fan/__init__.py @@ -1,26 +1,43 @@ import voluptuous as vol import esphomeyaml.config_validation as cv -from esphomeyaml.const import CONF_OSCILLATION_COMMAND_TOPIC, CONF_OSCILLATION_STATE_TOPIC, \ - CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC -from esphomeyaml.helpers import add, setup_mqtt_component +from esphomeyaml.const import CONF_ID, CONF_MQTT_ID, CONF_OSCILLATION_COMMAND_TOPIC, \ + CONF_OSCILLATION_STATE_TOPIC, CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC +from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ + +}) + +FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ + cv.GenerateID('fan'): cv.register_variable_id, + cv.GenerateID('mqtt_fan', CONF_MQTT_ID): cv.register_variable_id, vol.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.publish_topic, vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic, -}).extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA.schema) +}) + +fan_ns = esphomelib_ns.namespace('fan') +FanState = fan_ns.FanState +MQTTFanComponent = fan_ns.MQTTFanComponent +MakeFan = Application.MakeFan -def setup_mqtt_fan(obj, config): +def setup_fan_core_(fan_var, mqtt_var, config): if CONF_OSCILLATION_STATE_TOPIC in config: - add(obj.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC])) + add(mqtt_var.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC])) if CONF_OSCILLATION_COMMAND_TOPIC in config: - add(obj.set_custom_oscillation_command_topic(config[CONF_OSCILLATION_COMMAND_TOPIC])) + add(mqtt_var.set_custom_oscillation_command_topic(config[CONF_OSCILLATION_COMMAND_TOPIC])) if CONF_SPEED_STATE_TOPIC in config: - add(obj.set_custom_speed_state_topic(config[CONF_SPEED_STATE_TOPIC])) + add(mqtt_var.set_custom_speed_state_topic(config[CONF_SPEED_STATE_TOPIC])) if CONF_SPEED_COMMAND_TOPIC in config: - add(obj.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC])) - setup_mqtt_component(obj, config) + add(mqtt_var.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC])) + setup_mqtt_component(mqtt_var, config) + + +def setup_fan(fan_obj, mqtt_obj, config): + fan_var = Pvariable(FanState, config[CONF_ID], fan_obj, has_side_effects=False) + mqtt_var = Pvariable(MQTTFanComponent, config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False) + setup_fan_core_(fan_var, mqtt_var, config) BUILD_FLAGS = '-DUSE_FAN' diff --git a/esphomeyaml/components/fan/binary.py b/esphomeyaml/components/fan/binary.py index b62dc9f1ba..8d5a5b9128 100644 --- a/esphomeyaml/components/fan/binary.py +++ b/esphomeyaml/components/fan/binary.py @@ -2,22 +2,23 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import fan -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT from esphomeyaml.helpers import App, add, get_variable, variable PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ - cv.GenerateID('binary_fan'): cv.register_variable_id, + cv.GenerateID('binary_fan', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_OUTPUT): cv.variable_id, vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id, -}) +}).extend(fan.FAN_SCHEMA.schema) def to_code(config): output = get_variable(config[CONF_OUTPUT]) rhs = App.make_fan(config[CONF_NAME]) - fan_struct = variable('Application::MakeFan', config[CONF_ID], rhs) + fan_struct = variable(fan.MakeFan, config[CONF_MAKE_ID], rhs) add(fan_struct.Poutput.set_binary(output)) if CONF_OSCILLATION_OUTPUT in config: oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT]) add(fan_struct.Poutput.set_oscillation(oscillation_output)) - fan.setup_mqtt_fan(fan_struct.Pmqtt, config) + + fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config) diff --git a/esphomeyaml/components/fan/speed.py b/esphomeyaml/components/fan/speed.py index 0d94aacac7..d2e4be49e6 100644 --- a/esphomeyaml/components/fan/speed.py +++ b/esphomeyaml/components/fan/speed.py @@ -2,13 +2,13 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import fan -from esphomeyaml.const import CONF_HIGH, CONF_ID, CONF_LOW, \ - CONF_MEDIUM, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT, CONF_SPEED, \ - CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC +from esphomeyaml.const import CONF_HIGH, CONF_LOW, CONF_MAKE_ID, CONF_MEDIUM, CONF_NAME, \ + CONF_OSCILLATION_OUTPUT, CONF_OUTPUT, CONF_SPEED, CONF_SPEED_COMMAND_TOPIC, \ + CONF_SPEED_STATE_TOPIC from esphomeyaml.helpers import App, add, get_variable, variable PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ - cv.GenerateID('speed_fan'): cv.register_variable_id, + cv.GenerateID('speed_fan', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_OUTPUT): cv.variable_id, vol.Optional(CONF_SPEED_STATE_TOPIC): cv.publish_topic, vol.Optional(CONF_SPEED_COMMAND_TOPIC): cv.subscribe_topic, @@ -18,13 +18,13 @@ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ vol.Required(CONF_MEDIUM): cv.zero_to_one_float, vol.Required(CONF_HIGH): cv.zero_to_one_float, }), -}) +}).extend(fan.FAN_SCHEMA.schema) def to_code(config): output = get_variable(config[CONF_OUTPUT]) rhs = App.make_fan(config[CONF_NAME]) - fan_struct = variable('Application::MakeFan', config[CONF_ID], rhs) + fan_struct = variable(fan.MakeFan, config[CONF_MAKE_ID], rhs) if CONF_SPEED in config: speeds = config[CONF_SPEED] add(fan_struct.Poutput.set_speed(output, 0.0, @@ -37,4 +37,5 @@ def to_code(config): if CONF_OSCILLATION_OUTPUT in config: oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT]) add(fan_struct.Poutput.set_oscillation(oscillation_output)) - fan.setup_mqtt_fan(fan_struct.Pmqtt, config) + + fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config) diff --git a/esphomeyaml/components/i2c.py b/esphomeyaml/components/i2c.py index b9dfc5a31c..b3b563d9b6 100644 --- a/esphomeyaml/components/i2c.py +++ b/esphomeyaml/components/i2c.py @@ -4,7 +4,7 @@ import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.const import CONF_FREQUENCY, CONF_SCL, CONF_SDA, CONF_SCAN, CONF_ID, \ CONF_RECEIVE_TIMEOUT -from esphomeyaml.helpers import App, add, Pvariable +from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns CONFIG_SCHEMA = vol.Schema({ cv.GenerateID('i2c'): cv.register_variable_id, @@ -15,10 +15,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_SCAN): cv.boolean, }) +I2CComponent = esphomelib_ns.I2CComponent + def to_code(config): rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN)) - i2c = Pvariable('I2CComponent', config[CONF_ID], rhs) + i2c = Pvariable(I2CComponent, config[CONF_ID], rhs) if CONF_FREQUENCY in config: add(i2c.set_frequency(config[CONF_FREQUENCY])) if CONF_RECEIVE_TIMEOUT in config: diff --git a/esphomeyaml/components/ir_transmitter.py b/esphomeyaml/components/ir_transmitter.py index c402aedeb9..7ac2af7bc3 100644 --- a/esphomeyaml/components/ir_transmitter.py +++ b/esphomeyaml/components/ir_transmitter.py @@ -2,11 +2,10 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins +from esphomeyaml.components import switch from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression -IR_TRANSMITTER_COMPONENT_CLASS = 'switch_::IRTransmitterComponent' - CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ cv.GenerateID('ir_transmitter'): cv.register_variable_id, vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, @@ -14,12 +13,14 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ vol.Range(min=1, max=100)), })]) +IRTransmitterComponent = switch.switch_ns.namespace('IRTransmitterComponent') + def to_code(config): for conf in config: pin = gpio_output_pin_expression(conf[CONF_PIN]) rhs = App.make_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT)) - Pvariable(IR_TRANSMITTER_COMPONENT_CLASS, conf[CONF_ID], rhs) + Pvariable(IRTransmitterComponent, conf[CONF_ID], rhs) BUILD_FLAGS = '-DUSE_IR_TRANSMITTER' diff --git a/esphomeyaml/components/light/__init__.py b/esphomeyaml/components/light/__init__.py index 63ef94b229..e6669c7e70 100644 --- a/esphomeyaml/components/light/__init__.py +++ b/esphomeyaml/components/light/__init__.py @@ -1,17 +1,40 @@ import esphomeyaml.config_validation as cv -from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT -from esphomeyaml.helpers import add +from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \ + CONF_MQTT_ID +from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ -}).extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA.schema) +}) + +LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ + cv.GenerateID('light'): cv.register_variable_id, + cv.GenerateID('mqtt_light', CONF_MQTT_ID): cv.register_variable_id, +}) + +light_ns = esphomelib_ns.namespace('light') +LightState = light_ns.LightState +MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent +ToggleAction = light_ns.ToggleAction +TurnOffAction = light_ns.TurnOffAction +TurnOnAction = light_ns.TurnOnAction +MakeLight = Application.MakeLight -def setup_light_component(obj, config): +def setup_light_core_(light_var, mqtt_var, config): if CONF_DEFAULT_TRANSITION_LENGTH in config: - add(obj.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH])) + add(light_var.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH])) if CONF_GAMMA_CORRECT in config: - add(obj.set_gamma_correct(config[CONF_GAMMA_CORRECT])) + add(light_var.set_gamma_correct(config[CONF_GAMMA_CORRECT])) + + setup_mqtt_component(mqtt_var, config) + + +def setup_light(light_obj, mqtt_obj, config): + light_var = Pvariable(LightState, config[CONF_ID], light_obj, has_side_effects=False) + mqtt_var = Pvariable(MQTTJSONLightComponent, config[CONF_MQTT_ID], mqtt_obj, + has_side_effects=False) + setup_light_core_(light_var, mqtt_var, config) BUILD_FLAGS = '-DUSE_LIGHT' diff --git a/esphomeyaml/components/light/binary.py b/esphomeyaml/components/light/binary.py index 4cc808a74f..a469f5e932 100644 --- a/esphomeyaml/components/light/binary.py +++ b/esphomeyaml/components/light/binary.py @@ -1,20 +1,18 @@ - import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import light -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_OUTPUT -from esphomeyaml.helpers import App, get_variable, variable, setup_mqtt_component +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT +from esphomeyaml.helpers import App, get_variable, variable PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ - cv.GenerateID('binary_light'): cv.register_variable_id, + cv.GenerateID('binary_light', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_OUTPUT): cv.variable_id, -}) +}).extend(light.LIGHT_SCHEMA.schema) def to_code(config): output = get_variable(config[CONF_OUTPUT]) rhs = App.make_binary_light(config[CONF_NAME], output) - light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) - setup_mqtt_component(light_struct.Pmqtt, config) - light.setup_light_component(light_struct.Pstate, config) + light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) + light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) diff --git a/esphomeyaml/components/light/fastled_clockless.py b/esphomeyaml/components/light/fastled_clockless.py index 85b1d95c97..afaabffa0d 100644 --- a/esphomeyaml/components/light/fastled_clockless.py +++ b/esphomeyaml/components/light/fastled_clockless.py @@ -4,10 +4,10 @@ import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import light from esphomeyaml.const import CONF_CHIPSET, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ - CONF_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, CONF_NUM_LEDS, CONF_PIN, CONF_POWER_SUPPLY, \ + CONF_MAKE_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, CONF_NUM_LEDS, CONF_PIN, CONF_POWER_SUPPLY, \ CONF_RGB_ORDER -from esphomeyaml.helpers import App, RawExpression, TemplateArguments, add, get_variable, \ - setup_mqtt_component, variable +from esphomeyaml.helpers import App, Application, RawExpression, TemplateArguments, add, \ + get_variable, variable TYPES = [ 'NEOPIXEL', @@ -53,24 +53,26 @@ def validate(value): PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({ - cv.GenerateID('fast_led_clockless_light'): cv.register_variable_id, + cv.GenerateID('fast_led_clockless_light', CONF_MAKE_ID): cv.register_variable_id, - vol.Required(CONF_CHIPSET): vol.All(vol.Upper, vol.Any(*TYPES)), + vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*TYPES)), vol.Required(CONF_PIN): pins.output_pin, vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int, vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, - vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, vol.Any(*RGB_ORDERS)), + vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, cv.one_of(*RGB_ORDERS)), vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, -}), validate) +}).extend(light.LIGHT_SCHEMA.schema), validate) + +MakeFastLEDLight = Application.MakeFastLEDLight def to_code(config): rhs = App.make_fast_led_light(config[CONF_NAME]) - make = variable('Application::MakeFastLEDLight', config[CONF_ID], rhs) + make = variable(MakeFastLEDLight, config[CONF_MAKE_ID], rhs) fast_led = make.Pfast_led rgb_order = None @@ -87,8 +89,7 @@ def to_code(config): power_supply = get_variable(config[CONF_POWER_SUPPLY]) add(fast_led.set_power_supply(power_supply)) - setup_mqtt_component(make.Pmqtt, config) - light.setup_light_component(make.Pstate, config) + light.setup_light(make.Pstate, make.Pmqtt, config) BUILD_FLAGS = '-DUSE_FAST_LED_LIGHT' diff --git a/esphomeyaml/components/light/fastled_spi.py b/esphomeyaml/components/light/fastled_spi.py index 62cb30dc08..54be4f7d47 100644 --- a/esphomeyaml/components/light/fastled_spi.py +++ b/esphomeyaml/components/light/fastled_spi.py @@ -4,10 +4,10 @@ import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import light from esphomeyaml.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, \ - CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, \ - CONF_NUM_LEDS, CONF_POWER_SUPPLY, CONF_RGB_ORDER -from esphomeyaml.helpers import App, RawExpression, TemplateArguments, add, get_variable, \ - setup_mqtt_component, variable + CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_MAKE_ID, CONF_MAX_REFRESH_RATE, \ + CONF_NAME, CONF_NUM_LEDS, CONF_POWER_SUPPLY, CONF_RGB_ORDER +from esphomeyaml.helpers import App, Application, RawExpression, TemplateArguments, add, \ + get_variable, variable CHIPSETS = [ 'LPD8806', @@ -30,25 +30,27 @@ RGB_ORDERS = [ ] PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ - cv.GenerateID('fast_led_spi_light'): cv.register_variable_id, + cv.GenerateID('fast_led_spi_light', CONF_MAKE_ID): cv.register_variable_id, - vol.Required(CONF_CHIPSET): vol.All(vol.Upper, vol.Any(*CHIPSETS)), + vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*CHIPSETS)), vol.Required(CONF_DATA_PIN): pins.output_pin, vol.Required(CONF_CLOCK_PIN): pins.output_pin, vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int, - vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, vol.Any(*RGB_ORDERS)), + vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, cv.one_of(*RGB_ORDERS)), vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, -}) +}).extend(light.LIGHT_SCHEMA.schema) + +MakeFastLEDLight = Application.MakeFastLEDLight def to_code(config): rhs = App.make_fast_led_light(config[CONF_NAME]) - make = variable('Application::MakeFastLEDLight', config[CONF_ID], rhs) + make = variable(MakeFastLEDLight, config[CONF_MAKE_ID], rhs) fast_led = make.Pfast_led rgb_order = None @@ -67,8 +69,7 @@ def to_code(config): power_supply = get_variable(config[CONF_POWER_SUPPLY]) add(fast_led.set_power_supply(power_supply)) - setup_mqtt_component(make.Pmqtt, config) - light.setup_light_component(make.Pstate, config) + light.setup_light(make.Pstate, make.Pmqtt, config) BUILD_FLAGS = '-DUSE_FAST_LED_LIGHT' diff --git a/esphomeyaml/components/light/monochromatic.py b/esphomeyaml/components/light/monochromatic.py index 901dd6ce74..af5422d3f4 100644 --- a/esphomeyaml/components/light/monochromatic.py +++ b/esphomeyaml/components/light/monochromatic.py @@ -2,21 +2,20 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import light -from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \ +from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_MAKE_ID, \ CONF_NAME, CONF_OUTPUT -from esphomeyaml.helpers import App, get_variable, setup_mqtt_component, variable +from esphomeyaml.helpers import App, get_variable, variable PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ - cv.GenerateID('monochromatic_light'): cv.register_variable_id, + cv.GenerateID('monochromatic_light', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_OUTPUT): cv.variable_id, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, -}) +}).extend(light.LIGHT_SCHEMA.schema) def to_code(config): output = get_variable(config[CONF_OUTPUT]) rhs = App.make_monochromatic_light(config[CONF_NAME], output) - light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) - setup_mqtt_component(light_struct.Pmqtt, config) - light.setup_light_component(light_struct.Pstate, config) + light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) + light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) diff --git a/esphomeyaml/components/light/rgb.py b/esphomeyaml/components/light/rgb.py index 5ae306cb9c..83b6f8dab7 100644 --- a/esphomeyaml/components/light/rgb.py +++ b/esphomeyaml/components/light/rgb.py @@ -3,17 +3,17 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import light from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ - CONF_GREEN, CONF_ID, CONF_NAME, CONF_RED -from esphomeyaml.helpers import App, get_variable, setup_mqtt_component, variable + CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED +from esphomeyaml.helpers import App, get_variable, variable PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ - cv.GenerateID('rgb_light'): cv.register_variable_id, + cv.GenerateID('rgb_light', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_RED): cv.variable_id, vol.Required(CONF_GREEN): cv.variable_id, vol.Required(CONF_BLUE): cv.variable_id, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, -}) +}).extend(light.LIGHT_SCHEMA.schema) def to_code(config): @@ -21,6 +21,5 @@ def to_code(config): green = get_variable(config[CONF_GREEN]) blue = get_variable(config[CONF_BLUE]) rhs = App.make_rgb_light(config[CONF_NAME], red, green, blue) - light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) - setup_mqtt_component(light_struct.Pmqtt, config) - light.setup_light_component(light_struct.Pstate, config) + light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) + light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) diff --git a/esphomeyaml/components/light/rgbw.py b/esphomeyaml/components/light/rgbw.py index 05008cf053..cdbfc8828c 100644 --- a/esphomeyaml/components/light/rgbw.py +++ b/esphomeyaml/components/light/rgbw.py @@ -3,18 +3,18 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import light from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ - CONF_GREEN, CONF_ID, CONF_NAME, CONF_RED, CONF_WHITE -from esphomeyaml.helpers import App, get_variable, setup_mqtt_component, variable + CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE +from esphomeyaml.helpers import App, get_variable, variable PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ - cv.GenerateID('rgbw_light'): cv.register_variable_id, + cv.GenerateID('rgbw_light', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_RED): cv.variable_id, vol.Required(CONF_GREEN): cv.variable_id, vol.Required(CONF_BLUE): cv.variable_id, vol.Required(CONF_WHITE): cv.variable_id, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, -}) +}).extend(light.LIGHT_SCHEMA.schema) def to_code(config): @@ -23,6 +23,5 @@ def to_code(config): blue = get_variable(config[CONF_BLUE]) white = get_variable(config[CONF_WHITE]) rhs = App.make_rgbw_light(config[CONF_NAME], red, green, blue, white) - light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) - setup_mqtt_component(light_struct.Pmqtt, config) - light.setup_light_component(light_struct.Pstate, config) + light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) + light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) diff --git a/esphomeyaml/components/logger.py b/esphomeyaml/components/logger.py index 6c7be146c4..a48956042b 100644 --- a/esphomeyaml/components/logger.py +++ b/esphomeyaml/components/logger.py @@ -4,14 +4,34 @@ import esphomeyaml.config_validation as cv from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, \ CONF_TX_BUFFER_SIZE from esphomeyaml.core import ESPHomeYAMLError -from esphomeyaml.helpers import App, Pvariable, RawExpression, add +from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, global_ns -LOG_LEVELS = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE'] +LOG_LEVELS = { + 'NONE': global_ns.ESPHOMELIB_LOG_LEVEL_NONE, + 'ERROR': global_ns.ESPHOMELIB_LOG_LEVEL_ERROR, + 'WARN': global_ns.ESPHOMELIB_LOG_LEVEL_WARN, + 'INFO': global_ns.ESPHOMELIB_LOG_LEVEL_INFO, + 'DEBUG': global_ns.ESPHOMELIB_LOG_LEVEL_DEBUG, + 'VERBOSE': global_ns.ESPHOMELIB_LOG_LEVEL_VERBOSE, + 'VERY_VERBOSE': global_ns.ESPHOMELIB_LOG_LEVEL_VERY_VERBOSE, +} + +LOG_LEVEL_SEVERITY = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE'] # pylint: disable=invalid-name -is_log_level = vol.All(vol.Upper, vol.Any(*LOG_LEVELS)) +is_log_level = vol.All(vol.Upper, cv.one_of(*LOG_LEVELS)) -CONFIG_SCHEMA = vol.Schema({ + +def validate_local_no_higher_than_global(value): + global_level = value.get(CONF_LEVEL, 'DEBUG') + for tag, level in value.get(CONF_LOGS, {}).iteritems(): + if LOG_LEVEL_SEVERITY.index(level) > LOG_LEVEL_SEVERITY.index(global_level): + raise ESPHomeYAMLError(u"The local log level {} for {} must be less severe than the " + u"global log level {}.".format(level, tag, global_level)) + return value + + +CONFIG_SCHEMA = vol.All(vol.Schema({ cv.GenerateID(CONF_LOGGER): cv.register_variable_id, vol.Optional(CONF_BAUD_RATE): cv.positive_int, vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int, @@ -19,33 +39,23 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_LOGS): vol.Schema({ cv.string: is_log_level, }) -}) +}), validate_local_no_higher_than_global) - -def esphomelib_log_level(level): - return u'ESPHOMELIB_LOG_LEVEL_{}'.format(level) - - -def exp_log_level(level): - return RawExpression(esphomelib_log_level(level)) +LogComponent = esphomelib_ns.LogComponent def to_code(config): rhs = App.init_log(config.get(CONF_BAUD_RATE)) - log = Pvariable(u'LogComponent', config[CONF_ID], rhs) + log = Pvariable(LogComponent, config[CONF_ID], rhs) if CONF_TX_BUFFER_SIZE in config: add(log.set_tx_buffer_size(config[CONF_TX_BUFFER_SIZE])) if CONF_LEVEL in config: - add(log.set_global_log_level(exp_log_level(config[CONF_LEVEL]))) + add(log.set_global_log_level(LOG_LEVELS[config[CONF_LEVEL]])) for tag, level in config.get(CONF_LOGS, {}).iteritems(): - global_level = config.get(CONF_LEVEL, 'DEBUG') - if LOG_LEVELS.index(level) > LOG_LEVELS.index(global_level): - raise ESPHomeYAMLError(u"The local log level {} for {} must be less severe than the " - u"global log level {}.".format(level, tag, global_level)) - add(log.set_log_level(tag, exp_log_level(level))) + add(log.set_log_level(tag, LOG_LEVELS[level])) def required_build_flags(config): if CONF_LEVEL in config: - return u'-DESPHOMELIB_LOG_LEVEL={}'.format(esphomelib_log_level(config[CONF_LEVEL])) + return u'-DESPHOMELIB_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]])) return None diff --git a/esphomeyaml/components/mqtt.py b/esphomeyaml/components/mqtt.py index 64b1b0b574..8ae4725a3c 100644 --- a/esphomeyaml/components/mqtt.py +++ b/esphomeyaml/components/mqtt.py @@ -3,12 +3,14 @@ import re import voluptuous as vol import esphomeyaml.config_validation as cv +from esphomeyaml import automation from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \ - CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_SSL_FINGERPRINTS, CONF_ID, CONF_LOG_TOPIC, \ - CONF_MQTT, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, CONF_TOPIC, \ - CONF_TOPIC_PREFIX, CONF_USERNAME, CONF_WILL_MESSAGE, CONF_KEEPALIVE -from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, add, \ - exp_empty_optional, RawExpression + CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LOG_TOPIC, \ + CONF_MQTT, CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, \ + CONF_SSL_FINGERPRINTS, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, \ + CONF_WILL_MESSAGE +from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, \ + TemplateArguments, add, esphomelib_ns, optional, std_string, RawExpression def validate_message_just_topic(value): @@ -18,7 +20,7 @@ def validate_message_just_topic(value): MQTT_MESSAGE_BASE = vol.Schema({ vol.Required(CONF_TOPIC): cv.publish_topic, - vol.Optional(CONF_QOS, default=0): vol.All(vol.Coerce(int), vol.In([0, 1, 2])), + vol.Optional(CONF_QOS, default=0): cv.mqtt_qos, vol.Optional(CONF_RETAIN, default=True): cv.boolean, }) @@ -28,12 +30,15 @@ MQTT_MESSAGE_SCHEMA = vol.Any(None, MQTT_MESSAGE_BASE.extend({ vol.Required(CONF_PAYLOAD): cv.mqtt_payload, })) +mqtt_ns = esphomelib_ns.namespace('mqtt') +MQTTMessage = mqtt_ns.MQTTMessage +MQTTClientComponent = mqtt_ns.MQTTClientComponent +MQTTPublishAction = mqtt_ns.MQTTPublishAction +MQTTMessageTrigger = mqtt_ns.MQTTMessageTrigger + def validate_broker(value): value = cv.string_strict(value) - if value.endswith(u'.local'): - raise vol.Invalid(u"MQTT server addresses ending with '.local' are currently unsupported." - u" Please use the static IP instead.") if u':' in value: raise vol.Invalid(u"Please specify the port using the port: option") if not value: @@ -65,14 +70,18 @@ CONFIG_SCHEMA = vol.Schema({ 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_ON_MESSAGE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ + vol.Required(CONF_TOPIC): cv.publish_topic, + vol.Optional(CONF_QOS, 0): cv.mqtt_qos, + })]) }) def exp_mqtt_message(config): if config is None: - return exp_empty_optional('mqtt::MQTTMessage') + return optional(TemplateArguments(MQTTMessage)) exp = StructInitializer( - 'mqtt::MQTTMessage', + MQTTMessage, ('topic', config[CONF_TOPIC]), ('payload', config.get(CONF_PAYLOAD, "")), ('qos', config[CONF_QOS]), @@ -84,7 +93,7 @@ def exp_mqtt_message(config): def to_code(config): rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT], config[CONF_USERNAME], config[CONF_PASSWORD]) - mqtt = Pvariable('mqtt::MQTTClientComponent', config[CONF_ID], rhs) + mqtt = Pvariable(MQTTClientComponent, config[CONF_ID], rhs) if not config.get(CONF_DISCOVERY, True): add(mqtt.disable_discovery()) if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config: @@ -120,6 +129,11 @@ def to_code(config): if CONF_KEEPALIVE in config: add(mqtt.set_keep_alive(config[CONF_KEEPALIVE])) + for conf in config.get(CONF_ON_MESSAGE, []): + rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS]) + trigger = Pvariable(MQTTMessageTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, std_string, conf) + def required_build_flags(config): if CONF_SSL_FINGERPRINTS in config: diff --git a/esphomeyaml/components/ota.py b/esphomeyaml/components/ota.py index 33deff16af..7398202ece 100644 --- a/esphomeyaml/components/ota.py +++ b/esphomeyaml/components/ota.py @@ -8,7 +8,7 @@ from esphomeyaml import core from esphomeyaml.const import CONF_ID, CONF_OTA, CONF_PASSWORD, CONF_PORT, CONF_SAFE_MODE, \ ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 from esphomeyaml.core import ESPHomeYAMLError -from esphomeyaml.helpers import App, Pvariable, add +from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns _LOGGER = logging.getLogger(__name__) @@ -20,10 +20,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_PASSWORD): cv.string, }) +OTAComponent = esphomelib_ns.OTAComponent + def to_code(config): rhs = App.init_ota() - ota = Pvariable('OTAComponent', config[CONF_ID], rhs) + ota = Pvariable(OTAComponent, config[CONF_ID], rhs) if CONF_PASSWORD in config: hash_ = hashlib.md5(config[CONF_PASSWORD].encode()).hexdigest() add(ota.set_auth_password_hash(hash_)) diff --git a/esphomeyaml/components/output/__init__.py b/esphomeyaml/components/output/__init__.py index c4f29fd6b1..1c3940f8cf 100644 --- a/esphomeyaml/components/output/__init__.py +++ b/esphomeyaml/components/output/__init__.py @@ -1,19 +1,24 @@ - import voluptuous as vol import esphomeyaml.config_validation as cv -from esphomeyaml.const import CONF_POWER_SUPPLY, CONF_INVERTED, CONF_MAX_POWER -from esphomeyaml.helpers import get_variable, add +from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY +from esphomeyaml.helpers import add, esphomelib_ns, get_variable PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ + +}) + +BINARY_OUTPUT_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({ vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, vol.Optional(CONF_INVERTED): cv.boolean, -}).extend(cv.REQUIRED_ID_SCHEMA.schema) +}) -FLOAT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ +FLOAT_OUTPUT_SCHEMA = BINARY_OUTPUT_SCHEMA.extend({ vol.Optional(CONF_MAX_POWER): cv.zero_to_one_float, }) +output_ns = esphomelib_ns.namespace('output') + def setup_output_platform(obj, config, skip_power_supply=False): if CONF_INVERTED in config: diff --git a/esphomeyaml/components/output/esp8266_pwm.py b/esphomeyaml/components/output/esp8266_pwm.py index 8bc507df2c..c457062e61 100644 --- a/esphomeyaml/components/output/esp8266_pwm.py +++ b/esphomeyaml/components/output/esp8266_pwm.py @@ -15,15 +15,17 @@ def valid_pwm_pin(value): return value -PLATFORM_SCHEMA = output.FLOAT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({ vol.Required(CONF_PIN): vol.All(pins.GPIO_INTERNAL_OUTPUT_PIN_SCHEMA, valid_pwm_pin), -}) +}).extend(output.FLOAT_OUTPUT_SCHEMA.schema) + +ESP8266PWMOutput = output.output_ns.ESP8266PWMOutput def to_code(config): pin = gpio_output_pin_expression(config[CONF_PIN]) rhs = App.make_esp8266_pwm_output(pin) - gpio = Pvariable('output::ESP8266PWMOutput', config[CONF_ID], rhs) + gpio = Pvariable(ESP8266PWMOutput, config[CONF_ID], rhs) output.setup_output_platform(gpio, config) diff --git a/esphomeyaml/components/output/gpio.py b/esphomeyaml/components/output/gpio.py index c6c67a396f..c82a551d24 100644 --- a/esphomeyaml/components/output/gpio.py +++ b/esphomeyaml/components/output/gpio.py @@ -7,13 +7,15 @@ from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({ vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, -}) +}).extend(output.BINARY_OUTPUT_SCHEMA.schema) + +GPIOBinaryOutputComponent = output.output_ns.GPIOBinaryOutputComponent def to_code(config): pin = gpio_output_pin_expression(config[CONF_PIN]) rhs = App.make_gpio_output(pin) - gpio = Pvariable('output::GPIOBinaryOutputComponent', config[CONF_ID], rhs) + gpio = Pvariable(GPIOBinaryOutputComponent, config[CONF_ID], rhs) output.setup_output_platform(gpio, config) diff --git a/esphomeyaml/components/output/ledc.py b/esphomeyaml/components/output/ledc.py index f6c8dd5c01..fbcb73799a 100644 --- a/esphomeyaml/components/output/ledc.py +++ b/esphomeyaml/components/output/ledc.py @@ -19,12 +19,15 @@ def validate_frequency_bit_depth(obj): return obj -PLATFORM_SCHEMA = vol.All(output.FLOAT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = vol.All(output.PLATFORM_SCHEMA.extend({ vol.Required(CONF_PIN): vol.All(pins.output_pin, vol.Range(min=0, max=33)), vol.Optional(CONF_FREQUENCY): cv.frequency, vol.Optional(CONF_BIT_DEPTH): vol.All(vol.Coerce(int), vol.Range(min=1, max=15)), vol.Optional(CONF_CHANNEL): vol.All(vol.Coerce(int), vol.Range(min=0, max=15)) -}), validate_frequency_bit_depth) +}).extend(output.FLOAT_OUTPUT_SCHEMA.schema), validate_frequency_bit_depth) + + +LEDCOutputComponent = output.output_ns.LEDCOutputComponent def to_code(config): @@ -32,7 +35,7 @@ def to_code(config): if frequency is None and CONF_BIT_DEPTH in config: frequency = 1000 rhs = App.make_ledc_output(config[CONF_PIN], frequency, config.get(CONF_BIT_DEPTH)) - ledc = Pvariable('output::LEDCOutputComponent', config[CONF_ID], rhs) + ledc = Pvariable(LEDCOutputComponent, config[CONF_ID], rhs) if CONF_CHANNEL in config: add(ledc.set_channel(config[CONF_CHANNEL])) output.setup_output_platform(ledc, config) diff --git a/esphomeyaml/components/output/pca9685.py b/esphomeyaml/components/output/pca9685.py index ffa8453280..1d617efa76 100644 --- a/esphomeyaml/components/output/pca9685.py +++ b/esphomeyaml/components/output/pca9685.py @@ -2,26 +2,28 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import output -from esphomeyaml.components.pca9685 import PCA9685_COMPONENT_TYPE +from esphomeyaml.components.pca9685 import PCA9685OutputComponent from esphomeyaml.const import CONF_CHANNEL, CONF_ID, CONF_PCA9685_ID, CONF_POWER_SUPPLY from esphomeyaml.helpers import Pvariable, get_variable DEPENDENCIES = ['pca9685'] -PLATFORM_SCHEMA = output.FLOAT_PLATFORM_SCHEMA.extend({ +PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({ vol.Required(CONF_CHANNEL): vol.All(vol.Coerce(int), vol.Range(min=0, max=15)), vol.Optional(CONF_PCA9685_ID): cv.variable_id, -}) +}).extend(output.FLOAT_OUTPUT_SCHEMA.schema) + +Channel = PCA9685OutputComponent.Channel def to_code(config): power_supply = None if CONF_POWER_SUPPLY in config: power_supply = get_variable(config[CONF_POWER_SUPPLY]) - pca9685 = get_variable(config.get(CONF_PCA9685_ID), PCA9685_COMPONENT_TYPE) + pca9685 = get_variable(config.get(CONF_PCA9685_ID), PCA9685OutputComponent) rhs = pca9685.create_channel(config[CONF_CHANNEL], power_supply) - out = Pvariable('output::PCA9685OutputComponent::Channel', config[CONF_ID], rhs) + out = Pvariable(Channel, config[CONF_ID], rhs) output.setup_output_platform(out, config, skip_power_supply=True) diff --git a/esphomeyaml/components/pca9685.py b/esphomeyaml/components/pca9685.py index 3d1031e719..d1a9c59c3a 100644 --- a/esphomeyaml/components/pca9685.py +++ b/esphomeyaml/components/pca9685.py @@ -1,14 +1,13 @@ import voluptuous as vol import esphomeyaml.config_validation as cv +from esphomeyaml.components import output from esphomeyaml.const import CONF_ADDRESS, CONF_FREQUENCY, CONF_ID, CONF_PHASE_BALANCER -from esphomeyaml.helpers import App, HexIntLiteral, Pvariable, RawExpression, add +from esphomeyaml.helpers import App, HexIntLiteral, Pvariable, add DEPENDENCIES = ['i2c'] -PHASE_BALANCERS = ['None', 'Linear', 'Weaved'] - -PCA9685_COMPONENT_TYPE = 'output::PCA9685OutputComponent' +PCA9685OutputComponent = output.output_ns.namespace('PCA9685OutputComponent') PHASE_BALANCER_MESSAGE = ("The phase_balancer option has been removed in version 1.5.0. " "esphomelib will now automatically choose a suitable phase balancer.") @@ -28,13 +27,9 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCA9685_SCHEMA]) def to_code(config): for conf in config: rhs = App.make_pca9685_component(conf.get(CONF_FREQUENCY)) - pca9685 = Pvariable(PCA9685_COMPONENT_TYPE, conf[CONF_ID], rhs) + pca9685 = Pvariable(PCA9685OutputComponent, conf[CONF_ID], rhs) if CONF_ADDRESS in conf: add(pca9685.set_address(HexIntLiteral(conf[CONF_ADDRESS]))) - if CONF_PHASE_BALANCER in conf: - phase_balancer = RawExpression(u'PCA9685_PhaseBalancer_{}'.format( - conf[CONF_PHASE_BALANCER])) - add(pca9685.set_phase_balancer(phase_balancer)) BUILD_FLAGS = '-DUSE_PCA9685_OUTPUT' diff --git a/esphomeyaml/components/pcf8574.py b/esphomeyaml/components/pcf8574.py index 82be871292..8f10226fab 100644 --- a/esphomeyaml/components/pcf8574.py +++ b/esphomeyaml/components/pcf8574.py @@ -2,7 +2,7 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_PCF8575 -from esphomeyaml.helpers import App, Pvariable +from esphomeyaml.helpers import App, Pvariable, esphomelib_ns DEPENDENCIES = ['i2c'] @@ -14,11 +14,14 @@ PCF8574_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCF8574_SCHEMA]) +io_ns = esphomelib_ns.namespace('io') +PCF8574Component = io_ns.PCF8574Component + def to_code(config): for conf in config: rhs = App.make_pcf8574_component(conf[CONF_ADDRESS], conf[CONF_PCF8575]) - Pvariable('io::PCF8574Component', conf[CONF_ID], rhs) + Pvariable(PCF8574Component, conf[CONF_ID], rhs) BUILD_FLAGS = '-DUSE_PCF8574' diff --git a/esphomeyaml/components/power_supply.py b/esphomeyaml/components/power_supply.py index d70383454d..e6aee6edaa 100644 --- a/esphomeyaml/components/power_supply.py +++ b/esphomeyaml/components/power_supply.py @@ -3,7 +3,7 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN -from esphomeyaml.helpers import App, Pvariable, add, gpio_output_pin_expression +from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, gpio_output_pin_expression POWER_SUPPLY_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({ vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, @@ -13,12 +13,13 @@ POWER_SUPPLY_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({ CONFIG_SCHEMA = vol.All(cv.ensure_list, [POWER_SUPPLY_SCHEMA]) +PowerSupplyComponent = esphomelib_ns.PowerSupplyComponent + def to_code(config): for conf in config: - pin = gpio_output_pin_expression(conf[CONF_PIN]) - rhs = App.make_power_supply(pin) - psu = Pvariable('PowerSupplyComponent', conf[CONF_ID], rhs) + rhs = App.make_power_supply(gpio_output_pin_expression(conf[CONF_PIN])) + psu = Pvariable(PowerSupplyComponent, conf[CONF_ID], rhs) if CONF_ENABLE_TIME in conf: add(psu.set_enable_time(conf[CONF_ENABLE_TIME])) if CONF_KEEP_ON_TIME in conf: diff --git a/esphomeyaml/components/sensor/__init__.py b/esphomeyaml/components/sensor/__init__.py index 2c0be9c8e9..c9a8ac46bc 100644 --- a/esphomeyaml/components/sensor/__init__.py +++ b/esphomeyaml/components/sensor/__init__.py @@ -1,13 +1,15 @@ import voluptuous as vol import esphomeyaml.config_validation as cv +from esphomeyaml import automation from esphomeyaml.const import CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_DEBOUNCE, CONF_DELTA, \ CONF_EXPIRE_AFTER, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, CONF_FILTER_NAN, \ - CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_LAMBDA, CONF_MQTT_ID, CONF_MULTIPLY, \ - CONF_NAME, CONF_OFFSET, CONF_OR, CONF_SEND_EVERY, CONF_SLIDING_WINDOW_MOVING_AVERAGE, \ - CONF_THROTTLE, CONF_UNIQUE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE -from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \ - setup_mqtt_component + CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_ID, CONF_LAMBDA, CONF_MAX, CONF_MIN, \ + CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_ON_RAW_VALUE, CONF_ON_VALUE, \ + CONF_ON_VALUE_RANGE, CONF_OR, CONF_SEND_EVERY, CONF_SLIDING_WINDOW_MOVING_AVERAGE, \ + CONF_THROTTLE, CONF_TRIGGER_ID, CONF_UNIQUE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE +from esphomeyaml.helpers import App, ArrayInitializer, NAN, Pvariable, add, esphomelib_ns, float_, \ + process_lambda, setup_mqtt_component, templatable PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ @@ -18,91 +20,102 @@ def validate_recursive_filter(value): return FILTERS_SCHEMA(value) -FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.Any( - vol.Schema({vol.Required(CONF_OFFSET): vol.Coerce(float)}), - vol.Schema({vol.Required(CONF_MULTIPLY): vol.Coerce(float)}), - vol.Schema({vol.Required(CONF_FILTER_OUT): vol.Coerce(float)}), - vol.Schema({vol.Required(CONF_FILTER_NAN): None}), - vol.Schema({ - vol.Required(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.Schema({ - vol.Required(CONF_WINDOW_SIZE): cv.positive_not_null_int, - vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int, - }) - }), - vol.Schema({ - vol.Required(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({ - vol.Required(CONF_ALPHA): cv.positive_float, - vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int, - }) - }), - vol.Schema({vol.Required(CONF_LAMBDA): cv.string_strict}), - vol.Schema({vol.Required(CONF_THROTTLE): cv.positive_time_period_milliseconds}), - vol.Schema({vol.Required(CONF_DELTA): vol.Coerce(float)}), - vol.Schema({vol.Required(CONF_UNIQUE): None}), - vol.Schema({vol.Required(CONF_HEARTBEAT): cv.positive_time_period_milliseconds}), - vol.Schema({vol.Required(CONF_DEBOUNCE): cv.positive_time_period_milliseconds}), - vol.Schema({vol.Required(CONF_OR): validate_recursive_filter}), -)]) +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] -MQTT_SENSOR_SCHEMA = vol.Schema({ +FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({ + vol.Optional(CONF_OFFSET): vol.Coerce(float), + vol.Optional(CONF_MULTIPLY): vol.Coerce(float), + vol.Optional(CONF_FILTER_OUT): vol.Coerce(float), + vol.Optional(CONF_FILTER_NAN): None, + vol.Optional(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.Schema({ + vol.Required(CONF_WINDOW_SIZE): cv.positive_not_null_int, + vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int, + }), + vol.Optional(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({ + vol.Required(CONF_ALPHA): cv.positive_float, + vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int, + }), + vol.Optional(CONF_LAMBDA): cv.lambda_, + vol.Optional(CONF_THROTTLE): cv.positive_time_period_milliseconds, + vol.Optional(CONF_DELTA): vol.Coerce(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_at_exactly_one_key(*FILTER_KEYS))]) + +SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({ + cv.GenerateID('mqtt_sensor', CONF_MQTT_ID): cv.register_variable_id, + cv.GenerateID('sensor'): cv.register_variable_id, vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string_strict, vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ACCURACY_DECIMALS): vol.Coerce(int), vol.Optional(CONF_EXPIRE_AFTER): vol.Any(None, cv.positive_time_period_milliseconds), - vol.Optional(CONF_FILTERS): FILTERS_SCHEMA -}) - -MQTT_SENSOR_ID_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ - cv.GenerateID('mqtt_sensor', CONF_MQTT_ID): cv.register_variable_id, + vol.Optional(CONF_FILTERS): FILTERS_SCHEMA, + vol.Optional(CONF_ON_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), + vol.Optional(CONF_ON_RAW_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), + vol.Optional(CONF_ON_VALUE_RANGE): vol.All(cv.ensure_list, [vol.All( + automation.AUTOMATION_SCHEMA.extend({ + vol.Optional(CONF_MIN): vol.Coerce(float), + vol.Optional(CONF_MAX): vol.Coerce(float), + }), cv.has_at_least_one_key(CONF_MIN, CONF_MAX))]), }) # pylint: disable=invalid-name -OffsetFilter = MockObj('new sensor::OffsetFilter') -MultiplyFilter = MockObj('new sensor::MultiplyFilter') -FilterOutValueFilter = MockObj('new sensor::FilterOutValueFilter') -FilterOutNANFilter = MockObj('new sensor::FilterOutNANFilter') -SlidingWindowMovingAverageFilter = MockObj('new sensor::SlidingWindowMovingAverageFilter') -ExponentialMovingAverageFilter = MockObj('new sensor::ExponentialMovingAverageFilter') -LambdaFilter = MockObj('new sensor::LambdaFilter') -ThrottleFilter = MockObj('new sensor::ThrottleFilter') -DeltaFilter = MockObj('new sensor::DeltaFilter') -OrFilter = MockObj('new sensor::OrFilter') -HeartbeatFilter = MockObj('new sensor::HeartbeatFilter') -DebounceFilter = MockObj('new sensor::DebounceFilter') -UniqueFilter = MockObj('new sensor::UniqueFilter') +sensor_ns = esphomelib_ns.namespace('sensor') +Sensor = sensor_ns.Sensor +MQTTSensorComponent = sensor_ns.MQTTSensorComponent +OffsetFilter = sensor_ns.OffsetFilter +MultiplyFilter = sensor_ns.MultiplyFilter +FilterOutValueFilter = sensor_ns.FilterOutValueFilter +FilterOutNANFilter = sensor_ns.FilterOutNANFilter +SlidingWindowMovingAverageFilter = sensor_ns.SlidingWindowMovingAverageFilter +ExponentialMovingAverageFilter = sensor_ns.ExponentialMovingAverageFilter +LambdaFilter = sensor_ns.LambdaFilter +ThrottleFilter = sensor_ns.ThrottleFilter +DeltaFilter = sensor_ns.DeltaFilter +OrFilter = sensor_ns.OrFilter +HeartbeatFilter = sensor_ns.HeartbeatFilter +DebounceFilter = sensor_ns.DebounceFilter +UniqueFilter = sensor_ns.UniqueFilter + +SensorValueTrigger = sensor_ns.SensorValueTrigger +RawSensorValueTrigger = sensor_ns.RawSensorValueTrigger +ValueRangeTrigger = sensor_ns.ValueRangeTrigger def setup_filter(config): if CONF_OFFSET in config: - return OffsetFilter(config[CONF_OFFSET]) + return OffsetFilter.new(config[CONF_OFFSET]) if CONF_MULTIPLY in config: - return MultiplyFilter(config[CONF_MULTIPLY]) + return MultiplyFilter.new(config[CONF_MULTIPLY]) if CONF_FILTER_OUT in config: - return FilterOutValueFilter(config[CONF_FILTER_OUT]) + return FilterOutValueFilter.new(config[CONF_FILTER_OUT]) if CONF_FILTER_NAN in config: return FilterOutNANFilter() if CONF_SLIDING_WINDOW_MOVING_AVERAGE in config: conf = config[CONF_SLIDING_WINDOW_MOVING_AVERAGE] - return SlidingWindowMovingAverageFilter(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY]) + return SlidingWindowMovingAverageFilter.new(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY]) if CONF_EXPONENTIAL_MOVING_AVERAGE in config: conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE] - return ExponentialMovingAverageFilter(conf[CONF_ALPHA], conf[CONF_SEND_EVERY]) + return ExponentialMovingAverageFilter.new(conf[CONF_ALPHA], conf[CONF_SEND_EVERY]) if CONF_LAMBDA in config: - s = u'[](float x) -> Optional {{ return {}; }}'.format(config[CONF_LAMBDA]) - return LambdaFilter(RawExpression(s)) + return LambdaFilter.new(process_lambda(config[CONF_LAMBDA], [(float_, 'x')])) if CONF_THROTTLE in config: - return ThrottleFilter(config[CONF_THROTTLE]) + return ThrottleFilter.new(config[CONF_THROTTLE]) if CONF_DELTA in config: - return DeltaFilter(config[CONF_DELTA]) + return DeltaFilter.new(config[CONF_DELTA]) if CONF_OR in config: - return OrFilter(setup_filters(config[CONF_OR])) + return OrFilter.new(setup_filters(config[CONF_OR])) if CONF_HEARTBEAT in config: - return App.register_component(HeartbeatFilter(config[CONF_HEARTBEAT])) + return App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT])) if CONF_DEBOUNCE in config: - return App.register_component(DebounceFilter(config[CONF_DEBOUNCE])) + return App.register_component(DebounceFilter.new(config[CONF_DEBOUNCE])) if CONF_UNIQUE in config: - return UniqueFilter() + return UniqueFilter.new() raise ValueError(u"Filter unsupported: {}".format(config)) @@ -110,31 +123,54 @@ def setup_filters(config): return ArrayInitializer(*[setup_filter(x) for x in config]) -def setup_mqtt_sensor_component(obj, config): +def setup_sensor_core_(sensor_var, mqtt_var, config): + if CONF_UNIT_OF_MEASUREMENT in config: + add(sensor_var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) + if CONF_ICON in config: + add(sensor_var.set_icon(config[CONF_ICON])) + if CONF_ACCURACY_DECIMALS in config: + add(sensor_var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS])) + if CONF_FILTERS in config: + add(sensor_var.set_filters(setup_filters(config[CONF_FILTERS]))) + + for conf in config.get(CONF_ON_VALUE, []): + rhs = sensor_var.make_value_trigger() + trigger = Pvariable(SensorValueTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, float_, conf) + for conf in config.get(CONF_ON_RAW_VALUE, []): + rhs = sensor_var.make_raw_value_trigger() + trigger = Pvariable(RawSensorValueTrigger, conf[CONF_TRIGGER_ID], rhs) + automation.build_automation(trigger, float_, conf) + for conf in config.get(CONF_ON_VALUE_RANGE, []): + rhs = sensor_var.make_value_range_trigger() + trigger = Pvariable(ValueRangeTrigger, conf[CONF_TRIGGER_ID], rhs) + if CONF_MIN in conf: + trigger.set_min(templatable(conf[CONF_MIN], float_, float_)) + if CONF_MAX in conf: + trigger.set_max(templatable(conf[CONF_MAX], float_, float_)) + automation.build_automation(trigger, float_, conf) + if CONF_EXPIRE_AFTER in config: if config[CONF_EXPIRE_AFTER] is None: - add(obj.disable_expire_after()) + add(mqtt_var.disable_expire_after()) else: - add(obj.set_expire_after(config[CONF_EXPIRE_AFTER])) - setup_mqtt_component(obj, config) + add(mqtt_var.set_expire_after(config[CONF_EXPIRE_AFTER])) + setup_mqtt_component(mqtt_var, config) -def setup_sensor(obj, config): - if CONF_UNIT_OF_MEASUREMENT in config: - add(obj.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) - if CONF_ICON in config: - add(obj.set_icon(config[CONF_ICON])) - if CONF_ACCURACY_DECIMALS in config: - add(obj.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS])) - if CONF_FILTERS in config: - add(obj.set_filters(setup_filters(config[CONF_FILTERS]))) +def setup_sensor(sensor_obj, mqtt_obj, config): + sensor_var = Pvariable(Sensor, config[CONF_ID], sensor_obj, has_side_effects=False) + mqtt_var = Pvariable(MQTTSensorComponent, config[CONF_MQTT_ID], mqtt_obj, + has_side_effects=False) + setup_sensor_core_(sensor_var, mqtt_var, config) def register_sensor(var, config): - setup_sensor(var, config) - rhs = App.register_sensor(var) - mqtt_sensor = Pvariable('sensor::MQTTSensorComponent', config[CONF_MQTT_ID], rhs) - setup_mqtt_sensor_component(mqtt_sensor, config) + sensor_var = Pvariable(Sensor, config[CONF_ID], var, has_side_effects=True) + rhs = App.register_sensor(sensor_var) + mqtt_var = Pvariable(MQTTSensorComponent, config[CONF_MQTT_ID], rhs, + has_side_effects=True) + setup_sensor_core_(sensor_var, mqtt_var, config) BUILD_FLAGS = '-DUSE_SENSOR' diff --git a/esphomeyaml/components/sensor/adc.py b/esphomeyaml/components/sensor/adc.py index 7aa02426e3..0cfdae36c0 100644 --- a/esphomeyaml/components/sensor/adc.py +++ b/esphomeyaml/components/sensor/adc.py @@ -3,37 +3,35 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_ATTENUATION, CONF_ID, CONF_NAME, CONF_PIN, \ +from esphomeyaml.const import CONF_ATTENUATION, CONF_MAKE_ID, CONF_NAME, CONF_PIN, \ CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, RawExpression, add, variable +from esphomeyaml.helpers import App, Application, add, global_ns, variable ATTENUATION_MODES = { - '0db': 'ADC_0db', - '2.5db': 'ADC_2_5db', - '6db': 'ADC_6db', - '11db': 'ADC_11db', + '0db': global_ns.ADC_0db, + '2.5db': global_ns.ADC_2_5db, + '6db': global_ns.ADC_6db, + '11db': global_ns.ADC_11db, } -ATTENUATION_MODE_SCHEMA = vol.Any(*list(ATTENUATION_MODES.keys())) - PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('adc'): cv.register_variable_id, + cv.GenerateID('adc', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_PIN): pins.analog_pin, - vol.Optional(CONF_ATTENUATION): vol.All(cv.only_on_esp32, ATTENUATION_MODE_SCHEMA), + vol.Optional(CONF_ATTENUATION): vol.All(cv.only_on_esp32, cv.one_of(*ATTENUATION_MODES)), vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeADCSensor = Application.MakeADCSensor def to_code(config): rhs = App.make_adc_sensor(config[CONF_NAME], config[CONF_PIN], config.get(CONF_UPDATE_INTERVAL)) - make = variable('Application::MakeADCSensor', config[CONF_ID], rhs) + make = variable(MakeADCSensor, config[CONF_MAKE_ID], rhs) adc = make.Padc if CONF_ATTENUATION in config: - attenuation = ATTENUATION_MODES[config[CONF_ATTENUATION]] - add(adc.set_attenuation(RawExpression(attenuation))) - sensor.setup_sensor(adc, config) - sensor.setup_mqtt_sensor_component(make.Pmqtt, config) + add(adc.set_attenuation(ATTENUATION_MODES[config[CONF_ATTENUATION]])) + sensor.setup_sensor(make.Padc, make.Pmqtt, config) BUILD_FLAGS = '-DUSE_ADC_SENSOR' diff --git a/esphomeyaml/components/sensor/ads1115.py b/esphomeyaml/components/sensor/ads1115.py index ffcdca1687..be649f12d8 100644 --- a/esphomeyaml/components/sensor/ads1115.py +++ b/esphomeyaml/components/sensor/ads1115.py @@ -2,30 +2,31 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_UPDATE_INTERVAL, \ - CONF_NAME, CONF_ID -from esphomeyaml.helpers import RawExpression, get_variable, Pvariable +from esphomeyaml.components.ads1115 import ADS1115Component +from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_NAME, \ + CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import get_variable DEPENDENCIES = ['ads1115'] MUX = { - 'A0_A1': 'sensor::ADS1115_MULTIPLEXER_P0_N1', - 'A0_A3': 'sensor::ADS1115_MULTIPLEXER_P0_N3', - 'A1_A3': 'sensor::ADS1115_MULTIPLEXER_P1_N3', - 'A2_A3': 'sensor::ADS1115_MULTIPLEXER_P2_N3', - 'A0_GND': 'sensor::ADS1115_MULTIPLEXER_P0_NG', - 'A1_GND': 'sensor::ADS1115_MULTIPLEXER_P1_NG', - 'A2_GND': 'sensor::ADS1115_MULTIPLEXER_P2_NG', - 'A3_GND': 'sensor::ADS1115_MULTIPLEXER_P3_NG', + 'A0_A1': sensor.sensor_ns.ADS1115_MULTIPLEXER_P0_N1, + 'A0_A3': sensor.sensor_ns.ADS1115_MULTIPLEXER_P0_N3, + 'A1_A3': sensor.sensor_ns.ADS1115_MULTIPLEXER_P1_N3, + 'A2_A3': sensor.sensor_ns.ADS1115_MULTIPLEXER_P2_N3, + 'A0_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P0_NG, + 'A1_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P1_NG, + 'A2_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P2_NG, + 'A3_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P3_NG, } GAIN = { - '6.144': 'sensor::ADS1115_GAIN_6P144', - '4.096': 'sensor::ADS1115_GAIN_6P096', - '2.048': 'sensor::ADS1115_GAIN_2P048', - '1.024': 'sensor::ADS1115_GAIN_1P024', - '0.512': 'sensor::ADS1115_GAIN_0P512', - '0.256': 'sensor::ADS1115_GAIN_0P256', + '6.144': sensor.sensor_ns.ADS1115_GAIN_6P144, + '4.096': sensor.sensor_ns.ADS1115_GAIN_6P096, + '2.048': sensor.sensor_ns.ADS1115_GAIN_2P048, + '1.024': sensor.sensor_ns.ADS1115_GAIN_1P024, + '0.512': sensor.sensor_ns.ADS1115_GAIN_0P512, + '0.256': sensor.sensor_ns.ADS1115_GAIN_0P256, } @@ -42,21 +43,20 @@ def validate_gain(value): PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ cv.GenerateID('ads1115_sensor'): cv.register_variable_id, - vol.Required(CONF_MULTIPLEXER): vol.All(vol.Upper, vol.Any(*list(MUX.keys()))), + vol.Required(CONF_MULTIPLEXER): vol.All(vol.Upper, cv.one_of(*MUX)), vol.Required(CONF_GAIN): validate_gain, vol.Optional(CONF_ADS1115_ID): cv.variable_id, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}).extend(sensor.MQTT_SENSOR_ID_SCHEMA.schema) +}).extend(sensor.SENSOR_SCHEMA.schema) def to_code(config): - hub = get_variable(config.get(CONF_ADS1115_ID), u'sensor::ADS1115Component') + hub = get_variable(config.get(CONF_ADS1115_ID), ADS1115Component) - mux = RawExpression(MUX[config[CONF_MULTIPLEXER]]) - gain = RawExpression(GAIN[config[CONF_GAIN]]) + mux = MUX[config[CONF_MULTIPLEXER]] + gain = GAIN[config[CONF_GAIN]] rhs = hub.get_sensor(config[CONF_NAME], mux, gain, config.get(CONF_UPDATE_INTERVAL)) - sensor_ = Pvariable('sensor::ADS1115Sensor', config[CONF_ID], rhs) - sensor.register_sensor(sensor_, config) + sensor.register_sensor(rhs, config) BUILD_FLAGS = '-DUSE_ADS1115_SENSOR' diff --git a/esphomeyaml/components/sensor/bh1750.py b/esphomeyaml/components/sensor/bh1750.py index bed6a7803e..d119ebdbe6 100644 --- a/esphomeyaml/components/sensor/bh1750.py +++ b/esphomeyaml/components/sensor/bh1750.py @@ -2,36 +2,36 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_NAME, CONF_RESOLUTION, \ +from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_RESOLUTION, \ CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, RawExpression, add, variable +from esphomeyaml.helpers import App, Application, add, variable DEPENDENCIES = ['i2c'] BH1750_RESOLUTIONS = { - 4.0: 'sensor::BH1750_RESOLUTION_4P0_LX', - 1.0: 'sensor::BH1750_RESOLUTION_1P0_LX', - 0.5: 'sensor::BH1750_RESOLUTION_0P5_LX', + 4.0: sensor.sensor_ns.BH1750_RESOLUTION_4P0_LX, + 1.0: sensor.sensor_ns.BH1750_RESOLUTION_1P0_LX, + 0.5: sensor.sensor_ns.BH1750_RESOLUTION_0P5_LX, } PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('bh1750_sensor'): cv.register_variable_id, + cv.GenerateID('bh1750_sensor', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_ADDRESS, default=0x23): cv.i2c_address, - vol.Optional(CONF_RESOLUTION): vol.All(cv.positive_float, vol.Any(*BH1750_RESOLUTIONS)), + vol.Optional(CONF_RESOLUTION): vol.All(cv.positive_float, cv.one_of(*BH1750_RESOLUTIONS)), vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeBH1750Sensor = Application.MakeBH1750Sensor def to_code(config): rhs = App.make_bh1750_sensor(config[CONF_NAME], config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL)) - make_bh1750 = variable('Application::MakeBH1750Sensor', config[CONF_ID], rhs) + make_bh1750 = variable(MakeBH1750Sensor, config[CONF_MAKE_ID], rhs) bh1750 = make_bh1750.Pbh1750 if CONF_RESOLUTION in config: - constant = BH1750_RESOLUTIONS[config[CONF_RESOLUTION]] - add(bh1750.set_resolution(RawExpression(constant))) - sensor.setup_sensor(bh1750, config) - sensor.setup_mqtt_sensor_component(make_bh1750.Pmqtt, config) + add(bh1750.set_resolution(BH1750_RESOLUTIONS[config[CONF_RESOLUTION]])) + sensor.setup_sensor(bh1750, make_bh1750.Pmqtt, config) BUILD_FLAGS = '-DUSE_BH1750' diff --git a/esphomeyaml/components/sensor/bme280.py b/esphomeyaml/components/sensor/bme280.py index 86114831fc..3f264aaf27 100644 --- a/esphomeyaml/components/sensor/bme280.py +++ b/esphomeyaml/components/sensor/bme280.py @@ -2,44 +2,45 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_ADDRESS, CONF_HUMIDITY, CONF_ID, CONF_IIR_FILTER, CONF_NAME, \ - CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, RawExpression, add, variable +from esphomeyaml.const import CONF_ADDRESS, CONF_HUMIDITY, CONF_IIR_FILTER, CONF_MAKE_ID, \ + CONF_NAME, CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, Application, add, variable DEPENDENCIES = ['i2c'] OVERSAMPLING_OPTIONS = { - 'NONE': 'sensor::BME280_OVERSAMPLING_NONE', - '1X': 'sensor::BME280_OVERSAMPLING_1X', - '2X': 'sensor::BME280_OVERSAMPLING_2X', - '4X': 'sensor::BME280_OVERSAMPLING_4X', - '8X': 'sensor::BME280_OVERSAMPLING_8X', - '16X': 'sensor::BME280_OVERSAMPLING_16X', + 'NONE': sensor.sensor_ns.BME280_OVERSAMPLING_NONE, + '1X': sensor.sensor_ns.BME280_OVERSAMPLING_1X, + '2X': sensor.sensor_ns.BME280_OVERSAMPLING_2X, + '4X': sensor.sensor_ns.BME280_OVERSAMPLING_4X, + '8X': sensor.sensor_ns.BME280_OVERSAMPLING_8X, + '16X': sensor.sensor_ns.BME280_OVERSAMPLING_16X, } IIR_FILTER_OPTIONS = { - 'OFF': 'sensor::BME280_IIR_FILTER_OFF', - '2X': 'sensor::BME280_IIR_FILTER_2X', - '4X': 'sensor::BME280_IIR_FILTER_4X', - '8X': 'sensor::BME280_IIR_FILTER_8X', - '16X': 'sensor::BME280_IIR_FILTER_16X', + 'OFF': sensor.sensor_ns.BME280_IIR_FILTER_OFF, + '2X': sensor.sensor_ns.BME280_IIR_FILTER_2X, + '4X': sensor.sensor_ns.BME280_IIR_FILTER_4X, + '8X': sensor.sensor_ns.BME280_IIR_FILTER_8X, + '16X': sensor.sensor_ns.BME280_IIR_FILTER_16X, } -BME280_OVERSAMPLING_SENSOR_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ - vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, vol.Any(*OVERSAMPLING_OPTIONS)), +BME280_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({ + vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)), }) PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('bme280'): cv.register_variable_id, + cv.GenerateID('bme280', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address, vol.Required(CONF_TEMPERATURE): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): BME280_OVERSAMPLING_SENSOR_SCHEMA, - vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, vol.Any(*IIR_FILTER_OPTIONS)), + vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, cv.one_of(*IIR_FILTER_OPTIONS)), vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeBME280Sensor = Application.MakeBME280Sensor + def to_code(config): rhs = App.make_bme280_sensor(config[CONF_TEMPERATURE][CONF_NAME], @@ -47,29 +48,27 @@ def to_code(config): config[CONF_HUMIDITY][CONF_NAME], config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL)) - make = variable('Application::MakeBME280Sensor', config[CONF_ID], rhs) + make = variable(MakeBME280Sensor, config[CONF_MAKE_ID], rhs) bme280 = make.Pbme280 if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]: constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]] - add(bme280.set_temperature_oversampling(RawExpression(constant))) + add(bme280.set_temperature_oversampling(constant)) if CONF_OVERSAMPLING in config[CONF_PRESSURE]: constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]] - add(bme280.set_pressure_oversampling(RawExpression(constant))) + add(bme280.set_pressure_oversampling(constant)) if CONF_OVERSAMPLING in config[CONF_HUMIDITY]: constant = OVERSAMPLING_OPTIONS[config[CONF_HUMIDITY][CONF_OVERSAMPLING]] - add(bme280.set_humidity_oversampling(RawExpression(constant))) + add(bme280.set_humidity_oversampling(constant)) if CONF_IIR_FILTER in config: constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]] - add(bme280.set_iir_filter(RawExpression(constant))) + add(bme280.set_iir_filter(constant)) - sensor.setup_sensor(bme280.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_temperature, config[CONF_TEMPERATURE]) - - sensor.setup_sensor(bme280.Pget_pressure_sensor(), config[CONF_PRESSURE]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_pressure, config[CONF_PRESSURE]) - - sensor.setup_sensor(bme280.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_humidity, config[CONF_HUMIDITY]) + sensor.setup_sensor(bme280.Pget_temperature_sensor(), make.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(bme280.Pget_pressure_sensor(), make.Pmqtt_pressure, + config[CONF_PRESSURE]) + sensor.setup_sensor(bme280.Pget_humidity_sensor(), make.Pmqtt_humidity, + config[CONF_HUMIDITY]) BUILD_FLAGS = '-DUSE_BME280' diff --git a/esphomeyaml/components/sensor/bme680.py b/esphomeyaml/components/sensor/bme680.py index c1dae08783..d717c8a4af 100644 --- a/esphomeyaml/components/sensor/bme680.py +++ b/esphomeyaml/components/sensor/bme680.py @@ -2,49 +2,51 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_ADDRESS, CONF_HUMIDITY, CONF_ID, CONF_IIR_FILTER, CONF_NAME, \ - CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, CONF_GAS_RESISTANCE -from esphomeyaml.helpers import App, RawExpression, add, variable +from esphomeyaml.const import CONF_ADDRESS, CONF_GAS_RESISTANCE, CONF_HUMIDITY, CONF_IIR_FILTER, \ + CONF_MAKE_ID, CONF_NAME, CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, \ + CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, Application, add, variable DEPENDENCIES = ['i2c'] OVERSAMPLING_OPTIONS = { - 'NONE': 'sensor::BME680_OVERSAMPLING_NONE', - '1X': 'sensor::BME680_OVERSAMPLING_1X', - '2X': 'sensor::BME680_OVERSAMPLING_2X', - '4X': 'sensor::BME680_OVERSAMPLING_4X', - '8X': 'sensor::BME680_OVERSAMPLING_8X', - '16X': 'sensor::BME680_OVERSAMPLING_16X', + 'NONE': sensor.sensor_ns.BME680_OVERSAMPLING_NONE, + '1X': sensor.sensor_ns.BME680_OVERSAMPLING_1X, + '2X': sensor.sensor_ns.BME680_OVERSAMPLING_2X, + '4X': sensor.sensor_ns.BME680_OVERSAMPLING_4X, + '8X': sensor.sensor_ns.BME680_OVERSAMPLING_8X, + '16X': sensor.sensor_ns.BME680_OVERSAMPLING_16X, } IIR_FILTER_OPTIONS = { - 'OFF': 'sensor::BME680_IIR_FILTER_OFF', - '1X': 'sensor::BME680_IIR_FILTER_1X', - '3X': 'sensor::BME680_IIR_FILTER_3X', - '7X': 'sensor::BME680_IIR_FILTER_7X', - '15X': 'sensor::BME680_IIR_FILTER_15X', - '31X': 'sensor::BME680_IIR_FILTER_31X', - '63X': 'sensor::BME680_IIR_FILTER_63X', - '127X': 'sensor::BME680_IIR_FILTER_127X', + 'OFF': sensor.sensor_ns.BME680_IIR_FILTER_OFF, + '1X': sensor.sensor_ns.BME680_IIR_FILTER_1X, + '3X': sensor.sensor_ns.BME680_IIR_FILTER_3X, + '7X': sensor.sensor_ns.BME680_IIR_FILTER_7X, + '15X': sensor.sensor_ns.BME680_IIR_FILTER_15X, + '31X': sensor.sensor_ns.BME680_IIR_FILTER_31X, + '63X': sensor.sensor_ns.BME680_IIR_FILTER_63X, + '127X': sensor.sensor_ns.BME680_IIR_FILTER_127X, } -BME680_OVERSAMPLING_SENSOR_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ - vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, vol.Any(*OVERSAMPLING_OPTIONS)), +BME680_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({ + vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)), }) PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('bme680'): cv.register_variable_id, + cv.GenerateID('bme680', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_ADDRESS, default=0x76): cv.i2c_address, vol.Required(CONF_TEMPERATURE): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): BME680_OVERSAMPLING_SENSOR_SCHEMA, - vol.Required(CONF_GAS_RESISTANCE): MQTT_SENSOR_SCHEMA, - vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, vol.Any(*IIR_FILTER_OPTIONS)), + vol.Required(CONF_GAS_RESISTANCE): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, cv.one_of(*IIR_FILTER_OPTIONS)), # TODO: Heater vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeBME680Sensor = Application.MakeBME680Sensor + def to_code(config): rhs = App.make_bme680_sensor(config[CONF_TEMPERATURE][CONF_NAME], @@ -53,32 +55,29 @@ def to_code(config): config[CONF_GAS_RESISTANCE][CONF_NAME], config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL)) - make = variable('Application::MakeBME680Sensor', config[CONF_ID], rhs) + make = variable(MakeBME680Sensor, config[CONF_MAKE_ID], rhs) bme680 = make.Pbme680 if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]: constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]] - add(bme680.set_temperature_oversampling(RawExpression(constant))) + add(bme680.set_temperature_oversampling(constant)) if CONF_OVERSAMPLING in config[CONF_PRESSURE]: constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]] - add(bme680.set_pressure_oversampling(RawExpression(constant))) + add(bme680.set_pressure_oversampling(constant)) if CONF_OVERSAMPLING in config[CONF_HUMIDITY]: constant = OVERSAMPLING_OPTIONS[config[CONF_HUMIDITY][CONF_OVERSAMPLING]] - add(bme680.set_humidity_oversampling(RawExpression(constant))) + add(bme680.set_humidity_oversampling(constant)) if CONF_IIR_FILTER in config: constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]] - add(bme680.set_iir_filter(RawExpression(constant))) + add(bme680.set_iir_filter(constant)) - sensor.setup_sensor(bme680.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_temperature, config[CONF_TEMPERATURE]) - - sensor.setup_sensor(bme680.Pget_pressure_sensor(), config[CONF_PRESSURE]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_pressure, config[CONF_PRESSURE]) - - sensor.setup_sensor(bme680.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_humidity, config[CONF_HUMIDITY]) - - sensor.setup_sensor(bme680.Pget_gas_resistance_sensor(), config[CONF_GAS_RESISTANCE]) - sensor.setup_mqtt_sensor_component(make.Pmqtt_gas_resistance, config[CONF_GAS_RESISTANCE]) + sensor.setup_sensor(bme680.Pget_temperature_sensor(), make.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(bme680.Pget_pressure_sensor(), make.Pmqtt_pressure, + config[CONF_PRESSURE]) + sensor.setup_sensor(bme680.Pget_humidity_sensor(), make.Pmqtt_humidity, + config[CONF_HUMIDITY]) + sensor.setup_sensor(bme680.Pget_gas_resistance_sensor(), make.Pmqtt_gas_resistance, + config[CONF_GAS_RESISTANCE]) BUILD_FLAGS = '-DUSE_BME680' diff --git a/esphomeyaml/components/sensor/bmp085.py b/esphomeyaml/components/sensor/bmp085.py index 5f6c47ccbe..4d63b6b941 100644 --- a/esphomeyaml/components/sensor/bmp085.py +++ b/esphomeyaml/components/sensor/bmp085.py @@ -2,33 +2,35 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_NAME, \ - CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, HexIntLiteral, add, variable +from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_PRESSURE, \ + CONF_TEMPERATURE, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, HexIntLiteral, add, variable, Application DEPENDENCIES = ['i2c'] PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('bmp085_sensor'): cv.register_variable_id, - vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, - vol.Required(CONF_PRESSURE): MQTT_SENSOR_SCHEMA, + cv.GenerateID('bmp085_sensor', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, + vol.Required(CONF_PRESSURE): sensor.SENSOR_SCHEMA, vol.Optional(CONF_ADDRESS): cv.i2c_address, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeBMP085Sensor = Application.MakeBMP085Sensor + def to_code(config): rhs = App.make_bmp085_sensor(config[CONF_TEMPERATURE][CONF_NAME], config[CONF_PRESSURE][CONF_NAME], config.get(CONF_UPDATE_INTERVAL)) - bmp = variable('Application::MakeBMP085Sensor', config[CONF_ID], rhs) + bmp = variable(MakeBMP085Sensor, config[CONF_MAKE_ID], rhs) if CONF_ADDRESS in config: add(bmp.Pbmp.set_address(HexIntLiteral(config[CONF_ADDRESS]))) - sensor.setup_sensor(bmp.Pbmp.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(bmp.Pmqtt_temperature, config[CONF_TEMPERATURE]) - sensor.setup_sensor(bmp.Pbmp.Pget_pressure_sensor(), config[CONF_PRESSURE]) - sensor.setup_mqtt_sensor_component(bmp.Pmqtt_pressure, config[CONF_PRESSURE]) + + sensor.setup_sensor(bmp.Pbmp.Pget_temperature_sensor(), bmp.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(bmp.Pbmp.Pget_pressure_sensor(), bmp.Pmqtt_pressure, + config[CONF_PRESSURE]) BUILD_FLAGS = '-DUSE_BMP085_SENSOR' diff --git a/esphomeyaml/components/sensor/dallas.py b/esphomeyaml/components/sensor/dallas.py index 2be1e2b80b..d770ee6ec1 100644 --- a/esphomeyaml/components/sensor/dallas.py +++ b/esphomeyaml/components/sensor/dallas.py @@ -2,23 +2,21 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.dallas import DALLAS_COMPONENT_CLASS +from esphomeyaml.components.dallas import DallasComponent from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \ - CONF_RESOLUTION, \ - CONF_UPDATE_INTERVAL, CONF_ID -from esphomeyaml.helpers import HexIntLiteral, get_variable, Pvariable + CONF_RESOLUTION, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import HexIntLiteral, get_variable PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('dallas_sensor'): cv.register_variable_id, vol.Exclusive(CONF_ADDRESS, 'dallas'): cv.hex_int, vol.Exclusive(CONF_INDEX, 'dallas'): cv.positive_int, vol.Optional(CONF_DALLAS_ID): cv.variable_id, vol.Optional(CONF_RESOLUTION): vol.All(vol.Coerce(int), vol.Range(min=8, max=12)), -}).extend(sensor.MQTT_SENSOR_ID_SCHEMA.schema), cv.has_at_least_one_key(CONF_ADDRESS, CONF_INDEX)) +}).extend(sensor.SENSOR_SCHEMA.schema), cv.has_at_least_one_key(CONF_ADDRESS, CONF_INDEX)) def to_code(config): - hub = get_variable(config.get(CONF_DALLAS_ID), DALLAS_COMPONENT_CLASS) + hub = get_variable(config.get(CONF_DALLAS_ID), DallasComponent) update_interval = config.get(CONF_UPDATE_INTERVAL) if CONF_RESOLUTION in config and update_interval is None: update_interval = 10000 @@ -30,8 +28,7 @@ def to_code(config): else: rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX], update_interval, config.get(CONF_RESOLUTION)) - sensor_ = Pvariable('sensor::DallasTemperatureSensor', config[CONF_ID], rhs) - sensor.register_sensor(sensor_, config) + sensor.register_sensor(rhs, config) BUILD_FLAGS = '-DUSE_DALLAS_SENSOR' diff --git a/esphomeyaml/components/sensor/dht.py b/esphomeyaml/components/sensor/dht.py index 54edae5e72..0b3b28f622 100644 --- a/esphomeyaml/components/sensor/dht.py +++ b/esphomeyaml/components/sensor/dht.py @@ -2,43 +2,45 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_MODEL, CONF_NAME, CONF_PIN, \ +from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_MODEL, CONF_NAME, CONF_PIN, \ CONF_TEMPERATURE, CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, RawExpression, add, variable, gpio_output_pin_expression +from esphomeyaml.helpers import App, Application, add, gpio_output_pin_expression, variable from esphomeyaml.pins import GPIO_OUTPUT_PIN_SCHEMA DHT_MODELS = { - 'AUTO_DETECT': 'sensor::DHT_MODEL_AUTO_DETECT', - 'DHT11': 'sensor::DHT_MODEL_DHT11', - 'DHT22': 'sensor::DHT_MODEL_DHT22', - 'AM2302': 'sensor::DHT_MODEL_AM2302', - 'RHT03': 'sensor::DHT_MODEL_RHT03', + 'AUTO_DETECT': sensor.sensor_ns.DHT_MODEL_AUTO_DETECT, + 'DHT11': sensor.sensor_ns.DHT_MODEL_DHT11, + 'DHT22': sensor.sensor_ns.DHT_MODEL_DHT22, + 'AM2302': sensor.sensor_ns.DHT_MODEL_AM2302, + 'RHT03': sensor.sensor_ns.DHT_MODEL_RHT03, } PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('dht_sensor'): cv.register_variable_id, + cv.GenerateID('dht_sensor', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_PIN): GPIO_OUTPUT_PIN_SCHEMA, - vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, - vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, - vol.Optional(CONF_MODEL): vol.All(vol.Upper, vol.Any(*DHT_MODELS)), + vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, + vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_MODEL): vol.All(vol.Upper, cv.one_of(*DHT_MODELS)), vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeDHTSensor = Application.MakeDHTSensor + def to_code(config): pin = gpio_output_pin_expression(config[CONF_PIN]) rhs = App.make_dht_sensor(config[CONF_TEMPERATURE][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME], pin, config.get(CONF_UPDATE_INTERVAL)) - dht = variable('Application::MakeDHTSensor', config[CONF_ID], rhs) + dht = variable(MakeDHTSensor, config[CONF_MAKE_ID], rhs) if CONF_MODEL in config: constant = DHT_MODELS[config[CONF_MODEL]] - add(dht.Pdht.set_dht_model(RawExpression(constant))) - sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(dht.Pmqtt_temperature, config[CONF_TEMPERATURE]) - sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(dht.Pmqtt_humidity, config[CONF_HUMIDITY]) + add(dht.Pdht.set_dht_model(constant)) + + sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), + dht.Pmqtt_temperature, config[CONF_TEMPERATURE]) + sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), + dht.Pmqtt_humidity, config[CONF_HUMIDITY]) BUILD_FLAGS = '-DUSE_DHT_SENSOR' diff --git a/esphomeyaml/components/sensor/dht12.py b/esphomeyaml/components/sensor/dht12.py index d440e3a42b..c74a6f73a1 100644 --- a/esphomeyaml/components/sensor/dht12.py +++ b/esphomeyaml/components/sensor/dht12.py @@ -2,30 +2,32 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_NAME, CONF_TEMPERATURE, \ +from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \ CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, variable +from esphomeyaml.helpers import App, Application, variable DEPENDENCIES = ['i2c'] PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('dht_sensor'): cv.register_variable_id, - vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, - vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, + cv.GenerateID('dht_sensor', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, + vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeDHT12Sensor = Application.MakeDHT12Sensor + def to_code(config): rhs = App.make_dht12_sensor(config[CONF_TEMPERATURE][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME], config.get(CONF_UPDATE_INTERVAL)) - dht = variable('Application::MakeDHT12Sensor', config[CONF_ID], rhs) - sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(dht.Pmqtt_temperature, config[CONF_TEMPERATURE]) - sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(dht.Pmqtt_humidity, config[CONF_HUMIDITY]) + dht = variable(MakeDHT12Sensor, config[CONF_MAKE_ID], rhs) + + sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), dht.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), dht.Pmqtt_humidity, + config[CONF_HUMIDITY]) BUILD_FLAGS = '-DUSE_DHT12_SENSOR' diff --git a/esphomeyaml/components/sensor/hdc1080.py b/esphomeyaml/components/sensor/hdc1080.py index 25112b1cf4..94a9dd6d1d 100644 --- a/esphomeyaml/components/sensor/hdc1080.py +++ b/esphomeyaml/components/sensor/hdc1080.py @@ -2,30 +2,32 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_NAME, CONF_TEMPERATURE, \ +from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \ CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, variable +from esphomeyaml.helpers import App, variable, Application DEPENDENCIES = ['i2c'] PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('dht_sensor'): cv.register_variable_id, - vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, - vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, + cv.GenerateID('hdc1080_sensor', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, + vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeHDC1080Sensor = Application.MakeHDC1080Sensor + def to_code(config): rhs = App.make_hdc1080_sensor(config[CONF_TEMPERATURE][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME], config.get(CONF_UPDATE_INTERVAL)) - hdc1080 = variable('Application::MakeHDC1080Sensor', config[CONF_ID], rhs) - sensor.setup_sensor(hdc1080.Phdc1080.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(hdc1080.Pmqtt_temperature, config[CONF_TEMPERATURE]) - sensor.setup_sensor(hdc1080.Phdc1080.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(hdc1080.Pmqtt_humidity, config[CONF_HUMIDITY]) + hdc1080 = variable(MakeHDC1080Sensor, config[CONF_MAKE_ID], rhs) + + sensor.setup_sensor(hdc1080.Phdc1080.Pget_temperature_sensor(), hdc1080.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(hdc1080.Phdc1080.Pget_humidity_sensor(), hdc1080.Pmqtt_humidity, + config[CONF_HUMIDITY]) BUILD_FLAGS = '-DUSE_HDC1080_SENSOR' diff --git a/esphomeyaml/components/sensor/htu21d.py b/esphomeyaml/components/sensor/htu21d.py index aa7d2e639f..fb8a49a804 100644 --- a/esphomeyaml/components/sensor/htu21d.py +++ b/esphomeyaml/components/sensor/htu21d.py @@ -2,30 +2,31 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_NAME, CONF_TEMPERATURE, \ +from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \ CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, variable +from esphomeyaml.helpers import App, variable, Application DEPENDENCIES = ['i2c'] PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('htu21d'): cv.register_variable_id, - vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, - vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, + cv.GenerateID('htu21d', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, + vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeHTU21DSensor = Application.MakeHTU21DSensor + def to_code(config): rhs = App.make_htu21d_sensor(config[CONF_TEMPERATURE][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME], config.get(CONF_UPDATE_INTERVAL)) - htu21d = variable('Application::MakeHTU21DSensor', config[CONF_ID], rhs) - sensor.setup_sensor(htu21d.Phtu21d.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(htu21d.Pmqtt_temperature, config[CONF_TEMPERATURE]) - sensor.setup_sensor(htu21d.Phtu21d.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(htu21d.Pmqtt_humidity, config[CONF_HUMIDITY]) + htu21d = variable(MakeHTU21DSensor, config[CONF_MAKE_ID], rhs) + sensor.setup_sensor(htu21d.Phtu21d.Pget_temperature_sensor(), htu21d.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(htu21d.Phtu21d.Pget_humidity_sensor(), htu21d.Pmqtt_humidity, + config[CONF_HUMIDITY]) BUILD_FLAGS = '-DUSE_HTU21D_SENSOR' diff --git a/esphomeyaml/components/sensor/max6675.py b/esphomeyaml/components/sensor/max6675.py new file mode 100644 index 0000000000..de0d3e9374 --- /dev/null +++ b/esphomeyaml/components/sensor/max6675.py @@ -0,0 +1,32 @@ +import voluptuous as vol + +import esphomeyaml.config_validation as cv +from esphomeyaml import pins +from esphomeyaml.components import sensor +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN_CLOCK, CONF_PIN_CS, CONF_PIN_MISO, \ + CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, \ + gpio_output_pin_expression, variable + +PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ + cv.GenerateID('max6675', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_PIN_CS): pins.GPIO_OUTPUT_PIN_SCHEMA, + vol.Required(CONF_PIN_CLOCK): pins.GPIO_OUTPUT_PIN_SCHEMA, + vol.Optional(CONF_PIN_MISO): pins.GPIO_INPUT_PIN_SCHEMA, + vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeMAX6675Sensor = Application.MakeMAX6675Sensor + + +def to_code(config): + pin_cs = gpio_output_pin_expression(config[CONF_PIN_CS]) + pin_clock = gpio_output_pin_expression(config[CONF_PIN_CLOCK]) + pin_miso = gpio_input_pin_expression(config[CONF_PIN_MISO]) + rhs = App.make_max6675_sensor(config[CONF_NAME], pin_cs, pin_clock, pin_miso, + config.get(CONF_UPDATE_INTERVAL)) + make = variable(MakeMAX6675Sensor, config[CONF_MAKE_ID], rhs) + sensor.setup_sensor(make.Pmax6675, make.Pmqtt, config) + + +BUILD_FLAGS = '-DUSE_MAX6675_SENSOR' diff --git a/esphomeyaml/components/sensor/mpu6050.py b/esphomeyaml/components/sensor/mpu6050.py index f936a1b2fe..0d7ee16599 100644 --- a/esphomeyaml/components/sensor/mpu6050.py +++ b/esphomeyaml/components/sensor/mpu6050.py @@ -2,8 +2,8 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_ID_SCHEMA -from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_MQTT_ID, CONF_NAME, CONF_TEMPERATURE, \ +from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_MQTT_ID, CONF_NAME, \ + CONF_TEMPERATURE, \ CONF_UPDATE_INTERVAL from esphomeyaml.helpers import App, Pvariable @@ -16,57 +16,63 @@ CONF_GYRO_X = 'gyro_x' CONF_GYRO_Y = 'gyro_y' CONF_GYRO_Z = 'gyro_z' -PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('mpu6050'): cv.register_variable_id, +PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({ + cv.GenerateID('mpu6050', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_ADDRESS, default=0x68): cv.i2c_address, - vol.Optional(CONF_ACCEL_X): MQTT_SENSOR_ID_SCHEMA, - vol.Optional(CONF_ACCEL_Y): MQTT_SENSOR_ID_SCHEMA, - vol.Optional(CONF_ACCEL_Z): MQTT_SENSOR_ID_SCHEMA, - vol.Optional(CONF_GYRO_X): MQTT_SENSOR_ID_SCHEMA, - vol.Optional(CONF_GYRO_Y): MQTT_SENSOR_ID_SCHEMA, - vol.Optional(CONF_GYRO_Z): MQTT_SENSOR_ID_SCHEMA, - vol.Optional(CONF_TEMPERATURE): MQTT_SENSOR_ID_SCHEMA, + vol.Optional(CONF_ACCEL_X): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_ACCEL_Y): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_ACCEL_Z): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_GYRO_X): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_GYRO_Y): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_GYRO_Z): sensor.SENSOR_SCHEMA, + vol.Optional(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}) +}), cv.has_at_least_one_key(CONF_ACCEL_X, CONF_ACCEL_Y, CONF_ACCEL_Z, + CONF_GYRO_X, CONF_GYRO_Y, CONF_GYRO_Z)) + +MPU6050Component = sensor.sensor_ns.MPU6050Component +MPU6050AccelSensor = sensor.sensor_ns.MPU6050AccelSensor +MPU6050GyroSensor = sensor.sensor_ns.MPU6050GyroSensor +MPU6050TemperatureSensor = sensor.sensor_ns.MPU6050TemperatureSensor def to_code(config): rhs = App.make_mpu6050_sensor(config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL)) - mpu = Pvariable('sensor::MPU6050Component', config[CONF_ID], rhs) + mpu = Pvariable(MPU6050Component, config[CONF_MAKE_ID], rhs) if CONF_ACCEL_X in config: conf = config[CONF_ACCEL_X] rhs = mpu.Pmake_accel_x_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050AccelSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050AccelSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) if CONF_ACCEL_Y in config: conf = config[CONF_ACCEL_Y] rhs = mpu.Pmake_accel_y_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050AccelSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050AccelSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) if CONF_ACCEL_Z in config: conf = config[CONF_ACCEL_Z] rhs = mpu.Pmake_accel_z_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050AccelSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050AccelSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) if CONF_GYRO_X in config: conf = config[CONF_GYRO_X] rhs = mpu.Pmake_gyro_x_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050GyroSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050GyroSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) if CONF_GYRO_Y in config: conf = config[CONF_GYRO_Y] rhs = mpu.Pmake_gyro_y_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050GyroSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050GyroSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) if CONF_GYRO_Z in config: conf = config[CONF_GYRO_Z] rhs = mpu.Pmake_gyro_z_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050GyroSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050GyroSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) if CONF_TEMPERATURE in config: conf = config[CONF_TEMPERATURE] rhs = mpu.Pmake_temperature_sensor(conf[CONF_NAME]) - sensor_ = Pvariable('sensor::MPU6050TemperatureSensor', conf[CONF_MQTT_ID], rhs) + sensor_ = Pvariable(MPU6050TemperatureSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(sensor_, conf) diff --git a/esphomeyaml/components/sensor/pulse_counter.py b/esphomeyaml/components/sensor/pulse_counter.py index 86736fdc78..93eb12acca 100644 --- a/esphomeyaml/components/sensor/pulse_counter.py +++ b/esphomeyaml/components/sensor/pulse_counter.py @@ -3,32 +3,32 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_ID, CONF_INTERNAL_FILTER, \ - CONF_NAME, CONF_PIN, CONF_PULL_MODE, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, \ +from esphomeyaml.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_INTERNAL_FILTER, \ + CONF_MAKE_ID, CONF_NAME, CONF_PIN, CONF_PULL_MODE, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, \ ESP_PLATFORM_ESP32 -from esphomeyaml.helpers import App, RawExpression, add, variable +from esphomeyaml.helpers import App, add, global_ns, variable, Application ESP_PLATFORMS = [ESP_PLATFORM_ESP32] GPIO_PULL_MODES = { - 'PULLUP': 'GPIO_PULLUP_ONLY', - 'PULLDOWN': 'GPIO_PULLDOWN_ONLY', - 'PULLUP_PULLDOWN': 'GPIO_PULLUP_PULLDOWN', - 'FLOATING': 'GPIO_FLOATING', + 'PULLUP': global_ns.GPIO_PULLUP_ONLY, + 'PULLDOWN': global_ns.GPIO_PULLDOWN_ONLY, + 'PULLUP_PULLDOWN': global_ns.GPIO_PULLUP_PULLDOWN, + 'FLOATING': global_ns.GPIO_FLOATING, } -GPIO_PULL_MODE_SCHEMA = vol.All(vol.Upper, vol.Any(*list(GPIO_PULL_MODES.keys()))) +GPIO_PULL_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*GPIO_PULL_MODES)) COUNT_MODES = { - 'DISABLE': 'PCNT_COUNT_DIS', - 'INCREMENT': 'PCNT_COUNT_INC', - 'DECREMENT': 'PCNT_COUNT_DEC', + 'DISABLE': global_ns.PCNT_COUNT_DIS, + 'INCREMENT': global_ns.PCNT_COUNT_INC, + 'DECREMENT': global_ns.PCNT_COUNT_DEC, } -COUNT_MODE_SCHEMA = vol.All(vol.Upper, vol.Any(*list(COUNT_MODES.keys()))) +COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(COUNT_MODES)) PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('pulse_counter'): cv.register_variable_id, + cv.GenerateID('pulse_counter', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_PIN): pins.input_pin, vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA, vol.Optional(CONF_COUNT_MODE): vol.Schema({ @@ -37,26 +37,27 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ }), vol.Optional(CONF_INTERNAL_FILTER): vol.All(vol.Coerce(int), vol.Range(min=0, max=1023)), vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakePulseCounterSensor = Application.MakePulseCounterSensor def to_code(config): rhs = App.make_pulse_counter_sensor(config[CONF_NAME], config[CONF_PIN], config.get(CONF_UPDATE_INTERVAL)) - make = variable('Application::MakePulseCounterSensor', config[CONF_ID], rhs) + make = variable(MakePulseCounterSensor, config[CONF_MAKE_ID], rhs) pcnt = make.Ppcnt if CONF_PULL_MODE in config: pull_mode = GPIO_PULL_MODES[config[CONF_PULL_MODE]] - add(pcnt.set_pull_mode(RawExpression(pull_mode))) + add(pcnt.set_pull_mode(pull_mode)) if CONF_COUNT_MODE in config: count_mode = config[CONF_COUNT_MODE] rising_edge = COUNT_MODES[count_mode[CONF_RISING_EDGE]] falling_edge = COUNT_MODES[count_mode[CONF_FALLING_EDGE]] - add(pcnt.set_edge_mode(RawExpression(rising_edge), RawExpression(falling_edge))) + add(pcnt.set_edge_mode(rising_edge, falling_edge)) if CONF_INTERNAL_FILTER in config: add(pcnt.set_filter(config[CONF_INTERNAL_FILTER])) - sensor.setup_sensor(pcnt, config) - sensor.setup_mqtt_sensor_component(make.Pmqtt, config) + sensor.setup_sensor(make.Ppcnt, make.Pmqtt, config) BUILD_FLAGS = '-DUSE_PULSE_COUNTER_SENSOR' diff --git a/esphomeyaml/components/sensor/rotary_encoder.py b/esphomeyaml/components/sensor/rotary_encoder.py index c470da5cdd..dbdef902ec 100644 --- a/esphomeyaml/components/sensor/rotary_encoder.py +++ b/esphomeyaml/components/sensor/rotary_encoder.py @@ -3,13 +3,13 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_RESOLUTION -from esphomeyaml.helpers import App, RawExpression, add, gpio_input_pin_expression, variable +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_RESOLUTION +from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, variable RESOLUTIONS = { - '1': 'sensor::ROTARY_ENCODER_1_PULSE_PER_CYCLE', - '2': 'sensor::ROTARY_ENCODER_2_PULSES_PER_CYCLE', - '4': 'sensor::ROTARY_ENCODER_4_PULSES_PER_CYCLE', + '1': sensor.sensor_ns.ROTARY_ENCODER_1_PULSE_PER_CYCLE, + '2': sensor.sensor_ns.ROTARY_ENCODER_2_PULSES_PER_CYCLE, + '4': sensor.sensor_ns.ROTARY_ENCODER_4_PULSES_PER_CYCLE, } CONF_PIN_A = 'pin_a' @@ -17,28 +17,29 @@ CONF_PIN_B = 'pin_b' CONF_PIN_RESET = 'pin_reset' PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('rotary_encoder'): cv.register_variable_id, + cv.GenerateID('rotary_encoder', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_PIN_A): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Required(CONF_PIN_B): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Optional(CONF_PIN_RESET): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, - vol.Optional(CONF_RESOLUTION): vol.All(cv.string, vol.Any(*RESOLUTIONS)), -}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) + vol.Optional(CONF_RESOLUTION): vol.All(cv.string, cv.one_of(*RESOLUTIONS)), +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeRotaryEncoderSensor = Application.MakeRotaryEncoderSensor def to_code(config): pin_a = gpio_input_pin_expression(config[CONF_PIN_A]) pin_b = gpio_input_pin_expression(config[CONF_PIN_B]) rhs = App.make_rotary_encoder_sensor(config[CONF_NAME], pin_a, pin_b) - make = variable('Application::MakeRotaryEncoderSensor', config[CONF_ID], rhs) + make = variable(MakeRotaryEncoderSensor, config[CONF_MAKE_ID], rhs) encoder = make.Protary_encoder if CONF_PIN_RESET in config: pin_i = gpio_input_pin_expression(config[CONF_PIN_RESET]) add(encoder.set_reset_pin(pin_i)) if CONF_RESOLUTION in config: resolution = RESOLUTIONS[config[CONF_RESOLUTION]] - add(encoder.set_resolution(RawExpression(resolution))) - sensor.setup_sensor(encoder, config) - sensor.setup_mqtt_sensor_component(make.Pmqtt, config) + add(encoder.set_resolution(resolution)) + sensor.setup_sensor(encoder, make.Pmqtt, config) BUILD_FLAGS = '-DUSE_ROTARY_ENCODER_SENSOR' diff --git a/esphomeyaml/components/sensor/sht3xd.py b/esphomeyaml/components/sensor/sht3xd.py index a996e39dcb..3c87770dd5 100644 --- a/esphomeyaml/components/sensor/sht3xd.py +++ b/esphomeyaml/components/sensor/sht3xd.py @@ -2,44 +2,43 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA -from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_NAME, CONF_TEMPERATURE, \ - CONF_UPDATE_INTERVAL, CONF_ADDRESS, CONF_ACCURACY -from esphomeyaml.helpers import App, variable, RawExpression, add +from esphomeyaml.const import CONF_ACCURACY, CONF_ADDRESS, CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, \ + CONF_TEMPERATURE, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, Application, add, variable DEPENDENCIES = ['i2c'] SHT_ACCURACIES = { - 'LOW': 'sensor::SHT3XD_ACCURACY_LOW', - 'MEDIUM': 'sensor::SHT3XD_ACCURACY_MEDIUM', - 'HIGH': 'sensor::SHT3XD_ACCURACY_HIGH', + 'LOW': sensor.sensor_ns.SHT3XD_ACCURACY_LOW, + 'MEDIUM': sensor.sensor_ns.SHT3XD_ACCURACY_MEDIUM, + 'HIGH': sensor.sensor_ns.SHT3XD_ACCURACY_HIGH, } PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('sht3xd'): cv.register_variable_id, - vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, - vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, + cv.GenerateID('sht3xd', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, + vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address, - vol.Optional(CONF_ACCURACY): vol.All(vol.Upper, vol.Any(*SHT_ACCURACIES)), + vol.Optional(CONF_ACCURACY): vol.All(vol.Upper, cv.one_of(*SHT_ACCURACIES)), vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, }) +MakeSHT3XDSensor = Application.MakeSHT3XDSensor + def to_code(config): rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME], config.get(CONF_UPDATE_INTERVAL)) - sht3xd = variable('Application::MakeSHT3XDSensor', config[CONF_ID], rhs) + sht3xd = variable(MakeSHT3XDSensor, config[CONF_MAKE_ID], rhs) if CONF_ACCURACY in config: - constant = RawExpression(SHT_ACCURACIES[config[CONF_ACCURACY]]) - add(sht3xd.Psht3xd.set_accuracy(constant)) + add(sht3xd.Psht3xd.set_accuracy(SHT_ACCURACIES[config[CONF_ACCURACY]])) - sensor.setup_sensor(sht3xd.Psht3xd.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) - sensor.setup_mqtt_sensor_component(sht3xd.Pmqtt_temperature, config[CONF_TEMPERATURE]) - - sensor.setup_sensor(sht3xd.PPsht3xd.Pget_humidity_sensor(), config[CONF_HUMIDITY]) - sensor.setup_mqtt_sensor_component(sht3xd.Pmqtt_humidity, config[CONF_HUMIDITY]) + sensor.setup_sensor(sht3xd.Psht3xd.Pget_temperature_sensor(), sht3xd.Pmqtt_temperature, + config[CONF_TEMPERATURE]) + sensor.setup_sensor(sht3xd.Psht3xd.Pget_humidity_sensor(), sht3xd.Pmqtt_humidity, + config[CONF_HUMIDITY]) BUILD_FLAGS = '-DUSE_SHT3XD' diff --git a/esphomeyaml/components/sensor/template.py b/esphomeyaml/components/sensor/template.py new file mode 100644 index 0000000000..6fd20d96c4 --- /dev/null +++ b/esphomeyaml/components/sensor/template.py @@ -0,0 +1,25 @@ +import voluptuous as vol + +import esphomeyaml.config_validation as cv +from esphomeyaml.components import sensor +from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, process_lambda, variable, Application + +PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ + cv.GenerateID('template_sensor', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_LAMBDA): cv.lambda_, + vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeTemplateSensor = Application.MakeTemplateSensor + + +def to_code(config): + template_ = process_lambda(config[CONF_LAMBDA], []) + rhs = App.make_template_sensor(config[CONF_NAME], template_, + config.get(CONF_UPDATE_INTERVAL)) + make = variable(MakeTemplateSensor, config[CONF_MAKE_ID], rhs) + sensor.setup_sensor(make.Ptemplate_, make.Pmqtt, config) + + +BUILD_FLAGS = '-DUSE_TEMPLATE_SENSOR' diff --git a/esphomeyaml/components/sensor/tsl2561.py b/esphomeyaml/components/sensor/tsl2561.py index 4445f043a4..72c8804763 100644 --- a/esphomeyaml/components/sensor/tsl2561.py +++ b/esphomeyaml/components/sensor/tsl2561.py @@ -2,20 +2,20 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_ADDRESS, CONF_GAIN, CONF_ID, CONF_INTEGRATION_TIME, CONF_NAME, \ - CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, RawExpression, add, variable +from esphomeyaml.const import CONF_ADDRESS, CONF_GAIN, CONF_INTEGRATION_TIME, CONF_MAKE_ID, \ + CONF_NAME, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, Application, add, variable DEPENDENCIES = ['i2c'] INTEGRATION_TIMES = { - 14: 'sensor::TSL2561_INTEGRATION_14MS', - 101: 'sensor::TSL2561_INTEGRATION_101MS', - 402: 'sensor::TSL2561_INTEGRATION_402MS', + 14: sensor.sensor_ns.TSL2561_INTEGRATION_14MS, + 101: sensor.sensor_ns.TSL2561_INTEGRATION_101MS, + 402: sensor.sensor_ns.TSL2561_INTEGRATION_402MS, } GAINS = { - '1X': 'sensor::TSL2561_GAIN_1X', - '16X': 'sensor::TSL2561_GAIN_16X', + '1X': sensor.sensor_ns.TSL2561_GAIN_1X, + '16X': sensor.sensor_ns.TSL2561_GAIN_16X, } CONF_IS_CS_PACKAGE = 'is_cs_package' @@ -29,30 +29,29 @@ def validate_integration_time(value): PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('tsl2561_sensor'): cv.register_variable_id, + cv.GenerateID('tsl2561_sensor', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_ADDRESS, default=0x39): cv.i2c_address, vol.Optional(CONF_INTEGRATION_TIME): validate_integration_time, - vol.Optional(CONF_GAIN): vol.All(vol.Upper, vol.Any(*GAINS)), + vol.Optional(CONF_GAIN): vol.All(vol.Upper, cv.one_of(*GAINS)), vol.Optional(CONF_IS_CS_PACKAGE): cv.boolean, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeTSL2561Sensor = Application.MakeTSL2561Sensor def to_code(config): rhs = App.make_tsl2561_sensor(config[CONF_NAME], config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL)) - make_tsl = variable('Application::MakeTSL2561Sensor', config[CONF_ID], rhs) + make_tsl = variable(MakeTSL2561Sensor, config[CONF_MAKE_ID], rhs) tsl2561 = make_tsl.Ptsl2561 if CONF_INTEGRATION_TIME in config: - constant = INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]] - add(tsl2561.set_integration_time(RawExpression(constant))) + add(tsl2561.set_integration_time(INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]])) if CONF_GAIN in config: - constant = GAINS[config[CONF_GAIN]] - add(tsl2561.set_gain(RawExpression(constant))) + add(tsl2561.set_gain(GAINS[config[CONF_GAIN]])) if CONF_IS_CS_PACKAGE in config: add(tsl2561.set_is_cs_package(config[CONF_IS_CS_PACKAGE])) - sensor.setup_sensor(tsl2561, config) - sensor.setup_mqtt_sensor_component(make_tsl.Pmqtt, config) + sensor.setup_sensor(tsl2561, make_tsl.Pmqtt, config) BUILD_FLAGS = '-DUSE_TSL2561' diff --git a/esphomeyaml/components/sensor/ultrasonic.py b/esphomeyaml/components/sensor/ultrasonic.py index 3ea86fb0d8..2cde3af027 100644 --- a/esphomeyaml/components/sensor/ultrasonic.py +++ b/esphomeyaml/components/sensor/ultrasonic.py @@ -3,19 +3,21 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import sensor -from esphomeyaml.const import CONF_ECHO_PIN, CONF_ID, CONF_NAME, \ - CONF_TIMEOUT_METER, CONF_TIMEOUT_TIME, CONF_TRIGGER_PIN, CONF_UPDATE_INTERVAL -from esphomeyaml.helpers import App, add, variable, gpio_output_pin_expression, \ - gpio_input_pin_expression +from esphomeyaml.const import CONF_ECHO_PIN, CONF_MAKE_ID, CONF_NAME, CONF_TIMEOUT_METER, \ + CONF_TIMEOUT_TIME, CONF_TRIGGER_PIN, CONF_UPDATE_INTERVAL +from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, \ + gpio_output_pin_expression, variable PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ - cv.GenerateID('ultrasonic'): cv.register_variable_id, + cv.GenerateID('ultrasonic', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_TRIGGER_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_ECHO_PIN): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Exclusive(CONF_TIMEOUT_METER, 'timeout'): cv.positive_float, vol.Exclusive(CONF_TIMEOUT_TIME, 'timeout'): cv.positive_time_period_microseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, -}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) +}).extend(sensor.SENSOR_SCHEMA.schema) + +MakeUltrasonicSensor = Application.MakeUltrasonicSensor def to_code(config): @@ -23,14 +25,13 @@ def to_code(config): echo = gpio_input_pin_expression(config[CONF_ECHO_PIN]) rhs = App.make_ultrasonic_sensor(config[CONF_NAME], trigger, echo, config.get(CONF_UPDATE_INTERVAL)) - make = variable('Application::MakeUltrasonicSensor', config[CONF_ID], rhs) + make = variable(MakeUltrasonicSensor, config[CONF_MAKE_ID], rhs) ultrasonic = make.Pultrasonic if CONF_TIMEOUT_TIME in config: add(ultrasonic.set_timeout_us(config[CONF_TIMEOUT_TIME])) elif CONF_TIMEOUT_METER in config: add(ultrasonic.set_timeout_m(config[CONF_TIMEOUT_METER])) - sensor.setup_sensor(ultrasonic, config) - sensor.setup_mqtt_sensor_component(make.Pmqtt, config) + sensor.setup_sensor(ultrasonic, make.Pmqtt, config) BUILD_FLAGS = '-DUSE_ULTRASONIC_SENSOR' diff --git a/esphomeyaml/components/switch/__init__.py b/esphomeyaml/components/switch/__init__.py index 447c3dde42..04871c3243 100644 --- a/esphomeyaml/components/switch/__init__.py +++ b/esphomeyaml/components/switch/__init__.py @@ -1,39 +1,50 @@ import voluptuous as vol import esphomeyaml.config_validation as cv -from esphomeyaml.const import CONF_ICON, CONF_INVERTED, CONF_MQTT_ID -from esphomeyaml.helpers import App, Pvariable, add, setup_mqtt_component +from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_INVERTED, CONF_MQTT_ID +from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, setup_mqtt_component PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ }) -MQTT_SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ +SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ + cv.GenerateID('switch_'): cv.register_variable_id, + cv.GenerateID('mqtt_switch', CONF_MQTT_ID): cv.register_variable_id, vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_INVERTED): cv.boolean, }) -MQTT_SWITCH_ID_SCHEMA = MQTT_SWITCH_SCHEMA.extend({ - cv.GenerateID('mqtt_switch', CONF_MQTT_ID): cv.register_variable_id, -}) +switch_ns = esphomelib_ns.namespace('switch_') +Switch = switch_ns.Switch +MQTTSwitchComponent = switch_ns.MQTTSwitchComponent +ToggleAction = switch_ns.ToggleAction +TurnOffAction = switch_ns.TurnOffAction +TurnOnAction = switch_ns.TurnOnAction -def setup_mqtt_switch(obj, config): - setup_mqtt_component(obj, config) - - -def setup_switch(obj, config): +def setup_switch_core_(switch_var, mqtt_var, config): if CONF_ICON in config: - add(obj.set_icon(config[CONF_ICON])) + add(switch_var.set_icon(config[CONF_ICON])) if CONF_INVERTED in config: - add(obj.set_inverted(config[CONF_INVERTED])) + add(switch_var.set_inverted(config[CONF_INVERTED])) + + setup_mqtt_component(mqtt_var, config) + + +def setup_switch(switch_obj, mqtt_obj, config): + switch_var = Pvariable(Switch, config[CONF_ID], switch_obj, has_side_effects=False) + mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], mqtt_obj, + has_side_effects=False) + setup_switch_core_(switch_var, mqtt_var, config) def register_switch(var, config): - setup_switch(var, config) - rhs = App.register_switch(var) - mqtt_switch = Pvariable('switch_::MQTTSwitchComponent', config[CONF_MQTT_ID], rhs) - setup_mqtt_switch(mqtt_switch, config) + switch_var = Pvariable(Switch, config[CONF_ID], var, has_side_effects=True) + rhs = App.register_switch(switch_var) + mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], rhs, + has_side_effects=True) + setup_switch_core_(switch_var, mqtt_var, config) BUILD_FLAGS = '-DUSE_SWITCH' diff --git a/esphomeyaml/components/switch/gpio.py b/esphomeyaml/components/switch/gpio.py index cddd13b9ff..11cee63870 100644 --- a/esphomeyaml/components/switch/gpio.py +++ b/esphomeyaml/components/switch/gpio.py @@ -3,20 +3,21 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import pins from esphomeyaml.components import switch -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_PIN -from esphomeyaml.helpers import App, variable, gpio_output_pin_expression +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN +from esphomeyaml.helpers import App, Application, gpio_output_pin_expression, variable PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ - cv.GenerateID('gpio_switch'): cv.register_variable_id, + cv.GenerateID('gpio_switch', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, -}).extend(switch.MQTT_SWITCH_SCHEMA.schema) +}).extend(switch.SWITCH_SCHEMA.schema) + +MakeGPIOSwitch = Application.MakeGPIOSwitch def to_code(config): rhs = App.make_gpio_switch(config[CONF_NAME], gpio_output_pin_expression(config[CONF_PIN])) - gpio = variable('Application::MakeGPIOSwitch', config[CONF_ID], rhs) - switch.setup_switch(gpio.Pswitch_, config) - switch.setup_mqtt_switch(gpio.Pmqtt, config) + gpio = variable(MakeGPIOSwitch, config[CONF_MAKE_ID], rhs) + switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config) BUILD_FLAGS = '-DUSE_GPIO_SWITCH' diff --git a/esphomeyaml/components/switch/ir_transmitter.py b/esphomeyaml/components/switch/ir_transmitter.py index ac35498bce..0b9c21f04a 100644 --- a/esphomeyaml/components/switch/ir_transmitter.py +++ b/esphomeyaml/components/switch/ir_transmitter.py @@ -2,12 +2,13 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import switch -from esphomeyaml.components.ir_transmitter import IR_TRANSMITTER_COMPONENT_CLASS +from esphomeyaml.components.ir_transmitter import IRTransmitterComponent from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_COMMAND, CONF_DATA, \ - CONF_ID, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, CONF_PANASONIC, \ - CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME, CONF_INVERTED + CONF_ID, CONF_INVERTED, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \ + CONF_PANASONIC, CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME from esphomeyaml.core import ESPHomeYAMLError -from esphomeyaml.helpers import ArrayInitializer, HexIntLiteral, MockObj, Pvariable, get_variable +from esphomeyaml.helpers import App, ArrayInitializer, HexIntLiteral, Pvariable, \ + get_variable DEPENDENCIES = ['ir_transmitter'] @@ -46,10 +47,12 @@ PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({ })), vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id, vol.Optional(CONF_INVERTED): cv.invalid("IR Transmitters do not support inverted mode!"), -}).extend(switch.MQTT_SWITCH_ID_SCHEMA.schema), cv.has_at_least_one_key(*IR_KEYS)) +}).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_least_one_key(*IR_KEYS)) # pylint: disable=invalid-name -SendData = MockObj('switch_::ir::SendData', '::') +ir_ns = switch.switch_ns.namespace('ir') +SendData = ir_ns.namespace('SendData') +DataTransmitter = IRTransmitterComponent.DataTransmitter def safe_hex(value): @@ -87,17 +90,15 @@ def exp_send_data(config): else: times = config[CONF_REPEAT][CONF_TIMES] wait_us = config[CONF_REPEAT][CONF_WAIT_TIME] - base = MockObj(unicode(base), u'.') base = base.repeat(times, wait_us) return base def to_code(config): - ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IR_TRANSMITTER_COMPONENT_CLASS) + ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IRTransmitterComponent) send_data = exp_send_data(config) - rhs = ir.create_transmitter(config[CONF_NAME], send_data) - switch_ = Pvariable(IR_TRANSMITTER_COMPONENT_CLASS + '::DataTransmitter', config[CONF_ID], - rhs) + rhs = App.register_component(ir.create_transmitter(config[CONF_NAME], send_data)) + switch_ = Pvariable(DataTransmitter, config[CONF_ID], rhs) switch.register_switch(switch_, config) diff --git a/esphomeyaml/components/switch/output.py b/esphomeyaml/components/switch/output.py index 89832e4ae4..c4e4785b0f 100644 --- a/esphomeyaml/components/switch/output.py +++ b/esphomeyaml/components/switch/output.py @@ -2,21 +2,22 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import switch -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_OUTPUT -from esphomeyaml.helpers import App, get_variable, variable +from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT +from esphomeyaml.helpers import App, Application, get_variable, variable PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ - cv.GenerateID('output_switch'): cv.register_variable_id, + cv.GenerateID('output_switch', CONF_MAKE_ID): cv.register_variable_id, vol.Required(CONF_OUTPUT): cv.variable_id, -}).extend(switch.MQTT_SWITCH_SCHEMA.schema) +}).extend(switch.SWITCH_SCHEMA.schema) + +MakeSimpleSwitch = Application.MakeSimpleSwitch def to_code(config): output = get_variable(config[CONF_OUTPUT]) rhs = App.make_simple_switch(config[CONF_NAME], output) - gpio = variable('Application::MakeSimpleSwitch', config[CONF_ID], rhs) - switch.setup_switch(gpio.Pswitch_, config) - switch.setup_mqtt_switch(gpio.Pmqtt, config) + gpio = variable(MakeSimpleSwitch, config[CONF_MAKE_ID], rhs) + switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config) BUILD_FLAGS = '-DUSE_SIMPLE_SWITCH' diff --git a/esphomeyaml/components/switch/restart.py b/esphomeyaml/components/switch/restart.py index 1eab632881..fd97face66 100644 --- a/esphomeyaml/components/switch/restart.py +++ b/esphomeyaml/components/switch/restart.py @@ -2,20 +2,21 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import switch -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_INVERTED -from esphomeyaml.helpers import App, variable +from esphomeyaml.const import CONF_INVERTED, CONF_MAKE_ID, CONF_NAME +from esphomeyaml.helpers import App, Application, variable PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ - cv.GenerateID('restart_switch'): cv.register_variable_id, + cv.GenerateID('restart_switch', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_INVERTED): cv.invalid("Restart switches do not support inverted mode!"), -}).extend(switch.MQTT_SWITCH_SCHEMA.schema) +}).extend(switch.SWITCH_SCHEMA.schema) + +MakeRestartSwitch = Application.MakeRestartSwitch def to_code(config): rhs = App.make_restart_switch(config[CONF_NAME]) - restart = variable('Application::MakeRestartSwitch', config[CONF_ID], rhs) - switch.setup_switch(restart.Prestart, config) - switch.setup_mqtt_switch(restart.Pmqtt, config) + restart = variable(MakeRestartSwitch, config[CONF_MAKE_ID], rhs) + switch.setup_switch(restart.Prestart, restart.Pmqtt, config) BUILD_FLAGS = '-DUSE_RESTART_SWITCH' diff --git a/esphomeyaml/components/switch/shutdown.py b/esphomeyaml/components/switch/shutdown.py index e3b3f2641c..46517c3b2b 100644 --- a/esphomeyaml/components/switch/shutdown.py +++ b/esphomeyaml/components/switch/shutdown.py @@ -2,21 +2,21 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml.components import switch -from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_INVERTED -from esphomeyaml.helpers import App, variable +from esphomeyaml.const import CONF_INVERTED, CONF_MAKE_ID, CONF_NAME +from esphomeyaml.helpers import App, Application, variable PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ - cv.GenerateID('shutdown_switch'): cv.register_variable_id, + cv.GenerateID('shutdown_switch', CONF_MAKE_ID): cv.register_variable_id, vol.Optional(CONF_INVERTED): cv.invalid("Shutdown switches do not support inverted mode!"), -}).extend(switch.MQTT_SWITCH_SCHEMA.schema) +}).extend(switch.SWITCH_SCHEMA.schema) + +MakeShutdownSwitch = Application.MakeShutdownSwitch def to_code(config): rhs = App.make_shutdown_switch(config[CONF_NAME]) - shutdown = variable('Application::MakeShutdownSwitch', config[CONF_ID], - rhs) - switch.setup_switch(shutdown.Pshutdown, config) - switch.setup_mqtt_switch(shutdown.Pmqtt, config) + shutdown = variable(MakeShutdownSwitch, config[CONF_MAKE_ID], rhs) + switch.setup_switch(shutdown.Pshutdown, shutdown.Pmqtt, config) BUILD_FLAGS = '-DUSE_SHUTDOWN_SWITCH' diff --git a/esphomeyaml/components/switch/template.py b/esphomeyaml/components/switch/template.py new file mode 100644 index 0000000000..8c30e4b271 --- /dev/null +++ b/esphomeyaml/components/switch/template.py @@ -0,0 +1,35 @@ +import voluptuous as vol + +import esphomeyaml.config_validation as cv +from esphomeyaml import automation +from esphomeyaml.components import switch +from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_TURN_OFF_ACTION, \ + CONF_TURN_ON_ACTION +from esphomeyaml.helpers import App, Application, process_lambda, variable, NoArg, add + +PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ + cv.GenerateID('template_switch', CONF_MAKE_ID): cv.register_variable_id, + vol.Required(CONF_LAMBDA): cv.lambda_, + vol.Optional(CONF_TURN_OFF_ACTION): automation.ACTIONS_SCHEMA, + vol.Optional(CONF_TURN_ON_ACTION): automation.ACTIONS_SCHEMA, +}).extend(switch.SWITCH_SCHEMA.schema) + +MakeTemplateSwitch = Application.MakeTemplateSwitch + + +def to_code(config): + template_ = process_lambda(config[CONF_LAMBDA], []) + rhs = App.make_template_switch(config[CONF_NAME], template_) + make = variable(MakeTemplateSwitch, config[CONF_MAKE_ID], rhs) + + if CONF_TURN_OFF_ACTION in config: + actions = automation.build_actions(config[CONF_TURN_OFF_ACTION], NoArg) + add(make.Ptemplate_.add_turn_off_actions(actions)) + if CONF_TURN_ON_ACTION in config: + actions = automation.build_actions(config[CONF_TURN_ON_ACTION], NoArg) + add(make.Ptemplate_.add_turn_on_actions(actions)) + + switch.setup_switch(make.Ptemplate_, make.Pmqtt, config) + + +BUILD_FLAGS = '-DUSE_TEMPLATE_SWITCH' diff --git a/esphomeyaml/components/web_server.py b/esphomeyaml/components/web_server.py index 54b1c54fe1..9a6eaef398 100644 --- a/esphomeyaml/components/web_server.py +++ b/esphomeyaml/components/web_server.py @@ -5,7 +5,7 @@ import voluptuous as vol import esphomeyaml.config_validation as cv from esphomeyaml import core from esphomeyaml.const import CONF_PORT, CONF_JS_URL, CONF_CSS_URL, CONF_ID, ESP_PLATFORM_ESP32 -from esphomeyaml.helpers import App, add, Pvariable +from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns _LOGGER = logging.getLogger(__name__) @@ -16,10 +16,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_JS_URL): vol.Url, }) +WebServer = esphomelib_ns.WebServer + def to_code(config): rhs = App.init_web_server(config.get(CONF_PORT)) - web_server = Pvariable('WebServer', config[CONF_ID], rhs) + web_server = Pvariable(WebServer, config[CONF_ID], rhs) if CONF_CSS_URL in config: add(web_server.set_css_url(config[CONF_CSS_URL])) if CONF_JS_URL in config: diff --git a/esphomeyaml/components/wifi.py b/esphomeyaml/components/wifi.py index f58ffcdbb6..c1d09010fe 100644 --- a/esphomeyaml/components/wifi.py +++ b/esphomeyaml/components/wifi.py @@ -5,7 +5,7 @@ from esphomeyaml import core from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_GATEWAY, \ CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, \ ESP_PLATFORM_ESP8266 -from esphomeyaml.helpers import App, MockObj, Pvariable, StructInitializer, add +from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, esphomelib_ns, global_ns def validate_password(value): @@ -45,7 +45,9 @@ CONFIG_SCHEMA = vol.Schema({ }) # pylint: disable=invalid-name -IPAddress = MockObj('IPAddress') +IPAddress = global_ns.IPAddress +ManualIP = esphomelib_ns.ManualIP +WiFiComponent = esphomelib_ns.WiFiComponent def safe_ip(ip): @@ -56,7 +58,7 @@ def safe_ip(ip): def manual_ip(config): return StructInitializer( - 'ManualIP', + ManualIP, ('static_ip', safe_ip(config[CONF_STATIC_IP])), ('gateway', safe_ip(config[CONF_GATEWAY])), ('subnet', safe_ip(config[CONF_SUBNET])), @@ -72,7 +74,7 @@ def to_code(config): rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD)) else: rhs = App.init_wifi() - wifi = Pvariable('WiFiComponent', config[CONF_ID], rhs) + wifi = Pvariable(WiFiComponent, config[CONF_ID], rhs) if sta and CONF_MANUAL_IP in config: add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP]))) diff --git a/esphomeyaml/config.py b/esphomeyaml/config.py index 2ae7be69df..8c503453dc 100644 --- a/esphomeyaml/config.py +++ b/esphomeyaml/config.py @@ -29,7 +29,7 @@ CORE_SCHEMA = vol.Schema({ vol.Optional(CONF_LIBRARY_URI, default=DEFAULT_LIBRARY_URI): cv.string, vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean, vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean, - vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, vol.Any(*BUILD_FLASH_MODES)), + vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)), }) REQUIRED_COMPONENTS = [ @@ -171,6 +171,12 @@ def validate_config(config): if not success: continue + esp_platforms = getattr(platform, 'ESP_PLATFORMS', ESP_PLATFORMS) + if core.ESP_PLATFORM not in esp_platforms: + result.add_error( + u"Platform {}.{} doesn't support {}.".format(domain, p_name, core.ESP_PLATFORM)) + continue + if hasattr(platform, u'PLATFORM_SCHEMA'): try: p_validated = platform.PLATFORM_SCHEMA(p_config) diff --git a/esphomeyaml/config_validation.py b/esphomeyaml/config_validation.py index 455a5e125b..d036391b14 100644 --- a/esphomeyaml/config_validation.py +++ b/esphomeyaml/config_validation.py @@ -12,8 +12,8 @@ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOV CONF_NAME, CONF_PAYLOAD_AVAILABLE, \ CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \ ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 -from esphomeyaml.core import HexInt, IPAddress, TimePeriod, TimePeriodMilliseconds, \ - TimePeriodMicroseconds, TimePeriodSeconds +from esphomeyaml.core import HexInt, IPAddress, TimePeriod, TimePeriodMicroseconds, \ + TimePeriodMilliseconds, TimePeriodSeconds, Lambda from esphomeyaml.helpers import ensure_unique_string _LOGGER = logging.getLogger(__name__) @@ -134,7 +134,7 @@ def int_(value): hex_int = vol.Coerce(hex_int_) -match_cpp_var_ = vol.Match(r'^[a-zA-Z_][a-zA-Z0-9_]+$', msg=u"Must be a valid C++ variable name") +match_cpp_var_ = vol.Match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', msg=u"Must be a valid C++ variable name") def variable_id(value): @@ -144,6 +144,14 @@ def variable_id(value): return value +def templatable(other_validators): + def validator(value): + if isinstance(value, Lambda): + return value + return other_validators(value) + return validator + + def only_on(platforms): if not isinstance(platforms, list): platforms = [platforms] @@ -170,10 +178,24 @@ def has_at_least_one_key(*keys): if not isinstance(obj, dict): raise vol.Invalid('expected dictionary') - for k in obj.keys(): - if k in keys: - return obj - raise vol.Invalid('must contain one of {}.'.format(', '.join(keys))) + if not any(k in keys for k in obj): + raise vol.Invalid('Must contain at least one of {}.'.format(', '.join(keys))) + return obj + + return validate + + +def has_at_exactly_one_key(*keys): + def validate(obj): + if not isinstance(obj, dict): + raise vol.Invalid('expected dictionary') + + number = sum(k in keys for k in obj) + if number > 1: + raise vol.Invalid("Cannot specify more than one of {}.".format(', '.join(keys))) + if number < 1: + raise vol.Invalid('Must contain exactly one of {}.'.format(', '.join(keys))) + return obj return validate @@ -410,6 +432,14 @@ def mqtt_payload(value): return string(value) +def mqtt_qos(value): + try: + value = int(value) + except (TypeError, ValueError): + raise vol.Invalid(u"MQTT Quality of Service must be integer, got {}".format(value)) + return one_of(0, 1, 2)(value) + + uint8_t = vol.All(int_, vol.Range(min=0, max=255)) uint16_t = vol.All(int_, vol.Range(min=0, max=65535)) uint32_t = vol.All(int_, vol.Range(min=0, max=4294967295)) @@ -429,6 +459,22 @@ def valid(value): return value +def one_of(*values): + options = u', '.join(u"'{}'".format(x) for x in values) + + def validator(value): + if value not in values: + raise vol.Invalid(u"Unknown value '{}', must be one of {}".format(value, options)) + return value + return validator + + +def lambda_(value): + if isinstance(value, Lambda): + return value + return Lambda(string_strict(value)) + + REGISTERED_IDS = set() diff --git a/esphomeyaml/const.py b/esphomeyaml/const.py index 9aa378c7f3..685019b088 100644 --- a/esphomeyaml/const.py +++ b/esphomeyaml/const.py @@ -34,6 +34,13 @@ CONF_USERNAME = 'username' CONF_POWER_SUPPLY = 'power_supply' CONF_ID = 'id' CONF_MQTT_ID = 'mqtt_id' +CONF_SENSOR_ID = 'sensor_id' +CONF_TRIGGER_ID = 'trigger_id' +CONF_ACTION_ID = 'action_id' +CONF_CONDITION_ID = 'condition_id' +CONF_MAKE_ID = 'make_id' +CONF_AUTOMATION_ID = 'automation_id' +CONF_DELAY = 'delay' CONF_PIN = 'pin' CONF_NUMBER = 'number' CONF_INVERTED = 'inverted' @@ -70,6 +77,15 @@ CONF_TOPIC = 'topic' CONF_PAYLOAD_AVAILABLE = 'payload_available' CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available' CONF_DEFAULT_TRANSITION_LENGTH = 'default_transition_length' +CONF_TRANSITION_LENGTH = 'transition_length' +CONF_FLASH_LENGTH = 'flash_length' +CONF_BRIGHTNESS = 'brightness' +CONF_EFFECT = 'effect' +CONF_MIN = 'min' +CONF_MAX = 'max' +CONF_ON = 'on' +CONF_IF = 'if' +CONF_THEN = 'then' CONF_BINARY = 'binary' CONF_WHITE = 'white' CONF_RGBW = 'rgbw' @@ -112,6 +128,8 @@ CONF_LAMBDA = 'lambda' CONF_THROTTLE = 'throttle' CONF_DELTA = 'delta' CONF_OR = 'or' +CONF_AND = 'and' +CONF_RANGE = 'range' CONF_UNIQUE = 'unique' CONF_HEARTBEAT = 'heartbeat' CONF_DEBOUNCE = 'debounce' @@ -192,6 +210,24 @@ CONF_CLOCK_PIN = 'clock_pin' CONF_RGB_ORDER = 'rgb_order' CONF_ACCURACY = 'accuracy' CONF_BOARD_FLASH_MODE = 'board_flash_mode' +CONF_ON_PRESS = 'on_press' +CONF_ON_RELEASE = 'on_release' +CONF_ON_CLICK = 'on_click' +CONF_ON_DOUBLE_CLICK = 'on_double_click' +CONF_MIN_LENGTH = 'min_length' +CONF_MAX_LENGTH = 'max_length' +CONF_ON_VALUE = 'on_value' +CONF_ON_RAW_VALUE = 'on_raw_value' +CONF_ON_VALUE_RANGE = 'on_value_range' +CONF_ON_MESSAGE = 'on_message' +CONF_PIN_CS = 'pin_cs' +CONF_PIN_CLOCK = 'pin_clock' +CONF_PIN_MISO = 'pin_miso' +CONF_TURN_ON_ACTION = 'turn_on_action' +CONF_TURN_OFF_ACTION = 'turn_off_action' +CONF_OPEN_ACTION = 'open_action' +CONF_CLOSE_ACTION = 'close_action' +CONF_STOP_ACTION = 'stop_action' ESP32_BOARDS = [ 'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1', diff --git a/esphomeyaml/core.py b/esphomeyaml/core.py index 2475e5b09c..fc58602375 100644 --- a/esphomeyaml/core.py +++ b/esphomeyaml/core.py @@ -171,6 +171,14 @@ class TimePeriodSeconds(TimePeriod): pass +class Lambda(object): + def __init__(self, value): + self.value = value + + def __str__(self): + return u'Lambda<{}>'.format(self.value) + + CONFIG_PATH = None SIMPLIFY = True ESP_PLATFORM = '' diff --git a/esphomeyaml/helpers.py b/esphomeyaml/helpers.py index fa11b4073a..ff40e05729 100644 --- a/esphomeyaml/helpers.py +++ b/esphomeyaml/helpers.py @@ -10,7 +10,7 @@ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOV CONF_MODE, CONF_NUMBER, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_PCF8574, \ CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC from esphomeyaml.core import ESPHomeYAMLError, HexInt, TimePeriodMicroseconds, \ - TimePeriodMilliseconds, TimePeriodSeconds + TimePeriodMilliseconds, TimePeriodSeconds, Lambda _LOGGER = logging.getLogger(__name__) @@ -58,6 +58,9 @@ class Expression(object): continue require.require() + def has_side_effects(self): + return self.required + class RawExpression(Expression): def __init__(self, text): @@ -65,7 +68,7 @@ class RawExpression(Expression): self.text = text def __str__(self): - return self.text + return str(self.text) # pylint: disable=redefined-builtin @@ -85,6 +88,9 @@ class AssignmentExpression(Expression): type_ = u'auto' return u"{} {}{} = {}".format(type_, self.modifier, self.name, self.rhs) + def has_side_effects(self): + return self.rhs.has_side_effects() + class ExpressionList(Expression): def __init__(self, *args): @@ -100,7 +106,7 @@ class ExpressionList(Expression): self.args.append(exp) def __str__(self): - text = u", ".join(unicode(x) for x in self.args) + text = u", ".join(str(x) for x in self.args) return indent_all_but_first_and_last(text) @@ -137,6 +143,8 @@ class StructInitializer(Expression): def __init__(self, base, *args): super(StructInitializer, self).__init__() self.base = base + if isinstance(base, Expression): + self.requires.append(base) if not isinstance(args, OrderedDict): args = OrderedDict(args) self.args = OrderedDict() @@ -180,6 +188,57 @@ class ArrayInitializer(Expression): return cpp +# pylint: disable=invalid-name +class ParameterExpression(Expression): + def __init__(self, type, id): + super(ParameterExpression, self).__init__() + self.type = type + self.id = id + + def __str__(self): + return u"{} {}".format(self.type, self.id) + + +class ParameterListExpression(Expression): + def __init__(self, *parameters): + super(ParameterListExpression, self).__init__() + self.parameters = [] + for parameter in parameters: + if not isinstance(parameter, ParameterExpression): + parameter = ParameterExpression(*parameter) + self.parameters.append(parameter) + self.requires.append(parameter) + + def __str__(self): + return u", ".join(unicode(x) for x in self.parameters) + + +class LambdaExpression(Expression): + def __init__(self, parts, parameters, capture='=', return_type=None): + super(LambdaExpression, self).__init__() + self.parts = parts + if not isinstance(parameters, ParameterListExpression): + parameters = ParameterListExpression(*parameters) + self.parameters = parameters + self.requires.append(self.parameters) + self.capture = capture + self.return_type = return_type + if return_type is not None: + self.requires.append(return_type) + for i in range(1, len(parts), 2): + self.requires.append(parts[i]) + + def __str__(self): + cpp = u'[{}]({})'.format(self.capture, self.parameters) + if self.return_type is not None: + cpp += u' -> {}'.format(self.return_type) + cpp += u' {\n' + for part in self.parts: + cpp += unicode(part) + cpp += u'\n}' + return indent_all_but_first_and_last(cpp) + + class Literal(Expression): def __str__(self): raise NotImplementedError @@ -235,9 +294,9 @@ class HexIntLiteral(Literal): class FloatLiteral(Literal): - def __init__(self, float_): + def __init__(self, value): super(FloatLiteral, self).__init__() - self.float_ = float_ + self.float_ = value def __str__(self): return u"{:f}f".format(self.float_) @@ -297,23 +356,30 @@ def statement(expression): return ExpressionStatement(expression) +def register_variable(type, id, obj): + _VARIABLES[id] = obj, type + + # pylint: disable=redefined-builtin, invalid-name def variable(type, id, rhs): rhs = safe_exp(rhs) obj = MockObj(id, u'.') assignment = AssignmentExpression(type, '', id, rhs, obj) add(assignment) - _VARIABLES[id] = obj, type + register_variable(type, id, obj) obj.requires.append(assignment) return obj -def Pvariable(type, id, rhs): +def Pvariable(type, id, rhs, has_side_effects=True): rhs = safe_exp(rhs) - obj = MockObj(id, u'->') + if not has_side_effects and hasattr(rhs, '_has_side_effects'): + # pylint: disable=attribute-defined-outside-init, protected-access + rhs._has_side_effects = False + obj = MockObj(id, u'->', has_side_effects=has_side_effects) assignment = AssignmentExpression(type, '*', id, rhs, obj) add(assignment) - _VARIABLES[id] = obj, type + register_variable(type, id, obj) obj.requires.append(assignment) return obj @@ -324,32 +390,41 @@ _EXPRESSIONS = [] def get_variable(id, type=None): - result = None - while _QUEUE: + def get_result(): if id is not None: if id in _VARIABLES: - result = _VARIABLES[id][0] - break + return _VARIABLES[id][0] elif type is not None: - result = next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None) - if result is not None: - break + return next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None) + return None + + while _QUEUE: + result = get_result() + if result is not None: + return result func, config = _QUEUE.popleft() func(config) if id is None and type is None: return None + result = get_result() if result is None: - if id is not None: - if id in _VARIABLES: - result = _VARIABLES[id][0] - elif type is not None: - result = next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None) - - if result is None: - raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type {}".format(id, type)) + raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type {}".format(id, type)) return result +def process_lambda(value, parameters, capture='=', return_type=None): + parts = re.split(r'id\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)\.', value.value) + for i in range(1, len(parts), 2): + parts[i] = get_variable(parts[i])._ + return LambdaExpression(parts, parameters, capture, return_type) + + +def templatable(value, input_type, output_type): + if isinstance(value, Lambda): + return process_lambda(value, [(input_type, 'x')], return_type=output_type) + return value + + def add_task(func, config): _QUEUE.append((func, config)) @@ -362,18 +437,28 @@ def add(expression, require=True): class MockObj(Expression): - def __init__(self, base, op=u'.'): + def __init__(self, base, op=u'.', has_side_effects=True): self.base = base self.op = op + self._has_side_effects = has_side_effects super(MockObj, self).__init__() def __getattr__(self, attr): + if attr == u'_': + obj = MockObj(u'{}{}'.format(self.base, self.op)) + obj.requires.append(self) + return obj + if attr == u'new': + obj = MockObj(u'new {}'.format(self.base), u'->') + obj.requires.append(self) + return obj next_op = u'.' - if attr.startswith(u'P'): + if attr.startswith(u'P') and self.op != '::': attr = attr[1:] next_op = u'->' - op = self.op - obj = MockObj(u'{}{}{}'.format(self.base, op, attr), next_op) + if attr.startswith(u'_'): + attr = attr[1:] + obj = MockObj(u'{}{}{}'.format(self.base, self.op, attr), next_op) obj.requires.append(self) return obj @@ -394,12 +479,41 @@ class MockObj(Expression): continue require.require() + def template(self, args): + if not isinstance(args, TemplateArguments): + args = TemplateArguments(args) + obj = MockObj(u'{}{}'.format(self.base, args)) + obj.requires.append(self) + obj.requires.append(args) + return obj -App = MockObj(u'App') + def namespace(self, name): + obj = MockObj(u'{}{}{}'.format(self.base, self.op, name), u'::') + obj.requires.append(self) + return obj -GPIOPin = MockObj(u'GPIOPin') -GPIOOutputPin = MockObj(u'GPIOOutputPin') -GPIOInputPin = MockObj(u'GPIOInputPin') + def has_side_effects(self): + return self._has_side_effects + + +global_ns = MockObj('', '') +float_ = global_ns.namespace('float') +bool_ = global_ns.namespace('bool') +std_ns = global_ns.namespace('std') +std_string = std_ns.string +uint8 = global_ns.namespace('uint8_t') +uint16 = global_ns.namespace('uint16_t') +uint32 = global_ns.namespace('uint32_t') +NAN = global_ns.namespace('NAN') +esphomelib_ns = global_ns # using namespace esphomelib; +NoArg = esphomelib_ns.NoArg +App = esphomelib_ns.App +Application = esphomelib_ns.namespace('Application') +optional = esphomelib_ns.optional + +GPIOPin = esphomelib_ns.GPIOPin +GPIOOutputPin = esphomelib_ns.GPIOOutputPin +GPIOInputPin = esphomelib_ns.GPIOInputPin def get_gpio_pin_number(conf): @@ -453,15 +567,6 @@ def setup_mqtt_component(obj, config): availability[CONF_PAYLOAD_NOT_AVAILABLE])) -def exp_empty_optional(type): - return RawExpression(u'Optional<{}>()'.format(type)) - - -def exp_optional(type, value): - if value is None: - return exp_empty_optional(type) - return value - # shlex's quote for Python 2.7 _find_unsafe = re.compile(r'[^\w@%+=:,./-]').search diff --git a/esphomeyaml/pins.py b/esphomeyaml/pins.py index 9ebd041440..5709fa6b6e 100644 --- a/esphomeyaml/pins.py +++ b/esphomeyaml/pins.py @@ -64,7 +64,8 @@ ESP32_BOARD_TO_PINS = { def _translate_pin(value): if isinstance(value, dict) or value is None: - raise vol.Invalid(u"This option doesn't allow more complicated options like inverted.") + raise vol.Invalid(u"This variable only supports pin numbers, not full pin schemas " + u"(with inverted and mode).") if isinstance(value, int): return value try: @@ -171,9 +172,9 @@ PIN_MODES_ESP32 = [ def pin_mode(value): value = vol.All(vol.Coerce(str), vol.Upper)(value) if core.ESP_PLATFORM == ESP_PLATFORM_ESP32: - return vol.Any(*PIN_MODES_ESP32)(value) + return cv.one_of(*PIN_MODES_ESP32)(value) elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266: - return vol.Any(*PIN_MODES_ESP8266)(value) + return cv.one_of(*PIN_MODES_ESP8266)(value) raise vol.Invalid(u"Invalid ESP platform.") diff --git a/esphomeyaml/yaml_util.py b/esphomeyaml/yaml_util.py index c949f4d3a6..0707565bf6 100644 --- a/esphomeyaml/yaml_util.py +++ b/esphomeyaml/yaml_util.py @@ -8,8 +8,7 @@ from collections import OrderedDict import yaml -from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, MACAddress, TimePeriod, \ - TimePeriodMicroseconds, TimePeriodMilliseconds, TimePeriodSeconds +from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, Lambda, MACAddress, TimePeriod _LOGGER = logging.getLogger(__name__) @@ -195,6 +194,10 @@ def _secret_yaml(loader, node): return secrets[node.value] +def _lambda(loader, node): + return Lambda(unicode(node.value)) + + yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _ordered_dict) yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_SEQUENCE_TAG, _construct_seq) yaml.SafeLoader.add_constructor('!env_var', _env_var_yaml) @@ -206,6 +209,7 @@ yaml.SafeLoader.add_constructor('!include_dir_merge_list', yaml.SafeLoader.add_constructor('!include_dir_named', _include_dir_named_yaml) yaml.SafeLoader.add_constructor('!include_dir_merge_named', _include_dir_merge_named_yaml) +yaml.SafeLoader.add_constructor('!lambda', _lambda) # From: https://gist.github.com/miracle2k/3184458 @@ -270,6 +274,11 @@ def represent_time_period(dumper, data): return represent_odict(dumper, 'tag:yaml.org,2002:map', dictionary) +def represent_lambda(_, data): + node = yaml.ScalarNode(tag='!lambda', value=data.value, style='>') + return node + + yaml.SafeDumper.add_representer( OrderedDict, lambda dumper, value: @@ -286,7 +295,5 @@ yaml.SafeDumper.add_representer(unicode, unicode_representer) yaml.SafeDumper.add_representer(HexInt, hex_int_representer) yaml.SafeDumper.add_representer(IPAddress, stringify_representer) yaml.SafeDumper.add_representer(MACAddress, stringify_representer) -yaml.SafeDumper.add_representer(TimePeriod, represent_time_period) -yaml.SafeDumper.add_representer(TimePeriodMicroseconds, represent_time_period) -yaml.SafeDumper.add_representer(TimePeriodMilliseconds, represent_time_period) -yaml.SafeDumper.add_representer(TimePeriodSeconds, represent_time_period) +yaml.SafeDumper.add_multi_representer(TimePeriod, represent_time_period) +yaml.SafeDumper.add_multi_representer(Lambda, represent_lambda) diff --git a/pylintrc b/pylintrc index ae5f36a83e..24b0b0408f 100644 --- a/pylintrc +++ b/pylintrc @@ -14,6 +14,8 @@ disable= too-many-arguments, too-many-return-statements, duplicate-code, + invalid-name, + cyclic-import, additional-builtins=