Add template publish actions and switch triggers (#391)

* Add template publish actions and switch triggers

* Fix

* Add tests

* Add cover

* Lint

* Fix

* Fix
This commit is contained in:
Otto Winter 2019-02-10 23:35:07 +01:00 committed by GitHub
parent 61762bf299
commit 4b7a41922c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 165 additions and 17 deletions

View file

@ -125,6 +125,9 @@ def validate_automation(extra_schema=None, extra_validators=None, single=False):
# First try as a sequence of actions # First try as a sequence of actions
return [schema({CONF_THEN: value})] return [schema({CONF_THEN: value})]
except vol.Invalid as err: except vol.Invalid as err:
if err.path and err.path[0] == CONF_THEN:
err.path.pop(0)
# Next try as a sequence of automations # Next try as a sequence of automations
try: try:
return vol.Schema([schema])(value) return vol.Schema([schema])(value)

View file

@ -1,15 +1,18 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml.automation import ACTION_REGISTRY
from esphomeyaml.components import binary_sensor from esphomeyaml.components import binary_sensor
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_NAME from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE
from esphomeyaml.cpp_generator import Pvariable, add, process_lambda from esphomeyaml.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphomeyaml.cpp_helpers import setup_component from esphomeyaml.cpp_helpers import setup_component
from esphomeyaml.cpp_types import App, Component, bool_, optional from esphomeyaml.cpp_types import Action, App, Component, bool_, optional
TemplateBinarySensor = binary_sensor.binary_sensor_ns.class_('TemplateBinarySensor', TemplateBinarySensor = binary_sensor.binary_sensor_ns.class_('TemplateBinarySensor',
binary_sensor.BinarySensor, binary_sensor.BinarySensor,
Component) Component)
BinarySensorPublishAction = binary_sensor.binary_sensor_ns.class_('BinarySensorPublishAction',
Action)
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateBinarySensor), cv.GenerateID(): cv.declare_variable_id(TemplateBinarySensor),
@ -31,6 +34,26 @@ def to_code(config):
BUILD_FLAGS = '-DUSE_TEMPLATE_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_TEMPLATE_BINARY_SENSOR'
CONF_BINARY_SENSOR_TEMPLATE_PUBLISH = 'binary_sensor.template.publish'
BINARY_SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(binary_sensor.BinarySensor),
vol.Required(CONF_STATE): cv.templatable(cv.boolean),
})
@ACTION_REGISTRY.register(CONF_BINARY_SENSOR_TEMPLATE_PUBLISH,
BINARY_SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def binary_sensor_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_binary_sensor_publish_action(template_arg)
type = BinarySensorPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, bool_):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config): def to_hass_config(data, config):
return binary_sensor.core_to_hass_config(data, config) return binary_sensor.core_to_hass_config(data, config)

View file

@ -22,6 +22,12 @@ CoverState = cover_ns.class_('CoverState')
COVER_OPEN = cover_ns.COVER_OPEN COVER_OPEN = cover_ns.COVER_OPEN
COVER_CLOSED = cover_ns.COVER_CLOSED COVER_CLOSED = cover_ns.COVER_CLOSED
validate_cover_state = cv.one_of('OPEN', 'CLOSED', upper=True)
COVER_STATES = {
'OPEN': COVER_OPEN,
'CLOSED': COVER_CLOSED,
}
# Actions # Actions
OpenAction = cover_ns.class_('OpenAction', Action) OpenAction = cover_ns.class_('OpenAction', Action)
CloseAction = cover_ns.class_('CloseAction', Action) CloseAction = cover_ns.class_('CloseAction', Action)

View file

@ -1,15 +1,18 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import automation from esphomeyaml import automation
from esphomeyaml.automation import ACTION_REGISTRY
from esphomeyaml.components import cover from esphomeyaml.components import cover
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_ID, CONF_LAMBDA, \ from esphomeyaml.const import CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_ID, CONF_LAMBDA, \
CONF_NAME, CONF_OPEN_ACTION, CONF_OPTIMISTIC, CONF_STOP_ACTION CONF_NAME, CONF_OPEN_ACTION, CONF_OPTIMISTIC, CONF_STATE, CONF_STOP_ACTION
from esphomeyaml.cpp_generator import Pvariable, add, process_lambda from esphomeyaml.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphomeyaml.cpp_helpers import setup_component from esphomeyaml.cpp_helpers import setup_component
from esphomeyaml.cpp_types import App, NoArg, optional from esphomeyaml.cpp_types import Action, App, NoArg, optional
from esphomeyaml.py_compat import string_types
TemplateCover = cover.cover_ns.class_('TemplateCover', cover.Cover) TemplateCover = cover.cover_ns.class_('TemplateCover', cover.Cover)
CoverPublishAction = cover.cover_ns.class_('CoverPublishAction', Action)
PLATFORM_SCHEMA = cv.nameable(cover.COVER_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.nameable(cover.COVER_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateCover), cv.GenerateID(): cv.declare_variable_id(TemplateCover),
@ -51,6 +54,30 @@ def to_code(config):
BUILD_FLAGS = '-DUSE_TEMPLATE_COVER' BUILD_FLAGS = '-DUSE_TEMPLATE_COVER'
CONF_COVER_TEMPLATE_PUBLISH = 'cover.template.publish'
COVER_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(cover.Cover),
vol.Required(CONF_STATE): cv.templatable(cover.validate_cover_state),
})
@ACTION_REGISTRY.register(CONF_COVER_TEMPLATE_PUBLISH,
COVER_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def cover_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_cover_publish_action(template_arg)
type = CoverPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
state = config[CONF_STATE]
if isinstance(state, string_types):
template_ = cover.COVER_STATES[state]
else:
for template_ in templatable(state, arg_type, cover.CoverState):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config): def to_hass_config(data, config):
ret = cover.core_to_hass_config(data, config) ret = cover.core_to_hass_config(data, config)

View file

@ -1,13 +1,15 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml.automation import ACTION_REGISTRY
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_UPDATE_INTERVAL from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE, CONF_UPDATE_INTERVAL
from esphomeyaml.cpp_generator import Pvariable, add, process_lambda from esphomeyaml.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphomeyaml.cpp_helpers import setup_component from esphomeyaml.cpp_helpers import setup_component
from esphomeyaml.cpp_types import App, float_, optional from esphomeyaml.cpp_types import Action, App, float_, optional
TemplateSensor = sensor.sensor_ns.class_('TemplateSensor', sensor.PollingSensorComponent) TemplateSensor = sensor.sensor_ns.class_('TemplateSensor', sensor.PollingSensorComponent)
SensorPublishAction = sensor.sensor_ns.class_('SensorPublishAction', Action)
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateSensor), cv.GenerateID(): cv.declare_variable_id(TemplateSensor),
@ -31,6 +33,25 @@ def to_code(config):
BUILD_FLAGS = '-DUSE_TEMPLATE_SENSOR' BUILD_FLAGS = '-DUSE_TEMPLATE_SENSOR'
CONF_SENSOR_TEMPLATE_PUBLISH = 'sensor.template.publish'
SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(sensor.Sensor),
vol.Required(CONF_STATE): cv.templatable(cv.float_),
})
@ACTION_REGISTRY.register(CONF_SENSOR_TEMPLATE_PUBLISH, SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def sensor_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_sensor_publish_action(template_arg)
type = SensorPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, float_):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config): def to_hass_config(data, config):
return sensor.core_to_hass_config(data, config) return sensor.core_to_hass_config(data, config)

View file

@ -1,14 +1,15 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import automation
from esphomeyaml.automation import maybe_simple_id, ACTION_REGISTRY, CONDITION_REGISTRY, Condition from esphomeyaml.automation import maybe_simple_id, ACTION_REGISTRY, CONDITION_REGISTRY, Condition
from esphomeyaml.components import mqtt from esphomeyaml.components import mqtt
from esphomeyaml.components.mqtt import setup_mqtt_component from esphomeyaml.components.mqtt import setup_mqtt_component
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_INVERTED, CONF_MQTT_ID, CONF_INTERNAL, \ from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_INVERTED, CONF_MQTT_ID, CONF_INTERNAL, \
CONF_OPTIMISTIC CONF_OPTIMISTIC, CONF_ON_TURN_ON, CONF_ON_TURN_OFF, CONF_TRIGGER_ID
from esphomeyaml.core import CORE from esphomeyaml.core import CORE
from esphomeyaml.cpp_generator import add, Pvariable, get_variable from esphomeyaml.cpp_generator import add, Pvariable, get_variable
from esphomeyaml.cpp_types import esphomelib_ns, Nameable, Action, App from esphomeyaml.cpp_types import esphomelib_ns, Nameable, Action, App, Trigger, NoArg
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
@ -24,11 +25,19 @@ TurnOffAction = switch_ns.class_('TurnOffAction', Action)
TurnOnAction = switch_ns.class_('TurnOnAction', Action) TurnOnAction = switch_ns.class_('TurnOnAction', Action)
SwitchCondition = switch_ns.class_('SwitchCondition', Condition) SwitchCondition = switch_ns.class_('SwitchCondition', Condition)
SwitchTurnOnTrigger = switch_ns.class_('SwitchTurnOnTrigger', Trigger.template(NoArg))
SwitchTurnOffTrigger = switch_ns.class_('SwitchTurnOffTrigger', Trigger.template(NoArg))
SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSwitchComponent), cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSwitchComponent),
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_INVERTED): cv.boolean,
vol.Optional(CONF_ON_TURN_ON): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SwitchTurnOnTrigger),
}),
vol.Optional(CONF_ON_TURN_OFF): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SwitchTurnOffTrigger),
}),
}) })
SWITCH_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(SWITCH_SCHEMA.schema) SWITCH_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(SWITCH_SCHEMA.schema)
@ -41,6 +50,14 @@ def setup_switch_core_(switch_var, config):
add(switch_var.set_icon(config[CONF_ICON])) add(switch_var.set_icon(config[CONF_ICON]))
if CONF_INVERTED in config: if CONF_INVERTED in config:
add(switch_var.set_inverted(config[CONF_INVERTED])) add(switch_var.set_inverted(config[CONF_INVERTED]))
for conf in config.get(CONF_ON_TURN_ON, []):
rhs = switch_var.make_switch_turn_on_trigger()
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_TURN_OFF, []):
rhs = switch_var.make_switch_turn_off_trigger()
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
setup_mqtt_component(switch_var.Pget_mqtt(), config) setup_mqtt_component(switch_var.Pget_mqtt(), config)

View file

@ -1,15 +1,18 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import automation from esphomeyaml import automation
from esphomeyaml.automation import ACTION_REGISTRY
from esphomeyaml.components import switch from esphomeyaml.components import switch
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OPTIMISTIC, \ from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OPTIMISTIC, \
CONF_RESTORE_STATE, CONF_TURN_OFF_ACTION, CONF_TURN_ON_ACTION, CONF_ASSUMED_STATE CONF_RESTORE_STATE, \
from esphomeyaml.cpp_generator import Pvariable, add, process_lambda CONF_STATE, CONF_TURN_OFF_ACTION, CONF_TURN_ON_ACTION, CONF_ASSUMED_STATE
from esphomeyaml.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphomeyaml.cpp_helpers import setup_component from esphomeyaml.cpp_helpers import setup_component
from esphomeyaml.cpp_types import App, Component, NoArg, bool_, optional from esphomeyaml.cpp_types import Action, App, Component, NoArg, bool_, optional
TemplateSwitch = switch.switch_ns.class_('TemplateSwitch', switch.Switch, Component) TemplateSwitch = switch.switch_ns.class_('TemplateSwitch', switch.Switch, Component)
SwitchPublishAction = switch.switch_ns.class_('SwitchPublishAction', Action)
PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateSwitch), cv.GenerateID(): cv.declare_variable_id(TemplateSwitch),
@ -52,6 +55,25 @@ def to_code(config):
BUILD_FLAGS = '-DUSE_TEMPLATE_SWITCH' BUILD_FLAGS = '-DUSE_TEMPLATE_SWITCH'
CONF_SWITCH_TEMPLATE_PUBLISH = 'switch.template.publish'
SWITCH_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(switch.Switch),
vol.Required(CONF_STATE): cv.templatable(cv.boolean),
})
@ACTION_REGISTRY.register(CONF_SWITCH_TEMPLATE_PUBLISH, SWITCH_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def switch_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_switch_publish_action(template_arg)
type = SwitchPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, bool_):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config): def to_hass_config(data, config):
return switch.core_to_hass_config(data, config) return switch.core_to_hass_config(data, config)

View file

@ -401,6 +401,8 @@ CONF_VARIANT = 'variant'
CONF_METHOD = 'method' CONF_METHOD = 'method'
CONF_FAST_CONNECT = 'fast_connect' CONF_FAST_CONNECT = 'fast_connect'
CONF_INTERLOCK = 'interlock' CONF_INTERLOCK = 'interlock'
CONF_ON_TURN_ON = 'on_turn_on'
CONF_ON_TURN_OFF = 'on_turn_off'
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_' ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage' ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'

View file

@ -433,13 +433,21 @@ sensor:
update_interval: 15s update_interval: 15s
- platform: template - platform: template
name: "Template Sensor" name: "Template Sensor"
lambda: >- id: template_sensor
lambda: |-
if (id(ultrasonic_sensor1).state > 1) { if (id(ultrasonic_sensor1).state > 1) {
return 42.0; return 42.0;
} else { } else {
return {}; return {};
} }
update_interval: 15s update_interval: 15s
on_value:
- sensor.template.publish:
id: template_sensor
state: 43.0
- sensor.template.publish:
id: template_sensor
state: !lambda 'return NAN;'
- platform: tsl2561 - platform: tsl2561
name: "TSL2561 Ambient Light" name: "TSL2561 Ambient Light"
address: 0x39 address: 0x39
@ -560,7 +568,8 @@ binary_sensor:
name: "Nextion Component 2 Touch" name: "Nextion Component 2 Touch"
- platform: template - platform: template
name: "Garage Door Open" name: "Garage Door Open"
lambda: >- id: garage_door
lambda: |-
if (isnan(id(my_sensor).state)) { if (isnan(id(my_sensor).state)) {
// isnan checks if the ultrasonic sensor echo // isnan checks if the ultrasonic sensor echo
// has timed out, resulting in a NaN (not a number) state // has timed out, resulting in a NaN (not a number) state
@ -573,6 +582,10 @@ binary_sensor:
// Garage Door is closed. // Garage Door is closed.
return false; return false;
} }
on_press:
- binary_sensor.template.publish:
id: garage_door
state: OFF
- platform: pn532 - platform: pn532
uid: 74-10-37-94 uid: 74-10-37-94
name: "PN532 NFC Tag" name: "PN532 NFC Tag"
@ -885,6 +898,7 @@ switch:
- -1000 - -1000
- platform: template - platform: template
name: Living Room Lights name: Living Room Lights
id: livingroom_lights
optimistic: True optimistic: True
assumed_state: yes assumed_state: yes
turn_on_action: turn_on_action:
@ -898,6 +912,10 @@ switch:
turn_off_action: turn_off_action:
- switch.turn_on: living_room_lights_off - switch.turn_on: living_room_lights_off
restore_state: False restore_state: False
on_turn_on:
- switch.template.publish:
id: livingroom_lights
state: yes
- platform: restart - platform: restart
name: "Living Room Restart" name: "Living Room Restart"
- platform: shutdown - platform: shutdown
@ -926,6 +944,10 @@ switch:
optimistic: true optimistic: true
assumed_state: no assumed_state: no
restore_state: True restore_state: True
on_turn_off:
- switch.template.publish:
id: my_switch
state: !lambda 'return false;'
- platform: uart - platform: uart
name: "UART String Output" name: "UART String Output"
data: 'DataToSend' data: 'DataToSend'
@ -1041,13 +1063,18 @@ time:
cover: cover:
- platform: template - platform: template
name: "Template Cover" name: "Template Cover"
lambda: >- id: template_cover
lambda: |-
if (id(binary_sensor1).state) { if (id(binary_sensor1).state) {
return cover::COVER_OPEN; return cover::COVER_OPEN;
} else { } else {
return {}; return {};
} }
optimistic: true optimistic: true
open_action:
- cover.template.publish:
id: template_cover
state: CLOSED
assumed_state: no assumed_state: no
debug: debug: