diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 64780a340d..94a5b7284e 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,11 +4,10 @@
**Related issue (if applicable):** fixes
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#
-**Pull request in [esphome-core](https://github.com/esphome/esphome-core) with C++ framework changes (if applicable):** esphome/esphome-core#
## Checklist:
- [ ] The code change is tested and works locally.
- [ ] Tests have been added to verify that the new code works (under `tests/` folder).
If user exposed functionality or configuration variables are added/changed:
- - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
+ - [ ] Documentation added/updated in [esphome-docs](https://github.com/esphome/esphome-docs).
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f4e2fa40af..94116bcee1 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -41,11 +41,11 @@ stages:
- |
if [[ "${IS_HASSIO}" == "YES" ]]; then
- BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.4.3
+ BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.5.1
BUILD_TO=esphome/esphome-hassio-${BUILD_ARCH}
DOCKERFILE=docker/Dockerfile.hassio
else
- BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.4.3
+ BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.5.1
if [[ "${BUILD_ARCH}" == "amd64" ]]; then
BUILD_TO=esphome/esphome
else
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 0416f2496e..f844fa741e 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -1,9 +1,8 @@
-ARG BUILD_FROM=esphome/esphome-base-amd64:1.4.3
+ARG BUILD_FROM=esphome/esphome-base-amd64:1.5.1
FROM ${BUILD_FROM}
COPY . .
-RUN \
- pip2 install --no-cache-dir --no-binary :all: -e .
+RUN pip2 install --no-cache-dir -e .
WORKDIR /config
ENTRYPOINT ["esphome"]
diff --git a/docker/Dockerfile.hassio b/docker/Dockerfile.hassio
index eaa7d9d504..4d3d0b88f1 100644
--- a/docker/Dockerfile.hassio
+++ b/docker/Dockerfile.hassio
@@ -1,4 +1,4 @@
-ARG BUILD_FROM=esphome/esphome-hassio-base-amd64:1.4.3
+ARG BUILD_FROM
FROM ${BUILD_FROM}
# Copy root filesystem
@@ -6,8 +6,7 @@ COPY docker/rootfs/ /
COPY setup.py setup.cfg MANIFEST.in /opt/esphome/
COPY esphome /opt/esphome/esphome
-RUN \
- pip2 install --no-cache-dir --no-binary :all: -e /opt/esphome
+RUN pip2 install --no-cache-dir -e /opt/esphome
# Build arguments
ARG BUILD_VERSION=dev
diff --git a/docker/Dockerfile.test b/docker/Dockerfile.test
index 32978c0785..daf1199796 100644
--- a/docker/Dockerfile.test
+++ b/docker/Dockerfile.test
@@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
python-pil \
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*rm -rf /var/lib/apt/lists/* /tmp/* && \
- pip install --no-cache-dir --no-binary :all: platformio && \
+ pip install --no-cache-dir platformio && \
platformio settings set enable_telemetry No && \
platformio settings set check_libraries_interval 1000000 && \
platformio settings set check_platformio_interval 1000000 && \
diff --git a/docker/hooks/build b/docker/hooks/build
deleted file mode 100755
index 60879aaa88..0000000000
--- a/docker/hooks/build
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-# the Docker repository tag being built.
-declare CACHE_TAG
-echo "CACHE_TAG: ${CACHE_TAG}"
-# the name and tag of the Docker repository being built. (This variable is a combination of DOCKER_REPO:CACHE_TAG.)
-declare IMAGE_NAME
-echo "IMAGE_NAME: ${IMAGE_NAME}"
-# the architecture to build
-declare BUILD_ARCH
-echo "BUILD_ARCH: ${BUILD_ARCH}"
-# whether this is a hassio build
-declare IS_HASSIO
-echo "IS_HASSIO: ${IS_HASSIO}"
-echo "PWD: $PWD"
-
-if [[ ${IS_HASSIO} = "YES" ]]; then
- docker build \
- --build-arg "BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.4.3" \
- --build-arg "BUILD_VERSION=${CACHE_TAG}" \
- -t "${IMAGE_NAME}" -f ../docker/Dockerfile.hassio ..
-else
- docker build \
- --build-arg "BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.4.3" \
- -t "${IMAGE_NAME}" -f ../docker/Dockerfile ..
-fi
diff --git a/docker/hooks/pre_build b/docker/hooks/pre_build
deleted file mode 100755
index aff12dd3f5..0000000000
--- a/docker/hooks/pre_build
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env bash
-
-# the architecture to build
-declare BUILD_ARCH
-
-echo "BUILD_ARCH: ${BUILD_ARCH}"
-
-if [[ ${BUILD_ARCH} = "amd64" ]]; then
- echo "No qemu required..."
- exit 0
-fi
-if [[ ${BUILD_ARCH} = "i386" ]]; then
- echo "No qemu required..."
- exit 0
-fi
-
-echo "Installing qemu..."
-docker run --rm --privileged multiarch/qemu-user-static:register --reset
diff --git a/docker/rootfs/etc/cont-init.d/20-nginx.sh b/docker/rootfs/etc/cont-init.d/20-nginx.sh
index cd9b2c6b80..107a25c47a 100755
--- a/docker/rootfs/etc/cont-init.d/20-nginx.sh
+++ b/docker/rootfs/etc/cont-init.d/20-nginx.sh
@@ -6,21 +6,29 @@
declare certfile
declare keyfile
-declare port
+declare direct_port
+declare ingress_interface
+declare ingress_port
mkdir -p /var/log/nginx
-# Enable SSL
-if bashio::config.true 'ssl'; then
- rm /etc/nginx/nginx.conf
- mv /etc/nginx/nginx-ssl.conf /etc/nginx/nginx.conf
+direct_port=$(bashio::addon.port 6052)
+if bashio::var.has_value "${direct_port}"; then
+ if bashio::config.true 'ssl'; then
+ certfile=$(bashio::config 'certfile')
+ keyfile=$(bashio::config 'keyfile')
- certfile=$(bashio::config 'certfile')
- keyfile=$(bashio::config 'keyfile')
+ mv /etc/nginx/servers/direct-ssl.disabled /etc/nginx/servers/direct.conf
+ sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/servers/direct.conf
+ sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/servers/direct.conf
+ else
+ mv /etc/nginx/servers/direct.disabled /etc/nginx/servers/direct.conf
+ fi
- sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/nginx.conf
- sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/nginx.conf
+ sed -i "s/%%port%%/${direct_port}/g" /etc/nginx/servers/direct.conf
fi
-port=$(bashio::config 'port')
-sed -i "s/%%port%%/${port}/g" /etc/nginx/nginx.conf
+ingress_port=$(bashio::addon.ingress_port)
+ingress_interface=$(bashio::addon.ip_address)
+sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
+sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
diff --git a/docker/rootfs/etc/cont-init.d/30-esphome.sh b/docker/rootfs/etc/cont-init.d/30-esphome.sh
index 26df8081bd..8fc1b472c0 100644
--- a/docker/rootfs/etc/cont-init.d/30-esphome.sh
+++ b/docker/rootfs/etc/cont-init.d/30-esphome.sh
@@ -10,6 +10,6 @@ if bashio::config.has_value 'esphome_version'; then
esphome_version=$(bashio::config 'esphome_version')
full_url="https://github.com/esphome/esphome/archive/${esphome_version}.zip"
bashio::log.info "Installing esphome version '${esphome_version}' (${full_url})..."
- pip2 install --no-cache-dir --no-binary :all: "${full_url}" \
+ pip2 install -U --no-cache-dir "${full_url}" \
|| bashio::exit.nok "Failed installing esphome pinned version."
fi
diff --git a/docker/rootfs/etc/nginx/includes/mime.types b/docker/rootfs/etc/nginx/includes/mime.types
new file mode 100644
index 0000000000..7c7cdef2d1
--- /dev/null
+++ b/docker/rootfs/etc/nginx/includes/mime.types
@@ -0,0 +1,96 @@
+types {
+ text/html html htm shtml;
+ text/css css;
+ text/xml xml;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ application/javascript js;
+ application/atom+xml atom;
+ application/rss+xml rss;
+
+ text/mathml mml;
+ text/plain txt;
+ text/vnd.sun.j2me.app-descriptor jad;
+ text/vnd.wap.wml wml;
+ text/x-component htc;
+
+ image/png png;
+ image/svg+xml svg svgz;
+ image/tiff tif tiff;
+ image/vnd.wap.wbmp wbmp;
+ image/webp webp;
+ image/x-icon ico;
+ image/x-jng jng;
+ image/x-ms-bmp bmp;
+
+ font/woff woff;
+ font/woff2 woff2;
+
+ application/java-archive jar war ear;
+ application/json json;
+ application/mac-binhex40 hqx;
+ application/msword doc;
+ application/pdf pdf;
+ application/postscript ps eps ai;
+ application/rtf rtf;
+ application/vnd.apple.mpegurl m3u8;
+ application/vnd.google-earth.kml+xml kml;
+ application/vnd.google-earth.kmz kmz;
+ application/vnd.ms-excel xls;
+ application/vnd.ms-fontobject eot;
+ application/vnd.ms-powerpoint ppt;
+ application/vnd.oasis.opendocument.graphics odg;
+ application/vnd.oasis.opendocument.presentation odp;
+ application/vnd.oasis.opendocument.spreadsheet ods;
+ application/vnd.oasis.opendocument.text odt;
+ application/vnd.openxmlformats-officedocument.presentationml.presentation
+ pptx;
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
+ xlsx;
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document
+ docx;
+ application/vnd.wap.wmlc wmlc;
+ application/x-7z-compressed 7z;
+ application/x-cocoa cco;
+ application/x-java-archive-diff jardiff;
+ application/x-java-jnlp-file jnlp;
+ application/x-makeself run;
+ application/x-perl pl pm;
+ application/x-pilot prc pdb;
+ application/x-rar-compressed rar;
+ application/x-redhat-package-manager rpm;
+ application/x-sea sea;
+ application/x-shockwave-flash swf;
+ application/x-stuffit sit;
+ application/x-tcl tcl tk;
+ application/x-x509-ca-cert der pem crt;
+ application/x-xpinstall xpi;
+ application/xhtml+xml xhtml;
+ application/xspf+xml xspf;
+ application/zip zip;
+
+ application/octet-stream bin exe dll;
+ application/octet-stream deb;
+ application/octet-stream dmg;
+ application/octet-stream iso img;
+ application/octet-stream msi msp msm;
+
+ audio/midi mid midi kar;
+ audio/mpeg mp3;
+ audio/ogg ogg;
+ audio/x-m4a m4a;
+ audio/x-realaudio ra;
+
+ video/3gpp 3gpp 3gp;
+ video/mp2t ts;
+ video/mp4 mp4;
+ video/mpeg mpeg mpg;
+ video/quicktime mov;
+ video/webm webm;
+ video/x-flv flv;
+ video/x-m4v m4v;
+ video/x-mng mng;
+ video/x-ms-asf asx asf;
+ video/x-ms-wmv wmv;
+ video/x-msvideo avi;
+}
diff --git a/docker/rootfs/etc/nginx/includes/proxy_params.conf b/docker/rootfs/etc/nginx/includes/proxy_params.conf
new file mode 100644
index 0000000000..c00b4800e8
--- /dev/null
+++ b/docker/rootfs/etc/nginx/includes/proxy_params.conf
@@ -0,0 +1,16 @@
+proxy_http_version 1.1;
+proxy_ignore_client_abort off;
+proxy_read_timeout 86400s;
+proxy_redirect off;
+proxy_send_timeout 86400s;
+proxy_max_temp_file_size 0;
+
+proxy_set_header Accept-Encoding "";
+proxy_set_header Connection $connection_upgrade;
+proxy_set_header Host $http_host;
+proxy_set_header Upgrade $http_upgrade;
+proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+proxy_set_header X-Forwarded-Proto $scheme;
+proxy_set_header X-NginX-Proxy true;
+proxy_set_header X-Real-IP $remote_addr;
+proxy_set_header Authorization "";
diff --git a/docker/rootfs/etc/nginx/includes/server_params.conf b/docker/rootfs/etc/nginx/includes/server_params.conf
new file mode 100644
index 0000000000..479dfa10f6
--- /dev/null
+++ b/docker/rootfs/etc/nginx/includes/server_params.conf
@@ -0,0 +1,6 @@
+root /dev/null;
+server_name $hostname;
+
+add_header X-Content-Type-Options nosniff;
+add_header X-XSS-Protection "1; mode=block";
+add_header X-Robots-Tag none;
diff --git a/docker/rootfs/etc/nginx/includes/ssl_params.conf b/docker/rootfs/etc/nginx/includes/ssl_params.conf
new file mode 100644
index 0000000000..6f15005998
--- /dev/null
+++ b/docker/rootfs/etc/nginx/includes/ssl_params.conf
@@ -0,0 +1,9 @@
+ssl_protocols TLSv1.2;
+ssl_prefer_server_ciphers on;
+ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
+ssl_ecdh_curve secp384r1;
+ssl_session_timeout 10m;
+ssl_session_cache shared:SSL:10m;
+ssl_session_tickets off;
+ssl_stapling on;
+ssl_stapling_verify on;
diff --git a/docker/rootfs/etc/nginx/nginx-ssl.conf b/docker/rootfs/etc/nginx/nginx-ssl.conf
deleted file mode 100755
index cd76036fde..0000000000
--- a/docker/rootfs/etc/nginx/nginx-ssl.conf
+++ /dev/null
@@ -1,62 +0,0 @@
-worker_processes 1;
-pid /var/run/nginx.pid;
-error_log stderr;
-
-events {
- worker_connections 1024;
-}
-
-http {
- access_log stdout;
- include mime.types;
- default_type application/octet-stream;
- sendfile on;
- keepalive_timeout 65;
-
- upstream esphome {
- ip_hash;
- server unix:/var/run/esphome.sock;
- }
- map $http_upgrade $connection_upgrade {
- default upgrade;
- '' close;
- }
-
- server {
- server_name hassio.local;
- listen %%port%% default_server ssl;
- root /dev/null;
-
- ssl_certificate /ssl/%%certfile%%;
- ssl_certificate_key /ssl/%%keyfile%%;
- ssl_protocols TLSv1.2;
- ssl_prefer_server_ciphers on;
- ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
- ssl_ecdh_curve secp384r1;
- ssl_session_timeout 10m;
- ssl_session_cache shared:SSL:10m;
- ssl_session_tickets off;
- ssl_stapling on;
- ssl_stapling_verify on;
-
- # Redirect http requests to https on the same port.
- # https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
- error_page 497 https://$http_host$request_uri;
-
- location / {
- proxy_redirect off;
- proxy_pass http://esphome;
-
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $connection_upgrade;
- proxy_set_header Authorization "";
-
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header Host $http_host;
- proxy_set_header X-NginX-Proxy true;
- }
- }
-}
diff --git a/docker/rootfs/etc/nginx/nginx.conf b/docker/rootfs/etc/nginx/nginx.conf
index 4a0067c12f..8ebf572816 100755
--- a/docker/rootfs/etc/nginx/nginx.conf
+++ b/docker/rootfs/etc/nginx/nginx.conf
@@ -1,46 +1,33 @@
-worker_processes 1;
+daemon off;
+user root;
pid /var/run/nginx.pid;
-error_log stderr;
-
+worker_processes 1;
+# Hass.io addon log
+error_log /proc/1/fd/1 error;
events {
- worker_connections 1024;
+ worker_connections 1024;
}
http {
- access_log stdout;
- include mime.types;
- default_type application/octet-stream;
- sendfile on;
- keepalive_timeout 65;
+ include /etc/nginx/includes/mime.types;
+ access_log stdout;
+ default_type application/octet-stream;
+ gzip on;
+ keepalive_timeout 65;
+ sendfile on;
+ server_tokens off;
- upstream esphome {
- ip_hash;
- server unix:/var/run/esphome.sock;
- }
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
- server {
- server_name hassio.local;
- listen %%port%% default_server;
- root /dev/null;
+ # Use Hass.io supervisor as resolver
+ resolver 172.30.32.2;
- location / {
- proxy_redirect off;
- proxy_pass http://esphome;
-
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $connection_upgrade;
- proxy_set_header Authorization "";
-
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header Host $http_host;
- proxy_set_header X-NginX-Proxy true;
- }
+ upstream esphome {
+ server unix:/var/run/esphome.sock;
}
+
+ include /etc/nginx/servers/*.conf;
}
diff --git a/docker/rootfs/etc/nginx/servers/direct-ssl.disabled b/docker/rootfs/etc/nginx/servers/direct-ssl.disabled
new file mode 100644
index 0000000000..bec9c88051
--- /dev/null
+++ b/docker/rootfs/etc/nginx/servers/direct-ssl.disabled
@@ -0,0 +1,17 @@
+server {
+ listen %%port%% default_server ssl http2;
+
+ include /etc/nginx/includes/server_params.conf;
+ include /etc/nginx/includes/proxy_params.conf;
+ include /etc/nginx/includes/ssl_params.conf;
+ # Clear Hass.io Ingress header
+ proxy_set_header X-Hassio-Ingress "";
+
+ # Redirect http requests to https on the same port.
+ # https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
+ error_page 497 https://$http_host$request_uri;
+
+ location / {
+ proxy_pass http://esphome;
+ }
+}
diff --git a/docker/rootfs/etc/nginx/servers/direct.disabled b/docker/rootfs/etc/nginx/servers/direct.disabled
new file mode 100644
index 0000000000..51f57cab88
--- /dev/null
+++ b/docker/rootfs/etc/nginx/servers/direct.disabled
@@ -0,0 +1,12 @@
+server {
+ listen %%port%% default_server;
+
+ include /etc/nginx/includes/server_params.conf;
+ include /etc/nginx/includes/proxy_params.conf;
+ # Clear Hass.io Ingress header
+ proxy_set_header X-Hassio-Ingress "";
+
+ location / {
+ proxy_pass http://esphome;
+ }
+}
diff --git a/docker/rootfs/etc/nginx/servers/ingress.conf b/docker/rootfs/etc/nginx/servers/ingress.conf
new file mode 100644
index 0000000000..6699ded0cb
--- /dev/null
+++ b/docker/rootfs/etc/nginx/servers/ingress.conf
@@ -0,0 +1,16 @@
+server {
+ listen %%interface%%:%%port%% default_server;
+
+ include /etc/nginx/includes/server_params.conf;
+ include /etc/nginx/includes/proxy_params.conf;
+ # Set Hass.io Ingress header
+ proxy_set_header X-Hassio-Ingress "YES";
+
+ location / {
+ # Only allow from Hass.io supervisor
+ allow 172.30.32.2;
+ deny all;
+
+ proxy_pass http://esphome;
+ }
+}
\ No newline at end of file
diff --git a/docker/rootfs/etc/services.d/nginx/run b/docker/rootfs/etc/services.d/nginx/run
index adf93bc8dd..8582167b96 100755
--- a/docker/rootfs/etc/services.d/nginx/run
+++ b/docker/rootfs/etc/services.d/nginx/run
@@ -4,5 +4,11 @@
# Runs the NGINX proxy
# ==============================================================================
+bashio::log.info "Waiting for dashboard to come up..."
+
+while [[ ! -S /var/run/esphome.sock ]]; do
+ sleep 0.5
+done
+
bashio::log.info "Starting NGINX..."
-exec nginx -g "daemon off;"
+exec nginx
diff --git a/esphome/__main__.py b/esphome/__main__.py
index c00d6c00e4..4b01b5425f 100644
--- a/esphome/__main__.py
+++ b/esphome/__main__.py
@@ -195,8 +195,13 @@ def clean_mqtt(config, args):
return mqtt.clear_topic(config, args.topic, args.username, args.password, args.client_id)
-def setup_log(debug=False):
- log_level = logging.DEBUG if debug else logging.INFO
+def setup_log(debug=False, quiet=False):
+ if debug:
+ log_level = logging.DEBUG
+ elif quiet:
+ log_level = logging.CRITICAL
+ else:
+ log_level = logging.INFO
logging.basicConfig(level=log_level)
fmt = "%(levelname)s %(message)s"
colorfmt = "%(log_color)s{}%(reset)s".format(fmt)
@@ -236,6 +241,13 @@ def command_config(args, config):
return 0
+def command_vscode(args):
+ from esphome import vscode
+
+ CORE.config_path = args.configuration
+ vscode.read_config()
+
+
def command_compile(args, config):
exit_code = write_cpp(config)
if exit_code != 0:
@@ -321,7 +333,8 @@ def command_dashboard(args):
PRE_CONFIG_ACTIONS = {
'wizard': command_wizard,
'version': command_version,
- 'dashboard': command_dashboard
+ 'dashboard': command_dashboard,
+ 'vscode': command_vscode,
}
POST_CONFIG_ACTIONS = {
@@ -340,8 +353,9 @@ def parse_args(argv):
parser = argparse.ArgumentParser(prog='esphome')
parser.add_argument('-v', '--verbose', help="Enable verbose esphome logs.",
action='store_true')
- parser.add_argument('--dashboard', help="Internal flag to set if the command is run from the "
- "dashboard.", action='store_true')
+ parser.add_argument('-q', '--quiet', help="Disable all esphome logs.",
+ action='store_true')
+ parser.add_argument('--dashboard', help=argparse.SUPPRESS, action='store_true')
parser.add_argument('configuration', help='Your YAML configuration file.')
subparsers = parser.add_subparsers(help='Commands', dest='command')
@@ -404,12 +418,13 @@ def parse_args(argv):
dashboard.add_argument("--open-ui", help="Open the dashboard UI in a browser.",
action='store_true')
dashboard.add_argument("--hassio",
- help="Internal flag used to tell esphome is started as a Hass.io "
- "add-on.",
+ help=argparse.SUPPRESS,
action="store_true")
dashboard.add_argument("--socket",
help="Make the dashboard serve under a unix socket", type=str)
+ subparsers.add_parser('vscode', help=argparse.SUPPRESS)
+
return parser.parse_args(argv[1:])
@@ -417,7 +432,7 @@ def run_esphome(argv):
args = parse_args(argv)
CORE.dashboard = args.dashboard
- setup_log(args.verbose)
+ setup_log(args.verbose, args.quiet)
if args.command in PRE_CONFIG_ACTIONS:
try:
return PRE_CONFIG_ACTIONS[args.command](args)
diff --git a/esphome/automation.py b/esphome/automation.py
index cabd42a451..d6d568f7ef 100644
--- a/esphome/automation.py
+++ b/esphome/automation.py
@@ -1,15 +1,9 @@
-import copy
-
+import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.const import CONF_ABOVE, CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, CONF_BELOW, \
- CONF_CONDITION, CONF_CONDITION_ID, CONF_DELAY, CONF_ELSE, CONF_ID, CONF_IF, CONF_LAMBDA, \
- CONF_OR, CONF_RANGE, CONF_THEN, CONF_TRIGGER_ID, CONF_WAIT_UNTIL, CONF_WHILE
+from esphome.const import CONF_AUTOMATION_ID, CONF_CONDITION, CONF_ELSE, CONF_ID, CONF_THEN, \
+ CONF_TRIGGER_ID, CONF_TYPE_ID, CONF_TIME
from esphome.core import coroutine
-from esphome.cpp_generator import Pvariable, TemplateArguments, add, get_variable, \
- process_lambda, templatable
-from esphome.cpp_types import Action, App, Component, PollingComponent, Trigger, bool_, \
- esphome_ns, float_, uint32, void
-from esphome.util import ServiceRegistry
+from esphome.util import Registry
def maybe_simple_id(*validators):
@@ -18,97 +12,50 @@ def maybe_simple_id(*validators):
def validate(value):
if isinstance(value, dict):
return validator(value)
- return validator({CONF_ID: value})
+ with cv.remove_prepend_path([CONF_ID]):
+ return validator({CONF_ID: value})
return validate
-def validate_recursive_condition(value):
- is_list = isinstance(value, list)
- value = cv.ensure_list()(value)[:]
- for i, item in enumerate(value):
- path = [i] if is_list else []
- item = copy.deepcopy(item)
- if not isinstance(item, dict):
- raise cv.Invalid(u"Condition must consist of key-value mapping! Got {}".format(item),
- path)
- key = next((x for x in item if x != CONF_CONDITION_ID), None)
- if key is None:
- raise cv.Invalid(u"Key missing from action! Got {}".format(item), path)
- if key not in CONDITION_REGISTRY:
- raise cv.Invalid(u"Unable to find condition with the name '{}', is the "
- u"component loaded?".format(key), path + [key])
- item.setdefault(CONF_CONDITION_ID, None)
- key2 = next((x for x in item if x not in (CONF_CONDITION_ID, key)), None)
- if key2 is not None:
- raise cv.Invalid(u"Cannot have two conditions in one item. Key '{}' overrides '{}'! "
- u"Did you forget to indent the block inside the condition?"
- u"".format(key, key2), path)
- validator = CONDITION_REGISTRY[key][0]
- try:
- condition = validator(item[key] or {})
- except cv.Invalid as err:
- err.prepend(path)
- raise err
- value[i] = {
- CONF_CONDITION_ID: cv.declare_variable_id(Condition)(item[CONF_CONDITION_ID]),
- key: condition,
- }
- return value
+def register_action(name, action_type, schema):
+ return ACTION_REGISTRY.register(name, action_type, schema)
-def validate_recursive_action(value):
- is_list = isinstance(value, list)
- if not is_list:
- value = [value]
- for i, item in enumerate(value):
- path = [i] if is_list else []
- item = copy.deepcopy(item)
- if not isinstance(item, dict):
- raise cv.Invalid(u"Action must consist of key-value mapping! Got {}".format(item),
- path)
- key = next((x for x in item if x != CONF_ACTION_ID), None)
- if key is None:
- raise cv.Invalid(u"Key missing from action! Got {}".format(item), path)
- if key not in ACTION_REGISTRY:
- raise cv.Invalid(u"Unable to find action with the name '{}', is the component loaded?"
- u"".format(key), path + [key])
- item.setdefault(CONF_ACTION_ID, None)
- key2 = next((x for x in item if x not in (CONF_ACTION_ID, key)), None)
- if key2 is not None:
- raise cv.Invalid(u"Cannot have two actions in one item. Key '{}' overrides '{}'! "
- u"Did you forget to indent the block inside the action?"
- u"".format(key, key2), path)
- validator = ACTION_REGISTRY[key][0]
- try:
- action = validator(item[key] or {})
- except cv.Invalid as err:
- err.prepend(path)
- raise err
- value[i] = {
- CONF_ACTION_ID: cv.declare_variable_id(Action)(item[CONF_ACTION_ID]),
- key: action,
- }
- return value
+def register_condition(name, condition_type, schema):
+ return CONDITION_REGISTRY.register(name, condition_type, schema)
-ACTION_REGISTRY = ServiceRegistry()
-CONDITION_REGISTRY = ServiceRegistry()
+Action = cg.esphome_ns.class_('Action')
+Trigger = cg.esphome_ns.class_('Trigger')
+ACTION_REGISTRY = Registry()
+Condition = cg.esphome_ns.class_('Condition')
+CONDITION_REGISTRY = Registry()
+validate_action = cv.validate_registry_entry('action', ACTION_REGISTRY)
+validate_action_list = cv.validate_registry('action', ACTION_REGISTRY)
+validate_condition = cv.validate_registry_entry('condition', CONDITION_REGISTRY)
+validate_condition_list = cv.validate_registry('condition', CONDITION_REGISTRY)
-# pylint: disable=invalid-name
-DelayAction = esphome_ns.class_('DelayAction', Action, Component)
-LambdaAction = esphome_ns.class_('LambdaAction', Action)
-IfAction = esphome_ns.class_('IfAction', Action)
-WhileAction = esphome_ns.class_('WhileAction', Action)
-WaitUntilAction = esphome_ns.class_('WaitUntilAction', Action, Component)
-UpdateComponentAction = esphome_ns.class_('UpdateComponentAction', Action)
-Automation = esphome_ns.class_('Automation')
-Condition = esphome_ns.class_('Condition')
-AndCondition = esphome_ns.class_('AndCondition', Condition)
-OrCondition = esphome_ns.class_('OrCondition', Condition)
-RangeCondition = esphome_ns.class_('RangeCondition', Condition)
-LambdaCondition = esphome_ns.class_('LambdaCondition', Condition)
+def validate_potentially_and_condition(value):
+ if isinstance(value, list):
+ with cv.remove_prepend_path(['and']):
+ return validate_condition({
+ 'and': value
+ })
+ return validate_condition(value)
+
+
+DelayAction = cg.esphome_ns.class_('DelayAction', Action, cg.Component)
+LambdaAction = cg.esphome_ns.class_('LambdaAction', Action)
+IfAction = cg.esphome_ns.class_('IfAction', Action)
+WhileAction = cg.esphome_ns.class_('WhileAction', Action)
+WaitUntilAction = cg.esphome_ns.class_('WaitUntilAction', Action, cg.Component)
+UpdateComponentAction = cg.esphome_ns.class_('UpdateComponentAction', Action)
+Automation = cg.esphome_ns.class_('Automation')
+
+LambdaCondition = cg.esphome_ns.class_('LambdaCondition', Condition)
+ForCondition = cg.esphome_ns.class_('ForCondition', Condition)
def validate_automation(extra_schema=None, extra_validators=None, single=False):
@@ -120,24 +67,28 @@ def validate_automation(extra_schema=None, extra_validators=None, single=False):
def validator_(value):
if isinstance(value, list):
+ # List of items, there are two possible options here, either a sequence of
+ # actions (no then:) or a list of automations.
try:
# First try as a sequence of actions
- return [schema({CONF_THEN: value})]
+ # If that succeeds, return immediately
+ with cv.remove_prepend_path([CONF_THEN]):
+ return [schema({CONF_THEN: value})]
except cv.Invalid as err:
- if err.path and err.path[0] == CONF_THEN:
- err.path.pop(0)
-
# Next try as a sequence of automations
try:
return cv.Schema([schema])(value)
except cv.Invalid as err2:
- if 'Unable to find action' in str(err):
+ if u'extra keys not allowed' in str(err2) and len(err2.path) == 2:
+ raise err
+ if u'Unable to find action' in str(err):
raise err2
raise cv.MultipleInvalid([err, err2])
elif isinstance(value, dict):
if CONF_THEN in value:
return [schema(value)]
- return [schema({CONF_THEN: value})]
+ with cv.remove_prepend_path([CONF_THEN]):
+ return [schema({CONF_THEN: value})]
# This should only happen with invalid configs, but let's have a nice error message.
return [schema(value)]
@@ -155,175 +106,132 @@ def validate_automation(extra_schema=None, extra_validators=None, single=False):
AUTOMATION_SCHEMA = cv.Schema({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(Trigger),
- cv.GenerateID(CONF_AUTOMATION_ID): cv.declare_variable_id(Automation),
- cv.Required(CONF_THEN): validate_recursive_action,
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger),
+ cv.GenerateID(CONF_AUTOMATION_ID): cv.declare_id(Automation),
+ cv.Required(CONF_THEN): validate_action_list,
})
-AND_CONDITION_SCHEMA = validate_recursive_condition
+AndCondition = cg.esphome_ns.class_('AndCondition', Condition)
+OrCondition = cg.esphome_ns.class_('OrCondition', Condition)
+NotCondition = cg.esphome_ns.class_('NotCondition', Condition)
-@CONDITION_REGISTRY.register(CONF_AND, AND_CONDITION_SCHEMA)
+@register_condition('and', AndCondition, validate_condition_list)
def and_condition_to_code(config, condition_id, template_arg, args):
- conditions = yield build_conditions(config, template_arg, args)
- rhs = AndCondition.new(template_arg, conditions)
- type = AndCondition.template(template_arg)
- yield Pvariable(condition_id, rhs, type=type)
+ conditions = yield build_condition_list(config, template_arg, args)
+ yield cg.new_Pvariable(condition_id, template_arg, conditions)
-OR_CONDITION_SCHEMA = validate_recursive_condition
-
-
-@CONDITION_REGISTRY.register(CONF_OR, OR_CONDITION_SCHEMA)
+@register_condition('or', OrCondition, validate_condition_list)
def or_condition_to_code(config, condition_id, template_arg, args):
- conditions = yield build_conditions(config, template_arg, args)
- rhs = OrCondition.new(template_arg, conditions)
- type = OrCondition.template(template_arg)
- yield Pvariable(condition_id, rhs, type=type)
+ conditions = yield build_condition_list(config, template_arg, args)
+ yield cg.new_Pvariable(condition_id, template_arg, conditions)
-RANGE_CONDITION_SCHEMA = cv.All(cv.Schema({
- cv.Optional(CONF_ABOVE): cv.templatable(cv.float_),
- cv.Optional(CONF_BELOW): cv.templatable(cv.float_),
-}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))
+@register_condition('not', NotCondition, validate_condition)
+def not_condition_to_code(config, condition_id, template_arg, args):
+ condition = yield build_condition(config, template_arg, args)
+ yield cg.new_Pvariable(condition_id, template_arg, condition)
-@CONDITION_REGISTRY.register(CONF_RANGE, RANGE_CONDITION_SCHEMA)
-def range_condition_to_code(config, condition_id, template_arg, args):
- conditions = yield build_conditions(config, template_arg, args)
- rhs = RangeCondition.new(template_arg, conditions)
- type = RangeCondition.template(template_arg)
- condition = Pvariable(condition_id, rhs, type=type)
- if CONF_ABOVE in config:
- template_ = yield templatable(config[CONF_ABOVE], args, float_)
- condition.set_min(template_)
- if CONF_BELOW in config:
- template_ = yield templatable(config[CONF_BELOW], args, float_)
- condition.set_max(template_)
- yield condition
+@register_condition('lambda', LambdaCondition, cv.lambda_)
+def lambda_condition_to_code(config, condition_id, template_arg, args):
+ lambda_ = yield cg.process_lambda(config, args, return_type=bool)
+ yield cg.new_Pvariable(condition_id, template_arg, lambda_)
-DELAY_ACTION_SCHEMA = cv.templatable(cv.positive_time_period_milliseconds)
+@register_condition('for', ForCondition, cv.Schema({
+ cv.Required(CONF_TIME): cv.templatable(cv.positive_time_period_milliseconds),
+ cv.Required(CONF_CONDITION): validate_potentially_and_condition,
+}).extend(cv.COMPONENT_SCHEMA))
+def for_condition_to_code(config, condition_id, template_arg, args):
+ condition = yield build_condition(config[CONF_CONDITION], cg.TemplateArguments(), [])
+ var = cg.new_Pvariable(condition_id, template_arg, condition)
+ yield cg.register_component(var, config)
+ templ = yield cg.templatable(config[CONF_TIME], args, cg.uint32)
+ cg.add(var.set_time(templ))
+ yield var
-@ACTION_REGISTRY.register(CONF_DELAY, DELAY_ACTION_SCHEMA)
+@register_action('delay', DelayAction, cv.templatable(cv.positive_time_period_milliseconds))
def delay_action_to_code(config, action_id, template_arg, args):
- rhs = App.register_component(DelayAction.new(template_arg))
- type = DelayAction.template(template_arg)
- action = Pvariable(action_id, rhs, type=type)
- template_ = yield templatable(config, args, uint32)
- add(action.set_delay(template_))
- yield action
+ var = cg.new_Pvariable(action_id, template_arg)
+ yield cg.register_component(var, {})
+ template_ = yield cg.templatable(config, args, cg.uint32)
+ cg.add(var.set_delay(template_))
+ yield var
-IF_ACTION_SCHEMA = cv.All({
- cv.Required(CONF_CONDITION): validate_recursive_condition,
- cv.Optional(CONF_THEN): validate_recursive_action,
- cv.Optional(CONF_ELSE): validate_recursive_action,
-}, cv.has_at_least_one_key(CONF_THEN, CONF_ELSE))
-
-
-@ACTION_REGISTRY.register(CONF_IF, IF_ACTION_SCHEMA)
+@register_action('if', IfAction, cv.All({
+ cv.Required(CONF_CONDITION): validate_potentially_and_condition,
+ cv.Optional(CONF_THEN): validate_action_list,
+ cv.Optional(CONF_ELSE): validate_action_list,
+}, cv.has_at_least_one_key(CONF_THEN, CONF_ELSE)))
def if_action_to_code(config, action_id, template_arg, args):
- conditions = yield build_conditions(config[CONF_CONDITION], template_arg, args)
- rhs = IfAction.new(template_arg, conditions)
- type = IfAction.template(template_arg)
- action = Pvariable(action_id, rhs, type=type)
+ conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
+ var = cg.new_Pvariable(action_id, template_arg, conditions)
if CONF_THEN in config:
- actions = yield build_actions(config[CONF_THEN], template_arg, args)
- add(action.add_then(actions))
+ actions = yield build_action_list(config[CONF_THEN], template_arg, args)
+ cg.add(var.add_then(actions))
if CONF_ELSE in config:
- actions = yield build_actions(config[CONF_ELSE], template_arg, args)
- add(action.add_else(actions))
- yield action
+ actions = yield build_action_list(config[CONF_ELSE], template_arg, args)
+ cg.add(var.add_else(actions))
+ yield var
-WHILE_ACTION_SCHEMA = cv.Schema({
- cv.Required(CONF_CONDITION): validate_recursive_condition,
- cv.Required(CONF_THEN): validate_recursive_action,
-})
-
-
-@ACTION_REGISTRY.register(CONF_WHILE, WHILE_ACTION_SCHEMA)
+@register_action('while', WhileAction, cv.Schema({
+ cv.Required(CONF_CONDITION): validate_potentially_and_condition,
+ cv.Required(CONF_THEN): validate_action_list,
+}))
def while_action_to_code(config, action_id, template_arg, args):
- conditions = yield build_conditions(config[CONF_CONDITION], template_arg, args)
- rhs = WhileAction.new(template_arg, conditions)
- type = WhileAction.template(template_arg)
- action = Pvariable(action_id, rhs, type=type)
- actions = yield build_actions(config[CONF_THEN], template_arg, args)
- add(action.add_then(actions))
- yield action
+ conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
+ var = cg.new_Pvariable(action_id, template_arg, conditions)
+ actions = yield build_action_list(config[CONF_THEN], template_arg, args)
+ cg.add(var.add_then(actions))
+ yield var
def validate_wait_until(value):
schema = cv.Schema({
- cv.Required(CONF_CONDITION): validate_recursive_condition
+ cv.Required(CONF_CONDITION): validate_potentially_and_condition,
})
if isinstance(value, dict) and CONF_CONDITION in value:
return schema(value)
return validate_wait_until({CONF_CONDITION: value})
-WAIT_UNTIL_ACTION_SCHEMA = validate_wait_until
-
-
-@ACTION_REGISTRY.register(CONF_WAIT_UNTIL, WAIT_UNTIL_ACTION_SCHEMA)
+@register_action('wait_until', WaitUntilAction, validate_wait_until)
def wait_until_action_to_code(config, action_id, template_arg, args):
- conditions = yield build_conditions(config[CONF_CONDITION], template_arg, args)
- rhs = WaitUntilAction.new(template_arg, conditions)
- type = WaitUntilAction.template(template_arg)
- action = Pvariable(action_id, rhs, type=type)
- add(App.register_component(action))
- yield action
+ conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
+ var = cg.new_Pvariable(action_id, template_arg, conditions)
+ yield cg.register_component(var, {})
+ yield var
-LAMBDA_ACTION_SCHEMA = cv.lambda_
-
-
-@ACTION_REGISTRY.register(CONF_LAMBDA, LAMBDA_ACTION_SCHEMA)
+@register_action('lambda', LambdaAction, cv.lambda_)
def lambda_action_to_code(config, action_id, template_arg, args):
- lambda_ = yield process_lambda(config, args, return_type=void)
- rhs = LambdaAction.new(template_arg, lambda_)
- type = LambdaAction.template(template_arg)
- yield Pvariable(action_id, rhs, type=type)
+ lambda_ = yield cg.process_lambda(config, args, return_type=cg.void)
+ yield cg.new_Pvariable(action_id, template_arg, lambda_)
-LAMBDA_CONDITION_SCHEMA = cv.lambda_
-
-
-@CONDITION_REGISTRY.register(CONF_LAMBDA, LAMBDA_CONDITION_SCHEMA)
-def lambda_condition_to_code(config, condition_id, template_arg, args):
- lambda_ = yield process_lambda(config, args, return_type=bool_)
- rhs = LambdaCondition.new(template_arg, lambda_)
- type = LambdaCondition.template(template_arg)
- yield Pvariable(condition_id, rhs, type=type)
-
-
-CONF_COMPONENT_UPDATE = 'component.update'
-COMPONENT_UPDATE_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(PollingComponent),
-})
-
-
-@ACTION_REGISTRY.register(CONF_COMPONENT_UPDATE, COMPONENT_UPDATE_ACTION_SCHEMA)
+@register_action('component.update', UpdateComponentAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(cg.PollingComponent),
+}))
def component_update_action_to_code(config, action_id, template_arg, args):
- var = yield get_variable(config[CONF_ID])
- rhs = UpdateComponentAction.new(template_arg, var)
- type = UpdateComponentAction.template(template_arg)
- yield Pvariable(action_id, rhs, type=type)
+ comp = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, comp)
@coroutine
def build_action(full_config, template_arg, args):
- action_id = full_config[CONF_ACTION_ID]
- key, config = next((k, v) for k, v in full_config.items() if k in ACTION_REGISTRY)
-
- builder = coroutine(ACTION_REGISTRY[key][1])
+ registry_entry, config = cg.extract_registry_entry_config(ACTION_REGISTRY, full_config)
+ action_id = full_config[CONF_TYPE_ID]
+ builder = registry_entry.coroutine_fun
yield builder(config, action_id, template_arg, args)
@coroutine
-def build_actions(config, templ, arg_type):
+def build_action_list(config, templ, arg_type):
actions = []
for conf in config:
action = yield build_action(conf, templ, arg_type)
@@ -333,15 +241,14 @@ def build_actions(config, templ, arg_type):
@coroutine
def build_condition(full_config, template_arg, args):
- action_id = full_config[CONF_CONDITION_ID]
- key, config = next((k, v) for k, v in full_config.items() if k in CONDITION_REGISTRY)
-
- builder = coroutine(CONDITION_REGISTRY[key][1])
+ registry_entry, config = cg.extract_registry_entry_config(CONDITION_REGISTRY, full_config)
+ action_id = full_config[CONF_TYPE_ID]
+ builder = registry_entry.coroutine_fun
yield builder(config, action_id, template_arg, args)
@coroutine
-def build_conditions(config, templ, args):
+def build_condition_list(config, templ, args):
conditions = []
for conf in config:
condition = yield build_condition(conf, templ, args)
@@ -352,10 +259,8 @@ def build_conditions(config, templ, args):
@coroutine
def build_automation(trigger, args, config):
arg_types = [arg[0] for arg in args]
- templ = TemplateArguments(*arg_types)
- type = Automation.template(templ)
- rhs = type.new(trigger)
- obj = Pvariable(config[CONF_AUTOMATION_ID], rhs, type=type)
- actions = yield build_actions(config[CONF_THEN], templ, args)
- add(obj.add_actions(actions))
+ templ = cg.TemplateArguments(*arg_types)
+ obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
+ actions = yield build_action_list(config[CONF_THEN], templ, args)
+ cg.add(obj.add_actions(actions))
yield obj
diff --git a/esphome/codegen.py b/esphome/codegen.py
index eb9738d5a0..883d5f8636 100644
--- a/esphome/codegen.py
+++ b/esphome/codegen.py
@@ -13,14 +13,14 @@ from esphome.cpp_generator import ( # noqa
StructInitializer, ArrayInitializer, safe_exp, Statement,
progmem_array, statement, variable, Pvariable, new_Pvariable,
add, add_global, add_library, add_build_flag, add_define,
- get_variable, process_lambda, is_template, templatable, MockObj,
+ get_variable, get_variable_with_full_id, process_lambda, is_template, templatable, MockObj,
MockObjClass)
from esphome.cpp_helpers import ( # noqa
gpio_pin_expression, register_component, build_registry_entry,
- build_registry_list)
+ build_registry_list, extract_registry_entry_config)
from esphome.cpp_types import ( # noqa
global_ns, void, nullptr, float_, bool_, std_ns, std_string,
std_vector, uint8, uint16, uint32, int32, const_char_ptr, NAN,
- esphome_ns, App, Nameable, Trigger, Action, Component, ComponentPtr,
+ esphome_ns, App, Nameable, Component, ComponentPtr,
PollingComponent, Application, optional, arduino_json_ns, JsonObject,
JsonObjectRef, JsonObjectConstRef, Controller, GPIOPin)
diff --git a/esphome/components/a4988/a4988.h b/esphome/components/a4988/a4988.h
index 8c56f27104..10fb5e0015 100644
--- a/esphome/components/a4988/a4988.h
+++ b/esphome/components/a4988/a4988.h
@@ -9,7 +9,8 @@ namespace a4988 {
class A4988 : public stepper::Stepper, public Component {
public:
- A4988(GPIOPin *step_pin, GPIOPin *dir_pin) : step_pin_(step_pin), dir_pin_(dir_pin) {}
+ void set_step_pin(GPIOPin *step_pin) { step_pin_ = step_pin; }
+ void set_dir_pin(GPIOPin *dir_pin) { dir_pin_ = dir_pin; }
void set_sleep_pin(GPIOPin *sleep_pin) { this->sleep_pin_ = sleep_pin; }
void setup() override;
void dump_config() override;
diff --git a/esphome/components/a4988/stepper.py b/esphome/components/a4988/stepper.py
index 6f6c9ae55c..29696dbd5e 100644
--- a/esphome/components/a4988/stepper.py
+++ b/esphome/components/a4988/stepper.py
@@ -9,7 +9,7 @@ a4988_ns = cg.esphome_ns.namespace('a4988')
A4988 = a4988_ns.class_('A4988', stepper.Stepper, cg.Component)
CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend({
- cv.Required(CONF_ID): cv.declare_variable_id(A4988),
+ cv.Required(CONF_ID): cv.declare_id(A4988),
cv.Required(CONF_STEP_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_DIR_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_SLEEP_PIN): pins.gpio_output_pin_schema,
@@ -17,12 +17,15 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend({
def to_code(config):
- step_pin = yield cg.gpio_pin_expression(config[CONF_STEP_PIN])
- dir_pin = yield cg.gpio_pin_expression(config[CONF_DIR_PIN])
- var = cg.new_Pvariable(config[CONF_ID], step_pin, dir_pin)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield stepper.register_stepper(var, config)
+ step_pin = yield cg.gpio_pin_expression(config[CONF_STEP_PIN])
+ cg.add(var.set_step_pin(step_pin))
+ dir_pin = yield cg.gpio_pin_expression(config[CONF_DIR_PIN])
+ cg.add(var.set_dir_pin(dir_pin))
+
if CONF_SLEEP_PIN in config:
sleep_pin = yield cg.gpio_pin_expression(config[CONF_SLEEP_PIN])
cg.add(var.set_sleep_pin(sleep_pin))
diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp
index 6dc23a3e2d..849a1f31e5 100644
--- a/esphome/components/adc/adc_sensor.cpp
+++ b/esphome/components/adc/adc_sensor.cpp
@@ -6,9 +6,6 @@ namespace adc {
static const char *TAG = "adc";
-ADCSensor::ADCSensor(const std::string &name, uint8_t pin, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval), pin_(pin) {}
-
#ifdef ARDUINO_ARCH_ESP32
void ADCSensor::set_attenuation(adc_attenuation_t attenuation) { this->attenuation_ = attenuation; }
#endif
diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h
index 1790ea24e3..72afe5c1e9 100644
--- a/esphome/components/adc/adc_sensor.h
+++ b/esphome/components/adc/adc_sensor.h
@@ -7,11 +7,8 @@
namespace esphome {
namespace adc {
-class ADCSensor : public sensor::PollingSensorComponent {
+class ADCSensor : public sensor::Sensor, public PollingComponent {
public:
- /// Construct the ADCSensor with the provided pin and update interval in ms.
- explicit ADCSensor(const std::string &name, uint8_t pin, uint32_t update_interval);
-
#ifdef ARDUINO_ARCH_ESP32
/// Set the attenuation for this pin. Only available on the ESP32.
void set_attenuation(adc_attenuation_t attenuation);
@@ -26,6 +23,7 @@ class ADCSensor : public sensor::PollingSensorComponent {
void dump_config() override;
/// `HARDWARE_LATE` setup priority.
float get_setup_priority() const override;
+ void set_pin(uint8_t pin) { this->pin_ = pin; }
#ifdef ARDUINO_ARCH_ESP8266
std::string unique_id() override;
diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py
index 973016b004..c369ea5be5 100644
--- a/esphome/components/adc/sensor.py
+++ b/esphome/components/adc/sensor.py
@@ -2,8 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-from esphome.const import CONF_ATTENUATION, CONF_ID, CONF_NAME, CONF_PIN, CONF_UPDATE_INTERVAL, \
- CONF_ICON, ICON_FLASH, CONF_UNIT_OF_MEASUREMENT, UNIT_VOLT, CONF_ACCURACY_DECIMALS
+from esphome.const import CONF_ATTENUATION, CONF_ID, CONF_PIN, ICON_FLASH, UNIT_VOLT
ATTENUATION_MODES = {
'0db': cg.global_ns.ADC_0db,
@@ -23,30 +22,24 @@ def validate_adc_pin(value):
adc_ns = cg.esphome_ns.namespace('adc')
ADCSensor = adc_ns.class_('ADCSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(ADCSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2).extend({
+ cv.GenerateID(): cv.declare_id(ADCSensor),
cv.Required(CONF_PIN): validate_adc_pin,
- cv.Optional(CONF_ATTENUATION): cv.All(cv.only_on_esp32, cv.one_of(*ATTENUATION_MODES,
- lower=True)),
-
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
- cv.Optional(CONF_ICON, default=ICON_FLASH): sensor.icon,
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_VOLT): sensor.unit_of_measurement,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=2): sensor.accuracy_decimals,
-}).extend(cv.COMPONENT_SCHEMA))
+ cv.SplitDefault(CONF_ATTENUATION, esp32='0db'):
+ cv.All(cv.only_on_esp32, cv.enum(ATTENUATION_MODES, lower=True)),
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- pin = config[CONF_PIN]
- if pin == 'VCC':
- pin = 0
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield sensor.register_sensor(var, config)
+ if config[CONF_PIN] == 'VCC':
cg.add_define('USE_ADC_SENSOR_VCC')
cg.add_global(cg.global_ns.ADC_MODE(cg.global_ns.ADC_VCC))
- rhs = ADCSensor.new(config[CONF_NAME], pin, config[CONF_UPDATE_INTERVAL])
- adc = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(adc, config)
- yield sensor.register_sensor(adc, config)
+ else:
+ cg.add(var.set_pin(config[CONF_PIN]))
if CONF_ATTENUATION in config:
- cg.add(adc.set_attenuation(ATTENUATION_MODES[config[CONF_ATTENUATION]]))
+ cg.add(var.set_attenuation(config[CONF_ATTENUATION]))
diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py
index 354ea0d9d1..e34bab8582 100644
--- a/esphome/components/ads1115/__init__.py
+++ b/esphome/components/ads1115/__init__.py
@@ -11,7 +11,7 @@ ads1115_ns = cg.esphome_ns.namespace('ads1115')
ADS1115Component = ads1115_ns.class_('ADS1115Component', cg.Component, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(ADS1115Component),
+ cv.GenerateID(): cv.declare_id(ADS1115Component),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(None))
diff --git a/esphome/components/ads1115/ads1115.h b/esphome/components/ads1115/ads1115.h
index af66e9c87f..863bb247aa 100644
--- a/esphome/components/ads1115/ads1115.h
+++ b/esphome/components/ads1115/ads1115.h
@@ -48,9 +48,6 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
class ADS1115Sensor : public sensor::Sensor {
public:
- ADS1115Sensor(const std::string &name, uint32_t update_interval)
- : sensor::Sensor(name), update_interval_(update_interval) {}
-
void set_multiplexer(ADS1115Multiplexer multiplexer);
void set_gain(ADS1115Gain gain);
diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor.py
index e8c96ba7ad..4a1d109c23 100644
--- a/esphome/components/ads1115/sensor.py
+++ b/esphome/components/ads1115/sensor.py
@@ -2,8 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.components.ads1115 import ADS1115Component
-from esphome.const import CONF_GAIN, CONF_MULTIPLEXER, CONF_UPDATE_INTERVAL, \
- ICON_FLASH, UNIT_VOLT, CONF_ID, CONF_NAME
+from esphome.const import CONF_GAIN, CONF_MULTIPLEXER, ICON_FLASH, UNIT_VOLT, CONF_ID
from esphome.py_compat import string_types
from . import ads1115_ns
@@ -38,27 +37,26 @@ def validate_gain(value):
elif not isinstance(value, string_types):
raise cv.Invalid('invalid gain "{}"'.format(value))
- return cv.one_of(*GAIN)(value)
+ return cv.enum(GAIN)(value)
ADS1115Sensor = ads1115_ns.class_('ADS1115Sensor', sensor.Sensor)
-
CONF_ADS1115_ID = 'ads1115_id'
-CONFIG_SCHEMA = cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 3).extend({
- cv.GenerateID(): cv.declare_variable_id(ADS1115Sensor),
- cv.GenerateID(CONF_ADS1115_ID): cv.use_variable_id(ADS1115Component),
- cv.Required(CONF_MULTIPLEXER): cv.one_of(*MUX, upper=True, space='_'),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 3).extend({
+ cv.GenerateID(): cv.declare_id(ADS1115Sensor),
+ cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
+ cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space='_'),
cv.Required(CONF_GAIN): validate_gain,
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}))
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- hub = yield cg.get_variable(config[CONF_ADS1115_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
- cg.add(var.set_multiplexer(MUX[config[CONF_MULTIPLEXER]]))
- cg.add(var.set_gain(GAIN[config[CONF_GAIN]]))
+ var = cg.new_Pvariable(config[CONF_ID])
yield sensor.register_sensor(var, config)
+ cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
+ cg.add(var.set_gain(config[CONF_GAIN]))
+
+ hub = yield cg.get_variable(config[CONF_ADS1115_ID])
cg.add(hub.register_sensor(var))
diff --git a/esphome/components/apds9960/__init__.py b/esphome/components/apds9960/__init__.py
index 8090a4e921..4725c16032 100644
--- a/esphome/components/apds9960/__init__.py
+++ b/esphome/components/apds9960/__init__.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
-from esphome.const import CONF_ID, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID
DEPENDENCIES = ['i2c']
AUTO_LOAD = ['sensor', 'binary_sensor']
@@ -13,12 +13,11 @@ apds9960_nds = cg.esphome_ns.namespace('apds9960')
APDS9960 = apds9960_nds.class_('APDS9960', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(APDS9960),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x39))
+ cv.GenerateID(): cv.declare_id(APDS9960),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x39))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/apds9960/apds9960.h b/esphome/components/apds9960/apds9960.h
index 88df6b9c92..ae44b5da0f 100644
--- a/esphome/components/apds9960/apds9960.h
+++ b/esphome/components/apds9960/apds9960.h
@@ -10,7 +10,6 @@ namespace apds9960 {
class APDS9960 : public PollingComponent, public i2c::I2CDevice {
public:
- APDS9960(uint32_t update_interval) : PollingComponent(update_interval) {}
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/apds9960/binary_sensor.py b/esphome/components/apds9960/binary_sensor.py
index eae76c69b1..4404510909 100644
--- a/esphome/components/apds9960/binary_sensor.py
+++ b/esphome/components/apds9960/binary_sensor.py
@@ -13,11 +13,11 @@ DIRECTIONS = {
'RIGHT': 'set_right_direction',
}
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
- cv.GenerateID(CONF_APDS9960_ID): cv.use_variable_id(APDS9960),
+ cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
cv.Optional(CONF_DEVICE_CLASS, default=DEVICE_CLASS_MOVING): binary_sensor.device_class,
-}))
+})
def to_code(config):
diff --git a/esphome/components/apds9960/sensor.py b/esphome/components/apds9960/sensor.py
index 8d1bd1428f..58087cbe86 100644
--- a/esphome/components/apds9960/sensor.py
+++ b/esphome/components/apds9960/sensor.py
@@ -1,8 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
-from esphome.const import CONF_TYPE, CONF_UNIT_OF_MEASUREMENT, CONF_ACCURACY_DECIMALS, CONF_ICON, \
- UNIT_PERCENT, ICON_LIGHTBULB
+from esphome.const import CONF_TYPE, UNIT_PERCENT, ICON_LIGHTBULB
from . import APDS9960, CONF_APDS9960_ID
DEPENDENCIES = ['apds9960']
@@ -15,14 +14,10 @@ TYPES = {
'PROXIMITY': 'set_proximity',
}
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_PERCENT, ICON_LIGHTBULB, 1).extend({
cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
- cv.GenerateID(CONF_APDS9960_ID): cv.use_variable_id(APDS9960),
-
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): sensor.unit_of_measurement,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=1): sensor.accuracy_decimals,
- cv.Optional(CONF_ICON, default=ICON_LIGHTBULB): sensor.icon,
-}))
+ cv.GenerateID(CONF_APDS9960_ID): cv.use_id(APDS9960),
+})
def to_code(config):
diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py
index 1ae788306a..97465f1f7c 100644
--- a/esphome/components/api/__init__.py
+++ b/esphome/components/api/__init__.py
@@ -1,20 +1,21 @@
-
-from esphome import automation
-from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY, Condition
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.automation import Condition
from esphome.const import CONF_DATA, CONF_DATA_TEMPLATE, CONF_ID, CONF_PASSWORD, CONF_PORT, \
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES, CONF_SERVICES, CONF_TRIGGER_ID
from esphome.core import CORE, coroutine_with_priority
+DEPENDENCIES = ['network']
+
api_ns = cg.esphome_ns.namespace('api')
APIServer = api_ns.class_('APIServer', cg.Component, cg.Controller)
-HomeAssistantServiceCallAction = api_ns.class_('HomeAssistantServiceCallAction', cg.Action)
+HomeAssistantServiceCallAction = api_ns.class_('HomeAssistantServiceCallAction', automation.Action)
KeyValuePair = api_ns.class_('KeyValuePair')
TemplatableKeyValuePair = api_ns.class_('TemplatableKeyValuePair')
APIConnectedCondition = api_ns.class_('APIConnectedCondition', Condition)
-UserService = api_ns.class_('UserService', cg.Trigger)
+UserService = api_ns.class_('UserService', automation.Trigger)
ServiceTypeArgument = api_ns.class_('ServiceTypeArgument')
ServiceArgType = api_ns.enum('ServiceArgType')
SERVICE_ARG_TYPES = {
@@ -30,14 +31,13 @@ SERVICE_ARG_NATIVE_TYPES = {
'string': cg.std_string,
}
-
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(APIServer),
+ cv.GenerateID(): cv.declare_id(APIServer),
cv.Optional(CONF_PORT, default=6053): cv.port,
cv.Optional(CONF_PASSWORD, default=''): cv.string_strict,
cv.Optional(CONF_REBOOT_TIMEOUT, default='5min'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SERVICES): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(UserService),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserService),
cv.Required(CONF_SERVICE): cv.valid_name,
cv.Optional(CONF_VARIABLES, default={}): cv.Schema({
cv.validate_id_name: cv.one_of(*SERVICE_ARG_TYPES, lower=True),
@@ -48,13 +48,12 @@ CONFIG_SCHEMA = cv.Schema({
@coroutine_with_priority(40.0)
def to_code(config):
- rhs = APIServer.new()
- api = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(api, config)
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
- cg.add(api.set_port(config[CONF_PORT]))
- cg.add(api.set_password(config[CONF_PASSWORD]))
- cg.add(api.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
+ cg.add(var.set_port(config[CONF_PORT]))
+ cg.add(var.set_password(config[CONF_PASSWORD]))
+ cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
for conf in config.get(CONF_SERVICES, []):
template_args = []
@@ -65,10 +64,9 @@ def to_code(config):
template_args.append(native)
func_args.append((native, name))
service_type_args.append(ServiceTypeArgument(name, SERVICE_ARG_TYPES[var_]))
- func = api.make_user_service_trigger.template(*template_args)
- rhs = func(conf[CONF_SERVICE], service_type_args)
- type_ = UserService.template(*template_args)
- trigger = cg.Pvariable(conf[CONF_TRIGGER_ID], rhs, type=type_)
+ templ = cg.TemplateArguments(*template_args)
+ trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], templ,
+ conf[CONF_SERVICE], service_type_args)
yield automation.build_automation(trigger, func_args, conf)
cg.add_define('USE_API')
@@ -78,9 +76,8 @@ def to_code(config):
cg.add_library('ESPAsyncTCP', '1.2.0')
-CONF_HOMEASSISTANT_SERVICE = 'homeassistant.service'
HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.use_variable_id(APIServer),
+ cv.GenerateID(): cv.use_id(APIServer),
cv.Required(CONF_SERVICE): cv.string,
cv.Optional(CONF_DATA): cv.Schema({
cv.string: cv.string,
@@ -94,34 +91,27 @@ HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema({
})
-@ACTION_REGISTRY.register(CONF_HOMEASSISTANT_SERVICE, HOMEASSISTANT_SERVICE_ACTION_SCHEMA)
+@automation.register_action('homeassistant.service', HomeAssistantServiceCallAction,
+ HOMEASSISTANT_SERVICE_ACTION_SCHEMA)
def homeassistant_service_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = HomeAssistantServiceCallAction.template(template_arg)
- rhs = type.new(var)
- act = cg.Pvariable(action_id, rhs, type=type)
- cg.add(act.set_service(config[CONF_SERVICE]))
+ serv = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, serv)
+ cg.add(var.set_service(config[CONF_SERVICE]))
if CONF_DATA in config:
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA].items()]
- cg.add(act.set_data(datas))
+ cg.add(var.set_data(datas))
if CONF_DATA_TEMPLATE in config:
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA_TEMPLATE].items()]
- cg.add(act.set_data_template(datas))
+ cg.add(var.set_data_template(datas))
if CONF_VARIABLES in config:
datas = []
for key, value in config[CONF_VARIABLES].items():
value_ = yield cg.process_lambda(value, [])
datas.append(TemplatableKeyValuePair(key, value_))
- cg.add(act.set_variables(datas))
- yield act
+ cg.add(var.set_variables(datas))
+ yield var
-CONF_API_CONNECTED = 'api.connected'
-API_CONNECTED_CONDITION_SCHEMA = cv.Schema({})
-
-
-@CONDITION_REGISTRY.register(CONF_API_CONNECTED, API_CONNECTED_CONDITION_SCHEMA)
+@automation.register_condition('api.connected', APIConnectedCondition, {})
def api_connected_to_code(config, condition_id, template_arg, args):
- rhs = APIConnectedCondition.new(template_arg)
- type = APIConnectedCondition.template(template_arg)
- yield cg.Pvariable(condition_id, rhs, type=type)
+ yield cg.new_Pvariable(condition_id, template_arg)
diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp
index 6c0662f159..2e9b9f6841 100644
--- a/esphome/components/api/api_server.cpp
+++ b/esphome/components/api/api_server.cpp
@@ -999,7 +999,7 @@ bool APIConnection::send_log_message(int level, const char *tag, const char *lin
bool success = this->send_buffer(APIMessageType::SUBSCRIBE_LOGS_RESPONSE);
if (!success) {
- auto buffer = this->get_buffer();
+ buffer = this->get_buffer();
// bool send_failed = 4;
buffer.encode_bool(4, true);
return this->send_buffer(APIMessageType::SUBSCRIBE_LOGS_RESPONSE);
diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h
index 0d25535b15..be75d87264 100644
--- a/esphome/components/api/api_server.h
+++ b/esphome/components/api/api_server.h
@@ -226,10 +226,7 @@ template class HomeAssistantServiceCallAction : public Actionresp_.set_data_template(data_template);
}
void set_variables(const std::vector &variables) { this->resp_.set_variables(variables); }
- void play(Ts... x) override {
- this->parent_->send_service_call(this->resp_);
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->parent_->send_service_call(this->resp_); }
protected:
APIServer *parent_;
diff --git a/esphome/components/bang_bang/bang_bang_climate.cpp b/esphome/components/bang_bang/bang_bang_climate.cpp
index 6c24d3ea4f..1bdabaec37 100644
--- a/esphome/components/bang_bang/bang_bang_climate.cpp
+++ b/esphome/components/bang_bang/bang_bang_climate.cpp
@@ -138,11 +138,8 @@ void BangBangClimate::set_away_config(const BangBangClimateTargetTempConfig &awa
this->supports_away_ = true;
this->away_config_ = away_config;
}
-BangBangClimate::BangBangClimate(const std::string &name)
- : climate::Climate(name),
- idle_trigger_(new Trigger<>()),
- cool_trigger_(new Trigger<>()),
- heat_trigger_(new Trigger<>()) {}
+BangBangClimate::BangBangClimate()
+ : idle_trigger_(new Trigger<>()), cool_trigger_(new Trigger<>()), heat_trigger_(new Trigger<>()) {}
void BangBangClimate::set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
Trigger<> *BangBangClimate::get_idle_trigger() const { return this->idle_trigger_; }
Trigger<> *BangBangClimate::get_cool_trigger() const { return this->cool_trigger_; }
diff --git a/esphome/components/bang_bang/bang_bang_climate.h b/esphome/components/bang_bang/bang_bang_climate.h
index ad07bf0e4b..716655d20f 100644
--- a/esphome/components/bang_bang/bang_bang_climate.h
+++ b/esphome/components/bang_bang/bang_bang_climate.h
@@ -19,7 +19,7 @@ struct BangBangClimateTargetTempConfig {
class BangBangClimate : public climate::Climate, public Component {
public:
- BangBangClimate(const std::string &name);
+ BangBangClimate();
void setup() override;
void set_sensor(sensor::Sensor *sensor);
diff --git a/esphome/components/bang_bang/climate.py b/esphome/components/bang_bang/climate.py
index ce20d0dbb1..7837749ba7 100644
--- a/esphome/components/bang_bang/climate.py
+++ b/esphome/components/bang_bang/climate.py
@@ -4,15 +4,15 @@ from esphome import automation
from esphome.components import climate, sensor
from esphome.const import CONF_AWAY_CONFIG, CONF_COOL_ACTION, \
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_HEAT_ACTION, \
- CONF_ID, CONF_IDLE_ACTION, CONF_NAME, CONF_SENSOR
+ CONF_ID, CONF_IDLE_ACTION, CONF_SENSOR
bang_bang_ns = cg.esphome_ns.namespace('bang_bang')
BangBangClimate = bang_bang_ns.class_('BangBangClimate', climate.ClimateDevice)
BangBangClimateTargetTempConfig = bang_bang_ns.struct('BangBangClimateTargetTempConfig')
-CONFIG_SCHEMA = cv.nameable(climate.CLIMATE_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(BangBangClimate),
- cv.Required(CONF_SENSOR): cv.use_variable_id(sensor.Sensor),
+CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(BangBangClimate),
+ cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
cv.Required(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature,
cv.Required(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature,
cv.Required(CONF_IDLE_ACTION): automation.validate_automation(single=True),
@@ -26,7 +26,7 @@ CONFIG_SCHEMA = cv.nameable(climate.CLIMATE_SCHEMA.extend({
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield climate.register_climate(var, config)
diff --git a/esphome/components/bh1750/bh1750.cpp b/esphome/components/bh1750/bh1750.cpp
index 63b6c2d382..9cd152e1ef 100644
--- a/esphome/components/bh1750/bh1750.cpp
+++ b/esphome/components/bh1750/bh1750.cpp
@@ -8,9 +8,6 @@ static const char *TAG = "bh1750.sensor";
static const uint8_t BH1750_COMMAND_POWER_ON = 0b00000001;
-BH1750Sensor::BH1750Sensor(const std::string &name, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval) {}
-
void BH1750Sensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up BH1750 '%s'...", this->name_.c_str());
if (!this->write_bytes(BH1750_COMMAND_POWER_ON, nullptr, 0)) {
diff --git a/esphome/components/bh1750/bh1750.h b/esphome/components/bh1750/bh1750.h
index 276b808b1c..8df0bda02a 100644
--- a/esphome/components/bh1750/bh1750.h
+++ b/esphome/components/bh1750/bh1750.h
@@ -15,10 +15,8 @@ enum BH1750Resolution {
};
/// This class implements support for the i2c-based BH1750 ambient light sensor.
-class BH1750Sensor : public sensor::PollingSensorComponent, public i2c::I2CDevice {
+class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
public:
- BH1750Sensor(const std::string &name, uint32_t update_interval);
-
/** Set the resolution of this sensor.
*
* Possible values are:
diff --git a/esphome/components/bh1750/sensor.py b/esphome/components/bh1750/sensor.py
index ecab63ff79..27ee3d1b85 100644
--- a/esphome/components/bh1750/sensor.py
+++ b/esphome/components/bh1750/sensor.py
@@ -1,8 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_RESOLUTION, CONF_UPDATE_INTERVAL, UNIT_LUX, \
- ICON_BRIGHTNESS_5
+from esphome.const import CONF_ID, CONF_RESOLUTION, UNIT_LUX, ICON_BRIGHTNESS_5
DEPENDENCIES = ['i2c']
@@ -16,17 +15,16 @@ BH1750_RESOLUTIONS = {
BH1750Sensor = bh1750_ns.class_('BH1750Sensor', sensor.PollingSensorComponent, i2c.I2CDevice)
-CONFIG_SCHEMA = cv.nameable(sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1).extend({
- cv.GenerateID(): cv.declare_variable_id(BH1750Sensor),
- cv.Optional(CONF_RESOLUTION, default=0.0): cv.one_of(*BH1750_RESOLUTIONS, float=True),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x23)))
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1).extend({
+ cv.GenerateID(): cv.declare_id(BH1750Sensor),
+ cv.Optional(CONF_RESOLUTION, default=0.5): cv.enum(BH1750_RESOLUTIONS, float=True),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x23))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
yield i2c.register_i2c_device(var, config)
- cg.add(var.set_resolution(BH1750_RESOLUTIONS[config[CONF_RESOLUTION]]))
+ cg.add(var.set_resolution(config[CONF_RESOLUTION]))
diff --git a/esphome/components/binary/fan/__init__.py b/esphome/components/binary/fan/__init__.py
index 082e24630e..6ba04ce355 100644
--- a/esphome/components/binary/fan/__init__.py
+++ b/esphome/components/binary/fan/__init__.py
@@ -1,25 +1,27 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import fan, output
-from esphome.const import CONF_OSCILLATION_OUTPUT, CONF_OUTPUT, \
- CONF_OUTPUT_ID
+from esphome.const import CONF_OSCILLATION_OUTPUT, CONF_OUTPUT, CONF_OUTPUT_ID
from .. import binary_ns
BinaryFan = binary_ns.class_('BinaryFan', cg.Component)
-CONFIG_SCHEMA = cv.nameable(fan.FAN_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(BinaryFan),
- cv.Required(CONF_OUTPUT): cv.use_variable_id(output.BinaryOutput),
- cv.Optional(CONF_OSCILLATION_OUTPUT): cv.use_variable_id(output.BinaryOutput),
-}).extend(cv.COMPONENT_SCHEMA))
+CONFIG_SCHEMA = fan.FAN_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(BinaryFan),
+ cv.Required(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
+ cv.Optional(CONF_OSCILLATION_OUTPUT): cv.use_id(output.BinaryOutput),
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- output_ = yield cg.get_variable(config[CONF_OUTPUT])
- state = yield fan.create_fan_state(config)
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], state, output_)
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield cg.register_component(var, config)
+ fan_ = yield fan.create_fan_state(config)
+ cg.add(var.set_fan(fan_))
+ output_ = yield cg.get_variable(config[CONF_OUTPUT])
+ cg.add(var.set_output(output_))
+
if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
cg.add(var.set_oscillation(oscillation_output))
diff --git a/esphome/components/binary/fan/binary_fan.h b/esphome/components/binary/fan/binary_fan.h
index 897352304d..980d2629f6 100644
--- a/esphome/components/binary/fan/binary_fan.h
+++ b/esphome/components/binary/fan/binary_fan.h
@@ -9,7 +9,8 @@ namespace binary {
class BinaryFan : public Component {
public:
- BinaryFan(fan::FanState *fan, output::BinaryOutput *output) : fan_(fan), output_(output) {}
+ void set_fan(fan::FanState *fan) { fan_ = fan; }
+ void set_output(output::BinaryOutput *output) { output_ = output; }
void setup() override;
void loop() override;
void dump_config() override;
diff --git a/esphome/components/binary/light/__init__.py b/esphome/components/binary/light/__init__.py
index 846fe24b84..6167ae239f 100644
--- a/esphome/components/binary/light/__init__.py
+++ b/esphome/components/binary/light/__init__.py
@@ -6,13 +6,15 @@ from .. import binary_ns
BinaryLightOutput = binary_ns.class_('BinaryLightOutput', light.LightOutput)
-CONFIG_SCHEMA = cv.nameable(light.BINARY_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(BinaryLightOutput),
- cv.Required(CONF_OUTPUT): cv.use_variable_id(output.BinaryOutput),
-}))
+CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(BinaryLightOutput),
+ cv.Required(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
+})
def to_code(config):
- out = yield cg.get_variable(config[CONF_OUTPUT])
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], out)
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield light.register_light(var, config)
+
+ out = yield cg.get_variable(config[CONF_OUTPUT])
+ cg.add(var.set_output(out))
diff --git a/esphome/components/binary/light/binary_light_output.h b/esphome/components/binary/light/binary_light_output.h
index 1d55d06623..731973bdad 100644
--- a/esphome/components/binary/light/binary_light_output.h
+++ b/esphome/components/binary/light/binary_light_output.h
@@ -9,7 +9,7 @@ namespace binary {
class BinaryLightOutput : public light::LightOutput {
public:
- BinaryLightOutput(output::BinaryOutput *output) : output_(output) {}
+ void set_output(output::BinaryOutput *output) { output_ = output; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(false);
diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py
index 380160c554..336870392d 100644
--- a/esphome/components/binary_sensor/__init__.py
+++ b/esphome/components/binary_sensor/__init__.py
@@ -1,16 +1,16 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation, core
-from esphome.automation import CONDITION_REGISTRY, Condition, maybe_simple_id
+from esphome.automation import Condition, maybe_simple_id
from esphome.components import mqtt
from esphome.const import CONF_DEVICE_CLASS, CONF_FILTERS, \
CONF_ID, CONF_INTERNAL, CONF_INVALID_COOLDOWN, CONF_INVERTED, \
CONF_MAX_LENGTH, CONF_MIN_LENGTH, CONF_ON_CLICK, \
CONF_ON_DOUBLE_CLICK, CONF_ON_MULTI_CLICK, CONF_ON_PRESS, CONF_ON_RELEASE, CONF_ON_STATE, \
- CONF_STATE, CONF_TIMING, CONF_TRIGGER_ID, CONF_FOR, CONF_VALUE, CONF_NAME, CONF_MQTT_ID
-from esphome.core import CORE, coroutine
+ CONF_STATE, CONF_TIMING, CONF_TRIGGER_ID, CONF_FOR, CONF_NAME, CONF_MQTT_ID
+from esphome.core import CORE, coroutine, coroutine_with_priority
from esphome.py_compat import string_types
-from esphome.util import ServiceRegistry
+from esphome.util import Registry
DEVICE_CLASSES = [
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
@@ -26,15 +26,15 @@ BinarySensor = binary_sensor_ns.class_('BinarySensor', cg.Nameable)
BinarySensorPtr = BinarySensor.operator('ptr')
# Triggers
-PressTrigger = binary_sensor_ns.class_('PressTrigger', cg.Trigger.template())
-ReleaseTrigger = binary_sensor_ns.class_('ReleaseTrigger', cg.Trigger.template())
-ClickTrigger = binary_sensor_ns.class_('ClickTrigger', cg.Trigger.template())
-DoubleClickTrigger = binary_sensor_ns.class_('DoubleClickTrigger', cg.Trigger.template())
-MultiClickTrigger = binary_sensor_ns.class_('MultiClickTrigger', cg.Trigger.template(),
+PressTrigger = binary_sensor_ns.class_('PressTrigger', automation.Trigger.template())
+ReleaseTrigger = binary_sensor_ns.class_('ReleaseTrigger', automation.Trigger.template())
+ClickTrigger = binary_sensor_ns.class_('ClickTrigger', automation.Trigger.template())
+DoubleClickTrigger = binary_sensor_ns.class_('DoubleClickTrigger', automation.Trigger.template())
+MultiClickTrigger = binary_sensor_ns.class_('MultiClickTrigger', automation.Trigger.template(),
cg.Component)
MultiClickTriggerEvent = binary_sensor_ns.struct('MultiClickTriggerEvent')
-StateTrigger = binary_sensor_ns.class_('StateTrigger', cg.Trigger.template(bool))
-BinarySensorPublishAction = binary_sensor_ns.class_('BinarySensorPublishAction', cg.Action)
+StateTrigger = binary_sensor_ns.class_('StateTrigger', automation.Trigger.template(bool))
+BinarySensorPublishAction = binary_sensor_ns.class_('BinarySensorPublishAction', automation.Action)
# Condition
BinarySensorCondition = binary_sensor_ns.class_('BinarySensorCondition', Condition)
@@ -46,55 +46,34 @@ DelayedOffFilter = binary_sensor_ns.class_('DelayedOffFilter', Filter, cg.Compon
InvertFilter = binary_sensor_ns.class_('InvertFilter', Filter)
LambdaFilter = binary_sensor_ns.class_('LambdaFilter', Filter)
-FILTER_REGISTRY = ServiceRegistry()
-validate_filters = cv.validate_registry('filter', FILTER_REGISTRY, [CONF_ID])
+FILTER_REGISTRY = Registry()
+validate_filters = cv.validate_registry('filter', FILTER_REGISTRY)
-@FILTER_REGISTRY.register('invert',
- cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(InvertFilter)
- }))
-def invert_filter_to_code(config):
- rhs = InvertFilter.new()
- var = cg.Pvariable(config[CONF_ID], rhs)
+@FILTER_REGISTRY.register('invert', InvertFilter, {})
+def invert_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id)
+
+
+@FILTER_REGISTRY.register('delayed_on', DelayedOnFilter,
+ cv.positive_time_period_milliseconds)
+def delayed_on_filter_to_code(config, filter_id):
+ var = cg.new_Pvariable(filter_id, config)
+ yield cg.register_component(var, {})
yield var
-@FILTER_REGISTRY.register('delayed_on',
- cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DelayedOnFilter),
- cv.Required(CONF_VALUE): cv.positive_time_period_milliseconds,
- }).extend(cv.COMPONENT_SCHEMA)))
-def delayed_on_filter_to_code(config):
- rhs = DelayedOnFilter.new(config[CONF_VALUE])
- var = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(var, config)
+@FILTER_REGISTRY.register('delayed_off', DelayedOffFilter, cv.positive_time_period_milliseconds)
+def delayed_off_filter_to_code(config, filter_id):
+ var = cg.new_Pvariable(filter_id, config)
+ yield cg.register_component(var, {})
yield var
-@FILTER_REGISTRY.register('delayed_off',
- cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DelayedOffFilter),
- cv.Required(CONF_VALUE): cv.positive_time_period_milliseconds,
- }).extend(cv.COMPONENT_SCHEMA)))
-def delayed_off_filter_to_code(config):
- rhs = DelayedOffFilter.new(config[CONF_VALUE])
- var = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(var, config)
- yield var
-
-
-@FILTER_REGISTRY.register('lambda',
- cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(LambdaFilter),
- cv.Required(CONF_VALUE): cv.lambda_,
- })))
-def lambda_filter_to_code(config):
- lambda_ = yield cg.process_lambda(config[CONF_VALUE], [(bool, 'x')],
- return_type=cg.optional.template(bool))
- rhs = LambdaFilter.new(lambda_)
- var = cg.Pvariable(config[CONF_ID], rhs)
- yield var
+@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.lambda_)
+def lambda_filter_to_code(config, filter_id):
+ lambda_ = yield cg.process_lambda(config, [(bool, 'x')], return_type=cg.optional.template(bool))
+ yield cg.new_Pvariable(filter_id, lambda_)
MULTI_CLICK_TIMING_SCHEMA = cv.Schema({
@@ -193,35 +172,35 @@ def validate_multi_click_timing(value):
device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space='_')
BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(BinarySensor),
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTBinarySensorComponent),
+ cv.GenerateID(): cv.declare_id(BinarySensor),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTBinarySensorComponent),
cv.Optional(CONF_DEVICE_CLASS): device_class,
cv.Optional(CONF_FILTERS): validate_filters,
cv.Optional(CONF_ON_PRESS): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(PressTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger),
}),
cv.Optional(CONF_ON_RELEASE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ReleaseTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger),
}),
cv.Optional(CONF_ON_CLICK): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ClickTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger),
cv.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
}),
cv.Optional(CONF_ON_DOUBLE_CLICK): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(DoubleClickTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger),
cv.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
}),
cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MultiClickTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger),
cv.Required(CONF_TIMING): cv.All([parse_multi_click_timing_str],
validate_multi_click_timing),
cv.Optional(CONF_INVALID_COOLDOWN, default='1s'): cv.positive_time_period_milliseconds,
}),
cv.Optional(CONF_ON_STATE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(StateTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
}),
cv.Optional(CONF_INVERTED): cv.invalid(
@@ -234,6 +213,7 @@ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
@coroutine
def setup_binary_sensor_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(CONF_INTERNAL))
if CONF_DEVICE_CLASS in config:
@@ -300,28 +280,28 @@ def new_binary_sensor(config):
yield var
-BINARY_SENSOR_IS_ON_OFF_CONDITION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(BinarySensor),
- cv.Optional(CONF_FOR): cv.positive_time_period_milliseconds,
+BINARY_SENSOR_CONDITION_SCHEMA = maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(BinarySensor),
+ cv.Optional(CONF_FOR): cv.invalid("This option has been removed in 1.13, please use the "
+ "'for' condition instead."),
})
-@CONDITION_REGISTRY.register('binary_sensor.is_on', BINARY_SENSOR_IS_ON_OFF_CONDITION_SCHEMA)
+@automation.register_condition('binary_sensor.is_on', BinarySensorCondition,
+ BINARY_SENSOR_CONDITION_SCHEMA)
def binary_sensor_is_on_to_code(config, condition_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = BinarySensorCondition.template(template_arg)
- rhs = type.new(var, True, config.get(CONF_FOR))
- yield cg.Pvariable(condition_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(condition_id, template_arg, paren, True)
-@CONDITION_REGISTRY.register('binary_sensor.is_off', BINARY_SENSOR_IS_ON_OFF_CONDITION_SCHEMA)
+@automation.register_condition('binary_sensor.is_off', BinarySensorCondition,
+ BINARY_SENSOR_CONDITION_SCHEMA)
def binary_sensor_is_off_to_code(config, condition_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = BinarySensorCondition.template(template_arg)
- rhs = type.new(var, False, config.get(CONF_FOR))
- yield cg.Pvariable(condition_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(condition_id, template_arg, paren, False)
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_BINARY_SENSOR')
cg.add_global(binary_sensor_ns.using)
diff --git a/esphome/components/binary_sensor/automation.h b/esphome/components/binary_sensor/automation.h
index 2fdbb1ec45..e9ff37446d 100644
--- a/esphome/components/binary_sensor/automation.h
+++ b/esphome/components/binary_sensor/automation.h
@@ -125,22 +125,12 @@ class StateTrigger : public Trigger {
template class BinarySensorCondition : public Condition {
public:
- BinarySensorCondition(BinarySensor *parent, bool state, uint32_t for_time = 0)
- : parent_(parent), state_(state), for_time_(for_time) {
- parent->add_on_state_callback([this](bool state) { this->last_state_time_ = millis(); });
- }
- bool check(Ts... x) override {
- if (this->parent_->state != this->state_)
- return false;
-
- return millis() - this->last_state_time_ >= this->for_time_;
- }
+ BinarySensorCondition(BinarySensor *parent, bool state) : parent_(parent), state_(state) {}
+ bool check(Ts... x) override { return this->parent_->state == this->state_; }
protected:
BinarySensor *parent_;
bool state_;
- uint32_t last_state_time_{0};
- uint32_t for_time_{0};
};
template class BinarySensorPublishAction : public Action {
@@ -150,7 +140,6 @@ template class BinarySensorPublishAction : public Action
void play(Ts... x) override {
auto val = this->state_.value(x...);
this->sensor_->publish_state(val);
- this->play_next(x...);
}
protected:
diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h
index 3dd7004c01..51c7a57ff6 100644
--- a/esphome/components/binary_sensor/binary_sensor.h
+++ b/esphome/components/binary_sensor/binary_sensor.h
@@ -24,12 +24,12 @@ namespace binary_sensor {
*/
class BinarySensor : public Nameable {
public:
+ explicit BinarySensor();
/** Construct a binary sensor with the specified name
*
* @param name Name of this binary sensor.
*/
explicit BinarySensor(const std::string &name);
- explicit BinarySensor();
/** Add a callback to be notified of state changes.
*
diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py
index c4cbd89f3b..beab5448be 100644
--- a/esphome/components/ble_presence/binary_sensor.py
+++ b/esphome/components/ble_presence/binary_sensor.py
@@ -11,10 +11,10 @@ ble_presence_ns = cg.esphome_ns.namespace('ble_presence')
BLEPresenceDevice = ble_presence_ns.class_('BLEPresenceDevice', binary_sensor.BinarySensor,
cg.Component, ESPBTDeviceListener)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(BLEPresenceDevice),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(BLEPresenceDevice),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
-}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA))
+}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py
index 7fb34649c9..22e1c82f64 100644
--- a/esphome/components/ble_rssi/sensor.py
+++ b/esphome/components/ble_rssi/sensor.py
@@ -3,8 +3,7 @@ import esphome.config_validation as cv
from esphome.components import sensor
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
ESP_BLE_DEVICE_SCHEMA
-from esphome.const import CONF_MAC_ADDRESS, CONF_NAME, CONF_ID, CONF_UNIT_OF_MEASUREMENT, \
- CONF_ICON, CONF_ACCURACY_DECIMALS, UNIT_DECIBEL, ICON_SIGNAL
+from esphome.const import CONF_MAC_ADDRESS, CONF_NAME, CONF_ID, UNIT_DECIBEL, ICON_SIGNAL
DEPENDENCIES = ['esp32_ble_tracker']
@@ -12,14 +11,10 @@ ble_rssi_ns = cg.esphome_ns.namespace('ble_rssi')
BLERSSISensor = ble_rssi_ns.class_('BLERSSISensor', sensor.Sensor, cg.Component,
ESPBTDeviceListener)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(BLERSSISensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_DECIBEL, ICON_SIGNAL, 0).extend({
+ cv.GenerateID(): cv.declare_id(BLERSSISensor),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
-
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_DECIBEL): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_SIGNAL): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals
-}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA))
+}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
diff --git a/esphome/components/bme280/bme280.h b/esphome/components/bme280/bme280.h
index 69ad9a7416..82724d6887 100644
--- a/esphome/components/bme280/bme280.h
+++ b/esphome/components/bme280/bme280.h
@@ -60,8 +60,6 @@ enum BME280IIRFilter {
/// This class implements support for the BME280 Temperature+Pressure+Humidity i2c sensor.
class BME280Component : public PollingComponent, public i2c::I2CDevice {
public:
- BME280Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
diff --git a/esphome/components/bme280/sensor.py b/esphome/components/bme280/sensor.py
index 65b7513868..651752102f 100644
--- a/esphome/components/bme280/sensor.py
+++ b/esphome/components/bme280/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_IIR_FILTER, CONF_OVERSAMPLING, \
- CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, ICON_THERMOMETER, \
+ CONF_PRESSURE, CONF_TEMPERATURE, ICON_THERMOMETER, \
UNIT_CELSIUS, UNIT_HECTOPASCAL, ICON_GAUGE, ICON_WATER_PERCENT, UNIT_PERCENT
DEPENDENCIES = ['i2c']
@@ -30,29 +30,28 @@ IIR_FILTER_OPTIONS = {
BME280Component = bme280_ns.class_('BME280Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(BME280Component),
- cv.Optional(CONF_TEMPERATURE): cv.nameable(
+ cv.GenerateID(): cv.declare_id(BME280Component),
+ cv.Optional(CONF_TEMPERATURE):
sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_PRESSURE): cv.nameable(
+ cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_PRESSURE):
sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1).extend({
cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_HUMIDITY): cv.nameable(
+ cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_HUMIDITY):
sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1).extend({
cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_IIR_FILTER, default='OFF'): cv.one_of(*IIR_FILTER_OPTIONS, upper=True),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x77))
+ cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_IIR_FILTER, default='OFF'): cv.enum(IIR_FILTER_OPTIONS, upper=True),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x77))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
@@ -60,18 +59,18 @@ def to_code(config):
conf = config[CONF_TEMPERATURE]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_temperature_sensor(sens))
- cg.add(var.set_temperature_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING]))
if CONF_PRESSURE in config:
conf = config[CONF_PRESSURE]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_pressure_sensor(sens))
- cg.add(var.set_pressure_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING]))
if CONF_HUMIDITY in config:
conf = config[CONF_HUMIDITY]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_humidity_sensor(sens))
- cg.add(var.set_humidity_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING]))
- cg.add(var.set_iir_filter(IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]]))
+ cg.add(var.set_iir_filter(config[CONF_IIR_FILTER]))
diff --git a/esphome/components/bme680/bme680.h b/esphome/components/bme680/bme680.h
index e69fb1dadc..0671cd990e 100644
--- a/esphome/components/bme680/bme680.h
+++ b/esphome/components/bme680/bme680.h
@@ -68,8 +68,6 @@ struct BME680CalibrationData {
class BME680Component : public PollingComponent, public i2c::I2CDevice {
public:
- BME680Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
/// Set the temperature oversampling value. Defaults to 16X.
void set_temperature_oversampling(BME680Oversampling temperature_oversampling);
/// Set the pressure oversampling value. Defaults to 16X.
diff --git a/esphome/components/bme680/sensor.py b/esphome/components/bme680/sensor.py
index 826e9a5bf6..64973fb91c 100644
--- a/esphome/components/bme680/sensor.py
+++ b/esphome/components/bme680/sensor.py
@@ -4,7 +4,7 @@ from esphome import core
from esphome.components import i2c, sensor
from esphome.const import CONF_DURATION, CONF_GAS_RESISTANCE, CONF_HEATER, \
CONF_HUMIDITY, CONF_ID, CONF_IIR_FILTER, CONF_OVERSAMPLING, CONF_PRESSURE, \
- CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, UNIT_OHM, ICON_GAS_CYLINDER, UNIT_CELSIUS, \
+ CONF_TEMPERATURE, UNIT_OHM, ICON_GAS_CYLINDER, UNIT_CELSIUS, \
ICON_THERMOMETER, UNIT_HECTOPASCAL, ICON_GAUGE, ICON_WATER_PERCENT, UNIT_PERCENT
DEPENDENCIES = ['i2c']
@@ -35,36 +35,35 @@ IIR_FILTER_OPTIONS = {
BME680Component = bme680_ns.class_('BME680Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(BME680Component),
- cv.Optional(CONF_TEMPERATURE): cv.nameable(
+ cv.GenerateID(): cv.declare_id(BME680Component),
+ cv.Optional(CONF_TEMPERATURE):
sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_PRESSURE): cv.nameable(
+ cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_PRESSURE):
sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1).extend({
cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_HUMIDITY): cv.nameable(
+ cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_HUMIDITY):
sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1).extend({
cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_GAS_RESISTANCE): cv.nameable(
- sensor.sensor_schema(UNIT_OHM, ICON_GAS_CYLINDER, 1)),
- cv.Optional(CONF_IIR_FILTER, default='OFF'): cv.one_of(*IIR_FILTER_OPTIONS, upper=True),
+ cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_GAS_RESISTANCE):
+ sensor.sensor_schema(UNIT_OHM, ICON_GAS_CYLINDER, 1),
+ cv.Optional(CONF_IIR_FILTER, default='OFF'): cv.enum(IIR_FILTER_OPTIONS, upper=True),
cv.Optional(CONF_HEATER): cv.Any(None, cv.All(cv.Schema({
- cv.Optional(CONF_TEMPERATURE, default=320): cv.All(cv.Coerce(int), cv.Range(200, 400)),
+ cv.Optional(CONF_TEMPERATURE, default=320): cv.int_range(min=200, max=400),
cv.Optional(CONF_DURATION, default='150ms'): cv.All(
cv.positive_time_period_milliseconds, cv.Range(max=core.TimePeriod(milliseconds=4032)))
- }, cv.has_at_least_one_key(CONF_TEMPERATURE, CONF_DURATION)))),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x76))
+ }), cv.has_at_least_one_key(CONF_TEMPERATURE, CONF_DURATION))),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x76))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
@@ -72,19 +71,19 @@ def to_code(config):
conf = config[CONF_TEMPERATURE]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_temperature_sensor(sens))
- cg.add(var.set_temperature_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING]))
if CONF_PRESSURE in config:
conf = config[CONF_PRESSURE]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_pressure_sensor(sens))
- cg.add(var.set_pressure_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING]))
if CONF_HUMIDITY in config:
conf = config[CONF_HUMIDITY]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_humidity_sensor(sens))
- cg.add(var.set_humidity_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_humidity_oversampling(conf[CONF_OVERSAMPLING]))
if CONF_GAS_RESISTANCE in config:
conf = config[CONF_GAS_RESISTANCE]
diff --git a/esphome/components/bmp085/bmp085.h b/esphome/components/bmp085/bmp085.h
index 9013dad09b..d84b4d43ef 100644
--- a/esphome/components/bmp085/bmp085.h
+++ b/esphome/components/bmp085/bmp085.h
@@ -9,8 +9,6 @@ namespace bmp085 {
class BMP085Component : public PollingComponent, public i2c::I2CDevice {
public:
- BMP085Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_pressure(sensor::Sensor *pressure) { pressure_ = pressure; }
diff --git a/esphome/components/bmp085/sensor.py b/esphome/components/bmp085/sensor.py
index 54e3262725..558c6978b1 100644
--- a/esphome/components/bmp085/sensor.py
+++ b/esphome/components/bmp085/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID, CONF_PRESSURE, CONF_TEMPERATURE, \
- CONF_UPDATE_INTERVAL, UNIT_CELSIUS, ICON_THERMOMETER, ICON_GAUGE, UNIT_HECTOPASCAL
+ UNIT_CELSIUS, ICON_THERMOMETER, ICON_GAUGE, UNIT_HECTOPASCAL
DEPENDENCIES = ['i2c']
@@ -10,17 +10,14 @@ bmp085_ns = cg.esphome_ns.namespace('bmp085')
BMP085Component = bmp085_ns.class_('BMP085Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(BMP085Component),
- cv.Optional(CONF_TEMPERATURE):
- cv.nameable(sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
- cv.Optional(CONF_PRESSURE):
- cv.nameable(sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x77))
+ cv.GenerateID(): cv.declare_id(BMP085Component),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Optional(CONF_PRESSURE): sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x77))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/bmp280/bmp280.cpp b/esphome/components/bmp280/bmp280.cpp
index 20b034a996..aed9f3e515 100644
--- a/esphome/components/bmp280/bmp280.cpp
+++ b/esphome/components/bmp280/bmp280.cpp
@@ -233,7 +233,6 @@ uint16_t BMP280Component::read_u16_le_(uint8_t a_register) {
return (data >> 8) | (data << 8);
}
int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); }
-BMP280Component::BMP280Component(uint32_t update_interval) : PollingComponent(update_interval) {}
} // namespace bmp280
} // namespace esphome
diff --git a/esphome/components/bmp280/bmp280.h b/esphome/components/bmp280/bmp280.h
index 300943db87..f8646fb547 100644
--- a/esphome/components/bmp280/bmp280.h
+++ b/esphome/components/bmp280/bmp280.h
@@ -53,7 +53,6 @@ enum BMP280IIRFilter {
/// This class implements support for the BMP280 Temperature+Pressure i2c sensor.
class BMP280Component : public PollingComponent, public i2c::I2CDevice {
public:
- BMP280Component(uint32_t update_interval);
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
diff --git a/esphome/components/bmp280/sensor.py b/esphome/components/bmp280/sensor.py
index 6e73aa8eb7..63c9655331 100644
--- a/esphome/components/bmp280/sensor.py
+++ b/esphome/components/bmp280/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID, CONF_PRESSURE, CONF_TEMPERATURE, \
- CONF_UPDATE_INTERVAL, UNIT_CELSIUS, ICON_THERMOMETER, ICON_GAUGE, UNIT_HECTOPASCAL, \
+ UNIT_CELSIUS, ICON_THERMOMETER, ICON_GAUGE, UNIT_HECTOPASCAL, \
CONF_IIR_FILTER, CONF_OVERSAMPLING
DEPENDENCIES = ['i2c']
@@ -30,24 +30,19 @@ IIR_FILTER_OPTIONS = {
BMP280Component = bmp280_ns.class_('BMP280Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(BMP280Component),
- cv.Optional(CONF_TEMPERATURE): cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
- cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_PRESSURE): cv.nameable(
- sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1).extend({
- cv.Optional(CONF_OVERSAMPLING, default='16X'):
- cv.one_of(*OVERSAMPLING_OPTIONS, upper=True),
- })),
- cv.Optional(CONF_IIR_FILTER, default='OFF'): cv.one_of(*IIR_FILTER_OPTIONS, upper=True),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x77))
+ cv.GenerateID(): cv.declare_id(BMP280Component),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
+ cv.Optional(CONF_OVERSAMPLING, default='16X'): cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_PRESSURE): sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1).extend({
+ cv.Optional(CONF_OVERSAMPLING, default='16X'): cv.enum(OVERSAMPLING_OPTIONS, upper=True),
+ }),
+ cv.Optional(CONF_IIR_FILTER, default='OFF'): cv.enum(IIR_FILTER_OPTIONS, upper=True),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x77))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
@@ -55,10 +50,10 @@ def to_code(config):
conf = config[CONF_TEMPERATURE]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_temperature_sensor(sens))
- cg.add(var.set_temperature_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_temperature_oversampling(conf[CONF_OVERSAMPLING]))
if CONF_PRESSURE in config:
conf = config[CONF_PRESSURE]
sens = yield sensor.new_sensor(conf)
cg.add(var.set_pressure_sensor(sens))
- cg.add(var.set_pressure_oversampling(OVERSAMPLING_OPTIONS[conf[CONF_OVERSAMPLING]]))
+ cg.add(var.set_pressure_oversampling(conf[CONF_OVERSAMPLING]))
diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py
index 3f5a9ca283..ba0b37ed8c 100644
--- a/esphome/components/climate/__init__.py
+++ b/esphome/components/climate/__init__.py
@@ -1,19 +1,20 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY
+from esphome import automation
from esphome.components import mqtt
from esphome.const import CONF_AWAY, CONF_ID, CONF_INTERNAL, CONF_MAX_TEMPERATURE, \
CONF_MIN_TEMPERATURE, CONF_MODE, CONF_TARGET_TEMPERATURE, \
CONF_TARGET_TEMPERATURE_HIGH, CONF_TARGET_TEMPERATURE_LOW, CONF_TEMPERATURE_STEP, CONF_VISUAL, \
- CONF_MQTT_ID
-from esphome.core import CORE, coroutine
+ CONF_MQTT_ID, CONF_NAME
+from esphome.core import CORE, coroutine, coroutine_with_priority
+
+IS_PLATFORM_COMPONENT = True
climate_ns = cg.esphome_ns.namespace('climate')
ClimateDevice = climate_ns.class_('Climate', cg.Nameable)
ClimateCall = climate_ns.class_('ClimateCall')
ClimateTraits = climate_ns.class_('ClimateTraits')
-# MQTTClimateComponent = climate_ns.class_('MQTTClimateComponent', mqtt.MQTTComponent)
ClimateMode = climate_ns.enum('ClimateMode')
CLIMATE_MODES = {
@@ -23,14 +24,14 @@ CLIMATE_MODES = {
'HEAT': ClimateMode.CLIMATE_MODE_HEAT,
}
-validate_climate_mode = cv.one_of(*CLIMATE_MODES, upper=True)
+validate_climate_mode = cv.enum(CLIMATE_MODES, upper=True)
# Actions
-ControlAction = climate_ns.class_('ControlAction', cg.Action)
+ControlAction = climate_ns.class_('ControlAction', automation.Action)
CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(ClimateDevice),
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTClimateComponent),
+ cv.GenerateID(): cv.declare_id(ClimateDevice),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTClimateComponent),
cv.Optional(CONF_VISUAL, default={}): cv.Schema({
cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
@@ -42,6 +43,7 @@ CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
@coroutine
def setup_climate_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(config[CONF_INTERNAL]))
visual = config[CONF_VISUAL]
@@ -66,7 +68,7 @@ def register_climate(var, config):
CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(ClimateDevice),
+ cv.Required(CONF_ID): cv.use_id(ClimateDevice),
cv.Optional(CONF_MODE): cv.templatable(validate_climate_mode),
cv.Optional(CONF_TARGET_TEMPERATURE): cv.templatable(cv.temperature),
cv.Optional(CONF_TARGET_TEMPERATURE_LOW): cv.templatable(cv.temperature),
@@ -75,31 +77,29 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema({
})
-@ACTION_REGISTRY.register('climate.control', CLIMATE_CONTROL_ACTION_SCHEMA)
+@automation.register_action('climate.control', ControlAction, CLIMATE_CONTROL_ACTION_SCHEMA)
def climate_control_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ControlAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
if CONF_MODE in config:
- template_ = yield cg.templatable(config[CONF_MODE], args, ClimateMode,
- to_exp=CLIMATE_MODES)
- cg.add(action.set_mode(template_))
+ template_ = yield cg.templatable(config[CONF_MODE], args, ClimateMode)
+ cg.add(var.set_mode(template_))
if CONF_TARGET_TEMPERATURE in config:
template_ = yield cg.templatable(config[CONF_TARGET_TEMPERATURE], args, float)
- cg.add(action.set_target_temperature(template_))
+ cg.add(var.set_target_temperature(template_))
if CONF_TARGET_TEMPERATURE_LOW in config:
template_ = yield cg.templatable(config[CONF_TARGET_TEMPERATURE_LOW], args, float)
- cg.add(action.set_target_temperature_low(template_))
+ cg.add(var.set_target_temperature_low(template_))
if CONF_TARGET_TEMPERATURE_HIGH in config:
template_ = yield cg.templatable(config[CONF_TARGET_TEMPERATURE_HIGH], args, float)
- cg.add(action.set_target_temperature_high(template_))
+ cg.add(var.set_target_temperature_high(template_))
if CONF_AWAY in config:
template_ = yield cg.templatable(config[CONF_AWAY], args, bool)
- cg.add(action.set_away(template_))
- yield action
+ cg.add(var.set_away(template_))
+ yield var
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_CLIMATE')
cg.add_global(climate_ns.using)
diff --git a/esphome/components/climate/automation.h b/esphome/components/climate/automation.h
index b1668c9d98..845773a0ab 100644
--- a/esphome/components/climate/automation.h
+++ b/esphome/components/climate/automation.h
@@ -18,7 +18,8 @@ template class ControlAction : public Action {
void play(Ts... x) override {
auto call = this->climate_->make_call();
- call.set_target_temperature(this->mode_.optional_value(x...));
+ call.set_mode(this->mode_.optional_value(x...));
+ call.set_target_temperature(this->target_temperature_.optional_value(x...));
call.set_target_temperature_low(this->target_temperature_low_.optional_value(x...));
call.set_target_temperature_high(this->target_temperature_high_.optional_value(x...));
call.set_away(this->away_.optional_value(x...));
diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h
index 0eba29da5e..102d700d58 100644
--- a/esphome/components/climate/climate.h
+++ b/esphome/components/climate/climate.h
@@ -114,10 +114,10 @@ struct ClimateDeviceRestoreState {
*/
class Climate : public Nameable {
public:
- /// Construct a climate device with a name.
- Climate(const std::string &name);
/// Construct a climate device with empty name (will be set later).
Climate();
+ /// Construct a climate device with a name.
+ Climate(const std::string &name);
/// The active mode of the climate device.
ClimateMode mode{CLIMATE_MODE_OFF};
diff --git a/esphome/components/cover/__init__.py b/esphome/components/cover/__init__.py
index 6abe571703..ed6ebe98fa 100644
--- a/esphome/components/cover/__init__.py
+++ b/esphome/components/cover/__init__.py
@@ -1,10 +1,11 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id, Condition
+from esphome import automation
+from esphome.automation import maybe_simple_id, Condition
from esphome.components import mqtt
from esphome.const import CONF_ID, CONF_INTERNAL, CONF_DEVICE_CLASS, CONF_STATE, \
- CONF_POSITION, CONF_TILT, CONF_STOP, CONF_MQTT_ID
-from esphome.core import CORE, coroutine
+ CONF_POSITION, CONF_TILT, CONF_STOP, CONF_MQTT_ID, CONF_NAME
+from esphome.core import CORE, coroutine, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -24,7 +25,7 @@ COVER_STATES = {
'OPEN': COVER_OPEN,
'CLOSED': COVER_CLOSED,
}
-validate_cover_state = cv.one_of(*COVER_STATES, upper=True)
+validate_cover_state = cv.enum(COVER_STATES, upper=True)
CoverOperation = cover_ns.enum('CoverOperation')
COVER_OPERATIONS = {
@@ -32,20 +33,20 @@ COVER_OPERATIONS = {
'OPENING': CoverOperation.COVER_OPERATION_OPENING,
'CLOSING': CoverOperation.COVER_OPERATION_CLOSING,
}
-validate_cover_operation = cv.one_of(*COVER_OPERATIONS, upper=True)
+validate_cover_operation = cv.enum(COVER_OPERATIONS, upper=True)
# Actions
-OpenAction = cover_ns.class_('OpenAction', cg.Action)
-CloseAction = cover_ns.class_('CloseAction', cg.Action)
-StopAction = cover_ns.class_('StopAction', cg.Action)
-ControlAction = cover_ns.class_('ControlAction', cg.Action)
-CoverPublishAction = cover_ns.class_('CoverPublishAction', cg.Action)
+OpenAction = cover_ns.class_('OpenAction', automation.Action)
+CloseAction = cover_ns.class_('CloseAction', automation.Action)
+StopAction = cover_ns.class_('StopAction', automation.Action)
+ControlAction = cover_ns.class_('ControlAction', automation.Action)
+CoverPublishAction = cover_ns.class_('CoverPublishAction', automation.Action)
CoverIsOpenCondition = cover_ns.class_('CoverIsOpenCondition', Condition)
CoverIsClosedCondition = cover_ns.class_('CoverIsClosedCondition', Condition)
COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(Cover),
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTCoverComponent),
+ cv.GenerateID(): cv.declare_id(Cover),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTCoverComponent),
cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True),
# TODO: MQTT topic options
})
@@ -53,6 +54,7 @@ COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
@coroutine
def setup_cover_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(config[CONF_INTERNAL]))
if CONF_DEVICE_CLASS in config:
@@ -72,65 +74,57 @@ def register_cover(var, config):
COVER_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(Cover),
+ cv.Required(CONF_ID): cv.use_id(Cover),
})
-@ACTION_REGISTRY.register('cover.open', COVER_ACTION_SCHEMA)
+@automation.register_action('cover.open', OpenAction, COVER_ACTION_SCHEMA)
def cover_open_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = OpenAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('cover.close', COVER_ACTION_SCHEMA)
+@automation.register_action('cover.close', CloseAction, COVER_ACTION_SCHEMA)
def cover_close_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = CloseAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('cover.stop', COVER_ACTION_SCHEMA)
+@automation.register_action('cover.stop', StopAction, COVER_ACTION_SCHEMA)
def cover_stop_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = StopAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
COVER_CONTROL_ACTION_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(Cover),
+ cv.Required(CONF_ID): cv.use_id(Cover),
cv.Optional(CONF_STOP): cv.templatable(cv.boolean),
- cv.Exclusive(CONF_STATE, 'pos'): cv.templatable(cv.one_of(*COVER_STATES)),
+ cv.Exclusive(CONF_STATE, 'pos'): cv.templatable(validate_cover_state),
cv.Exclusive(CONF_POSITION, 'pos'): cv.templatable(cv.percentage),
cv.Optional(CONF_TILT): cv.templatable(cv.percentage),
})
-@ACTION_REGISTRY.register('cover.control', COVER_CONTROL_ACTION_SCHEMA)
+@automation.register_action('cover.control', ControlAction, COVER_CONTROL_ACTION_SCHEMA)
def cover_control_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = StopAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
if CONF_STOP in config:
template_ = yield cg.templatable(config[CONF_STOP], args, bool)
- cg.add(action.set_stop(template_))
+ cg.add(var.set_stop(template_))
if CONF_STATE in config:
- template_ = yield cg.templatable(config[CONF_STATE], args, float,
- to_exp=COVER_STATES)
- cg.add(action.set_position(template_))
+ template_ = yield cg.templatable(config[CONF_STATE], args, float)
+ cg.add(var.set_position(template_))
if CONF_POSITION in config:
template_ = yield cg.templatable(config[CONF_POSITION], args, float)
- cg.add(action.set_position(template_))
+ cg.add(var.set_position(template_))
if CONF_TILT in config:
template_ = yield cg.templatable(config[CONF_TILT], args, float)
- cg.add(action.set_tilt(template_))
- yield action
+ cg.add(var.set_tilt(template_))
+ yield var
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_COVER')
cg.add_global(cover_ns.using)
diff --git a/esphome/components/cover/automation.h b/esphome/components/cover/automation.h
index 296760263b..a8eb0cdf99 100644
--- a/esphome/components/cover/automation.h
+++ b/esphome/components/cover/automation.h
@@ -11,10 +11,7 @@ template class OpenAction : public Action {
public:
explicit OpenAction(Cover *cover) : cover_(cover) {}
- void play(Ts... x) override {
- this->cover_->open();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->cover_->open(); }
protected:
Cover *cover_;
@@ -24,10 +21,7 @@ template class CloseAction : public Action {
public:
explicit CloseAction(Cover *cover) : cover_(cover) {}
- void play(Ts... x) override {
- this->cover_->close();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->cover_->close(); }
protected:
Cover *cover_;
@@ -37,10 +31,7 @@ template class StopAction : public Action {
public:
explicit StopAction(Cover *cover) : cover_(cover) {}
- void play(Ts... x) override {
- this->cover_->stop();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->cover_->stop(); }
protected:
Cover *cover_;
@@ -59,7 +50,6 @@ template class ControlAction : public Action {
if (this->tilt_.has_value())
call.set_tilt(this->tilt_.value(x...));
call.perform();
- this->play_next(x...);
}
TEMPLATABLE_VALUE(bool, stop)
@@ -81,7 +71,6 @@ template class CoverPublishAction : public Action {
if (this->current_operation_.has_value())
this->cover_->current_operation = this->current_operation_.value(x...);
this->cover_->publish_state();
- this->play_next(x...);
}
TEMPLATABLE_VALUE(float, position)
diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h
index bace869ba6..12011e1b4c 100644
--- a/esphome/components/cover/cover.h
+++ b/esphome/components/cover/cover.h
@@ -105,8 +105,8 @@ const char *cover_operation_to_str(CoverOperation op);
*/
class Cover : public Nameable {
public:
- explicit Cover(const std::string &name);
explicit Cover();
+ explicit Cover(const std::string &name);
/// The current operation of the cover (idle, opening, closing).
CoverOperation current_operation{COVER_OPERATION_IDLE};
diff --git a/esphome/components/cse7766/cse7766.h b/esphome/components/cse7766/cse7766.h
index c7ed4d4e55..6cacfee072 100644
--- a/esphome/components/cse7766/cse7766.h
+++ b/esphome/components/cse7766/cse7766.h
@@ -9,8 +9,6 @@ namespace cse7766 {
class CSE7766Component : public PollingComponent, public uart::UARTDevice {
public:
- CSE7766Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
diff --git a/esphome/components/cse7766/sensor.py b/esphome/components/cse7766/sensor.py
index 6de12266c4..a415d67688 100644
--- a/esphome/components/cse7766/sensor.py
+++ b/esphome/components/cse7766/sensor.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, uart
-from esphome.const import CONF_CURRENT, CONF_ID, CONF_POWER, CONF_UPDATE_INTERVAL, CONF_VOLTAGE, \
+from esphome.const import CONF_CURRENT, CONF_ID, CONF_POWER, CONF_VOLTAGE, \
UNIT_VOLT, ICON_FLASH, UNIT_AMPERE, UNIT_WATT
DEPENDENCIES = ['uart']
@@ -10,18 +10,16 @@ cse7766_ns = cg.esphome_ns.namespace('cse7766')
CSE7766Component = cse7766_ns.class_('CSE7766Component', cg.PollingComponent, uart.UARTDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CSE7766Component),
+ cv.GenerateID(): cv.declare_id(CSE7766Component),
- cv.Optional(CONF_VOLTAGE): cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1)),
- cv.Optional(CONF_CURRENT): cv.nameable(
- sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2)),
- cv.Optional(CONF_POWER): cv.nameable(sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
+ cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1),
+ cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
+ cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1),
+}).extend(cv.polling_component_schema('60s')).extend(uart.UART_DEVICE_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield uart.register_uart_device(var, config)
diff --git a/esphome/components/custom/binary_sensor/__init__.py b/esphome/components/custom/binary_sensor/__init__.py
index afcb577f3f..b08988cc5a 100644
--- a/esphome/components/custom/binary_sensor/__init__.py
+++ b/esphome/components/custom/binary_sensor/__init__.py
@@ -1,16 +1,15 @@
-from esphome.components import binary_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_BINARY_SENSORS, CONF_ID, CONF_LAMBDA, CONF_NAME
+import esphome.config_validation as cv
+from esphome.components import binary_sensor
+from esphome.const import CONF_BINARY_SENSORS, CONF_ID, CONF_LAMBDA
from .. import custom_ns
CustomBinarySensorConstructor = custom_ns.class_('CustomBinarySensorConstructor')
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomBinarySensorConstructor),
+ cv.GenerateID(): cv.declare_id(CustomBinarySensorConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
- cv.Required(CONF_BINARY_SENSORS):
- cv.ensure_list(cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA)),
+ cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(binary_sensor.BINARY_SENSOR_SCHEMA),
})
@@ -22,5 +21,4 @@ def to_code(config):
custom = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_BINARY_SENSORS]):
rhs = custom.Pget_binary_sensor(i)
- cg.add(rhs.set_name(conf[CONF_NAME]))
yield binary_sensor.register_binary_sensor(rhs, conf)
diff --git a/esphome/components/custom/output/__init__.py b/esphome/components/custom/output/__init__.py
index 0b60df6ff3..3266cbda98 100644
--- a/esphome/components/custom/output/__init__.py
+++ b/esphome/components/custom/output/__init__.py
@@ -8,22 +8,22 @@ CustomBinaryOutputConstructor = custom_ns.class_('CustomBinaryOutputConstructor'
CustomFloatOutputConstructor = custom_ns.class_('CustomFloatOutputConstructor')
BINARY_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomBinaryOutputConstructor),
+ cv.GenerateID(): cv.declare_id(CustomBinaryOutputConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
cv.Required(CONF_TYPE): 'binary',
cv.Required(CONF_OUTPUTS):
cv.ensure_list(output.BINARY_OUTPUT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(output.BinaryOutput),
+ cv.GenerateID(): cv.declare_id(output.BinaryOutput),
})),
})
FLOAT_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomFloatOutputConstructor),
+ cv.GenerateID(): cv.declare_id(CustomFloatOutputConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
cv.Required(CONF_TYPE): 'float',
cv.Required(CONF_OUTPUTS):
cv.ensure_list(output.FLOAT_OUTPUT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(output.FloatOutput),
+ cv.GenerateID(): cv.declare_id(output.FloatOutput),
})),
})
diff --git a/esphome/components/custom/sensor/__init__.py b/esphome/components/custom/sensor/__init__.py
index 7ed12c0eaa..6503cc0c69 100644
--- a/esphome/components/custom/sensor/__init__.py
+++ b/esphome/components/custom/sensor/__init__.py
@@ -1,17 +1,15 @@
-from esphome.components import sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import sensor
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_SENSORS
from .. import custom_ns
CustomSensorConstructor = custom_ns.class_('CustomSensorConstructor')
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomSensorConstructor),
+ cv.GenerateID(): cv.declare_id(CustomSensorConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
- cv.Required(CONF_SENSORS): cv.ensure_list(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(sensor.Sensor),
- })),
+ cv.Required(CONF_SENSORS): cv.ensure_list(sensor.SENSOR_SCHEMA),
})
diff --git a/esphome/components/custom/switch/__init__.py b/esphome/components/custom/switch/__init__.py
index 3a7c7499b2..b0da14b4f1 100644
--- a/esphome/components/custom/switch/__init__.py
+++ b/esphome/components/custom/switch/__init__.py
@@ -8,11 +8,11 @@ from .. import custom_ns
CustomSwitchConstructor = custom_ns.class_('CustomSwitchConstructor')
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomSwitchConstructor),
+ cv.GenerateID(): cv.declare_id(CustomSwitchConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
cv.Required(CONF_SWITCHES):
cv.ensure_list(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(switch.Switch),
+ cv.GenerateID(): cv.declare_id(switch.Switch),
})),
})
diff --git a/esphome/components/custom/text_sensor/__init__.py b/esphome/components/custom/text_sensor/__init__.py
index 601392facc..40b8be8d76 100644
--- a/esphome/components/custom/text_sensor/__init__.py
+++ b/esphome/components/custom/text_sensor/__init__.py
@@ -7,11 +7,11 @@ from .. import custom_ns
CustomTextSensorConstructor = custom_ns.class_('CustomTextSensorConstructor')
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomTextSensorConstructor),
+ cv.GenerateID(): cv.declare_id(CustomTextSensorConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
cv.Required(CONF_TEXT_SENSORS):
cv.ensure_list(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(text_sensor.TextSensor),
+ cv.GenerateID(): cv.declare_id(text_sensor.TextSensor),
})),
})
diff --git a/esphome/components/custom_component/__init__.py b/esphome/components/custom_component/__init__.py
index 0bc2eea2c3..0dcbb163c8 100644
--- a/esphome/components/custom_component/__init__.py
+++ b/esphome/components/custom_component/__init__.py
@@ -7,10 +7,10 @@ CustomComponentConstructor = custom_component_ns.class_('CustomComponentConstruc
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CustomComponentConstructor),
+ cv.GenerateID(): cv.declare_id(CustomComponentConstructor),
cv.Required(CONF_LAMBDA): cv.lambda_,
cv.Optional(CONF_COMPONENTS): cv.ensure_list(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(cg.Component)
+ cv.GenerateID(): cv.declare_id(cg.Component)
}).extend(cv.COMPONENT_SCHEMA)),
})
diff --git a/esphome/components/cwww/cwww_light_output.h b/esphome/components/cwww/cwww_light_output.h
index db042a9a00..4497d051e4 100644
--- a/esphome/components/cwww/cwww_light_output.h
+++ b/esphome/components/cwww/cwww_light_output.h
@@ -9,12 +9,10 @@ namespace cwww {
class CWWWLightOutput : public light::LightOutput {
public:
- CWWWLightOutput(output::FloatOutput *cold_white, output::FloatOutput *warm_white, float cold_white_temperature,
- float warm_white_temperature)
- : cold_white_(cold_white),
- warm_white_(warm_white),
- cold_white_temperature_(cold_white_temperature),
- warm_white_temperature_(warm_white_temperature) {}
+ void set_cold_white(output::FloatOutput *cold_white) { cold_white_ = cold_white; }
+ void set_warm_white(output::FloatOutput *warm_white) { warm_white_ = warm_white; }
+ void set_cold_white_temperature(float cold_white_temperature) { cold_white_temperature_ = cold_white_temperature; }
+ void set_warm_white_temperature(float warm_white_temperature) { warm_white_temperature_ = warm_white_temperature; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
diff --git a/esphome/components/cwww/light.py b/esphome/components/cwww/light.py
index 5c3a0e01f4..5d2b4ab2c9 100644
--- a/esphome/components/cwww/light.py
+++ b/esphome/components/cwww/light.py
@@ -7,19 +7,22 @@ from esphome.const import CONF_OUTPUT_ID, CONF_COLD_WHITE, CONF_WARM_WHITE, \
cwww_ns = cg.esphome_ns.namespace('cwww')
CWWWLightOutput = cwww_ns.class_('CWWWLightOutput', light.LightOutput)
-CONFIG_SCHEMA = cv.nameable(light.RGB_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(CWWWLightOutput),
- cv.Required(CONF_COLD_WHITE): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_WARM_WHITE): cv.use_variable_id(output.FloatOutput),
+CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(CWWWLightOutput),
+ cv.Required(CONF_COLD_WHITE): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_WARM_WHITE): cv.use_id(output.FloatOutput),
cv.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature,
cv.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature,
-}))
+})
def to_code(config):
- cwhite = yield cg.get_variable(config[CONF_COLD_WHITE])
- wwhite = yield cg.get_variable(config[CONF_WARM_WHITE])
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], cwhite, wwhite,
- config[CONF_COLD_WHITE_COLOR_TEMPERATURE],
- config[CONF_WARM_WHITE_COLOR_TEMPERATURE])
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield light.register_light(var, config)
+ cwhite = yield cg.get_variable(config[CONF_COLD_WHITE])
+ cg.add(var.set_cold_white(cwhite))
+ cg.add(var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]))
+
+ wwhite = yield cg.get_variable(config[CONF_WARM_WHITE])
+ cg.add(var.set_warm_white(wwhite))
+ cg.add(var.set_warm_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]))
diff --git a/esphome/components/dallas/__init__.py b/esphome/components/dallas/__init__.py
index e523e59a44..85ab4300ee 100644
--- a/esphome/components/dallas/__init__.py
+++ b/esphome/components/dallas/__init__.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
-from esphome.const import CONF_ID, CONF_PIN, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID, CONF_PIN
MULTI_CONF = True
AUTO_LOAD = ['sensor']
@@ -12,15 +12,14 @@ DallasComponent = dallas_ns.class_('DallasComponent', cg.PollingComponent)
ESPOneWire = dallas_ns.class_('ESPOneWire')
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DallasComponent),
- cv.GenerateID(CONF_ONE_WIRE_ID): cv.declare_variable_id(ESPOneWire),
+ cv.GenerateID(): cv.declare_id(DallasComponent),
+ cv.GenerateID(CONF_ONE_WIRE_ID): cv.declare_id(ESPOneWire),
cv.Required(CONF_PIN): pins.gpio_input_pin_schema,
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA)
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
pin = yield cg.gpio_pin_expression(config[CONF_PIN])
one_wire = cg.new_Pvariable(config[CONF_ONE_WIRE_ID], pin)
- var = cg.new_Pvariable(config[CONF_ID], one_wire, config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID], one_wire)
yield cg.register_component(var, config)
diff --git a/esphome/components/dallas/dallas_component.cpp b/esphome/components/dallas/dallas_component.cpp
index ce3a22e75b..1d3e693ff9 100644
--- a/esphome/components/dallas/dallas_component.cpp
+++ b/esphome/components/dallas/dallas_component.cpp
@@ -95,15 +95,13 @@ void DallasComponent::dump_config() {
}
}
-DallasTemperatureSensor *DallasComponent::get_sensor_by_address(const std::string &name, uint64_t address,
- uint8_t resolution) {
- auto s = new DallasTemperatureSensor(name, address, resolution, this);
+DallasTemperatureSensor *DallasComponent::get_sensor_by_address(uint64_t address, uint8_t resolution) {
+ auto s = new DallasTemperatureSensor(address, resolution, this);
this->sensors_.push_back(s);
return s;
}
-DallasTemperatureSensor *DallasComponent::get_sensor_by_index(const std::string &name, uint8_t index,
- uint8_t resolution) {
- auto s = this->get_sensor_by_address(name, 0, resolution);
+DallasTemperatureSensor *DallasComponent::get_sensor_by_index(uint8_t index, uint8_t resolution) {
+ auto s = this->get_sensor_by_address(0, resolution);
s->set_index(index);
return s;
}
@@ -148,12 +146,10 @@ void DallasComponent::update() {
});
}
}
-DallasComponent::DallasComponent(ESPOneWire *one_wire, uint32_t update_interval)
- : PollingComponent(update_interval), one_wire_(one_wire) {}
+DallasComponent::DallasComponent(ESPOneWire *one_wire) : one_wire_(one_wire) {}
-DallasTemperatureSensor::DallasTemperatureSensor(const std::string &name, uint64_t address, uint8_t resolution,
- DallasComponent *parent)
- : sensor::Sensor(name), parent_(parent) {
+DallasTemperatureSensor::DallasTemperatureSensor(uint64_t address, uint8_t resolution, DallasComponent *parent)
+ : parent_(parent) {
this->set_address(address);
this->set_resolution(resolution);
}
diff --git a/esphome/components/dallas/dallas_component.h b/esphome/components/dallas/dallas_component.h
index db7cb1159c..d32aec1758 100644
--- a/esphome/components/dallas/dallas_component.h
+++ b/esphome/components/dallas/dallas_component.h
@@ -11,10 +11,10 @@ class DallasTemperatureSensor;
class DallasComponent : public PollingComponent {
public:
- explicit DallasComponent(ESPOneWire *one_wire, uint32_t update_interval);
+ explicit DallasComponent(ESPOneWire *one_wire);
- DallasTemperatureSensor *get_sensor_by_address(const std::string &name, uint64_t address, uint8_t resolution);
- DallasTemperatureSensor *get_sensor_by_index(const std::string &name, uint8_t index, uint8_t resolution);
+ DallasTemperatureSensor *get_sensor_by_address(uint64_t address, uint8_t resolution);
+ DallasTemperatureSensor *get_sensor_by_index(uint8_t index, uint8_t resolution);
void setup() override;
void dump_config() override;
@@ -33,7 +33,7 @@ class DallasComponent : public PollingComponent {
/// Internal class that helps us create multiple sensors for one Dallas hub.
class DallasTemperatureSensor : public sensor::Sensor {
public:
- DallasTemperatureSensor(const std::string &name, uint64_t address, uint8_t resolution, DallasComponent *parent);
+ DallasTemperatureSensor(uint64_t address, uint8_t resolution, DallasComponent *parent);
/// Helper to get a pointer to the address as uint8_t.
uint8_t *get_address8();
diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py
index 1f25698c18..2236f919f2 100644
--- a/esphome/components/dallas/sensor.py
+++ b/esphome/components/dallas/sensor.py
@@ -1,24 +1,19 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
-from esphome.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \
- CONF_RESOLUTION, CONF_UNIT_OF_MEASUREMENT, UNIT_CELSIUS, CONF_ICON, ICON_THERMOMETER, \
- CONF_ACCURACY_DECIMALS, CONF_ID
+from esphome.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_RESOLUTION, UNIT_CELSIUS, \
+ ICON_THERMOMETER, CONF_ID
from . import DallasComponent, dallas_ns
DallasTemperatureSensor = dallas_ns.class_('DallasTemperatureSensor', sensor.Sensor)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(DallasTemperatureSensor),
- cv.GenerateID(CONF_DALLAS_ID): cv.use_variable_id(DallasComponent),
+CONFIG_SCHEMA = cv.All(sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
+ cv.GenerateID(): cv.declare_id(DallasTemperatureSensor),
+ cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent),
cv.Optional(CONF_ADDRESS): cv.hex_int,
cv.Optional(CONF_INDEX): cv.positive_int,
cv.Optional(CONF_RESOLUTION, default=12): cv.All(cv.int_, cv.Range(min=9, max=12)),
-
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_CELSIUS): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_THERMOMETER): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=1): sensor.accuracy_decimals,
}), cv.has_exactly_one_key(CONF_ADDRESS, CONF_INDEX))
@@ -26,9 +21,8 @@ def to_code(config):
hub = yield cg.get_variable(config[CONF_DALLAS_ID])
if CONF_ADDRESS in config:
address = config[CONF_ADDRESS]
- rhs = hub.Pget_sensor_by_address(config[CONF_NAME], address, config.get(CONF_RESOLUTION))
+ rhs = hub.Pget_sensor_by_address(address, config.get(CONF_RESOLUTION))
else:
- rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX],
- config.get(CONF_RESOLUTION))
+ rhs = hub.Pget_sensor_by_index(config[CONF_INDEX], config.get(CONF_RESOLUTION))
var = cg.Pvariable(config[CONF_ID], rhs)
yield sensor.register_sensor(var, config)
diff --git a/esphome/components/debug/__init__.py b/esphome/components/debug/__init__.py
index 681317f263..a40dadb5c2 100644
--- a/esphome/components/debug/__init__.py
+++ b/esphome/components/debug/__init__.py
@@ -7,11 +7,10 @@ DEPENDENCIES = ['logger']
debug_ns = cg.esphome_ns.namespace('debug')
DebugComponent = debug_ns.class_('DebugComponent', cg.Component)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DebugComponent),
+ cv.GenerateID(): cv.declare_id(DebugComponent),
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- rhs = DebugComponent.new()
- var = cg.Pvariable(config[CONF_ID], rhs)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py
index b5f42528b4..93ef04d195 100644
--- a/esphome/components/deep_sleep/__init__.py
+++ b/esphome/components/deep_sleep/__init__.py
@@ -1,7 +1,7 @@
-from esphome import pins
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
+import esphome.config_validation as cv
+from esphome import pins, automation
+from esphome.automation import maybe_simple_id
from esphome.const import CONF_ID, CONF_MODE, CONF_NUMBER, CONF_PINS, CONF_RUN_CYCLES, \
CONF_RUN_DURATION, CONF_SLEEP_DURATION, CONF_WAKEUP_PIN
@@ -16,8 +16,8 @@ def validate_pin_number(value):
deep_sleep_ns = cg.esphome_ns.namespace('deep_sleep')
DeepSleepComponent = deep_sleep_ns.class_('DeepSleepComponent', cg.Component)
-EnterDeepSleepAction = deep_sleep_ns.class_('EnterDeepSleepAction', cg.Action)
-PreventDeepSleepAction = deep_sleep_ns.class_('PreventDeepSleepAction', cg.Action)
+EnterDeepSleepAction = deep_sleep_ns.class_('EnterDeepSleepAction', automation.Action)
+PreventDeepSleepAction = deep_sleep_ns.class_('PreventDeepSleepAction', automation.Action)
WakeupPinMode = deep_sleep_ns.enum('WakeupPinMode')
WAKEUP_PIN_MODES = {
@@ -37,17 +37,17 @@ CONF_WAKEUP_PIN_MODE = 'wakeup_pin_mode'
CONF_ESP32_EXT1_WAKEUP = 'esp32_ext1_wakeup'
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DeepSleepComponent),
+ cv.GenerateID(): cv.declare_id(DeepSleepComponent),
cv.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_WAKEUP_PIN): cv.All(cv.only_on_esp32, pins.internal_gpio_input_pin_schema,
validate_pin_number),
cv.Optional(CONF_WAKEUP_PIN_MODE): cv.All(cv.only_on_esp32,
- cv.one_of(*WAKEUP_PIN_MODES), upper=True),
+ cv.enum(WAKEUP_PIN_MODES), upper=True),
cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All(cv.only_on_esp32, cv.Schema({
cv.Required(CONF_PINS): cv.ensure_list(pins.shorthand_input_pin, validate_pin_number),
- cv.Required(CONF_MODE): cv.one_of(*EXT1_WAKEUP_MODES, upper=True),
+ cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True),
})),
cv.Optional(CONF_RUN_CYCLES): cv.invalid("The run_cycles option has been removed in 1.11.0 as "
@@ -66,7 +66,7 @@ def to_code(config):
pin = yield cg.gpio_pin_expression(config[CONF_WAKEUP_PIN])
cg.add(var.set_wakeup_pin(pin))
if CONF_WAKEUP_PIN_MODE in config:
- cg.add(var.set_wakeup_pin_mode(WAKEUP_PIN_MODES[config[CONF_WAKEUP_PIN_MODE]]))
+ cg.add(var.set_wakeup_pin_mode(config[CONF_WAKEUP_PIN_MODE]))
if CONF_RUN_DURATION in config:
cg.add(var.set_run_duration(config[CONF_RUN_DURATION]))
@@ -78,7 +78,7 @@ def to_code(config):
struct = cg.StructInitializer(
Ext1Wakeup,
('mask', mask),
- ('wakeup_mode', EXT1_WAKEUP_MODES[conf[CONF_MODE]])
+ ('wakeup_mode', conf[CONF_MODE])
)
cg.add(var.set_ext1_wakeup(struct))
@@ -86,21 +86,17 @@ def to_code(config):
DEEP_SLEEP_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(DeepSleepComponent),
+ cv.GenerateID(): cv.use_id(DeepSleepComponent),
})
-@ACTION_REGISTRY.register('deep_sleep.enter', DEEP_SLEEP_ACTION_SCHEMA)
+@automation.register_action('deep_sleep.enter', EnterDeepSleepAction, DEEP_SLEEP_ACTION_SCHEMA)
def deep_sleep_enter_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = EnterDeepSleepAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('deep_sleep.prevent', DEEP_SLEEP_ACTION_SCHEMA)
+@automation.register_action('deep_sleep.prevent', PreventDeepSleepAction, DEEP_SLEEP_ACTION_SCHEMA)
def deep_sleep_prevent_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = PreventDeepSleepAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
diff --git a/esphome/components/deep_sleep/deep_sleep_component.h b/esphome/components/deep_sleep/deep_sleep_component.h
index d1af7a814b..4372a3f66c 100644
--- a/esphome/components/deep_sleep/deep_sleep_component.h
+++ b/esphome/components/deep_sleep/deep_sleep_component.h
@@ -85,10 +85,7 @@ template class EnterDeepSleepAction : public Action {
public:
EnterDeepSleepAction(DeepSleepComponent *deep_sleep) : deep_sleep_(deep_sleep) {}
- void play(Ts... x) override {
- this->deep_sleep_->begin_sleep(true);
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->deep_sleep_->begin_sleep(true); }
protected:
DeepSleepComponent *deep_sleep_;
@@ -98,10 +95,7 @@ template class PreventDeepSleepAction : public Action {
public:
PreventDeepSleepAction(DeepSleepComponent *deep_sleep) : deep_sleep_(deep_sleep) {}
- void play(Ts... x) override {
- this->deep_sleep_->prevent_deep_sleep();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->deep_sleep_->prevent_deep_sleep(); }
protected:
DeepSleepComponent *deep_sleep_;
diff --git a/esphome/components/dht/dht.cpp b/esphome/components/dht/dht.cpp
index 03c3ddba08..79732bb269 100644
--- a/esphome/components/dht/dht.cpp
+++ b/esphome/components/dht/dht.cpp
@@ -7,12 +7,6 @@ namespace dht {
static const char *TAG = "dht";
-DHT::DHT(const std::string &temperature_name, const std::string &humidity_name, GPIOPin *pin, uint32_t update_interval)
- : PollingComponent(update_interval),
- pin_(pin),
- temperature_sensor_(new sensor::Sensor(temperature_name)),
- humidity_sensor_(new sensor::Sensor(humidity_name)) {}
-
void DHT::setup() {
ESP_LOGCONFIG(TAG, "Setting up DHT...");
this->pin_->digital_write(true);
@@ -71,8 +65,6 @@ void DHT::set_dht_model(DHTModel model) {
this->model_ = model;
this->is_auto_detect_ = model == DHT_MODEL_AUTO_DETECT;
}
-sensor::Sensor *DHT::get_temperature_sensor() const { return this->temperature_sensor_; }
-sensor::Sensor *DHT::get_humidity_sensor() const { return this->humidity_sensor_; }
bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) {
*humidity = NAN;
*temperature = NAN;
diff --git a/esphome/components/dht/dht.h b/esphome/components/dht/dht.h
index 5e3b35988b..4ed5d4e022 100644
--- a/esphome/components/dht/dht.h
+++ b/esphome/components/dht/dht.h
@@ -18,13 +18,6 @@ enum DHTModel {
/// Component for reading temperature/humidity measurements from DHT11/DHT22 sensors.
class DHT : public PollingComponent {
public:
- /** Construct a DHTComponent.
- *
- * @param pin The pin which DHT sensor is connected to.
- * @param update_interval The interval in ms the sensor should be checked.
- */
- DHT(const std::string &temperature_name, const std::string &humidity_name, GPIOPin *pin, uint32_t update_interval);
-
/** Manually select the DHT model.
*
* Valid values are:
@@ -40,10 +33,10 @@ class DHT : public PollingComponent {
*/
void set_dht_model(DHTModel model);
- // ========== INTERNAL METHODS ==========
- // (In most use cases you won't need these)
- sensor::Sensor *get_temperature_sensor() const;
- sensor::Sensor *get_humidity_sensor() const;
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
+ void set_model(DHTModel model) { model_ = model; }
+ void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
+ void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
/// Set up the pins and check connection.
void setup() override;
@@ -59,8 +52,8 @@ class DHT : public PollingComponent {
GPIOPin *pin_;
DHTModel model_{DHT_MODEL_AUTO_DETECT};
bool is_auto_detect_{false};
- sensor::Sensor *temperature_sensor_;
- sensor::Sensor *humidity_sensor_;
+ sensor::Sensor *temperature_sensor_{nullptr};
+ sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace dht
diff --git a/esphome/components/dht/sensor.py b/esphome/components/dht/sensor.py
index 4975c7a052..e1e18bb7f9 100644
--- a/esphome/components/dht/sensor.py
+++ b/esphome/components/dht/sensor.py
@@ -1,11 +1,10 @@
-from esphome.components import sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_MODEL, CONF_NAME, \
- CONF_PIN, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, CONF_ACCURACY_DECIMALS, CONF_ICON, \
- ICON_THERMOMETER, CONF_UNIT_OF_MEASUREMENT, UNIT_CELSIUS, ICON_WATER_PERCENT, UNIT_PERCENT
+import esphome.config_validation as cv
+from esphome import pins
+from esphome.components import sensor
+from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_MODEL, CONF_PIN, CONF_TEMPERATURE, \
+ CONF_UPDATE_INTERVAL, ICON_THERMOMETER, UNIT_CELSIUS, ICON_WATER_PERCENT, UNIT_PERCENT
from esphome.cpp_helpers import gpio_pin_expression
-from esphome.pins import gpio_input_pullup_pin_schema
dht_ns = cg.esphome_ns.namespace('dht')
DHTModel = dht_ns.enum('DHTModel')
@@ -20,31 +19,27 @@ DHT_MODELS = {
DHT = dht_ns.class_('DHT', cg.PollingComponent)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DHT),
- cv.Required(CONF_PIN): gpio_input_pullup_pin_schema,
- cv.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_ACCURACY_DECIMALS, default=1): sensor.accuracy_decimals,
- cv.Optional(CONF_ICON, default=ICON_THERMOMETER): sensor.icon,
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_CELSIUS): sensor.unit_of_measurement,
- })),
- cv.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals,
- cv.Optional(CONF_ICON, default=ICON_WATER_PERCENT): sensor.icon,
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): sensor.unit_of_measurement,
- })),
- cv.Optional(CONF_MODEL, default='auto detect'): cv.one_of(*DHT_MODELS, upper=True, space='_'),
+ cv.GenerateID(): cv.declare_id(DHT),
+ cv.Required(CONF_PIN): pins.gpio_input_pin_schema,
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 0),
+ cv.Optional(CONF_MODEL, default='auto detect'): cv.enum(DHT_MODELS, upper=True, space='_'),
cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA)
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- pin = yield gpio_pin_expression(config[CONF_PIN])
- rhs = DHT.new(config[CONF_TEMPERATURE][CONF_NAME],
- config[CONF_HUMIDITY][CONF_NAME],
- pin, config[CONF_UPDATE_INTERVAL])
- dht = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(dht, config)
- yield sensor.register_sensor(dht.Pget_temperature_sensor(), config[CONF_TEMPERATURE])
- yield sensor.register_sensor(dht.Pget_humidity_sensor(), config[CONF_HUMIDITY])
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
- cg.add(dht.set_dht_model(DHT_MODELS[config[CONF_MODEL]]))
+ pin = yield gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
+
+ if CONF_TEMPERATURE in config:
+ sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
+ cg.add(var.set_temperature_sensor(sens))
+ if CONF_HUMIDITY in config:
+ sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
+ cg.add(var.set_humidity_sensor(sens))
+
+ cg.add(var.set_dht_model(config[CONF_MODEL]))
diff --git a/esphome/components/dht12/dht12.h b/esphome/components/dht12/dht12.h
index 1974c0ba8c..ae4d4fd607 100644
--- a/esphome/components/dht12/dht12.h
+++ b/esphome/components/dht12/dht12.h
@@ -9,8 +9,6 @@ namespace dht12 {
class DHT12Component : public PollingComponent, public i2c::I2CDevice {
public:
- DHT12Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/dht12/sensor.py b/esphome/components/dht12/sensor.py
index 932f6ffa68..7d86e8c836 100644
--- a/esphome/components/dht12/sensor.py
+++ b/esphome/components/dht12/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, \
- CONF_UPDATE_INTERVAL, UNIT_CELSIUS, ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_PERCENT
+ UNIT_CELSIUS, ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_PERCENT
DEPENDENCIES = ['i2c']
@@ -10,17 +10,14 @@ dht12_ns = cg.esphome_ns.namespace('dht12')
DHT12Component = dht12_ns.class_('DHT12Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DHT12Component),
- cv.Optional(CONF_TEMPERATURE):
- cv.nameable(sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
- cv.Optional(CONF_HUMIDITY):
- cv.nameable(sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x5C))
+ cv.GenerateID(): cv.declare_id(DHT12Component),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x5C))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/display/__init__.py b/esphome/components/display/__init__.py
index 2592a3a480..5c204fc7a4 100644
--- a/esphome/components/display/__init__.py
+++ b/esphome/components/display/__init__.py
@@ -1,10 +1,10 @@
# coding=utf-8
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome import core
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
+from esphome import core, automation
+from esphome.automation import maybe_simple_id
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES, CONF_ROTATION, CONF_UPDATE_INTERVAL
-from esphome.core import coroutine
+from esphome.core import coroutine, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -13,9 +13,9 @@ DisplayBuffer = display_ns.class_('DisplayBuffer')
DisplayPage = display_ns.class_('DisplayPage')
DisplayPagePtr = DisplayPage.operator('ptr')
DisplayBufferRef = DisplayBuffer.operator('ref')
-DisplayPageShowAction = display_ns.class_('DisplayPageShowAction', cg.Action)
-DisplayPageShowNextAction = display_ns.class_('DisplayPageShowNextAction', cg.Action)
-DisplayPageShowPrevAction = display_ns.class_('DisplayPageShowPrevAction', cg.Action)
+DisplayPageShowAction = display_ns.class_('DisplayPageShowAction', automation.Action)
+DisplayPageShowNextAction = display_ns.class_('DisplayPageShowNextAction', automation.Action)
+DisplayPageShowPrevAction = display_ns.class_('DisplayPageShowPrevAction', automation.Action)
DISPLAY_ROTATIONS = {
0: display_ns.DISPLAY_ROTATION_0_DEGREES,
@@ -29,11 +29,7 @@ def validate_rotation(value):
value = cv.string(value)
if value.endswith(u"°"):
value = value[:-1]
- try:
- value = int(value)
- except ValueError:
- raise cv.Invalid(u"Expected integer for rotation")
- return cv.one_of(*DISPLAY_ROTATIONS)(value)
+ return cv.enum(DISPLAY_ROTATIONS, int=True)(value)
BASIC_DISPLAY_SCHEMA = cv.Schema({
@@ -44,7 +40,7 @@ BASIC_DISPLAY_SCHEMA = cv.Schema({
FULL_DISPLAY_SCHEMA = BASIC_DISPLAY_SCHEMA.extend({
cv.Optional(CONF_ROTATION): validate_rotation,
cv.Optional(CONF_PAGES): cv.All(cv.ensure_list({
- cv.GenerateID(): cv.declare_variable_id(DisplayPage),
+ cv.GenerateID(): cv.declare_id(DisplayPage),
cv.Required(CONF_LAMBDA): cv.lambda_,
}), cv.Length(min=1)),
})
@@ -71,38 +67,37 @@ def register_display(var, config):
yield setup_display_core_(var, config)
-@ACTION_REGISTRY.register('display.page.show', maybe_simple_id({
- cv.Required(CONF_ID): cv.templatable(cv.use_variable_id(DisplayPage)),
+@automation.register_action('display.page.show', DisplayPageShowAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.templatable(cv.use_id(DisplayPage)),
}))
def display_page_show_to_code(config, action_id, template_arg, args):
- type = DisplayPageShowAction.template(template_arg)
- action = cg.Pvariable(action_id, type.new(), type=type)
+ var = cg.new_Pvariable(action_id, template_arg)
if isinstance(config[CONF_ID], core.Lambda):
template_ = yield cg.templatable(config[CONF_ID], args, DisplayPagePtr)
- cg.add(action.set_page(template_))
+ cg.add(var.set_page(template_))
else:
- var = yield cg.get_variable(config[CONF_ID])
- cg.add(action.set_page(var))
- yield action
+ paren = yield cg.get_variable(config[CONF_ID])
+ cg.add(var.set_page(paren))
+ yield var
-@ACTION_REGISTRY.register('display.page.show_next', maybe_simple_id({
- cv.Required(CONF_ID): cv.templatable(cv.use_variable_id(DisplayBuffer)),
+@automation.register_action('display.page.show_next', DisplayPageShowNextAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.templatable(cv.use_id(DisplayBuffer)),
}))
def display_page_show_next_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = DisplayPageShowNextAction.template(template_arg)
- yield cg.Pvariable(action_id, type.new(var), type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('display.page.show_previous', maybe_simple_id({
- cv.Required(CONF_ID): cv.templatable(cv.use_variable_id(DisplayBuffer)),
-}))
+@automation.register_action('display.page.show_previous', DisplayPageShowPrevAction,
+ maybe_simple_id({
+ cv.Required(CONF_ID): cv.templatable(cv.use_id(DisplayBuffer)),
+ }))
def display_page_show_previous_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = DisplayPageShowPrevAction.template(template_arg)
- yield cg.Pvariable(action_id, type.new(var), type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_global(display_ns.using)
diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h
index 90dfba43e3..57b95eee29 100644
--- a/esphome/components/display/display_buffer.h
+++ b/esphome/components/display/display_buffer.h
@@ -396,17 +396,13 @@ template class DisplayPageShowAction : public Action {
if (page != nullptr) {
page->show();
}
- this->play_next(x...);
}
};
template class DisplayPageShowNextAction : public Action {
public:
DisplayPageShowNextAction(DisplayBuffer *buffer) : buffer_(buffer) {}
- void play(Ts... x) override {
- this->buffer_->show_next_page();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->buffer_->show_next_page(); }
protected:
DisplayBuffer *buffer_;
@@ -415,10 +411,7 @@ template class DisplayPageShowNextAction : public Action
template class DisplayPageShowPrevAction : public Action {
public:
DisplayPageShowPrevAction(DisplayBuffer *buffer) : buffer_(buffer) {}
- void play(Ts... x) override {
- this->buffer_->show_prev_page();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->buffer_->show_prev_page(); }
protected:
DisplayBuffer *buffer_;
diff --git a/esphome/components/duty_cycle/duty_cycle_sensor.h b/esphome/components/duty_cycle/duty_cycle_sensor.h
index 3657f97c3a..2205bec729 100644
--- a/esphome/components/duty_cycle/duty_cycle_sensor.h
+++ b/esphome/components/duty_cycle/duty_cycle_sensor.h
@@ -17,10 +17,9 @@ struct DutyCycleSensorStore {
static void gpio_intr(DutyCycleSensorStore *arg);
};
-class DutyCycleSensor : public sensor::PollingSensorComponent {
+class DutyCycleSensor : public sensor::Sensor, public PollingComponent {
public:
- DutyCycleSensor(const std::string &name, uint32_t update_interval, GPIOPin *pin)
- : PollingSensorComponent(name, update_interval), pin_(pin) {}
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
void setup() override;
float get_setup_priority() const override;
diff --git a/esphome/components/duty_cycle/sensor.py b/esphome/components/duty_cycle/sensor.py
index 30adf66930..d60ff0d8be 100644
--- a/esphome/components/duty_cycle/sensor.py
+++ b/esphome/components/duty_cycle/sensor.py
@@ -1,23 +1,23 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-import esphome.config_validation as cv
-import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_NAME, CONF_PIN, CONF_UPDATE_INTERVAL, UNIT_PERCENT, \
- ICON_PERCENT
+from esphome.const import CONF_ID, CONF_PIN, UNIT_PERCENT, ICON_PERCENT
duty_cycle_ns = cg.esphome_ns.namespace('duty_cycle')
DutyCycleSensor = duty_cycle_ns.class_('DutyCycleSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.sensor_schema(UNIT_PERCENT, ICON_PERCENT, 1).extend({
- cv.GenerateID(): cv.declare_variable_id(DutyCycleSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_PERCENT, ICON_PERCENT, 1).extend({
+ cv.GenerateID(): cv.declare_id(DutyCycleSensor),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- pin = yield cg.gpio_pin_expression(config[CONF_PIN])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL], pin)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
+
+ pin = yield cg.gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
diff --git a/esphome/components/endstop/cover.py b/esphome/components/endstop/cover.py
index d597110041..0d65cc1078 100644
--- a/esphome/components/endstop/cover.py
+++ b/esphome/components/endstop/cover.py
@@ -1,32 +1,32 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import automation
from esphome.components import binary_sensor, cover
-import esphome.config_validation as cv
-import esphome.codegen as cg
from esphome.const import CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, \
- CONF_CLOSE_ENDSTOP, CONF_ID, CONF_NAME, CONF_OPEN_ACTION, CONF_OPEN_DURATION, \
+ CONF_CLOSE_ENDSTOP, CONF_ID, CONF_OPEN_ACTION, CONF_OPEN_DURATION, \
CONF_OPEN_ENDSTOP, CONF_STOP_ACTION, CONF_MAX_DURATION
endstop_ns = cg.esphome_ns.namespace('endstop')
EndstopCover = endstop_ns.class_('EndstopCover', cover.Cover, cg.Component)
-CONFIG_SCHEMA = cv.nameable(cover.COVER_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(EndstopCover),
+CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(EndstopCover),
cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True),
- cv.Required(CONF_OPEN_ENDSTOP): cv.use_variable_id(binary_sensor.BinarySensor),
+ cv.Required(CONF_OPEN_ENDSTOP): cv.use_id(binary_sensor.BinarySensor),
cv.Required(CONF_OPEN_ACTION): automation.validate_automation(single=True),
cv.Required(CONF_OPEN_DURATION): cv.positive_time_period_milliseconds,
cv.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
- cv.Required(CONF_CLOSE_ENDSTOP): cv.use_variable_id(binary_sensor.BinarySensor),
+ cv.Required(CONF_CLOSE_ENDSTOP): cv.use_id(binary_sensor.BinarySensor),
cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_MAX_DURATION): cv.positive_time_period_milliseconds,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield cover.register_cover(var, config)
diff --git a/esphome/components/endstop/endstop_cover.h b/esphome/components/endstop/endstop_cover.h
index c75ff9d4c8..f8d2746234 100644
--- a/esphome/components/endstop/endstop_cover.h
+++ b/esphome/components/endstop/endstop_cover.h
@@ -10,8 +10,6 @@ namespace endstop {
class EndstopCover : public cover::Cover, public Component {
public:
- EndstopCover(const std::string &name) : cover::Cover(name) {}
-
void setup() override;
void loop() override;
void dump_config() override;
diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py
index 310b7c22b8..2f02e71fef 100644
--- a/esphome/components/esp32_ble_beacon/__init__.py
+++ b/esphome/components/esp32_ble_beacon/__init__.py
@@ -12,7 +12,7 @@ CONF_MAJOR = 'major'
CONF_MINOR = 'minor'
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(ESP32BLEBeacon),
+ cv.GenerateID(): cv.declare_id(ESP32BLEBeacon),
cv.Required(CONF_TYPE): cv.one_of('IBEACON', upper=True),
cv.Required(CONF_UUID): cv.uuid,
cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t,
diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py
index 193a250822..c77e5cd440 100644
--- a/esphome/components/esp32_ble_tracker/__init__.py
+++ b/esphome/components/esp32_ble_tracker/__init__.py
@@ -11,12 +11,12 @@ ESP32BLETracker = esp32_ble_tracker_ns.class_('ESP32BLETracker', cg.Component)
ESPBTDeviceListener = esp32_ble_tracker_ns.class_('ESPBTDeviceListener')
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(ESP32BLETracker),
+ cv.GenerateID(): cv.declare_id(ESP32BLETracker),
cv.Optional(CONF_SCAN_INTERVAL, default='300s'): cv.positive_time_period_seconds,
}).extend(cv.COMPONENT_SCHEMA)
ESP_BLE_DEVICE_SCHEMA = cv.Schema({
- cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_variable_id(ESP32BLETracker),
+ cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_id(ESP32BLETracker),
})
diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py
index 9708b11c3d..4e7901571f 100644
--- a/esphome/components/esp32_camera/__init__.py
+++ b/esphome/components/esp32_camera/__init__.py
@@ -58,7 +58,7 @@ CONF_TEST_PATTERN = 'test_pattern'
camera_range_param = cv.All(cv.int_, cv.Range(min=-2, max=2))
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(ESP32Camera),
+ cv.GenerateID(): cv.declare_id(ESP32Camera),
cv.Required(CONF_NAME): cv.string,
cv.Required(CONF_DATA_PINS): cv.All([pins.input_pin], cv.Length(min=8, max=8)),
cv.Required(CONF_VSYNC_PIN): pins.input_pin,
@@ -80,7 +80,7 @@ CONFIG_SCHEMA = cv.Schema({
max=60)),
cv.Optional(CONF_IDLE_FRAMERATE, default='0.1 fps'): cv.All(cv.framerate,
cv.Range(min=0, max=1)),
- cv.Optional(CONF_RESOLUTION, default='640X480'): cv.one_of(*FRAME_SIZES, upper=True),
+ cv.Optional(CONF_RESOLUTION, default='640X480'): cv.enum(FRAME_SIZES, upper=True),
cv.Optional(CONF_JPEG_QUALITY, default=10): cv.All(cv.int_, cv.Range(min=10, max=63)),
cv.Optional(CONF_CONTRAST, default=0): camera_range_param,
cv.Optional(CONF_BRIGHTNESS, default=0): camera_range_param,
@@ -124,7 +124,7 @@ def to_code(config):
cg.add(var.set_idle_update_interval(0))
else:
cg.add(var.set_idle_update_interval(1000 / config[CONF_IDLE_FRAMERATE]))
- cg.add(var.set_frame_size(FRAME_SIZES[config[CONF_RESOLUTION]]))
+ cg.add(var.set_frame_size(config[CONF_RESOLUTION]))
cg.add_define('USE_ESP32_CAMERA')
cg.add_build_flag('-DBOARD_HAS_PSRAM')
diff --git a/esphome/components/esp32_hall/sensor.py b/esphome/components/esp32_hall/sensor.py
index 62badf3bd0..81a90c8c10 100644
--- a/esphome/components/esp32_hall/sensor.py
+++ b/esphome/components/esp32_hall/sensor.py
@@ -1,22 +1,18 @@
-from esphome.components import sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import sensor
from esphome.const import CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, ESP_PLATFORM_ESP32, \
- CONF_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_ACCURACY_DECIMALS, UNIT_MICROTESLA, ICON_MAGNET
+ UNIT_MICROTESLA, ICON_MAGNET
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
esp32_hall_ns = cg.esphome_ns.namespace('esp32_hall')
ESP32HallSensor = esp32_hall_ns.class_('ESP32HallSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(ESP32HallSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_MICROTESLA, ICON_MAGNET, 1).extend({
+ cv.GenerateID(): cv.declare_id(ESP32HallSensor),
cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_MICROTESLA): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_MAGNET): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=-1): sensor.accuracy_decimals,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py
index bc2698a020..3bdc988fcc 100644
--- a/esphome/components/esp32_touch/__init__.py
+++ b/esphome/components/esp32_touch/__init__.py
@@ -44,7 +44,7 @@ VOLTAGE_ATTENUATION = {
}
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(ESP32TouchComponent),
+ cv.GenerateID(): cv.declare_id(ESP32TouchComponent),
cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean,
cv.Optional(CONF_IIR_FILTER, default='0ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SLEEP_DURATION, default='27306us'):
diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py
index 27b93a1df2..94748e53e8 100644
--- a/esphome/components/esp32_touch/binary_sensor.py
+++ b/esphome/components/esp32_touch/binary_sensor.py
@@ -34,12 +34,12 @@ def validate_touch_pad(value):
ESP32TouchBinarySensor = esp32_touch_ns.class_('ESP32TouchBinarySensor', binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(ESP32TouchBinarySensor),
- cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_variable_id(ESP32TouchComponent),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(ESP32TouchBinarySensor),
+ cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_id(ESP32TouchComponent),
cv.Required(CONF_PIN): validate_touch_pad,
cv.Required(CONF_THRESHOLD): cv.uint16_t,
-}))
+})
def to_code(config):
diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.cpp b/esphome/components/esp8266_pwm/esp8266_pwm.cpp
index e76e161708..363f4d24bc 100644
--- a/esphome/components/esp8266_pwm/esp8266_pwm.cpp
+++ b/esphome/components/esp8266_pwm/esp8266_pwm.cpp
@@ -25,6 +25,8 @@ void ESP8266PWM::dump_config() {
LOG_FLOAT_OUTPUT(this);
}
void HOT ESP8266PWM::write_state(float state) {
+ this->last_output_ = state;
+
// Also check pin inversion
if (this->pin_->is_inverted()) {
state = 1.0f - state;
diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.h b/esphome/components/esp8266_pwm/esp8266_pwm.h
index 4ea611952c..b6839985b0 100644
--- a/esphome/components/esp8266_pwm/esp8266_pwm.h
+++ b/esphome/components/esp8266_pwm/esp8266_pwm.h
@@ -2,6 +2,7 @@
#include "esphome/core/component.h"
#include "esphome/core/esphal.h"
+#include "esphome/core/automation.h"
#include "esphome/components/output/float_output.h"
namespace esphome {
@@ -9,9 +10,13 @@ namespace esp8266_pwm {
class ESP8266PWM : public output::FloatOutput, public Component {
public:
- explicit ESP8266PWM(GPIOPin *pin) : pin_(pin) {}
-
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
void set_frequency(float frequency) { this->frequency_ = frequency; }
+ /// Dynamically update frequency
+ void update_frequency(float frequency) {
+ this->set_frequency(frequency);
+ this->write_state(this->last_output_);
+ }
/// Initialize pin
void setup() override;
@@ -24,6 +29,22 @@ class ESP8266PWM : public output::FloatOutput, public Component {
GPIOPin *pin_;
float frequency_{1000.0};
+ /// Cache last output level for dynamic frequency updating
+ float last_output_{0.0};
+};
+
+template class SetFrequencyAction : public Action {
+ public:
+ SetFrequencyAction(ESP8266PWM *parent) : parent_(parent) {}
+ TEMPLATABLE_VALUE(float, frequency);
+
+ void play(Ts... x) {
+ float freq = this->frequency_.value(x...);
+ this->parent_->update_frequency(freq);
+ }
+
+ protected:
+ ESP8266PWM *parent_;
};
} // namespace esp8266_pwm
diff --git a/esphome/components/esp8266_pwm/output.py b/esphome/components/esp8266_pwm/output.py
index bbabf33980..e973490525 100644
--- a/esphome/components/esp8266_pwm/output.py
+++ b/esphome/components/esp8266_pwm/output.py
@@ -1,4 +1,4 @@
-from esphome import pins
+from esphome import pins, automation
from esphome.components import output
import esphome.config_validation as cv
import esphome.codegen as cg
@@ -15,18 +15,34 @@ def valid_pwm_pin(value):
esp8266_pwm_ns = cg.esphome_ns.namespace('esp8266_pwm')
ESP8266PWM = esp8266_pwm_ns.class_('ESP8266PWM', output.FloatOutput, cg.Component)
+SetFrequencyAction = esp8266_pwm_ns.class_('SetFrequencyAction', automation.Action)
+validate_frequency = cv.All(cv.frequency, cv.Range(min=1.0e-6))
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend({
- cv.Required(CONF_ID): cv.declare_variable_id(ESP8266PWM),
+ cv.Required(CONF_ID): cv.declare_id(ESP8266PWM),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_output_pin_schema, valid_pwm_pin),
- cv.Optional(CONF_FREQUENCY, default='1kHz'): cv.All(cv.frequency, cv.Range(min=1.0e-6)),
+ cv.Optional(CONF_FREQUENCY, default='1kHz'): validate_frequency,
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- pin = yield cg.gpio_pin_expression(config[CONF_PIN])
- var = cg.new_Pvariable(config[CONF_ID], pin)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield output.register_output(var, config)
+ pin = yield cg.gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
+
cg.add(var.set_frequency(config[CONF_FREQUENCY]))
+
+
+@automation.register_action('output.esp8266_pwm.set_frequency', SetFrequencyAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(ESP8266PWM),
+ cv.Required(CONF_FREQUENCY): cv.templatable(validate_frequency),
+}))
+def esp8266_set_frequency_to_code(config, action_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
+ template_ = yield cg.templatable(config[CONF_FREQUENCY], args, float)
+ cg.add(var.set_frequency(template_))
+ yield var
diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py
index 4aa25affdf..50a0d99d32 100644
--- a/esphome/components/ethernet/__init__.py
+++ b/esphome/components/ethernet/__init__.py
@@ -7,6 +7,7 @@ from esphome.core import CORE, coroutine_with_priority
CONFLICTS_WITH = ['wifi']
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
+AUTO_LOAD = ['network']
ethernet_ns = cg.esphome_ns.namespace('ethernet')
CONF_PHY_ADDR = 'phy_addr'
@@ -54,12 +55,12 @@ def validate(config):
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(EthernetComponent),
- cv.Required(CONF_TYPE): cv.one_of(*ETHERNET_TYPES, upper=True),
+ cv.GenerateID(): cv.declare_id(EthernetComponent),
+ cv.Required(CONF_TYPE): cv.enum(ETHERNET_TYPES, upper=True),
cv.Required(CONF_MDC_PIN): pins.output_pin,
cv.Required(CONF_MDIO_PIN): pins.input_output_pin,
- cv.Optional(CONF_CLK_MODE, default='GPIO0_IN'): cv.one_of(*CLK_MODES, upper=True, space='_'),
- cv.Optional(CONF_PHY_ADDR, default=0): cv.All(cv.int_, cv.Range(min=0, max=31)),
+ cv.Optional(CONF_CLK_MODE, default='GPIO0_IN'): cv.enum(CLK_MODES, upper=True, space='_'),
+ cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31),
cv.Optional(CONF_POWER_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_MANUAL_IP): MANUAL_IP_SCHEMA,
cv.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
@@ -87,7 +88,7 @@ def to_code(config):
cg.add(var.set_phy_addr(config[CONF_PHY_ADDR]))
cg.add(var.set_mdc_pin(config[CONF_MDC_PIN]))
cg.add(var.set_mdio_pin(config[CONF_MDIO_PIN]))
- cg.add(var.set_type(ETHERNET_TYPES[config[CONF_TYPE]]))
+ cg.add(var.set_type(config[CONF_TYPE]))
cg.add(var.set_clk_mode(CLK_MODES[config[CONF_CLK_MODE]]))
cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py
index c7787cd3f1..ffddf83acc 100644
--- a/esphome/components/fan/__init__.py
+++ b/esphome/components/fan/__init__.py
@@ -1,11 +1,12 @@
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.automation import maybe_simple_id
from esphome.components import mqtt
from esphome.const import CONF_ID, CONF_INTERNAL, CONF_MQTT_ID, CONF_OSCILLATING, \
CONF_OSCILLATION_COMMAND_TOPIC, CONF_OSCILLATION_STATE_TOPIC, CONF_SPEED, \
CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC, CONF_NAME
-from esphome.core import CORE, coroutine
+from esphome.core import CORE, coroutine, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -14,9 +15,9 @@ FanState = fan_ns.class_('FanState', cg.Nameable, cg.Component)
MakeFan = cg.Application.struct('MakeFan')
# Actions
-TurnOnAction = fan_ns.class_('TurnOnAction', cg.Action)
-TurnOffAction = fan_ns.class_('TurnOffAction', cg.Action)
-ToggleAction = fan_ns.class_('ToggleAction', cg.Action)
+TurnOnAction = fan_ns.class_('TurnOnAction', automation.Action)
+TurnOffAction = fan_ns.class_('TurnOffAction', automation.Action)
+ToggleAction = fan_ns.class_('ToggleAction', automation.Action)
FanSpeed = fan_ns.enum('FanSpeed')
FAN_SPEEDS = {
@@ -27,8 +28,8 @@ FAN_SPEEDS = {
}
FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(FanState),
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTFanComponent),
+ cv.GenerateID(): cv.declare_id(FanState),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTFanComponent),
cv.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.All(cv.requires_component('mqtt'),
cv.publish_topic),
cv.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.All(cv.requires_component('mqtt'),
@@ -38,6 +39,7 @@ FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
@coroutine
def setup_fan_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(config[CONF_INTERNAL]))
@@ -66,52 +68,46 @@ def register_fan(var, config):
@coroutine
def create_fan_state(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield register_fan(var, config)
yield var
FAN_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(FanState),
+ cv.Required(CONF_ID): cv.use_id(FanState),
})
-@ACTION_REGISTRY.register('fan.toggle', FAN_ACTION_SCHEMA)
+@automation.register_action('fan.toggle', ToggleAction, FAN_ACTION_SCHEMA)
def fan_toggle_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ToggleAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('fan.turn_off', FAN_ACTION_SCHEMA)
+@automation.register_action('fan.turn_off', TurnOffAction, FAN_ACTION_SCHEMA)
def fan_turn_off_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TurnOffAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('fan.turn_on', maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(FanState),
+@automation.register_action('fan.turn_on', TurnOnAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(FanState),
cv.Optional(CONF_OSCILLATING): cv.templatable(cv.boolean),
- cv.Optional(CONF_SPEED): cv.templatable(cv.one_of(*FAN_SPEEDS, upper=True)),
+ cv.Optional(CONF_SPEED): cv.templatable(cv.enum(FAN_SPEEDS, upper=True)),
}))
def fan_turn_on_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TurnOnAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
if CONF_OSCILLATING in config:
template_ = yield cg.templatable(config[CONF_OSCILLATING], args, bool)
- cg.add(action.set_oscillating(template_))
+ cg.add(var.set_oscillating(template_))
if CONF_SPEED in config:
- template_ = yield cg.templatable(config[CONF_SPEED], args, FanSpeed,
- to_exp=FAN_SPEEDS)
- cg.add(action.set_speed(template_))
- yield action
+ template_ = yield cg.templatable(config[CONF_SPEED], args, FanSpeed)
+ cg.add(var.set_speed(template_))
+ yield var
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_FAN')
cg.add_global(fan_ns.using)
diff --git a/esphome/components/fan/automation.h b/esphome/components/fan/automation.h
index ebbb2fba9f..dfa72a3ea6 100644
--- a/esphome/components/fan/automation.h
+++ b/esphome/components/fan/automation.h
@@ -23,7 +23,6 @@ template class TurnOnAction : public Action {
call.set_speed(this->speed_.value(x...));
}
call.perform();
- this->play_next(x...);
}
protected:
@@ -34,10 +33,7 @@ template class TurnOffAction : public Action {
public:
explicit TurnOffAction(FanState *state) : state_(state) {}
- void play(Ts... x) override {
- this->state_->turn_off().perform();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->state_->turn_off().perform(); }
protected:
FanState *state_;
@@ -47,10 +43,7 @@ template class ToggleAction : public Action {
public:
explicit ToggleAction(FanState *state) : state_(state) {}
- void play(Ts... x) override {
- this->state_->toggle().perform();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->state_->toggle().perform(); }
protected:
FanState *state_;
diff --git a/esphome/components/fan/fan_state.cpp b/esphome/components/fan/fan_state.cpp
index e662cb9eeb..af170a755c 100644
--- a/esphome/components/fan/fan_state.cpp
+++ b/esphome/components/fan/fan_state.cpp
@@ -13,10 +13,10 @@ void FanState::add_on_state_callback(std::function &&callback) {
}
FanState::FanState(const std::string &name) : Nameable(name) {}
-FanState::StateCall FanState::turn_on() { return this->make_call().set_state(true); }
-FanState::StateCall FanState::turn_off() { return this->make_call().set_state(false); }
-FanState::StateCall FanState::toggle() { return this->make_call().set_state(!this->state); }
-FanState::StateCall FanState::make_call() { return FanState::StateCall(this); }
+FanStateCall FanState::turn_on() { return this->make_call().set_state(true); }
+FanStateCall FanState::turn_off() { return this->make_call().set_state(false); }
+FanStateCall FanState::toggle() { return this->make_call().set_state(!this->state); }
+FanStateCall FanState::make_call() { return FanStateCall(this); }
struct FanStateRTCState {
bool state;
@@ -39,32 +39,7 @@ void FanState::setup() {
float FanState::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; }
uint32_t FanState::hash_base() { return 418001110UL; }
-FanState::StateCall::StateCall(FanState *state) : state_(state) {}
-FanState::StateCall &FanState::StateCall::set_state(bool state) {
- this->binary_state_ = state;
- return *this;
-}
-FanState::StateCall &FanState::StateCall::set_state(optional state) {
- this->binary_state_ = state;
- return *this;
-}
-FanState::StateCall &FanState::StateCall::set_oscillating(bool oscillating) {
- this->oscillating_ = oscillating;
- return *this;
-}
-FanState::StateCall &FanState::StateCall::set_oscillating(optional oscillating) {
- this->oscillating_ = oscillating;
- return *this;
-}
-FanState::StateCall &FanState::StateCall::set_speed(FanSpeed speed) {
- this->speed_ = speed;
- return *this;
-}
-FanState::StateCall &FanState::StateCall::set_speed(optional speed) {
- this->speed_ = speed;
- return *this;
-}
-void FanState::StateCall::perform() const {
+void FanStateCall::perform() const {
if (this->binary_state_.has_value()) {
this->state_->state = *this->binary_state_;
}
@@ -92,7 +67,7 @@ void FanState::StateCall::perform() const {
this->state_->state_callback_.call();
}
-FanState::StateCall &FanState::StateCall::set_speed(const char *speed) {
+FanStateCall &FanStateCall::set_speed(const char *speed) {
if (strcasecmp(speed, "low") == 0) {
this->set_speed(FAN_SPEED_LOW);
} else if (strcasecmp(speed, "medium") == 0) {
diff --git a/esphome/components/fan/fan_state.h b/esphome/components/fan/fan_state.h
index eb3faf3eb6..4e937c68bd 100644
--- a/esphome/components/fan/fan_state.h
+++ b/esphome/components/fan/fan_state.h
@@ -15,8 +15,50 @@ enum FanSpeed {
FAN_SPEED_HIGH = 2 ///< The fan is running on high/full speed.
};
+class FanState;
+
+class FanStateCall {
+ public:
+ explicit FanStateCall(FanState *state) : state_(state) {}
+
+ FanStateCall &set_state(bool binary_state) {
+ this->binary_state_ = binary_state;
+ return *this;
+ }
+ FanStateCall &set_state(optional binary_state) {
+ this->binary_state_ = binary_state;
+ return *this;
+ }
+ FanStateCall &set_oscillating(bool oscillating) {
+ this->oscillating_ = oscillating;
+ return *this;
+ }
+ FanStateCall &set_oscillating(optional oscillating) {
+ this->oscillating_ = oscillating;
+ return *this;
+ }
+ FanStateCall &set_speed(FanSpeed speed) {
+ this->speed_ = speed;
+ return *this;
+ }
+ FanStateCall &set_speed(optional speed) {
+ this->speed_ = speed;
+ return *this;
+ }
+ FanStateCall &set_speed(const char *speed);
+
+ void perform() const;
+
+ protected:
+ FanState *const state_;
+ optional binary_state_;
+ optional oscillating_{};
+ optional speed_{};
+};
+
class FanState : public Nameable, public Component {
public:
+ FanState() = default;
/// Construct the fan state with name.
explicit FanState(const std::string &name);
@@ -35,36 +77,17 @@ class FanState : public Nameable, public Component {
/// The current fan speed.
FanSpeed speed{FAN_SPEED_HIGH};
- class StateCall {
- public:
- explicit StateCall(FanState *state);
-
- FanState::StateCall &set_state(bool state);
- FanState::StateCall &set_state(optional state);
- FanState::StateCall &set_oscillating(bool oscillating);
- FanState::StateCall &set_oscillating(optional oscillating);
- FanState::StateCall &set_speed(FanSpeed speed);
- FanState::StateCall &set_speed(optional speed);
- FanState::StateCall &set_speed(const char *speed);
-
- void perform() const;
-
- protected:
- FanState *const state_;
- optional binary_state_;
- optional oscillating_{};
- optional speed_{};
- };
-
- FanState::StateCall turn_on();
- FanState::StateCall turn_off();
- FanState::StateCall toggle();
- FanState::StateCall make_call();
+ FanStateCall turn_on();
+ FanStateCall turn_off();
+ FanStateCall toggle();
+ FanStateCall make_call();
void setup() override;
float get_setup_priority() const override;
protected:
+ friend FanStateCall;
+
uint32_t hash_base() override;
FanTraits traits_{};
diff --git a/esphome/components/fastled_base/__init__.py b/esphome/components/fastled_base/__init__.py
index 22249651be..5ad7280ee8 100644
--- a/esphome/components/fastled_base/__init__.py
+++ b/esphome/components/fastled_base/__init__.py
@@ -19,13 +19,13 @@ RGB_ORDERS = [
]
BASE_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(FastLEDLightOutput),
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(FastLEDLightOutput),
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
cv.Optional(CONF_RGB_ORDER): cv.one_of(*RGB_ORDERS, upper=True),
cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
- cv.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(power_supply.PowerSupply),
+ cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply),
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/fastled_base/fastled_light.h b/esphome/components/fastled_base/fastled_light.h
index 24a5918506..55a48fcb3e 100644
--- a/esphome/components/fastled_base/fastled_light.h
+++ b/esphome/components/fastled_base/fastled_light.h
@@ -27,11 +27,6 @@ class FastLEDLightOutput : public Component, public light::AddressableLight {
inline int32_t size() const override { return this->num_leds_; }
- inline light::ESPColorView operator[](int32_t index) const override {
- return light::ESPColorView(&this->leds_[index].r, &this->leds_[index].g, &this->leds_[index].b, nullptr,
- &this->effect_data_[index], &this->correction_);
- }
-
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
@@ -236,6 +231,11 @@ class FastLEDLightOutput : public Component, public light::AddressableLight {
}
protected:
+ light::ESPColorView get_view_internal(int32_t index) const override {
+ return {&this->leds_[index].r, &this->leds_[index].g, &this->leds_[index].b, nullptr,
+ &this->effect_data_[index], &this->correction_};
+ }
+
CLEDController *controller_{nullptr};
CRGB *leds_{nullptr};
uint8_t *effect_data_{nullptr};
diff --git a/esphome/components/fastled_clockless/light.py b/esphome/components/fastled_clockless/light.py
index eebc19a79f..340dc0ab05 100644
--- a/esphome/components/fastled_clockless/light.py
+++ b/esphome/components/fastled_clockless/light.py
@@ -38,7 +38,7 @@ def validate(value):
return value
-CONFIG_SCHEMA = cv.nameable(fastled_base.BASE_SCHEMA.extend({
+CONFIG_SCHEMA = cv.All(fastled_base.BASE_SCHEMA.extend({
cv.Required(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Required(CONF_PIN): pins.output_pin,
}), validate)
diff --git a/esphome/components/fastled_spi/light.py b/esphome/components/fastled_spi/light.py
index ad7df9e98e..959c8a1b19 100644
--- a/esphome/components/fastled_spi/light.py
+++ b/esphome/components/fastled_spi/light.py
@@ -17,11 +17,11 @@ CHIPSETS = [
'DOTSTAR',
]
-CONFIG_SCHEMA = cv.nameable(fastled_base.BASE_SCHEMA.extend({
+CONFIG_SCHEMA = fastled_base.BASE_SCHEMA.extend({
cv.Required(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Required(CONF_DATA_PIN): pins.output_pin,
cv.Required(CONF_CLOCK_PIN): pins.output_pin,
-}))
+})
def to_code(config):
diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py
index 888c00cb14..774b49dbc1 100644
--- a/esphome/components/font/__init__.py
+++ b/esphome/components/font/__init__.py
@@ -67,11 +67,11 @@ DEFAULT_GLYPHS = u' !"%()+,-.:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklm
CONF_RAW_DATA_ID = 'raw_data_id'
FONT_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(Font),
+ cv.Required(CONF_ID): cv.declare_id(Font),
cv.Required(CONF_FILE): validate_truetype_file,
cv.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs,
cv.Optional(CONF_SIZE, default=20): cv.All(cv.int_, cv.Range(min=1)),
- cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(cg.uint8),
+ cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
})
CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA)
@@ -80,7 +80,7 @@ CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA)
def to_code(config):
from PIL import ImageFont
- path = CORE.relative_path(config[CONF_FILE])
+ path = CORE.relative_config_path(config[CONF_FILE])
try:
font = ImageFont.truetype(path, config[CONF_SIZE])
except Exception as e:
diff --git a/esphome/components/globals/__init__.py b/esphome/components/globals/__init__.py
index c06d1cf543..4dce6e7583 100644
--- a/esphome/components/globals/__init__.py
+++ b/esphome/components/globals/__init__.py
@@ -1,23 +1,26 @@
import hashlib
-from esphome import config_validation as cv
+from esphome import config_validation as cv, automation
from esphome import codegen as cg
-from esphome.const import CONF_ID, CONF_INITIAL_VALUE, CONF_RESTORE_VALUE, CONF_TYPE
+from esphome.const import CONF_ID, CONF_INITIAL_VALUE, CONF_RESTORE_VALUE, CONF_TYPE, CONF_VALUE
+from esphome.core import coroutine_with_priority
from esphome.py_compat import IS_PY3
globals_ns = cg.esphome_ns.namespace('globals')
GlobalsComponent = globals_ns.class_('GlobalsComponent', cg.Component)
+GlobalVarSetAction = globals_ns.class_('GlobalVarSetAction', automation.Action)
MULTI_CONF = True
-
CONFIG_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(GlobalsComponent),
+ cv.Required(CONF_ID): cv.declare_id(GlobalsComponent),
cv.Required(CONF_TYPE): cv.string_strict,
cv.Optional(CONF_INITIAL_VALUE): cv.string_strict,
- cv.Optional(CONF_RESTORE_VALUE): cv.boolean,
+ cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA)
+# Run with low priority so that namespaces are registered first
+@coroutine_with_priority(-100.0)
def to_code(config):
type_ = cg.RawExpression(config[CONF_TYPE])
template_args = cg.TemplateArguments(type_)
@@ -31,9 +34,22 @@ def to_code(config):
glob = cg.Pvariable(config[CONF_ID], rhs, type=res_type)
yield cg.register_component(glob, config)
- if config.get(CONF_RESTORE_VALUE, False):
+ if config[CONF_RESTORE_VALUE]:
value = config[CONF_ID].id
if IS_PY3 and isinstance(value, str):
value = value.encode()
hash_ = int(hashlib.md5(value).hexdigest()[:8], 16)
cg.add(glob.set_restore_value(hash_))
+
+
+@automation.register_action('globals.set', GlobalVarSetAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(GlobalsComponent),
+ cv.Required(CONF_VALUE): cv.templatable(cv.string_strict),
+}))
+def globals_set_to_code(config, action_id, template_arg, args):
+ full_id, paren = yield cg.get_variable_with_full_id(config[CONF_ID])
+ template_arg = cg.TemplateArguments(full_id.type, *template_arg)
+ var = cg.new_Pvariable(action_id, template_arg, paren)
+ templ = yield cg.templatable(config[CONF_VALUE], args, None)
+ cg.add(var.set_value(templ))
+ yield var
diff --git a/esphome/components/globals/globals_component.h b/esphome/components/globals/globals_component.h
index af5435a056..c7d2a18d84 100644
--- a/esphome/components/globals/globals_component.h
+++ b/esphome/components/globals/globals_component.h
@@ -8,6 +8,7 @@ namespace globals {
template class GlobalsComponent : public Component {
public:
+ using value_type = T;
explicit GlobalsComponent() = default;
explicit GlobalsComponent(T initial_value) : value_(initial_value) {}
explicit GlobalsComponent(std::array::type, std::extent::value> initial_value) {
@@ -49,5 +50,19 @@ template class GlobalsComponent : public Component {
ESPPreferenceObject rtc_;
};
+template class GlobalVarSetAction : public Action {
+ public:
+ explicit GlobalVarSetAction(C *parent) : parent_(parent) {}
+
+ using T = typename C::value_type;
+
+ TEMPLATABLE_VALUE(T, value);
+
+ void play(Ts... x) override { this->parent_->value() = this->value_.value(x...); }
+
+ protected:
+ C *parent_;
+};
+
} // namespace globals
} // namespace esphome
diff --git a/esphome/components/gpio/binary_sensor/__init__.py b/esphome/components/gpio/binary_sensor/__init__.py
index cbe8f730c9..e269de5a71 100644
--- a/esphome/components/gpio/binary_sensor/__init__.py
+++ b/esphome/components/gpio/binary_sensor/__init__.py
@@ -2,20 +2,21 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import binary_sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_PIN
+from esphome.const import CONF_ID, CONF_PIN
from .. import gpio_ns
GPIOBinarySensor = gpio_ns.class_('GPIOBinarySensor', binary_sensor.BinarySensor, cg.Component)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(GPIOBinarySensor),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(GPIOBinarySensor),
cv.Required(CONF_PIN): pins.gpio_input_pin_schema
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield binary_sensor.register_binary_sensor(var, config)
+
pin = yield cg.gpio_pin_expression(config[CONF_PIN])
- rhs = GPIOBinarySensor.new(config[CONF_NAME], pin)
- gpio = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(gpio, config)
- yield binary_sensor.register_binary_sensor(gpio, config)
+ cg.add(var.set_pin(pin))
diff --git a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp
index 7d7d54f6cb..dff3609ce2 100644
--- a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp
+++ b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp
@@ -19,8 +19,6 @@ void GPIOBinarySensor::dump_config() {
void GPIOBinarySensor::loop() { this->publish_state(this->pin_->digital_read()); }
float GPIOBinarySensor::get_setup_priority() const { return setup_priority::HARDWARE; }
-GPIOBinarySensor::GPIOBinarySensor(const std::string &name, GPIOPin *pin)
- : binary_sensor::BinarySensor(name), pin_(pin) {}
} // namespace gpio
} // namespace esphome
diff --git a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h
index f03ce20f26..cfe49b3c94 100644
--- a/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h
+++ b/esphome/components/gpio/binary_sensor/gpio_binary_sensor.h
@@ -8,8 +8,7 @@ namespace gpio {
class GPIOBinarySensor : public binary_sensor::BinarySensor, public Component {
public:
- explicit GPIOBinarySensor(const std::string &name, GPIOPin *pin);
-
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
// ========== INTERNAL METHODS ==========
// (In most use cases you won't need these)
/// Setup pin
diff --git a/esphome/components/gpio/output/__init__.py b/esphome/components/gpio/output/__init__.py
index 5c2228f321..bab23c824b 100644
--- a/esphome/components/gpio/output/__init__.py
+++ b/esphome/components/gpio/output/__init__.py
@@ -9,13 +9,15 @@ GPIOBinaryOutput = gpio_ns.class_('GPIOBinaryOutput', output.BinaryOutput,
cg.Component)
CONFIG_SCHEMA = output.BINARY_OUTPUT_SCHEMA.extend({
- cv.Required(CONF_ID): cv.declare_variable_id(GPIOBinaryOutput),
+ cv.Required(CONF_ID): cv.declare_id(GPIOBinaryOutput),
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield output.register_output(var, config)
+ yield cg.register_component(var, config)
+
pin = yield cg.gpio_pin_expression(config[CONF_PIN])
- gpio = cg.new_Pvariable(config[CONF_ID], pin)
- yield output.register_output(gpio, config)
- yield cg.register_component(gpio, config)
+ cg.add(var.set_pin(pin))
diff --git a/esphome/components/gpio/output/gpio_binary_output.h b/esphome/components/gpio/output/gpio_binary_output.h
index b2dcc8cbf0..0a7dfb46e2 100644
--- a/esphome/components/gpio/output/gpio_binary_output.h
+++ b/esphome/components/gpio/output/gpio_binary_output.h
@@ -9,7 +9,7 @@ namespace gpio {
class GPIOBinaryOutput : public output::BinaryOutput, public Component {
public:
- explicit GPIOBinaryOutput(GPIOPin *pin) : pin_(pin) {}
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
void setup() override {
this->turn_off();
diff --git a/esphome/components/gpio/switch/__init__.py b/esphome/components/gpio/switch/__init__.py
index 69a100a002..7b383cb8a9 100644
--- a/esphome/components/gpio/switch/__init__.py
+++ b/esphome/components/gpio/switch/__init__.py
@@ -1,8 +1,8 @@
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import pins
from esphome.components import switch
-from esphome.const import CONF_ID, CONF_INTERLOCK, CONF_NAME, CONF_PIN, CONF_RESTORE_MODE
+from esphome.const import CONF_ID, CONF_INTERLOCK, CONF_PIN, CONF_RESTORE_MODE
from .. import gpio_ns
GPIOSwitch = gpio_ns.class_('GPIOSwitch', switch.Switch, cg.Component)
@@ -15,27 +15,28 @@ RESTORE_MODES = {
'ALWAYS_ON': GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_ON,
}
-CONFIG_SCHEMA = cv.nameable(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(GPIOSwitch),
+CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(GPIOSwitch),
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_RESTORE_MODE, default='RESTORE_DEFAULT_OFF'):
- cv.one_of(*RESTORE_MODES, upper=True, space='_'),
- cv.Optional(CONF_INTERLOCK): cv.ensure_list(cv.use_variable_id(switch.Switch)),
-}).extend(cv.COMPONENT_SCHEMA))
+ cv.enum(RESTORE_MODES, upper=True, space='_'),
+ cv.Optional(CONF_INTERLOCK): cv.ensure_list(cv.use_id(switch.Switch)),
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- pin = yield cg.gpio_pin_expression(config[CONF_PIN])
- rhs = GPIOSwitch.new(config[CONF_NAME], pin)
- gpio = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(gpio, config)
- yield switch.register_switch(gpio, config)
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield switch.register_switch(var, config)
- cg.add(gpio.set_restore_mode(RESTORE_MODES[config[CONF_RESTORE_MODE]]))
+ pin = yield cg.gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
+
+ cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
if CONF_INTERLOCK in config:
interlock = []
for it in config[CONF_INTERLOCK]:
lock = yield cg.get_variable(it)
interlock.append(lock)
- cg.add(gpio.set_interlock(interlock))
+ cg.add(var.set_interlock(interlock))
diff --git a/esphome/components/gpio/switch/gpio_switch.cpp b/esphome/components/gpio/switch/gpio_switch.cpp
index f7fc29ce28..22139d6b9c 100644
--- a/esphome/components/gpio/switch/gpio_switch.cpp
+++ b/esphome/components/gpio/switch/gpio_switch.cpp
@@ -6,8 +6,6 @@ namespace gpio {
static const char *TAG = "switch.gpio";
-GPIOSwitch::GPIOSwitch(const std::string &name, GPIOPin *pin) : Switch(name), Component(), pin_(pin) {}
-
float GPIOSwitch::get_setup_priority() const { return setup_priority::HARDWARE; }
void GPIOSwitch::setup() {
ESP_LOGCONFIG(TAG, "Setting up GPIO Switch '%s'...", this->name_.c_str());
diff --git a/esphome/components/gpio/switch/gpio_switch.h b/esphome/components/gpio/switch/gpio_switch.h
index a7be5fbb83..ceace477b2 100644
--- a/esphome/components/gpio/switch/gpio_switch.h
+++ b/esphome/components/gpio/switch/gpio_switch.h
@@ -15,7 +15,7 @@ enum GPIOSwitchRestoreMode {
class GPIOSwitch : public switch_::Switch, public Component {
public:
- GPIOSwitch(const std::string &name, GPIOPin *pin);
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
void set_restore_mode(GPIOSwitchRestoreMode restore_mode);
diff --git a/esphome/components/hdc1080/hdc1080.h b/esphome/components/hdc1080/hdc1080.h
index 41e1040188..9cb87cdb8b 100644
--- a/esphome/components/hdc1080/hdc1080.h
+++ b/esphome/components/hdc1080/hdc1080.h
@@ -9,9 +9,6 @@ namespace hdc1080 {
class HDC1080Component : public PollingComponent, public i2c::I2CDevice {
public:
- /// Initialize the component with the provided update interval.
- HDC1080Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
diff --git a/esphome/components/hdc1080/sensor.py b/esphome/components/hdc1080/sensor.py
index 451abcf620..00b8296351 100644
--- a/esphome/components/hdc1080/sensor.py
+++ b/esphome/components/hdc1080/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, \
- CONF_UPDATE_INTERVAL, ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_CELSIUS, UNIT_PERCENT
+ ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_CELSIUS, UNIT_PERCENT
DEPENDENCIES = ['i2c']
@@ -10,17 +10,14 @@ hdc1080_ns = cg.esphome_ns.namespace('hdc1080')
HDC1080Component = hdc1080_ns.class_('HDC1080Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(HDC1080Component),
- cv.Optional(CONF_TEMPERATURE): cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
- cv.Optional(CONF_HUMIDITY): cv.nameable(
- sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 0)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x40))
+ cv.GenerateID(): cv.declare_id(HDC1080Component),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 0),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x40))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/hlw8012/hlw8012.cpp b/esphome/components/hlw8012/hlw8012.cpp
index a97440c540..c5138b7562 100644
--- a/esphome/components/hlw8012/hlw8012.cpp
+++ b/esphome/components/hlw8012/hlw8012.cpp
@@ -32,17 +32,17 @@ void HLW8012Component::dump_config() {
float HLW8012Component::get_setup_priority() const { return setup_priority::DATA; }
void HLW8012Component::update() {
// HLW8012 has 50% duty cycle
+ const uint32_t last_rise_cf = this->cf_store_.get_last_rise();
+ const uint32_t last_rise_cf1 = this->cf1_store_.get_last_rise();
+ const uint32_t now = micros();
float full_cycle_cf = this->cf_store_.get_pulse_width_s() * 2;
float full_cycle_cf1 = this->cf1_store_.get_pulse_width_s() * 2;
- float cf_hz, cf1_hz;
+ float cf_hz = 0.0f, cf1_hz = 0.0f;
+ auto update_interval_micros = static_cast(this->update_interval_ * 1e3f);
- if (full_cycle_cf == 0.0f)
- cf_hz = 0.0f;
- else
+ if (full_cycle_cf != 0.0f && now - last_rise_cf < update_interval_micros * 3)
cf_hz = 1.0f / full_cycle_cf;
- if (full_cycle_cf1 == 0.0f)
- cf1_hz = 0.0f;
- else
+ if (full_cycle_cf1 != 0.0f && now - last_rise_cf1 < update_interval_micros * 3)
cf1_hz = 1.0f / full_cycle_cf1;
if (this->nth_value_++ < 2) {
diff --git a/esphome/components/hlw8012/hlw8012.h b/esphome/components/hlw8012/hlw8012.h
index e4553ed124..3eb1ea97c9 100644
--- a/esphome/components/hlw8012/hlw8012.h
+++ b/esphome/components/hlw8012/hlw8012.h
@@ -10,8 +10,6 @@ namespace hlw8012 {
class HLW8012Component : public PollingComponent {
public:
- HLW8012Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/hlw8012/sensor.py b/esphome/components/hlw8012/sensor.py
index c4b971df93..3dd1f0ae33 100644
--- a/esphome/components/hlw8012/sensor.py
+++ b/esphome/components/hlw8012/sensor.py
@@ -3,8 +3,8 @@ import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
from esphome.const import CONF_CHANGE_MODE_EVERY, CONF_CURRENT, \
- CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_SEL_PIN, CONF_UPDATE_INTERVAL, \
- CONF_VOLTAGE, CONF_VOLTAGE_DIVIDER, ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
+ CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_SEL_PIN, CONF_VOLTAGE, CONF_VOLTAGE_DIVIDER, \
+ ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
AUTO_LOAD = ['pulse_width']
@@ -14,26 +14,25 @@ HLW8012Component = hlw8012_ns.class_('HLW8012Component', cg.PollingComponent)
CONF_CF1_PIN = 'cf1_pin'
CONF_CF_PIN = 'cf_pin'
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(HLW8012Component),
+ cv.GenerateID(): cv.declare_id(HLW8012Component),
cv.Required(CONF_SEL_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_CF_PIN): cv.All(pins.internal_gpio_input_pullup_pin_schema,
pins.validate_has_interrupt),
cv.Required(CONF_CF1_PIN): cv.All(pins.internal_gpio_input_pullup_pin_schema,
pins.validate_has_interrupt),
- cv.Optional(CONF_VOLTAGE): cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1)),
- cv.Optional(CONF_CURRENT): cv.nameable(sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2)),
- cv.Optional(CONF_POWER): cv.nameable(sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1)),
+ cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1),
+ cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
+ cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1),
cv.Optional(CONF_CURRENT_RESISTOR, default=0.001): cv.resistance,
cv.Optional(CONF_VOLTAGE_DIVIDER, default=2351): cv.positive_float,
cv.Optional(CONF_CHANGE_MODE_EVERY, default=8): cv.All(cv.uint32_t, cv.Range(min=1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA)
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
sel = yield cg.gpio_pin_expression(config[CONF_SEL_PIN])
diff --git a/esphome/components/hmc5883l/hmc5883l.h b/esphome/components/hmc5883l/hmc5883l.h
index d531a581e5..3946f1fb10 100644
--- a/esphome/components/hmc5883l/hmc5883l.h
+++ b/esphome/components/hmc5883l/hmc5883l.h
@@ -20,8 +20,6 @@ enum HMC5883LRange {
class HMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
public:
- HMC5883LComponent(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/hmc5883l/sensor.py b/esphome/components/hmc5883l/sensor.py
index 800e563fc0..afb8ffac7d 100644
--- a/esphome/components/hmc5883l/sensor.py
+++ b/esphome/components/hmc5883l/sensor.py
@@ -2,8 +2,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
-from esphome.const import CONF_ADDRESS, CONF_ID, CONF_RANGE, CONF_UPDATE_INTERVAL, \
- ICON_MAGNET, UNIT_MICROTESLA, UNIT_DEGREES, ICON_SCREEN_ROTATION
+from esphome.const import CONF_ADDRESS, CONF_ID, CONF_RANGE, ICON_MAGNET, UNIT_MICROTESLA, \
+ UNIT_DEGREES, ICON_SCREEN_ROTATION
DEPENDENCIES = ['i2c']
@@ -33,30 +33,29 @@ def validate_range(value):
value = cv.string(value)
if value.endswith(u'µT') or value.endswith('uT'):
value = value[:-2]
- return cv.one_of(*HMC5883L_RANGES, int=True)(value)
+ return cv.enum(HMC5883L_RANGES, int=True)(value)
field_strength_schema = sensor.sensor_schema(UNIT_MICROTESLA, ICON_MAGNET, 1)
heading_schema = sensor.sensor_schema(UNIT_DEGREES, ICON_SCREEN_ROTATION, 1)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(HMC5883LComponent),
+ cv.GenerateID(): cv.declare_id(HMC5883LComponent),
cv.Optional(CONF_ADDRESS): cv.i2c_address,
- cv.Optional(CONF_FIELD_STRENGTH_X): cv.nameable(field_strength_schema),
- cv.Optional(CONF_FIELD_STRENGTH_Y): cv.nameable(field_strength_schema),
- cv.Optional(CONF_FIELD_STRENGTH_Z): cv.nameable(field_strength_schema),
- cv.Optional(CONF_HEADING): cv.nameable(heading_schema),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
+ cv.Optional(CONF_FIELD_STRENGTH_X): field_strength_schema,
+ cv.Optional(CONF_FIELD_STRENGTH_Y): field_strength_schema,
+ cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema,
+ cv.Optional(CONF_HEADING): heading_schema,
cv.Optional(CONF_RANGE, default='130uT'): validate_range,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x1E))
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x1E))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
- cg.add(var.set_range(HMC5883L_RANGES[config[CONF_RANGE]]))
+ cg.add(var.set_range(config[CONF_RANGE]))
if CONF_FIELD_STRENGTH_X in config:
sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_X])
cg.add(var.set_x_sensor(sens))
diff --git a/esphome/components/homeassistant/binary_sensor/__init__.py b/esphome/components/homeassistant/binary_sensor/__init__.py
index e738f2f1be..b78836f18f 100644
--- a/esphome/components/homeassistant/binary_sensor/__init__.py
+++ b/esphome/components/homeassistant/binary_sensor/__init__.py
@@ -1,20 +1,22 @@
-from esphome.components import binary_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME
+import esphome.config_validation as cv
+from esphome.components import binary_sensor
+from esphome.const import CONF_ENTITY_ID, CONF_ID
from .. import homeassistant_ns
DEPENDENCIES = ['api']
HomeassistantBinarySensor = homeassistant_ns.class_('HomeassistantBinarySensor',
binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(HomeassistantBinarySensor),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(HomeassistantBinarySensor),
cv.Required(CONF_ENTITY_ID): cv.entity_id,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_ENTITY_ID])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield binary_sensor.register_binary_sensor(var, config)
+
+ cg.add(var.set_entity_id(config[CONF_ENTITY_ID]))
diff --git a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp
index 801ee5aabc..61c73d272b 100644
--- a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp
+++ b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.cpp
@@ -31,8 +31,6 @@ void HomeassistantBinarySensor::dump_config() {
ESP_LOGCONFIG(TAG, " Entity ID: '%s'", this->entity_id_.c_str());
}
float HomeassistantBinarySensor::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
-HomeassistantBinarySensor::HomeassistantBinarySensor(const std::string &name, const std::string &entity_id)
- : BinarySensor(name), entity_id_(entity_id) {}
} // namespace homeassistant
} // namespace esphome
diff --git a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h
index fd675d31f4..c2c7ec4480 100644
--- a/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h
+++ b/esphome/components/homeassistant/binary_sensor/homeassistant_binary_sensor.h
@@ -8,7 +8,7 @@ namespace homeassistant {
class HomeassistantBinarySensor : public binary_sensor::BinarySensor, public Component {
public:
- HomeassistantBinarySensor(const std::string &name, const std::string &entity_id);
+ void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/homeassistant/sensor/__init__.py b/esphome/components/homeassistant/sensor/__init__.py
index 23aeba77db..cd5e4a74e2 100644
--- a/esphome/components/homeassistant/sensor/__init__.py
+++ b/esphome/components/homeassistant/sensor/__init__.py
@@ -1,20 +1,22 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
-from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME
+from esphome.const import CONF_ENTITY_ID, CONF_ID, ICON_EMPTY, UNIT_EMPTY
from .. import homeassistant_ns
DEPENDENCIES = ['api']
HomeassistantSensor = homeassistant_ns.class_('HomeassistantSensor', sensor.Sensor)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(HomeassistantSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({
+ cv.GenerateID(): cv.declare_id(HomeassistantSensor),
cv.Required(CONF_ENTITY_ID): cv.entity_id,
-}))
+})
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_ENTITY_ID])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
+
+ cg.add(var.set_entity_id(config[CONF_ENTITY_ID]))
diff --git a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp
index 63555e61b2..6b1299f70e 100644
--- a/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp
+++ b/esphome/components/homeassistant/sensor/homeassistant_sensor.cpp
@@ -7,8 +7,6 @@ namespace homeassistant {
static const char *TAG = "homeassistant.sensor";
-HomeassistantSensor::HomeassistantSensor(const std::string &name, const std::string &entity_id)
- : Sensor(name), entity_id_(entity_id) {}
void HomeassistantSensor::setup() {
api::global_api_server->subscribe_home_assistant_state(this->entity_id_, [this](std::string state) {
auto val = parse_float(state);
diff --git a/esphome/components/homeassistant/sensor/homeassistant_sensor.h b/esphome/components/homeassistant/sensor/homeassistant_sensor.h
index 0d7ed61b11..baca6594c1 100644
--- a/esphome/components/homeassistant/sensor/homeassistant_sensor.h
+++ b/esphome/components/homeassistant/sensor/homeassistant_sensor.h
@@ -8,7 +8,7 @@ namespace homeassistant {
class HomeassistantSensor : public sensor::Sensor, public Component {
public:
- HomeassistantSensor(const std::string &name, const std::string &entity_id);
+ void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/homeassistant/text_sensor/__init__.py b/esphome/components/homeassistant/text_sensor/__init__.py
index 105be3cb5b..2d06473f3c 100644
--- a/esphome/components/homeassistant/text_sensor/__init__.py
+++ b/esphome/components/homeassistant/text_sensor/__init__.py
@@ -1,7 +1,7 @@
-from esphome.components import text_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME
+import esphome.config_validation as cv
+from esphome.components import text_sensor
+from esphome.const import CONF_ENTITY_ID, CONF_ID
from .. import homeassistant_ns
DEPENDENCIES = ['api']
@@ -9,13 +9,15 @@ DEPENDENCIES = ['api']
HomeassistantTextSensor = homeassistant_ns.class_('HomeassistantTextSensor',
text_sensor.TextSensor, cg.Component)
-CONFIG_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(HomeassistantTextSensor),
+CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(HomeassistantTextSensor),
cv.Required(CONF_ENTITY_ID): cv.entity_id,
-}))
+})
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_ENTITY_ID])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield text_sensor.register_text_sensor(var, config)
+
+ cg.add(var.set_entity_id(config[CONF_ENTITY_ID]))
diff --git a/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h b/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h
index d38fd288e6..02a74af1db 100644
--- a/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h
+++ b/esphome/components/homeassistant/text_sensor/homeassistant_text_sensor.h
@@ -8,8 +8,7 @@ namespace homeassistant {
class HomeassistantTextSensor : public text_sensor::TextSensor, public Component {
public:
- HomeassistantTextSensor(const std::string &name, const std::string &entity_id)
- : TextSensor(name), entity_id_(entity_id) {}
+ void set_entity_id(const std::string &entity_id) { entity_id_ = entity_id; }
void dump_config() override;
void setup() override;
diff --git a/esphome/components/homeassistant/time/__init__.py b/esphome/components/homeassistant/time/__init__.py
index 233be2945a..fd40de68d9 100644
--- a/esphome/components/homeassistant/time/__init__.py
+++ b/esphome/components/homeassistant/time/__init__.py
@@ -9,7 +9,7 @@ DEPENDENCIES = ['api']
HomeassistantTime = homeassistant_ns.class_('HomeassistantTime', time_.RealTimeClock)
CONFIG_SCHEMA = time_.TIME_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(HomeassistantTime),
+ cv.GenerateID(): cv.declare_id(HomeassistantTime),
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/homeassistant/time/homeassistant_time.cpp b/esphome/components/homeassistant/time/homeassistant_time.cpp
index 5e0004bff9..b21fd4c0ce 100644
--- a/esphome/components/homeassistant/time/homeassistant_time.cpp
+++ b/esphome/components/homeassistant/time/homeassistant_time.cpp
@@ -14,7 +14,7 @@ float HomeassistantTime::get_setup_priority() const { return setup_priority::DAT
void HomeassistantTime::setup() {
global_homeassistant_time = this;
- this->set_interval(15 * 60 * 1000, [this]() {
+ this->set_interval(15 * 60 * 1000, []() {
// re-request time every 15 minutes
api::global_api_server->request_time();
});
diff --git a/esphome/components/htu21d/htu21d.h b/esphome/components/htu21d/htu21d.h
index 4b18b7ae5f..a408f06d01 100644
--- a/esphome/components/htu21d/htu21d.h
+++ b/esphome/components/htu21d/htu21d.h
@@ -9,7 +9,6 @@ namespace htu21d {
class HTU21DComponent : public PollingComponent, public i2c::I2CDevice {
public:
- HTU21DComponent(uint32_t update_interval) : PollingComponent(update_interval) {}
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
diff --git a/esphome/components/htu21d/sensor.py b/esphome/components/htu21d/sensor.py
index 880a871652..20053d27dd 100644
--- a/esphome/components/htu21d/sensor.py
+++ b/esphome/components/htu21d/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, \
- CONF_UPDATE_INTERVAL, ICON_THERMOMETER, UNIT_CELSIUS, UNIT_PERCENT, ICON_WATER_PERCENT
+ ICON_THERMOMETER, UNIT_CELSIUS, UNIT_PERCENT, ICON_WATER_PERCENT
DEPENDENCIES = ['i2c']
@@ -10,17 +10,14 @@ htu21d_ns = cg.esphome_ns.namespace('htu21d')
HTU21DComponent = htu21d_ns.class_('HTU21DComponent', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(HTU21DComponent),
- cv.Required(CONF_TEMPERATURE): cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
- cv.Required(CONF_HUMIDITY): cv.nameable(
- sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x40))
+ cv.GenerateID(): cv.declare_id(HTU21DComponent),
+ cv.Required(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Required(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x40))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/hx711/hx711.cpp b/esphome/components/hx711/hx711.cpp
index 8c5dfad414..efa9e7b264 100644
--- a/esphome/components/hx711/hx711.cpp
+++ b/esphome/components/hx711/hx711.cpp
@@ -58,10 +58,6 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
*result = data;
return true;
}
-HX711Sensor::HX711Sensor(const std::string &name, GPIOPin *dout, GPIOPin *sck, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval), dout_pin_(dout), sck_pin_(sck) {}
-
-void HX711Sensor::set_gain(HX711Gain gain) { this->gain_ = gain; }
} // namespace hx711
} // namespace esphome
diff --git a/esphome/components/hx711/hx711.h b/esphome/components/hx711/hx711.h
index 81c78003e3..91c8317ee5 100644
--- a/esphome/components/hx711/hx711.h
+++ b/esphome/components/hx711/hx711.h
@@ -13,17 +13,17 @@ enum HX711Gain {
HX711_GAIN_64 = 3,
};
-class HX711Sensor : public sensor::PollingSensorComponent {
+class HX711Sensor : public sensor::Sensor, public PollingComponent {
public:
- HX711Sensor(const std::string &name, GPIOPin *dout, GPIOPin *sck, uint32_t update_interval);
+ void set_dout_pin(GPIOPin *dout_pin) { dout_pin_ = dout_pin; }
+ void set_sck_pin(GPIOPin *sck_pin) { sck_pin_ = sck_pin; }
+ void set_gain(HX711Gain gain) { gain_ = gain; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void update() override;
- void set_gain(HX711Gain gain);
-
protected:
bool read_sensor_(uint32_t *result);
diff --git a/esphome/components/hx711/sensor.py b/esphome/components/hx711/sensor.py
index ec7df245ff..bc22397065 100644
--- a/esphome/components/hx711/sensor.py
+++ b/esphome/components/hx711/sensor.py
@@ -1,9 +1,8 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-import esphome.config_validation as cv
-import esphome.codegen as cg
-from esphome.const import CONF_CLK_PIN, CONF_GAIN, CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, \
- ICON_SCALE
+from esphome.const import CONF_CLK_PIN, CONF_GAIN, CONF_ID, ICON_SCALE
hx711_ns = cg.esphome_ns.namespace('hx711')
HX711Sensor = hx711_ns.class_('HX711Sensor', sensor.PollingSensorComponent)
@@ -17,21 +16,21 @@ GAINS = {
64: HX711Gain.HX711_GAIN_64,
}
-CONFIG_SCHEMA = cv.nameable(sensor.sensor_schema('', ICON_SCALE, 0).extend({
- cv.GenerateID(): cv.declare_variable_id(HX711Sensor),
+CONFIG_SCHEMA = sensor.sensor_schema('', ICON_SCALE, 0).extend({
+ cv.GenerateID(): cv.declare_id(HX711Sensor),
cv.Required(CONF_DOUT_PIN): pins.gpio_input_pin_schema,
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
- cv.Optional(CONF_GAIN, default=128): cv.one_of(*GAINS, int=True),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA))
+ cv.Optional(CONF_GAIN, default=128): cv.enum(GAINS, int=True),
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- dout_pin = yield cg.gpio_pin_expression(config[CONF_DOUT_PIN])
- sck_pin = yield cg.gpio_pin_expression(config[CONF_CLK_PIN])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], dout_pin, sck_pin,
- config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
- cg.add(var.set_gain(GAINS[config[CONF_GAIN]]))
+ dout_pin = yield cg.gpio_pin_expression(config[CONF_DOUT_PIN])
+ cg.add(var.set_dout_pin(dout_pin))
+ sck_pin = yield cg.gpio_pin_expression(config[CONF_CLK_PIN])
+ cg.add(var.set_sck_pin(sck_pin))
+ cg.add(var.set_gain(config[CONF_GAIN]))
diff --git a/esphome/components/i2c/__init__.py b/esphome/components/i2c/__init__.py
index 1a0e016686..0c71f18019 100644
--- a/esphome/components/i2c/__init__.py
+++ b/esphome/components/i2c/__init__.py
@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_FREQUENCY, CONF_ID, CONF_SCAN, CONF_SCL, CONF_SDA, CONF_ADDRESS, \
CONF_I2C_ID
-from esphome.core import coroutine
+from esphome.core import coroutine, coroutine_with_priority
i2c_ns = cg.esphome_ns.namespace('i2c')
I2CComponent = i2c_ns.class_('I2CComponent', cg.Component)
@@ -11,7 +11,7 @@ I2CDevice = i2c_ns.class_('I2CDevice')
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(I2CComponent),
+ cv.GenerateID(): cv.declare_id(I2CComponent),
cv.Optional(CONF_SDA, default='SDA'): pins.input_pin,
cv.Optional(CONF_SCL, default='SCL'): pins.input_pin,
cv.Optional(CONF_FREQUENCY, default='50kHz'):
@@ -20,18 +20,28 @@ CONFIG_SCHEMA = cv.Schema({
}).extend(cv.COMPONENT_SCHEMA)
+@coroutine_with_priority(1.0)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_SDA], config[CONF_SCL],
- int(config[CONF_FREQUENCY]), config[CONF_SCAN])
+ cg.add_global(i2c_ns.using)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
+ cg.add(var.set_sda_pin(config[CONF_SDA]))
+ cg.add(var.set_scl_pin(config[CONF_SCL]))
+ cg.add(var.set_frequency(int(config[CONF_FREQUENCY])))
+ cg.add(var.set_scan(config[CONF_SCAN]))
cg.add_library('Wire', None)
- cg.add_global(i2c_ns.using)
def i2c_device_schema(default_address):
+ """Create a schema for a i2c device.
+
+ :param default_address: The default address of the i2c device, can be None to represent
+ a required option.
+ :return: The i2c device schema, `extend` this in your config schema.
+ """
schema = {
- cv.GenerateID(CONF_I2C_ID): cv.use_variable_id(I2CComponent),
+ cv.GenerateID(CONF_I2C_ID): cv.use_id(I2CComponent),
}
if default_address is None:
schema[cv.Required(CONF_ADDRESS)] = cv.i2c_address
@@ -42,6 +52,12 @@ def i2c_device_schema(default_address):
@coroutine
def register_i2c_device(var, config):
+ """Register an i2c device with the given config.
+
+ Sets the i2c bus to use and the i2c address.
+
+ This is a coroutine, you need to await it with a 'yield' expression!
+ """
parent = yield cg.get_variable(config[CONF_I2C_ID])
cg.add(var.set_i2c_parent(parent))
cg.add(var.set_i2c_address(config[CONF_ADDRESS]))
diff --git a/esphome/components/i2c/i2c.cpp b/esphome/components/i2c/i2c.cpp
index d24c9e8441..834fb1334a 100644
--- a/esphome/components/i2c/i2c.cpp
+++ b/esphome/components/i2c/i2c.cpp
@@ -8,8 +8,7 @@ namespace i2c {
static const char *TAG = "i2c";
-I2CComponent::I2CComponent(uint8_t sda_pin, uint8_t scl_pin, uint32_t frequency, bool scan)
- : sda_pin_(sda_pin), scl_pin_(scl_pin), frequency_(frequency), scan_(scan) {
+I2CComponent::I2CComponent() {
#ifdef ARDUINO_ARCH_ESP32
if (next_i2c_bus_num_ == 0)
this->wire_ = &Wire;
diff --git a/esphome/components/i2c/i2c.h b/esphome/components/i2c/i2c.h
index e8a13daaa4..0184c8020a 100644
--- a/esphome/components/i2c/i2c.h
+++ b/esphome/components/i2c/i2c.h
@@ -25,7 +25,11 @@ namespace i2c {
*/
class I2CComponent : public Component {
public:
- I2CComponent(uint8_t sda_pin, uint8_t scl_pin, uint32_t frequency, bool scan);
+ I2CComponent();
+ void set_sda_pin(uint8_t sda_pin) { sda_pin_ = sda_pin; }
+ void set_scl_pin(uint8_t scl_pin) { scl_pin_ = scl_pin; }
+ void set_frequency(uint32_t frequency) { frequency_ = frequency; }
+ void set_scan(bool scan) { scan_ = scan; }
/** Read len amount of bytes from a register into data. Optionally with a conversion time after
* writing the register value to the bus.
diff --git a/esphome/components/image/__init__.py b/esphome/components/image/__init__.py
index a7db6b5ab7..d933af1a93 100644
--- a/esphome/components/image/__init__.py
+++ b/esphome/components/image/__init__.py
@@ -17,10 +17,10 @@ Image_ = display.display_ns.class_('Image')
CONF_RAW_DATA_ID = 'raw_data_id'
IMAGE_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(Image_),
+ cv.Required(CONF_ID): cv.declare_id(Image_),
cv.Required(CONF_FILE): cv.file_,
cv.Optional(CONF_RESIZE): cv.dimensions,
- cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(cg.uint8),
+ cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
})
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA)
@@ -29,7 +29,7 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA)
def to_code(config):
from PIL import Image
- path = CORE.relative_path(config[CONF_FILE])
+ path = CORE.relative_config_path(config[CONF_FILE])
try:
image = Image.open(path)
except Exception as e:
diff --git a/esphome/components/ina219/ina219.h b/esphome/components/ina219/ina219.h
index 1df4e9726d..31cd22375e 100644
--- a/esphome/components/ina219/ina219.h
+++ b/esphome/components/ina219/ina219.h
@@ -9,7 +9,6 @@ namespace ina219 {
class INA219Component : public PollingComponent, public i2c::I2CDevice {
public:
- INA219Component(uint32_t update_interval) : PollingComponent(update_interval) {}
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/ina219/sensor.py b/esphome/components/ina219/sensor.py
index a3b60be439..a6f415edb0 100644
--- a/esphome/components/ina219/sensor.py
+++ b/esphome/components/ina219/sensor.py
@@ -4,7 +4,7 @@ import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_BUS_VOLTAGE, CONF_CURRENT, CONF_ID, \
CONF_MAX_CURRENT, CONF_MAX_VOLTAGE, CONF_POWER, CONF_SHUNT_RESISTANCE, \
- CONF_SHUNT_VOLTAGE, CONF_UPDATE_INTERVAL, ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
+ CONF_SHUNT_VOLTAGE, ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
DEPENDENCIES = ['i2c']
@@ -12,21 +12,20 @@ ina219_ns = cg.esphome_ns.namespace('ina219')
INA219Component = ina219_ns.class_('INA219Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(INA219Component),
- cv.Optional(CONF_BUS_VOLTAGE): cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2)),
- cv.Optional(CONF_SHUNT_VOLTAGE): cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2)),
- cv.Optional(CONF_CURRENT): cv.nameable(sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 3)),
- cv.Optional(CONF_POWER): cv.nameable(sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 2)),
+ cv.GenerateID(): cv.declare_id(INA219Component),
+ cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2),
+ cv.Optional(CONF_SHUNT_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2),
+ cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 3),
+ cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 2),
cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All(cv.resistance,
cv.Range(min=0.0, max=32.0)),
cv.Optional(CONF_MAX_VOLTAGE, default=32.0): cv.All(cv.voltage, cv.Range(min=0.0, max=32.0)),
cv.Optional(CONF_MAX_CURRENT, default=3.2): cv.All(cv.current, cv.Range(min=0.0)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x40))
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x40))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/ina3221/ina3221.h b/esphome/components/ina3221/ina3221.h
index b30fea4eec..f593badc09 100644
--- a/esphome/components/ina3221/ina3221.h
+++ b/esphome/components/ina3221/ina3221.h
@@ -9,7 +9,6 @@ namespace ina3221 {
class INA3221Component : public PollingComponent, public i2c::I2CDevice {
public:
- INA3221Component(uint32_t update_interval) : PollingComponent(update_interval) {}
void setup() override;
void dump_config() override;
void update() override;
diff --git a/esphome/components/ina3221/sensor.py b/esphome/components/ina3221/sensor.py
index 9e240e8b0c..199f7be624 100644
--- a/esphome/components/ina3221/sensor.py
+++ b/esphome/components/ina3221/sensor.py
@@ -3,7 +3,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_BUS_VOLTAGE, CONF_CURRENT, CONF_ID, CONF_POWER, \
- CONF_SHUNT_RESISTANCE, CONF_SHUNT_VOLTAGE, CONF_UPDATE_INTERVAL, ICON_FLASH, \
+ CONF_SHUNT_RESISTANCE, CONF_SHUNT_VOLTAGE, ICON_FLASH, \
UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
DEPENDENCIES = ['i2c']
@@ -16,25 +16,24 @@ ina3221_ns = cg.esphome_ns.namespace('ina3221')
INA3221Component = ina3221_ns.class_('INA3221Component', cg.PollingComponent, i2c.I2CDevice)
INA3221_CHANNEL_SCHEMA = cv.Schema({
- cv.Optional(CONF_BUS_VOLTAGE): cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2)),
- cv.Optional(CONF_SHUNT_VOLTAGE): cv.nameable(sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2)),
- cv.Optional(CONF_CURRENT): cv.nameable(sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2)),
- cv.Optional(CONF_POWER): cv.nameable(sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 2)),
+ cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2),
+ cv.Optional(CONF_SHUNT_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2),
+ cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
+ cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 2),
cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All(cv.resistance,
cv.Range(min=0.0, max=32.0)),
})
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(INA3221Component),
+ cv.GenerateID(): cv.declare_id(INA3221Component),
cv.Optional(CONF_CHANNEL_1): INA3221_CHANNEL_SCHEMA,
cv.Optional(CONF_CHANNEL_2): INA3221_CHANNEL_SCHEMA,
cv.Optional(CONF_CHANNEL_3): INA3221_CHANNEL_SCHEMA,
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x40))
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x40))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/integration/__init__.py b/esphome/components/integration/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/esphome/components/integration/integration_sensor.cpp b/esphome/components/integration/integration_sensor.cpp
new file mode 100644
index 0000000000..9ddfd2ad0b
--- /dev/null
+++ b/esphome/components/integration/integration_sensor.cpp
@@ -0,0 +1,68 @@
+#include "integration_sensor.h"
+#include "esphome/core/helpers.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace integration {
+
+static const char *TAG = "integration";
+
+void IntegrationSensor::setup() {
+ if (this->restore_) {
+ this->rtc_ = global_preferences.make_preference(this->get_object_id_hash());
+ this->rtc_.load(&this->result_);
+ }
+
+ this->last_update_ = millis();
+ this->publish_and_save_(this->result_);
+ this->sensor_->add_on_state_callback([this](float state) { this->process_sensor_value_(state); });
+}
+void IntegrationSensor::dump_config() { LOG_SENSOR("", "Integration Sensor", this); }
+std::string IntegrationSensor::unit_of_measurement() {
+ std::string suffix;
+ switch (this->time_) {
+ case INTEGRATION_SENSOR_TIME_MILLISECOND:
+ suffix = "ms";
+ break;
+ case INTEGRATION_SENSOR_TIME_SECOND:
+ suffix = "s";
+ break;
+ case INTEGRATION_SENSOR_TIME_MINUTE:
+ suffix = "min";
+ break;
+ case INTEGRATION_SENSOR_TIME_HOUR:
+ suffix = "h";
+ break;
+ case INTEGRATION_SENSOR_TIME_DAY:
+ suffix = "d";
+ break;
+ }
+ std::string base = this->sensor_->get_unit_of_measurement();
+ if (str_endswith(base, "/" + suffix)) {
+ return base.substr(0, base.size() - suffix.size() - 1);
+ }
+ return base + suffix;
+}
+void IntegrationSensor::process_sensor_value_(float value) {
+ const uint32_t now = millis();
+ const float old_value = this->last_value_;
+ const float new_value = value;
+ const uint32_t dt_ms = now - this->last_update_;
+ const float dt = dt_ms * this->get_time_factor_();
+ float area = 0.0f;
+ switch (this->method_) {
+ case INTEGRATION_METHOD_TRAPEZOID:
+ area = dt * (old_value + new_value) / 2.0f;
+ break;
+ case INTEGRATION_METHOD_LEFT:
+ area = dt * old_value;
+ break;
+ case INTEGRATION_METHOD_RIGHT:
+ area = dt * new_value;
+ break;
+ }
+ this->publish_and_save_(this->last_value_ + area);
+}
+
+} // namespace integration
+} // namespace esphome
diff --git a/esphome/components/integration/integration_sensor.h b/esphome/components/integration/integration_sensor.h
new file mode 100644
index 0000000000..6b1f4ccf1b
--- /dev/null
+++ b/esphome/components/integration/integration_sensor.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/core/preferences.h"
+#include "esphome/core/automation.h"
+#include "esphome/components/sensor/sensor.h"
+
+namespace esphome {
+namespace integration {
+
+enum IntegrationSensorTime {
+ INTEGRATION_SENSOR_TIME_MILLISECOND = 0,
+ INTEGRATION_SENSOR_TIME_SECOND,
+ INTEGRATION_SENSOR_TIME_MINUTE,
+ INTEGRATION_SENSOR_TIME_HOUR,
+ INTEGRATION_SENSOR_TIME_DAY,
+};
+
+enum IntegrationMethod {
+ INTEGRATION_METHOD_TRAPEZOID = 0,
+ INTEGRATION_METHOD_LEFT,
+ INTEGRATION_METHOD_RIGHT,
+};
+
+class IntegrationSensor : public sensor::Sensor, public Component {
+ public:
+ void setup() override;
+ void dump_config() override;
+ float get_setup_priority() const override { return setup_priority::DATA; }
+ void set_sensor(Sensor *sensor) { sensor_ = sensor; }
+ void set_time(IntegrationSensorTime time) { time_ = time; }
+ void set_method(IntegrationMethod method) { method_ = method; }
+ void set_restore(bool restore) { restore_ = restore; }
+ void reset() { this->publish_and_save_(0.0f); }
+
+ protected:
+ void process_sensor_value_(float value);
+ float get_time_factor_() {
+ switch (this->time_) {
+ case INTEGRATION_SENSOR_TIME_MILLISECOND:
+ return 1.0f;
+ case INTEGRATION_SENSOR_TIME_SECOND:
+ return 1.0f / 1000.0f;
+ case INTEGRATION_SENSOR_TIME_MINUTE:
+ return 1.0f / 60000.0f;
+ case INTEGRATION_SENSOR_TIME_HOUR:
+ return 1.0f / 3600000.0f;
+ case INTEGRATION_SENSOR_TIME_DAY:
+ return 1.0f / 86400000.0f;
+ default:
+ return 0.0f;
+ }
+ }
+ void publish_and_save_(float result) {
+ this->result_ = result;
+ this->publish_state(result);
+ this->rtc_.save(&result);
+ }
+ std::string unit_of_measurement() override;
+ std::string icon() override { return this->sensor_->get_icon(); }
+ int8_t accuracy_decimals() override { return this->sensor_->get_accuracy_decimals() + 2; }
+
+ sensor::Sensor *sensor_;
+ IntegrationSensorTime time_;
+ IntegrationMethod method_;
+ bool restore_;
+ ESPPreferenceObject rtc_;
+
+ uint32_t last_update_;
+ float result_{0.0f};
+ float last_value_{0.0f};
+};
+
+template class ResetAction : public Action {
+ public:
+ explicit ResetAction(IntegrationSensor *parent) : parent_(parent) {}
+
+ void play(Ts... x) override { this->parent_->reset(); }
+
+ protected:
+ IntegrationSensor *parent_;
+};
+
+} // namespace integration
+} // namespace esphome
diff --git a/esphome/components/integration/sensor.py b/esphome/components/integration/sensor.py
new file mode 100644
index 0000000000..13c69f81f2
--- /dev/null
+++ b/esphome/components/integration/sensor.py
@@ -0,0 +1,58 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.components import sensor
+from esphome.const import CONF_ID, CONF_TIME_ID, CONF_SENSOR, CONF_RESTORE
+
+integration_ns = cg.esphome_ns.namespace('integration')
+IntegrationSensor = integration_ns.class_('IntegrationSensor', sensor.Sensor, cg.Component)
+ResetAction = integration_ns.class_('ResetAction', automation.Action)
+
+IntegrationSensorTime = integration_ns.enum('IntegrationSensorTime')
+INTEGRATION_TIMES = {
+ 'ms': IntegrationSensorTime.INTEGRATION_SENSOR_TIME_MILLISECOND,
+ 's': IntegrationSensorTime.INTEGRATION_SENSOR_TIME_SECOND,
+ 'min': IntegrationSensorTime.INTEGRATION_SENSOR_TIME_MINUTE,
+ 'h': IntegrationSensorTime.INTEGRATION_SENSOR_TIME_HOUR,
+ 'd': IntegrationSensorTime.INTEGRATION_SENSOR_TIME_DAY,
+}
+IntegrationMethod = integration_ns.enum('IntegrationMethod')
+INTEGRATION_METHODS = {
+ 'trapezoid': IntegrationMethod.INTEGRATION_METHOD_TRAPEZOID,
+ 'left': IntegrationMethod.INTEGRATION_METHOD_LEFT,
+ 'right': IntegrationMethod.INTEGRATION_METHOD_RIGHT,
+}
+
+CONF_TIME_UNIT = 'time_unit'
+CONF_INTEGRATION_METHOD = 'integration_method'
+
+
+CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(IntegrationSensor),
+ cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
+ cv.Required(CONF_TIME_UNIT): cv.enum(INTEGRATION_TIMES, lower=True),
+ cv.Optional(CONF_INTEGRATION_METHOD, default='trapezoid'):
+ cv.enum(INTEGRATION_METHODS, lower=True),
+ cv.Optional(CONF_RESTORE, default=True): cv.boolean,
+}).extend(cv.COMPONENT_SCHEMA)
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+
+ yield cg.register_component(var, config)
+ yield sensor.register_sensor(var, config)
+
+ sens = yield cg.get_variable(config[CONF_SENSOR])
+ cg.add(var.set_sensor(sens))
+ cg.add(var.set_time(config[CONF_TIME_ID]))
+ cg.add(var.set_method(config[CONF_INTEGRATION_METHOD]))
+ cg.add(var.set_restore(config[CONF_RESTORE]))
+
+
+@automation.register_action('sensor.integration.reset', ResetAction, automation.maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(IntegrationSensor),
+}))
+def sensor_integration_reset_to_code(config, action_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
diff --git a/esphome/components/interval/__init__.py b/esphome/components/interval/__init__.py
index a4a4235479..e0816b7407 100644
--- a/esphome/components/interval/__init__.py
+++ b/esphome/components/interval/__init__.py
@@ -4,16 +4,19 @@ from esphome import automation
from esphome.const import CONF_ID, CONF_INTERVAL
interval_ns = cg.esphome_ns.namespace('interval')
-IntervalTrigger = interval_ns.class_('IntervalTrigger', cg.Trigger.template(), cg.PollingComponent)
+IntervalTrigger = interval_ns.class_('IntervalTrigger', automation.Trigger.template(),
+ cg.PollingComponent)
CONFIG_SCHEMA = automation.validate_automation(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(IntervalTrigger),
+ cv.GenerateID(): cv.declare_id(IntervalTrigger),
cv.Required(CONF_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(cv.COMPONENT_SCHEMA))
def to_code(config):
for conf in config:
- var = cg.new_Pvariable(conf[CONF_ID], conf[CONF_INTERVAL])
+ var = cg.new_Pvariable(conf[CONF_ID])
yield cg.register_component(var, conf)
yield automation.build_automation(var, [], conf)
+
+ cg.add(var.set_update_interval(conf[CONF_INTERVAL]))
diff --git a/esphome/components/interval/interval.h b/esphome/components/interval/interval.h
index a8365815d5..605ac868f3 100644
--- a/esphome/components/interval/interval.h
+++ b/esphome/components/interval/interval.h
@@ -8,7 +8,6 @@ namespace interval {
class IntervalTrigger : public Trigger<>, public PollingComponent {
public:
- IntervalTrigger(uint32_t update_interval) : PollingComponent(update_interval) {}
void update() override { this->trigger(); }
float get_setup_priority() const override { return setup_priority::DATA; }
};
diff --git a/esphome/components/json/__init__.py b/esphome/components/json/__init__.py
index f6a4a7f294..f719b05340 100644
--- a/esphome/components/json/__init__.py
+++ b/esphome/components/json/__init__.py
@@ -1,8 +1,10 @@
import esphome.codegen as cg
+from esphome.core import coroutine_with_priority
json_ns = cg.esphome_ns.namespace('json')
+@coroutine_with_priority(1.0)
def to_code(config):
cg.add_library('ArduinoJson-esphomelib', '5.13.3')
cg.add_define('USE_JSON')
diff --git a/esphome/components/lcd_base/__init__.py b/esphome/components/lcd_base/__init__.py
index 3cbda9e567..27f65f9336 100644
--- a/esphome/components/lcd_base/__init__.py
+++ b/esphome/components/lcd_base/__init__.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import display
-from esphome.const import CONF_DIMENSIONS, CONF_LAMBDA, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_DIMENSIONS, CONF_LAMBDA
from esphome.core import coroutine
lcd_base_ns = cg.esphome_ns.namespace('lcd_base')
@@ -20,8 +20,7 @@ def validate_lcd_dimensions(value):
LCD_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
cv.Required(CONF_DIMENSIONS): validate_lcd_dimensions,
- cv.Optional(CONF_UPDATE_INTERVAL, default='1s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA)
+}).extend(cv.polling_component_schema('1s'))
@coroutine
diff --git a/esphome/components/lcd_base/lcd_display.h b/esphome/components/lcd_base/lcd_display.h
index 366f869732..200600eb9c 100644
--- a/esphome/components/lcd_base/lcd_display.h
+++ b/esphome/components/lcd_base/lcd_display.h
@@ -16,8 +16,6 @@ using lcd_writer_t = std::function;
class LCDDisplay : public PollingComponent {
public:
- LCDDisplay(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_writer(lcd_writer_t &&writer) { this->writer_ = std::move(writer); }
void set_dimensions(uint8_t columns, uint8_t rows) {
this->columns_ = columns;
diff --git a/esphome/components/lcd_gpio/display.py b/esphome/components/lcd_gpio/display.py
index 435299058d..1f98955ece 100644
--- a/esphome/components/lcd_gpio/display.py
+++ b/esphome/components/lcd_gpio/display.py
@@ -2,8 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import lcd_base
-from esphome.const import CONF_DATA_PINS, CONF_ENABLE_PIN, CONF_RS_PIN, CONF_RW_PIN, CONF_ID, \
- CONF_UPDATE_INTERVAL
+from esphome.const import CONF_DATA_PINS, CONF_ENABLE_PIN, CONF_RS_PIN, CONF_RW_PIN, CONF_ID
AUTO_LOAD = ['lcd_base']
@@ -19,7 +18,7 @@ def validate_pin_length(value):
CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(GPIOLCDDisplay),
+ cv.GenerateID(): cv.declare_id(GPIOLCDDisplay),
cv.Required(CONF_DATA_PINS): cv.All([pins.gpio_output_pin_schema], validate_pin_length),
cv.Required(CONF_ENABLE_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_RS_PIN): pins.gpio_output_pin_schema,
@@ -28,7 +27,7 @@ CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend({
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield lcd_base.setup_lcd_display(var, config)
pins_ = []
for conf in config[CONF_DATA_PINS]:
diff --git a/esphome/components/lcd_gpio/gpio_lcd_display.h b/esphome/components/lcd_gpio/gpio_lcd_display.h
index 121b843fa9..ed3b0c1137 100644
--- a/esphome/components/lcd_gpio/gpio_lcd_display.h
+++ b/esphome/components/lcd_gpio/gpio_lcd_display.h
@@ -8,8 +8,6 @@ namespace lcd_gpio {
class GPIOLCDDisplay : public lcd_base::LCDDisplay {
public:
- GPIOLCDDisplay(uint32_t update_interval) : LCDDisplay(update_interval) {}
-
void setup() override;
void set_data_pins(GPIOPin *d0, GPIOPin *d1, GPIOPin *d2, GPIOPin *d3) {
this->data_pins_[0] = d0;
diff --git a/esphome/components/lcd_pcf8574/display.py b/esphome/components/lcd_pcf8574/display.py
index bdfd90d578..2bc04a283f 100644
--- a/esphome/components/lcd_pcf8574/display.py
+++ b/esphome/components/lcd_pcf8574/display.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import lcd_base, i2c
-from esphome.const import CONF_ID, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID
DEPENDENCIES = ['i2c']
AUTO_LOAD = ['lcd_base']
@@ -10,11 +10,11 @@ lcd_pcf8574_ns = cg.esphome_ns.namespace('lcd_pcf8574')
PCF8574LCDDisplay = lcd_pcf8574_ns.class_('PCF8574LCDDisplay', lcd_base.LCDDisplay, i2c.I2CDevice)
CONFIG_SCHEMA = lcd_base.LCD_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(PCF8574LCDDisplay),
+ cv.GenerateID(): cv.declare_id(PCF8574LCDDisplay),
}).extend(i2c.i2c_device_schema(0x3F))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield lcd_base.setup_lcd_display(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/lcd_pcf8574/pcf8574_display.h b/esphome/components/lcd_pcf8574/pcf8574_display.h
index d491e53da1..133679c501 100644
--- a/esphome/components/lcd_pcf8574/pcf8574_display.h
+++ b/esphome/components/lcd_pcf8574/pcf8574_display.h
@@ -9,7 +9,6 @@ namespace lcd_pcf8574 {
class PCF8574LCDDisplay : public lcd_base::LCDDisplay, public i2c::I2CDevice {
public:
- PCF8574LCDDisplay(uint32_t update_interval) : lcd_base::LCDDisplay(update_interval) {}
void setup() override;
void dump_config() override;
diff --git a/esphome/components/ledc/ledc_output.h b/esphome/components/ledc/ledc_output.h
index 3672cab906..d1b9b099ee 100644
--- a/esphome/components/ledc/ledc_output.h
+++ b/esphome/components/ledc/ledc_output.h
@@ -9,9 +9,11 @@
namespace esphome {
namespace ledc {
+extern uint8_t next_ledc_channel;
+
class LEDCOutput : public output::FloatOutput, public Component {
public:
- explicit LEDCOutput(GPIOPin *pin) : pin_(pin) {}
+ explicit LEDCOutput(GPIOPin *pin) : pin_(pin) { this->channel_ = next_ledc_channel++; }
void set_channel(uint8_t channel) { this->channel_ = channel; }
void set_bit_depth(uint8_t bit_depth) { this->bit_depth_ = bit_depth; }
@@ -35,8 +37,6 @@ class LEDCOutput : public output::FloatOutput, public Component {
float frequency_{};
};
-extern uint8_t next_ledc_channel;
-
} // namespace ledc
} // namespace esphome
diff --git a/esphome/components/ledc/output.py b/esphome/components/ledc/output.py
index 1a45ad17e3..fd75942672 100644
--- a/esphome/components/ledc/output.py
+++ b/esphome/components/ledc/output.py
@@ -22,7 +22,7 @@ ledc_ns = cg.esphome_ns.namespace('ledc')
LEDCOutput = ledc_ns.class_('LEDCOutput', output.FloatOutput, cg.Component)
CONFIG_SCHEMA = cv.All(output.FLOAT_OUTPUT_SCHEMA.extend({
- cv.Required(CONF_ID): cv.declare_variable_id(LEDCOutput),
+ cv.Required(CONF_ID): cv.declare_id(LEDCOutput),
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_FREQUENCY, default='1kHz'): cv.frequency,
cv.Optional(CONF_BIT_DEPTH, default=12): cv.All(cv.int_, cv.Range(min=1, max=15)),
diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py
index 9e550e93b6..858475f8cf 100644
--- a/esphome/components/light/__init__.py
+++ b/esphome/components/light/__init__.py
@@ -1,301 +1,20 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
from esphome.components import mqtt
-from esphome.const import CONF_ALPHA, CONF_BLUE, CONF_BRIGHTNESS, CONF_COLORS, CONF_COLOR_CORRECT, \
- CONF_COLOR_TEMPERATURE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_DURATION, CONF_EFFECT, \
- CONF_EFFECTS, CONF_FLASH_LENGTH, CONF_GAMMA_CORRECT, CONF_GREEN, CONF_ID, \
- CONF_INTERNAL, CONF_LAMBDA, CONF_NAME, CONF_NUM_LEDS, CONF_RANDOM, CONF_RED, \
- CONF_SPEED, CONF_STATE, CONF_TRANSITION_LENGTH, CONF_UPDATE_INTERVAL, CONF_WHITE, CONF_WIDTH, \
- CONF_MQTT_ID
-from esphome.core import coroutine
-from esphome.util import ServiceRegistry
+from esphome.const import CONF_COLOR_CORRECT, \
+ CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_ID, \
+ CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID
+from esphome.core import coroutine, coroutine_with_priority
+from .automation import light_control_to_code # noqa
+from .effects import validate_effects, BINARY_EFFECTS, \
+ MONOCHROMATIC_EFFECTS, RGB_EFFECTS, ADDRESSABLE_EFFECTS, EFFECTS_REGISTRY
+from .types import ( # noqa
+ LightState, AddressableLightState, light_ns, LightOutput, AddressableLight)
IS_PLATFORM_COMPONENT = True
-
-# Base
-light_ns = cg.esphome_ns.namespace('light')
-LightState = light_ns.class_('LightState', cg.Nameable, cg.Component)
-# Fake class for addressable lights
-AddressableLightState = light_ns.class_('LightState', LightState)
-LightOutput = light_ns.class_('LightOutput')
-AddressableLight = light_ns.class_('AddressableLight')
-AddressableLightRef = AddressableLight.operator('ref')
-
-# Actions
-ToggleAction = light_ns.class_('ToggleAction', cg.Action)
-LightControlAction = light_ns.class_('LightControlAction', cg.Action)
-
-LightColorValues = light_ns.class_('LightColorValues')
-
-# Effects
-LightEffect = light_ns.class_('LightEffect')
-RandomLightEffect = light_ns.class_('RandomLightEffect', LightEffect)
-LambdaLightEffect = light_ns.class_('LambdaLightEffect', LightEffect)
-StrobeLightEffect = light_ns.class_('StrobeLightEffect', LightEffect)
-StrobeLightEffectColor = light_ns.class_('StrobeLightEffectColor', LightEffect)
-FlickerLightEffect = light_ns.class_('FlickerLightEffect', LightEffect)
-AddressableLightEffect = light_ns.class_('AddressableLightEffect', LightEffect)
-AddressableLambdaLightEffect = light_ns.class_('AddressableLambdaLightEffect',
- AddressableLightEffect)
-AddressableRainbowLightEffect = light_ns.class_('AddressableRainbowLightEffect',
- AddressableLightEffect)
-AddressableColorWipeEffect = light_ns.class_('AddressableColorWipeEffect', AddressableLightEffect)
-AddressableColorWipeEffectColor = light_ns.struct('AddressableColorWipeEffectColor')
-AddressableScanEffect = light_ns.class_('AddressableScanEffect', AddressableLightEffect)
-AddressableTwinkleEffect = light_ns.class_('AddressableTwinkleEffect', AddressableLightEffect)
-AddressableRandomTwinkleEffect = light_ns.class_('AddressableRandomTwinkleEffect',
- AddressableLightEffect)
-AddressableFireworksEffect = light_ns.class_('AddressableFireworksEffect', AddressableLightEffect)
-AddressableFlickerEffect = light_ns.class_('AddressableFlickerEffect', AddressableLightEffect)
-
-CONF_STROBE = 'strobe'
-CONF_FLICKER = 'flicker'
-CONF_ADDRESSABLE_LAMBDA = 'addressable_lambda'
-CONF_ADDRESSABLE_RAINBOW = 'addressable_rainbow'
-CONF_ADDRESSABLE_COLOR_WIPE = 'addressable_color_wipe'
-CONF_ADDRESSABLE_SCAN = 'addressable_scan'
-CONF_ADDRESSABLE_TWINKLE = 'addressable_twinkle'
-CONF_ADDRESSABLE_RANDOM_TWINKLE = 'addressable_random_twinkle'
-CONF_ADDRESSABLE_FIREWORKS = 'addressable_fireworks'
-CONF_ADDRESSABLE_FLICKER = 'addressable_flicker'
-
-CONF_ADD_LED_INTERVAL = 'add_led_interval'
-CONF_REVERSE = 'reverse'
-CONF_MOVE_INTERVAL = 'move_interval'
-CONF_TWINKLE_PROBABILITY = 'twinkle_probability'
-CONF_PROGRESS_INTERVAL = 'progress_interval'
-CONF_SPARK_PROBABILITY = 'spark_probability'
-CONF_USE_RANDOM_COLOR = 'use_random_color'
-CONF_FADE_OUT_RATE = 'fade_out_rate'
-CONF_INTENSITY = 'intensity'
-
-BINARY_EFFECTS = [CONF_LAMBDA, CONF_STROBE]
-MONOCHROMATIC_EFFECTS = BINARY_EFFECTS + [CONF_FLICKER]
-RGB_EFFECTS = MONOCHROMATIC_EFFECTS + [CONF_RANDOM]
-ADDRESSABLE_EFFECTS = RGB_EFFECTS + [CONF_ADDRESSABLE_LAMBDA, CONF_ADDRESSABLE_RAINBOW,
- CONF_ADDRESSABLE_COLOR_WIPE, CONF_ADDRESSABLE_SCAN,
- CONF_ADDRESSABLE_TWINKLE, CONF_ADDRESSABLE_RANDOM_TWINKLE,
- CONF_ADDRESSABLE_FIREWORKS, CONF_ADDRESSABLE_FLICKER]
-
-EFFECTS_REGISTRY = ServiceRegistry()
-
-
-def register_effect(name, effect_type, default_name, schema, *extra_validators):
- schema = cv.Schema(schema).extend({
- cv.GenerateID(): cv.declare_variable_id(effect_type),
- cv.Optional(CONF_NAME, default=default_name): cv.string_strict,
- })
- validator = cv.All(schema, *extra_validators)
- register = EFFECTS_REGISTRY.register(name, validator)
-
- return register
-
-
-@register_effect('lambda', LambdaLightEffect, "Lambda", {
- cv.Required(CONF_LAMBDA): cv.lambda_,
- cv.Optional(CONF_UPDATE_INTERVAL, default='0ms'): cv.update_interval,
-})
-def lambda_effect_to_code(config):
- lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.void)
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], lambda_,
- config[CONF_UPDATE_INTERVAL])
-
-
-@register_effect('random', RandomLightEffect, "Random", {
- cv.Optional(CONF_TRANSITION_LENGTH, default='7.5s'): cv.positive_time_period_milliseconds,
- cv.Optional(CONF_UPDATE_INTERVAL, default='10s'): cv.positive_time_period_milliseconds,
-})
-def random_effect_to_code(config):
- effect = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH]))
- cg.add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL]))
- yield effect
-
-
-@register_effect('strobe', StrobeLightEffect, "Strobe", {
- cv.Optional(CONF_COLORS, default=[
- {CONF_STATE: True, CONF_DURATION: '0.5s'},
- {CONF_STATE: False, CONF_DURATION: '0.5s'},
- ]): cv.All(cv.ensure_list(cv.Schema({
- cv.Optional(CONF_STATE, default=True): cv.boolean,
- cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage,
- cv.Optional(CONF_RED, default=1.0): cv.percentage,
- cv.Optional(CONF_GREEN, default=1.0): cv.percentage,
- cv.Optional(CONF_BLUE, default=1.0): cv.percentage,
- cv.Optional(CONF_WHITE, default=1.0): cv.percentage,
- cv.Required(CONF_DURATION): cv.positive_time_period_milliseconds,
- }), cv.has_at_least_one_key(CONF_STATE, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE,
- CONF_WHITE)), cv.Length(min=2)),
-})
-def strobe_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- colors = []
- for color in config.get(CONF_COLORS, []):
- colors.append(cg.StructInitializer(
- StrobeLightEffectColor,
- ('color', LightColorValues(color[CONF_STATE], color[CONF_BRIGHTNESS],
- color[CONF_RED], color[CONF_GREEN], color[CONF_BLUE],
- color[CONF_WHITE])),
- ('duration', color[CONF_DURATION]),
- ))
- cg.add(var.set_colors(colors))
- yield var
-
-
-@register_effect('flicker', FlickerLightEffect, "Flicker", {
- cv.Optional(CONF_ALPHA, default=0.95): cv.percentage,
- cv.Optional(CONF_INTENSITY, default=0.015): cv.percentage,
-})
-def flicker_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_alpha(config[CONF_ALPHA]))
- cg.add(var.set_intensity(config[CONF_INTENSITY]))
- yield var
-
-
-@register_effect('addressable_lambda', AddressableLambdaLightEffect, "Addressable Lambda", {
- cv.Required(CONF_LAMBDA): cv.lambda_,
- cv.Optional(CONF_UPDATE_INTERVAL, default='0ms'): cv.positive_time_period_milliseconds,
-})
-def addressable_lambda_effect_to_code(config):
- args = [(AddressableLightRef, 'it')]
- lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void)
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], lambda_,
- config[CONF_UPDATE_INTERVAL])
- yield var
-
-
-@register_effect('addressable_rainbow', AddressableRainbowLightEffect, "Rainbow", {
- cv.Optional(CONF_SPEED, default=10): cv.uint32_t,
- cv.Optional(CONF_WIDTH, default=50): cv.uint32_t,
-})
-def addressable_rainbow_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_speed(config[CONF_SPEED]))
- cg.add(var.set_width(config[CONF_WIDTH]))
- yield var
-
-
-@register_effect('addressable_color_wipe', AddressableColorWipeEffect, "Color Wipe", {
- cv.Optional(CONF_COLORS, default=[{CONF_NUM_LEDS: 1, CONF_RANDOM: True}]): cv.ensure_list({
- cv.Optional(CONF_RED, default=1.0): cv.percentage,
- cv.Optional(CONF_GREEN, default=1.0): cv.percentage,
- cv.Optional(CONF_BLUE, default=1.0): cv.percentage,
- cv.Optional(CONF_WHITE, default=1.0): cv.percentage,
- cv.Optional(CONF_RANDOM, default=False): cv.boolean,
- cv.Required(CONF_NUM_LEDS): cv.All(cv.uint32_t, cv.Range(min=1)),
- }),
- cv.Optional(CONF_ADD_LED_INTERVAL, default='0.1s'): cv.positive_time_period_milliseconds,
- cv.Optional(CONF_REVERSE, default=False): cv.boolean,
-})
-def addressable_color_wipe_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_add_led_interval(config[CONF_ADD_LED_INTERVAL]))
- cg.add(var.set_reverse(config[CONF_REVERSE]))
- colors = []
- for color in config.get(CONF_COLORS, []):
- colors.append(cg.StructInitializer(
- AddressableColorWipeEffectColor,
- ('r', int(round(color[CONF_RED] * 255))),
- ('g', int(round(color[CONF_GREEN] * 255))),
- ('b', int(round(color[CONF_BLUE] * 255))),
- ('w', int(round(color[CONF_WHITE] * 255))),
- ('random', color[CONF_RANDOM]),
- ('num_leds', color[CONF_NUM_LEDS]),
- ))
- cg.add(var.set_colors(colors))
- yield var
-
-
-@register_effect('addressable_scan', AddressableScanEffect, "Scan", {
- cv.Optional(CONF_MOVE_INTERVAL, default='0.1s'): cv.positive_time_period_milliseconds,
-})
-def addressable_scan_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_move_interval(config[CONF_MOVE_INTERVAL]))
- yield var
-
-
-@register_effect('addressable_twinkle', AddressableTwinkleEffect, "Twinkle", {
- cv.Optional(CONF_TWINKLE_PROBABILITY, default='5%'): cv.percentage,
- cv.Optional(CONF_PROGRESS_INTERVAL, default='4ms'): cv.positive_time_period_milliseconds,
-})
-def addressable_twinkle_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY]))
- cg.add(var.set_progress_interval(config[CONF_PROGRESS_INTERVAL]))
- yield var
-
-
-@register_effect('addressable_random_twinkle', AddressableRandomTwinkleEffect, "Random Twinkle", {
- cv.Optional(CONF_TWINKLE_PROBABILITY, default='5%'): cv.percentage,
- cv.Optional(CONF_PROGRESS_INTERVAL, default='32ms'): cv.positive_time_period_milliseconds,
-})
-def addressable_random_twinkle_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY]))
- cg.add(var.set_progress_interval(config[CONF_PROGRESS_INTERVAL]))
- yield var
-
-
-@register_effect('addressable_fireworks', AddressableFireworksEffect, "Fireworks", {
- cv.Optional(CONF_UPDATE_INTERVAL, default='32ms'): cv.positive_time_period_milliseconds,
- cv.Optional(CONF_SPARK_PROBABILITY, default='10%'): cv.percentage,
- cv.Optional(CONF_USE_RANDOM_COLOR, default=False): cv.boolean,
- cv.Optional(CONF_FADE_OUT_RATE, default=120): cv.uint8_t,
-})
-def addressable_fireworks_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
- cg.add(var.set_spark_probability(config[CONF_SPARK_PROBABILITY]))
- cg.add(var.set_use_random_color(config[CONF_USE_RANDOM_COLOR]))
- cg.add(var.set_fade_out_rate(config[CONF_FADE_OUT_RATE]))
- yield var
-
-
-@register_effect('addressable_flicker', AddressableFlickerEffect, "Addressable Flicker", {
- cv.Optional(CONF_UPDATE_INTERVAL, default='16ms'): cv.positive_time_period_milliseconds,
- cv.Optional(CONF_INTENSITY, default='5%'): cv.percentage,
-})
-def addressable_flicker_effect_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
- cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
- cg.add(var.set_intensity(config[CONF_INTENSITY]))
- yield var
-
-
-def validate_effects(allowed_effects):
- def validator(value):
- value = cv.validate_registry('effect', EFFECTS_REGISTRY, [])(value)
- errors = []
- names = set()
- for i, x in enumerate(value):
- key = next(it for it in x.keys())
- if key not in allowed_effects:
- errors.append(
- cv.Invalid("The effect '{}' is not allowed for this "
- "light type".format(key), [i])
- )
- continue
- name = x[key][CONF_NAME]
- if name in names:
- errors.append(
- cv.Invalid(u"Found the effect name '{}' twice. All effects must have "
- u"unique names".format(name), [i])
- )
- continue
- names.add(name)
- if errors:
- raise cv.MultipleInvalid(errors)
- return value
-
- return validator
-
-
LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(LightState),
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTJSONLightComponent),
+ cv.GenerateID(): cv.declare_id(LightState),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTJSONLightComponent),
})
BINARY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend({
@@ -313,7 +32,7 @@ RGB_LIGHT_SCHEMA = BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({
})
ADDRESSABLE_LIGHT_SCHEMA = RGB_LIGHT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(AddressableLightState),
+ cv.GenerateID(): cv.declare_id(AddressableLightState),
cv.Optional(CONF_EFFECTS): validate_effects(ADDRESSABLE_EFFECTS),
cv.Optional(CONF_COLOR_CORRECT): cv.All([cv.percentage], cv.Length(min=3, max=4)),
})
@@ -346,102 +65,7 @@ def register_light(output_var, config):
yield setup_light_core_(light_var, output_var, config)
-@ACTION_REGISTRY.register('light.toggle', maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(LightState),
- cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
-}))
-def light_toggle_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ToggleAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
- if CONF_TRANSITION_LENGTH in config:
- template_ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
- cg.add(action.set_transition_length(template_))
- yield action
-
-
-@ACTION_REGISTRY.register('light.turn_off', maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(LightState),
- cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
-}))
-def light_turn_off_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = LightControlAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
- if CONF_TRANSITION_LENGTH in config:
- template_ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
- cg.add(action.set_transition_length(template_))
- yield action
-
-
-LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(LightState),
- cv.Optional(CONF_STATE): cv.templatable(cv.boolean),
- cv.Exclusive(CONF_TRANSITION_LENGTH, 'transformer'):
- cv.templatable(cv.positive_time_period_milliseconds),
- cv.Exclusive(CONF_FLASH_LENGTH, 'transformer'):
- cv.templatable(cv.positive_time_period_milliseconds),
- cv.Exclusive(CONF_EFFECT, 'transformer'): cv.templatable(cv.string),
- cv.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage),
- cv.Optional(CONF_RED): cv.templatable(cv.percentage),
- cv.Optional(CONF_GREEN): cv.templatable(cv.percentage),
- cv.Optional(CONF_BLUE): cv.templatable(cv.percentage),
- cv.Optional(CONF_WHITE): cv.templatable(cv.percentage),
- cv.Optional(CONF_COLOR_TEMPERATURE): cv.templatable(cv.color_temperature),
-})
-LIGHT_TURN_OFF_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(LightState),
- cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
- cv.Optional(CONF_STATE, default=False): False,
-})
-LIGHT_TURN_ON_ACTION_SCHEMA = maybe_simple_id(LIGHT_CONTROL_ACTION_SCHEMA.extend({
- cv.Optional(CONF_STATE, default=True): True,
-}))
-
-
-@ACTION_REGISTRY.register('light.turn_off', LIGHT_TURN_OFF_ACTION_SCHEMA)
-@ACTION_REGISTRY.register('light.turn_on', LIGHT_TURN_ON_ACTION_SCHEMA)
-@ACTION_REGISTRY.register('light.control', LIGHT_CONTROL_ACTION_SCHEMA)
-def light_control_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = LightControlAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
- if CONF_STATE in config:
- template_ = yield cg.templatable(config[CONF_STATE], args, bool)
- cg.add(action.set_state(template_))
- if CONF_TRANSITION_LENGTH in config:
- template_ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
- cg.add(action.set_transition_length(template_))
- if CONF_FLASH_LENGTH in config:
- template_ = yield cg.templatable(config[CONF_FLASH_LENGTH], args, cg.uint32)
- cg.add(action.set_flash_length(template_))
- if CONF_BRIGHTNESS in config:
- template_ = yield cg.templatable(config[CONF_BRIGHTNESS], args, float)
- cg.add(action.set_brightness(template_))
- if CONF_RED in config:
- template_ = yield cg.templatable(config[CONF_RED], args, float)
- cg.add(action.set_red(template_))
- if CONF_GREEN in config:
- template_ = yield cg.templatable(config[CONF_GREEN], args, float)
- cg.add(action.set_green(template_))
- if CONF_BLUE in config:
- template_ = yield cg.templatable(config[CONF_BLUE], args, float)
- cg.add(action.set_blue(template_))
- if CONF_WHITE in config:
- template_ = yield cg.templatable(config[CONF_WHITE], args, float)
- cg.add(action.set_white(template_))
- if CONF_COLOR_TEMPERATURE in config:
- template_ = yield cg.templatable(config[CONF_COLOR_TEMPERATURE], args, float)
- cg.add(action.set_color_temperature(template_))
- if CONF_EFFECT in config:
- template_ = yield cg.templatable(config[CONF_EFFECT], args, cg.std_string)
- cg.add(action.set_effect(template_))
- yield action
-
-
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_LIGHT')
cg.add_global(light_ns.using)
diff --git a/esphome/components/light/addressable_light.cpp b/esphome/components/light/addressable_light.cpp
new file mode 100644
index 0000000000..640d8112b1
--- /dev/null
+++ b/esphome/components/light/addressable_light.cpp
@@ -0,0 +1,96 @@
+#include "addressable_light.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace light {
+
+const ESPColor ESPColor::BLACK = ESPColor(0, 0, 0, 0);
+const ESPColor ESPColor::WHITE = ESPColor(255, 255, 255, 255);
+
+ESPColor ESPHSVColor::to_rgb() const {
+ // based on FastLED's hsv rainbow to rgb
+ const uint8_t hue = this->hue;
+ const uint8_t sat = this->saturation;
+ const uint8_t val = this->value;
+ // upper 3 hue bits are for branch selection, lower 5 are for values
+ const uint8_t offset8 = (hue & 0x1F) << 3; // 0..248
+ // third of the offset, 255/3 = 85 (actually only up to 82; 164)
+ const uint8_t third = esp_scale8(offset8, 85);
+ const uint8_t two_thirds = esp_scale8(offset8, 170);
+ ESPColor rgb(255, 255, 255, 0);
+ switch (hue >> 5) {
+ case 0b000:
+ rgb.r = 255 - third;
+ rgb.g = third;
+ rgb.b = 0;
+ break;
+ case 0b001:
+ rgb.r = 171;
+ rgb.g = 85 + third;
+ rgb.b = 0;
+ break;
+ case 0b010:
+ rgb.r = 171 - two_thirds;
+ rgb.g = 170 + third;
+ rgb.b = 0;
+ break;
+ case 0b011:
+ rgb.r = 0;
+ rgb.g = 255 - third;
+ rgb.b = third;
+ break;
+ case 0b100:
+ rgb.r = 0;
+ rgb.g = 171 - two_thirds;
+ rgb.b = 85 + two_thirds;
+ break;
+ case 0b101:
+ rgb.r = third;
+ rgb.g = 0;
+ rgb.b = 255 - third;
+ break;
+ case 0b110:
+ rgb.r = 85 + third;
+ rgb.g = 0;
+ rgb.b = 171 - third;
+ break;
+ case 0b111:
+ rgb.r = 170 + third;
+ rgb.g = 0;
+ rgb.b = 85 - third;
+ break;
+ default:
+ break;
+ }
+ // low saturation -> add uniform color to orig. hue
+ // high saturation -> use hue directly
+ // scales with square of saturation
+ // (r,g,b) = (r,g,b) * sat + (1 - sat)^2
+ rgb *= sat;
+ const uint8_t desat = 255 - sat;
+ rgb += esp_scale8(desat, desat);
+ // (r,g,b) = (r,g,b) * val
+ rgb *= val;
+ return rgb;
+}
+
+void ESPRangeView::set(const ESPColor &color) {
+ for (int32_t i = this->begin_; i < this->end_; i++) {
+ (*this->parent_)[i] = color;
+ }
+}
+ESPColorView ESPRangeView::operator[](int32_t index) const {
+ index = interpret_index(index, this->size());
+ return (*this->parent_)[index];
+}
+
+ESPColorView ESPRangeView::Iterator::operator*() const { return (*this->range_->parent_)[this->i_]; }
+
+int32_t HOT interpret_index(int32_t index, int32_t size) {
+ if (index < 0)
+ return size + index;
+ return index;
+}
+
+} // namespace light
+} // namespace esphome
diff --git a/esphome/components/light/addressable_light.h b/esphome/components/light/addressable_light.h
index a46d5d46da..993b430d3c 100644
--- a/esphome/components/light/addressable_light.h
+++ b/esphome/components/light/addressable_light.h
@@ -143,6 +143,13 @@ struct ESPColor {
return ESPColor(uint8_t((uint16_t(r) * 255U / max_rgb)), uint8_t((uint16_t(g) * 255U / max_rgb)),
uint8_t((uint16_t(b) * 255U / max_rgb)), w);
}
+ ESPColor fade_to_white(uint8_t amnt) { return ESPColor(255, 255, 255, 255) - (*this * amnt); }
+ ESPColor fade_to_black(uint8_t amnt) { return *this * amnt; }
+ ESPColor lighten(uint8_t delta) { return *this + delta; }
+ ESPColor darken(uint8_t delta) { return *this - delta; }
+
+ static const ESPColor BLACK;
+ static const ESPColor WHITE;
};
struct ESPHSVColor {
@@ -168,72 +175,7 @@ struct ESPHSVColor {
inline ESPHSVColor(uint8_t hue, uint8_t saturation, uint8_t value) ALWAYS_INLINE : hue(hue),
saturation(saturation),
value(value) {}
- ESPColor to_rgb() const {
- // based on FastLED's hsv rainbow to rgb
- const uint8_t hue = this->hue;
- const uint8_t sat = this->saturation;
- const uint8_t val = this->value;
- // upper 3 hue bits are for branch selection, lower 5 are for values
- const uint8_t offset8 = (hue & 0x1F) << 3; // 0..248
- // third of the offset, 255/3 = 85 (actually only up to 82; 164)
- const uint8_t third = esp_scale8(offset8, 85);
- const uint8_t two_thirds = esp_scale8(offset8, 170);
- ESPColor rgb(255, 255, 255, 0);
- switch (hue >> 5) {
- case 0b000:
- rgb.r = 255 - third;
- rgb.g = third;
- rgb.b = 0;
- break;
- case 0b001:
- rgb.r = 171;
- rgb.g = 85 + third;
- rgb.b = 0;
- break;
- case 0b010:
- rgb.r = 171 - two_thirds;
- rgb.g = 170 + third;
- rgb.b = 0;
- break;
- case 0b011:
- rgb.r = 0;
- rgb.g = 255 - third;
- rgb.b = third;
- break;
- case 0b100:
- rgb.r = 0;
- rgb.g = 171 - two_thirds;
- rgb.b = 85 + two_thirds;
- break;
- case 0b101:
- rgb.r = third;
- rgb.g = 0;
- rgb.b = 255 - third;
- break;
- case 0b110:
- rgb.r = 85 + third;
- rgb.g = 0;
- rgb.b = 171 - third;
- break;
- case 0b111:
- rgb.r = 170 + third;
- rgb.g = 0;
- rgb.b = 85 - third;
- break;
- default:
- break;
- }
- // low saturation -> add uniform color to orig. hue
- // high saturation -> use hue directly
- // scales with square of saturation
- // (r,g,b) = (r,g,b) * sat + (1 - sat)^2
- rgb *= sat;
- const uint8_t desat = 255 - sat;
- rgb += esp_scale8(desat, desat);
- // (r,g,b) = (r,g,b) * val
- rgb *= val;
- return rgb;
- }
+ ESPColor to_rgb() const;
};
class ESPColorCorrection {
@@ -321,75 +263,85 @@ class ESPColorCorrection {
uint8_t local_brightness_{255};
};
-class ESPColorView {
+class ESPColorSettable {
public:
- inline ESPColorView(uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *white, uint8_t *effect_data,
- const ESPColorCorrection *color_correction) ALWAYS_INLINE : red_(red),
- green_(green),
- blue_(blue),
- white_(white),
- effect_data_(effect_data),
- color_correction_(color_correction) {}
- inline const ESPColorView &operator=(const ESPColor &rhs) const ALWAYS_INLINE {
- this->set(rhs);
- return *this;
- }
- inline const ESPColorView &operator=(const ESPHSVColor &rhs) const ALWAYS_INLINE {
- this->set(rhs);
- return *this;
- }
- inline void set(const ESPColor &color) const ALWAYS_INLINE { this->set_rgbw(color.r, color.g, color.b, color.w); }
- inline void set(const ESPHSVColor &color) const ALWAYS_INLINE {
+ virtual void set(const ESPColor &color) = 0;
+ virtual void set_red(uint8_t red) = 0;
+ virtual void set_green(uint8_t green) = 0;
+ virtual void set_blue(uint8_t blue) = 0;
+ virtual void set_white(uint8_t white) = 0;
+ virtual void set_effect_data(uint8_t effect_data) = 0;
+ virtual void fade_to_white(uint8_t amnt) = 0;
+ virtual void fade_to_black(uint8_t amnt) = 0;
+ virtual void lighten(uint8_t delta) = 0;
+ virtual void darken(uint8_t delta) = 0;
+ void set(const ESPHSVColor &color) { this->set_hsv(color); }
+ void set_hsv(const ESPHSVColor &color) {
ESPColor rgb = color.to_rgb();
this->set_rgb(rgb.r, rgb.g, rgb.b);
}
- inline void set_red(uint8_t red) const ALWAYS_INLINE {
- *this->red_ = this->color_correction_->color_correct_red(red);
- }
- inline void set_green(uint8_t green) const ALWAYS_INLINE {
- *this->green_ = this->color_correction_->color_correct_green(green);
- }
- inline void set_blue(uint8_t blue) const ALWAYS_INLINE {
- *this->blue_ = this->color_correction_->color_correct_blue(blue);
- }
- inline void set_white(uint8_t white) const ALWAYS_INLINE {
- if (this->white_ == nullptr)
- return;
- *this->white_ = this->color_correction_->color_correct_white(white);
- }
- inline void set_rgb(uint8_t red, uint8_t green, uint8_t blue) const ALWAYS_INLINE {
+ void set_rgb(uint8_t red, uint8_t green, uint8_t blue) {
this->set_red(red);
this->set_green(green);
this->set_blue(blue);
}
- inline void set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) const ALWAYS_INLINE {
+ void set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
this->set_rgb(red, green, blue);
this->set_white(white);
}
- inline void set_effect_data(uint8_t effect_data) const ALWAYS_INLINE {
+};
+
+class ESPColorView : public ESPColorSettable {
+ public:
+ ESPColorView(uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *white, uint8_t *effect_data,
+ const ESPColorCorrection *color_correction)
+ : red_(red),
+ green_(green),
+ blue_(blue),
+ white_(white),
+ effect_data_(effect_data),
+ color_correction_(color_correction) {}
+ ESPColorView &operator=(const ESPColor &rhs) {
+ this->set(rhs);
+ return *this;
+ }
+ ESPColorView &operator=(const ESPHSVColor &rhs) {
+ this->set_hsv(rhs);
+ return *this;
+ }
+ void set(const ESPColor &color) override { this->set_rgbw(color.r, color.g, color.b, color.w); }
+ void set_red(uint8_t red) override { *this->red_ = this->color_correction_->color_correct_red(red); }
+ void set_green(uint8_t green) override { *this->green_ = this->color_correction_->color_correct_green(green); }
+ void set_blue(uint8_t blue) override { *this->blue_ = this->color_correction_->color_correct_blue(blue); }
+ void set_white(uint8_t white) override {
+ if (this->white_ == nullptr)
+ return;
+ *this->white_ = this->color_correction_->color_correct_white(white);
+ }
+ void set_effect_data(uint8_t effect_data) override {
if (this->effect_data_ == nullptr)
return;
*this->effect_data_ = effect_data;
}
- inline ESPColor get() const ALWAYS_INLINE {
- return ESPColor(this->get_red(), this->get_green(), this->get_blue(), this->get_white());
- }
- inline uint8_t get_red() const ALWAYS_INLINE { return this->color_correction_->color_uncorrect_red(*this->red_); }
- inline uint8_t get_green() const ALWAYS_INLINE {
- return this->color_correction_->color_uncorrect_green(*this->green_);
- }
- inline uint8_t get_blue() const ALWAYS_INLINE { return this->color_correction_->color_uncorrect_blue(*this->blue_); }
- inline uint8_t get_white() const ALWAYS_INLINE {
+ void fade_to_white(uint8_t amnt) override { this->set(this->get().fade_to_white(amnt)); }
+ void fade_to_black(uint8_t amnt) override { this->set(this->get().fade_to_black(amnt)); }
+ void lighten(uint8_t delta) override { this->set(this->get().lighten(delta)); }
+ void darken(uint8_t delta) override { this->set(this->get().darken(delta)); }
+ ESPColor get() const { return ESPColor(this->get_red(), this->get_green(), this->get_blue(), this->get_white()); }
+ uint8_t get_red() const { return this->color_correction_->color_uncorrect_red(*this->red_); }
+ uint8_t get_green() const { return this->color_correction_->color_uncorrect_green(*this->green_); }
+ uint8_t get_blue() const { return this->color_correction_->color_uncorrect_blue(*this->blue_); }
+ uint8_t get_white() const {
if (this->white_ == nullptr)
return 0;
return this->color_correction_->color_uncorrect_white(*this->white_);
}
- inline uint8_t get_effect_data() const ALWAYS_INLINE {
+ uint8_t get_effect_data() const {
if (this->effect_data_ == nullptr)
return 0;
return *this->effect_data_;
}
- inline void raw_set_color_correction(const ESPColorCorrection *color_correction) ALWAYS_INLINE {
+ void raw_set_color_correction(const ESPColorCorrection *color_correction) {
this->color_correction_ = color_correction;
}
@@ -402,11 +354,153 @@ class ESPColorView {
const ESPColorCorrection *color_correction_;
};
+class AddressableLight;
+
+int32_t interpret_index(int32_t index, int32_t size);
+
+class ESPRangeView : public ESPColorSettable {
+ public:
+ class Iterator {
+ public:
+ Iterator(ESPRangeView *range, int32_t i) : range_(range), i_(i) {}
+ Iterator operator++() {
+ this->i_++;
+ return *this;
+ }
+ bool operator!=(const Iterator &other) const { return this->i_ != other.i_; }
+ ESPColorView operator*() const;
+
+ protected:
+ ESPRangeView *range_;
+ int32_t i_;
+ };
+
+ ESPRangeView(AddressableLight *parent, int32_t begin, int32_t an_end) : parent_(parent), begin_(begin), end_(an_end) {
+ if (this->end_ < this->begin_) {
+ this->end_ = this->begin_;
+ }
+ }
+
+ ESPColorView operator[](int32_t index) const;
+ Iterator begin() { return {this, this->begin_}; }
+ Iterator end() { return {this, this->end_}; }
+
+ void set(const ESPColor &color) override;
+ ESPRangeView &operator=(const ESPColor &rhs) {
+ this->set(rhs);
+ return *this;
+ }
+ ESPRangeView &operator=(const ESPColorView &rhs) {
+ this->set(rhs.get());
+ return *this;
+ }
+ ESPRangeView &operator=(const ESPHSVColor &rhs) {
+ this->set_hsv(rhs);
+ return *this;
+ }
+ ESPRangeView &operator=(const ESPRangeView &rhs) {
+ // If size doesn't match, error (todo warning)
+ if (rhs.size() != this->size())
+ return *this;
+
+ if (this->parent_ != rhs.parent_) {
+ for (int32_t i = 0; i < this->size(); i++)
+ (*this)[i].set(rhs[i].get());
+ return *this;
+ }
+
+ // If both equal, already done
+ if (rhs.begin_ == this->begin_)
+ return *this;
+
+ if (rhs.begin_ < this->begin_) {
+ // Copy into rhs
+ for (int32_t i = 0; i < this->size(); i++)
+ rhs[i].set((*this)[i].get());
+ } else {
+ // Copy into this
+ for (int32_t i = 0; i < this->size(); i++)
+ (*this)[i].set(rhs[i].get());
+ }
+
+ return *this;
+ }
+ void set_red(uint8_t red) override {
+ for (auto c : *this)
+ c.set_red(red);
+ }
+ void set_green(uint8_t green) override {
+ for (auto c : *this)
+ c.set_green(green);
+ }
+ void set_blue(uint8_t blue) override {
+ for (auto c : *this)
+ c.set_blue(blue);
+ }
+ void set_white(uint8_t white) override {
+ for (auto c : *this)
+ c.set_white(white);
+ }
+ void set_effect_data(uint8_t effect_data) override {
+ for (auto c : *this)
+ c.set_effect_data(effect_data);
+ }
+ void fade_to_white(uint8_t amnt) override {
+ for (auto c : *this)
+ c.fade_to_white(amnt);
+ }
+ void fade_to_black(uint8_t amnt) override {
+ for (auto c : *this)
+ c.fade_to_white(amnt);
+ }
+ void lighten(uint8_t delta) override {
+ for (auto c : *this)
+ c.lighten(delta);
+ }
+ void darken(uint8_t delta) override {
+ for (auto c : *this)
+ c.darken(delta);
+ }
+ int32_t size() const { return this->end_ - this->begin_; }
+
+ protected:
+ AddressableLight *parent_;
+ int32_t begin_;
+ int32_t end_;
+};
+
class AddressableLight : public LightOutput {
public:
virtual int32_t size() const = 0;
- virtual ESPColorView operator[](int32_t index) const = 0;
+ ESPColorView operator[](int32_t index) const { return this->get_view_internal(interpret_index(index, this->size())); }
+ ESPColorView get(int32_t index) { return this->get_view_internal(interpret_index(index, this->size())); }
virtual void clear_effect_data() = 0;
+ ESPRangeView range(int32_t from, int32_t to) {
+ from = interpret_index(from, this->size());
+ to = interpret_index(to, this->size());
+ return ESPRangeView(this, from, to);
+ }
+ ESPRangeView all() { return ESPRangeView(this, 0, this->size()); }
+ ESPRangeView::Iterator begin() { return this->all().begin(); }
+ ESPRangeView::Iterator end() { return this->all().end(); }
+ void shift_left(int32_t amnt) {
+ if (amnt < 0) {
+ this->shift_right(-amnt);
+ return;
+ }
+ if (amnt > this->size())
+ amnt = this->size();
+ this->range(0, -amnt) = this->range(amnt, this->size());
+ }
+ void shift_right(int32_t amnt) {
+ if (amnt < 0) {
+ this->shift_left(-amnt);
+ return;
+ }
+ if (amnt > this->size())
+ amnt = this->size();
+ this->range(amnt, this->size()) = this->range(0, -amnt);
+ }
bool is_effect_active() const { return this->effect_active_; }
void set_effect_active(bool effect_active) { this->effect_active_ = effect_active; }
void write_state(LightState *state) override {
@@ -423,10 +517,7 @@ class AddressableLight : public LightOutput {
// white is not affected by brightness; so manually scale by state
uint8_t(roundf(val.get_white() * val.get_state() * 255.0f)));
- for (int i = 0; i < this->size(); i++) {
- (*this)[i] = color;
- }
-
+ this->all() = color;
this->schedule_show();
}
void set_correction(float red, float green, float blue, float white = 1.0f) {
@@ -439,6 +530,7 @@ class AddressableLight : public LightOutput {
protected:
bool should_show_() const { return this->effect_active_ || this->next_show_; }
void mark_shown_() { this->next_show_ = false; }
+ virtual ESPColorView get_view_internal(int32_t index) const = 0;
bool effect_active_{false};
bool next_show_{true};
diff --git a/esphome/components/light/addressable_light_effect.h b/esphome/components/light/addressable_light_effect.h
index 07b0ee34de..545af6a0f2 100644
--- a/esphome/components/light/addressable_light_effect.h
+++ b/esphome/components/light/addressable_light_effect.h
@@ -31,13 +31,9 @@ class AddressableLightEffect : public LightEffect {
void start_internal() override {
this->get_addressable_()->set_effect_active(true);
this->get_addressable_()->clear_effect_data();
- this->high_freq_.start();
this->start();
}
- void stop() override {
- this->get_addressable_()->set_effect_active(false);
- this->high_freq_.stop();
- }
+ void stop() override { this->get_addressable_()->set_effect_active(false); }
virtual void apply(AddressableLight &it, const ESPColor ¤t_color) = 0;
void apply() override {
LightColorValues color = this->state_->remote_values;
@@ -50,8 +46,6 @@ class AddressableLightEffect : public LightEffect {
protected:
AddressableLight *get_addressable_() const { return (AddressableLight *) this->state_->get_output(); }
-
- HighFrequencyLoopRequester high_freq_;
};
class AddressableLambdaLightEffect : public AddressableLightEffect {
@@ -82,9 +76,9 @@ class AddressableRainbowLightEffect : public AddressableLightEffect {
hsv.saturation = 240;
uint16_t hue = (millis() * this->speed_) % 0xFFFF;
const uint16_t add = 0xFFFF / this->width_;
- for (int i = 0; i < it.size(); i++) {
+ for (auto var : it) {
hsv.hue = hue >> 8;
- it[i] = hsv;
+ var = hsv;
hue += add;
}
}
@@ -113,22 +107,16 @@ class AddressableColorWipeEffect : public AddressableLightEffect {
if (now - this->last_add_ < this->add_led_interval_)
return;
this->last_add_ = now;
- if (!this->reverse_) {
- for (int i = 0; i < it.size() - 1; i++) {
- it[i] = it[i + 1].get();
- }
- } else {
- for (int i = it.size() - 1; i > 0; i--) {
- it[i] = it[i - 1].get();
- }
- }
+ if (this->reverse_)
+ it.shift_left(1);
+ else
+ it.shift_right(1);
const AddressableColorWipeEffectColor color = this->colors_[this->at_color_];
const ESPColor esp_color = ESPColor(color.r, color.g, color.b, color.w);
- if (!this->reverse_) {
- it[it.size() - 1] = esp_color;
- } else {
+ if (!this->reverse_)
+ it[-1] = esp_color;
+ else
it[0] = esp_color;
- }
if (++this->leds_added_ >= color.num_leds) {
this->leds_added_ = 0;
this->at_color_ = (this->at_color_ + 1) % this->colors_.size();
@@ -155,18 +143,14 @@ class AddressableScanEffect : public AddressableLightEffect {
public:
explicit AddressableScanEffect(const std::string &name) : AddressableLightEffect(name) {}
void set_move_interval(uint32_t move_interval) { this->move_interval_ = move_interval; }
- void apply(AddressableLight &addressable, const ESPColor ¤t_color) override {
- for (int i = 0; i < addressable.size(); i++) {
- if (i == this->at_led_)
- addressable[i] = current_color;
- else
- addressable[i] = ESPColor(0, 0, 0, 0);
- }
+ void apply(AddressableLight &it, const ESPColor ¤t_color) override {
+ it.all() = ESPColor::BLACK;
+ it[this->at_led_] = current_color;
const uint32_t now = millis();
if (now - this->last_move_ > this->move_interval_) {
if (direction_) {
this->at_led_++;
- if (this->at_led_ == addressable.size() - 1)
+ if (this->at_led_ == it.size() - 1)
this->direction_ = false;
} else {
this->at_led_--;
@@ -195,8 +179,7 @@ class AddressableTwinkleEffect : public AddressableLightEffect {
pos_add = pos_add32;
this->last_progress_ += pos_add32 * this->progress_interval_;
}
- for (int i = 0; i < addressable.size(); i++) {
- ESPColorView view = addressable[i];
+ for (auto view : addressable) {
if (view.get_effect_data() != 0) {
const uint8_t sine = half_sin8(view.get_effect_data());
view = current_color * sine;
@@ -206,7 +189,7 @@ class AddressableTwinkleEffect : public AddressableLightEffect {
else
view.set_effect_data(new_pos);
} else {
- view = ESPColor(0, 0, 0, 0);
+ view = ESPColor::BLACK;
}
}
while (random_float() < this->twinkle_probability_) {
@@ -236,8 +219,7 @@ class AddressableRandomTwinkleEffect : public AddressableLightEffect {
this->last_progress_ = now;
}
uint8_t subsine = ((8 * (now - this->last_progress_)) / this->progress_interval_) & 0b111;
- for (int i = 0; i < it.size(); i++) {
- ESPColorView view = it[i];
+ for (auto view : it) {
if (view.get_effect_data() != 0) {
const uint8_t x = (view.get_effect_data() >> 3) & 0b11111;
const uint8_t color = view.get_effect_data() & 0b111;
@@ -277,9 +259,8 @@ class AddressableFireworksEffect : public AddressableLightEffect {
public:
explicit AddressableFireworksEffect(const std::string &name) : AddressableLightEffect(name) {}
void start() override {
- const auto &it = *this->get_addressable_();
- for (int i = 0; i < it.size(); i++)
- it[i] = ESPColor(0, 0, 0, 0);
+ auto &it = *this->get_addressable_();
+ it.all() = ESPColor::BLACK;
}
void apply(AddressableLight &it, const ESPColor ¤t_color) override {
const uint32_t now = millis();
@@ -288,11 +269,11 @@ class AddressableFireworksEffect : public AddressableLightEffect {
this->last_update_ = now;
// "invert" the fade out parameter so that higher values make fade out faster
const uint8_t fade_out_mult = 255u - this->fade_out_rate_;
- for (int i = 0; i < it.size(); i++) {
- ESPColor target = it[i].get() * fade_out_mult;
+ for (auto view : it) {
+ ESPColor target = view.get() * fade_out_mult;
if (target.r < 64)
target *= 170;
- it[i] = target;
+ view = target;
}
int last = it.size() - 1;
it[0].set(it[0].get() + (it[1].get() * 128));
@@ -332,9 +313,9 @@ class AddressableFlickerEffect : public AddressableLightEffect {
return;
this->last_update_ = now;
fast_random_set_seed(random_uint32());
- for (int i = 0; i < it.size(); i++) {
+ for (auto var : it) {
const uint8_t flicker = fast_random_8() % this->intensity_;
- it[i] = (it[i].get() * delta_intensity) + (current_color * flicker);
+ var = (var.get() * delta_intensity) + (current_color * flicker);
}
}
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
diff --git a/esphome/components/light/automation.h b/esphome/components/light/automation.h
index 4fd001f5ba..f907c70963 100644
--- a/esphome/components/light/automation.h
+++ b/esphome/components/light/automation.h
@@ -2,6 +2,7 @@
#include "esphome/core/automation.h"
#include "light_state.h"
+#include "addressable_light.h"
namespace esphome {
namespace light {
@@ -16,7 +17,6 @@ template class ToggleAction : public Action {
auto call = this->state_->toggle();
call.set_transition_length(this->transition_length_.optional_value(x...));
call.perform();
- this->play_next(x...);
}
protected:
@@ -51,7 +51,30 @@ template class LightControlAction : public Action {
call.set_flash_length(this->flash_length_.optional_value(x...));
call.set_transition_length(this->transition_length_.optional_value(x...));
call.perform();
- this->play_next(x...);
+ }
+
+ protected:
+ LightState *parent_;
+};
+
+template class DimRelativeAction : public Action {
+ public:
+ explicit DimRelativeAction(LightState *parent) : parent_(parent) {}
+
+ TEMPLATABLE_VALUE(float, relative_brightness)
+ TEMPLATABLE_VALUE(uint32_t, transition_length)
+
+ void play(Ts... x) override {
+ auto call = this->parent_->make_call();
+ float rel = this->relative_brightness_.value(x...);
+ float cur;
+ this->parent_->remote_values.as_brightness(&cur);
+ float new_brightness = clamp(cur + rel, 0.0f, 1.0f);
+ call.set_state(new_brightness != 0.0f);
+ call.set_brightness(new_brightness);
+
+ call.set_transition_length(this->transition_length_.optional_value(x...));
+ call.perform();
}
protected:
@@ -61,7 +84,7 @@ template class LightControlAction : public Action {
template class LightIsOnCondition : public Condition {
public:
explicit LightIsOnCondition(LightState *state) : state_(state) {}
- bool check(Ts... x) override { return this->state_->get_current_values().is_on(); }
+ bool check(Ts... x) override { return this->state_->current_values.is_on(); }
protected:
LightState *state_;
@@ -69,11 +92,41 @@ template class LightIsOnCondition : public Condition {
template class LightIsOffCondition : public Condition {
public:
explicit LightIsOffCondition(LightState *state) : state_(state) {}
- bool check(Ts... x) override { return !this->state_->get_current_values().is_on(); }
+ bool check(Ts... x) override { return !this->state_->current_values.is_on(); }
protected:
LightState *state_;
};
+template class AddressableSet : public Action {
+ public:
+ explicit AddressableSet(LightState *parent) : parent_(parent) {}
+
+ TEMPLATABLE_VALUE(int32_t, range_from)
+ TEMPLATABLE_VALUE(int32_t, range_to)
+ TEMPLATABLE_VALUE(uint8_t, red)
+ TEMPLATABLE_VALUE(uint8_t, green)
+ TEMPLATABLE_VALUE(uint8_t, blue)
+ TEMPLATABLE_VALUE(uint8_t, white)
+
+ void play(Ts... x) override {
+ auto *out = (AddressableLight *) this->parent_->get_output();
+ int32_t range_from = this->range_from_.value_or(x..., 0);
+ int32_t range_to = this->range_to_.value_or(x..., out->size());
+ auto range = out->range(range_from, range_to);
+ if (this->red_.has_value())
+ range.set_red(this->red_.value(x...));
+ if (this->green_.has_value())
+ range.set_green(this->green_.value(x...));
+ if (this->blue_.has_value())
+ range.set_blue(this->blue_.value(x...));
+ if (this->white_.has_value())
+ range.set_white(this->white_.value(x...));
+ }
+
+ protected:
+ LightState *parent_;
+};
+
} // namespace light
} // namespace esphome
diff --git a/esphome/components/light/automation.py b/esphome/components/light/automation.py
new file mode 100644
index 0000000000..4718a22052
--- /dev/null
+++ b/esphome/components/light/automation.py
@@ -0,0 +1,105 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.const import CONF_ID, CONF_TRANSITION_LENGTH, CONF_STATE, CONF_FLASH_LENGTH, \
+ CONF_EFFECT, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, \
+ CONF_COLOR_TEMPERATURE
+from .types import DimRelativeAction, ToggleAction, LightState, LightControlAction
+
+
+@automation.register_action('light.toggle', ToggleAction, automation.maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(LightState),
+ cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
+}))
+def light_toggle_to_code(config, action_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
+ if CONF_TRANSITION_LENGTH in config:
+ template_ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
+ cg.add(var.set_transition_length(template_))
+ yield var
+
+
+LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(LightState),
+ cv.Optional(CONF_STATE): cv.templatable(cv.boolean),
+ cv.Exclusive(CONF_TRANSITION_LENGTH, 'transformer'):
+ cv.templatable(cv.positive_time_period_milliseconds),
+ cv.Exclusive(CONF_FLASH_LENGTH, 'transformer'):
+ cv.templatable(cv.positive_time_period_milliseconds),
+ cv.Exclusive(CONF_EFFECT, 'transformer'): cv.templatable(cv.string),
+ cv.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage),
+ cv.Optional(CONF_RED): cv.templatable(cv.percentage),
+ cv.Optional(CONF_GREEN): cv.templatable(cv.percentage),
+ cv.Optional(CONF_BLUE): cv.templatable(cv.percentage),
+ cv.Optional(CONF_WHITE): cv.templatable(cv.percentage),
+ cv.Optional(CONF_COLOR_TEMPERATURE): cv.templatable(cv.color_temperature),
+})
+LIGHT_TURN_OFF_ACTION_SCHEMA = automation.maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(LightState),
+ cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
+ cv.Optional(CONF_STATE, default=False): False,
+})
+LIGHT_TURN_ON_ACTION_SCHEMA = automation.maybe_simple_id(LIGHT_CONTROL_ACTION_SCHEMA.extend({
+ cv.Optional(CONF_STATE, default=True): True,
+}))
+
+
+@automation.register_action('light.turn_off', LightControlAction, LIGHT_TURN_OFF_ACTION_SCHEMA)
+@automation.register_action('light.turn_on', LightControlAction, LIGHT_TURN_ON_ACTION_SCHEMA)
+@automation.register_action('light.control', LightControlAction, LIGHT_CONTROL_ACTION_SCHEMA)
+def light_control_to_code(config, action_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
+ if CONF_STATE in config:
+ template_ = yield cg.templatable(config[CONF_STATE], args, bool)
+ cg.add(var.set_state(template_))
+ if CONF_TRANSITION_LENGTH in config:
+ template_ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
+ cg.add(var.set_transition_length(template_))
+ if CONF_FLASH_LENGTH in config:
+ template_ = yield cg.templatable(config[CONF_FLASH_LENGTH], args, cg.uint32)
+ cg.add(var.set_flash_length(template_))
+ if CONF_BRIGHTNESS in config:
+ template_ = yield cg.templatable(config[CONF_BRIGHTNESS], args, float)
+ cg.add(var.set_brightness(template_))
+ if CONF_RED in config:
+ template_ = yield cg.templatable(config[CONF_RED], args, float)
+ cg.add(var.set_red(template_))
+ if CONF_GREEN in config:
+ template_ = yield cg.templatable(config[CONF_GREEN], args, float)
+ cg.add(var.set_green(template_))
+ if CONF_BLUE in config:
+ template_ = yield cg.templatable(config[CONF_BLUE], args, float)
+ cg.add(var.set_blue(template_))
+ if CONF_WHITE in config:
+ template_ = yield cg.templatable(config[CONF_WHITE], args, float)
+ cg.add(var.set_white(template_))
+ if CONF_COLOR_TEMPERATURE in config:
+ template_ = yield cg.templatable(config[CONF_COLOR_TEMPERATURE], args, float)
+ cg.add(var.set_color_temperature(template_))
+ if CONF_EFFECT in config:
+ template_ = yield cg.templatable(config[CONF_EFFECT], args, cg.std_string)
+ cg.add(var.set_effect(template_))
+ yield var
+
+
+CONF_RELATIVE_BRIGHTNESS = 'relative_brightness'
+LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(LightState),
+ cv.Required(CONF_RELATIVE_BRIGHTNESS): cv.templatable(cv.percentage),
+ cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
+})
+
+
+@automation.register_action('light.dim_relative', DimRelativeAction,
+ LIGHT_DIM_RELATIVE_ACTION_SCHEMA)
+def light_dim_relative_to_code(config, action_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
+ templ = yield cg.templatable(config[CONF_RELATIVE_BRIGHTNESS], args, float)
+ cg.add(var.set_relative_brightness(templ))
+ if CONF_TRANSITION_LENGTH in config:
+ templ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
+ cg.add(var.set_transition_length(templ))
+ yield var
diff --git a/esphome/components/light/base_light_effects.h b/esphome/components/light/base_light_effects.h
index bcbb6d129a..4b33b77073 100644
--- a/esphome/components/light/base_light_effects.h
+++ b/esphome/components/light/base_light_effects.h
@@ -1,6 +1,7 @@
#pragma once
#include "light_effect.h"
+#include "esphome/core/automation.h"
namespace esphome {
namespace light {
@@ -63,6 +64,21 @@ class LambdaLightEffect : public LightEffect {
uint32_t last_run_{0};
};
+class AutomationLightEffect : public LightEffect {
+ public:
+ AutomationLightEffect(const std::string &name) : LightEffect(name) {}
+ void stop() override { this->trig_->stop(); }
+ void apply() override {
+ if (!this->trig_->is_running()) {
+ this->trig_->trigger();
+ }
+ }
+ Trigger<> *get_trig() const { return trig_; }
+
+ protected:
+ Trigger<> *trig_{new Trigger<>};
+};
+
struct StrobeLightEffectColor {
LightColorValues color;
uint32_t duration;
diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py
new file mode 100644
index 0000000000..93dea2628d
--- /dev/null
+++ b/esphome/components/light/effects.py
@@ -0,0 +1,262 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.const import CONF_NAME, CONF_LAMBDA, CONF_UPDATE_INTERVAL, CONF_TRANSITION_LENGTH, \
+ CONF_COLORS, CONF_STATE, CONF_DURATION, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, \
+ CONF_WHITE, CONF_ALPHA, CONF_INTENSITY, CONF_SPEED, CONF_WIDTH, CONF_NUM_LEDS, CONF_RANDOM, \
+ CONF_THEN
+from esphome.util import Registry
+from .types import LambdaLightEffect, RandomLightEffect, StrobeLightEffect, \
+ StrobeLightEffectColor, LightColorValues, AddressableLightRef, AddressableLambdaLightEffect, \
+ FlickerLightEffect, AddressableRainbowLightEffect, AddressableColorWipeEffect, \
+ AddressableColorWipeEffectColor, AddressableScanEffect, AddressableTwinkleEffect, \
+ AddressableRandomTwinkleEffect, AddressableFireworksEffect, AddressableFlickerEffect, \
+ AutomationLightEffect
+
+CONF_ADD_LED_INTERVAL = 'add_led_interval'
+CONF_REVERSE = 'reverse'
+CONF_MOVE_INTERVAL = 'move_interval'
+CONF_TWINKLE_PROBABILITY = 'twinkle_probability'
+CONF_PROGRESS_INTERVAL = 'progress_interval'
+CONF_SPARK_PROBABILITY = 'spark_probability'
+CONF_USE_RANDOM_COLOR = 'use_random_color'
+CONF_FADE_OUT_RATE = 'fade_out_rate'
+CONF_STROBE = 'strobe'
+CONF_FLICKER = 'flicker'
+CONF_ADDRESSABLE_LAMBDA = 'addressable_lambda'
+CONF_ADDRESSABLE_RAINBOW = 'addressable_rainbow'
+CONF_ADDRESSABLE_COLOR_WIPE = 'addressable_color_wipe'
+CONF_ADDRESSABLE_SCAN = 'addressable_scan'
+CONF_ADDRESSABLE_TWINKLE = 'addressable_twinkle'
+CONF_ADDRESSABLE_RANDOM_TWINKLE = 'addressable_random_twinkle'
+CONF_ADDRESSABLE_FIREWORKS = 'addressable_fireworks'
+CONF_ADDRESSABLE_FLICKER = 'addressable_flicker'
+CONF_AUTOMATION = 'automation'
+
+BINARY_EFFECTS = ['lambda', 'automation', 'strobe']
+MONOCHROMATIC_EFFECTS = BINARY_EFFECTS + ['flicker']
+RGB_EFFECTS = MONOCHROMATIC_EFFECTS + ['random']
+ADDRESSABLE_EFFECTS = RGB_EFFECTS + [CONF_ADDRESSABLE_LAMBDA, CONF_ADDRESSABLE_RAINBOW,
+ CONF_ADDRESSABLE_COLOR_WIPE, CONF_ADDRESSABLE_SCAN,
+ CONF_ADDRESSABLE_TWINKLE, CONF_ADDRESSABLE_RANDOM_TWINKLE,
+ CONF_ADDRESSABLE_FIREWORKS, CONF_ADDRESSABLE_FLICKER]
+
+EFFECTS_REGISTRY = Registry()
+
+
+def register_effect(name, effect_type, default_name, schema, *extra_validators):
+ schema = cv.Schema(schema).extend({
+ cv.Optional(CONF_NAME, default=default_name): cv.string_strict,
+ })
+ validator = cv.All(schema, *extra_validators)
+ return EFFECTS_REGISTRY.register(name, effect_type, validator)
+
+
+@register_effect('lambda', LambdaLightEffect, "Lambda", {
+ cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_UPDATE_INTERVAL, default='0ms'): cv.update_interval,
+})
+def lambda_effect_to_code(config, effect_id):
+ lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [], return_type=cg.void)
+ yield cg.new_Pvariable(effect_id, config[CONF_NAME], lambda_,
+ config[CONF_UPDATE_INTERVAL])
+
+
+@register_effect('automation', AutomationLightEffect, "Automation", {
+ cv.Required(CONF_THEN): automation.validate_automation(single=True),
+})
+def automation_effect_to_code(config, effect_id):
+ var = yield cg.new_Pvariable(effect_id, config[CONF_NAME])
+ yield automation.build_automation(var.get_trig(), [], config[CONF_THEN])
+ yield var
+
+
+@register_effect('random', RandomLightEffect, "Random", {
+ cv.Optional(CONF_TRANSITION_LENGTH, default='7.5s'): cv.positive_time_period_milliseconds,
+ cv.Optional(CONF_UPDATE_INTERVAL, default='10s'): cv.positive_time_period_milliseconds,
+})
+def random_effect_to_code(config, effect_id):
+ effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH]))
+ cg.add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL]))
+ yield effect
+
+
+@register_effect('strobe', StrobeLightEffect, "Strobe", {
+ cv.Optional(CONF_COLORS, default=[
+ {CONF_STATE: True, CONF_DURATION: '0.5s'},
+ {CONF_STATE: False, CONF_DURATION: '0.5s'},
+ ]): cv.All(cv.ensure_list(cv.Schema({
+ cv.Optional(CONF_STATE, default=True): cv.boolean,
+ cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage,
+ cv.Optional(CONF_RED, default=1.0): cv.percentage,
+ cv.Optional(CONF_GREEN, default=1.0): cv.percentage,
+ cv.Optional(CONF_BLUE, default=1.0): cv.percentage,
+ cv.Optional(CONF_WHITE, default=1.0): cv.percentage,
+ cv.Required(CONF_DURATION): cv.positive_time_period_milliseconds,
+ }), cv.has_at_least_one_key(CONF_STATE, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE,
+ CONF_WHITE)), cv.Length(min=2)),
+})
+def strobe_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ colors = []
+ for color in config.get(CONF_COLORS, []):
+ colors.append(cg.StructInitializer(
+ StrobeLightEffectColor,
+ ('color', LightColorValues(color[CONF_STATE], color[CONF_BRIGHTNESS],
+ color[CONF_RED], color[CONF_GREEN], color[CONF_BLUE],
+ color[CONF_WHITE])),
+ ('duration', color[CONF_DURATION]),
+ ))
+ cg.add(var.set_colors(colors))
+ yield var
+
+
+@register_effect('flicker', FlickerLightEffect, "Flicker", {
+ cv.Optional(CONF_ALPHA, default=0.95): cv.percentage,
+ cv.Optional(CONF_INTENSITY, default=0.015): cv.percentage,
+})
+def flicker_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_alpha(config[CONF_ALPHA]))
+ cg.add(var.set_intensity(config[CONF_INTENSITY]))
+ yield var
+
+
+@register_effect('addressable_lambda', AddressableLambdaLightEffect, "Addressable Lambda", {
+ cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_UPDATE_INTERVAL, default='0ms'): cv.positive_time_period_milliseconds,
+})
+def addressable_lambda_effect_to_code(config, effect_id):
+ args = [(AddressableLightRef, 'it')]
+ lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void)
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME], lambda_,
+ config[CONF_UPDATE_INTERVAL])
+ yield var
+
+
+@register_effect('addressable_rainbow', AddressableRainbowLightEffect, "Rainbow", {
+ cv.Optional(CONF_SPEED, default=10): cv.uint32_t,
+ cv.Optional(CONF_WIDTH, default=50): cv.uint32_t,
+})
+def addressable_rainbow_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_speed(config[CONF_SPEED]))
+ cg.add(var.set_width(config[CONF_WIDTH]))
+ yield var
+
+
+@register_effect('addressable_color_wipe', AddressableColorWipeEffect, "Color Wipe", {
+ cv.Optional(CONF_COLORS, default=[{CONF_NUM_LEDS: 1, CONF_RANDOM: True}]): cv.ensure_list({
+ cv.Optional(CONF_RED, default=1.0): cv.percentage,
+ cv.Optional(CONF_GREEN, default=1.0): cv.percentage,
+ cv.Optional(CONF_BLUE, default=1.0): cv.percentage,
+ cv.Optional(CONF_WHITE, default=1.0): cv.percentage,
+ cv.Optional(CONF_RANDOM, default=False): cv.boolean,
+ cv.Required(CONF_NUM_LEDS): cv.All(cv.uint32_t, cv.Range(min=1)),
+ }),
+ cv.Optional(CONF_ADD_LED_INTERVAL, default='0.1s'): cv.positive_time_period_milliseconds,
+ cv.Optional(CONF_REVERSE, default=False): cv.boolean,
+})
+def addressable_color_wipe_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_add_led_interval(config[CONF_ADD_LED_INTERVAL]))
+ cg.add(var.set_reverse(config[CONF_REVERSE]))
+ colors = []
+ for color in config.get(CONF_COLORS, []):
+ colors.append(cg.StructInitializer(
+ AddressableColorWipeEffectColor,
+ ('r', int(round(color[CONF_RED] * 255))),
+ ('g', int(round(color[CONF_GREEN] * 255))),
+ ('b', int(round(color[CONF_BLUE] * 255))),
+ ('w', int(round(color[CONF_WHITE] * 255))),
+ ('random', color[CONF_RANDOM]),
+ ('num_leds', color[CONF_NUM_LEDS]),
+ ))
+ cg.add(var.set_colors(colors))
+ yield var
+
+
+@register_effect('addressable_scan', AddressableScanEffect, "Scan", {
+ cv.Optional(CONF_MOVE_INTERVAL, default='0.1s'): cv.positive_time_period_milliseconds,
+})
+def addressable_scan_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_move_interval(config[CONF_MOVE_INTERVAL]))
+ yield var
+
+
+@register_effect('addressable_twinkle', AddressableTwinkleEffect, "Twinkle", {
+ cv.Optional(CONF_TWINKLE_PROBABILITY, default='5%'): cv.percentage,
+ cv.Optional(CONF_PROGRESS_INTERVAL, default='4ms'): cv.positive_time_period_milliseconds,
+})
+def addressable_twinkle_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY]))
+ cg.add(var.set_progress_interval(config[CONF_PROGRESS_INTERVAL]))
+ yield var
+
+
+@register_effect('addressable_random_twinkle', AddressableRandomTwinkleEffect, "Random Twinkle", {
+ cv.Optional(CONF_TWINKLE_PROBABILITY, default='5%'): cv.percentage,
+ cv.Optional(CONF_PROGRESS_INTERVAL, default='32ms'): cv.positive_time_period_milliseconds,
+})
+def addressable_random_twinkle_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY]))
+ cg.add(var.set_progress_interval(config[CONF_PROGRESS_INTERVAL]))
+ yield var
+
+
+@register_effect('addressable_fireworks', AddressableFireworksEffect, "Fireworks", {
+ cv.Optional(CONF_UPDATE_INTERVAL, default='32ms'): cv.positive_time_period_milliseconds,
+ cv.Optional(CONF_SPARK_PROBABILITY, default='10%'): cv.percentage,
+ cv.Optional(CONF_USE_RANDOM_COLOR, default=False): cv.boolean,
+ cv.Optional(CONF_FADE_OUT_RATE, default=120): cv.uint8_t,
+})
+def addressable_fireworks_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
+ cg.add(var.set_spark_probability(config[CONF_SPARK_PROBABILITY]))
+ cg.add(var.set_use_random_color(config[CONF_USE_RANDOM_COLOR]))
+ cg.add(var.set_fade_out_rate(config[CONF_FADE_OUT_RATE]))
+ yield var
+
+
+@register_effect('addressable_flicker', AddressableFlickerEffect, "Addressable Flicker", {
+ cv.Optional(CONF_UPDATE_INTERVAL, default='16ms'): cv.positive_time_period_milliseconds,
+ cv.Optional(CONF_INTENSITY, default='5%'): cv.percentage,
+})
+def addressable_flicker_effect_to_code(config, effect_id):
+ var = cg.new_Pvariable(effect_id, config[CONF_NAME])
+ cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
+ cg.add(var.set_intensity(config[CONF_INTENSITY]))
+ yield var
+
+
+def validate_effects(allowed_effects):
+ def validator(value):
+ value = cv.validate_registry('effect', EFFECTS_REGISTRY)(value)
+ errors = []
+ names = set()
+ for i, x in enumerate(value):
+ key = next(it for it in x.keys())
+ if key not in allowed_effects:
+ errors.append(
+ cv.Invalid("The effect '{}' is not allowed for this "
+ "light type".format(key), [i])
+ )
+ continue
+ name = x[key][CONF_NAME]
+ if name in names:
+ errors.append(
+ cv.Invalid(u"Found the effect name '{}' twice. All effects must have "
+ u"unique names".format(name), [i])
+ )
+ continue
+ names.add(name)
+ if errors:
+ raise cv.MultipleInvalid(errors)
+ return value
+
+ return validator
diff --git a/esphome/components/light/types.py b/esphome/components/light/types.py
new file mode 100644
index 0000000000..c9f638a4a4
--- /dev/null
+++ b/esphome/components/light/types.py
@@ -0,0 +1,39 @@
+import esphome.codegen as cg
+from esphome import automation
+
+# Base
+light_ns = cg.esphome_ns.namespace('light')
+LightState = light_ns.class_('LightState', cg.Nameable, cg.Component)
+# Fake class for addressable lights
+AddressableLightState = light_ns.class_('LightState', LightState)
+LightOutput = light_ns.class_('LightOutput')
+AddressableLight = light_ns.class_('AddressableLight')
+AddressableLightRef = AddressableLight.operator('ref')
+LightColorValues = light_ns.class_('LightColorValues')
+
+# Actions
+ToggleAction = light_ns.class_('ToggleAction', automation.Action)
+LightControlAction = light_ns.class_('LightControlAction', automation.Action)
+DimRelativeAction = light_ns.class_('DimRelativeAction', automation.Action)
+
+# Effects
+LightEffect = light_ns.class_('LightEffect')
+RandomLightEffect = light_ns.class_('RandomLightEffect', LightEffect)
+LambdaLightEffect = light_ns.class_('LambdaLightEffect', LightEffect)
+AutomationLightEffect = light_ns.class_('AutomationLightEffect', LightEffect)
+StrobeLightEffect = light_ns.class_('StrobeLightEffect', LightEffect)
+StrobeLightEffectColor = light_ns.class_('StrobeLightEffectColor', LightEffect)
+FlickerLightEffect = light_ns.class_('FlickerLightEffect', LightEffect)
+AddressableLightEffect = light_ns.class_('AddressableLightEffect', LightEffect)
+AddressableLambdaLightEffect = light_ns.class_('AddressableLambdaLightEffect',
+ AddressableLightEffect)
+AddressableRainbowLightEffect = light_ns.class_('AddressableRainbowLightEffect',
+ AddressableLightEffect)
+AddressableColorWipeEffect = light_ns.class_('AddressableColorWipeEffect', AddressableLightEffect)
+AddressableColorWipeEffectColor = light_ns.struct('AddressableColorWipeEffectColor')
+AddressableScanEffect = light_ns.class_('AddressableScanEffect', AddressableLightEffect)
+AddressableTwinkleEffect = light_ns.class_('AddressableTwinkleEffect', AddressableLightEffect)
+AddressableRandomTwinkleEffect = light_ns.class_('AddressableRandomTwinkleEffect',
+ AddressableLightEffect)
+AddressableFireworksEffect = light_ns.class_('AddressableFireworksEffect', AddressableLightEffect)
+AddressableFlickerEffect = light_ns.class_('AddressableFlickerEffect', AddressableLightEffect)
diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py
index c8b3dbaa67..9e351d0b01 100644
--- a/esphome/components/logger/__init__.py
+++ b/esphome/components/logger/__init__.py
@@ -2,7 +2,8 @@ import re
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY, LambdaAction
+from esphome import automation
+from esphome.automation import LambdaAction
from esphome.const import CONF_ARGS, CONF_BAUD_RATE, CONF_FORMAT, CONF_HARDWARE_UART, CONF_ID, \
CONF_LEVEL, CONF_LOGS, CONF_TAG, CONF_TX_BUFFER_SIZE
from esphome.core import CORE, EsphomeError, Lambda, coroutine_with_priority
@@ -71,7 +72,7 @@ def validate_local_no_higher_than_global(value):
Logger = logger_ns.class_('Logger', cg.Component)
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(Logger),
+ cv.GenerateID(): cv.declare_id(Logger),
cv.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int,
cv.Optional(CONF_TX_BUFFER_SIZE, default=512): cv.validate_bytes,
cv.Optional(CONF_HARDWARE_UART, default='UART0'): uart_selection,
@@ -172,7 +173,7 @@ LOGGER_LOG_ACTION_SCHEMA = cv.All(maybe_simple_message({
}), validate_printf)
-@ACTION_REGISTRY.register(CONF_LOGGER_LOG, LOGGER_LOG_ACTION_SCHEMA)
+@automation.register_action(CONF_LOGGER_LOG, LambdaAction, LOGGER_LOG_ACTION_SCHEMA)
def logger_log_action_to_code(config, action_id, template_arg, args):
esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]]
args_ = [cg.RawExpression(text_type(x)) for x in config[CONF_ARGS]]
@@ -180,6 +181,4 @@ def logger_log_action_to_code(config, action_id, template_arg, args):
text = text_type(cg.statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args_)))
lambda_ = yield cg.process_lambda(Lambda(text), args, return_type=cg.void)
- rhs = LambdaAction.new(template_arg, lambda_)
- type = LambdaAction.template(template_arg)
- yield cg.Pvariable(action_id, rhs, type=type)
+ yield cg.new_Pvariable(action_id, template_arg, lambda_)
diff --git a/esphome/components/max31855/max31855.cpp b/esphome/components/max31855/max31855.cpp
index 4465173430..18a00b10d7 100644
--- a/esphome/components/max31855/max31855.cpp
+++ b/esphome/components/max31855/max31855.cpp
@@ -6,9 +6,6 @@ namespace max31855 {
static const char *TAG = "max31855";
-MAX31855Sensor::MAX31855Sensor(const std::string &name, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval) {}
-
void MAX31855Sensor::update() {
this->enable();
delay(1);
diff --git a/esphome/components/max31855/max31855.h b/esphome/components/max31855/max31855.h
index b40799ff5c..f9cdf335f1 100644
--- a/esphome/components/max31855/max31855.h
+++ b/esphome/components/max31855/max31855.h
@@ -7,10 +7,8 @@
namespace esphome {
namespace max31855 {
-class MAX31855Sensor : public sensor::PollingSensorComponent, public spi::SPIDevice {
+class MAX31855Sensor : public sensor::Sensor, public PollingComponent, public spi::SPIDevice {
public:
- MAX31855Sensor(const std::string &name, uint32_t update_interval);
-
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/max31855/sensor.py b/esphome/components/max31855/sensor.py
index d76766ca85..7178488ebb 100644
--- a/esphome/components/max31855/sensor.py
+++ b/esphome/components/max31855/sensor.py
@@ -1,21 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, spi
-from esphome.const import CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, \
- ICON_THERMOMETER, UNIT_CELSIUS
+from esphome.const import CONF_ID, ICON_THERMOMETER, UNIT_CELSIUS
max31855_ns = cg.esphome_ns.namespace('max31855')
MAX31855Sensor = max31855_ns.class_('MAX31855Sensor', sensor.PollingSensorComponent, spi.SPIDevice)
-CONFIG_SCHEMA = cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
- cv.GenerateID(): cv.declare_variable_id(MAX31855Sensor),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
- }).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA))
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
+ cv.GenerateID(): cv.declare_id(MAX31855Sensor),
+}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield spi.register_spi_device(var, config)
yield sensor.register_sensor(var, config)
diff --git a/esphome/components/max6675/max6675.cpp b/esphome/components/max6675/max6675.cpp
index 9918aafe8e..e9bbfb4a05 100644
--- a/esphome/components/max6675/max6675.cpp
+++ b/esphome/components/max6675/max6675.cpp
@@ -6,9 +6,6 @@ namespace max6675 {
static const char *TAG = "max6675";
-MAX6675Sensor::MAX6675Sensor(const std::string &name, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval) {}
-
void MAX6675Sensor::update() {
this->enable();
delay(1);
diff --git a/esphome/components/max6675/max6675.h b/esphome/components/max6675/max6675.h
index e3e4f2061a..48f51fbe11 100644
--- a/esphome/components/max6675/max6675.h
+++ b/esphome/components/max6675/max6675.h
@@ -7,10 +7,8 @@
namespace esphome {
namespace max6675 {
-class MAX6675Sensor : public sensor::PollingSensorComponent, public spi::SPIDevice {
+class MAX6675Sensor : public sensor::Sensor, public PollingComponent, public spi::SPIDevice {
public:
- MAX6675Sensor(const std::string &name, uint32_t update_interval);
-
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/max6675/sensor.py b/esphome/components/max6675/sensor.py
index 9e27f483c7..af089614f0 100644
--- a/esphome/components/max6675/sensor.py
+++ b/esphome/components/max6675/sensor.py
@@ -1,21 +1,19 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, spi
-from esphome.const import CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, ICON_THERMOMETER, UNIT_CELSIUS
+from esphome.const import CONF_ID, ICON_THERMOMETER, UNIT_CELSIUS
max6675_ns = cg.esphome_ns.namespace('max6675')
MAX6675Sensor = max6675_ns.class_('MAX6675Sensor', sensor.PollingSensorComponent,
spi.SPIDevice)
-CONFIG_SCHEMA = cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
- cv.GenerateID(): cv.declare_variable_id(MAX6675Sensor),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
- }).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA))
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
+ cv.GenerateID(): cv.declare_id(MAX6675Sensor),
+}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield spi.register_spi_device(var, config)
yield sensor.register_sensor(var, config)
diff --git a/esphome/components/max7219/display.py b/esphome/components/max7219/display.py
index 92f386a9d0..b40fbafddb 100644
--- a/esphome/components/max7219/display.py
+++ b/esphome/components/max7219/display.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import display, spi
-from esphome.const import CONF_ID, CONF_INTENSITY, CONF_LAMBDA, CONF_NUM_CHIPS, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID, CONF_INTENSITY, CONF_LAMBDA, CONF_NUM_CHIPS
DEPENDENCIES = ['spi']
@@ -10,16 +10,15 @@ MAX7219Component = max7219_ns.class_('MAX7219Component', cg.PollingComponent, sp
MAX7219ComponentRef = MAX7219Component.operator('ref')
CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(MAX7219Component),
+ cv.GenerateID(): cv.declare_id(MAX7219Component),
- cv.Optional(CONF_UPDATE_INTERVAL, default='1s'): cv.update_interval,
cv.Optional(CONF_NUM_CHIPS, default=1): cv.All(cv.uint8_t, cv.Range(min=1)),
cv.Optional(CONF_INTENSITY, default=15): cv.All(cv.uint8_t, cv.Range(min=0, max=15)),
-}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA)
+}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield spi.register_spi_device(var, config)
yield display.register_display(var, config)
diff --git a/esphome/components/max7219/max7219.h b/esphome/components/max7219/max7219.h
index 6b3c7c399a..e2379fa69b 100644
--- a/esphome/components/max7219/max7219.h
+++ b/esphome/components/max7219/max7219.h
@@ -18,8 +18,6 @@ using max7219_writer_t = std::function;
class MAX7219Component : public PollingComponent, public spi::SPIDevice {
public:
- MAX7219Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_writer(max7219_writer_t &&writer);
void setup() override;
diff --git a/esphome/components/mcp23017/__init__.py b/esphome/components/mcp23017/__init__.py
index 94435c630d..4b798bf434 100644
--- a/esphome/components/mcp23017/__init__.py
+++ b/esphome/components/mcp23017/__init__.py
@@ -19,7 +19,7 @@ MCP23017 = mcp23017_ns.class_('MCP23017', cg.Component, i2c.I2CDevice)
MCP23017GPIOPin = mcp23017_ns.class_('MCP23017GPIOPin', cg.GPIOPin)
CONFIG_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(MCP23017),
+ cv.Required(CONF_ID): cv.declare_id(MCP23017),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x20))
@@ -31,15 +31,15 @@ def to_code(config):
CONF_MCP23017 = 'mcp23017'
MCP23017_OUTPUT_PIN_SCHEMA = cv.Schema({
- cv.Required(CONF_MCP23017): cv.use_variable_id(MCP23017),
+ cv.Required(CONF_MCP23017): cv.use_id(MCP23017),
cv.Required(CONF_NUMBER): cv.int_,
- cv.Optional(CONF_MODE, default="OUTPUT"): cv.one_of(*MCP23017_GPIO_MODES, upper=True),
+ cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(MCP23017_GPIO_MODES, upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
MCP23017_INPUT_PIN_SCHEMA = cv.Schema({
- cv.Required(CONF_MCP23017): cv.use_variable_id(MCP23017),
+ cv.Required(CONF_MCP23017): cv.use_id(MCP23017),
cv.Required(CONF_NUMBER): cv.int_,
- cv.Optional(CONF_MODE, default="INPUT"): cv.one_of(*MCP23017_GPIO_MODES, upper=True),
+ cv.Optional(CONF_MODE, default="INPUT"): cv.enum(MCP23017_GPIO_MODES, upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
@@ -48,5 +48,4 @@ MCP23017_INPUT_PIN_SCHEMA = cv.Schema({
(MCP23017_OUTPUT_PIN_SCHEMA, MCP23017_INPUT_PIN_SCHEMA))
def mcp23017_pin_to_code(config):
parent = yield cg.get_variable(config[CONF_MCP23017])
- yield MCP23017GPIOPin.new(parent, config[CONF_NUMBER],
- MCP23017_GPIO_MODES[config[CONF_MODE]], config[CONF_INVERTED])
+ yield MCP23017GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED])
diff --git a/esphome/components/mhz19/mhz19.h b/esphome/components/mhz19/mhz19.h
index 857e86a02f..3604628afc 100644
--- a/esphome/components/mhz19/mhz19.h
+++ b/esphome/components/mhz19/mhz19.h
@@ -9,8 +9,6 @@ namespace mhz19 {
class MHZ19Component : public PollingComponent, public uart::UARTDevice {
public:
- MHZ19Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
float get_setup_priority() const override;
void update() override;
diff --git a/esphome/components/mhz19/sensor.py b/esphome/components/mhz19/sensor.py
index de0d5c7420..368426e6f7 100644
--- a/esphome/components/mhz19/sensor.py
+++ b/esphome/components/mhz19/sensor.py
@@ -1,9 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, uart
-from esphome.const import CONF_CO2, CONF_ID, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, \
- ICON_PERIODIC_TABLE_CO2, UNIT_PARTS_PER_MILLION, UNIT_CELSIUS, \
- ICON_THERMOMETER
+from esphome.const import CONF_CO2, CONF_ID, CONF_TEMPERATURE, ICON_PERIODIC_TABLE_CO2, \
+ UNIT_PARTS_PER_MILLION, UNIT_CELSIUS, ICON_THERMOMETER
DEPENDENCIES = ['uart']
@@ -11,17 +10,14 @@ mhz19_ns = cg.esphome_ns.namespace('mhz19')
MHZ19Component = mhz19_ns.class_('MHZ19Component', cg.PollingComponent, uart.UARTDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MHZ19Component),
- cv.Required(CONF_CO2): cv.nameable(
- sensor.sensor_schema(UNIT_PARTS_PER_MILLION, ICON_PERIODIC_TABLE_CO2, 0)),
- cv.Optional(CONF_TEMPERATURE): cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 0)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
+ cv.GenerateID(): cv.declare_id(MHZ19Component),
+ cv.Required(CONF_CO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, ICON_PERIODIC_TABLE_CO2, 0),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 0),
+}).extend(cv.polling_component_schema('60s')).extend(uart.UART_DEVICE_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield uart.register_uart_device(var, config)
diff --git a/esphome/components/monochromatic/light.py b/esphome/components/monochromatic/light.py
index c69f547764..79faacff6c 100644
--- a/esphome/components/monochromatic/light.py
+++ b/esphome/components/monochromatic/light.py
@@ -6,13 +6,15 @@ from esphome.const import CONF_OUTPUT_ID, CONF_OUTPUT
monochromatic_ns = cg.esphome_ns.namespace('monochromatic')
MonochromaticLightOutput = monochromatic_ns.class_('MonochromaticLightOutput', light.LightOutput)
-CONFIG_SCHEMA = cv.nameable(light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(MonochromaticLightOutput),
- cv.Required(CONF_OUTPUT): cv.use_variable_id(output.FloatOutput),
-}))
+CONFIG_SCHEMA = light.BRIGHTNESS_ONLY_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(MonochromaticLightOutput),
+ cv.Required(CONF_OUTPUT): cv.use_id(output.FloatOutput),
+})
def to_code(config):
- out = yield cg.get_variable(config[CONF_OUTPUT])
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], out)
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield light.register_light(var, config)
+
+ out = yield cg.get_variable(config[CONF_OUTPUT])
+ cg.add(var.set_output(out))
diff --git a/esphome/components/monochromatic/monochromatic_light_output.h b/esphome/components/monochromatic/monochromatic_light_output.h
index 93c10bb27c..c3a015ff3c 100644
--- a/esphome/components/monochromatic/monochromatic_light_output.h
+++ b/esphome/components/monochromatic/monochromatic_light_output.h
@@ -9,7 +9,7 @@ namespace monochromatic {
class MonochromaticLightOutput : public light::LightOutput {
public:
- MonochromaticLightOutput(output::FloatOutput *output) : output_(output) {}
+ void set_output(output::FloatOutput *output) { output_ = output; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
diff --git a/esphome/components/mpr121/__init__.py b/esphome/components/mpr121/__init__.py
index 79a69037f9..9e1bd3726d 100644
--- a/esphome/components/mpr121/__init__.py
+++ b/esphome/components/mpr121/__init__.py
@@ -12,7 +12,7 @@ MPR121Component = mpr121_ns.class_('MPR121Component', cg.Component, i2c.I2CDevic
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MPR121Component),
+ cv.GenerateID(): cv.declare_id(MPR121Component),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x5A))
diff --git a/esphome/components/mpr121/binary_sensor.py b/esphome/components/mpr121/binary_sensor.py
index 7b2e5f5aca..100dacd6dd 100644
--- a/esphome/components/mpr121/binary_sensor.py
+++ b/esphome/components/mpr121/binary_sensor.py
@@ -1,21 +1,24 @@
-from esphome.components import binary_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_CHANNEL, CONF_NAME, CONF_ID
+import esphome.config_validation as cv
+from esphome.components import binary_sensor
+from esphome.const import CONF_CHANNEL, CONF_ID
from . import mpr121_ns, MPR121Component, CONF_MPR121_ID
DEPENDENCIES = ['mpr121']
MPR121Channel = mpr121_ns.class_('MPR121Channel', binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(MPR121Channel),
- cv.GenerateID(CONF_MPR121_ID): cv.use_variable_id(MPR121Component),
- cv.Required(CONF_CHANNEL): cv.All(cv.int_, cv.Range(min=0, max=11))
-}))
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(MPR121Channel),
+ cv.GenerateID(CONF_MPR121_ID): cv.use_id(MPR121Component),
+ cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=11),
+})
def to_code(config):
- hub = yield cg.get_variable(config[CONF_MPR121_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_CHANNEL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
+
+ cg.add(var.set_channel(config[CONF_CHANNEL]))
+
+ hub = yield cg.get_variable(config[CONF_MPR121_ID])
cg.add(hub.register_channel(var))
diff --git a/esphome/components/mpr121/mpr121.h b/esphome/components/mpr121/mpr121.h
index 4b05600e03..d5a2ec3243 100644
--- a/esphome/components/mpr121/mpr121.h
+++ b/esphome/components/mpr121/mpr121.h
@@ -47,11 +47,11 @@ enum {
class MPR121Channel : public binary_sensor::BinarySensor {
public:
- MPR121Channel(const std::string &name, int channel) : BinarySensor(name), channel_(channel) {}
+ void set_channel(uint8_t channel) { channel_ = channel; }
void process(uint16_t data) { this->publish_state(static_cast(data & (1 << this->channel_))); }
protected:
- int channel_{0};
+ uint8_t channel_{0};
};
class MPR121Component : public Component, public i2c::I2CDevice {
diff --git a/esphome/components/mpu6050/mpu6050.h b/esphome/components/mpu6050/mpu6050.h
index 3f6519bd2f..ab410105c0 100644
--- a/esphome/components/mpu6050/mpu6050.h
+++ b/esphome/components/mpu6050/mpu6050.h
@@ -9,8 +9,6 @@ namespace mpu6050 {
class MPU6050Component : public PollingComponent, public i2c::I2CDevice {
public:
- MPU6050Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void setup() override;
void dump_config() override;
diff --git a/esphome/components/mpu6050/sensor.py b/esphome/components/mpu6050/sensor.py
index 3dd7355f4a..bf44c67848 100644
--- a/esphome/components/mpu6050/sensor.py
+++ b/esphome/components/mpu6050/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID, CONF_TEMPERATURE, \
- CONF_UPDATE_INTERVAL, ICON_BRIEFCASE_DOWNLOAD, UNIT_METER_PER_SECOND_SQUARED, \
+ ICON_BRIEFCASE_DOWNLOAD, UNIT_METER_PER_SECOND_SQUARED, \
ICON_SCREEN_ROTATION, UNIT_DEGREE_PER_SECOND, ICON_THERMOMETER, UNIT_CELSIUS
DEPENDENCIES = ['i2c']
@@ -22,20 +22,19 @@ gyro_schema = sensor.sensor_schema(UNIT_DEGREE_PER_SECOND, ICON_SCREEN_ROTATION,
temperature_schema = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MPU6050Component),
- cv.Optional(CONF_ACCEL_X): cv.nameable(accel_schema),
- cv.Optional(CONF_ACCEL_Y): cv.nameable(accel_schema),
- cv.Optional(CONF_ACCEL_Z): cv.nameable(accel_schema),
- cv.Optional(CONF_GYRO_X): cv.nameable(gyro_schema),
- cv.Optional(CONF_GYRO_Y): cv.nameable(gyro_schema),
- cv.Optional(CONF_GYRO_Z): cv.nameable(gyro_schema),
- cv.Optional(CONF_TEMPERATURE): cv.nameable(temperature_schema),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x68))
+ cv.GenerateID(): cv.declare_id(MPU6050Component),
+ cv.Optional(CONF_ACCEL_X): accel_schema,
+ cv.Optional(CONF_ACCEL_Y): accel_schema,
+ cv.Optional(CONF_ACCEL_Z): accel_schema,
+ cv.Optional(CONF_GYRO_X): gyro_schema,
+ cv.Optional(CONF_GYRO_Y): gyro_schema,
+ cv.Optional(CONF_GYRO_Z): gyro_schema,
+ cv.Optional(CONF_TEMPERATURE): temperature_schema,
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x68))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/mqtt/__init__.py b/esphome/components/mqtt/__init__.py
index 3149bb8a6d..16a88f39e3 100644
--- a/esphome/components/mqtt/__init__.py
+++ b/esphome/components/mqtt/__init__.py
@@ -1,10 +1,10 @@
import re
-from esphome import automation
-from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY, Condition
-from esphome.components import logger
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.automation import Condition
+from esphome.components import logger
from esphome.const import CONF_AVAILABILITY, CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, \
CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, \
CONF_ID, CONF_KEEPALIVE, CONF_LEVEL, CONF_LOG_TOPIC, CONF_ON_JSON_MESSAGE, CONF_ON_MESSAGE, \
@@ -14,6 +14,7 @@ from esphome.const import CONF_AVAILABILITY, CONF_BIRTH_MESSAGE, CONF_BROKER, CO
CONF_WILL_MESSAGE
from esphome.core import coroutine_with_priority, coroutine, CORE
+DEPENDENCIES = ['network']
AUTO_LOAD = ['json']
@@ -37,11 +38,12 @@ MQTT_MESSAGE_SCHEMA = cv.Any(None, MQTT_MESSAGE_BASE.extend({
mqtt_ns = cg.esphome_ns.namespace('mqtt')
MQTTMessage = mqtt_ns.struct('MQTTMessage')
MQTTClientComponent = mqtt_ns.class_('MQTTClientComponent', cg.Component)
-MQTTPublishAction = mqtt_ns.class_('MQTTPublishAction', cg.Action)
-MQTTPublishJsonAction = mqtt_ns.class_('MQTTPublishJsonAction', cg.Action)
-MQTTMessageTrigger = mqtt_ns.class_('MQTTMessageTrigger', cg.Trigger.template(cg.std_string))
+MQTTPublishAction = mqtt_ns.class_('MQTTPublishAction', automation.Action)
+MQTTPublishJsonAction = mqtt_ns.class_('MQTTPublishJsonAction', automation.Action)
+MQTTMessageTrigger = mqtt_ns.class_('MQTTMessageTrigger',
+ automation.Trigger.template(cg.std_string))
MQTTJsonMessageTrigger = mqtt_ns.class_('MQTTJsonMessageTrigger',
- cg.Trigger.template(cg.JsonObjectConstRef))
+ automation.Trigger.template(cg.JsonObjectConstRef))
MQTTComponent = mqtt_ns.class_('MQTTComponent', cg.Component)
MQTTConnectedCondition = mqtt_ns.class_('MQTTConnectedCondition', Condition)
@@ -97,12 +99,12 @@ def validate_fingerprint(value):
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MQTTClientComponent),
+ cv.GenerateID(): cv.declare_id(MQTTClientComponent),
cv.Required(CONF_BROKER): cv.string_strict,
cv.Optional(CONF_PORT, default=1883): cv.port,
cv.Optional(CONF_USERNAME, default=''): cv.string,
cv.Optional(CONF_PASSWORD, default=''): cv.string,
- cv.Optional(CONF_CLIENT_ID, default=lambda: CORE.name): cv.All(cv.string, cv.Length(max=23)),
+ cv.Optional(CONF_CLIENT_ID, default=lambda: CORE.name): cv.string,
cv.Optional(CONF_DISCOVERY, default=True): cv.Any(cv.boolean, cv.one_of("CLEAN", upper=True)),
cv.Optional(CONF_DISCOVERY_RETAIN, default=True): cv.boolean,
cv.Optional(CONF_DISCOVERY_PREFIX, default="homeassistant"): cv.publish_topic,
@@ -120,13 +122,13 @@ CONFIG_SCHEMA = cv.All(cv.Schema({
cv.Optional(CONF_KEEPALIVE, default='15s'): cv.positive_time_period_seconds,
cv.Optional(CONF_REBOOT_TIMEOUT, default='5min'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_ON_MESSAGE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MQTTMessageTrigger),
cv.Required(CONF_TOPIC): cv.subscribe_topic,
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
cv.Optional(CONF_PAYLOAD): cv.string_strict,
}),
cv.Optional(CONF_ON_JSON_MESSAGE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTJsonMessageTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MQTTJsonMessageTrigger),
cv.Required(CONF_TOPIC): cv.subscribe_topic,
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
}),
@@ -148,6 +150,10 @@ def exp_mqtt_message(config):
@coroutine_with_priority(40.0)
def to_code(config):
+ cg.add_library('AsyncMqttClient', '0.8.2')
+ cg.add_define('USE_MQTT')
+ cg.add_global(mqtt_ns.using)
+
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_broker_address(config[CONF_BROKER]))
@@ -215,13 +221,9 @@ def to_code(config):
trig = cg.new_Pvariable(conf[CONF_TRIGGER_ID], conf[CONF_TOPIC], conf[CONF_QOS])
yield automation.build_automation(trig, [(cg.JsonObjectConstRef, 'x')], conf)
- cg.add_library('AsyncMqttClient', '0.8.2')
- cg.add_define('USE_MQTT')
- cg.add_global(mqtt_ns.using)
-
MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.use_variable_id(MQTTClientComponent),
+ cv.GenerateID(): cv.use_id(MQTTClientComponent),
cv.Required(CONF_TOPIC): cv.templatable(cv.publish_topic),
cv.Required(CONF_PAYLOAD): cv.templatable(cv.mqtt_payload),
cv.Optional(CONF_QOS, default=0): cv.templatable(cv.mqtt_qos),
@@ -229,26 +231,24 @@ MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema({
})
-@ACTION_REGISTRY.register('mqtt.publish', MQTT_PUBLISH_ACTION_SCHEMA)
+@automation.register_action('mqtt.publish', MQTTPublishAction, MQTT_PUBLISH_ACTION_SCHEMA)
def mqtt_publish_action_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = MQTTPublishAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_TOPIC], args, cg.std_string)
- cg.add(action.set_topic(template_))
+ cg.add(var.set_topic(template_))
template_ = yield cg.templatable(config[CONF_PAYLOAD], args, cg.std_string)
- cg.add(action.set_payload(template_))
+ cg.add(var.set_payload(template_))
template_ = yield cg.templatable(config[CONF_QOS], args, cg.uint8)
- cg.add(action.set_qos(template_))
+ cg.add(var.set_qos(template_))
template_ = yield cg.templatable(config[CONF_RETAIN], args, bool)
- cg.add(action.set_retain(template_))
- yield action
+ cg.add(var.set_retain(template_))
+ yield var
MQTT_PUBLISH_JSON_ACTION_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.use_variable_id(MQTTClientComponent),
+ cv.GenerateID(): cv.use_id(MQTTClientComponent),
cv.Required(CONF_TOPIC): cv.templatable(cv.publish_topic),
cv.Required(CONF_PAYLOAD): cv.lambda_,
cv.Optional(CONF_QOS, default=0): cv.templatable(cv.mqtt_qos),
@@ -256,23 +256,22 @@ MQTT_PUBLISH_JSON_ACTION_SCHEMA = cv.Schema({
})
-@ACTION_REGISTRY.register('mqtt.publish_json', MQTT_PUBLISH_JSON_ACTION_SCHEMA)
+@automation.register_action('mqtt.publish_json', MQTTPublishJsonAction,
+ MQTT_PUBLISH_JSON_ACTION_SCHEMA)
def mqtt_publish_json_action_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = MQTTPublishJsonAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_TOPIC], args, cg.std_string)
- cg.add(action.set_topic(template_))
+ cg.add(var.set_topic(template_))
args_ = args + [(cg.JsonObjectRef, 'root')]
lambda_ = yield cg.process_lambda(config[CONF_PAYLOAD], args_, return_type=cg.void)
- cg.add(action.set_payload(lambda_))
+ cg.add(var.set_payload(lambda_))
template_ = yield cg.templatable(config[CONF_QOS], args, cg.uint8)
- cg.add(action.set_qos(template_))
+ cg.add(var.set_qos(template_))
template_ = yield cg.templatable(config[CONF_RETAIN], args, bool)
- cg.add(action.set_retain(template_))
- yield action
+ cg.add(var.set_retain(template_))
+ yield var
def get_default_topic_for(data, component_type, name, suffix):
@@ -304,11 +303,9 @@ def register_mqtt_component(var, config):
availability[CONF_PAYLOAD_NOT_AVAILABLE]))
-@CONDITION_REGISTRY.register('mqtt.connected', cv.Schema({
- cv.GenerateID(): cv.use_variable_id(MQTTClientComponent),
+@automation.register_condition('mqtt.connected', MQTTConnectedCondition, cv.Schema({
+ cv.GenerateID(): cv.use_id(MQTTClientComponent),
}))
def mqtt_connected_to_code(config, condition_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = MQTTConnectedCondition.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(condition_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(condition_id, template_arg, paren)
diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h
index 5736a9daac..6f14b0c92c 100644
--- a/esphome/components/mqtt/mqtt_client.h
+++ b/esphome/components/mqtt/mqtt_client.h
@@ -302,7 +302,6 @@ template class MQTTPublishAction : public Action {
void play(Ts... x) override {
this->parent_->publish(this->topic_.value(x...), this->payload_.value(x...), this->qos_.value(x...),
this->retain_.value(x...));
- this->play_next(x...);
}
protected:
@@ -323,7 +322,6 @@ template class MQTTPublishJsonAction : public Action {
auto qos = this->qos_.value(x...);
auto retain = this->retain_.value(x...);
this->parent_->publish_json(topic, f, qos, retain);
- this->play_next(x...);
}
protected:
diff --git a/esphome/components/mqtt_subscribe/sensor/__init__.py b/esphome/components/mqtt_subscribe/sensor/__init__.py
index 22b9f70289..dedc2ac9a7 100644
--- a/esphome/components/mqtt_subscribe/sensor/__init__.py
+++ b/esphome/components/mqtt_subscribe/sensor/__init__.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import mqtt, sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_QOS, CONF_TOPIC
+from esphome.const import CONF_ID, CONF_QOS, CONF_TOPIC, UNIT_EMPTY, ICON_EMPTY
from .. import mqtt_subscribe_ns
DEPENDENCIES = ['mqtt']
@@ -9,19 +9,20 @@ DEPENDENCIES = ['mqtt']
CONF_MQTT_PARENT_ID = 'mqtt_parent_id'
MQTTSubscribeSensor = mqtt_subscribe_ns.class_('MQTTSubscribeSensor', sensor.Sensor, cg.Component)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(MQTTSubscribeSensor),
- cv.GenerateID(CONF_MQTT_PARENT_ID): cv.use_variable_id(mqtt.MQTTClientComponent),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({
+ cv.GenerateID(): cv.declare_id(MQTTSubscribeSensor),
+ cv.GenerateID(CONF_MQTT_PARENT_ID): cv.use_id(mqtt.MQTTClientComponent),
cv.Required(CONF_TOPIC): cv.subscribe_topic,
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- parent = yield cg.get_variable(config[CONF_MQTT_PARENT_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], parent, config[CONF_TOPIC])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
-
- cg.add(var.set_qos(config[CONF_QOS]))
-
yield sensor.register_sensor(var, config)
+
+ parent = yield cg.get_variable(config[CONF_MQTT_PARENT_ID])
+ cg.add(var.set_parent(parent))
+ cg.add(var.set_topic(config[CONF_TOPIC]))
+ cg.add(var.set_qos(config[CONF_QOS]))
diff --git a/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.h b/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.h
index 7e02797cb0..a303ccad89 100644
--- a/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.h
+++ b/esphome/components/mqtt_subscribe/sensor/mqtt_subscribe_sensor.h
@@ -9,9 +9,8 @@ namespace mqtt_subscribe {
class MQTTSubscribeSensor : public sensor::Sensor, public Component {
public:
- MQTTSubscribeSensor(const std::string &name, mqtt::MQTTClientComponent *parent, const std::string &topic)
- : Sensor(name), parent_(parent), topic_(topic) {}
-
+ void set_parent(mqtt::MQTTClientComponent *parent) { parent_ = parent; }
+ void set_topic(const std::string &topic) { topic_ = topic; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/mqtt_subscribe/text_sensor/__init__.py b/esphome/components/mqtt_subscribe/text_sensor/__init__.py
index 7dc5ae89ea..c80909669b 100644
--- a/esphome/components/mqtt_subscribe/text_sensor/__init__.py
+++ b/esphome/components/mqtt_subscribe/text_sensor/__init__.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor, mqtt
-from esphome.const import CONF_ID, CONF_NAME, CONF_QOS, CONF_TOPIC
+from esphome.const import CONF_ID, CONF_QOS, CONF_TOPIC
from .. import mqtt_subscribe_ns
DEPENDENCIES = ['mqtt']
@@ -10,19 +10,20 @@ CONF_MQTT_PARENT_ID = 'mqtt_parent_id'
MQTTSubscribeTextSensor = mqtt_subscribe_ns.class_('MQTTSubscribeTextSensor',
text_sensor.TextSensor, cg.Component)
-CONFIG_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(MQTTSubscribeTextSensor),
- cv.GenerateID(CONF_MQTT_PARENT_ID): cv.use_variable_id(mqtt.MQTTClientComponent),
+CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(MQTTSubscribeTextSensor),
+ cv.GenerateID(CONF_MQTT_PARENT_ID): cv.use_id(mqtt.MQTTClientComponent),
cv.Required(CONF_TOPIC): cv.subscribe_topic,
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- parent = yield cg.get_variable(config[CONF_MQTT_PARENT_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], parent, config[CONF_TOPIC])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
-
- cg.add(var.set_qos(config[CONF_QOS]))
-
yield text_sensor.register_text_sensor(var, config)
+
+ parent = yield cg.get_variable(config[CONF_MQTT_PARENT_ID])
+ cg.add(var.set_parent(parent))
+ cg.add(var.set_topic(config[CONF_TOPIC]))
+ cg.add(var.set_qos(config[CONF_QOS]))
diff --git a/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.h b/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.h
index d1e26307af..69409f6348 100644
--- a/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.h
+++ b/esphome/components/mqtt_subscribe/text_sensor/mqtt_subscribe_text_sensor.h
@@ -9,9 +9,8 @@ namespace mqtt_subscribe {
class MQTTSubscribeTextSensor : public text_sensor::TextSensor, public Component {
public:
- MQTTSubscribeTextSensor(const std::string &name, mqtt::MQTTClientComponent *parent, const std::string &topic)
- : TextSensor(name), parent_(parent), topic_(topic) {}
-
+ void set_parent(mqtt::MQTTClientComponent *parent) { parent_ = parent; }
+ void set_topic(const std::string &topic) { topic_ = topic; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/ms5611/ms5611.h b/esphome/components/ms5611/ms5611.h
index 1f09bdf8b9..b5663ad736 100644
--- a/esphome/components/ms5611/ms5611.h
+++ b/esphome/components/ms5611/ms5611.h
@@ -9,7 +9,6 @@ namespace ms5611 {
class MS5611Component : public PollingComponent, public i2c::I2CDevice {
public:
- MS5611Component(uint32_t update_interval) : PollingComponent(update_interval) {}
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/ms5611/sensor.py b/esphome/components/ms5611/sensor.py
index d8c18319a7..ab9aac6d5f 100644
--- a/esphome/components/ms5611/sensor.py
+++ b/esphome/components/ms5611/sensor.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID, CONF_PRESSURE, \
- CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, ICON_THERMOMETER, UNIT_CELSIUS, ICON_GAUGE, \
+ CONF_TEMPERATURE, ICON_THERMOMETER, UNIT_CELSIUS, ICON_GAUGE, \
UNIT_HECTOPASCAL
DEPENDENCIES = ['i2c']
@@ -11,16 +11,14 @@ ms5611_ns = cg.esphome_ns.namespace('ms5611')
MS5611Component = ms5611_ns.class_('MS5611Component', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MS5611Component),
- cv.Required(CONF_TEMPERATURE): cv.nameable(
- sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
- cv.Required(CONF_PRESSURE): cv.nameable(sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x77))
+ cv.GenerateID(): cv.declare_id(MS5611Component),
+ cv.Required(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Required(CONF_PRESSURE): sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 1),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x77))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/my9231/__init__.py b/esphome/components/my9231/__init__.py
index adc4201c40..82dfe3e083 100644
--- a/esphome/components/my9231/__init__.py
+++ b/esphome/components/my9231/__init__.py
@@ -10,7 +10,7 @@ MY9231OutputComponent = my9231_ns.class_('MY9231OutputComponent', cg.Component)
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MY9231OutputComponent),
+ cv.GenerateID(): cv.declare_id(MY9231OutputComponent),
cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_NUM_CHANNELS, default=6): cv.All(cv.int_, cv.Range(min=3, max=1020)),
@@ -20,11 +20,14 @@ CONFIG_SCHEMA = cv.Schema({
def to_code(config):
- di = yield cg.gpio_pin_expression(config[CONF_DATA_PIN])
- dcki = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN])
- var = cg.new_Pvariable(config[CONF_ID], di, dcki)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
+ di = yield cg.gpio_pin_expression(config[CONF_DATA_PIN])
+ cg.add(var.set_pin_di(di))
+ dcki = yield cg.gpio_pin_expression(config[CONF_CLOCK_PIN])
+ cg.add(var.set_pin_dcki(dcki))
+
cg.add(var.set_num_channels(config[CONF_NUM_CHANNELS]))
cg.add(var.set_num_chips(config[CONF_NUM_CHIPS]))
cg.add(var.set_bit_depth(config[CONF_BIT_DEPTH]))
diff --git a/esphome/components/my9231/my9231.h b/esphome/components/my9231/my9231.h
index f8f013ead6..d7c479c06b 100644
--- a/esphome/components/my9231/my9231.h
+++ b/esphome/components/my9231/my9231.h
@@ -10,12 +10,8 @@ namespace my9231 {
class MY9231OutputComponent : public Component {
public:
class Channel;
- /** Construct the component.
- *
- * @param pin_di The pin which DI is connected to.
- * @param pin_dcki The pin which DCKI is connected to.
- */
- MY9231OutputComponent(GPIOPin *pin_di, GPIOPin *pin_dcki) : pin_di_(pin_di), pin_dcki_(pin_dcki) {}
+ void set_pin_di(GPIOPin *pin_di) { pin_di_ = pin_di; }
+ void set_pin_dcki(GPIOPin *pin_dcki) { pin_dcki_ = pin_dcki; }
void set_num_channels(uint16_t num_channels) { this->num_channels_ = num_channels; }
void set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; }
@@ -31,7 +27,8 @@ class MY9231OutputComponent : public Component {
class Channel : public output::FloatOutput {
public:
- Channel(MY9231OutputComponent *parent, uint8_t channel) : parent_(parent), channel_(channel) {}
+ void set_parent(MY9231OutputComponent *parent) { parent_ = parent; }
+ void set_channel(uint8_t channel) { channel_ = channel; }
protected:
void write_state(float state) override {
diff --git a/esphome/components/my9231/output.py b/esphome/components/my9231/output.py
index 21f4623029..62460faec4 100644
--- a/esphome/components/my9231/output.py
+++ b/esphome/components/my9231/output.py
@@ -10,14 +10,17 @@ Channel = MY9231OutputComponent.class_('Channel', output.FloatOutput)
CONF_MY9231_ID = 'my9231_id'
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend({
- cv.GenerateID(CONF_MY9231_ID): cv.use_variable_id(MY9231OutputComponent),
+ cv.GenerateID(CONF_MY9231_ID): cv.use_id(MY9231OutputComponent),
- cv.Required(CONF_ID): cv.declare_variable_id(Channel),
+ cv.Required(CONF_ID): cv.declare_id(Channel),
cv.Required(CONF_CHANNEL): cv.All(cv.int_, cv.Range(min=0, max=65535)),
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- my9231 = yield cg.get_variable(config[CONF_MY9231_ID])
- var = cg.new_Pvariable(config[CONF_ID], my9231, config[CONF_CHANNEL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield output.register_output(var, config)
+
+ parent = yield cg.get_variable(config[CONF_MY9231_ID])
+ cg.add(var.set_parent(parent))
+ cg.add(var.set_channel(config[CONF_CHANNEL]))
diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py
index fcadd82a0c..060aeb0648 100644
--- a/esphome/components/neopixelbus/light.py
+++ b/esphome/components/neopixelbus/light.py
@@ -127,8 +127,8 @@ def validate(config):
raise cv.Invalid("Must specify at least one of 'pin' or 'clock_pin'+'data_pin'")
-CONFIG_SCHEMA = cv.nameable(light.ADDRESSABLE_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(NeoPixelBusLightOutputBase),
+CONFIG_SCHEMA = cv.All(light.ADDRESSABLE_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(NeoPixelBusLightOutputBase),
cv.Optional(CONF_TYPE, default='GRB'): validate_type,
cv.Optional(CONF_VARIANT, default='800KBPS'): validate_variant,
@@ -139,7 +139,7 @@ CONFIG_SCHEMA = cv.nameable(light.ADDRESSABLE_LIGHT_SCHEMA.extend({
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
- cv.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(power_supply.PowerSupply),
+ cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply),
}).extend(cv.COMPONENT_SCHEMA), validate, validate_method_pin)
diff --git a/esphome/components/neopixelbus/neopixelbus_light.h b/esphome/components/neopixelbus/neopixelbus_light.h
index 689ed9e71b..86ae21ddd0 100644
--- a/esphome/components/neopixelbus/neopixelbus_light.h
+++ b/esphome/components/neopixelbus/neopixelbus_light.h
@@ -144,29 +144,24 @@ class NeoPixelBusLightOutputBase : public Component, public light::AddressableLi
template
class NeoPixelRGBLightOutput : public NeoPixelBusLightOutputBase {
public:
- inline light::ESPColorView operator[](int32_t index) const override {
- uint8_t *base = this->controller_->Pixels() + 3ULL * index;
- return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
- nullptr, this->effect_data_ + index, &this->correction_);
- }
-
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
traits.set_supports_rgb(true);
return traits;
}
+
+ protected:
+ light::ESPColorView get_view_internal(int32_t index) const override {
+ uint8_t *base = this->controller_->Pixels() + 3ULL * index;
+ return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
+ nullptr, this->effect_data_ + index, &this->correction_);
+ }
};
template
class NeoPixelRGBWLightOutput : public NeoPixelBusLightOutputBase {
public:
- inline light::ESPColorView operator[](int32_t index) const override {
- uint8_t *base = this->controller_->Pixels() + 4ULL * index;
- return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
- base + this->rgb_offsets_[3], this->effect_data_ + index, &this->correction_);
- }
-
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
@@ -174,6 +169,13 @@ class NeoPixelRGBWLightOutput : public NeoPixelBusLightOutputBasecontroller_->Pixels() + 4ULL * index;
+ return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
+ base + this->rgb_offsets_[3], this->effect_data_ + index, &this->correction_);
+ }
};
} // namespace neopixelbus
diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py
new file mode 100644
index 0000000000..4486d62e1d
--- /dev/null
+++ b/esphome/components/network/__init__.py
@@ -0,0 +1 @@
+# Dummy package to allow components to depend on network
diff --git a/esphome/components/nextion/binary_sensor.py b/esphome/components/nextion/binary_sensor.py
index ef75d86c60..6003c59803 100644
--- a/esphome/components/nextion/binary_sensor.py
+++ b/esphome/components/nextion/binary_sensor.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
-from esphome.const import CONF_COMPONENT_ID, CONF_NAME, CONF_PAGE_ID, CONF_ID
+from esphome.const import CONF_COMPONENT_ID, CONF_PAGE_ID, CONF_ID
from . import nextion_ns
from .display import Nextion
@@ -11,18 +11,21 @@ CONF_NEXTION_ID = 'nextion_id'
NextionTouchComponent = nextion_ns.class_('NextionTouchComponent', binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(NextionTouchComponent),
- cv.GenerateID(CONF_NEXTION_ID): cv.use_variable_id(Nextion),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(NextionTouchComponent),
+ cv.GenerateID(CONF_NEXTION_ID): cv.use_id(Nextion),
cv.Required(CONF_PAGE_ID): cv.uint8_t,
cv.Required(CONF_COMPONENT_ID): cv.uint8_t,
-}))
+})
def to_code(config):
- hub = yield cg.get_variable(config[CONF_NEXTION_ID])
- rhs = hub.make_touch_component(config[CONF_NAME], config[CONF_PAGE_ID],
- config[CONF_COMPONENT_ID])
- var = cg.Pvariable(config[CONF_ID], rhs)
+ var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
+
+ hub = yield cg.get_variable(config[CONF_NEXTION_ID])
+ cg.add(hub.register_touch_component(var))
+
+ cg.add(var.set_component_id(config[CONF_COMPONENT_ID]))
+ cg.add(var.set_page_id(config[CONF_PAGE_ID]))
diff --git a/esphome/components/nextion/display.py b/esphome/components/nextion/display.py
index 5955f85f7d..30d7519380 100644
--- a/esphome/components/nextion/display.py
+++ b/esphome/components/nextion/display.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import display, uart
-from esphome.const import CONF_ID, CONF_LAMBDA, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID, CONF_LAMBDA
from . import nextion_ns
DEPENDENCIES = ['uart']
@@ -11,9 +11,8 @@ Nextion = nextion_ns.class_('Nextion', cg.PollingComponent, uart.UARTDevice)
NextionRef = Nextion.operator('ref')
CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(Nextion),
- cv.Optional(CONF_UPDATE_INTERVAL, default='5s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
+ cv.GenerateID(): cv.declare_id(Nextion),
+}).extend(cv.polling_component_schema('5s')).extend(uart.UART_DEVICE_SCHEMA)
def to_code(config):
diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp
index 99ff2126c3..f41a97ce7e 100644
--- a/esphome/components/nextion/nextion.cpp
+++ b/esphome/components/nextion/nextion.cpp
@@ -263,11 +263,6 @@ void Nextion::set_nextion_rtc_time(time::ESPTime time) {
void Nextion::set_backlight_brightness(uint8_t brightness) { this->send_command_printf("dim=%u", brightness); }
void Nextion::set_touch_sleep_timeout(uint16_t timeout) { this->send_command_printf("thsp=%u", timeout); }
-NextionTouchComponent *Nextion::make_touch_component(const std::string &name, uint8_t page_id, uint8_t component_id) {
- auto *ret = new NextionTouchComponent(name, page_id, component_id);
- this->touch_.push_back(ret);
- return ret;
-}
void Nextion::set_writer(const nextion_writer_t &writer) { this->writer_ = writer; }
void Nextion::set_component_text_printf(const char *component, const char *format, ...) {
va_list arg;
@@ -285,8 +280,6 @@ void NextionTouchComponent::process(uint8_t page_id, uint8_t component_id, bool
this->publish_state(on);
}
}
-NextionTouchComponent::NextionTouchComponent(const std::string &name, uint8_t page_id, uint8_t component_id)
- : BinarySensor(name), page_id_(page_id), component_id_(component_id) {}
} // namespace nextion
} // namespace esphome
diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h
index 8941e745d1..d8fe3762c9 100644
--- a/esphome/components/nextion/nextion.h
+++ b/esphome/components/nextion/nextion.h
@@ -19,8 +19,6 @@ using nextion_writer_t = std::function;
class Nextion : public PollingComponent, public uart::UARTDevice {
public:
- Nextion() : PollingComponent(0) {}
-
/**
* Set the text of a component to a static string.
* @param component The component name.
@@ -189,7 +187,7 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
// ========== INTERNAL METHODS ==========
// (In most use cases you won't need these)
- NextionTouchComponent *make_touch_component(const std::string &name, uint8_t page_id, uint8_t component_id);
+ void register_touch_component(NextionTouchComponent *obj) { this->touch_.push_back(obj); }
void setup() override;
float get_setup_priority() const override;
void update() override;
@@ -222,7 +220,8 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
class NextionTouchComponent : public binary_sensor::BinarySensor {
public:
- NextionTouchComponent(const std::string &name, uint8_t page_id, uint8_t component_id);
+ void set_page_id(uint8_t page_id) { page_id_ = page_id; }
+ void set_component_id(uint8_t component_id) { component_id_ = component_id; }
void process(uint8_t page_id, uint8_t component_id, bool on);
protected:
diff --git a/esphome/components/ota/__init__.py b/esphome/components/ota/__init__.py
index 0c202e50a6..e290e57baf 100644
--- a/esphome/components/ota/__init__.py
+++ b/esphome/components/ota/__init__.py
@@ -1,18 +1,15 @@
-import logging
-
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PASSWORD, CONF_PORT, CONF_SAFE_MODE
from esphome.core import CORE, coroutine_with_priority
-_LOGGER = logging.getLogger(__name__)
+DEPENDENCIES = ['network']
ota_ns = cg.esphome_ns.namespace('ota')
OTAComponent = ota_ns.class_('OTAComponent', cg.Component)
-
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(OTAComponent),
+ cv.GenerateID(): cv.declare_id(OTAComponent),
cv.Optional(CONF_SAFE_MODE, default=True): cv.boolean,
cv.SplitDefault(CONF_PORT, esp8266=8266, esp32=3232): cv.port,
cv.Optional(CONF_PASSWORD, default=''): cv.string,
@@ -21,10 +18,12 @@ CONFIG_SCHEMA = cv.Schema({
@coroutine_with_priority(50.0)
def to_code(config):
- ota = cg.new_Pvariable(config[CONF_ID], config[CONF_PORT])
- cg.add(ota.set_auth_password(config[CONF_PASSWORD]))
+ var = cg.new_Pvariable(config[CONF_ID])
+ cg.add(var.set_port(config[CONF_PORT]))
+ cg.add(var.set_auth_password(config[CONF_PASSWORD]))
+
if config[CONF_SAFE_MODE]:
- cg.add(ota.start_safe_mode())
+ cg.add(var.start_safe_mode())
if CORE.is_esp8266:
cg.add_library('Update', None)
@@ -32,4 +31,4 @@ def to_code(config):
cg.add_library('Hash', None)
# Register at end for safe mode
- yield cg.register_component(ota, config)
+ yield cg.register_component(var, config)
diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp
index f1b724f0bc..b69393c998 100644
--- a/esphome/components/ota/ota_component.cpp
+++ b/esphome/components/ota/ota_component.cpp
@@ -349,8 +349,6 @@ size_t OTAComponent::wait_receive_(uint8_t *buf, size_t bytes, bool check_discon
return bytes;
}
-OTAComponent::OTAComponent(uint16_t port) : port_(port) {}
-
void OTAComponent::set_auth_password(const std::string &password) { this->password_ = password; }
float OTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
diff --git a/esphome/components/ota/ota_component.h b/esphome/components/ota/ota_component.h
index 1040b9e6b0..e37cb7160c 100644
--- a/esphome/components/ota/ota_component.h
+++ b/esphome/components/ota/ota_component.h
@@ -35,12 +35,6 @@ enum OTAResponseTypes {
/// OTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA.
class OTAComponent : public Component {
public:
- /** Construct an OTAComponent. Defaults to no authentication.
- *
- * @param port The port ArduinoOTA will listen on.
- */
- explicit OTAComponent(uint16_t port);
-
/** Set a plaintext password that OTA will use for authentication.
*
* Warning: This password will be stored in plaintext in the ROM and can be read
diff --git a/esphome/components/output/__init__.py b/esphome/components/output/__init__.py
index 20c29f3df8..b406f62ee1 100644
--- a/esphome/components/output/__init__.py
+++ b/esphome/components/output/__init__.py
@@ -1,6 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
+from esphome import automation
+from esphome.automation import maybe_simple_id
from esphome.components import power_supply
from esphome.const import CONF_ID, CONF_INVERTED, CONF_LEVEL, CONF_MAX_POWER, \
CONF_MIN_POWER, CONF_POWER_SUPPLY
@@ -9,7 +10,7 @@ from esphome.core import CORE, coroutine
IS_PLATFORM_COMPONENT = True
BINARY_OUTPUT_SCHEMA = cv.Schema({
- cv.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(power_supply.PowerSupply),
+ cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply),
cv.Optional(CONF_INVERTED): cv.boolean,
})
@@ -25,9 +26,9 @@ FloatOutput = output_ns.class_('FloatOutput', BinaryOutput)
FloatOutputPtr = FloatOutput.operator('ptr')
# Actions
-TurnOffAction = output_ns.class_('TurnOffAction', cg.Action)
-TurnOnAction = output_ns.class_('TurnOnAction', cg.Action)
-SetLevelAction = output_ns.class_('SetLevelAction', cg.Action)
+TurnOffAction = output_ns.class_('TurnOffAction', automation.Action)
+TurnOnAction = output_ns.class_('TurnOnAction', automation.Action)
+SetLevelAction = output_ns.class_('SetLevelAction', automation.Action)
@coroutine
@@ -51,38 +52,32 @@ def register_output(var, config):
BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(BinaryOutput),
+ cv.Required(CONF_ID): cv.use_id(BinaryOutput),
})
-@ACTION_REGISTRY.register('output.turn_on', BINARY_OUTPUT_ACTION_SCHEMA)
+@automation.register_action('output.turn_on', TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA)
def output_turn_on_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TurnOnAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('output.turn_off', BINARY_OUTPUT_ACTION_SCHEMA)
+@automation.register_action('output.turn_off', TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA)
def output_turn_off_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TurnOffAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('output.set_level', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(FloatOutput),
+@automation.register_action('output.set_level', SetLevelAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(FloatOutput),
cv.Required(CONF_LEVEL): cv.templatable(cv.percentage),
}))
def output_set_level_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = SetLevelAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_LEVEL], args, float)
- cg.add(action.set_level(template_))
- yield action
+ cg.add(var.set_level(template_))
+ yield var
def to_code(config):
diff --git a/esphome/components/output/automation.h b/esphome/components/output/automation.h
index ef2c02ab4d..8c8a5ab61b 100644
--- a/esphome/components/output/automation.h
+++ b/esphome/components/output/automation.h
@@ -12,10 +12,7 @@ template class TurnOffAction : public Action {
public:
TurnOffAction(BinaryOutput *output) : output_(output) {}
- void play(Ts... x) override {
- this->output_->turn_off();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->output_->turn_off(); }
protected:
BinaryOutput *output_;
@@ -25,10 +22,7 @@ template class TurnOnAction : public Action {
public:
TurnOnAction(BinaryOutput *output) : output_(output) {}
- void play(Ts... x) override {
- this->output_->turn_on();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->output_->turn_on(); }
protected:
BinaryOutput *output_;
@@ -39,10 +33,7 @@ template class SetLevelAction : public Action {
SetLevelAction(FloatOutput *output) : output_(output) {}
TEMPLATABLE_VALUE(float, level)
- void play(Ts... x) override {
- this->output_->set_level(this->level_.value(x...));
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->output_->set_level(this->level_.value(x...)); }
protected:
FloatOutput *output_;
diff --git a/esphome/components/output/switch/__init__.py b/esphome/components/output/switch/__init__.py
index 1f1326c84c..5795271f8b 100644
--- a/esphome/components/output/switch/__init__.py
+++ b/esphome/components/output/switch/__init__.py
@@ -1,19 +1,21 @@
-from esphome.components import output, switch
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_NAME, CONF_OUTPUT
+import esphome.config_validation as cv
+from esphome.components import output, switch
+from esphome.const import CONF_ID, CONF_OUTPUT
from .. import output_ns
OutputSwitch = output_ns.class_('OutputSwitch', switch.Switch, cg.Component)
-CONFIG_SCHEMA = cv.nameable(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(OutputSwitch),
- cv.Required(CONF_OUTPUT): cv.use_variable_id(output.BinaryOutput),
-}).extend(cv.COMPONENT_SCHEMA))
+CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(OutputSwitch),
+ cv.Required(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- output_ = yield cg.get_variable(config[CONF_OUTPUT])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], output_)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield switch.register_switch(var, config)
+
+ output_ = yield cg.get_variable(config[CONF_OUTPUT])
+ cg.add(var.set_output(output_))
diff --git a/esphome/components/output/switch/output_switch.h b/esphome/components/output/switch/output_switch.h
index b281718f39..fc9540fede 100644
--- a/esphome/components/output/switch/output_switch.h
+++ b/esphome/components/output/switch/output_switch.h
@@ -9,7 +9,7 @@ namespace output {
class OutputSwitch : public switch_::Switch, public Component {
public:
- OutputSwitch(const std::string &name, BinaryOutput *output) : Switch(name), output_(output) {}
+ void set_output(BinaryOutput *output) { output_ = output; }
void setup() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
diff --git a/esphome/components/partition/light.py b/esphome/components/partition/light.py
index 46c0e3f23d..cfc709854f 100644
--- a/esphome/components/partition/light.py
+++ b/esphome/components/partition/light.py
@@ -15,14 +15,14 @@ def validate_from_to(value):
return value
-CONFIG_SCHEMA = cv.nameable(light.ADDRESSABLE_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(PartitionLightOutput),
+CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(PartitionLightOutput),
cv.Required(CONF_SEGMENTS): cv.All(cv.ensure_list({
- cv.Required(CONF_ID): cv.use_variable_id(light.AddressableLightState),
+ cv.Required(CONF_ID): cv.use_id(light.AddressableLightState),
cv.Required(CONF_FROM): cv.positive_int,
cv.Required(CONF_TO): cv.positive_int,
}, validate_from_to), cv.Length(min=1)),
-}))
+})
def to_code(config):
diff --git a/esphome/components/pca9685/__init__.py b/esphome/components/pca9685/__init__.py
index 7f902dc84e..8e02bd78df 100644
--- a/esphome/components/pca9685/__init__.py
+++ b/esphome/components/pca9685/__init__.py
@@ -10,7 +10,7 @@ pca9685_ns = cg.esphome_ns.namespace('pca9685')
PCA9685Output = pca9685_ns.class_('PCA9685Output', cg.Component, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(PCA9685Output),
+ cv.GenerateID(): cv.declare_id(PCA9685Output),
cv.Required(CONF_FREQUENCY): cv.All(cv.frequency,
cv.Range(min=23.84, max=1525.88)),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x40))
diff --git a/esphome/components/pca9685/output.py b/esphome/components/pca9685/output.py
index a1a557dde7..0c6855c1d4 100644
--- a/esphome/components/pca9685/output.py
+++ b/esphome/components/pca9685/output.py
@@ -10,8 +10,8 @@ PCA9685Channel = pca9685_ns.class_('PCA9685Channel', output.FloatOutput)
CONF_PCA9685_ID = 'pca9685_id'
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend({
- cv.Required(CONF_ID): cv.declare_variable_id(PCA9685Channel),
- cv.GenerateID(CONF_PCA9685_ID): cv.use_variable_id(PCA9685Output),
+ cv.Required(CONF_ID): cv.declare_id(PCA9685Channel),
+ cv.GenerateID(CONF_PCA9685_ID): cv.use_id(PCA9685Output),
cv.Required(CONF_CHANNEL): cv.All(cv.Coerce(int), cv.Range(min=0, max=15)),
})
diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py
index 065eb26652..ad74ac70a9 100644
--- a/esphome/components/pcf8574/__init__.py
+++ b/esphome/components/pcf8574/__init__.py
@@ -21,7 +21,7 @@ PCF8574GPIOPin = pcf8574_ns.class_('PCF8574GPIOPin', cg.GPIOPin)
CONF_PCF8574 = 'pcf8574'
CONF_PCF8575 = 'pcf8575'
CONFIG_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(PCF8574Component),
+ cv.Required(CONF_ID): cv.declare_id(PCF8574Component),
cv.Optional(CONF_PCF8575, default=False): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x21))
@@ -34,15 +34,15 @@ def to_code(config):
PCF8574_OUTPUT_PIN_SCHEMA = cv.Schema({
- cv.Required(CONF_PCF8574): cv.use_variable_id(PCF8574Component),
+ cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component),
cv.Required(CONF_NUMBER): cv.int_,
- cv.Optional(CONF_MODE, default="OUTPUT"): cv.one_of(*PCF8674_GPIO_MODES, upper=True),
+ cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(PCF8674_GPIO_MODES, upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
PCF8574_INPUT_PIN_SCHEMA = cv.Schema({
- cv.Required(CONF_PCF8574): cv.use_variable_id(PCF8574Component),
+ cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component),
cv.Required(CONF_NUMBER): cv.int_,
- cv.Optional(CONF_MODE, default="INPUT"): cv.one_of(*PCF8674_GPIO_MODES, upper=True),
+ cv.Optional(CONF_MODE, default="INPUT"): cv.enum(PCF8674_GPIO_MODES, upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
@@ -50,5 +50,4 @@ PCF8574_INPUT_PIN_SCHEMA = cv.Schema({
@pins.PIN_SCHEMA_REGISTRY.register('pcf8574', (PCF8574_OUTPUT_PIN_SCHEMA, PCF8574_INPUT_PIN_SCHEMA))
def pcf8574_pin_to_code(config):
parent = yield cg.get_variable(config[CONF_PCF8574])
- yield PCF8574GPIOPin.new(parent, config[CONF_NUMBER],
- PCF8674_GPIO_MODES[config[CONF_MODE]], config[CONF_INVERTED])
+ yield PCF8574GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED])
diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py
index adca5270f2..a949fbb1ca 100644
--- a/esphome/components/pmsx003/sensor.py
+++ b/esphome/components/pmsx003/sensor.py
@@ -41,21 +41,21 @@ def validate_pmsx003_sensors(value):
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(PMSX003Component),
- cv.Required(CONF_TYPE): cv.one_of(*PMSX003_TYPES, upper=True),
+ cv.GenerateID(): cv.declare_id(PMSX003Component),
+ cv.Required(CONF_TYPE): cv.enum(PMSX003_TYPES, upper=True),
cv.Optional(CONF_PM_1_0):
- cv.nameable(sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0)),
+ sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0),
cv.Optional(CONF_PM_2_5):
- cv.nameable(sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0)),
+ sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0),
cv.Optional(CONF_PM_10_0):
- cv.nameable(sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0)),
+ sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0),
cv.Optional(CONF_TEMPERATURE):
- cv.nameable(sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
+ sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
cv.Optional(CONF_HUMIDITY):
- cv.nameable(sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1)),
+ sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1),
cv.Optional(CONF_FORMALDEHYDE):
- cv.nameable(sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0)),
+ sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 0),
}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
@@ -64,7 +64,7 @@ def to_code(config):
yield cg.register_component(var, config)
yield uart.register_uart_device(var, config)
- cg.add(var.set_type(PMSX003_TYPES[config[CONF_TYPE]]))
+ cg.add(var.set_type(config[CONF_TYPE]))
if CONF_PM_1_0 in config:
sens = yield sensor.new_sensor(config[CONF_PM_1_0])
diff --git a/esphome/components/pn532/__init__.py b/esphome/components/pn532/__init__.py
index 659bb1ab55..c82d35b398 100644
--- a/esphome/components/pn532/__init__.py
+++ b/esphome/components/pn532/__init__.py
@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.components import spi
-from esphome.const import CONF_ID, CONF_ON_TAG, CONF_TRIGGER_ID, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID, CONF_ON_TAG, CONF_TRIGGER_ID
DEPENDENCIES = ['spi']
AUTO_LOAD = ['binary_sensor']
@@ -10,19 +10,18 @@ MULTI_CONF = True
pn532_ns = cg.esphome_ns.namespace('pn532')
PN532 = pn532_ns.class_('PN532', cg.PollingComponent, spi.SPIDevice)
-PN532Trigger = pn532_ns.class_('PN532Trigger', cg.Trigger.template(cg.std_string))
+PN532Trigger = pn532_ns.class_('PN532Trigger', automation.Trigger.template(cg.std_string))
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(PN532),
- cv.Optional(CONF_UPDATE_INTERVAL, default='1s'): cv.update_interval,
+ cv.GenerateID(): cv.declare_id(PN532),
cv.Optional(CONF_ON_TAG): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(PN532Trigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PN532Trigger),
}),
-}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA)
+}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield spi.register_spi_device(var, config)
diff --git a/esphome/components/pn532/binary_sensor.py b/esphome/components/pn532/binary_sensor.py
index d3bb51770e..1c5e220fa6 100644
--- a/esphome/components/pn532/binary_sensor.py
+++ b/esphome/components/pn532/binary_sensor.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
-from esphome.const import CONF_NAME, CONF_UID, CONF_ID
+from esphome.const import CONF_UID, CONF_ID
from esphome.core import HexInt
from . import pn532_ns, PN532
@@ -27,16 +27,18 @@ def validate_uid(value):
PN532BinarySensor = pn532_ns.class_('PN532BinarySensor', binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(PN532BinarySensor),
- cv.GenerateID(CONF_PN532_ID): cv.use_variable_id(PN532),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(PN532BinarySensor),
+ cv.GenerateID(CONF_PN532_ID): cv.use_id(PN532),
cv.Required(CONF_UID): validate_uid,
-}))
+})
def to_code(config):
- hub = yield cg.get_variable(config[CONF_PN532_ID])
- addr = [HexInt(int(x, 16)) for x in config[CONF_UID].split('-')]
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], addr)
- cg.add(hub.register_tag(var))
+ var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
+
+ hub = yield cg.get_variable(config[CONF_PN532_ID])
+ cg.add(hub.register_tag(var))
+ addr = [HexInt(int(x, 16)) for x in config[CONF_UID].split('-')]
+ cg.add(var.set_uid(addr))
diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp
index e00e13b4a6..07a41444ce 100644
--- a/esphome/components/pn532/pn532.cpp
+++ b/esphome/components/pn532/pn532.cpp
@@ -335,7 +335,6 @@ bool PN532::wait_ready_() {
return true;
}
-PN532::PN532(uint32_t update_interval) : PollingComponent(update_interval) {}
bool PN532::is_device_msb_first() { return false; }
void PN532::dump_config() {
ESP_LOGCONFIG(TAG, "PN532:");
@@ -358,9 +357,6 @@ void PN532::dump_config() {
}
}
-PN532BinarySensor::PN532BinarySensor(const std::string &name, const std::vector &uid)
- : BinarySensor(name), uid_(uid) {}
-
bool PN532BinarySensor::process(const uint8_t *data, uint8_t len) {
if (len != this->uid_.size())
return false;
diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h
index 3d36d1c426..d349c7a150 100644
--- a/esphome/components/pn532/pn532.h
+++ b/esphome/components/pn532/pn532.h
@@ -13,8 +13,6 @@ class PN532Trigger;
class PN532 : public PollingComponent, public spi::SPIDevice {
public:
- PN532(uint32_t update_interval);
-
void setup() override;
void dump_config() override;
@@ -69,7 +67,7 @@ class PN532 : public PollingComponent, public spi::SPIDevice {
class PN532BinarySensor : public binary_sensor::BinarySensor {
public:
- PN532BinarySensor(const std::string &name, const std::vector &uid);
+ void set_uid(const std::vector &uid) { uid_ = uid; }
bool process(const uint8_t *data, uint8_t len);
diff --git a/esphome/components/power_supply/__init__.py b/esphome/components/power_supply/__init__.py
index 8cf2e0d131..5646ffdc0b 100644
--- a/esphome/components/power_supply/__init__.py
+++ b/esphome/components/power_supply/__init__.py
@@ -1,6 +1,6 @@
-from esphome import pins
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import pins
from esphome.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN
power_supply_ns = cg.esphome_ns.namespace('power_supply')
@@ -8,7 +8,7 @@ PowerSupply = power_supply_ns.class_('PowerSupply', cg.Component)
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(PowerSupply),
+ cv.Required(CONF_ID): cv.declare_id(PowerSupply),
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_ENABLE_TIME, default='20ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_KEEP_ON_TIME, default='10s'): cv.positive_time_period_milliseconds,
@@ -16,9 +16,12 @@ CONFIG_SCHEMA = cv.Schema({
def to_code(config):
- pin = yield cg.gpio_pin_expression(config[CONF_PIN])
-
- var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_ENABLE_TIME],
- config[CONF_KEEP_ON_TIME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
+
+ pin = yield cg.gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
+ cg.add(var.set_enable_time(config[CONF_ENABLE_TIME]))
+ cg.add(var.set_keep_on_time(config[CONF_KEEP_ON_TIME]))
+
cg.add_define('USE_POWER_SUPPLY')
diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp
index f631b82ce0..5ce2e38eed 100644
--- a/esphome/components/power_supply/power_supply.cpp
+++ b/esphome/components/power_supply/power_supply.cpp
@@ -22,9 +22,6 @@ void PowerSupply::dump_config() {
float PowerSupply::get_setup_priority() const { return setup_priority::IO; }
-PowerSupply::PowerSupply(GPIOPin *pin, uint32_t enable_time, uint32_t keep_on_time)
- : pin_(pin), enable_time_(enable_time), keep_on_time_(keep_on_time) {}
-
bool PowerSupply::is_enabled() const { return this->enabled_; }
void PowerSupply::request_high_power() {
diff --git a/esphome/components/power_supply/power_supply.h b/esphome/components/power_supply/power_supply.h
index b7af802e51..b49da3b32a 100644
--- a/esphome/components/power_supply/power_supply.h
+++ b/esphome/components/power_supply/power_supply.h
@@ -8,7 +8,9 @@ namespace power_supply {
class PowerSupply : public Component {
public:
- explicit PowerSupply(GPIOPin *pin, uint32_t enable_time, uint32_t keep_on_time);
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
+ void set_enable_time(uint32_t enable_time) { enable_time_ = enable_time; }
+ void set_keep_on_time(uint32_t keep_on_time) { keep_on_time_ = keep_on_time; }
/// Is this power supply currently on?
bool is_enabled() const;
diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.h b/esphome/components/pulse_counter/pulse_counter_sensor.h
index 8acf333f47..cf73156147 100644
--- a/esphome/components/pulse_counter/pulse_counter_sensor.h
+++ b/esphome/components/pulse_counter/pulse_counter_sensor.h
@@ -48,16 +48,12 @@ struct PulseCounterStorage {
pulse_counter_t last_value{0};
};
-class PulseCounterSensor : public sensor::PollingSensorComponent {
+class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
public:
- explicit PulseCounterSensor(const std::string &name, GPIOPin *pin, uint32_t update_interval,
- PulseCounterCountMode rising_edge_mode, PulseCounterCountMode falling_edge_mode,
- uint32_t filter_us)
- : sensor::PollingSensorComponent(name, update_interval), pin_(pin) {
- this->storage_.rising_edge_mode = rising_edge_mode;
- this->storage_.falling_edge_mode = falling_edge_mode;
- this->storage_.filter_us = filter_us;
- }
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
+ void set_rising_edge_mode(PulseCounterCountMode mode) { storage_.rising_edge_mode = mode; }
+ void set_falling_edge_mode(PulseCounterCountMode mode) { storage_.falling_edge_mode = mode; }
+ void set_filter_us(uint32_t filter) { storage_.filter_us = filter; }
/// Unit of measurement is "pulses/min".
void setup() override;
diff --git a/esphome/components/pulse_counter/sensor.py b/esphome/components/pulse_counter/sensor.py
index 677f41c972..6fbdb00945 100644
--- a/esphome/components/pulse_counter/sensor.py
+++ b/esphome/components/pulse_counter/sensor.py
@@ -1,10 +1,10 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-import esphome.config_validation as cv
-import esphome.codegen as cg
from esphome.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_ID, CONF_INTERNAL_FILTER, \
- CONF_NAME, CONF_PIN, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, CONF_NUMBER, \
- CONF_ACCURACY_DECIMALS, CONF_ICON, CONF_UNIT_OF_MEASUREMENT, ICON_PULSE, UNIT_PULSES_PER_MINUTE
+ CONF_PIN, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, CONF_NUMBER, \
+ ICON_PULSE, UNIT_PULSES_PER_MINUTE
from esphome.core import CORE
pulse_counter_ns = cg.esphome_ns.namespace('pulse_counter')
@@ -15,7 +15,7 @@ COUNT_MODES = {
'DECREMENT': PulseCounterCountMode.PULSE_COUNTER_DECREMENT,
}
-COUNT_MODE_SCHEMA = cv.one_of(*COUNT_MODES, upper=True)
+COUNT_MODE_SCHEMA = cv.enum(COUNT_MODES, upper=True)
PulseCounterSensor = pulse_counter_ns.class_('PulseCounterSensor',
sensor.PollingSensorComponent)
@@ -38,8 +38,8 @@ def validate_pulse_counter_pin(value):
return value
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(PulseCounterSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_PULSES_PER_MINUTE, ICON_PULSE, 2).extend({
+ cv.GenerateID(): cv.declare_id(PulseCounterSensor),
cv.Required(CONF_PIN): validate_pulse_counter_pin,
cv.Optional(CONF_COUNT_MODE, default={
CONF_RISING_EDGE: 'INCREMENT',
@@ -50,20 +50,17 @@ CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
}),
cv.Optional(CONF_INTERNAL_FILTER, default='13us'): validate_internal_filter,
cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-
- cv.Optional(CONF_ACCURACY_DECIMALS, default=2): sensor.accuracy_decimals,
- cv.Optional(CONF_ICON, default=ICON_PULSE): sensor.icon,
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PULSES_PER_MINUTE):
- sensor.unit_of_measurement,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- pin = yield cg.gpio_pin_expression(config[CONF_PIN])
- count = config[CONF_COUNT_MODE]
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], pin, config[CONF_UPDATE_INTERVAL],
- COUNT_MODES[count[CONF_RISING_EDGE]],
- COUNT_MODES[count[CONF_FALLING_EDGE]],
- config[CONF_INTERNAL_FILTER])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
+
+ pin = yield cg.gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
+ count = config[CONF_COUNT_MODE]
+ cg.add(var.set_rising_edge_mode(count[CONF_RISING_EDGE]))
+ cg.add(var.set_falling_edge_mode(count[CONF_FALLING_EDGE]))
+ cg.add(var.set_filter_us(config[CONF_INTERNAL_FILTER]))
diff --git a/esphome/components/pulse_width/pulse_width.h b/esphome/components/pulse_width/pulse_width.h
index 7ac085e1f6..9d32ce99b1 100644
--- a/esphome/components/pulse_width/pulse_width.h
+++ b/esphome/components/pulse_width/pulse_width.h
@@ -19,6 +19,7 @@ class PulseWidthSensorStore {
static void gpio_intr(PulseWidthSensorStore *arg);
uint32_t get_pulse_width_us() const { return this->last_width_; }
float get_pulse_width_s() const { return this->last_width_ / 1e6f; }
+ uint32_t get_last_rise() const { return last_rise_; }
protected:
ISRInternalGPIOPin *pin_;
@@ -26,9 +27,8 @@ class PulseWidthSensorStore {
volatile uint32_t last_rise_{0};
};
-class PulseWidthSensor : public sensor::PollingSensorComponent {
+class PulseWidthSensor : public sensor::Sensor, public PollingComponent {
public:
- PulseWidthSensor(const std::string &name, uint32_t update_interval) : PollingSensorComponent(name, update_interval) {}
void set_pin(GPIOPin *pin) { pin_ = pin; }
void setup() override { this->store_.setup(this->pin_); }
void dump_config() override;
diff --git a/esphome/components/pulse_width/sensor.py b/esphome/components/pulse_width/sensor.py
index a2d8605c7a..42d1b0dbaa 100644
--- a/esphome/components/pulse_width/sensor.py
+++ b/esphome/components/pulse_width/sensor.py
@@ -2,23 +2,21 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_PIN, CONF_UPDATE_INTERVAL, UNIT_SECOND, \
- ICON_TIMER
+from esphome.const import CONF_ID, CONF_PIN, UNIT_SECOND, ICON_TIMER
pulse_width_ns = cg.esphome_ns.namespace('pulse_width')
PulseWidthSensor = pulse_width_ns.class_('PulseWidthSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 3).extend({
- cv.GenerateID(): cv.declare_variable_id(PulseWidthSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 3).extend({
+ cv.GenerateID(): cv.declare_id(PulseWidthSensor),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pullup_pin_schema,
pins.validate_has_interrupt),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
diff --git a/esphome/components/rdm6300/__init__.py b/esphome/components/rdm6300/__init__.py
index 60b183083b..ee5077c315 100644
--- a/esphome/components/rdm6300/__init__.py
+++ b/esphome/components/rdm6300/__init__.py
@@ -9,12 +9,12 @@ AUTO_LOAD = ['binary_sensor']
rdm6300_ns = cg.esphome_ns.namespace('rdm6300')
RDM6300Component = rdm6300_ns.class_('RDM6300Component', cg.Component, uart.UARTDevice)
-RDM6300Trigger = rdm6300_ns.class_('RDM6300Trigger', cg.Trigger.template(cg.uint32))
+RDM6300Trigger = rdm6300_ns.class_('RDM6300Trigger', automation.Trigger.template(cg.uint32))
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(RDM6300Component),
+ cv.GenerateID(): cv.declare_id(RDM6300Component),
cv.Optional(CONF_ON_TAG): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(RDM6300Trigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(RDM6300Trigger),
}),
}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
diff --git a/esphome/components/rdm6300/binary_sensor.py b/esphome/components/rdm6300/binary_sensor.py
index ed5e967411..81b24bed0e 100644
--- a/esphome/components/rdm6300/binary_sensor.py
+++ b/esphome/components/rdm6300/binary_sensor.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor, rdm6300
-from esphome.const import CONF_UID, CONF_ID, CONF_NAME
+from esphome.const import CONF_UID, CONF_ID
from . import rdm6300_ns
DEPENDENCIES = ['rdm6300']
@@ -9,15 +9,17 @@ DEPENDENCIES = ['rdm6300']
CONF_RDM6300_ID = 'rdm6300_id'
RDM6300BinarySensor = rdm6300_ns.class_('RDM6300BinarySensor', binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(RDM6300BinarySensor),
- cv.GenerateID(CONF_RDM6300_ID): cv.use_variable_id(rdm6300.RDM6300Component),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(RDM6300BinarySensor),
+ cv.GenerateID(CONF_RDM6300_ID): cv.use_id(rdm6300.RDM6300Component),
cv.Required(CONF_UID): cv.uint32_t,
-}))
+})
def to_code(config):
- hub = yield cg.get_variable(config[CONF_RDM6300_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UID])
+ var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
+
+ hub = yield cg.get_variable(config[CONF_RDM6300_ID])
cg.add(hub.register_card(var))
+ cg.add(var.set_id(config[CONF_UID]))
diff --git a/esphome/components/rdm6300/rdm6300.h b/esphome/components/rdm6300/rdm6300.h
index 3f0e70af5e..a67b6e7ce8 100644
--- a/esphome/components/rdm6300/rdm6300.h
+++ b/esphome/components/rdm6300/rdm6300.h
@@ -30,7 +30,7 @@ class RDM6300Component : public Component, public uart::UARTDevice {
class RDM6300BinarySensor : public binary_sensor::BinarySensor {
public:
- RDM6300BinarySensor(const std::string &name, uint32_t id) : BinarySensor(name), id_(id) {}
+ void set_id(uint32_t id) { id_ = id; }
bool process(uint32_t id) {
if (this->id_ == id) {
diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py
index ac6cc8aecb..cfe3ae4c59 100644
--- a/esphome/components/remote_base/__init__.py
+++ b/esphome/components/remote_base/__init__.py
@@ -1,15 +1,14 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
-from esphome.automation import ACTION_REGISTRY
-from esphome.components import binary_sensor as binary_sensor_
+from esphome.components import binary_sensor
from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID, CONF_NBITS, CONF_ADDRESS, \
CONF_COMMAND, CONF_CODE, CONF_PULSE_LENGTH, CONF_SYNC, CONF_ZERO, CONF_ONE, CONF_INVERTED, \
CONF_PROTOCOL, CONF_GROUP, CONF_DEVICE, CONF_STATE, CONF_CHANNEL, CONF_FAMILY, CONF_REPEAT, \
- CONF_WAIT_TIME, CONF_TIMES
+ CONF_WAIT_TIME, CONF_TIMES, CONF_TYPE_ID
from esphome.core import coroutine
from esphome.py_compat import string_types, text_type
-from esphome.util import ServiceRegistry
+from esphome.util import Registry, SimpleRegistry
AUTO_LOAD = ['binary_sensor']
@@ -20,10 +19,11 @@ ns = remote_base_ns = cg.esphome_ns.namespace('remote_base')
RemoteProtocol = ns.class_('RemoteProtocol')
RemoteReceiverListener = ns.class_('RemoteReceiverListener')
RemoteReceiverBinarySensorBase = ns.class_('RemoteReceiverBinarySensorBase',
- binary_sensor_.BinarySensor, cg.Component)
-RemoteReceiverTrigger = ns.class_('RemoteReceiverTrigger', cg.Trigger, RemoteReceiverListener)
+ binary_sensor.BinarySensor, cg.Component)
+RemoteReceiverTrigger = ns.class_('RemoteReceiverTrigger', automation.Trigger,
+ RemoteReceiverListener)
RemoteTransmitterDumper = ns.class_('RemoteTransmitterDumper')
-RemoteTransmitterActionBase = ns.class_('RemoteTransmitterActionBase', cg.Action)
+RemoteTransmitterActionBase = ns.class_('RemoteTransmitterActionBase', automation.Action)
RemoteReceiverBase = ns.class_('RemoteReceiverBase')
RemoteTransmitterBase = ns.class_('RemoteTransmitterBase')
@@ -44,32 +44,13 @@ def register_listener(var, config):
def register_binary_sensor(name, type, schema):
- if not isinstance(schema, cv.Schema):
- schema = cv.Schema(schema)
- validator = schema.extend({
- cv.GenerateID(): cv.declare_variable_id(type),
- cv.GenerateID(CONF_RECEIVER_ID): cv.use_variable_id(RemoteReceiverBase),
- })
- registerer = BINARY_SENSOR_REGISTRY.register(name, validator)
-
- def decorator(func):
- @coroutine
- def new_func(config):
- var = cg.new_Pvariable(config[CONF_ID])
- yield cg.register_component(var, config)
- yield register_listener(var, config)
- yield coroutine(func)(var, config)
- yield var
-
- return registerer(new_func)
-
- return decorator
+ return BINARY_SENSOR_REGISTRY.register(name, type, schema)
def register_trigger(name, type, data_type):
validator = automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(type),
- cv.GenerateID(CONF_RECEIVER_ID): cv.use_variable_id(RemoteReceiverBase),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(type),
+ cv.GenerateID(CONF_RECEIVER_ID): cv.use_id(RemoteReceiverBase),
})
registerer = TRIGGER_REGISTRY.register('on_{}'.format(name), validator)
@@ -88,18 +69,12 @@ def register_trigger(name, type, data_type):
def register_dumper(name, type):
- validator = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(type),
- cv.GenerateID(CONF_RECEIVER_ID): cv.use_variable_id(RemoteReceiverBase),
- })
- registerer = DUMPER_REGISTRY.register(name, validator)
+ registerer = DUMPER_REGISTRY.register(name, type, {})
def decorator(func):
@coroutine
- def new_func(config):
- var = cg.new_Pvariable(config[CONF_ID])
- receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
- cg.add(receiver.register_dumper(var))
+ def new_func(config, dumper_id):
+ var = cg.new_Pvariable(dumper_id)
yield coroutine(func)(var, config)
yield var
@@ -110,22 +85,21 @@ def register_dumper(name, type):
def register_action(name, type_, schema):
validator = templatize(schema).extend({
- cv.GenerateID(): cv.declare_variable_id(type_),
- cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_variable_id(RemoteTransmitterBase),
+ cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(RemoteTransmitterBase),
cv.Optional(CONF_REPEAT): cv.Schema({
cv.Required(CONF_TIMES): cv.templatable(cv.positive_int),
cv.Optional(CONF_WAIT_TIME, default='10ms'):
cv.templatable(cv.positive_time_period_milliseconds),
}),
})
- registerer = ACTION_REGISTRY.register('remote_transmitter.transmit_{}'.format(name), validator)
+ registerer = automation.register_action('remote_transmitter.transmit_{}'.format(name),
+ type_, validator)
def decorator(func):
@coroutine
def new_func(config, action_id, template_arg, args):
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
- type = type_.template(template_arg)
- var = cg.Pvariable(action_id, type.new(), type=type)
+ var = cg.new_Pvariable(action_id, template_arg)
cg.add(var.set_parent(transmitter))
if CONF_REPEAT in config:
conf = config[CONF_REPEAT]
@@ -143,29 +117,27 @@ def register_action(name, type_, schema):
def declare_protocol(name):
data = ns.struct('{}Data'.format(name))
- protocol = ns.class_('{}Protocol'.format(name))
- binary_sensor = ns.class_('{}BinarySensor'.format(name), RemoteReceiverBinarySensorBase)
+ binary_sensor_ = ns.class_('{}BinarySensor'.format(name), RemoteReceiverBinarySensorBase)
trigger = ns.class_('{}Trigger'.format(name), RemoteReceiverTrigger)
action = ns.class_('{}Action'.format(name), RemoteTransmitterActionBase)
dumper = ns.class_('{}Dumper'.format(name), RemoteTransmitterDumper)
- return data, protocol, binary_sensor, trigger, action, dumper
+ return data, binary_sensor_, trigger, action, dumper
-BINARY_SENSOR_REGISTRY = ServiceRegistry()
-TRIGGER_REGISTRY = ServiceRegistry()
-DUMPER_REGISTRY = ServiceRegistry()
+BINARY_SENSOR_REGISTRY = Registry(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(CONF_RECEIVER_ID): cv.use_id(RemoteReceiverBase),
+}))
+validate_binary_sensor = cv.validate_registry_entry('remote receiver', BINARY_SENSOR_REGISTRY)
+TRIGGER_REGISTRY = SimpleRegistry()
+DUMPER_REGISTRY = Registry({
+ cv.GenerateID(CONF_RECEIVER_ID): cv.use_id(RemoteReceiverBase),
+})
def validate_dumpers(value):
if isinstance(value, string_types) and value.lower() == 'all':
return validate_dumpers(list(DUMPER_REGISTRY.keys()))
- return cv.validate_registry('dumper', DUMPER_REGISTRY, [])(value)
-
-
-def validate_binary_sensor(base_schema):
- validator = cv.validate_registry_entry('remote receiver', BINARY_SENSOR_REGISTRY,
- cv.extract_keys(base_schema))
- return validator
+ return cv.validate_registry('dumper', DUMPER_REGISTRY)(value)
def validate_triggers(base_schema):
@@ -173,7 +145,7 @@ def validate_triggers(base_schema):
def validator(config):
added_keys = {}
- for key, (valid, _) in TRIGGER_REGISTRY.items():
+ for key, (_, valid) in TRIGGER_REGISTRY.items():
added_keys[cv.Optional(key)] = valid
new_schema = base_schema.extend(added_keys)
return new_schema(config)
@@ -182,8 +154,14 @@ def validate_triggers(base_schema):
@coroutine
-def build_binary_sensor(config):
- var = yield cg.build_registry_entry(BINARY_SENSOR_REGISTRY, config)
+def build_binary_sensor(full_config):
+ registry_entry, config = cg.extract_registry_entry_config(BINARY_SENSOR_REGISTRY, full_config)
+ type_id = full_config[CONF_TYPE_ID]
+ builder = registry_entry.coroutine_fun
+ var = cg.new_Pvariable(type_id)
+ yield cg.register_component(var, full_config)
+ yield register_listener(var, full_config)
+ yield builder(var, config)
yield var
@@ -191,17 +169,23 @@ def build_binary_sensor(config):
def build_triggers(full_config):
for key in TRIGGER_REGISTRY:
for config in full_config.get(key, []):
- func = TRIGGER_REGISTRY[key][1]
+ func = TRIGGER_REGISTRY[key][0]
yield func(config)
@coroutine
def build_dumpers(config):
- yield cg.build_registry_list(DUMPER_REGISTRY, config)
+ dumpers = []
+ for conf in config:
+ dumper = yield cg.build_registry_entry(DUMPER_REGISTRY, conf)
+ receiver = yield cg.get_variable(conf[CONF_RECEIVER_ID])
+ cg.add(receiver.register_dumper(dumper))
+ dumpers.append(dumper)
+ yield dumpers
# JVC
-JVCData, JVCProtocol, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol('JVC')
+JVCData, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol('JVC')
JVC_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t})
@@ -230,7 +214,7 @@ def jvc_action(var, config, args):
# LG
-LGData, LGProtocol, LGBinarySensor, LGTrigger, LGAction, LGDumper = declare_protocol('LG')
+LGData, LGBinarySensor, LGTrigger, LGAction, LGDumper = declare_protocol('LG')
LG_SCHEMA = cv.Schema({
cv.Required(CONF_DATA): cv.hex_uint32_t,
cv.Optional(CONF_NBITS, default=28): cv.one_of(28, 32, int=True),
@@ -265,7 +249,7 @@ def lg_action(var, config, args):
# NEC
-NECData, NECProtocol, NECBinarySensor, NECTrigger, NECAction, NECDumper = declare_protocol('NEC')
+NECData, NECBinarySensor, NECTrigger, NECAction, NECDumper = declare_protocol('NEC')
NEC_SCHEMA = cv.Schema({
cv.Required(CONF_ADDRESS): cv.hex_uint16_t,
cv.Required(CONF_COMMAND): cv.hex_uint16_t,
@@ -300,8 +284,7 @@ def nec_action(var, config, args):
# Sony
-SonyData, SonyProtocol, SonyBinarySensor, SonyTrigger, SonyAction, SonyDumper = declare_protocol(
- 'Sony')
+SonyData, SonyBinarySensor, SonyTrigger, SonyAction, SonyDumper = declare_protocol('Sony')
SONY_SCHEMA = cv.Schema({
cv.Required(CONF_DATA): cv.hex_uint32_t,
cv.Optional(CONF_NBITS, default=12): cv.one_of(12, 15, 20, int=True),
@@ -349,12 +332,12 @@ def validate_raw_alternating(value):
return value
-RawData, RawProtocol, RawBinarySensor, RawTrigger, RawAction, RawDumper = declare_protocol('Raw')
+RawData, RawBinarySensor, RawTrigger, RawAction, RawDumper = declare_protocol('Raw')
CONF_CODE_STORAGE_ID = 'code_storage_id'
RAW_SCHEMA = cv.Schema({
cv.Required(CONF_CODE): cv.All([cv.Any(cv.int_, cv.time_period_microseconds)],
cv.Length(min=1), validate_raw_alternating),
- cv.GenerateID(CONF_CODE_STORAGE_ID): cv.declare_variable_id(cg.int32),
+ cv.GenerateID(CONF_CODE_STORAGE_ID): cv.declare_id(cg.int32),
})
@@ -389,7 +372,7 @@ def raw_action(var, config, args):
# RC5
-RC5Data, RC5Protocol, RC5BinarySensor, RC5Trigger, RC5Action, RC5Dumper = declare_protocol('RC5')
+RC5Data, RC5BinarySensor, RC5Trigger, RC5Action, RC5Dumper = declare_protocol('RC5')
RC5_SCHEMA = cv.Schema({
cv.Required(CONF_ADDRESS): cv.All(cv.hex_int, cv.Range(min=0, max=0x1F)),
cv.Required(CONF_COMMAND): cv.All(cv.hex_int, cv.Range(min=0, max=0x3F)),
@@ -591,7 +574,7 @@ def rc_switch_dumper(var, config):
# Samsung
-(SamsungData, SamsungProtocol, SamsungBinarySensor, SamsungTrigger, SamsungAction,
+(SamsungData, SamsungBinarySensor, SamsungTrigger, SamsungAction,
SamsungDumper) = declare_protocol('Samsung')
SAMSUNG_SCHEMA = cv.Schema({
cv.Required(CONF_DATA): cv.hex_uint32_t,
@@ -623,7 +606,7 @@ def samsung_action(var, config, args):
# Panasonic
-(PanasonicData, PanasonicProtocol, PanasonicBinarySensor, PanasonicTrigger, PanasonicAction,
+(PanasonicData, PanasonicBinarySensor, PanasonicTrigger, PanasonicAction,
PanasonicDumper) = declare_protocol('Panasonic')
PANASONIC_SCHEMA = cv.Schema({
cv.Required(CONF_ADDRESS): cv.hex_uint16_t,
diff --git a/esphome/components/remote_base/raw_protocol.cpp b/esphome/components/remote_base/raw_protocol.cpp
index eb4d8d1800..4cbd37d476 100644
--- a/esphome/components/remote_base/raw_protocol.cpp
+++ b/esphome/components/remote_base/raw_protocol.cpp
@@ -11,7 +11,7 @@ void RawDumper::dump(RemoteReceiveData src) {
uint32_t buffer_offset = 0;
buffer_offset += sprintf(buffer, "Received Raw: ");
- for (int32_t i = 0; i < src.size(); i++) {
+ for (int32_t i = 0; i < src.size() - 1; i++) {
const int32_t value = src[i];
const uint32_t remaining_length = sizeof(buffer) - buffer_offset;
int written;
diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h
index ddbf679b0c..6ad63879ad 100644
--- a/esphome/components/remote_base/remote_base.h
+++ b/esphome/components/remote_base/remote_base.h
@@ -310,7 +310,6 @@ template class RemoteTransmitterActionBase : public Actionsend_times_.value_or(x..., 1));
call.set_send_wait(this->send_wait_.value_or(x..., 0));
call.perform();
- this->play_next(x...);
}
virtual void encode(RemoteTransmitData *dst, Ts... x) = 0;
diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py
index 0553da5b44..5742876e36 100644
--- a/esphome/components/remote_receiver/__init__.py
+++ b/esphome/components/remote_receiver/__init__.py
@@ -13,7 +13,7 @@ RemoteReceiverComponent = remote_receiver_ns.class_('RemoteReceiverComponent',
MULTI_CONF = True
CONFIG_SCHEMA = remote_base.validate_triggers(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(RemoteReceiverComponent),
+ cv.GenerateID(): cv.declare_id(RemoteReceiverComponent),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt),
cv.Optional(CONF_DUMP, default=[]): remote_base.validate_dumpers,
diff --git a/esphome/components/remote_receiver/binary_sensor.py b/esphome/components/remote_receiver/binary_sensor.py
index c89005767d..7be64e5a54 100644
--- a/esphome/components/remote_receiver/binary_sensor.py
+++ b/esphome/components/remote_receiver/binary_sensor.py
@@ -1,15 +1,10 @@
-from esphome.components import binary_sensor, remote_base
-import esphome.config_validation as cv
import esphome.codegen as cg
+from esphome.components import binary_sensor, remote_base
from esphome.const import CONF_NAME
DEPENDENCIES = ['remote_receiver']
-
-BASE_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({}, extra=cv.ALLOW_EXTRA)
-
-
-CONFIG_SCHEMA = cv.nameable(cv.All(BASE_SCHEMA, remote_base.validate_binary_sensor(BASE_SCHEMA)))
+CONFIG_SCHEMA = remote_base.validate_binary_sensor
def to_code(config):
diff --git a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp
index 85c708a5e7..cafbc34d69 100644
--- a/esphome/components/remote_receiver/remote_receiver_esp8266.cpp
+++ b/esphome/components/remote_receiver/remote_receiver_esp8266.cpp
@@ -13,17 +13,20 @@ void ICACHE_RAM_ATTR HOT RemoteReceiverComponentStore::gpio_intr(RemoteReceiverC
const uint32_t now = micros();
// If the lhs is 1 (rising edge) we should write to an uneven index and vice versa
const uint32_t next = (arg->buffer_write_at + 1) % arg->buffer_size;
- if (uint32_t(arg->pin->digital_read()) != next % 2)
+ const bool level = arg->pin->digital_read();
+ if (level != next % 2)
return;
+
+ // If next is buffer_read, we have hit an overflow
+ if (next == arg->buffer_read_at)
+ return;
+
const uint32_t last_change = arg->buffer[arg->buffer_write_at];
- if (now - last_change <= arg->filter_us)
+ const uint32_t time_since_change = now - last_change;
+ if (time_since_change <= arg->filter_us)
return;
arg->buffer[arg->buffer_write_at = next] = now;
-
- if (next == arg->buffer_read_at) {
- arg->overflow = true;
- }
}
void RemoteReceiverComponent::setup() {
@@ -39,15 +42,16 @@ void RemoteReceiverComponent::setup() {
// Make sure divisible by two. This way, we know that every 0bxxx0 index is a space and every 0bxxx1 index is a mark
s.buffer_size++;
}
+
s.buffer = new uint32_t[s.buffer_size];
+ void *buf = (void *) s.buffer;
+ memset(buf, 0, s.buffer_size * sizeof(uint32_t));
+
// First index is a space.
if (this->pin_->digital_read()) {
s.buffer_write_at = s.buffer_read_at = 1;
- s.buffer[1] = 0;
- s.buffer[0] = 0;
} else {
s.buffer_write_at = s.buffer_read_at = 0;
- s.buffer[0] = 0;
}
this->pin_->attach_interrupt(RemoteReceiverComponentStore::gpio_intr, &this->store_, CHANGE);
}
@@ -66,12 +70,6 @@ void RemoteReceiverComponent::dump_config() {
void RemoteReceiverComponent::loop() {
auto &s = this->store_;
- if (s.overflow) {
- s.buffer_read_at = s.buffer_write_at;
- s.overflow = false;
- ESP_LOGW(TAG, "Data is coming in too fast! Try increasing the buffer size.");
- return;
- }
// copy write at to local variables, as it's volatile
const uint32_t write_at = s.buffer_write_at;
@@ -82,7 +80,6 @@ void RemoteReceiverComponent::loop() {
const uint32_t now = micros();
if (now - s.buffer[write_at] < this->idle_us_)
// The last change was fewer than the configured idle time ago.
- // TODO: Handle case when loop() is not called quickly enough to catch idle
return;
ESP_LOGVV(TAG, "read_at=%u write_at=%u dist=%u now=%u end=%u", s.buffer_read_at, write_at, dist, now,
diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py
index 90be20f9e1..5e217de608 100644
--- a/esphome/components/remote_transmitter/__init__.py
+++ b/esphome/components/remote_transmitter/__init__.py
@@ -12,7 +12,7 @@ RemoteTransmitterComponent = remote_transmitter_ns.class_('RemoteTransmitterComp
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(RemoteTransmitterComponent),
+ cv.GenerateID(): cv.declare_id(RemoteTransmitterComponent),
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_CARRIER_DUTY_PERCENT): cv.All(cv.percentage_int, cv.Range(min=1, max=100)),
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h
index 6e5ef46171..a746d43926 100644
--- a/esphome/components/remote_transmitter/remote_transmitter.h
+++ b/esphome/components/remote_transmitter/remote_transmitter.h
@@ -36,7 +36,6 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, pu
std::vector rmt_temp_;
#endif
uint8_t carrier_duty_percent_{50};
- remote_base::RemoteTransmitData temp_;
};
} // namespace remote_transmitter
diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp
index 61d5bbb57f..7704f1d9ab 100644
--- a/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp
+++ b/esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp
@@ -63,12 +63,10 @@ void RemoteTransmitterComponent::space_(uint32_t usec) {
delay_microseconds_accurate(usec);
}
void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) {
+ ESP_LOGD(TAG, "Sending remote code...");
+ uint32_t on_time, off_time;
+ this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time);
for (uint32_t i = 0; i < send_times; i++) {
- uint32_t on_time, off_time;
- this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time);
- ESP_LOGD(TAG, "Sending remote code...");
-
- ESP.wdtFeed();
disable_interrupts();
for (int32_t item : this->temp_.get_data()) {
if (item > 0) {
diff --git a/esphome/components/restart/restart_switch.h b/esphome/components/restart/restart_switch.h
index c1bcf9e998..7f1902ab53 100644
--- a/esphome/components/restart/restart_switch.h
+++ b/esphome/components/restart/restart_switch.h
@@ -8,8 +8,6 @@ namespace restart {
class RestartSwitch : public switch_::Switch, public Component {
public:
- explicit RestartSwitch(const std::string &name) : switch_::Switch(name) {}
-
void dump_config() override;
protected:
diff --git a/esphome/components/restart/switch.py b/esphome/components/restart/switch.py
index 0042feb5bc..9517302d33 100644
--- a/esphome/components/restart/switch.py
+++ b/esphome/components/restart/switch.py
@@ -1,20 +1,20 @@
-from esphome.components import switch
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_INVERTED, CONF_NAME, CONF_ICON, ICON_RESTART
+import esphome.config_validation as cv
+from esphome.components import switch
+from esphome.const import CONF_ID, CONF_INVERTED, CONF_ICON, ICON_RESTART
restart_ns = cg.esphome_ns.namespace('restart')
RestartSwitch = restart_ns.class_('RestartSwitch', switch.Switch, cg.Component)
-CONFIG_SCHEMA = cv.nameable(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(RestartSwitch),
+CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(RestartSwitch),
cv.Optional(CONF_INVERTED): cv.invalid("Restart switches do not support inverted mode!"),
cv.Optional(CONF_ICON, default=ICON_RESTART): switch.icon,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield switch.register_switch(var, config)
diff --git a/esphome/components/rgb/light.py b/esphome/components/rgb/light.py
index 16932596b3..6bece17664 100644
--- a/esphome/components/rgb/light.py
+++ b/esphome/components/rgb/light.py
@@ -6,17 +6,21 @@ from esphome.const import CONF_BLUE, CONF_GREEN, CONF_RED, CONF_OUTPUT_ID
rgb_ns = cg.esphome_ns.namespace('rgb')
RGBLightOutput = rgb_ns.class_('RGBLightOutput', light.LightOutput)
-CONFIG_SCHEMA = cv.nameable(light.RGB_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(RGBLightOutput),
- cv.Required(CONF_RED): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_GREEN): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_BLUE): cv.use_variable_id(output.FloatOutput),
-}))
+CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(RGBLightOutput),
+ cv.Required(CONF_RED): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_GREEN): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_BLUE): cv.use_id(output.FloatOutput),
+})
def to_code(config):
- red = yield cg.get_variable(config[CONF_RED])
- green = yield cg.get_variable(config[CONF_GREEN])
- blue = yield cg.get_variable(config[CONF_BLUE])
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], red, green, blue)
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield light.register_light(var, config)
+
+ red = yield cg.get_variable(config[CONF_RED])
+ cg.add(var.set_red(red))
+ green = yield cg.get_variable(config[CONF_GREEN])
+ cg.add(var.set_green(green))
+ blue = yield cg.get_variable(config[CONF_BLUE])
+ cg.add(var.set_blue(blue))
diff --git a/esphome/components/rgb/rgb_light_output.h b/esphome/components/rgb/rgb_light_output.h
index b6b102200f..e612c80f73 100644
--- a/esphome/components/rgb/rgb_light_output.h
+++ b/esphome/components/rgb/rgb_light_output.h
@@ -9,8 +9,9 @@ namespace rgb {
class RGBLightOutput : public light::LightOutput {
public:
- RGBLightOutput(output::FloatOutput *red, output::FloatOutput *green, output::FloatOutput *blue)
- : red_(red), green_(green), blue_(blue) {}
+ void set_red(output::FloatOutput *red) { red_ = red; }
+ void set_green(output::FloatOutput *green) { green_ = green; }
+ void set_blue(output::FloatOutput *blue) { blue_ = blue; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
diff --git a/esphome/components/rgbw/light.py b/esphome/components/rgbw/light.py
index 9a4baea607..75d6082e5a 100644
--- a/esphome/components/rgbw/light.py
+++ b/esphome/components/rgbw/light.py
@@ -6,19 +6,24 @@ from esphome.const import CONF_BLUE, CONF_GREEN, CONF_RED, CONF_OUTPUT_ID, CONF_
rgbw_ns = cg.esphome_ns.namespace('rgbw')
RGBWLightOutput = rgbw_ns.class_('RGBWLightOutput', light.LightOutput)
-CONFIG_SCHEMA = cv.nameable(light.RGB_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(RGBWLightOutput),
- cv.Required(CONF_RED): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_GREEN): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_BLUE): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_WHITE): cv.use_variable_id(output.FloatOutput),
-}))
+CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(RGBWLightOutput),
+ cv.Required(CONF_RED): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_GREEN): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_BLUE): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_WHITE): cv.use_id(output.FloatOutput),
+})
def to_code(config):
- red = yield cg.get_variable(config[CONF_RED])
- green = yield cg.get_variable(config[CONF_GREEN])
- blue = yield cg.get_variable(config[CONF_BLUE])
- white = yield cg.get_variable(config[CONF_WHITE])
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], red, green, blue, white)
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield light.register_light(var, config)
+
+ red = yield cg.get_variable(config[CONF_RED])
+ cg.add(var.set_red(red))
+ green = yield cg.get_variable(config[CONF_GREEN])
+ cg.add(var.set_green(green))
+ blue = yield cg.get_variable(config[CONF_BLUE])
+ cg.add(var.set_blue(blue))
+ white = yield cg.get_variable(config[CONF_WHITE])
+ cg.add(var.set_white(white))
diff --git a/esphome/components/rgbw/rgbw_light_output.h b/esphome/components/rgbw/rgbw_light_output.h
index 92582e0b56..b58c7f9d54 100644
--- a/esphome/components/rgbw/rgbw_light_output.h
+++ b/esphome/components/rgbw/rgbw_light_output.h
@@ -9,9 +9,10 @@ namespace rgbw {
class RGBWLightOutput : public light::LightOutput {
public:
- RGBWLightOutput(output::FloatOutput *red, output::FloatOutput *green, output::FloatOutput *blue,
- output::FloatOutput *white)
- : red_(red), green_(green), blue_(blue), white_(white) {}
+ void set_red(output::FloatOutput *red) { red_ = red; }
+ void set_green(output::FloatOutput *green) { green_ = green; }
+ void set_blue(output::FloatOutput *blue) { blue_ = blue; }
+ void set_white(output::FloatOutput *white) { white_ = white; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
diff --git a/esphome/components/rgbww/light.py b/esphome/components/rgbww/light.py
index 4c458f42eb..143542f49c 100644
--- a/esphome/components/rgbww/light.py
+++ b/esphome/components/rgbww/light.py
@@ -8,25 +8,33 @@ from esphome.const import CONF_BLUE, CONF_GREEN, CONF_RED, CONF_OUTPUT_ID, CONF_
rgbww_ns = cg.esphome_ns.namespace('rgbww')
RGBWWLightOutput = rgbww_ns.class_('RGBWWLightOutput', light.LightOutput)
-CONFIG_SCHEMA = cv.nameable(light.RGB_LIGHT_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(RGBWWLightOutput),
- cv.Required(CONF_RED): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_GREEN): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_BLUE): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_COLD_WHITE): cv.use_variable_id(output.FloatOutput),
- cv.Required(CONF_WARM_WHITE): cv.use_variable_id(output.FloatOutput),
+CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(RGBWWLightOutput),
+ cv.Required(CONF_RED): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_GREEN): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_BLUE): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_COLD_WHITE): cv.use_id(output.FloatOutput),
+ cv.Required(CONF_WARM_WHITE): cv.use_id(output.FloatOutput),
cv.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature,
cv.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature,
-}))
+})
def to_code(config):
- red = yield cg.get_variable(config[CONF_RED])
- green = yield cg.get_variable(config[CONF_GREEN])
- blue = yield cg.get_variable(config[CONF_BLUE])
- cwhite = yield cg.get_variable(config[CONF_COLD_WHITE])
- wwhite = yield cg.get_variable(config[CONF_WARM_WHITE])
- var = cg.new_Pvariable(config[CONF_OUTPUT_ID], red, green, blue, cwhite, wwhite,
- config[CONF_COLD_WHITE_COLOR_TEMPERATURE],
- config[CONF_WARM_WHITE_COLOR_TEMPERATURE])
+ var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield light.register_light(var, config)
+
+ red = yield cg.get_variable(config[CONF_RED])
+ cg.add(var.set_red(red))
+ green = yield cg.get_variable(config[CONF_GREEN])
+ cg.add(var.set_green(green))
+ blue = yield cg.get_variable(config[CONF_BLUE])
+ cg.add(var.set_blue(blue))
+
+ cwhite = yield cg.get_variable(config[CONF_COLD_WHITE])
+ cg.add(var.set_cold_white(cwhite))
+ cg.add(var.set_cold_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]))
+
+ wwhite = yield cg.get_variable(config[CONF_WARM_WHITE])
+ cg.add(var.set_warm_white(wwhite))
+ cg.add(var.set_warm_white_temperature(config[CONF_COLD_WHITE_COLOR_TEMPERATURE]))
diff --git a/esphome/components/rgbww/rgbww_light_output.h b/esphome/components/rgbww/rgbww_light_output.h
index d6693e4538..dc1f09e09b 100644
--- a/esphome/components/rgbww/rgbww_light_output.h
+++ b/esphome/components/rgbww/rgbww_light_output.h
@@ -9,16 +9,13 @@ namespace rgbww {
class RGBWWLightOutput : public light::LightOutput {
public:
- RGBWWLightOutput(output::FloatOutput *red, output::FloatOutput *green, output::FloatOutput *blue,
- output::FloatOutput *cold_white, output::FloatOutput *warm_white, float cold_white_temperature,
- float warm_white_temperature)
- : red_(red),
- green_(green),
- blue_(blue),
- cold_white_(cold_white),
- warm_white_(warm_white),
- cold_white_temperature_(cold_white_temperature),
- warm_white_temperature_(warm_white_temperature) {}
+ void set_red(output::FloatOutput *red) { red_ = red; }
+ void set_green(output::FloatOutput *green) { green_ = green; }
+ void set_blue(output::FloatOutput *blue) { blue_ = blue; }
+ void set_cold_white(output::FloatOutput *cold_white) { cold_white_ = cold_white; }
+ void set_warm_white(output::FloatOutput *warm_white) { warm_white_ = warm_white; }
+ void set_cold_white_temperature(float cold_white_temperature) { cold_white_temperature_ = cold_white_temperature; }
+ void set_warm_white_temperature(float warm_white_temperature) { warm_white_temperature_ = warm_white_temperature; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
diff --git a/esphome/components/rotary_encoder/rotary_encoder.cpp b/esphome/components/rotary_encoder/rotary_encoder.cpp
index d97d61cf99..d88329d064 100644
--- a/esphome/components/rotary_encoder/rotary_encoder.cpp
+++ b/esphome/components/rotary_encoder/rotary_encoder.cpp
@@ -96,8 +96,6 @@ void ICACHE_RAM_ATTR HOT RotaryEncoderSensorStore::gpio_intr(RotaryEncoderSensor
arg->state = new_state;
}
-RotaryEncoderSensor::RotaryEncoderSensor(const std::string &name, GPIOPin *pin_a, GPIOPin *pin_b)
- : Sensor(name), Component(), pin_a_(pin_a), pin_b_(pin_b) {}
void RotaryEncoderSensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up Rotary Encoder '%s'...", this->name_.c_str());
diff --git a/esphome/components/rotary_encoder/rotary_encoder.h b/esphome/components/rotary_encoder/rotary_encoder.h
index b0239d01b6..b627a4e57f 100644
--- a/esphome/components/rotary_encoder/rotary_encoder.h
+++ b/esphome/components/rotary_encoder/rotary_encoder.h
@@ -31,7 +31,8 @@ struct RotaryEncoderSensorStore {
class RotaryEncoderSensor : public sensor::Sensor, public Component {
public:
- RotaryEncoderSensor(const std::string &name, GPIOPin *pin_a, GPIOPin *pin_b);
+ void set_pin_a(GPIOPin *pin_a) { pin_a_ = pin_a; }
+ void set_pin_b(GPIOPin *pin_b) { pin_b_ = pin_b; }
/** Set the resolution of the rotary encoder.
*
diff --git a/esphome/components/rotary_encoder/sensor.py b/esphome/components/rotary_encoder/sensor.py
index ca4db7b848..3eb2a5ca45 100644
--- a/esphome/components/rotary_encoder/sensor.py
+++ b/esphome/components/rotary_encoder/sensor.py
@@ -2,7 +2,8 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_RESOLUTION, CONF_MIN_VALUE, CONF_MAX_VALUE
+from esphome.const import CONF_ID, CONF_RESOLUTION, CONF_MIN_VALUE, CONF_MAX_VALUE, UNIT_STEPS, \
+ ICON_ROTATE_RIGHT
rotary_encoder_ns = cg.esphome_ns.namespace('rotary_encoder')
RotaryEncoderResolution = rotary_encoder_ns.enum('RotaryEncoderResolution')
@@ -29,32 +30,32 @@ def validate_min_max_value(config):
return config
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(RotaryEncoderSensor),
+CONFIG_SCHEMA = cv.All(sensor.sensor_schema(UNIT_STEPS, ICON_ROTATE_RIGHT, 0).extend({
+ cv.GenerateID(): cv.declare_id(RotaryEncoderSensor),
cv.Required(CONF_PIN_A): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt),
cv.Required(CONF_PIN_B): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt),
cv.Optional(CONF_PIN_RESET): pins.internal_gpio_input_pin_schema,
- cv.Optional(CONF_RESOLUTION, default=1): cv.one_of(*RESOLUTIONS, int=True),
+ cv.Optional(CONF_RESOLUTION, default=1): cv.enum(RESOLUTIONS, int=True),
cv.Optional(CONF_MIN_VALUE): cv.int_,
cv.Optional(CONF_MAX_VALUE): cv.int_,
}).extend(cv.COMPONENT_SCHEMA), validate_min_max_value)
def to_code(config):
- pin_a = yield cg.gpio_pin_expression(config[CONF_PIN_A])
- pin_b = yield cg.gpio_pin_expression(config[CONF_PIN_B])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], pin_a, pin_b)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
+ pin_a = yield cg.gpio_pin_expression(config[CONF_PIN_A])
+ cg.add(var.set_pin_a(pin_a))
+ pin_b = yield cg.gpio_pin_expression(config[CONF_PIN_B])
+ cg.add(var.set_pin_a(pin_b))
if CONF_PIN_RESET in config:
pin_i = yield cg.gpio_pin_expression(config[CONF_PIN_RESET])
cg.add(var.set_reset_pin(pin_i))
- if CONF_RESOLUTION in config:
- resolution = RESOLUTIONS[config[CONF_RESOLUTION]]
- cg.add(var.set_resolution(resolution))
+ cg.add(var.set_resolution(config[CONF_RESOLUTION]))
if CONF_MIN_VALUE in config:
cg.add(var.set_min_value(config[CONF_MIN_VALUE]))
if CONF_MAX_VALUE in config:
diff --git a/esphome/components/script/__init__.py b/esphome/components/script/__init__.py
index 06017f19e0..962e2d56ca 100644
--- a/esphome/components/script/__init__.py
+++ b/esphome/components/script/__init__.py
@@ -1,16 +1,17 @@
-from esphome import automation
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.automation import maybe_simple_id
from esphome.const import CONF_ID
script_ns = cg.esphome_ns.namespace('script')
-Script = script_ns.class_('Script', cg.Trigger.template())
-ScriptExecuteAction = script_ns.class_('ScriptExecuteAction', cg.Action)
-ScriptStopAction = script_ns.class_('ScriptStopAction', cg.Action)
+Script = script_ns.class_('Script', automation.Trigger.template())
+ScriptExecuteAction = script_ns.class_('ScriptExecuteAction', automation.Action)
+ScriptStopAction = script_ns.class_('ScriptStopAction', automation.Action)
+IsRunningCondition = script_ns.class_('IsRunningCondition', automation.Condition)
CONFIG_SCHEMA = automation.validate_automation({
- cv.Required(CONF_ID): cv.declare_variable_id(Script),
+ cv.Required(CONF_ID): cv.declare_id(Script),
})
@@ -20,21 +21,25 @@ def to_code(config):
yield automation.build_automation(trigger, [], conf)
-@ACTION_REGISTRY.register('script.execute', maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(Script),
+@automation.register_action('script.execute', ScriptExecuteAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(Script),
}))
def script_execute_action_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ScriptExecuteAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('script.stop', maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(Script)
+@automation.register_action('script.stop', ScriptStopAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(Script)
}))
def script_stop_action_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ScriptStopAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
+
+
+@automation.register_condition('script.is_running', IsRunningCondition, automation.maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(Script)
+}))
+def script_is_running_to_code(config, condition_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(condition_id, template_arg, paren)
diff --git a/esphome/components/script/script.h b/esphome/components/script/script.h
index bac275e37d..f937b9d637 100644
--- a/esphome/components/script/script.h
+++ b/esphome/components/script/script.h
@@ -7,17 +7,23 @@ namespace script {
class Script : public Trigger<> {
public:
- void execute() { this->trigger(); }
+ void execute() {
+ bool prev = this->in_stack_;
+ this->in_stack_ = true;
+ this->trigger();
+ this->in_stack_ = prev;
+ }
+ bool script_is_running() { return this->in_stack_ || this->is_running(); }
+
+ protected:
+ bool in_stack_{false};
};
template class ScriptExecuteAction : public Action {
public:
ScriptExecuteAction(Script *script) : script_(script) {}
- void play(Ts... x) override {
- this->script_->trigger();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->script_->trigger(); }
protected:
Script *script_;
@@ -27,14 +33,21 @@ template class ScriptStopAction : public Action {
public:
ScriptStopAction(Script *script) : script_(script) {}
- void play(Ts... x) override {
- this->script_->stop();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->script_->stop(); }
protected:
Script *script_;
};
+template class IsRunningCondition : public Condition {
+ public:
+ explicit IsRunningCondition(Script *parent) : parent_(parent) {}
+
+ bool check(Ts... x) override { return this->parent_->script_is_running(); }
+
+ protected:
+ Script *parent_;
+};
+
} // namespace script
} // namespace esphome
diff --git a/esphome/components/sds011/sds011.h b/esphome/components/sds011/sds011.h
index 5075ae3846..83f89df237 100644
--- a/esphome/components/sds011/sds011.h
+++ b/esphome/components/sds011/sds011.h
@@ -22,6 +22,8 @@ class SDS011Component : public Component, public uart::UARTDevice {
float get_setup_priority() const override;
+ void set_update_interval(uint32_t val) { /* ignore */
+ }
void set_update_interval_min(uint8_t update_interval_min);
protected:
diff --git a/esphome/components/sds011/sensor.py b/esphome/components/sds011/sensor.py
index da852e94fa..5b34b2dbbd 100644
--- a/esphome/components/sds011/sensor.py
+++ b/esphome/components/sds011/sensor.py
@@ -25,12 +25,12 @@ def validate_sds011_rx_mode(value):
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(SDS011Component),
+ cv.GenerateID(): cv.declare_id(SDS011Component),
cv.Optional(CONF_PM_2_5):
- cv.nameable(sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 1)),
+ sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 1),
cv.Optional(CONF_PM_10_0):
- cv.nameable(sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 1)),
+ sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 1),
cv.Optional(CONF_RX_ONLY, default=False): cv.boolean,
cv.Optional(CONF_UPDATE_INTERVAL, default='0min'): cv.positive_time_period_minutes,
diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py
index 72d5701f35..a233468762 100644
--- a/esphome/components/sensor/__init__.py
+++ b/esphome/components/sensor/__init__.py
@@ -3,18 +3,15 @@ import math
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
-from esphome.automation import CONDITION_REGISTRY
from esphome.components import mqtt
from esphome.const import CONF_ABOVE, CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_BELOW, \
- CONF_CALIBRATE_LINEAR, CONF_DEBOUNCE, CONF_DELTA, CONF_EXPIRE_AFTER, \
- CONF_FILTERS, CONF_FROM, \
- CONF_ICON, CONF_ID, CONF_INTERNAL, CONF_LAMBDA, CONF_MULTIPLY, CONF_OFFSET, \
- CONF_ON_RAW_VALUE, CONF_ON_VALUE, CONF_ON_VALUE_RANGE, CONF_OR, \
- CONF_SEND_EVERY, CONF_SEND_FIRST_AT, CONF_THROTTLE, CONF_TO, CONF_TRIGGER_ID, \
+ CONF_EXPIRE_AFTER, CONF_FILTERS, CONF_FROM, CONF_ICON, CONF_ID, CONF_INTERNAL, \
+ CONF_ON_RAW_VALUE, CONF_ON_VALUE, CONF_ON_VALUE_RANGE, \
+ CONF_SEND_EVERY, CONF_SEND_FIRST_AT, CONF_TO, CONF_TRIGGER_ID, \
CONF_UNIT_OF_MEASUREMENT, \
- CONF_WINDOW_SIZE, CONF_VALUE, CONF_HEARTBEAT, CONF_NAME, CONF_MQTT_ID
-from esphome.core import CORE, coroutine
-from esphome.util import ServiceRegistry
+ CONF_WINDOW_SIZE, CONF_NAME, CONF_MQTT_ID
+from esphome.core import CORE, coroutine, coroutine_with_priority
+from esphome.util import Registry
IS_PLATFORM_COMPONENT = True
@@ -28,8 +25,8 @@ def validate_send_first_at(value):
return value
-FILTER_REGISTRY = ServiceRegistry()
-validate_filters = cv.validate_registry('filter', FILTER_REGISTRY, [CONF_ID])
+FILTER_REGISTRY = Registry()
+validate_filters = cv.validate_registry('filter', FILTER_REGISTRY)
def validate_datapoint(value):
@@ -57,11 +54,12 @@ SensorPtr = Sensor.operator('ptr')
PollingSensorComponent = sensor_ns.class_('PollingSensorComponent', cg.PollingComponent, Sensor)
# Triggers
-SensorStateTrigger = sensor_ns.class_('SensorStateTrigger', cg.Trigger.template(cg.float_))
-SensorRawStateTrigger = sensor_ns.class_('SensorRawStateTrigger', cg.Trigger.template(cg.float_))
-ValueRangeTrigger = sensor_ns.class_('ValueRangeTrigger', cg.Trigger.template(cg.float_),
+SensorStateTrigger = sensor_ns.class_('SensorStateTrigger', automation.Trigger.template(cg.float_))
+SensorRawStateTrigger = sensor_ns.class_('SensorRawStateTrigger',
+ automation.Trigger.template(cg.float_))
+ValueRangeTrigger = sensor_ns.class_('ValueRangeTrigger', automation.Trigger.template(cg.float_),
cg.Component)
-SensorPublishAction = sensor_ns.class_('SensorPublishAction', cg.Action)
+SensorPublishAction = sensor_ns.class_('SensorPublishAction', automation.Action)
# Filters
Filter = sensor_ns.class_('Filter')
@@ -84,8 +82,8 @@ accuracy_decimals = cv.int_
icon = cv.icon
SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTSensorComponent),
- cv.GenerateID(): cv.declare_variable_id(Sensor),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTSensorComponent),
+ cv.GenerateID(): cv.declare_id(Sensor),
cv.Optional(CONF_UNIT_OF_MEASUREMENT): unit_of_measurement,
cv.Optional(CONF_ICON): icon,
cv.Optional(CONF_ACCURACY_DECIMALS): accuracy_decimals,
@@ -93,13 +91,13 @@ SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
cv.Any(None, cv.positive_time_period_milliseconds)),
cv.Optional(CONF_FILTERS): validate_filters,
cv.Optional(CONF_ON_VALUE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SensorStateTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorStateTrigger),
}),
cv.Optional(CONF_ON_RAW_VALUE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SensorRawStateTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SensorRawStateTrigger),
}),
cv.Optional(CONF_ON_VALUE_RANGE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ValueRangeTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ValueRangeTrigger),
cv.Optional(CONF_ABOVE): cv.float_,
cv.Optional(CONF_BELOW): cv.float_,
}, cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)),
@@ -115,117 +113,87 @@ def sensor_schema(unit_of_measurement_, icon_, accuracy_decimals_):
})
-@FILTER_REGISTRY.register(CONF_OFFSET, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(OffsetFilter),
- cv.Required(CONF_VALUE): cv.float_,
-})))
-def offset_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
+@FILTER_REGISTRY.register('offset', OffsetFilter, cv.float_)
+def offset_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config)
-@FILTER_REGISTRY.register(CONF_MULTIPLY, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(MultiplyFilter),
- cv.Required(CONF_VALUE): cv.float_,
-})))
-def multiply_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
+@FILTER_REGISTRY.register('multiply', MultiplyFilter, cv.float_)
+def multiply_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config)
-@FILTER_REGISTRY.register('filter_out', cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(FilterOutValueFilter),
- cv.Required(CONF_VALUE): cv.float_,
-})))
-def filter_out_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
+@FILTER_REGISTRY.register('filter_out', FilterOutValueFilter, cv.float_)
+def filter_out_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config)
-@FILTER_REGISTRY.register('sliding_window_moving_average', cv.All(cv.Schema({
- cv.GenerateID():
- cv.declare_variable_id(SlidingWindowMovingAverageFilter),
+SLIDING_AVERAGE_SCHEMA = cv.All(cv.Schema({
cv.Optional(CONF_WINDOW_SIZE, default=15): cv.positive_not_null_int,
cv.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
cv.Optional(CONF_SEND_FIRST_AT, default=1): cv.positive_not_null_int,
-}), validate_send_first_at))
-def sliding_window_moving_average_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY],
+}), validate_send_first_at)
+
+
+@FILTER_REGISTRY.register('sliding_window_moving_average', SlidingWindowMovingAverageFilter,
+ SLIDING_AVERAGE_SCHEMA)
+def sliding_window_moving_average_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config[CONF_WINDOW_SIZE], config[CONF_SEND_EVERY],
config[CONF_SEND_FIRST_AT])
-@FILTER_REGISTRY.register('exponential_moving_average', cv.Schema({
- cv.GenerateID():
- cv.declare_variable_id(ExponentialMovingAverageFilter),
+@FILTER_REGISTRY.register('exponential_moving_average', ExponentialMovingAverageFilter, cv.Schema({
cv.Optional(CONF_ALPHA, default=0.1): cv.positive_float,
cv.Optional(CONF_SEND_EVERY, default=15): cv.positive_not_null_int,
}))
-def exponential_moving_average_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_ALPHA], config[CONF_SEND_EVERY])
+def exponential_moving_average_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config[CONF_ALPHA], config[CONF_SEND_EVERY])
-@FILTER_REGISTRY.register(CONF_LAMBDA, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(LambdaFilter),
- cv.Required(CONF_VALUE): cv.lambda_,
-})))
-def lambda_filter_to_code(config):
- lambda_ = yield cg.process_lambda(config[CONF_VALUE], [(float, 'x')],
+@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.lambda_)
+def lambda_filter_to_code(config, filter_id):
+ lambda_ = yield cg.process_lambda(config, [(float, 'x')],
return_type=cg.optional.template(float))
- yield cg.new_Pvariable(config[CONF_ID], lambda_)
+ yield cg.new_Pvariable(filter_id, lambda_)
-@FILTER_REGISTRY.register(CONF_DELTA, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DeltaFilter),
- cv.Required(CONF_VALUE): cv.float_,
-})))
-def delta_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
+@FILTER_REGISTRY.register('delta', DeltaFilter, cv.float_)
+def delta_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config)
-@FILTER_REGISTRY.register(CONF_OR, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(OrFilter),
- cv.Required(CONF_VALUE): validate_filters,
-})))
-def or_filter_to_code(config):
- filters = yield build_filters(config[CONF_VALUE])
- yield cg.new_Pvariable(config[CONF_ID], filters)
+@FILTER_REGISTRY.register('or', OrFilter, validate_filters)
+def or_filter_to_code(config, filter_id):
+ filters = yield build_filters(config)
+ yield cg.new_Pvariable(filter_id, filters)
-@FILTER_REGISTRY.register(CONF_THROTTLE, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(ThrottleFilter),
- cv.Required(CONF_VALUE): cv.positive_time_period_milliseconds,
-})))
-def throttle_filter_to_code(config):
- yield cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
+@FILTER_REGISTRY.register('throttle', ThrottleFilter, cv.positive_time_period_milliseconds)
+def throttle_filter_to_code(config, filter_id):
+ yield cg.new_Pvariable(filter_id, config)
-@FILTER_REGISTRY.register(CONF_HEARTBEAT, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(HeartbeatFilter),
- cv.Required(CONF_VALUE): cv.positive_time_period_milliseconds,
-}).extend(cv.COMPONENT_SCHEMA)))
-def heartbeat_filter_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
- yield cg.register_component(var, config)
+@FILTER_REGISTRY.register('heartbeat', HeartbeatFilter, cv.positive_time_period_milliseconds)
+def heartbeat_filter_to_code(config, filter_id):
+ var = cg.new_Pvariable(filter_id, config)
+ yield cg.register_component(var, {})
yield var
-@FILTER_REGISTRY.register(CONF_DEBOUNCE, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(DebounceFilter),
- cv.Required(CONF_VALUE): cv.positive_time_period_milliseconds,
-}).extend(cv.COMPONENT_SCHEMA)))
-def debounce_filter_to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_VALUE])
- yield cg.register_component(var, config)
+@FILTER_REGISTRY.register('debounce', DebounceFilter, cv.positive_time_period_milliseconds)
+def debounce_filter_to_code(config, filter_id):
+ var = cg.new_Pvariable(filter_id, config)
+ yield cg.register_component(var, {})
yield var
-@FILTER_REGISTRY.register(CONF_CALIBRATE_LINEAR, cv.maybe_simple_value(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(CalibrateLinearFilter),
- cv.Required(CONF_VALUE): cv.All(
- cv.ensure_list(validate_datapoint), cv.Length(min=2)),
-}).extend(cv.COMPONENT_SCHEMA)))
-def calibrate_linear_filter_to_code(config):
- x = [conf[CONF_FROM] for conf in config[CONF_VALUE]]
- y = [conf[CONF_TO] for conf in config[CONF_VALUE]]
+@FILTER_REGISTRY.register('calibrate_linear', CalibrateLinearFilter, cv.All(
+ cv.ensure_list(validate_datapoint), cv.Length(min=2)))
+def calibrate_linear_filter_to_code(config, filter_id):
+ x = [conf[CONF_FROM] for conf in config]
+ y = [conf[CONF_TO] for conf in config]
k, b = fit_linear(x, y)
- yield cg.new_Pvariable(config[CONF_ID], k, b)
+ yield cg.new_Pvariable(filter_id, k, b)
@coroutine
@@ -235,6 +203,7 @@ def build_filters(config):
@coroutine
def setup_sensor_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(config[CONF_INTERNAL]))
if CONF_UNIT_OF_MEASUREMENT in config:
@@ -285,32 +254,30 @@ def register_sensor(var, config):
@coroutine
def new_sensor(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield register_sensor(var, config)
yield var
-CONF_SENSOR_IN_RANGE = 'sensor.in_range'
SENSOR_IN_RANGE_CONDITION_SCHEMA = cv.All({
- cv.Required(CONF_ID): cv.use_variable_id(Sensor),
+ cv.Required(CONF_ID): cv.use_id(Sensor),
cv.Optional(CONF_ABOVE): cv.float_,
cv.Optional(CONF_BELOW): cv.float_,
}, cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))
-@CONDITION_REGISTRY.register(CONF_SENSOR_IN_RANGE, SENSOR_IN_RANGE_CONDITION_SCHEMA)
+@automation.register_condition('sensor.in_range', SensorInRangeCondition,
+ SENSOR_IN_RANGE_CONDITION_SCHEMA)
def sensor_in_range_to_code(config, condition_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- rhs = var.make_sensor_in_range_condition(template_arg)
- type = SensorInRangeCondition.template(template_arg)
- cond = cg.Pvariable(condition_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(condition_id, template_arg, paren)
if CONF_ABOVE in config:
- cg.add(cond.set_min(config[CONF_ABOVE]))
+ cg.add(var.set_min(config[CONF_ABOVE]))
if CONF_BELOW in config:
- cg.add(cond.set_max(config[CONF_BELOW]))
+ cg.add(var.set_max(config[CONF_BELOW]))
- yield cond
+ yield var
def _mean(xs):
@@ -338,6 +305,7 @@ def fit_linear(x, y):
return k, b
+@coroutine_with_priority(40.0)
def to_code(config):
cg.add_define('USE_SENSOR')
cg.add_global(sensor_ns.using)
diff --git a/esphome/components/sensor/automation.h b/esphome/components/sensor/automation.h
index 158b993579..079077dba0 100644
--- a/esphome/components/sensor/automation.h
+++ b/esphome/components/sensor/automation.h
@@ -25,10 +25,7 @@ template class SensorPublishAction : public Action {
public:
SensorPublishAction(Sensor *sensor) : sensor_(sensor) {}
TEMPLATABLE_VALUE(float, state)
- void play(Ts... x) override {
- this->sensor_->publish_state(this->state_.value(x...));
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->sensor_->publish_state(this->state_.value(x...)); }
protected:
Sensor *sensor_;
diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp
index 7cb6e1268b..4923a1c09b 100644
--- a/esphome/components/sensor/filter.cpp
+++ b/esphome/components/sensor/filter.cpp
@@ -163,10 +163,10 @@ optional DeltaFilter::new_value(float value) {
// OrFilter
OrFilter::OrFilter(std::vector filters) : filters_(std::move(filters)), phi_(this) {}
-OrFilter::PhiNode::PhiNode(OrFilter *parent) : parent_(parent) {}
+OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {}
optional OrFilter::PhiNode::new_value(float value) {
- this->parent_->output(value);
+ this->or_parent_->output(value);
return {};
}
diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h
index 753a9ce1c2..6bd22be230 100644
--- a/esphome/components/sensor/filter.h
+++ b/esphome/components/sensor/filter.h
@@ -222,11 +222,11 @@ class OrFilter : public Filter {
protected:
class PhiNode : public Filter {
public:
- PhiNode(OrFilter *parent);
+ PhiNode(OrFilter *or_parent);
optional new_value(float value) override;
protected:
- OrFilter *parent_;
+ OrFilter *or_parent_;
};
std::vector filters_;
diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h
index c9710b7d24..1c7c854394 100644
--- a/esphome/components/sensor/sensor.h
+++ b/esphome/components/sensor/sensor.h
@@ -26,8 +26,8 @@ namespace sensor {
*/
class Sensor : public Nameable {
public:
- explicit Sensor(const std::string &name);
explicit Sensor();
+ explicit Sensor(const std::string &name);
/** Manually set the unit of measurement of this sensor. By default the sensor's default defined by
* unit_of_measurement() is used.
diff --git a/esphome/components/servo/__init__.py b/esphome/components/servo/__init__.py
index c16bff0474..92243ee18d 100644
--- a/esphome/components/servo/__init__.py
+++ b/esphome/components/servo/__init__.py
@@ -1,19 +1,20 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY, maybe_simple_id
+from esphome import automation
+from esphome.automation import maybe_simple_id
from esphome.components.output import FloatOutput
from esphome.const import CONF_ID, CONF_IDLE_LEVEL, CONF_MAX_LEVEL, CONF_MIN_LEVEL, CONF_OUTPUT, \
CONF_LEVEL
servo_ns = cg.esphome_ns.namespace('servo')
Servo = servo_ns.class_('Servo', cg.Component)
-ServoWriteAction = servo_ns.class_('ServoWriteAction', cg.Action)
-ServoDetachAction = servo_ns.class_('ServoDetachAction', cg.Action)
+ServoWriteAction = servo_ns.class_('ServoWriteAction', automation.Action)
+ServoDetachAction = servo_ns.class_('ServoDetachAction', automation.Action)
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.declare_variable_id(Servo),
- cv.Required(CONF_OUTPUT): cv.use_variable_id(FloatOutput),
+ cv.Required(CONF_ID): cv.declare_id(Servo),
+ cv.Required(CONF_OUTPUT): cv.use_id(FloatOutput),
cv.Optional(CONF_MIN_LEVEL, default='3%'): cv.percentage,
cv.Optional(CONF_IDLE_LEVEL, default='7.5%'): cv.percentage,
cv.Optional(CONF_MAX_LEVEL, default='12%'): cv.percentage,
@@ -21,34 +22,31 @@ CONFIG_SCHEMA = cv.Schema({
def to_code(config):
- out = yield cg.get_variable(config[CONF_OUTPUT])
- var = cg.new_Pvariable(config[CONF_ID], out)
- cg.register_component(var, config)
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ out = yield cg.get_variable(config[CONF_OUTPUT])
+ cg.add(var.set_output(out))
cg.add(var.set_min_level(config[CONF_MIN_LEVEL]))
cg.add(var.set_idle_level(config[CONF_IDLE_LEVEL]))
cg.add(var.set_max_level(config[CONF_MAX_LEVEL]))
-@ACTION_REGISTRY.register('servo.write', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(Servo),
+@automation.register_action('servo.write', ServoWriteAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(Servo),
cv.Required(CONF_LEVEL): cv.templatable(cv.possibly_negative_percentage),
}))
def servo_write_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ServoWriteAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_LEVEL], args, float)
- cg.add(action.set_value(template_))
- yield action
+ cg.add(var.set_value(template_))
+ yield var
-@ACTION_REGISTRY.register('servo.detach', maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(Servo),
+@automation.register_action('servo.detach', ServoDetachAction, maybe_simple_id({
+ cv.Required(CONF_ID): cv.use_id(Servo),
}))
def servo_detach_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ServoDetachAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
diff --git a/esphome/components/servo/servo.h b/esphome/components/servo/servo.h
index cfe71c50f3..3a0993c0c4 100644
--- a/esphome/components/servo/servo.h
+++ b/esphome/components/servo/servo.h
@@ -13,15 +13,15 @@ extern uint32_t global_servo_id;
class Servo : public Component {
public:
- Servo(output::FloatOutput *output) : output_(output) {}
+ void set_output(output::FloatOutput *output) { output_ = output; }
void write(float value) {
value = clamp(value, -1.0f, 1.0f);
float level;
if (value < 0.0)
- level = lerp(this->idle_level_, this->min_level_, -value);
+ level = lerp(-value, this->idle_level_, this->min_level_);
else
- level = lerp(this->idle_level_, this->max_level_, value);
+ level = lerp(value, this->idle_level_, this->max_level_);
this->output_->set_level(level);
this->save_level_(level);
@@ -63,10 +63,7 @@ template class ServoWriteAction : public Action {
public:
ServoWriteAction(Servo *servo) : servo_(servo) {}
TEMPLATABLE_VALUE(float, value)
- void play(Ts... x) override {
- this->servo_->write(this->value_.value(x...));
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->servo_->write(this->value_.value(x...)); }
protected:
Servo *servo_;
@@ -75,10 +72,7 @@ template class ServoWriteAction : public Action {
template class ServoDetachAction : public Action {
public:
ServoDetachAction(Servo *servo) : servo_(servo) {}
- void play(Ts... x) override {
- this->servo_->detach();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->servo_->detach(); }
protected:
Servo *servo_;
diff --git a/esphome/components/sht3xd/sensor.py b/esphome/components/sht3xd/sensor.py
index e6ed633da6..9bbdc47eec 100644
--- a/esphome/components/sht3xd/sensor.py
+++ b/esphome/components/sht3xd/sensor.py
@@ -1,9 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
-from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, \
- ICON_WATER_PERCENT, ICON_THERMOMETER, UNIT_CELSIUS, \
- UNIT_PERCENT
+from esphome.const import CONF_HUMIDITY, CONF_ID, CONF_TEMPERATURE, ICON_WATER_PERCENT, \
+ ICON_THERMOMETER, UNIT_CELSIUS, UNIT_PERCENT
DEPENDENCIES = ['i2c']
@@ -11,17 +10,14 @@ sht3xd_ns = cg.esphome_ns.namespace('sht3xd')
SHT3XDComponent = sht3xd_ns.class_('SHT3XDComponent', cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(SHT3XDComponent),
- cv.Required(CONF_TEMPERATURE):
- cv.nameable(sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1)),
- cv.Required(CONF_HUMIDITY):
- cv.nameable(sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1)),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x44))
+ cv.GenerateID(): cv.declare_id(SHT3XDComponent),
+ cv.Required(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Required(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x44))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
diff --git a/esphome/components/sht3xd/sht3xd.h b/esphome/components/sht3xd/sht3xd.h
index fa8e7589fa..709f8aebe7 100644
--- a/esphome/components/sht3xd/sht3xd.h
+++ b/esphome/components/sht3xd/sht3xd.h
@@ -10,8 +10,6 @@ namespace sht3xd {
/// This class implements support for the SHT3x-DIS family of temperature+humidity i2c sensors.
class SHT3XDComponent : public PollingComponent, public i2c::I2CDevice {
public:
- SHT3XDComponent(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
diff --git a/esphome/components/shutdown/shutdown_switch.h b/esphome/components/shutdown/shutdown_switch.h
index 18d6213ed0..6aa64ff06b 100644
--- a/esphome/components/shutdown/shutdown_switch.h
+++ b/esphome/components/shutdown/shutdown_switch.h
@@ -8,8 +8,6 @@ namespace shutdown {
class ShutdownSwitch : public switch_::Switch, public Component {
public:
- explicit ShutdownSwitch(const std::string &name) : switch_::Switch(name) {}
-
void dump_config() override;
protected:
diff --git a/esphome/components/shutdown/switch.py b/esphome/components/shutdown/switch.py
index 0d2b3b369f..9826f9bbe5 100644
--- a/esphome/components/shutdown/switch.py
+++ b/esphome/components/shutdown/switch.py
@@ -1,21 +1,21 @@
-from esphome.components import switch
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_INVERTED, CONF_NAME, CONF_ICON, ICON_POWER
+import esphome.config_validation as cv
+from esphome.components import switch
+from esphome.const import CONF_ID, CONF_INVERTED, CONF_ICON, ICON_POWER
shutdown_ns = cg.esphome_ns.namespace('shutdown')
ShutdownSwitch = shutdown_ns.class_('ShutdownSwitch', switch.Switch, cg.Component)
-CONFIG_SCHEMA = cv.nameable(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(ShutdownSwitch),
+CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(ShutdownSwitch),
cv.Optional(CONF_INVERTED): cv.invalid("Shutdown switches do not support inverted mode!"),
cv.Optional(CONF_ICON, default=ICON_POWER): switch.icon
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield switch.register_switch(var, config)
diff --git a/esphome/components/sntp/sntp_component.h b/esphome/components/sntp/sntp_component.h
index bcd2b12a24..785f458d6c 100644
--- a/esphome/components/sntp/sntp_component.h
+++ b/esphome/components/sntp/sntp_component.h
@@ -14,8 +14,6 @@ namespace sntp {
/// \see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
class SNTPComponent : public time::RealTimeClock {
public:
- SNTPComponent() : time::RealTimeClock() {}
-
void setup() override;
void dump_config() override;
/// Change the servers used by SNTP for timekeeping
diff --git a/esphome/components/sntp/time.py b/esphome/components/sntp/time.py
index 8132ed18ad..798600075e 100644
--- a/esphome/components/sntp/time.py
+++ b/esphome/components/sntp/time.py
@@ -4,6 +4,7 @@ import esphome.codegen as cg
from esphome.const import CONF_ID, CONF_SERVERS
+DEPENDENCIES = ['network']
sntp_ns = cg.esphome_ns.namespace('sntp')
SNTPComponent = sntp_ns.class_('SNTPComponent', time_.RealTimeClock)
@@ -11,7 +12,7 @@ SNTPComponent = sntp_ns.class_('SNTPComponent', time_.RealTimeClock)
DEFAULT_SERVERS = ["0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org"]
CONFIG_SCHEMA = time_.TIME_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(SNTPComponent),
+ cv.GenerateID(): cv.declare_id(SNTPComponent),
cv.Optional(CONF_SERVERS, default=DEFAULT_SERVERS):
cv.All(cv.ensure_list(cv.domain), cv.Length(min=1, max=3)),
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/speed/fan/__init__.py b/esphome/components/speed/fan/__init__.py
index e992bfdbe5..ae6d09dfac 100644
--- a/esphome/components/speed/fan/__init__.py
+++ b/esphome/components/speed/fan/__init__.py
@@ -7,16 +7,16 @@ from .. import speed_ns
SpeedFan = speed_ns.class_('SpeedFan', cg.Component)
-CONFIG_SCHEMA = cv.nameable(fan.FAN_SCHEMA.extend({
- cv.GenerateID(CONF_OUTPUT_ID): cv.declare_variable_id(SpeedFan),
- cv.Required(CONF_OUTPUT): cv.use_variable_id(output.FloatOutput),
- cv.Optional(CONF_OSCILLATION_OUTPUT): cv.use_variable_id(output.BinaryOutput),
+CONFIG_SCHEMA = fan.FAN_SCHEMA.extend({
+ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SpeedFan),
+ cv.Required(CONF_OUTPUT): cv.use_id(output.FloatOutput),
+ cv.Optional(CONF_OSCILLATION_OUTPUT): cv.use_id(output.BinaryOutput),
cv.Optional(CONF_SPEED, default={}): cv.Schema({
cv.Optional(CONF_LOW, default=0.33): cv.percentage,
cv.Optional(CONF_MEDIUM, default=0.66): cv.percentage,
cv.Optional(CONF_HIGH, default=1.0): cv.percentage,
}),
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py
index 1721014f65..69899d1e84 100644
--- a/esphome/components/spi/__init__.py
+++ b/esphome/components/spi/__init__.py
@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_CLK_PIN, CONF_ID, CONF_MISO_PIN, CONF_MOSI_PIN, CONF_SPI_ID, \
CONF_CS_PIN
-from esphome.core import coroutine
+from esphome.core import coroutine, coroutine_with_priority
spi_ns = cg.esphome_ns.namespace('spi')
SPIComponent = spi_ns.class_('SPIComponent', cg.Component)
@@ -11,29 +11,31 @@ SPIDevice = spi_ns.class_('SPIDevice')
MULTI_CONF = True
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(SPIComponent),
+ cv.GenerateID(): cv.declare_id(SPIComponent),
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema,
}), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN))
+@coroutine_with_priority(1.0)
def to_code(config):
- clk = yield cg.gpio_pin_expression(config[CONF_CLK_PIN])
- miso = mosi = cg.nullptr
- if CONF_MISO_PIN in config:
- miso = yield cg.gpio_pin_expression(config[CONF_MISO_PIN])
- if CONF_MOSI_PIN in config:
- mosi = yield cg.gpio_pin_expression(config[CONF_MOSI_PIN])
-
- var = cg.new_Pvariable(config[CONF_ID], clk, miso, mosi)
+ cg.add_global(spi_ns.using)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
- cg.add_global(spi_ns.using)
+ clk = yield cg.gpio_pin_expression(config[CONF_CLK_PIN])
+ cg.add(var.set_clk(clk))
+ if CONF_MISO_PIN in config:
+ miso = yield cg.gpio_pin_expression(config[CONF_MISO_PIN])
+ cg.add(var.set_miso(miso))
+ if CONF_MOSI_PIN in config:
+ mosi = yield cg.gpio_pin_expression(config[CONF_MOSI_PIN])
+ cg.add(var.set_mosi(mosi))
SPI_DEVICE_SCHEMA = cv.Schema({
- cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
+ cv.GenerateID(CONF_SPI_ID): cv.use_id(SPIComponent),
cv.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
})
diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h
index 9e053f0cda..600e1a0cd2 100644
--- a/esphome/components/spi/spi.h
+++ b/esphome/components/spi/spi.h
@@ -8,7 +8,9 @@ namespace spi {
class SPIComponent : public Component {
public:
- SPIComponent(GPIOPin *clk, GPIOPin *miso, GPIOPin *mosi) : clk_(clk), miso_(miso), mosi_(mosi) {}
+ void set_clk(GPIOPin *clk) { clk_ = clk; }
+ void set_miso(GPIOPin *miso) { miso_ = miso; }
+ void set_mosi(GPIOPin *mosi) { mosi_ = mosi; }
void setup() override;
@@ -30,8 +32,8 @@ class SPIComponent : public Component {
protected:
GPIOPin *clk_;
- GPIOPin *miso_;
- GPIOPin *mosi_;
+ GPIOPin *miso_{nullptr};
+ GPIOPin *mosi_{nullptr};
GPIOPin *active_cs_{nullptr};
bool msb_first_{true};
bool high_speed_{false};
diff --git a/esphome/components/ssd1306_base/__init__.py b/esphome/components/ssd1306_base/__init__.py
index 39cc95f46d..0a678452b2 100644
--- a/esphome/components/ssd1306_base/__init__.py
+++ b/esphome/components/ssd1306_base/__init__.py
@@ -2,9 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import display
-from esphome.components.spi import SPIComponent
-from esphome.const import CONF_EXTERNAL_VCC, CONF_LAMBDA, \
- CONF_MODEL, CONF_RESET_PIN, CONF_SPI_ID, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_EXTERNAL_VCC, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN
from esphome.core import coroutine
ssd1306_base_ns = cg.esphome_ns.namespace('ssd1306_base')
@@ -22,22 +20,21 @@ MODELS = {
'SH1106_64X48': SSD1306Model.SH1106_MODEL_64_48,
}
-SSD1306_MODEL = cv.one_of(*MODELS, upper=True, space="_")
+SSD1306_MODEL = cv.enum(MODELS, upper=True, space="_")
SSD1306_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend({
- cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
cv.Required(CONF_MODEL): SSD1306_MODEL,
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_EXTERNAL_VCC): cv.boolean,
- cv.Optional(CONF_UPDATE_INTERVAL, default='1s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA)
+}).extend(cv.polling_component_schema('1s'))
@coroutine
def setup_ssd1036(var, config):
yield cg.register_component(var, config)
yield display.register_display(var, config)
- cg.add(var.set_model(MODELS[config[CONF_MODEL]]))
+
+ cg.add(var.set_model(config[CONF_MODEL]))
if CONF_RESET_PIN in config:
reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN])
cg.add(var.set_reset_pin(reset))
diff --git a/esphome/components/ssd1306_base/ssd1306_base.h b/esphome/components/ssd1306_base/ssd1306_base.h
index bb76f740f9..66c12ec938 100644
--- a/esphome/components/ssd1306_base/ssd1306_base.h
+++ b/esphome/components/ssd1306_base/ssd1306_base.h
@@ -20,8 +20,6 @@ enum SSD1306Model {
class SSD1306 : public PollingComponent, public display::DisplayBuffer {
public:
- SSD1306() : PollingComponent(0) {}
-
void setup() override;
void display();
diff --git a/esphome/components/ssd1306_i2c/display.py b/esphome/components/ssd1306_i2c/display.py
index c6674e495f..eaa656f26b 100644
--- a/esphome/components/ssd1306_i2c/display.py
+++ b/esphome/components/ssd1306_i2c/display.py
@@ -10,7 +10,7 @@ ssd1306_i2c = cg.esphome_ns.namespace('ssd1306_i2c')
I2CSSD1306 = ssd1306_i2c.class_('I2CSSD1306', ssd1306_base.SSD1306, i2c.I2CDevice)
CONFIG_SCHEMA = cv.All(ssd1306_base.SSD1306_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(I2CSSD1306),
+ cv.GenerateID(): cv.declare_id(I2CSSD1306),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x3C)),
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))
diff --git a/esphome/components/ssd1306_i2c/ssd1306_i2c.h b/esphome/components/ssd1306_i2c/ssd1306_i2c.h
index 69f0297fc8..e3f21fe74c 100644
--- a/esphome/components/ssd1306_i2c/ssd1306_i2c.h
+++ b/esphome/components/ssd1306_i2c/ssd1306_i2c.h
@@ -9,8 +9,6 @@ namespace ssd1306_i2c {
class I2CSSD1306 : public ssd1306_base::SSD1306, public i2c::I2CDevice {
public:
- I2CSSD1306() = default;
-
void setup() override;
void dump_config() override;
diff --git a/esphome/components/ssd1306_spi/display.py b/esphome/components/ssd1306_spi/display.py
index 2dbfd4a270..65f0df1c51 100644
--- a/esphome/components/ssd1306_spi/display.py
+++ b/esphome/components/ssd1306_spi/display.py
@@ -11,15 +11,16 @@ ssd1306_spi = cg.esphome_ns.namespace('ssd1306_spi')
SPISSD1306 = ssd1306_spi.class_('SPISSD1306', ssd1306_base.SSD1306, spi.SPIDevice)
CONFIG_SCHEMA = cv.All(ssd1306_base.SSD1306_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(SPISSD1306),
+ cv.GenerateID(): cv.declare_id(SPISSD1306),
cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA),
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))
def to_code(config):
- dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN])
- var = cg.new_Pvariable(config[CONF_ID], dc)
-
+ var = cg.new_Pvariable(config[CONF_ID])
yield ssd1306_base.setup_ssd1036(var, config)
yield spi.register_spi_device(var, config)
+
+ dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN])
+ cg.add(var.set_dc_pin(dc))
diff --git a/esphome/components/ssd1306_spi/ssd1306_spi.h b/esphome/components/ssd1306_spi/ssd1306_spi.h
index 48e0036cb0..5d0640bd84 100644
--- a/esphome/components/ssd1306_spi/ssd1306_spi.h
+++ b/esphome/components/ssd1306_spi/ssd1306_spi.h
@@ -9,7 +9,7 @@ namespace ssd1306_spi {
class SPISSD1306 : public ssd1306_base::SSD1306, public spi::SPIDevice {
public:
- SPISSD1306(GPIOPin *dc_pin) : dc_pin_(dc_pin) {}
+ void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; }
void setup() override;
diff --git a/esphome/components/status/binary_sensor.py b/esphome/components/status/binary_sensor.py
index 9650d29c26..9963461cef 100644
--- a/esphome/components/status/binary_sensor.py
+++ b/esphome/components/status/binary_sensor.py
@@ -1,20 +1,20 @@
-from esphome.components import binary_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_NAME, CONF_DEVICE_CLASS, DEVICE_CLASS_CONNECTIVITY
+import esphome.config_validation as cv
+from esphome.components import binary_sensor
+from esphome.const import CONF_ID, CONF_DEVICE_CLASS, DEVICE_CLASS_CONNECTIVITY
status_ns = cg.esphome_ns.namespace('status')
StatusBinarySensor = status_ns.class_('StatusBinarySensor', binary_sensor.BinarySensor,
cg.Component)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(StatusBinarySensor),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(StatusBinarySensor),
cv.Optional(CONF_DEVICE_CLASS, default=DEVICE_CLASS_CONNECTIVITY): binary_sensor.device_class,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield binary_sensor.register_binary_sensor(var, config)
diff --git a/esphome/components/status/status_binary_sensor.cpp b/esphome/components/status/status_binary_sensor.cpp
index 2ea5844a61..5485c6ebcd 100644
--- a/esphome/components/status/status_binary_sensor.cpp
+++ b/esphome/components/status/status_binary_sensor.cpp
@@ -14,7 +14,6 @@ namespace status {
static const char *TAG = "status";
-StatusBinarySensor::StatusBinarySensor(const std::string &name) : BinarySensor(name) {}
void StatusBinarySensor::loop() {
bool status = network_is_connected();
#ifdef USE_MQTT
diff --git a/esphome/components/status/status_binary_sensor.h b/esphome/components/status/status_binary_sensor.h
index 1a0561799f..fa121291a1 100644
--- a/esphome/components/status/status_binary_sensor.h
+++ b/esphome/components/status/status_binary_sensor.h
@@ -8,9 +8,6 @@ namespace status {
class StatusBinarySensor : public binary_sensor::BinarySensor, public Component {
public:
- /// Construct the status binary sensor
- explicit StatusBinarySensor(const std::string &name);
-
void loop() override;
void setup() override;
diff --git a/esphome/components/status_led/__init__.py b/esphome/components/status_led/__init__.py
index 4b45ac28d2..26105b5e92 100644
--- a/esphome/components/status_led/__init__.py
+++ b/esphome/components/status_led/__init__.py
@@ -8,7 +8,7 @@ status_led_ns = cg.esphome_ns.namespace('status_led')
StatusLED = status_led_ns.class_('StatusLED', cg.Component)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(StatusLED),
+ cv.GenerateID(): cv.declare_id(StatusLED),
cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/stepper/__init__.py b/esphome/components/stepper/__init__.py
index 2fbd3cc718..087fb18137 100644
--- a/esphome/components/stepper/__init__.py
+++ b/esphome/components/stepper/__init__.py
@@ -1,9 +1,9 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY
+from esphome import automation
from esphome.const import CONF_ACCELERATION, CONF_DECELERATION, CONF_ID, CONF_MAX_SPEED, \
- CONF_POSITION, CONF_TARGET
-from esphome.core import CORE, coroutine
+ CONF_POSITION, CONF_TARGET, CONF_SPEED
+from esphome.core import CORE, coroutine, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -11,8 +11,9 @@ IS_PLATFORM_COMPONENT = True
stepper_ns = cg.esphome_ns.namespace('stepper')
Stepper = stepper_ns.class_('Stepper')
-SetTargetAction = stepper_ns.class_('SetTargetAction', cg.Action)
-ReportPositionAction = stepper_ns.class_('ReportPositionAction', cg.Action)
+SetTargetAction = stepper_ns.class_('SetTargetAction', automation.Action)
+ReportPositionAction = stepper_ns.class_('ReportPositionAction', automation.Action)
+SetSpeedAction = stepper_ns.class_('SetSpeedAction', automation.Action)
def validate_acceleration(value):
@@ -79,33 +80,42 @@ def register_stepper(var, config):
yield setup_stepper_core_(var, config)
-@ACTION_REGISTRY.register('stepper.set_target', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(Stepper),
+@automation.register_action('stepper.set_target', SetTargetAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(Stepper),
cv.Required(CONF_TARGET): cv.templatable(cv.int_),
}))
def stepper_set_target_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = SetTargetAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_TARGET], args, cg.int32)
- cg.add(action.set_target(template_))
- yield action
+ cg.add(var.set_target(template_))
+ yield var
-@ACTION_REGISTRY.register('stepper.report_position', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(Stepper),
+@automation.register_action('stepper.report_position', ReportPositionAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(Stepper),
cv.Required(CONF_POSITION): cv.templatable(cv.int_),
}))
def stepper_report_position_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ReportPositionAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_POSITION], args, cg.int32)
- cg.add(action.set_position(template_))
- yield action
+ cg.add(var.set_position(template_))
+ yield var
+@automation.register_action('stepper.set_speed', SetSpeedAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(Stepper),
+ cv.Required(CONF_SPEED): cv.templatable(validate_speed),
+}))
+def stepper_set_speed_to_code(config, action_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
+ template_ = yield cg.templatable(config[CONF_SPEED], args, cg.int32)
+ cg.add(var.set_speed(template_))
+ yield var
+
+
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_global(stepper_ns.using)
diff --git a/esphome/components/stepper/stepper.h b/esphome/components/stepper/stepper.h
index 4583017ae7..33777dce83 100644
--- a/esphome/components/stepper/stepper.h
+++ b/esphome/components/stepper/stepper.h
@@ -19,6 +19,7 @@ class Stepper {
void set_acceleration(float acceleration) { this->acceleration_ = acceleration; }
void set_deceleration(float deceleration) { this->deceleration_ = deceleration; }
void set_max_speed(float max_speed) { this->max_speed_ = max_speed; }
+ virtual void on_update_speed() {}
bool has_reached_target() { return this->current_position == this->target_position; }
int32_t current_position{0};
@@ -42,10 +43,7 @@ template class SetTargetAction : public Action {
TEMPLATABLE_VALUE(int32_t, target)
- void play(Ts... x) override {
- this->parent_->set_target(this->target_.value(x...));
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->parent_->set_target(this->target_.value(x...)); }
protected:
Stepper *parent_;
@@ -57,9 +55,22 @@ template class ReportPositionAction : public Action {
TEMPLATABLE_VALUE(int32_t, position)
+ void play(Ts... x) override { this->parent_->report_position(this->position_.value(x...)); }
+
+ protected:
+ Stepper *parent_;
+};
+
+template class SetSpeedAction : public Action {
+ public:
+ explicit SetSpeedAction(Stepper *parent) : parent_(parent) {}
+
+ TEMPLATABLE_VALUE(float, speed);
+
void play(Ts... x) override {
- this->parent_->report_position(this->position_.value(x...));
- this->play_next(x...);
+ float speed = this->speed_.value(x...);
+ this->parent_->set_max_speed(speed);
+ this->parent_->on_update_speed();
}
protected:
diff --git a/esphome/components/substitutions/__init__.py b/esphome/components/substitutions/__init__.py
index d63738a178..433a3066ee 100644
--- a/esphome/components/substitutions/__init__.py
+++ b/esphome/components/substitutions/__init__.py
@@ -1,9 +1,8 @@
import logging
import re
-from esphome import core
import esphome.config_validation as cv
-from esphome.core import EsphomeError
+from esphome import core
from esphome.py_compat import string_types
_LOGGER = logging.getLogger(__name__)
@@ -105,30 +104,24 @@ def _substitute_item(substitutions, item, path):
def do_substitution_pass(config):
if CONF_SUBSTITUTIONS not in config:
- return config
+ return
substitutions = config[CONF_SUBSTITUTIONS]
- if not isinstance(substitutions, dict):
- raise EsphomeError(u"Substitutions must be a key to value mapping, got {}"
- u"".format(type(substitutions)))
+ with cv.prepend_path('substitutions'):
+ if not isinstance(substitutions, dict):
+ raise cv.Invalid(u"Substitutions must be a key to value mapping, got {}"
+ u"".format(type(substitutions)))
- key = ''
- try:
replace_keys = []
for key, value in substitutions.items():
- sub = validate_substitution_key(key)
- if sub != key:
- replace_keys.append((key, sub))
- substitutions[key] = cv.string_strict(value)
+ with cv.prepend_path(key):
+ sub = validate_substitution_key(key)
+ if sub != key:
+ replace_keys.append((key, sub))
+ substitutions[key] = cv.string_strict(value)
for old, new in replace_keys:
substitutions[new] = substitutions[old]
del substitutions[old]
- except cv.Invalid as err:
- err.path.append(key)
-
- raise EsphomeError(u"Error while parsing substitutions: {}".format(err))
config[CONF_SUBSTITUTIONS] = substitutions
_substitute_item(substitutions, config, [])
-
- return config
diff --git a/esphome/components/switch/__init__.py b/esphome/components/switch/__init__.py
index f472474a8e..6425a364a1 100644
--- a/esphome/components/switch/__init__.py
+++ b/esphome/components/switch/__init__.py
@@ -1,11 +1,11 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
-from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY, Condition, maybe_simple_id
+from esphome.automation import Condition, maybe_simple_id
from esphome.components import mqtt
from esphome.const import CONF_ICON, CONF_ID, CONF_INTERNAL, CONF_INVERTED, CONF_ON_TURN_OFF, \
- CONF_ON_TURN_ON, CONF_TRIGGER_ID, CONF_MQTT_ID
-from esphome.core import CORE, coroutine
+ CONF_ON_TURN_ON, CONF_TRIGGER_ID, CONF_MQTT_ID, CONF_NAME
+from esphome.core import CORE, coroutine, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -13,32 +13,34 @@ switch_ns = cg.esphome_ns.namespace('switch_')
Switch = switch_ns.class_('Switch', cg.Nameable)
SwitchPtr = Switch.operator('ptr')
-ToggleAction = switch_ns.class_('ToggleAction', cg.Action)
-TurnOffAction = switch_ns.class_('TurnOffAction', cg.Action)
-TurnOnAction = switch_ns.class_('TurnOnAction', cg.Action)
-SwitchPublishAction = switch_ns.class_('SwitchPublishAction', cg.Action)
+ToggleAction = switch_ns.class_('ToggleAction', automation.Action)
+TurnOffAction = switch_ns.class_('TurnOffAction', automation.Action)
+TurnOnAction = switch_ns.class_('TurnOnAction', automation.Action)
+SwitchPublishAction = switch_ns.class_('SwitchPublishAction', automation.Action)
SwitchCondition = switch_ns.class_('SwitchCondition', Condition)
-SwitchTurnOnTrigger = switch_ns.class_('SwitchTurnOnTrigger', cg.Trigger.template())
-SwitchTurnOffTrigger = switch_ns.class_('SwitchTurnOffTrigger', cg.Trigger.template())
+SwitchTurnOnTrigger = switch_ns.class_('SwitchTurnOnTrigger', automation.Trigger.template())
+SwitchTurnOffTrigger = switch_ns.class_('SwitchTurnOffTrigger', automation.Trigger.template())
icon = cv.icon
SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTSwitchComponent),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTSwitchComponent),
cv.Optional(CONF_ICON): icon,
cv.Optional(CONF_INVERTED): cv.boolean,
cv.Optional(CONF_ON_TURN_ON): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SwitchTurnOnTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SwitchTurnOnTrigger),
}),
cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SwitchTurnOffTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SwitchTurnOffTrigger),
}),
})
+@coroutine
def setup_switch_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(config[CONF_INTERNAL]))
if CONF_ICON in config:
@@ -66,49 +68,31 @@ def register_switch(var, config):
SWITCH_ACTION_SCHEMA = maybe_simple_id({
- cv.Required(CONF_ID): cv.use_variable_id(Switch),
+ cv.Required(CONF_ID): cv.use_id(Switch),
})
-@ACTION_REGISTRY.register('switch.toggle', SWITCH_ACTION_SCHEMA)
+@automation.register_action('switch.toggle', ToggleAction, SWITCH_ACTION_SCHEMA)
+@automation.register_action('switch.turn_off', TurnOffAction, SWITCH_ACTION_SCHEMA)
+@automation.register_action('switch.turn_on', TurnOnAction, SWITCH_ACTION_SCHEMA)
def switch_toggle_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = ToggleAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(action_id, template_arg, paren)
-@ACTION_REGISTRY.register('switch.turn_off', SWITCH_ACTION_SCHEMA)
-def switch_turn_off_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TurnOffAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
-
-
-@ACTION_REGISTRY.register('switch.turn_on', SWITCH_ACTION_SCHEMA)
-def switch_turn_on_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TurnOnAction.template(template_arg)
- rhs = type.new(var)
- yield cg.Pvariable(action_id, rhs, type=type)
-
-
-@CONDITION_REGISTRY.register('switch.is_on', SWITCH_ACTION_SCHEMA)
+@automation.register_condition('switch.is_on', SwitchCondition, SWITCH_ACTION_SCHEMA)
def switch_is_on_to_code(config, condition_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = SwitchCondition.template(template_arg)
- rhs = type.new(var, True)
- yield cg.Pvariable(condition_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(condition_id, template_arg, paren)
-@CONDITION_REGISTRY.register('switch.is_off', SWITCH_ACTION_SCHEMA)
+@automation.register_condition('switch.is_off', SwitchCondition, SWITCH_ACTION_SCHEMA)
def switch_is_off_to_code(config, condition_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = SwitchCondition.template(template_arg)
- rhs = type.new(var, False)
- yield cg.Pvariable(condition_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ yield cg.new_Pvariable(condition_id, template_arg, paren)
+@coroutine_with_priority(100.0)
def to_code(config):
+ cg.add_global(switch_ns.using)
cg.add_define('USE_SWITCH')
diff --git a/esphome/components/switch/automation.h b/esphome/components/switch/automation.h
index d6e27c8166..90bdabf0f4 100644
--- a/esphome/components/switch/automation.h
+++ b/esphome/components/switch/automation.h
@@ -11,10 +11,7 @@ template class TurnOnAction : public Action {
public:
explicit TurnOnAction(Switch *a_switch) : switch_(a_switch) {}
- void play(Ts... x) override {
- this->switch_->turn_on();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->switch_->turn_on(); }
protected:
Switch *switch_;
@@ -24,10 +21,7 @@ template class TurnOffAction : public Action {
public:
explicit TurnOffAction(Switch *a_switch) : switch_(a_switch) {}
- void play(Ts... x) override {
- this->switch_->turn_off();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->switch_->turn_off(); }
protected:
Switch *switch_;
@@ -37,10 +31,7 @@ template class ToggleAction : public Action {
public:
explicit ToggleAction(Switch *a_switch) : switch_(a_switch) {}
- void play(Ts... x) override {
- this->switch_->toggle();
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->switch_->toggle(); }
protected:
Switch *switch_;
@@ -82,10 +73,7 @@ template class SwitchPublishAction : public Action {
public:
SwitchPublishAction(Switch *a_switch) : switch_(a_switch) {}
TEMPLATABLE_VALUE(bool, state)
- void play(Ts... x) override {
- this->switch_->publish_state(this->state_.value(x...));
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->switch_->publish_state(this->state_.value(x...)); }
protected:
Switch *switch_;
diff --git a/esphome/components/tcs34725/sensor.py b/esphome/components/tcs34725/sensor.py
index 88344bf726..478fe4aba6 100644
--- a/esphome/components/tcs34725/sensor.py
+++ b/esphome/components/tcs34725/sensor.py
@@ -3,7 +3,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_COLOR_TEMPERATURE, CONF_GAIN, CONF_ID, \
- CONF_ILLUMINANCE, CONF_INTEGRATION_TIME, CONF_UPDATE_INTERVAL, ICON_LIGHTBULB, \
+ CONF_ILLUMINANCE, CONF_INTEGRATION_TIME, ICON_LIGHTBULB, \
UNIT_PERCENT, ICON_THERMOMETER, UNIT_KELVIN, ICON_BRIGHTNESS_5, UNIT_LUX
DEPENDENCIES = ['i2c']
@@ -39,27 +39,26 @@ color_temperature_schema = sensor.sensor_schema(UNIT_KELVIN, ICON_THERMOMETER, 1
illuminance_schema = sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(TCS34725Component),
- cv.Optional(CONF_RED_CHANNEL): cv.nameable(color_channel_schema),
- cv.Optional(CONF_GREEN_CHANNEL): cv.nameable(color_channel_schema),
- cv.Optional(CONF_BLUE_CHANNEL): cv.nameable(color_channel_schema),
- cv.Optional(CONF_CLEAR_CHANNEL): cv.nameable(color_channel_schema),
- cv.Optional(CONF_ILLUMINANCE): cv.nameable(illuminance_schema),
- cv.Optional(CONF_COLOR_TEMPERATURE): cv.nameable(color_temperature_schema),
+ cv.GenerateID(): cv.declare_id(TCS34725Component),
+ cv.Optional(CONF_RED_CHANNEL): color_channel_schema,
+ cv.Optional(CONF_GREEN_CHANNEL): color_channel_schema,
+ cv.Optional(CONF_BLUE_CHANNEL): color_channel_schema,
+ cv.Optional(CONF_CLEAR_CHANNEL): color_channel_schema,
+ cv.Optional(CONF_ILLUMINANCE): illuminance_schema,
+ cv.Optional(CONF_COLOR_TEMPERATURE): color_temperature_schema,
cv.Optional(CONF_INTEGRATION_TIME, default='2.4ms'):
- cv.one_of(*TCS34725_INTEGRATION_TIMES, lower=True),
- cv.Optional(CONF_GAIN, default='1X'): cv.All(cv.Upper, cv.one_of(*TCS34725_GAINS), upper=True),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x29))
+ cv.enum(TCS34725_INTEGRATION_TIMES, lower=True),
+ cv.Optional(CONF_GAIN, default='1X'): cv.enum(TCS34725_GAINS, upper=True),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
- cg.add(var.set_integration_time(TCS34725_INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]]))
- cg.add(var.set_gain(TCS34725_GAINS[config[CONF_GAIN]]))
+ cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME]))
+ cg.add(var.set_gain(config[CONF_GAIN]))
if CONF_RED_CHANNEL in config:
sens = yield sensor.new_sensor(config[CONF_RED_CHANNEL])
diff --git a/esphome/components/tcs34725/tcs34725.h b/esphome/components/tcs34725/tcs34725.h
index 2347cbfcfb..b914db0eb0 100644
--- a/esphome/components/tcs34725/tcs34725.h
+++ b/esphome/components/tcs34725/tcs34725.h
@@ -25,8 +25,6 @@ enum TCS34725Gain {
class TCS34725Component : public PollingComponent, public i2c::I2CDevice {
public:
- TCS34725Component(uint32_t update_interval) : PollingComponent(update_interval) {}
-
void set_integration_time(TCS34725IntegrationTime integration_time);
void set_gain(TCS34725Gain gain);
diff --git a/esphome/components/template/binary_sensor/__init__.py b/esphome/components/template/binary_sensor/__init__.py
index 7fa530f50d..9c1fb549e6 100644
--- a/esphome/components/template/binary_sensor/__init__.py
+++ b/esphome/components/template/binary_sensor/__init__.py
@@ -1,21 +1,21 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.automation import ACTION_REGISTRY
+from esphome import automation
from esphome.components import binary_sensor
-from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE
+from esphome.const import CONF_ID, CONF_LAMBDA, CONF_STATE
from .. import template_ns
TemplateBinarySensor = template_ns.class_('TemplateBinarySensor', binary_sensor.BinarySensor,
cg.Component)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TemplateBinarySensor),
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TemplateBinarySensor),
cv.Optional(CONF_LAMBDA): cv.lambda_,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield binary_sensor.register_binary_sensor(var, config)
@@ -25,15 +25,15 @@ def to_code(config):
cg.add(var.set_template(template_))
-@ACTION_REGISTRY.register('binary_sensor.template.publish', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(binary_sensor.BinarySensor),
- cv.Required(CONF_STATE): cv.templatable(cv.boolean),
-}))
+@automation.register_action('binary_sensor.template.publish',
+ binary_sensor.BinarySensorPublishAction,
+ cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(binary_sensor.BinarySensor),
+ cv.Required(CONF_STATE): cv.templatable(cv.boolean),
+ }))
def binary_sensor_template_publish_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = binary_sensor.BinarySensorPublishAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_STATE], args, bool)
- cg.add(action.set_state(template_))
- yield action
+ cg.add(var.set_state(template_))
+ yield var
diff --git a/esphome/components/template/binary_sensor/template_binary_sensor.h b/esphome/components/template/binary_sensor/template_binary_sensor.h
index 35364f6be2..a28929b122 100644
--- a/esphome/components/template/binary_sensor/template_binary_sensor.h
+++ b/esphome/components/template/binary_sensor/template_binary_sensor.h
@@ -8,8 +8,6 @@ namespace template_ {
class TemplateBinarySensor : public Component, public binary_sensor::BinarySensor {
public:
- explicit TemplateBinarySensor(const std::string &name) : BinarySensor(name) {}
-
void set_template(std::function()> &&f) { this->f_ = f; }
void loop() override;
diff --git a/esphome/components/template/cover/__init__.py b/esphome/components/template/cover/__init__.py
index 2b47e937f0..0eccb9fc73 100644
--- a/esphome/components/template/cover/__init__.py
+++ b/esphome/components/template/cover/__init__.py
@@ -1,14 +1,12 @@
-from esphome import automation
-from esphome.automation import ACTION_REGISTRY
-from esphome.components import cover
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.components import cover
from esphome.const import CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_CURRENT_OPERATION, CONF_ID, \
- CONF_LAMBDA, CONF_NAME, CONF_OPEN_ACTION, CONF_OPTIMISTIC, CONF_POSITION, CONF_RESTORE_MODE, \
+ CONF_LAMBDA, CONF_OPEN_ACTION, CONF_OPTIMISTIC, CONF_POSITION, CONF_RESTORE_MODE, \
CONF_STATE, CONF_STOP_ACTION
from .. import template_ns
-
TemplateCover = template_ns.class_('TemplateCover', cover.Cover)
TemplateCoverRestoreMode = template_ns.enum('TemplateCoverRestoreMode')
@@ -18,20 +16,20 @@ RESTORE_MODES = {
'RESTORE_AND_CALL': TemplateCoverRestoreMode.COVER_RESTORE_AND_CALL,
}
-CONFIG_SCHEMA = cv.nameable(cover.COVER_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TemplateCover),
+CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TemplateCover),
cv.Optional(CONF_LAMBDA): cv.lambda_,
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean,
cv.Optional(CONF_OPEN_ACTION): automation.validate_automation(single=True),
cv.Optional(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
cv.Optional(CONF_STOP_ACTION): automation.validate_automation(single=True),
- cv.Optional(CONF_RESTORE_MODE, default='RESTORE'): cv.one_of(*RESTORE_MODES, upper=True),
-}).extend(cv.COMPONENT_SCHEMA))
+ cv.Optional(CONF_RESTORE_MODE, default='RESTORE'): cv.enum(RESTORE_MODES, upper=True),
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield cover.register_cover(var, config)
if CONF_LAMBDA in config:
@@ -47,29 +45,25 @@ def to_code(config):
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
- cg.add(var.set_restore_mode(RESTORE_MODES[config[CONF_RESTORE_MODE]]))
+ cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
-@ACTION_REGISTRY.register('cover.template.publish', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(cover.Cover),
+@automation.register_action('cover.template.publish', cover.CoverPublishAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(cover.Cover),
cv.Exclusive(CONF_STATE, 'pos'): cv.templatable(cover.validate_cover_state),
cv.Exclusive(CONF_POSITION, 'pos'): cv.templatable(cv.zero_to_one_float),
cv.Optional(CONF_CURRENT_OPERATION): cv.templatable(cover.validate_cover_operation),
}))
def cover_template_publish_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = cover.CoverPublishAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
if CONF_STATE in config:
- template_ = yield cg.templatable(config[CONF_STATE], args, float, to_exp=cover.COVER_STATES)
- cg.add(action.set_position(template_))
+ template_ = yield cg.templatable(config[CONF_STATE], args, float)
+ cg.add(var.set_position(template_))
if CONF_POSITION in config:
- template_ = yield cg.templatable(config[CONF_POSITION], args, float,
- to_exp=cover.COVER_STATES)
- cg.add(action.set_position(template_))
+ template_ = yield cg.templatable(config[CONF_POSITION], args, float)
+ cg.add(var.set_position(template_))
if CONF_CURRENT_OPERATION in config:
- template_ = yield cg.templatable(config[CONF_CURRENT_OPERATION], args,
- cover.CoverOperation, to_exp=cover.COVER_OPERATIONS)
- cg.add(action.set_current_operation(template_))
- yield action
+ template_ = yield cg.templatable(config[CONF_CURRENT_OPERATION], args, cover.CoverOperation)
+ cg.add(var.set_current_operation(template_))
+ yield var
diff --git a/esphome/components/template/cover/template_cover.cpp b/esphome/components/template/cover/template_cover.cpp
index 88e93c3e9d..dd1a081aaa 100644
--- a/esphome/components/template/cover/template_cover.cpp
+++ b/esphome/components/template/cover/template_cover.cpp
@@ -8,9 +8,8 @@ using namespace esphome::cover;
static const char *TAG = "template.cover";
-TemplateCover::TemplateCover(const std::string &name)
- : Cover(name),
- open_trigger_(new Trigger<>()),
+TemplateCover::TemplateCover()
+ : open_trigger_(new Trigger<>()),
close_trigger_(new Trigger<>),
stop_trigger_(new Trigger<>()),
position_trigger_(new Trigger()),
diff --git a/esphome/components/template/cover/template_cover.h b/esphome/components/template/cover/template_cover.h
index a96a7c16d4..3b9dcea50b 100644
--- a/esphome/components/template/cover/template_cover.h
+++ b/esphome/components/template/cover/template_cover.h
@@ -15,7 +15,7 @@ enum TemplateCoverRestoreMode {
class TemplateCover : public cover::Cover, public Component {
public:
- explicit TemplateCover(const std::string &name);
+ TemplateCover();
void set_state_lambda(std::function()> &&f);
Trigger<> *get_open_trigger() const;
diff --git a/esphome/components/template/sensor/__init__.py b/esphome/components/template/sensor/__init__.py
index 52d64e7fd9..1e9fe9cdee 100644
--- a/esphome/components/template/sensor/__init__.py
+++ b/esphome/components/template/sensor/__init__.py
@@ -1,45 +1,37 @@
-
-from esphome.automation import ACTION_REGISTRY
-from esphome.components import sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE, CONF_UPDATE_INTERVAL
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.components import sensor
+from esphome.const import CONF_ID, CONF_LAMBDA, CONF_STATE, UNIT_EMPTY, ICON_EMPTY
from .. import template_ns
TemplateSensor = template_ns.class_('TemplateSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TemplateSensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({
+ cv.GenerateID(): cv.declare_id(TemplateSensor),
cv.Optional(CONF_LAMBDA): cv.lambda_,
- cv.Optional(CONF_UPDATE_INTERVAL, default="60s"): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- rhs = TemplateSensor.new(config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
- template = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(template, config)
- yield sensor.register_sensor(template, config)
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield sensor.register_sensor(var, config)
if CONF_LAMBDA in config:
template_ = yield cg.process_lambda(config[CONF_LAMBDA], [],
return_type=cg.optional.template(float))
- cg.add(template.set_template(template_))
+ cg.add(var.set_template(template_))
-CONF_SENSOR_TEMPLATE_PUBLISH = 'sensor.template.publish'
-SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(sensor.Sensor),
- cv.Required(CONF_STATE): cv.templatable(cv.float_),
-})
-
-
-@ACTION_REGISTRY.register(CONF_SENSOR_TEMPLATE_PUBLISH, SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA)
+@automation.register_action('sensor.template.publish', sensor.SensorPublishAction,
+ cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(sensor.Sensor),
+ cv.Required(CONF_STATE): cv.templatable(cv.float_),
+ }))
def sensor_template_publish_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = sensor.SensorPublishAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_STATE], args, float)
- cg.add(action.set_state(template_))
- yield action
+ cg.add(var.set_state(template_))
+ yield var
diff --git a/esphome/components/template/sensor/template_sensor.cpp b/esphome/components/template/sensor/template_sensor.cpp
index e9f58527ad..e2d36f13a0 100644
--- a/esphome/components/template/sensor/template_sensor.cpp
+++ b/esphome/components/template/sensor/template_sensor.cpp
@@ -6,8 +6,6 @@ namespace template_ {
static const char *TAG = "template.sensor";
-TemplateSensor::TemplateSensor(const std::string &name, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval) {}
void TemplateSensor::update() {
if (!this->f_.has_value())
return;
diff --git a/esphome/components/template/sensor/template_sensor.h b/esphome/components/template/sensor/template_sensor.h
index da1b3a9abf..2630cb0b14 100644
--- a/esphome/components/template/sensor/template_sensor.h
+++ b/esphome/components/template/sensor/template_sensor.h
@@ -6,10 +6,8 @@
namespace esphome {
namespace template_ {
-class TemplateSensor : public sensor::PollingSensorComponent {
+class TemplateSensor : public sensor::Sensor, public PollingComponent {
public:
- TemplateSensor(const std::string &name, uint32_t update_interval);
-
void set_template(std::function()> &&f);
void update() override;
diff --git a/esphome/components/template/switch/__init__.py b/esphome/components/template/switch/__init__.py
index 407af98923..ac27770d47 100644
--- a/esphome/components/template/switch/__init__.py
+++ b/esphome/components/template/switch/__init__.py
@@ -1,27 +1,26 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
-from esphome.automation import ACTION_REGISTRY
from esphome.components import switch
-from esphome.const import CONF_ASSUMED_STATE, CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OPTIMISTIC, \
+from esphome.const import CONF_ASSUMED_STATE, CONF_ID, CONF_LAMBDA, CONF_OPTIMISTIC, \
CONF_RESTORE_STATE, CONF_STATE, CONF_TURN_OFF_ACTION, CONF_TURN_ON_ACTION
from .. import template_ns
TemplateSwitch = template_ns.class_('TemplateSwitch', switch.Switch, cg.Component)
-CONFIG_SCHEMA = cv.nameable(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TemplateSwitch),
+CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TemplateSwitch),
cv.Optional(CONF_LAMBDA): cv.lambda_,
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean,
cv.Optional(CONF_TURN_OFF_ACTION): automation.validate_automation(single=True),
cv.Optional(CONF_TURN_ON_ACTION): automation.validate_automation(single=True),
cv.Optional(CONF_RESTORE_STATE, default=False): cv.boolean,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield switch.register_switch(var, config)
@@ -40,15 +39,13 @@ def to_code(config):
cg.add(var.set_restore_state(config[CONF_RESTORE_STATE]))
-@ACTION_REGISTRY.register('switch.template.publish', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(switch.Switch),
+@automation.register_action('switch.template.publish', switch.SwitchPublishAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(switch.Switch),
cv.Required(CONF_STATE): cv.templatable(cv.boolean),
}))
def switch_template_publish_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = switch.SwitchPublishAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_STATE], args, bool)
- cg.add(action.set_state(template_))
- yield action
+ cg.add(var.set_state(template_))
+ yield var
diff --git a/esphome/components/template/switch/template_switch.cpp b/esphome/components/template/switch/template_switch.cpp
index 2c86e156a6..5868b30996 100644
--- a/esphome/components/template/switch/template_switch.cpp
+++ b/esphome/components/template/switch/template_switch.cpp
@@ -6,8 +6,8 @@ namespace template_ {
static const char *TAG = "template.switch";
-TemplateSwitch::TemplateSwitch(const std::string &name)
- : switch_::Switch(name), Component(), turn_on_trigger_(new Trigger<>()), turn_off_trigger_(new Trigger<>()) {}
+TemplateSwitch::TemplateSwitch() : turn_on_trigger_(new Trigger<>()), turn_off_trigger_(new Trigger<>()) {}
+
void TemplateSwitch::loop() {
if (!this->f_.has_value())
return;
diff --git a/esphome/components/template/switch/template_switch.h b/esphome/components/template/switch/template_switch.h
index 558a28c4e0..ef9b567451 100644
--- a/esphome/components/template/switch/template_switch.h
+++ b/esphome/components/template/switch/template_switch.h
@@ -9,7 +9,7 @@ namespace template_ {
class TemplateSwitch : public switch_::Switch, public Component {
public:
- explicit TemplateSwitch(const std::string &name);
+ TemplateSwitch();
void setup() override;
void dump_config() override;
diff --git a/esphome/components/template/text_sensor/__init__.py b/esphome/components/template/text_sensor/__init__.py
index 684c1b5bb9..23b71a3974 100644
--- a/esphome/components/template/text_sensor/__init__.py
+++ b/esphome/components/template/text_sensor/__init__.py
@@ -1,24 +1,22 @@
-from esphome.automation import ACTION_REGISTRY
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
from esphome.components import text_sensor
from esphome.components.text_sensor import TextSensorPublishAction
-import esphome.config_validation as cv
-import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE, CONF_UPDATE_INTERVAL
+from esphome.const import CONF_ID, CONF_LAMBDA, CONF_STATE
from .. import template_ns
-
TemplateTextSensor = template_ns.class_('TemplateTextSensor', text_sensor.TextSensor,
cg.PollingComponent)
-CONFIG_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TemplateTextSensor),
+CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TemplateTextSensor),
cv.Optional(CONF_LAMBDA): cv.lambda_,
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield text_sensor.register_text_sensor(var, config)
@@ -28,15 +26,13 @@ def to_code(config):
cg.add(var.set_template(template_))
-@ACTION_REGISTRY.register('text_sensor.template.publish', cv.Schema({
- cv.Required(CONF_ID): cv.use_variable_id(text_sensor.TextSensor),
+@automation.register_action('text_sensor.template.publish', TextSensorPublishAction, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(text_sensor.TextSensor),
cv.Required(CONF_STATE): cv.templatable(cv.string_strict),
}))
def text_sensor_template_publish_to_code(config, action_id, template_arg, args):
- var = yield cg.get_variable(config[CONF_ID])
- type = TextSensorPublishAction.template(template_arg)
- rhs = type.new(var)
- action = cg.Pvariable(action_id, rhs, type=type)
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = yield cg.templatable(config[CONF_STATE], args, cg.std_string)
- cg.add(action.set_state(template_))
- yield action
+ cg.add(var.set_state(template_))
+ yield var
diff --git a/esphome/components/template/text_sensor/template_text_sensor.cpp b/esphome/components/template/text_sensor/template_text_sensor.cpp
index 029de6c253..e06c70d95e 100644
--- a/esphome/components/template/text_sensor/template_text_sensor.cpp
+++ b/esphome/components/template/text_sensor/template_text_sensor.cpp
@@ -6,8 +6,6 @@ namespace template_ {
static const char *TAG = "template.text_sensor";
-TemplateTextSensor::TemplateTextSensor(const std::string &name, uint32_t update_interval)
- : TextSensor(name), PollingComponent(update_interval) {}
void TemplateTextSensor::update() {
if (!this->f_.has_value())
return;
diff --git a/esphome/components/template/text_sensor/template_text_sensor.h b/esphome/components/template/text_sensor/template_text_sensor.h
index 12bf643f51..07a2bd96fc 100644
--- a/esphome/components/template/text_sensor/template_text_sensor.h
+++ b/esphome/components/template/text_sensor/template_text_sensor.h
@@ -9,8 +9,6 @@ namespace template_ {
class TemplateTextSensor : public text_sensor::TextSensor, public PollingComponent {
public:
- TemplateTextSensor(const std::string &name, uint32_t update_interval);
-
void set_template(std::function()> &&f);
void update() override;
diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py
index eeba18fbea..f138f38d2f 100644
--- a/esphome/components/text_sensor/__init__.py
+++ b/esphome/components/text_sensor/__init__.py
@@ -3,8 +3,8 @@ import esphome.config_validation as cv
from esphome import automation
from esphome.components import mqtt
from esphome.const import CONF_ICON, CONF_ID, CONF_INTERNAL, CONF_ON_VALUE, \
- CONF_TRIGGER_ID, CONF_MQTT_ID
-from esphome.core import CORE, coroutine
+ CONF_TRIGGER_ID, CONF_MQTT_ID, CONF_NAME, CONF_STATE
+from esphome.core import CORE, coroutine, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -14,22 +14,24 @@ TextSensor = text_sensor_ns.class_('TextSensor', cg.Nameable)
TextSensorPtr = TextSensor.operator('ptr')
TextSensorStateTrigger = text_sensor_ns.class_('TextSensorStateTrigger',
- cg.Trigger.template(cg.std_string))
-TextSensorPublishAction = text_sensor_ns.class_('TextSensorPublishAction', cg.Action)
+ automation.Trigger.template(cg.std_string))
+TextSensorPublishAction = text_sensor_ns.class_('TextSensorPublishAction', automation.Action)
+TextSensorStateCondition = text_sensor_ns.class_('TextSensorStateCondition', automation.Condition)
icon = cv.icon
TEXT_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
- cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_variable_id(mqtt.MQTTTextSensor),
+ cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTTextSensor),
cv.Optional(CONF_ICON): icon,
cv.Optional(CONF_ON_VALUE): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(TextSensorStateTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TextSensorStateTrigger),
}),
})
@coroutine
def setup_text_sensor_core_(var, config):
+ cg.add(var.set_name(config[CONF_NAME]))
if CONF_INTERNAL in config:
cg.add(var.set_internal(config[CONF_INTERNAL]))
if CONF_ICON in config:
@@ -52,6 +54,19 @@ def register_text_sensor(var, config):
yield setup_text_sensor_core_(var, config)
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_TEXT_SENSOR')
cg.add_global(text_sensor_ns.using)
+
+
+@automation.register_condition('text_sensor.state', TextSensorStateCondition, cv.Schema({
+ cv.Required(CONF_ID): cv.use_id(TextSensor),
+ cv.Required(CONF_STATE): cv.templatable(cv.string_strict),
+}))
+def text_sensor_state_to_code(config, condition_id, template_arg, args):
+ paren = yield cg.get_variable(config[CONF_ID])
+ var = cg.new_Pvariable(condition_id, template_arg, paren)
+ templ = yield cg.templatable(config[CONF_STATE], args, cg.std_string)
+ cg.add(var.set_state(templ))
+ yield var
diff --git a/esphome/components/text_sensor/automation.cpp b/esphome/components/text_sensor/automation.cpp
deleted file mode 100644
index eddcf1f8d5..0000000000
--- a/esphome/components/text_sensor/automation.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "automation.h"
-#include "esphome/core/log.h"
-
-namespace esphome {
-namespace text_sensor {
-
-static const char *TAG = "text_sensor.automation";
-
-} // namespace text_sensor
-} // namespace esphome
diff --git a/esphome/components/text_sensor/automation.h b/esphome/components/text_sensor/automation.h
index 7e9eed949f..496efb1cc3 100644
--- a/esphome/components/text_sensor/automation.h
+++ b/esphome/components/text_sensor/automation.h
@@ -14,14 +14,23 @@ class TextSensorStateTrigger : public Trigger {
}
};
+template class TextSensorStateCondition : public Condition {
+ public:
+ explicit TextSensorStateCondition(TextSensor *parent) : parent_(parent) {}
+
+ TEMPLATABLE_VALUE(std::string, state)
+
+ bool check(Ts... x) override { return this->parent_->state == this->state_.value(x...); }
+
+ protected:
+ TextSensor *parent_;
+};
+
template class TextSensorPublishAction : public Action {
public:
TextSensorPublishAction(TextSensor *sensor) : sensor_(sensor) {}
TEMPLATABLE_VALUE(std::string, state)
- void play(Ts... x) override {
- this->sensor_->publish_state(this->state_.value(x...));
- this->play_next(x...);
- }
+ void play(Ts... x) override { this->sensor_->publish_state(this->state_.value(x...)); }
protected:
TextSensor *sensor_;
diff --git a/esphome/components/text_sensor/text_sensor.h b/esphome/components/text_sensor/text_sensor.h
index 901cc26785..719f0b0d62 100644
--- a/esphome/components/text_sensor/text_sensor.h
+++ b/esphome/components/text_sensor/text_sensor.h
@@ -19,8 +19,8 @@ namespace text_sensor {
class TextSensor : public Nameable {
public:
- explicit TextSensor(const std::string &name);
explicit TextSensor();
+ explicit TextSensor(const std::string &name);
void publish_state(std::string state);
diff --git a/esphome/components/time/__init__.py b/esphome/components/time/__init__.py
index 87640fbc15..82dc750486 100644
--- a/esphome/components/time/__init__.py
+++ b/esphome/components/time/__init__.py
@@ -12,7 +12,7 @@ from esphome import automation
from esphome.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \
CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID, \
CONF_AT, CONF_SECOND, CONF_HOUR, CONF_MINUTE
-from esphome.core import coroutine
+from esphome.core import coroutine, coroutine_with_priority
from esphome.py_compat import string_types
_LOGGER = logging.getLogger(__name__)
@@ -21,7 +21,7 @@ IS_PLATFORM_COMPONENT = True
time_ns = cg.esphome_ns.namespace('time')
RealTimeClock = time_ns.class_('RealTimeClock', cg.Component)
-CronTrigger = time_ns.class_('CronTrigger', cg.Trigger.template(), cg.Component)
+CronTrigger = time_ns.class_('CronTrigger', automation.Trigger.template(), cg.Component)
ESPTime = time_ns.struct('ESPTime')
@@ -252,7 +252,7 @@ def validate_tz(value):
TIME_SCHEMA = cv.Schema({
cv.Optional(CONF_TIMEZONE, default=detect_tz): validate_tz,
cv.Optional(CONF_ON_TIME): automation.validate_automation({
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(CronTrigger),
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CronTrigger),
cv.Optional(CONF_SECONDS): validate_cron_seconds,
cv.Optional(CONF_MINUTES): validate_cron_minutes,
cv.Optional(CONF_HOURS): validate_cron_hours,
@@ -293,6 +293,7 @@ def register_time(time_var, config):
yield setup_time_core_(time_var, config)
+@coroutine_with_priority(100.0)
def to_code(config):
cg.add_define('USE_TIME')
cg.add_global(time_ns.using)
diff --git a/esphome/components/time_based/cover.py b/esphome/components/time_based/cover.py
index 2e72e9be3e..85f606e6cc 100644
--- a/esphome/components/time_based/cover.py
+++ b/esphome/components/time_based/cover.py
@@ -1,16 +1,15 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import automation
from esphome.components import cover
-import esphome.config_validation as cv
-import esphome.codegen as cg
-from esphome.const import CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, CONF_ID, CONF_NAME, \
- CONF_OPEN_ACTION, CONF_OPEN_DURATION, CONF_STOP_ACTION
-
+from esphome.const import CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, CONF_ID, CONF_OPEN_ACTION, \
+ CONF_OPEN_DURATION, CONF_STOP_ACTION
time_based_ns = cg.esphome_ns.namespace('time_based')
TimeBasedCover = time_based_ns.class_('TimeBasedCover', cover.Cover, cg.Component)
-CONFIG_SCHEMA = cv.nameable(cover.COVER_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TimeBasedCover),
+CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TimeBasedCover),
cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True),
cv.Required(CONF_OPEN_ACTION): automation.validate_automation(single=True),
@@ -18,11 +17,11 @@ CONFIG_SCHEMA = cv.nameable(cover.COVER_SCHEMA.extend({
cv.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds,
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield cover.register_cover(var, config)
diff --git a/esphome/components/time_based/time_based_cover.cpp b/esphome/components/time_based/time_based_cover.cpp
index 2aafaf09f4..bbc887debc 100644
--- a/esphome/components/time_based/time_based_cover.cpp
+++ b/esphome/components/time_based/time_based_cover.cpp
@@ -45,7 +45,7 @@ float TimeBasedCover::get_setup_priority() const { return setup_priority::DATA;
CoverTraits TimeBasedCover::get_traits() {
auto traits = CoverTraits();
traits.set_supports_position(true);
- traits.set_is_assumed_state(false);
+ traits.set_is_assumed_state(true);
return traits;
}
void TimeBasedCover::control(const CoverCall &call) {
diff --git a/esphome/components/time_based/time_based_cover.h b/esphome/components/time_based/time_based_cover.h
index d7fb0a011c..60819d797b 100644
--- a/esphome/components/time_based/time_based_cover.h
+++ b/esphome/components/time_based/time_based_cover.h
@@ -9,7 +9,6 @@ namespace time_based {
class TimeBasedCover : public cover::Cover, public Component {
public:
- TimeBasedCover(const std::string &name) : cover::Cover(name) {}
void setup() override;
void loop() override;
void dump_config() override;
diff --git a/esphome/components/total_daily_energy/sensor.py b/esphome/components/total_daily_energy/sensor.py
index 0e5291a9a7..7fde9f5582 100644
--- a/esphome/components/total_daily_energy/sensor.py
+++ b/esphome/components/total_daily_energy/sensor.py
@@ -1,7 +1,7 @@
-from esphome.components import sensor, time
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_NAME, CONF_TIME_ID
+import esphome.config_validation as cv
+from esphome.components import sensor, time
+from esphome.const import CONF_ID, CONF_TIME_ID
DEPENDENCIES = ['time']
@@ -9,17 +9,20 @@ CONF_POWER_ID = 'power_id'
total_daily_energy_ns = cg.esphome_ns.namespace('total_daily_energy')
TotalDailyEnergy = total_daily_energy_ns.class_('TotalDailyEnergy', sensor.Sensor, cg.Component)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TotalDailyEnergy),
- cv.GenerateID(CONF_TIME_ID): cv.use_variable_id(time.RealTimeClock),
- cv.Required(CONF_POWER_ID): cv.use_variable_id(sensor.Sensor),
-}).extend(cv.COMPONENT_SCHEMA))
+CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TotalDailyEnergy),
+ cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
+ cv.Required(CONF_POWER_ID): cv.use_id(sensor.Sensor),
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- time_ = yield cg.get_variable(config[CONF_TIME_ID])
- sens = yield cg.get_variable(config[CONF_POWER_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], time_, sens)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
+
+ sens = yield cg.get_variable(config[CONF_POWER_ID])
+ cg.add(var.set_parent(sens))
+ time_ = yield cg.get_variable(config[CONF_TIME_ID])
+ cg.add(var.set_time(time_))
diff --git a/esphome/components/total_daily_energy/total_daily_energy.h b/esphome/components/total_daily_energy/total_daily_energy.h
index 1e54c79725..ae44125ffb 100644
--- a/esphome/components/total_daily_energy/total_daily_energy.h
+++ b/esphome/components/total_daily_energy/total_daily_energy.h
@@ -10,8 +10,8 @@ namespace total_daily_energy {
class TotalDailyEnergy : public sensor::Sensor, public Component {
public:
- TotalDailyEnergy(const std::string &name, time::RealTimeClock *time, Sensor *parent)
- : Sensor(name), time_(time), parent_(parent) {}
+ void set_time(time::RealTimeClock *time) { time_ = time; }
+ void set_parent(Sensor *parent) { parent_ = parent; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
diff --git a/esphome/components/tsl2561/sensor.py b/esphome/components/tsl2561/sensor.py
index 6708b99f3c..5171884a14 100644
--- a/esphome/components/tsl2561/sensor.py
+++ b/esphome/components/tsl2561/sensor.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
-from esphome.const import CONF_GAIN, CONF_ID, CONF_INTEGRATION_TIME, CONF_UPDATE_INTERVAL, CONF_NAME
+from esphome.const import CONF_GAIN, CONF_ID, CONF_INTEGRATION_TIME, UNIT_LUX, ICON_BRIGHTNESS_5
DEPENDENCIES = ['i2c']
@@ -24,26 +24,25 @@ CONF_IS_CS_PACKAGE = 'is_cs_package'
def validate_integration_time(value):
value = cv.positive_time_period_milliseconds(value).total_milliseconds
- return cv.one_of(*INTEGRATION_TIMES, int=True)(value)
+ return cv.enum(INTEGRATION_TIMES, int=True)(value)
TSL2561Sensor = tsl2561_ns.class_('TSL2561Sensor', sensor.PollingSensorComponent, i2c.I2CDevice)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TSL2561Sensor),
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1).extend({
+ cv.GenerateID(): cv.declare_id(TSL2561Sensor),
cv.Optional(CONF_INTEGRATION_TIME, default=402): validate_integration_time,
- cv.Optional(CONF_GAIN, default='1X'): cv.one_of(*GAINS, upper=True),
+ cv.Optional(CONF_GAIN, default='1X'): cv.enum(GAINS, upper=True),
cv.Optional(CONF_IS_CS_PACKAGE, default=False): cv.boolean,
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x39)))
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x39))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
yield sensor.register_sensor(var, config)
- cg.add(var.set_integration_time(INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]]))
- cg.add(var.set_gain(GAINS[config[CONF_GAIN]]))
+ cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME]))
+ cg.add(var.set_gain(config[CONF_GAIN]))
cg.add(var.set_is_cs_package(config[CONF_IS_CS_PACKAGE]))
diff --git a/esphome/components/tsl2561/tsl2561.cpp b/esphome/components/tsl2561/tsl2561.cpp
index 54047cff5a..ffd39a54b0 100644
--- a/esphome/components/tsl2561/tsl2561.cpp
+++ b/esphome/components/tsl2561/tsl2561.cpp
@@ -159,8 +159,6 @@ bool TSL2561Sensor::tsl2561_read_uint(uint8_t a_register, uint16_t *value) {
bool TSL2561Sensor::tsl2561_read_byte(uint8_t a_register, uint8_t *value) {
return this->read_byte(a_register | TSL2561_COMMAND_BIT, value);
}
-TSL2561Sensor::TSL2561Sensor(const std::string &name, uint32_t update_interval)
- : PollingSensorComponent(name, update_interval) {}
} // namespace tsl2561
} // namespace esphome
diff --git a/esphome/components/tsl2561/tsl2561.h b/esphome/components/tsl2561/tsl2561.h
index 8b4f052172..c54f41fb81 100644
--- a/esphome/components/tsl2561/tsl2561.h
+++ b/esphome/components/tsl2561/tsl2561.h
@@ -27,10 +27,8 @@ enum TSL2561Gain {
};
/// This class includes support for the TSL2561 i2c ambient light sensor.
-class TSL2561Sensor : public sensor::PollingSensorComponent, public i2c::I2CDevice {
+class TSL2561Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
public:
- TSL2561Sensor(const std::string &name, uint32_t update_interval);
-
/** Set the time that sensor values should be accumulated for.
*
* Longer means more accurate, but also mean more power consumption.
diff --git a/esphome/components/ttp229_lsf/__init__.py b/esphome/components/ttp229_lsf/__init__.py
index 849df358f7..8b26102c65 100644
--- a/esphome/components/ttp229_lsf/__init__.py
+++ b/esphome/components/ttp229_lsf/__init__.py
@@ -7,12 +7,12 @@ DEPENDENCIES = ['i2c']
AUTO_LOAD = ['binary_sensor']
CONF_TTP229_ID = 'ttp229_id'
-ttp229_ns = cg.esphome_ns.namespace('ttp229')
+ttp229_lsf_ns = cg.esphome_ns.namespace('ttp229_lsf')
-TTP229LSFComponent = ttp229_ns.class_('TTP229LSFComponent', cg.Component)
+TTP229LSFComponent = ttp229_lsf_ns.class_('TTP229LSFComponent', cg.Component, i2c.I2CDevice)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(TTP229LSFComponent),
+ cv.GenerateID(): cv.declare_id(TTP229LSFComponent),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x57))
diff --git a/esphome/components/ttp229_lsf/binary_sensor.py b/esphome/components/ttp229_lsf/binary_sensor.py
index 793d2beda1..da2f8d2717 100644
--- a/esphome/components/ttp229_lsf/binary_sensor.py
+++ b/esphome/components/ttp229_lsf/binary_sensor.py
@@ -1,21 +1,23 @@
-from esphome.components import binary_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_CHANNEL, CONF_NAME, CONF_ID
-from . import ttp229_ns, TTP229LSFComponent, CONF_TTP229_ID
+import esphome.config_validation as cv
+from esphome.components import binary_sensor
+from esphome.const import CONF_CHANNEL, CONF_ID
+from . import ttp229_lsf_ns, TTP229LSFComponent, CONF_TTP229_ID
DEPENDENCIES = ['ttp229_lsf']
-TTP229Channel = ttp229_ns.class_('TTP229Channel', binary_sensor.BinarySensor)
+TTP229Channel = ttp229_lsf_ns.class_('TTP229Channel', binary_sensor.BinarySensor)
-CONFIG_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(TTP229Channel),
- cv.GenerateID(CONF_TTP229_ID): cv.use_variable_id(TTP229LSFComponent),
- cv.Required(CONF_CHANNEL): cv.All(cv.Coerce(int), cv.Range(min=0, max=15))
-}))
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TTP229Channel),
+ cv.GenerateID(CONF_TTP229_ID): cv.use_id(TTP229LSFComponent),
+ cv.Required(CONF_CHANNEL): cv.All(cv.int_, cv.Range(min=0, max=15))
+})
def to_code(config):
- hub = yield cg.get_variable(config[CONF_TTP229_ID])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_CHANNEL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
+
+ cg.add(var.set_channel(config[CONF_CHANNEL]))
+ hub = yield cg.get_variable(config[CONF_TTP229_ID])
cg.add(hub.register_channel(var))
diff --git a/esphome/components/ttp229_lsf/ttp229.cpp b/esphome/components/ttp229_lsf/ttp229_lsf.cpp
similarity index 88%
rename from esphome/components/ttp229_lsf/ttp229.cpp
rename to esphome/components/ttp229_lsf/ttp229_lsf.cpp
index 2051cec862..2bd5f8556d 100644
--- a/esphome/components/ttp229_lsf/ttp229.cpp
+++ b/esphome/components/ttp229_lsf/ttp229_lsf.cpp
@@ -1,10 +1,10 @@
-#include "ttp229.h"
+#include "ttp229_lsf.h"
#include "esphome/core/log.h"
namespace esphome {
-namespace ttp229 {
+namespace ttp229_lsf {
-static const char *TAG = "ttp229";
+static const char *TAG = "ttp229_lsf";
void TTP229LSFComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up ttp229...");
@@ -39,5 +39,5 @@ void TTP229LSFComponent::loop() {
}
}
-} // namespace ttp229
+} // namespace ttp229_lsf
} // namespace esphome
diff --git a/esphome/components/ttp229_lsf/ttp229.h b/esphome/components/ttp229_lsf/ttp229_lsf.h
similarity index 84%
rename from esphome/components/ttp229_lsf/ttp229.h
rename to esphome/components/ttp229_lsf/ttp229_lsf.h
index c212c54570..2064d9b654 100644
--- a/esphome/components/ttp229_lsf/ttp229.h
+++ b/esphome/components/ttp229_lsf/ttp229_lsf.h
@@ -5,15 +5,15 @@
#include "esphome/components/i2c/i2c.h"
namespace esphome {
-namespace ttp229 {
+namespace ttp229_lsf {
class TTP229Channel : public binary_sensor::BinarySensor {
public:
- TTP229Channel(const std::string &name, int channel) : BinarySensor(name), channel_(channel) {}
+ void set_channel(uint8_t channel) { channel_ = channel; }
void process(uint16_t data) { this->publish_state(data & (1 << this->channel_)); }
protected:
- int channel_;
+ uint8_t channel_;
};
class TTP229LSFComponent : public Component, public i2c::I2CDevice {
@@ -32,5 +32,5 @@ class TTP229LSFComponent : public Component, public i2c::I2CDevice {
} error_code_{NONE};
};
-} // namespace ttp229
+} // namespace ttp229_lsf
} // namespace esphome
diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py
index 9bffc91701..ef959b69ef 100644
--- a/esphome/components/uart/__init__.py
+++ b/esphome/components/uart/__init__.py
@@ -1,6 +1,6 @@
-from esphome import pins
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import pins
from esphome.const import CONF_BAUD_RATE, CONF_ID, CONF_RX_PIN, CONF_TX_PIN, CONF_UART_ID
from esphome.core import CORE, coroutine
@@ -18,29 +18,36 @@ def validate_rx_pin(value):
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(UARTComponent),
+ cv.GenerateID(): cv.declare_id(UARTComponent),
+ cv.Required(CONF_BAUD_RATE): cv.All(cv.int_, cv.Range(min=1, max=115200)),
cv.Optional(CONF_TX_PIN): pins.output_pin,
cv.Optional(CONF_RX_PIN): validate_rx_pin,
- cv.Required(CONF_BAUD_RATE): cv.positive_int,
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_BAUD_RATE])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
+ cg.add(var.set_baud_rate(config[CONF_BAUD_RATE]))
+
if CONF_TX_PIN in config:
cg.add(var.set_tx_pin(config[CONF_TX_PIN]))
if CONF_RX_PIN in config:
cg.add(var.set_rx_pin(config[CONF_RX_PIN]))
+# A schema to use for all UART devices, all UART integrations must extend this!
UART_DEVICE_SCHEMA = cv.Schema({
- cv.GenerateID(CONF_UART_ID): cv.use_variable_id(UARTComponent),
+ cv.GenerateID(CONF_UART_ID): cv.use_id(UARTComponent),
})
@coroutine
def register_uart_device(var, config):
+ """Register a UART device, setting up all the internal values.
+
+ This is a coroutine, you need to await it with a 'yield' expression!
+ """
parent = yield cg.get_variable(config[CONF_UART_ID])
cg.add(var.set_uart_parent(parent))
diff --git a/esphome/components/uart/switch/__init__.py b/esphome/components/uart/switch/__init__.py
index 3fc14229a9..35e7877cc3 100644
--- a/esphome/components/uart/switch/__init__.py
+++ b/esphome/components/uart/switch/__init__.py
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import switch, uart
-from esphome.const import CONF_DATA, CONF_ID, CONF_INVERTED, CONF_NAME
+from esphome.const import CONF_DATA, CONF_ID, CONF_INVERTED
from esphome.core import HexInt
from esphome.py_compat import text_type, binary_type, char_to_byte
from .. import uart_ns
@@ -21,18 +21,20 @@ def validate_data(value):
raise cv.Invalid("data must either be a string wrapped in quotes or a list of bytes")
-CONFIG_SCHEMA = cv.nameable(switch.SWITCH_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(UARTSwitch),
+CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(UARTSwitch),
cv.Required(CONF_DATA): validate_data,
cv.Optional(CONF_INVERTED): cv.invalid("UART switches do not support inverted mode!"),
-}).extend(uart.UART_DEVICE_SCHEMA))
+}).extend(uart.UART_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- data = config[CONF_DATA]
- if isinstance(data, binary_type):
- data = [HexInt(char_to_byte(x)) for x in data]
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], data)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield switch.register_switch(var, config)
yield uart.register_uart_device(var, config)
+
+ data = config[CONF_DATA]
+ if isinstance(data, binary_type):
+ data = [HexInt(char_to_byte(x)) for x in data]
+ cg.add(var.set_data(data))
diff --git a/esphome/components/uart/switch/uart_switch.cpp b/esphome/components/uart/switch/uart_switch.cpp
index 73640f96d3..9974ee1179 100644
--- a/esphome/components/uart/switch/uart_switch.cpp
+++ b/esphome/components/uart/switch/uart_switch.cpp
@@ -6,9 +6,6 @@ namespace uart {
static const char *TAG = "uart.switch";
-UARTSwitch::UARTSwitch(const std::string &name, const std::vector &data)
- : switch_::Switch(name), data_(data) {}
-
void UARTSwitch::write_state(bool state) {
if (!state) {
this->publish_state(false);
diff --git a/esphome/components/uart/switch/uart_switch.h b/esphome/components/uart/switch/uart_switch.h
index e628b4920c..c8a1b0d8c5 100644
--- a/esphome/components/uart/switch/uart_switch.h
+++ b/esphome/components/uart/switch/uart_switch.h
@@ -9,7 +9,7 @@ namespace uart {
class UARTSwitch : public switch_::Switch, public UARTDevice, public Component {
public:
- UARTSwitch(const std::string &name, const std::vector &data);
+ void set_data(const std::vector &data) { data_ = data; }
void dump_config() override;
diff --git a/esphome/components/uart/uart.h b/esphome/components/uart/uart.h
index 9bfecc3431..005536de4a 100644
--- a/esphome/components/uart/uart.h
+++ b/esphome/components/uart/uart.h
@@ -40,7 +40,7 @@ class ESP8266SoftwareSerial {
class UARTComponent : public Component, public Stream {
public:
- UARTComponent(uint32_t baud_rate) : baud_rate_(baud_rate) {}
+ void set_baud_rate(uint32_t baud_rate) { baud_rate_ = baud_rate; }
void setup() override;
diff --git a/esphome/components/uln2003/stepper.py b/esphome/components/uln2003/stepper.py
index 82a57941d3..278fcf67eb 100644
--- a/esphome/components/uln2003/stepper.py
+++ b/esphome/components/uln2003/stepper.py
@@ -1,11 +1,10 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
from esphome import pins
from esphome.components import stepper
-import esphome.config_validation as cv
-import esphome.codegen as cg
from esphome.const import CONF_ID, CONF_PIN_A, CONF_PIN_B, CONF_PIN_C, CONF_PIN_D, \
CONF_SLEEP_WHEN_DONE, CONF_STEP_MODE
-
uln2003_ns = cg.esphome_ns.namespace('uln2003')
ULN2003StepMode = uln2003_ns.enum('ULN2003StepMode')
@@ -18,24 +17,29 @@ STEP_MODES = {
ULN2003 = uln2003_ns.class_('ULN2003', stepper.Stepper, cg.Component)
CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend({
- cv.Required(CONF_ID): cv.declare_variable_id(ULN2003),
+ cv.Required(CONF_ID): cv.declare_id(ULN2003),
cv.Required(CONF_PIN_A): pins.gpio_output_pin_schema,
cv.Required(CONF_PIN_B): pins.gpio_output_pin_schema,
cv.Required(CONF_PIN_C): pins.gpio_output_pin_schema,
cv.Required(CONF_PIN_D): pins.gpio_output_pin_schema,
cv.Optional(CONF_SLEEP_WHEN_DONE, default=False): cv.boolean,
- cv.Optional(CONF_STEP_MODE, default='FULL_STEP'): cv.one_of(*STEP_MODES, upper=True, space='_')
+ cv.Optional(CONF_STEP_MODE, default='FULL_STEP'): cv.enum(STEP_MODES, upper=True, space='_')
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- pin_a = yield cg.gpio_pin_expression(config[CONF_PIN_A])
- pin_b = yield cg.gpio_pin_expression(config[CONF_PIN_B])
- pin_c = yield cg.gpio_pin_expression(config[CONF_PIN_C])
- pin_d = yield cg.gpio_pin_expression(config[CONF_PIN_D])
- var = cg.new_Pvariable(config[CONF_ID], pin_a, pin_b, pin_c, pin_d)
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield stepper.register_stepper(var, config)
+ pin_a = yield cg.gpio_pin_expression(config[CONF_PIN_A])
+ cg.add(var.set_pin_a(pin_a))
+ pin_b = yield cg.gpio_pin_expression(config[CONF_PIN_B])
+ cg.add(var.set_pin_b(pin_b))
+ pin_c = yield cg.gpio_pin_expression(config[CONF_PIN_C])
+ cg.add(var.set_pin_c(pin_c))
+ pin_d = yield cg.gpio_pin_expression(config[CONF_PIN_D])
+ cg.add(var.set_pin_d(pin_d))
+
cg.add(var.set_sleep_when_done(config[CONF_SLEEP_WHEN_DONE]))
- cg.add(var.set_step_mode(STEP_MODES[config[CONF_STEP_MODE]]))
+ cg.add(var.set_step_mode(config[CONF_STEP_MODE]))
diff --git a/esphome/components/uln2003/uln2003.h b/esphome/components/uln2003/uln2003.h
index cdd8dd5d8b..4bcf1e88e3 100644
--- a/esphome/components/uln2003/uln2003.h
+++ b/esphome/components/uln2003/uln2003.h
@@ -15,8 +15,10 @@ enum ULN2003StepMode {
class ULN2003 : public stepper::Stepper, public Component {
public:
- ULN2003(GPIOPin *pin_a, GPIOPin *pin_b, GPIOPin *pin_c, GPIOPin *pin_d)
- : pin_a_(pin_a), pin_b_(pin_b), pin_c_(pin_c), pin_d_(pin_d) {}
+ void set_pin_a(GPIOPin *pin_a) { pin_a_ = pin_a; }
+ void set_pin_b(GPIOPin *pin_b) { pin_b_ = pin_b; }
+ void set_pin_c(GPIOPin *pin_c) { pin_c_ = pin_c; }
+ void set_pin_d(GPIOPin *pin_d) { pin_d_ = pin_d; }
void setup() override;
void loop() override;
diff --git a/esphome/components/ultrasonic/sensor.py b/esphome/components/ultrasonic/sensor.py
index b02b9f3f82..fa3934853c 100644
--- a/esphome/components/ultrasonic/sensor.py
+++ b/esphome/components/ultrasonic/sensor.py
@@ -2,8 +2,8 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
-from esphome.const import CONF_ECHO_PIN, CONF_ID, CONF_NAME, CONF_TRIGGER_PIN, \
- CONF_UPDATE_INTERVAL, CONF_TIMEOUT, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL
+from esphome.const import CONF_ECHO_PIN, CONF_ID, CONF_TRIGGER_PIN, \
+ CONF_TIMEOUT, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL
CONF_PULSE_TIME = 'pulse_time'
@@ -11,30 +11,30 @@ ultrasonic_ns = cg.esphome_ns.namespace('ultrasonic')
UltrasonicSensorComponent = ultrasonic_ns.class_('UltrasonicSensorComponent',
sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(
- sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({
- cv.GenerateID(): cv.declare_variable_id(UltrasonicSensorComponent),
- cv.Required(CONF_TRIGGER_PIN): pins.gpio_output_pin_schema,
- cv.Required(CONF_ECHO_PIN): pins.internal_gpio_input_pin_schema,
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({
+ cv.GenerateID(): cv.declare_id(UltrasonicSensorComponent),
+ cv.Required(CONF_TRIGGER_PIN): pins.gpio_output_pin_schema,
+ cv.Required(CONF_ECHO_PIN): pins.internal_gpio_input_pin_schema,
- cv.Optional(CONF_TIMEOUT, default='2m'): cv.distance,
- cv.Optional(CONF_PULSE_TIME, default='10us'): cv.positive_time_period_microseconds,
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
+ cv.Optional(CONF_TIMEOUT, default='2m'): cv.distance,
+ cv.Optional(CONF_PULSE_TIME, default='10us'): cv.positive_time_period_microseconds,
- cv.Optional('timeout_meter'): cv.invalid("The timeout_meter option has been renamed "
- "to 'timeout' in 1.12."),
- cv.Optional('timeout_time'): cv.invalid("The timeout_time option has been removed. Please "
- "use 'timeout' in 1.12."),
- }))
+ cv.Optional('timeout_meter'): cv.invalid("The timeout_meter option has been renamed "
+ "to 'timeout' in 1.12."),
+ cv.Optional('timeout_time'): cv.invalid("The timeout_time option has been removed. Please "
+ "use 'timeout' in 1.12."),
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- trigger = yield cg.gpio_pin_expression(config[CONF_TRIGGER_PIN])
- echo = yield cg.gpio_pin_expression(config[CONF_ECHO_PIN])
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], trigger, echo,
- config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
+ trigger = yield cg.gpio_pin_expression(config[CONF_TRIGGER_PIN])
+ cg.add(var.set_trigger_pin(trigger))
+ echo = yield cg.gpio_pin_expression(config[CONF_ECHO_PIN])
+ cg.add(var.set_echo_pin(echo))
+
cg.add(var.set_timeout_us(config[CONF_TIMEOUT] / (0.000343 / 2)))
cg.add(var.set_pulse_time_us(config[CONF_PULSE_TIME]))
diff --git a/esphome/components/ultrasonic/ultrasonic_sensor.cpp b/esphome/components/ultrasonic/ultrasonic_sensor.cpp
index 6ff575971d..5d4cd48bc1 100644
--- a/esphome/components/ultrasonic/ultrasonic_sensor.cpp
+++ b/esphome/components/ultrasonic/ultrasonic_sensor.cpp
@@ -6,9 +6,6 @@ namespace ultrasonic {
static const char *TAG = "ultrasonic.sensor";
-UltrasonicSensorComponent::UltrasonicSensorComponent(const std::string &name, GPIOPin *trigger_pin, GPIOPin *echo_pin,
- uint32_t update_interval)
- : PollingSensorComponent(name, update_interval), trigger_pin_(trigger_pin), echo_pin_(echo_pin) {}
void UltrasonicSensorComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up Ultrasonic Sensor...");
this->trigger_pin_->setup();
diff --git a/esphome/components/ultrasonic/ultrasonic_sensor.h b/esphome/components/ultrasonic/ultrasonic_sensor.h
index 749768c64a..633c1b17fb 100644
--- a/esphome/components/ultrasonic/ultrasonic_sensor.h
+++ b/esphome/components/ultrasonic/ultrasonic_sensor.h
@@ -7,15 +7,10 @@
namespace esphome {
namespace ultrasonic {
-class UltrasonicSensorComponent : public sensor::PollingSensorComponent {
+class UltrasonicSensorComponent : public sensor::Sensor, public PollingComponent {
public:
- /** Construct the ultrasonic sensor with the specified trigger pin and echo pin.
- *
- * @param trigger_pin The trigger pin where pulses are sent to.
- * @param echo_pin The echo pin where the echo is listened for.
- * @param update_interval The interval in ms the sensor should check for new values.
- */
- UltrasonicSensorComponent(const std::string &name, GPIOPin *trigger_pin, GPIOPin *echo_pin, uint32_t update_interval);
+ void set_trigger_pin(GPIOPin *trigger_pin) { trigger_pin_ = trigger_pin; }
+ void set_echo_pin(GPIOPin *echo_pin) { echo_pin_ = echo_pin; }
/// Set the timeout for waiting for the echo in µs.
void set_timeout_us(uint32_t timeout_us);
diff --git a/esphome/components/uptime/sensor.py b/esphome/components/uptime/sensor.py
index 33c5305cfe..e4f78c6411 100644
--- a/esphome/components/uptime/sensor.py
+++ b/esphome/components/uptime/sensor.py
@@ -1,24 +1,17 @@
-from esphome.components import sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, CONF_UNIT_OF_MEASUREMENT, \
- UNIT_SECOND, ICON_TIMER, CONF_ICON, CONF_ACCURACY_DECIMALS
+import esphome.config_validation as cv
+from esphome.components import sensor
+from esphome.const import CONF_ID, UNIT_SECOND, ICON_TIMER
uptime_ns = cg.esphome_ns.namespace('uptime')
UptimeSensor = uptime_ns.class_('UptimeSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(UptimeSensor),
-
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_SECOND): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_TIMER): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals,
-}).extend(cv.COMPONENT_SCHEMA))
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 0).extend({
+ cv.GenerateID(): cv.declare_id(UptimeSensor),
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- rhs = UptimeSensor.new(config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
- uptime = cg.Pvariable(config[CONF_ID], rhs)
- yield cg.register_component(uptime, config)
- yield sensor.register_sensor(uptime, config)
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield sensor.register_sensor(var, config)
diff --git a/esphome/components/uptime/uptime_sensor.cpp b/esphome/components/uptime/uptime_sensor.cpp
index 0ae794f2b7..a66ca0636f 100644
--- a/esphome/components/uptime/uptime_sensor.cpp
+++ b/esphome/components/uptime/uptime_sensor.cpp
@@ -7,8 +7,6 @@ namespace uptime {
static const char *TAG = "uptime.sensor";
-UptimeSensor::UptimeSensor(const std::string &name, uint32_t update_interval)
- : sensor::PollingSensorComponent(name, update_interval) {}
void UptimeSensor::update() {
const uint32_t ms = millis();
const uint64_t ms_mask = (1ULL << 32) - 1ULL;
diff --git a/esphome/components/uptime/uptime_sensor.h b/esphome/components/uptime/uptime_sensor.h
index 68e030af86..184022503d 100644
--- a/esphome/components/uptime/uptime_sensor.h
+++ b/esphome/components/uptime/uptime_sensor.h
@@ -6,10 +6,8 @@
namespace esphome {
namespace uptime {
-class UptimeSensor : public sensor::PollingSensorComponent {
+class UptimeSensor : public sensor::Sensor, public PollingComponent {
public:
- explicit UptimeSensor(const std::string &name, uint32_t update_interval);
-
void update() override;
float get_setup_priority() const override;
diff --git a/esphome/components/version/text_sensor.py b/esphome/components/version/text_sensor.py
index 4820581326..21044bb89f 100644
--- a/esphome/components/version/text_sensor.py
+++ b/esphome/components/version/text_sensor.py
@@ -1,18 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import text_sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_ICON, ICON_NEW_BOX
+from esphome.const import CONF_ID, CONF_ICON, ICON_NEW_BOX
version_ns = cg.esphome_ns.namespace('version')
VersionTextSensor = version_ns.class_('VersionTextSensor', text_sensor.TextSensor, cg.Component)
-CONFIG_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(VersionTextSensor),
+CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(VersionTextSensor),
cv.Optional(CONF_ICON, default=ICON_NEW_BOX): text_sensor.icon
-}).extend(cv.COMPONENT_SCHEMA))
+}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
+ var = cg.new_Pvariable(config[CONF_ID])
yield text_sensor.register_text_sensor(var, config)
yield cg.register_component(var, config)
diff --git a/esphome/components/version/version_text_sensor.cpp b/esphome/components/version/version_text_sensor.cpp
index 140778eb57..1e59deff96 100644
--- a/esphome/components/version/version_text_sensor.cpp
+++ b/esphome/components/version/version_text_sensor.cpp
@@ -9,7 +9,6 @@ static const char *TAG = "version.text_sensor";
void VersionTextSensor::setup() { this->publish_state(ESPHOME_VERSION " " + App.get_compilation_time()); }
float VersionTextSensor::get_setup_priority() const { return setup_priority::DATA; }
-VersionTextSensor::VersionTextSensor(const std::string &name) : text_sensor::TextSensor(name) {}
std::string VersionTextSensor::unique_id() { return get_mac_address() + "-version"; }
void VersionTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Version Text Sensor", this); }
diff --git a/esphome/components/version/version_text_sensor.h b/esphome/components/version/version_text_sensor.h
index 87e8412be0..cc798939ef 100644
--- a/esphome/components/version/version_text_sensor.h
+++ b/esphome/components/version/version_text_sensor.h
@@ -8,7 +8,6 @@ namespace version {
class VersionTextSensor : public text_sensor::TextSensor, public Component {
public:
- explicit VersionTextSensor(const std::string &name);
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py
index a980b2bac6..77a0bbc689 100644
--- a/esphome/components/waveshare_epaper/display.py
+++ b/esphome/components/waveshare_epaper/display.py
@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome import pins
from esphome.components import display, spi
from esphome.const import CONF_BUSY_PIN, CONF_DC_PIN, CONF_FULL_UPDATE_EVERY, \
- CONF_ID, CONF_LAMBDA, CONF_MODEL, CONF_PAGES, CONF_RESET_PIN, CONF_UPDATE_INTERVAL
+ CONF_ID, CONF_LAMBDA, CONF_MODEL, CONF_PAGES, CONF_RESET_PIN
DEPENDENCIES = ['spi']
@@ -38,27 +38,24 @@ def validate_full_update_every_only_type_a(value):
CONFIG_SCHEMA = cv.All(display.FULL_DISPLAY_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(WaveshareEPaper),
+ cv.GenerateID(): cv.declare_id(WaveshareEPaper),
cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_MODEL): cv.one_of(*MODELS, lower=True),
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_BUSY_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_FULL_UPDATE_EVERY): cv.uint32_t,
- cv.Optional(CONF_UPDATE_INTERVAL, default='1s'): cv.update_interval,
-}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA),
+}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA),
validate_full_update_every_only_type_a,
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))
def to_code(config):
- dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN])
-
model_type, model = MODELS[config[CONF_MODEL]]
if model_type == 'a':
- rhs = WaveshareEPaperTypeA.new(dc, model)
+ rhs = WaveshareEPaperTypeA.new(model)
var = cg.Pvariable(config[CONF_ID], rhs, type=WaveshareEPaperTypeA)
elif model_type == 'b':
- rhs = model.new(dc)
+ rhs = model.new()
var = cg.Pvariable(config[CONF_ID], rhs, type=model)
else:
raise NotImplementedError()
@@ -67,6 +64,9 @@ def to_code(config):
yield display.register_display(var, config)
yield spi.register_spi_device(var, config)
+ dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN])
+ cg.add(var.set_dc_pin(dc))
+
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(display.DisplayBufferRef, 'it')],
return_type=cg.void)
diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp
index 860a71b049..392134f52b 100644
--- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp
+++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp
@@ -110,7 +110,6 @@ void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, int color)
this->buffer_[pos] &= ~(0x80 >> subpos);
}
uint32_t WaveshareEPaper::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal() / 8u; }
-WaveshareEPaper::WaveshareEPaper(GPIOPin *dc_pin) : PollingComponent(0), dc_pin_(dc_pin) {}
bool WaveshareEPaper::is_device_high_speed() { return true; }
void WaveshareEPaper::start_command_() {
this->dc_pin_->digital_write(false);
@@ -246,8 +245,7 @@ void WaveshareEPaperTypeA::write_lut_(const uint8_t *lut) {
for (uint8_t i = 0; i < 30; i++)
this->data(lut[i]);
}
-WaveshareEPaperTypeA::WaveshareEPaperTypeA(GPIOPin *dc_pin, WaveshareEPaperTypeAModel model)
- : WaveshareEPaper(dc_pin), model_(model) {}
+WaveshareEPaperTypeA::WaveshareEPaperTypeA(WaveshareEPaperTypeAModel model) : model_(model) {}
void WaveshareEPaperTypeA::set_full_update_every(uint32_t full_update_every) {
this->full_update_every_ = full_update_every;
}
@@ -414,7 +412,6 @@ void HOT WaveshareEPaper2P7In::display() {
}
int WaveshareEPaper2P7In::get_width_internal() { return 176; }
int WaveshareEPaper2P7In::get_height_internal() { return 264; }
-WaveshareEPaper2P7In::WaveshareEPaper2P7In(GPIOPin *dc_pin) : WaveshareEPaper(dc_pin) {}
void WaveshareEPaper2P7In::dump_config() {
LOG_DISPLAY("", "Waveshare E-Paper", this);
ESP_LOGCONFIG(TAG, " Model: 2.7in");
@@ -523,7 +520,6 @@ void HOT WaveshareEPaper4P2In::display() {
int WaveshareEPaper4P2In::get_width_internal() { return 400; }
int WaveshareEPaper4P2In::get_height_internal() { return 300; }
bool WaveshareEPaper4P2In::is_device_high_speed() { return false; }
-WaveshareEPaper4P2In::WaveshareEPaper4P2In(GPIOPin *dc_pin) : WaveshareEPaper(dc_pin) {}
void WaveshareEPaper4P2In::dump_config() {
LOG_DISPLAY("", "Waveshare E-Paper", this);
ESP_LOGCONFIG(TAG, " Model: 4.2in");
@@ -609,7 +605,6 @@ void HOT WaveshareEPaper7P5In::display() {
}
int WaveshareEPaper7P5In::get_width_internal() { return 640; }
int WaveshareEPaper7P5In::get_height_internal() { return 384; }
-WaveshareEPaper7P5In::WaveshareEPaper7P5In(GPIOPin *dc_pin) : WaveshareEPaper(dc_pin) {}
void WaveshareEPaper7P5In::dump_config() {
LOG_DISPLAY("", "Waveshare E-Paper", this);
ESP_LOGCONFIG(TAG, " Model: 7.5in");
diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h
index 31e6eb819d..49bb21bc7f 100644
--- a/esphome/components/waveshare_epaper/waveshare_epaper.h
+++ b/esphome/components/waveshare_epaper/waveshare_epaper.h
@@ -9,7 +9,7 @@ namespace waveshare_epaper {
class WaveshareEPaper : public PollingComponent, public spi::SPIDevice, public display::DisplayBuffer {
public:
- WaveshareEPaper(GPIOPin *dc_pin);
+ void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; }
float get_setup_priority() const override;
void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
void set_busy_pin(GPIOPin *busy) { this->busy_pin_ = busy; }
@@ -53,7 +53,7 @@ enum WaveshareEPaperTypeAModel {
class WaveshareEPaperTypeA : public WaveshareEPaper {
public:
- WaveshareEPaperTypeA(GPIOPin *dc_pin, WaveshareEPaperTypeAModel model);
+ WaveshareEPaperTypeA(WaveshareEPaperTypeAModel model);
void setup() override;
@@ -83,7 +83,6 @@ enum WaveshareEPaperTypeBModel {
class WaveshareEPaper2P7In : public WaveshareEPaper {
public:
- WaveshareEPaper2P7In(GPIOPin *dc_pin);
void setup() override;
void display() override;
@@ -98,7 +97,6 @@ class WaveshareEPaper2P7In : public WaveshareEPaper {
class WaveshareEPaper4P2In : public WaveshareEPaper {
public:
- WaveshareEPaper4P2In(GPIOPin *dc_pin);
void setup() override;
void display() override;
@@ -115,7 +113,6 @@ class WaveshareEPaper4P2In : public WaveshareEPaper {
class WaveshareEPaper7P5In : public WaveshareEPaper {
public:
- WaveshareEPaper7P5In(GPIOPin *dc_pin);
void setup() override;
void display() override;
diff --git a/esphome/components/web_server/__init__.py b/esphome/components/web_server/__init__.py
index 615c276121..206fc2c733 100644
--- a/esphome/components/web_server/__init__.py
+++ b/esphome/components/web_server/__init__.py
@@ -3,13 +3,14 @@ import esphome.config_validation as cv
from esphome.const import CONF_CSS_URL, CONF_ID, CONF_JS_URL, CONF_PORT
from esphome.core import CORE, coroutine_with_priority
+DEPENDENCIES = ['network']
AUTO_LOAD = ['json']
web_server_ns = cg.esphome_ns.namespace('web_server')
WebServer = web_server_ns.class_('WebServer', cg.Component, cg.Controller)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(WebServer),
+ cv.GenerateID(): cv.declare_id(WebServer),
cv.Optional(CONF_PORT, default=80): cv.port,
cv.Optional(CONF_CSS_URL, default="https://esphome.io/_static/webserver-v1.min.css"): cv.string,
cv.Optional(CONF_JS_URL, default="https://esphome.io/_static/webserver-v1.min.js"): cv.string,
@@ -18,10 +19,12 @@ CONFIG_SCHEMA = cv.Schema({
@coroutine_with_priority(40.0)
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_PORT])
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+
+ cg.add(var.set_port(config[CONF_PORT]))
cg.add(var.set_css_url(config[CONF_CSS_URL]))
cg.add(var.set_js_url(config[CONF_JS_URL]))
- yield cg.register_component(var, config)
if CORE.is_esp32:
cg.add_library('FS', None)
diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp
index c43511e51b..882af4b995 100644
--- a/esphome/components/web_server/web_server.cpp
+++ b/esphome/components/web_server/web_server.cpp
@@ -61,8 +61,6 @@ UrlMatch match_url(const std::string &url, bool only_domain = false) {
return match;
}
-WebServer::WebServer(uint16_t port) : port_(port) {}
-
void WebServer::set_css_url(const char *css_url) { this->css_url_ = css_url; }
void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; }
diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h
index 72db3e36cb..7840a81dce 100644
--- a/esphome/components/web_server/web_server.h
+++ b/esphome/components/web_server/web_server.h
@@ -28,8 +28,7 @@ struct UrlMatch {
*/
class WebServer : public Controller, public Component, public AsyncWebHandler {
public:
- /// Initialize the web server with the specified port
- explicit WebServer(uint16_t port);
+ void set_port(uint16_t port) { port_ = port; }
/** Set the URL to the CSS that's sent to each client. Defaults to
* https://esphome.io/_static/webserver-v1.min.css
diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py
index 8be00a6c2a..9ac8b74ef2 100644
--- a/esphome/components/wifi/__init__.py
+++ b/esphome/components/wifi/__init__.py
@@ -1,12 +1,15 @@
-from esphome.automation import CONDITION_REGISTRY, Condition
-import esphome.config_validation as cv
import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.automation import Condition
from esphome.const import CONF_AP, CONF_BSSID, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, \
CONF_FAST_CONNECT, CONF_GATEWAY, CONF_HIDDEN, CONF_ID, CONF_MANUAL_IP, CONF_NETWORKS, \
CONF_PASSWORD, CONF_POWER_SAVE_MODE, CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, \
CONF_SUBNET, CONF_USE_ADDRESS
from esphome.core import CORE, HexInt, coroutine_with_priority
+AUTO_LOAD = ['network']
+
wifi_ns = cg.esphome_ns.namespace('wifi')
IPAddress = cg.global_ns.class_('IPAddress')
ManualIP = wifi_ns.struct('ManualIP')
@@ -54,7 +57,7 @@ STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
})
WIFI_NETWORK_BASE = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(WiFiAP),
+ cv.GenerateID(): cv.declare_id(WiFiAP),
cv.Optional(CONF_SSID): cv.ssid,
cv.Optional(CONF_PASSWORD): validate_password,
cv.Optional(CONF_CHANNEL): validate_channel,
@@ -106,7 +109,7 @@ def validate(config):
CONFIG_SCHEMA = cv.All(cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(WiFiComponent),
+ cv.GenerateID(): cv.declare_id(WiFiComponent),
cv.Optional(CONF_NETWORKS): cv.ensure_list(WIFI_NETWORK_STA),
cv.Optional(CONF_SSID): cv.ssid,
@@ -116,8 +119,7 @@ CONFIG_SCHEMA = cv.All(cv.Schema({
cv.Optional(CONF_AP): WIFI_NETWORK_AP,
cv.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
cv.Optional(CONF_REBOOT_TIMEOUT, default='5min'): cv.positive_time_period_milliseconds,
- cv.Optional(CONF_POWER_SAVE_MODE, default='NONE'):
- cv.one_of(*WIFI_POWER_SAVE_MODES, upper=True),
+ cv.Optional(CONF_POWER_SAVE_MODE, default='NONE'): cv.enum(WIFI_POWER_SAVE_MODES, upper=True),
cv.Optional(CONF_FAST_CONNECT, default=False): cv.boolean,
cv.Optional(CONF_USE_ADDRESS): cv.string_strict,
@@ -175,7 +177,7 @@ def to_code(config):
cg.add(wifi.set_ap(wifi_network(config[CONF_AP], config.get(CONF_MANUAL_IP))))
cg.add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
- cg.add(wifi.set_power_save_mode(WIFI_POWER_SAVE_MODES[config[CONF_POWER_SAVE_MODE]]))
+ cg.add(wifi.set_power_save_mode(config[CONF_POWER_SAVE_MODE]))
cg.add(wifi.set_fast_connect(config[CONF_FAST_CONNECT]))
if CORE.is_esp8266:
@@ -187,8 +189,6 @@ def to_code(config):
yield cg.register_component(wifi, config)
-@CONDITION_REGISTRY.register('wifi.connected', cv.Schema({}))
+@automation.register_condition('wifi.connected', WiFiConnectedCondition, cv.Schema({}))
def wifi_connected_to_code(config, condition_id, template_arg, args):
- rhs = WiFiConnectedCondition.new(template_arg)
- type = WiFiConnectedCondition.template(template_arg)
- yield cg.Pvariable(condition_id, rhs, type=type)
+ yield cg.new_Pvariable(condition_id, template_arg)
diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp
index ffea4982bd..28d911606b 100644
--- a/esphome/components/wifi/wifi_component.cpp
+++ b/esphome/components/wifi/wifi_component.cpp
@@ -297,7 +297,7 @@ void WiFiComponent::check_scanning_finished() {
}
std::stable_sort(this->scan_result_.begin(), this->scan_result_.end(),
- [this](const WiFiScanResult &a, const WiFiScanResult &b) {
+ [](const WiFiScanResult &a, const WiFiScanResult &b) {
if (a.get_matches() && !b.get_matches())
return true;
if (!a.get_matches() && b.get_matches())
diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py
index 56a073ba32..81ee787848 100644
--- a/esphome/components/wifi_info/text_sensor.py
+++ b/esphome/components/wifi_info/text_sensor.py
@@ -1,7 +1,7 @@
-from esphome.components import text_sensor
-import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import CONF_BSSID, CONF_ID, CONF_IP_ADDRESS, CONF_NAME, CONF_SSID
+import esphome.config_validation as cv
+from esphome.components import text_sensor
+from esphome.const import CONF_BSSID, CONF_ID, CONF_IP_ADDRESS, CONF_SSID
from esphome.core import coroutine
DEPENDENCIES = ['wifi']
@@ -12,15 +12,15 @@ SSIDWiFiInfo = wifi_info_ns.class_('SSIDWiFiInfo', text_sensor.TextSensor, cg.Co
BSSIDWiFiInfo = wifi_info_ns.class_('BSSIDWiFiInfo', text_sensor.TextSensor, cg.Component)
CONFIG_SCHEMA = cv.Schema({
- cv.Optional(CONF_IP_ADDRESS): cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(IPAddressWiFiInfo),
- })),
- cv.Optional(CONF_SSID): cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(SSIDWiFiInfo),
- })),
- cv.Optional(CONF_BSSID): cv.nameable(text_sensor.TEXT_SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(BSSIDWiFiInfo),
- })),
+ cv.Optional(CONF_IP_ADDRESS): text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(IPAddressWiFiInfo),
+ }),
+ cv.Optional(CONF_SSID): text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(SSIDWiFiInfo),
+ }),
+ cv.Optional(CONF_BSSID): text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(BSSIDWiFiInfo),
+ }),
})
@@ -28,7 +28,7 @@ CONFIG_SCHEMA = cv.Schema({
def setup_conf(config, key):
if key in config:
conf = config[key]
- var = cg.new_Pvariable(conf[CONF_ID], conf[CONF_NAME])
+ var = cg.new_Pvariable(conf[CONF_ID])
yield cg.register_component(var, conf)
yield text_sensor.register_text_sensor(var, conf)
diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.h b/esphome/components/wifi_info/wifi_info_text_sensor.h
index c3685db067..13e632bde1 100644
--- a/esphome/components/wifi_info/wifi_info_text_sensor.h
+++ b/esphome/components/wifi_info/wifi_info_text_sensor.h
@@ -9,7 +9,6 @@ namespace wifi_info {
class IPAddressWiFiInfo : public Component, public text_sensor::TextSensor {
public:
- IPAddressWiFiInfo(const std::string &name) : TextSensor(name) {}
void loop() override {
IPAddress ip = WiFi.localIP();
if (ip != this->last_ip_) {
@@ -25,7 +24,6 @@ class IPAddressWiFiInfo : public Component, public text_sensor::TextSensor {
class SSIDWiFiInfo : public Component, public text_sensor::TextSensor {
public:
- SSIDWiFiInfo(const std::string &name) : TextSensor(name) {}
void loop() override {
String ssid = WiFi.SSID();
if (this->last_ssid_ != ssid.c_str()) {
@@ -41,7 +39,6 @@ class SSIDWiFiInfo : public Component, public text_sensor::TextSensor {
class BSSIDWiFiInfo : public Component, public text_sensor::TextSensor {
public:
- BSSIDWiFiInfo(const std::string &name) : TextSensor(name) {}
void loop() override {
uint8_t *bssid = WiFi.BSSID();
if (memcmp(bssid, this->last_bssid_.data(), 6) != 0) {
diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py
index 48134919c9..e53daede1f 100644
--- a/esphome/components/wifi_signal/sensor.py
+++ b/esphome/components/wifi_signal/sensor.py
@@ -1,24 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
-from esphome.const import CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, CONF_ICON, \
- CONF_UNIT_OF_MEASUREMENT, CONF_ACCURACY_DECIMALS, ICON_WIFI, UNIT_DECIBEL
+from esphome.const import CONF_ID, ICON_WIFI, UNIT_DECIBEL
DEPENDENCIES = ['wifi']
wifi_signal_ns = cg.esphome_ns.namespace('wifi_signal')
WiFiSignalSensor = wifi_signal_ns.class_('WiFiSignalSensor', sensor.PollingSensorComponent)
-CONFIG_SCHEMA = cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.GenerateID(): cv.declare_variable_id(WiFiSignalSensor),
- cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
-
- cv.Optional(CONF_ICON, default=ICON_WIFI): sensor.icon,
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_DECIBEL): sensor.unit_of_measurement,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals,
-}).extend(cv.COMPONENT_SCHEMA))
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_DECIBEL, ICON_WIFI, 0).extend({
+ cv.GenerateID(): cv.declare_id(WiFiSignalSensor),
+}).extend(cv.polling_component_schema('60s'))
def to_code(config):
- var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
+ var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
diff --git a/esphome/components/wifi_signal/wifi_signal_sensor.h b/esphome/components/wifi_signal/wifi_signal_sensor.h
index 623d7acda8..8fe108a530 100644
--- a/esphome/components/wifi_signal/wifi_signal_sensor.h
+++ b/esphome/components/wifi_signal/wifi_signal_sensor.h
@@ -8,11 +8,8 @@
namespace esphome {
namespace wifi_signal {
-class WiFiSignalSensor : public sensor::PollingSensorComponent {
+class WiFiSignalSensor : public sensor::Sensor, public PollingComponent {
public:
- explicit WiFiSignalSensor(const std::string &name, uint32_t update_interval)
- : sensor::PollingSensorComponent(name, update_interval) {}
-
void update() override { this->publish_state(WiFi.RSSI()); }
void dump_config() override;
diff --git a/esphome/components/xiaomi_ble/__init__.py b/esphome/components/xiaomi_ble/__init__.py
index 3e0132d7ee..ef5df12cd9 100644
--- a/esphome/components/xiaomi_ble/__init__.py
+++ b/esphome/components/xiaomi_ble/__init__.py
@@ -10,7 +10,7 @@ xiaomi_ble_ns = cg.esphome_ns.namespace('xiaomi_ble')
XiaomiListener = xiaomi_ble_ns.class_('XiaomiListener', cg.Component, ESPBTDeviceListener)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(XiaomiListener),
+ cv.GenerateID(): cv.declare_id(XiaomiListener),
}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/xiaomi_miflora/sensor.py b/esphome/components/xiaomi_miflora/sensor.py
index 2b7d823c46..f6b44f9239 100644
--- a/esphome/components/xiaomi_miflora/sensor.py
+++ b/esphome/components/xiaomi_miflora/sensor.py
@@ -4,7 +4,6 @@ from esphome.components import sensor
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
ESP_BLE_DEVICE_SCHEMA
from esphome.const import CONF_BATTERY_LEVEL, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
- CONF_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_ACCURACY_DECIMALS, \
UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, ICON_BATTERY, CONF_ID, \
CONF_MOISTURE, CONF_ILLUMINANCE, ICON_BRIGHTNESS_5, UNIT_LUX, CONF_CONDUCTIVITY, \
UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER
@@ -16,34 +15,14 @@ xiaomi_miflora_ns = cg.esphome_ns.namespace('xiaomi_miflora')
XiaomiMiflora = xiaomi_miflora_ns.class_('XiaomiMiflora', ESPBTDeviceListener, cg.Component)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(XiaomiMiflora),
+ cv.GenerateID(): cv.declare_id(XiaomiMiflora),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
- cv.Optional(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_CELSIUS): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_THERMOMETER): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=1): sensor.accuracy_decimals
- })),
- cv.Optional(CONF_MOISTURE): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_WATER_PERCENT): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals
- })),
- cv.Optional(CONF_ILLUMINANCE): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_LUX): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_BRIGHTNESS_5): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals
- })),
- cv.Optional(CONF_CONDUCTIVITY): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_MICROSIEMENS_PER_CENTIMETER):
- sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_FLOWER): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals
- })),
- cv.Optional(CONF_BATTERY_LEVEL): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_BATTERY): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals
- })),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Optional(CONF_MOISTURE): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 0),
+ cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 0),
+ cv.Optional(CONF_CONDUCTIVITY):
+ sensor.sensor_schema(UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0),
+ cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 0),
}).extend(ESP_BLE_DEVICE_SCHEMA)
diff --git a/esphome/components/xiaomi_mijia/sensor.py b/esphome/components/xiaomi_mijia/sensor.py
index 0a90468805..ef68443304 100644
--- a/esphome/components/xiaomi_mijia/sensor.py
+++ b/esphome/components/xiaomi_mijia/sensor.py
@@ -4,7 +4,6 @@ from esphome.components import sensor
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
ESP_BLE_DEVICE_SCHEMA
from esphome.const import CONF_BATTERY_LEVEL, CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
- CONF_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_ACCURACY_DECIMALS, \
UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, ICON_BATTERY, CONF_ID
DEPENDENCIES = ['esp32_ble_tracker']
@@ -14,23 +13,11 @@ xiaomi_mijia_ns = cg.esphome_ns.namespace('xiaomi_mijia')
XiaomiMijia = xiaomi_mijia_ns.class_('XiaomiMijia', ESPBTDeviceListener, cg.Component)
CONFIG_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_variable_id(XiaomiMijia),
+ cv.GenerateID(): cv.declare_id(XiaomiMijia),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
- cv.Optional(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_CELSIUS): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_THERMOMETER): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=1): sensor.accuracy_decimals
- })),
- cv.Optional(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_WATER_PERCENT): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=1): sensor.accuracy_decimals
- })),
- cv.Optional(CONF_BATTERY_LEVEL): cv.nameable(sensor.SENSOR_SCHEMA.extend({
- cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): sensor.unit_of_measurement,
- cv.Optional(CONF_ICON, default=ICON_BATTERY): sensor.icon,
- cv.Optional(CONF_ACCURACY_DECIMALS, default=0): sensor.accuracy_decimals
- })),
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
+ cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1),
+ cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 0),
}).extend(ESP_BLE_DEVICE_SCHEMA)
diff --git a/esphome/config.py b/esphome/config.py
index 101e1d3857..901a78ea9a 100644
--- a/esphome/config.py
+++ b/esphome/config.py
@@ -6,20 +6,23 @@ import logging
import re
import os.path
+# pylint: disable=unused-import, wrong-import-order
+from contextlib import contextmanager
+
import voluptuous as vol
from esphome import core, core_config, yaml_util
from esphome.components import substitutions
+from esphome.components.substitutions import CONF_SUBSTITUTIONS
from esphome.const import CONF_ESPHOME, CONF_PLATFORM, ESP_PLATFORMS
-from esphome.core import CORE, EsphomeError
+from esphome.core import CORE, EsphomeError # noqa
from esphome.helpers import color, indent
from esphome.py_compat import text_type
from esphome.util import safe_print, OrderedDict
-# pylint: disable=unused-import, wrong-import-order
from typing import List, Optional, Tuple, Union # noqa
from esphome.core import ConfigType # noqa
-from esphome.yaml_util import is_secret
+from esphome.yaml_util import is_secret, ESPHomeDataBase
from esphome.voluptuous_schema import ExtraKeysInvalid
_LOGGER = logging.getLogger(__name__)
@@ -117,6 +120,9 @@ def _lookup_module(domain, is_platform):
try:
module = importlib.import_module(path)
except ImportError:
+ import traceback
+ _LOGGER.error("Unable to import component %s:", domain)
+ traceback.print_exc()
return None
except Exception: # pylint: disable=broad-except
import traceback
@@ -162,61 +168,83 @@ def iter_components(config):
ConfigPath = List[Union[str, int]]
-def _path_begins_with_(path, other): # type: (ConfigPath, ConfigPath) -> bool
+def _path_begins_with(path, other): # type: (ConfigPath, ConfigPath) -> bool
if len(path) < len(other):
return False
return path[:len(other)] == other
-def _path_begins_with(path, other): # type: (ConfigPath, ConfigPath) -> bool
- ret = _path_begins_with_(path, other)
- return ret
-
-
class Config(OrderedDict):
def __init__(self):
super(Config, self).__init__()
- self.errors = [] # type: List[Tuple[basestring, ConfigPath]]
- self.domains = [] # type: List[Tuple[ConfigPath, basestring]]
+ # A list of voluptuous errors
+ self.errors = [] # type: List[vol.Invalid]
+ # A list of paths that should be fully outputted
+ # The values will be the paths to all "domain", for example (['logger'], 'logger')
+ # or (['sensor', 'ultrasonic'], 'sensor.ultrasonic')
+ self.output_paths = [] # type: List[Tuple[ConfigPath, unicode]]
- def add_error(self, message, path):
+ def add_error(self, error):
+ # type: (vol.Invalid) -> None
+ if isinstance(error, vol.MultipleInvalid):
+ for err in error.errors:
+ self.add_error(err)
+ return
+ self.errors.append(error)
+
+ @contextmanager
+ def catch_error(self, path=None):
+ path = path or []
+ try:
+ yield
+ except vol.Invalid as e:
+ e.prepend(path)
+ self.add_error(e)
+
+ def add_str_error(self, message, path):
# type: (basestring, ConfigPath) -> None
- if not isinstance(message, text_type):
- message = text_type(message)
- self.errors.append((message, path))
+ self.add_error(vol.Invalid(message, path))
- def add_domain(self, path, name):
- # type: (ConfigPath, basestring) -> None
- self.domains.append((path, name))
+ def add_output_path(self, path, domain):
+ # type: (ConfigPath, unicode) -> None
+ self.output_paths.append((path, domain))
- def remove_domain(self, path, name):
- self.domains.remove((path, name))
-
- def lookup_domain(self, path):
- # type: (ConfigPath) -> Optional[basestring]
- best_len = 0
- best_domain = None
- for d_path, domain in self.domains:
- if len(d_path) < best_len:
- continue
- if _path_begins_with(path, d_path):
- best_len = len(d_path)
- best_domain = domain
- return best_domain
+ def remove_output_path(self, path, domain):
+ # type: (ConfigPath, unicode) -> None
+ self.output_paths.remove((path, domain))
def is_in_error_path(self, path):
- for _, p in self.errors:
- if _path_begins_with(p, path):
+ # type: (ConfigPath) -> bool
+ for err in self.errors:
+ if _path_begins_with(err.path, path):
return True
return False
+ def set_by_path(self, path, value):
+ conf = self
+ for key in path[:-1]:
+ conf = conf[key]
+ conf[path[-1]] = value
+
def get_error_for_path(self, path):
- for msg, p in self.errors:
- if self.nested_item_path(p) == path:
- return msg
+ # type: (ConfigPath) -> Optional[vol.Invalid]
+ for err in self.errors:
+ if self.get_deepest_path(err.path) == path:
+ return err
return None
- def nested_item(self, path):
+ def get_deepest_value_for_path(self, path):
+ # type: (ConfigPath) -> ConfigType
+ data = self
+ for item_index in path:
+ try:
+ data = data[item_index]
+ except (KeyError, IndexError, TypeError):
+ return data
+ return data
+
+ def get_nested_item(self, path):
+ # type: (ConfigPath) -> ConfigType
data = self
for item_index in path:
try:
@@ -225,7 +253,9 @@ class Config(OrderedDict):
return {}
return data
- def nested_item_path(self, path):
+ def get_deepest_path(self, path):
+ # type: (ConfigPath) -> ConfigPath
+ """Return the path that is the deepest reachable by following path."""
data = self
part = []
for item_index in path:
@@ -261,9 +291,13 @@ def do_id_pass(result): # type: (Config) -> None
searching_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
for id, path 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(u"ID {} redefined!".format(id.id), path)
- continue
+ if id.id is not None:
+ # Look for duplicate definitions
+ match = next((v for v in declare_ids if v[0].id == id.id), None)
+ if match is not None:
+ opath = u'->'.join(text_type(v) for v in match[1])
+ result.add_str_error(u"ID {} redefined! Check {}".format(id.id, opath), path)
+ continue
declare_ids.append((id, path))
else:
searching_ids.append((id, path))
@@ -278,14 +312,22 @@ def do_id_pass(result): # type: (Config) -> None
match = next((v[0] for v in declare_ids if v[0].id == id.id), None)
if match is None:
# No declared ID with this name
- result.add_error("Couldn't find ID '{}'".format(id.id), path)
+ import difflib
+ error = ("Couldn't find ID '{}'. Please check you have defined "
+ "an ID with that name in your configuration.".format(id.id))
+ # Find candidates
+ matches = difflib.get_close_matches(id.id, [v[0].id for v in declare_ids])
+ if matches:
+ matches_s = ', '.join('"{}"'.format(x) for x in matches)
+ error += " These IDs look similar: {}.".format(matches_s)
+ result.add_str_error(error, path)
continue
if not isinstance(match.type, MockObjClass) or not isinstance(id.type, MockObjClass):
continue
if not match.type.inherits_from(id.type):
- result.add_error("ID '{}' of type {} doesn't inherit from {}. Please double check "
- "your ID is pointing to the correct value"
- "".format(id.id, match.type, id.type), path)
+ result.add_str_error("ID '{}' of type {} doesn't inherit from {}. Please "
+ "double check your ID is pointing to the correct value"
+ "".format(id.id, match.type, id.type), path)
if id.id is None and id.type is not None:
for v in declare_ids:
@@ -296,204 +338,187 @@ def do_id_pass(result): # type: (Config) -> None
id.id = v[0].id
break
else:
- result.add_error("Couldn't resolve ID for type '{}'".format(id.type), path)
+ result.add_str_error("Couldn't resolve ID for type '{}'".format(id.type), path)
def validate_config(config):
result = Config()
- def _comp_error(ex, path):
- # type: (vol.Invalid, List[basestring]) -> None
- if isinstance(ex, vol.MultipleInvalid):
- errors = ex.errors
- else:
- errors = [ex]
+ # 1. Load substitutions
+ if CONF_SUBSTITUTIONS in config:
+ result[CONF_SUBSTITUTIONS] = config[CONF_SUBSTITUTIONS]
+ result.add_output_path([CONF_SUBSTITUTIONS], CONF_SUBSTITUTIONS)
+ try:
+ substitutions.do_substitution_pass(config)
+ except vol.Invalid as err:
+ result.add_error(err)
+ return result
- for e in errors:
- path_ = path + e.path
- domain = result.lookup_domain(path_) or ''
- result.add_error(_format_vol_invalid(e, config, path, domain), path_)
-
- skip_paths = list() # type: List[ConfigPath]
-
- # Step 1: Load everything
- result.add_domain([CONF_ESPHOME], CONF_ESPHOME)
+ # 2. Load partial core config
result[CONF_ESPHOME] = config[CONF_ESPHOME]
- config_queue = collections.deque()
+ result.add_output_path([CONF_ESPHOME], CONF_ESPHOME)
+ try:
+ core_config.preload_core_config(config)
+ except vol.Invalid as err:
+ result.add_error(err)
+ return result
+ # Remove temporary esphome config path again, it will be reloaded later
+ result.remove_output_path([CONF_ESPHOME], CONF_ESPHOME)
+
+ # 3. Load components.
+ # Load components (also AUTO_LOAD) and set output paths of result
+ # Queue of items to load, FIFO
+ load_queue = collections.deque()
for domain, conf in config.items():
- config_queue.append((domain, conf))
+ load_queue.append((domain, conf))
- while config_queue:
- domain, conf = config_queue.popleft()
- domain = str(domain)
- if domain == CONF_ESPHOME or domain.startswith(u'.'):
- skip_paths.append([domain])
+ # List of items to enter next stage
+ check_queue = [] # type: List[Tuple[ConfigPath, str, ConfigType, ComponentManifest]]
+
+ # This step handles:
+ # - Adding output path
+ # - Auto Load
+ # - Loading configs into result
+
+ while load_queue:
+ domain, conf = load_queue.popleft()
+ domain = text_type(domain)
+ if domain.startswith(u'.'):
+ # Ignore top-level keys starting with a dot
continue
- result.add_domain([domain], domain)
+ result.add_output_path([domain], domain)
result[domain] = conf
- if conf is None:
- result[domain] = conf = {}
component = get_component(domain)
+ path = [domain]
if component is None:
- result.add_error(u"Component not found: {}".format(domain), [domain])
- skip_paths.append([domain])
- continue
-
- if component.is_multi_conf and not isinstance(conf, list):
- result[domain] = conf = [conf]
-
- success = True
- for dependency in component.dependencies:
- if dependency not in config:
- result.add_error(u"Component {} requires component {}".format(domain, dependency),
- [domain])
- success = False
- if not success:
- skip_paths.append([domain])
- continue
-
- success = True
- for conflict in component.conflicts_with:
- if conflict in config:
- result.add_error(u"Component {} cannot be used together with component {}"
- u"".format(domain, conflict), [domain])
- success = False
- if not success:
- skip_paths.append([domain])
+ result.add_str_error(u"Component not found: {}".format(domain), path)
continue
+ CORE.loaded_integrations.add(domain)
+ # Process AUTO_LOAD
for load in component.auto_load:
if load not in config:
- conf = core.AutoLoad()
- config[load] = conf
- config_queue.append((load, conf))
-
- if CORE.esp_platform not in component.esp_platforms:
- result.add_error(u"Component {} doesn't support {}.".format(domain, CORE.esp_platform),
- [domain])
- skip_paths.append([domain])
- continue
+ load_conf = core.AutoLoad()
+ config[load] = load_conf
+ load_queue.append((load, load_conf))
if not component.is_platform_component:
- if component.config_schema is None and not isinstance(conf, core.AutoLoad):
- result.add_error(u"Component {} cannot be loaded via YAML (no CONFIG_SCHEMA)."
- u"".format(domain), [domain])
- skip_paths.append([domain])
+ check_queue.append(([domain], domain, conf, component))
continue
- result.remove_domain([domain], domain)
+ # This is a platform component, proceed to reading platform entries
+ # Remove this is as an output path
+ result.remove_output_path([domain], domain)
+ # Ensure conf is a list
if not isinstance(conf, list) and conf:
result[domain] = conf = [conf]
for i, p_config in enumerate(conf):
+ path = [domain, i]
+ # Construct temporary unknown output path
+ p_domain = u'{}.unknown'.format(domain)
+ result.add_output_path(path, p_domain)
+ result[domain][i] = p_config
if not isinstance(p_config, dict):
- result.add_error(u"Platform schemas must have 'platform:' key", [domain, i])
- skip_paths.append([domain, i])
+ result.add_str_error(u"Platform schemas must be key-value pairs.", path)
continue
p_name = p_config.get('platform')
if p_name is None:
- result.add_error(u"No platform specified for {}".format(domain), [domain, i])
- skip_paths.append([domain, i])
+ result.add_str_error(u"No platform specified! See 'platform' key.", path)
continue
+ # Remove temp output path and construct new one
+ result.remove_output_path(path, p_domain)
p_domain = u'{}.{}'.format(domain, p_name)
- result.add_domain([domain, i], p_domain)
+ result.add_output_path(path, p_domain)
+ # Try Load platform
platform = get_platform(domain, p_name)
if platform is None:
- result.add_error(u"Platform not found: '{}'".format(p_domain), [domain, i])
- skip_paths.append([domain, i])
- continue
-
- success = True
- for dependency in platform.dependencies:
- if dependency not in config:
- result.add_error(u"Platform {} requires component {}"
- u"".format(p_domain, dependency), [domain, i])
- success = False
- if not success:
- skip_paths.append([domain, i])
- continue
-
- success = True
- for conflict in platform.conflicts_with:
- if conflict in config:
- result.add_error(u"Platform {} cannot be used together with component {}"
- u"".format(p_domain, conflict), [domain, i])
- success = False
- if not success:
- skip_paths.append([domain, i])
+ result.add_str_error(u"Platform not found: '{}'".format(p_domain), path)
continue
+ CORE.loaded_integrations.add(p_name)
+ # Process AUTO_LOAD
for load in platform.auto_load:
if load not in config:
- conf = core.AutoLoad()
- config[load] = conf
- config_queue.append((load, conf))
+ load_conf = core.AutoLoad()
+ config[load] = load_conf
+ load_queue.append((load, load_conf))
- if CORE.esp_platform not in platform.esp_platforms:
- result.add_error(u"Platform {} doesn't support {}."
- u"".format(p_domain, CORE.esp_platform), [domain, i])
- skip_paths.append([domain, i])
- continue
+ check_queue.append((path, p_domain, p_config, platform))
- if platform.config_schema is None:
- result.add_error(u"Platform {} cannot be loaded via YAML (no PLATFORM_SCHEMA)."
- u"".format(p_domain), [domain, i])
- skip_paths.append([domain])
+ # 4. Validate component metadata, including
+ # - Transformation (nullable, multi conf)
+ # - Dependencies
+ # - Conflicts
+ # - Supported ESP Platform
- # Step 2: Validate configuration
- try:
- result[CONF_ESPHOME] = core_config.CONFIG_SCHEMA(result[CONF_ESPHOME])
- except vol.Invalid as ex:
- _comp_error(ex, [CONF_ESPHOME])
+ # List of items to proceed to next stage
+ validate_queue = [] # type: List[Tuple[ConfigPath, ConfigType, ComponentManifest]]
+ for path, domain, conf, comp in check_queue:
+ if conf is None:
+ result[domain] = conf = {}
- for domain, conf in result.items():
- domain = str(domain)
- if [domain] in skip_paths:
- continue
- component = get_component(domain)
-
- if not component.is_platform_component:
- if component.config_schema is None:
- continue
-
- if component.is_multi_conf:
- for i, conf_ in enumerate(conf):
- try:
- validated = component.config_schema(conf_)
- result[domain][i] = validated
- except vol.Invalid as ex:
- _comp_error(ex, [domain, i])
- else:
- try:
- validated = component.config_schema(conf)
- result[domain] = validated
- except vol.Invalid as ex:
- _comp_error(ex, [domain])
- continue
+ success = True
+ for dependency in comp.dependencies:
+ if dependency not in config:
+ result.add_str_error(u"Component {} requires component {}"
+ u"".format(domain, dependency), path)
+ success = False
+ if not success:
continue
- for i, p_config in enumerate(conf):
- if [domain, i] in skip_paths:
- continue
- p_name = p_config['platform']
- platform = get_platform(domain, p_name)
+ success = True
+ for conflict in comp.conflicts_with:
+ if conflict in config:
+ result.add_str_error(u"Component {} cannot be used together with component {}"
+ u"".format(domain, conflict), path)
+ success = False
+ if not success:
+ continue
- if platform.config_schema is not None:
+ if CORE.esp_platform not in comp.esp_platforms:
+ result.add_str_error(u"Component {} doesn't support {}.".format(domain,
+ CORE.esp_platform),
+ path)
+ continue
+
+ if not comp.is_platform_component and comp.config_schema is None and \
+ not isinstance(conf, core.AutoLoad):
+ result.add_str_error(u"Component {} cannot be loaded via YAML "
+ u"(no CONFIG_SCHEMA).".format(domain), path)
+ continue
+
+ if comp.is_multi_conf:
+ if not isinstance(conf, list):
+ result[domain] = conf = [conf]
+ for i, part_conf in enumerate(conf):
+ validate_queue.append((path + [i], part_conf, comp))
+ continue
+
+ validate_queue.append((path, conf, comp))
+
+ # 5. Validate configuration schema
+ for path, conf, comp in validate_queue:
+ if comp.config_schema is None:
+ continue
+ with result.catch_error(path):
+ if comp.is_platform:
# Remove 'platform' key for validation
- input_conf = OrderedDict(p_config)
+ input_conf = OrderedDict(conf)
platform_val = input_conf.pop('platform')
- try:
- p_validated = platform.config_schema(input_conf)
- except vol.Invalid as ex:
- _comp_error(ex, [domain, i])
- continue
- if not isinstance(p_validated, OrderedDict):
- p_validated = OrderedDict(p_validated)
- p_validated['platform'] = platform_val
- p_validated.move_to_end('platform', last=False)
- result[domain][i] = p_validated
+ validated = comp.config_schema(input_conf)
+ # Ensure result is OrderedDict so we can call move_to_end
+ if not isinstance(validated, OrderedDict):
+ validated = OrderedDict(validated)
+ validated['platform'] = platform_val
+ validated.move_to_end('platform', last=False)
+ result.set_by_path(path, validated)
+ else:
+ validated = comp.config_schema(conf)
+ result.set_by_path(path, validated)
+ # 6. If no validation errors, check IDs
if not result.errors:
# Only parse IDs if no validation error. Otherwise
# user gets confusing messages
@@ -511,9 +536,6 @@ def _nested_getitem(data, path):
def humanize_error(config, validation_error):
- offending_item_summary = _nested_getitem(config, validation_error.path)
- if isinstance(offending_item_summary, dict):
- offending_item_summary = None
validation_error = text_type(validation_error)
m = re.match(r'^(.*?)\s*(?:for dictionary value )?@ data\[.*$', validation_error)
if m is not None:
@@ -521,19 +543,26 @@ def humanize_error(config, validation_error):
validation_error = validation_error.strip()
if not validation_error.endswith(u'.'):
validation_error += u'.'
- if offending_item_summary is None or is_secret(offending_item_summary):
- return validation_error
-
- return u"{} Got '{}'".format(validation_error, offending_item_summary)
+ return validation_error
-def _format_vol_invalid(ex, config, path, domain):
- # type: (vol.Invalid, ConfigType, ConfigPath, basestring) -> unicode
+def _get_parent_name(path, config):
+ if not path:
+ return ''
+ for domain_path, domain in config.output_paths:
+ if _path_begins_with(path, domain_path):
+ if len(path) > len(domain_path):
+ # Sub-item
+ break
+ return domain
+ return path[-1]
+
+
+def _format_vol_invalid(ex, config):
+ # type: (vol.Invalid, Config) -> unicode
message = u''
- try:
- paren = ex.path[-2]
- except IndexError:
- paren = domain
+
+ paren = _get_parent_name(ex.path[:-1], config)
if isinstance(ex, ExtraKeysInvalid):
if ex.candidates:
@@ -547,20 +576,25 @@ def _format_vol_invalid(ex, config, path, domain):
elif u'required key not provided' in ex.error_message:
message += u"'{}' is a required option for [{}].".format(ex.path[-1], paren)
else:
- message += humanize_error(_nested_getitem(config, path), ex)
+ message += humanize_error(config, ex)
return message
-def load_config():
+class InvalidYAMLError(EsphomeError):
+ def __init__(self, base_exc):
+ message = u"Invalid YAML syntax. Please see YAML syntax reference or use an " \
+ u"online YAML syntax validator:\n\n{}".format(base_exc)
+ super(InvalidYAMLError, self).__init__(message)
+ self.base_exc = base_exc
+
+
+def _load_config():
try:
config = yaml_util.load_yaml(CORE.config_path)
- except OSError:
- raise EsphomeError(u"Invalid YAML at {}. Please see YAML syntax reference or use an online "
- u"YAML syntax validator".format(CORE.config_path))
+ except EsphomeError as e:
+ raise InvalidYAMLError(e)
CORE.raw_config = config
- config = substitutions.do_substitution_pass(config)
- core_config.preload_core_config(config)
try:
result = validate_config(config)
@@ -573,13 +607,21 @@ def load_config():
return result
+def load_config():
+ try:
+ return _load_config()
+ except vol.Invalid as err:
+ raise EsphomeError("Error while parsing config: {}".format(err))
+
+
def line_info(obj, highlight=True):
"""Display line config source."""
if not highlight:
return None
- if hasattr(obj, '__config_file__'):
- return color('cyan', "[source {}:{}]"
- .format(obj.__config_file__, obj.__line__ or '?'))
+ if isinstance(obj, ESPHomeDataBase) and obj.esp_range is not None:
+ mark = obj.esp_range.start_mark
+ source = u"[source {}:{}]".format(mark.document, mark.line + 1)
+ return color('cyan', source)
return None
@@ -595,14 +637,14 @@ def _print_on_next_line(obj):
def dump_dict(config, path, at_root=True):
# type: (Config, ConfigPath, bool) -> Tuple[unicode, bool]
- conf = config.nested_item(path)
+ conf = config.get_nested_item(path)
ret = u''
multiline = False
if at_root:
error = config.get_error_for_path(path)
if error is not None:
- ret += u'\n' + color('bold_red', error) + u'\n'
+ ret += u'\n' + color('bold_red', _format_vol_invalid(error, config)) + u'\n'
if isinstance(conf, (list, tuple)):
multiline = True
@@ -614,14 +656,14 @@ def dump_dict(config, path, at_root=True):
path_ = path + [i]
error = config.get_error_for_path(path_)
if error is not None:
- ret += u'\n' + color('bold_red', error) + u'\n'
+ ret += u'\n' + color('bold_red', _format_vol_invalid(error, config)) + u'\n'
sep = u'- '
if config.is_in_error_path(path_):
sep = color('red', sep)
msg, _ = dump_dict(config, path_, at_root=False)
msg = indent(msg)
- inf = line_info(config.nested_item(path_), highlight=config.is_in_error_path(path_))
+ inf = line_info(config.get_nested_item(path_), highlight=config.is_in_error_path(path_))
if inf is not None:
msg = inf + u'\n' + msg
elif msg:
@@ -637,14 +679,14 @@ def dump_dict(config, path, at_root=True):
path_ = path + [k]
error = config.get_error_for_path(path_)
if error is not None:
- ret += u'\n' + color('bold_red', error) + u'\n'
+ ret += u'\n' + color('bold_red', _format_vol_invalid(error, config)) + u'\n'
st = u'{}: '.format(k)
if config.is_in_error_path(path_):
st = color('red', st)
msg, m = dump_dict(config, path_, at_root=False)
- inf = line_info(config.nested_item(path_), highlight=config.is_in_error_path(path_))
+ inf = line_info(config.get_nested_item(path_), highlight=config.is_in_error_path(path_))
if m:
msg = u'\n' + indent(msg)
@@ -717,12 +759,12 @@ def read_config(verbose):
safe_print(color('bold_red', u"Failed config"))
safe_print('')
- for path, domain in res.domains:
+ for path, domain in res.output_paths:
if not res.is_in_error_path(path):
continue
safe_print(color('bold_red', u'{}:'.format(domain)) + u' ' +
- (line_info(res.nested_item(path)) or u''))
+ (line_info(res.get_nested_item(path)) or u''))
safe_print(indent(dump_dict(res, path)[0]))
return None
return OrderedDict(res)
diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py
new file mode 100644
index 0000000000..c235371db1
--- /dev/null
+++ b/esphome/config_helpers.py
@@ -0,0 +1,27 @@
+from __future__ import print_function
+
+import codecs
+import json
+
+from esphome.core import CORE, EsphomeError
+from esphome.py_compat import safe_input
+
+
+def read_config_file(path):
+ # type: (basestring) -> unicode
+ if CORE.vscode:
+ print(json.dumps({
+ 'type': 'read_file',
+ 'path': path,
+ }))
+ data = json.loads(safe_input())
+ assert data['type'] == 'file_response'
+ return data['content']
+
+ try:
+ with codecs.open(path, encoding='utf-8') as handle:
+ return handle.read()
+ except IOError as exc:
+ raise EsphomeError(u"Error accessing file {}: {}".format(path, exc))
+ except UnicodeDecodeError as exc:
+ raise EsphomeError(u"Unable to read file {}: {}".format(path, exc))
diff --git a/esphome/config_validation.py b/esphome/config_validation.py
index 0c2321cb5b..56fb260679 100644
--- a/esphome/config_validation.py
+++ b/esphome/config_validation.py
@@ -5,6 +5,7 @@ from __future__ import print_function
import logging
import os
import re
+from contextlib import contextmanager
import uuid as uuid_
from datetime import datetime
@@ -14,9 +15,10 @@ from esphome import core
from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
CONF_INTERNAL, CONF_NAME, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, \
CONF_RETAIN, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, \
- CONF_HOUR, CONF_MINUTE, CONF_SECOND, CONF_VALUE
+ CONF_HOUR, CONF_MINUTE, CONF_SECOND, CONF_VALUE, CONF_UPDATE_INTERVAL, CONF_TYPE_ID
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
+from esphome.helpers import list_starts_with
from esphome.py_compat import integer_types, string_types, text_type, IS_PY2
from esphome.voluptuous_schema import _Schema
@@ -25,8 +27,6 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=invalid-name
Schema = _Schema
-Optional = vol.Optional
-Required = vol.Required
All = vol.All
Coerce = vol.Coerce
Range = vol.Range
@@ -39,14 +39,8 @@ Length = vol.Length
Exclusive = vol.Exclusive
Inclusive = vol.Inclusive
ALLOW_EXTRA = vol.ALLOW_EXTRA
-
-port = All(Coerce(int), Range(min=1, max=65535))
-float_ = Coerce(float)
-positive_float = All(float_, Range(min=0))
-zero_to_one_float = All(float_, Range(min=0, max=1))
-negative_one_to_one_float = All(float_, Range(min=-1, max=1))
-positive_int = All(Coerce(int), Range(min=0))
-positive_not_null_int = All(Coerce(int), Range(min=0, min_included=False))
+UNDEFINED = vol.UNDEFINED
+RequiredFieldInvalid = vol.RequiredFieldInvalid
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
@@ -66,11 +60,44 @@ RESERVED_IDS = [
'App', 'pinMode', 'delay', 'delayMicroseconds', 'digitalRead', 'digitalWrite', 'INPUT',
'OUTPUT',
'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'int8_t', 'int16_t', 'int32_t', 'int64_t',
- 'display', 'i2c', 'spi', 'uart', 'sensor', 'binary_sensor', 'climate', 'cover', 'text_sensor',
- 'api', 'fan', 'light', 'gpio', 'mqtt', 'ota', 'power_supply', 'wifi'
]
+class Optional(vol.Optional):
+ """Mark a field as optional and optionally define a default for the field.
+
+ When no default is defined, the validated config will not contain the key.
+ You can check if the key is defined with 'CONF_ in config'. Or to access
+ the key and return None if it does not exist, call config.get(CONF_)
+
+ If a default *is* set, the resulting validated config will always contain the
+ default value. You can therefore directly access the value using the
+ 'config[CONF_]' syntax.
+
+ In ESPHome, all configuration defaults should be defined with the Optional class
+ during config validation - specifically *not* in the C++ code or the code generation
+ phase.
+ """
+ def __init__(self, key, default=UNDEFINED):
+ super(Optional, self).__init__(key, default=default)
+
+
+class Required(vol.Required):
+ """Define a field to be required to be set. The validated configuration is guaranteed
+ to contain this key.
+
+ All required values should be acceessed with the `config[CONF_]` syntax in code
+ - *not* the `config.get(CONF_)` syntax.
+ """
+ def __init__(self, key):
+ super(Required, self).__init__(key)
+
+
+def check_not_templatable(value):
+ if isinstance(value, Lambda):
+ raise Invalid("This option is not templatable!")
+
+
def alphanumeric(value):
if value is None:
raise Invalid("string value is None")
@@ -90,46 +117,79 @@ def valid_name(value):
def string(value):
+ """Validate that a configuration value is a string. If not, automatically converts to a string.
+
+ Note that this can be lossy, for example the input value 60.00 (float) will be turned into
+ "60.0" (string). For values where this could be a problem `string_string` has to be used.
+ """
+ check_not_templatable(value)
if isinstance(value, (dict, list)):
raise Invalid("string value cannot be dictionary or list.")
+ if isinstance(value, bool):
+ raise Invalid("Auto-converted this value to boolean, please wrap the value in quotes.")
+ if isinstance(value, text_type):
+ return value
if value is not None:
return text_type(value)
raise Invalid("string value is None")
def string_strict(value):
- """Strictly only allow strings."""
- if isinstance(value, string_types):
+ """Like string, but only allows strings, and does not automatically convert other types to
+ strings."""
+ check_not_templatable(value)
+ if isinstance(value, text_type):
return value
+ if isinstance(value, string_types):
+ return text_type(value)
raise Invalid("Must be string, got {}. did you forget putting quotes "
"around the value?".format(type(value)))
def icon(value):
- """Validate icon."""
+ """Validate that a given config value is a valid icon."""
value = string_strict(value)
+ if not value:
+ return value
if value.startswith('mdi:'):
return value
raise Invalid('Icons should start with prefix "mdi:"')
def boolean(value):
- """Validate and coerce a boolean value."""
- if isinstance(value, str):
+ """Validate the given config option to be a boolean.
+
+ This option allows a bunch of different ways of expressing boolean values:
+ - instance of boolean
+ - 'true'/'false'
+ - 'yes'/'no'
+ - 'enable'/disable
+ """
+ check_not_templatable(value)
+ if isinstance(value, bool):
+ return value
+ if isinstance(value, string_types):
value = value.lower()
- if value in ('1', 'true', 'yes', 'on', 'enable'):
+ if value in ('true', 'yes', 'on', 'enable'):
return True
- if value in ('0', 'false', 'no', 'off', 'disable'):
+ if value in ('false', 'no', 'off', 'disable'):
return False
- raise Invalid('invalid boolean value {}'.format(value))
- return bool(value)
+ raise Invalid(u"Expected boolean value, but cannot convert {} to a boolean. "
+ u"Please use 'true' or 'false'".format(value))
def ensure_list(*validators):
- """Wrap value in list if it is not one."""
+ """Validate this configuration option to be a list.
+
+ If the config value is not a list, it is automatically converted to a
+ single-item list.
+
+ None and empty dictionaries are converted to empty lists.
+ """
user = All(*validators)
def validator(value):
+ check_not_templatable(value)
if value is None or (isinstance(value, dict) and not value):
return []
if not isinstance(value, list):
@@ -138,56 +198,80 @@ def ensure_list(*validators):
errs = []
for i, val in enumerate(value):
try:
- ret.append(user(val))
- except vol.MultipleInvalid as err:
- err.prepend([i])
+ with prepend_path([i]):
+ ret.append(user(val))
+ except MultipleInvalid as err:
errs.extend(err.errors)
except Invalid as err:
- err.prepend([i])
errs.append(err)
if errs:
- raise vol.MultipleInvalid(errs)
+ raise MultipleInvalid(errs)
return ret
return validator
-def ensure_list_not_empty(value):
- if isinstance(value, list):
- return value
- return [value]
-
-
-def ensure_dict(value):
- if value is None:
- return {}
- if not isinstance(value, dict):
- raise Invalid("Expected a dictionary")
- return value
-
-
-def hex_int_(value):
- if isinstance(value, integer_types):
- return HexInt(value)
- value = string_strict(value).lower()
- if value.startswith('0x'):
- return HexInt(int(value, 16))
- return HexInt(int(value))
+def hex_int(value):
+ """Validate the given value to be a hex integer. This is mostly for cosmetic
+ purposes of the generated code.
+ """
+ return HexInt(int_(value))
def int_(value):
+ """Validate that the config option is an integer.
+
+ Automatically also converts strings to ints.
+ """
+ check_not_templatable(value)
if isinstance(value, integer_types):
return value
value = string_strict(value).lower()
+ base = 10
if value.startswith('0x'):
- return int(value, 16)
- return int(value)
+ base = 16
+ try:
+ return int(value, base)
+ except ValueError:
+ raise Invalid(u"Expected integer, but cannot parse {} as an integer".format(value))
-hex_int = Coerce(hex_int_)
+def int_range(min=None, max=None, min_included=True, max_included=True):
+ """Validate that the config option is an integer in the given range."""
+ if min is not None:
+ assert isinstance(min, integer_types)
+ if max is not None:
+ assert isinstance(max, integer_types)
+ return All(int_, Range(min=min, max=max, min_included=min_included, max_included=max_included))
+
+
+def hex_int_range(min=None, max=None, min_included=True, max_included=True):
+ """Validate that the config option is an integer in the given range."""
+ return All(hex_int,
+ Range(min=min, max=max, min_included=min_included, max_included=max_included))
+
+
+def float_range(min=None, max=None, min_included=True, max_included=True):
+ """Validate that the config option is a floating point number in the given range."""
+ if min is not None:
+ assert isinstance(min, (int, float))
+ if max is not None:
+ assert isinstance(max, (int, float))
+ return All(float_, Range(min=min, max=max, min_included=min_included,
+ max_included=max_included))
+
+
+port = int_range(min=1, max=65535)
+float_ = Coerce(float)
+positive_float = float_range(min=0)
+zero_to_one_float = float_range(min=0, max=1)
+negative_one_to_one_float = float_range(min=-1, max=1)
+positive_int = int_range(min=0)
+positive_not_null_int = int_range(min=0, min_included=False)
def validate_id_name(value):
+ """Validate that the given value would be a valid C++ identifier name."""
value = string(value)
if not value:
raise Invalid("ID must not be empty")
@@ -201,22 +285,35 @@ def validate_id_name(value):
u"character and numbers. The character '{}' cannot be used"
u"".format(char))
if value in RESERVED_IDS:
- raise Invalid(u"ID {} is reserved internally and cannot be used".format(value))
+ raise Invalid(u"ID '{}' is reserved internally and cannot be used".format(value))
+ if value in CORE.loaded_integrations:
+ raise Invalid(u"ID '{}' conflicts with the name of an esphome integration, please use "
+ u"another ID name.".format(value))
return value
-def use_variable_id(type):
+def use_id(type):
+ """Declare that this configuration option should point to an ID with the given type."""
def validator(value):
+ check_not_templatable(value)
if value is None:
return core.ID(None, is_declaration=False, type=type)
+ if isinstance(value, core.ID) and value.is_declaration is False and value.type is type:
+ return value
return core.ID(validate_id_name(value), is_declaration=False, type=type)
return validator
-def declare_variable_id(type):
+def declare_id(type):
+ """Declare that this configuration option should be used to declare a variable ID
+ with the given type.
+
+ If two IDs with the same name exist, a validation error is thrown.
+ """
def validator(value):
+ check_not_templatable(value)
if value is None:
return core.ID(None, is_declaration=True, type=type)
@@ -226,17 +323,26 @@ def declare_variable_id(type):
def templatable(other_validators):
+ """Validate that the configuration option can (optionally) be templated.
+
+ The user can declare a value as template by using the '!lambda' tag. In that case,
+ validation is skipped. Otherwise (if the value is not templated) the validator given
+ as the first argument to this method is called.
+ """
+ schema = Schema(other_validators)
+
def validator(value):
if isinstance(value, Lambda):
- return value
+ return lambda_(value)
if isinstance(other_validators, dict):
- return Schema(other_validators)(value)
- return other_validators(value)
+ return schema(value)
+ return schema(value)
return validator
def only_on(platforms):
+ """Validate that this option can only be specified on the given ESP platforms."""
if not isinstance(platforms, list):
platforms = [platforms]
@@ -255,7 +361,7 @@ only_on_esp8266 = only_on('ESP8266')
# Adapted from:
# https://github.com/alecthomas/voluptuous/issues/115#issuecomment-144464666
def has_at_least_one_key(*keys):
- """Validate that at least one key exists."""
+ """Validate that at least one of the given keys exist in the config."""
def validate(obj):
"""Test keys exist in dict."""
@@ -270,6 +376,7 @@ def has_at_least_one_key(*keys):
def has_exactly_one_key(*keys):
+ """Validate that exactly one of the given keys exist in the config."""
def validate(obj):
if not isinstance(obj, dict):
raise Invalid('expected dictionary')
@@ -285,6 +392,7 @@ def has_exactly_one_key(*keys):
def has_at_most_one_key(*keys):
+ """Validate that at most one of the given keys exist in the config."""
def validate(obj):
if not isinstance(obj, dict):
raise Invalid('expected dictionary')
@@ -300,17 +408,17 @@ def has_at_most_one_key(*keys):
TIME_PERIOD_ERROR = "Time period {} should be format number + unit, for example 5ms, 5s, 5min, 5h"
time_period_dict = All(
- dict, Schema({
- 'days': float_,
- 'hours': float_,
- 'minutes': float_,
- 'seconds': float_,
- 'milliseconds': float_,
- 'microseconds': float_,
+ Schema({
+ Optional('days'): float_,
+ Optional('hours'): float_,
+ Optional('minutes'): float_,
+ Optional('seconds'): float_,
+ Optional('milliseconds'): float_,
+ Optional('microseconds'): float_,
}),
- has_at_least_one_key('days', 'hours', 'minutes',
- 'seconds', 'milliseconds', 'microseconds'),
- lambda value: TimePeriod(**value))
+ has_at_least_one_key('days', 'hours', 'minutes', 'seconds', 'milliseconds', 'microseconds'),
+ lambda value: TimePeriod(**value)
+)
def time_period_str_colon(value):
@@ -338,6 +446,8 @@ def time_period_str_colon(value):
def time_period_str_unit(value):
"""Validate and transform time period with time unit and integer value."""
+ check_not_templatable(value)
+
if isinstance(value, int):
raise Invalid("Don't know what '{0}' means as it has no time *unit*! Did you mean "
"'{0}s'?".format(value))
@@ -682,6 +792,7 @@ def mqtt_qos(value):
def requires_component(comp):
+ """Validate that this option can only be specified when the component `comp` is loaded."""
def validator(value):
if comp not in CORE.raw_config:
raise Invalid("This option requires component {}".format(comp))
@@ -690,16 +801,20 @@ def requires_component(comp):
return validator
-uint8_t = All(int_, Range(min=0, max=255))
-uint16_t = All(int_, Range(min=0, max=65535))
-uint32_t = All(int_, Range(min=0, max=4294967295))
-hex_uint8_t = All(hex_int, Range(min=0, max=255))
-hex_uint16_t = All(hex_int, Range(min=0, max=65535))
-hex_uint32_t = All(hex_int, Range(min=0, max=4294967295))
+uint8_t = int_range(min=0, max=255)
+uint16_t = int_range(min=0, max=65535)
+uint32_t = int_range(min=0, max=4294967295)
+hex_uint8_t = hex_int_range(min=0, max=255)
+hex_uint16_t = hex_int_range(min=0, max=65535)
+hex_uint32_t = hex_int_range(min=0, max=4294967295)
i2c_address = hex_uint8_t
def percentage(value):
+ """Validate that the value is a percentage.
+
+ The resulting value is an integer in the range 0.0 to 1.0.
+ """
value = possibly_negative_percentage(value)
return zero_to_one_float(value)
@@ -728,6 +843,9 @@ def percentage_int(value):
def invalid(message):
+ """Mark this value as invalid. Each time *any* value is passed here it will result in a
+ validation error with the given message.
+ """
def validator(value):
raise Invalid(message)
@@ -738,14 +856,56 @@ def valid(value):
return value
+@contextmanager
+def prepend_path(path):
+ """A contextmanager helper to prepend a path to all voluptuous errors."""
+ if not isinstance(path, (list, tuple)):
+ path = [path]
+ try:
+ yield
+ except vol.Invalid as e:
+ e.prepend(path)
+ raise e
+
+
+@contextmanager
+def remove_prepend_path(path):
+ """A contextmanager helper to remove a path from a voluptuous error."""
+ if not isinstance(path, (list, tuple)):
+ path = [path]
+ try:
+ yield
+ except vol.Invalid as e:
+ if list_starts_with(e.path, path):
+ # Can't set e.path (namedtuple
+ for _ in range(len(path)):
+ e.path.pop(0)
+ raise e
+
+
def one_of(*values, **kwargs):
+ """Validate that the config option is one of the given values.
+
+ :param values: The valid values for this type
+
+ :Keyword Arguments:
+ - *lower* (``bool``, default=False): Whether to convert the incoming values to lowercase
+ strings.
+ - *upper* (``bool``, default=False): Whether to convert the incoming values to uppercase
+ strings.
+ - *int* (``bool``, default=False): Whether to convert the incoming values to integers.
+ - *float* (``bool``, default=False): Whether to convert the incoming values to floats.
+ - *space* (``str``, default=' '): What to convert spaces in the input string to.
+ """
options = u', '.join(u"'{}'".format(x) for x in values)
- lower = kwargs.get('lower', False)
- upper = kwargs.get('upper', False)
- string_ = kwargs.get('string', False) or lower or upper
- to_int = kwargs.get('int', False)
- to_float = kwargs.get('float', False)
- space = kwargs.get('space', ' ')
+ lower = kwargs.pop('lower', False)
+ upper = kwargs.pop('upper', False)
+ string_ = kwargs.pop('string', False) or lower or upper
+ to_int = kwargs.pop('int', False)
+ to_float = kwargs.pop('float', False)
+ space = kwargs.pop('space', ' ')
+ if kwargs:
+ raise ValueError
def validator(value):
if string_:
@@ -760,16 +920,58 @@ def one_of(*values, **kwargs):
if upper:
value = Upper(value)
if value not in values:
- raise Invalid(u"Unknown value '{}', must be one of {}".format(value, options))
+ import difflib
+ options_ = [text_type(x) for x in values]
+ option = text_type(value)
+ matches = difflib.get_close_matches(option, options_)
+ if matches:
+ raise Invalid(u"Unknown value '{}', did you mean {}?"
+ u"".format(value, u", ".join(u"'{}'".format(x) for x in matches)))
+ raise Invalid(u"Unknown value '{}', valid options are {}.".format(value, options))
return value
return validator
-def lambda_(value):
- if isinstance(value, Lambda):
+def enum(mapping, **kwargs):
+ """Validate this config option against an enum mapping.
+
+ The mapping should be a dictionary with the key representing the config value name and
+ a value representing the expression to set during code generation.
+
+ Accepts all kwargs of one_of.
+ """
+ assert isinstance(mapping, dict)
+ one_of_validator = one_of(*mapping, **kwargs)
+
+ def validator(value):
+ from esphome.yaml_util import make_data_base
+
+ value = make_data_base(one_of_validator(value))
+ cls = value.__class__
+ value.__class__ = cls.__class__(cls.__name__ + "Enum", (cls, core.EnumValue), {})
+ value.enum_value = mapping[value]
return value
- return Lambda(string_strict(value))
+
+ return validator
+
+
+LAMBDA_ENTITY_ID_PROG = re.compile(r'id\(\s*([a-zA-Z0-9_]+\.[.a-zA-Z0-9_]+)\s*\)')
+
+
+def lambda_(value):
+ """Coerce this configuration option to a lambda."""
+ if not isinstance(value, Lambda):
+ value = Lambda(string_strict(value))
+ entity_id_parts = re.split(LAMBDA_ENTITY_ID_PROG, value.value)
+ if len(entity_id_parts) != 1:
+ entity_ids = ' '.join("'{}'".format(entity_id_parts[i])
+ for i in range(1, len(entity_id_parts), 2))
+ raise Invalid("Lambda contains reference to entity-id-style ID {}. "
+ "The id() wrapper only works for ESPHome-internal types. For importing "
+ "states from Home Assistant use the 'homeassistant' sensor platforms."
+ "".format(entity_ids))
+ return value
def dimensions(value):
@@ -792,23 +994,25 @@ def dimensions(value):
def directory(value):
value = string(value)
- path = CORE.relative_path(value)
+ path = CORE.relative_config_path(value)
if not os.path.exists(path):
- raise Invalid(u"Could not find directory '{}'. Please make sure it exists.".format(
- path))
+ raise Invalid(u"Could not find directory '{}'. Please make sure it exists (full path: {})."
+ u"".format(path, os.path.abspath(path)))
if not os.path.isdir(path):
- raise Invalid(u"Path '{}' is not a directory.".format(path))
+ raise Invalid(u"Path '{}' is not a directory (full path: {})."
+ u"".format(path, os.path.abspath(path)))
return value
def file_(value):
value = string(value)
- path = CORE.relative_path(value)
+ path = CORE.relative_config_path(value)
if not os.path.exists(path):
- raise Invalid(u"Could not find file '{}'. Please make sure it exists.".format(
- path))
+ raise Invalid(u"Could not find file '{}'. Please make sure it exists (full path: {})."
+ u"".format(path, os.path.abspath(path)))
if not os.path.isfile(path):
- raise Invalid(u"Path '{}' is not a file.".format(path))
+ raise Invalid(u"Path '{}' is not a file (full path: {})."
+ u"".format(path, os.path.abspath(path)))
return value
@@ -816,6 +1020,10 @@ ENTITY_ID_CHARACTERS = 'abcdefghijklmnopqrstuvwxyz0123456789_'
def entity_id(value):
+ """Validate that this option represents a valid Home Assistant entity id.
+
+ Should only be used for 'homeassistant' platforms.
+ """
value = string_strict(value).lower()
if value.count('.') != 1:
raise Invalid("Entity ID must have exactly one dot in it")
@@ -827,20 +1035,30 @@ def entity_id(value):
def extract_keys(schema):
+ """Extract the names of the keys from the given schema."""
if isinstance(schema, Schema):
schema = schema.schema
assert isinstance(schema, dict)
- keys = list(schema.keys())
+ keys = []
+ for skey in list(schema.keys()):
+ if isinstance(skey, string_types):
+ keys.append(skey)
+ elif isinstance(skey, vol.Marker) and isinstance(skey.schema, string_types):
+ keys.append(skey.schema)
+ else:
+ raise ValueError()
keys.sort()
return keys
class GenerateID(Optional):
+ """Mark this key as being an auto-generated ID key."""
def __init__(self, key=CONF_ID):
super(GenerateID, self).__init__(key, default=lambda: None)
class SplitDefault(Optional):
+ """Mark this key to have a split default for ESP8266/ESP32."""
def __init__(self, key, esp8266=vol.UNDEFINED, esp32=vol.UNDEFINED):
super(SplitDefault, self).__init__(key)
self._esp8266_default = vol.default_factory(esp8266)
@@ -861,6 +1079,7 @@ class SplitDefault(Optional):
class OnlyWith(Optional):
+ """Set the default value only if the given component is loaded."""
def __init__(self, key, component, default=None):
super(OnlyWith, self).__init__(key)
self._component = component
@@ -878,56 +1097,70 @@ class OnlyWith(Optional):
pass
-def nameable(*schemas):
- def validator(config):
- config = All(*schemas)(config)
- if CONF_NAME not in config and CONF_ID not in config:
- print(config)
+def _nameable_validator(config):
+ if CONF_NAME not in config and CONF_ID not in config:
+ raise Invalid("At least one of 'id:' or 'name:' is required!")
+ if CONF_NAME not in config:
+ id = config[CONF_ID]
+ if not id.is_manual:
raise Invalid("At least one of 'id:' or 'name:' is required!")
- if CONF_NAME not in config:
- id = config[CONF_ID]
- if not id.is_manual:
- print(config)
- raise Invalid("At least one of 'id:' or 'name:' is required!")
- config[CONF_NAME] = id.id
- config[CONF_INTERNAL] = True
- return config
+ config[CONF_NAME] = id.id
+ config[CONF_INTERNAL] = True
return config
-
- return validator
+ return config
-def validate_registry_entry(name, registry, ignore_keys):
+def ensure_schema(schema):
+ if not isinstance(schema, vol.Schema):
+ return Schema(schema)
+ return schema
+
+
+def validate_registry_entry(name, registry):
+ base_schema = ensure_schema(registry.base_schema).extend({
+ Optional(CONF_TYPE_ID): valid,
+ }, extra=ALLOW_EXTRA)
+ ignore_keys = extract_keys(base_schema)
+
def validator(value):
if isinstance(value, string_types):
value = {value: {}}
if not isinstance(value, dict):
raise Invalid(u"{} must consist of key-value mapping! Got {}"
u"".format(name.title(), value))
- item = value.copy()
- key = next((x for x in item if x not in ignore_keys), None)
+ value = base_schema(value)
+ key = next((x for x in value if x not in ignore_keys), None)
if key is None:
- raise Invalid(u"Key missing from {}! Got {}".format(name, item))
+ raise Invalid(u"Key missing from {}! Got {}".format(name, value))
if key not in registry:
- raise vol.Invalid(u"Unable to find {} with the name '{}'".format(name, key))
- key2 = next((x for x in item if x != key and x not in ignore_keys), None)
+ raise Invalid(u"Unable to find {} with the name '{}'".format(name, key), [key])
+ key2 = next((x for x in value if x != key and x not in ignore_keys), None)
if key2 is not None:
- raise vol.Invalid(u"Cannot have two {0}s in one item. Key '{1}' overrides '{2}'! "
- u"Did you forget to indent the block inside the {0}?"
- u"".format(name, key, key2))
- validator_ = registry[key][0]
- try:
- item[key] = validator_(item[key] or {})
- except vol.Invalid as err:
- err.prepend([key])
- raise err
- return item
+ raise Invalid(u"Cannot have two {0}s in one item. Key '{1}' overrides '{2}'! "
+ u"Did you forget to indent the block inside the {0}?"
+ u"".format(name, key, key2))
+
+ if value[key] is None:
+ value[key] = {}
+
+ registry_entry = registry[key]
+
+ with prepend_path([key]):
+ value[key] = registry_entry.schema(value[key])
+
+ if registry_entry.type_id is not None:
+ my_base_schema = base_schema.extend({
+ GenerateID(CONF_TYPE_ID): declare_id(registry_entry.type_id)
+ })
+ value = my_base_schema(value)
+
+ return value
return validator
-def validate_registry(name, registry, ignore_keys):
- return ensure_list(validate_registry_entry(name, registry, ignore_keys))
+def validate_registry(name, registry):
+ return ensure_list(validate_registry_entry(name, registry))
def maybe_simple_value(*validators):
@@ -956,6 +1189,7 @@ MQTT_COMPONENT_SCHEMA = Schema({
Any(None, MQTT_COMPONENT_AVAILABILITY_SCHEMA)),
Optional(CONF_INTERNAL): boolean,
})
+MQTT_COMPONENT_SCHEMA.add_extra(_nameable_validator)
MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({
Optional(CONF_COMMAND_TOPIC): All(requires_component('mqtt'), subscribe_topic),
@@ -964,3 +1198,19 @@ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({
COMPONENT_SCHEMA = Schema({
Optional(CONF_SETUP_PRIORITY): float_
})
+
+
+def polling_component_schema(default_update_interval):
+ """Validate that this component represents a PollingComponent with a configurable
+ update_interval.
+
+ :param default_update_interval: The default update interval to set for the integration.
+ """
+ if default_update_interval is None:
+ return COMPONENT_SCHEMA.extend({
+ Required(CONF_UPDATE_INTERVAL): default_update_interval,
+ })
+ assert isinstance(default_update_interval, string_types)
+ return COMPONENT_SCHEMA.extend({
+ Optional(CONF_UPDATE_INTERVAL, default=default_update_interval): update_interval,
+ })
diff --git a/esphome/const.py b/esphome/const.py
index 5860a724b9..10e2781b44 100644
--- a/esphome/const.py
+++ b/esphome/const.py
@@ -327,6 +327,7 @@ CONF_REPOSITORY = 'repository'
CONF_RESET_PIN = 'reset_pin'
CONF_RESIZE = 'resize'
CONF_RESOLUTION = 'resolution'
+CONF_RESTORE = 'restore'
CONF_RESTORE_MODE = 'restore_mode'
CONF_RESTORE_STATE = 'restore_state'
CONF_RESTORE_VALUE = 'restore_value'
@@ -397,6 +398,7 @@ CONF_THEN = 'then'
CONF_THRESHOLD = 'threshold'
CONF_THROTTLE = 'throttle'
CONF_TILT = 'tilt'
+CONF_TIME = 'time'
CONF_TIMEOUT = 'timeout'
CONF_TIMES = 'times'
CONF_TIMEZONE = 'timezone'
@@ -414,6 +416,7 @@ CONF_TURN_ON_ACTION = 'turn_on_action'
CONF_TX_BUFFER_SIZE = 'tx_buffer_size'
CONF_TX_PIN = 'tx_pin'
CONF_TYPE = 'type'
+CONF_TYPE_ID = 'type_id'
CONF_UART_ID = 'uart_id'
CONF_UID = 'uid'
CONF_UNIQUE = 'unique'
@@ -448,6 +451,7 @@ ICON_BATTERY = 'mdi:battery'
ICON_BRIEFCASE_DOWNLOAD = 'mdi:briefcase-download'
ICON_BRIGHTNESS_5 = 'mdi:brightness-5'
ICON_CHEMICAL_WEAPON = 'mdi:chemical-weapon'
+ICON_EMPTY = ''
ICON_FLASH = 'mdi:flash'
ICON_FLOWER = 'mdi:flower'
ICON_GAS_CYLINDER = 'mdi:gas-cylinder'
@@ -460,6 +464,7 @@ ICON_PERIODIC_TABLE_CO2 = 'mdi:periodic-table-co2'
ICON_POWER = 'mdi:power'
ICON_PULSE = 'mdi:pulse'
ICON_RESTART = 'mdi:restart'
+ICON_ROTATE_RIGHT = 'mdi:rotate-right'
ICON_SCALE = 'mdi:scale'
ICON_SCREEN_ROTATION = 'mdi:screen-rotation'
ICON_SIGNAL = 'mdi:signal'
@@ -473,6 +478,7 @@ UNIT_CELSIUS = u'°C'
UNIT_DECIBEL = 'dB'
UNIT_DEGREES = u'°'
UNIT_DEGREE_PER_SECOND = u'°/s'
+UNIT_EMPTY = ''
UNIT_HECTOPASCAL = 'hPa'
UNIT_KELVIN = 'K'
UNIT_LUX = 'lx'
@@ -486,6 +492,7 @@ UNIT_PARTS_PER_MILLION = 'ppm'
UNIT_PERCENT = '%'
UNIT_PULSES_PER_MINUTE = 'pulses/min'
UNIT_SECOND = 's'
+UNIT_STEPS = 'steps'
UNIT_VOLT = 'V'
UNIT_WATT = 'W'
diff --git a/esphome/core.py b/esphome/core.py
index 1f2794aff4..464782368e 100644
--- a/esphome/core.py
+++ b/esphome/core.py
@@ -2,6 +2,7 @@ import functools
import heapq
import inspect
import logging
+
import math
import os
import re
@@ -136,18 +137,18 @@ class TimePeriod(object):
def __str__(self):
if self.microseconds is not None:
- return '{} us'.format(self.total_microseconds)
+ return '{}us'.format(self.total_microseconds)
if self.milliseconds is not None:
- return '{} ms'.format(self.total_milliseconds)
+ return '{}ms'.format(self.total_milliseconds)
if self.seconds is not None:
- return '{} s'.format(self.total_seconds)
+ return '{}s'.format(self.total_seconds)
if self.minutes is not None:
- return '{} min'.format(self.total_minutes)
+ return '{}min'.format(self.total_minutes)
if self.hours is not None:
- return '{} h'.format(self.total_hours)
+ return '{}h'.format(self.total_hours)
if self.days is not None:
- return '{} d'.format(self.total_days)
- return '0'
+ return '{}d'.format(self.total_days)
+ return '0s'
@property
def total_microseconds(self):
@@ -225,7 +226,11 @@ LAMBDA_PROG = re.compile(r'id\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)(\.?)')
class Lambda(object):
def __init__(self, value):
- self._value = value
+ # pylint: disable=protected-access
+ if isinstance(value, Lambda):
+ self._value = value._value
+ else:
+ self._value = value
self._parts = None
self._requires_ids = None
@@ -259,11 +264,14 @@ class Lambda(object):
class ID(object):
- def __init__(self, id, is_declaration=False, type=None):
+ def __init__(self, id, is_declaration=False, type=None, is_manual=None):
self.id = id
- self.is_manual = id is not None
+ if is_manual is None:
+ self.is_manual = id is not None
+ else:
+ self.is_manual = is_manual
self.is_declaration = is_declaration
- self.type = type
+ self.type = type # type: Optional[MockObjClass]
def resolve(self, registered_ids):
from esphome.config_validation import RESERVED_IDS
@@ -292,6 +300,46 @@ class ID(object):
def __hash__(self):
return hash(self.id)
+ def copy(self):
+ return ID(self.id, is_declaration=self.is_declaration, type=self.type,
+ is_manual=self.is_manual)
+
+
+class DocumentLocation(object):
+ def __init__(self, document, line, column):
+ # type: (basestring, int, int) -> None
+ self.document = document # type: basestring
+ self.line = line # type: int
+ self.column = column # type: int
+
+ @classmethod
+ def from_mark(cls, mark):
+ return cls(
+ mark.name,
+ mark.line,
+ mark.column
+ )
+
+ def __str__(self):
+ return u'{} {}:{}'.format(self.document, self.line, self.column)
+
+
+class DocumentRange(object):
+ def __init__(self, start_mark, end_mark):
+ # type: (DocumentLocation, DocumentLocation) -> None
+ self.start_mark = start_mark # type: DocumentLocation
+ self.end_mark = end_mark # type: DocumentLocation
+
+ @classmethod
+ def from_marks(cls, start_mark, end_mark):
+ return cls(
+ DocumentLocation.from_mark(start_mark),
+ DocumentLocation.from_mark(end_mark)
+ )
+
+ def __str__(self):
+ return u'[{} - {}]'.format(self.start_mark, self.end_mark)
+
class Define(object):
def __init__(self, name, value=None):
@@ -354,10 +402,13 @@ def coroutine_with_priority(priority):
return func
@functools.wraps(func)
- def wrapper(*args, **kwargs):
+ def _wrapper_generator(*args, **kwargs):
+ instance_id = kwargs.pop('__esphome_coroutine_instance__')
if not inspect.isgeneratorfunction(func):
# If func is not a generator, return result immediately
yield func(*args, **kwargs)
+ # pylint: disable=protected-access
+ CORE._remove_coroutine(instance_id)
return
gen = func(*args, **kwargs)
var = None
@@ -376,6 +427,18 @@ def coroutine_with_priority(priority):
except StopIteration:
# Stopping iteration
yield var
+ # pylint: disable=protected-access
+ CORE._remove_coroutine(instance_id)
+
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ import random
+ instance_id = random.randint(0, 2**32)
+ kwargs['__esphome_coroutine_instance__'] = instance_id
+ gen = _wrapper_generator(*args, **kwargs)
+ # pylint: disable=protected-access
+ CORE._add_active_coroutine(instance_id, gen)
+ return gen
# pylint: disable=protected-access
wrapper._esphome_coroutine = True
@@ -402,6 +465,8 @@ class EsphomeCore(object):
def __init__(self):
# True if command is run from dashboard
self.dashboard = False
+ # True if command is run from vscode api
+ self.vscode = False
# The name of the node
self.name = None # type: str
# The relative path to the configuration YAML
@@ -434,6 +499,11 @@ class EsphomeCore(object):
self.build_flags = set() # type: Set[str]
# A set of defines to set for the compile process in esphome/core/defines.h
self.defines = set() # type: Set[Define]
+ # A dictionary of started coroutines, used to warn when a coroutine was not
+ # awaited.
+ self.active_coroutines = {} # type: Dict[int, Any]
+ # A set of strings of names of loaded integrations, used to find namespace ID conflicts
+ self.loaded_integrations = set()
def reset(self):
self.dashboard = False
@@ -452,6 +522,8 @@ class EsphomeCore(object):
self.libraries = set()
self.build_flags = set()
self.defines = set()
+ self.active_coroutines = {}
+ self.loaded_integrations = set()
@property
def address(self): # type: () -> str
@@ -463,6 +535,12 @@ class EsphomeCore(object):
return None
+ def _add_active_coroutine(self, instance_id, obj):
+ self.active_coroutines[instance_id] = obj
+
+ def _remove_coroutine(self, instance_id):
+ self.active_coroutines.pop(instance_id)
+
@property
def arduino_version(self): # type: () -> str
return self.config[CONF_ESPHOME][CONF_ARDUINO_VERSION]
@@ -475,7 +553,7 @@ class EsphomeCore(object):
def config_filename(self):
return os.path.basename(self.config_path)
- def relative_path(self, *path):
+ def relative_config_path(self, *path):
path_ = os.path.expanduser(os.path.join(*path))
return os.path.join(self.config_dir, path_)
@@ -541,6 +619,14 @@ class EsphomeCore(object):
except StopIteration:
_LOGGER.debug(" -> finished")
+ # Print not-awaited coroutines
+ for obj in self.active_coroutines.values():
+ _LOGGER.warning(u"Coroutine '%s' %s was never awaited with 'yield'.", obj.__name__, obj)
+ _LOGGER.warning(u"Please file a bug report with your configuration.")
+ if self.active_coroutines:
+ raise EsphomeError()
+ self.active_coroutines.clear()
+
def add(self, expression):
from esphome.cpp_generator import Expression, Statement, statement
@@ -643,10 +729,21 @@ class EsphomeCore(object):
return u'\n'.join(global_code) + u'\n'
-class AutoLoad(dict):
+class AutoLoad(OrderedDict):
pass
+class EnumValue(object):
+ """Special type used by ESPHome to mark enum values for cv.enum."""
+ @property
+ def enum_value(self):
+ return getattr(self, '_enum_value', None)
+
+ @enum_value.setter
+ def enum_value(self, value):
+ setattr(self, '_enum_value', value)
+
+
CORE = EsphomeCore()
ConfigType = Dict[str, Any]
diff --git a/esphome/core/automation.cpp b/esphome/core/automation.cpp
deleted file mode 100644
index 4df8fc974e..0000000000
--- a/esphome/core/automation.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "esphome/core/automation.h"
-
-namespace esphome {
-
-static const char *TAG = "automation";
-
-void StartupTrigger::setup() { this->trigger(); }
-float StartupTrigger::get_setup_priority() const {
- // Run after everything is set up
- return this->setup_priority_;
-}
-StartupTrigger::StartupTrigger(float setup_priority) : setup_priority_(setup_priority) {}
-
-void ShutdownTrigger::on_shutdown() { this->trigger(); }
-
-void LoopTrigger::loop() { this->trigger(); }
-float LoopTrigger::get_setup_priority() const { return setup_priority::DATA; }
-
-RangeCondition::RangeCondition() = default;
-
-bool RangeCondition::check(float x) {
- float min = this->min_.value(x);
- float max = this->max_.value(x);
- if (isnan(min)) {
- return x >= max;
- } else if (isnan(max)) {
- return x >= min;
- } else {
- return min <= x && x <= max;
- }
-}
-
-} // namespace esphome
diff --git a/esphome/core/automation.h b/esphome/core/automation.h
index 5fac5b8888..7f79ab3ccd 100644
--- a/esphome/core/automation.h
+++ b/esphome/core/automation.h
@@ -13,91 +13,53 @@ namespace esphome {
TemplatableValue name##_{}; \
\
public: \
- template void set_##name(V value_) { this->name##_ = value_; }
+ template void set_##name(V name) { this->name##_ = name; }
#define TEMPLATABLE_VALUE(type, name) TEMPLATABLE_VALUE_(type, name)
+/** Base class for all automation conditions.
+ *
+ * @tparam Ts The template parameters to pass when executing.
+ */
template class Condition {
public:
+ /// Check whether this condition passes. This condition check must be instant, and not cause any delays.
virtual bool check(Ts... x) = 0;
- bool check_tuple(const std::tuple &tuple);
+ /// Call check with a tuple of values as parameter.
+ bool check_tuple(const std::tuple &tuple) {
+ return this->check_tuple_(tuple, typename gens::type());
+ }
protected:
- template bool check_tuple_(const std::tuple &tuple, seq);
-};
-
-template class AndCondition : public Condition {
- public:
- explicit AndCondition(const std::vector *> &conditions);
- bool check(Ts... x) override;
-
- protected:
- std::vector *> conditions_;
-};
-
-template class OrCondition : public Condition {
- public:
- explicit OrCondition(const std::vector *> &conditions);
- bool check(Ts... x) override;
-
- protected:
- std::vector *> conditions_;
-};
-
-template class LambdaCondition : public Condition {
- public:
- explicit LambdaCondition(std::function &&f);
- bool check(Ts... x) override;
-
- protected:
- std::function f_;
-};
-
-class RangeCondition : public Condition {
- public:
- explicit RangeCondition();
- bool check(float x) override;
-
- template void set_min(V value) { this->min_ = value; }
- template void set_max(V value) { this->max_ = value; }
-
- protected:
- TemplatableValue min_{NAN};
- TemplatableValue max_{NAN};
+ template bool check_tuple_(const std::tuple &tuple, seq) {
+ return this->check(std::get(tuple)...);
+ }
};
template class Automation;
template class Trigger {
public:
- void trigger(Ts... x);
- void set_parent(Automation *parent);
- void stop();
+ void trigger(Ts... x) {
+ if (this->automation_parent_ == nullptr)
+ return;
+ this->automation_parent_->trigger(x...);
+ }
+ void set_automation_parent(Automation *automation_parent) { this->automation_parent_ = automation_parent; }
+ void stop() {
+ if (this->automation_parent_ == nullptr)
+ return;
+ this->automation_parent_->stop();
+ }
+ bool is_running() {
+ if (this->automation_parent_ == nullptr)
+ return false;
+ return this->automation_parent_.is_running();
+ }
protected:
- Automation *parent_{nullptr};
-};
-
-class StartupTrigger : public Trigger<>, public Component {
- public:
- explicit StartupTrigger(float setup_priority = setup_priority::LATE);
- void setup() override;
- float get_setup_priority() const override;
-
- protected:
- float setup_priority_;
-};
-
-class ShutdownTrigger : public Trigger<>, public Component {
- public:
- void on_shutdown() override;
-};
-
-class LoopTrigger : public Trigger<>, public Component {
- public:
- void loop() override;
- float get_setup_priority() const override;
+ Automation *automation_parent_{nullptr};
};
template class ActionList;
@@ -105,137 +67,100 @@ template class ActionList;
template class Action {
public:
virtual void play(Ts... x) = 0;
- void play_next(Ts... x);
- virtual void stop();
- void stop_next();
+ virtual void play_complex(Ts... x) {
+ this->play(x...);
+ this->play_next(x...);
+ }
+ void play_next(Ts... x) {
+ if (this->next_ != nullptr) {
+ this->next_->play_complex(x...);
+ }
+ }
+ virtual void stop() {}
+ virtual void stop_complex() {
+ this->stop();
+ this->stop_next();
+ }
+ void stop_next() {
+ if (this->next_ != nullptr) {
+ this->next_->stop_complex();
+ }
+ }
+ virtual bool is_running() { return this->is_running_next(); }
+ bool is_running_next() {
+ if (this->next_ == nullptr)
+ return false;
+ return this->next_->is_running();
+ }
- void play_next_tuple(const std::tuple &tuple);
+ void play_next_tuple(const std::tuple &tuple) {
+ this->play_next_tuple_(tuple, typename gens::type());
+ }
protected:
friend ActionList;
- template void play_next_tuple_(const std::tuple &tuple, seq);
+ template void play_next_tuple_(const std::tuple &tuple, seq) {
+ this->play_next(std::get(tuple)...);
+ }
Action *next_ = nullptr;
};
-template class DelayAction : public Action, public Component {
- public:
- explicit DelayAction();
-
- template void set_delay(V value) { this->delay_ = value; }
- void stop() override;
-
- void play(Ts... x) override;
- float get_setup_priority() const override;
-
- protected:
- TemplatableValue delay_{0};
-};
-
-template class LambdaAction : public Action {
- public:
- explicit LambdaAction(std::function &&f);
- void play(Ts... x) override;
-
- protected:
- std::function f_;
-};
-
-template class IfAction : public Action {
- public:
- explicit IfAction(std::vector *> conditions);
-
- void add_then(const std::vector *> &actions);
-
- void add_else(const std::vector *> &actions);
-
- void play(Ts... x) override;
-
- void stop() override;
-
- protected:
- std::vector *> conditions_;
- ActionList then_;
- ActionList else_;
-};
-
-template class WhileAction : public Action {
- public:
- WhileAction(const std::vector *> &conditions);
-
- void add_then(const std::vector *> &actions);
-
- void play(Ts... x) override;
-
- void stop() override;
-
- protected:
- std::vector *> conditions_;
- ActionList then_;
- bool is_running_{false};
-};
-
-template class WaitUntilAction : public Action, public Component {
- public:
- WaitUntilAction(const std::vector *> &conditions);
-
- void play(Ts... x) override;
-
- void stop() override;
-
- void loop() override;
-
- float get_setup_priority() const override;
-
- protected:
- std::vector *> conditions_;
- bool triggered_{false};
- std::tuple var_{};
-};
-
-template class UpdateComponentAction : public Action {
- public:
- UpdateComponentAction(PollingComponent *component);
- void play(Ts... x) override;
-
- protected:
- PollingComponent *component_;
-};
-
template class ActionList {
public:
- Action *add_action(Action *action);
- void add_actions(const std::vector *> &actions);
- void play(Ts... x);
- void stop();
- bool empty() const;
+ void add_action(Action *action) {
+ if (this->actions_end_ == nullptr) {
+ this->actions_begin_ = action;
+ } else {
+ this->actions_end_->next_ = action;
+ }
+ this->actions_end_ = action;
+ }
+ void add_actions(const std::vector *> &actions) {
+ for (auto *action : actions) {
+ this->add_action(action);
+ }
+ }
+ void play(Ts... x) {
+ if (this->actions_begin_ != nullptr)
+ this->actions_begin_->play_complex(x...);
+ }
+ void play_tuple(const std::tuple &tuple) { this->play_tuple_(tuple, typename gens::type()); }
+ void stop() {
+ if (this->actions_begin_ != nullptr)
+ this->actions_begin_->stop_complex();
+ }
+ bool empty() const { return this->actions_begin_ == nullptr; }
+ bool is_running() {
+ if (this->actions_begin_ == nullptr)
+ return false;
+ return this->actions_begin_->is_running();
+ }
protected:
+ template void play_tuple_(const std::tuple &tuple, seq