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

Compare commits

...

52 Commits

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

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

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

* Don't break flashing for older installations.
2018-06-08 11:34:06 +02:00
Johan Bloemberg
a04438e924 Make sure logs after upload works when using explicit OTA. (#42) 2018-06-08 10:41:01 +02:00
Otto Winter
e063f2aaea Fix hmac with non-ASCII passwords 2018-06-07 21:52:41 +02:00
Otto Winter
7b630bfb8b Fix HassIO edge config 2018-06-07 21:22:11 +02:00
Otto Winter
ec3366cce0 Dashboard authentication 2018-06-07 20:47:06 +02:00
Johan Bloemberg
135117714b Support specifying hostname/ip as --upload-port (#36) 2018-06-07 20:36:00 +02:00
Brandon Davidson
91e6304505 Add WiFi Signal Strength sensor (#35) 2018-06-07 19:29:18 +02:00
Otto Winter
361a9da868 on_boot and on_shutdown triggers 2018-06-07 17:06:50 +02:00
Otto Winter
31d7656c07 Lint 2018-06-07 17:04:33 +02:00
Otto Winter
d1a7751dc9 SHT3X-D Remove Accuracy Option 2018-06-07 11:27:04 +02:00
Otto Winter
e47bcb9abb Bump version to 1.6.2 2018-06-06 21:01:20 +02:00
Otto Winter
30b94f06b3 Add verbose mode for espota 2018-06-06 11:12:42 +02:00
Otto Winter
19dfdb77eb Fix MQTT logs 2018-06-06 11:12:29 +02:00
Otto Winter
b6e7ad3589 Fix OTA port not being set 2018-06-06 11:12:14 +02:00
Otto Winter
1267680379 Improve error messages 2018-06-06 10:27:59 +02:00
Otto Winter
b5f6b32fad Fix dallas resolution 2018-06-06 10:27:50 +02:00
Otto Winter
7068808d4f Fix optional returns from templates 2018-06-06 09:48:59 +02:00
Otto Winter
c82a44d541 Fix ESP32 touch sleep duration conversion 2018-06-06 09:30:14 +02:00
Otto Winter
e650473682 Fix ESP32 touch ID issue 2018-06-06 09:26:56 +02:00
Otto Winter
2ee0d4242d Make Automation output readable again 2018-06-06 09:18:39 +02:00
Otto Winter
b2aecf29dc Fix ESP32 BLE 2018-06-06 09:18:21 +02:00
Otto Winter
081c2f4e07 Fix SHT3xD with manual update interval 2018-06-06 09:06:14 +02:00
Otto Winter
0c77228421 Improve wrong pin error message 2018-06-06 08:55:53 +02:00
Otto Winter
8a509c6551 Fix MQTT publish 2018-06-06 08:35:31 +02:00
Otto Winter
d249820bcd Fix MQTT availability option 2018-06-06 08:35:23 +02:00
Otto Winter
f39cf52eae Fix WiFi domain option 2018-06-06 08:13:05 +02:00
Otto Winter
63fb252b46 Fix web server CSS/JS URL 2018-06-06 08:12:51 +02:00
Otto Winter
2f98adca49 Fix OrFilter 2018-06-06 08:12:39 +02:00
Otto Winter
084fc00517 Fix MQTT messages 2018-06-06 08:12:30 +02:00
Otto Winter
abeac23abd Fix i2c frequency 2018-06-06 08:12:17 +02:00
Otto Winter
7264e3a4bf Fix ultrasonic typo Fixes #62 2018-06-06 07:09:03 +02:00
Otto Winter
16eeb3af31 Attempt to solve UnicodeEncodeError in HassIO when running on RPi 2018-06-05 23:19:46 +02:00
Otto Winter
b799d2df7f Adjust serial port fetch interval 2018-06-05 23:19:28 +02:00
Otto Winter
11d55fec4f Better OSError handling for YAML parser 2018-06-05 23:18:56 +02:00
Otto Winter
923a5990c7 Fix erroneous validation. Fixes OttoWinter/esphomelib#59 2018-06-05 22:32:34 +02:00
Otto Winter
a0a615c335 Deep Sleep wakeup pin mode 2018-06-05 22:31:39 +02:00
Otto Winter
e9ced0cc3f Fix lint 2018-06-04 20:47:29 +02:00
Otto Winter
1a92381994 Update Dockerfile 2018-06-04 20:47:23 +02:00
Otto Winter
a07a7a87a2 Fix filter out nan filter 2018-06-04 20:47:15 +02:00
101 changed files with 1739 additions and 602 deletions

View File

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

131
.gitlab-ci.yml Normal file
View File

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

20
docker/Dockerfile.aarch64 Normal file
View File

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

19
docker/Dockerfile.amd64 Normal file
View File

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

20
docker/Dockerfile.armhf Normal file
View File

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

32
docker/Dockerfile.builder Normal file
View File

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

19
docker/Dockerfile.i386 Normal file
View File

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

4
docker/Dockerfile.lint Normal file
View File

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

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

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

View File

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

View File

@@ -1,12 +1,12 @@
; This file allows the docker build file to install the required platformio
; 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

View File

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

View File

@@ -21,9 +21,13 @@
"map": [
"config:rw"
],
"options": {},
"options": {
"password": ""
},
"schema": {
"password": "str?"
},
"environment": {
"ESPHOMEYAML_OTA_HOST_PORT": "6053"
},
"schema": {}
}
}

View File

@@ -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; exit 0; \
else \
echo \"\$(head -8 /pio/platformio.ini)\" >/pio/platformio.ini; \
platformio run -e espressif8266 -d /pio; exit 0; \
fi"
# Install latest esphomeyaml from git
RUN pip install --no-cache-dir \
esphomeyaml==${BUILD_VERSION}
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]

View File

@@ -9,8 +9,9 @@ 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.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_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
@@ -25,7 +26,8 @@ def get_name(config):
def get_base_path(config):
return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config))
build_path = config[CONF_ESPHOMEYAML].get(CONF_BUILD_PATH, get_name(config))
return os.path.join(os.path.dirname(core.CONFIG_PATH), build_path)
def get_serial_ports():
@@ -102,12 +104,15 @@ def run_miniterm(config, port, escape=False):
with serial.Serial(port, baudrate=baud_rate) as ser:
while True:
line = ser.readline()
line = ser.readline().replace('\r', '').replace('\n', '')
time = datetime.now().time().strftime('[%H:%M:%S]')
message = time + line.decode('unicode-escape').replace('\r', '').replace('\n', '')
message = time + line
if escape:
message = message.replace('\033', '\\033').encode('ascii', 'replace')
print(message)
message = message.replace('\033', '\\033')
try:
print(message)
except UnicodeEncodeError:
print(message.encode('ascii', 'backslashreplace'))
def write_cpp(config):
@@ -138,9 +143,7 @@ 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)
writer.write_platformio_project(config, get_base_path(config))
code_s = indent('\n'.join(line.rstrip() for line in all_code))
cpp_path = os.path.join(get_base_path(config), 'src', 'main.cpp')
@@ -179,7 +182,10 @@ def upload_using_esptool(config, port):
def upload_program(config, args, port):
_LOGGER.info("Uploading binary...")
if port != 'OTA':
# if upload is to a serial port use platformio, otherwise assume ota
serial_port = port.startswith('/') or port.startswith('COM')
if port != 'OTA' and serial_port:
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy:
return upload_using_esptool(config, port)
command = ['platformio', 'run', '-d', get_base_path(config),
@@ -192,7 +198,12 @@ 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
@@ -205,11 +216,14 @@ def upload_program(config, args, port):
espota_args = ['espota.py', '--debug', '--progress', '-i', host,
'-p', str(ota.get_port(config)), '-f', bin_file,
'-a', ota.get_auth(config), '-P', str(host_port)]
if args.verbose:
espota_args.append('-d')
return espota.main(espota_args)
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,
@@ -390,7 +404,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.',
@@ -423,6 +437,8 @@ 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='')
return parser.parse_args(argv[1:])

View File

@@ -132,6 +132,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),
@@ -205,7 +221,7 @@ def build_action(config, arg_type):
yield Pvariable(config[CONF_ACTION_ID], rhs, type=type)
elif CONF_MQTT_PUBLISH in config:
conf = config[CONF_MQTT_PUBLISH]
rhs = App.Pget_mqtt_client().Pmake_publish_action()
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
@@ -387,22 +403,23 @@ def build_actions(config, arg_type):
for action in build_action(conf, arg_type):
yield None
actions.append(action)
yield ArrayInitializer(*actions)
yield ArrayInitializer(*actions, multiline=False)
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):

View File

@@ -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": {}
}

View File

@@ -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
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,91 @@ 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
MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent
FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA]
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_INVERT): None,
vol.Optional(CONF_DELAYED_ON): cv.positive_time_period_milliseconds,
vol.Optional(CONF_DELAYED_OFF): cv.positive_time_period_milliseconds,
vol.Optional(CONF_LAMBDA): cv.lambda_,
}, cv.has_exactly_one_key(*FILTER_KEYS))])
BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
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_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()

View File

@@ -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(CONF_ESP32_BLE_ID):
yield
addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts]
rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False))
binary_sensor.register_binary_sensor(rhs, config)
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

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

View File

@@ -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):

View File

@@ -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)
vol.Required(CONF_PIN): pins.gpio_input_pin_schema
}))
def to_code(config):

View File

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

View File

@@ -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):

View File

@@ -3,19 +3,20 @@ 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
from esphomeyaml.helpers import App, Application, process_lambda, variable, optional, bool_
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):
template_ = None
for template_ in process_lambda(config[CONF_LAMBDA], []):
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)

View File

@@ -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)

View File

@@ -5,18 +5,18 @@ from esphomeyaml import automation
from esphomeyaml.components import cover
from esphomeyaml.const import CONF_CLOSE_ACTION, CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, \
CONF_OPEN_ACTION, CONF_STOP_ACTION, CONF_OPTIMISTIC
from esphomeyaml.helpers import App, Application, NoArg, add, process_lambda, variable
from esphomeyaml.helpers import App, Application, NoArg, add, process_lambda, variable, optional
MakeTemplateCover = Application.MakeTemplateCover
PLATFORM_SCHEMA = vol.All(cover.PLATFORM_SCHEMA.extend({
PLATFORM_SCHEMA = 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):
@@ -25,24 +25,19 @@ def to_code(config):
if CONF_LAMBDA in config:
template_ = None
for template_ in process_lambda(config[CONF_LAMBDA], []):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(cover.CoverState)):
yield
add(make.Ptemplate_.set_state_lambda(template_))
if CONF_OPEN_ACTION in config:
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]))

View File

@@ -16,11 +16,21 @@ def validate_pin_number(value):
DeepSleepComponent = esphomelib_ns.DeepSleepComponent
WAKEUP_PIN_MODES = {
'IGNORE': esphomelib_ns.WAKEUP_PIN_MODE_IGNORE,
'KEEP_AWAKE': esphomelib_ns.WAKEUP_PIN_MODE_KEEP_AWAKE,
'INVERT_WAKEUP': esphomelib_ns.WAKEUP_PIN_MODE_INVERT_WAKEUP,
}
CONF_WAKEUP_PIN_MODE = 'wakeup_pin_mode'
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(DeepSleepComponent),
vol.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
vol.Optional(CONF_WAKEUP_PIN): vol.All(cv.only_on_esp32, pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Optional(CONF_WAKEUP_PIN): vol.All(cv.only_on_esp32, pins.internal_gpio_input_pin_schema,
validate_pin_number),
vol.Optional(CONF_WAKEUP_PIN_MODE): vol.All(cv.only_on_esp32, vol.Upper,
cv.one_of(*WAKEUP_PIN_MODES)),
vol.Optional(CONF_RUN_CYCLES): cv.positive_int,
vol.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds,
})
@@ -36,6 +46,8 @@ def to_code(config):
for pin in gpio_input_pin_expression(config[CONF_WAKEUP_PIN]):
yield
add(deep_sleep.set_wakeup_pin(pin))
if CONF_WAKEUP_PIN_MODE in config:
add(deep_sleep.set_wakeup_pin_mode(WAKEUP_PIN_MODES[config[CONF_WAKEUP_PIN_MODE]]))
if CONF_RUN_CYCLES in config:
add(deep_sleep.set_run_cycles(config[CONF_RUN_CYCLES]))
if CONF_RUN_DURATION in config:

View File

@@ -1,24 +1,5 @@
import voluptuous as vol
from esphomeyaml import config_validation as cv
from esphomeyaml.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.")

View File

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

View File

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

View File

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

View File

@@ -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:

View File

@@ -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):

View File

@@ -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):

View File

@@ -12,9 +12,12 @@ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(I2CComponent),
vol.Required(CONF_SDA, default='SDA'): pins.input_output_pin,
vol.Required(CONF_SCL, default='SCL'): pins.input_output_pin,
vol.Optional(CONF_FREQUENCY): cv.positive_int,
vol.Optional(CONF_RECEIVE_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_FREQUENCY): vol.All(cv.frequency, vol.Range(min=0, min_included=False)),
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'

View File

@@ -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.")

View File

@@ -1,6 +1,6 @@
import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \
CONF_MQTT_ID
CONF_MQTT_ID, CONF_INTERNAL
from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
@@ -20,8 +20,12 @@ LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTJSONLightComponent),
})
LIGHT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(LIGHT_SCHEMA.schema)
def setup_light_core_(light_var, mqtt_var, config):
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:

View File

@@ -5,10 +5,10 @@ from esphomeyaml.components import light
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT
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)
}))
def to_code(config):

View File

@@ -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,7 @@ 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)
}), validate)
def to_code(config):

View File

@@ -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,7 @@ 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)
}))
def to_code(config):

View File

@@ -6,12 +6,12 @@ from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT
CONF_NAME, CONF_OUTPUT
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)
}))
def to_code(config):

View File

@@ -6,14 +6,14 @@ from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GA
CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED
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)
}))
def to_code(config):

View File

@@ -6,7 +6,7 @@ from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GA
CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE
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,7 @@ 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)
}))
def to_code(config):

View File

@@ -36,7 +36,7 @@ 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_TX_BUFFER_SIZE): cv.validate_bytes,
vol.Optional(CONF_LEVEL): is_log_level,
vol.Optional(CONF_LOGS): vol.Schema({
cv.string: is_log_level,

View File

@@ -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
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression, \
StructInitializer, \
TemplateArguments, add, esphomelib_ns, optional, std_string
@@ -16,7 +16,7 @@ from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression,
def validate_message_just_topic(value):
value = cv.publish_topic(value)
return {CONF_TOPIC: value}
return MQTT_MESSAGE_BASE({CONF_TOPIC: value})
MQTT_MESSAGE_BASE = vol.Schema({
@@ -71,10 +71,11 @@ CONFIG_SCHEMA = vol.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, 0): cv.mqtt_qos,
vol.Optional(CONF_QOS, default=0): cv.mqtt_qos,
})])
})
@@ -106,13 +107,13 @@ def to_code(config):
add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX]))
if CONF_BIRTH_MESSAGE in config:
birth_message = config[CONF_BIRTH_MESSAGE]
if birth_message is None:
if not birth_message:
add(mqtt.disable_birth_message())
else:
add(mqtt.set_birth_message(exp_mqtt_message(birth_message)))
if CONF_WILL_MESSAGE in config:
will_message = config[CONF_WILL_MESSAGE]
if will_message is None:
if not will_message:
add(mqtt.disable_last_will())
else:
add(mqtt.set_last_will(exp_mqtt_message(will_message)))
@@ -120,16 +121,18 @@ def to_code(config):
add(mqtt.set_client_id(config[CONF_CLIENT_ID]))
if CONF_LOG_TOPIC in config:
log_topic = config[CONF_LOG_TOPIC]
if log_topic is None:
if not log_topic:
add(mqtt.disable_log_message())
else:
add(mqtt.set_log_topic(exp_mqtt_message(log_topic)))
add(mqtt.set_log_message_template(exp_mqtt_message(log_topic)))
if CONF_SSL_FINGERPRINTS in config:
for fingerprint in config[CONF_SSL_FINGERPRINTS]:
arr = [RawExpression("0x{}".format(fingerprint[i:i + 2])) for i in range(0, 40, 2)]
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])

View File

@@ -29,6 +29,8 @@ def to_code(config):
if CONF_PASSWORD in config:
hash_ = hashlib.md5(config[CONF_PASSWORD].encode()).hexdigest()
add(ota.set_auth_password_hash(hash_))
if CONF_PORT in config:
add(ota.set_port(config[CONF_PORT]))
if config[CONF_SAFE_MODE]:
add(ota.start_safe_mode())

View File

@@ -14,14 +14,18 @@ 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')
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 +37,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'

View File

@@ -11,17 +11,17 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP8266]
def valid_pwm_pin(value):
if value[CONF_NUMBER] >= 16:
if value[CONF_NUMBER] > 16:
raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.")
return 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.GPIO_INTERNAL_OUTPUT_PIN_SCHEMA, valid_pwm_pin),
}).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
vol.Required(CONF_PIN): vol.All(pins.internal_gpio_output_pin_schema, valid_pwm_pin),
})
def to_code(config):

View File

@@ -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)
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
})
def to_code(config):

View File

@@ -15,19 +15,19 @@ def validate_frequency_bit_depth(obj):
bit_depth = obj.get(CONF_BIT_DEPTH, 12)
max_freq = APB_CLOCK_FREQ / (2**bit_depth)
if frequency > max_freq:
raise vol.Invalid('Maximum frequency for bit depth {} is {}'.format(bit_depth, max_freq))
raise vol.Invalid('Maximum frequency for bit depth {} is {}Hz'.format(bit_depth, max_freq))
return obj
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):

View File

@@ -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):

View File

@@ -9,7 +9,7 @@ PowerSupplyComponent = esphomelib_ns.PowerSupplyComponent
POWER_SUPPLY_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(PowerSupplyComponent),
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_ENABLE_TIME): cv.positive_time_period_milliseconds,
vol.Optional(CONF_KEEP_ON_TIME): cv.positive_time_period_milliseconds,
})

View File

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

View File

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

View File

@@ -4,12 +4,12 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import automation
from esphomeyaml.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:
@@ -100,7 +101,7 @@ def setup_filter(config):
elif CONF_FILTER_OUT in config:
yield FilterOutValueFilter.new(config[CONF_FILTER_OUT])
elif CONF_FILTER_NAN in config:
yield FilterOutNANFilter()
yield FilterOutNANFilter.new()
elif CONF_SLIDING_WINDOW_MOVING_AVERAGE in config:
conf = config[CONF_SLIDING_WINDOW_MOVING_AVERAGE]
yield SlidingWindowMovingAverageFilter.new(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY])
@@ -117,7 +118,10 @@ def setup_filter(config):
elif CONF_DELTA in config:
yield DeltaFilter.new(config[CONF_DELTA])
elif CONF_OR in config:
yield OrFilter.new(setup_filters(config[CONF_OR]))
filters = None
for filters in setup_filters(config[CONF_OR]):
yield None
yield OrFilter.new(filters)
elif CONF_HEARTBEAT in config:
yield App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT]))
elif CONF_DEBOUNCE in config:
@@ -131,12 +135,14 @@ def setup_filters(config):
for conf in config:
filter = None
for filter in setup_filter(conf):
yield
yield None
filters.append(filter)
yield ArrayInitializer(*filters)
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:

View File

@@ -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)
}))
def to_code(config):

View File

@@ -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)
}))
def to_code(config):

View File

@@ -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)
}))
def to_code(config):

View File

@@ -34,9 +34,9 @@ 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,
})

View File

@@ -38,10 +38,10 @@ 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,

View File

@@ -12,8 +12,8 @@ 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,
})

View File

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

View File

@@ -5,7 +5,7 @@ from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_MODEL, CONF_NAME, CONF_PIN, \
CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, add, gpio_output_pin_expression, variable
from esphomeyaml.pins import GPIO_OUTPUT_PIN_SCHEMA
from esphomeyaml.pins import gpio_output_pin_schema
DHT_MODELS = {
'AUTO_DETECT': sensor.sensor_ns.DHT_MODEL_AUTO_DETECT,
@@ -19,9 +19,9 @@ 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_PIN): gpio_output_pin_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,
})

View File

@@ -12,8 +12,8 @@ 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.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
})
@@ -24,9 +24,9 @@ def to_code(config):
config.get(CONF_UPDATE_INTERVAL))
dht = variable(config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), dht.Pmqtt_temperature,
sensor.setup_sensor(dht.Pdht12.Pget_temperature_sensor(), dht.Pmqtt_temperature,
config[CONF_TEMPERATURE])
sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), dht.Pmqtt_humidity,
sensor.setup_sensor(dht.Pdht12.Pget_humidity_sensor(), dht.Pmqtt_humidity,
config[CONF_HUMIDITY])

View File

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

View File

@@ -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)
}))
def to_code(config):

View File

@@ -12,8 +12,8 @@ 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.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
})

View File

@@ -12,8 +12,8 @@ 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.Required(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Required(CONF_HUMIDITY): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
})

View File

@@ -10,13 +10,13 @@ from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, \
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.Optional(CONF_PIN_MISO): pins.GPIO_INPUT_PIN_SCHEMA,
vol.Required(CONF_PIN_CS): pins.gpio_output_pin_schema,
vol.Required(CONF_PIN_CLOCK): pins.gpio_output_pin_schema,
vol.Required(CONF_PIN_MISO): pins.gpio_input_pin_schema,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema)
}))
def to_code(config):

View File

@@ -23,13 +23,13 @@ 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_ACCEL_X): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_ACCEL_Y): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_ACCEL_Z): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_GYRO_X): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_GYRO_Y): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_GYRO_Z): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_TEMPERATURE): cv.nameable(sensor.SENSOR_SCHEMA),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}), cv.has_at_least_one_key(CONF_ACCEL_X, CONF_ACCEL_Y, CONF_ACCEL_Z,
CONF_GYRO_X, CONF_GYRO_Y, CONF_GYRO_Z))

View File

@@ -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_INTERNAL_FILTER): validate_internal_filter,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema)
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)

View File

@@ -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.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Required(CONF_PIN_B): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Optional(CONF_PIN_RESET): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.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):

View File

@@ -4,37 +4,31 @@ 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_ACCURACY): cv.invalid("The accuracy option has been removed and now "
"defaults to HIGH."),
})
def to_code(config):
rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME],
config[CONF_ADDRESS],
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,

View File

@@ -3,20 +3,21 @@ 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
from esphomeyaml.helpers import App, process_lambda, variable, Application, float_, optional
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)
}))
def to_code(config):
template_ = None
for template_ in process_lambda(config[CONF_LAMBDA], []):
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))

View File

@@ -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)
}))
def to_code(config):

View File

@@ -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.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
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)
}))
def to_code(config):
@@ -25,7 +25,7 @@ def to_code(config):
for trigger in gpio_output_pin_expression(config[CONF_TRIGGER_PIN]):
yield
echo = None
for trigger in gpio_input_pin_expression(config[CONF_ECHO_PIN]):
for echo in gpio_input_pin_expression(config[CONF_ECHO_PIN]):
yield
rhs = App.make_ultrasonic_sensor(config[CONF_NAME], trigger, echo,
config.get(CONF_UPDATE_INTERVAL))

View File

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

View File

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

View File

@@ -1,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:

View File

@@ -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)
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
}))
def to_code(config):

View File

@@ -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'

View File

@@ -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):

View File

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

View File

@@ -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):

View File

@@ -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):

View File

@@ -5,17 +5,18 @@ from esphomeyaml import automation
from esphomeyaml.components import switch
from esphomeyaml.const import CONF_LAMBDA, CONF_MAKE_ID, CONF_NAME, CONF_TURN_OFF_ACTION, \
CONF_TURN_ON_ACTION, CONF_OPTIMISTIC
from esphomeyaml.helpers import App, Application, process_lambda, variable, NoArg, add
from esphomeyaml.helpers import App, Application, process_lambda, variable, NoArg, add, bool_, \
optional
MakeTemplateSwitch = Application.MakeTemplateSwitch
PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
PLATFORM_SCHEMA = 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):
@@ -24,19 +25,16 @@ def to_code(config):
if CONF_LAMBDA in config:
template_ = None
for template_ in process_lambda(config[CONF_LAMBDA], []):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(bool_)):
yield
add(make.Ptemplate_.set_state_lambda(template_))
if CONF_TURN_OFF_ACTION in config:
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]))

View File

@@ -14,8 +14,8 @@ WebServer = esphomelib_ns.WebServer
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(WebServer),
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_CSS_URL): vol.Url,
vol.Optional(CONF_JS_URL): vol.Url,
vol.Optional(CONF_CSS_URL): cv.string,
vol.Optional(CONF_JS_URL): cv.string,
})

View File

@@ -3,8 +3,8 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import core
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_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,58 @@ 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({
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.Required(CONF_DOMAIN, default='.local'): cv.domainname,
})
vol.Optional(CONF_DOMAIN, default='.local'): cv.domainname,
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
}), 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 +101,32 @@ def manual_ip(config):
)
def wifi_network(config):
return StructInitializer(
WiFiAp,
('ssid', config.get(CONF_SSID, "")),
('password', config.get(CONF_PASSWORD, "")),
('channel', config.get(CONF_CHANNEL, -1)),
('manual_ip', manual_ip(config.get(CONF_MANUAL_IP))),
)
def to_code(config):
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]))
def lib_deps(config):
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:

View File

@@ -1,6 +1,6 @@
{
"name": "esphomeyaml",
"version": "1.6.1",
"version": "1.7.0",
"slug": "esphomeyaml",
"description": "esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices.",
"url": "https://esphomelib.com/esphomeyaml/index.html",

View File

@@ -8,19 +8,21 @@ import voluptuous as vol
from voluptuous.humanize import humanize_error
import esphomeyaml.config_validation as cv
from esphomeyaml import core, yaml_util
from esphomeyaml import core, yaml_util, automation
from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
CONF_LIBRARY_URI, \
CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, ESP_PLATFORMS, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
CONF_LIBRARY_URI, CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, \
ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, CONF_ON_BOOT, CONF_TRIGGER_ID, \
CONF_PRIORITY, CONF_ON_SHUTDOWN
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, add, color
from esphomeyaml.helpers import App, add, color, esphomelib_ns, Pvariable, NoArg, const_char_p
_LOGGER = logging.getLogger(__name__)
DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.6.1'
DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.7.0'
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
StartupTrigger = esphomelib_ns.StartupTrigger
ShutdownTrigger = esphomelib_ns.ShutdownTrigger
CORE_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.valid_name,
@@ -30,6 +32,13 @@ CORE_SCHEMA = vol.Schema({
vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean,
vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean,
vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)),
vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(StartupTrigger),
vol.Optional(CONF_PRIORITY): vol.Coerce(float),
})]),
vol.Optional(CONF_ON_SHUTDOWN): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(ShutdownTrigger),
})]),
})
REQUIRED_COMPONENTS = [
@@ -43,6 +52,15 @@ _ALL_COMPONENTS = []
def core_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)
def get_component(domain):
if domain in _COMPONENT_CACHE:
@@ -175,7 +193,7 @@ def validate_config(config):
dependencies = getattr(component, 'DEPENDENCIES', [])
for dependency in dependencies:
if dependency not in _ALL_COMPONENTS:
result.add_error(u"Component {} requires {}".format(domain, dependency))
result.add_error(u"Component {} requires component {}".format(domain, dependency))
success = False
if not success:
continue
@@ -202,15 +220,15 @@ def validate_config(config):
continue
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(domain, p_name))
continue
success = True
dependencies = getattr(platform, 'DEPENDENCIES', [])
for dependency in dependencies:
if dependency not in _ALL_COMPONENTS:
result.add_error(u"Platform {}.{} requires {}".format(domain, p_name,
dependency))
result.add_error(u"Platform {}.{} requires component {}".format(domain, p_name,
dependency))
success = False
if not success:
continue

View File

@@ -4,6 +4,7 @@ from __future__ import print_function
import logging
import re
import uuid as uuid_
import voluptuous as vol
@@ -11,7 +12,7 @@ from esphomeyaml import core
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
@@ -246,13 +247,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 +278,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',
@@ -339,10 +326,33 @@ time_period = vol.Any(time_period_str_unit, time_period_str_colon, time_period_d
positive_time_period = vol.All(time_period, vol.Range(min=TimePeriod()))
positive_time_period_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,
@@ -366,6 +376,23 @@ def frequency(value):
return mantissa * multiplier
def validate_bytes(value):
value = string(value)
match = re.match(r"^([0-9]+)\s*(\w*?)(?:byte|B|b)?s?$", value)
if match is None:
raise vol.Invalid(u"Expected number of bytes with unit, got {}".format(value))
mantissa = int(match.group(1))
if match.group(2) not in METRIC_SUFFIXES:
raise vol.Invalid(u"Invalid metric suffix {}".format(match.group(2)))
multiplier = METRIC_SUFFIXES[match.group(2)]
if multiplier < 1:
raise vol.Invalid(u"Only suffixes with positive exponents are supported. "
u"Got {}".format(match.group(2)))
return int(mantissa * multiplier)
def hostname(value):
value = string(value)
if len(value) > 63:
@@ -496,6 +523,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)
@@ -532,6 +565,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 +593,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): MQTT_COMPONENT_AVAILABILITY_SCHEMA,
vol.Optional(CONF_AVAILABILITY): vol.Any(None, MQTT_COMPONENT_AVAILABILITY_SCHEMA),
vol.Optional(CONF_INTERNAL): boolean,
})
MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend({

View File

@@ -1,8 +1,8 @@
"""Constants used by esphomeyaml."""
MAJOR_VERSION = 1
MINOR_VERSION = 6
PATCH_VERSION = '1'
MINOR_VERSION = 7
PATCH_VERSION = '0'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
@@ -148,7 +148,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'
@@ -231,6 +230,23 @@ CONF_CLOSE_ACTION = 'close_action'
CONF_STOP_ACTION = 'stop_action'
CONF_DOMAIN = 'domain'
CONF_OPTIMISTIC = 'optimistic'
CONF_ON_BOOT = 'on_boot'
CONF_ON_SHUTDOWN = 'on_shutdown'
CONF_PRIORITY = 'priority'
CONF_DUMP = 'dump'
CONF_BUFFER_SIZE = 'buffer_size'
CONF_TOLERANCE = 'tolerance'
CONF_FILTER = 'filter'
CONF_IDLE = 'idle'
CONF_NETWORKS = 'networks'
CONF_INTERNAL = 'internal'
CONF_BUILD_PATH = 'build_path'
CONF_REBOOT_TIMEOUT = 'reboot_timeout'
CONF_INVERT = 'invert'
CONF_DELAYED_ON = 'delayed_on'
CONF_DELAYED_OFF = 'delayed_off'
CONF_UUID = 'uuid'
CONF_TYPE = 'type'
ESP32_BOARDS = [
'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1',

View File

@@ -32,6 +32,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)):

View File

@@ -2,6 +2,7 @@
from __future__ import print_function
import codecs
import hmac
import json
import logging
import os
@@ -27,6 +28,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 +45,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)
@@ -103,8 +113,11 @@ class EsphomeyamlValidateHandler(EsphomeyamlCommandWebSocket):
return ["esphomeyaml", config_file, "config"]
class SerialPortRequestHandler(tornado.web.RequestHandler):
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 +132,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,8 +148,12 @@ 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
@@ -151,8 +171,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,10 +185,26 @@ 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),
@@ -173,11 +213,12 @@ def make_app(debug=False):
(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,6 +228,21 @@ 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)

View File

@@ -524,7 +524,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;
@@ -571,7 +571,7 @@
inst._setSelectedStates();
return inst.getSelectedValues()[0];
};
setInterval(fetchSerialPorts, 2500);
setInterval(fetchSerialPorts, 5000);
fetchSerialPorts(true);
const logsModalElem = document.getElementById("modal-logs");

View File

@@ -456,7 +456,6 @@ def flush_tasks():
_TASKS.append((task, domain))
except StopIteration:
_LOGGER.debug(" -> %s finished", domain)
pass
def add(expression, require=True):
@@ -484,7 +483,7 @@ class MockObj(Expression):
obj.requires.append(self)
return obj
next_op = u'.'
if attr.startswith(u'P') and self.op != '::':
if attr.startswith(u'P') and self.op not in ['::', '']:
attr = attr[1:]
next_op = u'->'
if attr.startswith(u'_'):
@@ -535,6 +534,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
@@ -605,8 +605,11 @@ def setup_mqtt_component(obj, config):
add(obj.set_custom_command_topic(config[CONF_COMMAND_TOPIC]))
if CONF_AVAILABILITY in config:
availability = config[CONF_AVAILABILITY]
add(obj.set_availability(availability[CONF_TOPIC], availability[CONF_PAYLOAD_AVAILABLE],
availability[CONF_PAYLOAD_NOT_AVAILABLE]))
if not availability:
add(obj.disable_availability())
else:
add(obj.set_availability(availability[CONF_TOPIC], availability[CONF_PAYLOAD_AVAILABLE],
availability[CONF_PAYLOAD_NOT_AVAILABLE]))
# shlex's quote for Python 2.7

View File

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

View File

@@ -205,18 +205,38 @@ def shorthand_input_pin(value):
PCF8574_OUTPUT_PIN_SCHEMA = vol.Schema({
vol.Required(CONF_PCF8574): cv.use_variable_id(pcf8574.PCF8574Component),
vol.Required(CONF_NUMBER): vol.Coerce(int),
vol.Optional(CONF_MODE): vol.All(vol.Upper, "OUTPUT"),
vol.Optional(CONF_MODE): vol.All(vol.Upper, cv.one_of("OUTPUT")),
vol.Optional(CONF_INVERTED, default=False): cv.boolean,
})
PCF8574_INPUT_PIN_SCHEMA = PCF8574_OUTPUT_PIN_SCHEMA.extend({
vol.Optional(CONF_MODE): vol.All(vol.Upper, vol.Any("INPUT", "INPUT_PULLUP")),
vol.Optional(CONF_MODE): vol.All(vol.Upper, cv.one_of("INPUT", "INPUT_PULLUP")),
})
GPIO_INTERNAL_OUTPUT_PIN_SCHEMA = vol.Any(shorthand_output_pin, GPIO_FULL_OUTPUT_PIN_SCHEMA)
GPIO_OUTPUT_PIN_SCHEMA = vol.Any(PCF8574_OUTPUT_PIN_SCHEMA, GPIO_INTERNAL_OUTPUT_PIN_SCHEMA)
def internal_gpio_output_pin_schema(value):
if isinstance(value, dict):
return GPIO_FULL_OUTPUT_PIN_SCHEMA(value)
return shorthand_output_pin(value)
GPIO_INTERNAL_INPUT_PIN_SCHEMA = vol.Any(shorthand_input_pin, GPIO_FULL_INPUT_PIN_SCHEMA)
GPIO_INPUT_PIN_SCHEMA = vol.Any(PCF8574_INPUT_PIN_SCHEMA, GPIO_INTERNAL_INPUT_PIN_SCHEMA)
def gpio_output_pin_schema(value):
if isinstance(value, dict):
if CONF_PCF8574 in value:
return PCF8574_OUTPUT_PIN_SCHEMA(value)
return GPIO_FULL_OUTPUT_PIN_SCHEMA(value)
return shorthand_output_pin(value)
def internal_gpio_input_pin_schema(value):
if isinstance(value, dict):
return GPIO_FULL_INPUT_PIN_SCHEMA(value)
return shorthand_input_pin(value)
def gpio_input_pin_schema(value):
if isinstance(value, dict):
if CONF_PCF8574 in value:
return PCF8574_INPUT_PIN_SCHEMA(value)
return GPIO_FULL_INPUT_PIN_SCHEMA(value)
return shorthand_input_pin(value)

View File

@@ -82,6 +82,7 @@ def get_build_flags(config, key):
def get_ini_content(config):
version_specific_settings = determine_platformio_version_settings()
platform = config[CONF_ESPHOMEYAML][CONF_PLATFORM]
if platform in PLATFORM_TO_PLATFORMIO:
platform = PLATFORM_TO_PLATFORMIO[platform]
@@ -119,8 +120,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 +176,23 @@ 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)
if 'esp32_ble_beacon' in config:
content += 'board_build.partitions = partitions.csv\n'
partitions_csv = os.path.join(path, 'partitions.csv')
if not os.path.isfile(partitions_csv):
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 +213,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

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