mirror of
https://github.com/esphome/esphome.git
synced 2024-12-27 17:28:01 +01:00
Add 'at' time trigger (#493)
## Description: **Related issue (if applicable):** fixes <link to issue> **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> **Pull request in [esphome-core](https://github.com/esphome/esphome-core) with C++ framework changes (if applicable):** esphome/esphome-core#<esphome-core PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
This commit is contained in:
parent
526a414743
commit
a14d12b0c1
@ -7,13 +7,11 @@ import os
|
|||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from esphome import const, core_config, mqtt, platformio_api, wizard, writer, yaml_util
|
from esphome import const, core_config, platformio_api, wizard, writer, yaml_util
|
||||||
from esphome.api.client import run_logs
|
|
||||||
from esphome.config import get_component, iter_components, read_config, strip_default_ids
|
from esphome.config import get_component, iter_components, read_config, strip_default_ids
|
||||||
from esphome.const import CONF_BAUD_RATE, CONF_BROKER, CONF_ESPHOME, CONF_LOGGER, \
|
from esphome.const import CONF_BAUD_RATE, CONF_BROKER, CONF_ESPHOME, CONF_LOGGER, \
|
||||||
CONF_USE_CUSTOM_CODE
|
CONF_USE_CUSTOM_CODE
|
||||||
from esphome.core import CORE, EsphomeError
|
from esphome.core import CORE, EsphomeError
|
||||||
from esphome.cpp_generator import Expression, RawStatement, add, statement
|
|
||||||
from esphome.helpers import color, indent
|
from esphome.helpers import color, indent
|
||||||
from esphome.py_compat import IS_PY2, safe_input, text_type
|
from esphome.py_compat import IS_PY2, safe_input, text_type
|
||||||
from esphome.storage_json import StorageJSON, storage_path
|
from esphome.storage_json import StorageJSON, storage_path
|
||||||
@ -124,6 +122,8 @@ def run_miniterm(config, port):
|
|||||||
|
|
||||||
|
|
||||||
def write_cpp(config):
|
def write_cpp(config):
|
||||||
|
from esphome.cpp_generator import Expression, RawStatement, add, statement
|
||||||
|
|
||||||
_LOGGER.info("Generating C++ source...")
|
_LOGGER.info("Generating C++ source...")
|
||||||
|
|
||||||
CORE.add_job(core_config.to_code, config[CONF_ESPHOME], domain='esphome')
|
CORE.add_job(core_config.to_code, config[CONF_ESPHOME], domain='esphome')
|
||||||
@ -223,14 +223,20 @@ def show_logs(config, args, port):
|
|||||||
run_miniterm(config, port)
|
run_miniterm(config, port)
|
||||||
return 0
|
return 0
|
||||||
if get_port_type(port) == 'NETWORK' and 'api' in config:
|
if get_port_type(port) == 'NETWORK' and 'api' in config:
|
||||||
|
from esphome.api.client import run_logs
|
||||||
|
|
||||||
return run_logs(config, port)
|
return run_logs(config, port)
|
||||||
if get_port_type(port) == 'MQTT' and 'mqtt' in config:
|
if get_port_type(port) == 'MQTT' and 'mqtt' in config:
|
||||||
|
from esphome import mqtt
|
||||||
|
|
||||||
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)
|
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id)
|
||||||
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
def clean_mqtt(config, args):
|
def clean_mqtt(config, args):
|
||||||
|
from esphome import mqtt
|
||||||
|
|
||||||
return mqtt.clear_topic(config, args.topic, args.username, args.password, args.client_id)
|
return mqtt.clear_topic(config, args.topic, args.username, args.password, args.client_id)
|
||||||
|
|
||||||
|
|
||||||
@ -329,6 +335,8 @@ def command_clean_mqtt(args, config):
|
|||||||
|
|
||||||
|
|
||||||
def command_mqtt_fingerprint(args, config):
|
def command_mqtt_fingerprint(args, config):
|
||||||
|
from esphome import mqtt
|
||||||
|
|
||||||
return mqtt.get_fingerprint(config)
|
return mqtt.get_fingerprint(config)
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,8 +86,8 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema({
|
|||||||
def climate_control_to_code(config, action_id, template_arg, args):
|
def climate_control_to_code(config, action_id, template_arg, args):
|
||||||
for var in get_variable(config[CONF_ID]):
|
for var in get_variable(config[CONF_ID]):
|
||||||
yield None
|
yield None
|
||||||
rhs = var.make_control_action(template_arg)
|
|
||||||
type = ControlAction.template(template_arg)
|
type = ControlAction.template(template_arg)
|
||||||
|
rhs = type.new(var)
|
||||||
action = Pvariable(action_id, rhs, type=type)
|
action = Pvariable(action_id, rhs, type=type)
|
||||||
if CONF_MODE in config:
|
if CONF_MODE in config:
|
||||||
if isinstance(config[CONF_MODE], core.Lambda):
|
if isinstance(config[CONF_MODE], core.Lambda):
|
||||||
|
@ -7,7 +7,8 @@ import voluptuous as vol
|
|||||||
from esphome import automation
|
from esphome import automation
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \
|
from esphome.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \
|
||||||
CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID
|
CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID, \
|
||||||
|
CONF_AT, CONF_SECOND, CONF_HOUR, CONF_MINUTE
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
from esphome.cpp_generator import Pvariable, add
|
from esphome.cpp_generator import Pvariable, add
|
||||||
from esphome.cpp_types import App, Component, Trigger, esphome_ns
|
from esphome.cpp_types import App, Component, Trigger, esphome_ns
|
||||||
@ -232,15 +233,37 @@ def validate_cron_raw(value):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_time_at(value):
|
||||||
|
value = cv.time_of_day(value)
|
||||||
|
return {
|
||||||
|
CONF_HOURS: [value[CONF_HOUR]],
|
||||||
|
CONF_MINUTES: [value[CONF_MINUTE]],
|
||||||
|
CONF_SECONDS: [value[CONF_SECOND]],
|
||||||
|
CONF_DAYS_OF_MONTH: validate_cron_days_of_month('*'),
|
||||||
|
CONF_MONTHS: validate_cron_months('*'),
|
||||||
|
CONF_DAYS_OF_WEEK: validate_cron_days_of_week('*'),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def validate_cron_keys(value):
|
def validate_cron_keys(value):
|
||||||
if CONF_CRON in value:
|
if CONF_CRON in value:
|
||||||
for key in value.keys():
|
for key in value.keys():
|
||||||
if key in CRON_KEYS:
|
if key in CRON_KEYS:
|
||||||
raise vol.Invalid("Cannot use option {} when cron: is specified.".format(key))
|
raise vol.Invalid("Cannot use option {} when cron: is specified.".format(key))
|
||||||
|
if CONF_AT in value:
|
||||||
|
raise vol.Invalid("Cannot use option at with cron!")
|
||||||
cron_ = value[CONF_CRON]
|
cron_ = value[CONF_CRON]
|
||||||
value = {x: value[x] for x in value if x != CONF_CRON}
|
value = {x: value[x] for x in value if x != CONF_CRON}
|
||||||
value.update(cron_)
|
value.update(cron_)
|
||||||
return value
|
return value
|
||||||
|
elif CONF_AT in value:
|
||||||
|
for key in value.keys():
|
||||||
|
if key in CRON_KEYS:
|
||||||
|
raise vol.Invalid("Cannot use option {} when at: is specified.".format(key))
|
||||||
|
at_ = value[CONF_AT]
|
||||||
|
value = {x: value[x] for x in value if x != CONF_AT}
|
||||||
|
value.update(at_)
|
||||||
|
return value
|
||||||
return cv.has_at_least_one_key(*CRON_KEYS)(value)
|
return cv.has_at_least_one_key(*CRON_KEYS)(value)
|
||||||
|
|
||||||
|
|
||||||
@ -266,6 +289,7 @@ TIME_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||||||
vol.Optional(CONF_MONTHS): validate_cron_months,
|
vol.Optional(CONF_MONTHS): validate_cron_months,
|
||||||
vol.Optional(CONF_DAYS_OF_WEEK): validate_cron_days_of_week,
|
vol.Optional(CONF_DAYS_OF_WEEK): validate_cron_days_of_week,
|
||||||
vol.Optional(CONF_CRON): validate_cron_raw,
|
vol.Optional(CONF_CRON): validate_cron_raw,
|
||||||
|
vol.Optional(CONF_AT): validate_time_at,
|
||||||
}, validate_cron_keys),
|
}, validate_cron_keys),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"""Helpers for config validation using voluptuous."""
|
"""Helpers for config validation using voluptuous."""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@ -13,7 +14,7 @@ from esphome import core
|
|||||||
from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
|
from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
|
||||||
CONF_INTERNAL, CONF_NAME, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, \
|
CONF_INTERNAL, CONF_NAME, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, \
|
||||||
CONF_RETAIN, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, ESP_PLATFORM_ESP32, \
|
CONF_RETAIN, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, ESP_PLATFORM_ESP32, \
|
||||||
ESP_PLATFORM_ESP8266
|
ESP_PLATFORM_ESP8266, CONF_HOUR, CONF_MINUTE, CONF_SECOND
|
||||||
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
|
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
|
||||||
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
|
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
|
||||||
from esphome.py_compat import integer_types, string_types, text_type, IS_PY2
|
from esphome.py_compat import integer_types, string_types, text_type, IS_PY2
|
||||||
@ -391,6 +392,23 @@ positive_not_null_time_period = vol.All(time_period,
|
|||||||
vol.Range(min=TimePeriod(), min_included=False))
|
vol.Range(min=TimePeriod(), min_included=False))
|
||||||
|
|
||||||
|
|
||||||
|
def time_of_day(value):
|
||||||
|
value = string(value)
|
||||||
|
try:
|
||||||
|
date = datetime.strptime(value, '%H:%M:%S')
|
||||||
|
except ValueError as err:
|
||||||
|
try:
|
||||||
|
date = datetime.strptime(value, '%H:%M:%S %p')
|
||||||
|
except ValueError:
|
||||||
|
raise vol.Invalid("Invalid time of day: {}".format(err))
|
||||||
|
|
||||||
|
return {
|
||||||
|
CONF_HOUR: date.hour,
|
||||||
|
CONF_MINUTE: date.minute,
|
||||||
|
CONF_SECOND: date.second,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def mac_address(value):
|
def mac_address(value):
|
||||||
value = string_strict(value)
|
value = string_strict(value)
|
||||||
parts = value.split(':')
|
parts = value.split(':')
|
||||||
|
@ -361,8 +361,11 @@ CONF_HIDDEN = 'hidden'
|
|||||||
CONF_ON_LOOP = 'on_loop'
|
CONF_ON_LOOP = 'on_loop'
|
||||||
CONF_ON_TIME = 'on_time'
|
CONF_ON_TIME = 'on_time'
|
||||||
CONF_SECONDS = 'seconds'
|
CONF_SECONDS = 'seconds'
|
||||||
|
CONF_SECOND = 'second'
|
||||||
CONF_MINUTES = 'minutes'
|
CONF_MINUTES = 'minutes'
|
||||||
|
CONF_MINUTE = 'minute'
|
||||||
CONF_HOURS = 'hours'
|
CONF_HOURS = 'hours'
|
||||||
|
CONF_HOUR = 'hour'
|
||||||
CONF_DAYS_OF_MONTH = 'days_of_month'
|
CONF_DAYS_OF_MONTH = 'days_of_month'
|
||||||
CONF_MONTHS = 'months'
|
CONF_MONTHS = 'months'
|
||||||
CONF_DAYS_OF_WEEK = 'days_of_week'
|
CONF_DAYS_OF_WEEK = 'days_of_week'
|
||||||
@ -389,6 +392,7 @@ CONF_DIR_PIN = 'dir_pin'
|
|||||||
CONF_SLEEP_PIN = 'sleep_pin'
|
CONF_SLEEP_PIN = 'sleep_pin'
|
||||||
CONF_SEND_FIRST_AT = 'send_first_at'
|
CONF_SEND_FIRST_AT = 'send_first_at'
|
||||||
CONF_TIME_ID = 'time_id'
|
CONF_TIME_ID = 'time_id'
|
||||||
|
CONF_AT = 'at'
|
||||||
CONF_RESTORE_STATE = 'restore_state'
|
CONF_RESTORE_STATE = 'restore_state'
|
||||||
CONF_TIMING = 'timing'
|
CONF_TIMING = 'timing'
|
||||||
CONF_INVALID_COOLDOWN = 'invalid_cooldown'
|
CONF_INVALID_COOLDOWN = 'invalid_cooldown'
|
||||||
|
Loading…
Reference in New Issue
Block a user