1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-06 10:01:51 +00:00

Compare commits

...

67 Commits

Author SHA1 Message Date
Otto Winter
12c4b0788c Small fixes 2018-06-14 00:14:01 +02:00
Otto Winter
b13cc3a4a5 Fix lint 2018-06-13 23:01:50 +02:00
Otto Winter
c5d9bc5452 Bump version to 1.7.0 2018-06-13 22:56:49 +02:00
Otto Winter
6c6d21a7ab Allow simpler automation syntax 2018-06-13 21:27:58 +02:00
Otto Winter
9bb06782b2 Automate HassIO builds using Gitlab CI (#52)
* Add Gitlab CI

* Fix aarch64 edge build
2018-06-13 11:13:53 +02:00
Otto Winter
a827b51887 Add ESP32 BLE Beacon 2018-06-12 21:18:04 +02:00
Otto Winter
2c30d80490 Fix multi wifi validation 2018-06-11 16:13:46 +02:00
Otto Winter
e0acdc3ae0 Revert Multi Wifi 2018-06-11 15:22:03 +02:00
Otto Winter
36a3f96011 Fix RF receiver dumpers 2018-06-11 15:21:38 +02:00
Otto Winter
6ae8e3495f Add build_path option. Fixes#49 2018-06-11 10:12:44 +02:00
Otto Winter
6aa449115f Add internal modifier. Fixes ottowinter/esphomelib#77 2018-06-11 10:01:54 +02:00
Otto Winter
0be29d27d5 Fixes esphomelib#72 2018-06-08 20:33:14 +02:00
Otto Winter
68fa7489a2 Improve time config validation 2018-06-08 20:33:14 +02:00
Johan Bloemberg
d7699c93d6 Fix deprecation of board_flash_mode parameter (#41)
* Fix deprecation of board_flash_mode parameter

Fixes `Warning! `board_flash_mode` option is deprecated and will be removed in the next release! Please use `board_build.flash_mode` instead.`

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

View File

@@ -106,3 +106,4 @@ venv.bak/
config/ config/
examples/ examples/
Dockerfile Dockerfile
.git/

131
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,131 @@
---
# Based on https://gitlab.com/hassio-addons/addon-node-red/blob/master/.gitlab-ci.yml
variables:
DOCKER_DRIVER: overlay2
stages:
- lint
- build
- deploy
.lint: &lint
stage: lint
tags:
- python2.7
- esphomeyaml-lint
.hassio-builder: &hassio-builder
before_script:
- docker info
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
services:
- docker:dind
tags:
- hassio-builder
flake8:
<<: *lint
script:
- flake8 esphomeyaml
pylint:
<<: *lint
script:
- pylint esphomeyaml
.build: &build
<<: *hassio-builder
stage: build
script:
- |
hassio-builder.sh \
-t . \
-i ottowinter/esphomeyaml-hassio-${ADDON_ARCH} \
-d "$CI_REGISTRY" \
--${ADDON_ARCH}
- |
docker tag \
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:dev" \
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- docker push "${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- docker push "${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:dev"
# Generic deploy template
.deploy: &deploy
<<: *hassio-builder
stage: deploy
script:
- version=${CI_COMMIT_TAG:1}
- echo "Publishing version ${version}"
- docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
- docker pull "${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- |
docker tag \
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- |
docker tag \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
# Build jobs
build:armhf:
<<: *build
variables:
ADDON_ARCH: armhf
#build:aarch64:
# <<: *build
# variables:
# ADDON_ARCH: aarch64
build:i386:
<<: *build
variables:
ADDON_ARCH: i386
build:amd64:
<<: *build
variables:
ADDON_ARCH: amd64
# Deploy jobs
deploy:armhf:
<<: *deploy
variables:
ADDON_ARCH: armhf
only:
- /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/
except:
- /^(?!master).+@/
#deploy:aarch64:
# <<: *deploy
# variables:
# ADDON_ARCH: aarch64
# only:
# - /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/
# except:
# - /^(?!master).+@/
deploy:i386:
<<: *deploy
variables:
ADDON_ARCH: i386
only:
- /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/
except:
- /^(?!master).+@/
deploy:amd64:
<<: *deploy
variables:
ADDON_ARCH: amd64
only:
- /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/
except:
- /^(?!master).+@/

View File

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

20
docker/Dockerfile.aarch64 Normal file
View File

@@ -0,0 +1,20 @@
# Dockerfile for aarch64 version of HassIO add-on
FROM homeassistant/aarch64-base:latest
RUN apk add --no-cache \
python2 \
py2-pip \
git \
openssh \
libc6-compat \
&& \
pip install --no-cache-dir --no-binary :all: platformio && \
platformio settings set enable_telemetry No
COPY docker/platformio-esp8266.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
COPY . .
RUN pip install --no-cache-dir --no-binary :all: -e .
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

19
docker/Dockerfile.amd64 Normal file
View File

@@ -0,0 +1,19 @@
# Dockerfile for amd64 version of HassIO add-on
FROM ubuntu:bionic
RUN apt-get update && apt-get install -y --no-install-recommends \
python \
python-pip \
python-setuptools \
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 && \
platformio settings set enable_telemetry No
COPY docker/platformio.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
COPY . .
RUN pip install --no-cache-dir --no-binary :all: -e .
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

20
docker/Dockerfile.armhf Normal file
View File

@@ -0,0 +1,20 @@
# Dockerfile for armhf version of HassIO add-on
FROM homeassistant/armhf-base:latest
RUN apk add --no-cache \
python2 \
py2-pip \
git \
openssh \
libc6-compat \
&& \
pip install --no-cache-dir --no-binary :all: platformio && \
platformio settings set enable_telemetry No
COPY docker/platformio-esp8266.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
COPY . .
RUN pip install --no-cache-dir --no-binary :all: -e .
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

32
docker/Dockerfile.builder Normal file
View File

@@ -0,0 +1,32 @@
FROM multiarch/ubuntu-core:amd64-xenial
# setup locals
RUN apt-get update && apt-get install -y \
jq \
git \
python3-setuptools \
&& rm -rf /var/lib/apt/lists/* \
ENV LANG C.UTF-8
# Install docker
# https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
RUN apt-get update && apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
software-properties-common \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \
&& add-apt-repository "deb https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
&& apt-get update && apt-get install -y docker-ce \
&& rm -rf /var/lib/apt/lists/*
# setup arm binary support
RUN apt-get update && apt-get install -y \
qemu-user-static \
binfmt-support \
&& rm -rf /var/lib/apt/lists/*
COPY hassio-builder.sh /usr/bin/
WORKDIR /data

19
docker/Dockerfile.i386 Normal file
View File

@@ -0,0 +1,19 @@
# Dockerfile for i386 version of HassIO add-on
FROM i386/ubuntu:bionic
RUN apt-get update && apt-get install -y --no-install-recommends \
python \
python-pip \
python-setuptools \
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 && \
platformio settings set enable_telemetry No
COPY docker/platformio.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
COPY . .
RUN pip install --no-cache-dir --no-binary :all: -e .
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

4
docker/Dockerfile.lint Normal file
View File

@@ -0,0 +1,4 @@
FROM python:2.7
RUN pip install -r requirements.txt && \
pip install flake8==3.5.0 pylint==1.8.4

318
docker/hassio-builder.sh Executable file
View File

@@ -0,0 +1,318 @@
#!/usr/bin/env bash
# Based on Home Assistant's docker builder
######################
# Hass.io Build-env
######################
set -e
echo -- "$@"
#### Variable ####
DOCKER_TIMEOUT=20
DOCKER_PID=-1
DOCKER_HUB=""
DOCKER_CACHE="true"
DOCKER_LOCAL="false"
TARGET=""
IMAGE=""
BUILD_LIST=()
BUILD_TASKS=()
#### Misc functions ####
function print_help() {
cat << EOF
Hass.io build-env for ecosystem:
docker run --rm homeassistant/{arch}-builder:latest [options]
Options:
-h, --help
Display this help and exit.
Repository / Data
-t, --target <PATH_TO_BUILD>
Set local folder or path inside repository for build.
Version/Image handling
-i, --image <IMAGE_NAME>
Overwrite image name of build / support {arch}
Architecture
--armhf
Build for arm.
--amd64
Build for intel/amd 64bit.
--aarch64
Build for arm 64bit.
--i386
Build for intel/amd 32bit.
--all
Build all architecture.
Build handling
--no-cache
Disable cache for the build (from latest).
-d, --docker-hub <DOCKER_REPOSITORY>
Set or overwrite the docker repository.
Use the host docker socket if mapped into container:
/var/run/docker.sock
EOF
exit 1
}
#### Docker functions ####
function start_docker() {
local starttime
local endtime
if [ -S "/var/run/docker.sock" ]; then
echo "[INFO] Use host docker setup with '/var/run/docker.sock'"
DOCKER_LOCAL="true"
return 0
fi
echo "[INFO] Starting docker."
dockerd 2> /dev/null &
DOCKER_PID=$!
echo "[INFO] Waiting for docker to initialize..."
starttime="$(date +%s)"
endtime="$(date +%s)"
until docker info >/dev/null 2>&1; do
if [ $((endtime - starttime)) -le ${DOCKER_TIMEOUT} ]; then
sleep 1
endtime=$(date +%s)
else
echo "[ERROR] Timeout while waiting for docker to come up"
exit 1
fi
done
echo "[INFO] Docker was initialized"
}
function stop_docker() {
local starttime
local endtime
if [ "$DOCKER_LOCAL" == "true" ]; then
return 0
fi
echo "[INFO] Stopping in container docker..."
if [ "$DOCKER_PID" -gt 0 ] && kill -0 "$DOCKER_PID" 2> /dev/null; then
starttime="$(date +%s)"
endtime="$(date +%s)"
# Now wait for it to die
kill "$DOCKER_PID"
while kill -0 "$DOCKER_PID" 2> /dev/null; do
if [ $((endtime - starttime)) -le ${DOCKER_TIMEOUT} ]; then
sleep 1
endtime=$(date +%s)
else
echo "[ERROR] Timeout while waiting for container docker to die"
exit 1
fi
done
else
echo "[WARN] Your host might have been left with unreleased resources"
fi
}
function run_build() {
local build_dir=$1
local repository=$2
local image=$3
local version=$4
local build_arch=$5
local docker_cli=("${!6}")
local push_images=()
# Overwrites
if [ ! -z "$DOCKER_HUB" ]; then repository="$DOCKER_HUB"; fi
if [ ! -z "$IMAGE" ]; then image="$IMAGE"; fi
# Init Cache
if [ "$DOCKER_CACHE" == "true" ]; then
echo "[INFO] Init cache for $repository/$image:$version"
if docker pull "$repository/$image:latest" > /dev/null 2>&1; then
docker_cli+=("--cache-from" "$repository/$image:latest")
else
docker_cli+=("--no-cache")
echo "[WARN] No cache image found. Cache is disabled for build"
fi
else
docker_cli+=("--no-cache")
fi
# Build image
echo "[INFO] Run build for $repository/$image:$version"
docker build --pull -t "$repository/$image:$version" \
--label "io.hass.version=$version" \
--label "io.hass.arch=$build_arch" \
-f "$TARGET/docker/Dockerfile.$build_arch" \
"${docker_cli[@]}" \
"$build_dir"
echo "[INFO] Finish build for $repository/$image:$version"
docker tag "$repository/$image:$version" "$repository/$image:dev"
}
#### HassIO functions ####
function build_addon() {
local build_arch=$1
local docker_cli=()
local image=""
local repository=""
local raw_image=""
local name=""
local description=""
local url=""
local args=""
# Read addon config.json
name="$(jq --raw-output '.name // empty' "$TARGET/esphomeyaml/config.json" | sed "s/'//g")"
description="$(jq --raw-output '.description // empty' "$TARGET/esphomeyaml/config.json" | sed "s/'//g")"
url="$(jq --raw-output '.url // empty' "$TARGET/esphomeyaml/config.json")"
version="$(jq --raw-output '.version' "$TARGET/esphomeyaml/config.json")"
raw_image="$(jq --raw-output '.image // empty' "$TARGET/esphomeyaml/config.json")"
# Read data from image
if [ ! -z "$raw_image" ]; then
repository="$(echo "$raw_image" | cut -f 1 -d '/')"
image="$(echo "$raw_image" | cut -f 2 -d '/')"
fi
# Set additional labels
docker_cli+=("--label" "io.hass.name=$name")
docker_cli+=("--label" "io.hass.description=$description")
docker_cli+=("--label" "io.hass.type=addon")
if [ ! -z "$url" ]; then
docker_cli+=("--label" "io.hass.url=$url")
fi
# Start build
run_build "$TARGET" "$repository" "$image" "$version" \
"$build_arch" docker_cli[@]
}
#### initialized cross-build ####
function init_crosscompile() {
echo "[INFO] Setup crosscompiling feature"
(
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
update-binfmts --enable qemu-arm
update-binfmts --enable qemu-aarch64
) > /dev/null 2>&1 || echo "[WARN] Can't enable crosscompiling feature"
}
function clean_crosscompile() {
echo "[INFO] Clean crosscompiling feature"
if [ -f /proc/sys/fs/binfmt_misc ]; then
umount /proc/sys/fs/binfmt_misc || true
fi
(
update-binfmts --disable qemu-arm
update-binfmts --disable qemu-aarch64
) > /dev/null 2>&1 || echo "[WARN] No crosscompiling feature found for cleanup"
}
#### Error handling ####
function error_handling() {
stop_docker
clean_crosscompile
exit 1
}
trap 'error_handling' SIGINT SIGTERM
#### Parse arguments ####
while [[ $# -gt 0 ]]; do
key=$1
case ${key} in
-h|--help)
print_help
;;
-t|--target)
TARGET=$2
shift
;;
-i|--image)
IMAGE=$2
shift
;;
--no-cache)
DOCKER_CACHE="false"
;;
-d|--docker-hub)
DOCKER_HUB=$2
shift
;;
--armhf)
BUILD_LIST+=("armhf")
;;
--amd64)
BUILD_LIST+=("amd64")
;;
--i386)
BUILD_LIST+=("i386")
;;
--aarch64)
BUILD_LIST+=("aarch64")
;;
--all)
BUILD_LIST=("armhf" "amd64" "i386" "aarch64")
;;
*)
echo "[WARN] $0 : Argument '$1' unknown will be Ignoring"
;;
esac
shift
done
# Check if an architecture is available
if [ "${#BUILD_LIST[@]}" -eq 0 ]; then
echo "[ERROR] You need select an architecture for build!"
exit 1
fi
#### Main ####
mkdir -p /data
# Setup docker env
init_crosscompile
start_docker
# Select arch build
for arch in "${BUILD_LIST[@]}"; do
(build_addon "$arch") &
BUILD_TASKS+=($!)
done
# Wait until all build jobs are done
wait "${BUILD_TASKS[@]}"
# Cleanup docker env
clean_crosscompile
stop_docker
exit 0

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,20 +0,0 @@
# Dockerfile for HassIO add-on
ARG BUILD_FROM
FROM $BUILD_FROM
ENV LANG C.UTF-8
# Install requirements for add-on
RUN apk add --no-cache python2 py2-pip git openssh libc6-compat && \
pip install --no-cache-dir platformio && \
platformio platform install espressif8266 \
--with-package tool-esptool \
--with-package framework-arduinoespressif8266 \
--with-package tool-mkspiffs \
--with-package tool-espotapy
RUN pip install --no-cache-dir \
git+git://github.com/OttoWinter/esphomeyaml.git@v1.6.0 \
tornado esptool
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

View File

@@ -1,19 +1,20 @@
from __future__ import print_function from __future__ import print_function
import argparse import argparse
from datetime import datetime
import logging import logging
import os import os
import random import random
import sys import sys
from datetime import datetime
from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util
from esphomeyaml.config import core_to_code, get_component, iter_components, read_config from esphomeyaml.config import core_to_code, get_component, iter_components, read_config
from esphomeyaml.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, CONF_HOSTNAME, \ from esphomeyaml.const import CONF_BAUD_RATE, CONF_BUILD_PATH, CONF_DOMAIN, CONF_ESPHOMEYAML, \
CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, ESP_PLATFORM_ESP8266 CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, \
ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \ from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \
add_task, color, get_variable, indent, quote, statement add_job, color, flush_tasks, indent, quote, statement
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -25,7 +26,8 @@ def get_name(config):
def get_base_path(config): def get_base_path(config):
return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config)) build_path = config[CONF_ESPHOMEYAML].get(CONF_BUILD_PATH, get_name(config))
return os.path.join(os.path.dirname(core.CONFIG_PATH), build_path)
def get_serial_ports(): def get_serial_ports():
@@ -102,40 +104,34 @@ def run_miniterm(config, port, escape=False):
with serial.Serial(port, baudrate=baud_rate) as ser: with serial.Serial(port, baudrate=baud_rate) as ser:
while True: while True:
line = ser.readline() line = ser.readline().replace('\r', '').replace('\n', '')
time = datetime.now().time().strftime('[%H:%M:%S]') time = datetime.now().time().strftime('[%H:%M:%S]')
message = time + line.decode('unicode-escape').replace('\r', '').replace('\n', '') message = time + line
if escape: if escape:
message = message.replace('\033', '\\033').encode('ascii', 'replace') message = message.replace('\033', '\\033')
print(message) try:
print(message)
except UnicodeEncodeError:
print(message.encode('ascii', 'backslashreplace'))
def write_cpp(config): def write_cpp(config):
_LOGGER.info("Generating C++ source...") _LOGGER.info("Generating C++ source...")
add_task(core_to_code, config[CONF_ESPHOMEYAML]) add_job(core_to_code, config[CONF_ESPHOMEYAML], domain='esphomeyaml')
for domain in PRE_INITIALIZE: for domain in PRE_INITIALIZE:
if domain == CONF_ESPHOMEYAML: if domain == CONF_ESPHOMEYAML or domain not in config:
continue continue
if domain in config: add_job(get_component(domain).to_code, config[domain], domain=domain)
add_task(get_component(domain).to_code, config[domain])
# Clear queue
get_variable(None)
add(RawStatement(''))
for domain, component, conf in iter_components(config): for domain, component, conf in iter_components(config):
if domain in PRE_INITIALIZE: if domain in PRE_INITIALIZE or not hasattr(component, 'to_code'):
continue continue
if not hasattr(component, 'to_code'): add_job(component.to_code, conf, domain=domain)
continue
add_task(component.to_code, conf)
# Clear queue flush_tasks()
get_variable(None)
add(RawStatement('')) add(RawStatement(''))
add(RawStatement('')) add(RawStatement(''))
all_code = [] all_code = []
for exp in _EXPRESSIONS: for exp in _EXPRESSIONS:
if core.SIMPLIFY: if core.SIMPLIFY:
@@ -147,9 +143,7 @@ def write_cpp(config):
exp = exp.rhs exp = exp.rhs
all_code.append(unicode(statement(exp))) all_code.append(unicode(statement(exp)))
platformio_ini_s = writer.get_ini_content(config) writer.write_platformio_project(config, get_base_path(config))
ini_path = os.path.join(get_base_path(config), 'platformio.ini')
writer.write_platformio_ini(platformio_ini_s, ini_path)
code_s = indent('\n'.join(line.rstrip() for line in all_code)) code_s = indent('\n'.join(line.rstrip() for line in all_code))
cpp_path = os.path.join(get_base_path(config), 'src', 'main.cpp') cpp_path = os.path.join(get_base_path(config), 'src', 'main.cpp')
@@ -157,9 +151,12 @@ def write_cpp(config):
return 0 return 0
def compile_program(config): def compile_program(args, config):
_LOGGER.info("Compiling app...") _LOGGER.info("Compiling app...")
return run_platformio('platformio', 'run', '-d', get_base_path(config)) command = ['platformio', 'run', '-d', get_base_path(config)]
if args.verbose:
command.append('-v')
return run_platformio(*command)
def get_upload_host(config): def get_upload_host(config):
@@ -185,17 +182,28 @@ def upload_using_esptool(config, port):
def upload_program(config, args, port): def upload_program(config, args, port):
_LOGGER.info("Uploading binary...") _LOGGER.info("Uploading binary...")
if port != 'OTA':
# if upload is to a serial port use platformio, otherwise assume ota
serial_port = port.startswith('/') or port.startswith('COM')
if port != 'OTA' and serial_port:
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy: if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy:
return upload_using_esptool(config, port) return upload_using_esptool(config, port)
return run_platformio('platformio', 'run', '-d', get_base_path(config), command = ['platformio', 'run', '-d', get_base_path(config),
'-t', 'upload', '--upload-port', port) '-t', 'upload', '--upload-port', port]
if args.verbose:
command.append('-v')
return run_platformio(*command)
if 'ota' not in config: if 'ota' not in config:
_LOGGER.error("No serial port found and OTA not enabled. Can't upload!") _LOGGER.error("No serial port found and OTA not enabled. Can't upload!")
return -1 return -1
host = get_upload_host(config) # If hostname/ip is explicitly provided as upload-port argument, use this instead of zeroconf
# hostname. This is to support use cases where zeroconf (hostname.local) does not work.
if port != 'OTA':
host = port
else:
host = get_upload_host(config)
from esphomeyaml.components import ota from esphomeyaml.components import ota
from esphomeyaml import espota from esphomeyaml import espota
@@ -208,11 +216,14 @@ def upload_program(config, args, port):
espota_args = ['espota.py', '--debug', '--progress', '-i', host, espota_args = ['espota.py', '--debug', '--progress', '-i', host,
'-p', str(ota.get_port(config)), '-f', bin_file, '-p', str(ota.get_port(config)), '-f', bin_file,
'-a', ota.get_auth(config), '-P', str(host_port)] '-a', ota.get_auth(config), '-P', str(host_port)]
if args.verbose:
espota_args.append('-d')
return espota.main(espota_args) return espota.main(espota_args)
def show_logs(config, args, port, escape=False): def show_logs(config, args, port, escape=False):
if port != 'OTA': serial_port = port.startswith('/') or port.startswith('COM')
if port != 'OTA' and serial_port:
run_miniterm(config, port, escape=escape) run_miniterm(config, port, escape=escape)
return 0 return 0
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id, return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id,
@@ -223,8 +234,9 @@ def clean_mqtt(config, args):
return mqtt.clear_topic(config, args.topic, args.username, args.password, args.client_id) return mqtt.clear_topic(config, args.topic, args.username, args.password, args.client_id)
def setup_log(): def setup_log(debug=False):
logging.basicConfig(level=logging.INFO) log_level = logging.DEBUG if debug else logging.INFO
logging.basicConfig(level=log_level)
fmt = "%(levelname)s [%(name)s] %(message)s" fmt = "%(levelname)s [%(name)s] %(message)s"
colorfmt = "%(log_color)s{}%(reset)s".format(fmt) colorfmt = "%(log_color)s{}%(reset)s".format(fmt)
datefmt = '%H:%M:%S' datefmt = '%H:%M:%S'
@@ -253,7 +265,28 @@ def command_wizard(args):
return wizard.wizard(args.configuration) return wizard.wizard(args.configuration)
def strip_default_ids(config):
value = config
if isinstance(config, list):
value = type(config)()
for x in config:
if isinstance(x, core.ID) and not x.is_manual:
continue
value.append(strip_default_ids(x))
return value
elif isinstance(config, dict):
value = type(config)()
for k, v in config.iteritems():
if isinstance(v, core.ID) and not v.is_manual:
continue
value[k] = strip_default_ids(v)
return value
return value
def command_config(args, config): def command_config(args, config):
if not args.verbose:
config = strip_default_ids(config)
print(yaml_util.dump(config)) print(yaml_util.dump(config))
return 0 return 0
@@ -262,7 +295,7 @@ def command_compile(args, config):
exit_code = write_cpp(config) exit_code = write_cpp(config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
exit_code = compile_program(config) exit_code = compile_program(args, config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info(u"Successfully compiled program.") _LOGGER.info(u"Successfully compiled program.")
@@ -287,7 +320,7 @@ def command_run(args, config):
exit_code = write_cpp(config) exit_code = write_cpp(config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
exit_code = compile_program(config) exit_code = compile_program(args, config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info(u"Successfully compiled program.") _LOGGER.info(u"Successfully compiled program.")
@@ -339,6 +372,8 @@ POST_CONFIG_ACTIONS = {
def parse_args(argv): def parse_args(argv):
parser = argparse.ArgumentParser(prog='esphomeyaml') parser = argparse.ArgumentParser(prog='esphomeyaml')
parser.add_argument('-v', '--verbose', help="Enable verbose esphomeyaml logs.",
action='store_true')
parser.add_argument('configuration', help='Your YAML configuration file.') parser.add_argument('configuration', help='Your YAML configuration file.')
subparsers = parser.add_subparsers(help='Commands', dest='command') subparsers = parser.add_subparsers(help='Commands', dest='command')
@@ -369,7 +404,7 @@ def parse_args(argv):
parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, ' parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, '
'upload it, and start MQTT logs.') 'upload it, and start MQTT logs.')
parser_run.add_argument('--upload-port', help="Manually specify the upload port to use. " parser_run.add_argument('--upload-port', help="Manually specify the upload port/ip to use. "
"For example /dev/cu.SLAB_USBtoUART.") "For example /dev/cu.SLAB_USBtoUART.")
parser_run.add_argument('--host-port', help="Specify the host port to use for OTA", type=int) parser_run.add_argument('--host-port', help="Specify the host port to use for OTA", type=int)
parser_run.add_argument('--no-logs', help='Disable starting MQTT logs.', parser_run.add_argument('--no-logs', help='Disable starting MQTT logs.',
@@ -402,13 +437,15 @@ def parse_args(argv):
help="Create a simple webserver for a dashboard.") help="Create a simple webserver for a dashboard.")
dashboard.add_argument("--port", help="The HTTP port to open connections on.", type=int, dashboard.add_argument("--port", help="The HTTP port to open connections on.", type=int,
default=6052) default=6052)
dashboard.add_argument("--password", help="The optional password to require for all requests.",
type=str, default='')
return parser.parse_args(argv[1:]) return parser.parse_args(argv[1:])
def run_esphomeyaml(argv): def run_esphomeyaml(argv):
setup_log()
args = parse_args(argv) args = parse_args(argv)
setup_log(args.verbose)
if args.command in PRE_CONFIG_ACTIONS: if args.command in PRE_CONFIG_ACTIONS:
try: try:
return PRE_CONFIG_ACTIONS[args.command](args) return PRE_CONFIG_ACTIONS[args.command](args)

View File

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

View File

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

View File

@@ -2,10 +2,12 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import automation from esphomeyaml import automation
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INVERTED, CONF_MAX_LENGTH, \ from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INTERNAL, CONF_INVERTED, \
CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, CONF_ON_PRESS, \ CONF_MAX_LENGTH, CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, \
CONF_ON_RELEASE, CONF_TRIGGER_ID CONF_ON_PRESS, CONF_ON_RELEASE, CONF_TRIGGER_ID, CONF_FILTERS, CONF_INVERT, CONF_DELAYED_ON, \
from esphomeyaml.helpers import App, NoArg, Pvariable, add, esphomelib_ns, setup_mqtt_component CONF_DELAYED_OFF, CONF_LAMBDA
from esphomeyaml.helpers import App, NoArg, Pvariable, add, add_job, esphomelib_ns, \
setup_mqtt_component, bool_, process_lambda, ArrayInitializer
DEVICE_CLASSES = [ DEVICE_CLASSES = [
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas', '', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
@@ -24,72 +26,129 @@ ReleaseTrigger = binary_sensor_ns.ReleaseTrigger
ClickTrigger = binary_sensor_ns.ClickTrigger ClickTrigger = binary_sensor_ns.ClickTrigger
DoubleClickTrigger = binary_sensor_ns.DoubleClickTrigger DoubleClickTrigger = binary_sensor_ns.DoubleClickTrigger
BinarySensor = binary_sensor_ns.BinarySensor BinarySensor = binary_sensor_ns.BinarySensor
InvertFilter = binary_sensor_ns.InvertFilter
LambdaFilter = binary_sensor_ns.LambdaFilter
DelayedOnFilter = binary_sensor_ns.DelayedOnFilter
DelayedOffFilter = binary_sensor_ns.DelayedOffFilter
MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent
FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA]
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_INVERT): None,
vol.Optional(CONF_DELAYED_ON): cv.positive_time_period_milliseconds,
vol.Optional(CONF_DELAYED_OFF): cv.positive_time_period_milliseconds,
vol.Optional(CONF_LAMBDA): cv.lambda_,
}, cv.has_exactly_one_key(*FILTER_KEYS))])
BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
cv.GenerateID('mqtt_binary_sensor', CONF_MQTT_ID): cv.register_variable_id, cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTBinarySensorComponent),
cv.GenerateID('binary_sensor'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(BinarySensor),
vol.Optional(CONF_INVERTED): cv.boolean,
vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower, cv.one_of(*DEVICE_CLASSES)), vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower, cv.one_of(*DEVICE_CLASSES)),
vol.Optional(CONF_ON_PRESS): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), vol.Optional(CONF_FILTERS): FILTERS_SCHEMA,
vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]), vol.Optional(CONF_ON_PRESS): vol.All(cv.ensure_list, [automation.validate_automation({
vol.Optional(CONF_ON_CLICK): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(PressTrigger),
})]),
vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ReleaseTrigger),
})]),
vol.Optional(CONF_ON_CLICK): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ClickTrigger),
vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds, vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds,
vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds, vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
})]), })]),
vol.Optional(CONF_ON_DOUBLE_CLICK): vol.Optional(CONF_ON_DOUBLE_CLICK):
vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(DoubleClickTrigger),
vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds, vol.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds,
vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds, vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
})]), })]),
vol.Optional(CONF_INVERTED): cv.invalid(
"The inverted binary_sensor property has been replaced by the "
"new 'invert' binary sensor filter. Please see "
"https://esphomelib.com/esphomeyaml/components/binary_sensor/index.html."
),
}) })
BINARY_SENSOR_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(BINARY_SENSOR_SCHEMA.schema)
def setup_filter(config):
if CONF_INVERT in config:
yield InvertFilter.new()
elif CONF_DELAYED_OFF in config:
yield App.register_component(DelayedOffFilter.new(config[CONF_DELAYED_OFF]))
elif CONF_DELAYED_ON in config:
yield App.register_component(DelayedOnFilter.new(config[CONF_DELAYED_ON]))
elif CONF_LAMBDA in config:
lambda_ = None
for lambda_ in process_lambda(config[CONF_LAMBDA], [(bool_, 'x')]):
yield None
yield LambdaFilter.new(lambda_)
def setup_filters(config):
filters = []
for conf in config:
filter = None
for filter in setup_filter(conf):
yield None
filters.append(filter)
yield ArrayInitializer(*filters)
def setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config): def setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config):
if CONF_INTERNAL in config:
add(binary_sensor_var.set_internal(CONF_INTERNAL))
if CONF_DEVICE_CLASS in config: if CONF_DEVICE_CLASS in config:
add(binary_sensor_var.set_device_class(config[CONF_DEVICE_CLASS])) add(binary_sensor_var.set_device_class(config[CONF_DEVICE_CLASS]))
if CONF_INVERTED in config: if CONF_INVERTED in config:
add(binary_sensor_var.set_inverted(config[CONF_INVERTED])) add(binary_sensor_var.set_inverted(config[CONF_INVERTED]))
if CONF_FILTERS in config:
filters = None
for filters in setup_filters(config[CONF_FILTERS]):
yield
add(binary_sensor_var.add_filters(filters))
for conf in config.get(CONF_ON_PRESS, []): for conf in config.get(CONF_ON_PRESS, []):
rhs = binary_sensor_var.make_press_trigger() rhs = binary_sensor_var.make_press_trigger()
trigger = Pvariable(PressTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_RELEASE, []): for conf in config.get(CONF_ON_RELEASE, []):
rhs = binary_sensor_var.make_release_trigger() rhs = binary_sensor_var.make_release_trigger()
trigger = Pvariable(ReleaseTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_CLICK, []): for conf in config.get(CONF_ON_CLICK, []):
rhs = binary_sensor_var.make_click_trigger(conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH]) rhs = binary_sensor_var.make_click_trigger(conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH])
trigger = Pvariable(ClickTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_DOUBLE_CLICK, []): for conf in config.get(CONF_ON_DOUBLE_CLICK, []):
rhs = binary_sensor_var.make_double_click_trigger(conf[CONF_MIN_LENGTH], rhs = binary_sensor_var.make_double_click_trigger(conf[CONF_MIN_LENGTH],
conf[CONF_MAX_LENGTH]) conf[CONF_MAX_LENGTH])
trigger = Pvariable(DoubleClickTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf) automation.build_automation(trigger, NoArg, conf)
setup_mqtt_component(mqtt_var, config) setup_mqtt_component(mqtt_var, config)
def setup_binary_sensor(binary_sensor_obj, mqtt_obj, config): def setup_binary_sensor(binary_sensor_obj, mqtt_obj, config):
binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], binary_sensor_obj, binary_sensor_var = Pvariable(config[CONF_ID], binary_sensor_obj,
has_side_effects=False) has_side_effects=False)
mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj,
has_side_effects=False) has_side_effects=False)
setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config) add_job(setup_binary_sensor_core_, binary_sensor_var, mqtt_var, config)
def register_binary_sensor(var, config): def register_binary_sensor(var, config):
binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], var, binary_sensor_var = Pvariable(config[CONF_ID], var, has_side_effects=True)
has_side_effects=True)
rhs = App.register_binary_sensor(binary_sensor_var) rhs = App.register_binary_sensor(binary_sensor_var)
mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], rhs, mqtt_var = Pvariable(config[CONF_MQTT_ID], rhs, has_side_effects=True)
has_side_effects=True) add_job(setup_binary_sensor_core_, binary_sensor_var, mqtt_var, config)
setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_BINARY_SENSOR'

View File

@@ -1,43 +0,0 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor
from esphomeyaml.components.esp32_ble import ESP32BLETracker
from esphomeyaml.const import CONF_MAC_ADDRESS, CONF_NAME, ESP_PLATFORM_ESP32
from esphomeyaml.core import HexInt, MACAddress
from esphomeyaml.helpers import ArrayInitializer, get_variable
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_ble']
def validate_mac(value):
value = cv.string_strict(value)
parts = value.split(':')
if len(parts) != 6:
raise vol.Invalid("MAC Address must consist of 6 : (colon) separated parts")
parts_int = []
if any(len(part) != 2 for part in parts):
raise vol.Invalid("MAC Address must be format XX:XX:XX:XX:XX:XX")
for part in parts:
try:
parts_int.append(int(part, 16))
except ValueError:
raise vol.Invalid("MAC Address parts must be hexadecimal values from 00 to FF")
return MACAddress(*parts_int)
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
vol.Required(CONF_MAC_ADDRESS): validate_mac,
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config):
hub = get_variable(None, type=ESP32BLETracker)
addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts]
rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False))
binary_sensor.register_binary_sensor(rhs, config)
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

@@ -0,0 +1,30 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor
from esphomeyaml.components.esp32_ble_tracker import ESP32BLETracker
from esphomeyaml.const import CONF_MAC_ADDRESS, CONF_NAME, ESP_PLATFORM_ESP32
from esphomeyaml.core import HexInt
from esphomeyaml.helpers import ArrayInitializer, get_variable
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_ble_tracker']
CONF_ESP32_BLE_ID = 'esp32_ble_id'
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
vol.Required(CONF_MAC_ADDRESS): cv.mac_address,
cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_variable_id(ESP32BLETracker)
}))
def to_code(config):
hub = None
for hub in get_variable(config[CONF_ESP32_BLE_ID]):
yield
addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts]
rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False))
binary_sensor.register_binary_sensor(rhs, config)
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

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

View File

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

View File

@@ -0,0 +1,77 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor
from esphomeyaml.components.remote_receiver import RemoteReceiverComponent, remote_ns
from esphomeyaml.const import CONF_ADDRESS, CONF_COMMAND, CONF_DATA, \
CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, CONF_PANASONIC, CONF_RAW, CONF_SONY
from esphomeyaml.helpers import ArrayInitializer, Pvariable, get_variable
DEPENDENCIES = ['remote_receiver']
IR_KEYS = [CONF_NEC, CONF_LG, CONF_SONY, CONF_PANASONIC, CONF_RAW]
CONF_REMOTE_RECEIVER_ID = 'remote_receiver_id'
CONF_RECEIVER_ID = 'receiver_id'
RemoteReceiver = remote_ns.RemoteReceiver
LGReceiver = remote_ns.LGReceiver
NECReceiver = remote_ns.NECReceiver
PanasonicReceiver = remote_ns.PanasonicReceiver
RawReceiver = remote_ns.RawReceiver
SonyReceiver = remote_ns.SonyReceiver
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_LG): vol.Schema({
vol.Required(CONF_DATA): cv.hex_uint32_t,
vol.Optional(CONF_NBITS, default=28): vol.All(vol.Coerce(int), cv.one_of(28, 32)),
}),
vol.Optional(CONF_NEC): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint16_t,
}),
vol.Optional(CONF_SONY): vol.Schema({
vol.Required(CONF_DATA): cv.hex_uint32_t,
vol.Optional(CONF_NBITS, default=12): vol.All(vol.Coerce(int), cv.one_of(12, 15, 20)),
}),
vol.Optional(CONF_PANASONIC): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint32_t,
}),
vol.Optional(CONF_RAW): [vol.Any(vol.Coerce(int), cv.time_period_microseconds)],
cv.GenerateID(CONF_REMOTE_RECEIVER_ID): cv.use_variable_id(RemoteReceiverComponent),
cv.GenerateID(CONF_RECEIVER_ID): cv.declare_variable_id(RemoteReceiver),
}), cv.has_exactly_one_key(*IR_KEYS))
def receiver_base(config):
if CONF_LG in config:
conf = config[CONF_LG]
return LGReceiver.new(config[CONF_NAME], conf[CONF_DATA], conf[CONF_NBITS])
elif CONF_NEC in config:
conf = config[CONF_NEC]
return NECReceiver.new(config[CONF_NAME], conf[CONF_ADDRESS], conf[CONF_COMMAND])
elif CONF_PANASONIC in config:
conf = config[CONF_PANASONIC]
return PanasonicReceiver.new(config[CONF_NAME], conf[CONF_ADDRESS], conf[CONF_COMMAND])
elif CONF_SONY in config:
conf = config[CONF_SONY]
return SonyReceiver.new(config[CONF_NAME], conf[CONF_DATA], conf[CONF_NBITS])
elif CONF_RAW in config:
data = ArrayInitializer(*config[CONF_RAW], multiline=False)
return RawReceiver.new(config[CONF_NAME], data)
else:
raise ValueError("Unknown receiver type {}".format(config))
def to_code(config):
remote = None
for remote in get_variable(config[CONF_REMOTE_RECEIVER_ID]):
yield
rhs = receiver_base(config)
receiver = Pvariable(config[CONF_RECEIVER_ID], rhs)
binary_sensor.register_binary_sensor(remote.add_decoder(receiver), config)
BUILD_FLAGS = '-DUSE_REMOTE_RECEIVER'

View File

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

View File

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

View File

@@ -1,16 +1,11 @@
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_MQTT_ID from esphomeyaml.const import CONF_ID, CONF_MQTT_ID, CONF_INTERNAL
from esphomeyaml.helpers import Pvariable, esphomelib_ns, setup_mqtt_component from esphomeyaml.helpers import Pvariable, esphomelib_ns, setup_mqtt_component, add
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('cover'): cv.register_variable_id,
cv.GenerateID('mqtt_cover', CONF_MQTT_ID): cv.register_variable_id,
})
cover_ns = esphomelib_ns.namespace('cover') cover_ns = esphomelib_ns.namespace('cover')
Cover = cover_ns.Cover Cover = cover_ns.Cover
MQTTCoverComponent = cover_ns.MQTTCoverComponent MQTTCoverComponent = cover_ns.MQTTCoverComponent
@@ -21,15 +16,23 @@ OpenAction = cover_ns.OpenAction
CloseAction = cover_ns.CloseAction CloseAction = cover_ns.CloseAction
StopAction = cover_ns.StopAction StopAction = cover_ns.StopAction
COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(Cover),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTCoverComponent),
})
COVER_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(COVER_SCHEMA.schema)
def setup_cover_core_(cover_var, mqtt_var, config): def setup_cover_core_(cover_var, mqtt_var, config):
if CONF_INTERNAL in config:
add(cover_var.set_internal(config[CONF_INTERNAL]))
setup_mqtt_component(mqtt_var, config) setup_mqtt_component(mqtt_var, config)
def setup_cover(cover_obj, mqtt_obj, config): def setup_cover(cover_obj, mqtt_obj, config):
cover_var = Pvariable(Cover, config[CONF_ID], cover_obj, has_side_effects=False) cover_var = Pvariable(config[CONF_ID], cover_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTCoverComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False)
setup_cover_core_(cover_var, mqtt_var, config) setup_cover_core_(cover_var, mqtt_var, config)

View File

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

View File

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

View File

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

View File

@@ -1,24 +1,5 @@
import voluptuous as vol
from esphomeyaml import config_validation as cv from esphomeyaml import config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] CONFIG_SCHEMA = cv.invalid("The 'esp32_ble' component has been renamed to the 'esp32_ble_tracker' "
"component in order to avoid confusion with the new 'esp32_ble_beacon' "
CONFIG_SCHEMA = vol.Schema({ "component.")
cv.GenerateID('esp32_ble'): cv.register_variable_id,
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds,
})
ESP32BLETracker = esphomelib_ns.ESP32BLETracker
def to_code(config):
rhs = App.make_esp32_ble_tracker()
ble = Pvariable(ESP32BLETracker, config[CONF_ID], rhs)
if CONF_SCAN_INTERVAL in config:
add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL]))
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

@@ -0,0 +1,35 @@
import voluptuous as vol
from esphomeyaml import config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32, CONF_UUID, CONF_TYPE
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, RawExpression, ArrayInitializer
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
ESP32BLETracker = esphomelib_ns.ESP32BLETracker
CONF_MAJOR = 'major'
CONF_MINOR = 'minor'
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(ESP32BLETracker),
vol.Required(CONF_TYPE): vol.All(vol.Upper, cv.one_of('IBEACON')),
vol.Required(CONF_UUID): cv.uuid,
vol.Optional(CONF_MAJOR): cv.uint16_t,
vol.Optional(CONF_MINOR): cv.uint16_t,
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds,
})
def to_code(config):
uuid = config[CONF_UUID].hex
uuid_arr = [RawExpression('0x{}'.format(uuid[i:i+2])) for i in range(0, len(uuid), 2)]
rhs = App.make_esp32_ble_beacon(ArrayInitializer(*uuid_arr, multiline=False))
ble = Pvariable(config[CONF_ID], rhs)
if CONF_MAJOR in config:
add(ble.set_major(config[CONF_MAJOR]))
if CONF_MINOR in config:
add(ble.set_minor(config[CONF_MINOR]))
BUILD_FLAGS = '-DUSE_ESP32_BLE_BEACON'

View File

@@ -0,0 +1,24 @@
import voluptuous as vol
from esphomeyaml import config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
ESP32BLETracker = esphomelib_ns.ESP32BLETracker
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(ESP32BLETracker),
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds,
})
def to_code(config):
rhs = App.make_esp32_ble_tracker()
ble = Pvariable(config[CONF_ID], rhs)
if CONF_SCAN_INTERVAL in config:
add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL]))
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

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

View File

@@ -2,20 +2,13 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_MQTT_ID, CONF_OSCILLATION_COMMAND_TOPIC, \ from esphomeyaml.const import CONF_ID, CONF_MQTT_ID, CONF_OSCILLATION_COMMAND_TOPIC, \
CONF_OSCILLATION_STATE_TOPIC, CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC CONF_OSCILLATION_STATE_TOPIC, CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC, CONF_INTERNAL
from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('fan'): cv.register_variable_id,
cv.GenerateID('mqtt_fan', CONF_MQTT_ID): cv.register_variable_id,
vol.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.publish_topic,
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic,
})
fan_ns = esphomelib_ns.namespace('fan') fan_ns = esphomelib_ns.namespace('fan')
FanState = fan_ns.FanState FanState = fan_ns.FanState
MQTTFanComponent = fan_ns.MQTTFanComponent MQTTFanComponent = fan_ns.MQTTFanComponent
@@ -29,6 +22,15 @@ FAN_SPEED_LOW = fan_ns.FAN_SPEED_LOW
FAN_SPEED_MEDIUM = fan_ns.FAN_SPEED_MEDIUM FAN_SPEED_MEDIUM = fan_ns.FAN_SPEED_MEDIUM
FAN_SPEED_HIGH = fan_ns.FAN_SPEED_HIGH FAN_SPEED_HIGH = fan_ns.FAN_SPEED_HIGH
FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(FanState),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTFanComponent),
vol.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.publish_topic,
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic,
})
FAN_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(FAN_SCHEMA.schema)
FAN_SPEEDS = { FAN_SPEEDS = {
'OFF': FAN_SPEED_OFF, 'OFF': FAN_SPEED_OFF,
@@ -43,6 +45,9 @@ def validate_fan_speed(value):
def setup_fan_core_(fan_var, mqtt_var, config): def setup_fan_core_(fan_var, mqtt_var, config):
if CONF_INTERNAL in config:
add(fan_var.set_internal(config[CONF_INTERNAL]))
if CONF_OSCILLATION_STATE_TOPIC in config: if CONF_OSCILLATION_STATE_TOPIC in config:
add(mqtt_var.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC])) add(mqtt_var.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC]))
if CONF_OSCILLATION_COMMAND_TOPIC in config: if CONF_OSCILLATION_COMMAND_TOPIC in config:
@@ -55,8 +60,8 @@ def setup_fan_core_(fan_var, mqtt_var, config):
def setup_fan(fan_obj, mqtt_obj, config): def setup_fan(fan_obj, mqtt_obj, config):
fan_var = Pvariable(FanState, config[CONF_ID], fan_obj, has_side_effects=False) fan_var = Pvariable(config[CONF_ID], fan_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTFanComponent, config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False) mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
setup_fan_core_(fan_var, mqtt_var, config) setup_fan_core_(fan_var, mqtt_var, config)

View File

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

View File

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

View File

@@ -6,25 +6,26 @@ from esphomeyaml.const import CONF_FREQUENCY, CONF_SCL, CONF_SDA, CONF_SCAN, CON
CONF_RECEIVE_TIMEOUT CONF_RECEIVE_TIMEOUT
from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns
I2CComponent = esphomelib_ns.I2CComponent
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('i2c'): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(I2CComponent),
vol.Required(CONF_SDA, default='SDA'): pins.input_output_pin, vol.Required(CONF_SDA, default='SDA'): pins.input_output_pin,
vol.Required(CONF_SCL, default='SCL'): pins.input_output_pin, vol.Required(CONF_SCL, default='SCL'): pins.input_output_pin,
vol.Optional(CONF_FREQUENCY): cv.positive_int, vol.Optional(CONF_FREQUENCY): vol.All(cv.frequency, vol.Range(min=0, min_included=False)),
vol.Optional(CONF_RECEIVE_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_SCAN): cv.boolean, vol.Optional(CONF_SCAN): cv.boolean,
})
I2CComponent = esphomelib_ns.I2CComponent vol.Optional(CONF_RECEIVE_TIMEOUT): cv.invalid("The receive_timeout option has been removed "
"because timeouts are already handled by the "
"low-level i2c interface.")
})
def to_code(config): def to_code(config):
rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN)) rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN))
i2c = Pvariable(I2CComponent, config[CONF_ID], rhs) i2c = Pvariable(config[CONF_ID], rhs)
if CONF_FREQUENCY in config: if CONF_FREQUENCY in config:
add(i2c.set_frequency(config[CONF_FREQUENCY])) add(i2c.set_frequency(config[CONF_FREQUENCY]))
if CONF_RECEIVE_TIMEOUT in config:
add(i2c.set_receive_timeout(config[CONF_RECEIVE_TIMEOUT]))
BUILD_FLAGS = '-DUSE_I2C' BUILD_FLAGS = '-DUSE_I2C'

View File

@@ -1,26 +1,6 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.components import switch
from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ def CONFIG_SCHEMA(config):
cv.GenerateID('ir_transmitter'): cv.register_variable_id, raise vol.Invalid("The ir_transmitter component has been renamed to "
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, "remote_transmitter because of 433MHz signal support.")
vol.Optional(CONF_CARRIER_DUTY_PERCENT): vol.All(vol.Coerce(int),
vol.Range(min=1, max=100)),
})])
IRTransmitterComponent = switch.switch_ns.namespace('IRTransmitterComponent')
def to_code(config):
for conf in config:
pin = gpio_output_pin_expression(conf[CONF_PIN])
rhs = App.make_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT))
Pvariable(IRTransmitterComponent, conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'

View File

@@ -1,17 +1,12 @@
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \ from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \
CONF_MQTT_ID CONF_MQTT_ID, CONF_INTERNAL
from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('light'): cv.register_variable_id,
cv.GenerateID('mqtt_light', CONF_MQTT_ID): cv.register_variable_id,
})
light_ns = esphomelib_ns.namespace('light') light_ns = esphomelib_ns.namespace('light')
LightState = light_ns.LightState LightState = light_ns.LightState
MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent
@@ -20,8 +15,17 @@ TurnOffAction = light_ns.TurnOffAction
TurnOnAction = light_ns.TurnOnAction TurnOnAction = light_ns.TurnOnAction
MakeLight = Application.MakeLight MakeLight = Application.MakeLight
LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(LightState),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTJSONLightComponent),
})
LIGHT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(LIGHT_SCHEMA.schema)
def setup_light_core_(light_var, mqtt_var, config): def setup_light_core_(light_var, mqtt_var, config):
if CONF_INTERNAL in config:
add(light_var.set_internal(config[CONF_INTERNAL]))
if CONF_DEFAULT_TRANSITION_LENGTH in config: if CONF_DEFAULT_TRANSITION_LENGTH in config:
add(light_var.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH])) add(light_var.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH]))
if CONF_GAMMA_CORRECT in config: if CONF_GAMMA_CORRECT in config:
@@ -31,9 +35,8 @@ def setup_light_core_(light_var, mqtt_var, config):
def setup_light(light_obj, mqtt_obj, config): def setup_light(light_obj, mqtt_obj, config):
light_var = Pvariable(LightState, config[CONF_ID], light_obj, has_side_effects=False) light_var = Pvariable(config[CONF_ID], light_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTJSONLightComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False)
setup_light_core_(light_var, mqtt_var, config) setup_light_core_(light_var, mqtt_var, config)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,16 +6,17 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import automation from esphomeyaml import automation
from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \ from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LOG_TOPIC, \ CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LOG_TOPIC, \
CONF_MQTT, CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, \ CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, \
CONF_SSL_FINGERPRINTS, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, \ CONF_SSL_FINGERPRINTS, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, \
CONF_WILL_MESSAGE CONF_WILL_MESSAGE, CONF_REBOOT_TIMEOUT
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, \ from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression, \
TemplateArguments, add, esphomelib_ns, optional, std_string, RawExpression StructInitializer, \
TemplateArguments, add, esphomelib_ns, optional, std_string
def validate_message_just_topic(value): def validate_message_just_topic(value):
value = cv.publish_topic(value) value = cv.publish_topic(value)
return {CONF_TOPIC: value} return MQTT_MESSAGE_BASE({CONF_TOPIC: value})
MQTT_MESSAGE_BASE = vol.Schema({ MQTT_MESSAGE_BASE = vol.Schema({
@@ -54,7 +55,7 @@ def validate_fingerprint(value):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(CONF_MQTT): cv.register_variable_id, cv.GenerateID(): cv.declare_variable_id(MQTTClientComponent),
vol.Required(CONF_BROKER): validate_broker, vol.Required(CONF_BROKER): validate_broker,
vol.Optional(CONF_PORT, default=1883): cv.port, vol.Optional(CONF_PORT, default=1883): cv.port,
vol.Optional(CONF_USERNAME, default=''): cv.string, vol.Optional(CONF_USERNAME, default=''): cv.string,
@@ -70,9 +71,11 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266, vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266,
cv.ensure_list, [validate_fingerprint]), cv.ensure_list, [validate_fingerprint]),
vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds, vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds,
vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({ vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger),
vol.Required(CONF_TOPIC): cv.publish_topic, vol.Required(CONF_TOPIC): cv.publish_topic,
vol.Optional(CONF_QOS, 0): cv.mqtt_qos, vol.Optional(CONF_QOS, default=0): cv.mqtt_qos,
})]) })])
}) })
@@ -93,7 +96,7 @@ def exp_mqtt_message(config):
def to_code(config): def to_code(config):
rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT], rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT],
config[CONF_USERNAME], config[CONF_PASSWORD]) config[CONF_USERNAME], config[CONF_PASSWORD])
mqtt = Pvariable(MQTTClientComponent, config[CONF_ID], rhs) mqtt = Pvariable(config[CONF_ID], rhs)
if not config.get(CONF_DISCOVERY, True): if not config.get(CONF_DISCOVERY, True):
add(mqtt.disable_discovery()) add(mqtt.disable_discovery())
if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config: if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
@@ -104,13 +107,13 @@ def to_code(config):
add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX])) add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX]))
if CONF_BIRTH_MESSAGE in config: if CONF_BIRTH_MESSAGE in config:
birth_message = config[CONF_BIRTH_MESSAGE] birth_message = config[CONF_BIRTH_MESSAGE]
if birth_message is None: if not birth_message:
add(mqtt.disable_birth_message()) add(mqtt.disable_birth_message())
else: else:
add(mqtt.set_birth_message(exp_mqtt_message(birth_message))) add(mqtt.set_birth_message(exp_mqtt_message(birth_message)))
if CONF_WILL_MESSAGE in config: if CONF_WILL_MESSAGE in config:
will_message = config[CONF_WILL_MESSAGE] will_message = config[CONF_WILL_MESSAGE]
if will_message is None: if not will_message:
add(mqtt.disable_last_will()) add(mqtt.disable_last_will())
else: else:
add(mqtt.set_last_will(exp_mqtt_message(will_message))) add(mqtt.set_last_will(exp_mqtt_message(will_message)))
@@ -118,20 +121,22 @@ def to_code(config):
add(mqtt.set_client_id(config[CONF_CLIENT_ID])) add(mqtt.set_client_id(config[CONF_CLIENT_ID]))
if CONF_LOG_TOPIC in config: if CONF_LOG_TOPIC in config:
log_topic = config[CONF_LOG_TOPIC] log_topic = config[CONF_LOG_TOPIC]
if log_topic is None: if not log_topic:
add(mqtt.disable_log_message()) add(mqtt.disable_log_message())
else: else:
add(mqtt.set_log_topic(exp_mqtt_message(log_topic))) add(mqtt.set_log_message_template(exp_mqtt_message(log_topic)))
if CONF_SSL_FINGERPRINTS in config: if CONF_SSL_FINGERPRINTS in config:
for fingerprint in config[CONF_SSL_FINGERPRINTS]: for fingerprint in config[CONF_SSL_FINGERPRINTS]:
arr = [RawExpression("0x{}".format(fingerprint[i:i + 2])) for i in range(0, 40, 2)] arr = [RawExpression("0x{}".format(fingerprint[i:i + 2])) for i in range(0, 40, 2)]
add(mqtt.add_ssl_fingerprint(ArrayInitializer(*arr, multiline=False))) add(mqtt.add_ssl_fingerprint(ArrayInitializer(*arr, multiline=False)))
if CONF_KEEPALIVE in config: if CONF_KEEPALIVE in config:
add(mqtt.set_keep_alive(config[CONF_KEEPALIVE])) add(mqtt.set_keep_alive(config[CONF_KEEPALIVE]))
if CONF_REBOOT_TIMEOUT in config:
add(mqtt.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
for conf in config.get(CONF_ON_MESSAGE, []): for conf in config.get(CONF_ON_MESSAGE, []):
rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS]) rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS])
trigger = Pvariable(MQTTMessageTrigger, conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, std_string, conf) automation.build_automation(trigger, std_string, conf)

View File

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

View File

@@ -1,6 +1,7 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components.power_supply import PowerSupplyComponent
from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY
from esphomeyaml.helpers import add, esphomelib_ns, get_variable from esphomeyaml.helpers import add, esphomelib_ns, get_variable
@@ -8,26 +9,37 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
BINARY_OUTPUT_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({ BINARY_OUTPUT_SCHEMA = vol.Schema({
vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_INVERTED): cv.boolean,
}) })
BINARY_OUTPUT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(BINARY_OUTPUT_SCHEMA.schema)
FLOAT_OUTPUT_SCHEMA = BINARY_OUTPUT_SCHEMA.extend({ FLOAT_OUTPUT_SCHEMA = BINARY_OUTPUT_SCHEMA.extend({
vol.Optional(CONF_MAX_POWER): cv.percentage, vol.Optional(CONF_MAX_POWER): cv.percentage,
}) })
FLOAT_OUTPUT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(FLOAT_OUTPUT_SCHEMA.schema)
output_ns = esphomelib_ns.namespace('output') output_ns = esphomelib_ns.namespace('output')
def setup_output_platform(obj, config, skip_power_supply=False): def setup_output_platform_(obj, config, skip_power_supply=False):
if CONF_INVERTED in config: if CONF_INVERTED in config:
add(obj.set_inverted(config[CONF_INVERTED])) add(obj.set_inverted(config[CONF_INVERTED]))
if not skip_power_supply and CONF_POWER_SUPPLY in config: if not skip_power_supply and CONF_POWER_SUPPLY in config:
power_supply = get_variable(config[CONF_POWER_SUPPLY]) power_supply = None
for power_supply in get_variable(config[CONF_POWER_SUPPLY]):
yield
add(obj.set_power_supply(power_supply)) add(obj.set_power_supply(power_supply))
if CONF_MAX_POWER in config: if CONF_MAX_POWER in config:
add(obj.set_max_power(config[CONF_MAX_POWER])) add(obj.set_max_power(config[CONF_MAX_POWER]))
def setup_output_platform(obj, config, skip_power_supply=False):
for _ in setup_output_platform_(obj, config, skip_power_supply):
yield
BUILD_FLAGS = '-DUSE_OUTPUT' BUILD_FLAGS = '-DUSE_OUTPUT'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,62 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.const import CONF_BUFFER_SIZE, CONF_DUMP, CONF_FILTER, CONF_ID, CONF_IDLE, \
CONF_PIN, CONF_TOLERANCE
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, gpio_input_pin_expression
remote_ns = esphomelib_ns.namespace('remote')
RemoteReceiverComponent = remote_ns.RemoteReceiverComponent
DUMPERS = {
'lg': remote_ns.LGDumper,
'nec': remote_ns.NECDumper,
'panasonic': remote_ns.PanasonicDumper,
'raw': remote_ns.RawDumper,
'sony': remote_ns.SonyDumper,
}
def validate_dumpers_all(value):
if not isinstance(value, (str, unicode)):
raise vol.Invalid("Not valid dumpers")
if value.upper() == "ALL":
return list(DUMPERS)
raise vol.Invalid("Not valid dumpers")
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
cv.GenerateID(): cv.declare_variable_id(RemoteReceiverComponent),
vol.Required(CONF_PIN): pins.gpio_input_pin_schema,
vol.Optional(CONF_DUMP, default=[]):
vol.Any(validate_dumpers_all,
vol.All(cv.ensure_list, [vol.All(vol.Lower, cv.one_of(*DUMPERS))])),
vol.Optional(CONF_TOLERANCE): vol.All(cv.percentage_int, vol.Range(min=0)),
vol.Optional(CONF_BUFFER_SIZE): cv.validate_bytes,
vol.Optional(CONF_FILTER): cv.positive_time_period_microseconds,
vol.Optional(CONF_IDLE): cv.positive_time_period_microseconds,
})])
def to_code(config):
for conf in config:
pin = None
for pin in gpio_input_pin_expression(conf[CONF_PIN]):
yield
rhs = App.make_remote_receiver_component(pin)
receiver = Pvariable(conf[CONF_ID], rhs)
for dumper in conf[CONF_DUMP]:
add(receiver.add_dumper(DUMPERS[dumper].new()))
if CONF_TOLERANCE in conf:
add(receiver.set_tolerance(conf[CONF_TOLERANCE]))
if CONF_BUFFER_SIZE in conf:
add(receiver.set_buffer_size(conf[CONF_BUFFER_SIZE]))
if CONF_FILTER in conf:
add(receiver.set_filter_us(conf[CONF_FILTER]))
if CONF_IDLE in conf:
add(receiver.set_idle_us(conf[CONF_IDLE]))
BUILD_FLAGS = '-DUSE_REMOTE_RECEIVER'

View File

@@ -0,0 +1,31 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, gpio_output_pin_expression
remote_ns = esphomelib_ns.namespace('remote')
RemoteTransmitterComponent = remote_ns.RemoteTransmitterComponent
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
cv.GenerateID(): cv.declare_variable_id(RemoteTransmitterComponent),
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_CARRIER_DUTY_PERCENT): vol.All(cv.percentage_int,
vol.Range(min=1, max=100)),
})])
def to_code(config):
for conf in config:
pin = None
for pin in gpio_output_pin_expression(conf[CONF_PIN]):
yield
rhs = App.make_remote_transmitter_component(pin)
transmitter = Pvariable(conf[CONF_ID], rhs)
if CONF_CARRIER_DUTY_PERCENT in conf:
add(transmitter.set_carrier_duty_percent(conf[CONF_CARRIER_DUTY_PERCENT]))
BUILD_FLAGS = '-DUSE_REMOTE_TRANSMITTER'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, variable
MakeDutyCycleSensor = Application.MakeDutyCycleSensor
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeDutyCycleSensor),
vol.Required(CONF_PIN): pins.internal_gpio_input_pin_schema,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}))
def to_code(config):
pin = None
for pin in gpio_input_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_duty_cycle_sensor(config[CONF_NAME], pin,
config.get(CONF_UPDATE_INTERVAL))
make = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Pduty, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_DUTY_CYCLE_SENSOR'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,62 +1,66 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import core, pins
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_INTERNAL_FILTER, \ from esphomeyaml.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_INTERNAL_FILTER, \
CONF_MAKE_ID, CONF_NAME, CONF_PIN, CONF_PULL_MODE, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, \ CONF_MAKE_ID, CONF_NAME, CONF_PIN, CONF_PULL_MODE, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, \
ESP_PLATFORM_ESP32 ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, add, global_ns, variable, Application from esphomeyaml.helpers import App, Application, add, variable, gpio_input_pin_expression
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
GPIO_PULL_MODES = {
'PULLUP': global_ns.GPIO_PULLUP_ONLY,
'PULLDOWN': global_ns.GPIO_PULLDOWN_ONLY,
'PULLUP_PULLDOWN': global_ns.GPIO_PULLUP_PULLDOWN,
'FLOATING': global_ns.GPIO_FLOATING,
}
GPIO_PULL_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*GPIO_PULL_MODES))
COUNT_MODES = { COUNT_MODES = {
'DISABLE': global_ns.PCNT_COUNT_DIS, 'DISABLE': sensor.sensor_ns.PULSE_COUNTER_DISABLE,
'INCREMENT': global_ns.PCNT_COUNT_INC, 'INCREMENT': sensor.sensor_ns.PULSE_COUNTER_INCREMENT,
'DECREMENT': global_ns.PCNT_COUNT_DEC, 'DECREMENT': sensor.sensor_ns.PULSE_COUNTER_DECREMENT,
} }
COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*COUNT_MODES)) COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*COUNT_MODES))
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ MakePulseCounterSensor = Application.MakePulseCounterSensor
cv.GenerateID('pulse_counter', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.input_pin,
vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA, def validate_internal_filter(value):
if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
if isinstance(value, int):
raise vol.Invalid("Please specify the internal filter in microseconds now "
"(since 1.7.0). For example '17ms'")
value = cv.positive_time_period_microseconds(value)
if value.total_microseconds > 13:
raise vol.Invalid("Maximum internal filter value for ESP32 is 13us")
return value
else:
return cv.positive_time_period_microseconds(value)
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakePulseCounterSensor),
vol.Required(CONF_PIN): pins.internal_gpio_input_pin_schema,
vol.Optional(CONF_COUNT_MODE): vol.Schema({ vol.Optional(CONF_COUNT_MODE): vol.Schema({
vol.Required(CONF_RISING_EDGE): COUNT_MODE_SCHEMA, vol.Required(CONF_RISING_EDGE): COUNT_MODE_SCHEMA,
vol.Required(CONF_FALLING_EDGE): COUNT_MODE_SCHEMA, vol.Required(CONF_FALLING_EDGE): COUNT_MODE_SCHEMA,
}), }),
vol.Optional(CONF_INTERNAL_FILTER): vol.All(vol.Coerce(int), vol.Range(min=0, max=1023)), vol.Optional(CONF_INTERNAL_FILTER): validate_internal_filter,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema)
MakePulseCounterSensor = Application.MakePulseCounterSensor vol.Optional(CONF_PULL_MODE): cv.invalid("The pull_mode option has been removed in 1.7.0, "
"please use the pin mode schema now.")
}))
def to_code(config): def to_code(config):
rhs = App.make_pulse_counter_sensor(config[CONF_NAME], config[CONF_PIN], pin = None
for pin in gpio_input_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_pulse_counter_sensor(config[CONF_NAME], pin,
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable(MakePulseCounterSensor, config[CONF_MAKE_ID], rhs) make = variable(config[CONF_MAKE_ID], rhs)
pcnt = make.Ppcnt pcnt = make.Ppcnt
if CONF_PULL_MODE in config:
pull_mode = GPIO_PULL_MODES[config[CONF_PULL_MODE]]
add(pcnt.set_pull_mode(pull_mode))
if CONF_COUNT_MODE in config: if CONF_COUNT_MODE in config:
count_mode = config[CONF_COUNT_MODE] rising_edge = COUNT_MODES[config[CONF_COUNT_MODE][CONF_RISING_EDGE]]
rising_edge = COUNT_MODES[count_mode[CONF_RISING_EDGE]] falling_edge = COUNT_MODES[config[CONF_COUNT_MODE][CONF_FALLING_EDGE]]
falling_edge = COUNT_MODES[count_mode[CONF_FALLING_EDGE]]
add(pcnt.set_edge_mode(rising_edge, falling_edge)) add(pcnt.set_edge_mode(rising_edge, falling_edge))
if CONF_INTERNAL_FILTER in config: if CONF_INTERNAL_FILTER in config:
add(pcnt.set_filter(config[CONF_INTERNAL_FILTER])) add(pcnt.set_filter_us(config[CONF_INTERNAL_FILTER]))
sensor.setup_sensor(make.Ppcnt, make.Pmqtt, config) sensor.setup_sensor(make.Ppcnt, make.Pmqtt, config)

View File

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

View File

@@ -4,36 +4,30 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ACCURACY, CONF_ADDRESS, CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, \ from esphomeyaml.const import CONF_ACCURACY, CONF_ADDRESS, CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, \
CONF_TEMPERATURE, CONF_UPDATE_INTERVAL CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, add, variable from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
SHT_ACCURACIES = { MakeSHT3XDSensor = Application.MakeSHT3XDSensor
'LOW': sensor.sensor_ns.SHT3XD_ACCURACY_LOW,
'MEDIUM': sensor.sensor_ns.SHT3XD_ACCURACY_MEDIUM,
'HIGH': sensor.sensor_ns.SHT3XD_ACCURACY_HIGH,
}
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('sht3xd', CONF_MAKE_ID): cv.register_variable_id, cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeSHT3XDSensor),
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address,
vol.Optional(CONF_ACCURACY): vol.All(vol.Upper, cv.one_of(*SHT_ACCURACIES)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
})
MakeSHT3XDSensor = Application.MakeSHT3XDSensor vol.Optional(CONF_ACCURACY): cv.invalid("The accuracy option has been removed and now "
"defaults to HIGH."),
})
def to_code(config): def to_code(config):
rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
sht3xd = variable(MakeSHT3XDSensor, config[CONF_MAKE_ID], rhs) sht3xd = variable(config[CONF_MAKE_ID], rhs)
if CONF_ACCURACY in config:
add(sht3xd.Psht3xd.set_accuracy(SHT_ACCURACIES[config[CONF_ACCURACY]]))
sensor.setup_sensor(sht3xd.Psht3xd.Pget_temperature_sensor(), sht3xd.Pmqtt_temperature, sensor.setup_sensor(sht3xd.Psht3xd.Pget_temperature_sensor(), sht3xd.Pmqtt_temperature,
config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,22 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, variable
MakeWiFiSignalSensor = Application.MakeWiFiSignalSensor
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeWiFiSignalSensor),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}))
def to_code(config):
rhs = App.make_wifi_signal_sensor(config[CONF_NAME], config.get(CONF_UPDATE_INTERVAL))
make = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Pwifi, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_WIFI_SIGNAL_SENSOR'

View File

@@ -0,0 +1,23 @@
import voluptuous as vol
from esphomeyaml import config_validation as cv, pins
from esphomeyaml.const import CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, esphomelib_ns, gpio_output_pin_expression
StatusLED = esphomelib_ns.StatusLED
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(StatusLED),
vol.Optional(CONF_PIN): pins.gpio_output_pin_schema,
})
def to_code(config):
pin = None
for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_status_led(pin)
Pvariable(config[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_STATUS_LED'

View File

@@ -1,20 +1,13 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_INVERTED, CONF_MQTT_ID from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_INVERTED, CONF_MQTT_ID, CONF_INTERNAL
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, setup_mqtt_component from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('switch_'): cv.register_variable_id,
cv.GenerateID('mqtt_switch', CONF_MQTT_ID): cv.register_variable_id,
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INVERTED): cv.boolean,
})
switch_ns = esphomelib_ns.namespace('switch_') switch_ns = esphomelib_ns.namespace('switch_')
Switch = switch_ns.Switch Switch = switch_ns.Switch
MQTTSwitchComponent = switch_ns.MQTTSwitchComponent MQTTSwitchComponent = switch_ns.MQTTSwitchComponent
@@ -22,8 +15,19 @@ ToggleAction = switch_ns.ToggleAction
TurnOffAction = switch_ns.TurnOffAction TurnOffAction = switch_ns.TurnOffAction
TurnOnAction = switch_ns.TurnOnAction TurnOnAction = switch_ns.TurnOnAction
SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(Switch),
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSwitchComponent),
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INVERTED): cv.boolean,
})
SWITCH_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(SWITCH_SCHEMA.schema)
def setup_switch_core_(switch_var, mqtt_var, config): def setup_switch_core_(switch_var, mqtt_var, config):
if CONF_INTERNAL in config:
add(switch_var.set_internal(config[CONF_INTERNAL]))
if CONF_ICON in config: if CONF_ICON in config:
add(switch_var.set_icon(config[CONF_ICON])) add(switch_var.set_icon(config[CONF_ICON]))
if CONF_INVERTED in config: if CONF_INVERTED in config:
@@ -33,17 +37,15 @@ def setup_switch_core_(switch_var, mqtt_var, config):
def setup_switch(switch_obj, mqtt_obj, config): def setup_switch(switch_obj, mqtt_obj, config):
switch_var = Pvariable(Switch, config[CONF_ID], switch_obj, has_side_effects=False) switch_var = Pvariable(config[CONF_ID], switch_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], mqtt_obj, mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
has_side_effects=False)
setup_switch_core_(switch_var, mqtt_var, config) setup_switch_core_(switch_var, mqtt_var, config)
def register_switch(var, config): def register_switch(var, config):
switch_var = Pvariable(Switch, config[CONF_ID], var, has_side_effects=True) switch_var = Pvariable(config[CONF_ID], var, has_side_effects=True)
rhs = App.register_switch(switch_var) rhs = App.register_switch(switch_var)
mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], rhs, mqtt_var = Pvariable(config[CONF_MQTT_ID], rhs, has_side_effects=True)
has_side_effects=True)
setup_switch_core_(switch_var, mqtt_var, config) setup_switch_core_(switch_var, mqtt_var, config)

View File

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

View File

@@ -1,103 +0,0 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import switch
from esphomeyaml.components.ir_transmitter import IRTransmitterComponent
from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_COMMAND, CONF_DATA, \
CONF_INVERTED, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \
CONF_PANASONIC, CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, ArrayInitializer, HexIntLiteral, get_variable
DEPENDENCIES = ['ir_transmitter']
IR_KEYS = [CONF_NEC, CONF_LG, CONF_SONY, CONF_PANASONIC, CONF_RAW]
WAIT_TIME_MESSAGE = "The wait_time_us option has been renamed to wait_time in order to decrease " \
"ambiguity. "
PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('ir_transmitter_switch'): cv.register_variable_id,
vol.Exclusive(CONF_NEC, 'code'): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint16_t,
}),
vol.Exclusive(CONF_LG, 'code'): vol.Schema({
vol.Required(CONF_DATA): cv.hex_uint32_t,
vol.Optional(CONF_NBITS, default=28): vol.All(vol.Coerce(int), vol.Range(min=0, max=32)),
}),
vol.Exclusive(CONF_SONY, 'code'): vol.Schema({
vol.Required(CONF_DATA): cv.hex_uint32_t,
vol.Optional(CONF_NBITS, default=12): vol.All(vol.Coerce(int), vol.Range(min=0, max=32)),
}),
vol.Exclusive(CONF_PANASONIC, 'code'): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint32_t,
}),
vol.Exclusive(CONF_RAW, 'code'): vol.Schema({
vol.Required(CONF_CARRIER_FREQUENCY): vol.All(cv.frequency, vol.Coerce(int)),
vol.Required(CONF_DATA): [vol.Coerce(int)],
}),
vol.Optional(CONF_REPEAT): vol.Any(cv.positive_not_null_int, vol.Schema({
vol.Required(CONF_TIMES): cv.positive_not_null_int,
vol.Required(CONF_WAIT_TIME): cv.positive_time_period_microseconds,
vol.Optional('wait_time_us'): cv.invalid(WAIT_TIME_MESSAGE),
})),
vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id,
vol.Optional(CONF_INVERTED): cv.invalid("IR Transmitters do not support inverted mode!"),
}).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_least_one_key(*IR_KEYS))
# pylint: disable=invalid-name
ir_ns = switch.switch_ns.namespace('ir')
SendData = ir_ns.namespace('SendData')
DataTransmitter = IRTransmitterComponent.DataTransmitter
def safe_hex(value):
if value is None:
return None
return HexIntLiteral(value)
def exp_send_data(config):
if CONF_NEC in config:
conf = config[CONF_NEC]
base = SendData.from_nec(safe_hex(conf[CONF_ADDRESS]),
safe_hex(conf[CONF_COMMAND]))
elif CONF_LG in config:
conf = config[CONF_LG]
base = SendData.from_lg(safe_hex(conf[CONF_DATA]), conf.get(CONF_NBITS))
elif CONF_SONY in config:
conf = config[CONF_SONY]
base = SendData.from_sony(safe_hex(conf[CONF_DATA]), conf.get(CONF_NBITS))
elif CONF_PANASONIC in config:
conf = config[CONF_PANASONIC]
base = SendData.from_panasonic(safe_hex(conf[CONF_ADDRESS]),
safe_hex(conf[CONF_COMMAND]))
elif CONF_RAW in config:
conf = config[CONF_RAW]
data = ArrayInitializer(*conf[CONF_DATA])
base = SendData.from_raw(data, conf[CONF_CARRIER_FREQUENCY])
else:
raise ESPHomeYAMLError(u"Unsupported IR mode {}".format(config))
if CONF_REPEAT in config:
if isinstance(config[CONF_REPEAT], int):
times = config[CONF_REPEAT]
wait_us = None
else:
times = config[CONF_REPEAT][CONF_TIMES]
wait_us = config[CONF_REPEAT][CONF_WAIT_TIME]
base = base.repeat(times, wait_us)
return base
def to_code(config):
ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IRTransmitterComponent)
send_data = exp_send_data(config)
rhs = App.register_component(ir.create_transmitter(config[CONF_NAME], send_data))
switch.register_switch(rhs, config)
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'

View File

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

View File

@@ -0,0 +1,105 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import switch
from esphomeyaml.components.remote_transmitter import RemoteTransmitterComponent, remote_ns
from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_COMMAND, CONF_DATA, \
CONF_INVERTED, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \
CONF_PANASONIC, CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, get_variable
DEPENDENCIES = ['remote_transmitter']
IR_KEYS = [CONF_NEC, CONF_LG, CONF_SONY, CONF_PANASONIC, CONF_RAW]
CONF_REMOTE_TRANSMITTER_ID = 'remote_transmitter_id'
CONF_TRANSMITTER_ID = 'transmitter_id'
RemoteTransmitter = remote_ns.RemoteTransmitter
LGTransmitter = remote_ns.LGTransmitter
NECTransmitter = remote_ns.NECTransmitter
PanasonicTransmitter = remote_ns.PanasonicTransmitter
RawTransmitter = remote_ns.RawTransmitter
SonyTransmitter = remote_ns.SonyTransmitter
validate_raw_data = [vol.Any(vol.Coerce(int), cv.time_period_microseconds)]
PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_LG): vol.Schema({
vol.Required(CONF_DATA): cv.hex_uint32_t,
vol.Optional(CONF_NBITS, default=28): vol.All(vol.Coerce(int), cv.one_of(28, 32)),
}),
vol.Optional(CONF_NEC): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint16_t,
}),
vol.Optional(CONF_SONY): vol.Schema({
vol.Required(CONF_DATA): cv.hex_uint32_t,
vol.Optional(CONF_NBITS, default=12): vol.All(vol.Coerce(int), cv.one_of(12, 15, 20)),
}),
vol.Optional(CONF_PANASONIC): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint32_t,
}),
vol.Optional(CONF_RAW): vol.Any(validate_raw_data, vol.Schema({
vol.Required(CONF_DATA): validate_raw_data,
vol.Optional(CONF_CARRIER_FREQUENCY): vol.All(cv.frequency, vol.Coerce(int)),
})),
vol.Optional(CONF_REPEAT): vol.Any(cv.positive_not_null_int, vol.Schema({
vol.Required(CONF_TIMES): cv.positive_not_null_int,
vol.Required(CONF_WAIT_TIME): cv.positive_time_period_microseconds,
})),
cv.GenerateID(CONF_REMOTE_TRANSMITTER_ID): cv.use_variable_id(RemoteTransmitterComponent),
cv.GenerateID(CONF_TRANSMITTER_ID): cv.declare_variable_id(RemoteTransmitter),
vol.Optional(CONF_INVERTED): cv.invalid("Remote Transmitters do not support inverted mode!"),
}), cv.has_exactly_one_key(*IR_KEYS))
def transmitter_base(config):
if CONF_LG in config:
conf = config[CONF_LG]
return LGTransmitter.new(config[CONF_NAME], conf[CONF_DATA], conf[CONF_NBITS])
elif CONF_NEC in config:
conf = config[CONF_NEC]
return NECTransmitter.new(config[CONF_NAME], conf[CONF_ADDRESS], conf[CONF_COMMAND])
elif CONF_PANASONIC in config:
conf = config[CONF_PANASONIC]
return PanasonicTransmitter.new(config[CONF_NAME], conf[CONF_ADDRESS], conf[CONF_COMMAND])
elif CONF_SONY in config:
conf = config[CONF_SONY]
return SonyTransmitter.new(config[CONF_NAME], conf[CONF_DATA], conf[CONF_NBITS])
elif CONF_RAW in config:
conf = config[CONF_RAW]
if isinstance(conf, dict):
data = conf[CONF_DATA]
carrier_frequency = conf.get(CONF_CARRIER_FREQUENCY)
else:
data = conf
carrier_frequency = None
return RawTransmitter.new(config[CONF_NAME], ArrayInitializer(*data, multiline=False),
carrier_frequency)
else:
raise ValueError("Unknown transmitter type {}".format(config))
def to_code(config):
remote = None
for remote in get_variable(config[CONF_REMOTE_TRANSMITTER_ID]):
yield
rhs = App.register_component(transmitter_base(config))
transmitter = Pvariable(config[CONF_TRANSMITTER_ID], rhs)
if CONF_REPEAT in config:
if isinstance(config[CONF_REPEAT], int):
times = config[CONF_REPEAT]
wait_us = 1000
else:
times = config[CONF_REPEAT][CONF_TIMES]
wait_us = config[CONF_REPEAT][CONF_WAIT_TIME]
add(transmitter.set_repeat(times, wait_us))
switch.register_switch(remote.add_transmitter(transmitter), config)
BUILD_FLAGS = '-DUSE_REMOTE_TRANSMITTER'

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,8 +3,8 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core from esphomeyaml import core
from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, \ from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, \
CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_SSID, \ CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_REBOOT_TIMEOUT, \
CONF_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266 CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266
from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, esphomelib_ns, global_ns from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, esphomelib_ns, global_ns
@@ -19,6 +19,15 @@ def validate_password(value):
return value return value
def validate_channel(value):
value = cv.positive_int(value)
if value < 1:
raise vol.Invalid("Minimum WiFi channel is 1")
if value > 14:
raise vol.Invalid("Maximum WiFi channel is 14")
return value
AP_MANUAL_IP_SCHEMA = vol.Schema({ AP_MANUAL_IP_SCHEMA = vol.Schema({
vol.Required(CONF_STATIC_IP): cv.ipv4, vol.Required(CONF_STATIC_IP): cv.ipv4,
vol.Required(CONF_GATEWAY): cv.ipv4, vol.Required(CONF_GATEWAY): cv.ipv4,
@@ -30,34 +39,58 @@ STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4, vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4,
}) })
CONFIG_SCHEMA = vol.Schema({ WIFI_NETWORK_BASE = vol.Schema({
cv.GenerateID('wifi'): cv.register_variable_id, vol.Required(CONF_SSID): cv.ssid,
vol.Optional(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password, vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA, vol.Optional(CONF_CHANNEL): validate_channel,
vol.Optional(CONF_AP): vol.Schema({ vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
vol.Required(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_CHANNEL): vol.All(cv.positive_int, vol.Range(min=1, max=14)),
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
}),
vol.Optional(CONF_HOSTNAME): cv.hostname,
vol.Required(CONF_DOMAIN, default='.local'): cv.domainname,
}) })
WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend({
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
})
WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend({
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
})
def validate(config):
if CONF_PASSWORD in config and CONF_SSID not in config:
raise vol.Invalid("Cannot have WiFi password without SSID!")
if CONF_SSID not in config and CONF_AP not in config:
raise vol.Invalid("Please specify at least an SSID or an Access Point "
"to create.")
return config
# pylint: disable=invalid-name # pylint: disable=invalid-name
IPAddress = global_ns.IPAddress IPAddress = global_ns.IPAddress
ManualIP = esphomelib_ns.ManualIP ManualIP = esphomelib_ns.ManualIP
WiFiComponent = esphomelib_ns.WiFiComponent WiFiComponent = esphomelib_ns.WiFiComponent
WiFiAp = esphomelib_ns.WiFiAp
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(WiFiComponent),
vol.Optional(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
vol.Optional(CONF_AP): WIFI_NETWORK_AP,
vol.Optional(CONF_HOSTNAME): cv.hostname,
vol.Optional(CONF_DOMAIN, default='.local'): cv.domainname,
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
}), validate)
def safe_ip(ip): def safe_ip(ip):
if ip is None: if ip is None:
return None return IPAddress(0, 0, 0, 0)
return IPAddress(*ip.args) return IPAddress(*ip.args)
def manual_ip(config): def manual_ip(config):
if config is None:
return None
return StructInitializer( return StructInitializer(
ManualIP, ManualIP,
('static_ip', safe_ip(config[CONF_STATIC_IP])), ('static_ip', safe_ip(config[CONF_STATIC_IP])),
@@ -68,31 +101,32 @@ def manual_ip(config):
) )
def wifi_network(config):
return StructInitializer(
WiFiAp,
('ssid', config.get(CONF_SSID, "")),
('password', config.get(CONF_PASSWORD, "")),
('channel', config.get(CONF_CHANNEL, -1)),
('manual_ip', manual_ip(config.get(CONF_MANUAL_IP))),
)
def to_code(config): def to_code(config):
sta = CONF_SSID in config rhs = App.init_wifi()
ap = CONF_AP in config wifi = Pvariable(config[CONF_ID], rhs)
if sta:
rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD))
else:
rhs = App.init_wifi()
wifi = Pvariable(WiFiComponent, config[CONF_ID], rhs)
if sta and CONF_MANUAL_IP in config: if CONF_SSID in config:
add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP]))) add(wifi.set_sta(wifi_network(config)))
if ap: if CONF_AP in config:
conf = config[CONF_AP] add(wifi.set_ap(wifi_network(config[CONF_AP])))
password = config.get(CONF_PASSWORD)
if password is None and CONF_CHANNEL in conf:
password = u""
add(wifi.set_ap(conf[CONF_SSID], password, conf.get(CONF_CHANNEL)))
if CONF_MANUAL_IP in conf:
add(wifi.set_ap_manual_ip(manual_ip(conf[CONF_MANUAL_IP])))
if CONF_HOSTNAME in config: if CONF_HOSTNAME in config:
add(wifi.set_hostname(config[CONF_HOSTNAME])) add(wifi.set_hostname(config[CONF_HOSTNAME]))
if CONF_REBOOT_TIMEOUT in config:
add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
def lib_deps(config): def lib_deps(config):
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266: if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:

View File

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

View File

@@ -8,19 +8,21 @@ import voluptuous as vol
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core, yaml_util from esphomeyaml import core, yaml_util, automation
from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \ from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
CONF_LIBRARY_URI, \ CONF_LIBRARY_URI, CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, \
CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, ESP_PLATFORMS, \ ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, CONF_ON_BOOT, CONF_TRIGGER_ID, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 CONF_PRIORITY, CONF_ON_SHUTDOWN
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, add, color from esphomeyaml.helpers import App, add, color, esphomelib_ns, Pvariable, NoArg, const_char_p
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.6.0' DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.7.0'
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
StartupTrigger = esphomelib_ns.StartupTrigger
ShutdownTrigger = esphomelib_ns.ShutdownTrigger
CORE_SCHEMA = vol.Schema({ CORE_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.valid_name, vol.Required(CONF_NAME): cv.valid_name,
@@ -30,6 +32,13 @@ CORE_SCHEMA = vol.Schema({
vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean, vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean,
vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean, vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean,
vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)), vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)),
vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(StartupTrigger),
vol.Optional(CONF_PRIORITY): vol.Coerce(float),
})]),
vol.Optional(CONF_ON_SHUTDOWN): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ShutdownTrigger),
})]),
}) })
REQUIRED_COMPONENTS = [ REQUIRED_COMPONENTS = [
@@ -43,6 +52,15 @@ _ALL_COMPONENTS = []
def core_to_code(config): def core_to_code(config):
add(App.set_name(config[CONF_NAME])) add(App.set_name(config[CONF_NAME]))
for conf in config.get(CONF_ON_BOOT, []):
rhs = App.register_component(StartupTrigger.new(conf.get(CONF_PRIORITY)))
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_SHUTDOWN, []):
trigger = Pvariable(conf[CONF_TRIGGER_ID], ShutdownTrigger.new())
automation.build_automation(trigger, const_char_p, conf)
def get_component(domain): def get_component(domain):
if domain in _COMPONENT_CACHE: if domain in _COMPONENT_CACHE:
@@ -93,6 +111,50 @@ class Config(OrderedDict):
self.errors.append((message, domain, config)) self.errors.append((message, domain, config))
def iter_ids(config, prefix=None, parent=None):
prefix = prefix or []
parent = parent or {}
if isinstance(config, core.ID):
yield config, prefix, parent
elif isinstance(config, core.Lambda):
for id in config.requires_ids:
yield id, prefix, parent
elif isinstance(config, list):
for i, item in enumerate(config):
for result in iter_ids(item, prefix + [str(i)], config):
yield result
elif isinstance(config, dict):
for key, value in config.iteritems():
for result in iter_ids(value, prefix + [str(key)], config):
yield result
def do_id_pass(result):
declare_ids = []
searching_ids = []
for id, prefix, config in iter_ids(result):
if id.is_declaration:
if id.id is not None and any(v[0].id == id.id for v in declare_ids):
result.add_error("ID {} redefined!".format(id.id), '.'.join(prefix), config)
continue
declare_ids.append((id, prefix, config))
else:
searching_ids.append((id, prefix, config))
# Resolve default ids after manual IDs
for id, _, _ in declare_ids:
id.resolve([v[0].id for v in declare_ids])
# Check searched IDs
for id, prefix, config in searching_ids:
if id.id is not None and not any(v[0].id == id.id for v in declare_ids):
result.add_error("Couldn't find ID {}".format(id.id), '.'.join(prefix), config)
if id.id is None and id.type is not None:
id.id = next((v[0].id for v in declare_ids if v[0].type == id.type), None)
if id.id is None:
result.add_error("Couldn't resolve ID for type {}".format(id.type),
'.'.join(prefix), config)
def validate_config(config): def validate_config(config):
global _ALL_COMPONENTS global _ALL_COMPONENTS
@@ -131,7 +193,7 @@ def validate_config(config):
dependencies = getattr(component, 'DEPENDENCIES', []) dependencies = getattr(component, 'DEPENDENCIES', [])
for dependency in dependencies: for dependency in dependencies:
if dependency not in _ALL_COMPONENTS: if dependency not in _ALL_COMPONENTS:
result.add_error(u"Component {} requires {}".format(domain, dependency)) result.add_error(u"Component {} requires component {}".format(domain, dependency))
success = False success = False
if not success: if not success:
continue continue
@@ -158,15 +220,15 @@ def validate_config(config):
continue continue
platform = get_platform(domain, p_name) platform = get_platform(domain, p_name)
if platform is None: if platform is None:
result.add_error(u"Platform not found: {}.{}") result.add_error(u"Platform not found: {}.{}".format(domain, p_name))
continue continue
success = True success = True
dependencies = getattr(platform, 'DEPENDENCIES', []) dependencies = getattr(platform, 'DEPENDENCIES', [])
for dependency in dependencies: for dependency in dependencies:
if dependency not in _ALL_COMPONENTS: if dependency not in _ALL_COMPONENTS:
result.add_error(u"Platform {}.{} requires {}".format(domain, p_name, result.add_error(u"Platform {}.{} requires component {}".format(domain, p_name,
dependency)) dependency))
success = False success = False
if not success: if not success:
continue continue
@@ -185,6 +247,8 @@ def validate_config(config):
continue continue
platforms.append(p_validated) platforms.append(p_validated)
result[domain] = platforms result[domain] = platforms
do_id_pass(result)
return result return result
@@ -237,8 +301,10 @@ def load_config(path):
try: try:
result = validate_config(config) result = validate_config(config)
except ESPHomeYAMLError:
raise
except Exception: except Exception:
print(u"Unexpected exception while reading configuration:") _LOGGER.error(u"Unexpected exception while reading configuration:")
raise raise
return result return result
@@ -279,18 +345,18 @@ def dump_dict(layer, indent_count=3, listi=False, **kwargs):
def read_config(path): def read_config(path):
_LOGGER.debug("Reading configuration...") _LOGGER.info("Reading configuration...")
try: try:
res = load_config(path) res = load_config(path)
except ESPHomeYAMLError as err: except ESPHomeYAMLError as err:
_LOGGER.error(u"Error while reading config: %s", err) _LOGGER.error(u"Error while reading config: %s", err)
return None return None
excepts = {} excepts = {}
for err in res.errors: for message, domain, config in res.errors:
domain = err[1] or u"General Error" domain = domain or u"General Error"
excepts.setdefault(domain, []).append(err[0]) excepts.setdefault(domain, []).append(message)
if err[2] is not None: if config is not None:
excepts[domain].append(err[2]) excepts[domain].append(config)
if excepts: if excepts:
print(color('bold_white', u"Failed config")) print(color('bold_white', u"Failed config"))

View File

@@ -4,6 +4,7 @@ from __future__ import print_function
import logging import logging
import re import re
import uuid as uuid_
import voluptuous as vol import voluptuous as vol
@@ -11,10 +12,9 @@ from esphomeyaml import core
from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
CONF_NAME, CONF_PAYLOAD_AVAILABLE, \ CONF_NAME, CONF_PAYLOAD_AVAILABLE, \
CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \ CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, CONF_INTERNAL
from esphomeyaml.core import HexInt, IPAddress, TimePeriod, TimePeriodMicroseconds, \ from esphomeyaml.core import HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds, Lambda TimePeriodMilliseconds, TimePeriodSeconds
from esphomeyaml.helpers import ensure_unique_string
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -57,8 +57,10 @@ def alphanumeric(value):
def valid_name(value): def valid_name(value):
value = string_strict(value) value = string_strict(value)
if not all(c in ALLOWED_NAME_CHARS for c in value): for c in value:
raise vol.Invalid(u"Valid characters for name are {}".format(ALLOWED_NAME_CHARS)) if c not in ALLOWED_NAME_CHARS:
raise vol.Invalid(u"'{}' is an invalid character for names. Valid characters are: {}"
u"".format(c, ALLOWED_NAME_CHARS))
return value return value
@@ -136,7 +138,7 @@ def int_(value):
hex_int = vol.Coerce(hex_int_) hex_int = vol.Coerce(hex_int_)
def variable_id(value): def variable_id_str_(value):
value = string(value) value = string(value)
if not value: if not value:
raise vol.Invalid("ID must not be empty") raise vol.Invalid("ID must not be empty")
@@ -153,11 +155,32 @@ def variable_id(value):
return value return value
def use_variable_id(type):
def validator(value):
if value is None:
return core.ID(None, is_declaration=False, type=type)
return core.ID(variable_id_str_(value), is_declaration=False, type=type)
return validator
def declare_variable_id(type):
def validator(value):
if value is None:
return core.ID(None, is_declaration=True, type=type)
return core.ID(variable_id_str_(value), is_declaration=True, type=type)
return validator
def templatable(other_validators): def templatable(other_validators):
def validator(value): def validator(value):
if isinstance(value, Lambda): if isinstance(value, Lambda):
return value return value
return other_validators(value) return other_validators(value)
return validator return validator
@@ -194,7 +217,7 @@ def has_at_least_one_key(*keys):
return validate return validate
def has_at_exactly_one_key(*keys): def has_exactly_one_key(*keys):
def validate(obj): def validate(obj):
if not isinstance(obj, dict): if not isinstance(obj, dict):
raise vol.Invalid('expected dictionary') raise vol.Invalid('expected dictionary')
@@ -225,14 +248,6 @@ time_period_dict = vol.All(
lambda value: TimePeriod(**value)) lambda value: TimePeriod(**value))
TIME_PERIOD_EXPLICIT_MESSAGE = ("The old way of being able to write time values without a "
"time unit (like \"1000\" for 1000 milliseconds) has been "
"removed in 1.5.0 as it was ambiguous in some places. Please "
"now explicitly specify the time unit (like \"1000ms\"). See "
"https://esphomelib.com/esphomeyaml/configuration-types.html#time "
"for more information.")
def time_period_str_colon(value): def time_period_str_colon(value):
"""Validate and transform time offset with format HH:MM[:SS].""" """Validate and transform time offset with format HH:MM[:SS]."""
if isinstance(value, int): if isinstance(value, int):
@@ -263,13 +278,6 @@ def time_period_str_unit(value):
elif not isinstance(value, (str, unicode)): elif not isinstance(value, (str, unicode)):
raise vol.Invalid("Expected string for time period with unit.") raise vol.Invalid("Expected string for time period with unit.")
try:
float(value)
except ValueError:
pass
else:
raise vol.Invalid(TIME_PERIOD_EXPLICIT_MESSAGE)
unit_to_kwarg = { unit_to_kwarg = {
'us': 'microseconds', 'us': 'microseconds',
'microseconds': 'microseconds', 'microseconds': 'microseconds',
@@ -318,11 +326,33 @@ time_period = vol.Any(time_period_str_unit, time_period_str_colon, time_period_d
positive_time_period = vol.All(time_period, vol.Range(min=TimePeriod())) positive_time_period = vol.All(time_period, vol.Range(min=TimePeriod()))
positive_time_period_milliseconds = vol.All(positive_time_period, time_period_in_milliseconds_) positive_time_period_milliseconds = vol.All(positive_time_period, time_period_in_milliseconds_)
positive_time_period_seconds = vol.All(positive_time_period, time_period_in_seconds_) positive_time_period_seconds = vol.All(positive_time_period, time_period_in_seconds_)
time_period_microseconds = vol.All(time_period, time_period_in_microseconds_)
positive_time_period_microseconds = vol.All(positive_time_period, time_period_in_microseconds_) positive_time_period_microseconds = vol.All(positive_time_period, time_period_in_microseconds_)
positive_not_null_time_period = vol.All(time_period, positive_not_null_time_period = vol.All(time_period,
vol.Range(min=TimePeriod(), min_included=False)) vol.Range(min=TimePeriod(), min_included=False))
def mac_address(value):
value = string_strict(value)
parts = value.split(':')
if len(parts) != 6:
raise vol.Invalid("MAC Address must consist of 6 : (colon) separated parts")
parts_int = []
if any(len(part) != 2 for part in parts):
raise vol.Invalid("MAC Address must be format XX:XX:XX:XX:XX:XX")
for part in parts:
try:
parts_int.append(int(part, 16))
except ValueError:
raise vol.Invalid("MAC Address parts must be hexadecimal values from 00 to FF")
return core.MACAddress(*parts_int)
def uuid(value):
return vol.Coerce(uuid_.UUID)(value)
METRIC_SUFFIXES = { METRIC_SUFFIXES = {
'E': 1e18, 'P': 1e15, 'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'da': 10, 'd': 1e-1, 'E': 1e18, 'P': 1e15, 'T': 1e12, 'G': 1e9, 'M': 1e6, 'k': 1e3, 'da': 10, 'd': 1e-1,
'c': 1e-2, 'm': 0.001, u'µ': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18, 'c': 1e-2, 'm': 0.001, u'µ': 1e-6, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15, 'a': 1e-18,
@@ -346,6 +376,23 @@ def frequency(value):
return mantissa * multiplier return mantissa * multiplier
def validate_bytes(value):
value = string(value)
match = re.match(r"^([0-9]+)\s*(\w*?)(?:byte|B|b)?s?$", value)
if match is None:
raise vol.Invalid(u"Expected number of bytes with unit, got {}".format(value))
mantissa = int(match.group(1))
if match.group(2) not in METRIC_SUFFIXES:
raise vol.Invalid(u"Invalid metric suffix {}".format(match.group(2)))
multiplier = METRIC_SUFFIXES[match.group(2)]
if multiplier < 1:
raise vol.Invalid(u"Only suffixes with positive exponents are supported. "
u"Got {}".format(match.group(2)))
return int(mantissa * multiplier)
def hostname(value): def hostname(value):
value = string(value) value = string(value)
if len(value) > 63: if len(value) > 63:
@@ -476,9 +523,16 @@ def percentage(value):
return zero_to_one_float(value) return zero_to_one_float(value)
def percentage_int(value):
if isinstance(value, (str, unicode)) and value.endswith('%'):
value = int(value[:-1].rstrip())
return value
def invalid(message): def invalid(message):
def validator(value): def validator(value):
raise vol.Invalid(message) raise vol.Invalid(message)
return validator return validator
@@ -493,6 +547,7 @@ def one_of(*values):
if value not in values: if value not in values:
raise vol.Invalid(u"Unknown value '{}', must be one of {}".format(value, options)) raise vol.Invalid(u"Unknown value '{}', must be one of {}".format(value, options))
return value return value
return validator return validator
@@ -505,26 +560,27 @@ def lambda_(value):
REGISTERED_IDS = set() REGISTERED_IDS = set()
def register_variable_id(value):
s = variable_id(value)
if s in REGISTERED_IDS:
raise vol.Invalid("This ID has already been used")
REGISTERED_IDS.add(s)
return s
class GenerateID(vol.Optional): class GenerateID(vol.Optional):
def __init__(self, basename, key=CONF_ID): def __init__(self, key=CONF_ID):
self._basename = basename super(GenerateID, self).__init__(key, default=lambda: None)
super(GenerateID, self).__init__(key, default=self.default_variable_id)
def default_variable_id(self):
return ensure_unique_string(self._basename, REGISTERED_IDS)
REQUIRED_ID_SCHEMA = vol.Schema({ def nameable(*schemas):
vol.Required(CONF_ID): register_variable_id, def validator(config):
}) config = vol.All(*schemas)(config)
if CONF_NAME not in config and CONF_ID not in config:
raise vol.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 vol.Invalid("At least one of 'id:' or 'name:' is required!")
config[CONF_NAME] = id.id
config[CONF_INTERNAL] = True
return config
return config
return validator
PLATFORM_SCHEMA = vol.Schema({ PLATFORM_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): valid, vol.Required(CONF_PLATFORM): valid,
@@ -537,11 +593,12 @@ MQTT_COMPONENT_AVAILABILITY_SCHEMA = vol.Schema({
}) })
MQTT_COMPONENT_SCHEMA = vol.Schema({ MQTT_COMPONENT_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): string, vol.Optional(CONF_NAME): string,
vol.Optional(CONF_RETAIN): boolean, vol.Optional(CONF_RETAIN): boolean,
vol.Optional(CONF_DISCOVERY): boolean, vol.Optional(CONF_DISCOVERY): boolean,
vol.Optional(CONF_STATE_TOPIC): publish_topic, vol.Optional(CONF_STATE_TOPIC): publish_topic,
vol.Optional(CONF_AVAILABILITY): MQTT_COMPONENT_AVAILABILITY_SCHEMA, vol.Optional(CONF_AVAILABILITY): vol.Any(None, MQTT_COMPONENT_AVAILABILITY_SCHEMA),
vol.Optional(CONF_INTERNAL): boolean,
}) })
MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({

View File

@@ -1,7 +1,7 @@
"""Constants used by esphomeyaml.""" """Constants used by esphomeyaml."""
MAJOR_VERSION = 1 MAJOR_VERSION = 1
MINOR_VERSION = 6 MINOR_VERSION = 7
PATCH_VERSION = '0' PATCH_VERSION = '0'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
@@ -148,7 +148,6 @@ CONF_TRIGGER_PIN = 'trigger_pin'
CONF_ECHO_PIN = 'echo_pin' CONF_ECHO_PIN = 'echo_pin'
CONF_TIMEOUT_METER = 'timeout_meter' CONF_TIMEOUT_METER = 'timeout_meter'
CONF_TIMEOUT_TIME = 'timeout_time' CONF_TIMEOUT_TIME = 'timeout_time'
CONF_IR_TRANSMITTER_ID = 'ir_transmitter_id'
CONF_CARRIER_DUTY_PERCENT = 'carrier_duty_percent' CONF_CARRIER_DUTY_PERCENT = 'carrier_duty_percent'
CONF_NEC = 'nec' CONF_NEC = 'nec'
CONF_COMMAND = 'command' CONF_COMMAND = 'command'
@@ -231,6 +230,23 @@ CONF_CLOSE_ACTION = 'close_action'
CONF_STOP_ACTION = 'stop_action' CONF_STOP_ACTION = 'stop_action'
CONF_DOMAIN = 'domain' CONF_DOMAIN = 'domain'
CONF_OPTIMISTIC = 'optimistic' CONF_OPTIMISTIC = 'optimistic'
CONF_ON_BOOT = 'on_boot'
CONF_ON_SHUTDOWN = 'on_shutdown'
CONF_PRIORITY = 'priority'
CONF_DUMP = 'dump'
CONF_BUFFER_SIZE = 'buffer_size'
CONF_TOLERANCE = 'tolerance'
CONF_FILTER = 'filter'
CONF_IDLE = 'idle'
CONF_NETWORKS = 'networks'
CONF_INTERNAL = 'internal'
CONF_BUILD_PATH = 'build_path'
CONF_REBOOT_TIMEOUT = 'reboot_timeout'
CONF_INVERT = 'invert'
CONF_DELAYED_ON = 'delayed_on'
CONF_DELAYED_OFF = 'delayed_off'
CONF_UUID = 'uuid'
CONF_TYPE = 'type'
ESP32_BOARDS = [ ESP32_BOARDS = [
'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1', 'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1',
@@ -253,3 +269,5 @@ ESP_BOARDS_FOR_PLATFORM = {
ESP_PLATFORM_ESP32: ESP32_BOARDS, ESP_PLATFORM_ESP32: ESP32_BOARDS,
ESP_PLATFORM_ESP8266: ESP8266_BOARDS ESP_PLATFORM_ESP8266: ESP8266_BOARDS
} }
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'

View File

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

Some files were not shown because too many files have changed in this diff Show More