1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-14 05:45:48 +00:00

Compare commits

...

44 Commits

Author SHA1 Message Date
Otto Winter
e47bcb9abb Bump version to 1.6.2 2018-06-06 21:01:20 +02:00
Otto Winter
30b94f06b3 Add verbose mode for espota 2018-06-06 11:12:42 +02:00
Otto Winter
19dfdb77eb Fix MQTT logs 2018-06-06 11:12:29 +02:00
Otto Winter
b6e7ad3589 Fix OTA port not being set 2018-06-06 11:12:14 +02:00
Otto Winter
1267680379 Improve error messages 2018-06-06 10:27:59 +02:00
Otto Winter
b5f6b32fad Fix dallas resolution 2018-06-06 10:27:50 +02:00
Otto Winter
7068808d4f Fix optional returns from templates 2018-06-06 09:48:59 +02:00
Otto Winter
c82a44d541 Fix ESP32 touch sleep duration conversion 2018-06-06 09:30:14 +02:00
Otto Winter
e650473682 Fix ESP32 touch ID issue 2018-06-06 09:26:56 +02:00
Otto Winter
2ee0d4242d Make Automation output readable again 2018-06-06 09:18:39 +02:00
Otto Winter
b2aecf29dc Fix ESP32 BLE 2018-06-06 09:18:21 +02:00
Otto Winter
081c2f4e07 Fix SHT3xD with manual update interval 2018-06-06 09:06:14 +02:00
Otto Winter
0c77228421 Improve wrong pin error message 2018-06-06 08:55:53 +02:00
Otto Winter
8a509c6551 Fix MQTT publish 2018-06-06 08:35:31 +02:00
Otto Winter
d249820bcd Fix MQTT availability option 2018-06-06 08:35:23 +02:00
Otto Winter
f39cf52eae Fix WiFi domain option 2018-06-06 08:13:05 +02:00
Otto Winter
63fb252b46 Fix web server CSS/JS URL 2018-06-06 08:12:51 +02:00
Otto Winter
2f98adca49 Fix OrFilter 2018-06-06 08:12:39 +02:00
Otto Winter
084fc00517 Fix MQTT messages 2018-06-06 08:12:30 +02:00
Otto Winter
abeac23abd Fix i2c frequency 2018-06-06 08:12:17 +02:00
Otto Winter
7264e3a4bf Fix ultrasonic typo Fixes #62 2018-06-06 07:09:03 +02:00
Otto Winter
16eeb3af31 Attempt to solve UnicodeEncodeError in HassIO when running on RPi 2018-06-05 23:19:46 +02:00
Otto Winter
b799d2df7f Adjust serial port fetch interval 2018-06-05 23:19:28 +02:00
Otto Winter
11d55fec4f Better OSError handling for YAML parser 2018-06-05 23:18:56 +02:00
Otto Winter
923a5990c7 Fix erroneous validation. Fixes OttoWinter/esphomelib#59 2018-06-05 22:32:34 +02:00
Otto Winter
a0a615c335 Deep Sleep wakeup pin mode 2018-06-05 22:31:39 +02:00
Otto Winter
e9ced0cc3f Fix lint 2018-06-04 20:47:29 +02:00
Otto Winter
1a92381994 Update Dockerfile 2018-06-04 20:47:23 +02:00
Otto Winter
a07a7a87a2 Fix filter out nan filter 2018-06-04 20:47:15 +02:00
Otto Winter
6a823f5777 Bump version to 1.6.1 2018-06-03 23:45:57 +02:00
Otto Winter
419c5afe27 Update Dockerfiles 2018-06-03 23:45:29 +02:00
Otto Winter
17798dee1e HassIO add-on pre-built images 2018-06-03 19:22:25 +02:00
Otto Winter
ee2c53585f Add Sonoff S20 example 2018-06-03 13:00:40 +02:00
Otto Winter
2f05acfa5a Validate configuration button 2018-06-03 12:16:43 +02:00
Otto Winter
f4d393a59e Fix dashboard upload port selection 2018-06-03 11:18:53 +02:00
Otto Winter
967aa53bad add_job 2018-06-03 07:11:11 +02:00
Otto Winter
4f3f460105 ESP32 Hall Sensor 2018-06-02 23:25:13 +02:00
Otto Winter
6e85a741ae New coroutine-based task execution 2018-06-02 22:22:20 +02:00
Otto Winter
2db45898e2 Sonoff 4CH example with automation 2018-06-02 15:41:11 +02:00
Otto Winter
eb62599a98 ADC VCC support Fixes #26 2018-06-02 13:43:49 +02:00
Otto Winter
9f0737e5b9 Fix pylint... Again... 2018-06-01 23:01:31 +02:00
Otto Winter
7a393c1a3a Fix template/switch cover example. Fixes #27 2018-06-01 22:58:23 +02:00
Otto Winter
4fa7bc196a Warn about tornado. Fixes #24 2018-06-01 22:49:14 +02:00
Brandon Davidson
65d0dd47f3 Fix #27 - invalid code gen for Template Cover (#29) 2018-06-01 22:48:07 +02:00
93 changed files with 1859 additions and 948 deletions

View File

@@ -4,7 +4,7 @@ python:
- "2.7" - "2.7"
install: install:
- pip install -r requirements.txt - pip install -r requirements.txt
- pip install flake8==3.5.0 pylint==1.8.4 - pip install tornado esptool flake8==3.5.0 pylint==1.8.4
script: script:
- flake8 esphomeyaml - flake8 esphomeyaml
- pylint esphomeyaml - pylint esphomeyaml

View File

@@ -0,0 +1,43 @@
# Dockerfile for HassIO add-on
ARG BUILD_FROM=ubuntu:bionic
FROM ${BUILD_FROM}
# Re-declare BUILD_FROM to fix weird docker issue
ARG BUILD_FROM
# On amd64 and alike, using ubuntu as the base is better as building
# for the ESP32 only works with glibc (and ubuntu). However, on armhf
# the build toolchain frequently procudes segfaults under ubuntu.
# -> Use ubuntu for most architectures, except alpine for armhf
#
# * python and related required because this is a python project
# * git required for platformio library dependencies downloads
# * libc6-compat and openssh required on alpine for weird reasons
# * disable platformio telemetry on install
RUN /bin/bash -c "if [[ '$BUILD_FROM' = *\"ubuntu\"* ]]; then \
apt-get update && apt-get install -y --no-install-recommends \
python python-pip python-setuptools git && \
rm -rf /var/lib/apt/lists/* /tmp/*; \
else \
apk add --no-cache python2 py2-pip git openssh libc6-compat; \
fi" && \
pip install --no-cache-dir platformio && \
platformio settings set enable_telemetry No
# Create fake project to make platformio install all depdencies.
# * Ignore build errors from platformio - empty project
# * On alpine, only install ESP8266 toolchain
COPY platformio.ini /pio/platformio.ini
RUN /bin/bash -c "if [[ '$BUILD_FROM' = *\"ubuntu\"* ]]; then \
platformio run -e espressif32 -e espressif8266 -d /pio; exit 0; \
else \
echo \"\$(head -8 /pio/platformio.ini)\" >/pio/platformio.ini; \
platformio run -e espressif8266 -d /pio; exit 0; \
fi"
# Install latest esphomeyaml from git
RUN pip install --no-cache-dir \
git+git://github.com/OttoWinter/esphomeyaml.git
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

View File

@@ -0,0 +1,10 @@
{
"squash": false,
"build_from": {
"aarch64": "arm64v8/ubuntu:bionic",
"amd64": "ubuntu:bionic",
"armhf": "homeassistant/armhf-base:latest",
"i386": "i386/ubuntu:bionic"
},
"args": {}
}

View File

@@ -0,0 +1,29 @@
{
"name": "esphomeyaml-edge",
"version": "dev",
"slug": "esphomeyaml-edge",
"description": "Development build of the esphomeyaml HassIO add-on.",
"url": "https://esphomelib.com/esphomeyaml/index.html",
"startup": "application",
"webui": "http://[HOST]:[PORT:6052]",
"boot": "auto",
"ports": {
"6052/tcp": 6052,
"6053/tcp": 6053
},
"arch": [
"aarch64",
"amd64",
"armhf",
"i386"
],
"auto_uart": true,
"map": [
"config:rw"
],
"options": {},
"environment": {
"ESPHOMEYAML_OTA_HOST_PORT": "6053"
},
"schema": {}
}

View File

@@ -0,0 +1,12 @@
; This file allows the docker build file to install the required platformio
; platforms
[env:espressif8266]
platform = espressif8266
board = nodemcuv2
framework = arduino
[env:espressif32]
platform = espressif32
board = nodemcu-32s
framework = arduino

View File

@@ -1,20 +1,44 @@
# Dockerfile for HassIO add-on # Dockerfile for HassIO add-on
ARG BUILD_FROM=ubuntu:bionic
FROM ${BUILD_FROM}
# Re-declare BUILD_FROM to fix weird docker issue
ARG BUILD_FROM ARG BUILD_FROM
FROM $BUILD_FROM ARG BUILD_VERSION
ENV LANG C.UTF-8 # On amd64 and alike, using ubuntu as the base is better as building
# for the ESP32 only works with glibc (and ubuntu). However, on armhf
# Install requirements for add-on # the build toolchain frequently procudes segfaults under ubuntu.
RUN apk add --no-cache python2 py2-pip git openssh libc6-compat && \ # -> Use ubuntu for most architectures, except alpine for armhf
#
# * python and related required because this is a python project
# * git required for platformio library dependencies downloads
# * libc6-compat and openssh required on alpine for weird reasons
# * disable platformio telemetry on install
RUN /bin/bash -c "if [[ '$BUILD_FROM' = *\"ubuntu\"* ]]; then \
apt-get update && apt-get install -y --no-install-recommends \
python python-pip python-setuptools git && \
rm -rf /var/lib/apt/lists/* /tmp/*; \
else \
apk add --no-cache python2 py2-pip git openssh libc6-compat; \
fi" && \
pip install --no-cache-dir platformio && \ pip install --no-cache-dir platformio && \
platformio platform install espressif8266 \ platformio settings set enable_telemetry No
--with-package tool-esptool \
--with-package framework-arduinoespressif8266 \
--with-package tool-mkspiffs \
--with-package tool-espotapy
# Create fake project to make platformio install all depdencies.
# * Ignore build errors from platformio - empty project
# * On alpine, only install ESP8266 toolchain
COPY platformio.ini /pio/platformio.ini
RUN /bin/bash -c "if [[ '$BUILD_FROM' = *\"ubuntu\"* ]]; then \
platformio run -e espressif32 -e espressif8266 -d /pio; \
else \
echo \"\$(head -8 /pio/platformio.ini)\" >/pio/platformio.ini; \
platformio run -e espressif8266 -d /pio; \
fi"; exit 0
# Install latest esphomeyaml from git
RUN pip install --no-cache-dir \ RUN pip install --no-cache-dir \
git+git://github.com/OttoWinter/esphomeyaml.git@v1.6.0 \ esphomeyaml==${BUILD_VERSION}
tornado esptool
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"] CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

View File

@@ -1,11 +1,11 @@
from __future__ import print_function from __future__ import print_function
import argparse import argparse
from datetime import datetime
import logging import logging
import os import os
import random import random
import sys import sys
from datetime import datetime
from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util
from esphomeyaml.config import core_to_code, get_component, iter_components, read_config from esphomeyaml.config import core_to_code, get_component, iter_components, read_config
@@ -13,7 +13,7 @@ from esphomeyaml.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, CON
CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, ESP_PLATFORM_ESP8266 CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \ from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \
add_task, color, get_variable, indent, quote, statement add_job, color, flush_tasks, indent, quote, statement
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -102,40 +102,34 @@ def run_miniterm(config, port, escape=False):
with serial.Serial(port, baudrate=baud_rate) as ser: with serial.Serial(port, baudrate=baud_rate) as ser:
while True: while True:
line = ser.readline() line = ser.readline().replace('\r', '').replace('\n', '')
time = datetime.now().time().strftime('[%H:%M:%S]') time = datetime.now().time().strftime('[%H:%M:%S]')
message = time + line.decode('unicode-escape').replace('\r', '').replace('\n', '') message = time + line
if escape: if escape:
message = message.replace('\033', '\\033').encode('ascii', 'replace') message = message.replace('\033', '\\033')
print(message) try:
print(message)
except UnicodeEncodeError:
print(message.encode('ascii', 'backslashreplace'))
def write_cpp(config): def write_cpp(config):
_LOGGER.info("Generating C++ source...") _LOGGER.info("Generating C++ source...")
add_task(core_to_code, config[CONF_ESPHOMEYAML]) add_job(core_to_code, config[CONF_ESPHOMEYAML], domain='esphomeyaml')
for domain in PRE_INITIALIZE: for domain in PRE_INITIALIZE:
if domain == CONF_ESPHOMEYAML: if domain == CONF_ESPHOMEYAML or domain not in config:
continue continue
if domain in config: add_job(get_component(domain).to_code, config[domain], domain=domain)
add_task(get_component(domain).to_code, config[domain])
# Clear queue
get_variable(None)
add(RawStatement(''))
for domain, component, conf in iter_components(config): for domain, component, conf in iter_components(config):
if domain in PRE_INITIALIZE: if domain in PRE_INITIALIZE or not hasattr(component, 'to_code'):
continue continue
if not hasattr(component, 'to_code'): add_job(component.to_code, conf, domain=domain)
continue
add_task(component.to_code, conf)
# Clear queue flush_tasks()
get_variable(None)
add(RawStatement('')) add(RawStatement(''))
add(RawStatement('')) add(RawStatement(''))
all_code = [] all_code = []
for exp in _EXPRESSIONS: for exp in _EXPRESSIONS:
if core.SIMPLIFY: if core.SIMPLIFY:
@@ -157,9 +151,12 @@ def write_cpp(config):
return 0 return 0
def compile_program(config): def compile_program(args, config):
_LOGGER.info("Compiling app...") _LOGGER.info("Compiling app...")
return run_platformio('platformio', 'run', '-d', get_base_path(config)) command = ['platformio', 'run', '-d', get_base_path(config)]
if args.verbose:
command.append('-v')
return run_platformio(*command)
def get_upload_host(config): def get_upload_host(config):
@@ -188,8 +185,11 @@ def upload_program(config, args, port):
if port != 'OTA': if port != 'OTA':
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy: if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy:
return upload_using_esptool(config, port) return upload_using_esptool(config, port)
return run_platformio('platformio', 'run', '-d', get_base_path(config), command = ['platformio', 'run', '-d', get_base_path(config),
'-t', 'upload', '--upload-port', port) '-t', 'upload', '--upload-port', port]
if args.verbose:
command.append('-v')
return run_platformio(*command)
if 'ota' not in config: if 'ota' not in config:
_LOGGER.error("No serial port found and OTA not enabled. Can't upload!") _LOGGER.error("No serial port found and OTA not enabled. Can't upload!")
@@ -208,6 +208,8 @@ def upload_program(config, args, port):
espota_args = ['espota.py', '--debug', '--progress', '-i', host, espota_args = ['espota.py', '--debug', '--progress', '-i', host,
'-p', str(ota.get_port(config)), '-f', bin_file, '-p', str(ota.get_port(config)), '-f', bin_file,
'-a', ota.get_auth(config), '-P', str(host_port)] '-a', ota.get_auth(config), '-P', str(host_port)]
if args.verbose:
espota_args.append('-d')
return espota.main(espota_args) return espota.main(espota_args)
@@ -223,8 +225,9 @@ def clean_mqtt(config, args):
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)
def setup_log(): def setup_log(debug=False):
logging.basicConfig(level=logging.INFO) log_level = logging.DEBUG if debug else logging.INFO
logging.basicConfig(level=log_level)
fmt = "%(levelname)s [%(name)s] %(message)s" fmt = "%(levelname)s [%(name)s] %(message)s"
colorfmt = "%(log_color)s{}%(reset)s".format(fmt) colorfmt = "%(log_color)s{}%(reset)s".format(fmt)
datefmt = '%H:%M:%S' datefmt = '%H:%M:%S'
@@ -253,7 +256,28 @@ def command_wizard(args):
return wizard.wizard(args.configuration) return wizard.wizard(args.configuration)
def strip_default_ids(config):
value = config
if isinstance(config, list):
value = type(config)()
for x in config:
if isinstance(x, core.ID) and not x.is_manual:
continue
value.append(strip_default_ids(x))
return value
elif isinstance(config, dict):
value = type(config)()
for k, v in config.iteritems():
if isinstance(v, core.ID) and not v.is_manual:
continue
value[k] = strip_default_ids(v)
return value
return value
def command_config(args, config): def command_config(args, config):
if not args.verbose:
config = strip_default_ids(config)
print(yaml_util.dump(config)) print(yaml_util.dump(config))
return 0 return 0
@@ -262,7 +286,7 @@ def command_compile(args, config):
exit_code = write_cpp(config) exit_code = write_cpp(config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
exit_code = compile_program(config) exit_code = compile_program(args, config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info(u"Successfully compiled program.") _LOGGER.info(u"Successfully compiled program.")
@@ -287,7 +311,7 @@ def command_run(args, config):
exit_code = write_cpp(config) exit_code = write_cpp(config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
exit_code = compile_program(config) exit_code = compile_program(args, config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info(u"Successfully compiled program.") _LOGGER.info(u"Successfully compiled program.")
@@ -339,6 +363,8 @@ POST_CONFIG_ACTIONS = {
def parse_args(argv): def parse_args(argv):
parser = argparse.ArgumentParser(prog='esphomeyaml') parser = argparse.ArgumentParser(prog='esphomeyaml')
parser.add_argument('-v', '--verbose', help="Enable verbose esphomeyaml logs.",
action='store_true')
parser.add_argument('configuration', help='Your YAML configuration file.') parser.add_argument('configuration', help='Your YAML configuration file.')
subparsers = parser.add_subparsers(help='Commands', dest='command') subparsers = parser.add_subparsers(help='Commands', dest='command')
@@ -407,8 +433,8 @@ def parse_args(argv):
def run_esphomeyaml(argv): def run_esphomeyaml(argv):
setup_log()
args = parse_args(argv) args = parse_args(argv)
setup_log(args.verbose)
if args.command in PRE_CONFIG_ACTIONS: if args.command in PRE_CONFIG_ACTIONS:
try: try:
return PRE_CONFIG_ACTIONS[args.command](args) return PRE_CONFIG_ACTIONS[args.command](args)

View File

@@ -2,15 +2,16 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import cover, fan from esphomeyaml.components import cover, fan
from esphomeyaml.const import CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, CONF_BLUE, \ from esphomeyaml.const import CONF_ABOVE, CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, \
CONF_BRIGHTNESS, CONF_CONDITION_ID, CONF_DELAY, CONF_EFFECT, CONF_FLASH_LENGTH, CONF_GREEN, \ CONF_BELOW, \
CONF_ID, CONF_IF, CONF_LAMBDA, CONF_OR, CONF_OSCILLATING, CONF_PAYLOAD, \ CONF_BLUE, CONF_BRIGHTNESS, CONF_CONDITION_ID, CONF_DELAY, CONF_EFFECT, CONF_FLASH_LENGTH, \
CONF_QOS, CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_SPEED, CONF_THEN, CONF_TOPIC, \ CONF_GREEN, CONF_ID, CONF_IF, CONF_LAMBDA, CONF_OR, CONF_OSCILLATING, CONF_PAYLOAD, CONF_QOS, \
CONF_TRANSITION_LENGTH, CONF_TRIGGER_ID, CONF_WHITE, CONF_ABOVE, CONF_BELOW CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_SPEED, CONF_THEN, CONF_TOPIC, CONF_TRANSITION_LENGTH, \
CONF_TRIGGER_ID, CONF_WHITE
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, \ from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, \
bool_, esphomelib_ns, float_, get_variable, process_lambda, std_string, templatable, uint32, \ bool_, esphomelib_ns, float_, get_variable, process_lambda, std_string, templatable, uint32, \
uint8 uint8, add_job
CONF_MQTT_PUBLISH = 'mqtt.publish' CONF_MQTT_PUBLISH = 'mqtt.publish'
CONF_LIGHT_TOGGLE = 'light.toggle' CONF_LIGHT_TOGGLE = 'light.toggle'
@@ -32,7 +33,7 @@ ACTION_KEYS = [CONF_DELAY, CONF_MQTT_PUBLISH, CONF_LIGHT_TOGGLE, CONF_LIGHT_TURN
CONF_FAN_TURN_OFF, CONF_FAN_TURN_ON] CONF_FAN_TURN_OFF, CONF_FAN_TURN_ON]
ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({ ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
cv.GenerateID('action', CONF_ACTION_ID): cv.register_variable_id, cv.GenerateID(CONF_ACTION_ID): cv.declare_variable_id(None),
vol.Optional(CONF_DELAY): cv.templatable(cv.positive_time_period_milliseconds), vol.Optional(CONF_DELAY): cv.templatable(cv.positive_time_period_milliseconds),
vol.Optional(CONF_MQTT_PUBLISH): vol.Schema({ vol.Optional(CONF_MQTT_PUBLISH): vol.Schema({
vol.Required(CONF_TOPIC): cv.templatable(cv.publish_topic), vol.Required(CONF_TOPIC): cv.templatable(cv.publish_topic),
@@ -41,15 +42,15 @@ ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_RETAIN): cv.templatable(cv.boolean), vol.Optional(CONF_RETAIN): cv.templatable(cv.boolean),
}), }),
vol.Optional(CONF_LIGHT_TOGGLE): vol.Schema({ vol.Optional(CONF_LIGHT_TOGGLE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
}), }),
vol.Optional(CONF_LIGHT_TURN_OFF): vol.Schema({ vol.Optional(CONF_LIGHT_TURN_OFF): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
}), }),
vol.Optional(CONF_LIGHT_TURN_ON): vol.Schema({ vol.Optional(CONF_LIGHT_TURN_ON): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Exclusive(CONF_TRANSITION_LENGTH, 'transformer'): vol.Exclusive(CONF_TRANSITION_LENGTH, 'transformer'):
cv.templatable(cv.positive_time_period_milliseconds), cv.templatable(cv.positive_time_period_milliseconds),
vol.Exclusive(CONF_FLASH_LENGTH, 'transformer'): vol.Exclusive(CONF_FLASH_LENGTH, 'transformer'):
@@ -62,45 +63,45 @@ ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_EFFECT): cv.templatable(cv.string), vol.Optional(CONF_EFFECT): cv.templatable(cv.string),
}), }),
vol.Optional(CONF_SWITCH_TOGGLE): vol.Schema({ vol.Optional(CONF_SWITCH_TOGGLE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_SWITCH_TURN_OFF): vol.Schema({ vol.Optional(CONF_SWITCH_TURN_OFF): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_SWITCH_TURN_ON): vol.Schema({ vol.Optional(CONF_SWITCH_TURN_ON): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_COVER_OPEN): vol.Schema({ vol.Optional(CONF_COVER_OPEN): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_COVER_CLOSE): vol.Schema({ vol.Optional(CONF_COVER_CLOSE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_COVER_STOP): vol.Schema({ vol.Optional(CONF_COVER_STOP): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_COVER_OPEN): vol.Schema({ vol.Optional(CONF_COVER_OPEN): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_COVER_CLOSE): vol.Schema({ vol.Optional(CONF_COVER_CLOSE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_COVER_STOP): vol.Schema({ vol.Optional(CONF_COVER_STOP): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_FAN_TOGGLE): vol.Schema({ vol.Optional(CONF_FAN_TOGGLE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_FAN_TURN_OFF): vol.Schema({ vol.Optional(CONF_FAN_TURN_OFF): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
}), }),
vol.Optional(CONF_FAN_TURN_ON): vol.Schema({ vol.Optional(CONF_FAN_TURN_ON): vol.Schema({
vol.Required(CONF_ID): cv.variable_id, vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Optional(CONF_OSCILLATING): cv.templatable(cv.boolean), vol.Optional(CONF_OSCILLATING): cv.templatable(cv.boolean),
vol.Optional(CONF_SPEED): cv.templatable(fan.validate_fan_speed), vol.Optional(CONF_SPEED): cv.templatable(fan.validate_fan_speed),
}), }),
vol.Optional(CONF_LAMBDA): cv.lambda_, vol.Optional(CONF_LAMBDA): cv.lambda_,
}, cv.has_at_exactly_one_key(*ACTION_KEYS))]) }, cv.has_exactly_one_key(*ACTION_KEYS))])
# pylint: disable=invalid-name # pylint: disable=invalid-name
DelayAction = esphomelib_ns.DelayAction DelayAction = esphomelib_ns.DelayAction
@@ -115,7 +116,7 @@ def validate_recursive_condition(value):
CONDITION_KEYS = [CONF_AND, CONF_OR, CONF_RANGE, CONF_LAMBDA] CONDITION_KEYS = [CONF_AND, CONF_OR, CONF_RANGE, CONF_LAMBDA]
CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({ CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
cv.GenerateID('condition', CONF_CONDITION_ID): cv.register_variable_id, cv.GenerateID(CONF_CONDITION_ID): cv.declare_variable_id(None),
vol.Optional(CONF_AND): validate_recursive_condition, vol.Optional(CONF_AND): validate_recursive_condition,
vol.Optional(CONF_OR): validate_recursive_condition, vol.Optional(CONF_OR): validate_recursive_condition,
vol.Optional(CONF_RANGE): vol.All(vol.Schema({ vol.Optional(CONF_RANGE): vol.All(vol.Schema({
@@ -123,7 +124,7 @@ CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_BELOW): vol.Coerce(float), vol.Optional(CONF_BELOW): vol.Coerce(float),
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)), }), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)),
vol.Optional(CONF_LAMBDA): cv.lambda_, vol.Optional(CONF_LAMBDA): cv.lambda_,
}), cv.has_at_exactly_one_key(*CONDITION_KEYS)]) }), cv.has_exactly_one_key(*CONDITION_KEYS)])
# pylint: disable=invalid-name # pylint: disable=invalid-name
AndCondition = esphomelib_ns.AndCondition AndCondition = esphomelib_ns.AndCondition
@@ -132,8 +133,8 @@ RangeCondition = esphomelib_ns.RangeCondition
LambdaCondition = esphomelib_ns.LambdaCondition LambdaCondition = esphomelib_ns.LambdaCondition
AUTOMATION_SCHEMA = vol.Schema({ AUTOMATION_SCHEMA = vol.Schema({
cv.GenerateID('trigger', CONF_TRIGGER_ID): cv.register_variable_id, cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(None),
cv.GenerateID('automation', CONF_AUTOMATION_ID): cv.register_variable_id, cv.GenerateID(CONF_AUTOMATION_ID): cv.declare_variable_id(None),
vol.Optional(CONF_IF): CONDITIONS_SCHEMA, vol.Optional(CONF_IF): CONDITIONS_SCHEMA,
vol.Required(CONF_THEN): ACTIONS_SCHEMA, vol.Required(CONF_THEN): ACTIONS_SCHEMA,
}) })
@@ -142,156 +143,267 @@ AUTOMATION_SCHEMA = vol.Schema({
def build_condition(config, arg_type): def build_condition(config, arg_type):
template_arg = TemplateArguments(arg_type) template_arg = TemplateArguments(arg_type)
if CONF_AND in config: if CONF_AND in config:
return AndCondition.new(template_arg, build_conditions(config[CONF_AND], template_arg)) yield AndCondition.new(template_arg, build_conditions(config[CONF_AND], template_arg))
if CONF_OR in config: elif CONF_OR in config:
return OrCondition.new(template_arg, build_conditions(config[CONF_OR], template_arg)) yield OrCondition.new(template_arg, build_conditions(config[CONF_OR], template_arg))
if CONF_LAMBDA in config: elif CONF_LAMBDA in config:
return LambdaCondition.new(template_arg, lambda_ = None
process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')])) for lambda_ in process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')]):
if CONF_RANGE in config: yield
yield LambdaCondition.new(template_arg, lambda_)
elif CONF_RANGE in config:
conf = config[CONF_RANGE] conf = config[CONF_RANGE]
rhs = RangeCondition.new(template_arg) rhs = RangeCondition.new(template_arg)
condition = Pvariable(RangeCondition.template(template_arg), config[CONF_CONDITION_ID], rhs) type = RangeCondition.template(template_arg)
condition = Pvariable(config[CONF_CONDITION_ID], rhs, type=type)
if CONF_ABOVE in conf: if CONF_ABOVE in conf:
condition.set_min(templatable(conf[CONF_ABOVE], arg_type, float_)) template_ = None
for template_ in templatable(conf[CONF_ABOVE], arg_type, float_):
yield
condition.set_min(template_)
if CONF_BELOW in conf: if CONF_BELOW in conf:
condition.set_max(templatable(conf[CONF_BELOW], arg_type, float_)) template_ = None
return condition for template_ in templatable(conf[CONF_BELOW], arg_type, float_):
raise ESPHomeYAMLError(u"Unsupported condition {}".format(config)) yield
condition.set_max(template_)
yield condition
else:
raise ESPHomeYAMLError(u"Unsupported condition {}".format(config))
def build_conditions(config, arg_type): def build_conditions(config, arg_type):
return ArrayInitializer(*[build_condition(x, arg_type) for x in config]) conditions = []
for conf in config:
condition = None
for condition in build_condition(conf, arg_type):
yield None
conditions.append(condition)
yield ArrayInitializer(*conditions)
def build_action(config, arg_type): def build_action(config, arg_type):
from esphomeyaml.components import light, mqtt, switch from esphomeyaml.components import light, mqtt, switch
template_arg = TemplateArguments(arg_type) template_arg = TemplateArguments(arg_type)
# Keep pylint from freaking out
var = None
if CONF_DELAY in config: if CONF_DELAY in config:
rhs = App.register_component(DelayAction.new(template_arg)) rhs = App.register_component(DelayAction.new(template_arg))
action = Pvariable(DelayAction.template(template_arg), config[CONF_ACTION_ID], rhs) type = DelayAction.template(template_arg)
add(action.set_delay(templatable(config[CONF_DELAY], arg_type, uint32))) action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
return action template_ = None
for template_ in templatable(config[CONF_DELAY], arg_type, uint32):
yield
add(action.set_delay(template_))
yield action
elif CONF_LAMBDA in config: elif CONF_LAMBDA in config:
rhs = LambdaAction.new(template_arg, process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')])) lambda_ = None
return Pvariable(LambdaAction.template(template_arg), config[CONF_ACTION_ID], rhs) for lambda_ in process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')]):
yield None
rhs = LambdaAction.new(template_arg, lambda_)
type = LambdaAction.template(template_arg)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_MQTT_PUBLISH in config: elif CONF_MQTT_PUBLISH in config:
conf = config[CONF_MQTT_PUBLISH] conf = config[CONF_MQTT_PUBLISH]
rhs = App.Pget_mqtt_client().Pmake_publish_action() rhs = App.Pget_mqtt_client().Pmake_publish_action(template_arg)
action = Pvariable(mqtt.MQTTPublishAction.template(template_arg), config[CONF_ACTION_ID], type = mqtt.MQTTPublishAction.template(template_arg)
rhs) action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
add(action.set_topic(templatable(conf[CONF_TOPIC], arg_type, std_string))) template_ = None
add(action.set_payload(templatable(conf[CONF_PAYLOAD], arg_type, std_string))) for template_ in templatable(conf[CONF_TOPIC], arg_type, std_string):
yield None
add(action.set_topic(template_))
template_ = None
for template_ in templatable(conf[CONF_PAYLOAD], arg_type, std_string):
yield None
add(action.set_payload(template_))
if CONF_QOS in conf: if CONF_QOS in conf:
add(action.set_qos(templatable(conf[CONF_QOS], arg_type, uint8))) template_ = None
for template_ in templatable(conf[CONF_QOS], arg_type, uint8):
yield
add(action.set_qos(template_))
if CONF_RETAIN in conf: if CONF_RETAIN in conf:
add(action.set_retain(templatable(conf[CONF_RETAIN], arg_type, bool_))) template_ = None
return action for template_ in templatable(conf[CONF_RETAIN], arg_type, bool_):
yield None
add(action.set_retain(template_))
yield action
elif CONF_LIGHT_TOGGLE in config: elif CONF_LIGHT_TOGGLE in config:
conf = config[CONF_LIGHT_TOGGLE] conf = config[CONF_LIGHT_TOGGLE]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_toggle_action(template_arg) rhs = var.make_toggle_action(template_arg)
action = Pvariable(light.ToggleAction.template(template_arg), config[CONF_ACTION_ID], rhs) type = light.ToggleAction.template(template_arg)
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
if CONF_TRANSITION_LENGTH in conf: if CONF_TRANSITION_LENGTH in conf:
add(action.set_transition_length( template_ = None
templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32) for template_ in templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32):
)) yield None
return action add(action.set_transition_length(template_))
yield action
elif CONF_LIGHT_TURN_OFF in config: elif CONF_LIGHT_TURN_OFF in config:
conf = config[CONF_LIGHT_TURN_OFF] conf = config[CONF_LIGHT_TURN_OFF]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_turn_off_action(template_arg) rhs = var.make_turn_off_action(template_arg)
action = Pvariable(light.TurnOffAction.template(template_arg), config[CONF_ACTION_ID], rhs) type = light.TurnOffAction.template(template_arg)
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
if CONF_TRANSITION_LENGTH in conf: if CONF_TRANSITION_LENGTH in conf:
add(action.set_transition_length( template_ = None
templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32) for template_ in templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32):
)) yield None
return action add(action.set_transition_length(template_))
yield action
elif CONF_LIGHT_TURN_ON in config: elif CONF_LIGHT_TURN_ON in config:
conf = config[CONF_LIGHT_TURN_ON] conf = config[CONF_LIGHT_TURN_ON]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_turn_on_action(template_arg) rhs = var.make_turn_on_action(template_arg)
action = Pvariable(light.TurnOnAction.template(template_arg), config[CONF_ACTION_ID], rhs) type = light.TurnOnAction.template(template_arg)
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
if CONF_TRANSITION_LENGTH in conf: if CONF_TRANSITION_LENGTH in conf:
add(action.set_transition_length( template_ = None
templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32) for template_ in templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32):
)) yield None
add(action.set_transition_length(template_))
if CONF_FLASH_LENGTH in conf: if CONF_FLASH_LENGTH in conf:
add(action.set_flash_length(templatable(conf[CONF_FLASH_LENGTH], arg_type, uint32))) template_ = None
for template_ in templatable(conf[CONF_FLASH_LENGTH], arg_type, uint32):
yield None
add(action.set_flash_length(template_))
if CONF_BRIGHTNESS in conf: if CONF_BRIGHTNESS in conf:
add(action.set_brightness(templatable(conf[CONF_BRIGHTNESS], arg_type, float_))) template_ = None
for template_ in templatable(conf[CONF_BRIGHTNESS], arg_type, float_):
yield None
add(action.set_brightness(template_))
if CONF_RED in conf: if CONF_RED in conf:
add(action.set_red(templatable(conf[CONF_RED], arg_type, float_))) template_ = None
for template_ in templatable(conf[CONF_RED], arg_type, float_):
yield None
add(action.set_red(template_))
if CONF_GREEN in conf: if CONF_GREEN in conf:
add(action.set_green(templatable(conf[CONF_GREEN], arg_type, float_))) template_ = None
for template_ in templatable(conf[CONF_GREEN], arg_type, float_):
yield None
add(action.set_green(template_))
if CONF_BLUE in conf: if CONF_BLUE in conf:
add(action.set_blue(templatable(conf[CONF_BLUE], arg_type, float_))) template_ = None
for template_ in templatable(conf[CONF_BLUE], arg_type, float_):
yield None
add(action.set_blue(template_))
if CONF_WHITE in conf: if CONF_WHITE in conf:
add(action.set_white(templatable(conf[CONF_WHITE], arg_type, float_))) template_ = None
for template_ in templatable(conf[CONF_WHITE], arg_type, float_):
yield None
add(action.set_white(template_))
if CONF_EFFECT in conf: if CONF_EFFECT in conf:
add(action.set_effect(templatable(conf[CONF_EFFECT], arg_type, std_string))) template_ = None
return action for template_ in templatable(conf[CONF_EFFECT], arg_type, std_string):
yield None
add(action.set_effect(template_))
yield action
elif CONF_SWITCH_TOGGLE in config: elif CONF_SWITCH_TOGGLE in config:
conf = config[CONF_SWITCH_TOGGLE] conf = config[CONF_SWITCH_TOGGLE]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_toggle_action(template_arg) rhs = var.make_toggle_action(template_arg)
return Pvariable(switch.ToggleAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = switch.ToggleAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_SWITCH_TURN_OFF in config: elif CONF_SWITCH_TURN_OFF in config:
conf = config[CONF_SWITCH_TURN_OFF] conf = config[CONF_SWITCH_TURN_OFF]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_turn_off_action(template_arg) rhs = var.make_turn_off_action(template_arg)
return Pvariable(switch.TurnOffAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = switch.TurnOffAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_SWITCH_TURN_ON in config: elif CONF_SWITCH_TURN_ON in config:
conf = config[CONF_SWITCH_TURN_ON] conf = config[CONF_SWITCH_TURN_ON]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_turn_on_action(template_arg) rhs = var.make_turn_on_action(template_arg)
return Pvariable(switch.TurnOnAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = switch.TurnOnAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_COVER_OPEN in config: elif CONF_COVER_OPEN in config:
conf = config[CONF_COVER_OPEN] conf = config[CONF_COVER_OPEN]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_open_action(template_arg) rhs = var.make_open_action(template_arg)
return Pvariable(cover.OpenAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = cover.OpenAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_COVER_CLOSE in config: elif CONF_COVER_CLOSE in config:
conf = config[CONF_COVER_CLOSE] conf = config[CONF_COVER_CLOSE]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_close_action(template_arg) rhs = var.make_close_action(template_arg)
return Pvariable(cover.CloseAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = cover.CloseAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_COVER_STOP in config: elif CONF_COVER_STOP in config:
conf = config[CONF_COVER_STOP] conf = config[CONF_COVER_STOP]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_stop_action(template_arg) rhs = var.make_stop_action(template_arg)
return Pvariable(cover.StopAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = cover.StopAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_FAN_TOGGLE in config: elif CONF_FAN_TOGGLE in config:
conf = config[CONF_FAN_TOGGLE] conf = config[CONF_FAN_TOGGLE]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_toggle_action(template_arg) rhs = var.make_toggle_action(template_arg)
return Pvariable(fan.ToggleAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = fan.ToggleAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_FAN_TURN_OFF in config: elif CONF_FAN_TURN_OFF in config:
conf = config[CONF_FAN_TURN_OFF] conf = config[CONF_FAN_TURN_OFF]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_turn_off_action(template_arg) rhs = var.make_turn_off_action(template_arg)
return Pvariable(fan.TurnOffAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = fan.TurnOffAction.template(arg_type)
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_FAN_TURN_ON in config: elif CONF_FAN_TURN_ON in config:
conf = config[CONF_FAN_TURN_ON] conf = config[CONF_FAN_TURN_ON]
var = get_variable(conf[CONF_ID]) for var in get_variable(conf[CONF_ID]):
yield None
rhs = var.make_turn_on_action(template_arg) rhs = var.make_turn_on_action(template_arg)
action = Pvariable(fan.TurnOnAction.template(arg_type), config[CONF_ACTION_ID], rhs) type = fan.TurnOnAction.template(arg_type)
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
if CONF_OSCILLATING in config: if CONF_OSCILLATING in config:
add(action.set_oscillating(templatable(conf[CONF_OSCILLATING], arg_type, bool_))) template_ = None
for template_ in templatable(conf[CONF_OSCILLATING], arg_type, bool_):
yield None
add(action.set_oscillating(template_))
if CONF_SPEED in config: if CONF_SPEED in config:
add(action.set_speed(templatable(conf[CONF_SPEED], arg_type, fan.FanSpeed))) template_ = None
return action for template_ in templatable(conf[CONF_SPEED], arg_type, fan.FanSpeed):
raise ESPHomeYAMLError(u"Unsupported action {}".format(config)) yield None
add(action.set_speed(template_))
yield action
else:
raise ESPHomeYAMLError(u"Unsupported action {}".format(config))
def build_actions(config, arg_type): def build_actions(config, arg_type):
return ArrayInitializer(*[build_action(x, arg_type) for x in config]) actions = []
for conf in config:
action = None
for action in build_action(conf, arg_type):
yield None
actions.append(action)
yield ArrayInitializer(*actions, multiline=False)
def build_automation_(trigger, arg_type, config):
rhs = App.make_automation(trigger)
type = Automation.template(arg_type)
obj = Pvariable(config[CONF_AUTOMATION_ID], rhs, type=type)
if CONF_IF in config:
conditions = None
for conditions in build_conditions(config[CONF_IF], arg_type):
yield
add(obj.add_conditions(conditions))
actions = None
for actions in build_actions(config[CONF_THEN], arg_type):
yield
add(obj.add_actions(actions))
def build_automation(trigger, arg_type, config): def build_automation(trigger, arg_type, config):
rhs = App.make_automation(trigger) add_job(build_automation_, trigger, arg_type, config)
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)))

10
esphomeyaml/build.json Normal file
View File

@@ -0,0 +1,10 @@
{
"squash": false,
"build_from": {
"aarch64": "arm64v8/ubuntu:bionic",
"amd64": "ubuntu:bionic",
"armhf": "homeassistant/armhf-base:latest",
"i386": "i386/ubuntu:bionic"
},
"args": {}
}

View File

@@ -12,7 +12,7 @@ ADS1115Component = sensor.sensor_ns.ADS1115Component
RATE_REMOVE_MESSAGE = """The rate option has been removed in 1.5.0 and is no longer required.""" RATE_REMOVE_MESSAGE = """The rate option has been removed in 1.5.0 and is no longer required."""
ADS1115_SCHEMA = vol.Schema({ ADS1115_SCHEMA = vol.Schema({
cv.GenerateID('ads1115'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(ADS1115Component),
vol.Required(CONF_ADDRESS): cv.i2c_address, vol.Required(CONF_ADDRESS): cv.i2c_address,
vol.Optional(CONF_RATE): cv.invalid(RATE_REMOVE_MESSAGE) vol.Optional(CONF_RATE): cv.invalid(RATE_REMOVE_MESSAGE)
@@ -24,7 +24,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [ADS1115_SCHEMA])
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_ads1115_component(conf[CONF_ADDRESS]) rhs = App.make_ads1115_component(conf[CONF_ADDRESS])
Pvariable(ADS1115Component, conf[CONF_ID], rhs) Pvariable(conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_ADS1115_SENSOR' BUILD_FLAGS = '-DUSE_ADS1115_SENSOR'

View File

@@ -5,7 +5,8 @@ from esphomeyaml import automation
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INVERTED, CONF_MAX_LENGTH, \ 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_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, CONF_ON_PRESS, \
CONF_ON_RELEASE, CONF_TRIGGER_ID CONF_ON_RELEASE, CONF_TRIGGER_ID
from esphomeyaml.helpers import App, NoArg, Pvariable, add, esphomelib_ns, setup_mqtt_component from esphomeyaml.helpers import App, NoArg, Pvariable, add, esphomelib_ns, setup_mqtt_component, \
add_job
DEVICE_CLASSES = [ DEVICE_CLASSES = [
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas', '', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
@@ -27,18 +28,24 @@ BinarySensor = binary_sensor_ns.BinarySensor
MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent
BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
cv.GenerateID('mqtt_binary_sensor', CONF_MQTT_ID): cv.register_variable_id, cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTBinarySensorComponent),
cv.GenerateID('binary_sensor'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(BinarySensor),
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_INVERTED): cv.boolean,
vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower, cv.one_of(*DEVICE_CLASSES)), 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_PRESS): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(PressTrigger),
})]),
vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ReleaseTrigger),
})]),
vol.Optional(CONF_ON_CLICK): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ vol.Optional(CONF_ON_CLICK): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ClickTrigger),
vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds, 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_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
})]), })]),
vol.Optional(CONF_ON_DOUBLE_CLICK): vol.Optional(CONF_ON_DOUBLE_CLICK):
vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(DoubleClickTrigger),
vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds, 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_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
})]), })]),
@@ -53,43 +60,41 @@ def setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config):
for conf in config.get(CONF_ON_PRESS, []): for conf in config.get(CONF_ON_PRESS, []):
rhs = binary_sensor_var.make_press_trigger() rhs = binary_sensor_var.make_press_trigger()
trigger = Pvariable(PressTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_RELEASE, []): for conf in config.get(CONF_ON_RELEASE, []):
rhs = binary_sensor_var.make_release_trigger() rhs = binary_sensor_var.make_release_trigger()
trigger = Pvariable(ReleaseTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_CLICK, []): for conf in config.get(CONF_ON_CLICK, []):
rhs = binary_sensor_var.make_click_trigger(conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH]) rhs = binary_sensor_var.make_click_trigger(conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH])
trigger = Pvariable(ClickTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_DOUBLE_CLICK, []): for conf in config.get(CONF_ON_DOUBLE_CLICK, []):
rhs = binary_sensor_var.make_double_click_trigger(conf[CONF_MIN_LENGTH], rhs = binary_sensor_var.make_double_click_trigger(conf[CONF_MIN_LENGTH],
conf[CONF_MAX_LENGTH]) conf[CONF_MAX_LENGTH])
trigger = Pvariable(DoubleClickTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
setup_mqtt_component(mqtt_var, config) setup_mqtt_component(mqtt_var, config)
def setup_binary_sensor(binary_sensor_obj, mqtt_obj, config): def setup_binary_sensor(binary_sensor_obj, mqtt_obj, config):
binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], binary_sensor_obj, binary_sensor_var = Pvariable(config[CONF_ID], binary_sensor_obj,
has_side_effects=False) has_side_effects=False)
mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj,
has_side_effects=False) has_side_effects=False)
setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config) add_job(setup_binary_sensor_core_, binary_sensor_var, mqtt_var, config)
def register_binary_sensor(var, config): def register_binary_sensor(var, config):
binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], var, binary_sensor_var = Pvariable(config[CONF_ID], var, has_side_effects=True)
has_side_effects=True)
rhs = App.register_binary_sensor(binary_sensor_var) rhs = App.register_binary_sensor(binary_sensor_var)
mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], rhs, mqtt_var = Pvariable(config[CONF_MQTT_ID], rhs, has_side_effects=True)
has_side_effects=True) add_job(setup_binary_sensor_core_, binary_sensor_var, mqtt_var, config)
setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_BINARY_SENSOR'

View File

@@ -10,6 +10,8 @@ from esphomeyaml.helpers import ArrayInitializer, get_variable
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_ble'] DEPENDENCIES = ['esp32_ble']
CONF_ESP32_BLE_ID = 'esp32_ble_id'
def validate_mac(value): def validate_mac(value):
value = cv.string_strict(value) value = cv.string_strict(value)
@@ -30,11 +32,14 @@ def validate_mac(value):
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
vol.Required(CONF_MAC_ADDRESS): validate_mac, vol.Required(CONF_MAC_ADDRESS): validate_mac,
cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_variable_id(ESP32BLETracker)
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) }).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
hub = get_variable(None, type=ESP32BLETracker) hub = None
for hub in get_variable(config[CONF_ESP32_BLE_ID]):
yield
addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts] addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts]
rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False)) rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False))
binary_sensor.register_binary_sensor(rhs, config) binary_sensor.register_binary_sensor(rhs, config)

View File

@@ -11,6 +11,8 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_touch'] DEPENDENCIES = ['esp32_touch']
CONF_ESP32_TOUCH_ID = 'esp32_touch_id'
TOUCH_PADS = { TOUCH_PADS = {
4: global_ns.TOUCH_PAD_NUM0, 4: global_ns.TOUCH_PAD_NUM0,
0: global_ns.TOUCH_PAD_NUM1, 0: global_ns.TOUCH_PAD_NUM1,
@@ -35,11 +37,14 @@ def validate_touch_pad(value):
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
vol.Required(CONF_PIN): validate_touch_pad, vol.Required(CONF_PIN): validate_touch_pad,
vol.Required(CONF_THRESHOLD): cv.uint16_t, vol.Required(CONF_THRESHOLD): cv.uint16_t,
cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_variable_id(ESP32TouchComponent),
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema) }).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
hub = get_variable(None, type=ESP32TouchComponent) hub = None
for hub in get_variable(config[CONF_ESP32_TOUCH_ID]):
yield
touch_pad = TOUCH_PADS[config[CONF_PIN]] touch_pad = TOUCH_PADS[config[CONF_PIN]]
rhs = hub.make_touch_pad(config[CONF_NAME], touch_pad, config[CONF_THRESHOLD]) rhs = hub.make_touch_pad(config[CONF_NAME], touch_pad, config[CONF_THRESHOLD])
binary_sensor.register_binary_sensor(rhs, config) binary_sensor.register_binary_sensor(rhs, config)

View File

@@ -6,18 +6,20 @@ from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN
from esphomeyaml.helpers import App, gpio_input_pin_expression, variable, Application from esphomeyaml.helpers import App, gpio_input_pin_expression, variable, Application
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('gpio_binary_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.GPIO_INPUT_PIN_SCHEMA
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
MakeGPIOBinarySensor = Application.MakeGPIOBinarySensor MakeGPIOBinarySensor = Application.MakeGPIOBinarySensor
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeGPIOBinarySensor),
vol.Required(CONF_PIN): pins.gpio_input_pin_schema
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
rhs = App.make_gpio_binary_sensor(config[CONF_NAME], pin = None
gpio_input_pin_expression(config[CONF_PIN])) for pin in gpio_input_pin_expression(config[CONF_PIN]):
gpio = variable(MakeGPIOBinarySensor, config[CONF_MAKE_ID], rhs) yield
rhs = App.make_gpio_binary_sensor(config[CONF_NAME], pin)
gpio = variable(config[CONF_MAKE_ID], rhs)
binary_sensor.setup_binary_sensor(gpio.Pgpio, gpio.Pmqtt, config) binary_sensor.setup_binary_sensor(gpio.Pgpio, gpio.Pmqtt, config)

View File

@@ -5,16 +5,16 @@ from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['mqtt'] DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('status_binary_sensor', CONF_MAKE_ID): cv.register_variable_id,
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
MakeStatusBinarySensor = Application.MakeStatusBinarySensor MakeStatusBinarySensor = Application.MakeStatusBinarySensor
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeStatusBinarySensor),
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
rhs = App.make_status_binary_sensor(config[CONF_NAME]) rhs = App.make_status_binary_sensor(config[CONF_NAME])
status = variable(MakeStatusBinarySensor, config[CONF_MAKE_ID], rhs) status = variable(config[CONF_MAKE_ID], rhs)
binary_sensor.setup_binary_sensor(status.Pstatus, status.Pmqtt, config) binary_sensor.setup_binary_sensor(status.Pstatus, status.Pmqtt, config)

View File

@@ -3,20 +3,23 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME
from esphomeyaml.helpers import App, Application, process_lambda, variable from esphomeyaml.helpers import App, Application, process_lambda, variable, optional, bool_
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 MakeTemplateBinarySensor = Application.MakeTemplateBinarySensor
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeTemplateBinarySensor),
vol.Required(CONF_LAMBDA): cv.lambda_,
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
template_ = process_lambda(config[CONF_LAMBDA], []) template_ = None
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(bool_)):
yield
rhs = App.make_template_binary_sensor(config[CONF_NAME], template_) rhs = App.make_template_binary_sensor(config[CONF_NAME], template_)
make = variable(MakeTemplateBinarySensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
binary_sensor.setup_binary_sensor(make.Ptemplate_, make.Pmqtt, config) binary_sensor.setup_binary_sensor(make.Ptemplate_, make.Pmqtt, config)

View File

@@ -6,11 +6,6 @@ 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_ns = esphomelib_ns.namespace('cover')
Cover = cover_ns.Cover Cover = cover_ns.Cover
MQTTCoverComponent = cover_ns.MQTTCoverComponent MQTTCoverComponent = cover_ns.MQTTCoverComponent
@@ -21,15 +16,19 @@ OpenAction = cover_ns.OpenAction
CloseAction = cover_ns.CloseAction CloseAction = cover_ns.CloseAction
StopAction = cover_ns.StopAction StopAction = cover_ns.StopAction
COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(Cover),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTCoverComponent),
})
def setup_cover_core_(cover_var, mqtt_var, config): def setup_cover_core_(cover_var, mqtt_var, config):
setup_mqtt_component(mqtt_var, config) setup_mqtt_component(mqtt_var, config)
def setup_cover(cover_obj, mqtt_obj, config): def setup_cover(cover_obj, mqtt_obj, config):
cover_var = Pvariable(Cover, config[CONF_ID], cover_obj, has_side_effects=False) cover_var = Pvariable(config[CONF_ID], cover_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTCoverComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False)
setup_cover_core_(cover_var, mqtt_var, config) setup_cover_core_(cover_var, mqtt_var, config)

View File

@@ -5,35 +5,44 @@ from esphomeyaml import automation
from esphomeyaml.components import cover from esphomeyaml.components import cover
from esphomeyaml.const import CONF_CLOSE_ACTION, CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, \ from esphomeyaml.const import CONF_CLOSE_ACTION, CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, \
CONF_OPEN_ACTION, CONF_STOP_ACTION, CONF_OPTIMISTIC CONF_OPEN_ACTION, CONF_STOP_ACTION, CONF_OPTIMISTIC
from esphomeyaml.helpers import App, Application, NoArg, add, process_lambda, variable from esphomeyaml.helpers import App, Application, NoArg, add, process_lambda, variable, optional
MakeTemplateCover = Application.MakeTemplateCover
PLATFORM_SCHEMA = vol.All(cover.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(cover.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_cover', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeTemplateCover),
vol.Optional(CONF_LAMBDA): cv.lambda_, vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_OPTIMISTIC): cv.boolean, vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_OPEN_ACTION): automation.ACTIONS_SCHEMA, vol.Optional(CONF_OPEN_ACTION): automation.ACTIONS_SCHEMA,
vol.Optional(CONF_CLOSE_ACTION): automation.ACTIONS_SCHEMA, vol.Optional(CONF_CLOSE_ACTION): automation.ACTIONS_SCHEMA,
vol.Optional(CONF_STOP_ACTION): automation.ACTIONS_SCHEMA, vol.Optional(CONF_STOP_ACTION): automation.ACTIONS_SCHEMA,
}).extend(cover.COVER_SCHEMA.schema), cv.has_at_exactly_one_key(CONF_LAMBDA, CONF_OPTIMISTIC)) }).extend(cover.COVER_SCHEMA.schema), cv.has_at_least_one_key(CONF_LAMBDA, CONF_OPTIMISTIC))
MakeTemplateCover = Application.MakeTemplateCover
def to_code(config): def to_code(config):
rhs = App.make_template_cover(config[CONF_NAME]) rhs = App.make_template_cover(config[CONF_NAME])
make = variable(MakeTemplateCover, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
if CONF_LAMBDA in config: if CONF_LAMBDA in config:
template_ = process_lambda(config[CONF_LAMBDA], []) template_ = None
add(make.Ptemplate.set_state_lambda(template_)) for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(cover.CoverState)):
yield
add(make.Ptemplate_.set_state_lambda(template_))
if CONF_OPEN_ACTION in config: if CONF_OPEN_ACTION in config:
actions = automation.build_actions(config[CONF_OPEN_ACTION], NoArg) actions = None
for actions in automation.build_actions(config[CONF_OPEN_ACTION], NoArg):
yield
add(make.Ptemplate_.add_open_actions(actions)) add(make.Ptemplate_.add_open_actions(actions))
if CONF_CLOSE_ACTION in config: if CONF_CLOSE_ACTION in config:
actions = automation.build_actions(config[CONF_CLOSE_ACTION], NoArg) actions = None
for actions in automation.build_actions(config[CONF_CLOSE_ACTION], NoArg):
yield
add(make.Ptemplate_.add_close_actions(actions)) add(make.Ptemplate_.add_close_actions(actions))
if CONF_STOP_ACTION in config: if CONF_STOP_ACTION in config:
actions = automation.build_actions(config[CONF_STOP_ACTION], NoArg) actions = None
for actions in automation.build_actions(config[CONF_STOP_ACTION], NoArg):
yield
add(make.Ptemplate_.add_stop_actions(actions)) add(make.Ptemplate_.add_stop_actions(actions))
if CONF_OPTIMISTIC in config: if CONF_OPTIMISTIC in config:
add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC])) add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC]))

View File

@@ -9,7 +9,7 @@ from esphomeyaml.helpers import App, Pvariable
DallasComponent = sensor.sensor_ns.DallasComponent DallasComponent = sensor.sensor_ns.DallasComponent
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
cv.GenerateID('dallas'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(DallasComponent),
vol.Required(CONF_PIN): pins.input_output_pin, vol.Required(CONF_PIN): pins.input_output_pin,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
})]) })])
@@ -18,7 +18,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_dallas_component(conf[CONF_PIN], conf.get(CONF_UPDATE_INTERVAL)) rhs = App.make_dallas_component(conf[CONF_PIN], conf.get(CONF_UPDATE_INTERVAL))
Pvariable(DallasComponent, conf[CONF_ID], rhs) Pvariable(conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_DALLAS_SENSOR' BUILD_FLAGS = '-DUSE_DALLAS_SENSOR'

View File

@@ -14,26 +14,40 @@ def validate_pin_number(value):
return value return value
DeepSleepComponent = esphomelib_ns.DeepSleepComponent
WAKEUP_PIN_MODES = {
'IGNORE': esphomelib_ns.WAKEUP_PIN_MODE_IGNORE,
'KEEP_AWAKE': esphomelib_ns.WAKEUP_PIN_MODE_KEEP_AWAKE,
'INVERT_WAKEUP': esphomelib_ns.WAKEUP_PIN_MODE_INVERT_WAKEUP,
}
CONF_WAKEUP_PIN_MODE = 'wakeup_pin_mode'
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('deep_sleep'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(DeepSleepComponent),
vol.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, vol.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
vol.Optional(CONF_WAKEUP_PIN): vol.All(cv.only_on_esp32, pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Optional(CONF_WAKEUP_PIN): vol.All(cv.only_on_esp32, pins.internal_gpio_input_pin_schema,
validate_pin_number), validate_pin_number),
vol.Optional(CONF_WAKEUP_PIN_MODE): vol.All(cv.only_on_esp32, vol.Upper,
cv.one_of(*WAKEUP_PIN_MODES)),
vol.Optional(CONF_RUN_CYCLES): cv.positive_int, vol.Optional(CONF_RUN_CYCLES): cv.positive_int,
vol.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds, vol.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds,
}) })
DeepSleepComponent = esphomelib_ns.DeepSleepComponent
def to_code(config): def to_code(config):
rhs = App.make_deep_sleep_component() rhs = App.make_deep_sleep_component()
deep_sleep = Pvariable(DeepSleepComponent, config[CONF_ID], rhs) deep_sleep = Pvariable(config[CONF_ID], rhs)
if CONF_SLEEP_DURATION in config: if CONF_SLEEP_DURATION in config:
add(deep_sleep.set_sleep_duration(config[CONF_SLEEP_DURATION])) add(deep_sleep.set_sleep_duration(config[CONF_SLEEP_DURATION]))
if CONF_WAKEUP_PIN in config: if CONF_WAKEUP_PIN in config:
pin = gpio_input_pin_expression(config[CONF_WAKEUP_PIN]) pin = None
for pin in gpio_input_pin_expression(config[CONF_WAKEUP_PIN]):
yield
add(deep_sleep.set_wakeup_pin(pin)) add(deep_sleep.set_wakeup_pin(pin))
if CONF_WAKEUP_PIN_MODE in config:
add(deep_sleep.set_wakeup_pin_mode(WAKEUP_PIN_MODES[config[CONF_WAKEUP_PIN_MODE]]))
if CONF_RUN_CYCLES in config: if CONF_RUN_CYCLES in config:
add(deep_sleep.set_run_cycles(config[CONF_RUN_CYCLES])) add(deep_sleep.set_run_cycles(config[CONF_RUN_CYCLES]))
if CONF_RUN_DURATION in config: if CONF_RUN_DURATION in config:

View File

@@ -6,17 +6,17 @@ from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
ESP32BLETracker = esphomelib_ns.ESP32BLETracker
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('esp32_ble'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(ESP32BLETracker),
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds,
}) })
ESP32BLETracker = esphomelib_ns.ESP32BLETracker
def to_code(config): def to_code(config):
rhs = App.make_esp32_ble_tracker() rhs = App.make_esp32_ble_tracker()
ble = Pvariable(ESP32BLETracker, config[CONF_ID], rhs) ble = Pvariable(config[CONF_ID], rhs)
if CONF_SCAN_INTERVAL in config: if CONF_SCAN_INTERVAL in config:
add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL])) add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL]))

View File

@@ -41,8 +41,10 @@ VOLTAGE_ATTENUATION = {
'0V': global_ns.TOUCH_HVOLT_ATTEN_0V, '0V': global_ns.TOUCH_HVOLT_ATTEN_0V,
} }
ESP32TouchComponent = binary_sensor.binary_sensor_ns.ESP32TouchComponent
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('esp32_ble'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(ESP32TouchComponent),
vol.Optional(CONF_SETUP_MODE): cv.boolean, vol.Optional(CONF_SETUP_MODE): cv.boolean,
vol.Optional(CONF_IIR_FILTER): cv.positive_time_period_milliseconds, vol.Optional(CONF_IIR_FILTER): cv.positive_time_period_milliseconds,
vol.Optional(CONF_SLEEP_DURATION): vol.Optional(CONF_SLEEP_DURATION):
@@ -54,18 +56,16 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_VOLTAGE_ATTENUATION): validate_voltage(VOLTAGE_ATTENUATION), vol.Optional(CONF_VOLTAGE_ATTENUATION): validate_voltage(VOLTAGE_ATTENUATION),
}) })
ESP32TouchComponent = binary_sensor.binary_sensor_ns.ESP32TouchComponent
def to_code(config): def to_code(config):
rhs = App.make_esp32_touch_component() rhs = App.make_esp32_touch_component()
touch = Pvariable(ESP32TouchComponent, config[CONF_ID], rhs) touch = Pvariable(config[CONF_ID], rhs)
if CONF_SETUP_MODE in config: if CONF_SETUP_MODE in config:
add(touch.set_setup_mode(config[CONF_SETUP_MODE])) add(touch.set_setup_mode(config[CONF_SETUP_MODE]))
if CONF_IIR_FILTER in config: if CONF_IIR_FILTER in config:
add(touch.set_iir_filter(config[CONF_IIR_FILTER])) add(touch.set_iir_filter(config[CONF_IIR_FILTER]))
if CONF_SLEEP_DURATION in config: if CONF_SLEEP_DURATION in config:
sleep_duration = int(config[CONF_SLEEP_DURATION].total_microseconds * 6.6667) sleep_duration = int(config[CONF_SLEEP_DURATION].total_microseconds * 0.15)
add(touch.set_sleep_duration(sleep_duration)) add(touch.set_sleep_duration(sleep_duration))
if CONF_MEASUREMENT_DURATION in config: if CONF_MEASUREMENT_DURATION in config:
measurement_duration = int(config[CONF_MEASUREMENT_DURATION].total_microseconds * 0.125) measurement_duration = int(config[CONF_MEASUREMENT_DURATION].total_microseconds * 0.125)

View File

@@ -9,13 +9,6 @@ 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,
})
fan_ns = esphomelib_ns.namespace('fan') fan_ns = esphomelib_ns.namespace('fan')
FanState = fan_ns.FanState FanState = fan_ns.FanState
MQTTFanComponent = fan_ns.MQTTFanComponent MQTTFanComponent = fan_ns.MQTTFanComponent
@@ -29,6 +22,13 @@ FAN_SPEED_LOW = fan_ns.FAN_SPEED_LOW
FAN_SPEED_MEDIUM = fan_ns.FAN_SPEED_MEDIUM FAN_SPEED_MEDIUM = fan_ns.FAN_SPEED_MEDIUM
FAN_SPEED_HIGH = fan_ns.FAN_SPEED_HIGH FAN_SPEED_HIGH = fan_ns.FAN_SPEED_HIGH
FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(FanState),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTFanComponent),
vol.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.publish_topic,
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic,
})
FAN_SPEEDS = { FAN_SPEEDS = {
'OFF': FAN_SPEED_OFF, 'OFF': FAN_SPEED_OFF,
@@ -55,8 +55,8 @@ def setup_fan_core_(fan_var, mqtt_var, config):
def setup_fan(fan_obj, mqtt_obj, config): def setup_fan(fan_obj, mqtt_obj, config):
fan_var = Pvariable(FanState, config[CONF_ID], fan_obj, has_side_effects=False) fan_var = Pvariable(config[CONF_ID], fan_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTFanComponent, config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False) mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
setup_fan_core_(fan_var, mqtt_var, config) setup_fan_core_(fan_var, mqtt_var, config)

View File

@@ -6,19 +6,24 @@ from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OSCILLATION_OUTPUT,
from esphomeyaml.helpers import App, add, get_variable, variable from esphomeyaml.helpers import App, add, get_variable, variable
PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
cv.GenerateID('binary_fan', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(fan.MakeFan),
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id, vol.Optional(CONF_OSCILLATION_OUTPUT): cv.use_variable_id(None),
}).extend(fan.FAN_SCHEMA.schema) }).extend(fan.FAN_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = None
for output in get_variable(config[CONF_OUTPUT]):
yield
rhs = App.make_fan(config[CONF_NAME]) rhs = App.make_fan(config[CONF_NAME])
fan_struct = variable(fan.MakeFan, config[CONF_MAKE_ID], rhs) fan_struct = variable(config[CONF_MAKE_ID], rhs)
add(fan_struct.Poutput.set_binary(output)) add(fan_struct.Poutput.set_binary(output))
if CONF_OSCILLATION_OUTPUT in config: if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT]) oscillation_output = None
for oscillation_output in get_variable(config[CONF_OSCILLATION_OUTPUT]):
yield
add(fan_struct.Poutput.set_oscillation(oscillation_output)) add(fan_struct.Poutput.set_oscillation(oscillation_output))
fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config) fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config)

View File

@@ -8,11 +8,11 @@ from esphomeyaml.const import CONF_HIGH, CONF_LOW, CONF_MAKE_ID, CONF_MEDIUM, CO
from esphomeyaml.helpers import App, add, get_variable, variable from esphomeyaml.helpers import App, add, get_variable, variable
PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
cv.GenerateID('speed_fan', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(fan.MakeFan),
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
vol.Optional(CONF_SPEED_STATE_TOPIC): cv.publish_topic, vol.Optional(CONF_SPEED_STATE_TOPIC): cv.publish_topic,
vol.Optional(CONF_SPEED_COMMAND_TOPIC): cv.subscribe_topic, vol.Optional(CONF_SPEED_COMMAND_TOPIC): cv.subscribe_topic,
vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id, vol.Optional(CONF_OSCILLATION_OUTPUT): cv.use_variable_id(None),
vol.Optional(CONF_SPEED): vol.Schema({ vol.Optional(CONF_SPEED): vol.Schema({
vol.Required(CONF_LOW): cv.percentage, vol.Required(CONF_LOW): cv.percentage,
vol.Required(CONF_MEDIUM): cv.percentage, vol.Required(CONF_MEDIUM): cv.percentage,
@@ -22,9 +22,11 @@ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = None
for output in get_variable(config[CONF_OUTPUT]):
yield
rhs = App.make_fan(config[CONF_NAME]) rhs = App.make_fan(config[CONF_NAME])
fan_struct = variable(fan.MakeFan, config[CONF_MAKE_ID], rhs) fan_struct = variable(config[CONF_MAKE_ID], rhs)
if CONF_SPEED in config: if CONF_SPEED in config:
speeds = config[CONF_SPEED] speeds = config[CONF_SPEED]
add(fan_struct.Poutput.set_speed(output, 0.0, add(fan_struct.Poutput.set_speed(output, 0.0,
@@ -35,7 +37,9 @@ def to_code(config):
add(fan_struct.Poutput.set_speed(output)) add(fan_struct.Poutput.set_speed(output))
if CONF_OSCILLATION_OUTPUT in config: if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT]) oscillation_output = None
for oscillation_output in get_variable(config[CONF_OSCILLATION_OUTPUT]):
yield
add(fan_struct.Poutput.set_oscillation(oscillation_output)) add(fan_struct.Poutput.set_oscillation(oscillation_output))
fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config) fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config)

View File

@@ -6,21 +6,21 @@ from esphomeyaml.const import CONF_FREQUENCY, CONF_SCL, CONF_SDA, CONF_SCAN, CON
CONF_RECEIVE_TIMEOUT CONF_RECEIVE_TIMEOUT
from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns
I2CComponent = esphomelib_ns.I2CComponent
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('i2c'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(I2CComponent),
vol.Required(CONF_SDA, default='SDA'): pins.input_output_pin, vol.Required(CONF_SDA, default='SDA'): pins.input_output_pin,
vol.Required(CONF_SCL, default='SCL'): pins.input_output_pin, vol.Required(CONF_SCL, default='SCL'): pins.input_output_pin,
vol.Optional(CONF_FREQUENCY): cv.positive_int, vol.Optional(CONF_FREQUENCY): vol.All(cv.frequency, vol.Range(min=0, min_included=False)),
vol.Optional(CONF_RECEIVE_TIMEOUT): cv.positive_time_period_milliseconds, vol.Optional(CONF_RECEIVE_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_SCAN): cv.boolean, vol.Optional(CONF_SCAN): cv.boolean,
}) })
I2CComponent = esphomelib_ns.I2CComponent
def to_code(config): def to_code(config):
rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN)) rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN))
i2c = Pvariable(I2CComponent, config[CONF_ID], rhs) i2c = Pvariable(config[CONF_ID], rhs)
if CONF_FREQUENCY in config: if CONF_FREQUENCY in config:
add(i2c.set_frequency(config[CONF_FREQUENCY])) add(i2c.set_frequency(config[CONF_FREQUENCY]))
if CONF_RECEIVE_TIMEOUT in config: if CONF_RECEIVE_TIMEOUT in config:

View File

@@ -6,21 +6,23 @@ from esphomeyaml.components import switch
from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
IRTransmitterComponent = switch.switch_ns.namespace('IRTransmitterComponent')
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
cv.GenerateID('ir_transmitter'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(IRTransmitterComponent),
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_CARRIER_DUTY_PERCENT): vol.All(vol.Coerce(int), vol.Optional(CONF_CARRIER_DUTY_PERCENT): vol.All(vol.Coerce(int),
vol.Range(min=1, max=100)), vol.Range(min=1, max=100)),
})]) })])
IRTransmitterComponent = switch.switch_ns.namespace('IRTransmitterComponent')
def to_code(config): def to_code(config):
for conf in config: for conf in config:
pin = gpio_output_pin_expression(conf[CONF_PIN]) pin = None
for pin in gpio_output_pin_expression(conf[CONF_PIN]):
yield
rhs = App.make_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT)) rhs = App.make_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT))
Pvariable(IRTransmitterComponent, conf[CONF_ID], rhs) Pvariable(conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER' BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'

View File

@@ -7,11 +7,6 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
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') light_ns = esphomelib_ns.namespace('light')
LightState = light_ns.LightState LightState = light_ns.LightState
MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent
@@ -20,6 +15,11 @@ TurnOffAction = light_ns.TurnOffAction
TurnOnAction = light_ns.TurnOnAction TurnOnAction = light_ns.TurnOnAction
MakeLight = Application.MakeLight MakeLight = Application.MakeLight
LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(LightState),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTJSONLightComponent),
})
def setup_light_core_(light_var, mqtt_var, config): def setup_light_core_(light_var, mqtt_var, config):
if CONF_DEFAULT_TRANSITION_LENGTH in config: if CONF_DEFAULT_TRANSITION_LENGTH in config:
@@ -31,9 +31,8 @@ def setup_light_core_(light_var, mqtt_var, config):
def setup_light(light_obj, mqtt_obj, config): def setup_light(light_obj, mqtt_obj, config):
light_var = Pvariable(LightState, config[CONF_ID], light_obj, has_side_effects=False) light_var = Pvariable(config[CONF_ID], light_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTJSONLightComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False)
setup_light_core_(light_var, mqtt_var, config) setup_light_core_(light_var, mqtt_var, config)

View File

@@ -6,13 +6,15 @@ from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, get_variable, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('binary_light', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
}).extend(light.LIGHT_SCHEMA.schema) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = None
for output in get_variable(config[CONF_OUTPUT]):
yield
rhs = App.make_binary_light(config[CONF_NAME], output) rhs = App.make_binary_light(config[CONF_NAME], output)
light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) light_struct = variable(config[CONF_MAKE_ID], rhs)
light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)

View File

@@ -3,6 +3,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.components.power_supply import PowerSupplyComponent
from esphomeyaml.const import CONF_CHIPSET, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ from esphomeyaml.const import CONF_CHIPSET, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \
CONF_MAKE_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 CONF_RGB_ORDER
@@ -52,8 +53,10 @@ def validate(value):
return value return value
MakeFastLEDLight = Application.MakeFastLEDLight
PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({
cv.GenerateID('fast_led_clockless_light', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeFastLEDLight),
vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*TYPES)), vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*TYPES)),
vol.Required(CONF_PIN): pins.output_pin, vol.Required(CONF_PIN): pins.output_pin,
@@ -64,15 +67,13 @@ PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
}).extend(light.LIGHT_SCHEMA.schema), validate) }).extend(light.LIGHT_SCHEMA.schema), validate)
MakeFastLEDLight = Application.MakeFastLEDLight
def to_code(config): def to_code(config):
rhs = App.make_fast_led_light(config[CONF_NAME]) rhs = App.make_fast_led_light(config[CONF_NAME])
make = variable(MakeFastLEDLight, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
fast_led = make.Pfast_led fast_led = make.Pfast_led
rgb_order = None rgb_order = None
@@ -86,7 +87,9 @@ def to_code(config):
add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
if CONF_POWER_SUPPLY in config: if CONF_POWER_SUPPLY in config:
power_supply = get_variable(config[CONF_POWER_SUPPLY]) power_supply = None
for power_supply in get_variable(config[CONF_POWER_SUPPLY]):
yield
add(fast_led.set_power_supply(power_supply)) add(fast_led.set_power_supply(power_supply))
light.setup_light(make.Pstate, make.Pmqtt, config) light.setup_light(make.Pstate, make.Pmqtt, config)

View File

@@ -3,6 +3,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.components.power_supply import PowerSupplyComponent
from esphomeyaml.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, \ from esphomeyaml.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, \
CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_MAKE_ID, CONF_MAX_REFRESH_RATE, \ 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 CONF_NAME, CONF_NUM_LEDS, CONF_POWER_SUPPLY, CONF_RGB_ORDER
@@ -29,8 +30,10 @@ RGB_ORDERS = [
'BGR', 'BGR',
] ]
MakeFastLEDLight = Application.MakeFastLEDLight
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('fast_led_spi_light', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeFastLEDLight),
vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*CHIPSETS)), vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*CHIPSETS)),
vol.Required(CONF_DATA_PIN): pins.output_pin, vol.Required(CONF_DATA_PIN): pins.output_pin,
@@ -42,15 +45,13 @@ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
}).extend(light.LIGHT_SCHEMA.schema) }).extend(light.LIGHT_SCHEMA.schema)
MakeFastLEDLight = Application.MakeFastLEDLight
def to_code(config): def to_code(config):
rhs = App.make_fast_led_light(config[CONF_NAME]) rhs = App.make_fast_led_light(config[CONF_NAME])
make = variable(MakeFastLEDLight, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
fast_led = make.Pfast_led fast_led = make.Pfast_led
rgb_order = None rgb_order = None
@@ -66,7 +67,9 @@ def to_code(config):
add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
if CONF_POWER_SUPPLY in config: if CONF_POWER_SUPPLY in config:
power_supply = get_variable(config[CONF_POWER_SUPPLY]) power_supply = None
for power_supply in get_variable(config[CONF_POWER_SUPPLY]):
yield
add(fast_led.set_power_supply(power_supply)) add(fast_led.set_power_supply(power_supply))
light.setup_light(make.Pstate, make.Pmqtt, config) light.setup_light(make.Pstate, make.Pmqtt, config)

View File

@@ -7,15 +7,17 @@ from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT
from esphomeyaml.helpers import App, get_variable, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('monochromatic_light', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}).extend(light.LIGHT_SCHEMA.schema) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = None
for output in get_variable(config[CONF_OUTPUT]):
yield
rhs = App.make_monochromatic_light(config[CONF_NAME], output) rhs = App.make_monochromatic_light(config[CONF_NAME], output)
light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) light_struct = variable(config[CONF_MAKE_ID], rhs)
light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)

View File

@@ -7,19 +7,25 @@ from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GA
from esphomeyaml.helpers import App, get_variable, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('rgb_light', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
vol.Required(CONF_RED): cv.variable_id, vol.Required(CONF_RED): cv.use_variable_id(None),
vol.Required(CONF_GREEN): cv.variable_id, vol.Required(CONF_GREEN): cv.use_variable_id(None),
vol.Required(CONF_BLUE): cv.variable_id, vol.Required(CONF_BLUE): cv.use_variable_id(None),
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}).extend(light.LIGHT_SCHEMA.schema) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
red = get_variable(config[CONF_RED]) red = None
green = get_variable(config[CONF_GREEN]) for red in get_variable(config[CONF_RED]):
blue = get_variable(config[CONF_BLUE]) yield
green = None
for green in get_variable(config[CONF_GREEN]):
yield
blue = None
for blue in get_variable(config[CONF_BLUE]):
yield
rhs = App.make_rgb_light(config[CONF_NAME], red, green, blue) rhs = App.make_rgb_light(config[CONF_NAME], red, green, blue)
light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) light_struct = variable(config[CONF_MAKE_ID], rhs)
light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)

View File

@@ -7,21 +7,29 @@ from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GA
from esphomeyaml.helpers import App, get_variable, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('rgbw_light', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
vol.Required(CONF_RED): cv.variable_id, vol.Required(CONF_RED): cv.use_variable_id(None),
vol.Required(CONF_GREEN): cv.variable_id, vol.Required(CONF_GREEN): cv.use_variable_id(None),
vol.Required(CONF_BLUE): cv.variable_id, vol.Required(CONF_BLUE): cv.use_variable_id(None),
vol.Required(CONF_WHITE): cv.variable_id, vol.Required(CONF_WHITE): cv.use_variable_id(None),
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}).extend(light.LIGHT_SCHEMA.schema) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
red = get_variable(config[CONF_RED]) red = None
green = get_variable(config[CONF_GREEN]) for red in get_variable(config[CONF_RED]):
blue = get_variable(config[CONF_BLUE]) yield
white = get_variable(config[CONF_WHITE]) green = None
for green in get_variable(config[CONF_GREEN]):
yield
blue = None
for blue in get_variable(config[CONF_BLUE]):
yield
white = None
for white in get_variable(config[CONF_WHITE]):
yield
rhs = App.make_rgbw_light(config[CONF_NAME], red, green, blue, white) rhs = App.make_rgbw_light(config[CONF_NAME], red, green, blue, white)
light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs) light_struct = variable(config[CONF_MAKE_ID], rhs)
light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)

View File

@@ -1,7 +1,7 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, \ from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGS, \
CONF_TX_BUFFER_SIZE CONF_TX_BUFFER_SIZE
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, global_ns from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, global_ns
@@ -31,8 +31,10 @@ def validate_local_no_higher_than_global(value):
return value return value
LogComponent = esphomelib_ns.LogComponent
CONFIG_SCHEMA = vol.All(vol.Schema({ CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(CONF_LOGGER): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(LogComponent),
vol.Optional(CONF_BAUD_RATE): cv.positive_int, vol.Optional(CONF_BAUD_RATE): cv.positive_int,
vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int, vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int,
vol.Optional(CONF_LEVEL): is_log_level, vol.Optional(CONF_LEVEL): is_log_level,
@@ -41,12 +43,10 @@ CONFIG_SCHEMA = vol.All(vol.Schema({
}) })
}), validate_local_no_higher_than_global) }), validate_local_no_higher_than_global)
LogComponent = esphomelib_ns.LogComponent
def to_code(config): def to_code(config):
rhs = App.init_log(config.get(CONF_BAUD_RATE)) rhs = App.init_log(config.get(CONF_BAUD_RATE))
log = Pvariable(LogComponent, config[CONF_ID], rhs) log = Pvariable(config[CONF_ID], rhs)
if CONF_TX_BUFFER_SIZE in config: if CONF_TX_BUFFER_SIZE in config:
add(log.set_tx_buffer_size(config[CONF_TX_BUFFER_SIZE])) add(log.set_tx_buffer_size(config[CONF_TX_BUFFER_SIZE]))
if CONF_LEVEL in config: if CONF_LEVEL in config:

View File

@@ -6,16 +6,17 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import automation from esphomeyaml import automation
from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \ from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LOG_TOPIC, \ 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_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_SSL_FINGERPRINTS, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, \
CONF_WILL_MESSAGE CONF_WILL_MESSAGE
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, \ from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression, \
TemplateArguments, add, esphomelib_ns, optional, std_string, RawExpression StructInitializer, \
TemplateArguments, add, esphomelib_ns, optional, std_string
def validate_message_just_topic(value): def validate_message_just_topic(value):
value = cv.publish_topic(value) value = cv.publish_topic(value)
return {CONF_TOPIC: value} return MQTT_MESSAGE_BASE({CONF_TOPIC: value})
MQTT_MESSAGE_BASE = vol.Schema({ MQTT_MESSAGE_BASE = vol.Schema({
@@ -54,7 +55,7 @@ def validate_fingerprint(value):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(CONF_MQTT): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(MQTTClientComponent),
vol.Required(CONF_BROKER): validate_broker, vol.Required(CONF_BROKER): validate_broker,
vol.Optional(CONF_PORT, default=1883): cv.port, vol.Optional(CONF_PORT, default=1883): cv.port,
vol.Optional(CONF_USERNAME, default=''): cv.string, vol.Optional(CONF_USERNAME, default=''): cv.string,
@@ -71,8 +72,9 @@ CONFIG_SCHEMA = vol.Schema({
cv.ensure_list, [validate_fingerprint]), cv.ensure_list, [validate_fingerprint]),
vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds, vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds,
vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger),
vol.Required(CONF_TOPIC): cv.publish_topic, vol.Required(CONF_TOPIC): cv.publish_topic,
vol.Optional(CONF_QOS, 0): cv.mqtt_qos, vol.Optional(CONF_QOS, default=0): cv.mqtt_qos,
})]) })])
}) })
@@ -93,7 +95,7 @@ def exp_mqtt_message(config):
def to_code(config): def to_code(config):
rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT], rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT],
config[CONF_USERNAME], config[CONF_PASSWORD]) config[CONF_USERNAME], config[CONF_PASSWORD])
mqtt = Pvariable(MQTTClientComponent, config[CONF_ID], rhs) mqtt = Pvariable(config[CONF_ID], rhs)
if not config.get(CONF_DISCOVERY, True): if not config.get(CONF_DISCOVERY, True):
add(mqtt.disable_discovery()) add(mqtt.disable_discovery())
if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config: if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
@@ -104,13 +106,13 @@ def to_code(config):
add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX])) add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX]))
if CONF_BIRTH_MESSAGE in config: if CONF_BIRTH_MESSAGE in config:
birth_message = config[CONF_BIRTH_MESSAGE] birth_message = config[CONF_BIRTH_MESSAGE]
if birth_message is None: if not birth_message:
add(mqtt.disable_birth_message()) add(mqtt.disable_birth_message())
else: else:
add(mqtt.set_birth_message(exp_mqtt_message(birth_message))) add(mqtt.set_birth_message(exp_mqtt_message(birth_message)))
if CONF_WILL_MESSAGE in config: if CONF_WILL_MESSAGE in config:
will_message = config[CONF_WILL_MESSAGE] will_message = config[CONF_WILL_MESSAGE]
if will_message is None: if not will_message:
add(mqtt.disable_last_will()) add(mqtt.disable_last_will())
else: else:
add(mqtt.set_last_will(exp_mqtt_message(will_message))) add(mqtt.set_last_will(exp_mqtt_message(will_message)))
@@ -118,10 +120,10 @@ def to_code(config):
add(mqtt.set_client_id(config[CONF_CLIENT_ID])) add(mqtt.set_client_id(config[CONF_CLIENT_ID]))
if CONF_LOG_TOPIC in config: if CONF_LOG_TOPIC in config:
log_topic = config[CONF_LOG_TOPIC] log_topic = config[CONF_LOG_TOPIC]
if log_topic is None: if not log_topic:
add(mqtt.disable_log_message()) add(mqtt.disable_log_message())
else: else:
add(mqtt.set_log_topic(exp_mqtt_message(log_topic))) add(mqtt.set_log_message_template(exp_mqtt_message(log_topic)))
if CONF_SSL_FINGERPRINTS in config: if CONF_SSL_FINGERPRINTS in config:
for fingerprint in config[CONF_SSL_FINGERPRINTS]: for fingerprint in config[CONF_SSL_FINGERPRINTS]:
arr = [RawExpression("0x{}".format(fingerprint[i:i + 2])) for i in range(0, 40, 2)] arr = [RawExpression("0x{}".format(fingerprint[i:i + 2])) for i in range(0, 40, 2)]
@@ -131,7 +133,7 @@ def to_code(config):
for conf in config.get(CONF_ON_MESSAGE, []): for conf in config.get(CONF_ON_MESSAGE, []):
rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS]) rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS])
trigger = Pvariable(MQTTMessageTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, std_string, conf) automation.build_automation(trigger, std_string, conf)

View File

@@ -12,23 +12,25 @@ from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
OTAComponent = esphomelib_ns.OTAComponent
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(CONF_OTA): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(OTAComponent),
vol.Optional(CONF_SAFE_MODE, default=True): cv.boolean, vol.Optional(CONF_SAFE_MODE, default=True): cv.boolean,
# TODO Num attempts + wait time # TODO Num attempts + wait time
vol.Optional(CONF_PORT): cv.port, vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_PASSWORD): cv.string, vol.Optional(CONF_PASSWORD): cv.string,
}) })
OTAComponent = esphomelib_ns.OTAComponent
def to_code(config): def to_code(config):
rhs = App.init_ota() rhs = App.init_ota()
ota = Pvariable(OTAComponent, config[CONF_ID], rhs) ota = Pvariable(config[CONF_ID], rhs)
if CONF_PASSWORD in config: if CONF_PASSWORD in config:
hash_ = hashlib.md5(config[CONF_PASSWORD].encode()).hexdigest() hash_ = hashlib.md5(config[CONF_PASSWORD].encode()).hexdigest()
add(ota.set_auth_password_hash(hash_)) add(ota.set_auth_password_hash(hash_))
if CONF_PORT in config:
add(ota.set_port(config[CONF_PORT]))
if config[CONF_SAFE_MODE]: if config[CONF_SAFE_MODE]:
add(ota.start_safe_mode()) add(ota.start_safe_mode())

View File

@@ -1,6 +1,7 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components.power_supply import PowerSupplyComponent
from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY
from esphomeyaml.helpers import add, esphomelib_ns, get_variable from esphomeyaml.helpers import add, esphomelib_ns, get_variable
@@ -8,8 +9,8 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
BINARY_OUTPUT_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({ BINARY_OUTPUT_SCHEMA = vol.Schema({
vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_INVERTED): cv.boolean,
}) })
@@ -24,7 +25,9 @@ def setup_output_platform(obj, config, skip_power_supply=False):
if CONF_INVERTED in config: if CONF_INVERTED in config:
add(obj.set_inverted(config[CONF_INVERTED])) add(obj.set_inverted(config[CONF_INVERTED]))
if not skip_power_supply and CONF_POWER_SUPPLY in config: if not skip_power_supply and CONF_POWER_SUPPLY in config:
power_supply = get_variable(config[CONF_POWER_SUPPLY]) power_supply = None
for power_supply in get_variable(config[CONF_POWER_SUPPLY]):
yield
add(obj.set_power_supply(power_supply)) add(obj.set_power_supply(power_supply))
if CONF_MAX_POWER in config: if CONF_MAX_POWER in config:
add(obj.set_max_power(config[CONF_MAX_POWER])) add(obj.set_max_power(config[CONF_MAX_POWER]))

View File

@@ -1,8 +1,9 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import pins from esphomeyaml import pins
import esphomeyaml.config_validation as cv
from esphomeyaml.components import output from esphomeyaml.components import output
from esphomeyaml.const import CONF_ID, CONF_PIN, ESP_PLATFORM_ESP8266, CONF_NUMBER from esphomeyaml.const import CONF_ID, CONF_NUMBER, CONF_PIN, ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
@@ -10,22 +11,25 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP8266]
def valid_pwm_pin(value): def valid_pwm_pin(value):
if value[CONF_NUMBER] >= 16: if value[CONF_NUMBER] > 16:
raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.") raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.")
return value return value
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 ESP8266PWMOutput = output.output_ns.ESP8266PWMOutput
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_ID): cv.declare_variable_id(ESP8266PWMOutput),
vol.Required(CONF_PIN): vol.All(pins.internal_gpio_output_pin_schema, valid_pwm_pin),
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
def to_code(config): def to_code(config):
pin = gpio_output_pin_expression(config[CONF_PIN]) pin = None
for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_esp8266_pwm_output(pin) rhs = App.make_esp8266_pwm_output(pin)
gpio = Pvariable(ESP8266PWMOutput, config[CONF_ID], rhs) gpio = Pvariable(config[CONF_ID], rhs)
output.setup_output_platform(gpio, config) output.setup_output_platform(gpio, config)

View File

@@ -1,21 +1,25 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import pins from esphomeyaml import pins
import esphomeyaml.config_validation as cv
from esphomeyaml.components import output from esphomeyaml.components import output
from esphomeyaml.const import CONF_ID, CONF_PIN from esphomeyaml.const import CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression 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 GPIOBinaryOutputComponent = output.output_ns.GPIOBinaryOutputComponent
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_ID): cv.declare_variable_id(GPIOBinaryOutputComponent),
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
}).extend(output.BINARY_OUTPUT_SCHEMA.schema)
def to_code(config): def to_code(config):
pin = gpio_output_pin_expression(config[CONF_PIN]) pin = None
for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_gpio_output(pin) rhs = App.make_gpio_output(pin)
gpio = Pvariable(GPIOBinaryOutputComponent, config[CONF_ID], rhs) gpio = Pvariable(config[CONF_ID], rhs)
output.setup_output_platform(gpio, config) output.setup_output_platform(gpio, config)

View File

@@ -15,11 +15,14 @@ def validate_frequency_bit_depth(obj):
bit_depth = obj.get(CONF_BIT_DEPTH, 12) bit_depth = obj.get(CONF_BIT_DEPTH, 12)
max_freq = APB_CLOCK_FREQ / (2**bit_depth) max_freq = APB_CLOCK_FREQ / (2**bit_depth)
if frequency > max_freq: if frequency > max_freq:
raise vol.Invalid('Maximum frequency for bit depth {} is {}'.format(bit_depth, max_freq)) raise vol.Invalid('Maximum frequency for bit depth {} is {}Hz'.format(bit_depth, max_freq))
return obj return obj
LEDCOutputComponent = output.output_ns.LEDCOutputComponent
PLATFORM_SCHEMA = vol.All(output.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_ID): cv.declare_variable_id(LEDCOutputComponent),
vol.Required(CONF_PIN): pins.output_pin, vol.Required(CONF_PIN): pins.output_pin,
vol.Optional(CONF_FREQUENCY): cv.frequency, 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_BIT_DEPTH): vol.All(vol.Coerce(int), vol.Range(min=1, max=15)),
@@ -27,15 +30,12 @@ PLATFORM_SCHEMA = vol.All(output.PLATFORM_SCHEMA.extend({
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema), validate_frequency_bit_depth) }).extend(output.FLOAT_OUTPUT_SCHEMA.schema), validate_frequency_bit_depth)
LEDCOutputComponent = output.output_ns.LEDCOutputComponent
def to_code(config): def to_code(config):
frequency = config.get(CONF_FREQUENCY) frequency = config.get(CONF_FREQUENCY)
if frequency is None and CONF_BIT_DEPTH in config: if frequency is None and CONF_BIT_DEPTH in config:
frequency = 1000 frequency = 1000
rhs = App.make_ledc_output(config[CONF_PIN], frequency, config.get(CONF_BIT_DEPTH)) rhs = App.make_ledc_output(config[CONF_PIN], frequency, config.get(CONF_BIT_DEPTH))
ledc = Pvariable(LEDCOutputComponent, config[CONF_ID], rhs) ledc = Pvariable(config[CONF_ID], rhs)
if CONF_CHANNEL in config: if CONF_CHANNEL in config:
add(ledc.set_channel(config[CONF_CHANNEL])) add(ledc.set_channel(config[CONF_CHANNEL]))
output.setup_output_platform(ledc, config) output.setup_output_platform(ledc, config)

View File

@@ -8,22 +8,26 @@ from esphomeyaml.helpers import Pvariable, get_variable
DEPENDENCIES = ['pca9685'] DEPENDENCIES = ['pca9685']
Channel = PCA9685OutputComponent.Channel
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_ID): cv.declare_variable_id(Channel),
vol.Required(CONF_CHANNEL): vol.All(vol.Coerce(int), vol.Required(CONF_CHANNEL): vol.All(vol.Coerce(int),
vol.Range(min=0, max=15)), vol.Range(min=0, max=15)),
vol.Optional(CONF_PCA9685_ID): cv.variable_id, cv.GenerateID(CONF_PCA9685_ID): cv.use_variable_id(PCA9685OutputComponent),
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema) }).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
Channel = PCA9685OutputComponent.Channel
def to_code(config): def to_code(config):
power_supply = None power_supply = None
if CONF_POWER_SUPPLY in config: if CONF_POWER_SUPPLY in config:
power_supply = get_variable(config[CONF_POWER_SUPPLY]) for power_supply in get_variable(config[CONF_POWER_SUPPLY]):
pca9685 = get_variable(config.get(CONF_PCA9685_ID), PCA9685OutputComponent) yield
pca9685 = None
for pca9685 in get_variable(config[CONF_PCA9685_ID]):
yield
rhs = pca9685.create_channel(config[CONF_CHANNEL], power_supply) rhs = pca9685.create_channel(config[CONF_CHANNEL], power_supply)
out = Pvariable(Channel, config[CONF_ID], rhs) out = Pvariable(config[CONF_ID], rhs)
output.setup_output_platform(out, config, skip_power_supply=True) output.setup_output_platform(out, config, skip_power_supply=True)

View File

@@ -13,7 +13,7 @@ PHASE_BALANCER_MESSAGE = ("The phase_balancer option has been removed in version
"esphomelib will now automatically choose a suitable phase balancer.") "esphomelib will now automatically choose a suitable phase balancer.")
PCA9685_SCHEMA = vol.Schema({ PCA9685_SCHEMA = vol.Schema({
cv.GenerateID('pca9685'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(PCA9685OutputComponent),
vol.Required(CONF_FREQUENCY): vol.All(cv.frequency, vol.Required(CONF_FREQUENCY): vol.All(cv.frequency,
vol.Range(min=23.84, max=1525.88)), vol.Range(min=23.84, max=1525.88)),
vol.Optional(CONF_ADDRESS): cv.i2c_address, vol.Optional(CONF_ADDRESS): cv.i2c_address,
@@ -27,7 +27,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCA9685_SCHEMA])
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_pca9685_component(conf.get(CONF_FREQUENCY)) rhs = App.make_pca9685_component(conf.get(CONF_FREQUENCY))
pca9685 = Pvariable(PCA9685OutputComponent, conf[CONF_ID], rhs) pca9685 = Pvariable(conf[CONF_ID], rhs)
if CONF_ADDRESS in conf: if CONF_ADDRESS in conf:
add(pca9685.set_address(HexIntLiteral(conf[CONF_ADDRESS]))) add(pca9685.set_address(HexIntLiteral(conf[CONF_ADDRESS])))

View File

@@ -6,22 +6,22 @@ from esphomeyaml.helpers import App, Pvariable, esphomelib_ns
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
io_ns = esphomelib_ns.namespace('io')
PCF8574Component = io_ns.PCF8574Component
PCF8574_SCHEMA = vol.Schema({ PCF8574_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.register_variable_id, vol.Required(CONF_ID): cv.declare_variable_id(PCF8574Component),
vol.Optional(CONF_ADDRESS, default=0x21): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x21): cv.i2c_address,
vol.Optional(CONF_PCF8575, default=False): cv.boolean, vol.Optional(CONF_PCF8575, default=False): cv.boolean,
}) })
CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCF8574_SCHEMA]) CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCF8574_SCHEMA])
io_ns = esphomelib_ns.namespace('io')
PCF8574Component = io_ns.PCF8574Component
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_pcf8574_component(conf[CONF_ADDRESS], conf[CONF_PCF8575]) rhs = App.make_pcf8574_component(conf[CONF_ADDRESS], conf[CONF_PCF8575])
Pvariable(PCF8574Component, conf[CONF_ID], rhs) Pvariable(conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_PCF8574' BUILD_FLAGS = '-DUSE_PCF8574'

View File

@@ -5,21 +5,25 @@ from esphomeyaml import pins
from esphomeyaml.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN from esphomeyaml.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, 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({ PowerSupplyComponent = esphomelib_ns.PowerSupplyComponent
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
POWER_SUPPLY_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(PowerSupplyComponent),
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_ENABLE_TIME): cv.positive_time_period_milliseconds, vol.Optional(CONF_ENABLE_TIME): cv.positive_time_period_milliseconds,
vol.Optional(CONF_KEEP_ON_TIME): cv.positive_time_period_milliseconds, vol.Optional(CONF_KEEP_ON_TIME): cv.positive_time_period_milliseconds,
}) })
CONFIG_SCHEMA = vol.All(cv.ensure_list, [POWER_SUPPLY_SCHEMA]) CONFIG_SCHEMA = vol.All(cv.ensure_list, [POWER_SUPPLY_SCHEMA])
PowerSupplyComponent = esphomelib_ns.PowerSupplyComponent
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_power_supply(gpio_output_pin_expression(conf[CONF_PIN])) pin = None
psu = Pvariable(PowerSupplyComponent, conf[CONF_ID], rhs) for pin in gpio_output_pin_expression(conf[CONF_PIN]):
yield
rhs = App.make_power_supply(pin)
psu = Pvariable(conf[CONF_ID], rhs)
if CONF_ENABLE_TIME in conf: if CONF_ENABLE_TIME in conf:
add(psu.set_enable_time(conf[CONF_ENABLE_TIME])) add(psu.set_enable_time(conf[CONF_ENABLE_TIME]))
if CONF_KEEP_ON_TIME in conf: if CONF_KEEP_ON_TIME in conf:

View File

@@ -9,7 +9,7 @@ from esphomeyaml.const import CONF_ABOVE, CONF_ACCURACY_DECIMALS, CONF_ALPHA, CO
CONF_ON_VALUE_RANGE, CONF_OR, CONF_SEND_EVERY, CONF_SLIDING_WINDOW_MOVING_AVERAGE, \ 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 CONF_THROTTLE, CONF_TRIGGER_ID, CONF_UNIQUE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, esphomelib_ns, float_, \ from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, esphomelib_ns, float_, \
process_lambda, setup_mqtt_component, templatable process_lambda, setup_mqtt_component, templatable, add_job
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
@@ -44,25 +44,7 @@ FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds, vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_DEBOUNCE): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEBOUNCE): cv.positive_time_period_milliseconds,
vol.Optional(CONF_OR): validate_recursive_filter, vol.Optional(CONF_OR): validate_recursive_filter,
}, cv.has_at_exactly_one_key(*FILTER_KEYS))]) }, cv.has_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,
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_ABOVE): vol.Coerce(float),
vol.Optional(CONF_BELOW): vol.Coerce(float),
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))]),
})
# pylint: disable=invalid-name # pylint: disable=invalid-name
sensor_ns = esphomelib_ns.namespace('sensor') sensor_ns = esphomelib_ns.namespace('sensor')
@@ -86,41 +68,75 @@ SensorValueTrigger = sensor_ns.SensorValueTrigger
RawSensorValueTrigger = sensor_ns.RawSensorValueTrigger RawSensorValueTrigger = sensor_ns.RawSensorValueTrigger
ValueRangeTrigger = sensor_ns.ValueRangeTrigger ValueRangeTrigger = sensor_ns.ValueRangeTrigger
SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSensorComponent),
cv.GenerateID(): cv.declare_variable_id(Sensor),
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,
vol.Optional(CONF_ON_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SensorValueTrigger),
})]),
vol.Optional(CONF_ON_RAW_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(RawSensorValueTrigger),
})]),
vol.Optional(CONF_ON_VALUE_RANGE): vol.All(cv.ensure_list, [vol.All(
automation.AUTOMATION_SCHEMA.extend({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ValueRangeTrigger),
vol.Optional(CONF_ABOVE): vol.Coerce(float),
vol.Optional(CONF_BELOW): vol.Coerce(float),
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))]),
})
def setup_filter(config): def setup_filter(config):
if CONF_OFFSET in config: if CONF_OFFSET in config:
return OffsetFilter.new(config[CONF_OFFSET]) yield OffsetFilter.new(config[CONF_OFFSET])
if CONF_MULTIPLY in config: elif CONF_MULTIPLY in config:
return MultiplyFilter.new(config[CONF_MULTIPLY]) yield MultiplyFilter.new(config[CONF_MULTIPLY])
if CONF_FILTER_OUT in config: elif CONF_FILTER_OUT in config:
return FilterOutValueFilter.new(config[CONF_FILTER_OUT]) yield FilterOutValueFilter.new(config[CONF_FILTER_OUT])
if CONF_FILTER_NAN in config: elif CONF_FILTER_NAN in config:
return FilterOutNANFilter() yield FilterOutNANFilter.new()
if CONF_SLIDING_WINDOW_MOVING_AVERAGE in config: elif CONF_SLIDING_WINDOW_MOVING_AVERAGE in config:
conf = config[CONF_SLIDING_WINDOW_MOVING_AVERAGE] conf = config[CONF_SLIDING_WINDOW_MOVING_AVERAGE]
return SlidingWindowMovingAverageFilter.new(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY]) yield SlidingWindowMovingAverageFilter.new(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY])
if CONF_EXPONENTIAL_MOVING_AVERAGE in config: elif CONF_EXPONENTIAL_MOVING_AVERAGE in config:
conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE] conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE]
return ExponentialMovingAverageFilter.new(conf[CONF_ALPHA], conf[CONF_SEND_EVERY]) yield ExponentialMovingAverageFilter.new(conf[CONF_ALPHA], conf[CONF_SEND_EVERY])
if CONF_LAMBDA in config: elif CONF_LAMBDA in config:
return LambdaFilter.new(process_lambda(config[CONF_LAMBDA], [(float_, 'x')])) lambda_ = None
if CONF_THROTTLE in config: for lambda_ in process_lambda(config[CONF_LAMBDA], [(float_, 'x')]):
return ThrottleFilter.new(config[CONF_THROTTLE]) yield None
if CONF_DELTA in config: yield LambdaFilter.new(lambda_)
return DeltaFilter.new(config[CONF_DELTA]) elif CONF_THROTTLE in config:
if CONF_OR in config: yield ThrottleFilter.new(config[CONF_THROTTLE])
return OrFilter.new(setup_filters(config[CONF_OR])) elif CONF_DELTA in config:
if CONF_HEARTBEAT in config: yield DeltaFilter.new(config[CONF_DELTA])
return App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT])) elif CONF_OR in config:
if CONF_DEBOUNCE in config: filters = None
return App.register_component(DebounceFilter.new(config[CONF_DEBOUNCE])) for filters in setup_filters(config[CONF_OR]):
if CONF_UNIQUE in config: yield None
return UniqueFilter.new() yield OrFilter.new(filters)
raise ValueError(u"Filter unsupported: {}".format(config)) elif CONF_HEARTBEAT in config:
yield App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT]))
elif CONF_DEBOUNCE in config:
yield App.register_component(DebounceFilter.new(config[CONF_DEBOUNCE]))
elif CONF_UNIQUE in config:
yield UniqueFilter.new()
def setup_filters(config): def setup_filters(config):
return ArrayInitializer(*[setup_filter(x) for x in config]) filters = []
for conf in config:
filter = None
for filter in setup_filter(conf):
yield None
filters.append(filter)
yield ArrayInitializer(*filters)
def setup_sensor_core_(sensor_var, mqtt_var, config): def setup_sensor_core_(sensor_var, mqtt_var, config):
@@ -131,23 +147,32 @@ def setup_sensor_core_(sensor_var, mqtt_var, config):
if CONF_ACCURACY_DECIMALS in config: if CONF_ACCURACY_DECIMALS in config:
add(sensor_var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS])) add(sensor_var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
if CONF_FILTERS in config: if CONF_FILTERS in config:
add(sensor_var.set_filters(setup_filters(config[CONF_FILTERS]))) filters = None
for filters in setup_filters(config[CONF_FILTERS]):
yield
add(sensor_var.set_filters(filters))
for conf in config.get(CONF_ON_VALUE, []): for conf in config.get(CONF_ON_VALUE, []):
rhs = sensor_var.make_value_trigger() rhs = sensor_var.make_value_trigger()
trigger = Pvariable(SensorValueTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, float_, conf) automation.build_automation(trigger, float_, conf)
for conf in config.get(CONF_ON_RAW_VALUE, []): for conf in config.get(CONF_ON_RAW_VALUE, []):
rhs = sensor_var.make_raw_value_trigger() rhs = sensor_var.make_raw_value_trigger()
trigger = Pvariable(RawSensorValueTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, float_, conf) automation.build_automation(trigger, float_, conf)
for conf in config.get(CONF_ON_VALUE_RANGE, []): for conf in config.get(CONF_ON_VALUE_RANGE, []):
rhs = sensor_var.make_value_range_trigger() rhs = sensor_var.make_value_range_trigger()
trigger = Pvariable(ValueRangeTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
if CONF_ABOVE in conf: if CONF_ABOVE in conf:
trigger.set_min(templatable(conf[CONF_ABOVE], float_, float_)) template_ = None
for template_ in templatable(conf[CONF_ABOVE], float_, float_):
yield
trigger.set_min(template_)
if CONF_BELOW in conf: if CONF_BELOW in conf:
trigger.set_max(templatable(conf[CONF_BELOW], float_, float_)) template_ = None
for template_ in templatable(conf[CONF_BELOW], float_, float_):
yield
trigger.set_max(template_)
automation.build_automation(trigger, float_, conf) automation.build_automation(trigger, float_, conf)
if CONF_EXPIRE_AFTER in config: if CONF_EXPIRE_AFTER in config:
@@ -159,18 +184,16 @@ def setup_sensor_core_(sensor_var, mqtt_var, config):
def setup_sensor(sensor_obj, mqtt_obj, config): def setup_sensor(sensor_obj, mqtt_obj, config):
sensor_var = Pvariable(Sensor, config[CONF_ID], sensor_obj, has_side_effects=False) sensor_var = Pvariable(config[CONF_ID], sensor_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTSensorComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False) add_job(setup_sensor_core_, sensor_var, mqtt_var, config)
setup_sensor_core_(sensor_var, mqtt_var, config)
def register_sensor(var, config): def register_sensor(var, config):
sensor_var = Pvariable(Sensor, config[CONF_ID], var, has_side_effects=True) sensor_var = Pvariable(config[CONF_ID], var, has_side_effects=True)
rhs = App.register_sensor(sensor_var) rhs = App.register_sensor(sensor_var)
mqtt_var = Pvariable(MQTTSensorComponent, config[CONF_MQTT_ID], rhs, mqtt_var = Pvariable(config[CONF_MQTT_ID], rhs, has_side_effects=True)
has_side_effects=True) add_job(setup_sensor_core_, sensor_var, mqtt_var, config)
setup_sensor_core_(sensor_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_SENSOR' BUILD_FLAGS = '-DUSE_SENSOR'

View File

@@ -14,20 +14,31 @@ ATTENUATION_MODES = {
'11db': global_ns.ADC_11db, '11db': global_ns.ADC_11db,
} }
def validate_adc_pin(value):
vcc = str(value).upper()
if vcc == 'VCC':
return cv.only_on_esp8266(vcc)
return pins.analog_pin(value)
MakeADCSensor = Application.MakeADCSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('adc', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeADCSensor),
vol.Required(CONF_PIN): pins.analog_pin, vol.Required(CONF_PIN): validate_adc_pin,
vol.Optional(CONF_ATTENUATION): vol.All(cv.only_on_esp32, cv.one_of(*ATTENUATION_MODES)), 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, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeADCSensor = Application.MakeADCSensor
def to_code(config): def to_code(config):
rhs = App.make_adc_sensor(config[CONF_NAME], config[CONF_PIN], pin = config[CONF_PIN]
if pin == 'VCC':
pin = 0
rhs = App.make_adc_sensor(config[CONF_NAME], pin,
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeADCSensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
adc = make.Padc adc = make.Padc
if CONF_ATTENUATION in config: if CONF_ATTENUATION in config:
add(adc.set_attenuation(ATTENUATION_MODES[config[CONF_ATTENUATION]])) add(adc.set_attenuation(ATTENUATION_MODES[config[CONF_ATTENUATION]]))
@@ -35,3 +46,9 @@ def to_code(config):
BUILD_FLAGS = '-DUSE_ADC_SENSOR' BUILD_FLAGS = '-DUSE_ADC_SENSOR'
def required_build_flags(config):
if config[CONF_PIN] == 'VCC':
return '-DUSE_ADC_SENSOR_VCC'
return None

View File

@@ -46,16 +46,17 @@ def validate_mux(value):
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('ads1115_sensor'): cv.register_variable_id,
vol.Required(CONF_MULTIPLEXER): validate_mux, vol.Required(CONF_MULTIPLEXER): validate_mux,
vol.Required(CONF_GAIN): validate_gain, vol.Required(CONF_GAIN): validate_gain,
vol.Optional(CONF_ADS1115_ID): cv.variable_id, cv.GenerateID(CONF_ADS1115_ID): cv.use_variable_id(ADS1115Component),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
hub = get_variable(config.get(CONF_ADS1115_ID), ADS1115Component) hub = None
for hub in get_variable(config[CONF_ADS1115_ID]):
yield
mux = MUX[config[CONF_MULTIPLEXER]] mux = MUX[config[CONF_MULTIPLEXER]]
gain = GAIN[config[CONF_GAIN]] gain = GAIN[config[CONF_GAIN]]

View File

@@ -14,20 +14,20 @@ BH1750_RESOLUTIONS = {
0.5: sensor.sensor_ns.BH1750_RESOLUTION_0P5_LX, 0.5: sensor.sensor_ns.BH1750_RESOLUTION_0P5_LX,
} }
MakeBH1750Sensor = Application.MakeBH1750Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bh1750_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBH1750Sensor),
vol.Optional(CONF_ADDRESS, default=0x23): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x23): cv.i2c_address,
vol.Optional(CONF_RESOLUTION): vol.All(cv.positive_float, cv.one_of(*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, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeBH1750Sensor = Application.MakeBH1750Sensor
def to_code(config): def to_code(config):
rhs = App.make_bh1750_sensor(config[CONF_NAME], config[CONF_ADDRESS], rhs = App.make_bh1750_sensor(config[CONF_NAME], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make_bh1750 = variable(MakeBH1750Sensor, config[CONF_MAKE_ID], rhs) make_bh1750 = variable(config[CONF_MAKE_ID], rhs)
bh1750 = make_bh1750.Pbh1750 bh1750 = make_bh1750.Pbh1750
if CONF_RESOLUTION in config: if CONF_RESOLUTION in config:
add(bh1750.set_resolution(BH1750_RESOLUTIONS[config[CONF_RESOLUTION]])) add(bh1750.set_resolution(BH1750_RESOLUTIONS[config[CONF_RESOLUTION]]))

View File

@@ -29,8 +29,10 @@ BME280_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({
vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)), vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)),
}) })
MakeBME280Sensor = Application.MakeBME280Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bme280', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBME280Sensor),
vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address,
vol.Required(CONF_TEMPERATURE): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): BME280_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_PRESSURE): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): BME280_OVERSAMPLING_SENSOR_SCHEMA,
@@ -39,8 +41,6 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeBME280Sensor = Application.MakeBME280Sensor
def to_code(config): def to_code(config):
rhs = App.make_bme280_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_bme280_sensor(config[CONF_TEMPERATURE][CONF_NAME],
@@ -48,7 +48,7 @@ def to_code(config):
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config[CONF_ADDRESS], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeBME280Sensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
bme280 = make.Pbme280 bme280 = make.Pbme280
if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]: if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]:
constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]]

View File

@@ -33,8 +33,10 @@ BME680_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({
vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)), vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)),
}) })
MakeBME680Sensor = Application.MakeBME680Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bme680', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBME680Sensor),
vol.Optional(CONF_ADDRESS, default=0x76): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x76): cv.i2c_address,
vol.Required(CONF_TEMPERATURE): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): BME680_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_PRESSURE): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): BME680_OVERSAMPLING_SENSOR_SCHEMA,
@@ -45,8 +47,6 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeBME680Sensor = Application.MakeBME680Sensor
def to_code(config): def to_code(config):
rhs = App.make_bme680_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_bme680_sensor(config[CONF_TEMPERATURE][CONF_NAME],
@@ -55,7 +55,7 @@ def to_code(config):
config[CONF_GAS_RESISTANCE][CONF_NAME], config[CONF_GAS_RESISTANCE][CONF_NAME],
config[CONF_ADDRESS], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeBME680Sensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
bme680 = make.Pbme680 bme680 = make.Pbme680
if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]: if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]:
constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]]

View File

@@ -4,26 +4,26 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_PRESSURE, \ from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_PRESSURE, \
CONF_TEMPERATURE, CONF_UPDATE_INTERVAL CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, HexIntLiteral, add, variable, Application from esphomeyaml.helpers import App, Application, HexIntLiteral, add, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
MakeBMP085Sensor = Application.MakeBMP085Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bmp085_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBMP085Sensor),
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_PRESSURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_ADDRESS): cv.i2c_address, vol.Optional(CONF_ADDRESS): cv.i2c_address,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeBMP085Sensor = Application.MakeBMP085Sensor
def to_code(config): def to_code(config):
rhs = App.make_bmp085_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_bmp085_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_PRESSURE][CONF_NAME], config[CONF_PRESSURE][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
bmp = variable(MakeBMP085Sensor, config[CONF_MAKE_ID], rhs) bmp = variable(config[CONF_MAKE_ID], rhs)
if CONF_ADDRESS in config: if CONF_ADDRESS in config:
add(bmp.Pbmp.set_address(HexIntLiteral(config[CONF_ADDRESS]))) add(bmp.Pbmp.set_address(HexIntLiteral(config[CONF_ADDRESS])))

View File

@@ -4,30 +4,27 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.dallas import DallasComponent from esphomeyaml.components.dallas import DallasComponent
from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \ from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \
CONF_RESOLUTION, CONF_UPDATE_INTERVAL CONF_RESOLUTION
from esphomeyaml.helpers import HexIntLiteral, get_variable from esphomeyaml.helpers import HexIntLiteral, get_variable
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
vol.Exclusive(CONF_ADDRESS, 'dallas'): cv.hex_int, vol.Exclusive(CONF_ADDRESS, 'dallas'): cv.hex_int,
vol.Exclusive(CONF_INDEX, 'dallas'): cv.positive_int, vol.Exclusive(CONF_INDEX, 'dallas'): cv.positive_int,
vol.Optional(CONF_DALLAS_ID): cv.variable_id, cv.GenerateID(CONF_DALLAS_ID): cv.use_variable_id(DallasComponent),
vol.Optional(CONF_RESOLUTION): vol.All(vol.Coerce(int), vol.Range(min=8, max=12)), vol.Optional(CONF_RESOLUTION): vol.All(vol.Coerce(int), vol.Range(min=9, max=12)),
}).extend(sensor.SENSOR_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): def to_code(config):
hub = get_variable(config.get(CONF_DALLAS_ID), DallasComponent) hub = None
update_interval = config.get(CONF_UPDATE_INTERVAL) for hub in get_variable(config[CONF_DALLAS_ID]):
if CONF_RESOLUTION in config and update_interval is None: yield
update_interval = 10000
if CONF_ADDRESS in config: if CONF_ADDRESS in config:
address = HexIntLiteral(config[CONF_ADDRESS]) address = HexIntLiteral(config[CONF_ADDRESS])
rhs = hub.Pget_sensor_by_address(config[CONF_NAME], address, update_interval, rhs = hub.Pget_sensor_by_address(config[CONF_NAME], address, config.get(CONF_RESOLUTION))
config.get(CONF_RESOLUTION))
else: else:
rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX], rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX],
update_interval, config.get(CONF_RESOLUTION)) config.get(CONF_RESOLUTION))
sensor.register_sensor(rhs, config) sensor.register_sensor(rhs, config)

View File

@@ -5,7 +5,7 @@ from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_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 CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, add, gpio_output_pin_expression, variable from esphomeyaml.helpers import App, Application, add, gpio_output_pin_expression, variable
from esphomeyaml.pins import GPIO_OUTPUT_PIN_SCHEMA from esphomeyaml.pins import gpio_output_pin_schema
DHT_MODELS = { DHT_MODELS = {
'AUTO_DETECT': sensor.sensor_ns.DHT_MODEL_AUTO_DETECT, 'AUTO_DETECT': sensor.sensor_ns.DHT_MODEL_AUTO_DETECT,
@@ -15,24 +15,26 @@ DHT_MODELS = {
'RHT03': sensor.sensor_ns.DHT_MODEL_RHT03, 'RHT03': sensor.sensor_ns.DHT_MODEL_RHT03,
} }
MakeDHTSensor = Application.MakeDHTSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('dht_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeDHTSensor),
vol.Required(CONF_PIN): GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): gpio_output_pin_schema,
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): 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_MODEL): vol.All(vol.Upper, cv.one_of(*DHT_MODELS)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeDHTSensor = Application.MakeDHTSensor
def to_code(config): def to_code(config):
pin = gpio_output_pin_expression(config[CONF_PIN]) pin = None
for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_dht_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_dht_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
pin, config.get(CONF_UPDATE_INTERVAL)) pin, config.get(CONF_UPDATE_INTERVAL))
dht = variable(MakeDHTSensor, config[CONF_MAKE_ID], rhs) dht = variable(config[CONF_MAKE_ID], rhs)
if CONF_MODEL in config: if CONF_MODEL in config:
constant = DHT_MODELS[config[CONF_MODEL]] constant = DHT_MODELS[config[CONF_MODEL]]
add(dht.Pdht.set_dht_model(constant)) add(dht.Pdht.set_dht_model(constant))

View File

@@ -8,25 +8,25 @@ from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
MakeDHT12Sensor = Application.MakeDHT12Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('dht_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeDHT12Sensor),
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeDHT12Sensor = Application.MakeDHT12Sensor
def to_code(config): def to_code(config):
rhs = App.make_dht12_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_dht12_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
dht = variable(MakeDHT12Sensor, config[CONF_MAKE_ID], rhs) dht = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), dht.Pmqtt_temperature, sensor.setup_sensor(dht.Pdht12.Pget_temperature_sensor(), dht.Pmqtt_temperature,
config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])
sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), dht.Pmqtt_humidity, sensor.setup_sensor(dht.Pdht12.Pget_humidity_sensor(), dht.Pmqtt_humidity,
config[CONF_HUMIDITY]) config[CONF_HUMIDITY])

View File

@@ -0,0 +1,24 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL, ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, Application, variable
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
MakeESP32HallSensor = Application.MakeESP32HallSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeESP32HallSensor),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema)
def to_code(config):
rhs = App.make_esp32_hall_sensor(config[CONF_NAME], config.get(CONF_UPDATE_INTERVAL))
make = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Phall, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_ESP32_HALL_SENSOR'

View File

@@ -4,27 +4,28 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \ from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \
CONF_UPDATE_INTERVAL CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, variable, Application from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
MakeHDC1080Sensor = Application.MakeHDC1080Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('hdc1080_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHDC1080Sensor),
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeHDC1080Sensor = Application.MakeHDC1080Sensor
def to_code(config): def to_code(config):
rhs = App.make_hdc1080_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_hdc1080_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
hdc1080 = variable(MakeHDC1080Sensor, config[CONF_MAKE_ID], rhs) hdc1080 = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(hdc1080.Phdc1080.Pget_temperature_sensor(), hdc1080.Pmqtt_temperature, sensor.setup_sensor(hdc1080.Phdc1080.Pget_temperature_sensor(),
hdc1080.Pmqtt_temperature,
config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])
sensor.setup_sensor(hdc1080.Phdc1080.Pget_humidity_sensor(), hdc1080.Pmqtt_humidity, sensor.setup_sensor(hdc1080.Phdc1080.Pget_humidity_sensor(), hdc1080.Pmqtt_humidity,
config[CONF_HUMIDITY]) config[CONF_HUMIDITY])

View File

@@ -4,25 +4,25 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \ from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \
CONF_UPDATE_INTERVAL CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, variable, Application from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
MakeHTU21DSensor = Application.MakeHTU21DSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('htu21d', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHTU21DSensor),
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeHTU21DSensor = Application.MakeHTU21DSensor
def to_code(config): def to_code(config):
rhs = App.make_htu21d_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_htu21d_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
htu21d = variable(MakeHTU21DSensor, config[CONF_MAKE_ID], rhs) htu21d = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(htu21d.Phtu21d.Pget_temperature_sensor(), htu21d.Pmqtt_temperature, sensor.setup_sensor(htu21d.Phtu21d.Pget_temperature_sensor(), htu21d.Pmqtt_temperature,
config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])
sensor.setup_sensor(htu21d.Phtu21d.Pget_humidity_sensor(), htu21d.Pmqtt_humidity, sensor.setup_sensor(htu21d.Phtu21d.Pget_humidity_sensor(), htu21d.Pmqtt_humidity,

View File

@@ -8,24 +8,30 @@ from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN_CLOCK, CONF_PIN_
from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, \ from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, \
gpio_output_pin_expression, variable gpio_output_pin_expression, variable
MakeMAX6675Sensor = Application.MakeMAX6675Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('max6675', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeMAX6675Sensor),
vol.Required(CONF_PIN_CS): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN_CS): pins.gpio_output_pin_schema,
vol.Required(CONF_PIN_CLOCK): 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.Required(CONF_PIN_MISO): pins.gpio_input_pin_schema,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeMAX6675Sensor = Application.MakeMAX6675Sensor
def to_code(config): def to_code(config):
pin_cs = gpio_output_pin_expression(config[CONF_PIN_CS]) pin_cs = None
pin_clock = gpio_output_pin_expression(config[CONF_PIN_CLOCK]) for pin_cs in gpio_output_pin_expression(config[CONF_PIN_CS]):
pin_miso = gpio_input_pin_expression(config[CONF_PIN_MISO]) yield
pin_clock = None
for pin_clock in gpio_output_pin_expression(config[CONF_PIN_CLOCK]):
yield
pin_miso = None
for pin_miso in gpio_input_pin_expression(config[CONF_PIN_MISO]):
yield
rhs = App.make_max6675_sensor(config[CONF_NAME], pin_cs, pin_clock, pin_miso, rhs = App.make_max6675_sensor(config[CONF_NAME], pin_cs, pin_clock, pin_miso,
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeMAX6675Sensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Pmax6675, make.Pmqtt, config) sensor.setup_sensor(make.Pmax6675, make.Pmqtt, config)

View File

@@ -2,8 +2,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_MQTT_ID, CONF_NAME, \ from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_NAME, CONF_TEMPERATURE, \
CONF_TEMPERATURE, \
CONF_UPDATE_INTERVAL CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Pvariable from esphomeyaml.helpers import App, Pvariable
@@ -16,8 +15,13 @@ CONF_GYRO_X = 'gyro_x'
CONF_GYRO_Y = 'gyro_y' CONF_GYRO_Y = 'gyro_y'
CONF_GYRO_Z = 'gyro_z' CONF_GYRO_Z = 'gyro_z'
MPU6050Component = sensor.sensor_ns.MPU6050Component
MPU6050AccelSensor = sensor.sensor_ns.MPU6050AccelSensor
MPU6050GyroSensor = sensor.sensor_ns.MPU6050GyroSensor
MPU6050TemperatureSensor = sensor.sensor_ns.MPU6050TemperatureSensor
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('mpu6050', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(MPU6050Component),
vol.Optional(CONF_ADDRESS, default=0x68): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x68): cv.i2c_address,
vol.Optional(CONF_ACCEL_X): sensor.SENSOR_SCHEMA, vol.Optional(CONF_ACCEL_X): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_ACCEL_Y): sensor.SENSOR_SCHEMA, vol.Optional(CONF_ACCEL_Y): sensor.SENSOR_SCHEMA,
@@ -30,50 +34,38 @@ PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
}), cv.has_at_least_one_key(CONF_ACCEL_X, CONF_ACCEL_Y, CONF_ACCEL_Z, }), cv.has_at_least_one_key(CONF_ACCEL_X, CONF_ACCEL_Y, CONF_ACCEL_Z,
CONF_GYRO_X, CONF_GYRO_Y, CONF_GYRO_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): def to_code(config):
rhs = App.make_mpu6050_sensor(config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL)) rhs = App.make_mpu6050_sensor(config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL))
mpu = Pvariable(MPU6050Component, config[CONF_MAKE_ID], rhs) mpu = Pvariable(config[CONF_ID], rhs)
if CONF_ACCEL_X in config: if CONF_ACCEL_X in config:
conf = config[CONF_ACCEL_X] conf = config[CONF_ACCEL_X]
rhs = mpu.Pmake_accel_x_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_accel_x_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050AccelSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
if CONF_ACCEL_Y in config: if CONF_ACCEL_Y in config:
conf = config[CONF_ACCEL_Y] conf = config[CONF_ACCEL_Y]
rhs = mpu.Pmake_accel_y_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_accel_y_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050AccelSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
if CONF_ACCEL_Z in config: if CONF_ACCEL_Z in config:
conf = config[CONF_ACCEL_Z] conf = config[CONF_ACCEL_Z]
rhs = mpu.Pmake_accel_z_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_accel_z_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050AccelSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
if CONF_GYRO_X in config: if CONF_GYRO_X in config:
conf = config[CONF_GYRO_X] conf = config[CONF_GYRO_X]
rhs = mpu.Pmake_gyro_x_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_gyro_x_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050GyroSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
if CONF_GYRO_Y in config: if CONF_GYRO_Y in config:
conf = config[CONF_GYRO_Y] conf = config[CONF_GYRO_Y]
rhs = mpu.Pmake_gyro_y_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_gyro_y_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050GyroSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
if CONF_GYRO_Z in config: if CONF_GYRO_Z in config:
conf = config[CONF_GYRO_Z] conf = config[CONF_GYRO_Z]
rhs = mpu.Pmake_gyro_z_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_gyro_z_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050GyroSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
if CONF_TEMPERATURE in config: if CONF_TEMPERATURE in config:
conf = config[CONF_TEMPERATURE] conf = config[CONF_TEMPERATURE]
rhs = mpu.Pmake_temperature_sensor(conf[CONF_NAME]) rhs = mpu.Pmake_temperature_sensor(conf[CONF_NAME])
sensor_ = Pvariable(MPU6050TemperatureSensor, conf[CONF_MQTT_ID], rhs) sensor.register_sensor(rhs, conf)
sensor.register_sensor(sensor_, conf)
BUILD_FLAGS = '-DUSE_MPU6050' BUILD_FLAGS = '-DUSE_MPU6050'

View File

@@ -27,8 +27,10 @@ COUNT_MODES = {
COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*COUNT_MODES)) COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*COUNT_MODES))
MakePulseCounterSensor = Application.MakePulseCounterSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('pulse_counter', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakePulseCounterSensor),
vol.Required(CONF_PIN): pins.input_pin, vol.Required(CONF_PIN): pins.input_pin,
vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA, vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA,
vol.Optional(CONF_COUNT_MODE): vol.Schema({ vol.Optional(CONF_COUNT_MODE): vol.Schema({
@@ -39,13 +41,11 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakePulseCounterSensor = Application.MakePulseCounterSensor
def to_code(config): def to_code(config):
rhs = App.make_pulse_counter_sensor(config[CONF_NAME], config[CONF_PIN], rhs = App.make_pulse_counter_sensor(config[CONF_NAME], config[CONF_PIN],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakePulseCounterSensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
pcnt = make.Ppcnt pcnt = make.Ppcnt
if CONF_PULL_MODE in config: if CONF_PULL_MODE in config:
pull_mode = GPIO_PULL_MODES[config[CONF_PULL_MODE]] pull_mode = GPIO_PULL_MODES[config[CONF_PULL_MODE]]

View File

@@ -16,25 +16,31 @@ CONF_PIN_A = 'pin_a'
CONF_PIN_B = 'pin_b' CONF_PIN_B = 'pin_b'
CONF_PIN_RESET = 'pin_reset' CONF_PIN_RESET = 'pin_reset'
MakeRotaryEncoderSensor = Application.MakeRotaryEncoderSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('rotary_encoder', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeRotaryEncoderSensor),
vol.Required(CONF_PIN_A): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Required(CONF_PIN_A): pins.internal_gpio_input_pin_schema,
vol.Required(CONF_PIN_B): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Required(CONF_PIN_B): pins.internal_gpio_input_pin_schema,
vol.Optional(CONF_PIN_RESET): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Optional(CONF_PIN_RESET): pins.internal_gpio_input_pin_schema,
vol.Optional(CONF_RESOLUTION): vol.All(cv.string, cv.one_of(*RESOLUTIONS)), vol.Optional(CONF_RESOLUTION): vol.All(cv.string, cv.one_of(*RESOLUTIONS)),
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeRotaryEncoderSensor = Application.MakeRotaryEncoderSensor
def to_code(config): def to_code(config):
pin_a = gpio_input_pin_expression(config[CONF_PIN_A]) pin_a = None
pin_b = gpio_input_pin_expression(config[CONF_PIN_B]) for pin_a in gpio_input_pin_expression(config[CONF_PIN_A]):
yield
pin_b = None
for pin_b in gpio_input_pin_expression(config[CONF_PIN_B]):
yield
rhs = App.make_rotary_encoder_sensor(config[CONF_NAME], pin_a, pin_b) rhs = App.make_rotary_encoder_sensor(config[CONF_NAME], pin_a, pin_b)
make = variable(MakeRotaryEncoderSensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
encoder = make.Protary_encoder encoder = make.Protary_encoder
if CONF_PIN_RESET in config: if CONF_PIN_RESET in config:
pin_i = gpio_input_pin_expression(config[CONF_PIN_RESET]) pin_i = None
for pin_i in gpio_input_pin_expression(config[CONF_PIN_RESET]):
yield
add(encoder.set_reset_pin(pin_i)) add(encoder.set_reset_pin(pin_i))
if CONF_RESOLUTION in config: if CONF_RESOLUTION in config:
resolution = RESOLUTIONS[config[CONF_RESOLUTION]] resolution = RESOLUTIONS[config[CONF_RESOLUTION]]

View File

@@ -14,8 +14,10 @@ SHT_ACCURACIES = {
'HIGH': sensor.sensor_ns.SHT3XD_ACCURACY_HIGH, 'HIGH': sensor.sensor_ns.SHT3XD_ACCURACY_HIGH,
} }
MakeSHT3XDSensor = Application.MakeSHT3XDSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('sht3xd', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeSHT3XDSensor),
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address,
@@ -23,14 +25,13 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeSHT3XDSensor = Application.MakeSHT3XDSensor
def to_code(config): def to_code(config):
rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
sht3xd = variable(MakeSHT3XDSensor, config[CONF_MAKE_ID], rhs) sht3xd = variable(config[CONF_MAKE_ID], rhs)
if CONF_ACCURACY in config: if CONF_ACCURACY in config:
add(sht3xd.Psht3xd.set_accuracy(SHT_ACCURACIES[config[CONF_ACCURACY]])) add(sht3xd.Psht3xd.set_accuracy(SHT_ACCURACIES[config[CONF_ACCURACY]]))

View File

@@ -3,22 +3,25 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, process_lambda, variable, Application from esphomeyaml.helpers import App, process_lambda, variable, Application, float_, optional
MakeTemplateSensor = Application.MakeTemplateSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeTemplateSensor),
vol.Required(CONF_LAMBDA): cv.lambda_, vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeTemplateSensor = Application.MakeTemplateSensor
def to_code(config): def to_code(config):
template_ = process_lambda(config[CONF_LAMBDA], []) template_ = None
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(float_)):
yield
rhs = App.make_template_sensor(config[CONF_NAME], template_, rhs = App.make_template_sensor(config[CONF_NAME], template_,
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeTemplateSensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Ptemplate_, make.Pmqtt, config) sensor.setup_sensor(make.Ptemplate_, make.Pmqtt, config)

View File

@@ -28,8 +28,10 @@ def validate_integration_time(value):
return value return value
MakeTSL2561Sensor = Application.MakeTSL2561Sensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('tsl2561_sensor', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeTSL2561Sensor),
vol.Optional(CONF_ADDRESS, default=0x39): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x39): cv.i2c_address,
vol.Optional(CONF_INTEGRATION_TIME): validate_integration_time, vol.Optional(CONF_INTEGRATION_TIME): validate_integration_time,
vol.Optional(CONF_GAIN): vol.All(vol.Upper, cv.one_of(*GAINS)), vol.Optional(CONF_GAIN): vol.All(vol.Upper, cv.one_of(*GAINS)),
@@ -37,13 +39,11 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeTSL2561Sensor = Application.MakeTSL2561Sensor
def to_code(config): def to_code(config):
rhs = App.make_tsl2561_sensor(config[CONF_NAME], config[CONF_ADDRESS], rhs = App.make_tsl2561_sensor(config[CONF_NAME], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make_tsl = variable(MakeTSL2561Sensor, config[CONF_MAKE_ID], rhs) make_tsl = variable(config[CONF_MAKE_ID], rhs)
tsl2561 = make_tsl.Ptsl2561 tsl2561 = make_tsl.Ptsl2561
if CONF_INTEGRATION_TIME in config: if CONF_INTEGRATION_TIME in config:
add(tsl2561.set_integration_time(INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]])) add(tsl2561.set_integration_time(INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]]))

View File

@@ -8,24 +8,28 @@ from esphomeyaml.const import CONF_ECHO_PIN, CONF_MAKE_ID, CONF_NAME, CONF_TIMEO
from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, \ from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, \
gpio_output_pin_expression, variable gpio_output_pin_expression, variable
MakeUltrasonicSensor = Application.MakeUltrasonicSensor
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('ultrasonic', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeUltrasonicSensor),
vol.Required(CONF_TRIGGER_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_TRIGGER_PIN): pins.gpio_output_pin_schema,
vol.Required(CONF_ECHO_PIN): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA, vol.Required(CONF_ECHO_PIN): pins.internal_gpio_input_pin_schema,
vol.Exclusive(CONF_TIMEOUT_METER, 'timeout'): cv.positive_float, vol.Exclusive(CONF_TIMEOUT_METER, 'timeout'): cv.positive_float,
vol.Exclusive(CONF_TIMEOUT_TIME, 'timeout'): cv.positive_time_period_microseconds, vol.Exclusive(CONF_TIMEOUT_TIME, 'timeout'): cv.positive_time_period_microseconds,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeUltrasonicSensor = Application.MakeUltrasonicSensor
def to_code(config): def to_code(config):
trigger = gpio_output_pin_expression(config[CONF_TRIGGER_PIN]) trigger = None
echo = gpio_input_pin_expression(config[CONF_ECHO_PIN]) for trigger in gpio_output_pin_expression(config[CONF_TRIGGER_PIN]):
yield
echo = None
for echo in gpio_input_pin_expression(config[CONF_ECHO_PIN]):
yield
rhs = App.make_ultrasonic_sensor(config[CONF_NAME], trigger, echo, rhs = App.make_ultrasonic_sensor(config[CONF_NAME], trigger, echo,
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeUltrasonicSensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
ultrasonic = make.Pultrasonic ultrasonic = make.Pultrasonic
if CONF_TIMEOUT_TIME in config: if CONF_TIMEOUT_TIME in config:
add(ultrasonic.set_timeout_us(config[CONF_TIMEOUT_TIME])) add(ultrasonic.set_timeout_us(config[CONF_TIMEOUT_TIME]))

View File

@@ -8,13 +8,6 @@ PLATFORM_SCHEMA = cv.PLATFORM_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,
})
switch_ns = esphomelib_ns.namespace('switch_') switch_ns = esphomelib_ns.namespace('switch_')
Switch = switch_ns.Switch Switch = switch_ns.Switch
MQTTSwitchComponent = switch_ns.MQTTSwitchComponent MQTTSwitchComponent = switch_ns.MQTTSwitchComponent
@@ -22,6 +15,13 @@ ToggleAction = switch_ns.ToggleAction
TurnOffAction = switch_ns.TurnOffAction TurnOffAction = switch_ns.TurnOffAction
TurnOnAction = switch_ns.TurnOnAction TurnOnAction = switch_ns.TurnOnAction
SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(Switch),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSwitchComponent),
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INVERTED): cv.boolean,
})
def setup_switch_core_(switch_var, mqtt_var, config): def setup_switch_core_(switch_var, mqtt_var, config):
if CONF_ICON in config: if CONF_ICON in config:
@@ -33,17 +33,15 @@ def setup_switch_core_(switch_var, mqtt_var, config):
def setup_switch(switch_obj, mqtt_obj, config): def setup_switch(switch_obj, mqtt_obj, config):
switch_var = Pvariable(Switch, config[CONF_ID], switch_obj, has_side_effects=False) switch_var = Pvariable(config[CONF_ID], switch_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False)
setup_switch_core_(switch_var, mqtt_var, config) setup_switch_core_(switch_var, mqtt_var, config)
def register_switch(var, config): def register_switch(var, config):
switch_var = Pvariable(Switch, config[CONF_ID], var, has_side_effects=True) switch_var = Pvariable(config[CONF_ID], var, has_side_effects=True)
rhs = App.register_switch(switch_var) rhs = App.register_switch(switch_var)
mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], rhs, mqtt_var = Pvariable(config[CONF_MQTT_ID], rhs, has_side_effects=True)
has_side_effects=True)
setup_switch_core_(switch_var, mqtt_var, config) setup_switch_core_(switch_var, mqtt_var, config)

View File

@@ -6,17 +6,20 @@ from esphomeyaml.components import switch
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN
from esphomeyaml.helpers import App, Application, gpio_output_pin_expression, variable from esphomeyaml.helpers import App, Application, gpio_output_pin_expression, variable
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('gpio_switch', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
}).extend(switch.SWITCH_SCHEMA.schema)
MakeGPIOSwitch = Application.MakeGPIOSwitch MakeGPIOSwitch = Application.MakeGPIOSwitch
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeGPIOSwitch),
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
}).extend(switch.SWITCH_SCHEMA.schema)
def to_code(config): def to_code(config):
rhs = App.make_gpio_switch(config[CONF_NAME], gpio_output_pin_expression(config[CONF_PIN])) pin = None
gpio = variable(MakeGPIOSwitch, config[CONF_MAKE_ID], rhs) for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_gpio_switch(config[CONF_NAME], pin)
gpio = variable(config[CONF_MAKE_ID], rhs)
switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config) switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config)

View File

@@ -17,7 +17,6 @@ WAIT_TIME_MESSAGE = "The wait_time_us option has been renamed to wait_time in or
"ambiguity. " "ambiguity. "
PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('ir_transmitter_switch'): cv.register_variable_id,
vol.Exclusive(CONF_NEC, 'code'): vol.Schema({ vol.Exclusive(CONF_NEC, 'code'): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t, vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint16_t, vol.Required(CONF_COMMAND): cv.hex_uint16_t,
@@ -44,7 +43,7 @@ PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
vol.Optional('wait_time_us'): cv.invalid(WAIT_TIME_MESSAGE), vol.Optional('wait_time_us'): cv.invalid(WAIT_TIME_MESSAGE),
})), })),
vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id, cv.GenerateID(CONF_IR_TRANSMITTER_ID): cv.use_variable_id(IRTransmitterComponent),
vol.Optional(CONF_INVERTED): cv.invalid("IR Transmitters do not support inverted mode!"), vol.Optional(CONF_INVERTED): cv.invalid("IR Transmitters do not support inverted mode!"),
}).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_least_one_key(*IR_KEYS)) }).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_least_one_key(*IR_KEYS))
@@ -94,7 +93,9 @@ def exp_send_data(config):
def to_code(config): def to_code(config):
ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IRTransmitterComponent) ir = None
for ir in get_variable(config[CONF_IR_TRANSMITTER_ID]):
yield
send_data = exp_send_data(config) send_data = exp_send_data(config)
rhs = App.register_component(ir.create_transmitter(config[CONF_NAME], send_data)) rhs = App.register_component(ir.create_transmitter(config[CONF_NAME], send_data))
switch.register_switch(rhs, config) switch.register_switch(rhs, config)

View File

@@ -5,18 +5,20 @@ from esphomeyaml.components import switch
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, Application, get_variable, variable from esphomeyaml.helpers import App, Application, get_variable, variable
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('output_switch', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_OUTPUT): cv.variable_id,
}).extend(switch.SWITCH_SCHEMA.schema)
MakeSimpleSwitch = Application.MakeSimpleSwitch MakeSimpleSwitch = Application.MakeSimpleSwitch
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeSimpleSwitch),
vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
}).extend(switch.SWITCH_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = None
for output in get_variable(config[CONF_OUTPUT]):
yield
rhs = App.make_simple_switch(config[CONF_NAME], output) rhs = App.make_simple_switch(config[CONF_NAME], output)
gpio = variable(MakeSimpleSwitch, config[CONF_MAKE_ID], rhs) gpio = variable(config[CONF_MAKE_ID], rhs)
switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config) switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config)

View File

@@ -5,17 +5,17 @@ from esphomeyaml.components import switch
from esphomeyaml.const import CONF_INVERTED, CONF_MAKE_ID, CONF_NAME from esphomeyaml.const import CONF_INVERTED, CONF_MAKE_ID, CONF_NAME
from esphomeyaml.helpers import App, Application, variable from esphomeyaml.helpers import App, Application, variable
MakeRestartSwitch = Application.MakeRestartSwitch
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('restart_switch', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeRestartSwitch),
vol.Optional(CONF_INVERTED): cv.invalid("Restart switches do not support inverted mode!"), vol.Optional(CONF_INVERTED): cv.invalid("Restart switches do not support inverted mode!"),
}).extend(switch.SWITCH_SCHEMA.schema) }).extend(switch.SWITCH_SCHEMA.schema)
MakeRestartSwitch = Application.MakeRestartSwitch
def to_code(config): def to_code(config):
rhs = App.make_restart_switch(config[CONF_NAME]) rhs = App.make_restart_switch(config[CONF_NAME])
restart = variable(MakeRestartSwitch, config[CONF_MAKE_ID], rhs) restart = variable(config[CONF_MAKE_ID], rhs)
switch.setup_switch(restart.Prestart, restart.Pmqtt, config) switch.setup_switch(restart.Prestart, restart.Pmqtt, config)

View File

@@ -5,17 +5,17 @@ from esphomeyaml.components import switch
from esphomeyaml.const import CONF_INVERTED, CONF_MAKE_ID, CONF_NAME from esphomeyaml.const import CONF_INVERTED, CONF_MAKE_ID, CONF_NAME
from esphomeyaml.helpers import App, Application, variable from esphomeyaml.helpers import App, Application, variable
MakeShutdownSwitch = Application.MakeShutdownSwitch
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('shutdown_switch', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeShutdownSwitch),
vol.Optional(CONF_INVERTED): cv.invalid("Shutdown switches do not support inverted mode!"), vol.Optional(CONF_INVERTED): cv.invalid("Shutdown switches do not support inverted mode!"),
}).extend(switch.SWITCH_SCHEMA.schema) }).extend(switch.SWITCH_SCHEMA.schema)
MakeShutdownSwitch = Application.MakeShutdownSwitch
def to_code(config): def to_code(config):
rhs = App.make_shutdown_switch(config[CONF_NAME]) rhs = App.make_shutdown_switch(config[CONF_NAME])
shutdown = variable(MakeShutdownSwitch, config[CONF_MAKE_ID], rhs) shutdown = variable(config[CONF_MAKE_ID], rhs)
switch.setup_switch(shutdown.Pshutdown, shutdown.Pmqtt, config) switch.setup_switch(shutdown.Pshutdown, shutdown.Pmqtt, config)

View File

@@ -5,31 +5,39 @@ from esphomeyaml import automation
from esphomeyaml.components import switch from esphomeyaml.components import switch
from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_TURN_OFF_ACTION, \ from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_TURN_OFF_ACTION, \
CONF_TURN_ON_ACTION, CONF_OPTIMISTIC CONF_TURN_ON_ACTION, CONF_OPTIMISTIC
from esphomeyaml.helpers import App, Application, process_lambda, variable, NoArg, add from esphomeyaml.helpers import App, Application, process_lambda, variable, NoArg, add, bool_, \
optional
MakeTemplateSwitch = Application.MakeTemplateSwitch
PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_switch', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeTemplateSwitch),
vol.Optional(CONF_LAMBDA): cv.lambda_, vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_OPTIMISTIC): cv.boolean, vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_TURN_OFF_ACTION): automation.ACTIONS_SCHEMA, vol.Optional(CONF_TURN_OFF_ACTION): automation.ACTIONS_SCHEMA,
vol.Optional(CONF_TURN_ON_ACTION): automation.ACTIONS_SCHEMA, vol.Optional(CONF_TURN_ON_ACTION): automation.ACTIONS_SCHEMA,
}).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_exactly_one_key(CONF_LAMBDA, CONF_OPTIMISTIC)) }).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_least_one_key(CONF_LAMBDA, CONF_OPTIMISTIC))
MakeTemplateSwitch = Application.MakeTemplateSwitch
def to_code(config): def to_code(config):
rhs = App.make_template_switch(config[CONF_NAME]) rhs = App.make_template_switch(config[CONF_NAME])
make = variable(MakeTemplateSwitch, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
if CONF_LAMBDA in config: if CONF_LAMBDA in config:
template_ = process_lambda(config[CONF_LAMBDA], []) template_ = None
add(make.Ptemplate.set_state_lambda(template_)) for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(bool_)):
yield
add(make.Ptemplate_.set_state_lambda(template_))
if CONF_TURN_OFF_ACTION in config: if CONF_TURN_OFF_ACTION in config:
actions = automation.build_actions(config[CONF_TURN_OFF_ACTION], NoArg) actions = None
for actions in automation.build_actions(config[CONF_TURN_OFF_ACTION], NoArg):
yield
add(make.Ptemplate_.add_turn_off_actions(actions)) add(make.Ptemplate_.add_turn_off_actions(actions))
if CONF_TURN_ON_ACTION in config: if CONF_TURN_ON_ACTION in config:
actions = automation.build_actions(config[CONF_TURN_ON_ACTION], NoArg) actions = None
for actions in automation.build_actions(config[CONF_TURN_ON_ACTION], NoArg):
yield
add(make.Ptemplate_.add_turn_on_actions(actions)) add(make.Ptemplate_.add_turn_on_actions(actions))
if CONF_OPTIMISTIC in config: if CONF_OPTIMISTIC in config:
add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC])) add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC]))

View File

@@ -9,19 +9,19 @@ from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('web_server'): cv.register_variable_id,
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_CSS_URL): vol.Url,
vol.Optional(CONF_JS_URL): vol.Url,
})
WebServer = esphomelib_ns.WebServer WebServer = esphomelib_ns.WebServer
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(WebServer),
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_CSS_URL): cv.string,
vol.Optional(CONF_JS_URL): cv.string,
})
def to_code(config): def to_code(config):
rhs = App.init_web_server(config.get(CONF_PORT)) rhs = App.init_web_server(config.get(CONF_PORT))
web_server = Pvariable(WebServer, config[CONF_ID], rhs) web_server = Pvariable(config[CONF_ID], rhs)
if CONF_CSS_URL in config: if CONF_CSS_URL in config:
add(web_server.set_css_url(config[CONF_CSS_URL])) add(web_server.set_css_url(config[CONF_CSS_URL]))
if CONF_JS_URL in config: if CONF_JS_URL in config:

View File

@@ -30,8 +30,13 @@ STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4, vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4,
}) })
# pylint: disable=invalid-name
IPAddress = global_ns.IPAddress
ManualIP = esphomelib_ns.ManualIP
WiFiComponent = esphomelib_ns.WiFiComponent
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('wifi'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(WiFiComponent),
vol.Optional(CONF_SSID): cv.ssid, vol.Optional(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password, vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA, vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
@@ -42,14 +47,9 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA, vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
}), }),
vol.Optional(CONF_HOSTNAME): cv.hostname, vol.Optional(CONF_HOSTNAME): cv.hostname,
vol.Required(CONF_DOMAIN, default='.local'): cv.domainname, vol.Optional(CONF_DOMAIN, default='.local'): cv.domainname,
}) })
# pylint: disable=invalid-name
IPAddress = global_ns.IPAddress
ManualIP = esphomelib_ns.ManualIP
WiFiComponent = esphomelib_ns.WiFiComponent
def safe_ip(ip): def safe_ip(ip):
if ip is None: if ip is None:
@@ -75,7 +75,7 @@ def to_code(config):
rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD)) rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD))
else: else:
rhs = App.init_wifi() rhs = App.init_wifi()
wifi = Pvariable(WiFiComponent, config[CONF_ID], rhs) wifi = Pvariable(config[CONF_ID], rhs)
if sta and CONF_MANUAL_IP in config: if sta and CONF_MANUAL_IP in config:
add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP]))) add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP])))

View File

@@ -1,6 +1,6 @@
{ {
"name": "esphomeyaml", "name": "esphomeyaml",
"version": "1.6.0", "version": "1.6.2",
"slug": "esphomeyaml", "slug": "esphomeyaml",
"description": "esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices.", "description": "esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices.",
"url": "https://esphomelib.com/esphomeyaml/index.html", "url": "https://esphomelib.com/esphomeyaml/index.html",
@@ -19,5 +19,6 @@
"environment": { "environment": {
"ESPHOMEYAML_OTA_HOST_PORT": "6053" "ESPHOMEYAML_OTA_HOST_PORT": "6053"
}, },
"schema": {} "schema": {},
"image": "ottowinter/esphomeyaml-hassio-{arch}"
} }

View File

@@ -18,7 +18,7 @@ from esphomeyaml.helpers import App, add, color
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.6.0' DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.6.2'
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
@@ -93,6 +93,50 @@ class Config(OrderedDict):
self.errors.append((message, domain, config)) self.errors.append((message, domain, config))
def iter_ids(config, prefix=None, parent=None):
prefix = prefix or []
parent = parent or {}
if isinstance(config, core.ID):
yield config, prefix, parent
elif isinstance(config, core.Lambda):
for id in config.requires_ids:
yield id, prefix, parent
elif isinstance(config, list):
for i, item in enumerate(config):
for result in iter_ids(item, prefix + [str(i)], config):
yield result
elif isinstance(config, dict):
for key, value in config.iteritems():
for result in iter_ids(value, prefix + [str(key)], config):
yield result
def do_id_pass(result):
declare_ids = []
searching_ids = []
for id, prefix, config in iter_ids(result):
if id.is_declaration:
if id.id is not None and any(v[0].id == id.id for v in declare_ids):
result.add_error("ID {} redefined!".format(id.id), '.'.join(prefix), config)
continue
declare_ids.append((id, prefix, config))
else:
searching_ids.append((id, prefix, config))
# Resolve default ids after manual IDs
for id, _, _ in declare_ids:
id.resolve([v[0].id for v in declare_ids])
# Check searched IDs
for id, prefix, config in searching_ids:
if id.id is not None and not any(v[0].id == id.id for v in declare_ids):
result.add_error("Couldn't find ID {}".format(id.id), '.'.join(prefix), config)
if id.id is None and id.type is not None:
id.id = next((v[0].id for v in declare_ids if v[0].type == id.type), None)
if id.id is None:
result.add_error("Couldn't resolve ID for type {}".format(id.type),
'.'.join(prefix), config)
def validate_config(config): def validate_config(config):
global _ALL_COMPONENTS global _ALL_COMPONENTS
@@ -131,7 +175,7 @@ def validate_config(config):
dependencies = getattr(component, 'DEPENDENCIES', []) dependencies = getattr(component, 'DEPENDENCIES', [])
for dependency in dependencies: for dependency in dependencies:
if dependency not in _ALL_COMPONENTS: if dependency not in _ALL_COMPONENTS:
result.add_error(u"Component {} requires {}".format(domain, dependency)) result.add_error(u"Component {} requires component {}".format(domain, dependency))
success = False success = False
if not success: if not success:
continue continue
@@ -165,8 +209,8 @@ def validate_config(config):
dependencies = getattr(platform, 'DEPENDENCIES', []) dependencies = getattr(platform, 'DEPENDENCIES', [])
for dependency in dependencies: for dependency in dependencies:
if dependency not in _ALL_COMPONENTS: if dependency not in _ALL_COMPONENTS:
result.add_error(u"Platform {}.{} requires {}".format(domain, p_name, result.add_error(u"Platform {}.{} requires component {}".format(domain, p_name,
dependency)) dependency))
success = False success = False
if not success: if not success:
continue continue
@@ -185,6 +229,8 @@ def validate_config(config):
continue continue
platforms.append(p_validated) platforms.append(p_validated)
result[domain] = platforms result[domain] = platforms
do_id_pass(result)
return result return result
@@ -237,8 +283,10 @@ def load_config(path):
try: try:
result = validate_config(config) result = validate_config(config)
except ESPHomeYAMLError:
raise
except Exception: except Exception:
print(u"Unexpected exception while reading configuration:") _LOGGER.error(u"Unexpected exception while reading configuration:")
raise raise
return result return result
@@ -279,18 +327,18 @@ def dump_dict(layer, indent_count=3, listi=False, **kwargs):
def read_config(path): def read_config(path):
_LOGGER.debug("Reading configuration...") _LOGGER.info("Reading configuration...")
try: try:
res = load_config(path) res = load_config(path)
except ESPHomeYAMLError as err: except ESPHomeYAMLError as err:
_LOGGER.error(u"Error while reading config: %s", err) _LOGGER.error(u"Error while reading config: %s", err)
return None return None
excepts = {} excepts = {}
for err in res.errors: for message, domain, config in res.errors:
domain = err[1] or u"General Error" domain = domain or u"General Error"
excepts.setdefault(domain, []).append(err[0]) excepts.setdefault(domain, []).append(message)
if err[2] is not None: if config is not None:
excepts[domain].append(err[2]) excepts[domain].append(config)
if excepts: if excepts:
print(color('bold_white', u"Failed config")) print(color('bold_white', u"Failed config"))

View File

@@ -12,9 +12,8 @@ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOV
CONF_NAME, CONF_PAYLOAD_AVAILABLE, \ CONF_NAME, CONF_PAYLOAD_AVAILABLE, \
CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \ CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
from esphomeyaml.core import HexInt, IPAddress, TimePeriod, TimePeriodMicroseconds, \ from esphomeyaml.core import HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds, Lambda TimePeriodMilliseconds, TimePeriodSeconds
from esphomeyaml.helpers import ensure_unique_string
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -57,8 +56,10 @@ def alphanumeric(value):
def valid_name(value): def valid_name(value):
value = string_strict(value) value = string_strict(value)
if not all(c in ALLOWED_NAME_CHARS for c in value): for c in value:
raise vol.Invalid(u"Valid characters for name are {}".format(ALLOWED_NAME_CHARS)) if c not in ALLOWED_NAME_CHARS:
raise vol.Invalid(u"'{}' is an invalid character for names. Valid characters are: {}"
u"".format(c, ALLOWED_NAME_CHARS))
return value return value
@@ -136,7 +137,7 @@ def int_(value):
hex_int = vol.Coerce(hex_int_) hex_int = vol.Coerce(hex_int_)
def variable_id(value): def variable_id_str_(value):
value = string(value) value = string(value)
if not value: if not value:
raise vol.Invalid("ID must not be empty") raise vol.Invalid("ID must not be empty")
@@ -153,11 +154,32 @@ def variable_id(value):
return value return value
def use_variable_id(type):
def validator(value):
if value is None:
return core.ID(None, is_declaration=False, type=type)
return core.ID(variable_id_str_(value), is_declaration=False, type=type)
return validator
def declare_variable_id(type):
def validator(value):
if value is None:
return core.ID(None, is_declaration=True, type=type)
return core.ID(variable_id_str_(value), is_declaration=True, type=type)
return validator
def templatable(other_validators): def templatable(other_validators):
def validator(value): def validator(value):
if isinstance(value, Lambda): if isinstance(value, Lambda):
return value return value
return other_validators(value) return other_validators(value)
return validator return validator
@@ -194,7 +216,7 @@ def has_at_least_one_key(*keys):
return validate return validate
def has_at_exactly_one_key(*keys): def has_exactly_one_key(*keys):
def validate(obj): def validate(obj):
if not isinstance(obj, dict): if not isinstance(obj, dict):
raise vol.Invalid('expected dictionary') raise vol.Invalid('expected dictionary')
@@ -224,7 +246,6 @@ time_period_dict = vol.All(
'seconds', 'milliseconds', 'microseconds'), 'seconds', 'milliseconds', 'microseconds'),
lambda value: TimePeriod(**value)) lambda value: TimePeriod(**value))
TIME_PERIOD_EXPLICIT_MESSAGE = ("The old way of being able to write time values without a " TIME_PERIOD_EXPLICIT_MESSAGE = ("The old way of being able to write time values without a "
"time unit (like \"1000\" for 1000 milliseconds) has been " "time unit (like \"1000\" for 1000 milliseconds) has been "
"removed in 1.5.0 as it was ambiguous in some places. Please " "removed in 1.5.0 as it was ambiguous in some places. Please "
@@ -322,7 +343,6 @@ positive_time_period_microseconds = vol.All(positive_time_period, time_period_in
positive_not_null_time_period = vol.All(time_period, positive_not_null_time_period = vol.All(time_period,
vol.Range(min=TimePeriod(), min_included=False)) vol.Range(min=TimePeriod(), min_included=False))
METRIC_SUFFIXES = { METRIC_SUFFIXES = {
'E': 1e18, 'P': 1e15, 'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'da': 10, 'd': 1e-1, 'E': 1e18, 'P': 1e15, 'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'da': 10, 'd': 1e-1,
'c': 1e-2, 'm': 0.001, u'µ': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18, 'c': 1e-2, 'm': 0.001, u'µ': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18,
@@ -479,6 +499,7 @@ def percentage(value):
def invalid(message): def invalid(message):
def validator(value): def validator(value):
raise vol.Invalid(message) raise vol.Invalid(message)
return validator return validator
@@ -493,6 +514,7 @@ def one_of(*values):
if value not in values: if value not in values:
raise vol.Invalid(u"Unknown value '{}', must be one of {}".format(value, options)) raise vol.Invalid(u"Unknown value '{}', must be one of {}".format(value, options))
return value return value
return validator return validator
@@ -505,26 +527,10 @@ def lambda_(value):
REGISTERED_IDS = set() REGISTERED_IDS = set()
def register_variable_id(value):
s = variable_id(value)
if s in REGISTERED_IDS:
raise vol.Invalid("This ID has already been used")
REGISTERED_IDS.add(s)
return s
class GenerateID(vol.Optional): class GenerateID(vol.Optional):
def __init__(self, basename, key=CONF_ID): def __init__(self, key=CONF_ID):
self._basename = basename super(GenerateID, self).__init__(key, default=lambda: None)
super(GenerateID, self).__init__(key, default=self.default_variable_id)
def default_variable_id(self):
return ensure_unique_string(self._basename, REGISTERED_IDS)
REQUIRED_ID_SCHEMA = vol.Schema({
vol.Required(CONF_ID): register_variable_id,
})
PLATFORM_SCHEMA = vol.Schema({ PLATFORM_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): valid, vol.Required(CONF_PLATFORM): valid,
@@ -541,7 +547,7 @@ MQTT_COMPONENT_SCHEMA = vol.Schema({
vol.Optional(CONF_RETAIN): boolean, vol.Optional(CONF_RETAIN): boolean,
vol.Optional(CONF_DISCOVERY): boolean, vol.Optional(CONF_DISCOVERY): boolean,
vol.Optional(CONF_STATE_TOPIC): publish_topic, vol.Optional(CONF_STATE_TOPIC): publish_topic,
vol.Optional(CONF_AVAILABILITY): MQTT_COMPONENT_AVAILABILITY_SCHEMA, vol.Optional(CONF_AVAILABILITY): vol.Any(None, MQTT_COMPONENT_AVAILABILITY_SCHEMA),
}) })
MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({

View File

@@ -2,7 +2,7 @@
MAJOR_VERSION = 1 MAJOR_VERSION = 1
MINOR_VERSION = 6 MINOR_VERSION = 6
PATCH_VERSION = '0' PATCH_VERSION = '2'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
@@ -253,3 +253,5 @@ ESP_BOARDS_FOR_PLATFORM = {
ESP_PLATFORM_ESP32: ESP32_BOARDS, ESP_PLATFORM_ESP32: ESP32_BOARDS,
ESP_PLATFORM_ESP8266: ESP8266_BOARDS ESP_PLATFORM_ESP8266: ESP8266_BOARDS
} }
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'

View File

@@ -1,4 +1,5 @@
import math import math
import re
from collections import OrderedDict from collections import OrderedDict
@@ -174,11 +175,59 @@ class TimePeriodSeconds(TimePeriod):
class Lambda(object): class Lambda(object):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
self.parts = re.split(r'id\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)\.', value)
self.requires_ids = [ID(self.parts[i]) for i in range(1, len(self.parts), 2)]
def __str__(self): def __str__(self):
return self.value
def __repr__(self):
return u'Lambda<{}>'.format(self.value) return u'Lambda<{}>'.format(self.value)
def ensure_unique_string(preferred_string, current_strings):
test_string = preferred_string
current_strings_set = set(current_strings)
tries = 1
while test_string in current_strings_set:
tries += 1
test_string = u"{}_{}".format(preferred_string, tries)
return test_string
class ID(object):
def __init__(self, id, is_declaration=False, type=None):
self.id = id
self.is_manual = id is not None
self.is_declaration = is_declaration
self.type = type
def resolve(self, registered_ids):
if self.id is None:
base = str(self.type).replace('::', '_').lower()
name = ''.join(c for c in base if c.isalnum() or c == '_')
self.id = ensure_unique_string(name, registered_ids)
return self.id
def __str__(self):
return self.id
def __repr__(self):
return u'ID<{} declaration={}, type={}, manual={}>'.format(
self.id, self.is_declaration, self.type, self.is_manual)
def __eq__(self, other):
if not isinstance(other, ID):
raise ValueError("other must be ID")
return self.id == other.id
def __hash__(self):
return hash(self.id)
CONFIG_PATH = None CONFIG_PATH = None
SIMPLIFY = True SIMPLIFY = True
ESP_PLATFORM = '' ESP_PLATFORM = ''

View File

@@ -1,3 +1,4 @@
# pylint: disable=wrong-import-position
from __future__ import print_function from __future__ import print_function
import codecs import codecs
@@ -7,6 +8,11 @@ import os
import random import random
import subprocess import subprocess
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml import const, core, __main__
from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name
from esphomeyaml.helpers import quote
try: try:
import tornado import tornado
import tornado.gen import tornado.gen
@@ -17,15 +23,12 @@ try:
import tornado.websocket import tornado.websocket
import tornado.concurrent import tornado.concurrent
except ImportError as err: except ImportError as err:
pass tornado = None
from esphomeyaml import const, core, __main__
from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name
from esphomeyaml.helpers import quote
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONFIG_DIR = '' CONFIG_DIR = ''
# pylint: disable=abstract-method, arguments-differ # pylint: disable=abstract-method, arguments-differ
class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler): class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler):
def __init__(self, application, request, **kwargs): def __init__(self, application, request, **kwargs):
@@ -93,17 +96,27 @@ class EsphomeyamlCompileHandler(EsphomeyamlCommandWebSocket):
return ["esphomeyaml", config_file, "compile"] return ["esphomeyaml", config_file, "compile"]
class EsphomeyamlValidateHandler(EsphomeyamlCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphomeyaml", config_file, "config"]
class SerialPortRequestHandler(tornado.web.RequestHandler): class SerialPortRequestHandler(tornado.web.RequestHandler):
def get(self): def get(self):
ports = get_serial_ports() ports = get_serial_ports()
data = [] data = []
for port, desc in ports: for port, desc in ports:
if port == '/dev/ttyAMA0': if port == '/dev/ttyAMA0':
# ignore RPi built-in serial port desc = 'UART pins on GPIO header'
continue split_desc = desc.split(' - ')
if len(split_desc) == 2 and split_desc[0] == split_desc[1]:
# Some serial ports repeat their values
desc = split_desc[0]
data.append({'port': port, 'desc': desc}) data.append({'port': port, 'desc': desc})
data.append({'port': 'OTA', 'desc': 'Over-The-Air Upload/Logs'}) data.append({'port': 'OTA', 'desc': 'Over-The-Air'})
self.write(json.dumps(data)) self.write(json.dumps(sorted(data, reverse=True)))
class WizardRequestHandler(tornado.web.RequestHandler): class WizardRequestHandler(tornado.web.RequestHandler):
@@ -116,7 +129,7 @@ class WizardRequestHandler(tornado.web.RequestHandler):
with codecs.open(destination, 'w') as f_handle: with codecs.open(destination, 'w') as f_handle:
f_handle.write(config) f_handle.write(config)
self.redirect('/') self.redirect('/?begin=True')
class DownloadBinaryRequestHandler(tornado.web.RequestHandler): class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
@@ -140,36 +153,43 @@ class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
class MainRequestHandler(tornado.web.RequestHandler): class MainRequestHandler(tornado.web.RequestHandler):
def get(self): def get(self):
begin = bool(self.get_argument('begin', False))
files = sorted([f for f in os.listdir(CONFIG_DIR) if f.endswith('.yaml') and files = sorted([f for f in os.listdir(CONFIG_DIR) if f.endswith('.yaml') and
not f.startswith('.')]) not f.startswith('.')])
full_path_files = [os.path.join(CONFIG_DIR, f) for f in files] full_path_files = [os.path.join(CONFIG_DIR, f) for f in files]
self.render("templates/index.html", files=files, full_path_files=full_path_files, self.render("templates/index.html", files=files, full_path_files=full_path_files,
version=const.__version__) version=const.__version__, begin=begin)
def make_app(): def make_app(debug=False):
static_path = os.path.join(os.path.dirname(__file__), 'static') static_path = os.path.join(os.path.dirname(__file__), 'static')
return tornado.web.Application([ return tornado.web.Application([
(r"/", MainRequestHandler), (r"/", MainRequestHandler),
(r"/logs", EsphomeyamlLogsHandler), (r"/logs", EsphomeyamlLogsHandler),
(r"/run", EsphomeyamlRunHandler), (r"/run", EsphomeyamlRunHandler),
(r"/compile", EsphomeyamlCompileHandler), (r"/compile", EsphomeyamlCompileHandler),
(r"/validate", EsphomeyamlValidateHandler),
(r"/download.bin", DownloadBinaryRequestHandler), (r"/download.bin", DownloadBinaryRequestHandler),
(r"/serial-ports", SerialPortRequestHandler), (r"/serial-ports", SerialPortRequestHandler),
(r"/wizard.html", WizardRequestHandler), (r"/wizard.html", WizardRequestHandler),
(r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}), (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}),
], debug=False) ], debug=debug)
def start_web_server(args): def start_web_server(args):
global CONFIG_DIR global CONFIG_DIR
if tornado is None:
raise ESPHomeYAMLError("Attempted to load dashboard, but tornado is not installed! "
"Please run \"pip2 install tornado esptool\" in your terminal.")
CONFIG_DIR = args.configuration CONFIG_DIR = args.configuration
if not os.path.exists(CONFIG_DIR): if not os.path.exists(CONFIG_DIR):
os.makedirs(CONFIG_DIR) os.makedirs(CONFIG_DIR)
_LOGGER.info("Starting dashboard web server on port %s and configuration dir %s...", _LOGGER.info("Starting dashboard web server on port %s and configuration dir %s...",
args.port, CONFIG_DIR) args.port, CONFIG_DIR)
app = make_app() app = make_app(args.verbose)
app.listen(args.port) app.listen(args.port)
try: try:
tornado.ioloop.IOLoop.current().start() tornado.ioloop.IOLoop.current().start()

View File

@@ -121,9 +121,9 @@
} }
.modal { .modal {
width: 90%; width: 95%;
max-height: 85%; max-height: 90%;
height: 80% !important; height: 85% !important;
} }
.page-footer { .page-footer {
@@ -155,7 +155,9 @@
} }
.select-port-container { .select-port-container {
margin-top: 19px; margin-top: 8px;
margin-right: 24px;
width: 350px;
} }
</style> </style>
</head> </head>
@@ -165,9 +167,23 @@
<nav> <nav>
<div class="nav-wrapper indigo"> <div class="nav-wrapper indigo">
<a href="#" class="brand-logo left">esphomeyaml Dashboard</a> <a href="#" class="brand-logo left">esphomeyaml Dashboard</a>
<div class="select-port-container right" id="select-port-target">
<select></select>
</div>
</div> </div>
</nav> </nav>
<div class="tap-target pink lighten-1 select-port" data-target="select-port-target">
<div class="tap-target-content">
<h5>Select Upload Port</h5>
<p>
Here you can select where esphomeyaml will attempt to show logs and upload firmwares to.
By default, this is "OTA", or Over-The-Air. Note that you might have to restart the HassIO add-on
for new serial ports to be detected.
</p>
</div>
</div>
<div class="ribbon"></div> <div class="ribbon"></div>
</header> </header>
@@ -191,6 +207,7 @@
<a href="#" class="action-upload" data-node="{{ file }}">Upload</a> <a href="#" class="action-upload" data-node="{{ file }}">Upload</a>
<a href="#" class="action-compile" data-node="{{ file }}">Compile</a> <a href="#" class="action-compile" data-node="{{ file }}">Compile</a>
<a href="#" class="action-show-logs" data-node="{{ file }}">Show Logs</a> <a href="#" class="action-show-logs" data-node="{{ file }}">Show Logs</a>
<a href="#" class="action-validate" data-node="{{ file }}">Validate</a>
</div> </div>
</div> </div>
</div> </div>
@@ -201,64 +218,50 @@
<div id="modal-logs" class="modal modal-fixed-footer"> <div id="modal-logs" class="modal modal-fixed-footer">
<div class="modal-content"> <div class="modal-content">
<h4>Show Logs</h4> <h4>Show Logs <code class="inlinecode filename"></code></h4>
<div class="upload-port row">
<div class="col s12">
<h5>Found multiple serial ports, please choose one:</h5>
</div>
<div class="input-field col s8">
<select></select>
</div>
<div class="col s4 select-port-container">
<button class="btn waves-effect waves-light upload-port-submit" type="submit" name="action">Select
<i class="material-icons right">send</i>
</button>
</div>
</div>
<div class="log-container"> <div class="log-container">
<pre class="log"></pre> <pre class="log"></pre>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat">Close</a> <a class="modal-close waves-effect waves-green btn-flat stop-logs">Close</a>
</div> </div>
</div> </div>
<div id="modal-upload" class="modal modal-fixed-footer"> <div id="modal-upload" class="modal modal-fixed-footer">
<div class="modal-content"> <div class="modal-content">
<h4>Compile And Upload</h4> <h4>Compile And Upload <code class="inlinecode filename"></code></h4>
<div class="upload-port row">
<div class="col s12">
<h5>Found multiple upload options, please choose one:</h5>
</div>
<div class="input-field col s8">
<select></select>
</div>
<div class="col s4 select-port-container">
<button class="btn waves-effect waves-light upload-port-submit" type="submit" name="action">Select
<i class="material-icons right">send</i>
</button>
</div>
</div>
<div class="log-container"> <div class="log-container">
<pre class="log"></pre> <pre class="log"></pre>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat">Stop</a> <a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div> </div>
</div> </div>
<div id="modal-compile" class="modal modal-fixed-footer"> <div id="modal-compile" class="modal modal-fixed-footer">
<div class="modal-content"> <div class="modal-content">
<h4>Compile</h4> <h4>Compile <code class="inlinecode filename"></code></h4>
<div class="log-container"> <div class="log-container">
<pre class="log"></pre> <pre class="log"></pre>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat disabled download-binary">Download Binary</a> <a class="modal-close waves-effect waves-green btn-flat disabled download-binary">Download Binary</a>
<a class="modal-close waves-effect waves-green btn-flat">Stop</a> <a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<div id="modal-validate" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Validate <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div> </div>
</div> </div>
@@ -278,7 +281,7 @@
their successors (the <a href="https://www.espressif.com/en/products/hardware/esp32/overview" target="_blank">ESP32s</a>) their successors (the <a href="https://www.espressif.com/en/products/hardware/esp32/overview" target="_blank">ESP32s</a>)
are great low-cost microcontrollers that can communicate with the outside world using WiFi. are great low-cost microcontrollers that can communicate with the outside world using WiFi.
They're found in many devices such as the popular Sonoff/iTead, but also exist as development boards They're found in many devices such as the popular Sonoff/iTead, but also exist as development boards
such as the <a href="http://nodemcu.com/index_en.html" target="_blank">NodeMCU</a>. such as the <a href="https://esphomelib.com/esphomeyaml/devices/nodemcu_esp8266.html" target="_blank">NodeMCU</a>.
<p> <p>
</p> </p>
<a href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml</a>, <a href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml</a>,
@@ -303,7 +306,7 @@
</div> </div>
</div> </div>
<div class="step-actions"> <div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step"">CONTINUE</button> <button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div> </div>
</div> </div>
</li> </li>
@@ -313,8 +316,7 @@
<div class="row"> <div class="row">
<p> <p>
Great! Now I need to know what type of microcontroller you're using so that I can compile firmware for them. Great! Now I need to know what type of microcontroller you're using so that I can compile firmware for them.
Please choose either ESP32 or ESP8266 (use ESP8266 for Sonoff devices). Note that the ESP32 is currently Please choose either ESP32 or ESP8266 (use ESP8266 for Sonoff devices).
unsupported if HassIO is running on a Raspberry Pi.
</p> </p>
<div class="input-field col s12"> <div class="input-field col s12">
<select id="esp_type" name="platform" required> <select id="esp_type" name="platform" required>
@@ -358,8 +360,8 @@
</div> </div>
<p> <p>
Esphomelib automatically sets up an Over-The-Air update server on the node Esphomelib automatically sets up an Over-The-Air update server on the node
so that you only need to flash a firmware once. Optionally, you can set a password for this so that you only need to flash a firmware via USB once.
upload process here. Optionally, you can set a password for this upload process here:
</p> </p>
<div class="input-field col s12"> <div class="input-field col s12">
<input id="ota_password" class="validate" name="ota_password" type="password"> <input id="ota_password" class="validate" name="ota_password" type="password">
@@ -384,7 +386,7 @@
<p> <p>
When you're done with that, please enter your MQTT broker here. For example When you're done with that, please enter your MQTT broker here. For example
<code class="inlinecode">192.168.1.100</code> (Note <code class="inlinecode">192.168.1.100</code> (Note
<code class="inlinecode">hassio.local</code> often doesn't work, please use a static IP). <code class="inlinecode">hassio.local</code> doesn't always work, please use a static IP).
Please also specify the MQTT username and password you wish esphomelib to use Please also specify the MQTT username and password you wish esphomelib to use
(leave them empty if you're not using any authentication). (leave them empty if you're not using any authentication).
</p> </p>
@@ -420,22 +422,29 @@
<ul class="browser-default"> <ul class="browser-default">
<li> <li>
Flash the firmware. This can be done using the “UPLOAD” option in the dashboard. See Flash the firmware. This can be done using the “UPLOAD” option in the dashboard. See
<a href="https://esphomelib.com/esphomeyaml/index.html#using-with" target="_blank">this</a> <a href="https://esphomelib.com/esphomeyaml/index.html#devices" target="_blank">this</a>
for guides on how to flash different types of devices. Note that you need to restart this add-on for guides on how to flash different types of devices. Note that you need to restart this add-on
for newly plugged in serial devices to be detected. for newly plugged in serial devices to be detected.
</li> </li>
<li>
With the current configuration, your node will only connect to WiFi and MQTT. To make it actually <i>do</i>
stuff, follow
<a href="https://esphomelib.com/esphomeyaml/guides/getting_started_hassio.html#adding-some-basic-features">
the rest of the getting started guide
</a>.
</li>
<li> <li>
See the <a href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml index</a> See the <a href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml index</a>
for a list of supported sensors/devices. for a list of supported sensors/devices.
</li> </li>
<li> <li>
Join the <a href="https://discord.gg/KhAMKrd" target="_blank">Discord server</a> and say hi. When I Join the <a href="https://discord.gg/KhAMKrd" target="_blank">Discord server</a> and say hi! When I
have time, I would be happy to help with issues and discuss new features. have time, I would be happy to help with issues and discuss new features.
</li> </li>
<li> <li>
Star <a href="https://github.com/OttoWinter/esphomelib" target="_blank">esphomelib</a> and Star <a href="https://github.com/OttoWinter/esphomelib" target="_blank">esphomelib</a> and
<a href="https://github.com/OttoWinter/esphomeyaml" target="_blank">esphomeyaml</a> on GitHub and <a href="https://github.com/OttoWinter/esphomeyaml" target="_blank">esphomeyaml</a> on GitHub
report issues using the bug trackers there. if you find this software awesome and report issues using the bug trackers there.
</li> </li>
</ul> </ul>
<div class="step-actions"> <div class="step-actions">
@@ -455,7 +464,7 @@
<i class="material-icons">add</i> <i class="material-icons">add</i>
</a> </a>
<div class="tap-target pink lighten-1" data-target="setup-wizard-start"> <div class="tap-target pink lighten-1 setup-wizard" data-target="setup-wizard-start">
<div class="tap-target-content"> <div class="tap-target-content">
<h5>Set up your first Node</h5> <h5>Set up your first Node</h5>
<p> <p>
@@ -505,19 +514,67 @@
}; };
let configuration = ""; let configuration = "";
const ws_url = 'ws://' + window.location.hostname + ':' + window.location.port; let wsProtocol = "ws:";
if (window.location.protocol === "https:") {
wsProtocol = 'wss:';
}
const wsUrl = wsProtocol + '//' + window.location.hostname + ':' + window.location.port;
const portSelect = document.querySelector('.nav-wrapper select');
let ports = [];
const fetchSerialPorts = (begin=false) => {
fetch('/serial-ports').then(res => res.json())
.then(response => {
if (ports.length === response.length) {
let allEqual = true;
for (let i = 0; i < response.length; i++) {
if (ports[i].port !== response[i].port) {
allEqual = false;
break;
}
}
if (allEqual)
return;
}
ports = response;
const inst = M.FormSelect.getInstance(portSelect);
if (inst !== undefined) {
inst.destroy();
}
portSelect.innerHTML = "";
const prevSelected = getUploadPort();
for (let i = 0; i < response.length; i++) {
const val = response[i];
if (val.port === prevSelected) {
portSelect.innerHTML += `<option value="${val.port}" selected>${val.port} (${val.desc})</option>`;
} else {
portSelect.innerHTML += `<option value="${val.port}">${val.port} (${val.desc})</option>`;
}
}
M.FormSelect.init(portSelect, {});
if (!begin)
M.toast({html: "Discovered new serial port."});
});
};
const getUploadPort = () => {
const inst = M.FormSelect.getInstance(portSelect);
if (inst === undefined) {
return "OTA";
}
inst._setSelectedStates();
return inst.getSelectedValues()[0];
};
setInterval(fetchSerialPorts, 5000);
fetchSerialPorts(true);
const logsModalElem = document.getElementById("modal-logs"); const logsModalElem = document.getElementById("modal-logs");
const logsPortSelect = logsModalElem.querySelector('select');
const logsPortDiv = logsModalElem.querySelector(".upload-port");
const logsPortSubmit = logsModalElem.querySelector('.upload-port-submit');
let logsStart = undefined;
logsPortSubmit.addEventListener('click', () => {
const inst = M.FormSelect.getInstance(logsPortSelect);
logsStart(inst.getSelectedValues()[0]);
inst.destroy();
});
document.querySelectorAll(".action-show-logs").forEach((showLogs) => { document.querySelectorAll(".action-show-logs").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => { showLogs.addEventListener('click', (e) => {
@@ -525,145 +582,15 @@
const modalInstance = M.Modal.getInstance(logsModalElem); const modalInstance = M.Modal.getInstance(logsModalElem);
const log = logsModalElem.querySelector(".log"); const log = logsModalElem.querySelector(".log");
log.innerHTML = ""; log.innerHTML = "";
const stopLogsButton = logsModalElem.querySelector(".stop-logs");
if (M.FormSelect.getInstance(logsPortSelect) !== undefined) { let stopped = false;
M.FormSelect.getInstance(logsPortSelect).destroy(); stopLogsButton.innerHTML = "Stop";
}
modalInstance.open(); modalInstance.open();
if (logsPortDiv.classList.contains('hide')) { const filenameField = logsModalElem.querySelector('.filename');
logsPortDiv.classList.remove('hide'); filenameField.innerHTML = configuration;
}
logsStart = (port) => { const logSocket = new WebSocket(wsUrl + "/logs");
logsPortDiv.classList.add('hide');
const logSocket = new WebSocket(ws_url + "/logs");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully!"});
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: port});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
M.toast({html: 'Terminated process.'});
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
};
fetch('/serial-ports').then(res => res.json())
.then(response => {
if (response.length > 1) {
logsPortSelect.innerHTML = "";
for (let i = 0; i < response.length; i++) {
const val = response[i];
logsPortSelect.innerHTML += `<option value="${val.port}">${val.port} (${val.desc})</option>`;
}
M.FormSelect.init(logsPortSelect, {});
} else {
logsStart("OTA");
}
});
});
});
const uploadModalElem = document.getElementById("modal-upload");
const uploadPortSelect = uploadModalElem.querySelector('select');
const uploadPortDiv = uploadModalElem.querySelector(".upload-port");
const uploadPortSubmit = uploadModalElem.querySelector('.upload-port-submit');
let uploadStart = undefined;
uploadPortSubmit.addEventListener('click', () => {
const inst = M.FormSelect.getInstance(uploadPortSelect);
uploadStart(inst.getSelectedValues()[0]);
inst.destroy();
});
document.querySelectorAll(".action-upload").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(uploadModalElem);
const log = uploadModalElem.querySelector(".log");
log.innerHTML = "";
if (M.FormSelect.getInstance(uploadPortSelect) !== undefined) {
M.FormSelect.getInstance(uploadPortSelect).destroy();
}
modalInstance.open();
if (uploadPortDiv.classList.contains('hide')) {
uploadPortDiv.classList.remove('hide');
}
uploadStart = (port) => {
uploadPortDiv.classList.add('hide');
const logSocket = new WebSocket(ws_url + "/run");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully!"});
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: port});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
M.toast({html: 'Terminated process.'});
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
};
fetch('/serial-ports').then(res => res.json())
.then(response => {
if (response.length > 1) {
uploadPortSelect.innerHTML = "";
for (let i = 0; i < response.length; i++) {
const val = response[i];
uploadPortSelect.innerHTML += `<option value="${val.port}">${val.port} (${val.desc})</option>`;
}
M.FormSelect.init(uploadPortSelect, {});
} else {
uploadStart("OTA");
}
});
});
});
const compileModalElem = document.getElementById("modal-compile");
const downloadButton = compileModalElem.querySelector('.download-binary');
document.querySelectorAll(".action-compile").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(compileModalElem);
const log = compileModalElem.querySelector(".log");
log.innerHTML = "";
downloadButton.classList.add('disabled');
modalInstance.open();
const logSocket = new WebSocket(ws_url + "/compile");
logSocket.addEventListener('message', (event) => { logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.event === "line") { if (data.event === "line") {
@@ -671,19 +598,23 @@
log.innerHTML += colorReplace(msg); log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") { } else if (data.event === "exit") {
if (data.code === 0) { if (data.code === 0) {
M.toast({html: "Program exited successfully!"}); M.toast({html: "Program exited successfully."});
downloadButton.classList.remove('disabled');
} else { } else {
M.toast({html: `Program failed with code ${data.code}`}); M.toast({html: `Program failed with code ${data.code}`});
} }
stopLogsButton.innerHTML = "Close";
stopped = true;
} }
}); });
logSocket.addEventListener('open', () => { logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration}); const msg = JSON.stringify({configuration: configuration, port: getUploadPort()});
logSocket.send(msg); logSocket.send(msg);
}); });
logSocket.addEventListener('close', () => { logSocket.addEventListener('close', () => {
M.toast({html: 'Terminated process.'}); if (!stopped) {
M.toast({html: 'Terminated process.'});
}
}); });
modalInstance.options.onCloseStart = () => { modalInstance.options.onCloseStart = () => {
logSocket.close(); logSocket.close();
@@ -691,6 +622,159 @@
}); });
}); });
const uploadModalElem = document.getElementById("modal-upload");
document.querySelectorAll(".action-upload").forEach((upload) => {
upload.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(uploadModalElem);
const log = uploadModalElem.querySelector(".log");
log.innerHTML = "";
const stopLogsButton = uploadModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = uploadModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/run");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: getUploadPort()});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const validateModalElem = document.getElementById("modal-validate");
document.querySelectorAll(".action-validate").forEach((upload) => {
upload.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(validateModalElem);
const log = validateModalElem.querySelector(".log");
log.innerHTML = "";
const stopLogsButton = validateModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = validateModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/validate");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({
html: `<code class="inlinecode">${configuration}</code> is valid 👍`,
displayLength: 5000,
});
} else {
M.toast({
html: `<code class="inlinecode">${configuration}</code> is invalid 😕`,
displayLength: 5000,
});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const compileModalElem = document.getElementById("modal-compile");
const downloadButton = compileModalElem.querySelector('.download-binary');
document.querySelectorAll(".action-compile").forEach((upload) => {
upload.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(compileModalElem);
const log = compileModalElem.querySelector(".log");
log.innerHTML = "";
const stopLogsButton = compileModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
downloadButton.classList.add('disabled');
modalInstance.open();
const filenameField = compileModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/compile");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
downloadButton.classList.remove('disabled');
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
downloadButton.addEventListener('click', () => { downloadButton.addEventListener('click', () => {
const link = document.createElement("a"); const link = document.createElement("a");
link.download = name; link.download = name;
@@ -722,7 +806,7 @@
{% if len(files) == 0 %} {% if len(files) == 0 %}
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const tapTargetElem = document.querySelector('.tap-target'); const tapTargetElem = document.querySelector('.tap-target.setup-wizard');
const tapTargetInstance = M.TapTarget.getInstance(tapTargetElem); const tapTargetInstance = M.TapTarget.getInstance(tapTargetElem);
tapTargetInstance.options.onOpen = () => { tapTargetInstance.options.onOpen = () => {
$('.tap-target-origin').on('click', () => { $('.tap-target-origin').on('click', () => {
@@ -734,5 +818,23 @@
</script> </script>
{% end %} {% end %}
{% if begin %}
<script>
window.history.replaceState({}, document.title, "/");
document.addEventListener('DOMContentLoaded', () => {
const tapTargetElem = document.querySelector('.tap-target.select-port');
const tapTargetInstance = M.TapTarget.getInstance(tapTargetElem);
tapTargetInstance.open();
tapTargetInstance.contentEl.style["top"] = "300px";
tapTargetInstance.contentEl.style["padding"] = "250px";
tapTargetInstance.waveEl.style["top"] = "250px";
tapTargetInstance.waveEl.style["left"] = "250px";
tapTargetInstance.waveEl.style["width"] = "300px";
tapTargetInstance.waveEl.style["height"] = "300px";
});
</script>
{% end %}
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
from __future__ import print_function from __future__ import print_function
import inspect
import logging import logging
import re import re
from collections import OrderedDict, deque from collections import OrderedDict, deque
@@ -9,8 +10,8 @@ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOV
CONF_INVERTED, \ CONF_INVERTED, \
CONF_MODE, CONF_NUMBER, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_PCF8574, \ CONF_MODE, CONF_NUMBER, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_PCF8574, \
CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC
from esphomeyaml.core import ESPHomeYAMLError, HexInt, TimePeriodMicroseconds, \ from esphomeyaml.core import ESPHomeYAMLError, HexInt, Lambda, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds, Lambda TimePeriodMilliseconds, TimePeriodSeconds
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -356,87 +357,112 @@ def statement(expression):
return ExpressionStatement(expression) return ExpressionStatement(expression)
def register_variable(type, id, obj): def register_variable(id, obj):
_VARIABLES[id] = obj, type _LOGGER.debug("Registered variable %s of type %s", id.id, id.type)
_VARIABLES[id] = obj
# pylint: disable=redefined-builtin, invalid-name # pylint: disable=redefined-builtin, invalid-name
def variable(type, id, rhs): def variable(id, rhs, type=None):
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
obj = MockObj(id, u'.') obj = MockObj(id, u'.')
assignment = AssignmentExpression(type, '', id, rhs, obj) id.type = type or id.type
assignment = AssignmentExpression(id.type, '', id, rhs, obj)
add(assignment) add(assignment)
register_variable(type, id, obj) register_variable(id, obj)
obj.requires.append(assignment) obj.requires.append(assignment)
return obj return obj
def Pvariable(type, id, rhs, has_side_effects=True): def Pvariable(id, rhs, has_side_effects=True, type=None):
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
if not has_side_effects and hasattr(rhs, '_has_side_effects'): if not has_side_effects and hasattr(rhs, '_has_side_effects'):
# pylint: disable=attribute-defined-outside-init, protected-access # pylint: disable=attribute-defined-outside-init, protected-access
rhs._has_side_effects = False rhs._has_side_effects = False
obj = MockObj(id, u'->', has_side_effects=has_side_effects) obj = MockObj(id, u'->', has_side_effects=has_side_effects)
assignment = AssignmentExpression(type, '*', id, rhs, obj) id.type = type or id.type
assignment = AssignmentExpression(id.type, '*', id, rhs, obj)
add(assignment) add(assignment)
register_variable(type, id, obj) register_variable(id, obj)
obj.requires.append(assignment) obj.requires.append(assignment)
return obj return obj
_QUEUE = deque() _TASKS = deque()
_VARIABLES = {} _VARIABLES = {}
_EXPRESSIONS = [] _EXPRESSIONS = []
def get_variable(id, type=None): def get_variable(id):
def get_result(): while True:
if id is not None: if id in _VARIABLES:
if id in _VARIABLES: yield _VARIABLES[id]
return _VARIABLES[id][0] return
elif type is not None: _LOGGER.debug("Waiting for variable %s", id)
return next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None) yield 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 type is None:
raise ESPHomeYAMLError(u"Couldn't find ID '{}'".format(id))
raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type '{}'".format(id, type))
return result
def process_lambda(value, parameters, capture='=', return_type=None): def process_lambda(value, parameters, capture='=', return_type=None):
if value is None: if value is None:
return None yield
parts = re.split(r'id\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)\.', value.value) return
for i in range(1, len(parts), 2): parts = value.parts[:]
parts[i] = get_variable(parts[i])._ for i, id in enumerate(value.requires_ids):
return LambdaExpression(parts, parameters, capture, return_type) var = None
for var in get_variable(id):
yield
parts[i*2 + 1] = var._
yield LambdaExpression(parts, parameters, capture, return_type)
return
def templatable(value, input_type, output_type): def templatable(value, input_type, output_type):
if isinstance(value, Lambda): if isinstance(value, Lambda):
return process_lambda(value, [(input_type, 'x')], return_type=output_type) lambda_ = None
return value for lambda_ in process_lambda(value, [(input_type, 'x')], return_type=output_type):
yield None
yield lambda_
else:
yield value
def add_task(func, config): def add_job(func, *args, **kwargs):
_QUEUE.append((func, config)) domain = kwargs.get('domain')
if inspect.isgeneratorfunction(func):
def func_():
yield
for _ in func(*args):
yield
else:
def func_():
yield
func(*args)
gen = func_()
_TASKS.append((gen, domain))
return gen
def flush_tasks():
i = 0
while _TASKS:
i += 1
if i > 1000000:
raise ESPHomeYAMLError("Circular dependency detected!")
task, domain = _TASKS.popleft()
_LOGGER.debug("Executing task for domain=%s", domain)
try:
task.next()
_TASKS.append((task, domain))
except StopIteration:
_LOGGER.debug(" -> %s finished", domain)
def add(expression, require=True): def add(expression, require=True):
if require and isinstance(expression, Expression): if require and isinstance(expression, Expression):
expression.require() expression.require()
_EXPRESSIONS.append(expression) _EXPRESSIONS.append(expression)
_LOGGER.debug("Adding: %s", statement(expression))
return expression return expression
@@ -457,7 +483,7 @@ class MockObj(Expression):
obj.requires.append(self) obj.requires.append(self)
return obj return obj
next_op = u'.' next_op = u'.'
if attr.startswith(u'P') and self.op != '::': if attr.startswith(u'P') and self.op not in ['::', '']:
attr = attr[1:] attr = attr[1:]
next_op = u'->' next_op = u'->'
if attr.startswith(u'_'): if attr.startswith(u'_'):
@@ -528,32 +554,43 @@ def get_gpio_pin_number(conf):
def generic_gpio_pin_expression_(conf, mock_obj, default_mode): def generic_gpio_pin_expression_(conf, mock_obj, default_mode):
if conf is None: if conf is None:
return None return
number = conf[CONF_NUMBER] number = conf[CONF_NUMBER]
inverted = conf.get(CONF_INVERTED) inverted = conf.get(CONF_INVERTED)
if CONF_PCF8574 in conf: if CONF_PCF8574 in conf:
hub = get_variable(conf[CONF_PCF8574], 'io::PCF8574Component') hub = None
for hub in get_variable(conf[CONF_PCF8574]):
yield None
if default_mode == u'INPUT': if default_mode == u'INPUT':
mode = conf.get(CONF_MODE, u'INPUT') mode = conf.get(CONF_MODE, u'INPUT')
return hub.make_input_pin(number, yield hub.make_input_pin(number,
RawExpression('PCF8574_' + mode), RawExpression('PCF8574_' + mode),
inverted) inverted)
return
elif default_mode == u'OUTPUT': elif default_mode == u'OUTPUT':
return hub.make_output_pin(number, inverted) yield hub.make_output_pin(number, inverted)
return
else: else:
raise ESPHomeYAMLError(u"Unknown default mode {}".format(default_mode)) raise ESPHomeYAMLError(u"Unknown default mode {}".format(default_mode))
if len(conf) == 1: if len(conf) == 1:
return IntLiteral(number) yield IntLiteral(number)
return
mode = RawExpression(conf.get(CONF_MODE, default_mode)) mode = RawExpression(conf.get(CONF_MODE, default_mode))
return mock_obj(number, mode, inverted) yield mock_obj(number, mode, inverted)
def gpio_output_pin_expression(conf): def gpio_output_pin_expression(conf):
return generic_gpio_pin_expression_(conf, GPIOOutputPin, 'OUTPUT') exp = None
for exp in generic_gpio_pin_expression_(conf, GPIOOutputPin, 'OUTPUT'):
yield None
yield exp
def gpio_input_pin_expression(conf): def gpio_input_pin_expression(conf):
return generic_gpio_pin_expression_(conf, GPIOInputPin, 'INPUT') exp = None
for exp in generic_gpio_pin_expression_(conf, GPIOInputPin, 'INPUT'):
yield None
yield exp
def setup_mqtt_component(obj, config): def setup_mqtt_component(obj, config):
@@ -567,8 +604,11 @@ def setup_mqtt_component(obj, config):
add(obj.set_custom_command_topic(config[CONF_COMMAND_TOPIC])) add(obj.set_custom_command_topic(config[CONF_COMMAND_TOPIC]))
if CONF_AVAILABILITY in config: if CONF_AVAILABILITY in config:
availability = config[CONF_AVAILABILITY] availability = config[CONF_AVAILABILITY]
add(obj.set_availability(availability[CONF_TOPIC], availability[CONF_PAYLOAD_AVAILABLE], if not availability:
availability[CONF_PAYLOAD_NOT_AVAILABLE])) add(obj.disable_availability())
else:
add(obj.set_availability(availability[CONF_TOPIC], availability[CONF_PAYLOAD_AVAILABLE],
availability[CONF_PAYLOAD_NOT_AVAILABLE]))
# shlex's quote for Python 2.7 # shlex's quote for Python 2.7

View File

@@ -10,7 +10,7 @@ from esphomeyaml import core
from esphomeyaml.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOMEYAML, \ from esphomeyaml.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOMEYAML, \
CONF_LOG_TOPIC, \ CONF_LOG_TOPIC, \
CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \ CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \
CONF_USERNAME CONF_USERNAME, CONF_TOPIC
from esphomeyaml.helpers import color from esphomeyaml.helpers import color
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -45,7 +45,7 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None,
elif CONF_MQTT in config: elif CONF_MQTT in config:
conf = config[CONF_MQTT] conf = config[CONF_MQTT]
if CONF_LOG_TOPIC in conf: if CONF_LOG_TOPIC in conf:
topic = config[CONF_MQTT][CONF_LOG_TOPIC] topic = config[CONF_MQTT][CONF_LOG_TOPIC][CONF_TOPIC]
elif CONF_TOPIC_PREFIX in config[CONF_MQTT]: elif CONF_TOPIC_PREFIX in config[CONF_MQTT]:
topic = config[CONF_MQTT][CONF_TOPIC_PREFIX] + u'/debug' topic = config[CONF_MQTT][CONF_TOPIC_PREFIX] + u'/debug'
else: else:
@@ -57,10 +57,13 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None,
def on_message(client, userdata, msg): def on_message(client, userdata, msg):
time = datetime.now().time().strftime(u'[%H:%M:%S]') time = datetime.now().time().strftime(u'[%H:%M:%S]')
message = msg.payload.decode('utf-8') message = time + msg.payload
if escape: if escape:
message = message.replace('\033', '\\033') message = message.replace('\033', '\\033')
print(time + message) try:
print(message)
except UnicodeEncodeError:
print(message.encode('ascii', 'backslashreplace'))
return initialize(config, [topic], on_message, username, password, client_id) return initialize(config, [topic], on_message, username, password, client_id)

View File

@@ -4,6 +4,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core from esphomeyaml import core
from esphomeyaml.components import pcf8574
from esphomeyaml.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_PCF8574, \ from esphomeyaml.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_PCF8574, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
@@ -202,20 +203,40 @@ def shorthand_input_pin(value):
PCF8574_OUTPUT_PIN_SCHEMA = vol.Schema({ PCF8574_OUTPUT_PIN_SCHEMA = vol.Schema({
vol.Required(CONF_PCF8574): cv.variable_id, vol.Required(CONF_PCF8574): cv.use_variable_id(pcf8574.PCF8574Component),
vol.Required(CONF_NUMBER): vol.Coerce(int), vol.Required(CONF_NUMBER): vol.Coerce(int),
vol.Optional(CONF_MODE): vol.All(vol.Upper, "OUTPUT"), vol.Optional(CONF_MODE): vol.All(vol.Upper, cv.one_of("OUTPUT")),
vol.Optional(CONF_INVERTED, default=False): cv.boolean, vol.Optional(CONF_INVERTED, default=False): cv.boolean,
}) })
PCF8574_INPUT_PIN_SCHEMA = PCF8574_OUTPUT_PIN_SCHEMA.extend({ PCF8574_INPUT_PIN_SCHEMA = PCF8574_OUTPUT_PIN_SCHEMA.extend({
vol.Optional(CONF_MODE): vol.All(vol.Upper, vol.Any("INPUT", "INPUT_PULLUP")), vol.Optional(CONF_MODE): vol.All(vol.Upper, cv.one_of("INPUT", "INPUT_PULLUP")),
}) })
GPIO_INTERNAL_OUTPUT_PIN_SCHEMA = vol.Any(shorthand_output_pin, GPIO_FULL_OUTPUT_PIN_SCHEMA)
GPIO_OUTPUT_PIN_SCHEMA = vol.Any(PCF8574_OUTPUT_PIN_SCHEMA, GPIO_INTERNAL_OUTPUT_PIN_SCHEMA) def internal_gpio_output_pin_schema(value):
if isinstance(value, dict):
return GPIO_FULL_OUTPUT_PIN_SCHEMA(value)
return shorthand_output_pin(value)
GPIO_INTERNAL_INPUT_PIN_SCHEMA = vol.Any(shorthand_input_pin, GPIO_FULL_INPUT_PIN_SCHEMA)
GPIO_INPUT_PIN_SCHEMA = vol.Any(PCF8574_INPUT_PIN_SCHEMA, GPIO_INTERNAL_INPUT_PIN_SCHEMA) def gpio_output_pin_schema(value):
if isinstance(value, dict):
if CONF_PCF8574 in value:
return PCF8574_OUTPUT_PIN_SCHEMA(value)
return GPIO_FULL_OUTPUT_PIN_SCHEMA(value)
return shorthand_output_pin(value)
def internal_gpio_input_pin_schema(value):
if isinstance(value, dict):
return GPIO_FULL_INPUT_PIN_SCHEMA(value)
return shorthand_input_pin(value)
def gpio_input_pin_schema(value):
if isinstance(value, dict):
if CONF_PCF8574 in value:
return PCF8574_INPUT_PIN_SCHEMA(value)
return GPIO_FULL_INPUT_PIN_SCHEMA(value)
return shorthand_input_pin(value)

View File

@@ -0,0 +1,12 @@
; This file allows the docker build file to install the required platformio
; platforms
[env:espressif8266]
platform = espressif8266
board = nodemcuv2
framework = arduino
[env:espressif32]
platform = espressif32
board = nodemcu-32s
framework = arduino

View File

@@ -306,5 +306,5 @@ def wizard(path):
print(color('bold_white', " discovery: True")) print(color('bold_white', " discovery: True"))
print() print()
print(" > Then follow the rest of the getting started guide:") print(" > Then follow the rest of the getting started guide:")
print(" > https://esphomelib.com/esphomeyaml/getting-started.html") print(" > https://esphomelib.com/esphomeyaml/guides/getting_started_command_line.html")
return 0 return 0

View File

@@ -8,6 +8,7 @@ from collections import OrderedDict
import yaml import yaml
from esphomeyaml import core
from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, Lambda, MACAddress, TimePeriod from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, Lambda, MACAddress, TimePeriod
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -47,8 +48,9 @@ def load_yaml(fname):
with codecs.open(fname, encoding='utf-8') as conf_file: with codecs.open(fname, encoding='utf-8') as conf_file:
return yaml.load(conf_file, Loader=SafeLineLoader) or OrderedDict() return yaml.load(conf_file, Loader=SafeLineLoader) or OrderedDict()
except yaml.YAMLError as exc: except yaml.YAMLError as exc:
_LOGGER.error(exc)
raise ESPHomeYAMLError(exc) raise ESPHomeYAMLError(exc)
except IOError as exc:
raise ESPHomeYAMLError(u"Error accessing file {}: {}".format(fname, exc))
except UnicodeDecodeError as exc: except UnicodeDecodeError as exc:
_LOGGER.error(u"Unable to read file %s: %s", fname, exc) _LOGGER.error(u"Unable to read file %s: %s", fname, exc)
raise ESPHomeYAMLError(exc) raise ESPHomeYAMLError(exc)
@@ -279,6 +281,10 @@ def represent_lambda(_, data):
return node return node
def represent_id(_, data):
return yaml.ScalarNode(tag=u'tag:yaml.org,2002:str', value=data.id)
yaml.SafeDumper.add_representer( yaml.SafeDumper.add_representer(
OrderedDict, OrderedDict,
lambda dumper, value: lambda dumper, value:
@@ -297,3 +303,4 @@ yaml.SafeDumper.add_representer(IPAddress, stringify_representer)
yaml.SafeDumper.add_representer(MACAddress, stringify_representer) yaml.SafeDumper.add_representer(MACAddress, stringify_representer)
yaml.SafeDumper.add_multi_representer(TimePeriod, represent_time_period) yaml.SafeDumper.add_multi_representer(TimePeriod, represent_time_period)
yaml.SafeDumper.add_multi_representer(Lambda, represent_lambda) yaml.SafeDumper.add_multi_representer(Lambda, represent_lambda)
yaml.SafeDumper.add_multi_representer(core.ID, represent_id)

91
examples/sonoff_4ch.yaml Normal file
View File

@@ -0,0 +1,91 @@
esphomeyaml:
name: <NAME_OF_NODE>
platform: ESP8266
board: esp01_1m
board_flash_mode: dout
wifi:
ssid: <YOUR_SSID>
password: <YOUR_PASSWORD>
mqtt:
broker: <YOUR_MQTT_BROKER>
username: <YOUR_USERNAME>
password: <YOUR_PASSWORD>
logger:
ota:
binary_sensor:
- platform: gpio
pin:
number: GPIO0
mode: INPUT_PULLUP
inverted: True
name: "Sonoff 4CH Button 1"
on_press:
then:
switch.toggle:
id: relay_1
- platform: gpio
pin:
number: GPIO9
mode: INPUT_PULLUP
inverted: True
name: "Sonoff 4CH Button 2"
on_press:
then:
switch.toggle:
id: relay_2
- platform: gpio
pin:
number: GPIO10
mode: INPUT_PULLUP
inverted: True
name: "Sonoff 4CH Button 3"
on_press:
then:
switch.toggle:
id: relay_3
- platform: gpio
pin:
number: GPIO14
mode: INPUT_PULLUP
inverted: True
name: "Sonoff 4CH Button 4"
on_press:
then:
switch.toggle:
id: relay_4
- platform: status
name: "Sonoff 4CH Status"
switch:
- platform: gpio
name: "Sonoff 4CH Relay 1"
pin: GPIO12
id: relay_1
- platform: gpio
name: "Sonoff 4CH Relay 2"
pin: GPIO5
id: relay_2
- platform: gpio
name: "Sonoff 4CH Relay 3"
pin: GPIO4
id: relay_3
- platform: gpio
name: "Sonoff 4CH Relay 4"
pin: GPIO15
id: relay_4
output:
- platform: esp8266_pwm
id: blue_led
pin: GPIO13
inverted: True
light:
- platform: monochromatic
name: "Sonoff 4CH Blue LED"
output: blue_led

50
examples/sonoff_s20.yaml Normal file
View File

@@ -0,0 +1,50 @@
esphomeyaml:
name: <NAME_OF_NODE>
platform: ESP8266
board: esp01_1m
board_flash_mode: dout
wifi:
ssid: <YOUR_SSID>
password: <YOUR_PASSWORD>
mqtt:
broker: <YOUR_MQTT_BROKER>
username: <YOUR_USERNAME>
password: <YOUR_PASSWORD>
logger:
ota:
binary_sensor:
- platform: gpio
pin:
number: GPIO0
mode: INPUT_PULLUP
inverted: True
name: "Sonoff S20 Button"
on_press:
then:
- switch.toggle:
id: relay
- platform: status
name: "Sonoff S20 Status"
switch:
- platform: gpio
name: "Sonoff S20 Relay"
pin: GPIO12
id: relay
output:
- platform: esp8266_pwm
id: s20_green_led
pin: GPIO13
inverted: True
light:
- platform: monochromatic
name: "Sonoff S20 Green LED"
output: s20_green_led

View File

@@ -16,6 +16,7 @@ disable=
duplicate-code, duplicate-code,
invalid-name, invalid-name,
cyclic-import, cyclic-import,
redefined-builtin,
additional-builtins= additional-builtins=

View File

@@ -3,3 +3,5 @@ platformio==3.5.2
pyyaml==3.12 pyyaml==3.12
paho-mqtt==1.3.1 paho-mqtt==1.3.1
colorlog==3.1.2 colorlog==3.1.2
tornado==5.0.2
esptool==2.3.1

View File

@@ -27,6 +27,8 @@ REQUIRES = [
'pyyaml>=3.12', 'pyyaml>=3.12',
'paho-mqtt>=1.3.1', 'paho-mqtt>=1.3.1',
'colorlog>=3.1.2', 'colorlog>=3.1.2',
'tornado>=5.0.0',
'esptool>=2.3.1',
] ]
CLASSIFIERS = [ CLASSIFIERS = [