Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7671f0c90 | ||
|
|
639b97ccb2 | ||
|
|
0374b3a0b3 | ||
|
|
7ce753b76f | ||
|
|
05a1089ed2 | ||
|
|
71947bb6ac | ||
|
|
ef54e33b70 | ||
|
|
12f20fc3cf | ||
|
|
ffdcddc18e | ||
|
|
85d70eb5a0 | ||
|
|
ffb793177a | ||
|
|
d3f2fab88a | ||
|
|
0fa52d0ce6 | ||
|
|
cf264a2743 | ||
|
|
433b605bef | ||
|
|
6e60c6493a | ||
|
|
4e63bc96d5 | ||
|
|
ce4b339d16 | ||
|
|
ab6d293d0d | ||
|
|
5e5137960d | ||
|
|
8dba37846b | ||
|
|
5cd82d7c25 | ||
|
|
bc8354bad5 | ||
|
|
2abbe1bca3 | ||
|
|
74c70509c2 | ||
|
|
1576e1847e | ||
|
|
9ea9b4b102 | ||
|
|
490743c26e | ||
|
|
1c7bddd005 | ||
|
|
5c39f73fda | ||
|
|
2fc78a1b33 | ||
|
|
03249780fd | ||
|
|
5170a7cdf4 | ||
|
|
5680de79a9 | ||
|
|
61bd2a3a44 | ||
|
|
7802c63f5a | ||
|
|
94bef2a5a4 | ||
|
|
12c4b0788c | ||
|
|
b13cc3a4a5 | ||
|
|
c5d9bc5452 | ||
|
|
6c6d21a7ab | ||
|
|
9bb06782b2 | ||
|
|
a827b51887 | ||
|
|
2c30d80490 | ||
|
|
e0acdc3ae0 | ||
|
|
36a3f96011 | ||
|
|
6ae8e3495f | ||
|
|
6aa449115f | ||
|
|
0be29d27d5 | ||
|
|
68fa7489a2 | ||
|
|
d7699c93d6 | ||
|
|
a04438e924 | ||
|
|
e063f2aaea | ||
|
|
7b630bfb8b | ||
|
|
ec3366cce0 | ||
|
|
135117714b | ||
|
|
91e6304505 | ||
|
|
361a9da868 | ||
|
|
31d7656c07 | ||
|
|
d1a7751dc9 |
@@ -106,3 +106,5 @@ venv.bak/
|
||||
config/
|
||||
examples/
|
||||
Dockerfile
|
||||
.git/
|
||||
tests/build/
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -104,3 +104,4 @@ venv.bak/
|
||||
.mypy_cache/
|
||||
|
||||
config/
|
||||
tests/build/
|
||||
|
||||
187
.gitlab-ci.yml
Normal file
187
.gitlab-ci.yml
Normal file
@@ -0,0 +1,187 @@
|
||||
---
|
||||
# Based on https://gitlab.com/hassio-addons/addon-node-red/blob/master/.gitlab-ci.yml
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- test
|
||||
- build
|
||||
- deploy
|
||||
|
||||
.lint: &lint
|
||||
stage: lint
|
||||
tags:
|
||||
- python2.7
|
||||
- esphomeyaml-lint
|
||||
|
||||
.test: &test
|
||||
stage: test
|
||||
before_script:
|
||||
- pip install -e .
|
||||
tags:
|
||||
- python2.7
|
||||
- esphomeyaml-test
|
||||
variables:
|
||||
TZ: UTC
|
||||
cache:
|
||||
paths:
|
||||
- tests/build
|
||||
|
||||
.docker-builder: &docker-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
|
||||
|
||||
test1:
|
||||
<<: *test
|
||||
script:
|
||||
- esphomeyaml tests/test1.yaml compile
|
||||
|
||||
test2:
|
||||
<<: *test
|
||||
script:
|
||||
- esphomeyaml tests/test2.yaml compile
|
||||
|
||||
.build-hassio: &build-hassio
|
||||
<<: *docker-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"
|
||||
retry: 2
|
||||
|
||||
# Generic deploy template
|
||||
.deploy: &deploy
|
||||
<<: *docker-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}" \
|
||||
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
|
||||
- |
|
||||
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 "${CI_REGISTRY}/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:normal:
|
||||
<<: *docker-builder
|
||||
stage: build
|
||||
script:
|
||||
- docker build -t "${CI_REGISTRY}/ottowinter/esphomeyaml:dev" .
|
||||
- |
|
||||
docker tag \
|
||||
"${CI_REGISTRY}/ottowinter/esphomeyaml:dev" \
|
||||
"${CI_REGISTRY}/ottowinter/esphomeyaml:${CI_COMMIT_SHA}"
|
||||
- docker push "${CI_REGISTRY}/ottowinter/esphomeyaml:${CI_COMMIT_SHA}"
|
||||
- docker push "${CI_REGISTRY}/ottowinter/esphomeyaml:dev"
|
||||
|
||||
build:armhf:
|
||||
<<: *build-hassio
|
||||
variables:
|
||||
ADDON_ARCH: armhf
|
||||
|
||||
#build:aarch64:
|
||||
# <<: *build
|
||||
# variables:
|
||||
# ADDON_ARCH: aarch64
|
||||
|
||||
build:i386:
|
||||
<<: *build-hassio
|
||||
variables:
|
||||
ADDON_ARCH: i386
|
||||
|
||||
build:amd64:
|
||||
<<: *build-hassio
|
||||
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).+@/
|
||||
|
||||
deploy:pypi:
|
||||
stage: deploy
|
||||
before_script:
|
||||
- pip install -e .
|
||||
- pip install twine
|
||||
script:
|
||||
- python setup.py sdist
|
||||
- twine upload dist/*
|
||||
tags:
|
||||
- python2.7
|
||||
- esphomeyaml-test
|
||||
only:
|
||||
- /^v\d+\.\d+\.\d+(?:(?:(?:\+|\.)?[a-zA-Z0-9]+)*)?$/
|
||||
except:
|
||||
- /^(?!master).+@/
|
||||
22
.travis.yml
22
.travis.yml
@@ -2,9 +2,19 @@ sudo: false
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
- pip install tornado esptool flake8==3.5.0 pylint==1.8.4
|
||||
script:
|
||||
- flake8 esphomeyaml
|
||||
- pylint esphomeyaml
|
||||
jobs:
|
||||
include:
|
||||
- name: "Lint"
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
- pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow
|
||||
script:
|
||||
- flake8 esphomeyaml
|
||||
- pylint esphomeyaml
|
||||
- name: "Test"
|
||||
install:
|
||||
- pip install -e .
|
||||
- pip install tzlocal pillow
|
||||
script:
|
||||
- esphomeyaml tests/test1.yaml compile
|
||||
- esphomeyaml tests/test2.yaml compile
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -1,21 +1,26 @@
|
||||
FROM python:2.7
|
||||
MAINTAINER Otto Winter <contact@otto-winter.com>
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python-pil \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV ESPHOMEYAML_OTA_HOST_PORT=6123
|
||||
EXPOSE 6123
|
||||
VOLUME /config
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY requirements.txt /usr/src/app/
|
||||
RUN pip install --no-cache-dir -r requirements.txt && \
|
||||
pip install --no-cache-dir tornado esptool
|
||||
RUN pip install --no-cache-dir --no-binary :all: platformio && \
|
||||
platformio settings set enable_telemetry No
|
||||
|
||||
COPY docker/platformio.ini /usr/src/app/
|
||||
RUN platformio settings set enable_telemetry No && \
|
||||
platformio run -e espressif32 -e espressif8266; exit 0
|
||||
|
||||
COPY . .
|
||||
RUN pip install -e .
|
||||
RUN pip install --no-cache-dir -e . && \
|
||||
pip install --no-cache-dir tzlocal pillow
|
||||
|
||||
WORKDIR /config
|
||||
ENTRYPOINT ["esphomeyaml"]
|
||||
CMD ["/config", "dashboard"]
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Otto Winter
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
21
docker/Dockerfile.aarch64
Normal file
21
docker/Dockerfile.aarch64
Normal file
@@ -0,0 +1,21 @@
|
||||
# Dockerfile for aarch64 version of HassIO add-on
|
||||
FROM arm64v8/ubuntu:bionic
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python \
|
||||
python-pip \
|
||||
python-setuptools \
|
||||
python-pil \
|
||||
git \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*rm -rf /var/lib/apt/lists/* /tmp/* && \
|
||||
pip install --no-cache-dir --no-binary :all: platformio && \
|
||||
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 . && \
|
||||
pip install --no-cache-dir --no-binary :all: tzlocal
|
||||
|
||||
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
|
||||
21
docker/Dockerfile.amd64
Normal file
21
docker/Dockerfile.amd64
Normal file
@@ -0,0 +1,21 @@
|
||||
# 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 \
|
||||
python-pil \
|
||||
git \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*rm -rf /var/lib/apt/lists/* /tmp/* && \
|
||||
pip install --no-cache-dir --no-binary :all: platformio && \
|
||||
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 . && \
|
||||
pip install --no-cache-dir --no-binary :all: tzlocal
|
||||
|
||||
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
|
||||
31
docker/Dockerfile.armhf
Normal file
31
docker/Dockerfile.armhf
Normal file
@@ -0,0 +1,31 @@
|
||||
# Dockerfile for armhf version of HassIO add-on
|
||||
FROM homeassistant/armhf-base:latest
|
||||
|
||||
RUN apk add --no-cache \
|
||||
python2 \
|
||||
python2-dev \
|
||||
py2-pip \
|
||||
git \
|
||||
gcc \
|
||||
openssh \
|
||||
libc6-compat \
|
||||
jpeg-dev \
|
||||
zlib-dev \
|
||||
freetype-dev \
|
||||
lcms2-dev \
|
||||
openjpeg-dev \
|
||||
tiff-dev \
|
||||
libc-dev \
|
||||
linux-headers \
|
||||
&& \
|
||||
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 . && \
|
||||
pip install --no-cache-dir pillow tzlocal
|
||||
|
||||
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
|
||||
32
docker/Dockerfile.builder
Normal file
32
docker/Dockerfile.builder
Normal 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 docker/hassio-builder.sh /usr/bin/
|
||||
|
||||
WORKDIR /data
|
||||
21
docker/Dockerfile.i386
Normal file
21
docker/Dockerfile.i386
Normal file
@@ -0,0 +1,21 @@
|
||||
# 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 \
|
||||
python-pil \
|
||||
git \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*rm -rf /var/lib/apt/lists/* /tmp/* && \
|
||||
pip install --no-cache-dir --no-binary :all: platformio && \
|
||||
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 . && \
|
||||
pip install --no-cache-dir --no-binary :all: tzlocal
|
||||
|
||||
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
|
||||
6
docker/Dockerfile.lint
Normal file
6
docker/Dockerfile.lint
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM python:2.7
|
||||
|
||||
COPY requirements.txt /requirements.txt
|
||||
|
||||
RUN pip install -r /requirements.txt && \
|
||||
pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow
|
||||
19
docker/Dockerfile.test
Normal file
19
docker/Dockerfile.test
Normal file
@@ -0,0 +1,19 @@
|
||||
FROM ubuntu:bionic
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python \
|
||||
python-pip \
|
||||
python-setuptools \
|
||||
python-pil \
|
||||
git \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*rm -rf /var/lib/apt/lists/* /tmp/* && \
|
||||
pip install --no-cache-dir --no-binary :all: platformio && \
|
||||
platformio settings set enable_telemetry No
|
||||
|
||||
COPY docker/platformio.ini /pio/platformio.ini
|
||||
RUN platformio run -d /pio; rm -rf /pio
|
||||
|
||||
COPY requirements.txt /requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir -r /requirements.txt && \
|
||||
pip install --no-cache-dir tzlocal pillow
|
||||
318
docker/hassio-builder.sh
Executable file
318
docker/hassio-builder.sh
Executable 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
|
||||
7
docker/platformio-esp8266.ini
Normal file
7
docker/platformio-esp8266.ini
Normal 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
|
||||
@@ -1,12 +1,12 @@
|
||||
; This file allows the docker build file to install the required platformio
|
||||
; platforms
|
||||
|
||||
[env:espressif32]
|
||||
platform = espressif32
|
||||
board = nodemcu-32s
|
||||
framework = arduino
|
||||
|
||||
[env:espressif8266]
|
||||
platform = espressif8266
|
||||
board = nodemcuv2
|
||||
framework = arduino
|
||||
|
||||
[env:espressif32]
|
||||
platform = espressif32
|
||||
board = nodemcu-32s
|
||||
framework = arduino
|
||||
|
||||
@@ -16,10 +16,25 @@ ARG BUILD_FROM
|
||||
# * 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 && \
|
||||
python python-pip python-setuptools python-pil git && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/*; \
|
||||
else \
|
||||
apk add --no-cache python2 py2-pip git openssh libc6-compat; \
|
||||
apk add --no-cache \
|
||||
python2 \
|
||||
python2-dev \
|
||||
py2-pip \
|
||||
git \
|
||||
gcc \
|
||||
openssh \
|
||||
libc6-compat \
|
||||
jpeg-dev \
|
||||
zlib-dev \
|
||||
freetype-dev \
|
||||
lcms2-dev \
|
||||
openjpeg-dev \
|
||||
tiff-dev \
|
||||
libc-dev \
|
||||
linux-headers; \
|
||||
fi" && \
|
||||
pip install --no-cache-dir platformio && \
|
||||
platformio settings set enable_telemetry No
|
||||
@@ -38,6 +53,7 @@ RUN /bin/bash -c "if [[ '$BUILD_FROM' = *\"ubuntu\"* ]]; then \
|
||||
|
||||
# Install latest esphomeyaml from git
|
||||
RUN pip install --no-cache-dir \
|
||||
git+git://github.com/OttoWinter/esphomeyaml.git
|
||||
git+git://github.com/OttoWinter/esphomeyaml.git && \
|
||||
pip install --no-cache-dir pillow tzlocal
|
||||
|
||||
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
|
||||
|
||||
@@ -21,9 +21,13 @@
|
||||
"map": [
|
||||
"config:rw"
|
||||
],
|
||||
"options": {},
|
||||
"options": {
|
||||
"password": ""
|
||||
},
|
||||
"schema": {
|
||||
"password": "str?"
|
||||
},
|
||||
"environment": {
|
||||
"ESPHOMEYAML_OTA_HOST_PORT": "6053"
|
||||
},
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Dockerfile for HassIO add-on
|
||||
ARG BUILD_FROM=ubuntu:bionic
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# Re-declare BUILD_FROM to fix weird docker issue
|
||||
ARG BUILD_FROM
|
||||
ARG BUILD_VERSION
|
||||
|
||||
# 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; \
|
||||
else \
|
||||
echo \"\$(head -8 /pio/platformio.ini)\" >/pio/platformio.ini; \
|
||||
platformio run -e espressif8266 -d /pio; \
|
||||
fi"; exit 0
|
||||
|
||||
# Install latest esphomeyaml from git
|
||||
RUN pip install --no-cache-dir \
|
||||
esphomeyaml==${BUILD_VERSION}
|
||||
|
||||
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
|
||||
@@ -7,27 +7,21 @@ import random
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
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.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, CONF_HOSTNAME, \
|
||||
CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml import const, core, core_config, mqtt, wizard, writer, yaml_util
|
||||
from esphomeyaml.config import get_component, iter_components, read_config
|
||||
from esphomeyaml.const import CONF_BAUD_RATE, CONF_BUILD_PATH, CONF_DOMAIN, CONF_ESPHOMEYAML, \
|
||||
CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \
|
||||
CONF_WIFI, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \
|
||||
add_job, color, flush_tasks, indent, quote, statement
|
||||
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, \
|
||||
_EXPRESSIONS, add, \
|
||||
add_job, color, flush_tasks, indent, quote, statement, relative_path
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'web_server', 'i2c']
|
||||
|
||||
|
||||
def get_name(config):
|
||||
return config[CONF_ESPHOMEYAML][CONF_NAME]
|
||||
|
||||
|
||||
def get_base_path(config):
|
||||
return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config))
|
||||
|
||||
|
||||
def get_serial_ports():
|
||||
# from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py
|
||||
from serial.tools.list_ports import comports
|
||||
@@ -97,12 +91,22 @@ def run_platformio(*cmd, **kwargs):
|
||||
|
||||
def run_miniterm(config, port, escape=False):
|
||||
import serial
|
||||
baud_rate = config.get(CONF_LOGGER, {}).get(CONF_BAUD_RATE, 115200)
|
||||
if CONF_LOGGER not in config:
|
||||
_LOGGER.info("Logger is not enabled. Not starting UART logs.")
|
||||
return
|
||||
baud_rate = config['logger'][CONF_BAUD_RATE]
|
||||
if baud_rate == 0:
|
||||
_LOGGER.info("UART logging is disabled (baud_rate=0). Not starting UART logs.")
|
||||
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
|
||||
|
||||
with serial.Serial(port, baudrate=baud_rate) as ser:
|
||||
while True:
|
||||
line = ser.readline().replace('\r', '').replace('\n', '')
|
||||
try:
|
||||
raw = ser.readline()
|
||||
except serial.SerialException:
|
||||
_LOGGER.error("Serial port closed!")
|
||||
return
|
||||
line = raw.replace('\r', '').replace('\n', '')
|
||||
time = datetime.now().time().strftime('[%H:%M:%S]')
|
||||
message = time + line
|
||||
if escape:
|
||||
@@ -116,7 +120,7 @@ def run_miniterm(config, port, escape=False):
|
||||
def write_cpp(config):
|
||||
_LOGGER.info("Generating C++ source...")
|
||||
|
||||
add_job(core_to_code, config[CONF_ESPHOMEYAML], domain='esphomeyaml')
|
||||
add_job(core_config.to_code, config[CONF_ESPHOMEYAML], domain='esphomeyaml')
|
||||
for domain in PRE_INITIALIZE:
|
||||
if domain == CONF_ESPHOMEYAML or domain not in config:
|
||||
continue
|
||||
@@ -132,7 +136,7 @@ def write_cpp(config):
|
||||
add(RawStatement(''))
|
||||
all_code = []
|
||||
for exp in _EXPRESSIONS:
|
||||
if core.SIMPLIFY:
|
||||
if not config[CONF_ESPHOMEYAML][CONF_USE_CUSTOM_CODE]:
|
||||
if isinstance(exp, Expression) and not exp.required:
|
||||
continue
|
||||
if isinstance(exp, AssignmentExpression) and not exp.obj.required:
|
||||
@@ -141,19 +145,19 @@ def write_cpp(config):
|
||||
exp = exp.rhs
|
||||
all_code.append(unicode(statement(exp)))
|
||||
|
||||
platformio_ini_s = writer.get_ini_content(config)
|
||||
ini_path = os.path.join(get_base_path(config), 'platformio.ini')
|
||||
writer.write_platformio_ini(platformio_ini_s, ini_path)
|
||||
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
|
||||
writer.write_platformio_project(config, build_path)
|
||||
|
||||
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(build_path, 'src', 'main.cpp')
|
||||
writer.write_cpp(code_s, cpp_path)
|
||||
return 0
|
||||
|
||||
|
||||
def compile_program(args, config):
|
||||
_LOGGER.info("Compiling app...")
|
||||
command = ['platformio', 'run', '-d', get_base_path(config)]
|
||||
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
|
||||
command = ['platformio', 'run', '-d', build_path]
|
||||
if args.verbose:
|
||||
command.append('-v')
|
||||
return run_platformio(*command)
|
||||
@@ -172,8 +176,8 @@ def get_upload_host(config):
|
||||
def upload_using_esptool(config, port):
|
||||
import esptool
|
||||
|
||||
name = get_name(config)
|
||||
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
|
||||
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
|
||||
path = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin')
|
||||
# pylint: disable=protected-access
|
||||
return run_platformio('esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
|
||||
'--chip', 'esp8266', '--port', port, 'write_flash', '0x0',
|
||||
@@ -182,10 +186,14 @@ def upload_using_esptool(config, port):
|
||||
|
||||
def upload_program(config, args, port):
|
||||
_LOGGER.info("Uploading binary...")
|
||||
if port != 'OTA':
|
||||
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
|
||||
|
||||
# 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:
|
||||
return upload_using_esptool(config, port)
|
||||
command = ['platformio', 'run', '-d', get_base_path(config),
|
||||
command = ['platformio', 'run', '-d', build_path,
|
||||
'-t', 'upload', '--upload-port', port]
|
||||
if args.verbose:
|
||||
command.append('-v')
|
||||
@@ -195,12 +203,17 @@ def upload_program(config, args, port):
|
||||
_LOGGER.error("No serial port found and OTA not enabled. Can't upload!")
|
||||
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 import espota
|
||||
|
||||
bin_file = os.path.join(get_base_path(config), '.pioenvs', get_name(config), 'firmware.bin')
|
||||
bin_file = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin')
|
||||
if args.host_port is not None:
|
||||
host_port = args.host_port
|
||||
else:
|
||||
@@ -214,7 +227,8 @@ def upload_program(config, args, port):
|
||||
|
||||
|
||||
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)
|
||||
return 0
|
||||
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id,
|
||||
@@ -286,6 +300,9 @@ def command_compile(args, config):
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
if args.only_generate:
|
||||
_LOGGER.info(u"Successfully generated source code.")
|
||||
return 0
|
||||
exit_code = compile_program(args, config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
@@ -371,7 +388,11 @@ def parse_args(argv):
|
||||
subparsers.required = True
|
||||
subparsers.add_parser('config', help='Validate the configuration and spit it out.')
|
||||
|
||||
subparsers.add_parser('compile', help='Read the configuration and compile a program.')
|
||||
parser_compile = subparsers.add_parser('compile',
|
||||
help='Read the configuration and compile a program.')
|
||||
parser_compile.add_argument('--only-generate',
|
||||
help="Only generate source code, do not compile.",
|
||||
action='store_true')
|
||||
|
||||
parser_upload = subparsers.add_parser('upload', help='Validate the configuration '
|
||||
'and upload the latest binary.')
|
||||
@@ -395,7 +416,7 @@ def parse_args(argv):
|
||||
|
||||
parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, '
|
||||
'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.")
|
||||
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.',
|
||||
@@ -428,6 +449,10 @@ def parse_args(argv):
|
||||
help="Create a simple webserver for a dashboard.")
|
||||
dashboard.add_argument("--port", help="The HTTP port to open connections on.", type=int,
|
||||
default=6052)
|
||||
dashboard.add_argument("--password", help="The optional password to require for all requests.",
|
||||
type=str, default='')
|
||||
dashboard.add_argument("--open-ui", help="Open the dashboard UI in a browser.",
|
||||
action='store_true')
|
||||
|
||||
return parser.parse_args(argv[1:])
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import cover, fan
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml.components import cover, deep_sleep, fan, output
|
||||
from esphomeyaml.const import CONF_ABOVE, CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, \
|
||||
CONF_BELOW, \
|
||||
CONF_BLUE, CONF_BRIGHTNESS, CONF_CONDITION_ID, CONF_DELAY, CONF_EFFECT, CONF_FLASH_LENGTH, \
|
||||
CONF_GREEN, CONF_ID, CONF_IF, CONF_LAMBDA, CONF_OR, CONF_OSCILLATING, CONF_PAYLOAD, CONF_QOS, \
|
||||
CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_SPEED, CONF_THEN, CONF_TOPIC, CONF_TRANSITION_LENGTH, \
|
||||
CONF_TRIGGER_ID, CONF_WHITE
|
||||
CONF_BELOW, CONF_BLUE, CONF_BRIGHTNESS, CONF_CONDITION, CONF_CONDITION_ID, CONF_DELAY, \
|
||||
CONF_EFFECT, CONF_ELSE, CONF_FLASH_LENGTH, CONF_GREEN, CONF_ID, CONF_IF, CONF_LAMBDA, \
|
||||
CONF_LEVEL, CONF_OR, CONF_OSCILLATING, CONF_PAYLOAD, CONF_QOS, CONF_RANGE, CONF_RED, \
|
||||
CONF_RETAIN, CONF_SPEED, CONF_THEN, CONF_TOPIC, CONF_TRANSITION_LENGTH, CONF_TRIGGER_ID, \
|
||||
CONF_WHITE, CONF_COLOR_TEMPERATURE
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, \
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, add_job, \
|
||||
bool_, esphomelib_ns, float_, get_variable, process_lambda, std_string, templatable, uint32, \
|
||||
uint8, add_job
|
||||
uint8
|
||||
|
||||
CONF_MQTT_PUBLISH = 'mqtt.publish'
|
||||
CONF_LIGHT_TOGGLE = 'light.toggle'
|
||||
@@ -26,11 +27,37 @@ CONF_COVER_STOP = 'cover.stop'
|
||||
CONF_FAN_TOGGLE = 'fan.toggle'
|
||||
CONF_FAN_TURN_OFF = 'fan.turn_off'
|
||||
CONF_FAN_TURN_ON = 'fan.turn_on'
|
||||
CONF_OUTPUT_TURN_ON = 'output.turn_on'
|
||||
CONF_OUTPUT_TURN_OFF = 'output.turn_off'
|
||||
CONF_OUTPUT_SET_LEVEL = 'output.set_level'
|
||||
CONF_DEEP_SLEEP_ENTER = 'deep_sleep.enter'
|
||||
CONF_DEEP_SLEEP_PREVENT = 'deep_sleep.prevent'
|
||||
|
||||
|
||||
def maybe_simple_id(*validators):
|
||||
validator = vol.All(*validators)
|
||||
|
||||
def validate(value):
|
||||
if isinstance(value, dict):
|
||||
return validator(value)
|
||||
return validator({CONF_ID: value})
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
def validate_recursive_condition(value):
|
||||
return CONDITIONS_SCHEMA(value)
|
||||
|
||||
|
||||
def validate_recursive_action(value):
|
||||
return ACTIONS_SCHEMA(value)
|
||||
|
||||
|
||||
ACTION_KEYS = [CONF_DELAY, CONF_MQTT_PUBLISH, CONF_LIGHT_TOGGLE, CONF_LIGHT_TURN_OFF,
|
||||
CONF_LIGHT_TURN_ON, CONF_SWITCH_TOGGLE, CONF_SWITCH_TURN_OFF, CONF_SWITCH_TURN_ON,
|
||||
CONF_LAMBDA, CONF_COVER_OPEN, CONF_COVER_CLOSE, CONF_COVER_STOP, CONF_FAN_TOGGLE,
|
||||
CONF_FAN_TURN_OFF, CONF_FAN_TURN_ON]
|
||||
CONF_FAN_TURN_OFF, CONF_FAN_TURN_ON, CONF_OUTPUT_TURN_ON, CONF_OUTPUT_TURN_OFF,
|
||||
CONF_OUTPUT_SET_LEVEL, CONF_IF, CONF_DEEP_SLEEP_ENTER, CONF_DEEP_SLEEP_PREVENT]
|
||||
|
||||
ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
cv.GenerateID(CONF_ACTION_ID): cv.declare_variable_id(None),
|
||||
@@ -41,15 +68,15 @@ ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
vol.Optional(CONF_QOS): cv.templatable(cv.mqtt_qos),
|
||||
vol.Optional(CONF_RETAIN): cv.templatable(cv.boolean),
|
||||
}),
|
||||
vol.Optional(CONF_LIGHT_TOGGLE): vol.Schema({
|
||||
vol.Optional(CONF_LIGHT_TOGGLE): maybe_simple_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_LIGHT_TURN_OFF): vol.Schema({
|
||||
vol.Optional(CONF_LIGHT_TURN_OFF): maybe_simple_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_LIGHT_TURN_ON): vol.Schema({
|
||||
vol.Optional(CONF_LIGHT_TURN_ON): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
vol.Exclusive(CONF_TRANSITION_LENGTH, 'transformer'):
|
||||
cv.templatable(cv.positive_time_period_milliseconds),
|
||||
@@ -60,62 +87,78 @@ ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
vol.Optional(CONF_GREEN): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_BLUE): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_WHITE): cv.templatable(cv.percentage),
|
||||
vol.Optional(CONF_COLOR_TEMPERATURE): cv.templatable(cv.positive_float),
|
||||
vol.Optional(CONF_EFFECT): cv.templatable(cv.string),
|
||||
}),
|
||||
vol.Optional(CONF_SWITCH_TOGGLE): vol.Schema({
|
||||
vol.Optional(CONF_SWITCH_TOGGLE): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_SWITCH_TURN_OFF): vol.Schema({
|
||||
vol.Optional(CONF_SWITCH_TURN_OFF): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_SWITCH_TURN_ON): vol.Schema({
|
||||
vol.Optional(CONF_SWITCH_TURN_ON): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_COVER_OPEN): vol.Schema({
|
||||
vol.Optional(CONF_COVER_OPEN): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_COVER_CLOSE): vol.Schema({
|
||||
vol.Optional(CONF_COVER_CLOSE): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_COVER_STOP): vol.Schema({
|
||||
vol.Optional(CONF_COVER_STOP): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_COVER_OPEN): vol.Schema({
|
||||
vol.Optional(CONF_COVER_OPEN): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_COVER_CLOSE): vol.Schema({
|
||||
vol.Optional(CONF_COVER_CLOSE): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_COVER_STOP): vol.Schema({
|
||||
vol.Optional(CONF_COVER_STOP): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_FAN_TOGGLE): vol.Schema({
|
||||
vol.Optional(CONF_FAN_TOGGLE): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_FAN_TURN_OFF): vol.Schema({
|
||||
vol.Optional(CONF_FAN_TURN_OFF): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_FAN_TURN_ON): vol.Schema({
|
||||
vol.Optional(CONF_FAN_TURN_ON): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
vol.Optional(CONF_OSCILLATING): cv.templatable(cv.boolean),
|
||||
vol.Optional(CONF_SPEED): cv.templatable(fan.validate_fan_speed),
|
||||
}),
|
||||
vol.Optional(CONF_OUTPUT_TURN_OFF): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
}),
|
||||
vol.Optional(CONF_OUTPUT_TURN_ON): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None)
|
||||
}),
|
||||
vol.Optional(CONF_OUTPUT_SET_LEVEL): {
|
||||
vol.Required(CONF_ID): cv.use_variable_id(None),
|
||||
vol.Required(CONF_LEVEL): cv.percentage,
|
||||
},
|
||||
vol.Optional(CONF_DEEP_SLEEP_ENTER): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(deep_sleep.DeepSleepComponent),
|
||||
}),
|
||||
vol.Optional(CONF_DEEP_SLEEP_PREVENT): maybe_simple_id({
|
||||
vol.Required(CONF_ID): cv.use_variable_id(deep_sleep.DeepSleepComponent),
|
||||
}),
|
||||
vol.Optional(CONF_IF): vol.All({
|
||||
vol.Required(CONF_CONDITION): validate_recursive_condition,
|
||||
vol.Optional(CONF_THEN): validate_recursive_action,
|
||||
vol.Optional(CONF_ELSE): validate_recursive_action,
|
||||
}, cv.has_at_least_one_key(CONF_THEN, CONF_ELSE)),
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
}, cv.has_exactly_one_key(*ACTION_KEYS))])
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
DelayAction = esphomelib_ns.DelayAction
|
||||
LambdaAction = esphomelib_ns.LambdaAction
|
||||
IfAction = esphomelib_ns.IfAction
|
||||
Automation = esphomelib_ns.Automation
|
||||
|
||||
|
||||
def validate_recursive_condition(value):
|
||||
return CONDITIONS_SCHEMA(value)
|
||||
|
||||
|
||||
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, [cv.templatable({
|
||||
cv.GenerateID(CONF_CONDITION_ID): cv.declare_variable_id(None),
|
||||
vol.Optional(CONF_AND): validate_recursive_condition,
|
||||
vol.Optional(CONF_OR): validate_recursive_condition,
|
||||
@@ -124,7 +167,7 @@ CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
vol.Optional(CONF_BELOW): vol.Coerce(float),
|
||||
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)),
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
}), cv.has_exactly_one_key(*CONDITION_KEYS)])
|
||||
})])
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
AndCondition = esphomelib_ns.AndCondition
|
||||
@@ -132,6 +175,22 @@ OrCondition = esphomelib_ns.OrCondition
|
||||
RangeCondition = esphomelib_ns.RangeCondition
|
||||
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({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(None),
|
||||
cv.GenerateID(CONF_AUTOMATION_ID): cv.declare_variable_id(None),
|
||||
@@ -142,7 +201,12 @@ AUTOMATION_SCHEMA = vol.Schema({
|
||||
|
||||
def build_condition(config, arg_type):
|
||||
template_arg = TemplateArguments(arg_type)
|
||||
if CONF_AND in config:
|
||||
if isinstance(config, core.Lambda):
|
||||
lambda_ = None
|
||||
for lambda_ in process_lambda(config, [(arg_type, 'x')]):
|
||||
yield
|
||||
yield LambdaCondition.new(template_arg, lambda_)
|
||||
elif CONF_AND in config:
|
||||
yield AndCondition.new(template_arg, build_conditions(config[CONF_AND], template_arg))
|
||||
elif CONF_OR in config:
|
||||
yield OrCondition.new(template_arg, build_conditions(config[CONF_OR], template_arg))
|
||||
@@ -181,201 +245,225 @@ def build_conditions(config, arg_type):
|
||||
yield ArrayInitializer(*conditions)
|
||||
|
||||
|
||||
def build_action(config, arg_type):
|
||||
def build_action(full_config, arg_type):
|
||||
from esphomeyaml.components import light, mqtt, switch
|
||||
|
||||
template_arg = TemplateArguments(arg_type)
|
||||
# Keep pylint from freaking out
|
||||
var = None
|
||||
if CONF_DELAY in config:
|
||||
action_id = full_config[CONF_ACTION_ID]
|
||||
key, config = next((k, v) for k, v in full_config.items() if k in ACTION_KEYS)
|
||||
if key == CONF_DELAY:
|
||||
rhs = App.register_component(DelayAction.new(template_arg))
|
||||
type = DelayAction.template(template_arg)
|
||||
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
template_ = None
|
||||
for template_ in templatable(config[CONF_DELAY], arg_type, uint32):
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
for template_ in templatable(config, arg_type, uint32):
|
||||
yield
|
||||
add(action.set_delay(template_))
|
||||
yield action
|
||||
elif CONF_LAMBDA in config:
|
||||
lambda_ = None
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')]):
|
||||
elif key == CONF_LAMBDA:
|
||||
for lambda_ in process_lambda(config, [(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:
|
||||
conf = config[CONF_MQTT_PUBLISH]
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_MQTT_PUBLISH:
|
||||
rhs = App.Pget_mqtt_client().Pmake_publish_action(template_arg)
|
||||
type = mqtt.MQTTPublishAction.template(template_arg)
|
||||
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_TOPIC], arg_type, std_string):
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
for template_ in templatable(config[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):
|
||||
for template_ in templatable(config[CONF_PAYLOAD], arg_type, std_string):
|
||||
yield None
|
||||
add(action.set_payload(template_))
|
||||
if CONF_QOS in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_QOS], arg_type, uint8):
|
||||
if CONF_QOS in config:
|
||||
for template_ in templatable(config[CONF_QOS], arg_type, uint8):
|
||||
yield
|
||||
add(action.set_qos(template_))
|
||||
if CONF_RETAIN in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_RETAIN], arg_type, bool_):
|
||||
if CONF_RETAIN in config:
|
||||
for template_ in templatable(config[CONF_RETAIN], arg_type, bool_):
|
||||
yield None
|
||||
add(action.set_retain(template_))
|
||||
yield action
|
||||
elif CONF_LIGHT_TOGGLE in config:
|
||||
conf = config[CONF_LIGHT_TOGGLE]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
elif key == CONF_LIGHT_TOGGLE:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_toggle_action(template_arg)
|
||||
type = light.ToggleAction.template(template_arg)
|
||||
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
if CONF_TRANSITION_LENGTH in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32):
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
if CONF_TRANSITION_LENGTH in config:
|
||||
for template_ in templatable(config[CONF_TRANSITION_LENGTH], arg_type, uint32):
|
||||
yield None
|
||||
add(action.set_transition_length(template_))
|
||||
yield action
|
||||
elif CONF_LIGHT_TURN_OFF in config:
|
||||
conf = config[CONF_LIGHT_TURN_OFF]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
elif key == CONF_LIGHT_TURN_OFF:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_off_action(template_arg)
|
||||
type = light.TurnOffAction.template(template_arg)
|
||||
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
if CONF_TRANSITION_LENGTH in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32):
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
if CONF_TRANSITION_LENGTH in config:
|
||||
for template_ in templatable(config[CONF_TRANSITION_LENGTH], arg_type, uint32):
|
||||
yield None
|
||||
add(action.set_transition_length(template_))
|
||||
yield action
|
||||
elif CONF_LIGHT_TURN_ON in config:
|
||||
conf = config[CONF_LIGHT_TURN_ON]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
elif key == CONF_LIGHT_TURN_ON:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_on_action(template_arg)
|
||||
type = light.TurnOnAction.template(template_arg)
|
||||
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
if CONF_TRANSITION_LENGTH in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32):
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
if CONF_TRANSITION_LENGTH in config:
|
||||
for template_ in templatable(config[CONF_TRANSITION_LENGTH], arg_type, uint32):
|
||||
yield None
|
||||
add(action.set_transition_length(template_))
|
||||
if CONF_FLASH_LENGTH in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_FLASH_LENGTH], arg_type, uint32):
|
||||
if CONF_FLASH_LENGTH in config:
|
||||
for template_ in templatable(config[CONF_FLASH_LENGTH], arg_type, uint32):
|
||||
yield None
|
||||
add(action.set_flash_length(template_))
|
||||
if CONF_BRIGHTNESS in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_BRIGHTNESS], arg_type, float_):
|
||||
if CONF_BRIGHTNESS in config:
|
||||
for template_ in templatable(config[CONF_BRIGHTNESS], arg_type, float_):
|
||||
yield None
|
||||
add(action.set_brightness(template_))
|
||||
if CONF_RED in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_RED], arg_type, float_):
|
||||
if CONF_RED in config:
|
||||
for template_ in templatable(config[CONF_RED], arg_type, float_):
|
||||
yield None
|
||||
add(action.set_red(template_))
|
||||
if CONF_GREEN in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_GREEN], arg_type, float_):
|
||||
if CONF_GREEN in config:
|
||||
for template_ in templatable(config[CONF_GREEN], arg_type, float_):
|
||||
yield None
|
||||
add(action.set_green(template_))
|
||||
if CONF_BLUE in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_BLUE], arg_type, float_):
|
||||
if CONF_BLUE in config:
|
||||
for template_ in templatable(config[CONF_BLUE], arg_type, float_):
|
||||
yield None
|
||||
add(action.set_blue(template_))
|
||||
if CONF_WHITE in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_WHITE], arg_type, float_):
|
||||
if CONF_WHITE in config:
|
||||
for template_ in templatable(config[CONF_WHITE], arg_type, float_):
|
||||
yield None
|
||||
add(action.set_white(template_))
|
||||
if CONF_EFFECT in conf:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_EFFECT], arg_type, std_string):
|
||||
if CONF_COLOR_TEMPERATURE in config:
|
||||
for template_ in templatable(config[CONF_COLOR_TEMPERATURE], arg_type, float_):
|
||||
yield None
|
||||
add(action.set_color_temperature(template_))
|
||||
if CONF_EFFECT in config:
|
||||
for template_ in templatable(config[CONF_EFFECT], arg_type, std_string):
|
||||
yield None
|
||||
add(action.set_effect(template_))
|
||||
yield action
|
||||
elif CONF_SWITCH_TOGGLE in config:
|
||||
conf = config[CONF_SWITCH_TOGGLE]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
elif key == CONF_SWITCH_TOGGLE:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_toggle_action(template_arg)
|
||||
type = switch.ToggleAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_SWITCH_TURN_OFF in config:
|
||||
conf = config[CONF_SWITCH_TURN_OFF]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_SWITCH_TURN_OFF:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_off_action(template_arg)
|
||||
type = switch.TurnOffAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_SWITCH_TURN_ON in config:
|
||||
conf = config[CONF_SWITCH_TURN_ON]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_SWITCH_TURN_ON:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_on_action(template_arg)
|
||||
type = switch.TurnOnAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_COVER_OPEN in config:
|
||||
conf = config[CONF_COVER_OPEN]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_COVER_OPEN:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_open_action(template_arg)
|
||||
type = cover.OpenAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_COVER_CLOSE in config:
|
||||
conf = config[CONF_COVER_CLOSE]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_COVER_CLOSE:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_close_action(template_arg)
|
||||
type = cover.CloseAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_COVER_STOP in config:
|
||||
conf = config[CONF_COVER_STOP]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_COVER_STOP:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_stop_action(template_arg)
|
||||
type = cover.StopAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_FAN_TOGGLE in config:
|
||||
conf = config[CONF_FAN_TOGGLE]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_FAN_TOGGLE:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_toggle_action(template_arg)
|
||||
type = fan.ToggleAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_FAN_TURN_OFF in config:
|
||||
conf = config[CONF_FAN_TURN_OFF]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_FAN_TURN_OFF:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_off_action(template_arg)
|
||||
type = fan.TurnOffAction.template(arg_type)
|
||||
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
elif CONF_FAN_TURN_ON in config:
|
||||
conf = config[CONF_FAN_TURN_ON]
|
||||
for var in get_variable(conf[CONF_ID]):
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_FAN_TURN_ON:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_on_action(template_arg)
|
||||
type = fan.TurnOnAction.template(arg_type)
|
||||
action = Pvariable(config[CONF_ACTION_ID], rhs, type=type)
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
if CONF_OSCILLATING in config:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_OSCILLATING], arg_type, bool_):
|
||||
for template_ in templatable(config[CONF_OSCILLATING], arg_type, bool_):
|
||||
yield None
|
||||
add(action.set_oscillating(template_))
|
||||
if CONF_SPEED in config:
|
||||
template_ = None
|
||||
for template_ in templatable(conf[CONF_SPEED], arg_type, fan.FanSpeed):
|
||||
for template_ in templatable(config[CONF_SPEED], arg_type, fan.FanSpeed):
|
||||
yield None
|
||||
add(action.set_speed(template_))
|
||||
yield action
|
||||
elif key == CONF_OUTPUT_TURN_OFF:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_off_action(template_arg)
|
||||
type = output.TurnOffAction.template(arg_type)
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_OUTPUT_TURN_ON:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_turn_on_action(template_arg)
|
||||
type = output.TurnOnAction.template(arg_type)
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_OUTPUT_SET_LEVEL:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_set_level_action(template_arg)
|
||||
type = output.SetLevelAction.template(arg_type)
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
for template_ in templatable(config[CONF_LEVEL], arg_type, bool_):
|
||||
yield None
|
||||
add(action.set_level(template_))
|
||||
yield action
|
||||
elif key == CONF_IF:
|
||||
for conditions in build_conditions(config[CONF_CONDITION], arg_type):
|
||||
yield None
|
||||
rhs = IfAction.new(template_arg, conditions)
|
||||
type = IfAction.template(template_arg)
|
||||
action = Pvariable(action_id, rhs, type=type)
|
||||
if CONF_THEN in config:
|
||||
for actions in build_actions(config[CONF_THEN], arg_type):
|
||||
yield None
|
||||
add(action.add_then(actions))
|
||||
if CONF_ELSE in config:
|
||||
for actions in build_actions(config[CONF_ELSE], arg_type):
|
||||
yield None
|
||||
add(action.add_else(actions))
|
||||
yield action
|
||||
elif key == CONF_DEEP_SLEEP_ENTER:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_enter_deep_sleep_action(template_arg)
|
||||
type = deep_sleep.EnterDeepSleepAction.template(arg_type)
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
elif key == CONF_DEEP_SLEEP_PREVENT:
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_prevent_deep_sleep_action(template_arg)
|
||||
type = deep_sleep.PreventDeepSleepAction.template(arg_type)
|
||||
yield Pvariable(action_id, rhs, type=type)
|
||||
else:
|
||||
raise ESPHomeYAMLError(u"Unsupported action {}".format(config))
|
||||
|
||||
@@ -391,18 +479,19 @@ def build_actions(config, arg_type):
|
||||
|
||||
|
||||
def build_automation_(trigger, arg_type, config):
|
||||
rhs = App.make_automation(trigger)
|
||||
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
|
||||
yield None
|
||||
add(obj.add_conditions(conditions))
|
||||
actions = None
|
||||
for actions in build_actions(config[CONF_THEN], arg_type):
|
||||
yield
|
||||
yield None
|
||||
add(obj.add_actions(actions))
|
||||
yield obj
|
||||
|
||||
|
||||
def build_automation(trigger, arg_type, config):
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"squash": false,
|
||||
"build_from": {
|
||||
"aarch64": "arm64v8/ubuntu:bionic",
|
||||
"amd64": "ubuntu:bionic",
|
||||
"armhf": "homeassistant/armhf-base:latest",
|
||||
"i386": "i386/ubuntu:bionic"
|
||||
},
|
||||
"args": {}
|
||||
}
|
||||
@@ -2,11 +2,12 @@ import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import automation
|
||||
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INVERTED, CONF_MAX_LENGTH, \
|
||||
CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, CONF_ON_PRESS, \
|
||||
CONF_ON_RELEASE, CONF_TRIGGER_ID
|
||||
from esphomeyaml.helpers import App, NoArg, Pvariable, add, esphomelib_ns, setup_mqtt_component, \
|
||||
add_job
|
||||
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INTERNAL, CONF_INVERTED, \
|
||||
CONF_MAX_LENGTH, CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, CONF_ON_DOUBLE_CLICK, \
|
||||
CONF_ON_PRESS, CONF_ON_RELEASE, CONF_TRIGGER_ID, CONF_FILTERS, CONF_INVERT, CONF_DELAYED_ON, \
|
||||
CONF_DELAYED_OFF, CONF_LAMBDA, CONF_HEARTBEAT
|
||||
from esphomeyaml.helpers import App, NoArg, Pvariable, add, add_job, esphomelib_ns, \
|
||||
setup_mqtt_component, bool_, process_lambda, ArrayInitializer
|
||||
|
||||
DEVICE_CLASSES = [
|
||||
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
|
||||
@@ -25,38 +26,95 @@ ReleaseTrigger = binary_sensor_ns.ReleaseTrigger
|
||||
ClickTrigger = binary_sensor_ns.ClickTrigger
|
||||
DoubleClickTrigger = binary_sensor_ns.DoubleClickTrigger
|
||||
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
|
||||
HeartbeatFilter = binary_sensor_ns.HeartbeatFilter
|
||||
MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent
|
||||
|
||||
FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA, CONF_HEARTBEAT]
|
||||
|
||||
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_HEARTBEAT): 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({
|
||||
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTBinarySensorComponent),
|
||||
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_ON_PRESS): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
|
||||
vol.Optional(CONF_FILTERS): FILTERS_SCHEMA,
|
||||
vol.Optional(CONF_ON_PRESS): vol.All(cv.ensure_list, [automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(PressTrigger),
|
||||
})]),
|
||||
vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
|
||||
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.AUTOMATION_SCHEMA.extend({
|
||||
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_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
|
||||
})]),
|
||||
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_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_HEARTBEAT in config:
|
||||
yield App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT]))
|
||||
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):
|
||||
if CONF_INTERNAL in config:
|
||||
add(binary_sensor_var.set_internal(CONF_INTERNAL))
|
||||
if CONF_DEVICE_CLASS in config:
|
||||
add(binary_sensor_var.set_device_class(config[CONF_DEVICE_CLASS]))
|
||||
if CONF_INVERTED in config:
|
||||
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, []):
|
||||
rhs = binary_sensor_var.make_press_trigger()
|
||||
|
||||
@@ -1,48 +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']
|
||||
|
||||
CONF_ESP32_BLE_ID = 'esp32_ble_id'
|
||||
|
||||
|
||||
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,
|
||||
cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_variable_id(ESP32BLETracker)
|
||||
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
|
||||
|
||||
|
||||
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'
|
||||
23
esphomeyaml/components/binary_sensor/esp32_ble_tracker.py
Normal file
23
esphomeyaml/components/binary_sensor/esp32_ble_tracker.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import binary_sensor
|
||||
from esphomeyaml.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESP32BLETracker, \
|
||||
make_address_array
|
||||
from esphomeyaml.const import CONF_MAC_ADDRESS, CONF_NAME
|
||||
from esphomeyaml.helpers import get_variable
|
||||
|
||||
DEPENDENCIES = ['esp32_ble_tracker']
|
||||
|
||||
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
|
||||
rhs = hub.make_presence_sensor(config[CONF_NAME], make_address_array(config[CONF_MAC_ADDRESS]))
|
||||
binary_sensor.register_binary_sensor(rhs, config)
|
||||
@@ -34,11 +34,11 @@ def validate_touch_pad(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_THRESHOLD): cv.uint16_t,
|
||||
cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_variable_id(ESP32TouchComponent),
|
||||
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -8,10 +8,10 @@ from esphomeyaml.helpers import App, gpio_input_pin_expression, variable, Applic
|
||||
|
||||
MakeGPIOBinarySensor = Application.MakeGPIOBinarySensor
|
||||
|
||||
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
|
||||
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
|
||||
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
26
esphomeyaml/components/binary_sensor/nextion.py
Normal file
26
esphomeyaml/components/binary_sensor/nextion.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import binary_sensor
|
||||
from esphomeyaml.components.display.nextion import Nextion
|
||||
from esphomeyaml.const import CONF_COMPONENT_ID, CONF_NAME, CONF_PAGE_ID
|
||||
from esphomeyaml.helpers import get_variable
|
||||
|
||||
DEPENDENCIES = ['display']
|
||||
|
||||
CONF_NEXTION_ID = 'nextion_id'
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_PAGE_ID): cv.uint8_t,
|
||||
vol.Required(CONF_COMPONENT_ID): cv.uint8_t,
|
||||
cv.GenerateID(CONF_NEXTION_ID): cv.use_variable_id(Nextion)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = None
|
||||
for hub in get_variable(config[CONF_NEXTION_ID]):
|
||||
yield
|
||||
rhs = hub.make_touch_component(config[CONF_NAME], config[CONF_PAGE_ID],
|
||||
config[CONF_COMPONENT_ID])
|
||||
binary_sensor.register_binary_sensor(rhs, config)
|
||||
42
esphomeyaml/components/binary_sensor/pn532.py
Normal file
42
esphomeyaml/components/binary_sensor/pn532.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import binary_sensor
|
||||
from esphomeyaml.components.pn532 import PN532Component
|
||||
from esphomeyaml.const import CONF_NAME, CONF_UID
|
||||
from esphomeyaml.core import HexInt
|
||||
from esphomeyaml.helpers import ArrayInitializer, get_variable
|
||||
|
||||
DEPENDENCIES = ['pn532']
|
||||
|
||||
CONF_PN532_ID = 'pn532_id'
|
||||
|
||||
|
||||
def validate_uid(value):
|
||||
value = cv.string_strict(value)
|
||||
for x in value.split('-'):
|
||||
if len(x) != 2:
|
||||
raise vol.Invalid("Each part (separated by '-') of the UID must be two characters "
|
||||
"long.")
|
||||
try:
|
||||
x = int(x, 16)
|
||||
except ValueError:
|
||||
raise vol.Invalid("Valid characters for parts of a UID are 0123456789ABCDEF.")
|
||||
if x < 0 or x > 255:
|
||||
raise vol.Invalid("Valid values for UID parts (separated by '-') are 00 to FF")
|
||||
return value
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_UID): validate_uid,
|
||||
cv.GenerateID(CONF_PN532_ID): cv.use_variable_id(PN532Component)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = None
|
||||
for hub in get_variable(config[CONF_PN532_ID]):
|
||||
yield
|
||||
addr = [HexInt(int(x, 16)) for x in config[CONF_UID].split('-')]
|
||||
rhs = hub.make_tag(config[CONF_NAME], ArrayInitializer(*addr, multiline=False))
|
||||
binary_sensor.register_binary_sensor(rhs, config)
|
||||
23
esphomeyaml/components/binary_sensor/rdm6300.py
Normal file
23
esphomeyaml/components/binary_sensor/rdm6300.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import binary_sensor, rdm6300
|
||||
from esphomeyaml.const import CONF_NAME, CONF_UID
|
||||
from esphomeyaml.helpers import get_variable
|
||||
|
||||
DEPENDENCIES = ['rdm6300']
|
||||
|
||||
CONF_RDM6300_ID = 'rdm6300_id'
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_UID): cv.uint32_t,
|
||||
cv.GenerateID(CONF_RDM6300_ID): cv.use_variable_id(rdm6300.RDM6300Component)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = None
|
||||
for hub in get_variable(config[CONF_RDM6300_ID]):
|
||||
yield
|
||||
rhs = hub.make_card(config[CONF_NAME], config[CONF_UID])
|
||||
binary_sensor.register_binary_sensor(rhs, config)
|
||||
114
esphomeyaml/components/binary_sensor/remote_receiver.py
Normal file
114
esphomeyaml/components/binary_sensor/remote_receiver.py
Normal file
@@ -0,0 +1,114 @@
|
||||
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.components.remote_transmitter import RC_SWITCH_RAW_SCHEMA, \
|
||||
RC_SWITCH_TYPE_A_SCHEMA, RC_SWITCH_TYPE_B_SCHEMA, RC_SWITCH_TYPE_C_SCHEMA, \
|
||||
RC_SWITCH_TYPE_D_SCHEMA, binary_code, build_rc_switch_protocol
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_CHANNEL, CONF_CODE, CONF_COMMAND, CONF_DATA, \
|
||||
CONF_DEVICE, CONF_FAMILY, CONF_GROUP, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \
|
||||
CONF_PANASONIC, CONF_PROTOCOL, CONF_RAW, CONF_RC_SWITCH_RAW, CONF_RC_SWITCH_TYPE_A, \
|
||||
CONF_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C, CONF_RC_SWITCH_TYPE_D, CONF_SONY, CONF_STATE
|
||||
from esphomeyaml.helpers import ArrayInitializer, Pvariable, get_variable
|
||||
|
||||
DEPENDENCIES = ['remote_receiver']
|
||||
|
||||
REMOTE_KEYS = [CONF_NEC, CONF_LG, CONF_SONY, CONF_PANASONIC, CONF_RAW, CONF_RC_SWITCH_RAW,
|
||||
CONF_RC_SWITCH_TYPE_A, CONF_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C,
|
||||
CONF_RC_SWITCH_TYPE_D]
|
||||
|
||||
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
|
||||
RCSwitchRawReceiver = remote_ns.RCSwitchRawReceiver
|
||||
RCSwitchTypeAReceiver = remote_ns.RCSwitchTypeAReceiver
|
||||
RCSwitchTypeBReceiver = remote_ns.RCSwitchTypeBReceiver
|
||||
RCSwitchTypeCReceiver = remote_ns.RCSwitchTypeCReceiver
|
||||
RCSwitchTypeDReceiver = remote_ns.RCSwitchTypeDReceiver
|
||||
|
||||
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)],
|
||||
vol.Optional(CONF_RC_SWITCH_RAW): RC_SWITCH_RAW_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_A): RC_SWITCH_TYPE_A_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_B): RC_SWITCH_TYPE_B_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_C): RC_SWITCH_TYPE_C_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_D): RC_SWITCH_TYPE_D_SCHEMA,
|
||||
|
||||
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(*REMOTE_KEYS))
|
||||
|
||||
|
||||
def receiver_base(full_config):
|
||||
name = full_config[CONF_NAME]
|
||||
key, config = next((k, v) for k, v in full_config.items() if k in REMOTE_KEYS)
|
||||
if key == CONF_LG:
|
||||
return LGReceiver.new(name, config[CONF_DATA], config[CONF_NBITS])
|
||||
elif key == CONF_NEC:
|
||||
return NECReceiver.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
|
||||
elif key == CONF_PANASONIC:
|
||||
return PanasonicReceiver.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
|
||||
elif key == CONF_SONY:
|
||||
return SonyReceiver.new(name, config[CONF_DATA], config[CONF_NBITS])
|
||||
elif key == CONF_RAW:
|
||||
data = ArrayInitializer(*config[CONF_RAW], multiline=False)
|
||||
return RawReceiver.new(name, data)
|
||||
elif key == CONF_RC_SWITCH_RAW:
|
||||
return RCSwitchRawReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
binary_code(config[CONF_CODE]), len(config[CONF_CODE]))
|
||||
elif key == CONF_RC_SWITCH_TYPE_A:
|
||||
return RCSwitchTypeAReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
binary_code(config[CONF_GROUP]),
|
||||
binary_code(config[CONF_DEVICE]),
|
||||
config[CONF_STATE])
|
||||
elif key == CONF_RC_SWITCH_TYPE_B:
|
||||
return RCSwitchTypeBReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
config[CONF_ADDRESS], config[CONF_CHANNEL],
|
||||
config[CONF_STATE])
|
||||
elif key == CONF_RC_SWITCH_TYPE_C:
|
||||
return RCSwitchTypeCReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
ord(config[CONF_FAMILY][0]) - ord('a'),
|
||||
config[CONF_GROUP], config[CONF_DEVICE],
|
||||
config[CONF_STATE])
|
||||
elif key == CONF_RC_SWITCH_TYPE_D:
|
||||
return RCSwitchTypeDReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
ord(config[CONF_GROUP][0]) - ord('a'),
|
||||
config[CONF_DEVICE], config[CONF_STATE])
|
||||
else:
|
||||
raise NotImplementedError("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'
|
||||
@@ -7,9 +7,9 @@ DEPENDENCIES = ['mqtt']
|
||||
|
||||
MakeStatusBinarySensor = Application.MakeStatusBinarySensor
|
||||
|
||||
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
|
||||
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeStatusBinarySensor),
|
||||
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -3,24 +3,26 @@ import voluptuous as vol
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import binary_sensor
|
||||
from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME
|
||||
from esphomeyaml.helpers import App, Application, process_lambda, variable, optional, bool_
|
||||
from esphomeyaml.helpers import App, Application, process_lambda, variable, optional, bool_, add
|
||||
|
||||
MakeTemplateBinarySensor = Application.MakeTemplateBinarySensor
|
||||
|
||||
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
|
||||
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_,
|
||||
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_template_binary_sensor(config[CONF_NAME])
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
binary_sensor.setup_binary_sensor(make.Ptemplate_, make.Pmqtt, config)
|
||||
|
||||
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_)
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
binary_sensor.setup_binary_sensor(make.Ptemplate_, make.Pmqtt, config)
|
||||
add(make.Ptemplate_.set_template(template_))
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_TEMPLATE_BINARY_SENSOR'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_ID, CONF_MQTT_ID
|
||||
from esphomeyaml.helpers import Pvariable, esphomelib_ns, setup_mqtt_component
|
||||
from esphomeyaml.const import CONF_ID, CONF_MQTT_ID, CONF_INTERNAL
|
||||
from esphomeyaml.helpers import Pvariable, esphomelib_ns, setup_mqtt_component, add
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
|
||||
@@ -21,8 +21,12 @@ COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
|
||||
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):
|
||||
if CONF_INTERNAL in config:
|
||||
add(cover_var.set_internal(config[CONF_INTERNAL]))
|
||||
setup_mqtt_component(mqtt_var, config)
|
||||
|
||||
|
||||
|
||||
@@ -9,20 +9,22 @@ from esphomeyaml.helpers import App, Application, NoArg, add, process_lambda, va
|
||||
|
||||
MakeTemplateCover = Application.MakeTemplateCover
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(cover.PLATFORM_SCHEMA.extend({
|
||||
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.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_least_one_key(CONF_LAMBDA, CONF_OPTIMISTIC))
|
||||
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):
|
||||
rhs = App.make_template_cover(config[CONF_NAME])
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
|
||||
cover.setup_cover(make.Ptemplate_, make.Pmqtt, config)
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = None
|
||||
for template_ in process_lambda(config[CONF_LAMBDA], [],
|
||||
@@ -30,24 +32,16 @@ def to_code(config):
|
||||
yield
|
||||
add(make.Ptemplate_.set_state_lambda(template_))
|
||||
if CONF_OPEN_ACTION in config:
|
||||
actions = None
|
||||
for actions in automation.build_actions(config[CONF_OPEN_ACTION], NoArg):
|
||||
yield
|
||||
add(make.Ptemplate_.add_open_actions(actions))
|
||||
automation.build_automation(make.Ptemplate_.get_open_trigger(), NoArg,
|
||||
config[CONF_OPEN_ACTION])
|
||||
if CONF_CLOSE_ACTION in config:
|
||||
actions = None
|
||||
for actions in automation.build_actions(config[CONF_CLOSE_ACTION], NoArg):
|
||||
yield
|
||||
add(make.Ptemplate_.add_close_actions(actions))
|
||||
automation.build_automation(make.Ptemplate_.get_close_trigger(), NoArg,
|
||||
config[CONF_CLOSE_ACTION])
|
||||
if CONF_STOP_ACTION in config:
|
||||
actions = None
|
||||
for actions in automation.build_actions(config[CONF_STOP_ACTION], NoArg):
|
||||
yield
|
||||
add(make.Ptemplate_.add_stop_actions(actions))
|
||||
automation.build_automation(make.Ptemplate_.get_stop_trigger(), NoArg,
|
||||
config[CONF_STOP_ACTION])
|
||||
if CONF_OPTIMISTIC in config:
|
||||
add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||
|
||||
cover.setup_cover(make.Ptemplate_, make.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_TEMPLATE_COVER'
|
||||
|
||||
@@ -11,7 +11,7 @@ DallasComponent = sensor.sensor_ns.DallasComponent
|
||||
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(DallasComponent),
|
||||
vol.Required(CONF_PIN): pins.input_output_pin,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})])
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ def validate_pin_number(value):
|
||||
|
||||
|
||||
DeepSleepComponent = esphomelib_ns.DeepSleepComponent
|
||||
EnterDeepSleepAction = esphomelib_ns.EnterDeepSleepAction
|
||||
PreventDeepSleepAction = esphomelib_ns.PreventDeepSleepAction
|
||||
|
||||
WAKEUP_PIN_MODES = {
|
||||
'IGNORE': esphomelib_ns.WAKEUP_PIN_MODE_IGNORE,
|
||||
|
||||
56
esphomeyaml/components/display/__init__.py
Normal file
56
esphomeyaml/components/display/__init__.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# coding=utf-8
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_LAMBDA, CONF_ROTATION, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import add, add_job, esphomelib_ns
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
|
||||
})
|
||||
|
||||
display_ns = esphomelib_ns.namespace('display')
|
||||
DisplayBuffer = display_ns.DisplayBuffer
|
||||
DisplayBufferRef = DisplayBuffer.operator('ref')
|
||||
|
||||
DISPLAY_ROTATIONS = {
|
||||
0: display_ns.DISPLAY_ROTATION_0_DEGREES,
|
||||
90: display_ns.DISPLAY_ROTATION_90_DEGREES,
|
||||
180: display_ns.DISPLAY_ROTATION_180_DEGREES,
|
||||
270: display_ns.DISPLAY_ROTATION_270_DEGREES,
|
||||
}
|
||||
|
||||
|
||||
def validate_rotation(value):
|
||||
value = cv.string(value)
|
||||
if value.endswith(u"°"):
|
||||
value = value[:-1]
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
raise vol.Invalid(u"Expected integer for rotation")
|
||||
return cv.one_of(*DISPLAY_ROTATIONS)(value)
|
||||
|
||||
|
||||
BASIC_DISPLAY_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
})
|
||||
|
||||
FULL_DISPLAY_PLATFORM_SCHEMA = BASIC_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_ROTATION): validate_rotation,
|
||||
})
|
||||
|
||||
|
||||
def setup_display_core_(display_var, config):
|
||||
if CONF_UPDATE_INTERVAL in config:
|
||||
add(display_var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
|
||||
if CONF_ROTATION in config:
|
||||
add(display_var.set_rotation(DISPLAY_ROTATIONS[config[CONF_ROTATION]]))
|
||||
|
||||
|
||||
def setup_display(display_var, config):
|
||||
add_job(setup_display_core_, display_var, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_DISPLAY'
|
||||
72
esphomeyaml/components/display/lcd_gpio.py
Normal file
72
esphomeyaml/components/display/lcd_gpio.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.const import CONF_DATA_PINS, CONF_DIMENSIONS, CONF_ENABLE_PIN, CONF_ID, \
|
||||
CONF_LAMBDA, CONF_RS_PIN, CONF_RW_PIN
|
||||
from esphomeyaml.helpers import App, Pvariable, add, gpio_output_pin_expression, process_lambda
|
||||
|
||||
GPIOLCDDisplay = display.display_ns.GPIOLCDDisplay
|
||||
LCDDisplay = display.display_ns.LCDDisplay
|
||||
LCDDisplayRef = LCDDisplay.operator('ref')
|
||||
|
||||
|
||||
def validate_lcd_dimensions(value):
|
||||
value = cv.dimensions(value)
|
||||
if value[0] > 0x40:
|
||||
raise vol.Invalid("LCD displays can't have more than 64 columns")
|
||||
if value[1] > 4:
|
||||
raise vol.Invalid("LCD displays can't have more than 4 rows")
|
||||
return value
|
||||
|
||||
|
||||
def validate_pin_length(value):
|
||||
if len(value) != 4 and len(value) != 8:
|
||||
raise vol.Invalid("LCD Displays can either operate in 4-pin or 8-pin mode,"
|
||||
"not {}-pin mode".format(len(value)))
|
||||
return value
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = display.BASIC_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(GPIOLCDDisplay),
|
||||
vol.Required(CONF_DIMENSIONS): validate_lcd_dimensions,
|
||||
|
||||
vol.Required(CONF_DATA_PINS): vol.All([pins.gpio_output_pin_schema], validate_pin_length),
|
||||
vol.Required(CONF_ENABLE_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Required(CONF_RS_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_RW_PIN): pins.gpio_output_pin_schema,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_gpio_lcd_display(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1])
|
||||
lcd = Pvariable(config[CONF_ID], rhs)
|
||||
pins_ = []
|
||||
for conf in config[CONF_DATA_PINS]:
|
||||
for pin in gpio_output_pin_expression(conf):
|
||||
yield
|
||||
pins_.append(pin)
|
||||
add(lcd.set_data_pins(*pins_))
|
||||
for enable in gpio_output_pin_expression(config[CONF_ENABLE_PIN]):
|
||||
yield
|
||||
add(lcd.set_enable_pin(enable))
|
||||
|
||||
for rs in gpio_output_pin_expression(config[CONF_RS_PIN]):
|
||||
yield
|
||||
add(lcd.set_rs_pin(rs))
|
||||
|
||||
if CONF_RW_PIN in config:
|
||||
for rw in gpio_output_pin_expression(config[CONF_RW_PIN]):
|
||||
yield
|
||||
add(lcd.set_rw_pin(rw))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], [(LCDDisplayRef, 'it')]):
|
||||
yield
|
||||
add(lcd.set_writer(lambda_))
|
||||
|
||||
display.setup_display(lcd, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_LCD_DISPLAY'
|
||||
35
esphomeyaml/components/display/lcd_pcf8574.py
Normal file
35
esphomeyaml/components/display/lcd_pcf8574.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.components.display.lcd_gpio import LCDDisplayRef, validate_lcd_dimensions
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_DIMENSIONS, CONF_ID, CONF_LAMBDA
|
||||
from esphomeyaml.helpers import App, Pvariable, add, process_lambda
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
PCF8574LCDDisplay = display.display_ns.PCF8574LCDDisplay
|
||||
|
||||
PLATFORM_SCHEMA = display.BASIC_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(PCF8574LCDDisplay),
|
||||
vol.Required(CONF_DIMENSIONS): validate_lcd_dimensions,
|
||||
vol.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_pcf8574_lcd_display(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1])
|
||||
lcd = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if CONF_ADDRESS in config:
|
||||
add(lcd.set_address(config[CONF_ADDRESS]))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], [(LCDDisplayRef, 'it')]):
|
||||
yield
|
||||
add(lcd.set_writer(lambda_))
|
||||
|
||||
display.setup_display(lcd, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = ['-DUSE_LCD_DISPLAY', '-DUSE_LCD_DISPLAY_PCF8574']
|
||||
48
esphomeyaml/components/display/max7219.py
Normal file
48
esphomeyaml/components/display/max7219.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.components.spi import SPIComponent
|
||||
from esphomeyaml.const import CONF_CS_PIN, CONF_ID, CONF_INTENSITY, CONF_LAMBDA, CONF_NUM_CHIPS, \
|
||||
CONF_SPI_ID
|
||||
from esphomeyaml.helpers import App, Pvariable, add, get_variable, gpio_output_pin_expression, \
|
||||
process_lambda
|
||||
|
||||
DEPENDENCIES = ['spi']
|
||||
|
||||
MAX7219Component = display.display_ns.MAX7219Component
|
||||
MAX7219ComponentRef = MAX7219Component.operator('ref')
|
||||
|
||||
PLATFORM_SCHEMA = display.BASIC_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(MAX7219Component),
|
||||
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
|
||||
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
|
||||
|
||||
vol.Optional(CONF_NUM_CHIPS): vol.All(cv.uint8_t, vol.Range(min=1)),
|
||||
vol.Optional(CONF_INTENSITY): vol.All(cv.uint8_t, vol.Range(min=0, max=15)),
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for spi in get_variable(config[CONF_SPI_ID]):
|
||||
yield
|
||||
for cs in gpio_output_pin_expression(config[CONF_CS_PIN]):
|
||||
yield
|
||||
rhs = App.make_max7219(spi, cs)
|
||||
max7219 = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if CONF_NUM_CHIPS in config:
|
||||
add(max7219.set_num_chips(config[CONF_NUM_CHIPS]))
|
||||
if CONF_INTENSITY in config:
|
||||
add(max7219.set_intensity(config[CONF_INTENSITY]))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], [(MAX7219ComponentRef, 'it')]):
|
||||
yield
|
||||
add(max7219.set_writer(lambda_))
|
||||
|
||||
display.setup_display(max7219, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_MAX7219'
|
||||
32
esphomeyaml/components/display/nextion.py
Normal file
32
esphomeyaml/components/display/nextion.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.components.uart import UARTComponent
|
||||
from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_UART_ID
|
||||
from esphomeyaml.helpers import App, Pvariable, add, get_variable, process_lambda
|
||||
|
||||
DEPENDENCIES = ['uart']
|
||||
|
||||
Nextion = display.display_ns.Nextion
|
||||
NextionRef = Nextion.operator('ref')
|
||||
|
||||
PLATFORM_SCHEMA = display.BASIC_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(Nextion),
|
||||
cv.GenerateID(CONF_UART_ID): cv.use_variable_id(UARTComponent),
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for uart in get_variable(config[CONF_UART_ID]):
|
||||
yield
|
||||
rhs = App.make_nextion(uart)
|
||||
nextion = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], [(NextionRef, 'it')]):
|
||||
yield
|
||||
add(nextion.set_writer(lambda_))
|
||||
|
||||
display.setup_display(nextion, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_NEXTION'
|
||||
46
esphomeyaml/components/display/ssd1306_i2c.py
Normal file
46
esphomeyaml/components/display/ssd1306_i2c.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.components.display import ssd1306_spi
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_EXTERNAL_VCC, CONF_ID, \
|
||||
CONF_MODEL, CONF_RESET_PIN, CONF_LAMBDA
|
||||
from esphomeyaml.helpers import App, Pvariable, add, \
|
||||
gpio_output_pin_expression, process_lambda
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
I2CSSD1306 = display.display_ns.I2CSSD1306
|
||||
|
||||
PLATFORM_SCHEMA = display.FULL_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(I2CSSD1306),
|
||||
vol.Required(CONF_MODEL): ssd1306_spi.SSD1306_MODEL,
|
||||
vol.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_EXTERNAL_VCC): cv.boolean,
|
||||
vol.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
ssd = Pvariable(config[CONF_ID], App.make_i2c_ssd1306())
|
||||
add(ssd.set_model(ssd1306_spi.MODELS[config[CONF_MODEL]]))
|
||||
|
||||
if CONF_RESET_PIN in config:
|
||||
for reset in gpio_output_pin_expression(config[CONF_RESET_PIN]):
|
||||
yield
|
||||
add(ssd.set_reset_pin(reset))
|
||||
if CONF_EXTERNAL_VCC in config:
|
||||
add(ssd.set_external_vcc(config[CONF_EXTERNAL_VCC]))
|
||||
if CONF_ADDRESS in config:
|
||||
add(ssd.set_address(config[CONF_ADDRESS]))
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA],
|
||||
[(display.DisplayBufferRef, 'it')]):
|
||||
yield
|
||||
add(ssd.set_writer(lambda_))
|
||||
|
||||
display.setup_display(ssd, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_SSD1306'
|
||||
68
esphomeyaml/components/display/ssd1306_spi.py
Normal file
68
esphomeyaml/components/display/ssd1306_spi.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.components.spi import SPIComponent
|
||||
from esphomeyaml.const import CONF_CS_PIN, CONF_DC_PIN, CONF_EXTERNAL_VCC, \
|
||||
CONF_ID, CONF_MODEL, \
|
||||
CONF_RESET_PIN, CONF_SPI_ID, CONF_LAMBDA
|
||||
from esphomeyaml.helpers import App, Pvariable, add, get_variable, \
|
||||
gpio_output_pin_expression, process_lambda
|
||||
|
||||
DEPENDENCIES = ['spi']
|
||||
|
||||
SPISSD1306 = display.display_ns.SPISSD1306
|
||||
|
||||
MODELS = {
|
||||
'SSD1306_128X32': display.display_ns.SSD1306_MODEL_128_32,
|
||||
'SSD1306_128X64': display.display_ns.SSD1306_MODEL_128_64,
|
||||
'SSD1306_96X16': display.display_ns.SSD1306_MODEL_96_16,
|
||||
'SSD1306_64X48': display.display_ns.SSD1306_MODEL_64_48,
|
||||
'SH1106_128X32': display.display_ns.SH1106_MODEL_128_32,
|
||||
'SH1106_128X64': display.display_ns.SH1106_MODEL_128_64,
|
||||
'SH1106_96X16': display.display_ns.SH1106_MODEL_96_16,
|
||||
'SH1106_64X48': display.display_ns.SH1106_MODEL_64_48,
|
||||
}
|
||||
|
||||
SSD1306_MODEL = vol.All(vol.Upper, vol.Replace(' ', '_'), cv.one_of(*MODELS))
|
||||
|
||||
PLATFORM_SCHEMA = display.FULL_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(SPISSD1306),
|
||||
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
|
||||
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Required(CONF_MODEL): SSD1306_MODEL,
|
||||
vol.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_EXTERNAL_VCC): cv.boolean,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for spi in get_variable(config[CONF_SPI_ID]):
|
||||
yield
|
||||
for cs in gpio_output_pin_expression(config[CONF_CS_PIN]):
|
||||
yield
|
||||
for dc in gpio_output_pin_expression(config[CONF_DC_PIN]):
|
||||
yield
|
||||
|
||||
rhs = App.make_spi_ssd1306(spi, cs, dc)
|
||||
ssd = Pvariable(config[CONF_ID], rhs)
|
||||
add(ssd.set_model(MODELS[config[CONF_MODEL]]))
|
||||
|
||||
if CONF_RESET_PIN in config:
|
||||
for reset in gpio_output_pin_expression(config[CONF_RESET_PIN]):
|
||||
yield
|
||||
add(ssd.set_reset_pin(reset))
|
||||
if CONF_EXTERNAL_VCC in config:
|
||||
add(ssd.set_external_vcc(config[CONF_EXTERNAL_VCC]))
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA],
|
||||
[(display.DisplayBufferRef, 'it')]):
|
||||
yield
|
||||
add(ssd.set_writer(lambda_))
|
||||
|
||||
display.setup_display(ssd, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_SSD1306'
|
||||
84
esphomeyaml/components/display/waveshare_epaper.py
Normal file
84
esphomeyaml/components/display/waveshare_epaper.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.components.spi import SPIComponent
|
||||
from esphomeyaml.const import CONF_BUSY_PIN, CONF_CS_PIN, CONF_DC_PIN, CONF_FULL_UPDATE_EVERY, \
|
||||
CONF_ID, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN, CONF_SPI_ID
|
||||
from esphomeyaml.helpers import App, Pvariable, add, get_variable, gpio_input_pin_expression, \
|
||||
gpio_output_pin_expression, process_lambda
|
||||
|
||||
DEPENDENCIES = ['spi']
|
||||
|
||||
WaveshareEPaperTypeA = display.display_ns.WaveshareEPaperTypeA
|
||||
WaveshareEPaper = display.display_ns.WaveshareEPaper
|
||||
|
||||
MODELS = {
|
||||
'1.54in': ('a', display.display_ns.WAVESHARE_EPAPER_1_54_IN),
|
||||
'2.13in': ('a', display.display_ns.WAVESHARE_EPAPER_2_13_IN),
|
||||
'2.90in': ('a', display.display_ns.WAVESHARE_EPAPER_2_9_IN),
|
||||
'2.70in': ('b', display.display_ns.WAVESHARE_EPAPER_2_7_IN),
|
||||
'4.20in': ('b', display.display_ns.WAVESHARE_EPAPER_4_2_IN),
|
||||
'7.50in': ('b', display.display_ns.WAVESHARE_EPAPER_7_5_IN),
|
||||
}
|
||||
|
||||
|
||||
def validate_full_update_every_only_type_a(value):
|
||||
if CONF_FULL_UPDATE_EVERY not in value:
|
||||
return value
|
||||
if MODELS[value[CONF_MODEL]][0] != 'a':
|
||||
raise vol.Invalid("The 'full_update_every' option is only available for models "
|
||||
"'1.54in', '2.13in' and '2.90in'.")
|
||||
return value
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(display.FULL_DISPLAY_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(None),
|
||||
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
|
||||
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Required(CONF_MODEL): vol.All(vol.Lower, cv.one_of(*MODELS)),
|
||||
vol.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_BUSY_PIN): pins.gpio_input_pin_schema,
|
||||
vol.Optional(CONF_FULL_UPDATE_EVERY): cv.uint32_t,
|
||||
}), validate_full_update_every_only_type_a)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for spi in get_variable(config[CONF_SPI_ID]):
|
||||
yield
|
||||
for cs in gpio_output_pin_expression(config[CONF_CS_PIN]):
|
||||
yield
|
||||
for dc in gpio_output_pin_expression(config[CONF_DC_PIN]):
|
||||
yield
|
||||
|
||||
model_type, model = MODELS[config[CONF_MODEL]]
|
||||
if model_type == 'a':
|
||||
rhs = App.make_waveshare_epaper_type_a(spi, cs, dc, model)
|
||||
epaper = Pvariable(config[CONF_ID], rhs, type=WaveshareEPaperTypeA)
|
||||
elif model_type == 'b':
|
||||
rhs = App.make_waveshare_epaper_type_b(spi, cs, dc, model)
|
||||
epaper = Pvariable(config[CONF_ID], rhs, type=WaveshareEPaper)
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], [(display.DisplayBufferRef, 'it')]):
|
||||
yield
|
||||
add(epaper.set_writer(lambda_))
|
||||
if CONF_RESET_PIN in config:
|
||||
for reset in gpio_output_pin_expression(config[CONF_RESET_PIN]):
|
||||
yield
|
||||
add(epaper.set_reset_pin(reset))
|
||||
if CONF_BUSY_PIN in config:
|
||||
for reset in gpio_input_pin_expression(config[CONF_BUSY_PIN]):
|
||||
yield
|
||||
add(epaper.set_busy_pin(reset))
|
||||
if CONF_FULL_UPDATE_EVERY in config:
|
||||
add(epaper.set_full_update_every(config[CONF_FULL_UPDATE_EVERY]))
|
||||
|
||||
display.setup_display(epaper, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_WAVESHARE_EPAPER'
|
||||
@@ -1,24 +1,5 @@
|
||||
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'
|
||||
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' "
|
||||
"component.")
|
||||
|
||||
35
esphomeyaml/components/esp32_ble_beacon.py
Normal file
35
esphomeyaml/components/esp32_ble_beacon.py
Normal 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]
|
||||
|
||||
ESP32BLEBeacon = esphomelib_ns.ESP32BLEBeacon
|
||||
|
||||
CONF_MAJOR = 'major'
|
||||
CONF_MINOR = 'minor'
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(ESP32BLEBeacon),
|
||||
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'
|
||||
31
esphomeyaml/components/esp32_ble_tracker.py
Normal file
31
esphomeyaml/components/esp32_ble_tracker.py
Normal file
@@ -0,0 +1,31 @@
|
||||
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.core import HexInt
|
||||
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, ArrayInitializer
|
||||
|
||||
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
|
||||
|
||||
CONF_ESP32_BLE_ID = 'esp32_ble_id'
|
||||
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 make_address_array(address):
|
||||
addr = [HexInt(i) for i in address.parts]
|
||||
return ArrayInitializer(*addr, multiline=False)
|
||||
|
||||
|
||||
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'
|
||||
@@ -2,7 +2,7 @@ import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
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
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
@@ -29,6 +29,8 @@ FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
|
||||
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic,
|
||||
})
|
||||
|
||||
FAN_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(FAN_SCHEMA.schema)
|
||||
|
||||
|
||||
FAN_SPEEDS = {
|
||||
'OFF': FAN_SPEED_OFF,
|
||||
@@ -43,6 +45,9 @@ def validate_fan_speed(value):
|
||||
|
||||
|
||||
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:
|
||||
add(mqtt_var.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC]))
|
||||
if CONF_OSCILLATION_COMMAND_TOPIC in config:
|
||||
|
||||
@@ -5,11 +5,11 @@ from esphomeyaml.components import fan
|
||||
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT
|
||||
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(CONF_MAKE_ID): cv.declare_variable_id(fan.MakeFan),
|
||||
vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
|
||||
vol.Optional(CONF_OSCILLATION_OUTPUT): cv.use_variable_id(None),
|
||||
}).extend(fan.FAN_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -7,7 +7,7 @@ from esphomeyaml.const import CONF_HIGH, CONF_LOW, CONF_MAKE_ID, CONF_MEDIUM, CO
|
||||
CONF_SPEED_STATE_TOPIC
|
||||
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(CONF_MAKE_ID): cv.declare_variable_id(fan.MakeFan),
|
||||
vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
|
||||
vol.Optional(CONF_SPEED_STATE_TOPIC): cv.publish_topic,
|
||||
@@ -18,7 +18,7 @@ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_MEDIUM): cv.percentage,
|
||||
vol.Required(CONF_HIGH): cv.percentage,
|
||||
}),
|
||||
}).extend(fan.FAN_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
121
esphomeyaml/components/font.py
Normal file
121
esphomeyaml/components/font.py
Normal file
@@ -0,0 +1,121 @@
|
||||
# coding=utf-8
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml.components import display
|
||||
from esphomeyaml.const import CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_SIZE
|
||||
from esphomeyaml.core import HexInt
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \
|
||||
relative_path
|
||||
|
||||
DEPENDENCIES = ['display']
|
||||
|
||||
Font = display.display_ns.Font
|
||||
Glyph = display.display_ns.Glyph
|
||||
|
||||
|
||||
def validate_glyphs(value):
|
||||
if isinstance(value, list):
|
||||
value = vol.Schema([cv.string])(value)
|
||||
value = vol.Schema([cv.string])(list(value))
|
||||
|
||||
def comparator(x, y):
|
||||
x_ = x.encode('utf-8')
|
||||
y_ = y.encode('utf-8')
|
||||
|
||||
for c in range(min(len(x_), len(y_))):
|
||||
if x_[c] < y_[c]:
|
||||
return -1
|
||||
if x_[c] > y_[c]:
|
||||
return 1
|
||||
|
||||
if len(x_) < len(y_):
|
||||
return -1
|
||||
elif len(x_) > len(y_):
|
||||
return 1
|
||||
else:
|
||||
raise vol.Invalid(u"Found duplicate glyph {}".format(x))
|
||||
|
||||
value.sort(cmp=comparator)
|
||||
return value
|
||||
|
||||
|
||||
def validate_pillow_installed(value):
|
||||
try:
|
||||
import PIL
|
||||
except ImportError:
|
||||
raise vol.Invalid("Please install the pillow python package to use this feature. "
|
||||
"(pip2 install pillow)")
|
||||
|
||||
if PIL.__version__[0] < '4':
|
||||
raise vol.Invalid("Please update your pillow installation to at least 4.0.x. "
|
||||
"(pip2 install -U pillow)")
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def validate_truetype_file(value):
|
||||
if value.endswith('.zip'): # for Google Fonts downloads
|
||||
raise vol.Invalid(u"Please unzip the font archive '{}' first and then use the .ttf files "
|
||||
u"inside.".format(value))
|
||||
if not value.endswith('.ttf'):
|
||||
raise vol.Invalid(u"Only truetype (.ttf) files are supported. Please make sure you're "
|
||||
u"using the correct format or rename the extension to .ttf")
|
||||
return cv.file_(value)
|
||||
|
||||
|
||||
DEFAULT_GLYPHS = u' !"%()+,-.:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°'
|
||||
CONF_RAW_DATA_ID = 'raw_data_id'
|
||||
|
||||
FONT_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_ID): cv.declare_variable_id(Font),
|
||||
vol.Required(CONF_FILE): validate_truetype_file,
|
||||
vol.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs,
|
||||
vol.Optional(CONF_SIZE, default=20): vol.All(cv.int_, vol.Range(min=1)),
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(None),
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.All(validate_pillow_installed, cv.ensure_list, [FONT_SCHEMA])
|
||||
|
||||
|
||||
def to_code(config):
|
||||
from PIL import ImageFont
|
||||
|
||||
for conf in config:
|
||||
path = relative_path(conf[CONF_FILE])
|
||||
try:
|
||||
font = ImageFont.truetype(path, conf[CONF_SIZE])
|
||||
except Exception as e:
|
||||
raise core.ESPHomeYAMLError(u"Could not load truetype file {}: {}".format(path, e))
|
||||
|
||||
ascent, descent = font.getmetrics()
|
||||
|
||||
glyph_args = {}
|
||||
data = []
|
||||
for glyph in conf[CONF_GLYPHS]:
|
||||
mask = font.getmask(glyph, mode='1')
|
||||
_, (offset_x, offset_y) = font.font.getsize(glyph)
|
||||
width, height = mask.size
|
||||
width8 = ((width + 7) // 8) * 8
|
||||
glyph_data = [0 for _ in range(height * width8 // 8)] # noqa: F812
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if not mask.getpixel((x, y)):
|
||||
continue
|
||||
pos = x + y * width8
|
||||
glyph_data[pos // 8] |= 0x80 >> (pos % 8)
|
||||
glyph_args[glyph] = (len(data), offset_x, offset_y, width, height)
|
||||
data += glyph_data
|
||||
|
||||
raw_data = MockObj(conf[CONF_RAW_DATA_ID])
|
||||
add(RawExpression('static const uint8_t {}[{}] PROGMEM = {}'.format(
|
||||
raw_data, len(data),
|
||||
ArrayInitializer(*[HexInt(x) for x in data], multiline=False))))
|
||||
|
||||
glyphs = []
|
||||
for glyph in conf[CONF_GLYPHS]:
|
||||
glyphs.append(Glyph(glyph, raw_data, *glyph_args[glyph]))
|
||||
|
||||
rhs = App.make_font(ArrayInitializer(*glyphs), ascent, ascent + descent)
|
||||
Pvariable(conf[CONF_ID], rhs)
|
||||
@@ -13,8 +13,11 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_SDA, default='SDA'): pins.input_output_pin,
|
||||
vol.Required(CONF_SCL, default='SCL'): pins.input_output_pin,
|
||||
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_RECEIVE_TIMEOUT): cv.invalid("The receive_timeout option has been removed "
|
||||
"because timeouts are already handled by the "
|
||||
"low-level i2c interface.")
|
||||
})
|
||||
|
||||
|
||||
@@ -23,8 +26,6 @@ def to_code(config):
|
||||
i2c = Pvariable(config[CONF_ID], rhs)
|
||||
if CONF_FREQUENCY in config:
|
||||
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'
|
||||
|
||||
65
esphomeyaml/components/image.py
Normal file
65
esphomeyaml/components/image.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# coding=utf-8
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml.components import display, font
|
||||
from esphomeyaml.const import CONF_FILE, CONF_ID, CONF_RESIZE
|
||||
from esphomeyaml.core import HexInt
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \
|
||||
relative_path
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['display']
|
||||
|
||||
Image_ = display.display_ns.Image
|
||||
|
||||
CONF_RAW_DATA_ID = 'raw_data_id'
|
||||
|
||||
IMAGE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_ID): cv.declare_variable_id(Image_),
|
||||
vol.Required(CONF_FILE): cv.file_,
|
||||
vol.Optional(CONF_RESIZE): cv.dimensions,
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(None),
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.All(font.validate_pillow_installed, cv.ensure_list, [IMAGE_SCHEMA])
|
||||
|
||||
|
||||
def to_code(config):
|
||||
from PIL import Image
|
||||
|
||||
for conf in config:
|
||||
path = relative_path(conf[CONF_FILE])
|
||||
try:
|
||||
image = Image.open(path)
|
||||
except Exception as e:
|
||||
raise core.ESPHomeYAMLError(u"Could not load image file {}: {}".format(path, e))
|
||||
|
||||
if CONF_RESIZE in conf:
|
||||
image.thumbnail(conf[CONF_RESIZE])
|
||||
|
||||
image = image.convert('1', dither=Image.NONE)
|
||||
width, height = image.size
|
||||
if width > 500 or height > 500:
|
||||
_LOGGER.warning("The image you requested is very big. Please consider using the resize "
|
||||
"parameter")
|
||||
width8 = ((width + 7) // 8) * 8
|
||||
data = [0 for _ in range(height * width8 // 8)]
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if image.getpixel((x, y)):
|
||||
continue
|
||||
pos = x + y * width8
|
||||
data[pos // 8] |= 0x80 >> (pos % 8)
|
||||
|
||||
raw_data = MockObj(conf[CONF_RAW_DATA_ID])
|
||||
add(RawExpression('static const uint8_t {}[{}] PROGMEM = {}'.format(
|
||||
raw_data, len(data),
|
||||
ArrayInitializer(*[HexInt(x) for x in data], multiline=False))))
|
||||
|
||||
rhs = App.make_image(raw_data, width, height)
|
||||
Pvariable(conf[CONF_ID], rhs)
|
||||
@@ -1,28 +1,6 @@
|
||||
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
|
||||
|
||||
IRTransmitterComponent = switch.switch_ns.namespace('IRTransmitterComponent')
|
||||
|
||||
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(IRTransmitterComponent),
|
||||
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_CARRIER_DUTY_PERCENT): vol.All(vol.Coerce(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_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT))
|
||||
Pvariable(conf[CONF_ID], rhs)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'
|
||||
def CONFIG_SCHEMA(config):
|
||||
raise vol.Invalid("The ir_transmitter component has been renamed to "
|
||||
"remote_transmitter because of 433MHz signal support.")
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \
|
||||
CONF_MQTT_ID
|
||||
from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component
|
||||
from esphomeyaml.const import CONF_ALPHA, CONF_BLUE, CONF_BRIGHTNESS, CONF_COLORS, \
|
||||
CONF_DEFAULT_TRANSITION_LENGTH, CONF_DURATION, CONF_EFFECTS, CONF_EFFECT_ID, \
|
||||
CONF_GAMMA_CORRECT, \
|
||||
CONF_GREEN, CONF_ID, CONF_INTERNAL, CONF_LAMBDA, CONF_MQTT_ID, CONF_NAME, CONF_NUM_LEDS, \
|
||||
CONF_RANDOM, CONF_RED, CONF_SPEED, CONF_STATE, CONF_TRANSITION_LENGTH, CONF_UPDATE_INTERVAL, \
|
||||
CONF_WHITE, CONF_WIDTH
|
||||
from esphomeyaml.helpers import Application, ArrayInitializer, Pvariable, RawExpression, \
|
||||
StructInitializer, add, add_job, esphomelib_ns, process_lambda, setup_mqtt_component
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
|
||||
@@ -9,23 +16,317 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
|
||||
light_ns = esphomelib_ns.namespace('light')
|
||||
LightState = light_ns.LightState
|
||||
LightColorValues = light_ns.LightColorValues
|
||||
MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent
|
||||
ToggleAction = light_ns.ToggleAction
|
||||
TurnOffAction = light_ns.TurnOffAction
|
||||
TurnOnAction = light_ns.TurnOnAction
|
||||
MakeLight = Application.MakeLight
|
||||
RandomLightEffect = light_ns.RandomLightEffect
|
||||
LambdaLightEffect = light_ns.LambdaLightEffect
|
||||
StrobeLightEffect = light_ns.StrobeLightEffect
|
||||
StrobeLightEffectColor = light_ns.StrobeLightEffectColor
|
||||
FlickerLightEffect = light_ns.FlickerLightEffect
|
||||
FastLEDLambdaLightEffect = light_ns.FastLEDLambdaLightEffect
|
||||
FastLEDRainbowLightEffect = light_ns.FastLEDRainbowLightEffect
|
||||
FastLEDColorWipeEffect = light_ns.FastLEDColorWipeEffect
|
||||
FastLEDColorWipeEffectColor = light_ns.FastLEDColorWipeEffectColor
|
||||
FastLEDScanEffect = light_ns.FastLEDScanEffect
|
||||
FastLEDScanEffectColor = light_ns.FastLEDScanEffectColor
|
||||
FastLEDTwinkleEffect = light_ns.FastLEDTwinkleEffect
|
||||
FastLEDRandomTwinkleEffect = light_ns.FastLEDRandomTwinkleEffect
|
||||
FastLEDFireworksEffect = light_ns.FastLEDFireworksEffect
|
||||
FastLEDFlickerEffect = light_ns.FastLEDFlickerEffect
|
||||
FastLEDLightOutputComponent = light_ns.FastLEDLightOutputComponent
|
||||
|
||||
CONF_STROBE = 'strobe'
|
||||
CONF_FLICKER = 'flicker'
|
||||
CONF_FASTLED_LAMBDA = 'fastled_lambda'
|
||||
CONF_FASTLED_RAINBOW = 'fastled_rainbow'
|
||||
CONF_FASTLED_COLOR_WIPE = 'fastled_color_wipe'
|
||||
CONF_FASTLED_SCAN = 'fastled_scan'
|
||||
CONF_FASTLED_TWINKLE = 'fastled_twinkle'
|
||||
CONF_FASTLED_RANDOM_TWINKLE = 'fastled_random_twinkle'
|
||||
CONF_FASTLED_FIREWORKS = 'fastled_fireworks'
|
||||
CONF_FASTLED_FLICKER = 'fastled_flicker'
|
||||
|
||||
CONF_ADD_LED_INTERVAL = 'add_led_interval'
|
||||
CONF_REVERSE = 'reverse'
|
||||
CONF_MOVE_INTERVAL = 'move_interval'
|
||||
CONF_TWINKLE_PROBABILITY = 'twinkle_probability'
|
||||
CONF_PROGRESS_INTERVAL = 'progress_interval'
|
||||
CONF_SPARK_PROBABILITY = 'spark_probability'
|
||||
CONF_USE_RANDOM_COLOR = 'use_random_color'
|
||||
CONF_FADE_OUT_RATE = 'fade_out_rate'
|
||||
CONF_INTENSITY = 'intensity'
|
||||
|
||||
BINARY_EFFECTS = [CONF_LAMBDA, CONF_STROBE]
|
||||
MONOCHROMATIC_EFFECTS = BINARY_EFFECTS + [CONF_FLICKER]
|
||||
RGB_EFFECTS = MONOCHROMATIC_EFFECTS + [CONF_RANDOM]
|
||||
FASTLED_EFFECTS = RGB_EFFECTS + [CONF_FASTLED_LAMBDA, CONF_FASTLED_RAINBOW, CONF_FASTLED_COLOR_WIPE,
|
||||
CONF_FASTLED_SCAN, CONF_FASTLED_TWINKLE,
|
||||
CONF_FASTLED_RANDOM_TWINKLE, CONF_FASTLED_FIREWORKS,
|
||||
CONF_FASTLED_FLICKER]
|
||||
|
||||
EFFECTS_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_LAMBDA): vol.Schema({
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL, default='0ms'): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_RANDOM): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(RandomLightEffect),
|
||||
vol.Optional(CONF_NAME, default="Random"): cv.string,
|
||||
vol.Optional(CONF_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_STROBE): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(StrobeLightEffect),
|
||||
vol.Optional(CONF_NAME, default="Strobe"): cv.string,
|
||||
vol.Optional(CONF_COLORS): vol.All(cv.ensure_list, [vol.All(vol.Schema({
|
||||
vol.Optional(CONF_STATE, default=True): cv.boolean,
|
||||
vol.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_RED, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_GREEN, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_BLUE, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_WHITE, default=1.0): cv.percentage,
|
||||
vol.Required(CONF_DURATION): cv.positive_time_period_milliseconds,
|
||||
}), cv.has_at_least_one_key(CONF_STATE, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE,
|
||||
CONF_WHITE))], vol.Length(min=2)),
|
||||
}),
|
||||
vol.Optional(CONF_FLICKER): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FlickerLightEffect),
|
||||
vol.Optional(CONF_NAME, default="Flicker"): cv.string,
|
||||
vol.Optional(CONF_ALPHA): cv.percentage,
|
||||
vol.Optional(CONF_INTENSITY): cv.percentage,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_LAMBDA): vol.Schema({
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL, default='0ms'): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_RAINBOW): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDRainbowLightEffect),
|
||||
vol.Optional(CONF_NAME, default="Rainbow"): cv.string,
|
||||
vol.Optional(CONF_SPEED): cv.uint32_t,
|
||||
vol.Optional(CONF_WIDTH): cv.uint32_t,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_COLOR_WIPE): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDColorWipeEffect),
|
||||
vol.Optional(CONF_NAME, default="Color Wipe"): cv.string,
|
||||
vol.Optional(CONF_COLORS): vol.All(cv.ensure_list, [vol.Schema({
|
||||
vol.Optional(CONF_RED, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_GREEN, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_BLUE, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_RANDOM, default=False): cv.boolean,
|
||||
vol.Required(CONF_NUM_LEDS): vol.All(cv.uint32_t, vol.Range(min=1)),
|
||||
})]),
|
||||
vol.Optional(CONF_ADD_LED_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_REVERSE): cv.boolean,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_SCAN): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDScanEffect),
|
||||
vol.Optional(CONF_NAME, default="Scan"): cv.string,
|
||||
vol.Optional(CONF_MOVE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_TWINKLE): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDTwinkleEffect),
|
||||
vol.Optional(CONF_NAME, default="Twinkle"): cv.string,
|
||||
vol.Optional(CONF_TWINKLE_PROBABILITY): cv.percentage,
|
||||
vol.Optional(CONF_PROGRESS_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_RANDOM_TWINKLE): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDRandomTwinkleEffect),
|
||||
vol.Optional(CONF_NAME, default="Random Twinkle"): cv.string,
|
||||
vol.Optional(CONF_TWINKLE_PROBABILITY): cv.percentage,
|
||||
vol.Optional(CONF_PROGRESS_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_FIREWORKS): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDFireworksEffect),
|
||||
vol.Optional(CONF_NAME, default="Fireworks"): cv.string,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_SPARK_PROBABILITY): cv.percentage,
|
||||
vol.Optional(CONF_USE_RANDOM_COLOR): cv.boolean,
|
||||
vol.Optional(CONF_FADE_OUT_RATE): cv.uint8_t,
|
||||
}),
|
||||
vol.Optional(CONF_FASTLED_FLICKER): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDFlickerEffect),
|
||||
vol.Optional(CONF_NAME, default="FastLED Flicker"): cv.string,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_INTENSITY): cv.percentage,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
def validate_effects(allowed_effects):
|
||||
def validator(value):
|
||||
value = cv.ensure_list(value)
|
||||
names = set()
|
||||
ret = []
|
||||
for i, effect in enumerate(value):
|
||||
if not isinstance(effect, dict):
|
||||
raise vol.Invalid("Each effect must be a dictionary, not {}".format(type(value)))
|
||||
if len(effect) > 1:
|
||||
raise vol.Invalid("Each entry in the 'effects:' option must be a single effect.")
|
||||
if not effect:
|
||||
raise vol.Invalid("Found no effect for the {}th entry in 'effects:'!".format(i))
|
||||
key = next(iter(effect.keys()))
|
||||
if key not in allowed_effects:
|
||||
raise vol.Invalid("The effect '{}' does not exist or is not allowed for this "
|
||||
"light type".format(key))
|
||||
effect[key] = effect[key] or {}
|
||||
conf = EFFECTS_SCHEMA(effect)
|
||||
name = conf[key][CONF_NAME]
|
||||
if name in names:
|
||||
raise vol.Invalid(u"Found the effect name '{}' twice. All effects must have "
|
||||
u"unique names".format(name))
|
||||
names.add(name)
|
||||
ret.append(conf)
|
||||
return ret
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
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 build_effect(full_config):
|
||||
key, config = next(iter(full_config.items()))
|
||||
if key == CONF_LAMBDA:
|
||||
lambda_ = None
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], []):
|
||||
yield None
|
||||
yield LambdaLightEffect.new(config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL])
|
||||
elif key == CONF_RANDOM:
|
||||
rhs = RandomLightEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_TRANSITION_LENGTH in config:
|
||||
add(effect.set_transition_length(config[CONF_TRANSITION_LENGTH]))
|
||||
if CONF_UPDATE_INTERVAL in config:
|
||||
add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL]))
|
||||
yield effect
|
||||
elif key == CONF_STROBE:
|
||||
rhs = StrobeLightEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
colors = []
|
||||
for color in config.get(CONF_COLORS, []):
|
||||
colors.append(StructInitializer(
|
||||
StrobeLightEffectColor,
|
||||
('color', LightColorValues(color[CONF_STATE], color[CONF_BRIGHTNESS],
|
||||
color[CONF_RED], color[CONF_GREEN], color[CONF_BLUE],
|
||||
color[CONF_WHITE])),
|
||||
('duration', color[CONF_DURATION]),
|
||||
))
|
||||
if colors:
|
||||
add(effect.set_colors(ArrayInitializer(*colors)))
|
||||
yield effect
|
||||
elif key == CONF_FLICKER:
|
||||
rhs = FlickerLightEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_ALPHA in config:
|
||||
add(effect.set_alpha(config[CONF_ALPHA]))
|
||||
if CONF_INTENSITY in config:
|
||||
add(effect.set_intensity(config[CONF_INTENSITY]))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_LAMBDA:
|
||||
lambda_ = None
|
||||
args = [(RawExpression('FastLEDLightOutputComponent &'), 'it')]
|
||||
for lambda_ in process_lambda(config[CONF_LAMBDA], args):
|
||||
yield None
|
||||
yield FastLEDLambdaLightEffect.new(config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL])
|
||||
elif key == CONF_FASTLED_RAINBOW:
|
||||
rhs = FastLEDRainbowLightEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_SPEED in config:
|
||||
add(effect.set_speed(config[CONF_SPEED]))
|
||||
if CONF_WIDTH in config:
|
||||
add(effect.set_width(config[CONF_WIDTH]))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_COLOR_WIPE:
|
||||
rhs = FastLEDColorWipeEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_ADD_LED_INTERVAL in config:
|
||||
add(effect.set_add_led_interval(config[CONF_ADD_LED_INTERVAL]))
|
||||
if CONF_REVERSE in config:
|
||||
add(effect.set_reverse(config[CONF_REVERSE]))
|
||||
colors = []
|
||||
for color in config.get(CONF_COLORS, []):
|
||||
colors.append(StructInitializer(
|
||||
FastLEDColorWipeEffectColor,
|
||||
('r', color[CONF_RED]),
|
||||
('g', color[CONF_GREEN]),
|
||||
('b', color[CONF_BLUE]),
|
||||
('random', color[CONF_RANDOM]),
|
||||
('num_leds', color[CONF_NUM_LEDS]),
|
||||
))
|
||||
if colors:
|
||||
add(effect.set_colors(ArrayInitializer(*colors)))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_SCAN:
|
||||
rhs = FastLEDScanEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_MOVE_INTERVAL in config:
|
||||
add(effect.set_move_interval(config[CONF_MOVE_INTERVAL]))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_TWINKLE:
|
||||
rhs = FastLEDTwinkleEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_TWINKLE_PROBABILITY in config:
|
||||
add(effect.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY]))
|
||||
if CONF_PROGRESS_INTERVAL in config:
|
||||
add(effect.set_progress_interval(config[CONF_PROGRESS_INTERVAL]))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_RANDOM_TWINKLE:
|
||||
rhs = FastLEDRandomTwinkleEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_TWINKLE_PROBABILITY in config:
|
||||
add(effect.set_twinkle_probability(config[CONF_TWINKLE_PROBABILITY]))
|
||||
if CONF_PROGRESS_INTERVAL in config:
|
||||
add(effect.set_progress_interval(config[CONF_PROGRESS_INTERVAL]))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_FIREWORKS:
|
||||
rhs = FastLEDFireworksEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_UPDATE_INTERVAL in config:
|
||||
add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL]))
|
||||
if CONF_SPARK_PROBABILITY in config:
|
||||
add(effect.set_spark_probability(config[CONF_SPARK_PROBABILITY]))
|
||||
if CONF_USE_RANDOM_COLOR in config:
|
||||
add(effect.set_spark_probability(config[CONF_USE_RANDOM_COLOR]))
|
||||
if CONF_FADE_OUT_RATE in config:
|
||||
add(effect.set_spark_probability(config[CONF_FADE_OUT_RATE]))
|
||||
yield effect
|
||||
elif key == CONF_FASTLED_FLICKER:
|
||||
rhs = FastLEDFlickerEffect.new(config[CONF_NAME])
|
||||
effect = Pvariable(config[CONF_EFFECT_ID], rhs)
|
||||
if CONF_UPDATE_INTERVAL in config:
|
||||
add(effect.set_update_interval(config[CONF_UPDATE_INTERVAL]))
|
||||
if CONF_INTENSITY in config:
|
||||
add(effect.set_intensity(config[CONF_INTENSITY]))
|
||||
yield effect
|
||||
else:
|
||||
raise NotImplementedError("Effect {} not implemented".format(next(config.keys())))
|
||||
|
||||
|
||||
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:
|
||||
add(light_var.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH]))
|
||||
if CONF_GAMMA_CORRECT in config:
|
||||
add(light_var.set_gamma_correct(config[CONF_GAMMA_CORRECT]))
|
||||
effects = []
|
||||
for conf in config.get(CONF_EFFECTS, []):
|
||||
for effect in build_effect(conf):
|
||||
yield
|
||||
effects.append(effect)
|
||||
if effects:
|
||||
add(light_var.add_effects(ArrayInitializer(*effects)))
|
||||
|
||||
setup_mqtt_component(mqtt_var, config)
|
||||
|
||||
@@ -33,7 +334,7 @@ def setup_light_core_(light_var, mqtt_var, config):
|
||||
def setup_light(light_obj, mqtt_obj, config):
|
||||
light_var = Pvariable(config[CONF_ID], light_obj, has_side_effects=False)
|
||||
mqtt_var = Pvariable(config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
|
||||
setup_light_core_(light_var, mqtt_var, config)
|
||||
add_job(setup_light_core_, light_var, mqtt_var, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_LIGHT'
|
||||
|
||||
@@ -2,13 +2,14 @@ import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
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, CONF_EFFECTS
|
||||
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(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
|
||||
vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
|
||||
}).extend(light.LIGHT_SCHEMA.schema)
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.BINARY_EFFECTS),
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
34
esphomeyaml/components/light/cwww.py
Normal file
34
esphomeyaml/components/light/cwww.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import light
|
||||
from esphomeyaml.components.light.rgbww import validate_cold_white_colder, \
|
||||
validate_color_temperature
|
||||
from esphomeyaml.const import CONF_COLD_WHITE, CONF_COLD_WHITE_COLOR_TEMPERATURE, \
|
||||
CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_MAKE_ID, \
|
||||
CONF_NAME, CONF_WARM_WHITE, CONF_WARM_WHITE_COLOR_TEMPERATURE
|
||||
from esphomeyaml.helpers import App, get_variable, variable
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
|
||||
vol.Required(CONF_COLD_WHITE): cv.use_variable_id(None),
|
||||
vol.Required(CONF_WARM_WHITE): cv.use_variable_id(None),
|
||||
vol.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): validate_color_temperature,
|
||||
vol.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): validate_color_temperature,
|
||||
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.MONOCHROMATIC_EFFECTS),
|
||||
}), validate_cold_white_colder)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for cold_white in get_variable(config[CONF_COLD_WHITE]):
|
||||
yield
|
||||
for warm_white in get_variable(config[CONF_WARM_WHITE]):
|
||||
yield
|
||||
rhs = App.make_cwww_light(config[CONF_NAME], config[CONF_COLD_WHITE_COLOR_TEMPERATURE],
|
||||
config[CONF_WARM_WHITE_COLOR_TEMPERATURE],
|
||||
cold_white, warm_white)
|
||||
light_struct = variable(config[CONF_MAKE_ID], rhs)
|
||||
light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)
|
||||
@@ -6,7 +6,7 @@ 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, \
|
||||
CONF_MAKE_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, CONF_NUM_LEDS, CONF_PIN, CONF_POWER_SUPPLY, \
|
||||
CONF_RGB_ORDER
|
||||
CONF_RGB_ORDER, CONF_EFFECTS
|
||||
from esphomeyaml.helpers import App, Application, RawExpression, TemplateArguments, add, \
|
||||
get_variable, variable
|
||||
|
||||
@@ -55,7 +55,7 @@ def validate(value):
|
||||
|
||||
MakeFastLEDLight = Application.MakeFastLEDLight
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({
|
||||
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)),
|
||||
@@ -68,7 +68,8 @@ PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
|
||||
}).extend(light.LIGHT_SCHEMA.schema), validate)
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.FASTLED_EFFECTS),
|
||||
}), validate)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -6,7 +6,7 @@ from esphomeyaml.components import light
|
||||
from esphomeyaml.components.power_supply import PowerSupplyComponent
|
||||
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_NAME, CONF_NUM_LEDS, CONF_POWER_SUPPLY, CONF_RGB_ORDER
|
||||
CONF_NAME, CONF_NUM_LEDS, CONF_POWER_SUPPLY, CONF_RGB_ORDER, CONF_EFFECTS
|
||||
from esphomeyaml.helpers import App, Application, RawExpression, TemplateArguments, add, \
|
||||
get_variable, variable
|
||||
|
||||
@@ -32,7 +32,7 @@ RGB_ORDERS = [
|
||||
|
||||
MakeFastLEDLight = Application.MakeFastLEDLight
|
||||
|
||||
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
|
||||
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)),
|
||||
@@ -46,7 +46,8 @@ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
|
||||
}).extend(light.LIGHT_SCHEMA.schema)
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.FASTLED_EFFECTS),
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -3,15 +3,16 @@ import voluptuous as vol
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import light
|
||||
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_MAKE_ID, \
|
||||
CONF_NAME, CONF_OUTPUT
|
||||
CONF_NAME, CONF_OUTPUT, CONF_EFFECTS
|
||||
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(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
|
||||
vol.Required(CONF_OUTPUT): cv.use_variable_id(None),
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
}).extend(light.LIGHT_SCHEMA.schema)
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.MONOCHROMATIC_EFFECTS),
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -3,17 +3,18 @@ import voluptuous as vol
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import light
|
||||
from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \
|
||||
CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED
|
||||
CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_EFFECTS
|
||||
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(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
|
||||
vol.Required(CONF_RED): cv.use_variable_id(None),
|
||||
vol.Required(CONF_GREEN): cv.use_variable_id(None),
|
||||
vol.Required(CONF_BLUE): cv.use_variable_id(None),
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
}).extend(light.LIGHT_SCHEMA.schema)
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.RGB_EFFECTS),
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -3,10 +3,10 @@ import voluptuous as vol
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import light
|
||||
from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \
|
||||
CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE
|
||||
CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE, CONF_EFFECTS
|
||||
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(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
|
||||
vol.Required(CONF_RED): cv.use_variable_id(None),
|
||||
vol.Required(CONF_GREEN): cv.use_variable_id(None),
|
||||
@@ -14,7 +14,8 @@ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_WHITE): cv.use_variable_id(None),
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
}).extend(light.LIGHT_SCHEMA.schema)
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.RGB_EFFECTS),
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
62
esphomeyaml/components/light/rgbww.py
Normal file
62
esphomeyaml/components/light/rgbww.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import light
|
||||
from esphomeyaml.const import CONF_BLUE, CONF_COLD_WHITE, CONF_COLD_WHITE_COLOR_TEMPERATURE, \
|
||||
CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_GREEN, CONF_MAKE_ID, \
|
||||
CONF_NAME, CONF_RED, CONF_WARM_WHITE, CONF_WARM_WHITE_COLOR_TEMPERATURE
|
||||
from esphomeyaml.helpers import App, get_variable, variable
|
||||
|
||||
|
||||
def validate_color_temperature(value):
|
||||
try:
|
||||
val = cv.float_with_unit('Color Temperature', 'mireds')(value)
|
||||
except vol.Invalid:
|
||||
val = 1000000.0 / cv.float_with_unit('Color Temperature', 'K')(value)
|
||||
if val < 0:
|
||||
raise vol.Invalid("Color temperature cannot be negative")
|
||||
return val
|
||||
|
||||
|
||||
def validate_cold_white_colder(value):
|
||||
cw = value[CONF_COLD_WHITE_COLOR_TEMPERATURE]
|
||||
ww = value[CONF_WARM_WHITE_COLOR_TEMPERATURE]
|
||||
if cw > ww:
|
||||
raise vol.Invalid("Cold white color temperature cannot be higher than warm white")
|
||||
if cw == ww:
|
||||
raise vol.Invalid("Cold white color temperature cannot be the same as warm white")
|
||||
return value
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(light.MakeLight),
|
||||
vol.Required(CONF_RED): cv.use_variable_id(None),
|
||||
vol.Required(CONF_GREEN): cv.use_variable_id(None),
|
||||
vol.Required(CONF_BLUE): cv.use_variable_id(None),
|
||||
vol.Required(CONF_COLD_WHITE): cv.use_variable_id(None),
|
||||
vol.Required(CONF_WARM_WHITE): cv.use_variable_id(None),
|
||||
vol.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): validate_color_temperature,
|
||||
vol.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): validate_color_temperature,
|
||||
|
||||
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
|
||||
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_EFFECTS): light.validate_effects(light.RGB_EFFECTS),
|
||||
}), validate_cold_white_colder)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for red in get_variable(config[CONF_RED]):
|
||||
yield
|
||||
for green in get_variable(config[CONF_GREEN]):
|
||||
yield
|
||||
for blue in get_variable(config[CONF_BLUE]):
|
||||
yield
|
||||
for cold_white in get_variable(config[CONF_COLD_WHITE]):
|
||||
yield
|
||||
for warm_white in get_variable(config[CONF_WARM_WHITE]):
|
||||
yield
|
||||
rhs = App.make_rgbww_light(config[CONF_NAME], config[CONF_COLD_WHITE_COLOR_TEMPERATURE],
|
||||
config[CONF_WARM_WHITE_COLOR_TEMPERATURE],
|
||||
red, green, blue, cold_white, warm_white)
|
||||
light_struct = variable(config[CONF_MAKE_ID], rhs)
|
||||
light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)
|
||||
@@ -35,8 +35,8 @@ LogComponent = esphomelib_ns.LogComponent
|
||||
|
||||
CONFIG_SCHEMA = vol.All(vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(LogComponent),
|
||||
vol.Optional(CONF_BAUD_RATE): cv.positive_int,
|
||||
vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int,
|
||||
vol.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int,
|
||||
vol.Optional(CONF_TX_BUFFER_SIZE): cv.validate_bytes,
|
||||
vol.Optional(CONF_LEVEL): is_log_level,
|
||||
vol.Optional(CONF_LOGS): vol.Schema({
|
||||
cv.string: is_log_level,
|
||||
|
||||
@@ -8,7 +8,7 @@ from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, C
|
||||
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LOG_TOPIC, \
|
||||
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_WILL_MESSAGE
|
||||
CONF_WILL_MESSAGE, CONF_REBOOT_TIMEOUT, CONF_SHUTDOWN_MESSAGE
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression, \
|
||||
StructInitializer, \
|
||||
TemplateArguments, add, esphomelib_ns, optional, std_string
|
||||
@@ -66,12 +66,14 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_DISCOVERY_PREFIX): cv.publish_topic,
|
||||
vol.Optional(CONF_BIRTH_MESSAGE): MQTT_MESSAGE_SCHEMA,
|
||||
vol.Optional(CONF_WILL_MESSAGE): MQTT_MESSAGE_SCHEMA,
|
||||
vol.Optional(CONF_SHUTDOWN_MESSAGE): MQTT_MESSAGE_SCHEMA,
|
||||
vol.Optional(CONF_TOPIC_PREFIX): cv.publish_topic,
|
||||
vol.Optional(CONF_LOG_TOPIC): MQTT_MESSAGE_TEMPLATE_SCHEMA,
|
||||
vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266,
|
||||
cv.ensure_list, [validate_fingerprint]),
|
||||
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.Optional(CONF_QOS, default=0): cv.mqtt_qos,
|
||||
@@ -98,7 +100,7 @@ def to_code(config):
|
||||
mqtt = Pvariable(config[CONF_ID], rhs)
|
||||
if not config.get(CONF_DISCOVERY, True):
|
||||
add(mqtt.disable_discovery())
|
||||
if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
|
||||
elif CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
|
||||
discovery_retain = config.get(CONF_DISCOVERY_RETAIN, True)
|
||||
discovery_prefix = config.get(CONF_DISCOVERY_PREFIX, 'homeassistant')
|
||||
add(mqtt.set_discovery_info(discovery_prefix, discovery_retain))
|
||||
@@ -116,6 +118,12 @@ def to_code(config):
|
||||
add(mqtt.disable_last_will())
|
||||
else:
|
||||
add(mqtt.set_last_will(exp_mqtt_message(will_message)))
|
||||
if CONF_SHUTDOWN_MESSAGE in config:
|
||||
shutdown_message = config[CONF_SHUTDOWN_MESSAGE]
|
||||
if not shutdown_message:
|
||||
add(mqtt.disable_shutdown_message())
|
||||
else:
|
||||
add(mqtt.set_shutdown_message(exp_mqtt_message(shutdown_message)))
|
||||
if CONF_CLIENT_ID in config:
|
||||
add(mqtt.set_client_id(config[CONF_CLIENT_ID]))
|
||||
if CONF_LOG_TOPIC in config:
|
||||
@@ -130,6 +138,8 @@ def to_code(config):
|
||||
add(mqtt.add_ssl_fingerprint(ArrayInitializer(*arr, multiline=False)))
|
||||
if CONF_KEEPALIVE in config:
|
||||
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, []):
|
||||
rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS])
|
||||
|
||||
@@ -14,14 +14,21 @@ BINARY_OUTPUT_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_INVERTED): cv.boolean,
|
||||
})
|
||||
|
||||
BINARY_OUTPUT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(BINARY_OUTPUT_SCHEMA.schema)
|
||||
|
||||
FLOAT_OUTPUT_SCHEMA = BINARY_OUTPUT_SCHEMA.extend({
|
||||
vol.Optional(CONF_MAX_POWER): cv.percentage,
|
||||
})
|
||||
|
||||
FLOAT_OUTPUT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(FLOAT_OUTPUT_SCHEMA.schema)
|
||||
|
||||
output_ns = esphomelib_ns.namespace('output')
|
||||
TurnOffAction = output_ns.TurnOffAction
|
||||
TurnOnAction = output_ns.TurnOnAction
|
||||
SetLevelAction = output_ns.SetLevelAction
|
||||
|
||||
|
||||
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:
|
||||
add(obj.set_inverted(config[CONF_INVERTED]))
|
||||
if not skip_power_supply and CONF_POWER_SUPPLY in config:
|
||||
@@ -33,4 +40,9 @@ def setup_output_platform(obj, config, skip_power_supply=False):
|
||||
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'
|
||||
|
||||
@@ -18,10 +18,10 @@ def valid_pwm_pin(value):
|
||||
|
||||
ESP8266PWMOutput = output.output_ns.ESP8266PWMOutput
|
||||
|
||||
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
|
||||
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),
|
||||
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -8,10 +8,10 @@ from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
|
||||
|
||||
GPIOBinaryOutputComponent = output.output_ns.GPIOBinaryOutputComponent
|
||||
|
||||
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
|
||||
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,
|
||||
}).extend(output.BINARY_OUTPUT_SCHEMA.schema)
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -21,13 +21,13 @@ def validate_frequency_bit_depth(obj):
|
||||
|
||||
LEDCOutputComponent = output.output_ns.LEDCOutputComponent
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(output.PLATFORM_SCHEMA.extend({
|
||||
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.Optional(CONF_FREQUENCY): cv.frequency,
|
||||
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))
|
||||
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema), validate_frequency_bit_depth)
|
||||
}), validate_frequency_bit_depth)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -10,12 +10,12 @@ DEPENDENCIES = ['pca9685']
|
||||
|
||||
Channel = PCA9685OutputComponent.Channel
|
||||
|
||||
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
|
||||
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.Range(min=0, max=15)),
|
||||
cv.GenerateID(CONF_PCA9685_ID): cv.use_variable_id(PCA9685OutputComponent),
|
||||
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
34
esphomeyaml/components/pn532.py
Normal file
34
esphomeyaml/components/pn532.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import binary_sensor
|
||||
from esphomeyaml.components.spi import SPIComponent
|
||||
from esphomeyaml.const import CONF_CS_PIN, CONF_ID, CONF_SPI_ID, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Pvariable, get_variable, gpio_output_pin_expression
|
||||
|
||||
DEPENDENCIES = ['spi']
|
||||
|
||||
PN532Component = binary_sensor.binary_sensor_ns.PN532Component
|
||||
|
||||
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(PN532Component),
|
||||
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
|
||||
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})])
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for conf in config:
|
||||
spi = None
|
||||
for spi in get_variable(conf[CONF_SPI_ID]):
|
||||
yield
|
||||
cs = None
|
||||
for cs in gpio_output_pin_expression(conf[CONF_CS_PIN]):
|
||||
yield
|
||||
rhs = App.make_pn532_component(spi, cs, conf.get(CONF_UPDATE_INTERVAL))
|
||||
Pvariable(conf[CONF_ID], rhs)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_PN532'
|
||||
28
esphomeyaml/components/rdm6300.py
Normal file
28
esphomeyaml/components/rdm6300.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import binary_sensor
|
||||
from esphomeyaml.components.uart import UARTComponent
|
||||
from esphomeyaml.const import CONF_ID, CONF_UART_ID
|
||||
from esphomeyaml.helpers import App, Pvariable, get_variable
|
||||
|
||||
DEPENDENCIES = ['uart']
|
||||
|
||||
RDM6300Component = binary_sensor.binary_sensor_ns.RDM6300Component
|
||||
|
||||
CONFIG_SCHEMA = vol.All(cv.ensure_list_not_empty, [vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(RDM6300Component),
|
||||
cv.GenerateID(CONF_UART_ID): cv.use_variable_id(UARTComponent),
|
||||
})])
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for conf in config:
|
||||
uart = None
|
||||
for uart in get_variable(conf[CONF_UART_ID]):
|
||||
yield
|
||||
rhs = App.make_rdm6300_component(uart)
|
||||
Pvariable(conf[CONF_ID], rhs)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_RDM6300'
|
||||
63
esphomeyaml/components/remote_receiver.py
Normal file
63
esphomeyaml/components/remote_receiver.py
Normal file
@@ -0,0 +1,63 @@
|
||||
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,
|
||||
'rc_switch': remote_ns.RCSwitchDumper,
|
||||
}
|
||||
|
||||
|
||||
def validate_dumpers_all(value):
|
||||
if not isinstance(value, (str, unicode)):
|
||||
raise vol.Invalid("Not valid dumpers")
|
||||
if value.upper() == "ALL":
|
||||
return list(sorted(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'
|
||||
116
esphomeyaml/components/remote_transmitter.py
Normal file
116
esphomeyaml/components/remote_transmitter.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_DUTY_PERCENT, CONF_CHANNEL, CONF_CODE, \
|
||||
CONF_DEVICE, CONF_FAMILY, CONF_GROUP, CONF_ID, CONF_INVERTED, CONF_ONE, CONF_PIN, \
|
||||
CONF_PROTOCOL, CONF_PULSE_LENGTH, CONF_STATE, CONF_SYNC, CONF_ZERO
|
||||
from esphomeyaml.core import HexInt
|
||||
from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, gpio_output_pin_expression
|
||||
|
||||
remote_ns = esphomelib_ns.namespace('remote')
|
||||
|
||||
RemoteTransmitterComponent = remote_ns.RemoteTransmitterComponent
|
||||
RCSwitchProtocol = remote_ns.RCSwitchProtocol
|
||||
rc_switch_protocols = remote_ns.rc_switch_protocols
|
||||
|
||||
|
||||
def validate_rc_switch_code(value):
|
||||
if not isinstance(value, (str, unicode)):
|
||||
raise vol.Invalid("All RCSwitch codes must be in quotes ('')")
|
||||
for c in value:
|
||||
if c not in ('0', '1'):
|
||||
raise vol.Invalid(u"Invalid RCSwitch code character '{}'. Only '0' and '1' are allowed"
|
||||
u"".format(c))
|
||||
if len(value) > 32:
|
||||
raise vol.Invalid("Maximum length for RCSwitch codes is 32, code '{}' has length {}"
|
||||
"".format(value, len(value)))
|
||||
if not value:
|
||||
raise vol.Invalid("RCSwitch code must not be empty")
|
||||
return value
|
||||
|
||||
|
||||
RC_SWITCH_TIMING_SCHEMA = vol.All([cv.uint8_t], vol.Length(min=2, max=2))
|
||||
|
||||
RC_SWITCH_PROTOCOL_SCHEMA = vol.Any(
|
||||
vol.All(vol.Coerce(int), vol.Range(min=1, max=7)),
|
||||
vol.Schema({
|
||||
vol.Required(CONF_PULSE_LENGTH): cv.uint32_t,
|
||||
vol.Optional(CONF_SYNC, default=[1, 31]): RC_SWITCH_TIMING_SCHEMA,
|
||||
vol.Optional(CONF_ZERO, default=[1, 3]): RC_SWITCH_TIMING_SCHEMA,
|
||||
vol.Optional(CONF_ONE, default=[3, 1]): RC_SWITCH_TIMING_SCHEMA,
|
||||
vol.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
})
|
||||
)
|
||||
|
||||
RC_SWITCH_RAW_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_CODE): validate_rc_switch_code,
|
||||
vol.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
|
||||
})
|
||||
RC_SWITCH_TYPE_A_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_GROUP): vol.All(validate_rc_switch_code, vol.Length(min=5, max=5)),
|
||||
vol.Required(CONF_DEVICE): vol.All(validate_rc_switch_code, vol.Length(min=5, max=5)),
|
||||
vol.Required(CONF_STATE): cv.boolean,
|
||||
vol.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
|
||||
})
|
||||
RC_SWITCH_TYPE_B_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_ADDRESS): vol.All(cv.uint8_t, vol.Range(min=1, max=4)),
|
||||
vol.Required(CONF_CHANNEL): vol.All(cv.uint8_t, vol.Range(min=1, max=4)),
|
||||
vol.Required(CONF_STATE): cv.boolean,
|
||||
vol.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
|
||||
})
|
||||
RC_SWITCH_TYPE_C_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_FAMILY): vol.All(
|
||||
cv.string, vol.Lower,
|
||||
cv.one_of('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p')),
|
||||
vol.Required(CONF_GROUP): vol.All(cv.uint8_t, vol.Range(min=1, max=4)),
|
||||
vol.Required(CONF_DEVICE): vol.All(cv.uint8_t, vol.Range(min=1, max=4)),
|
||||
vol.Required(CONF_STATE): cv.boolean,
|
||||
vol.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
|
||||
})
|
||||
RC_SWITCH_TYPE_D_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_GROUP): vol.All(cv.string, vol.Lower, cv.one_of('a', 'b', 'c', 'd')),
|
||||
vol.Required(CONF_DEVICE): vol.All(cv.uint8_t, vol.Range(min=1, max=3)),
|
||||
vol.Required(CONF_STATE): cv.boolean,
|
||||
vol.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
|
||||
})
|
||||
|
||||
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 build_rc_switch_protocol(config):
|
||||
if isinstance(config, int):
|
||||
return rc_switch_protocols[config]
|
||||
pl = config[CONF_PULSE_LENGTH]
|
||||
return RCSwitchProtocol(config[CONF_SYNC][0] * pl, config[CONF_SYNC][1] * pl,
|
||||
config[CONF_ZERO][0] * pl, config[CONF_ZERO][1] * pl,
|
||||
config[CONF_ONE][0] * pl, config[CONF_ONE][1] * pl,
|
||||
config[CONF_INVERTED])
|
||||
|
||||
|
||||
def binary_code(value):
|
||||
code = 0
|
||||
for val in value:
|
||||
code <<= 1
|
||||
code |= val == '1'
|
||||
return HexInt(code)
|
||||
|
||||
|
||||
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'
|
||||
@@ -4,12 +4,12 @@ import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import automation
|
||||
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_FILTER_NAN, CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_ID, CONF_LAMBDA, \
|
||||
CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_ON_RAW_VALUE, CONF_ON_VALUE,\
|
||||
CONF_FILTER_NAN, CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_ID, CONF_INTERNAL, \
|
||||
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_THROTTLE, CONF_TRIGGER_ID, CONF_UNIQUE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, esphomelib_ns, float_, \
|
||||
process_lambda, setup_mqtt_component, templatable, add_job
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, add_job, esphomelib_ns, \
|
||||
float_, process_lambda, setup_mqtt_component, templatable
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
|
||||
@@ -71,26 +71,27 @@ ValueRangeTrigger = sensor_ns.ValueRangeTrigger
|
||||
SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSensorComponent),
|
||||
cv.GenerateID(): cv.declare_variable_id(Sensor),
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string_strict,
|
||||
vol.Optional(CONF_ICON): cv.icon,
|
||||
vol.Optional(CONF_ACCURACY_DECIMALS): vol.Coerce(int),
|
||||
vol.Optional(CONF_EXPIRE_AFTER): vol.Any(None, cv.positive_time_period_milliseconds),
|
||||
vol.Optional(CONF_FILTERS): FILTERS_SCHEMA,
|
||||
vol.Optional(CONF_ON_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
|
||||
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.AUTOMATION_SCHEMA.extend({
|
||||
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.AUTOMATION_SCHEMA.extend({
|
||||
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):
|
||||
if CONF_OFFSET in config:
|
||||
@@ -140,6 +141,8 @@ def setup_filters(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:
|
||||
add(sensor_var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
|
||||
if CONF_ICON in config:
|
||||
|
||||
@@ -24,12 +24,12 @@ def validate_adc_pin(value):
|
||||
|
||||
MakeADCSensor = Application.MakeADCSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -45,12 +45,12 @@ def validate_mux(value):
|
||||
return cv.one_of(*MUX)(value)
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_MULTIPLEXER): validate_mux,
|
||||
vol.Required(CONF_GAIN): validate_gain,
|
||||
cv.GenerateID(CONF_ADS1115_ID): cv.use_variable_id(ADS1115Component),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -16,12 +16,12 @@ BH1750_RESOLUTIONS = {
|
||||
|
||||
MakeBH1750Sensor = Application.MakeBH1750Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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_RESOLUTION): vol.All(cv.positive_float, cv.one_of(*BH1750_RESOLUTIONS)),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
23
esphomeyaml/components/sensor/ble_rssi.py
Normal file
23
esphomeyaml/components/sensor/ble_rssi.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESP32BLETracker, \
|
||||
make_address_array
|
||||
from esphomeyaml.const import CONF_MAC_ADDRESS, CONF_NAME
|
||||
from esphomeyaml.helpers import get_variable
|
||||
|
||||
DEPENDENCIES = ['esp32_ble_tracker']
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(sensor.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
|
||||
rhs = hub.make_rssi_sensor(config[CONF_NAME], make_address_array(config[CONF_MAC_ADDRESS]))
|
||||
sensor.register_sensor(rhs, config)
|
||||
@@ -34,11 +34,11 @@ MakeBME280Sensor = Application.MakeBME280Sensor
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBME280Sensor),
|
||||
vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address,
|
||||
vol.Required(CONF_TEMPERATURE): BME280_OVERSAMPLING_SENSOR_SCHEMA,
|
||||
vol.Required(CONF_PRESSURE): BME280_OVERSAMPLING_SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): BME280_OVERSAMPLING_SENSOR_SCHEMA,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(BME280_OVERSAMPLING_SENSOR_SCHEMA),
|
||||
vol.Required(CONF_PRESSURE): cv.nameable(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_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_GAS_RESISTANCE, CONF_HUMIDITY, CONF_IIR_FILTER, \
|
||||
CONF_MAKE_ID, CONF_NAME, CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, \
|
||||
CONF_UPDATE_INTERVAL
|
||||
CONF_UPDATE_INTERVAL, CONF_HEATER, CONF_DURATION
|
||||
from esphomeyaml.helpers import App, Application, add, variable
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
@@ -38,13 +39,17 @@ MakeBME680Sensor = Application.MakeBME680Sensor
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBME680Sensor),
|
||||
vol.Optional(CONF_ADDRESS, default=0x76): cv.i2c_address,
|
||||
vol.Required(CONF_TEMPERATURE): BME680_OVERSAMPLING_SENSOR_SCHEMA,
|
||||
vol.Required(CONF_PRESSURE): BME680_OVERSAMPLING_SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): BME680_OVERSAMPLING_SENSOR_SCHEMA,
|
||||
vol.Required(CONF_GAS_RESISTANCE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(BME680_OVERSAMPLING_SENSOR_SCHEMA),
|
||||
vol.Required(CONF_PRESSURE): cv.nameable(BME680_OVERSAMPLING_SENSOR_SCHEMA),
|
||||
vol.Required(CONF_HUMIDITY): cv.nameable(BME680_OVERSAMPLING_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)),
|
||||
# TODO: Heater
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_HEATER): vol.Any(None, vol.All(vol.Schema({
|
||||
vol.Optional(CONF_TEMPERATURE, default=320): vol.All(vol.Coerce(int), vol.Range(200, 400)),
|
||||
vol.Optional(CONF_DURATION, default='150ms'): vol.All(
|
||||
cv.positive_time_period_milliseconds, vol.Range(max=core.TimePeriod(milliseconds=4032)))
|
||||
}, cv.has_at_least_one_key(CONF_TEMPERATURE, CONF_DURATION)))),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
@@ -69,6 +74,12 @@ def to_code(config):
|
||||
if CONF_IIR_FILTER in config:
|
||||
constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]]
|
||||
add(bme680.set_iir_filter(constant))
|
||||
if CONF_HEATER in config:
|
||||
conf = config[CONF_HEATER]
|
||||
if not conf:
|
||||
add(bme680.set_heater(0, 0))
|
||||
else:
|
||||
add(bme680.set_heater(conf[CONF_TEMPERATURE], conf[CONF_DURATION]))
|
||||
|
||||
sensor.setup_sensor(bme680.Pget_temperature_sensor(), make.Pmqtt_temperature,
|
||||
config[CONF_TEMPERATURE])
|
||||
|
||||
@@ -12,10 +12,10 @@ MakeBMP085Sensor = Application.MakeBMP085Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBMP085Sensor),
|
||||
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_PRESSURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_PRESSURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
|
||||
67
esphomeyaml/components/sensor/bmp280.py
Normal file
67
esphomeyaml/components/sensor/bmp280.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_IIR_FILTER, CONF_MAKE_ID, \
|
||||
CONF_NAME, CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Application, add, variable
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
OVERSAMPLING_OPTIONS = {
|
||||
'NONE': sensor.sensor_ns.BMP280_OVERSAMPLING_NONE,
|
||||
'1X': sensor.sensor_ns.BMP280_OVERSAMPLING_1X,
|
||||
'2X': sensor.sensor_ns.BMP280_OVERSAMPLING_2X,
|
||||
'4X': sensor.sensor_ns.BMP280_OVERSAMPLING_4X,
|
||||
'8X': sensor.sensor_ns.BMP280_OVERSAMPLING_8X,
|
||||
'16X': sensor.sensor_ns.BMP280_OVERSAMPLING_16X,
|
||||
}
|
||||
|
||||
IIR_FILTER_OPTIONS = {
|
||||
'OFF': sensor.sensor_ns.BMP280_IIR_FILTER_OFF,
|
||||
'2X': sensor.sensor_ns.BMP280_IIR_FILTER_2X,
|
||||
'4X': sensor.sensor_ns.BMP280_IIR_FILTER_4X,
|
||||
'8X': sensor.sensor_ns.BMP280_IIR_FILTER_8X,
|
||||
'16X': sensor.sensor_ns.BMP280_IIR_FILTER_16X,
|
||||
}
|
||||
|
||||
BMP280_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({
|
||||
vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)),
|
||||
})
|
||||
|
||||
MakeBMP280Sensor = Application.MakeBMP280Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeBMP280Sensor),
|
||||
vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(BMP280_OVERSAMPLING_SENSOR_SCHEMA),
|
||||
vol.Required(CONF_PRESSURE): cv.nameable(BMP280_OVERSAMPLING_SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, cv.one_of(*IIR_FILTER_OPTIONS)),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_bmp280_sensor(config[CONF_TEMPERATURE][CONF_NAME],
|
||||
config[CONF_PRESSURE][CONF_NAME],
|
||||
config[CONF_ADDRESS],
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
bmp280 = make.Pbmp280
|
||||
if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]:
|
||||
constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]]
|
||||
add(bmp280.set_temperature_oversampling(constant))
|
||||
if CONF_OVERSAMPLING in config[CONF_PRESSURE]:
|
||||
constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]]
|
||||
add(bmp280.set_pressure_oversampling(constant))
|
||||
if CONF_IIR_FILTER in config:
|
||||
constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]]
|
||||
add(bmp280.set_iir_filter(constant))
|
||||
|
||||
sensor.setup_sensor(bmp280.Pget_temperature_sensor(), make.Pmqtt_temperature,
|
||||
config[CONF_TEMPERATURE])
|
||||
sensor.setup_sensor(bmp280.Pget_pressure_sensor(), make.Pmqtt_pressure,
|
||||
config[CONF_PRESSURE])
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_BMP280'
|
||||
@@ -7,12 +7,12 @@ from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAM
|
||||
CONF_RESOLUTION
|
||||
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_INDEX, 'dallas'): cv.positive_int,
|
||||
cv.GenerateID(CONF_DALLAS_ID): cv.use_variable_id(DallasComponent),
|
||||
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):
|
||||
|
||||
@@ -20,10 +20,10 @@ MakeDHTSensor = Application.MakeDHTSensor
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeDHTSensor),
|
||||
vol.Required(CONF_PIN): gpio_output_pin_schema,
|
||||
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(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_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ MakeDHT12Sensor = Application.MakeDHT12Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeDHT12Sensor),
|
||||
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
|
||||
28
esphomeyaml/components/sensor/duty_cycle.py
Normal file
28
esphomeyaml/components/sensor/duty_cycle.py
Normal 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.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
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'
|
||||
@@ -9,10 +9,10 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
|
||||
|
||||
MakeESP32HallSensor = Application.MakeESP32HallSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -12,9 +12,9 @@ MakeHDC1080Sensor = Application.MakeHDC1080Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHDC1080Sensor),
|
||||
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
|
||||
57
esphomeyaml/components/sensor/hlw8012.py
Normal file
57
esphomeyaml/components/sensor/hlw8012.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_CF1_PIN, CONF_CF_PIN, CONF_CHANGE_MODE_EVERY, CONF_CURRENT, \
|
||||
CONF_CURRENT_RESISTOR, CONF_ID, CONF_NAME, CONF_POWER, CONF_SEL_PIN, CONF_UPDATE_INTERVAL, \
|
||||
CONF_VOLTAGE, CONF_VOLTAGE_DIVIDER
|
||||
from esphomeyaml.helpers import App, Pvariable, add, gpio_output_pin_expression
|
||||
|
||||
HLW8012Component = sensor.sensor_ns.HLW8012Component
|
||||
HLW8012VoltageSensor = sensor.sensor_ns.HLW8012VoltageSensor
|
||||
HLW8012CurrentSensor = sensor.sensor_ns.HLW8012CurrentSensor
|
||||
HLW8012PowerSensor = sensor.sensor_ns.HLW8012PowerSensor
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(HLW8012Component),
|
||||
vol.Required(CONF_SEL_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Required(CONF_CF_PIN): pins.input_pin,
|
||||
vol.Required(CONF_CF1_PIN): pins.input_pin,
|
||||
|
||||
vol.Optional(CONF_VOLTAGE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_CURRENT): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_POWER): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
|
||||
vol.Optional(CONF_CURRENT_RESISTOR): cv.resistance,
|
||||
vol.Optional(CONF_VOLTAGE_DIVIDER): cv.positive_float,
|
||||
vol.Optional(CONF_CHANGE_MODE_EVERY): vol.All(cv.uint32_t, vol.Range(min=1)),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}), cv.has_at_least_one_key(CONF_VOLTAGE, CONF_CURRENT, CONF_POWER))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
sel = None
|
||||
for sel in gpio_output_pin_expression(config[CONF_SEL_PIN]):
|
||||
yield
|
||||
|
||||
rhs = App.make_hlw8012(sel, config[CONF_CF_PIN], config[CONF_CF1_PIN],
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
hlw = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if CONF_VOLTAGE in config:
|
||||
conf = config[CONF_VOLTAGE]
|
||||
sensor.register_sensor(hlw.make_voltage_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_CURRENT in config:
|
||||
conf = config[CONF_CURRENT]
|
||||
sensor.register_sensor(hlw.make_current_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_POWER in config:
|
||||
conf = config[CONF_POWER]
|
||||
sensor.register_sensor(hlw.make_power_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_CURRENT_RESISTOR in config:
|
||||
add(hlw.set_current_resistor(config[CONF_CURRENT_RESISTOR]))
|
||||
if CONF_CHANGE_MODE_EVERY in config:
|
||||
add(hlw.set_change_mode_every(config[CONF_CHANGE_MODE_EVERY]))
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_HLW8012'
|
||||
73
esphomeyaml/components/sensor/hmc5883l.py
Normal file
73
esphomeyaml/components/sensor/hmc5883l.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# coding=utf-8
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, CONF_RANGE
|
||||
from esphomeyaml.helpers import App, Pvariable, add
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
CONF_FIELD_STRENGTH_X = 'field_strength_x'
|
||||
CONF_FIELD_STRENGTH_Y = 'field_strength_y'
|
||||
CONF_FIELD_STRENGTH_Z = 'field_strength_z'
|
||||
CONF_HEADING = 'heading'
|
||||
|
||||
HMC5883LComponent = sensor.sensor_ns.HMC5883LComponent
|
||||
HMC5883LFieldStrengthSensor = sensor.sensor_ns.HMC5883LFieldStrengthSensor
|
||||
HMC5883LHeadingSensor = sensor.sensor_ns.HMC5883LHeadingSensor
|
||||
|
||||
HMC5883L_RANGES = {
|
||||
88: sensor.sensor_ns.HMC5883L_RANGE_88_UT,
|
||||
130: sensor.sensor_ns.HMC5883L_RANGE_130_UT,
|
||||
190: sensor.sensor_ns.HMC5883L_RANGE_190_UT,
|
||||
250: sensor.sensor_ns.HMC5883L_RANGE_250_UT,
|
||||
400: sensor.sensor_ns.HMC5883L_RANGE_400_UT,
|
||||
470: sensor.sensor_ns.HMC5883L_RANGE_470_UT,
|
||||
560: sensor.sensor_ns.HMC5883L_RANGE_560_UT,
|
||||
810: sensor.sensor_ns.HMC5883L_RANGE_810_UT,
|
||||
}
|
||||
|
||||
|
||||
def validate_range(value):
|
||||
value = cv.string(value)
|
||||
if value.endswith(u'µT') or value.endswith('uT'):
|
||||
value = value[:-2]
|
||||
return cv.one_of(*HMC5883L_RANGES)(int(value))
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(HMC5883LComponent),
|
||||
vol.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
vol.Optional(CONF_FIELD_STRENGTH_X): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_FIELD_STRENGTH_Y): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_FIELD_STRENGTH_Z): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_HEADING): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
vol.Optional(CONF_RANGE): validate_range,
|
||||
}), cv.has_at_least_one_key(CONF_FIELD_STRENGTH_X, CONF_FIELD_STRENGTH_Y, CONF_FIELD_STRENGTH_Z,
|
||||
CONF_HEADING))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_hmc5883l(config.get(CONF_UPDATE_INTERVAL))
|
||||
hmc = Pvariable(config[CONF_ID], rhs)
|
||||
if CONF_ADDRESS in config:
|
||||
add(hmc.set_address(config[CONF_ADDRESS]))
|
||||
if CONF_RANGE in config:
|
||||
add(hmc.set_range(HMC5883L_RANGES[config[CONF_RANGE]]))
|
||||
if CONF_FIELD_STRENGTH_X in config:
|
||||
conf = config[CONF_FIELD_STRENGTH_X]
|
||||
sensor.register_sensor(hmc.Pmake_x_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_FIELD_STRENGTH_Y in config:
|
||||
conf = config[CONF_FIELD_STRENGTH_Y]
|
||||
sensor.register_sensor(hmc.Pmake_y_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_FIELD_STRENGTH_Z in config:
|
||||
conf = config[CONF_FIELD_STRENGTH_Z]
|
||||
sensor.register_sensor(hmc.Pmake_z_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_HEADING in config:
|
||||
conf = config[CONF_HEADING]
|
||||
sensor.register_sensor(hmc.Pmake_heading_sensor(conf[CONF_NAME]), conf)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_HMC5883L'
|
||||
@@ -12,9 +12,9 @@ MakeHTU21DSensor = Application.MakeHTU21DSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHTU21DSensor),
|
||||
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
|
||||
46
esphomeyaml/components/sensor/hx711.py
Normal file
46
esphomeyaml/components/sensor/hx711.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_GAIN, CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL, CONF_CLK_PIN
|
||||
from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, variable
|
||||
|
||||
MakeHX711Sensor = Application.MakeHX711Sensor
|
||||
|
||||
CONF_DOUT_PIN = 'dout_pin'
|
||||
|
||||
GAINS = {
|
||||
128: sensor.sensor_ns.HX711_GAIN_128,
|
||||
32: sensor.sensor_ns.HX711_GAIN_32,
|
||||
64: sensor.sensor_ns.HX711_GAIN_64,
|
||||
}
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHX711Sensor),
|
||||
vol.Required(CONF_DOUT_PIN): pins.gpio_input_pin_schema,
|
||||
vol.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_GAIN): vol.All(cv.int_, cv.one_of(*GAINS)),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
dout_pin = None
|
||||
for dout_pin in gpio_input_pin_expression(config[CONF_DOUT_PIN]):
|
||||
yield
|
||||
sck_pin = None
|
||||
for sck_pin in gpio_input_pin_expression(config[CONF_CLK_PIN]):
|
||||
yield
|
||||
|
||||
rhs = App.make_hx711_sensor(config[CONF_NAME], dout_pin, sck_pin,
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
|
||||
if CONF_GAIN in config:
|
||||
add(make.Phx711.set_gain(GAINS[config[CONF_GAIN]]))
|
||||
|
||||
sensor.setup_sensor(make.Phx711, make.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_HX711'
|
||||
53
esphomeyaml/components/sensor/ina219.py
Normal file
53
esphomeyaml/components/sensor/ina219.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# coding=utf-8
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_CURRENT, CONF_ID, CONF_MAX_CURRENT, \
|
||||
CONF_MAX_VOLTAGE, CONF_NAME, CONF_POWER, CONF_UPDATE_INTERVAL, CONF_BUS_VOLTAGE, \
|
||||
CONF_SHUNT_VOLTAGE, CONF_SHUNT_RESISTANCE
|
||||
from esphomeyaml.helpers import App, Pvariable
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
INA219Component = sensor.sensor_ns.INA219Component
|
||||
INA219VoltageSensor = sensor.sensor_ns.INA219VoltageSensor
|
||||
INA219CurrentSensor = sensor.sensor_ns.INA219CurrentSensor
|
||||
INA219PowerSensor = sensor.sensor_ns.INA219PowerSensor
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(INA219Component),
|
||||
vol.Optional(CONF_ADDRESS, default=0x40): cv.i2c_address,
|
||||
vol.Optional(CONF_BUS_VOLTAGE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_SHUNT_VOLTAGE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_CURRENT): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_POWER): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_SHUNT_RESISTANCE, default=0.1): vol.All(cv.resistance,
|
||||
vol.Range(min=0.0, max=32.0)),
|
||||
vol.Optional(CONF_MAX_VOLTAGE, default=32.0): vol.All(cv.voltage, vol.Range(min=0.0, max=32.0)),
|
||||
vol.Optional(CONF_MAX_CURRENT, default=3.2): vol.All(cv.current, vol.Range(min=0.0)),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}), cv.has_at_least_one_key(CONF_BUS_VOLTAGE, CONF_SHUNT_VOLTAGE, CONF_CURRENT,
|
||||
CONF_POWER))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_ina219(config[CONF_SHUNT_RESISTANCE],
|
||||
config[CONF_MAX_CURRENT], config[CONF_MAX_VOLTAGE],
|
||||
config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL))
|
||||
ina = Pvariable(config[CONF_ID], rhs)
|
||||
if CONF_BUS_VOLTAGE in config:
|
||||
conf = config[CONF_BUS_VOLTAGE]
|
||||
sensor.register_sensor(ina.Pmake_bus_voltage_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_SHUNT_VOLTAGE in config:
|
||||
conf = config[CONF_SHUNT_VOLTAGE]
|
||||
sensor.register_sensor(ina.Pmake_shunt_voltage_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_CURRENT in config:
|
||||
conf = config[CONF_CURRENT]
|
||||
sensor.register_sensor(ina.Pmake_current_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_POWER in config:
|
||||
conf = config[CONF_POWER]
|
||||
sensor.register_sensor(ina.Pmake_power_sensor(conf[CONF_NAME]), conf)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_INA219'
|
||||
64
esphomeyaml/components/sensor/ina3221.py
Normal file
64
esphomeyaml/components/sensor/ina3221.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# coding=utf-8
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_BUS_VOLTAGE, CONF_CURRENT, CONF_ID, CONF_NAME, \
|
||||
CONF_POWER, CONF_SHUNT_RESISTANCE, CONF_SHUNT_VOLTAGE, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Pvariable, add
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
CONF_CHANNEL_1 = 'channel_1'
|
||||
CONF_CHANNEL_2 = 'channel_2'
|
||||
CONF_CHANNEL_3 = 'channel_3'
|
||||
|
||||
INA3221Component = sensor.sensor_ns.INA3221Component
|
||||
INA3221VoltageSensor = sensor.sensor_ns.INA3221VoltageSensor
|
||||
INA3221CurrentSensor = sensor.sensor_ns.INA3221CurrentSensor
|
||||
INA3221PowerSensor = sensor.sensor_ns.INA3221PowerSensor
|
||||
|
||||
INA3221_CHANNEL_SCHEMA = vol.All(vol.Schema({
|
||||
vol.Optional(CONF_BUS_VOLTAGE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_SHUNT_VOLTAGE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_CURRENT): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_POWER): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_SHUNT_RESISTANCE, default=0.1): vol.All(cv.resistance,
|
||||
vol.Range(min=0.0, max=32.0)),
|
||||
}), cv.has_at_least_one_key(CONF_BUS_VOLTAGE, CONF_SHUNT_VOLTAGE, CONF_CURRENT,
|
||||
CONF_POWER))
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(INA3221Component),
|
||||
vol.Optional(CONF_ADDRESS, default=0x40): cv.i2c_address,
|
||||
vol.Optional(CONF_CHANNEL_1): INA3221_CHANNEL_SCHEMA,
|
||||
vol.Optional(CONF_CHANNEL_2): INA3221_CHANNEL_SCHEMA,
|
||||
vol.Optional(CONF_CHANNEL_3): INA3221_CHANNEL_SCHEMA,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_ina3221(config[CONF_ADDRESS], config.get(CONF_UPDATE_INTERVAL))
|
||||
ina = Pvariable(config[CONF_ID], rhs)
|
||||
for i, channel in enumerate([CONF_CHANNEL_1, CONF_CHANNEL_2, CONF_CHANNEL_3]):
|
||||
if channel not in config:
|
||||
continue
|
||||
conf = config[channel]
|
||||
if CONF_SHUNT_RESISTANCE in conf:
|
||||
add(ina.set_shunt_resistance(i, conf[CONF_SHUNT_RESISTANCE]))
|
||||
if CONF_BUS_VOLTAGE in conf:
|
||||
c = conf[CONF_BUS_VOLTAGE]
|
||||
sensor.register_sensor(ina.Pmake_bus_voltage_sensor(i, c[CONF_NAME]), c)
|
||||
if CONF_SHUNT_VOLTAGE in conf:
|
||||
c = conf[CONF_SHUNT_VOLTAGE]
|
||||
sensor.register_sensor(ina.Pmake_shunt_voltage_sensor(i, c[CONF_NAME]), c)
|
||||
if CONF_CURRENT in conf:
|
||||
c = conf[CONF_CURRENT]
|
||||
sensor.register_sensor(ina.Pmake_current_sensor(i, c[CONF_NAME]), c)
|
||||
if CONF_POWER in conf:
|
||||
c = conf[CONF_POWER]
|
||||
sensor.register_sensor(ina.Pmake_power_sensor(i, c[CONF_NAME]), c)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_INA3221'
|
||||
@@ -3,33 +3,29 @@ 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_CLOCK, CONF_PIN_CS, CONF_PIN_MISO, \
|
||||
from esphomeyaml.components.spi import SPIComponent
|
||||
from esphomeyaml.const import CONF_CS_PIN, CONF_MAKE_ID, CONF_NAME, CONF_SPI_ID, \
|
||||
CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, \
|
||||
gpio_output_pin_expression, variable
|
||||
from esphomeyaml.helpers import App, Application, get_variable, gpio_output_pin_expression, variable
|
||||
|
||||
MakeMAX6675Sensor = Application.MakeMAX6675Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
|
||||
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
pin_cs = None
|
||||
for pin_cs in gpio_output_pin_expression(config[CONF_PIN_CS]):
|
||||
spi = None
|
||||
for spi in get_variable(config[CONF_SPI_ID]):
|
||||
yield
|
||||
pin_clock = None
|
||||
for pin_clock in gpio_output_pin_expression(config[CONF_PIN_CLOCK]):
|
||||
cs = None
|
||||
for cs in gpio_output_pin_expression(config[CONF_CS_PIN]):
|
||||
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], spi, cs,
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
sensor.setup_sensor(make.Pmax6675, make.Pmqtt, config)
|
||||
|
||||
38
esphomeyaml/components/sensor/mhz19.py
Normal file
38
esphomeyaml/components/sensor/mhz19.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.components.uart import UARTComponent
|
||||
from esphomeyaml.const import CONF_CO2, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, CONF_UART_ID, \
|
||||
CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Application, get_variable, variable
|
||||
|
||||
DEPENDENCIES = ['uart']
|
||||
|
||||
MakeMHZ19Sensor = Application.MakeMHZ19Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeMHZ19Sensor),
|
||||
cv.GenerateID(CONF_UART_ID): cv.use_variable_id(UARTComponent),
|
||||
vol.Required(CONF_CO2): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
uart = None
|
||||
for uart in get_variable(config[CONF_UART_ID]):
|
||||
yield
|
||||
rhs = App.make_mhz19_sensor(uart, config[CONF_CO2][CONF_NAME],
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
mhz19 = make.Pmhz19
|
||||
sensor.setup_sensor(mhz19.Pget_co2_sensor(), make.Pmqtt, config[CONF_CO2])
|
||||
|
||||
if CONF_TEMPERATURE in config:
|
||||
sensor.register_sensor(mhz19.Pmake_temperature_sensor(config[CONF_TEMPERATURE][CONF_NAME]),
|
||||
config[CONF_TEMPERATURE])
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_MHZ19'
|
||||
@@ -23,14 +23,14 @@ 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): 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,
|
||||
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.update_interval,
|
||||
}), cv.has_at_least_one_key(CONF_ACCEL_X, CONF_ACCEL_Y, CONF_ACCEL_Z,
|
||||
CONF_GYRO_X, CONF_GYRO_Y, CONF_GYRO_Z))
|
||||
|
||||
|
||||
37
esphomeyaml/components/sensor/ms5611.py
Normal file
37
esphomeyaml/components/sensor/ms5611.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_PRESSURE, \
|
||||
CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Application, add, variable
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
MakeMS5611Sensor = Application.MakeMS5611Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeMS5611Sensor),
|
||||
vol.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_PRESSURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_ms5611_sensor(config[CONF_TEMPERATURE][CONF_NAME],
|
||||
config[CONF_PRESSURE][CONF_NAME],
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
|
||||
if CONF_ADDRESS in config:
|
||||
add(make.Pms5611.set_address(config[CONF_ADDRESS]))
|
||||
|
||||
sensor.setup_sensor(make.Pms5611.Pget_temperature_sensor(), make.Pmqtt_temperature,
|
||||
config[CONF_TEMPERATURE])
|
||||
sensor.setup_sensor(make.Pms5611.Pget_pressure_sensor(), make.Pmqtt_pressure,
|
||||
config[CONF_PRESSURE])
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_MS5611'
|
||||
@@ -1,62 +1,66 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml import core, pins
|
||||
from esphomeyaml.components import sensor
|
||||
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, \
|
||||
ESP_PLATFORM_ESP32
|
||||
from esphomeyaml.helpers import App, add, global_ns, variable, Application
|
||||
|
||||
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))
|
||||
from esphomeyaml.helpers import App, Application, add, variable, gpio_input_pin_expression
|
||||
|
||||
COUNT_MODES = {
|
||||
'DISABLE': global_ns.PCNT_COUNT_DIS,
|
||||
'INCREMENT': global_ns.PCNT_COUNT_INC,
|
||||
'DECREMENT': global_ns.PCNT_COUNT_DEC,
|
||||
'DISABLE': sensor.sensor_ns.PULSE_COUNTER_DISABLE,
|
||||
'INCREMENT': sensor.sensor_ns.PULSE_COUNTER_INCREMENT,
|
||||
'DECREMENT': sensor.sensor_ns.PULSE_COUNTER_DECREMENT,
|
||||
}
|
||||
|
||||
COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*COUNT_MODES))
|
||||
|
||||
MakePulseCounterSensor = Application.MakePulseCounterSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
|
||||
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.input_pin,
|
||||
vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA,
|
||||
vol.Required(CONF_PIN): pins.internal_gpio_input_pin_schema,
|
||||
vol.Optional(CONF_COUNT_MODE): vol.Schema({
|
||||
vol.Required(CONF_RISING_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_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_INTERNAL_FILTER): validate_internal_filter,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
|
||||
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):
|
||||
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))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
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:
|
||||
count_mode = config[CONF_COUNT_MODE]
|
||||
rising_edge = COUNT_MODES[count_mode[CONF_RISING_EDGE]]
|
||||
falling_edge = COUNT_MODES[count_mode[CONF_FALLING_EDGE]]
|
||||
rising_edge = COUNT_MODES[config[CONF_COUNT_MODE][CONF_RISING_EDGE]]
|
||||
falling_edge = COUNT_MODES[config[CONF_COUNT_MODE][CONF_FALLING_EDGE]]
|
||||
add(pcnt.set_edge_mode(rising_edge, falling_edge))
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ CONF_PIN_RESET = 'pin_reset'
|
||||
|
||||
MakeRotaryEncoderSensor = Application.MakeRotaryEncoderSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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)),
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -4,25 +4,21 @@ import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ACCURACY, CONF_ADDRESS, CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, \
|
||||
CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Application, add, variable
|
||||
from esphomeyaml.helpers import App, Application, variable
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
SHT_ACCURACIES = {
|
||||
'LOW': sensor.sensor_ns.SHT3XD_ACCURACY_LOW,
|
||||
'MEDIUM': sensor.sensor_ns.SHT3XD_ACCURACY_MEDIUM,
|
||||
'HIGH': sensor.sensor_ns.SHT3XD_ACCURACY_HIGH,
|
||||
}
|
||||
|
||||
MakeSHT3XDSensor = Application.MakeSHT3XDSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeSHT3XDSensor),
|
||||
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
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.update_interval,
|
||||
|
||||
vol.Optional(CONF_ACCURACY): cv.invalid("The accuracy option has been removed and now "
|
||||
"defaults to HIGH."),
|
||||
})
|
||||
|
||||
|
||||
@@ -33,9 +29,6 @@ def to_code(config):
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
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,
|
||||
config[CONF_TEMPERATURE])
|
||||
sensor.setup_sensor(sht3xd.Psht3xd.Pget_humidity_sensor(), sht3xd.Pmqtt_humidity,
|
||||
|
||||
80
esphomeyaml/components/sensor/tcs34725.py
Normal file
80
esphomeyaml/components/sensor/tcs34725.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# coding=utf-8
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_COLOR_TEMPERATURE, CONF_GAIN, CONF_ID, \
|
||||
CONF_ILLUMINANCE, CONF_INTEGRATION_TIME, CONF_NAME, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, Pvariable, add
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
CONF_RED_CHANNEL = 'red_channel'
|
||||
CONF_GREEN_CHANNEL = 'green_channel'
|
||||
CONF_BLUE_CHANNEL = 'blue_channel'
|
||||
CONF_CLEAR_CHANNEL = 'clear_channel'
|
||||
|
||||
TCS34725Component = sensor.sensor_ns.TCS34725Component
|
||||
|
||||
TCS34725_INTEGRATION_TIMES = {
|
||||
'2.4ms': sensor.sensor_ns.TCS34725_INTEGRATION_TIME_2_4MS,
|
||||
'24ms': sensor.sensor_ns.TCS34725_INTEGRATION_TIME_24MS,
|
||||
'50ms': sensor.sensor_ns.TCS34725_INTEGRATION_TIME_50MS,
|
||||
'101ms': sensor.sensor_ns.TCS34725_INTEGRATION_TIME_101MS,
|
||||
'154ms': sensor.sensor_ns.TCS34725_INTEGRATION_TIME_154MS,
|
||||
'700ms': sensor.sensor_ns.TCS34725_INTEGRATION_TIME_700MS,
|
||||
}
|
||||
|
||||
TCS34725_GAINS = {
|
||||
'1X': sensor.sensor_ns.TCS34725_GAIN_1X,
|
||||
'4X': sensor.sensor_ns.TCS34725_GAIN_4X,
|
||||
'16X': sensor.sensor_ns.TCS34725_GAIN_16X,
|
||||
'60X': sensor.sensor_ns.TCS34725_GAIN_60X,
|
||||
}
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(TCS34725Component),
|
||||
vol.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
vol.Optional(CONF_RED_CHANNEL): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_GREEN_CHANNEL): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_BLUE_CHANNEL): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_CLEAR_CHANNEL): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_ILLUMINANCE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_COLOR_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_INTEGRATION_TIME): cv.one_of(*TCS34725_INTEGRATION_TIMES),
|
||||
vol.Optional(CONF_GAIN): vol.All(vol.Upper, cv.one_of(*TCS34725_GAINS)),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}), cv.has_at_least_one_key(CONF_RED_CHANNEL, CONF_GREEN_CHANNEL, CONF_BLUE_CHANNEL,
|
||||
CONF_CLEAR_CHANNEL, CONF_ILLUMINANCE, CONF_COLOR_TEMPERATURE))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_tcs34725(config.get(CONF_UPDATE_INTERVAL))
|
||||
tcs = Pvariable(config[CONF_ID], rhs)
|
||||
if CONF_ADDRESS in config:
|
||||
add(tcs.set_address(config[CONF_ADDRESS]))
|
||||
if CONF_INTEGRATION_TIME in config:
|
||||
add(tcs.set_integration_time(TCS34725_INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]]))
|
||||
if CONF_GAIN in config:
|
||||
add(tcs.set_gain(TCS34725_GAINS[config[CONF_GAIN]]))
|
||||
if CONF_RED_CHANNEL in config:
|
||||
conf = config[CONF_RED_CHANNEL]
|
||||
sensor.register_sensor(tcs.Pmake_red_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_GREEN_CHANNEL in config:
|
||||
conf = config[CONF_GREEN_CHANNEL]
|
||||
sensor.register_sensor(tcs.Pmake_green_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_BLUE_CHANNEL in config:
|
||||
conf = config[CONF_BLUE_CHANNEL]
|
||||
sensor.register_sensor(tcs.Pmake_blue_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_CLEAR_CHANNEL in config:
|
||||
conf = config[CONF_CLEAR_CHANNEL]
|
||||
sensor.register_sensor(tcs.Pmake_clear_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_ILLUMINANCE in config:
|
||||
conf = config[CONF_ILLUMINANCE]
|
||||
sensor.register_sensor(tcs.Pmake_illuminance_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_COLOR_TEMPERATURE in config:
|
||||
conf = config[CONF_COLOR_TEMPERATURE]
|
||||
sensor.register_sensor(tcs.Pmake_color_temperature_sensor(conf[CONF_NAME]), conf)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_TCS34725'
|
||||
@@ -3,26 +3,27 @@ import voluptuous as vol
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_UPDATE_INTERVAL
|
||||
from esphomeyaml.helpers import App, process_lambda, variable, Application, float_, optional
|
||||
from esphomeyaml.helpers import App, process_lambda, variable, Application, float_, optional, add
|
||||
|
||||
MakeTemplateSensor = Application.MakeTemplateSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_template_sensor(config[CONF_NAME], config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
sensor.setup_sensor(make.Ptemplate_, make.Pmqtt, config)
|
||||
|
||||
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_,
|
||||
config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
sensor.setup_sensor(make.Ptemplate_, make.Pmqtt, config)
|
||||
add(make.Ptemplate_.set_template(template_))
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_TEMPLATE_SENSOR'
|
||||
|
||||
@@ -30,14 +30,14 @@ def validate_integration_time(value):
|
||||
|
||||
MakeTSL2561Sensor = Application.MakeTSL2561Sensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
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_INTEGRATION_TIME): validate_integration_time,
|
||||
vol.Optional(CONF_GAIN): vol.All(vol.Upper, cv.one_of(*GAINS)),
|
||||
vol.Optional(CONF_IS_CS_PACKAGE): cv.boolean,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -10,14 +10,14 @@ from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression
|
||||
|
||||
MakeUltrasonicSensor = Application.MakeUltrasonicSensor
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
|
||||
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_TIME, 'timeout'): cv.positive_time_period_microseconds,
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
}).extend(sensor.SENSOR_SCHEMA.schema)
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
22
esphomeyaml/components/sensor/uptime.py
Normal file
22
esphomeyaml/components/sensor/uptime.py
Normal 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
|
||||
|
||||
MakeUptimeSensor = Application.MakeUptimeSensor
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeUptimeSensor),
|
||||
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_uptime_sensor(config[CONF_NAME], config.get(CONF_UPDATE_INTERVAL))
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
sensor.setup_sensor(make.Puptime, make.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_UPTIME_SENSOR'
|
||||
22
esphomeyaml/components/sensor/wifi_signal.py
Normal file
22
esphomeyaml/components/sensor/wifi_signal.py
Normal 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.update_interval,
|
||||
}))
|
||||
|
||||
|
||||
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'
|
||||
47
esphomeyaml/components/sensor/xiaomi_miflora.py
Normal file
47
esphomeyaml/components/sensor/xiaomi_miflora.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESP32BLETracker, \
|
||||
make_address_array
|
||||
from esphomeyaml.const import CONF_BATTERY_LEVEL, CONF_CONDUCTIVITY, CONF_ILLUMINANCE, \
|
||||
CONF_MAC_ADDRESS, CONF_MAKE_ID, CONF_MOISTURE, CONF_NAME, CONF_TEMPERATURE
|
||||
from esphomeyaml.helpers import Pvariable, esphomelib_ns, get_variable
|
||||
|
||||
DEPENDENCIES = ['esp32_ble_tracker']
|
||||
|
||||
XiaomiMiFloraDevice = esphomelib_ns.XiaomiMiFloraDevice
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(XiaomiMiFloraDevice),
|
||||
cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_variable_id(ESP32BLETracker),
|
||||
vol.Required(CONF_MAC_ADDRESS): cv.mac_address,
|
||||
vol.Optional(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_MOISTURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_ILLUMINANCE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_CONDUCTIVITY): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_BATTERY_LEVEL): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = None
|
||||
for hub in get_variable(config[CONF_ESP32_BLE_ID]):
|
||||
yield
|
||||
rhs = hub.make_miflora_sensor(make_address_array(config[CONF_MAC_ADDRESS]))
|
||||
dev = Pvariable(config[CONF_MAKE_ID], rhs)
|
||||
if CONF_TEMPERATURE in config:
|
||||
conf = config[CONF_TEMPERATURE]
|
||||
sensor.register_sensor(dev.Pmake_temperature_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_MOISTURE in config:
|
||||
conf = config[CONF_MOISTURE]
|
||||
sensor.register_sensor(dev.Pmake_moisture_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_ILLUMINANCE in config:
|
||||
conf = config[CONF_ILLUMINANCE]
|
||||
sensor.register_sensor(dev.Pmake_illuminance_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_CONDUCTIVITY in config:
|
||||
conf = config[CONF_CONDUCTIVITY]
|
||||
sensor.register_sensor(dev.Pmake_conductivity_sensor(conf[CONF_NAME]), conf)
|
||||
if CONF_BATTERY_LEVEL in config:
|
||||
conf = config[CONF_BATTERY_LEVEL]
|
||||
sensor.register_sensor(dev.Pmake_battery_level_sensor(conf[CONF_NAME]), conf)
|
||||
37
esphomeyaml/components/sensor/xiaomi_mijia.py
Normal file
37
esphomeyaml/components/sensor/xiaomi_mijia.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import sensor
|
||||
from esphomeyaml.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESP32BLETracker, \
|
||||
make_address_array
|
||||
from esphomeyaml.const import CONF_BATTERY_LEVEL, CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_MAKE_ID, \
|
||||
CONF_NAME, CONF_TEMPERATURE
|
||||
from esphomeyaml.helpers import Pvariable, esphomelib_ns, get_variable
|
||||
|
||||
DEPENDENCIES = ['esp32_ble_tracker']
|
||||
|
||||
XiaomiMiJiaDevice = esphomelib_ns.XiaomiMiJiaDevice
|
||||
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(XiaomiMiJiaDevice),
|
||||
cv.GenerateID(CONF_ESP32_BLE_ID): cv.use_variable_id(ESP32BLETracker),
|
||||
vol.Required(CONF_MAC_ADDRESS): cv.mac_address,
|
||||
vol.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
vol.Optional(CONF_BATTERY_LEVEL): cv.nameable(sensor.SENSOR_SCHEMA),
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = None
|
||||
for hub in get_variable(config[CONF_ESP32_BLE_ID]):
|
||||
yield
|
||||
rhs = hub.make_mijia_sensor(config[CONF_TEMPERATURE][CONF_NAME],
|
||||
config[CONF_HUMIDITY][CONF_NAME],
|
||||
make_address_array(config[CONF_MAC_ADDRESS]))
|
||||
dev = Pvariable(config[CONF_MAKE_ID], rhs)
|
||||
sensor.register_sensor(dev.Pget_temperature_sensor(), config[CONF_TEMPERATURE])
|
||||
sensor.register_sensor(dev.Pget_humidity_sensor(), config[CONF_HUMIDITY])
|
||||
if CONF_BATTERY_LEVEL in config:
|
||||
conf = config[CONF_BATTERY_LEVEL]
|
||||
sensor.register_sensor(dev.Pmake_battery_level_sensor(conf[CONF_NAME]), conf)
|
||||
38
esphomeyaml/components/spi.py
Normal file
38
esphomeyaml/components/spi.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.const import CONF_CLK_PIN, CONF_ID, CONF_MISO_PIN, CONF_MOSI_PIN
|
||||
from esphomeyaml.helpers import App, Pvariable, esphomelib_ns, gpio_input_pin_expression, \
|
||||
gpio_output_pin_expression, add
|
||||
|
||||
SPIComponent = esphomelib_ns.SPIComponent
|
||||
|
||||
SPI_SCHEMA = vol.All(vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(SPIComponent),
|
||||
vol.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
|
||||
vol.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema,
|
||||
vol.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema,
|
||||
}), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN))
|
||||
|
||||
CONFIG_SCHEMA = vol.All(cv.ensure_list, [SPI_SCHEMA])
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for conf in config:
|
||||
clk = None
|
||||
for clk in gpio_output_pin_expression(conf[CONF_CLK_PIN]):
|
||||
yield
|
||||
rhs = App.init_spi(clk)
|
||||
spi = Pvariable(conf[CONF_ID], rhs)
|
||||
if CONF_MISO_PIN in conf:
|
||||
for miso in gpio_input_pin_expression(conf[CONF_MISO_PIN]):
|
||||
yield
|
||||
add(spi.set_miso(miso))
|
||||
if CONF_MOSI_PIN in conf:
|
||||
for mosi in gpio_input_pin_expression(conf[CONF_MOSI_PIN]):
|
||||
yield
|
||||
add(spi.set_mosi(mosi))
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_SPI'
|
||||
23
esphomeyaml/components/status_led.py
Normal file
23
esphomeyaml/components/status_led.py
Normal 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
|
||||
|
||||
StatusLEDComponent = esphomelib_ns.StatusLEDComponent
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(StatusLEDComponent),
|
||||
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'
|
||||
@@ -1,7 +1,7 @@
|
||||
import voluptuous as vol
|
||||
|
||||
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
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
@@ -22,8 +22,12 @@ SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
|
||||
vol.Optional(CONF_INVERTED): cv.boolean,
|
||||
})
|
||||
|
||||
SWITCH_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(SWITCH_SCHEMA.schema)
|
||||
|
||||
|
||||
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:
|
||||
add(switch_var.set_icon(config[CONF_ICON]))
|
||||
if CONF_INVERTED in config:
|
||||
|
||||
@@ -8,10 +8,10 @@ from esphomeyaml.helpers import App, Application, gpio_output_pin_expression, va
|
||||
|
||||
MakeGPIOSwitch = Application.MakeGPIOSwitch
|
||||
|
||||
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
|
||||
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,
|
||||
}).extend(switch.SWITCH_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -1,104 +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({
|
||||
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),
|
||||
})),
|
||||
cv.GenerateID(CONF_IR_TRANSMITTER_ID): cv.use_variable_id(IRTransmitterComponent),
|
||||
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 = None
|
||||
for ir in get_variable(config[CONF_IR_TRANSMITTER_ID]):
|
||||
yield
|
||||
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'
|
||||
@@ -7,10 +7,10 @@ from esphomeyaml.helpers import App, Application, get_variable, variable
|
||||
|
||||
MakeSimpleSwitch = Application.MakeSimpleSwitch
|
||||
|
||||
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
|
||||
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),
|
||||
}).extend(switch.SWITCH_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
142
esphomeyaml/components/switch/remote_transmitter.py
Normal file
142
esphomeyaml/components/switch/remote_transmitter.py
Normal file
@@ -0,0 +1,142 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import switch
|
||||
from esphomeyaml.components.remote_transmitter import RC_SWITCH_RAW_SCHEMA, \
|
||||
RC_SWITCH_TYPE_A_SCHEMA, RC_SWITCH_TYPE_B_SCHEMA, RC_SWITCH_TYPE_C_SCHEMA, \
|
||||
RC_SWITCH_TYPE_D_SCHEMA, RemoteTransmitterComponent, binary_code, build_rc_switch_protocol, \
|
||||
remote_ns
|
||||
from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_CHANNEL, CONF_CODE, \
|
||||
CONF_COMMAND, CONF_DATA, CONF_DEVICE, CONF_FAMILY, CONF_GROUP, CONF_INVERTED, CONF_LG, \
|
||||
CONF_NAME, CONF_NBITS, CONF_NEC, CONF_PANASONIC, CONF_PROTOCOL, CONF_RAW, CONF_RC_SWITCH_RAW, \
|
||||
CONF_RC_SWITCH_TYPE_A, CONF_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C, CONF_RC_SWITCH_TYPE_D, \
|
||||
CONF_REPEAT, CONF_SONY, CONF_STATE, CONF_TIMES, \
|
||||
CONF_WAIT_TIME
|
||||
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, add, get_variable
|
||||
|
||||
DEPENDENCIES = ['remote_transmitter']
|
||||
|
||||
REMOTE_KEYS = [CONF_NEC, CONF_LG, CONF_SONY, CONF_PANASONIC, CONF_RAW, CONF_RC_SWITCH_RAW,
|
||||
CONF_RC_SWITCH_TYPE_A, CONF_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C,
|
||||
CONF_RC_SWITCH_TYPE_D]
|
||||
|
||||
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
|
||||
RCSwitchRawTransmitter = remote_ns.RCSwitchRawTransmitter
|
||||
RCSwitchTypeATransmitter = remote_ns.RCSwitchTypeATransmitter
|
||||
RCSwitchTypeBTransmitter = remote_ns.RCSwitchTypeBTransmitter
|
||||
RCSwitchTypeCTransmitter = remote_ns.RCSwitchTypeCTransmitter
|
||||
RCSwitchTypeDTransmitter = remote_ns.RCSwitchTypeDTransmitter
|
||||
|
||||
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_RC_SWITCH_RAW): RC_SWITCH_RAW_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_A): RC_SWITCH_TYPE_A_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_B): RC_SWITCH_TYPE_B_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_C): RC_SWITCH_TYPE_C_SCHEMA,
|
||||
vol.Optional(CONF_RC_SWITCH_TYPE_D): RC_SWITCH_TYPE_D_SCHEMA,
|
||||
|
||||
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(*REMOTE_KEYS))
|
||||
|
||||
|
||||
def transmitter_base(full_config):
|
||||
name = full_config[CONF_NAME]
|
||||
key, config = next((k, v) for k, v in full_config.items() if k in REMOTE_KEYS)
|
||||
|
||||
if key == CONF_LG:
|
||||
return LGTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS])
|
||||
elif key == CONF_NEC:
|
||||
return NECTransmitter.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
|
||||
elif key == CONF_PANASONIC:
|
||||
return PanasonicTransmitter.new(name, config[CONF_ADDRESS], config[CONF_COMMAND])
|
||||
elif key == CONF_SONY:
|
||||
return SonyTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS])
|
||||
elif key == CONF_RAW:
|
||||
if isinstance(config, dict):
|
||||
data = config[CONF_DATA]
|
||||
carrier_frequency = config.get(CONF_CARRIER_FREQUENCY)
|
||||
else:
|
||||
data = config
|
||||
carrier_frequency = None
|
||||
return RawTransmitter.new(name, ArrayInitializer(*data, multiline=False),
|
||||
carrier_frequency)
|
||||
elif key == CONF_RC_SWITCH_RAW:
|
||||
return RCSwitchRawTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
binary_code(config[CONF_CODE]), len(config[CONF_CODE]))
|
||||
elif key == CONF_RC_SWITCH_TYPE_A:
|
||||
return RCSwitchTypeATransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
binary_code(config[CONF_GROUP]),
|
||||
binary_code(config[CONF_DEVICE]),
|
||||
config[CONF_STATE])
|
||||
elif key == CONF_RC_SWITCH_TYPE_B:
|
||||
return RCSwitchTypeBTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
config[CONF_ADDRESS], config[CONF_CHANNEL],
|
||||
config[CONF_STATE])
|
||||
elif key == CONF_RC_SWITCH_TYPE_C:
|
||||
return RCSwitchTypeCTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
ord(config[CONF_FAMILY][0]) - ord('a'),
|
||||
config[CONF_GROUP], config[CONF_DEVICE],
|
||||
config[CONF_STATE])
|
||||
elif key == CONF_RC_SWITCH_TYPE_D:
|
||||
return RCSwitchTypeDTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
|
||||
ord(config[CONF_GROUP][0]) - ord('a'),
|
||||
config[CONF_DEVICE], config[CONF_STATE])
|
||||
else:
|
||||
raise NotImplementedError("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'
|
||||
@@ -7,10 +7,10 @@ from esphomeyaml.helpers import App, Application, variable
|
||||
|
||||
MakeRestartSwitch = Application.MakeRestartSwitch
|
||||
|
||||
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
|
||||
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!"),
|
||||
}).extend(switch.SWITCH_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -7,10 +7,10 @@ from esphomeyaml.helpers import App, Application, variable
|
||||
|
||||
MakeShutdownSwitch = Application.MakeShutdownSwitch
|
||||
|
||||
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
|
||||
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!"),
|
||||
}).extend(switch.SWITCH_SCHEMA.schema)
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
|
||||
@@ -10,19 +10,21 @@ from esphomeyaml.helpers import App, Application, process_lambda, variable, NoAr
|
||||
|
||||
MakeTemplateSwitch = Application.MakeTemplateSwitch
|
||||
|
||||
PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
|
||||
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.ACTIONS_SCHEMA,
|
||||
vol.Optional(CONF_TURN_ON_ACTION): automation.ACTIONS_SCHEMA,
|
||||
}).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_least_one_key(CONF_LAMBDA, CONF_OPTIMISTIC))
|
||||
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):
|
||||
rhs = App.make_template_switch(config[CONF_NAME])
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
|
||||
switch.setup_switch(make.Ptemplate_, make.Pmqtt, config)
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = None
|
||||
for template_ in process_lambda(config[CONF_LAMBDA], [],
|
||||
@@ -30,19 +32,13 @@ def to_code(config):
|
||||
yield
|
||||
add(make.Ptemplate_.set_state_lambda(template_))
|
||||
if CONF_TURN_OFF_ACTION in config:
|
||||
actions = None
|
||||
for actions in automation.build_actions(config[CONF_TURN_OFF_ACTION], NoArg):
|
||||
yield
|
||||
add(make.Ptemplate_.add_turn_off_actions(actions))
|
||||
automation.build_automation(make.Ptemplate_.get_turn_off_trigger(), NoArg,
|
||||
config[CONF_TURN_OFF_ACTION])
|
||||
if CONF_TURN_ON_ACTION in config:
|
||||
actions = None
|
||||
for actions in automation.build_actions(config[CONF_TURN_ON_ACTION], NoArg):
|
||||
yield
|
||||
add(make.Ptemplate_.add_turn_on_actions(actions))
|
||||
automation.build_automation(make.Ptemplate_.get_turn_on_trigger(), NoArg,
|
||||
config[CONF_TURN_ON_ACTION])
|
||||
if CONF_OPTIMISTIC in config:
|
||||
add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||
|
||||
switch.setup_switch(make.Ptemplate_, make.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_TEMPLATE_SWITCH'
|
||||
|
||||
45
esphomeyaml/components/switch/uart.py
Normal file
45
esphomeyaml/components/switch/uart.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import switch
|
||||
from esphomeyaml.components.uart import UARTComponent
|
||||
from esphomeyaml.const import CONF_DATA, CONF_INVERTED, CONF_MAKE_ID, CONF_NAME, CONF_UART_ID
|
||||
from esphomeyaml.core import HexInt
|
||||
from esphomeyaml.helpers import App, Application, ArrayInitializer, get_variable, variable
|
||||
|
||||
DEPENDENCIES = ['uart']
|
||||
|
||||
MakeUARTSwitch = Application.MakeUARTSwitch
|
||||
|
||||
|
||||
def validate_data(value):
|
||||
if isinstance(value, unicode):
|
||||
return value.encode('utf-8')
|
||||
elif isinstance(value, str):
|
||||
return value
|
||||
elif isinstance(value, list):
|
||||
return vol.Schema([cv.hex_uint8_t])(value)
|
||||
raise vol.Invalid("data must either be a string wrapped in quotes or a list of bytes")
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeUARTSwitch),
|
||||
cv.GenerateID(CONF_UART_ID): cv.use_variable_id(UARTComponent),
|
||||
vol.Required(CONF_DATA): validate_data,
|
||||
vol.Optional(CONF_INVERTED): cv.invalid("UART switches do not support inverted mode!"),
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
uart = None
|
||||
for uart in get_variable(config[CONF_UART_ID]):
|
||||
yield
|
||||
data = config[CONF_DATA]
|
||||
if isinstance(data, str):
|
||||
data = [HexInt(ord(x)) for x in data]
|
||||
rhs = App.make_uart_switch(uart, config[CONF_NAME], ArrayInitializer(*data, multiline=False))
|
||||
restart = variable(config[CONF_MAKE_ID], rhs)
|
||||
switch.setup_switch(restart.Puart, restart.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_UART_SWITCH'
|
||||
276
esphomeyaml/components/time/__init__.py
Normal file
276
esphomeyaml/components/time/__init__.py
Normal file
@@ -0,0 +1,276 @@
|
||||
import datetime
|
||||
import logging
|
||||
import math
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import automation
|
||||
from esphomeyaml.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \
|
||||
CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID
|
||||
from esphomeyaml.helpers import App, NoArg, Pvariable, add, add_job, esphomelib_ns
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
|
||||
|
||||
})
|
||||
|
||||
time_ns = esphomelib_ns.namespace('time')
|
||||
CronTrigger = time_ns.CronTrigger
|
||||
|
||||
|
||||
def _tz_timedelta(td):
|
||||
offset_hour = int(td.total_seconds() / (60 * 60))
|
||||
offset_minute = int(abs(td.total_seconds() / 60)) % 60
|
||||
offset_second = int(abs(td.total_seconds())) % 60
|
||||
if offset_hour == 0 and offset_minute == 0 and offset_second == 0:
|
||||
return '0'
|
||||
elif offset_minute == 0 and offset_second == 0:
|
||||
return '{}'.format(offset_hour)
|
||||
elif offset_second == 0:
|
||||
return '{}:{}'.format(offset_hour, offset_minute)
|
||||
return '{}:{}:{}'.format(offset_hour, offset_minute, offset_second)
|
||||
|
||||
|
||||
# https://stackoverflow.com/a/16804556/8924614
|
||||
def _week_of_month(dt):
|
||||
first_day = dt.replace(day=1)
|
||||
dom = dt.day
|
||||
adjusted_dom = dom + first_day.weekday()
|
||||
return int(math.ceil(adjusted_dom / 7.0))
|
||||
|
||||
|
||||
def _tz_dst_str(dt):
|
||||
td = datetime.timedelta(hours=dt.hour, minutes=dt.minute, seconds=dt.second)
|
||||
return 'M{}.{}.{}/{}'.format(dt.month, _week_of_month(dt), dt.isoweekday() % 7,
|
||||
_tz_timedelta(td))
|
||||
|
||||
|
||||
def detect_tz():
|
||||
try:
|
||||
import tzlocal
|
||||
import pytz
|
||||
except ImportError:
|
||||
raise vol.Invalid("No timezone specified and 'tzlocal' not installed. To automatically "
|
||||
"detect the timezone please install tzlocal (pip2 install tzlocal)")
|
||||
try:
|
||||
tz = tzlocal.get_localzone()
|
||||
except pytz.exceptions.UnknownTimeZoneError:
|
||||
_LOGGER.warning("Could not auto-detect timezone. Using UTC...")
|
||||
return 'UTC'
|
||||
|
||||
def _dst(dt, is_dst):
|
||||
try:
|
||||
return tz.dst(dt, is_dst=is_dst)
|
||||
except TypeError: # stupid pytz...
|
||||
return tz.dst(dt)
|
||||
|
||||
def _tzname(dt, is_dst):
|
||||
try:
|
||||
return tz.tzname(dt, is_dst=is_dst)
|
||||
except TypeError: # stupid pytz...
|
||||
return tz.tzname(dt)
|
||||
|
||||
def _utcoffset(dt, is_dst):
|
||||
try:
|
||||
return tz.utcoffset(dt, is_dst=is_dst)
|
||||
except TypeError: # stupid pytz...
|
||||
return tz.utcoffset(dt)
|
||||
|
||||
dst_begins = None
|
||||
dst_tzname = None
|
||||
dst_utcoffset = None
|
||||
dst_ends = None
|
||||
norm_tzname = None
|
||||
norm_utcoffset = None
|
||||
|
||||
hour = datetime.timedelta(hours=1)
|
||||
this_year = datetime.datetime.now().year
|
||||
dt = datetime.datetime(year=this_year, month=1, day=1)
|
||||
last_dst = None
|
||||
while dt.year == this_year:
|
||||
current_dst = _dst(dt, not last_dst)
|
||||
is_dst = bool(current_dst)
|
||||
if is_dst != last_dst:
|
||||
if is_dst:
|
||||
dst_begins = dt
|
||||
dst_tzname = _tzname(dt, True)
|
||||
dst_utcoffset = _utcoffset(dt, True)
|
||||
else:
|
||||
dst_ends = dt + hour
|
||||
norm_tzname = _tzname(dt, False)
|
||||
norm_utcoffset = _utcoffset(dt, False)
|
||||
last_dst = is_dst
|
||||
dt += hour
|
||||
|
||||
tzbase = '{}{}'.format(norm_tzname, _tz_timedelta(-1 * norm_utcoffset))
|
||||
if dst_begins is None:
|
||||
# No DST in this timezone
|
||||
_LOGGER.info("Auto-detected timezone '%s' with UTC offset %s",
|
||||
norm_tzname, _tz_timedelta(norm_utcoffset))
|
||||
return tzbase
|
||||
tzext = '{}{},{},{}'.format(dst_tzname, _tz_timedelta(-1 * dst_utcoffset),
|
||||
_tz_dst_str(dst_begins), _tz_dst_str(dst_ends))
|
||||
_LOGGER.info("Auto-detected timezone '%s' with UTC offset %s and daylight savings time from "
|
||||
"%s to %s",
|
||||
norm_tzname, _tz_timedelta(norm_utcoffset), dst_begins.strftime("%x %X"),
|
||||
dst_ends.strftime("%x %X"))
|
||||
return tzbase + tzext
|
||||
|
||||
|
||||
def _parse_cron_int(value, special_mapping, message):
|
||||
special_mapping = special_mapping or {}
|
||||
if isinstance(value, (str, unicode)) and value in special_mapping:
|
||||
return special_mapping[value]
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
raise vol.Invalid(message.format(value))
|
||||
|
||||
|
||||
def _parse_cron_part(part, min_value, max_value, special_mapping):
|
||||
if part == '*' or part == '?':
|
||||
return set(x for x in range(min_value, max_value + 1))
|
||||
if '/' in part:
|
||||
data = part.split('/')
|
||||
if len(data) > 2:
|
||||
raise vol.Invalid(u"Can't have more than two '/' in one time expression, got {}"
|
||||
.format(part))
|
||||
offset, repeat = data
|
||||
offset_n = 0
|
||||
if offset:
|
||||
offset_n = _parse_cron_int(offset, special_mapping,
|
||||
u"Offset for '/' time expression must be an integer, got {}")
|
||||
|
||||
try:
|
||||
repeat_n = int(repeat)
|
||||
except ValueError:
|
||||
raise vol.Invalid(u"Repeat for '/' time expression must be an integer, got {}"
|
||||
.format(repeat))
|
||||
return set(x for x in range(offset_n, max_value + 1, repeat_n))
|
||||
if '-' in part:
|
||||
data = part.split('-')
|
||||
if len(data) > 2:
|
||||
raise vol.Invalid(u"Can't have more than two '-' in range time expression '{}'"
|
||||
.format(part))
|
||||
begin, end = data
|
||||
begin_n = _parse_cron_int(begin, special_mapping, u"Number for time range must be integer, "
|
||||
u"got {}")
|
||||
end_n = _parse_cron_int(end, special_mapping, u"Number for time range must be integer, "
|
||||
u"got {}")
|
||||
if end_n < begin_n:
|
||||
return set(x for x in range(end_n, max_value + 1)) | \
|
||||
set(x for x in range(min_value, begin_n + 1))
|
||||
return set(x for x in range(begin_n, end_n + 1))
|
||||
|
||||
return {_parse_cron_int(part, special_mapping, u"Number for time expression must be an "
|
||||
u"integer, got {}")}
|
||||
|
||||
|
||||
def cron_expression_validator(name, min_value, max_value, special_mapping=None):
|
||||
def validator(value):
|
||||
if isinstance(value, list):
|
||||
for v in value:
|
||||
if not isinstance(v, int):
|
||||
raise vol.Invalid(
|
||||
"Expected integer for {} '{}', got {}".format(v, name, type(v)))
|
||||
if v < min_value or v > max_value:
|
||||
raise vol.Invalid(
|
||||
"{} {} is out of range (min={} max={}).".format(name, v, min_value,
|
||||
max_value))
|
||||
return list(sorted(value))
|
||||
value = cv.string(value)
|
||||
values = set()
|
||||
for part in value.split(','):
|
||||
values |= _parse_cron_part(part, min_value, max_value, special_mapping)
|
||||
return validator(list(values))
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
validate_cron_seconds = cron_expression_validator('seconds', 0, 60)
|
||||
validate_cron_minutes = cron_expression_validator('minutes', 0, 59)
|
||||
validate_cron_hours = cron_expression_validator('hours', 0, 23)
|
||||
validate_cron_days_of_month = cron_expression_validator('days of month', 1, 31)
|
||||
validate_cron_months = cron_expression_validator('months', 1, 12, {
|
||||
'JAN': 1, 'FEB': 2, 'MAR': 3, 'APR': 4, 'MAY': 5, 'JUN': 6, 'JUL': 7, 'AUG': 8,
|
||||
'SEP': 9, 'OCT': 10, 'NOV': 11, 'DEC': 12
|
||||
})
|
||||
validate_cron_days_of_week = cron_expression_validator('days of week', 1, 7, {
|
||||
'SUN': 1, 'MON': 2, 'TUE': 3, 'WED': 4, 'THU': 5, 'FRI': 6, 'SAT': 7
|
||||
})
|
||||
CRON_KEYS = [CONF_SECONDS, CONF_MINUTES, CONF_HOURS, CONF_DAYS_OF_MONTH, CONF_MONTHS,
|
||||
CONF_DAYS_OF_WEEK]
|
||||
|
||||
|
||||
def validate_cron_raw(value):
|
||||
value = cv.string(value)
|
||||
value = value.split(' ')
|
||||
if len(value) != 6:
|
||||
raise vol.Invalid("Cron expression must consist of exactly 6 space-separated parts, "
|
||||
"not {}".format(len(value)))
|
||||
seconds, minutes, hours, days_of_month, months, days_of_week = value
|
||||
return {
|
||||
CONF_SECONDS: validate_cron_seconds(seconds),
|
||||
CONF_MINUTES: validate_cron_minutes(minutes),
|
||||
CONF_HOURS: validate_cron_hours(hours),
|
||||
CONF_DAYS_OF_MONTH: validate_cron_days_of_month(days_of_month),
|
||||
CONF_MONTHS: validate_cron_months(months),
|
||||
CONF_DAYS_OF_WEEK: validate_cron_days_of_week(days_of_week),
|
||||
}
|
||||
|
||||
|
||||
def validate_cron_keys(value):
|
||||
if CONF_CRON in value:
|
||||
for key in value.keys():
|
||||
if key in CRON_KEYS:
|
||||
raise vol.Invalid("Cannot use option {} when cron: is specified.".format(key))
|
||||
cron_ = value[CONF_CRON]
|
||||
value = {x: value[x] for x in value if x != CONF_CRON}
|
||||
value.update(cron_)
|
||||
return value
|
||||
return cv.has_at_least_one_key(*CRON_KEYS)(value)
|
||||
|
||||
|
||||
TIME_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_TIMEZONE, default=detect_tz): cv.string,
|
||||
vol.Optional(CONF_ON_TIME): vol.All(cv.ensure_list, [vol.All(automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(CronTrigger),
|
||||
vol.Optional(CONF_SECONDS): validate_cron_seconds,
|
||||
vol.Optional(CONF_MINUTES): validate_cron_minutes,
|
||||
vol.Optional(CONF_HOURS): validate_cron_hours,
|
||||
vol.Optional(CONF_DAYS_OF_MONTH): validate_cron_days_of_month,
|
||||
vol.Optional(CONF_MONTHS): validate_cron_months,
|
||||
vol.Optional(CONF_DAYS_OF_WEEK): validate_cron_days_of_week,
|
||||
vol.Optional(CONF_CRON): validate_cron_raw,
|
||||
}), validate_cron_keys)]),
|
||||
})
|
||||
|
||||
|
||||
def setup_time_core_(time_var, config):
|
||||
add(time_var.set_timezone(config[CONF_TIMEZONE]))
|
||||
|
||||
for conf in config.get(CONF_ON_TIME, []):
|
||||
rhs = App.register_component(time_var.Pmake_cron_trigger())
|
||||
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
|
||||
for second in conf.get(CONF_SECONDS, [x for x in range(0, 61)]):
|
||||
add(trigger.add_second(second))
|
||||
for minute in conf.get(CONF_MINUTES, [x for x in range(0, 60)]):
|
||||
add(trigger.add_minute(minute))
|
||||
for hour in conf.get(CONF_HOURS, [x for x in range(0, 24)]):
|
||||
add(trigger.add_hour(hour))
|
||||
for day_of_month in conf.get(CONF_DAYS_OF_MONTH, [x for x in range(1, 32)]):
|
||||
add(trigger.add_day_of_month(day_of_month))
|
||||
for month in conf.get(CONF_MONTHS, [x for x in range(1, 13)]):
|
||||
add(trigger.add_month(month))
|
||||
for day_of_week in conf.get(CONF_DAYS_OF_WEEK, [x for x in range(1, 8)]):
|
||||
add(trigger.add_day_of_week(day_of_week))
|
||||
automation.build_automation(trigger, NoArg, conf)
|
||||
|
||||
|
||||
def setup_time(time_var, config):
|
||||
add_job(setup_time_core_, time_var, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_TIME'
|
||||
24
esphomeyaml/components/time/sntp.py
Normal file
24
esphomeyaml/components/time/sntp.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import time as time_
|
||||
from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_SERVERS
|
||||
from esphomeyaml.helpers import App, Pvariable
|
||||
|
||||
SNTPComponent = time_.time_ns.SNTPComponent
|
||||
|
||||
PLATFORM_SCHEMA = time_.TIME_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(SNTPComponent),
|
||||
vol.Optional(CONF_SERVERS): vol.All(cv.ensure_list, [cv.string], vol.Length(max=3)),
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_sntp_component(*config.get(CONF_SERVERS, []))
|
||||
sntp = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
time_.setup_time(sntp, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_SNTP_COMPONENT'
|
||||
28
esphomeyaml/components/uart.py
Normal file
28
esphomeyaml/components/uart.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import pins
|
||||
from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_RX_PIN, CONF_TX_PIN
|
||||
from esphomeyaml.helpers import App, Pvariable, esphomelib_ns
|
||||
|
||||
UARTComponent = esphomelib_ns.UARTComponent
|
||||
|
||||
SPI_SCHEMA = vol.All(vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(UARTComponent),
|
||||
vol.Optional(CONF_TX_PIN): pins.output_pin,
|
||||
vol.Optional(CONF_RX_PIN): pins.input_pin,
|
||||
vol.Required(CONF_BAUD_RATE): cv.positive_int,
|
||||
}), cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN))
|
||||
|
||||
CONFIG_SCHEMA = vol.All(cv.ensure_list, [SPI_SCHEMA])
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for conf in config:
|
||||
tx = conf.get(CONF_TX_PIN, -1)
|
||||
rx = conf.get(CONF_RX_PIN, -1)
|
||||
rhs = App.init_uart(tx, rx, conf[CONF_BAUD_RATE])
|
||||
Pvariable(conf[CONF_ID], rhs)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_UART'
|
||||
@@ -1,10 +1,10 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import core
|
||||
import esphomeyaml.config_validation as cv
|
||||
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_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266
|
||||
CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_POWER_SAVE_MODE,\
|
||||
CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, esphomelib_ns, global_ns
|
||||
|
||||
|
||||
@@ -19,6 +19,15 @@ def validate_password(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({
|
||||
vol.Required(CONF_STATIC_IP): cv.ipv4,
|
||||
vol.Required(CONF_GATEWAY): cv.ipv4,
|
||||
@@ -30,34 +39,65 @@ STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
|
||||
vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4,
|
||||
})
|
||||
|
||||
WIFI_NETWORK_BASE = vol.Schema({
|
||||
vol.Required(CONF_SSID): cv.ssid,
|
||||
vol.Optional(CONF_PASSWORD): validate_password,
|
||||
vol.Optional(CONF_CHANNEL): validate_channel,
|
||||
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
|
||||
})
|
||||
|
||||
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
|
||||
IPAddress = global_ns.IPAddress
|
||||
ManualIP = esphomelib_ns.ManualIP
|
||||
WiFiComponent = esphomelib_ns.WiFiComponent
|
||||
WiFiAp = esphomelib_ns.WiFiAp
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
WIFI_POWER_SAVE_MODES = {
|
||||
'NONE': esphomelib_ns.WIFI_POWER_SAVE_NONE,
|
||||
'LIGHT': esphomelib_ns.WIFI_POWER_SAVE_LIGHT,
|
||||
'HIGH': esphomelib_ns.WIFI_POWER_SAVE_HIGH,
|
||||
}
|
||||
|
||||
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): vol.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_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,
|
||||
vol.Optional(CONF_POWER_SAVE_MODE): vol.All(vol.Upper, cv.one_of(*WIFI_POWER_SAVE_MODES)),
|
||||
}), validate)
|
||||
|
||||
|
||||
def safe_ip(ip):
|
||||
if ip is None:
|
||||
return None
|
||||
return IPAddress(0, 0, 0, 0)
|
||||
return IPAddress(*ip.args)
|
||||
|
||||
|
||||
def manual_ip(config):
|
||||
if config is None:
|
||||
return None
|
||||
return StructInitializer(
|
||||
ManualIP,
|
||||
('static_ip', safe_ip(config[CONF_STATIC_IP])),
|
||||
@@ -68,31 +108,35 @@ 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):
|
||||
sta = CONF_SSID in config
|
||||
ap = CONF_AP in config
|
||||
if sta:
|
||||
rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD))
|
||||
else:
|
||||
rhs = App.init_wifi()
|
||||
rhs = App.init_wifi()
|
||||
wifi = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if sta and CONF_MANUAL_IP in config:
|
||||
add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP])))
|
||||
if CONF_SSID in config:
|
||||
add(wifi.set_sta(wifi_network(config)))
|
||||
|
||||
if ap:
|
||||
conf = 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_AP in config:
|
||||
add(wifi.set_ap(wifi_network(config[CONF_AP])))
|
||||
|
||||
if CONF_HOSTNAME in config:
|
||||
add(wifi.set_hostname(config[CONF_HOSTNAME]))
|
||||
|
||||
if CONF_REBOOT_TIMEOUT in config:
|
||||
add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
||||
|
||||
if CONF_POWER_SAVE_MODE in config:
|
||||
add(wifi.set_power_save_mode(WIFI_POWER_SAVE_MODES[CONF_POWER_SAVE_MODE]))
|
||||
|
||||
|
||||
def lib_deps(config):
|
||||
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "esphomeyaml",
|
||||
"version": "1.6.2",
|
||||
"version": "1.8.2",
|
||||
"slug": "esphomeyaml",
|
||||
"description": "esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices.",
|
||||
"url": "https://esphomelib.com/esphomeyaml/index.html",
|
||||
@@ -15,10 +15,14 @@
|
||||
"map": [
|
||||
"config:rw"
|
||||
],
|
||||
"options": {},
|
||||
"environment": {
|
||||
"ESPHOMEYAML_OTA_HOST_PORT": "6053"
|
||||
},
|
||||
"schema": {},
|
||||
"options": {
|
||||
"password": ""
|
||||
},
|
||||
"schema": {
|
||||
"password": "str?"
|
||||
},
|
||||
"image": "ottowinter/esphomeyaml-hassio-{arch}"
|
||||
}
|
||||
|
||||
@@ -7,43 +7,20 @@ from collections import OrderedDict
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import core, yaml_util
|
||||
from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
|
||||
CONF_LIBRARY_URI, \
|
||||
CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, ESP_PLATFORMS, \
|
||||
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml import core, yaml_util, core_config
|
||||
from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_PLATFORM, CONF_WIFI, ESP_PLATFORMS
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import App, add, color
|
||||
from esphomeyaml.helpers import color
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.6.2'
|
||||
|
||||
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
|
||||
|
||||
CORE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_NAME): cv.valid_name,
|
||||
vol.Required(CONF_PLATFORM): cv.string,
|
||||
vol.Required(CONF_BOARD): cv.string,
|
||||
vol.Optional(CONF_LIBRARY_URI, default=DEFAULT_LIBRARY_URI): cv.string,
|
||||
vol.Optional(CONF_SIMPLIFY, 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)),
|
||||
})
|
||||
|
||||
REQUIRED_COMPONENTS = [
|
||||
CONF_ESPHOMEYAML, CONF_WIFI
|
||||
]
|
||||
|
||||
_COMPONENT_CACHE = {}
|
||||
_ALL_COMPONENTS = []
|
||||
|
||||
|
||||
def core_to_code(config):
|
||||
add(App.set_name(config[CONF_NAME]))
|
||||
|
||||
|
||||
def get_component(domain):
|
||||
if domain in _COMPONENT_CACHE:
|
||||
return _COMPONENT_CACHE[domain]
|
||||
@@ -51,7 +28,7 @@ def get_component(domain):
|
||||
path = 'esphomeyaml.components.{}'.format(domain)
|
||||
try:
|
||||
module = importlib.import_module(path)
|
||||
except ImportError as err:
|
||||
except (ImportError, ValueError) as err:
|
||||
_LOGGER.debug(err)
|
||||
else:
|
||||
_COMPONENT_CACHE[domain] = module
|
||||
@@ -152,30 +129,33 @@ def validate_config(config):
|
||||
result.add_error(_format_config_error(ex, domain, config), domain, config)
|
||||
|
||||
try:
|
||||
result[CONF_ESPHOMEYAML] = CORE_SCHEMA(config[CONF_ESPHOMEYAML])
|
||||
result[CONF_ESPHOMEYAML] = core_config.CONFIG_SCHEMA(config[CONF_ESPHOMEYAML])
|
||||
except vol.Invalid as ex:
|
||||
_comp_error(ex, CONF_ESPHOMEYAML, config)
|
||||
_comp_error(ex, CONF_ESPHOMEYAML, config[CONF_ESPHOMEYAML])
|
||||
|
||||
for domain, conf in config.iteritems():
|
||||
if domain == CONF_ESPHOMEYAML:
|
||||
domain = str(domain)
|
||||
if domain == CONF_ESPHOMEYAML or domain.startswith('.'):
|
||||
continue
|
||||
if conf is None:
|
||||
conf = {}
|
||||
component = get_component(domain)
|
||||
if component is None:
|
||||
result.add_error(u"Component not found: {}".format(domain))
|
||||
result.add_error(u"Component not found: {}".format(domain), domain, conf)
|
||||
continue
|
||||
|
||||
esp_platforms = getattr(component, 'ESP_PLATFORMS', ESP_PLATFORMS)
|
||||
if core.ESP_PLATFORM not in esp_platforms:
|
||||
result.add_error(u"Component {} doesn't support {}.".format(domain, core.ESP_PLATFORM))
|
||||
result.add_error(u"Component {} doesn't support {}.".format(domain, core.ESP_PLATFORM),
|
||||
domain, conf)
|
||||
continue
|
||||
|
||||
success = True
|
||||
dependencies = getattr(component, 'DEPENDENCIES', [])
|
||||
for dependency in dependencies:
|
||||
if dependency not in _ALL_COMPONENTS:
|
||||
result.add_error(u"Component {} requires component {}".format(domain, dependency))
|
||||
result.add_error(u"Component {} requires component {}".format(domain, dependency),
|
||||
domain, conf)
|
||||
success = False
|
||||
if not success:
|
||||
continue
|
||||
@@ -194,23 +174,25 @@ def validate_config(config):
|
||||
platforms = []
|
||||
for p_config in conf:
|
||||
if not isinstance(p_config, dict):
|
||||
result.add_error(u"Platform schemas must have 'platform:' key")
|
||||
result.add_error(u"Platform schemas must have 'platform:' key", )
|
||||
continue
|
||||
p_name = p_config.get(u'platform')
|
||||
if p_name is None:
|
||||
result.add_error(u"No platform specified for {}".format(domain))
|
||||
continue
|
||||
p_domain = u'{}.{}'.format(domain, p_name)
|
||||
platform = get_platform(domain, p_name)
|
||||
if platform is None:
|
||||
result.add_error(u"Platform not found: {}.{}")
|
||||
result.add_error(u"Platform not found: '{}'".format(p_domain), p_domain, p_config)
|
||||
continue
|
||||
|
||||
success = True
|
||||
dependencies = getattr(platform, 'DEPENDENCIES', [])
|
||||
for dependency in dependencies:
|
||||
if dependency not in _ALL_COMPONENTS:
|
||||
result.add_error(u"Platform {}.{} requires component {}".format(domain, p_name,
|
||||
dependency))
|
||||
result.add_error(
|
||||
u"Platform {} requires component {}".format(p_domain, dependency),
|
||||
p_domain, p_config)
|
||||
success = False
|
||||
if not success:
|
||||
continue
|
||||
@@ -218,14 +200,15 @@ def validate_config(config):
|
||||
esp_platforms = getattr(platform, 'ESP_PLATFORMS', ESP_PLATFORMS)
|
||||
if core.ESP_PLATFORM not in esp_platforms:
|
||||
result.add_error(
|
||||
u"Platform {}.{} doesn't support {}.".format(domain, p_name, core.ESP_PLATFORM))
|
||||
u"Platform {} doesn't support {}.".format(p_domain, core.ESP_PLATFORM),
|
||||
p_domain, p_config)
|
||||
continue
|
||||
|
||||
if hasattr(platform, u'PLATFORM_SCHEMA'):
|
||||
try:
|
||||
p_validated = platform.PLATFORM_SCHEMA(p_config)
|
||||
except vol.Invalid as ex:
|
||||
_comp_error(ex, u'{}.{}'.format(domain, p_name), p_config)
|
||||
_comp_error(ex, p_domain, p_config)
|
||||
continue
|
||||
platforms.append(p_validated)
|
||||
result[domain] = platforms
|
||||
@@ -263,23 +246,7 @@ def load_config(path):
|
||||
except OSError:
|
||||
raise ESPHomeYAMLError(u"Could not read configuration file at {}".format(path))
|
||||
core.RAW_CONFIG = config
|
||||
|
||||
if CONF_ESPHOMEYAML not in config:
|
||||
raise ESPHomeYAMLError(u"No esphomeyaml section in config")
|
||||
core_conf = config[CONF_ESPHOMEYAML]
|
||||
if CONF_PLATFORM not in core_conf:
|
||||
raise ESPHomeYAMLError("esphomeyaml.platform not specified.")
|
||||
esp_platform = unicode(core_conf[CONF_PLATFORM])
|
||||
esp_platform = esp_platform.upper()
|
||||
if '8266' in esp_platform:
|
||||
esp_platform = ESP_PLATFORM_ESP8266
|
||||
if '32' in esp_platform:
|
||||
esp_platform = ESP_PLATFORM_ESP32
|
||||
core.ESP_PLATFORM = esp_platform
|
||||
if CONF_BOARD not in core_conf:
|
||||
raise ESPHomeYAMLError("esphomeyaml.board not specified.")
|
||||
core.BOARD = unicode(core_conf[CONF_BOARD])
|
||||
core.SIMPLIFY = cv.boolean(core_conf.get(CONF_SIMPLIFY, True))
|
||||
core_config.preload_core_config(config)
|
||||
|
||||
try:
|
||||
result = validate_config(config)
|
||||
@@ -347,4 +314,4 @@ def read_config(path):
|
||||
dump_dict(config, reset='red')
|
||||
print(color('reset'))
|
||||
return None
|
||||
return dict(**res)
|
||||
return OrderedDict(res)
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import uuid as uuid_
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml import core, helpers
|
||||
from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
|
||||
CONF_NAME, CONF_PAYLOAD_AVAILABLE, \
|
||||
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, Lambda, TimePeriod, TimePeriodMicroseconds, \
|
||||
TimePeriodMilliseconds, TimePeriodSeconds
|
||||
|
||||
@@ -101,13 +103,19 @@ def boolean(value):
|
||||
|
||||
def ensure_list(value):
|
||||
"""Wrap value in list if it is not one."""
|
||||
if value is None:
|
||||
if value is None or (isinstance(value, dict) and not value):
|
||||
return []
|
||||
if isinstance(value, list):
|
||||
return value
|
||||
return [value]
|
||||
|
||||
|
||||
def ensure_list_not_empty(value):
|
||||
if isinstance(value, list):
|
||||
return value
|
||||
return [value]
|
||||
|
||||
|
||||
def ensure_dict(value):
|
||||
if value is None:
|
||||
return {}
|
||||
@@ -178,6 +186,8 @@ def templatable(other_validators):
|
||||
def validator(value):
|
||||
if isinstance(value, Lambda):
|
||||
return value
|
||||
if isinstance(other_validators, dict):
|
||||
return vol.Schema(other_validators)(value)
|
||||
return other_validators(value)
|
||||
|
||||
return validator
|
||||
@@ -231,6 +241,19 @@ def has_exactly_one_key(*keys):
|
||||
return validate
|
||||
|
||||
|
||||
def has_at_most_one_key(*keys):
|
||||
def validate(obj):
|
||||
if not isinstance(obj, dict):
|
||||
raise vol.Invalid('expected dictionary')
|
||||
|
||||
number = sum(k in keys for k in obj)
|
||||
if number > 1:
|
||||
raise vol.Invalid("Cannot specify more than one of {}.".format(', '.join(keys)))
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
TIME_PERIOD_ERROR = "Time period {} should be format number + unit, for example 5ms, 5s, 5min, 5h"
|
||||
|
||||
time_period_dict = vol.All(
|
||||
@@ -246,13 +269,6 @@ time_period_dict = vol.All(
|
||||
'seconds', 'milliseconds', 'microseconds'),
|
||||
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):
|
||||
"""Validate and transform time offset with format HH:MM[:SS]."""
|
||||
@@ -284,13 +300,6 @@ def time_period_str_unit(value):
|
||||
elif not isinstance(value, (str, unicode)):
|
||||
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 = {
|
||||
'us': 'microseconds',
|
||||
'microseconds': 'microseconds',
|
||||
@@ -335,14 +344,43 @@ def time_period_in_seconds_(value):
|
||||
return TimePeriodSeconds(**value.as_dict())
|
||||
|
||||
|
||||
def update_interval(value):
|
||||
if value == 'never':
|
||||
return 4294967295 # uint32_t max
|
||||
return positive_time_period_milliseconds(value)
|
||||
|
||||
|
||||
time_period = vol.Any(time_period_str_unit, time_period_str_colon, time_period_dict)
|
||||
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_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_not_null_time_period = vol.All(time_period,
|
||||
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 = {
|
||||
'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,
|
||||
@@ -350,20 +388,46 @@ METRIC_SUFFIXES = {
|
||||
}
|
||||
|
||||
|
||||
def frequency(value):
|
||||
def float_with_unit(quantity, regex_suffix):
|
||||
pattern = re.compile(r"^([-+]?[0-9]*\.?[0-9]*)\s*(\w*?)" + regex_suffix + "$")
|
||||
|
||||
def validator(value):
|
||||
match = pattern.match(string(value))
|
||||
|
||||
if match is None:
|
||||
raise vol.Invalid(u"Expected {} with unit, got {}".format(quantity, value))
|
||||
|
||||
mantissa = float(match.group(1))
|
||||
if match.group(2) not in METRIC_SUFFIXES:
|
||||
raise vol.Invalid(u"Invalid {} suffix {}".format(quantity, match.group(2)))
|
||||
|
||||
multiplier = METRIC_SUFFIXES[match.group(2)]
|
||||
return mantissa * multiplier
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
frequency = float_with_unit("frequency", r"(Hz|HZ|hz)?")
|
||||
resistance = float_with_unit("resistance", r"(Ω|Ω|ohm|Ohm|OHM)?")
|
||||
current = float_with_unit("current", r"(a|A|amp|Amp|amps|Amps|ampere|Ampere)?")
|
||||
voltage = float_with_unit("voltage", r"(v|V|volt|Volts)?")
|
||||
|
||||
|
||||
def validate_bytes(value):
|
||||
value = string(value)
|
||||
match = re.match(r"^([-+]?[0-9]*\.?[0-9]*)\s*(\w*?)(?:Hz|HZ|hz)?$", value)
|
||||
match = re.match(r"^([0-9]+)\s*(\w*?)(?:byte|B|b)?s?$", value)
|
||||
|
||||
if match is None:
|
||||
raise vol.Invalid(u"Expected frequency with unit, "
|
||||
u"got {}".format(value))
|
||||
raise vol.Invalid(u"Expected number of bytes with unit, got {}".format(value))
|
||||
|
||||
mantissa = float(match.group(1))
|
||||
mantissa = int(match.group(1))
|
||||
if match.group(2) not in METRIC_SUFFIXES:
|
||||
raise vol.Invalid(u"Invalid frequency suffix {}".format(match.group(2)))
|
||||
|
||||
raise vol.Invalid(u"Invalid metric suffix {}".format(match.group(2)))
|
||||
multiplier = METRIC_SUFFIXES[match.group(2)]
|
||||
return mantissa * multiplier
|
||||
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):
|
||||
@@ -496,6 +560,12 @@ def percentage(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 validator(value):
|
||||
raise vol.Invalid(message)
|
||||
@@ -524,6 +594,46 @@ def lambda_(value):
|
||||
return Lambda(string_strict(value))
|
||||
|
||||
|
||||
def dimensions(value):
|
||||
if isinstance(value, list):
|
||||
if len(value) != 2:
|
||||
raise vol.Invalid(u"Dimensions must have a length of two, not {}".format(len(value)))
|
||||
try:
|
||||
width, height = int(value[0]), int(value[1])
|
||||
except ValueError:
|
||||
raise vol.Invalid(u"Width and height dimensions must be integers")
|
||||
if width <= 0 or height <= 0:
|
||||
raise vol.Invalid(u"Width and height must at least be 1")
|
||||
return [width, height]
|
||||
value = string(value)
|
||||
match = re.match(r"\s*([0-9]+)\s*[xX]\s*([0-9]+)\s*", value)
|
||||
if not match:
|
||||
raise vol.Invalid(u"Invalid value '{}' for dimensions. Only WIDTHxHEIGHT is allowed.")
|
||||
return dimensions([match.group(1), match.group(2)])
|
||||
|
||||
|
||||
def directory(value):
|
||||
value = string(value)
|
||||
path = helpers.relative_path(value)
|
||||
if not os.path.exists(path):
|
||||
raise vol.Invalid(u"Could not find directory '{}'. Please make sure it exists.".format(
|
||||
path))
|
||||
if not os.path.isdir(path):
|
||||
raise vol.Invalid(u"Path '{}' is not a directory.".format(path))
|
||||
return value
|
||||
|
||||
|
||||
def file_(value):
|
||||
value = string(value)
|
||||
path = helpers.relative_path(value)
|
||||
if not os.path.exists(path):
|
||||
raise vol.Invalid(u"Could not find file '{}'. Please make sure it exists.".format(
|
||||
path))
|
||||
if not os.path.isfile(path):
|
||||
raise vol.Invalid(u"Path '{}' is not a file.".format(path))
|
||||
return value
|
||||
|
||||
|
||||
REGISTERED_IDS = set()
|
||||
|
||||
|
||||
@@ -532,6 +642,23 @@ class GenerateID(vol.Optional):
|
||||
super(GenerateID, self).__init__(key, default=lambda: None)
|
||||
|
||||
|
||||
def nameable(*schemas):
|
||||
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({
|
||||
vol.Required(CONF_PLATFORM): valid,
|
||||
})
|
||||
@@ -543,11 +670,12 @@ MQTT_COMPONENT_AVAILABILITY_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_DISCOVERY): boolean,
|
||||
vol.Optional(CONF_STATE_TOPIC): publish_topic,
|
||||
vol.Optional(CONF_AVAILABILITY): vol.Any(None, MQTT_COMPONENT_AVAILABILITY_SCHEMA),
|
||||
vol.Optional(CONF_INTERNAL): boolean,
|
||||
})
|
||||
|
||||
MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"""Constants used by esphomeyaml."""
|
||||
|
||||
MAJOR_VERSION = 1
|
||||
MINOR_VERSION = 6
|
||||
MINOR_VERSION = 8
|
||||
PATCH_VERSION = '2'
|
||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||
ESPHOMELIB_VERSION = '1.8.2'
|
||||
|
||||
ESP_PLATFORM_ESP32 = 'ESP32'
|
||||
ESP_PLATFORM_ESP8266 = 'ESP8266'
|
||||
@@ -16,9 +17,14 @@ CONF_ESPHOMEYAML = 'esphomeyaml'
|
||||
CONF_NAME = 'name'
|
||||
CONF_PLATFORM = 'platform'
|
||||
CONF_BOARD = 'board'
|
||||
CONF_SIMPLIFY = 'simplify'
|
||||
CONF_USE_BUILD_FLAGS = 'use_build_flags'
|
||||
CONF_LIBRARY_URI = 'library_uri'
|
||||
CONF_ESPHOMELIB_VERSION = 'esphomelib_version'
|
||||
CONF_USE_CUSTOM_CODE = 'use_custom_code'
|
||||
CONF_ARDUINO_VERSION = 'arduino_version'
|
||||
CONF_LOCAL = 'local'
|
||||
CONF_REPOSITORY = 'repository'
|
||||
CONF_COMMIT = 'commit'
|
||||
CONF_TAG = 'tag'
|
||||
CONF_BRANCH = 'branch'
|
||||
CONF_LOGGER = 'logger'
|
||||
CONF_WIFI = 'wifi'
|
||||
CONF_SSID = 'ssid'
|
||||
@@ -99,6 +105,7 @@ CONF_LOGS = 'logs'
|
||||
CONF_PORT = 'port'
|
||||
CONF_WILL_MESSAGE = 'will_message'
|
||||
CONF_BIRTH_MESSAGE = 'birth_message'
|
||||
CONF_SHUTDOWN_MESSAGE = 'shutdown_message'
|
||||
CONF_PAYLOAD = 'payload'
|
||||
CONF_QOS = 'qos'
|
||||
CONF_DISCOVERY_RETAIN = 'discovery_retain'
|
||||
@@ -148,7 +155,6 @@ CONF_TRIGGER_PIN = 'trigger_pin'
|
||||
CONF_ECHO_PIN = 'echo_pin'
|
||||
CONF_TIMEOUT_METER = 'timeout_meter'
|
||||
CONF_TIMEOUT_TIME = 'timeout_time'
|
||||
CONF_IR_TRANSMITTER_ID = 'ir_transmitter_id'
|
||||
CONF_CARRIER_DUTY_PERCENT = 'carrier_duty_percent'
|
||||
CONF_NEC = 'nec'
|
||||
CONF_COMMAND = 'command'
|
||||
@@ -221,9 +227,10 @@ CONF_ON_VALUE = 'on_value'
|
||||
CONF_ON_RAW_VALUE = 'on_raw_value'
|
||||
CONF_ON_VALUE_RANGE = 'on_value_range'
|
||||
CONF_ON_MESSAGE = 'on_message'
|
||||
CONF_PIN_CS = 'pin_cs'
|
||||
CONF_PIN_CLOCK = 'pin_clock'
|
||||
CONF_PIN_MISO = 'pin_miso'
|
||||
CONF_CS_PIN = 'cs_pin'
|
||||
CONF_CLK_PIN = 'clk_pin'
|
||||
CONF_MISO_PIN = 'miso_pin'
|
||||
CONF_MOSI_PIN = 'mosi_pin'
|
||||
CONF_TURN_ON_ACTION = 'turn_on_action'
|
||||
CONF_TURN_OFF_ACTION = 'turn_off_action'
|
||||
CONF_OPEN_ACTION = 'open_action'
|
||||
@@ -231,27 +238,109 @@ CONF_CLOSE_ACTION = 'close_action'
|
||||
CONF_STOP_ACTION = 'stop_action'
|
||||
CONF_DOMAIN = 'domain'
|
||||
CONF_OPTIMISTIC = 'optimistic'
|
||||
|
||||
ESP32_BOARDS = [
|
||||
'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1',
|
||||
'pocket_32', 'espectro32', 'esp32vn-iot-uno', 'esp320', 'esp-wrover-kit',
|
||||
'esp32dev', 'heltec_wifi_kit32', 'heltec_wifi_lora_32', 'hornbill32dev',
|
||||
'hornbill32minima', 'intorobot', 'm5stack-core-esp32', 'mhetesp32devkit',
|
||||
'mhetesp32minikit', 'nano32', 'microduino-core-esp32', 'nodemcu-32s',
|
||||
'quantum', 'esp32-evb', 'esp32-gateway', 'onehorse32dev', 'esp32thing',
|
||||
'espino32', 'lolin32', 'wemosbat', 'widora-air', 'nina_w10',
|
||||
]
|
||||
|
||||
ESP8266_BOARDS = [
|
||||
'gen4iod', 'huzzah', 'oak', 'espduino', 'espectro', 'espresso_lite_v1',
|
||||
'espresso_lite_v2', 'espino', 'esp01', 'esp01_1m', 'esp07', 'esp12e', 'esp8285',
|
||||
'esp_wroom_02', 'phoenix_v1', 'phoenix_v2', 'wifinfo', 'heltex_wifi_kit_8',
|
||||
'nodemcu', 'nodemcuv2', 'modwifi', 'wio_node', 'sparkfunBlynk', 'thing',
|
||||
'thingdev', 'esp210', 'espinotee', 'd1', 'd1_mini', 'd1_mini_lite', 'd1_mini_pro',
|
||||
]
|
||||
ESP_BOARDS_FOR_PLATFORM = {
|
||||
ESP_PLATFORM_ESP32: ESP32_BOARDS,
|
||||
ESP_PLATFORM_ESP8266: ESP8266_BOARDS
|
||||
}
|
||||
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'
|
||||
CONF_SPI_ID = 'spi_id'
|
||||
CONF_UART_ID = 'uart_id'
|
||||
CONF_UID = 'uid'
|
||||
CONF_TX_PIN = 'tx_pin'
|
||||
CONF_RX_PIN = 'rx_pin'
|
||||
CONF_CO2 = 'co2'
|
||||
CONF_SHUNT_RESISTANCE = 'shunt_resistance'
|
||||
CONF_MAX_CURRENT = 'max_current'
|
||||
CONF_MAX_VOLTAGE = 'max_voltage'
|
||||
CONF_CURRENT = 'current'
|
||||
CONF_POWER = 'power'
|
||||
CONF_BUS_VOLTAGE = 'bus_voltage'
|
||||
CONF_SHUNT_VOLTAGE = 'shunt_voltage'
|
||||
CONF_CONDITION = 'condition'
|
||||
CONF_ELSE = 'else'
|
||||
CONF_EFFECTS = 'effects'
|
||||
CONF_RANDOM = 'random'
|
||||
CONF_EFFECT_ID = 'effect_id'
|
||||
CONF_COLORS = 'colors'
|
||||
CONF_STATE = 'state'
|
||||
CONF_DURATION = 'duration'
|
||||
CONF_WIDTH = 'width'
|
||||
CONF_ILLUMINANCE = 'illuminance'
|
||||
CONF_COLOR_TEMPERATURE = 'color_temperature'
|
||||
CONF_BATTERY_LEVEL = 'battery_level'
|
||||
CONF_MOISTURE = 'moisture'
|
||||
CONF_CONDUCTIVITY = 'conductivity'
|
||||
CONF_RC_SWITCH_RAW = 'rc_switch_raw'
|
||||
CONF_RC_SWITCH_TYPE_A = 'rc_switch_type_a'
|
||||
CONF_RC_SWITCH_TYPE_B = 'rc_switch_type_b'
|
||||
CONF_RC_SWITCH_TYPE_C = 'rc_switch_type_c'
|
||||
CONF_RC_SWITCH_TYPE_D = 'rc_switch_type_d'
|
||||
CONF_CODE = 'code'
|
||||
CONF_PROTOCOL = 'protocol'
|
||||
CONF_PULSE_LENGTH = 'pulse_length'
|
||||
CONF_SYNC = 'sync'
|
||||
CONF_ZERO = 'zero'
|
||||
CONF_ONE = 'one'
|
||||
CONF_GROUP = 'group'
|
||||
CONF_DEVICE = 'device'
|
||||
CONF_FAMILY = 'family'
|
||||
CONF_FILE = 'file'
|
||||
CONF_GLYPHS = 'glyphs'
|
||||
CONF_SIZE = 'size'
|
||||
CONF_RESIZE = 'resize'
|
||||
CONF_ROTATION = 'rotation'
|
||||
CONF_DC_PIN = 'dc_pin'
|
||||
CONF_RESET_PIN = 'reset_pin'
|
||||
CONF_BUSY_PIN = 'busy_pin'
|
||||
CONF_FULL_UPDATE_EVERY = 'full_update_every'
|
||||
CONF_DATA_PINS = 'data_pins'
|
||||
CONF_ENABLE_PIN = 'enable_pin'
|
||||
CONF_RS_PIN = 'rs_pin'
|
||||
CONF_RW_PIN = 'rw_pin'
|
||||
CONF_DIMENSIONS = 'dimensions'
|
||||
CONF_NUM_CHIPS = 'num_chips'
|
||||
CONF_INTENSITY = 'intensity'
|
||||
CONF_EXTERNAL_VCC = 'external_vcc'
|
||||
CONF_TIMEZONE = 'timezone'
|
||||
CONF_SERVERS = 'servers'
|
||||
CONF_HEATER = 'heater'
|
||||
CONF_VOLTAGE = 'voltage'
|
||||
CONF_CURRENT_RESISTOR = 'current_resistor'
|
||||
CONF_VOLTAGE_DIVIDER = 'voltage_divider'
|
||||
CONF_SEL_PIN = 'sel_pin'
|
||||
CONF_CF_PIN = 'cf_pin'
|
||||
CONF_CF1_PIN = 'cf1_pin'
|
||||
CONF_CHANGE_MODE_EVERY = 'change_mode_every'
|
||||
CONF_PAGE_ID = 'page_id'
|
||||
CONF_COMPONENT_ID = 'component_id'
|
||||
CONF_COLD_WHITE = 'cold_white'
|
||||
CONF_WARM_WHITE = 'warm_white'
|
||||
CONF_COLD_WHITE_COLOR_TEMPERATURE = 'cold_white_color_temperature'
|
||||
CONF_WARM_WHITE_COLOR_TEMPERATURE = 'warm_white_color_temperature'
|
||||
CONF_ON_LOOP = 'on_loop'
|
||||
CONF_ON_TIME = 'on_time'
|
||||
CONF_SECONDS = 'seconds'
|
||||
CONF_MINUTES = 'minutes'
|
||||
CONF_HOURS = 'hours'
|
||||
CONF_DAYS_OF_MONTH = 'days_of_month'
|
||||
CONF_MONTHS = 'months'
|
||||
CONF_DAYS_OF_WEEK = 'days_of_week'
|
||||
CONF_CRON = 'cron'
|
||||
CONF_POWER_SAVE_MODE = 'power_save_mode'
|
||||
|
||||
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
|
||||
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'
|
||||
ARDUINO_VERSION_ESP8266_DEV = 'https://github.com/platformio/platform-espressif8266.git#feature' \
|
||||
'/stage'
|
||||
|
||||
@@ -10,6 +10,8 @@ class ESPHomeYAMLError(Exception):
|
||||
|
||||
class HexInt(long):
|
||||
def __str__(self):
|
||||
if 0 <= self <= 255:
|
||||
return "0x{:02X}".format(self)
|
||||
return "0x{:X}".format(self)
|
||||
|
||||
|
||||
@@ -32,6 +34,12 @@ class MACAddress(object):
|
||||
def __str__(self):
|
||||
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):
|
||||
if isinstance(value, (int, long)):
|
||||
@@ -175,8 +183,8 @@ class TimePeriodSeconds(TimePeriod):
|
||||
class Lambda(object):
|
||||
def __init__(self, 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)]
|
||||
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), 3)]
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
@@ -213,6 +221,8 @@ class ID(object):
|
||||
return self.id
|
||||
|
||||
def __str__(self):
|
||||
if self.id is None:
|
||||
return ''
|
||||
return self.id
|
||||
|
||||
def __repr__(self):
|
||||
@@ -229,7 +239,7 @@ class ID(object):
|
||||
|
||||
|
||||
CONFIG_PATH = None
|
||||
SIMPLIFY = True
|
||||
ESP_PLATFORM = ''
|
||||
BOARD = ''
|
||||
RAW_CONFIG = None
|
||||
NAME = ''
|
||||
|
||||
254
esphomeyaml/core_config.py
Normal file
254
esphomeyaml/core_config.py
Normal file
@@ -0,0 +1,254 @@
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml import automation, core, pins
|
||||
from esphomeyaml.const import CONF_ARDUINO_VERSION, CONF_BOARD, CONF_BOARD_FLASH_MODE, \
|
||||
CONF_BRANCH, CONF_BUILD_PATH, CONF_COMMIT, CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, \
|
||||
CONF_LOCAL, CONF_NAME, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, CONF_PLATFORM, \
|
||||
CONF_PRIORITY, CONF_REPOSITORY, CONF_TAG, CONF_TRIGGER_ID, CONF_USE_CUSTOM_CODE, \
|
||||
ESPHOMELIB_VERSION, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, ARDUINO_VERSION_ESP8266_DEV, \
|
||||
ARDUINO_VERSION_ESP32_DEV
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.helpers import App, NoArg, Pvariable, add, const_char_p, esphomelib_ns, \
|
||||
relative_path
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
LIBRARY_URI_REPO = u'https://github.com/OttoWinter/esphomelib.git'
|
||||
|
||||
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
|
||||
StartupTrigger = esphomelib_ns.StartupTrigger
|
||||
ShutdownTrigger = esphomelib_ns.ShutdownTrigger
|
||||
LoopTrigger = esphomelib_ns.LoopTrigger
|
||||
|
||||
VERSION_REGEX = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+(?:-beta)?(?:-alpha)?$')
|
||||
|
||||
|
||||
def validate_board(value):
|
||||
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
|
||||
board_pins = pins.ESP8266_BOARD_PINS
|
||||
elif core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
|
||||
board_pins = pins.ESP32_BOARD_PINS
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
if value not in board_pins:
|
||||
raise vol.Invalid(u"Could not find board '{}'. Valid boards are {}".format(
|
||||
value, u', '.join(pins.ESP8266_BOARD_PINS.keys())))
|
||||
return value
|
||||
|
||||
|
||||
def validate_simple_esphomelib_version(value):
|
||||
value = cv.string_strict(value)
|
||||
if value.upper() == 'LATEST':
|
||||
return {
|
||||
CONF_REPOSITORY: LIBRARY_URI_REPO,
|
||||
CONF_TAG: 'v' + ESPHOMELIB_VERSION,
|
||||
}
|
||||
elif value.upper() == 'DEV':
|
||||
return {
|
||||
CONF_REPOSITORY: LIBRARY_URI_REPO,
|
||||
CONF_BRANCH: 'master'
|
||||
}
|
||||
elif VERSION_REGEX.match(value) is not None:
|
||||
return {
|
||||
CONF_REPOSITORY: LIBRARY_URI_REPO,
|
||||
CONF_TAG: 'v' + value,
|
||||
}
|
||||
return value
|
||||
|
||||
|
||||
def validate_local_esphomelib_version(value):
|
||||
value = cv.directory(value)
|
||||
path = relative_path(value)
|
||||
library_json = os.path.join(path, 'library.json')
|
||||
if not os.path.exists(library_json):
|
||||
raise vol.Invalid(u"Could not find '{}' file. '{}' does not seem to point to an "
|
||||
u"esphomelib copy.".format(library_json, value))
|
||||
return value
|
||||
|
||||
|
||||
def validate_commit(value):
|
||||
value = cv.string(value)
|
||||
if re.match(r"^[0-9a-f]{7,}$", value) is None:
|
||||
raise vol.Invalid("Commit option only accepts commit hashes in hex format.")
|
||||
return value
|
||||
|
||||
|
||||
ESPHOMELIB_VERSION_SCHEMA = vol.Any(
|
||||
validate_simple_esphomelib_version,
|
||||
vol.Schema({
|
||||
vol.Required(CONF_LOCAL): validate_local_esphomelib_version,
|
||||
}),
|
||||
vol.All(
|
||||
vol.Schema({
|
||||
vol.Optional(CONF_REPOSITORY, default=LIBRARY_URI_REPO): cv.string,
|
||||
vol.Optional(CONF_COMMIT): validate_commit,
|
||||
vol.Optional(CONF_BRANCH): cv.string,
|
||||
vol.Optional(CONF_TAG): cv.string,
|
||||
}),
|
||||
cv.has_at_most_one_key(CONF_COMMIT, CONF_BRANCH, CONF_TAG)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def validate_platform(value):
|
||||
value = cv.string(value)
|
||||
if value.upper() in ('ESP8266', 'ESPRESSIF8266'):
|
||||
return ESP_PLATFORM_ESP8266
|
||||
if value.upper() in ('ESP32', 'ESPRESSIF32'):
|
||||
return ESP_PLATFORM_ESP32
|
||||
raise vol.Invalid(u"Invalid platform '{}'. Only options are ESP8266 and ESP32. Please note "
|
||||
u"the old way to use the latest arduino framework version has been split up "
|
||||
u"into the arduino_version configuration option.".format(value))
|
||||
|
||||
|
||||
PLATFORMIO_ESP8266_LUT = {
|
||||
'2.4.2': 'espressif8266@1.8.0',
|
||||
'2.4.1': 'espressif8266@1.7.3',
|
||||
'2.4.0': 'espressif8266@1.6.0',
|
||||
'2.3.0': 'espressif8266@1.5.0',
|
||||
'RECOMMENDED': 'espressif8266@>=1.8.0',
|
||||
'LATEST': 'espressif8266',
|
||||
'DEV': ARDUINO_VERSION_ESP8266_DEV,
|
||||
}
|
||||
|
||||
PLATFORMIO_ESP32_LUT = {
|
||||
'1.0.0': 'espressif32@1.4.0',
|
||||
'RECOMMENDED': 'espressif32@>=1.4.0',
|
||||
'LATEST': 'espressif32',
|
||||
'DEV': ARDUINO_VERSION_ESP32_DEV,
|
||||
}
|
||||
|
||||
|
||||
def validate_arduino_version(value):
|
||||
value = cv.string_strict(value)
|
||||
value_ = value.upper()
|
||||
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
|
||||
if VERSION_REGEX.match(value) is not None and value_ not in PLATFORMIO_ESP8266_LUT:
|
||||
raise vol.Invalid("Unfortunately the arduino framework version '{}' is unsupported "
|
||||
"at this time. You can override this by manually using "
|
||||
"espressif8266@<platformio version>")
|
||||
if value_ in PLATFORMIO_ESP8266_LUT:
|
||||
return PLATFORMIO_ESP8266_LUT[value_]
|
||||
return value
|
||||
elif core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
|
||||
if VERSION_REGEX.match(value) is not None and value_ not in PLATFORMIO_ESP32_LUT:
|
||||
raise vol.Invalid("Unfortunately the arduino framework version '{}' is unsupported "
|
||||
"at this time. You can override this by manually using "
|
||||
"espressif32@<platformio version>")
|
||||
if value_ in PLATFORMIO_ESP32_LUT:
|
||||
return PLATFORMIO_ESP32_LUT[value_]
|
||||
return value
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def default_build_path():
|
||||
return core.NAME
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_NAME): cv.valid_name,
|
||||
vol.Required(CONF_PLATFORM): vol.All(vol.Upper, cv.one_of('ESP8266', 'ESPRESSIF8266',
|
||||
'ESP32', 'ESPRESSIF32')),
|
||||
vol.Required(CONF_BOARD): validate_board,
|
||||
vol.Optional(CONF_ESPHOMELIB_VERSION, default='latest'): ESPHOMELIB_VERSION_SCHEMA,
|
||||
vol.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version,
|
||||
vol.Optional(CONF_USE_CUSTOM_CODE, default=False): cv.boolean,
|
||||
vol.Optional(CONF_BUILD_PATH, default=default_build_path): cv.string,
|
||||
|
||||
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),
|
||||
})]),
|
||||
vol.Optional(CONF_ON_LOOP): vol.All(cv.ensure_list, [automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(LoopTrigger),
|
||||
})]),
|
||||
|
||||
vol.Optional('library_uri'): cv.invalid("The library_uri option has been removed in 1.8.0 and "
|
||||
"was moved into the esphomelib_version option.")
|
||||
})
|
||||
|
||||
|
||||
def preload_core_config(config):
|
||||
if CONF_ESPHOMEYAML not in config:
|
||||
raise ESPHomeYAMLError(u"No esphomeyaml section in config")
|
||||
core_conf = config[CONF_ESPHOMEYAML]
|
||||
if CONF_PLATFORM not in core_conf:
|
||||
raise ESPHomeYAMLError("esphomeyaml.platform not specified.")
|
||||
if CONF_BOARD not in core_conf:
|
||||
raise ESPHomeYAMLError("esphomeyaml.board not specified.")
|
||||
if CONF_NAME not in core_conf:
|
||||
raise ESPHomeYAMLError("esphomeyaml.name not specified.")
|
||||
|
||||
try:
|
||||
core.ESP_PLATFORM = validate_platform(core_conf[CONF_PLATFORM])
|
||||
core.BOARD = validate_board(core_conf[CONF_BOARD])
|
||||
core.NAME = cv.valid_name(core_conf[CONF_NAME])
|
||||
except vol.Invalid as e:
|
||||
raise ESPHomeYAMLError(unicode(e))
|
||||
|
||||
|
||||
def run_command(*args):
|
||||
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
rc = p.returncode
|
||||
return rc, stdout, stderr
|
||||
|
||||
|
||||
def update_esphomelib_repo(config):
|
||||
esphomelib_version = config[CONF_ESPHOMELIB_VERSION]
|
||||
if CONF_REPOSITORY not in esphomelib_version:
|
||||
return
|
||||
|
||||
build_path = relative_path(config[CONF_BUILD_PATH])
|
||||
esphomelib_path = os.path.join(build_path, '.piolibdeps', 'esphomelib')
|
||||
is_default_branch = all(x not in esphomelib_version
|
||||
for x in (CONF_BRANCH, CONF_TAG, CONF_COMMIT))
|
||||
if not (CONF_BRANCH in esphomelib_version or is_default_branch):
|
||||
# Git commit hash or tag cannot be updated
|
||||
return
|
||||
|
||||
rc, _, _ = run_command('git', '-C', esphomelib_path, '--help')
|
||||
if rc != 0:
|
||||
# git not installed or repo not downloaded yet
|
||||
return
|
||||
rc, _, _ = run_command('git', '-C', esphomelib_path, 'diff-index', '--quiet', 'HEAD', '--')
|
||||
if rc != 0:
|
||||
# local changes, cannot update
|
||||
_LOGGER.warn("Local changes in esphomelib copy from git. Will not auto-update.")
|
||||
return
|
||||
rc, _, _ = run_command('git', '-C', esphomelib_path, 'pull')
|
||||
if rc != 0:
|
||||
_LOGGER.warn("Couldn't auto-update local git copy of esphomelib.")
|
||||
return
|
||||
|
||||
|
||||
def to_code(config):
|
||||
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)
|
||||
|
||||
for conf in config.get(CONF_ON_LOOP, []):
|
||||
rhs = App.register_component(LoopTrigger.new())
|
||||
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
|
||||
automation.build_automation(trigger, NoArg, conf)
|
||||
|
||||
update_esphomelib_repo(config)
|
||||
@@ -2,16 +2,18 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import codecs
|
||||
import hmac
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
|
||||
from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_BUILD_PATH
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml import const, core, __main__
|
||||
from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name
|
||||
from esphomeyaml.helpers import quote
|
||||
from esphomeyaml.__main__ import get_serial_ports
|
||||
from esphomeyaml.helpers import quote, relative_path
|
||||
|
||||
try:
|
||||
import tornado
|
||||
@@ -27,6 +29,13 @@ except ImportError as err:
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
CONFIG_DIR = ''
|
||||
PASSWORD = ''
|
||||
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class BaseHandler(tornado.web.RequestHandler):
|
||||
def is_authenticated(self):
|
||||
return not PASSWORD or self.get_secure_cookie('authenticated') == 'yes'
|
||||
|
||||
|
||||
# pylint: disable=abstract-method, arguments-differ
|
||||
@@ -37,6 +46,8 @@ class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler):
|
||||
self.closed = False
|
||||
|
||||
def on_message(self, message):
|
||||
if PASSWORD and self.get_secure_cookie('authenticated') != 'yes':
|
||||
return
|
||||
if self.proc is not None:
|
||||
return
|
||||
command = self.build_command(message)
|
||||
@@ -56,7 +67,10 @@ class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler):
|
||||
break
|
||||
if data.endswith('\r') and random.randrange(100) < 90:
|
||||
continue
|
||||
data = data.replace('\033', '\\033')
|
||||
try:
|
||||
data = data.replace('\033', '\\033')
|
||||
except UnicodeDecodeError:
|
||||
data = data.encode('ascii', 'backslashreplace')
|
||||
self.write_message({'event': 'line', 'data': data})
|
||||
|
||||
def proc_on_exit(self, returncode):
|
||||
@@ -103,8 +117,18 @@ class EsphomeyamlValidateHandler(EsphomeyamlCommandWebSocket):
|
||||
return ["esphomeyaml", config_file, "config"]
|
||||
|
||||
|
||||
class SerialPortRequestHandler(tornado.web.RequestHandler):
|
||||
class EsphomeyamlCleanMqttHandler(EsphomeyamlCommandWebSocket):
|
||||
def build_command(self, message):
|
||||
js = json.loads(message)
|
||||
config_file = os.path.join(CONFIG_DIR, js['configuration'])
|
||||
return ["esphomeyaml", config_file, "clean-mqtt"]
|
||||
|
||||
|
||||
class SerialPortRequestHandler(BaseHandler):
|
||||
def get(self):
|
||||
if not self.is_authenticated():
|
||||
self.redirect('/login')
|
||||
return
|
||||
ports = get_serial_ports()
|
||||
data = []
|
||||
for port, desc in ports:
|
||||
@@ -119,10 +143,13 @@ class SerialPortRequestHandler(tornado.web.RequestHandler):
|
||||
self.write(json.dumps(sorted(data, reverse=True)))
|
||||
|
||||
|
||||
class WizardRequestHandler(tornado.web.RequestHandler):
|
||||
class WizardRequestHandler(BaseHandler):
|
||||
def post(self):
|
||||
from esphomeyaml import wizard
|
||||
|
||||
if not self.is_authenticated():
|
||||
self.redirect('/login')
|
||||
return
|
||||
kwargs = {k: ''.join(v) for k, v in self.request.arguments.iteritems()}
|
||||
config = wizard.wizard_file(**kwargs)
|
||||
destination = os.path.join(CONFIG_DIR, kwargs['name'] + '.yaml')
|
||||
@@ -132,16 +159,20 @@ class WizardRequestHandler(tornado.web.RequestHandler):
|
||||
self.redirect('/?begin=True')
|
||||
|
||||
|
||||
class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
|
||||
class DownloadBinaryRequestHandler(BaseHandler):
|
||||
def get(self):
|
||||
if not self.is_authenticated():
|
||||
self.redirect('/login')
|
||||
return
|
||||
|
||||
configuration = self.get_argument('configuration')
|
||||
config_file = os.path.join(CONFIG_DIR, configuration)
|
||||
core.CONFIG_PATH = config_file
|
||||
config = __main__.read_config(core.CONFIG_PATH)
|
||||
name = get_name(config)
|
||||
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
|
||||
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
|
||||
path = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin')
|
||||
self.set_header('Content-Type', 'application/octet-stream')
|
||||
self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(name))
|
||||
self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(core.NAME))
|
||||
with open(path, 'rb') as f:
|
||||
while 1:
|
||||
data = f.read(16384) # or some other nice-sized chunk
|
||||
@@ -151,8 +182,12 @@ class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
|
||||
self.finish()
|
||||
|
||||
|
||||
class MainRequestHandler(tornado.web.RequestHandler):
|
||||
class MainRequestHandler(BaseHandler):
|
||||
def get(self):
|
||||
if not self.is_authenticated():
|
||||
self.redirect('/login')
|
||||
return
|
||||
|
||||
begin = bool(self.get_argument('begin', False))
|
||||
files = sorted([f for f in os.listdir(CONFIG_DIR) if f.endswith('.yaml') and
|
||||
not f.startswith('.')])
|
||||
@@ -161,23 +196,41 @@ class MainRequestHandler(tornado.web.RequestHandler):
|
||||
version=const.__version__, begin=begin)
|
||||
|
||||
|
||||
class LoginHandler(BaseHandler):
|
||||
def get(self):
|
||||
self.write('<html><body><form action="/login" method="post">'
|
||||
'Password: <input type="password" name="password">'
|
||||
'<input type="submit" value="Sign in">'
|
||||
'</form></body></html>')
|
||||
|
||||
def post(self):
|
||||
password = str(self.get_argument("password", ''))
|
||||
password = hmac.new(password).digest()
|
||||
if hmac.compare_digest(PASSWORD, password):
|
||||
self.set_secure_cookie("authenticated", "yes")
|
||||
self.redirect("/")
|
||||
|
||||
|
||||
def make_app(debug=False):
|
||||
static_path = os.path.join(os.path.dirname(__file__), 'static')
|
||||
return tornado.web.Application([
|
||||
(r"/", MainRequestHandler),
|
||||
(r"/login", LoginHandler),
|
||||
(r"/logs", EsphomeyamlLogsHandler),
|
||||
(r"/run", EsphomeyamlRunHandler),
|
||||
(r"/compile", EsphomeyamlCompileHandler),
|
||||
(r"/validate", EsphomeyamlValidateHandler),
|
||||
(r"/clean-mqtt", EsphomeyamlCleanMqttHandler),
|
||||
(r"/download.bin", DownloadBinaryRequestHandler),
|
||||
(r"/serial-ports", SerialPortRequestHandler),
|
||||
(r"/wizard.html", WizardRequestHandler),
|
||||
(r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}),
|
||||
], debug=debug)
|
||||
], debug=debug, cookie_secret=PASSWORD)
|
||||
|
||||
|
||||
def start_web_server(args):
|
||||
global CONFIG_DIR
|
||||
global PASSWORD
|
||||
|
||||
if tornado is None:
|
||||
raise ESPHomeYAMLError("Attempted to load dashboard, but tornado is not installed! "
|
||||
@@ -187,10 +240,31 @@ def start_web_server(args):
|
||||
if not os.path.exists(CONFIG_DIR):
|
||||
os.makedirs(CONFIG_DIR)
|
||||
|
||||
# HassIO options storage
|
||||
PASSWORD = args.password
|
||||
if os.path.isfile('/data/options.json'):
|
||||
with open('/data/options.json') as f:
|
||||
js = json.load(f)
|
||||
PASSWORD = js.get('password') or PASSWORD
|
||||
|
||||
if PASSWORD:
|
||||
PASSWORD = hmac.new(str(PASSWORD)).digest()
|
||||
# Use the digest of the password as our cookie secret. This makes sure the cookie
|
||||
# isn't too short. It, of course, enables local hash brute forcing (because the cookie
|
||||
# secret can be brute forced without making requests). But the hashing algorithm used
|
||||
# by tornado is apparently strong enough to make brute forcing even a short string pretty
|
||||
# hard.
|
||||
|
||||
_LOGGER.info("Starting dashboard web server on port %s and configuration dir %s...",
|
||||
args.port, CONFIG_DIR)
|
||||
app = make_app(args.verbose)
|
||||
app.listen(args.port)
|
||||
|
||||
if args.open_ui:
|
||||
import webbrowser
|
||||
|
||||
webbrowser.open('localhost:{}'.format(args.port))
|
||||
|
||||
try:
|
||||
tornado.ioloop.IOLoop.current().start()
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@@ -159,7 +159,13 @@
|
||||
margin-right: 24px;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.dropdown-trigger {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -189,7 +195,7 @@
|
||||
|
||||
<main>
|
||||
<div class="container">
|
||||
{% for file, full_path in zip(files, full_path_files) %}
|
||||
{% for i, (file, full_path) in enumerate(zip(files, full_path_files)) %}
|
||||
<div class="row">
|
||||
<div class="col s8 offset-s2 m10 offset-m1 l12">
|
||||
<div class="card horizontal">
|
||||
@@ -198,7 +204,10 @@
|
||||
</div>
|
||||
<div class="card-stacked">
|
||||
<div class="card-content">
|
||||
<span class="card-title">{{ escape(file) }}</span>
|
||||
<span class="card-title">
|
||||
{{ escape(file) }}
|
||||
<i class="material-icons right dropdown-trigger" data-target="dropdown-{{ i }}">more_vert</i>
|
||||
</span>
|
||||
<p>
|
||||
Full path: <code class="inlinecode">{{ escape(full_path) }}</code>
|
||||
</p>
|
||||
@@ -209,6 +218,9 @@
|
||||
<a href="#" class="action-show-logs" data-node="{{ file }}">Show Logs</a>
|
||||
<a href="#" class="action-validate" data-node="{{ file }}">Validate</a>
|
||||
</div>
|
||||
<ul id="dropdown-{{ i }}" class="dropdown-content">
|
||||
<li><a href="#" class="action-clean-mqtt" data-node="{{ file }}">Clean MQTT</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -297,8 +309,8 @@
|
||||
<p>
|
||||
First, I need to know what this node should be called. Choose this name wisely, changing this
|
||||
later makes Over-The-Air Update attempts difficult.
|
||||
It may only contain the characters <code class="inlinecode">a-z</code>,
|
||||
<code class="inlinecode">0-9</code> and <code class="inlinecode">_</code>
|
||||
Names must be <strong>lowercase</strong> and <strong>must not contain spaces</strong> (allowed characters: <code class="inlinecode">a-z</code>,
|
||||
<code class="inlinecode">0-9</code> and <code class="inlinecode">_</code>)
|
||||
</p>
|
||||
<div class="input-field col s12">
|
||||
<input id="node_name" class="validate" type="text" name="name" required>
|
||||
@@ -460,6 +472,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-clean-mqtt" class="modal modal-fixed-footer">
|
||||
<div class="modal-content">
|
||||
<h4>Clean MQTT discovery <code class="inlinecode filename"></code></h4>
|
||||
<div class="log-container">
|
||||
<pre class="log"></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="btn-floating btn-large ribbon-fab waves-effect waves-light pink accent-2" id="setup-wizard-start">
|
||||
<i class="material-icons">add</i>
|
||||
</a>
|
||||
@@ -524,7 +548,7 @@
|
||||
let ports = [];
|
||||
|
||||
const fetchSerialPorts = (begin=false) => {
|
||||
fetch('/serial-ports').then(res => res.json())
|
||||
fetch('/serial-ports', {credentials: "same-origin"}).then(res => res.json())
|
||||
.then(response => {
|
||||
if (ports.length === response.length) {
|
||||
let allEqual = true;
|
||||
@@ -537,6 +561,7 @@
|
||||
if (allEqual)
|
||||
return;
|
||||
}
|
||||
const hasNewPort = response.length >= ports.length;
|
||||
|
||||
ports = response;
|
||||
|
||||
@@ -557,7 +582,7 @@
|
||||
}
|
||||
|
||||
M.FormSelect.init(portSelect, {});
|
||||
if (!begin)
|
||||
if (!begin && hasNewPort)
|
||||
M.toast({html: "Discovered new serial port."});
|
||||
});
|
||||
};
|
||||
@@ -782,6 +807,48 @@
|
||||
link.click();
|
||||
});
|
||||
|
||||
const cleanMqttModalElem = document.getElementById("modal-clean-mqtt");
|
||||
|
||||
document.querySelectorAll(".action-clean-mqtt").forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
configuration = e.target.getAttribute('data-node');
|
||||
const modalInstance = M.Modal.getInstance(cleanMqttModalElem);
|
||||
const log = cleanMqttModalElem.querySelector(".log");
|
||||
log.innerHTML = "";
|
||||
const stopLogsButton = cleanMqttModalElem.querySelector(".stop-logs");
|
||||
let stopped = false;
|
||||
stopLogsButton.innerHTML = "Stop";
|
||||
modalInstance.open();
|
||||
|
||||
const filenameField = cleanMqttModalElem.querySelector('.filename');
|
||||
filenameField.innerHTML = configuration;
|
||||
|
||||
const logSocket = new WebSocket(wsUrl + "/clean-mqtt");
|
||||
logSocket.addEventListener('message', (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.event === "line") {
|
||||
const msg = data.data;
|
||||
log.innerHTML += colorReplace(msg);
|
||||
} else if (data.event === "exit") {
|
||||
stopLogsButton.innerHTML = "Close";
|
||||
stopped = true;
|
||||
}
|
||||
});
|
||||
logSocket.addEventListener('open', () => {
|
||||
const msg = JSON.stringify({configuration: configuration});
|
||||
logSocket.send(msg);
|
||||
});
|
||||
logSocket.addEventListener('close', () => {
|
||||
if (!stopped) {
|
||||
M.toast({html: 'Terminated process.'});
|
||||
}
|
||||
});
|
||||
modalInstance.options.onCloseStart = () => {
|
||||
logSocket.close();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const modalSetupElem = document.getElementById("modal-wizard");
|
||||
const setupWizardStart = document.getElementById('setup-wizard-start');
|
||||
const startWizard = () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict, deque
|
||||
|
||||
@@ -85,8 +86,6 @@ class AssignmentExpression(Expression):
|
||||
|
||||
def __str__(self):
|
||||
type_ = self.type
|
||||
if core.SIMPLIFY:
|
||||
type_ = u'auto'
|
||||
return u"{} {}{} = {}".format(type_, self.modifier, self.name, self.rhs)
|
||||
|
||||
def has_side_effects(self):
|
||||
@@ -107,7 +106,7 @@ class ExpressionList(Expression):
|
||||
self.args.append(exp)
|
||||
|
||||
def __str__(self):
|
||||
text = u", ".join(str(x) for x in self.args)
|
||||
text = u", ".join(unicode(x) for x in self.args)
|
||||
return indent_all_but_first_and_last(text)
|
||||
|
||||
|
||||
@@ -226,7 +225,7 @@ class LambdaExpression(Expression):
|
||||
self.return_type = return_type
|
||||
if return_type is not None:
|
||||
self.requires.append(return_type)
|
||||
for i in range(1, len(parts), 2):
|
||||
for i in range(1, len(parts), 3):
|
||||
self.requires.append(parts[i])
|
||||
|
||||
def __str__(self):
|
||||
@@ -273,6 +272,12 @@ class IntLiteral(Literal):
|
||||
self.i = i
|
||||
|
||||
def __str__(self):
|
||||
if self.i > 4294967295:
|
||||
return u'{}ULL'.format(self.i)
|
||||
if self.i > 2147483647:
|
||||
return u'{}UL'.format(self.i)
|
||||
if self.i < -2147483648:
|
||||
return u'{}LL'.format(self.i)
|
||||
return unicode(self.i)
|
||||
|
||||
|
||||
@@ -411,7 +416,11 @@ def process_lambda(value, parameters, capture='=', return_type=None):
|
||||
var = None
|
||||
for var in get_variable(id):
|
||||
yield
|
||||
parts[i*2 + 1] = var._
|
||||
if parts[i * 3 + 2] == '.':
|
||||
parts[i * 3 + 1] = var._
|
||||
else:
|
||||
parts[i * 3 + 1] = var
|
||||
parts[i * 3 + 2] = ''
|
||||
yield LambdaExpression(parts, parameters, capture, return_type)
|
||||
return
|
||||
|
||||
@@ -522,9 +531,27 @@ class MockObj(Expression):
|
||||
obj.requires.append(self)
|
||||
return obj
|
||||
|
||||
def operator(self, name):
|
||||
if name == 'ref':
|
||||
obj = MockObj(u'{} &'.format(self.base), u'')
|
||||
obj.requires.append(self)
|
||||
return obj
|
||||
raise NotImplementedError()
|
||||
|
||||
def has_side_effects(self):
|
||||
return self._has_side_effects
|
||||
|
||||
def __getitem__(self, item):
|
||||
next_op = u'.'
|
||||
if isinstance(item, str) and item.startswith(u'P'):
|
||||
item = item[1:]
|
||||
next_op = u'->'
|
||||
obj = MockObj(u'{}[{}]'.format(self.base, item), next_op)
|
||||
obj.requires.append(self)
|
||||
if isinstance(item, Expression):
|
||||
obj.requires.append(item)
|
||||
return obj
|
||||
|
||||
|
||||
global_ns = MockObj('', '')
|
||||
float_ = global_ns.namespace('float')
|
||||
@@ -534,6 +561,7 @@ std_string = std_ns.string
|
||||
uint8 = global_ns.namespace('uint8_t')
|
||||
uint16 = global_ns.namespace('uint16_t')
|
||||
uint32 = global_ns.namespace('uint32_t')
|
||||
const_char_p = global_ns.namespace('const char *')
|
||||
NAN = global_ns.namespace('NAN')
|
||||
esphomelib_ns = global_ns # using namespace esphomelib;
|
||||
NoArg = esphomelib_ns.NoArg
|
||||
@@ -633,3 +661,7 @@ def color(the_color, message='', reset=None):
|
||||
if not message:
|
||||
return parse_colors(the_color)
|
||||
return parse_colors(the_color) + message + escape_codes[reset or 'reset']
|
||||
|
||||
|
||||
def relative_path(path):
|
||||
return os.path.join(os.path.dirname(core.CONFIG_PATH), os.path.expanduser(path))
|
||||
|
||||
@@ -2,6 +2,8 @@ from __future__ import print_function
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import ssl
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
@@ -10,7 +12,7 @@ from esphomeyaml import core
|
||||
from esphomeyaml.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOMEYAML, \
|
||||
CONF_LOG_TOPIC, \
|
||||
CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \
|
||||
CONF_USERNAME, CONF_TOPIC
|
||||
CONF_USERNAME, CONF_TOPIC, CONF_SSL_FINGERPRINTS
|
||||
from esphomeyaml.helpers import color
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -30,6 +32,14 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
|
||||
config[CONF_MQTT][CONF_PASSWORD])
|
||||
elif username:
|
||||
client.username_pw_set(username, password)
|
||||
|
||||
if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS):
|
||||
if sys.version_info >= (2, 7, 13):
|
||||
tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member
|
||||
else:
|
||||
tls_version = ssl.PROTOCOL_SSLv23
|
||||
client.tls_set(ca_certs=None, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED,
|
||||
tls_version=tls_version, ciphers=None)
|
||||
client.connect(config[CONF_MQTT][CONF_BROKER], config[CONF_MQTT][CONF_PORT])
|
||||
|
||||
try:
|
||||
@@ -73,12 +83,18 @@ def clear_topic(config, topic, username=None, password=None, client_id=None):
|
||||
discovery_prefix = config[CONF_MQTT].get(CONF_DISCOVERY_PREFIX, u'homeassistant')
|
||||
name = config[CONF_ESPHOMEYAML][CONF_NAME]
|
||||
topic = u'{}/+/{}/#'.format(discovery_prefix, name)
|
||||
_LOGGER.info(u"Clearing messages from %s", topic)
|
||||
_LOGGER.info(u"Clearing messages from '%s'", topic)
|
||||
_LOGGER.info(u"Please close this window when no more messages appear and the "
|
||||
u"MQTT topic has been cleared of retained messages.")
|
||||
|
||||
def on_message(client, userdata, msg):
|
||||
if not msg.payload:
|
||||
if not msg.payload or not msg.retain:
|
||||
return
|
||||
try:
|
||||
print(u"Clearing topic {}".format(msg.topic))
|
||||
except UnicodeDecodeError:
|
||||
print(u"Skipping non-UTF-8 topic (prohibited by MQTT standard)")
|
||||
return
|
||||
print(u"Clearing topic {}".format(msg.topic))
|
||||
client.publish(msg.topic, None, retain=True)
|
||||
|
||||
return initialize(config, [topic], on_message, username, password, client_id)
|
||||
@@ -86,8 +102,6 @@ def clear_topic(config, topic, username=None, password=None, client_id=None):
|
||||
|
||||
# From marvinroger/async-mqtt-client -> scripts/get-fingerprint/get-fingerprint.py
|
||||
def get_fingerprint(config):
|
||||
import ssl
|
||||
|
||||
addr = config[CONF_MQTT][CONF_BROKER], config[CONF_MQTT][CONF_PORT]
|
||||
_LOGGER.info("Getting fingerprint from %s:%s", addr[0], addr[1])
|
||||
try:
|
||||
|
||||
@@ -10,59 +10,162 @@ from esphomeyaml.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_PCF857
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ESP8266_PINS = {
|
||||
'A0': 17, 'SS': 15, 'MOSI': 13, 'MISO': 12, 'SCK': 14,
|
||||
}
|
||||
ESP8266_NODEMCU_PINS = dict(ESP8266_PINS, **{
|
||||
'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 15, 'D9': 3,
|
||||
'D10': 1, 'LED': 16, 'SDA': 4, 'SCL': 5,
|
||||
})
|
||||
ESP8266_D1_PINS = dict(ESP8266_PINS, **{
|
||||
'D0': 3, 'D1': 1, 'D2': 16, 'D3': 5, 'D4': 4, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 0, 'D9': 2,
|
||||
'D10': 15, 'D11': 13, 'D12': 14, 'D13': 14, 'D14': 4, 'D15': 5, 'LED': 2, 'SDA': 4, 'SCL': 5,
|
||||
})
|
||||
ESP8266_D1_MINI_PINS = dict(ESP8266_PINS, **{
|
||||
'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 15, 'RX': 3,
|
||||
'TX': 1, 'LED': 2, 'SDA': 4, 'SCL': 5,
|
||||
})
|
||||
ESP8266_THING_PINS = dict(ESP8266_PINS, **{
|
||||
'LED': 5, 'SDA': 2, 'SCL': 14,
|
||||
})
|
||||
ESP8266_ADAFRUIT_PINS = dict(ESP8266_PINS, **{
|
||||
'LED': 0, 'SDA': 4, 'SCL': 5,
|
||||
})
|
||||
ESP8266_ESPDUINO_PINS = dict(ESP8266_PINS, **{
|
||||
'LED': 16, 'SDA': 4, 'SCL': 5,
|
||||
})
|
||||
ESP8266_BOARD_TO_PINS = {
|
||||
'huzzah': ESP8266_ADAFRUIT_PINS,
|
||||
'espduino': ESP8266_ESPDUINO_PINS,
|
||||
'nodemcu': ESP8266_NODEMCU_PINS, 'nodemcuv2': ESP8266_NODEMCU_PINS,
|
||||
'thing': ESP8266_THING_PINS, 'thingdev': ESP8266_THING_PINS,
|
||||
'd1': ESP8266_D1_PINS,
|
||||
'd1_mini': ESP8266_D1_MINI_PINS, 'd1_mini_lite': ESP8266_D1_MINI_PINS,
|
||||
'd1_mini_pro': ESP8266_D1_MINI_PINS
|
||||
ESP8266_BASE_PINS = {
|
||||
'A0': 17, 'SS': 15, 'MOSI': 13, 'MISO': 12, 'SCK': 14, 'SDA': 4, 'SCL': 5, 'RX': 3, 'TX': 1
|
||||
}
|
||||
|
||||
ESP32_PINS = {
|
||||
ESP8266_BOARD_PINS = {
|
||||
'd1': {'D0': 3, 'D1': 1, 'D2': 16, 'D3': 5, 'D4': 4, 'D5': 14, 'D6': 12, 'D7': 13, 'D8': 0,
|
||||
'D9': 2, 'D10': 15, 'D11': 13, 'D12': 14, 'D13': 14, 'D14': 4, 'D15': 5, 'LED': 2},
|
||||
'd1_mini': {'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13,
|
||||
'D8': 15, 'LED': 2},
|
||||
'd1_mini_lite': 'd1_mini',
|
||||
'd1_mini_pro': 'd1_mini',
|
||||
'esp01': {},
|
||||
'esp01_1m': {},
|
||||
'esp07': {},
|
||||
'esp12e': {},
|
||||
'esp210': {},
|
||||
'esp8285': {},
|
||||
'esp_wroom_02': {},
|
||||
'espduino': {'LED': 16},
|
||||
'espectro': {'LED': 15, 'BUTTON': 2},
|
||||
'espino': {'LED': 2, 'LED_RED': 2, 'LED_GREEN': 4, 'LED_BLUE': 5, 'BUTTON': 0},
|
||||
'espinotee': {'LED': 16},
|
||||
'espresso_lite_v1': {'LED': 16},
|
||||
'espresso_lite_v2': {'LED': 2},
|
||||
'gen4iod': {},
|
||||
'heltec_wifi_kit_8': 'd1_mini',
|
||||
'huzzah': {'LED': 0},
|
||||
'modwifi': {},
|
||||
'nodemcu': {'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12, 'D7': 13,
|
||||
'D8': 15, 'D9': 3, 'D10': 1, 'LED': 16},
|
||||
'nodemcuv2': 'nodemcu',
|
||||
'oak': {'P0': 2, 'P1': 5, 'P2': 0, 'P3': 3, 'P4': 1, 'P5': 4, 'P6': 15, 'P7': 13, 'P8': 12,
|
||||
'P9': 14, 'P10': 16, 'P11': 17, 'LED': 5},
|
||||
'phoenix_v1': {'LED': 16},
|
||||
'phoenix_v2': {'LED': 2},
|
||||
'sparkfunBlynk': 'thing',
|
||||
'thing': {'LED': 5, 'SDA': 2, 'SCL': 14},
|
||||
'thingdev': 'thing',
|
||||
'wifi_slot': {'LED': 2},
|
||||
'wifiduino': {'D0': 3, 'D1': 1, 'D2': 2, 'D3': 0, 'D4': 4, 'D5': 5, 'D6': 16, 'D7': 14,
|
||||
'D8': 12, 'D9': 13, 'D10': 15, 'D11': 13, 'D12': 12, 'D13': 14},
|
||||
'wifinfo': {'LED': 12, 'D0': 16, 'D1': 5, 'D2': 4, 'D3': 0, 'D4': 2, 'D5': 14, 'D6': 12,
|
||||
'D7': 13, 'D8': 15, 'D9': 3, 'D10': 1},
|
||||
'wio_link': {'LED': 2, 'GROVE': 15},
|
||||
'wio_node': 'nodemcu',
|
||||
'xinabox_cw01': {'SDA': 2, 'SCL': 14, 'LED': 5, 'LED_RED': 12, 'LED_GREEN': 13}
|
||||
}
|
||||
|
||||
ESP32_BASE_PINS = {
|
||||
'TX': 1, 'RX': 3, 'SDA': 21, 'SCL': 22, 'SS': 5, 'MOSI': 23, 'MISO': 19, 'SCK': 18, 'A0': 36,
|
||||
'A3': 39, 'A4': 32, 'A5': 33, 'A6': 34, 'A7': 35, 'A10': 4, 'A11': 0, 'A12': 2, 'A13': 15,
|
||||
'A14': 13, 'A15': 12, 'A16': 14, 'A17': 27, 'A18': 25, 'A19': 26, 'T0': 4, 'T1': 0, 'T2': 2,
|
||||
'T3': 15, 'T4': 12, 'T5': 12, 'T6': 14, 'T7': 27, 'T8': 33, 'T9': 32, 'DAC1': 25, 'DAC2': 26,
|
||||
'T3': 15, 'T4': 13, 'T5': 12, 'T6': 14, 'T7': 27, 'T8': 33, 'T9': 32, 'DAC1': 25, 'DAC2': 26,
|
||||
'SVP': 36, 'SVN': 39,
|
||||
}
|
||||
ESP32_NODEMCU_32S_PINS = dict(ESP32_PINS, **{
|
||||
'LED': 2,
|
||||
})
|
||||
ESP32_LOLIN32_PINS = dict(ESP32_PINS, **{
|
||||
'LED': 5
|
||||
})
|
||||
ESP32_BOARD_TO_PINS = {
|
||||
'nodemcu-32s': ESP32_NODEMCU_32S_PINS,
|
||||
'lolin32': ESP32_LOLIN32_PINS,
|
||||
|
||||
ESP32_BOARD_PINS = {
|
||||
'alksesp32': {'D0': 40, 'D1': 41, 'D2': 15, 'D3': 2, 'D4': 0, 'D5': 4, 'D6': 16, 'D7': 17,
|
||||
'D8': 5, 'D9': 18, 'D10': 19, 'D11': 21, 'D12': 22, 'D13': 23, 'A0': 32, 'A1': 33,
|
||||
'A2': 25, 'A3': 26, 'A4': 27, 'A5': 14, 'A6': 12, 'A7': 15, 'L_R': 22, 'L_G': 17,
|
||||
'L_Y': 23, 'L_B': 5, 'L_RGB_R': 4, 'L_RGB_G': 21, 'L_RGB_B': 16, 'SW1': 15,
|
||||
'SW2': 2, 'SW3': 0, 'POT1': 32, 'POT2': 33, 'PIEZO1': 19, 'PIEZO2': 18,
|
||||
'PHOTO': 25, 'DHT_PIN': 26, 'S1': 4, 'S2': 16, 'S3': 18, 'S4': 19, 'S5': 21,
|
||||
'SDA': 27, 'SCL': 14, 'SS': 19, 'MOSI': 21, 'MISO': 22, 'SCK': 23},
|
||||
'esp-wrover-kit': {},
|
||||
'esp32-evb': {'BUTTON': 34, 'SDA': 13, 'SCL': 16, 'SS': 17, 'MOSI': 2, 'MISO': 15, 'SCK': 14},
|
||||
'esp32-gateway': {'LED': 33, 'BUTTON': 34, 'SCL': 16, 'SDA': 17},
|
||||
'esp320': {'LED': 5, 'SDA': 2, 'SCL': 14, 'SS': 15, 'MOSI': 13, 'MISO': 12, 'SCK': 14},
|
||||
'esp32dev': {},
|
||||
'esp32doit-devkit-v1': {'LED': 2},
|
||||
'esp32thing': {'LED': 5, 'BUTTON': 0, 'SS': 2},
|
||||
'esp32vn-iot-uno': {},
|
||||
'espea32': {'LED': 5, 'BUTTON': 0},
|
||||
'espectro32': {'LED': 15, 'SD_SS': 33},
|
||||
'espino32': {'LED': 16, 'BUTTON': 0},
|
||||
'featheresp32': {'LED': 13, 'TX': 17, 'RX': 16, 'SDA': 23, 'SS': 2, 'MOSI': 18, 'SCK': 5,
|
||||
'A0': 26, 'A1': 25, 'A2': 34, 'A4': 36, 'A5': 4, 'A6': 14, 'A7': 32, 'A8': 15,
|
||||
'A9': 33, 'A10': 27, 'A11': 12, 'A12': 13, 'A13': 35},
|
||||
'firebeetle32': {'LED': 2},
|
||||
'heltec_wifi_kit_32': {'LED': 25, 'BUTTON': 0, 'A1': 37, 'A2': 38},
|
||||
'heltec_wifi_lora_32': {'LED': 25, 'BUTTON': 0, 'SDA': 4, 'SCL': 15, 'SS': 18, 'MOSI': 27,
|
||||
'SCK': 5, 'A1': 37, 'A2': 38, 'T8': 32, 'T9': 33, 'DAC1': 26,
|
||||
'DAC2': 25, 'OLED_SCL': 15, 'OLED_SDA': 4, 'OLED_RST': 16,
|
||||
'LORA_SCK': 5, 'LORA_MOSI': 27, 'LORA_MISO': 19, 'LORA_CS': 18,
|
||||
'LORA_RST': 14, 'LORA_IRQ': 26},
|
||||
'hornbill32dev': {'LED': 13, 'BUTTON': 0},
|
||||
'hornbill32minima': {'SS': 2},
|
||||
'intorobot': {'LED': 4, 'LED_RED': 27, 'LED_GREEN': 21, 'LED_BLUE': 22,
|
||||
'BUTTON': 0, 'SDA': 23, 'SCL': 19, 'MOSI': 16, 'MISO': 17, 'A1': 39, 'A2': 35,
|
||||
'A3': 25, 'A4': 26, 'A5': 14, 'A6': 12, 'A7': 15, 'A8': 13, 'A9': 2, 'D0': 19,
|
||||
'D1': 23, 'D2': 18, 'D3': 17, 'D4': 16, 'D5': 5, 'D6': 4, 'T0': 19, 'T1': 23,
|
||||
'T2': 18, 'T3': 17, 'T4': 16, 'T5': 5, 'T6': 4},
|
||||
'lolin32': {'LED': 5},
|
||||
'lolin_d32': {'LED': 5, 'VBAT': 35},
|
||||
'lolin_d32_pro': {'LED': 5, 'VBAT': 35, 'TF_CS': 4, 'TS_CS': 12, 'TFT_CS': 14, 'TFT_LED': 32,
|
||||
'TFT_RST': 33, 'TFT_DC': 27},
|
||||
'm5stack-core-esp32': {'TXD2': 17, 'RXD2': 16, 'G23': 23, 'G19': 19, 'G18': 18, 'G3': 3,
|
||||
'G16': 16, 'G21': 21, 'G2': 2, 'G12': 12, 'G15': 15, 'G35': 35,
|
||||
'G36': 36, 'G25': 25, 'G26': 26, 'G1': 1, 'G17': 17, 'G22': 22, 'G5': 5,
|
||||
'G13': 13, 'G0': 0, 'G34': 34, 'ADC1': 35, 'ADC2': 36},
|
||||
'm5stack-fire': {'G23': 23, 'G19': 19, 'G18': 18, 'G3': 3, 'G16': 16, 'G21': 21, 'G2': 2,
|
||||
'G12': 12, 'G15': 15, 'G35': 35, 'G36': 36, 'G25': 25, 'G26': 26, 'G1': 1,
|
||||
'G17': 17, 'G22': 22, 'G5': 5, 'G13': 13, 'G0': 0, 'G34': 34, 'ADC1': 35,
|
||||
'ADC2': 36},
|
||||
'mhetesp32devkit': {'LED': 2},
|
||||
'mhetesp32minikit': {'LED': 2},
|
||||
'microduino-core-esp32': {'SDA': 22, 'SCL': 21, 'SDA1': 12, 'SCL1': 13, 'A0': 12, 'A1': 13,
|
||||
'A2': 15, 'A3': 4, 'A6': 38, 'A7': 37, 'A8': 32, 'A9': 33, 'A10': 25,
|
||||
'A11': 26, 'A12': 27, 'A13': 14, 'D0': 3, 'D1': 1, 'D2': 16, 'D3': 17,
|
||||
'D4': 32, 'D5': 33, 'D6': 25, 'D7': 26, 'D8': 27, 'D9': 14, 'D10': 5,
|
||||
'D11': 23, 'D12': 19, 'D13': 18, 'D14': 12, 'D15': 13, 'D16': 15,
|
||||
'D17': 4, 'D18': 22, 'D19': 21, 'D20': 38, 'D21': 37},
|
||||
'nano32': {'LED': 16, 'BUTTON': 0},
|
||||
'nina_w10': {'LED_GREEN': 33, 'LED_RED': 23, 'LED_BLUE': 21, 'SW1': 33, 'SW2': 27, 'SDA': 12,
|
||||
'SCL': 13, 'D0': 3, 'D1': 1, 'D2': 26, 'D3': 25, 'D4': 35, 'D5': 27, 'D6': 22,
|
||||
'D7': 0, 'D8': 15, 'D9': 14, 'D10': 5, 'D11': 19, 'D12': 23, 'D13': 18, 'D14': 13,
|
||||
'D15': 12, 'D16': 32, 'D17': 33, 'D18': 21, 'D19': 34, 'D20': 36, 'D21': 39},
|
||||
'node32s': {},
|
||||
'nodemcu-32s': {'LED': 2, 'BUTTON': 0},
|
||||
'odroid_esp32': {'LED': 2, 'SDA': 15, 'SCL': 4, 'SS': 22, 'ADC1': 35, 'ADC2': 36},
|
||||
'onehorse32dev': {'LED': 5, 'BUTTON': 0, 'A1': 37, 'A2': 38},
|
||||
'pico32': {},
|
||||
'pocket_32': {'LED': 16},
|
||||
'quantum': {},
|
||||
'ttgo-lora32-v1': {'LED': 2, 'BUTTON': 0, 'SS': 18, 'MOSI': 27, 'SCK': 5, 'A1': 37, 'A2': 38,
|
||||
'T8': 32, 'T9': 33, 'DAC1': 26, 'DAC2': 25, 'OLED_SDA': 4, 'OLED_SCL': 15,
|
||||
'OLED_RST': 16, 'LORA_SCK': 5, 'LORA_MISO': 19, 'LORA_MOSI': 27,
|
||||
'LORA_CS': 18, 'LORA_RST': 14, 'LORA_IRQ': 26},
|
||||
'wemosbat': 'pocket_32',
|
||||
'widora-air': {'LED': 25, 'BUTTON': 0, 'SDA': 23, 'SCL': 19, 'MOSI': 16, 'MISO': 17, 'A1': 39,
|
||||
'A2': 35, 'A3': 25, 'A4': 26, 'A5': 14, 'A6': 12, 'A7': 15, 'A8': 13, 'A9': 2,
|
||||
'D0': 19, 'D1': 23, 'D2': 18, 'D3': 17, 'D4': 16, 'D5': 5, 'D6': 4, 'T0': 19,
|
||||
'T1': 23, 'T2': 18, 'T3': 17, 'T4': 16, 'T5': 5, 'T6': 4},
|
||||
'xinabox_cw02': {'LED': 27},
|
||||
}
|
||||
|
||||
|
||||
def _lookup_pin(platform, board, value):
|
||||
if platform == ESP_PLATFORM_ESP8266:
|
||||
board_pins = ESP8266_BOARD_PINS.get(board, {})
|
||||
base_pins = ESP8266_BASE_PINS
|
||||
elif platform == ESP_PLATFORM_ESP32:
|
||||
board_pins = ESP32_BOARD_PINS.get(board, {})
|
||||
base_pins = ESP32_BASE_PINS
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
if isinstance(board_pins, str):
|
||||
return _lookup_pin(platform, board_pins, value)
|
||||
if value in board_pins:
|
||||
return board_pins[value]
|
||||
if value in base_pins:
|
||||
return base_pins[value]
|
||||
raise vol.Invalid(u"Can't find internal pin number for {}.".format(value))
|
||||
|
||||
|
||||
def _translate_pin(value):
|
||||
if isinstance(value, dict) or value is None:
|
||||
raise vol.Invalid(u"This variable only supports pin numbers, not full pin schemas "
|
||||
@@ -75,27 +178,7 @@ def _translate_pin(value):
|
||||
pass
|
||||
if value.startswith('GPIO'):
|
||||
return vol.Coerce(int)(value[len('GPIO'):].strip())
|
||||
if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
|
||||
if value in ESP32_PINS:
|
||||
return ESP32_PINS[value]
|
||||
if core.BOARD not in ESP32_BOARD_TO_PINS:
|
||||
raise vol.Invalid(u"ESP32: Unknown board {} with unknown "
|
||||
u"pin {}.".format(core.BOARD, value))
|
||||
if value not in ESP32_BOARD_TO_PINS[core.BOARD]:
|
||||
raise vol.Invalid(u"ESP32: Board {} doesn't have "
|
||||
u"pin {}".format(core.BOARD, value))
|
||||
return ESP32_BOARD_TO_PINS[core.BOARD][value]
|
||||
elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
|
||||
if value in ESP8266_PINS:
|
||||
return ESP8266_PINS[value]
|
||||
if core.BOARD not in ESP8266_BOARD_TO_PINS:
|
||||
raise vol.Invalid(u"ESP8266: Unknown board {} with unknown "
|
||||
u"pin {}.".format(core.BOARD, value))
|
||||
if value not in ESP8266_BOARD_TO_PINS[core.BOARD]:
|
||||
raise vol.Invalid(u"ESP8266: Board {} doesn't have "
|
||||
u"pin {}".format(core.BOARD, value))
|
||||
return ESP8266_BOARD_TO_PINS[core.BOARD][value]
|
||||
raise vol.Invalid(u"Invalid ESP platform.")
|
||||
return _lookup_pin(core.ESP_PLATFORM, core.BOARD, value)
|
||||
|
||||
|
||||
def validate_gpio_pin(value):
|
||||
|
||||
@@ -8,12 +8,13 @@ import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import mqtt
|
||||
from esphomeyaml.const import ESP_BOARDS_FOR_PLATFORM, ESP_PLATFORMS, ESP_PLATFORM_ESP32, \
|
||||
ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml.const import ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml.helpers import color
|
||||
|
||||
|
||||
# pylint: disable=anomalous-backslash-in-string
|
||||
from esphomeyaml.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS
|
||||
|
||||
CORE_BIG = """ _____ ____ _____ ______
|
||||
/ ____/ __ \| __ \| ____|
|
||||
| | | | | | |__) | |__
|
||||
@@ -187,11 +188,12 @@ def wizard(path):
|
||||
# Don't sleep because user needs to copy link
|
||||
if platform == ESP_PLATFORM_ESP32:
|
||||
print("For example \"{}\".".format(color("bold_white", 'nodemcu-32s')))
|
||||
boards = list(ESP32_BOARD_PINS.keys())
|
||||
else:
|
||||
print("For example \"{}\".".format(color("bold_white", 'nodemcuv2')))
|
||||
boards = list(ESP8266_BOARD_PINS.keys())
|
||||
while True:
|
||||
board = raw_input(color("bold_white", "(board): "))
|
||||
boards = ESP_BOARDS_FOR_PLATFORM[platform]
|
||||
try:
|
||||
board = vol.All(vol.Lower, vol.Any(*boards))(board)
|
||||
break
|
||||
|
||||
@@ -2,14 +2,17 @@ from __future__ import print_function
|
||||
|
||||
import codecs
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml.config import iter_components
|
||||
from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
|
||||
CONF_LIBRARY_URI, \
|
||||
CONF_NAME, CONF_PLATFORM, CONF_USE_BUILD_FLAGS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
|
||||
from esphomeyaml.const import ARDUINO_VERSION_ESP32_DEV, CONF_ARDUINO_VERSION, CONF_BOARD, \
|
||||
CONF_BOARD_FLASH_MODE, CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, CONF_LOCAL, CONF_NAME, \
|
||||
CONF_USE_CUSTOM_CODE, ESP_PLATFORM_ESP32, CONF_REPOSITORY, CONF_COMMIT, CONF_BRANCH, CONF_TAG
|
||||
from esphomeyaml.core import ESPHomeYAMLError
|
||||
from esphomeyaml.core_config import VERSION_REGEX
|
||||
from esphomeyaml.helpers import relative_path
|
||||
|
||||
CPP_AUTO_GENERATE_BEGIN = u'// ========== AUTO GENERATED CODE BEGIN ==========='
|
||||
CPP_AUTO_GENERATE_END = u'// =========== AUTO GENERATED CODE END ============'
|
||||
@@ -57,11 +60,11 @@ lib_deps =
|
||||
build_flags =
|
||||
{build_flags}
|
||||
${{common.build_flags}}
|
||||
upload_speed = {upload_speed}
|
||||
"""
|
||||
|
||||
PLATFORM_TO_PLATFORMIO = {
|
||||
ESP_PLATFORM_ESP32: 'espressif32',
|
||||
ESP_PLATFORM_ESP8266: 'espressif8266'
|
||||
UPLOAD_SPEED_OVERRIDE = {
|
||||
'esp210': 57600,
|
||||
}
|
||||
|
||||
|
||||
@@ -81,18 +84,17 @@ def get_build_flags(config, key):
|
||||
return build_flags
|
||||
|
||||
|
||||
def get_ini_content(config):
|
||||
platform = config[CONF_ESPHOMEYAML][CONF_PLATFORM]
|
||||
if platform in PLATFORM_TO_PLATFORMIO:
|
||||
platform = PLATFORM_TO_PLATFORMIO[platform]
|
||||
def get_ini_content(config, path):
|
||||
version_specific_settings = determine_platformio_version_settings()
|
||||
options = {
|
||||
u'env': config[CONF_ESPHOMEYAML][CONF_NAME],
|
||||
u'platform': platform,
|
||||
u'platform': config[CONF_ESPHOMEYAML][CONF_ARDUINO_VERSION],
|
||||
u'board': config[CONF_ESPHOMEYAML][CONF_BOARD],
|
||||
u'build_flags': u'',
|
||||
u'upload_speed': UPLOAD_SPEED_OVERRIDE.get(core.BOARD, 115200),
|
||||
}
|
||||
build_flags = set()
|
||||
if config[CONF_ESPHOMEYAML][CONF_USE_BUILD_FLAGS]:
|
||||
if not config[CONF_ESPHOMEYAML][CONF_USE_CUSTOM_CODE]:
|
||||
build_flags |= get_build_flags(config, 'build_flags')
|
||||
build_flags |= get_build_flags(config, 'BUILD_FLAGS')
|
||||
build_flags.add(u"-DESPHOMEYAML_USE")
|
||||
@@ -105,13 +107,53 @@ def get_ini_content(config):
|
||||
options[u'build_flags'] = u'\n '.join(build_flags)
|
||||
|
||||
lib_deps = set()
|
||||
lib_deps.add(config[CONF_ESPHOMEYAML][CONF_LIBRARY_URI])
|
||||
|
||||
lib_version = config[CONF_ESPHOMEYAML][CONF_ESPHOMELIB_VERSION]
|
||||
lib_path = os.path.join(path, 'lib')
|
||||
dst_path = os.path.join(lib_path, 'esphomelib')
|
||||
if CONF_REPOSITORY in lib_version:
|
||||
tag = next((lib_version[x] for x in (CONF_COMMIT, CONF_BRANCH, CONF_TAG)
|
||||
if x in lib_version), None)
|
||||
if tag is None:
|
||||
lib_deps.add(lib_version[CONF_REPOSITORY])
|
||||
else:
|
||||
lib_deps.add(lib_version[CONF_REPOSITORY] + '#' + tag)
|
||||
if os.path.islink(dst_path):
|
||||
os.unlink(dst_path)
|
||||
else:
|
||||
src_path = relative_path(lib_version[CONF_LOCAL])
|
||||
do_write = True
|
||||
if os.path.islink(dst_path):
|
||||
old_path = os.path.join(os.readlink(dst_path), lib_path)
|
||||
if old_path != lib_path:
|
||||
os.unlink(dst_path)
|
||||
else:
|
||||
do_write = False
|
||||
if do_write:
|
||||
mkdir_p(lib_path)
|
||||
os.symlink(src_path, dst_path)
|
||||
|
||||
# Manually add lib_deps because platformio seems to ignore them inside libs/
|
||||
library_json_path = os.path.join(src_path, 'library.json')
|
||||
with codecs.open(library_json_path, 'r', encoding='utf-8') as f_handle:
|
||||
library_json_text = f_handle.read()
|
||||
|
||||
library_json = json.loads(library_json_text)
|
||||
for dep in library_json.get('dependencies', []):
|
||||
if 'version' in dep and VERSION_REGEX.match(dep['version']) is not None:
|
||||
lib_deps.add(dep['name'] + '@' + dep['version'])
|
||||
else:
|
||||
lib_deps.add(dep['version'])
|
||||
|
||||
lib_deps |= get_build_flags(config, 'LIB_DEPS')
|
||||
lib_deps |= get_build_flags(config, 'lib_deps')
|
||||
if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
|
||||
lib_deps |= {
|
||||
'Preferences', # Preferences helper
|
||||
}
|
||||
# Manual fix for AsyncTCP
|
||||
if config[CONF_ESPHOMEYAML].get(CONF_ARDUINO_VERSION) == ARDUINO_VERSION_ESP32_DEV:
|
||||
lib_deps.add('https://github.com/me-no-dev/AsyncTCP.git#idf-update')
|
||||
# avoid changing build flags order
|
||||
lib_deps = sorted(x for x in lib_deps if x)
|
||||
if lib_deps:
|
||||
@@ -119,8 +161,9 @@ def get_ini_content(config):
|
||||
|
||||
content = INI_CONTENT_FORMAT.format(**options)
|
||||
if CONF_BOARD_FLASH_MODE in config[CONF_ESPHOMEYAML]:
|
||||
flash_mode_key = version_specific_settings['flash_mode_key']
|
||||
flash_mode = config[CONF_ESPHOMEYAML][CONF_BOARD_FLASH_MODE]
|
||||
content += "board_flash_mode = {}\n".format(flash_mode)
|
||||
content += "{} = {}\n".format(flash_mode_key, flash_mode)
|
||||
return content
|
||||
|
||||
|
||||
@@ -174,6 +217,24 @@ def write_platformio_ini(content, path):
|
||||
f_handle.write(full_file)
|
||||
|
||||
|
||||
def write_platformio_project(config, path):
|
||||
platformio_ini = os.path.join(path, 'platformio.ini')
|
||||
content = get_ini_content(config, path)
|
||||
if 'esp32_ble_beacon' in config or 'esp32_ble_tracker' in config:
|
||||
content += 'board_build.partitions = partitions.csv\n'
|
||||
partitions_csv = os.path.join(path, 'partitions.csv')
|
||||
if not os.path.isfile(partitions_csv):
|
||||
mkdir_p(path)
|
||||
with open(partitions_csv, "w") as f:
|
||||
f.write("nvs, data, nvs, 0x009000, 0x005000,\n")
|
||||
f.write("otadata, data, ota, 0x00e000, 0x002000,\n")
|
||||
f.write("app0, app, ota_0, 0x010000, 0x190000,\n")
|
||||
f.write("app1, app, ota_1, 0x200000, 0x190000,\n")
|
||||
f.write("eeprom, data, 0x99, 0x390000, 0x001000,\n")
|
||||
f.write("spiffs, data, spiffs, 0x391000, 0x00F000\n")
|
||||
write_platformio_ini(content, platformio_ini)
|
||||
|
||||
|
||||
def write_cpp(code_s, path):
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
@@ -194,3 +255,16 @@ def write_cpp(code_s, path):
|
||||
return
|
||||
with codecs.open(path, 'w+', encoding='utf-8') as f_handle:
|
||||
f_handle.write(full_file)
|
||||
|
||||
|
||||
def determine_platformio_version_settings():
|
||||
import platformio
|
||||
|
||||
settings = {}
|
||||
|
||||
if platformio.VERSION < (3, 5, 3):
|
||||
settings['flash_mode_key'] = 'board_flash_mode'
|
||||
else:
|
||||
settings['flash_mode_key'] = 'board_build.flash_mode'
|
||||
|
||||
return settings
|
||||
|
||||
@@ -4,9 +4,11 @@ import codecs
|
||||
import fnmatch
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
from collections import OrderedDict
|
||||
|
||||
import yaml
|
||||
import yaml.constructor
|
||||
|
||||
from esphomeyaml import core
|
||||
from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, Lambda, MACAddress, TimePeriod
|
||||
@@ -62,14 +64,83 @@ def dump(dict_):
|
||||
dict_, default_flow_style=False, allow_unicode=True)
|
||||
|
||||
|
||||
def custom_construct_pairs(loader, node):
|
||||
pairs = []
|
||||
for kv in node.value:
|
||||
if isinstance(kv, yaml.ScalarNode):
|
||||
obj = loader.construct_object(kv)
|
||||
if not isinstance(obj, dict):
|
||||
raise ESPHomeYAMLError(
|
||||
"Expected mapping for anchored include tag, got {}".format(type(obj)))
|
||||
for key, value in obj.iteritems():
|
||||
pairs.append((key, value))
|
||||
else:
|
||||
key_node, value_node = kv
|
||||
key = loader.construct_object(key_node)
|
||||
value = loader.construct_object(value_node)
|
||||
pairs.append((key, value))
|
||||
|
||||
return pairs
|
||||
|
||||
|
||||
def custom_flatten_mapping(loader, node):
|
||||
pre_merge = []
|
||||
post_merge = []
|
||||
index = 0
|
||||
while index < len(node.value):
|
||||
if isinstance(node.value[index], yaml.ScalarNode):
|
||||
index += 1
|
||||
continue
|
||||
|
||||
key_node, value_node = node.value[index]
|
||||
if key_node.tag == u'tag:yaml.org,2002:merge':
|
||||
del node.value[index]
|
||||
|
||||
if isinstance(value_node, yaml.MappingNode):
|
||||
custom_flatten_mapping(loader, value_node)
|
||||
node.value = node.value[:index] + value_node.value + node.value[index:]
|
||||
elif isinstance(value_node, yaml.SequenceNode):
|
||||
submerge = []
|
||||
for subnode in value_node.value:
|
||||
if not isinstance(subnode, yaml.MappingNode):
|
||||
raise yaml.constructor.ConstructorError(
|
||||
"while constructing a mapping", node.start_mark,
|
||||
"expected a mapping for merging, but found %{}".format(subnode.id),
|
||||
subnode.start_mark)
|
||||
custom_flatten_mapping(loader, subnode)
|
||||
submerge.append(subnode.value)
|
||||
# submerge.reverse()
|
||||
node.value = node.value[:index] + submerge + node.value[index:]
|
||||
elif isinstance(value_node, yaml.ScalarNode):
|
||||
node.value = node.value[:index] + [value_node] + node.value[index:]
|
||||
# post_merge.append(value_node)
|
||||
else:
|
||||
raise yaml.constructor.ConstructorError(
|
||||
"while constructing a mapping", node.start_mark,
|
||||
"expected a mapping or list of mappings for merging, "
|
||||
"but found {}".format(value_node.id), value_node.start_mark)
|
||||
elif key_node.tag == u'tag:yaml.org,2002:value':
|
||||
key_node.tag = u'tag:yaml.org,2002:str'
|
||||
index += 1
|
||||
else:
|
||||
index += 1
|
||||
if pre_merge:
|
||||
node.value = pre_merge + node.value
|
||||
if post_merge:
|
||||
node.value = node.value + post_merge
|
||||
|
||||
|
||||
def _ordered_dict(loader, node):
|
||||
"""Load YAML mappings into an ordered dictionary to preserve key order."""
|
||||
loader.flatten_mapping(node)
|
||||
nodes = loader.construct_pairs(node)
|
||||
custom_flatten_mapping(loader, node)
|
||||
nodes = custom_construct_pairs(loader, node)
|
||||
|
||||
seen = {}
|
||||
for (key, _), (child_node, _) in zip(nodes, node.value):
|
||||
line = child_node.start_mark.line
|
||||
for (key, _), nv in zip(nodes, node.value):
|
||||
if isinstance(nv, yaml.ScalarNode):
|
||||
line = nv.start_mark.line
|
||||
else:
|
||||
line = nv[0].start_mark.line
|
||||
|
||||
try:
|
||||
hash(key)
|
||||
@@ -285,6 +356,10 @@ def represent_id(_, data):
|
||||
return yaml.ScalarNode(tag=u'tag:yaml.org,2002:str', value=data.id)
|
||||
|
||||
|
||||
def represent_uuid(_, data):
|
||||
return yaml.ScalarNode(tag=u'tag:yaml.org,2002:str', value=str(data))
|
||||
|
||||
|
||||
yaml.SafeDumper.add_representer(
|
||||
OrderedDict,
|
||||
lambda dumper, value:
|
||||
@@ -304,3 +379,4 @@ yaml.SafeDumper.add_representer(MACAddress, stringify_representer)
|
||||
yaml.SafeDumper.add_multi_representer(TimePeriod, represent_time_period)
|
||||
yaml.SafeDumper.add_multi_representer(Lambda, represent_lambda)
|
||||
yaml.SafeDumper.add_multi_representer(core.ID, represent_id)
|
||||
yaml.SafeDumper.add_multi_representer(uuid.UUID, represent_uuid)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Examples
|
||||
|
||||
This directory contains some of the ESP32/ESP8266 nodes I use at my home.
|
||||
@@ -1,127 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: cabinet
|
||||
platform: ESP32
|
||||
board: nodemcu-32s
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.203
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: cabinet
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
power_supply:
|
||||
- id: 'atx'
|
||||
pin:
|
||||
number: 13
|
||||
inverted: true
|
||||
|
||||
i2c:
|
||||
sda: 14
|
||||
scl: 27
|
||||
frequency: 400000
|
||||
|
||||
pca9685:
|
||||
- id: 'pca9685'
|
||||
frequency: 500
|
||||
|
||||
output:
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'cabinet1_red'
|
||||
channel: 14
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'cabinet1_green'
|
||||
channel: 15
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'cabinet1_blue'
|
||||
channel: 13
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'cabinet2_red'
|
||||
channel: 11
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'cabinet2_green'
|
||||
channel: 12
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'cabinet2_blue'
|
||||
channel: 10
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'room_red'
|
||||
channel: 8
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'room_green'
|
||||
channel: 9
|
||||
power_supply: 'atx'
|
||||
- platform: pca9685
|
||||
pca9685_id: 'pca9685'
|
||||
id: 'room_blue'
|
||||
channel: 7
|
||||
power_supply: 'atx'
|
||||
|
||||
light:
|
||||
- platform: rgb
|
||||
name: 'Cabinet Light 1'
|
||||
red: 'cabinet1_red'
|
||||
green: 'cabinet1_green'
|
||||
blue: 'cabinet1_blue'
|
||||
- platform: rgb
|
||||
name: 'Cabinet Light 2'
|
||||
red: 'cabinet2_red'
|
||||
green: 'cabinet2_green'
|
||||
blue: 'cabinet2_blue'
|
||||
- platform: rgb
|
||||
name: 'Room Light'
|
||||
red: 'room_red'
|
||||
green: 'room_green'
|
||||
blue: 'room_blue'
|
||||
|
||||
sensor:
|
||||
- platform: dht
|
||||
pin: 23
|
||||
temperature:
|
||||
name: 'Cabinet Temperature'
|
||||
humidity:
|
||||
name: 'Cabinet Humidity'
|
||||
model: DHT22
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin: 25
|
||||
name: 'Cabinet Motion'
|
||||
device_class: motion
|
||||
# Simple binary sensor that uses last will and birth messages to show
|
||||
# node state
|
||||
- platform: status
|
||||
name: "Cabinet Status"
|
||||
|
||||
switch:
|
||||
# Simple switch that restarts the ESP32
|
||||
- platform: restart
|
||||
name: "Cabinet Restart"
|
||||
@@ -1,57 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: dachboden
|
||||
platform: ESP8266
|
||||
board: nodemcuv2
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.212
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: dachboden
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
|
||||
dallas:
|
||||
id: 'dallas'
|
||||
pin: D1
|
||||
|
||||
sensor:
|
||||
- platform: dht
|
||||
pin: D3
|
||||
temperature:
|
||||
name: 'Dachboden Temperatur'
|
||||
humidity:
|
||||
name: 'Dachboden Luftfeuchtigkeit'
|
||||
model: DHT22
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x01031663650aff28
|
||||
name: "Dachboden Solar Süd Vorlauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x2b0416638fe6ff28
|
||||
name: "Dachboden Solar Süd Rücklauf"
|
||||
- platform: adc
|
||||
pin: A0
|
||||
name: "Dachboden Helligkeit"
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Dachboden Status"
|
||||
|
||||
switch:
|
||||
- platform: restart
|
||||
name: "Dachboden Neustart"
|
||||
@@ -1,117 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: heatpump
|
||||
platform: ESP32
|
||||
board: nodemcu-32s
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.204
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: heatpump
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
dallas:
|
||||
id: 'dallas'
|
||||
pin: 15
|
||||
|
||||
sensor:
|
||||
- platform: dht
|
||||
pin: 0
|
||||
temperature:
|
||||
name: 'Outside Temperature'
|
||||
humidity:
|
||||
name: 'Outside Humidity'
|
||||
model: DHT22
|
||||
- platform: pulse_counter
|
||||
pin: 12
|
||||
unit_of_measurement: 'kW'
|
||||
name: 'Stromverbrauch Wintergarten'
|
||||
update_interval: 30s
|
||||
expire_after: 60s
|
||||
filters:
|
||||
- multiply: 0.06
|
||||
- platform: pulse_counter
|
||||
pin: 13
|
||||
unit_of_measurement: 'kW'
|
||||
name: 'Stromverbrauch Wärmepumpe'
|
||||
update_interval: 30s
|
||||
expire_after: 60s
|
||||
filters:
|
||||
- multiply: 0.06
|
||||
- platform: pulse_counter
|
||||
pin: 14
|
||||
unit_of_measurement: 'kW'
|
||||
name: 'Stromverbrauch Gesamt'
|
||||
update_interval: 30s
|
||||
expire_after: 60s
|
||||
filters:
|
||||
- multiply: 0.06
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0xfe0000031f1eaf28
|
||||
name: "Boiler Temperatur Oben"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0xba0000031f0e5228
|
||||
name: "Boiler Temperatur Unten"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0xa40000031f055028
|
||||
name: "Boiler Temperatur Mitte"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x790000031ee1dc28
|
||||
name: "Heizung Rücklauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0xdd0000031efb0428
|
||||
name: "Ölheizung Vorlauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x710000031f0e7e28
|
||||
name: "Boiler Solar Rücklauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x92041703081aff28
|
||||
name: "Boiler Solar Vorlauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x2c04173159f4ff28
|
||||
name: "Heizung Vorlauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0xd10417315babff28
|
||||
name: "Wärmepumpe Vorlauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x6c0517024a17ff28
|
||||
name: "Boiler Heizung Vorlauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x7d04173139eeff28
|
||||
name: "Wärmepumpe Rücklauf"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x3204166398a5ff28
|
||||
name: "Wärmepumpe Verdampfer"
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Heizung Status"
|
||||
|
||||
switch:
|
||||
- platform: restart
|
||||
name: "Heizung Neustart"
|
||||
@@ -1,60 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: kuche
|
||||
platform: ESP8266
|
||||
board: nodemcuv2
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.211
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: kuche
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
|
||||
dallas:
|
||||
id: 'dallas'
|
||||
pin: D1
|
||||
|
||||
sensor:
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x69041662d7f1ff28
|
||||
name: "Küche Raumtemperatur"
|
||||
- platform: dallas
|
||||
dallas_id: 'dallas'
|
||||
address: 0x800416636bebff28
|
||||
name: "Küche Heizkörpertemperatur"
|
||||
- platform: adc
|
||||
pin: A0
|
||||
name: "Küche Helligkeit"
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
pin: D2
|
||||
id: 'ventilator'
|
||||
|
||||
fan:
|
||||
- platform: binary
|
||||
output: 'ventilator'
|
||||
name: 'Küche Heizkörper Ventilator'
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Küche Status"
|
||||
|
||||
switch:
|
||||
- platform: restart
|
||||
name: "Küche Neustart"
|
||||
@@ -1,58 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: lebensmittelkeller
|
||||
platform: ESP8266
|
||||
board: nodemcuv2
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.209
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: lebensmittelkeller
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
sensor:
|
||||
- platform: dht
|
||||
pin: D3
|
||||
temperature:
|
||||
name: 'Lebensmittelkeller Temperatur'
|
||||
humidity:
|
||||
name: 'Lebensmittelkeller Feuchtigkeit'
|
||||
model: DHT22
|
||||
- platform: adc
|
||||
pin: A0
|
||||
name: "Lebensmittelkeller Helligkeit"
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
pin: D4
|
||||
id: 'ventilator'
|
||||
|
||||
fan:
|
||||
- platform: binary
|
||||
output: 'ventilator'
|
||||
name: 'Lebensmittelkeller Ventilator'
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
pin: D2
|
||||
name: 'Lebensmittelkeller Entfeuchter'
|
||||
icon: 'mdi:water-off'
|
||||
- platform: restart
|
||||
name: "Lebensmittelkeller Neustart"
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Lebensmittelkeller Status"
|
||||
@@ -1,344 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: livingroom
|
||||
platform: ESP32
|
||||
board: nodemcu-32s
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.201
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: livingroom
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: 'fan_float'
|
||||
frequency: 50000
|
||||
pin: 22
|
||||
bit_depth: 8
|
||||
|
||||
dallas:
|
||||
pin: 23
|
||||
id: dallas
|
||||
|
||||
sensor:
|
||||
- platform: dallas
|
||||
dallas_id: dallas
|
||||
address: 0x1c0000031edd2a28
|
||||
name: "Wohnzimmer Raumtemperatur"
|
||||
filters:
|
||||
- sliding_window_moving_average:
|
||||
window_size: 15
|
||||
send_every: 15
|
||||
- filter_out: 85
|
||||
- platform: dallas
|
||||
dallas_id: dallas
|
||||
address: 0x7a0315a8371eff28
|
||||
name: "Wohnzimmer Heizkörpertemperatur"
|
||||
update_interval: 30s
|
||||
filters:
|
||||
- sliding_window_moving_average:
|
||||
window_size: 15
|
||||
send_every: 15
|
||||
- filter_out: 85
|
||||
|
||||
fan:
|
||||
- platform: speed
|
||||
output: 'fan_float'
|
||||
name: 'Wohnzimmer Heizkörper Ventilator'
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Wohnzimmer Status"
|
||||
|
||||
ir_transmitter:
|
||||
pin: 32
|
||||
id: 'ir'
|
||||
|
||||
switch:
|
||||
- platform: restart
|
||||
name: "Wohnzimmer Neustart"
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV On"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100BCBD
|
||||
repeat: 25
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Off"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100BCBD
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV SD Card"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x190D544
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Input TV"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1400C4D
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Input AV"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100A0A1
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Menu"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1004A4B
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Aspect Ratio"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1207B5A
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Viera Cast"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x190C958
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Direct TV REC"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1909100
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Info"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1009C9D
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Exit"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100CBCA
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Viera Link"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1908D1C
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Viera Tools"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100F7F6
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Guide"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x190E170
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Up"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1005253
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Left"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1007273
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV OK"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1009293
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Right"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100F2F3
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Down"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100D2D3
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Option"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x190E574
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Back"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1002B2A
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Red"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1000E0F
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Green"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1000E0F # TODO: FIXME
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Yellow"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1004E4F
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Blue"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100CECF
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Text"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x180C041
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Subtitle"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x180A021
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Index"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1801091
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Hold"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1809011
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 1"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1000809
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 2"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1008889
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 3"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1004849
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 4"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100C8C9
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 5"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1002829
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 6"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100A8A9
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 7"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1006869
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 8"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100E8E9
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 9"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1001819
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV 0"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1009899
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Mute"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1004C4D
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Last View"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100ECED
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Volume Up"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1000405
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Volume Down"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1008485
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Program Up"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1002C2D
|
||||
- platform: ir_transmitter
|
||||
ir_transmitter_id: 'ir'
|
||||
name: "Panasonic TV Program Down"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x100ACAD
|
||||
@@ -1,91 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: <NAME_OF_NODE>
|
||||
platform: ESP8266
|
||||
board: esp01_1m
|
||||
board_flash_mode: dout
|
||||
|
||||
wifi:
|
||||
ssid: <YOUR_SSID>
|
||||
password: <YOUR_PASSWORD>
|
||||
|
||||
mqtt:
|
||||
broker: <YOUR_MQTT_BROKER>
|
||||
username: <YOUR_USERNAME>
|
||||
password: <YOUR_PASSWORD>
|
||||
|
||||
logger:
|
||||
|
||||
ota:
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO0
|
||||
mode: INPUT_PULLUP
|
||||
inverted: True
|
||||
name: "Sonoff 4CH Button 1"
|
||||
on_press:
|
||||
then:
|
||||
switch.toggle:
|
||||
id: relay_1
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO9
|
||||
mode: INPUT_PULLUP
|
||||
inverted: True
|
||||
name: "Sonoff 4CH Button 2"
|
||||
on_press:
|
||||
then:
|
||||
switch.toggle:
|
||||
id: relay_2
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO10
|
||||
mode: INPUT_PULLUP
|
||||
inverted: True
|
||||
name: "Sonoff 4CH Button 3"
|
||||
on_press:
|
||||
then:
|
||||
switch.toggle:
|
||||
id: relay_3
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO14
|
||||
mode: INPUT_PULLUP
|
||||
inverted: True
|
||||
name: "Sonoff 4CH Button 4"
|
||||
on_press:
|
||||
then:
|
||||
switch.toggle:
|
||||
id: relay_4
|
||||
- platform: status
|
||||
name: "Sonoff 4CH Status"
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
name: "Sonoff 4CH Relay 1"
|
||||
pin: GPIO12
|
||||
id: relay_1
|
||||
- platform: gpio
|
||||
name: "Sonoff 4CH Relay 2"
|
||||
pin: GPIO5
|
||||
id: relay_2
|
||||
- platform: gpio
|
||||
name: "Sonoff 4CH Relay 3"
|
||||
pin: GPIO4
|
||||
id: relay_3
|
||||
- platform: gpio
|
||||
name: "Sonoff 4CH Relay 4"
|
||||
pin: GPIO15
|
||||
id: relay_4
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: blue_led
|
||||
pin: GPIO13
|
||||
inverted: True
|
||||
|
||||
light:
|
||||
- platform: monochromatic
|
||||
name: "Sonoff 4CH Blue LED"
|
||||
output: blue_led
|
||||
@@ -1,50 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: <NAME_OF_NODE>
|
||||
platform: ESP8266
|
||||
board: esp01_1m
|
||||
board_flash_mode: dout
|
||||
|
||||
wifi:
|
||||
ssid: <YOUR_SSID>
|
||||
password: <YOUR_PASSWORD>
|
||||
|
||||
mqtt:
|
||||
broker: <YOUR_MQTT_BROKER>
|
||||
username: <YOUR_USERNAME>
|
||||
password: <YOUR_PASSWORD>
|
||||
|
||||
logger:
|
||||
|
||||
ota:
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO0
|
||||
mode: INPUT_PULLUP
|
||||
inverted: True
|
||||
name: "Sonoff S20 Button"
|
||||
on_press:
|
||||
then:
|
||||
- switch.toggle:
|
||||
id: relay
|
||||
- platform: status
|
||||
name: "Sonoff S20 Status"
|
||||
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
name: "Sonoff S20 Relay"
|
||||
pin: GPIO12
|
||||
id: relay
|
||||
|
||||
output:
|
||||
- platform: esp8266_pwm
|
||||
id: s20_green_led
|
||||
pin: GPIO13
|
||||
inverted: True
|
||||
|
||||
light:
|
||||
- platform: monochromatic
|
||||
name: "Sonoff S20 Green LED"
|
||||
output: s20_green_led
|
||||
@@ -1,48 +0,0 @@
|
||||
esphomeyaml:
|
||||
name: terrasse
|
||||
platform: ESP32
|
||||
board: nodemcu-32s
|
||||
|
||||
logger:
|
||||
level: verbose
|
||||
|
||||
wifi:
|
||||
ssid: '[SSID]'
|
||||
password: '[PASSWORD]'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.205
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
|
||||
ota:
|
||||
|
||||
mqtt:
|
||||
broker: 192.168.178.84
|
||||
username: terrasse
|
||||
password: '[PASSWORD]'
|
||||
# This is the default
|
||||
discovery: true
|
||||
|
||||
dallas:
|
||||
pin: 25
|
||||
id: dallas
|
||||
|
||||
sensor:
|
||||
- platform: pulse_counter
|
||||
pin: 34
|
||||
name: "Terrasse Wind"
|
||||
- platform: pulse_counter
|
||||
pin: 39
|
||||
name: "Terrasse Regen"
|
||||
- platform: dallas
|
||||
dallas_id: dallas
|
||||
index: 0
|
||||
name: "Terrasse Temperatur"
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Terrasse Status"
|
||||
|
||||
switch:
|
||||
- platform: restart
|
||||
name: "Terrasse Neustart"
|
||||
1
pylintrc
1
pylintrc
@@ -17,6 +17,7 @@ disable=
|
||||
invalid-name,
|
||||
cyclic-import,
|
||||
redefined-builtin,
|
||||
undefined-loop-variable,
|
||||
|
||||
|
||||
additional-builtins=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
voluptuous==0.11.1
|
||||
platformio==3.5.2
|
||||
pyyaml==3.12
|
||||
paho-mqtt==1.3.1
|
||||
colorlog==3.1.2
|
||||
tornado==5.0.2
|
||||
esptool==2.3.1
|
||||
voluptuous>=0.11.1
|
||||
platformio>=3.5.3
|
||||
pyyaml>=3.12
|
||||
paho-mqtt>=1.3.1
|
||||
colorlog>=3.1.2
|
||||
tornado>=5.0.0
|
||||
esptool>=2.3.1
|
||||
|
||||
2
setup.py
2
setup.py
@@ -23,7 +23,7 @@ DOWNLOAD_URL = '{}/archive/{}.zip'.format(GITHUB_URL, const.__version__)
|
||||
|
||||
REQUIRES = [
|
||||
'voluptuous>=0.11.1',
|
||||
'platformio>=3.5.2',
|
||||
'platformio>=3.5.3',
|
||||
'pyyaml>=3.12',
|
||||
'paho-mqtt>=1.3.1',
|
||||
'colorlog>=3.1.2',
|
||||
|
||||
11
tests/README.md
Normal file
11
tests/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Tests for esphomeyaml
|
||||
|
||||
This directory contains some tests for esphomeyaml.
|
||||
At the moment, all the tests only work by simply executing
|
||||
`esphomeyaml` over some YAML files that are made to test
|
||||
all of esphomeyaml's features.
|
||||
|
||||
Of course this is all just very high-level and things like
|
||||
unit tests would be much better. So if you have time and know
|
||||
how to set up a unit testing framework for python, please do
|
||||
give it a try.
|
||||
903
tests/test1.yaml
Normal file
903
tests/test1.yaml
Normal file
@@ -0,0 +1,903 @@
|
||||
esphomeyaml:
|
||||
name: test1
|
||||
platform: ESP32
|
||||
board: nodemcu-32s
|
||||
# Use latest upstream esphomelib git version.
|
||||
esphomelib_version: dev
|
||||
# Use this for testing while developing:
|
||||
# esphomelib_version:
|
||||
# local: ~/path/to/esphomelib
|
||||
use_custom_code: false
|
||||
on_boot:
|
||||
priority: 150.0
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "ON BOOT!");
|
||||
on_shutdown:
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "ON SHUTDOWN!");
|
||||
on_loop:
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGV("main", "ON LOOP!");
|
||||
build_path: build/test1
|
||||
|
||||
wifi:
|
||||
ssid: 'MySSID'
|
||||
password: 'password1'
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.230
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
dns1: 1.1.1.1
|
||||
dns2: 1.2.2.1
|
||||
hostname: myverylonghostname
|
||||
domain: .local
|
||||
reboot_timeout: 120s
|
||||
|
||||
mqtt:
|
||||
broker: '192.168.178.84'
|
||||
port: 1883
|
||||
username: 'debug'
|
||||
password: 'debug'
|
||||
client_id: someclient
|
||||
discovery: True
|
||||
discovery_retain: False
|
||||
discovery_prefix: discovery
|
||||
topic_prefix: helloworld
|
||||
log_topic: helloworld/hi
|
||||
birth_message:
|
||||
will_message:
|
||||
shutdown_message:
|
||||
topic: topic/to/send/to
|
||||
payload: hi
|
||||
qos: 2
|
||||
retain: True
|
||||
keepalive: 60s
|
||||
reboot_timeout: 60s
|
||||
on_message:
|
||||
- topic: my/custom/topic
|
||||
qos: 0
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Got message %s", x.c_str());
|
||||
- topic: livingroom/ota_mode
|
||||
then:
|
||||
- deep_sleep.prevent:
|
||||
id: deep_sleep_1
|
||||
- topic: livingroom/ota_mode
|
||||
then:
|
||||
- deep_sleep.enter:
|
||||
id: deep_sleep_1
|
||||
|
||||
i2c:
|
||||
sda: 21
|
||||
scl: 22
|
||||
scan: True
|
||||
frequency: 100kHz
|
||||
|
||||
spi:
|
||||
clk_pin: GPIO21
|
||||
mosi_pin: GPIO22
|
||||
miso_pin: GPIO23
|
||||
|
||||
uart:
|
||||
tx_pin: GPIO22
|
||||
rx_pin: GPIO23
|
||||
baud_rate: 115200
|
||||
|
||||
ota:
|
||||
safe_mode: True
|
||||
password: 'superlongpasswordthatnoonewillknow'
|
||||
port: 3286
|
||||
|
||||
logger:
|
||||
baud_rate: 0
|
||||
level: VERBOSE
|
||||
logs:
|
||||
mqtt.component: DEBUG
|
||||
mqtt.client: ERROR
|
||||
|
||||
web_server:
|
||||
port: 8080
|
||||
css_url: https://esphomelib.com/_static/webserver-v1.min.css
|
||||
js_url: https://esphomelib.com/_static/webserver-v1.min.js
|
||||
|
||||
power_supply:
|
||||
id: 'atx_power_supply'
|
||||
enable_time: 20ms
|
||||
keep_on_time: 10s
|
||||
pin:
|
||||
number: 13
|
||||
inverted: true
|
||||
|
||||
deep_sleep:
|
||||
run_duration: 20s
|
||||
run_cycles: 500
|
||||
sleep_duration: 50s
|
||||
wakeup_pin: GPIO39
|
||||
wakeup_pin_mode: INVERT_WAKEUP
|
||||
id: deep_sleep_1
|
||||
|
||||
ads1115:
|
||||
address: 0x48
|
||||
|
||||
dallas:
|
||||
pin: GPIO23
|
||||
|
||||
sensor:
|
||||
- platform: adc
|
||||
pin: A0
|
||||
name: "Living Room Brightness"
|
||||
update_interval: '1:01'
|
||||
attenuation: 2.5db
|
||||
unit_of_measurement: "°C"
|
||||
icon: "mdi:water-percent"
|
||||
accuracy_decimals: 5
|
||||
expire_after: 120s
|
||||
filters:
|
||||
- offset: 2.0
|
||||
- multiply: 1.2
|
||||
- filter_out: 42.0
|
||||
- filter_nan:
|
||||
- sliding_window_moving_average:
|
||||
window_size: 15
|
||||
send_every: 15
|
||||
- exponential_moving_average:
|
||||
alpha: 0.1
|
||||
send_every: 15
|
||||
- throttle: 1s
|
||||
- heartbeat: 5s
|
||||
- debounce: 0.1s
|
||||
- delta: 5.0
|
||||
- unique:
|
||||
- or:
|
||||
- throttle: 1s
|
||||
- delta: 5.0
|
||||
- lambda: return x * (9.0/5.0) + 32.0;
|
||||
on_value:
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Got value %f", x);
|
||||
id(my_sensor).push_new_value(42.0);
|
||||
ESP_LOGI("main", "Value of my sensor: %f", id(my_sensor).value);
|
||||
ESP_LOGI("main", "Raw Value of my sensor: %f", id(my_sensor).value);
|
||||
on_value_range:
|
||||
above: 5
|
||||
below: 10
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Got value range %f", x);
|
||||
on_raw_value:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Got raw value %f", x);
|
||||
- mqtt.publish:
|
||||
topic: some/topic
|
||||
payload: Hello
|
||||
qos: 2
|
||||
retain: True
|
||||
- platform: ads1115
|
||||
multiplexer: 'A0_A1'
|
||||
gain: 1.024
|
||||
id: my_sensor
|
||||
filters:
|
||||
state_topic: hi/me
|
||||
retain: false
|
||||
availability:
|
||||
- platform: bh1750
|
||||
name: "Living Room Brightness 3"
|
||||
internal: true
|
||||
address: 0x23
|
||||
resolution: 1.0
|
||||
update_interval: 30s
|
||||
retain: False
|
||||
availability:
|
||||
state_topic: livingroom/custom_state_topic
|
||||
- platform: bme280
|
||||
temperature:
|
||||
name: "Outside Temperature"
|
||||
oversampling: 16x
|
||||
pressure:
|
||||
name: "Outside Pressure"
|
||||
oversampling: none
|
||||
humidity:
|
||||
name: "Outside Humidity"
|
||||
oversampling: 8x
|
||||
address: 0x77
|
||||
iir_filter: 16x
|
||||
update_interval: 15s
|
||||
- platform: bme680
|
||||
temperature:
|
||||
name: "Outside Temperature"
|
||||
oversampling: 16x
|
||||
pressure:
|
||||
name: "Outside Pressure"
|
||||
humidity:
|
||||
name: "Outside Humidity"
|
||||
gas_resistance:
|
||||
name: "Outside Gas Sensor"
|
||||
address: 0x77
|
||||
heater:
|
||||
temperature: 320
|
||||
duration: 150ms
|
||||
update_interval: 15s
|
||||
- platform: bmp085
|
||||
temperature:
|
||||
name: "Outside Temperature"
|
||||
pressure:
|
||||
name: "Outside Pressure"
|
||||
filters:
|
||||
- lambda: >-
|
||||
return x / powf(1.0 - (x / 44330.0), 5.255);
|
||||
update_interval: 15s
|
||||
- platform: bmp280
|
||||
temperature:
|
||||
name: "Outside Temperature"
|
||||
oversampling: 16x
|
||||
pressure:
|
||||
name: "Outside Pressure"
|
||||
address: 0x77
|
||||
update_interval: 15s
|
||||
iir_filter: 16x
|
||||
- platform: dallas
|
||||
address: 0x1C0000031EDD2A28
|
||||
name: "Living Room Temperature"
|
||||
resolution: 9
|
||||
- platform: dallas
|
||||
index: 1
|
||||
name: "Living Room Temperature 2"
|
||||
- platform: dht
|
||||
pin: GPIO26
|
||||
temperature:
|
||||
name: "Living Room Temperature 3"
|
||||
humidity:
|
||||
name: "Living Room Humidity 3"
|
||||
model: AM2302
|
||||
update_interval: 15s
|
||||
- platform: dht12
|
||||
temperature:
|
||||
name: "Living Room Temperature 4"
|
||||
humidity:
|
||||
name: "Living Room Humidity 4"
|
||||
update_interval: 15s
|
||||
- platform: duty_cycle
|
||||
pin: GPIO25
|
||||
name: Duty Cycle Sensor
|
||||
- platform: esp32_hall
|
||||
name: "ESP32 Hall Sensor"
|
||||
update_interval: 15s
|
||||
- platform: hdc1080
|
||||
temperature:
|
||||
name: "Living Room Temperature 5"
|
||||
humidity:
|
||||
name: "Living Room Pressure 5"
|
||||
update_interval: 15s
|
||||
- platform: hlw8012
|
||||
sel_pin: 5
|
||||
cf_pin: 14
|
||||
cf1_pin: 13
|
||||
current:
|
||||
name: "HLW8012 Current"
|
||||
voltage:
|
||||
name: "HLW8012 Voltage"
|
||||
power:
|
||||
name: "HLW8012 Power"
|
||||
update_interval: 15s
|
||||
current_resistor: 0.001 ohm
|
||||
voltage_divider: 2351
|
||||
change_mode_every: 16
|
||||
- platform: hmc5883l
|
||||
address: 0x68
|
||||
field_strength_x:
|
||||
name: "HMC5883L Field Strength X"
|
||||
field_strength_y:
|
||||
name: "HMC5883L Field Strength Y"
|
||||
field_strength_z:
|
||||
name: "HMC5883L Field Strength Z"
|
||||
heading:
|
||||
name: "HMC5883L Heading"
|
||||
range: 130uT
|
||||
update_interval: 15s
|
||||
- platform: hx711
|
||||
name: "HX711 Value"
|
||||
dout_pin: GPIO23
|
||||
clk_pin: GPIO24
|
||||
gain: 128
|
||||
update_interval: 15s
|
||||
- platform: ina219
|
||||
address: 0x40
|
||||
shunt_resistance: 0.1 ohm
|
||||
current:
|
||||
name: "INA219 Current"
|
||||
power:
|
||||
name: "INA219 Power"
|
||||
bus_voltage:
|
||||
name: "INA219 Bus Voltage"
|
||||
shunt_voltage:
|
||||
name: "INA219 Shunt Voltage"
|
||||
max_voltage: 32.0V
|
||||
max_current: 3.2A
|
||||
update_interval: 15s
|
||||
- platform: ina3221
|
||||
address: 0x40
|
||||
channel_1:
|
||||
shunt_resistance: 0.1 ohm
|
||||
current:
|
||||
name: "INA3221 Channel 1 Current"
|
||||
power:
|
||||
name: "INA3221 Channel 1 Power"
|
||||
bus_voltage:
|
||||
name: "INA3221 Channel 1 Bus Voltage"
|
||||
shunt_voltage:
|
||||
name: "INA3221 Channel 1 Shunt Voltage"
|
||||
update_interval: 15s
|
||||
- platform: htu21d
|
||||
temperature:
|
||||
name: "Living Room Temperature 6"
|
||||
humidity:
|
||||
name: "Living Room Humidity 6"
|
||||
update_interval: 15s
|
||||
- platform: max6675
|
||||
name: "Living Room Temperature"
|
||||
cs_pin: GPIO23
|
||||
update_interval: 15s
|
||||
- platform: mhz19
|
||||
co2:
|
||||
name: "MH-Z19 CO2 Value"
|
||||
temperature:
|
||||
name: "MH-Z19 Temperature"
|
||||
update_interval: 15s
|
||||
- platform: mpu6050
|
||||
address: 0x68
|
||||
accel_x:
|
||||
name: "MPU6050 Accel X"
|
||||
accel_y:
|
||||
name: "MPU6050 Accel Y"
|
||||
accel_z:
|
||||
name: "MPU6050 Accel z"
|
||||
gyro_x:
|
||||
name: "MPU6050 Gyro X"
|
||||
gyro_y:
|
||||
name: "MPU6050 Gyro Y"
|
||||
gyro_z:
|
||||
name: "MPU6050 Gyro z"
|
||||
temperature:
|
||||
name: "MPU6050 Temperature"
|
||||
- platform: ms5611
|
||||
temperature:
|
||||
name: "Outside Temperature"
|
||||
pressure:
|
||||
name: "Outside Pressure"
|
||||
address: 0x77
|
||||
update_interval: 15s
|
||||
- platform: pulse_counter
|
||||
name: "Pulse Counter"
|
||||
pin: GPIO12
|
||||
count_mode:
|
||||
rising_edge: INCREMENT
|
||||
falling_edge: DECREMENT
|
||||
internal_filter: 13us
|
||||
update_interval: 15s
|
||||
- platform: rotary_encoder
|
||||
name: "Rotary Encoder"
|
||||
pin_a: GPIO23
|
||||
pin_b: GPIO24
|
||||
pin_reset: GPIO25
|
||||
filters:
|
||||
- or:
|
||||
- debounce: 0.1s
|
||||
- delta: 10
|
||||
- platform: sht3xd
|
||||
temperature:
|
||||
name: "Living Room Temperature 8"
|
||||
humidity:
|
||||
name: "Living Room Humidity 8"
|
||||
address: 0x44
|
||||
update_interval: 15s
|
||||
- platform: template
|
||||
name: "Template Sensor"
|
||||
lambda: >-
|
||||
if (id(ultrasonic_sensor1).value > 1) {
|
||||
return 42.0;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
update_interval: 15s
|
||||
- platform: tsl2561
|
||||
name: "TSL2561 Ambient Light"
|
||||
address: 0x39
|
||||
update_interval: 15s
|
||||
is_cs_package: true
|
||||
integration_time: 402ms
|
||||
gain: 16x
|
||||
- platform: ultrasonic
|
||||
trigger_pin: GPIO24
|
||||
echo_pin:
|
||||
number: GPIO23
|
||||
inverted: true
|
||||
name: "Ultrasonic Sensor"
|
||||
timeout_meter: 5.5
|
||||
id: ultrasonic_sensor1
|
||||
- platform: uptime
|
||||
name: Uptime Sensor
|
||||
- platform: wifi_signal
|
||||
name: "WiFi Signal Sensor"
|
||||
update_interval: 15s
|
||||
|
||||
|
||||
esp32_touch:
|
||||
setup_mode: False
|
||||
iir_filter: 10ms
|
||||
sleep_duration: 27ms
|
||||
measurement_duration: 8ms
|
||||
low_voltage_reference: 0.5V
|
||||
high_voltage_reference: 2.7V
|
||||
voltage_attenuation: 1.5V
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin: GPIO9
|
||||
name: "Living Room Window"
|
||||
device_class: window
|
||||
filters:
|
||||
- invert:
|
||||
- delayed_on: 40ms
|
||||
- delayed_off: 40ms
|
||||
- heartbeat: 1s
|
||||
on_press:
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Pressed");
|
||||
on_release:
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Released");
|
||||
on_click:
|
||||
- min_length: 50ms
|
||||
max_length: 350ms
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Clicked");
|
||||
- then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Clicked");
|
||||
on_double_click:
|
||||
- min_length: 50ms
|
||||
max_length: 350ms
|
||||
then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Double Clicked");
|
||||
- then:
|
||||
- lambda: >-
|
||||
ESP_LOGD("main", "Double Clicked");
|
||||
id: binary_sensor1
|
||||
- platform: status
|
||||
name: "Living Room Status"
|
||||
- platform: esp32_touch
|
||||
name: "ESP32 Touch Pad GPIO27"
|
||||
pin: GPIO27
|
||||
threshold: 1000
|
||||
- platform: nextion
|
||||
page_id: 0
|
||||
component_id: 2
|
||||
name: "Nextion Component 2 Touch"
|
||||
- platform: template
|
||||
name: "Garage Door Open"
|
||||
lambda: >-
|
||||
if (isnan(id(my_sensor).value)) {
|
||||
// isnan checks if the ultrasonic sensor echo
|
||||
// has timed out, resulting in a NaN (not a number) state
|
||||
// in that case, return {} to indicate that we don't know.
|
||||
return {};
|
||||
} else if (id(my_sensor).value > 30) {
|
||||
// Garage Door is open.
|
||||
return true;
|
||||
} else {
|
||||
// Garage Door is closed.
|
||||
return false;
|
||||
}
|
||||
- platform: pn532
|
||||
uid: 74-10-37-94
|
||||
name: "PN532 NFC Tag"
|
||||
- platform: rdm6300
|
||||
uid: 7616525
|
||||
name: "RDM6300 NFC Tag"
|
||||
- platform: gpio
|
||||
name: "PCF binary sensor"
|
||||
pin:
|
||||
pcf8574: pcf8574_hub
|
||||
number: 1
|
||||
mode: INPUT
|
||||
inverted: True
|
||||
|
||||
pca9685:
|
||||
frequency: 500
|
||||
address: 0x0
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
pin: GPIO26
|
||||
id: gpio_26
|
||||
power_supply: atx_power_supply
|
||||
inverted: False
|
||||
- platform: ledc
|
||||
pin: 19
|
||||
id: gpio_19
|
||||
frequency: 1500Hz
|
||||
bit_depth: 8
|
||||
channel: 14
|
||||
max_power: 0.5
|
||||
- platform: pca9685
|
||||
id: pca_0
|
||||
channel: 0
|
||||
- platform: pca9685
|
||||
id: pca_1
|
||||
channel: 1
|
||||
- platform: pca9685
|
||||
id: pca_2
|
||||
channel: 2
|
||||
- platform: pca9685
|
||||
id: pca_3
|
||||
channel: 3
|
||||
- platform: pca9685
|
||||
id: pca_4
|
||||
channel: 4
|
||||
- platform: pca9685
|
||||
id: pca_5
|
||||
channel: 5
|
||||
- platform: pca9685
|
||||
id: pca_6
|
||||
channel: 6
|
||||
- platform: pca9685
|
||||
id: pca_7
|
||||
channel: 7
|
||||
- platform: gpio
|
||||
id: id2
|
||||
pin:
|
||||
pcf8574: pcf8574_hub
|
||||
number: 0
|
||||
mode: OUTPUT
|
||||
inverted: False
|
||||
|
||||
light:
|
||||
- platform: binary
|
||||
name: "Desk Lamp"
|
||||
output: gpio_26
|
||||
effects:
|
||||
- strobe:
|
||||
- strobe:
|
||||
name: "My Strobe"
|
||||
colors:
|
||||
- state: True
|
||||
duration: 250ms
|
||||
- state: False
|
||||
duration: 250ms
|
||||
- platform: monochromatic
|
||||
name: "Kitchen Lights"
|
||||
id: kitchen
|
||||
output: gpio_19
|
||||
gamma_correct: 2.8
|
||||
default_transition_length: 2s
|
||||
effects:
|
||||
- strobe:
|
||||
- flicker:
|
||||
- flicker:
|
||||
name: "My Flicker"
|
||||
alpha: 98%
|
||||
intensity: 1.5%
|
||||
- lambda:
|
||||
name: My Custom Effect
|
||||
update_interval: 1s
|
||||
lambda: |-
|
||||
static int state = 0;
|
||||
state += 1;
|
||||
if (state == 4)
|
||||
state = 0;
|
||||
- platform: rgb
|
||||
name: "Living Room Lights"
|
||||
red: pca_0
|
||||
green: pca_1
|
||||
blue: pca_2
|
||||
- platform: rgbw
|
||||
name: "Living Room Lights 2"
|
||||
red: pca_3
|
||||
green: pca_4
|
||||
blue: pca_5
|
||||
white: pca_6
|
||||
- platform: rgbww
|
||||
name: "Living Room Lights 2"
|
||||
red: pca_3
|
||||
green: pca_4
|
||||
blue: pca_5
|
||||
cold_white: pca_6
|
||||
warm_white: pca_6
|
||||
cold_white_color_temperature: 153 mireds
|
||||
warm_white_color_temperature: 500 mireds
|
||||
- platform: cwww
|
||||
name: "Living Room Lights 2"
|
||||
cold_white: pca_6
|
||||
warm_white: pca_6
|
||||
cold_white_color_temperature: 153 mireds
|
||||
warm_white_color_temperature: 500 mireds
|
||||
- platform: fastled_clockless
|
||||
chipset: WS2811
|
||||
pin: GPIO23
|
||||
num_leds: 60
|
||||
rgb_order: BRG
|
||||
max_refresh_rate: 20ms
|
||||
power_supply: atx_power_supply
|
||||
name: "FastLED WS2811 Light"
|
||||
effects:
|
||||
- fastled_color_wipe:
|
||||
- fastled_color_wipe:
|
||||
name: Color Wipe Effect With Custom Values
|
||||
colors:
|
||||
- red: 100%
|
||||
green: 100%
|
||||
blue: 100%
|
||||
num_leds: 1
|
||||
- red: 0%
|
||||
green: 0%
|
||||
blue: 0%
|
||||
num_leds: 1
|
||||
add_led_interval: 100ms
|
||||
reverse: False
|
||||
- fastled_scan:
|
||||
- fastled_scan:
|
||||
name: Scan Effect With Custom Values
|
||||
move_interval: 100ms
|
||||
- fastled_twinkle:
|
||||
- fastled_twinkle:
|
||||
name: Twinkle Effect With Custom Values
|
||||
twinkle_probability: 5%
|
||||
progress_interval: 4ms
|
||||
- fastled_random_twinkle:
|
||||
- fastled_random_twinkle:
|
||||
name: Random Twinkle Effect With Custom Values
|
||||
twinkle_probability: 5%
|
||||
progress_interval: 32ms
|
||||
- fastled_fireworks:
|
||||
- fastled_fireworks:
|
||||
name: Fireworks Effect With Custom Values
|
||||
update_interval: 32ms
|
||||
spark_probability: 10%
|
||||
use_random_color: false
|
||||
fade_out_rate: 120
|
||||
- fastled_flicker:
|
||||
- fastled_flicker:
|
||||
name: Flicker Effect With Custom Values
|
||||
update_interval: 16ms
|
||||
intensity: 5%
|
||||
- platform: fastled_spi
|
||||
chipset: WS2801
|
||||
data_pin: GPIO23
|
||||
clock_pin: GPIO22
|
||||
num_leds: 60
|
||||
rgb_order: BRG
|
||||
name: "FastLED SPI Light"
|
||||
|
||||
remote_transmitter:
|
||||
- pin: 32
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
pin: GPIO25
|
||||
name: "Living Room Dehumidifier"
|
||||
icon: "mdi:restart"
|
||||
inverted: True
|
||||
command_topic: custom_command_topic
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
nec:
|
||||
address: 0x4242
|
||||
command: 0x8484
|
||||
repeat: 25
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
lg:
|
||||
data: 4294967295
|
||||
nbits: 28
|
||||
repeat: 25
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
sony:
|
||||
data: 0xABCDEF
|
||||
nbits: 12
|
||||
repeat: 25
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
panasonic:
|
||||
address: 0x4004
|
||||
command: 0x1000BCD
|
||||
repeat: 25
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
rc_switch_raw:
|
||||
code: '001010011001111101011011'
|
||||
protocol: 1
|
||||
repeat: 25
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
rc_switch_type_a:
|
||||
group: '11001'
|
||||
device: '01000'
|
||||
state: True
|
||||
protocol:
|
||||
pulse_length: 175
|
||||
sync: [1, 31]
|
||||
zero: [1, 3]
|
||||
one: [3, 1]
|
||||
inverted: False
|
||||
repeat: 25
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
rc_switch_type_b:
|
||||
address: 4
|
||||
channel: 2
|
||||
state: True
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
rc_switch_type_c:
|
||||
family: 'a'
|
||||
group: 1
|
||||
device: 2
|
||||
state: True
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
id: living_room_lights_on
|
||||
rc_switch_type_d:
|
||||
group: 'a'
|
||||
device: 2
|
||||
state: True
|
||||
- platform: remote_transmitter
|
||||
name: "Panasonic TV Off"
|
||||
id: living_room_lights_off
|
||||
raw:
|
||||
carrier_frequency: 35kHz
|
||||
data:
|
||||
- 1000
|
||||
- -1000
|
||||
- platform: template
|
||||
name: Living Room Lights
|
||||
optimistic: True
|
||||
turn_on_action:
|
||||
- switch.turn_on: living_room_lights_on
|
||||
turn_off_action:
|
||||
- switch.turn_on: living_room_lights_off
|
||||
- platform: restart
|
||||
name: "Living Room Restart"
|
||||
- platform: shutdown
|
||||
name: "Living Room Shutdown"
|
||||
- platform: output
|
||||
name: "Generic Output"
|
||||
output: pca_6
|
||||
- platform: template
|
||||
name: "Template Switch"
|
||||
id: my_switch
|
||||
lambda: |-
|
||||
if (id(binary_sensor1).value) {
|
||||
return true;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
id(my_switch).publish_state(false);
|
||||
id(my_switch).publish_state(true);
|
||||
if (id(my_switch).value) {
|
||||
// Switch is ON, do something here
|
||||
id(my_switch).write_state(false);
|
||||
id(my_switch).write_state(true);
|
||||
} else {
|
||||
// Switch is OFF, do something else here
|
||||
}
|
||||
optimistic: true
|
||||
- platform: uart
|
||||
name: "UART String Output"
|
||||
data: 'DataToSend'
|
||||
- platform: uart
|
||||
name: "UART Bytes Output"
|
||||
data: [0xDE, 0xAD, 0xBE, 0xEF]
|
||||
|
||||
fan:
|
||||
- platform: binary
|
||||
output: gpio_26
|
||||
name: "Living Room Fan 1"
|
||||
- platform: speed
|
||||
output: pca_6
|
||||
name: "Living Room Fan 2"
|
||||
speed:
|
||||
low: 0.45
|
||||
medium: 0.75
|
||||
high: 1.0
|
||||
|
||||
display:
|
||||
- platform: lcd_gpio
|
||||
dimensions: 18x4
|
||||
data_pins:
|
||||
- GPIO19
|
||||
- GPIO20
|
||||
- GPIO21
|
||||
- GPIO22
|
||||
enable_pin: GPIO23
|
||||
rs_pin: GPIO24
|
||||
lambda: |-
|
||||
it.print("Hello World!");
|
||||
- platform: lcd_pcf8574
|
||||
dimensions: 18x4
|
||||
address: 0x3F
|
||||
lambda: |-
|
||||
it.print("Hello World!");
|
||||
- platform: max7219
|
||||
cs_pin: GPIO23
|
||||
num_chips: 1
|
||||
lambda: |-
|
||||
it.print("01234567");
|
||||
- platform: nextion
|
||||
lambda: |-
|
||||
it.set_component_value("gauge", 50);
|
||||
it.set_component_text("textview", "Hello World!");
|
||||
- platform: ssd1306_i2c
|
||||
model: "SSD1306 128x64"
|
||||
reset_pin: GPIO23
|
||||
address: 0x3C
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
- platform: ssd1306_spi
|
||||
model: "SSD1306 128x64"
|
||||
cs_pin: GPIO23
|
||||
dc_pin: GPIO23
|
||||
reset_pin: GPIO23
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
- platform: waveshare_epaper
|
||||
cs_pin: GPIO23
|
||||
dc_pin: GPIO23
|
||||
busy_pin: GPIO23
|
||||
reset_pin: GPIO23
|
||||
model: 2.90in
|
||||
full_update_every: 30
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
|
||||
remote_receiver:
|
||||
pin: GPIO32
|
||||
dump: all
|
||||
|
||||
status_led:
|
||||
pin: GPIO2
|
||||
|
||||
pn532:
|
||||
cs_pin: GPIO23
|
||||
update_interval: 1s
|
||||
|
||||
rdm6300:
|
||||
|
||||
time:
|
||||
- platform: sntp
|
||||
id: sntp_time
|
||||
servers:
|
||||
- 0.pool.ntp.org
|
||||
- 1.pool.ntp.org
|
||||
- 2.pool.ntp.org
|
||||
on_time:
|
||||
cron: '/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI'
|
||||
then:
|
||||
- lambda: 'ESP_LOGD("main", "time");'
|
||||
|
||||
cover:
|
||||
- platform: template
|
||||
name: "Template Cover"
|
||||
lambda: >-
|
||||
if (id(binary_sensor1).value) {
|
||||
return cover::COVER_OPEN;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
optimistic: true
|
||||
|
||||
debug:
|
||||
|
||||
pcf8574:
|
||||
- id: 'pcf8574_hub'
|
||||
address: 0x21
|
||||
pcf8575: False
|
||||
102
tests/test2.yaml
Normal file
102
tests/test2.yaml
Normal file
@@ -0,0 +1,102 @@
|
||||
esphomeyaml:
|
||||
name: test1
|
||||
platform: ESP32
|
||||
board: nodemcu-32s
|
||||
# Use latest upstream esphomelib git version.
|
||||
esphomelib_version: dev
|
||||
# Use this for testing while developing:
|
||||
# esphomelib_version:
|
||||
# local: ~/path/to/esphomelib
|
||||
use_custom_code: true
|
||||
build_path: build/test2
|
||||
|
||||
wifi:
|
||||
ssid: 'MySSID'
|
||||
password: 'password1'
|
||||
reboot_timeout: 120s
|
||||
|
||||
mqtt:
|
||||
broker: '192.168.178.84'
|
||||
port: 1883
|
||||
username: 'debug'
|
||||
password: 'debug'
|
||||
|
||||
i2c:
|
||||
sda: 21
|
||||
scl: 22
|
||||
scan: False
|
||||
|
||||
spi:
|
||||
clk_pin: GPIO21
|
||||
mosi_pin: GPIO22
|
||||
miso_pin: GPIO23
|
||||
|
||||
uart:
|
||||
tx_pin: GPIO22
|
||||
rx_pin: GPIO23
|
||||
baud_rate: 115200
|
||||
|
||||
ota:
|
||||
safe_mode: True
|
||||
port: 3286
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
web_server:
|
||||
|
||||
deep_sleep:
|
||||
run_duration: 20s
|
||||
sleep_duration: 50s
|
||||
|
||||
sensor:
|
||||
- platform: ble_rssi
|
||||
mac_address: AC:37:43:77:5F:4C
|
||||
name: "BLE Google Home Mini RSSI value"
|
||||
- platform: xiaomi_miflora
|
||||
mac_address: 94:2B:FF:5C:91:61
|
||||
temperature:
|
||||
name: "Xiaomi MiFlora Temperature"
|
||||
moisture:
|
||||
name: "Xiaomi MiFlora Moisture"
|
||||
illuminance:
|
||||
name: "Xiaomi MiFlora Illuminance"
|
||||
conductivity:
|
||||
name: "Xiaomi MiFlora Soil Conductivity"
|
||||
battery_level:
|
||||
name: "Xiaomi MiFlora Battery Level"
|
||||
- platform: xiaomi_mijia
|
||||
mac_address: 7A:80:8E:19:36:BA
|
||||
temperature:
|
||||
name: "Xiaomi MiJia Temperature"
|
||||
humidity:
|
||||
name: "Xiaomi MiJia Humidity"
|
||||
battery_level:
|
||||
name: "Xiaomi MiJia Battery Level"
|
||||
|
||||
|
||||
esp32_touch:
|
||||
setup_mode: True
|
||||
|
||||
binary_sensor:
|
||||
- platform: esp32_ble_tracker
|
||||
mac_address: AC:37:43:77:5F:4C
|
||||
name: "ESP32 BLE Tracker Google Home Mini"
|
||||
- platform: esp32_touch
|
||||
name: "ESP32 Touch Pad GPIO27"
|
||||
pin: GPIO27
|
||||
threshold: 1000
|
||||
|
||||
remote_receiver:
|
||||
pin: GPIO32
|
||||
dump: []
|
||||
|
||||
esp32_ble_tracker:
|
||||
scan_interval: 300s
|
||||
|
||||
esp32_ble_beacon:
|
||||
type: iBeacon
|
||||
uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98'
|
||||
|
||||
status_led:
|
||||
pin: GPIO2
|
||||
Reference in New Issue
Block a user