1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-10 11:55:52 +00:00

Compare commits

..

28 Commits

Author SHA1 Message Date
Otto Winter
d88634b196 Bump version to 1.6.0 2018-06-01 18:48:27 +02:00
Otto Winter
976627eb38 HassIO add-on 2018-06-01 18:45:23 +02:00
Otto Winter
5b995c0692 Updates 2018-06-01 18:06:18 +02:00
Otto Winter
2d4b475951 Fix cover automation 2018-05-27 15:00:56 +02:00
Otto Winter
93d962dd43 HassIO -> dashboard 2018-05-27 14:15:24 +02:00
Otto Winter
2e7d8540fb Update dev library URI 2018-05-21 20:55:39 +02:00
Otto Winter
677fe8bacf More Actions 2018-05-21 17:01:47 +02:00
Otto Winter
94d7ac4ef0 HassIO add-on (#18)
* HassIO Beginnings

* Updates

* Fix pylint errors

* Fix pylint error
2018-05-21 16:40:22 +02:00
Jimmy Hedman
ebb6d0d464 Add domain paramteter to wifi. (#16)
* Add domain paramteter to wifi.

- To be able to do OTA updates on networks that doesn't use .local as
  local domain parameter domain is added to wifi section. It's currently
  only used for OTA.

* Centralised default parameter for domain.

* Added input validation for domainname.
2018-05-21 15:47:30 +02:00
Jimmy Hedman
e8fe653140 Fix flake8 warnings. (#17) 2018-05-21 15:07:17 +02:00
Otto Winter
374ea7044c Automation API & Cleanup 2018-05-20 12:41:52 +02:00
Otto Winter
061798839d Bump version to 1.5.3 2018-05-18 09:45:28 +02:00
Otto Winter
b9b09a1763 Ultrasonic sensor echo must be internal 2018-05-18 09:44:41 +02:00
Otto Winter
61b3ead2df More sensor filters 2018-05-18 09:44:25 +02:00
Otto Winter
48e42cf478 FastLED power supply 2018-05-18 09:44:03 +02:00
Otto Winter
1a9ff55a61 Improve PCF8574 validation 2018-05-17 21:56:50 +02:00
Otto Winter
e04285581c Rotary Encoders 2018-05-17 21:35:39 +02:00
Otto Winter
9af30061cb More filters 2018-05-17 21:31:39 +02:00
Otto Winter
19929fafa5 Rotary Encoder 2018-05-17 19:57:55 +02:00
Otto Winter
3a9febaf85 Generic Switch inversion support fixes #14 2018-05-17 17:20:43 +02:00
Otto Winter
ebb5991889 DHT12 Support 2018-05-17 17:19:16 +02:00
Otto Winter
f18f8444c7 Bump version to 1.5.2 2018-05-16 23:05:35 +02:00
Otto Winter
10607f2a51 Fix GPIO expression issue with no inverted set 2018-05-16 23:04:33 +02:00
Otto Winter
d3ac5bfb27 Bump version to 1.5.1 2018-05-16 22:45:06 +02:00
Otto Winter
4b9bb2b731 Initial Sonoff support 2018-05-16 19:45:33 +02:00
Otto Winter
8639eb1b27 Fix PCF8574 inverted KeyError #12 2018-05-15 11:22:55 +02:00
Otto Winter
9979ee6ddf Fix C++ String escaping fixes #11 2018-05-15 11:09:27 +02:00
Otto Winter
ee502a7aaa Bump version to 1.5.0 2018-05-14 22:10:17 +02:00
88 changed files with 3127 additions and 906 deletions

View File

@@ -7,7 +7,8 @@ VOLUME /config
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/ COPY requirements.txt /usr/src/app/
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt && \
pip install --no-cache-dir tornado esptool
COPY docker/platformio.ini /usr/src/app/ COPY docker/platformio.ini /usr/src/app/
RUN platformio settings set enable_telemetry No && \ RUN platformio settings set enable_telemetry No && \

4
MANIFEST.in Normal file
View File

@@ -0,0 +1,4 @@
include README.md
include esphomeyaml/dashboard/templates/index.html
include esphomeyaml/dashboard/static/materialize-stepper.min.css
include esphomeyaml/dashboard/static/materialize-stepper.min.js

20
esphomeyaml/Dockerfile Normal file
View File

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

View File

@@ -1,17 +1,19 @@
from __future__ import print_function from __future__ import print_function
import argparse import argparse
from datetime import datetime
import logging import logging
import os import os
import random import random
import sys import sys
from esphomeyaml import core, mqtt, wizard, writer, yaml_util, const from esphomeyaml import const, core, mqtt, wizard, writer, yaml_util
from esphomeyaml.config import core_to_code, get_component, iter_components, read_config from esphomeyaml.config import core_to_code, get_component, iter_components, read_config
from esphomeyaml.const import CONF_BAUD_RATE, CONF_ESPHOMEYAML, CONF_HOSTNAME, CONF_LOGGER, \ from esphomeyaml.const import CONF_BAUD_RATE, CONF_DOMAIN, CONF_ESPHOMEYAML, CONF_HOSTNAME, \
CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI, ESP_PLATFORM_ESP8266
from esphomeyaml.helpers import AssignmentExpression, RawStatement, _EXPRESSIONS, add, add_task, \ from esphomeyaml.core import ESPHomeYAMLError
color, get_variable, indent, quote, statement, Expression from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \
add_task, color, get_variable, indent, quote, statement
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -26,28 +28,27 @@ def get_base_path(config):
return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config)) return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config))
def discover_serial_ports(): def get_serial_ports():
# from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py # from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py
try: from serial.tools.list_ports import comports
from serial.tools.list_ports import comports
except ImportError:
return None
result = [] result = []
descs = []
for port, desc, info in comports(): for port, desc, info in comports():
if not port: if not port:
continue continue
if "VID:PID" in info: if "VID:PID" in info:
result.append(port) result.append((port, desc))
descs.append(desc) return result
def choose_serial_port(config):
result = get_serial_ports()
if not result: if not result:
return None return 'OTA'
print(u"Found multiple serial port options, please choose one:") print(u"Found multiple serial port options, please choose one:")
for i, (res, desc) in enumerate(zip(result, descs)): for i, (res, desc) in enumerate(result):
print(u" [{}] {} ({})".format(i, res, desc)) print(u" [{}] {} ({})".format(i, res, desc))
print(u" [{}] Over The Air".format(len(result))) print(u" [{}] Over The Air ({})".format(len(result), get_upload_host(config)))
print() print()
while True: while True:
opt = raw_input('(number): ') opt = raw_input('(number): ')
@@ -62,11 +63,11 @@ def discover_serial_ports():
except ValueError: except ValueError:
print(color('red', u"Invalid option: '{}'".format(opt))) print(color('red', u"Invalid option: '{}'".format(opt)))
if opt == len(result): if opt == len(result):
return None return 'OTA'
return result[opt] return result[opt][0]
def run_platformio(*cmd): def run_platformio(*cmd, **kwargs):
def mock_exit(return_code): def mock_exit(return_code):
raise SystemExit(return_code) raise SystemExit(return_code)
@@ -75,10 +76,13 @@ def run_platformio(*cmd):
full_cmd = u' '.join(quote(x) for x in cmd) full_cmd = u' '.join(quote(x) for x in cmd)
_LOGGER.info(u"Running: %s", full_cmd) _LOGGER.info(u"Running: %s", full_cmd)
try: try:
import platformio.__main__ func = kwargs.get('main')
if func is None:
import platformio.__main__
func = platformio.__main__.main
sys.argv = list(cmd) sys.argv = list(cmd)
sys.exit = mock_exit sys.exit = mock_exit
return platformio.__main__.main() return func() or 0
except KeyboardInterrupt: except KeyboardInterrupt:
return 1 return 1
except SystemExit as err: except SystemExit as err:
@@ -91,13 +95,19 @@ def run_platformio(*cmd):
sys.exit = orig_exit sys.exit = orig_exit
def run_miniterm(config, port): def run_miniterm(config, port, escape=False):
from serial.tools import miniterm import serial
baud_rate = config.get(CONF_LOGGER, {}).get(CONF_BAUD_RATE, 115200) baud_rate = config.get(CONF_LOGGER, {}).get(CONF_BAUD_RATE, 115200)
sys.argv = ['miniterm', '--raw', '--exit-char', '3'] _LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
miniterm.main(
default_port=port, with serial.Serial(port, baudrate=baud_rate) as ser:
default_baudrate=baud_rate) while True:
line = ser.readline()
time = datetime.now().time().strftime('[%H:%M:%S]')
message = time + line.decode('unicode-escape').replace('\r', '').replace('\n', '')
if escape:
message = message.replace('\033', '\\033').encode('ascii', 'replace')
print(message)
def write_cpp(config): def write_cpp(config):
@@ -132,6 +142,8 @@ def write_cpp(config):
if isinstance(exp, Expression) and not exp.required: if isinstance(exp, Expression) and not exp.required:
continue continue
if isinstance(exp, AssignmentExpression) and not exp.obj.required: if isinstance(exp, AssignmentExpression) and not exp.obj.required:
if not exp.has_side_effects():
continue
exp = exp.rhs exp = exp.rhs
all_code.append(unicode(statement(exp))) all_code.append(unicode(statement(exp)))
@@ -150,9 +162,32 @@ def compile_program(config):
return run_platformio('platformio', 'run', '-d', get_base_path(config)) return run_platformio('platformio', 'run', '-d', get_base_path(config))
def get_upload_host(config):
if CONF_MANUAL_IP in config[CONF_WIFI]:
host = str(config[CONF_WIFI][CONF_MANUAL_IP][CONF_STATIC_IP])
elif CONF_HOSTNAME in config[CONF_WIFI]:
host = config[CONF_WIFI][CONF_HOSTNAME] + config[CONF_WIFI][CONF_DOMAIN]
else:
host = config[CONF_ESPHOMEYAML][CONF_NAME] + config[CONF_WIFI][CONF_DOMAIN]
return host
def upload_using_esptool(config, port):
import esptool
name = get_name(config)
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
# pylint: disable=protected-access
return run_platformio('esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
'--chip', 'esp8266', '--port', port, 'write_flash', '0x0',
path, main=esptool._main)
def upload_program(config, args, port): def upload_program(config, args, port):
_LOGGER.info("Uploading binary...") _LOGGER.info("Uploading binary...")
if port is not None: if port != 'OTA':
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy:
return upload_using_esptool(config, port)
return run_platformio('platformio', 'run', '-d', get_base_path(config), return run_platformio('platformio', 'run', '-d', get_base_path(config),
'-t', 'upload', '--upload-port', port) '-t', 'upload', '--upload-port', port)
@@ -160,12 +195,7 @@ def upload_program(config, args, port):
_LOGGER.error("No serial port found and OTA not enabled. Can't upload!") _LOGGER.error("No serial port found and OTA not enabled. Can't upload!")
return -1 return -1
if CONF_MANUAL_IP in config[CONF_WIFI]: host = get_upload_host(config)
host = str(config[CONF_WIFI][CONF_MANUAL_IP][CONF_STATIC_IP])
elif CONF_HOSTNAME in config[CONF_WIFI]:
host = config[CONF_WIFI][CONF_HOSTNAME] + u'.local'
else:
host = config[CONF_ESPHOMEYAML][CONF_NAME] + u'.local'
from esphomeyaml.components import ota from esphomeyaml.components import ota
from esphomeyaml import espota from esphomeyaml import espota
@@ -181,11 +211,12 @@ def upload_program(config, args, port):
return espota.main(espota_args) return espota.main(espota_args)
def show_logs(config, args, port): def show_logs(config, args, port, escape=False):
if port is not None and port != 'OTA': if port != 'OTA':
run_miniterm(config, port) run_miniterm(config, port, escape=escape)
return 0 return 0
return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id) return mqtt.show_logs(config, args.topic, args.username, args.password, args.client_id,
escape=escape)
def clean_mqtt(config, args): def clean_mqtt(config, args):
@@ -218,11 +249,98 @@ def setup_log():
pass pass
def main(): def command_wizard(args):
setup_log() return wizard.wizard(args.configuration)
def command_config(args, config):
print(yaml_util.dump(config))
return 0
def command_compile(args, config):
exit_code = write_cpp(config)
if exit_code != 0:
return exit_code
exit_code = compile_program(config)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully compiled program.")
return 0
def command_upload(args, config):
port = args.upload_port or choose_serial_port(config)
exit_code = upload_program(config, args, port)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully uploaded program.")
return 0
def command_logs(args, config):
port = args.serial_port or choose_serial_port(config)
return show_logs(config, args, port, escape=args.escape)
def command_run(args, config):
exit_code = write_cpp(config)
if exit_code != 0:
return exit_code
exit_code = compile_program(config)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully compiled program.")
port = args.upload_port or choose_serial_port(config)
exit_code = upload_program(config, args, port)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully uploaded program.")
if args.no_logs:
return 0
return show_logs(config, args, port, escape=args.escape)
def command_clean_mqtt(args, config):
return clean_mqtt(config, args)
def command_mqtt_fingerprint(args, config):
return mqtt.get_fingerprint(config)
def command_version(args):
print(u"Version: {}".format(const.__version__))
return 0
def command_dashboard(args):
from esphomeyaml.dashboard import dashboard
return dashboard.start_web_server(args)
PRE_CONFIG_ACTIONS = {
'wizard': command_wizard,
'version': command_version,
'dashboard': command_dashboard
}
POST_CONFIG_ACTIONS = {
'config': command_config,
'compile': command_compile,
'upload': command_upload,
'logs': command_logs,
'run': command_run,
'clean-mqtt': command_clean_mqtt,
'mqtt-fingerprint': command_mqtt_fingerprint,
}
def parse_args(argv):
parser = argparse.ArgumentParser(prog='esphomeyaml') parser = argparse.ArgumentParser(prog='esphomeyaml')
parser.add_argument('configuration', help='Your YAML configuration file.') parser.add_argument('configuration', help='Your YAML configuration file.')
subparsers = parser.add_subparsers(help='Commands', dest='command') subparsers = parser.add_subparsers(help='Commands', dest='command')
subparsers.required = True subparsers.required = True
subparsers.add_parser('config', help='Validate the configuration and spit it out.') subparsers.add_parser('config', help='Validate the configuration and spit it out.')
@@ -234,6 +352,9 @@ def main():
parser_upload.add_argument('--upload-port', help="Manually specify the upload port to use. " parser_upload.add_argument('--upload-port', help="Manually specify the upload port to use. "
"For example /dev/cu.SLAB_USBtoUART.") "For example /dev/cu.SLAB_USBtoUART.")
parser_upload.add_argument('--host-port', help="Specify the host port.", type=int) parser_upload.add_argument('--host-port', help="Specify the host port.", type=int)
parser_upload.add_argument('--use-esptoolpy',
help="Use esptool.py for the uploading (only for ESP8266)",
action='store_true')
parser_logs = subparsers.add_parser('logs', help='Validate the configuration ' parser_logs = subparsers.add_parser('logs', help='Validate the configuration '
'and show all MQTT logs.') 'and show all MQTT logs.')
@@ -243,6 +364,8 @@ def main():
parser_logs.add_argument('--client-id', help='Manually set the client id.') parser_logs.add_argument('--client-id', help='Manually set the client id.')
parser_logs.add_argument('--serial-port', help="Manually specify a serial port to use" parser_logs.add_argument('--serial-port', help="Manually specify a serial port to use"
"For example /dev/cu.SLAB_USBtoUART.") "For example /dev/cu.SLAB_USBtoUART.")
parser_logs.add_argument('--escape', help="Escape ANSI color codes for running in dashboard",
action='store_true')
parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, ' parser_run = subparsers.add_parser('run', help='Validate the configuration, create a binary, '
'upload it, and start MQTT logs.') 'upload it, and start MQTT logs.')
@@ -255,6 +378,11 @@ def main():
parser_run.add_argument('--username', help='Manually set the MQTT username for logs.') parser_run.add_argument('--username', help='Manually set the MQTT username for logs.')
parser_run.add_argument('--password', help='Manually set the MQTT password for logs.') parser_run.add_argument('--password', help='Manually set the MQTT password for logs.')
parser_run.add_argument('--client-id', help='Manually set the client id for logs.') parser_run.add_argument('--client-id', help='Manually set the client id for logs.')
parser_run.add_argument('--escape', help="Escape ANSI color codes for running in dashboard",
action='store_true')
parser_run.add_argument('--use-esptoolpy',
help="Use esptool.py for the uploading (only for ESP8266)",
action='store_true')
parser_clean = subparsers.add_parser('clean-mqtt', help="Helper to clear an MQTT topic from " parser_clean = subparsers.add_parser('clean-mqtt', help="Helper to clear an MQTT topic from "
"retain messages.") "retain messages.")
@@ -267,12 +395,26 @@ def main():
"you through setting up esphomeyaml.") "you through setting up esphomeyaml.")
subparsers.add_parser('mqtt-fingerprint', help="Get the SSL fingerprint from a MQTT broker.") subparsers.add_parser('mqtt-fingerprint', help="Get the SSL fingerprint from a MQTT broker.")
subparsers.add_parser('version', help="Print the esphomeyaml version and exit.") subparsers.add_parser('version', help="Print the esphomeyaml version and exit.")
args = parser.parse_args() dashboard = subparsers.add_parser('dashboard',
help="Create a simple webserver for a dashboard.")
dashboard.add_argument("--port", help="The HTTP port to open connections on.", type=int,
default=6052)
if args.command == 'wizard': return parser.parse_args(argv[1:])
return wizard.wizard(args.configuration)
def run_esphomeyaml(argv):
setup_log()
args = parse_args(argv)
if args.command in PRE_CONFIG_ACTIONS:
try:
return PRE_CONFIG_ACTIONS[args.command](args)
except ESPHomeYAMLError as e:
_LOGGER.error(e)
return 1
core.CONFIG_PATH = args.configuration core.CONFIG_PATH = args.configuration
@@ -280,54 +422,25 @@ def main():
if config is None: if config is None:
return 1 return 1
if args.command == 'config': if args.command in POST_CONFIG_ACTIONS:
print(yaml_util.dump(config)) try:
return 0 return POST_CONFIG_ACTIONS[args.command](args, config)
elif args.command == 'compile': except ESPHomeYAMLError as e:
exit_code = write_cpp(config) _LOGGER.error(e)
if exit_code != 0: return 1
return exit_code
exit_code = compile_program(config)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully compiled program.")
return 0
elif args.command == 'upload':
port = args.upload_port or discover_serial_ports()
exit_code = upload_program(config, args, port)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully uploaded program.")
return 0
elif args.command == 'logs':
port = args.serial_port or discover_serial_ports()
return show_logs(config, args, port)
elif args.command == 'clean-mqtt':
return clean_mqtt(config, args)
elif args.command == 'mqtt-fingerprint':
return mqtt.get_fingerprint(config)
elif args.command == 'run':
exit_code = write_cpp(config)
if exit_code != 0:
return exit_code
exit_code = compile_program(config)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully compiled program.")
port = args.upload_port or discover_serial_ports()
exit_code = upload_program(config, args, port)
if exit_code != 0:
return exit_code
_LOGGER.info(u"Successfully uploaded program.")
if args.no_logs:
return 0
return show_logs(config, args, port)
elif args.command == 'version':
print(u"Version: {}".format(const.__version__))
return 0
print(u"Unknown command {}".format(args.command)) print(u"Unknown command {}".format(args.command))
return 1 return 1
def main():
try:
return run_esphomeyaml(sys.argv)
except ESPHomeYAMLError as e:
_LOGGER.error(e)
return 1
except KeyboardInterrupt:
return 1
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

297
esphomeyaml/automation.py Normal file
View File

@@ -0,0 +1,297 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import cover, fan
from esphomeyaml.const import CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, CONF_BLUE, \
CONF_BRIGHTNESS, CONF_CONDITION_ID, CONF_DELAY, CONF_EFFECT, CONF_FLASH_LENGTH, CONF_GREEN, \
CONF_ID, CONF_IF, CONF_LAMBDA, CONF_OR, CONF_OSCILLATING, CONF_PAYLOAD, \
CONF_QOS, CONF_RANGE, CONF_RED, CONF_RETAIN, CONF_SPEED, CONF_THEN, CONF_TOPIC, \
CONF_TRANSITION_LENGTH, CONF_TRIGGER_ID, CONF_WHITE, CONF_ABOVE, CONF_BELOW
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, TemplateArguments, add, \
bool_, esphomelib_ns, float_, get_variable, process_lambda, std_string, templatable, uint32, \
uint8
CONF_MQTT_PUBLISH = 'mqtt.publish'
CONF_LIGHT_TOGGLE = 'light.toggle'
CONF_LIGHT_TURN_OFF = 'light.turn_off'
CONF_LIGHT_TURN_ON = 'light.turn_on'
CONF_SWITCH_TOGGLE = 'switch.toggle'
CONF_SWITCH_TURN_OFF = 'switch.turn_off'
CONF_SWITCH_TURN_ON = 'switch.turn_on'
CONF_COVER_OPEN = 'cover.open'
CONF_COVER_CLOSE = 'cover.close'
CONF_COVER_STOP = 'cover.stop'
CONF_FAN_TOGGLE = 'fan.toggle'
CONF_FAN_TURN_OFF = 'fan.turn_off'
CONF_FAN_TURN_ON = 'fan.turn_on'
ACTION_KEYS = [CONF_DELAY, CONF_MQTT_PUBLISH, CONF_LIGHT_TOGGLE, CONF_LIGHT_TURN_OFF,
CONF_LIGHT_TURN_ON, CONF_SWITCH_TOGGLE, CONF_SWITCH_TURN_OFF, CONF_SWITCH_TURN_ON,
CONF_LAMBDA, CONF_COVER_OPEN, CONF_COVER_CLOSE, CONF_COVER_STOP, CONF_FAN_TOGGLE,
CONF_FAN_TURN_OFF, CONF_FAN_TURN_ON]
ACTIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
cv.GenerateID('action', CONF_ACTION_ID): cv.register_variable_id,
vol.Optional(CONF_DELAY): cv.templatable(cv.positive_time_period_milliseconds),
vol.Optional(CONF_MQTT_PUBLISH): vol.Schema({
vol.Required(CONF_TOPIC): cv.templatable(cv.publish_topic),
vol.Required(CONF_PAYLOAD): cv.templatable(cv.mqtt_payload),
vol.Optional(CONF_QOS): cv.templatable(cv.mqtt_qos),
vol.Optional(CONF_RETAIN): cv.templatable(cv.boolean),
}),
vol.Optional(CONF_LIGHT_TOGGLE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
}),
vol.Optional(CONF_LIGHT_TURN_OFF): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
vol.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds),
}),
vol.Optional(CONF_LIGHT_TURN_ON): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
vol.Exclusive(CONF_TRANSITION_LENGTH, 'transformer'):
cv.templatable(cv.positive_time_period_milliseconds),
vol.Exclusive(CONF_FLASH_LENGTH, 'transformer'):
cv.templatable(cv.positive_time_period_milliseconds),
vol.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage),
vol.Optional(CONF_RED): cv.templatable(cv.percentage),
vol.Optional(CONF_GREEN): cv.templatable(cv.percentage),
vol.Optional(CONF_BLUE): cv.templatable(cv.percentage),
vol.Optional(CONF_WHITE): cv.templatable(cv.percentage),
vol.Optional(CONF_EFFECT): cv.templatable(cv.string),
}),
vol.Optional(CONF_SWITCH_TOGGLE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_SWITCH_TURN_OFF): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_SWITCH_TURN_ON): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_COVER_OPEN): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_COVER_CLOSE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_COVER_STOP): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_COVER_OPEN): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_COVER_CLOSE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_COVER_STOP): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_FAN_TOGGLE): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_FAN_TURN_OFF): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
}),
vol.Optional(CONF_FAN_TURN_ON): vol.Schema({
vol.Required(CONF_ID): cv.variable_id,
vol.Optional(CONF_OSCILLATING): cv.templatable(cv.boolean),
vol.Optional(CONF_SPEED): cv.templatable(fan.validate_fan_speed),
}),
vol.Optional(CONF_LAMBDA): cv.lambda_,
}, cv.has_at_exactly_one_key(*ACTION_KEYS))])
# pylint: disable=invalid-name
DelayAction = esphomelib_ns.DelayAction
LambdaAction = esphomelib_ns.LambdaAction
Automation = esphomelib_ns.Automation
def validate_recursive_condition(value):
return CONDITIONS_SCHEMA(value)
CONDITION_KEYS = [CONF_AND, CONF_OR, CONF_RANGE, CONF_LAMBDA]
CONDITIONS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
cv.GenerateID('condition', CONF_CONDITION_ID): cv.register_variable_id,
vol.Optional(CONF_AND): validate_recursive_condition,
vol.Optional(CONF_OR): validate_recursive_condition,
vol.Optional(CONF_RANGE): vol.All(vol.Schema({
vol.Optional(CONF_ABOVE): vol.Coerce(float),
vol.Optional(CONF_BELOW): vol.Coerce(float),
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW)),
vol.Optional(CONF_LAMBDA): cv.lambda_,
}), cv.has_at_exactly_one_key(*CONDITION_KEYS)])
# pylint: disable=invalid-name
AndCondition = esphomelib_ns.AndCondition
OrCondition = esphomelib_ns.OrCondition
RangeCondition = esphomelib_ns.RangeCondition
LambdaCondition = esphomelib_ns.LambdaCondition
AUTOMATION_SCHEMA = vol.Schema({
cv.GenerateID('trigger', CONF_TRIGGER_ID): cv.register_variable_id,
cv.GenerateID('automation', CONF_AUTOMATION_ID): cv.register_variable_id,
vol.Optional(CONF_IF): CONDITIONS_SCHEMA,
vol.Required(CONF_THEN): ACTIONS_SCHEMA,
})
def build_condition(config, arg_type):
template_arg = TemplateArguments(arg_type)
if CONF_AND in config:
return AndCondition.new(template_arg, build_conditions(config[CONF_AND], template_arg))
if CONF_OR in config:
return OrCondition.new(template_arg, build_conditions(config[CONF_OR], template_arg))
if CONF_LAMBDA in config:
return LambdaCondition.new(template_arg,
process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')]))
if CONF_RANGE in config:
conf = config[CONF_RANGE]
rhs = RangeCondition.new(template_arg)
condition = Pvariable(RangeCondition.template(template_arg), config[CONF_CONDITION_ID], rhs)
if CONF_ABOVE in conf:
condition.set_min(templatable(conf[CONF_ABOVE], arg_type, float_))
if CONF_BELOW in conf:
condition.set_max(templatable(conf[CONF_BELOW], arg_type, float_))
return condition
raise ESPHomeYAMLError(u"Unsupported condition {}".format(config))
def build_conditions(config, arg_type):
return ArrayInitializer(*[build_condition(x, arg_type) for x in config])
def build_action(config, arg_type):
from esphomeyaml.components import light, mqtt, switch
template_arg = TemplateArguments(arg_type)
if CONF_DELAY in config:
rhs = App.register_component(DelayAction.new(template_arg))
action = Pvariable(DelayAction.template(template_arg), config[CONF_ACTION_ID], rhs)
add(action.set_delay(templatable(config[CONF_DELAY], arg_type, uint32)))
return action
elif CONF_LAMBDA in config:
rhs = LambdaAction.new(template_arg, process_lambda(config[CONF_LAMBDA], [(arg_type, 'x')]))
return Pvariable(LambdaAction.template(template_arg), config[CONF_ACTION_ID], rhs)
elif CONF_MQTT_PUBLISH in config:
conf = config[CONF_MQTT_PUBLISH]
rhs = App.Pget_mqtt_client().Pmake_publish_action()
action = Pvariable(mqtt.MQTTPublishAction.template(template_arg), config[CONF_ACTION_ID],
rhs)
add(action.set_topic(templatable(conf[CONF_TOPIC], arg_type, std_string)))
add(action.set_payload(templatable(conf[CONF_PAYLOAD], arg_type, std_string)))
if CONF_QOS in conf:
add(action.set_qos(templatable(conf[CONF_QOS], arg_type, uint8)))
if CONF_RETAIN in conf:
add(action.set_retain(templatable(conf[CONF_RETAIN], arg_type, bool_)))
return action
elif CONF_LIGHT_TOGGLE in config:
conf = config[CONF_LIGHT_TOGGLE]
var = get_variable(conf[CONF_ID])
rhs = var.make_toggle_action(template_arg)
action = Pvariable(light.ToggleAction.template(template_arg), config[CONF_ACTION_ID], rhs)
if CONF_TRANSITION_LENGTH in conf:
add(action.set_transition_length(
templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32)
))
return action
elif CONF_LIGHT_TURN_OFF in config:
conf = config[CONF_LIGHT_TURN_OFF]
var = get_variable(conf[CONF_ID])
rhs = var.make_turn_off_action(template_arg)
action = Pvariable(light.TurnOffAction.template(template_arg), config[CONF_ACTION_ID], rhs)
if CONF_TRANSITION_LENGTH in conf:
add(action.set_transition_length(
templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32)
))
return action
elif CONF_LIGHT_TURN_ON in config:
conf = config[CONF_LIGHT_TURN_ON]
var = get_variable(conf[CONF_ID])
rhs = var.make_turn_on_action(template_arg)
action = Pvariable(light.TurnOnAction.template(template_arg), config[CONF_ACTION_ID], rhs)
if CONF_TRANSITION_LENGTH in conf:
add(action.set_transition_length(
templatable(conf[CONF_TRANSITION_LENGTH], arg_type, uint32)
))
if CONF_FLASH_LENGTH in conf:
add(action.set_flash_length(templatable(conf[CONF_FLASH_LENGTH], arg_type, uint32)))
if CONF_BRIGHTNESS in conf:
add(action.set_brightness(templatable(conf[CONF_BRIGHTNESS], arg_type, float_)))
if CONF_RED in conf:
add(action.set_red(templatable(conf[CONF_RED], arg_type, float_)))
if CONF_GREEN in conf:
add(action.set_green(templatable(conf[CONF_GREEN], arg_type, float_)))
if CONF_BLUE in conf:
add(action.set_blue(templatable(conf[CONF_BLUE], arg_type, float_)))
if CONF_WHITE in conf:
add(action.set_white(templatable(conf[CONF_WHITE], arg_type, float_)))
if CONF_EFFECT in conf:
add(action.set_effect(templatable(conf[CONF_EFFECT], arg_type, std_string)))
return action
elif CONF_SWITCH_TOGGLE in config:
conf = config[CONF_SWITCH_TOGGLE]
var = get_variable(conf[CONF_ID])
rhs = var.make_toggle_action(template_arg)
return Pvariable(switch.ToggleAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_SWITCH_TURN_OFF in config:
conf = config[CONF_SWITCH_TURN_OFF]
var = get_variable(conf[CONF_ID])
rhs = var.make_turn_off_action(template_arg)
return Pvariable(switch.TurnOffAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_SWITCH_TURN_ON in config:
conf = config[CONF_SWITCH_TURN_ON]
var = get_variable(conf[CONF_ID])
rhs = var.make_turn_on_action(template_arg)
return Pvariable(switch.TurnOnAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_COVER_OPEN in config:
conf = config[CONF_COVER_OPEN]
var = get_variable(conf[CONF_ID])
rhs = var.make_open_action(template_arg)
return Pvariable(cover.OpenAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_COVER_CLOSE in config:
conf = config[CONF_COVER_CLOSE]
var = get_variable(conf[CONF_ID])
rhs = var.make_close_action(template_arg)
return Pvariable(cover.CloseAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_COVER_STOP in config:
conf = config[CONF_COVER_STOP]
var = get_variable(conf[CONF_ID])
rhs = var.make_stop_action(template_arg)
return Pvariable(cover.StopAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_FAN_TOGGLE in config:
conf = config[CONF_FAN_TOGGLE]
var = get_variable(conf[CONF_ID])
rhs = var.make_toggle_action(template_arg)
return Pvariable(fan.ToggleAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_FAN_TURN_OFF in config:
conf = config[CONF_FAN_TURN_OFF]
var = get_variable(conf[CONF_ID])
rhs = var.make_turn_off_action(template_arg)
return Pvariable(fan.TurnOffAction.template(arg_type), config[CONF_ACTION_ID], rhs)
elif CONF_FAN_TURN_ON in config:
conf = config[CONF_FAN_TURN_ON]
var = get_variable(conf[CONF_ID])
rhs = var.make_turn_on_action(template_arg)
action = Pvariable(fan.TurnOnAction.template(arg_type), config[CONF_ACTION_ID], rhs)
if CONF_OSCILLATING in config:
add(action.set_oscillating(templatable(conf[CONF_OSCILLATING], arg_type, bool_)))
if CONF_SPEED in config:
add(action.set_speed(templatable(conf[CONF_SPEED], arg_type, fan.FanSpeed)))
return action
raise ESPHomeYAMLError(u"Unsupported action {}".format(config))
def build_actions(config, arg_type):
return ArrayInitializer(*[build_action(x, arg_type) for x in config])
def build_automation(trigger, arg_type, config):
rhs = App.make_automation(trigger)
obj = Pvariable(Automation.template(arg_type), config[CONF_AUTOMATION_ID], rhs)
if CONF_IF in config:
add(obj.add_conditions(build_conditions(config[CONF_IF], arg_type)))
add(obj.add_actions(build_actions(config[CONF_THEN], arg_type)))

View File

@@ -1,12 +1,13 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_RATE from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_RATE
from esphomeyaml.helpers import App, Pvariable from esphomeyaml.helpers import App, Pvariable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
ADS1115_COMPONENT_CLASS = 'sensor::ADS1115Component' ADS1115Component = sensor.sensor_ns.ADS1115Component
RATE_REMOVE_MESSAGE = """The rate option has been removed in 1.5.0 and is no longer required.""" RATE_REMOVE_MESSAGE = """The rate option has been removed in 1.5.0 and is no longer required."""
@@ -23,7 +24,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [ADS1115_SCHEMA])
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_ads1115_component(conf[CONF_ADDRESS]) rhs = App.make_ads1115_component(conf[CONF_ADDRESS])
Pvariable(ADS1115_COMPONENT_CLASS, conf[CONF_ID], rhs) Pvariable(ADS1115Component, conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_ADS1115_SENSOR' BUILD_FLAGS = '-DUSE_ADS1115_SENSOR'

View File

@@ -1,8 +1,11 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_INVERTED, CONF_MQTT_ID from esphomeyaml import automation
from esphomeyaml.helpers import add, setup_mqtt_component, App, Pvariable 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
DEVICE_CLASSES = [ DEVICE_CLASSES = [
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas', '', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
@@ -11,39 +14,82 @@ DEVICE_CLASSES = [
'sound', 'vibration', 'window' 'sound', 'vibration', 'window'
] ]
DEVICE_CLASSES_MSG = "Unknown device class. Must be one of {}".format(', '.join(DEVICE_CLASSES))
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_INVERTED): cv.boolean,
vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower,
vol.Any(*DEVICE_CLASSES, msg=DEVICE_CLASSES_MSG)),
})
MQTT_BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
}) })
MQTT_BINARY_SENSOR_ID_SCHEMA = MQTT_BINARY_SENSOR_SCHEMA.extend({ binary_sensor_ns = esphomelib_ns.namespace('binary_sensor')
PressTrigger = binary_sensor_ns.PressTrigger
ReleaseTrigger = binary_sensor_ns.ReleaseTrigger
ClickTrigger = binary_sensor_ns.ClickTrigger
DoubleClickTrigger = binary_sensor_ns.DoubleClickTrigger
BinarySensor = binary_sensor_ns.BinarySensor
MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent
BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
cv.GenerateID('mqtt_binary_sensor', CONF_MQTT_ID): cv.register_variable_id, cv.GenerateID('mqtt_binary_sensor', CONF_MQTT_ID): cv.register_variable_id,
cv.GenerateID('binary_sensor'): cv.register_variable_id,
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]),
vol.Optional(CONF_ON_RELEASE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]),
vol.Optional(CONF_ON_CLICK): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
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.Optional(CONF_MIN_LENGTH, default='50ms'): cv.positive_time_period_milliseconds,
vol.Optional(CONF_MAX_LENGTH, default='350ms'): cv.positive_time_period_milliseconds,
})]),
}) })
def setup_binary_sensor(obj, config): def setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config):
if CONF_DEVICE_CLASS in config: if CONF_DEVICE_CLASS in config:
add(obj.set_device_class(config[CONF_DEVICE_CLASS])) add(binary_sensor_var.set_device_class(config[CONF_DEVICE_CLASS]))
if CONF_INVERTED in config: if CONF_INVERTED in config:
add(obj.set_inverted(config[CONF_INVERTED])) add(binary_sensor_var.set_inverted(config[CONF_INVERTED]))
for conf in config.get(CONF_ON_PRESS, []):
rhs = binary_sensor_var.make_press_trigger()
trigger = Pvariable(PressTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_RELEASE, []):
rhs = binary_sensor_var.make_release_trigger()
trigger = Pvariable(ReleaseTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_CLICK, []):
rhs = binary_sensor_var.make_click_trigger(conf[CONF_MIN_LENGTH], conf[CONF_MAX_LENGTH])
trigger = Pvariable(ClickTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_DOUBLE_CLICK, []):
rhs = binary_sensor_var.make_double_click_trigger(conf[CONF_MIN_LENGTH],
conf[CONF_MAX_LENGTH])
trigger = Pvariable(DoubleClickTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
setup_mqtt_component(mqtt_var, config)
def setup_mqtt_binary_sensor(obj, config): def setup_binary_sensor(binary_sensor_obj, mqtt_obj, config):
setup_mqtt_component(obj, config) binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], binary_sensor_obj,
has_side_effects=False)
mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], mqtt_obj,
has_side_effects=False)
setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config)
def register_binary_sensor(var, config): def register_binary_sensor(var, config):
setup_binary_sensor(var, config) binary_sensor_var = Pvariable(BinarySensor, config[CONF_ID], var,
rhs = App.register_binary_sensor(var) has_side_effects=True)
mqtt_sensor = Pvariable('binary_sensor::MQTTBinarySensorComponent', config[CONF_MQTT_ID], rhs) rhs = App.register_binary_sensor(binary_sensor_var)
setup_mqtt_binary_sensor(mqtt_sensor, config) mqtt_var = Pvariable(MQTTBinarySensorComponent, config[CONF_MQTT_ID], rhs,
has_side_effects=True)
setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_BINARY_SENSOR'

View File

@@ -2,9 +2,10 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_ID, CONF_MAC_ADDRESS, CONF_NAME, ESP_PLATFORM_ESP32 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.core import HexInt, MACAddress
from esphomeyaml.helpers import ArrayInitializer, Pvariable, get_variable from esphomeyaml.helpers import ArrayInitializer, get_variable
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_ble'] DEPENDENCIES = ['esp32_ble']
@@ -28,17 +29,15 @@ def validate_mac(value):
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('esp32_ble_device'): cv.register_variable_id,
vol.Required(CONF_MAC_ADDRESS): validate_mac, vol.Required(CONF_MAC_ADDRESS): validate_mac,
}).extend(binary_sensor.MQTT_BINARY_SENSOR_ID_SCHEMA.schema) }).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
hub = get_variable(None, type='ESP32BLETracker') hub = get_variable(None, type=ESP32BLETracker)
addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts] addr = [HexInt(i) for i in config[CONF_MAC_ADDRESS].parts]
rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False)) rhs = hub.make_device(config[CONF_NAME], ArrayInitializer(*addr, multiline=False))
device = Pvariable('ESP32BLEDevice', config[CONF_ID], rhs) binary_sensor.register_binary_sensor(rhs, config)
binary_sensor.register_binary_sensor(device, config)
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER' BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

@@ -2,8 +2,9 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_PIN, CONF_THRESHOLD, ESP_PLATFORM_ESP32 from esphomeyaml.components.esp32_touch import ESP32TouchComponent
from esphomeyaml.helpers import Pvariable, RawExpression, get_variable from esphomeyaml.const import CONF_NAME, CONF_PIN, CONF_THRESHOLD, ESP_PLATFORM_ESP32
from esphomeyaml.helpers import get_variable, global_ns
from esphomeyaml.pins import validate_gpio_pin from esphomeyaml.pins import validate_gpio_pin
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
@@ -11,16 +12,16 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_touch'] DEPENDENCIES = ['esp32_touch']
TOUCH_PADS = { TOUCH_PADS = {
4: 'TOUCH_PAD_NUM0', 4: global_ns.TOUCH_PAD_NUM0,
0: 'TOUCH_PAD_NUM1', 0: global_ns.TOUCH_PAD_NUM1,
2: 'TOUCH_PAD_NUM2', 2: global_ns.TOUCH_PAD_NUM2,
15: 'TOUCH_PAD_NUM3', 15: global_ns.TOUCH_PAD_NUM3,
13: 'TOUCH_PAD_NUM4', 13: global_ns.TOUCH_PAD_NUM4,
12: 'TOUCH_PAD_NUM5', 12: global_ns.TOUCH_PAD_NUM5,
14: 'TOUCH_PAD_NUM6', 14: global_ns.TOUCH_PAD_NUM6,
27: 'TOUCH_PAD_NUM7', 27: global_ns.TOUCH_PAD_NUM7,
33: 'TOUCH_PAD_NUM8', 33: global_ns.TOUCH_PAD_NUM8,
32: 'TOUCH_PAD_NUM9', 32: global_ns.TOUCH_PAD_NUM9,
} }
@@ -32,18 +33,16 @@ def validate_touch_pad(value):
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('esp32_touch_pad'): cv.register_variable_id,
vol.Required(CONF_PIN): validate_touch_pad, vol.Required(CONF_PIN): validate_touch_pad,
vol.Required(CONF_THRESHOLD): cv.uint16_t, vol.Required(CONF_THRESHOLD): cv.uint16_t,
}).extend(binary_sensor.MQTT_BINARY_SENSOR_ID_SCHEMA.schema) }).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
hub = get_variable(None, type='binary_sensor::ESP32TouchComponent') hub = get_variable(None, type=ESP32TouchComponent)
touch_pad = RawExpression(TOUCH_PADS[config[CONF_PIN]]) touch_pad = TOUCH_PADS[config[CONF_PIN]]
rhs = hub.make_touch_pad(config[CONF_NAME], touch_pad, config[CONF_THRESHOLD]) rhs = hub.make_touch_pad(config[CONF_NAME], touch_pad, config[CONF_THRESHOLD])
device = Pvariable('ESP32TouchBinarySensor', config[CONF_ID], rhs) binary_sensor.register_binary_sensor(rhs, config)
binary_sensor.register_binary_sensor(device, config)
BUILD_FLAGS = '-DUSE_ESP32_TOUCH_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_ESP32_TOUCH_BINARY_SENSOR'

View File

@@ -3,22 +3,22 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import binary_sensor from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_ID, CONF_INVERTED, CONF_NAME, CONF_PIN from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN
from esphomeyaml.helpers import App, add, exp_gpio_input_pin, variable from esphomeyaml.helpers import App, gpio_input_pin_expression, variable, Application
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('gpio_binary_sensor'): cv.register_variable_id, cv.GenerateID('gpio_binary_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.GPIO_INPUT_PIN_SCHEMA vol.Required(CONF_PIN): pins.GPIO_INPUT_PIN_SCHEMA
}).extend(binary_sensor.MQTT_BINARY_SENSOR_SCHEMA.schema) }).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
MakeGPIOBinarySensor = Application.MakeGPIOBinarySensor
def to_code(config): def to_code(config):
rhs = App.make_gpio_binary_sensor(config[CONF_NAME], exp_gpio_input_pin(config[CONF_PIN])) rhs = App.make_gpio_binary_sensor(config[CONF_NAME],
gpio = variable('Application::MakeGPIOBinarySensor', config[CONF_ID], rhs) gpio_input_pin_expression(config[CONF_PIN]))
if CONF_INVERTED in config: gpio = variable(MakeGPIOBinarySensor, config[CONF_MAKE_ID], rhs)
add(gpio.Pgpio.set_inverted(config[CONF_INVERTED])) binary_sensor.setup_binary_sensor(gpio.Pgpio, gpio.Pmqtt, config)
binary_sensor.setup_binary_sensor(gpio.Pgpio, config)
binary_sensor.setup_mqtt_binary_sensor(gpio.Pmqtt, config)
BUILD_FLAGS = '-DUSE_GPIO_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_GPIO_BINARY_SENSOR'

View File

@@ -1,20 +1,21 @@
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import binary_sensor from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_ID, CONF_NAME from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME
from esphomeyaml.helpers import App, variable from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['mqtt'] DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('status_binary_sensor'): cv.register_variable_id, cv.GenerateID('status_binary_sensor', CONF_MAKE_ID): cv.register_variable_id,
}).extend(binary_sensor.MQTT_BINARY_SENSOR_SCHEMA.schema) }).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
MakeStatusBinarySensor = Application.MakeStatusBinarySensor
def to_code(config): def to_code(config):
rhs = App.make_status_binary_sensor(config[CONF_NAME]) rhs = App.make_status_binary_sensor(config[CONF_NAME])
status = variable('Application::MakeStatusBinarySensor', config[CONF_ID], rhs) status = variable(MakeStatusBinarySensor, config[CONF_MAKE_ID], rhs)
binary_sensor.setup_binary_sensor(status.Pstatus, config) binary_sensor.setup_binary_sensor(status.Pstatus, status.Pmqtt, config)
binary_sensor.setup_mqtt_binary_sensor(status.Pmqtt, config)
BUILD_FLAGS = '-DUSE_STATUS_BINARY_SENSOR' BUILD_FLAGS = '-DUSE_STATUS_BINARY_SENSOR'

View File

@@ -0,0 +1,23 @@
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
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_binary_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_LAMBDA): cv.lambda_,
}).extend(binary_sensor.BINARY_SENSOR_SCHEMA.schema)
MakeTemplateBinarySensor = Application.MakeTemplateBinarySensor
def to_code(config):
template_ = process_lambda(config[CONF_LAMBDA], [])
rhs = App.make_template_binary_sensor(config[CONF_NAME], template_)
make = variable(MakeTemplateBinarySensor, config[CONF_MAKE_ID], rhs)
binary_sensor.setup_binary_sensor(make.Ptemplate_, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_TEMPLATE_BINARY_SENSOR'

View File

@@ -0,0 +1,36 @@
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
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
})
COVER_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('cover'): cv.register_variable_id,
cv.GenerateID('mqtt_cover', CONF_MQTT_ID): cv.register_variable_id,
})
cover_ns = esphomelib_ns.namespace('cover')
Cover = cover_ns.Cover
MQTTCoverComponent = cover_ns.MQTTCoverComponent
CoverState = cover_ns.CoverState
COVER_OPEN = cover_ns.COVER_OPEN
COVER_CLOSED = cover_ns.COVER_CLOSED
OpenAction = cover_ns.OpenAction
CloseAction = cover_ns.CloseAction
StopAction = cover_ns.StopAction
def setup_cover_core_(cover_var, mqtt_var, config):
setup_mqtt_component(mqtt_var, config)
def setup_cover(cover_obj, mqtt_obj, config):
cover_var = Pvariable(Cover, config[CONF_ID], cover_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTCoverComponent, config[CONF_MQTT_ID], mqtt_obj,
has_side_effects=False)
setup_cover_core_(cover_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_COVER'

View File

@@ -0,0 +1,44 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
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
PLATFORM_SCHEMA = vol.All(cover.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_cover', CONF_MAKE_ID): cv.register_variable_id,
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_OPEN_ACTION): automation.ACTIONS_SCHEMA,
vol.Optional(CONF_CLOSE_ACTION): automation.ACTIONS_SCHEMA,
vol.Optional(CONF_STOP_ACTION): automation.ACTIONS_SCHEMA,
}).extend(cover.COVER_SCHEMA.schema), cv.has_at_exactly_one_key(CONF_LAMBDA, CONF_OPTIMISTIC))
MakeTemplateCover = Application.MakeTemplateCover
def to_code(config):
rhs = App.make_template_cover(config[CONF_NAME])
make = variable(MakeTemplateCover, config[CONF_MAKE_ID], rhs)
if CONF_LAMBDA in config:
template_ = process_lambda(config[CONF_LAMBDA], [])
add(make.Ptemplate.set_state_lambda(template_))
if CONF_OPEN_ACTION in config:
actions = automation.build_actions(config[CONF_OPEN_ACTION], NoArg)
add(make.Ptemplate_.add_open_actions(actions))
if CONF_CLOSE_ACTION in config:
actions = automation.build_actions(config[CONF_CLOSE_ACTION], NoArg)
add(make.Ptemplate_.add_close_actions(actions))
if CONF_STOP_ACTION in config:
actions = automation.build_actions(config[CONF_STOP_ACTION], NoArg)
add(make.Ptemplate_.add_stop_actions(actions))
if CONF_OPTIMISTIC in config:
add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC]))
cover.setup_cover(make.Ptemplate_, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_TEMPLATE_COVER'

View File

@@ -2,10 +2,11 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ID, CONF_PIN, CONF_UPDATE_INTERVAL from esphomeyaml.const import CONF_ID, CONF_PIN, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Pvariable from esphomeyaml.helpers import App, Pvariable
DALLAS_COMPONENT_CLASS = 'sensor::DallasComponent' DallasComponent = sensor.sensor_ns.DallasComponent
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
cv.GenerateID('dallas'): cv.register_variable_id, cv.GenerateID('dallas'): cv.register_variable_id,
@@ -17,7 +18,7 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_dallas_component(conf[CONF_PIN], conf.get(CONF_UPDATE_INTERVAL)) rhs = App.make_dallas_component(conf[CONF_PIN], conf.get(CONF_UPDATE_INTERVAL))
Pvariable(DALLAS_COMPONENT_CLASS, conf[CONF_ID], rhs) Pvariable(DallasComponent, conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_DALLAS_SENSOR' BUILD_FLAGS = '-DUSE_DALLAS_SENSOR'

View File

@@ -1,14 +1,14 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import config_validation as cv, pins from esphomeyaml import config_validation as cv, pins
from esphomeyaml.const import CONF_ID, CONF_RUN_CYCLES, CONF_RUN_DURATION, CONF_SLEEP_DURATION, \ from esphomeyaml.const import CONF_ID, CONF_NUMBER, CONF_RUN_CYCLES, CONF_RUN_DURATION, \
CONF_WAKEUP_PIN CONF_SLEEP_DURATION, CONF_WAKEUP_PIN
from esphomeyaml.helpers import App, Pvariable, add, exp_gpio_input_pin from esphomeyaml.helpers import App, Pvariable, add, gpio_input_pin_expression, esphomelib_ns
def validate_pin_number(value): def validate_pin_number(value):
valid_pins = [0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 39] valid_pins = [0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 39]
if value not in valid_pins: if value[CONF_NUMBER] not in valid_pins:
raise vol.Invalid(u"Only pins {} support wakeup" raise vol.Invalid(u"Only pins {} support wakeup"
u"".format(', '.join(str(x) for x in valid_pins))) u"".format(', '.join(str(x) for x in valid_pins)))
return value return value
@@ -17,20 +17,22 @@ def validate_pin_number(value):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('deep_sleep'): cv.register_variable_id, cv.GenerateID('deep_sleep'): cv.register_variable_id,
vol.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds, vol.Optional(CONF_SLEEP_DURATION): cv.positive_time_period_milliseconds,
vol.Optional(CONF_WAKEUP_PIN): vol.All(cv.only_on_esp32, pins.GPIO_INPUT_PIN_SCHEMA, vol.Optional(CONF_WAKEUP_PIN): vol.All(cv.only_on_esp32, pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
pins.schema_validate_number(validate_pin_number)), validate_pin_number),
vol.Optional(CONF_RUN_CYCLES): cv.positive_int, vol.Optional(CONF_RUN_CYCLES): cv.positive_int,
vol.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds, vol.Optional(CONF_RUN_DURATION): cv.positive_time_period_milliseconds,
}) })
DeepSleepComponent = esphomelib_ns.DeepSleepComponent
def to_code(config): def to_code(config):
rhs = App.make_deep_sleep_component() rhs = App.make_deep_sleep_component()
deep_sleep = Pvariable('DeepSleepComponent', config[CONF_ID], rhs) deep_sleep = Pvariable(DeepSleepComponent, config[CONF_ID], rhs)
if CONF_SLEEP_DURATION in config: if CONF_SLEEP_DURATION in config:
add(deep_sleep.set_sleep_duration(config[CONF_SLEEP_DURATION])) add(deep_sleep.set_sleep_duration(config[CONF_SLEEP_DURATION]))
if CONF_WAKEUP_PIN in config: if CONF_WAKEUP_PIN in config:
pin = exp_gpio_input_pin(config[CONF_WAKEUP_PIN]) pin = gpio_input_pin_expression(config[CONF_WAKEUP_PIN])
add(deep_sleep.set_wakeup_pin(pin)) add(deep_sleep.set_wakeup_pin(pin))
if CONF_RUN_CYCLES in config: if CONF_RUN_CYCLES in config:
add(deep_sleep.set_run_cycles(config[CONF_RUN_CYCLES])) add(deep_sleep.set_run_cycles(config[CONF_RUN_CYCLES]))

View File

@@ -2,7 +2,7 @@ import voluptuous as vol
from esphomeyaml import config_validation as cv from esphomeyaml import config_validation as cv
from esphomeyaml.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32 from esphomeyaml.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, Pvariable, add from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
@@ -11,10 +11,12 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_milliseconds,
}) })
ESP32BLETracker = esphomelib_ns.ESP32BLETracker
def to_code(config): def to_code(config):
rhs = App.make_esp32_ble_tracker() rhs = App.make_esp32_ble_tracker()
ble = Pvariable('ESP32BLETracker', config[CONF_ID], rhs) ble = Pvariable(ESP32BLETracker, config[CONF_ID], rhs)
if CONF_SCAN_INTERVAL in config: if CONF_SCAN_INTERVAL in config:
add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL])) add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL]))

View File

@@ -1,11 +1,12 @@
import voluptuous as vol import voluptuous as vol
from esphomeyaml import config_validation as cv from esphomeyaml import config_validation as cv
from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_ID, CONF_SETUP_MODE, CONF_IIR_FILTER, \ from esphomeyaml.const import CONF_ID, CONF_SETUP_MODE, CONF_IIR_FILTER, \
CONF_SLEEP_DURATION, CONF_MEASUREMENT_DURATION, CONF_LOW_VOLTAGE_REFERENCE, \ CONF_SLEEP_DURATION, CONF_MEASUREMENT_DURATION, CONF_LOW_VOLTAGE_REFERENCE, \
CONF_HIGH_VOLTAGE_REFERENCE, CONF_VOLTAGE_ATTENUATION, ESP_PLATFORM_ESP32 CONF_HIGH_VOLTAGE_REFERENCE, CONF_VOLTAGE_ATTENUATION, ESP_PLATFORM_ESP32
from esphomeyaml.core import TimePeriod from esphomeyaml.core import TimePeriod
from esphomeyaml.helpers import App, Pvariable, add from esphomeyaml.helpers import App, Pvariable, add, global_ns
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
@@ -17,29 +18,27 @@ def validate_voltage(values):
value = cv.string(value) value = cv.string(value)
if not value.endswith('V'): if not value.endswith('V'):
value += 'V' value += 'V'
if value not in values: return cv.one_of(*values)(value)
raise vol.Invalid('Must be one of {}'.format(values))
return value
return validator return validator
LOW_VOLTAGE_REFERENCE = { LOW_VOLTAGE_REFERENCE = {
'0.5V': 'TOUCH_LVOLT_0V5', '0.5V': global_ns.TOUCH_LVOLT_0V5,
'0.6V': 'TOUCH_LVOLT_0V6', '0.6V': global_ns.TOUCH_LVOLT_0V6,
'0.7V': 'TOUCH_LVOLT_0V7', '0.7V': global_ns.TOUCH_LVOLT_0V7,
'0.8V': 'TOUCH_LVOLT_0V8', '0.8V': global_ns.TOUCH_LVOLT_0V8,
} }
HIGH_VOLTAGE_REFERENCE = { HIGH_VOLTAGE_REFERENCE = {
'2.4V': 'TOUCH_HVOLT_2V4', '2.4V': global_ns.TOUCH_HVOLT_2V4,
'2.5V': 'TOUCH_HVOLT_2V5', '2.5V': global_ns.TOUCH_HVOLT_2V5,
'2.6V': 'TOUCH_HVOLT_2V6', '2.6V': global_ns.TOUCH_HVOLT_2V6,
'2.7V': 'TOUCH_HVOLT_2V7', '2.7V': global_ns.TOUCH_HVOLT_2V7,
} }
VOLTAGE_ATTENUATION = { VOLTAGE_ATTENUATION = {
'1.5V': 'TOUCH_HVOLT_ATTEN_1V5', '1.5V': global_ns.TOUCH_HVOLT_ATTEN_1V5,
'1V': 'TOUCH_HVOLT_ATTEN_1V', '1V': global_ns.TOUCH_HVOLT_ATTEN_1V,
'0.5V': 'TOUCH_HVOLT_ATTEN_0V5', '0.5V': global_ns.TOUCH_HVOLT_ATTEN_0V5,
'0V': 'TOUCH_HVOLT_ATTEN_0V', '0V': global_ns.TOUCH_HVOLT_ATTEN_0V,
} }
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
@@ -55,10 +54,12 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_VOLTAGE_ATTENUATION): validate_voltage(VOLTAGE_ATTENUATION), vol.Optional(CONF_VOLTAGE_ATTENUATION): validate_voltage(VOLTAGE_ATTENUATION),
}) })
ESP32TouchComponent = binary_sensor.binary_sensor_ns.ESP32TouchComponent
def to_code(config): def to_code(config):
rhs = App.make_esp32_touch_component() rhs = App.make_esp32_touch_component()
touch = Pvariable('binary_sensor::ESP32TouchComponent', config[CONF_ID], rhs) touch = Pvariable(ESP32TouchComponent, config[CONF_ID], rhs)
if CONF_SETUP_MODE in config: if CONF_SETUP_MODE in config:
add(touch.set_setup_mode(config[CONF_SETUP_MODE])) add(touch.set_setup_mode(config[CONF_SETUP_MODE]))
if CONF_IIR_FILTER in config: if CONF_IIR_FILTER in config:

View File

@@ -1,26 +1,63 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_OSCILLATION_COMMAND_TOPIC, CONF_OSCILLATION_STATE_TOPIC, \ from esphomeyaml.const import CONF_ID, CONF_MQTT_ID, CONF_OSCILLATION_COMMAND_TOPIC, \
CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC CONF_OSCILLATION_STATE_TOPIC, CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC
from esphomeyaml.helpers import add, setup_mqtt_component from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
})
FAN_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('fan'): cv.register_variable_id,
cv.GenerateID('mqtt_fan', CONF_MQTT_ID): cv.register_variable_id,
vol.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.publish_topic, vol.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.publish_topic,
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic, vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): cv.subscribe_topic,
}).extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA.schema) })
fan_ns = esphomelib_ns.namespace('fan')
FanState = fan_ns.FanState
MQTTFanComponent = fan_ns.MQTTFanComponent
MakeFan = Application.MakeFan
TurnOnAction = fan_ns.TurnOnAction
TurnOffAction = fan_ns.TurnOffAction
ToggleAction = fan_ns.ToggleAction
FanSpeed = fan_ns.FanSpeed
FAN_SPEED_OFF = fan_ns.FAN_SPEED_OFF
FAN_SPEED_LOW = fan_ns.FAN_SPEED_LOW
FAN_SPEED_MEDIUM = fan_ns.FAN_SPEED_MEDIUM
FAN_SPEED_HIGH = fan_ns.FAN_SPEED_HIGH
def setup_mqtt_fan(obj, config): FAN_SPEEDS = {
'OFF': FAN_SPEED_OFF,
'LOW': FAN_SPEED_LOW,
'MEDIUM': FAN_SPEED_MEDIUM,
'HIGH': FAN_SPEED_HIGH,
}
def validate_fan_speed(value):
return vol.All(vol.Upper, cv.one_of(*FAN_SPEEDS))(value)
def setup_fan_core_(fan_var, mqtt_var, config):
if CONF_OSCILLATION_STATE_TOPIC in config: if CONF_OSCILLATION_STATE_TOPIC in config:
add(obj.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC])) add(mqtt_var.set_custom_oscillation_state_topic(config[CONF_OSCILLATION_STATE_TOPIC]))
if CONF_OSCILLATION_COMMAND_TOPIC in config: if CONF_OSCILLATION_COMMAND_TOPIC in config:
add(obj.set_custom_oscillation_command_topic(config[CONF_OSCILLATION_COMMAND_TOPIC])) add(mqtt_var.set_custom_oscillation_command_topic(config[CONF_OSCILLATION_COMMAND_TOPIC]))
if CONF_SPEED_STATE_TOPIC in config: if CONF_SPEED_STATE_TOPIC in config:
add(obj.set_custom_speed_state_topic(config[CONF_SPEED_STATE_TOPIC])) add(mqtt_var.set_custom_speed_state_topic(config[CONF_SPEED_STATE_TOPIC]))
if CONF_SPEED_COMMAND_TOPIC in config: if CONF_SPEED_COMMAND_TOPIC in config:
add(obj.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC])) add(mqtt_var.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC]))
setup_mqtt_component(obj, config) setup_mqtt_component(mqtt_var, config)
def setup_fan(fan_obj, mqtt_obj, config):
fan_var = Pvariable(FanState, config[CONF_ID], fan_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTFanComponent, config[CONF_MQTT_ID], mqtt_obj, has_side_effects=False)
setup_fan_core_(fan_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_FAN' BUILD_FLAGS = '-DUSE_FAN'

View File

@@ -2,22 +2,23 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import fan from esphomeyaml.components import fan
from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT
from esphomeyaml.helpers import App, add, get_variable, variable from esphomeyaml.helpers import App, add, get_variable, variable
PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
cv.GenerateID('binary_fan'): cv.register_variable_id, cv.GenerateID('binary_fan', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.variable_id,
vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id, vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id,
}) }).extend(fan.FAN_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = get_variable(config[CONF_OUTPUT])
rhs = App.make_fan(config[CONF_NAME]) rhs = App.make_fan(config[CONF_NAME])
fan_struct = variable('Application::MakeFan', config[CONF_ID], rhs) fan_struct = variable(fan.MakeFan, config[CONF_MAKE_ID], rhs)
add(fan_struct.Poutput.set_binary(output)) add(fan_struct.Poutput.set_binary(output))
if CONF_OSCILLATION_OUTPUT in config: if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT]) oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT])
add(fan_struct.Poutput.set_oscillation(oscillation_output)) add(fan_struct.Poutput.set_oscillation(oscillation_output))
fan.setup_mqtt_fan(fan_struct.Pmqtt, config)
fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config)

View File

@@ -2,29 +2,29 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import fan from esphomeyaml.components import fan
from esphomeyaml.const import CONF_HIGH, CONF_ID, CONF_LOW, \ from esphomeyaml.const import CONF_HIGH, CONF_LOW, CONF_MAKE_ID, CONF_MEDIUM, CONF_NAME, \
CONF_MEDIUM, CONF_NAME, CONF_OSCILLATION_OUTPUT, CONF_OUTPUT, CONF_SPEED, \ CONF_OSCILLATION_OUTPUT, CONF_OUTPUT, CONF_SPEED, CONF_SPEED_COMMAND_TOPIC, \
CONF_SPEED_COMMAND_TOPIC, CONF_SPEED_STATE_TOPIC CONF_SPEED_STATE_TOPIC
from esphomeyaml.helpers import App, add, get_variable, variable from esphomeyaml.helpers import App, add, get_variable, variable
PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
cv.GenerateID('speed_fan'): cv.register_variable_id, cv.GenerateID('speed_fan', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.variable_id,
vol.Optional(CONF_SPEED_STATE_TOPIC): cv.publish_topic, vol.Optional(CONF_SPEED_STATE_TOPIC): cv.publish_topic,
vol.Optional(CONF_SPEED_COMMAND_TOPIC): cv.subscribe_topic, vol.Optional(CONF_SPEED_COMMAND_TOPIC): cv.subscribe_topic,
vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id, vol.Optional(CONF_OSCILLATION_OUTPUT): cv.variable_id,
vol.Optional(CONF_SPEED): vol.Schema({ vol.Optional(CONF_SPEED): vol.Schema({
vol.Required(CONF_LOW): cv.zero_to_one_float, vol.Required(CONF_LOW): cv.percentage,
vol.Required(CONF_MEDIUM): cv.zero_to_one_float, vol.Required(CONF_MEDIUM): cv.percentage,
vol.Required(CONF_HIGH): cv.zero_to_one_float, vol.Required(CONF_HIGH): cv.percentage,
}), }),
}) }).extend(fan.FAN_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = get_variable(config[CONF_OUTPUT])
rhs = App.make_fan(config[CONF_NAME]) rhs = App.make_fan(config[CONF_NAME])
fan_struct = variable('Application::MakeFan', config[CONF_ID], rhs) fan_struct = variable(fan.MakeFan, config[CONF_MAKE_ID], rhs)
if CONF_SPEED in config: if CONF_SPEED in config:
speeds = config[CONF_SPEED] speeds = config[CONF_SPEED]
add(fan_struct.Poutput.set_speed(output, 0.0, add(fan_struct.Poutput.set_speed(output, 0.0,
@@ -37,4 +37,5 @@ def to_code(config):
if CONF_OSCILLATION_OUTPUT in config: if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT]) oscillation_output = get_variable(config[CONF_OSCILLATION_OUTPUT])
add(fan_struct.Poutput.set_oscillation(oscillation_output)) add(fan_struct.Poutput.set_oscillation(oscillation_output))
fan.setup_mqtt_fan(fan_struct.Pmqtt, config)
fan.setup_fan(fan_struct.Pstate, fan_struct.Pmqtt, config)

View File

@@ -4,7 +4,7 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.const import CONF_FREQUENCY, CONF_SCL, CONF_SDA, CONF_SCAN, CONF_ID, \ from esphomeyaml.const import CONF_FREQUENCY, CONF_SCL, CONF_SDA, CONF_SCAN, CONF_ID, \
CONF_RECEIVE_TIMEOUT CONF_RECEIVE_TIMEOUT
from esphomeyaml.helpers import App, add, Pvariable from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('i2c'): cv.register_variable_id, cv.GenerateID('i2c'): cv.register_variable_id,
@@ -15,10 +15,12 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_SCAN): cv.boolean, vol.Optional(CONF_SCAN): cv.boolean,
}) })
I2CComponent = esphomelib_ns.I2CComponent
def to_code(config): def to_code(config):
rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN)) rhs = App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_SCAN))
i2c = Pvariable('I2CComponent', config[CONF_ID], rhs) i2c = Pvariable(I2CComponent, config[CONF_ID], rhs)
if CONF_FREQUENCY in config: if CONF_FREQUENCY in config:
add(i2c.set_frequency(config[CONF_FREQUENCY])) add(i2c.set_frequency(config[CONF_FREQUENCY]))
if CONF_RECEIVE_TIMEOUT in config: if CONF_RECEIVE_TIMEOUT in config:

View File

@@ -2,10 +2,9 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import switch
from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN from esphomeyaml.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, exp_gpio_output_pin from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
IR_TRANSMITTER_COMPONENT_CLASS = 'switch_::IRTransmitterComponent'
CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
cv.GenerateID('ir_transmitter'): cv.register_variable_id, cv.GenerateID('ir_transmitter'): cv.register_variable_id,
@@ -14,12 +13,14 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [vol.Schema({
vol.Range(min=1, max=100)), vol.Range(min=1, max=100)),
})]) })])
IRTransmitterComponent = switch.switch_ns.namespace('IRTransmitterComponent')
def to_code(config): def to_code(config):
for conf in config: for conf in config:
pin = exp_gpio_output_pin(conf[CONF_PIN]) pin = gpio_output_pin_expression(conf[CONF_PIN])
rhs = App.make_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT)) rhs = App.make_ir_transmitter(pin, conf.get(CONF_CARRIER_DUTY_PERCENT))
Pvariable(IR_TRANSMITTER_COMPONENT_CLASS, conf[CONF_ID], rhs) Pvariable(IRTransmitterComponent, conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER' BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'

View File

@@ -1,17 +1,40 @@
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \
from esphomeyaml.helpers import add CONF_MQTT_ID
from esphomeyaml.helpers import Application, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}).extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA.schema) })
LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID('light'): cv.register_variable_id,
cv.GenerateID('mqtt_light', CONF_MQTT_ID): cv.register_variable_id,
})
light_ns = esphomelib_ns.namespace('light')
LightState = light_ns.LightState
MQTTJSONLightComponent = light_ns.MQTTJSONLightComponent
ToggleAction = light_ns.ToggleAction
TurnOffAction = light_ns.TurnOffAction
TurnOnAction = light_ns.TurnOnAction
MakeLight = Application.MakeLight
def setup_light_component(obj, config): def setup_light_core_(light_var, mqtt_var, config):
if CONF_DEFAULT_TRANSITION_LENGTH in config: if CONF_DEFAULT_TRANSITION_LENGTH in config:
add(obj.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH])) add(light_var.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH]))
if CONF_GAMMA_CORRECT in config: if CONF_GAMMA_CORRECT in config:
add(obj.set_gamma_correct(config[CONF_GAMMA_CORRECT])) add(light_var.set_gamma_correct(config[CONF_GAMMA_CORRECT]))
setup_mqtt_component(mqtt_var, config)
def setup_light(light_obj, mqtt_obj, config):
light_var = Pvariable(LightState, config[CONF_ID], light_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTJSONLightComponent, config[CONF_MQTT_ID], mqtt_obj,
has_side_effects=False)
setup_light_core_(light_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_LIGHT' BUILD_FLAGS = '-DUSE_LIGHT'

View File

@@ -1,20 +1,18 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_OUTPUT from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, get_variable, variable, setup_mqtt_component from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('binary_light'): cv.register_variable_id, cv.GenerateID('binary_light', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.variable_id,
}) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = get_variable(config[CONF_OUTPUT])
rhs = App.make_binary_light(config[CONF_NAME], output) rhs = App.make_binary_light(config[CONF_NAME], output)
light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs)
setup_mqtt_component(light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View File

@@ -4,9 +4,10 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.const import CONF_CHIPSET, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ from esphomeyaml.const import CONF_CHIPSET, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \
CONF_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, CONF_NUM_LEDS, CONF_PIN, CONF_RGB_ORDER CONF_MAKE_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, CONF_NUM_LEDS, CONF_PIN, CONF_POWER_SUPPLY, \
from esphomeyaml.helpers import App, RawExpression, TemplateArguments, add, setup_mqtt_component, \ CONF_RGB_ORDER
variable from esphomeyaml.helpers import App, Application, RawExpression, TemplateArguments, add, \
get_variable, variable
TYPES = [ TYPES = [
'NEOPIXEL', 'NEOPIXEL',
@@ -52,23 +53,26 @@ def validate(value):
PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(light.PLATFORM_SCHEMA.extend({
cv.GenerateID('fast_led_clockless_light'): cv.register_variable_id, cv.GenerateID('fast_led_clockless_light', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_CHIPSET): vol.All(vol.Upper, vol.Any(*TYPES)), vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*TYPES)),
vol.Required(CONF_PIN): pins.output_pin, vol.Required(CONF_PIN): pins.output_pin,
vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int, vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, vol.Any(*RGB_ORDERS)), vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, cv.one_of(*RGB_ORDERS)),
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}), validate) vol.Optional(CONF_POWER_SUPPLY): cv.variable_id,
}).extend(light.LIGHT_SCHEMA.schema), validate)
MakeFastLEDLight = Application.MakeFastLEDLight
def to_code(config): def to_code(config):
rhs = App.make_fast_led_light(config[CONF_NAME]) rhs = App.make_fast_led_light(config[CONF_NAME])
make = variable('Application::MakeFastLEDLight', config[CONF_ID], rhs) make = variable(MakeFastLEDLight, config[CONF_MAKE_ID], rhs)
fast_led = make.Pfast_led fast_led = make.Pfast_led
rgb_order = None rgb_order = None
@@ -81,8 +85,11 @@ def to_code(config):
if CONF_MAX_REFRESH_RATE in config: if CONF_MAX_REFRESH_RATE in config:
add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
setup_mqtt_component(make.Pmqtt, config) if CONF_POWER_SUPPLY in config:
light.setup_light_component(make.Pstate, config) power_supply = get_variable(config[CONF_POWER_SUPPLY])
add(fast_led.set_power_supply(power_supply))
light.setup_light(make.Pstate, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_FAST_LED_LIGHT' BUILD_FLAGS = '-DUSE_FAST_LED_LIGHT'

View File

@@ -4,10 +4,10 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, \ from esphomeyaml.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, \
CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, CONF_MAX_REFRESH_RATE, CONF_NAME, \ CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_MAKE_ID, CONF_MAX_REFRESH_RATE, \
CONF_NUM_LEDS, CONF_RGB_ORDER CONF_NAME, CONF_NUM_LEDS, CONF_POWER_SUPPLY, CONF_RGB_ORDER
from esphomeyaml.helpers import App, TemplateArguments, add, setup_mqtt_component, variable, \ from esphomeyaml.helpers import App, Application, RawExpression, TemplateArguments, add, \
RawExpression get_variable, variable
CHIPSETS = [ CHIPSETS = [
'LPD8806', 'LPD8806',
@@ -30,24 +30,27 @@ RGB_ORDERS = [
] ]
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('fast_led_spi_light'): cv.register_variable_id, cv.GenerateID('fast_led_spi_light', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_CHIPSET): vol.All(vol.Upper, vol.Any(*CHIPSETS)), vol.Required(CONF_CHIPSET): vol.All(vol.Upper, cv.one_of(*CHIPSETS)),
vol.Required(CONF_DATA_PIN): pins.output_pin, vol.Required(CONF_DATA_PIN): pins.output_pin,
vol.Required(CONF_CLOCK_PIN): pins.output_pin, vol.Required(CONF_CLOCK_PIN): pins.output_pin,
vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int, vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, vol.Any(*RGB_ORDERS)), vol.Optional(CONF_RGB_ORDER): vol.All(vol.Upper, cv.one_of(*RGB_ORDERS)),
vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, vol.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}) vol.Optional(CONF_POWER_SUPPLY): cv.variable_id,
}).extend(light.LIGHT_SCHEMA.schema)
MakeFastLEDLight = Application.MakeFastLEDLight
def to_code(config): def to_code(config):
rhs = App.make_fast_led_light(config[CONF_NAME]) rhs = App.make_fast_led_light(config[CONF_NAME])
make = variable('Application::MakeFastLEDLight', config[CONF_ID], rhs) make = variable(MakeFastLEDLight, config[CONF_MAKE_ID], rhs)
fast_led = make.Pfast_led fast_led = make.Pfast_led
rgb_order = None rgb_order = None
@@ -62,8 +65,11 @@ def to_code(config):
if CONF_MAX_REFRESH_RATE in config: if CONF_MAX_REFRESH_RATE in config:
add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) add(fast_led.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
setup_mqtt_component(make.Pmqtt, config) if CONF_POWER_SUPPLY in config:
light.setup_light_component(make.Pstate, config) power_supply = get_variable(config[CONF_POWER_SUPPLY])
add(fast_led.set_power_supply(power_supply))
light.setup_light(make.Pstate, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_FAST_LED_LIGHT' BUILD_FLAGS = '-DUSE_FAST_LED_LIGHT'

View File

@@ -2,21 +2,20 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, \ from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_MAKE_ID, \
CONF_NAME, CONF_OUTPUT CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, get_variable, setup_mqtt_component, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('monochromatic_light'): cv.register_variable_id, cv.GenerateID('monochromatic_light', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.variable_id,
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = get_variable(config[CONF_OUTPUT])
rhs = App.make_monochromatic_light(config[CONF_NAME], output) rhs = App.make_monochromatic_light(config[CONF_NAME], output)
light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs)
setup_mqtt_component(light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View File

@@ -3,17 +3,17 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \
CONF_GREEN, CONF_ID, CONF_NAME, CONF_RED CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED
from esphomeyaml.helpers import App, get_variable, setup_mqtt_component, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('rgb_light'): cv.register_variable_id, cv.GenerateID('rgb_light', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_RED): cv.variable_id, vol.Required(CONF_RED): cv.variable_id,
vol.Required(CONF_GREEN): cv.variable_id, vol.Required(CONF_GREEN): cv.variable_id,
vol.Required(CONF_BLUE): cv.variable_id, vol.Required(CONF_BLUE): cv.variable_id,
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
@@ -21,6 +21,5 @@ def to_code(config):
green = get_variable(config[CONF_GREEN]) green = get_variable(config[CONF_GREEN])
blue = get_variable(config[CONF_BLUE]) blue = get_variable(config[CONF_BLUE])
rhs = App.make_rgb_light(config[CONF_NAME], red, green, blue) rhs = App.make_rgb_light(config[CONF_NAME], red, green, blue)
light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs)
setup_mqtt_component(light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View File

@@ -3,18 +3,18 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import light from esphomeyaml.components import light
from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \ from esphomeyaml.const import CONF_BLUE, CONF_DEFAULT_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, \
CONF_GREEN, CONF_ID, CONF_NAME, CONF_RED, CONF_WHITE CONF_GREEN, CONF_MAKE_ID, CONF_NAME, CONF_RED, CONF_WHITE
from esphomeyaml.helpers import App, get_variable, setup_mqtt_component, variable from esphomeyaml.helpers import App, get_variable, variable
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('rgbw_light'): cv.register_variable_id, cv.GenerateID('rgbw_light', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_RED): cv.variable_id, vol.Required(CONF_RED): cv.variable_id,
vol.Required(CONF_GREEN): cv.variable_id, vol.Required(CONF_GREEN): cv.variable_id,
vol.Required(CONF_BLUE): cv.variable_id, vol.Required(CONF_BLUE): cv.variable_id,
vol.Required(CONF_WHITE): cv.variable_id, vol.Required(CONF_WHITE): cv.variable_id,
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float, vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds, vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
}) }).extend(light.LIGHT_SCHEMA.schema)
def to_code(config): def to_code(config):
@@ -23,6 +23,5 @@ def to_code(config):
blue = get_variable(config[CONF_BLUE]) blue = get_variable(config[CONF_BLUE])
white = get_variable(config[CONF_WHITE]) white = get_variable(config[CONF_WHITE])
rhs = App.make_rgbw_light(config[CONF_NAME], red, green, blue, white) rhs = App.make_rgbw_light(config[CONF_NAME], red, green, blue, white)
light_struct = variable('Application::MakeLight', config[CONF_ID], rhs) light_struct = variable(light.MakeLight, config[CONF_MAKE_ID], rhs)
setup_mqtt_component(light_struct.Pmqtt, config) light.setup_light(light_struct.Pstate, light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View File

@@ -4,14 +4,34 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, \ from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, \
CONF_TX_BUFFER_SIZE CONF_TX_BUFFER_SIZE
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, Pvariable, RawExpression, add from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, global_ns
LOG_LEVELS = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE'] LOG_LEVELS = {
'NONE': global_ns.ESPHOMELIB_LOG_LEVEL_NONE,
'ERROR': global_ns.ESPHOMELIB_LOG_LEVEL_ERROR,
'WARN': global_ns.ESPHOMELIB_LOG_LEVEL_WARN,
'INFO': global_ns.ESPHOMELIB_LOG_LEVEL_INFO,
'DEBUG': global_ns.ESPHOMELIB_LOG_LEVEL_DEBUG,
'VERBOSE': global_ns.ESPHOMELIB_LOG_LEVEL_VERBOSE,
'VERY_VERBOSE': global_ns.ESPHOMELIB_LOG_LEVEL_VERY_VERBOSE,
}
LOG_LEVEL_SEVERITY = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE']
# pylint: disable=invalid-name # pylint: disable=invalid-name
is_log_level = vol.All(vol.Upper, vol.Any(*LOG_LEVELS)) is_log_level = vol.All(vol.Upper, cv.one_of(*LOG_LEVELS))
CONFIG_SCHEMA = vol.Schema({
def validate_local_no_higher_than_global(value):
global_level = value.get(CONF_LEVEL, 'DEBUG')
for tag, level in value.get(CONF_LOGS, {}).iteritems():
if LOG_LEVEL_SEVERITY.index(level) > LOG_LEVEL_SEVERITY.index(global_level):
raise ESPHomeYAMLError(u"The local log level {} for {} must be less severe than the "
u"global log level {}.".format(level, tag, global_level))
return value
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(CONF_LOGGER): cv.register_variable_id, cv.GenerateID(CONF_LOGGER): cv.register_variable_id,
vol.Optional(CONF_BAUD_RATE): cv.positive_int, vol.Optional(CONF_BAUD_RATE): cv.positive_int,
vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int, vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int,
@@ -19,33 +39,23 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_LOGS): vol.Schema({ vol.Optional(CONF_LOGS): vol.Schema({
cv.string: is_log_level, cv.string: is_log_level,
}) })
}) }), validate_local_no_higher_than_global)
LogComponent = esphomelib_ns.LogComponent
def esphomelib_log_level(level):
return u'ESPHOMELIB_LOG_LEVEL_{}'.format(level)
def exp_log_level(level):
return RawExpression(esphomelib_log_level(level))
def to_code(config): def to_code(config):
rhs = App.init_log(config.get(CONF_BAUD_RATE)) rhs = App.init_log(config.get(CONF_BAUD_RATE))
log = Pvariable(u'LogComponent', config[CONF_ID], rhs) log = Pvariable(LogComponent, config[CONF_ID], rhs)
if CONF_TX_BUFFER_SIZE in config: if CONF_TX_BUFFER_SIZE in config:
add(log.set_tx_buffer_size(config[CONF_TX_BUFFER_SIZE])) add(log.set_tx_buffer_size(config[CONF_TX_BUFFER_SIZE]))
if CONF_LEVEL in config: if CONF_LEVEL in config:
add(log.set_global_log_level(exp_log_level(config[CONF_LEVEL]))) add(log.set_global_log_level(LOG_LEVELS[config[CONF_LEVEL]]))
for tag, level in config.get(CONF_LOGS, {}).iteritems(): for tag, level in config.get(CONF_LOGS, {}).iteritems():
global_level = config.get(CONF_LEVEL, 'DEBUG') add(log.set_log_level(tag, LOG_LEVELS[level]))
if LOG_LEVELS.index(level) > LOG_LEVELS.index(global_level):
raise ESPHomeYAMLError(u"The local log level {} for {} must be less severe than the "
u"global log level {}.".format(level, tag, global_level))
add(log.set_log_level(tag, exp_log_level(level)))
def required_build_flags(config): def required_build_flags(config):
if CONF_LEVEL in config: if CONF_LEVEL in config:
return u'-DESPHOMELIB_LOG_LEVEL={}'.format(esphomelib_log_level(config[CONF_LEVEL])) return u'-DESPHOMELIB_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]]))
return None return None

View File

@@ -3,12 +3,14 @@ import re
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import automation
from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \ from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_SSL_FINGERPRINTS, CONF_ID, CONF_LOG_TOPIC, \ CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LOG_TOPIC, \
CONF_MQTT, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, CONF_TOPIC, \ CONF_MQTT, CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, \
CONF_TOPIC_PREFIX, CONF_USERNAME, CONF_WILL_MESSAGE, CONF_KEEPALIVE CONF_SSL_FINGERPRINTS, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, \
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, add, \ CONF_WILL_MESSAGE
exp_empty_optional, RawExpression from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, \
TemplateArguments, add, esphomelib_ns, optional, std_string, RawExpression
def validate_message_just_topic(value): def validate_message_just_topic(value):
@@ -18,7 +20,7 @@ def validate_message_just_topic(value):
MQTT_MESSAGE_BASE = vol.Schema({ MQTT_MESSAGE_BASE = vol.Schema({
vol.Required(CONF_TOPIC): cv.publish_topic, vol.Required(CONF_TOPIC): cv.publish_topic,
vol.Optional(CONF_QOS, default=0): vol.All(vol.Coerce(int), vol.In([0, 1, 2])), vol.Optional(CONF_QOS, default=0): cv.mqtt_qos,
vol.Optional(CONF_RETAIN, default=True): cv.boolean, vol.Optional(CONF_RETAIN, default=True): cv.boolean,
}) })
@@ -28,12 +30,15 @@ MQTT_MESSAGE_SCHEMA = vol.Any(None, MQTT_MESSAGE_BASE.extend({
vol.Required(CONF_PAYLOAD): cv.mqtt_payload, vol.Required(CONF_PAYLOAD): cv.mqtt_payload,
})) }))
mqtt_ns = esphomelib_ns.namespace('mqtt')
MQTTMessage = mqtt_ns.MQTTMessage
MQTTClientComponent = mqtt_ns.MQTTClientComponent
MQTTPublishAction = mqtt_ns.MQTTPublishAction
MQTTMessageTrigger = mqtt_ns.MQTTMessageTrigger
def validate_broker(value): def validate_broker(value):
value = cv.string_strict(value) value = cv.string_strict(value)
if value.endswith(u'.local'):
raise vol.Invalid(u"MQTT server addresses ending with '.local' are currently unsupported."
u" Please use the static IP instead.")
if u':' in value: if u':' in value:
raise vol.Invalid(u"Please specify the port using the port: option") raise vol.Invalid(u"Please specify the port using the port: option")
if not value: if not value:
@@ -65,14 +70,18 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266, vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266,
cv.ensure_list, [validate_fingerprint]), cv.ensure_list, [validate_fingerprint]),
vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds, vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds,
vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA.extend({
vol.Required(CONF_TOPIC): cv.publish_topic,
vol.Optional(CONF_QOS, 0): cv.mqtt_qos,
})])
}) })
def exp_mqtt_message(config): def exp_mqtt_message(config):
if config is None: if config is None:
return exp_empty_optional('mqtt::MQTTMessage') return optional(TemplateArguments(MQTTMessage))
exp = StructInitializer( exp = StructInitializer(
'mqtt::MQTTMessage', MQTTMessage,
('topic', config[CONF_TOPIC]), ('topic', config[CONF_TOPIC]),
('payload', config.get(CONF_PAYLOAD, "")), ('payload', config.get(CONF_PAYLOAD, "")),
('qos', config[CONF_QOS]), ('qos', config[CONF_QOS]),
@@ -84,7 +93,7 @@ def exp_mqtt_message(config):
def to_code(config): def to_code(config):
rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT], rhs = App.init_mqtt(config[CONF_BROKER], config[CONF_PORT],
config[CONF_USERNAME], config[CONF_PASSWORD]) config[CONF_USERNAME], config[CONF_PASSWORD])
mqtt = Pvariable('mqtt::MQTTClientComponent', config[CONF_ID], rhs) mqtt = Pvariable(MQTTClientComponent, config[CONF_ID], rhs)
if not config.get(CONF_DISCOVERY, True): if not config.get(CONF_DISCOVERY, True):
add(mqtt.disable_discovery()) add(mqtt.disable_discovery())
if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config: if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
@@ -120,6 +129,11 @@ def to_code(config):
if CONF_KEEPALIVE in config: if CONF_KEEPALIVE in config:
add(mqtt.set_keep_alive(config[CONF_KEEPALIVE])) add(mqtt.set_keep_alive(config[CONF_KEEPALIVE]))
for conf in config.get(CONF_ON_MESSAGE, []):
rhs = mqtt.make_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS])
trigger = Pvariable(MQTTMessageTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, std_string, conf)
def required_build_flags(config): def required_build_flags(config):
if CONF_SSL_FINGERPRINTS in config: if CONF_SSL_FINGERPRINTS in config:

View File

@@ -8,7 +8,7 @@ from esphomeyaml import core
from esphomeyaml.const import CONF_ID, CONF_OTA, CONF_PASSWORD, CONF_PORT, CONF_SAFE_MODE, \ from esphomeyaml.const import CONF_ID, CONF_OTA, CONF_PASSWORD, CONF_PORT, CONF_SAFE_MODE, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, Pvariable, add from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -20,10 +20,12 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_PASSWORD): cv.string, vol.Optional(CONF_PASSWORD): cv.string,
}) })
OTAComponent = esphomelib_ns.OTAComponent
def to_code(config): def to_code(config):
rhs = App.init_ota() rhs = App.init_ota()
ota = Pvariable('OTAComponent', config[CONF_ID], rhs) ota = Pvariable(OTAComponent, config[CONF_ID], rhs)
if CONF_PASSWORD in config: if CONF_PASSWORD in config:
hash_ = hashlib.md5(config[CONF_PASSWORD].encode()).hexdigest() hash_ = hashlib.md5(config[CONF_PASSWORD].encode()).hexdigest()
add(ota.set_auth_password_hash(hash_)) add(ota.set_auth_password_hash(hash_))

View File

@@ -1,19 +1,24 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_POWER_SUPPLY, CONF_INVERTED, CONF_MAX_POWER from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY
from esphomeyaml.helpers import get_variable, add from esphomeyaml.helpers import add, esphomelib_ns, get_variable
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
})
BINARY_OUTPUT_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({
vol.Optional(CONF_POWER_SUPPLY): cv.variable_id, vol.Optional(CONF_POWER_SUPPLY): cv.variable_id,
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_INVERTED): cv.boolean,
}).extend(cv.REQUIRED_ID_SCHEMA.schema)
FLOAT_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_MAX_POWER): cv.zero_to_one_float,
}) })
FLOAT_OUTPUT_SCHEMA = BINARY_OUTPUT_SCHEMA.extend({
vol.Optional(CONF_MAX_POWER): cv.percentage,
})
output_ns = esphomelib_ns.namespace('output')
def setup_output_platform(obj, config, skip_power_supply=False): def setup_output_platform(obj, config, skip_power_supply=False):
if CONF_INVERTED in config: if CONF_INVERTED in config:

View File

@@ -2,29 +2,30 @@ import voluptuous as vol
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import output from esphomeyaml.components import output
from esphomeyaml.const import CONF_ID, CONF_PIN, ESP_PLATFORM_ESP8266 from esphomeyaml.const import CONF_ID, CONF_PIN, ESP_PLATFORM_ESP8266, CONF_NUMBER
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, Pvariable, exp_gpio_output_pin from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
ESP_PLATFORMS = [ESP_PLATFORM_ESP8266] ESP_PLATFORMS = [ESP_PLATFORM_ESP8266]
def valid_pwm_pin(value): def valid_pwm_pin(value):
if value >= 16: if value[CONF_NUMBER] >= 16:
raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.") raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.")
return value return value
PLATFORM_SCHEMA = output.FLOAT_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_PIN): vol.All(pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): vol.All(pins.GPIO_INTERNAL_OUTPUT_PIN_SCHEMA, valid_pwm_pin),
pins.schema_validate_number(valid_pwm_pin)), }).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
})
ESP8266PWMOutput = output.output_ns.ESP8266PWMOutput
def to_code(config): def to_code(config):
pin = exp_gpio_output_pin(config[CONF_PIN]) pin = gpio_output_pin_expression(config[CONF_PIN])
rhs = App.make_esp8266_pwm_output(pin) rhs = App.make_esp8266_pwm_output(pin)
gpio = Pvariable('output::ESP8266PWMOutput', config[CONF_ID], rhs) gpio = Pvariable(ESP8266PWMOutput, config[CONF_ID], rhs)
output.setup_output_platform(gpio, config) output.setup_output_platform(gpio, config)

View File

@@ -3,17 +3,19 @@ import voluptuous as vol
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import output from esphomeyaml.components import output
from esphomeyaml.const import CONF_ID, CONF_PIN from esphomeyaml.const import CONF_ID, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, exp_gpio_output_pin from esphomeyaml.helpers import App, Pvariable, gpio_output_pin_expression
PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
}) }).extend(output.BINARY_OUTPUT_SCHEMA.schema)
GPIOBinaryOutputComponent = output.output_ns.GPIOBinaryOutputComponent
def to_code(config): def to_code(config):
pin = exp_gpio_output_pin(config[CONF_PIN]) pin = gpio_output_pin_expression(config[CONF_PIN])
rhs = App.make_gpio_output(pin) rhs = App.make_gpio_output(pin)
gpio = Pvariable('output::GPIOBinaryOutputComponent', config[CONF_ID], rhs) gpio = Pvariable(GPIOBinaryOutputComponent, config[CONF_ID], rhs)
output.setup_output_platform(gpio, config) output.setup_output_platform(gpio, config)

View File

@@ -19,12 +19,15 @@ def validate_frequency_bit_depth(obj):
return obj return obj
PLATFORM_SCHEMA = vol.All(output.FLOAT_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_PIN): vol.All(pins.output_pin, vol.Range(min=0, max=33)), vol.Required(CONF_PIN): pins.output_pin,
vol.Optional(CONF_FREQUENCY): cv.frequency, vol.Optional(CONF_FREQUENCY): cv.frequency,
vol.Optional(CONF_BIT_DEPTH): vol.All(vol.Coerce(int), vol.Range(min=1, max=15)), vol.Optional(CONF_BIT_DEPTH): vol.All(vol.Coerce(int), vol.Range(min=1, max=15)),
vol.Optional(CONF_CHANNEL): vol.All(vol.Coerce(int), vol.Range(min=0, max=15)) vol.Optional(CONF_CHANNEL): vol.All(vol.Coerce(int), vol.Range(min=0, max=15))
}), validate_frequency_bit_depth) }).extend(output.FLOAT_OUTPUT_SCHEMA.schema), validate_frequency_bit_depth)
LEDCOutputComponent = output.output_ns.LEDCOutputComponent
def to_code(config): def to_code(config):
@@ -32,7 +35,7 @@ def to_code(config):
if frequency is None and CONF_BIT_DEPTH in config: if frequency is None and CONF_BIT_DEPTH in config:
frequency = 1000 frequency = 1000
rhs = App.make_ledc_output(config[CONF_PIN], frequency, config.get(CONF_BIT_DEPTH)) rhs = App.make_ledc_output(config[CONF_PIN], frequency, config.get(CONF_BIT_DEPTH))
ledc = Pvariable('output::LEDCOutputComponent', config[CONF_ID], rhs) ledc = Pvariable(LEDCOutputComponent, config[CONF_ID], rhs)
if CONF_CHANNEL in config: if CONF_CHANNEL in config:
add(ledc.set_channel(config[CONF_CHANNEL])) add(ledc.set_channel(config[CONF_CHANNEL]))
output.setup_output_platform(ledc, config) output.setup_output_platform(ledc, config)

View File

@@ -2,26 +2,28 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import output from esphomeyaml.components import output
from esphomeyaml.components.pca9685 import PCA9685_COMPONENT_TYPE from esphomeyaml.components.pca9685 import PCA9685OutputComponent
from esphomeyaml.const import CONF_CHANNEL, CONF_ID, CONF_PCA9685_ID, CONF_POWER_SUPPLY from esphomeyaml.const import CONF_CHANNEL, CONF_ID, CONF_PCA9685_ID, CONF_POWER_SUPPLY
from esphomeyaml.helpers import Pvariable, get_variable from esphomeyaml.helpers import Pvariable, get_variable
DEPENDENCIES = ['pca9685'] DEPENDENCIES = ['pca9685']
PLATFORM_SCHEMA = output.FLOAT_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = output.PLATFORM_SCHEMA.extend({
vol.Required(CONF_CHANNEL): vol.All(vol.Coerce(int), vol.Required(CONF_CHANNEL): vol.All(vol.Coerce(int),
vol.Range(min=0, max=15)), vol.Range(min=0, max=15)),
vol.Optional(CONF_PCA9685_ID): cv.variable_id, vol.Optional(CONF_PCA9685_ID): cv.variable_id,
}) }).extend(output.FLOAT_OUTPUT_SCHEMA.schema)
Channel = PCA9685OutputComponent.Channel
def to_code(config): def to_code(config):
power_supply = None power_supply = None
if CONF_POWER_SUPPLY in config: if CONF_POWER_SUPPLY in config:
power_supply = get_variable(config[CONF_POWER_SUPPLY]) power_supply = get_variable(config[CONF_POWER_SUPPLY])
pca9685 = get_variable(config.get(CONF_PCA9685_ID), PCA9685_COMPONENT_TYPE) pca9685 = get_variable(config.get(CONF_PCA9685_ID), PCA9685OutputComponent)
rhs = pca9685.create_channel(config[CONF_CHANNEL], power_supply) rhs = pca9685.create_channel(config[CONF_CHANNEL], power_supply)
out = Pvariable('output::PCA9685OutputComponent::Channel', config[CONF_ID], rhs) out = Pvariable(Channel, config[CONF_ID], rhs)
output.setup_output_platform(out, config, skip_power_supply=True) output.setup_output_platform(out, config, skip_power_supply=True)

View File

@@ -1,14 +1,13 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import output
from esphomeyaml.const import CONF_ADDRESS, CONF_FREQUENCY, CONF_ID, CONF_PHASE_BALANCER from esphomeyaml.const import CONF_ADDRESS, CONF_FREQUENCY, CONF_ID, CONF_PHASE_BALANCER
from esphomeyaml.helpers import App, HexIntLiteral, Pvariable, RawExpression, add from esphomeyaml.helpers import App, HexIntLiteral, Pvariable, add
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
PHASE_BALANCERS = ['None', 'Linear', 'Weaved'] PCA9685OutputComponent = output.output_ns.namespace('PCA9685OutputComponent')
PCA9685_COMPONENT_TYPE = 'output::PCA9685OutputComponent'
PHASE_BALANCER_MESSAGE = ("The phase_balancer option has been removed in version 1.5.0. " PHASE_BALANCER_MESSAGE = ("The phase_balancer option has been removed in version 1.5.0. "
"esphomelib will now automatically choose a suitable phase balancer.") "esphomelib will now automatically choose a suitable phase balancer.")
@@ -28,13 +27,9 @@ CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCA9685_SCHEMA])
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_pca9685_component(conf.get(CONF_FREQUENCY)) rhs = App.make_pca9685_component(conf.get(CONF_FREQUENCY))
pca9685 = Pvariable(PCA9685_COMPONENT_TYPE, conf[CONF_ID], rhs) pca9685 = Pvariable(PCA9685OutputComponent, conf[CONF_ID], rhs)
if CONF_ADDRESS in conf: if CONF_ADDRESS in conf:
add(pca9685.set_address(HexIntLiteral(conf[CONF_ADDRESS]))) add(pca9685.set_address(HexIntLiteral(conf[CONF_ADDRESS])))
if CONF_PHASE_BALANCER in conf:
phase_balancer = RawExpression(u'PCA9685_PhaseBalancer_{}'.format(
conf[CONF_PHASE_BALANCER]))
add(pca9685.set_phase_balancer(phase_balancer))
BUILD_FLAGS = '-DUSE_PCA9685_OUTPUT' BUILD_FLAGS = '-DUSE_PCA9685_OUTPUT'

View File

@@ -2,7 +2,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_PCF8575 from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_PCF8575
from esphomeyaml.helpers import App, Pvariable from esphomeyaml.helpers import App, Pvariable, esphomelib_ns
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
@@ -14,11 +14,14 @@ PCF8574_SCHEMA = vol.Schema({
CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCF8574_SCHEMA]) CONFIG_SCHEMA = vol.All(cv.ensure_list, [PCF8574_SCHEMA])
io_ns = esphomelib_ns.namespace('io')
PCF8574Component = io_ns.PCF8574Component
def to_code(config): def to_code(config):
for conf in config: for conf in config:
rhs = App.make_pcf8574_component(conf[CONF_ADDRESS], conf[CONF_PCF8575]) rhs = App.make_pcf8574_component(conf[CONF_ADDRESS], conf[CONF_PCF8575])
Pvariable('io::PCF8574Component', conf[CONF_ID], rhs) Pvariable(PCF8574Component, conf[CONF_ID], rhs)
BUILD_FLAGS = '-DUSE_PCF8574' BUILD_FLAGS = '-DUSE_PCF8574'

View File

@@ -3,7 +3,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN from esphomeyaml.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN
from esphomeyaml.helpers import App, Pvariable, add, exp_gpio_output_pin from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, gpio_output_pin_expression
POWER_SUPPLY_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({ POWER_SUPPLY_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
@@ -13,12 +13,13 @@ POWER_SUPPLY_SCHEMA = cv.REQUIRED_ID_SCHEMA.extend({
CONFIG_SCHEMA = vol.All(cv.ensure_list, [POWER_SUPPLY_SCHEMA]) CONFIG_SCHEMA = vol.All(cv.ensure_list, [POWER_SUPPLY_SCHEMA])
PowerSupplyComponent = esphomelib_ns.PowerSupplyComponent
def to_code(config): def to_code(config):
for conf in config: for conf in config:
pin = exp_gpio_output_pin(conf[CONF_PIN]) rhs = App.make_power_supply(gpio_output_pin_expression(conf[CONF_PIN]))
rhs = App.make_power_supply(pin) psu = Pvariable(PowerSupplyComponent, conf[CONF_ID], rhs)
psu = Pvariable('PowerSupplyComponent', conf[CONF_ID], rhs)
if CONF_ENABLE_TIME in conf: if CONF_ENABLE_TIME in conf:
add(psu.set_enable_time(conf[CONF_ENABLE_TIME])) add(psu.set_enable_time(conf[CONF_ENABLE_TIME]))
if CONF_KEEP_ON_TIME in conf: if CONF_KEEP_ON_TIME in conf:

View File

@@ -1,107 +1,176 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_EXPIRE_AFTER, \ from esphomeyaml import automation
CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, CONF_FILTER_NAN, CONF_FILTER_OUT, CONF_ICON, \ from esphomeyaml.const import CONF_ABOVE, CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_BELOW, \
CONF_LAMBDA, CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_SEND_EVERY, \ CONF_DEBOUNCE, CONF_DELTA, CONF_EXPIRE_AFTER, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, \
CONF_SLIDING_WINDOW_MOVING_AVERAGE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE, CONF_ID CONF_FILTER_NAN, CONF_FILTER_OUT, CONF_HEARTBEAT, CONF_ICON, CONF_ID, CONF_LAMBDA, \
from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \ CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_ON_RAW_VALUE, CONF_ON_VALUE,\
setup_mqtt_component 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
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.Any(
vol.Schema({vol.Required(CONF_OFFSET): vol.Coerce(float)}),
vol.Schema({vol.Required(CONF_MULTIPLY): vol.Coerce(float)}),
vol.Schema({vol.Required(CONF_FILTER_OUT): vol.Coerce(float)}),
vol.Schema({vol.Required(CONF_FILTER_NAN): None}),
vol.Schema({
vol.Required(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.Schema({
vol.Required(CONF_WINDOW_SIZE): cv.positive_not_null_int,
vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int,
})
}),
vol.Schema({
vol.Required(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({
vol.Required(CONF_ALPHA): cv.positive_float,
vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int,
})
}),
vol.Schema({vol.Required(CONF_LAMBDA): cv.string_strict}),
)])
MQTT_SENSOR_SCHEMA = vol.Schema({ def validate_recursive_filter(value):
return FILTERS_SCHEMA(value)
FILTER_KEYS = [CONF_OFFSET, CONF_MULTIPLY, CONF_FILTER_OUT, CONF_FILTER_NAN,
CONF_SLIDING_WINDOW_MOVING_AVERAGE, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_LAMBDA,
CONF_THROTTLE, CONF_DELTA, CONF_UNIQUE, CONF_HEARTBEAT, CONF_DEBOUNCE, CONF_OR]
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_OFFSET): vol.Coerce(float),
vol.Optional(CONF_MULTIPLY): vol.Coerce(float),
vol.Optional(CONF_FILTER_OUT): vol.Coerce(float),
vol.Optional(CONF_FILTER_NAN): None,
vol.Optional(CONF_SLIDING_WINDOW_MOVING_AVERAGE): vol.Schema({
vol.Required(CONF_WINDOW_SIZE): cv.positive_not_null_int,
vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int,
}),
vol.Optional(CONF_EXPONENTIAL_MOVING_AVERAGE): vol.Schema({
vol.Required(CONF_ALPHA): cv.positive_float,
vol.Required(CONF_SEND_EVERY): cv.positive_not_null_int,
}),
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_THROTTLE): cv.positive_time_period_milliseconds,
vol.Optional(CONF_DELTA): vol.Coerce(float),
vol.Optional(CONF_UNIQUE): None,
vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_DEBOUNCE): cv.positive_time_period_milliseconds,
vol.Optional(CONF_OR): validate_recursive_filter,
}, cv.has_at_exactly_one_key(*FILTER_KEYS))])
SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
cv.GenerateID('mqtt_sensor', CONF_MQTT_ID): cv.register_variable_id,
cv.GenerateID('sensor'): cv.register_variable_id,
vol.Required(CONF_NAME): cv.string, vol.Required(CONF_NAME): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string_strict, vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string_strict,
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_ACCURACY_DECIMALS): vol.Coerce(int), vol.Optional(CONF_ACCURACY_DECIMALS): vol.Coerce(int),
vol.Optional(CONF_EXPIRE_AFTER): vol.Any(None, cv.positive_time_period_milliseconds), vol.Optional(CONF_EXPIRE_AFTER): vol.Any(None, cv.positive_time_period_milliseconds),
vol.Optional(CONF_FILTERS): FILTERS_SCHEMA vol.Optional(CONF_FILTERS): FILTERS_SCHEMA,
}) vol.Optional(CONF_ON_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]),
vol.Optional(CONF_ON_RAW_VALUE): vol.All(cv.ensure_list, [automation.AUTOMATION_SCHEMA]),
MQTT_SENSOR_ID_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ vol.Optional(CONF_ON_VALUE_RANGE): vol.All(cv.ensure_list, [vol.All(
cv.GenerateID('mqtt_sensor', CONF_MQTT_ID): cv.register_variable_id, automation.AUTOMATION_SCHEMA.extend({
vol.Optional(CONF_ABOVE): vol.Coerce(float),
vol.Optional(CONF_BELOW): vol.Coerce(float),
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))]),
}) })
# pylint: disable=invalid-name # pylint: disable=invalid-name
OffsetFilter = MockObj('new sensor::OffsetFilter') sensor_ns = esphomelib_ns.namespace('sensor')
MultiplyFilter = MockObj('new sensor::MultiplyFilter') Sensor = sensor_ns.Sensor
FilterOutValueFilter = MockObj('new sensor::FilterOutValueFilter') MQTTSensorComponent = sensor_ns.MQTTSensorComponent
FilterOutNANFilter = MockObj('new sensor::FilterOutNANFilter') OffsetFilter = sensor_ns.OffsetFilter
SlidingWindowMovingAverageFilter = MockObj('new sensor::SlidingWindowMovingAverageFilter') MultiplyFilter = sensor_ns.MultiplyFilter
ExponentialMovingAverageFilter = MockObj('new sensor::ExponentialMovingAverageFilter') FilterOutValueFilter = sensor_ns.FilterOutValueFilter
LambdaFilter = MockObj('new sensor::LambdaFilter') FilterOutNANFilter = sensor_ns.FilterOutNANFilter
SlidingWindowMovingAverageFilter = sensor_ns.SlidingWindowMovingAverageFilter
ExponentialMovingAverageFilter = sensor_ns.ExponentialMovingAverageFilter
LambdaFilter = sensor_ns.LambdaFilter
ThrottleFilter = sensor_ns.ThrottleFilter
DeltaFilter = sensor_ns.DeltaFilter
OrFilter = sensor_ns.OrFilter
HeartbeatFilter = sensor_ns.HeartbeatFilter
DebounceFilter = sensor_ns.DebounceFilter
UniqueFilter = sensor_ns.UniqueFilter
SensorValueTrigger = sensor_ns.SensorValueTrigger
RawSensorValueTrigger = sensor_ns.RawSensorValueTrigger
ValueRangeTrigger = sensor_ns.ValueRangeTrigger
def setup_filter(config): def setup_filter(config):
if CONF_OFFSET in config: if CONF_OFFSET in config:
return OffsetFilter(config[CONF_OFFSET]) return OffsetFilter.new(config[CONF_OFFSET])
if CONF_MULTIPLY in config: if CONF_MULTIPLY in config:
return MultiplyFilter(config[CONF_MULTIPLY]) return MultiplyFilter.new(config[CONF_MULTIPLY])
if CONF_FILTER_OUT in config: if CONF_FILTER_OUT in config:
return FilterOutValueFilter(config[CONF_FILTER_OUT]) return FilterOutValueFilter.new(config[CONF_FILTER_OUT])
if CONF_FILTER_NAN in config: if CONF_FILTER_NAN in config:
return FilterOutNANFilter() return FilterOutNANFilter()
if CONF_SLIDING_WINDOW_MOVING_AVERAGE in config: if CONF_SLIDING_WINDOW_MOVING_AVERAGE in config:
conf = config[CONF_SLIDING_WINDOW_MOVING_AVERAGE] conf = config[CONF_SLIDING_WINDOW_MOVING_AVERAGE]
return SlidingWindowMovingAverageFilter(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY]) return SlidingWindowMovingAverageFilter.new(conf[CONF_WINDOW_SIZE], conf[CONF_SEND_EVERY])
if CONF_EXPONENTIAL_MOVING_AVERAGE in config: if CONF_EXPONENTIAL_MOVING_AVERAGE in config:
conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE] conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE]
return ExponentialMovingAverageFilter(conf[CONF_ALPHA], conf[CONF_SEND_EVERY]) return ExponentialMovingAverageFilter.new(conf[CONF_ALPHA], conf[CONF_SEND_EVERY])
if CONF_LAMBDA in config: if CONF_LAMBDA in config:
s = u'[](float x) -> Optional<float> {{ return {}; }}'.format(config[CONF_LAMBDA]) return LambdaFilter.new(process_lambda(config[CONF_LAMBDA], [(float_, 'x')]))
return LambdaFilter(RawExpression(s)) if CONF_THROTTLE in config:
return ThrottleFilter.new(config[CONF_THROTTLE])
if CONF_DELTA in config:
return DeltaFilter.new(config[CONF_DELTA])
if CONF_OR in config:
return OrFilter.new(setup_filters(config[CONF_OR]))
if CONF_HEARTBEAT in config:
return App.register_component(HeartbeatFilter.new(config[CONF_HEARTBEAT]))
if CONF_DEBOUNCE in config:
return App.register_component(DebounceFilter.new(config[CONF_DEBOUNCE]))
if CONF_UNIQUE in config:
return UniqueFilter.new()
raise ValueError(u"Filter unsupported: {}".format(config)) raise ValueError(u"Filter unsupported: {}".format(config))
def setup_mqtt_sensor_component(obj, config): def setup_filters(config):
return ArrayInitializer(*[setup_filter(x) for x in config])
def setup_sensor_core_(sensor_var, mqtt_var, config):
if CONF_UNIT_OF_MEASUREMENT in config:
add(sensor_var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
if CONF_ICON in config:
add(sensor_var.set_icon(config[CONF_ICON]))
if CONF_ACCURACY_DECIMALS in config:
add(sensor_var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
if CONF_FILTERS in config:
add(sensor_var.set_filters(setup_filters(config[CONF_FILTERS])))
for conf in config.get(CONF_ON_VALUE, []):
rhs = sensor_var.make_value_trigger()
trigger = Pvariable(SensorValueTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, float_, conf)
for conf in config.get(CONF_ON_RAW_VALUE, []):
rhs = sensor_var.make_raw_value_trigger()
trigger = Pvariable(RawSensorValueTrigger, conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, float_, conf)
for conf in config.get(CONF_ON_VALUE_RANGE, []):
rhs = sensor_var.make_value_range_trigger()
trigger = Pvariable(ValueRangeTrigger, conf[CONF_TRIGGER_ID], rhs)
if CONF_ABOVE in conf:
trigger.set_min(templatable(conf[CONF_ABOVE], float_, float_))
if CONF_BELOW in conf:
trigger.set_max(templatable(conf[CONF_BELOW], float_, float_))
automation.build_automation(trigger, float_, conf)
if CONF_EXPIRE_AFTER in config: if CONF_EXPIRE_AFTER in config:
if config[CONF_EXPIRE_AFTER] is None: if config[CONF_EXPIRE_AFTER] is None:
add(obj.disable_expire_after()) add(mqtt_var.disable_expire_after())
else: else:
add(obj.set_expire_after(config[CONF_EXPIRE_AFTER])) add(mqtt_var.set_expire_after(config[CONF_EXPIRE_AFTER]))
setup_mqtt_component(obj, config) setup_mqtt_component(mqtt_var, config)
def setup_sensor(obj, config): def setup_sensor(sensor_obj, mqtt_obj, config):
if CONF_UNIT_OF_MEASUREMENT in config: sensor_var = Pvariable(Sensor, config[CONF_ID], sensor_obj, has_side_effects=False)
add(obj.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) mqtt_var = Pvariable(MQTTSensorComponent, config[CONF_MQTT_ID], mqtt_obj,
if CONF_ICON in config: has_side_effects=False)
add(obj.set_icon(config[CONF_ICON])) setup_sensor_core_(sensor_var, mqtt_var, config)
if CONF_ACCURACY_DECIMALS in config:
add(obj.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
if CONF_FILTERS in config:
filters = [setup_filter(x) for x in config[CONF_FILTERS]]
add(obj.set_filters(ArrayInitializer(*filters)))
def register_sensor(var, config): def register_sensor(var, config):
setup_sensor(var, config) sensor_var = Pvariable(Sensor, config[CONF_ID], var, has_side_effects=True)
rhs = App.register_sensor(var) rhs = App.register_sensor(sensor_var)
mqtt_sensor = Pvariable('sensor::MQTTSensorComponent', config[CONF_MQTT_ID], rhs) mqtt_var = Pvariable(MQTTSensorComponent, config[CONF_MQTT_ID], rhs,
setup_mqtt_sensor_component(mqtt_sensor, config) has_side_effects=True)
setup_sensor_core_(sensor_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_SENSOR' BUILD_FLAGS = '-DUSE_SENSOR'

View File

@@ -3,37 +3,35 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ATTENUATION, CONF_ID, CONF_NAME, CONF_PIN, \ from esphomeyaml.const import CONF_ATTENUATION, CONF_MAKE_ID, CONF_NAME, CONF_PIN, \
CONF_UPDATE_INTERVAL CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, RawExpression, add, variable from esphomeyaml.helpers import App, Application, add, global_ns, variable
ATTENUATION_MODES = { ATTENUATION_MODES = {
'0db': 'ADC_0db', '0db': global_ns.ADC_0db,
'2.5db': 'ADC_2_5db', '2.5db': global_ns.ADC_2_5db,
'6db': 'ADC_6db', '6db': global_ns.ADC_6db,
'11db': 'ADC_11db', '11db': global_ns.ADC_11db,
} }
ATTENUATION_MODE_SCHEMA = vol.Any(*list(ATTENUATION_MODES.keys()))
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('adc'): cv.register_variable_id, cv.GenerateID('adc', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.analog_pin, vol.Required(CONF_PIN): pins.analog_pin,
vol.Optional(CONF_ATTENUATION): vol.All(cv.only_on_esp32, ATTENUATION_MODE_SCHEMA), vol.Optional(CONF_ATTENUATION): vol.All(cv.only_on_esp32, cv.one_of(*ATTENUATION_MODES)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeADCSensor = Application.MakeADCSensor
def to_code(config): def to_code(config):
rhs = App.make_adc_sensor(config[CONF_NAME], config[CONF_PIN], rhs = App.make_adc_sensor(config[CONF_NAME], config[CONF_PIN],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable('Application::MakeADCSensor', config[CONF_ID], rhs) make = variable(MakeADCSensor, config[CONF_MAKE_ID], rhs)
adc = make.Padc adc = make.Padc
if CONF_ATTENUATION in config: if CONF_ATTENUATION in config:
attenuation = ATTENUATION_MODES[config[CONF_ATTENUATION]] add(adc.set_attenuation(ATTENUATION_MODES[config[CONF_ATTENUATION]]))
add(adc.set_attenuation(RawExpression(attenuation))) sensor.setup_sensor(make.Padc, make.Pmqtt, config)
sensor.setup_sensor(adc, config)
sensor.setup_mqtt_sensor_component(make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_ADC_SENSOR' BUILD_FLAGS = '-DUSE_ADC_SENSOR'

View File

@@ -2,30 +2,31 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_UPDATE_INTERVAL, \ from esphomeyaml.components.ads1115 import ADS1115Component
CONF_NAME, CONF_ID from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_NAME, \
from esphomeyaml.helpers import RawExpression, get_variable, Pvariable CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import get_variable
DEPENDENCIES = ['ads1115'] DEPENDENCIES = ['ads1115']
MUX = { MUX = {
'A0_A1': 'sensor::ADS1115_MULTIPLEXER_P0_N1', 'A0_A1': sensor.sensor_ns.ADS1115_MULTIPLEXER_P0_N1,
'A0_A3': 'sensor::ADS1115_MULTIPLEXER_P0_N3', 'A0_A3': sensor.sensor_ns.ADS1115_MULTIPLEXER_P0_N3,
'A1_A3': 'sensor::ADS1115_MULTIPLEXER_P1_N3', 'A1_A3': sensor.sensor_ns.ADS1115_MULTIPLEXER_P1_N3,
'A2_A3': 'sensor::ADS1115_MULTIPLEXER_P2_N3', 'A2_A3': sensor.sensor_ns.ADS1115_MULTIPLEXER_P2_N3,
'A0_GND': 'sensor::ADS1115_MULTIPLEXER_P0_NG', 'A0_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P0_NG,
'A1_GND': 'sensor::ADS1115_MULTIPLEXER_P1_NG', 'A1_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P1_NG,
'A2_GND': 'sensor::ADS1115_MULTIPLEXER_P2_NG', 'A2_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P2_NG,
'A3_GND': 'sensor::ADS1115_MULTIPLEXER_P3_NG', 'A3_GND': sensor.sensor_ns.ADS1115_MULTIPLEXER_P3_NG,
} }
GAIN = { GAIN = {
'6.144': 'sensor::ADS1115_GAIN_6P144', '6.144': sensor.sensor_ns.ADS1115_GAIN_6P144,
'4.096': 'sensor::ADS1115_GAIN_6P096', '4.096': sensor.sensor_ns.ADS1115_GAIN_6P096,
'2.048': 'sensor::ADS1115_GAIN_2P048', '2.048': sensor.sensor_ns.ADS1115_GAIN_2P048,
'1.024': 'sensor::ADS1115_GAIN_1P024', '1.024': sensor.sensor_ns.ADS1115_GAIN_1P024,
'0.512': 'sensor::ADS1115_GAIN_0P512', '0.512': sensor.sensor_ns.ADS1115_GAIN_0P512,
'0.256': 'sensor::ADS1115_GAIN_0P256', '0.256': sensor.sensor_ns.ADS1115_GAIN_0P256,
} }
@@ -35,28 +36,31 @@ def validate_gain(value):
elif not isinstance(value, (str, unicode)): elif not isinstance(value, (str, unicode)):
raise vol.Invalid('invalid gain "{}"'.format(value)) raise vol.Invalid('invalid gain "{}"'.format(value))
if value not in GAIN: return cv.one_of(*GAIN)(value)
raise vol.Invalid("Invalid gain, options are {}".format(', '.join(GAIN.keys())))
return value
def validate_mux(value):
value = cv.string(value).upper()
value = value.replace(' ', '_')
return cv.one_of(*MUX)(value)
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('ads1115_sensor'): cv.register_variable_id, cv.GenerateID('ads1115_sensor'): cv.register_variable_id,
vol.Required(CONF_MULTIPLEXER): vol.All(vol.Upper, vol.Any(*list(MUX.keys()))), vol.Required(CONF_MULTIPLEXER): validate_mux,
vol.Required(CONF_GAIN): validate_gain, vol.Required(CONF_GAIN): validate_gain,
vol.Optional(CONF_ADS1115_ID): cv.variable_id, vol.Optional(CONF_ADS1115_ID): cv.variable_id,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.MQTT_SENSOR_ID_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
def to_code(config): def to_code(config):
hub = get_variable(config.get(CONF_ADS1115_ID), u'sensor::ADS1115Component') hub = get_variable(config.get(CONF_ADS1115_ID), ADS1115Component)
mux = RawExpression(MUX[config[CONF_MULTIPLEXER]]) mux = MUX[config[CONF_MULTIPLEXER]]
gain = RawExpression(GAIN[config[CONF_GAIN]]) gain = GAIN[config[CONF_GAIN]]
rhs = hub.get_sensor(config[CONF_NAME], mux, gain, config.get(CONF_UPDATE_INTERVAL)) rhs = hub.get_sensor(config[CONF_NAME], mux, gain, config.get(CONF_UPDATE_INTERVAL))
sensor_ = Pvariable('sensor::ADS1115Sensor', config[CONF_ID], rhs) sensor.register_sensor(rhs, config)
sensor.register_sensor(sensor_, config)
BUILD_FLAGS = '-DUSE_ADS1115_SENSOR' BUILD_FLAGS = '-DUSE_ADS1115_SENSOR'

View File

@@ -2,36 +2,36 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_NAME, CONF_RESOLUTION, \ from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_RESOLUTION, \
CONF_UPDATE_INTERVAL CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, RawExpression, add, variable from esphomeyaml.helpers import App, Application, add, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
BH1750_RESOLUTIONS = { BH1750_RESOLUTIONS = {
4.0: 'sensor::BH1750_RESOLUTION_4P0_LX', 4.0: sensor.sensor_ns.BH1750_RESOLUTION_4P0_LX,
1.0: 'sensor::BH1750_RESOLUTION_1P0_LX', 1.0: sensor.sensor_ns.BH1750_RESOLUTION_1P0_LX,
0.5: 'sensor::BH1750_RESOLUTION_0P5_LX', 0.5: sensor.sensor_ns.BH1750_RESOLUTION_0P5_LX,
} }
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bh1750_sensor'): cv.register_variable_id, cv.GenerateID('bh1750_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Optional(CONF_ADDRESS, default=0x23): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x23): cv.i2c_address,
vol.Optional(CONF_RESOLUTION): vol.All(cv.positive_float, vol.Any(*BH1750_RESOLUTIONS)), vol.Optional(CONF_RESOLUTION): vol.All(cv.positive_float, cv.one_of(*BH1750_RESOLUTIONS)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeBH1750Sensor = Application.MakeBH1750Sensor
def to_code(config): def to_code(config):
rhs = App.make_bh1750_sensor(config[CONF_NAME], config[CONF_ADDRESS], rhs = App.make_bh1750_sensor(config[CONF_NAME], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make_bh1750 = variable('Application::MakeBH1750Sensor', config[CONF_ID], rhs) make_bh1750 = variable(MakeBH1750Sensor, config[CONF_MAKE_ID], rhs)
bh1750 = make_bh1750.Pbh1750 bh1750 = make_bh1750.Pbh1750
if CONF_RESOLUTION in config: if CONF_RESOLUTION in config:
constant = BH1750_RESOLUTIONS[config[CONF_RESOLUTION]] add(bh1750.set_resolution(BH1750_RESOLUTIONS[config[CONF_RESOLUTION]]))
add(bh1750.set_resolution(RawExpression(constant))) sensor.setup_sensor(bh1750, make_bh1750.Pmqtt, config)
sensor.setup_sensor(bh1750, config)
sensor.setup_mqtt_sensor_component(make_bh1750.Pmqtt, config)
BUILD_FLAGS = '-DUSE_BH1750' BUILD_FLAGS = '-DUSE_BH1750'

View File

@@ -2,44 +2,45 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA from esphomeyaml.const import CONF_ADDRESS, CONF_HUMIDITY, CONF_IIR_FILTER, CONF_MAKE_ID, \
from esphomeyaml.const import CONF_ADDRESS, CONF_HUMIDITY, CONF_ID, CONF_IIR_FILTER, CONF_NAME, \ CONF_NAME, CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL from esphomeyaml.helpers import App, Application, add, variable
from esphomeyaml.helpers import App, RawExpression, add, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
OVERSAMPLING_OPTIONS = { OVERSAMPLING_OPTIONS = {
'NONE': 'sensor::BME280_OVERSAMPLING_NONE', 'NONE': sensor.sensor_ns.BME280_OVERSAMPLING_NONE,
'1X': 'sensor::BME280_OVERSAMPLING_1X', '1X': sensor.sensor_ns.BME280_OVERSAMPLING_1X,
'2X': 'sensor::BME280_OVERSAMPLING_2X', '2X': sensor.sensor_ns.BME280_OVERSAMPLING_2X,
'4X': 'sensor::BME280_OVERSAMPLING_4X', '4X': sensor.sensor_ns.BME280_OVERSAMPLING_4X,
'8X': 'sensor::BME280_OVERSAMPLING_8X', '8X': sensor.sensor_ns.BME280_OVERSAMPLING_8X,
'16X': 'sensor::BME280_OVERSAMPLING_16X', '16X': sensor.sensor_ns.BME280_OVERSAMPLING_16X,
} }
IIR_FILTER_OPTIONS = { IIR_FILTER_OPTIONS = {
'OFF': 'sensor::BME280_IIR_FILTER_OFF', 'OFF': sensor.sensor_ns.BME280_IIR_FILTER_OFF,
'2X': 'sensor::BME280_IIR_FILTER_2X', '2X': sensor.sensor_ns.BME280_IIR_FILTER_2X,
'4X': 'sensor::BME280_IIR_FILTER_4X', '4X': sensor.sensor_ns.BME280_IIR_FILTER_4X,
'8X': 'sensor::BME280_IIR_FILTER_8X', '8X': sensor.sensor_ns.BME280_IIR_FILTER_8X,
'16X': 'sensor::BME280_IIR_FILTER_16X', '16X': sensor.sensor_ns.BME280_IIR_FILTER_16X,
} }
BME280_OVERSAMPLING_SENSOR_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ BME280_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({
vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, vol.Any(*OVERSAMPLING_OPTIONS)), vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)),
}) })
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bme280'): cv.register_variable_id, cv.GenerateID('bme280', CONF_MAKE_ID): cv.register_variable_id,
vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x77): cv.i2c_address,
vol.Required(CONF_TEMPERATURE): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): BME280_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_PRESSURE): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): BME280_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): BME280_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): BME280_OVERSAMPLING_SENSOR_SCHEMA,
vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, vol.Any(*IIR_FILTER_OPTIONS)), vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, cv.one_of(*IIR_FILTER_OPTIONS)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeBME280Sensor = Application.MakeBME280Sensor
def to_code(config): def to_code(config):
rhs = App.make_bme280_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_bme280_sensor(config[CONF_TEMPERATURE][CONF_NAME],
@@ -47,29 +48,27 @@ def to_code(config):
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config[CONF_ADDRESS], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable('Application::MakeBME280Sensor', config[CONF_ID], rhs) make = variable(MakeBME280Sensor, config[CONF_MAKE_ID], rhs)
bme280 = make.Pbme280 bme280 = make.Pbme280
if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]: if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]:
constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]]
add(bme280.set_temperature_oversampling(RawExpression(constant))) add(bme280.set_temperature_oversampling(constant))
if CONF_OVERSAMPLING in config[CONF_PRESSURE]: if CONF_OVERSAMPLING in config[CONF_PRESSURE]:
constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]]
add(bme280.set_pressure_oversampling(RawExpression(constant))) add(bme280.set_pressure_oversampling(constant))
if CONF_OVERSAMPLING in config[CONF_HUMIDITY]: if CONF_OVERSAMPLING in config[CONF_HUMIDITY]:
constant = OVERSAMPLING_OPTIONS[config[CONF_HUMIDITY][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_HUMIDITY][CONF_OVERSAMPLING]]
add(bme280.set_humidity_oversampling(RawExpression(constant))) add(bme280.set_humidity_oversampling(constant))
if CONF_IIR_FILTER in config: if CONF_IIR_FILTER in config:
constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]] constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]]
add(bme280.set_iir_filter(RawExpression(constant))) add(bme280.set_iir_filter(constant))
sensor.setup_sensor(bme280.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) sensor.setup_sensor(bme280.Pget_temperature_sensor(), make.Pmqtt_temperature,
sensor.setup_mqtt_sensor_component(make.Pmqtt_temperature, config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])
sensor.setup_sensor(bme280.Pget_pressure_sensor(), make.Pmqtt_pressure,
sensor.setup_sensor(bme280.Pget_pressure_sensor(), config[CONF_PRESSURE]) config[CONF_PRESSURE])
sensor.setup_mqtt_sensor_component(make.Pmqtt_pressure, config[CONF_PRESSURE]) sensor.setup_sensor(bme280.Pget_humidity_sensor(), make.Pmqtt_humidity,
config[CONF_HUMIDITY])
sensor.setup_sensor(bme280.Pget_humidity_sensor(), config[CONF_HUMIDITY])
sensor.setup_mqtt_sensor_component(make.Pmqtt_humidity, config[CONF_HUMIDITY])
BUILD_FLAGS = '-DUSE_BME280' BUILD_FLAGS = '-DUSE_BME280'

View File

@@ -2,49 +2,51 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA from esphomeyaml.const import CONF_ADDRESS, CONF_GAS_RESISTANCE, CONF_HUMIDITY, CONF_IIR_FILTER, \
from esphomeyaml.const import CONF_ADDRESS, CONF_HUMIDITY, CONF_ID, CONF_IIR_FILTER, CONF_NAME, \ CONF_MAKE_ID, CONF_NAME, CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, \
CONF_OVERSAMPLING, CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL, CONF_GAS_RESISTANCE CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, RawExpression, add, variable from esphomeyaml.helpers import App, Application, add, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
OVERSAMPLING_OPTIONS = { OVERSAMPLING_OPTIONS = {
'NONE': 'sensor::BME680_OVERSAMPLING_NONE', 'NONE': sensor.sensor_ns.BME680_OVERSAMPLING_NONE,
'1X': 'sensor::BME680_OVERSAMPLING_1X', '1X': sensor.sensor_ns.BME680_OVERSAMPLING_1X,
'2X': 'sensor::BME680_OVERSAMPLING_2X', '2X': sensor.sensor_ns.BME680_OVERSAMPLING_2X,
'4X': 'sensor::BME680_OVERSAMPLING_4X', '4X': sensor.sensor_ns.BME680_OVERSAMPLING_4X,
'8X': 'sensor::BME680_OVERSAMPLING_8X', '8X': sensor.sensor_ns.BME680_OVERSAMPLING_8X,
'16X': 'sensor::BME680_OVERSAMPLING_16X', '16X': sensor.sensor_ns.BME680_OVERSAMPLING_16X,
} }
IIR_FILTER_OPTIONS = { IIR_FILTER_OPTIONS = {
'OFF': 'sensor::BME680_IIR_FILTER_OFF', 'OFF': sensor.sensor_ns.BME680_IIR_FILTER_OFF,
'1X': 'sensor::BME680_IIR_FILTER_1X', '1X': sensor.sensor_ns.BME680_IIR_FILTER_1X,
'3X': 'sensor::BME680_IIR_FILTER_3X', '3X': sensor.sensor_ns.BME680_IIR_FILTER_3X,
'7X': 'sensor::BME680_IIR_FILTER_7X', '7X': sensor.sensor_ns.BME680_IIR_FILTER_7X,
'15X': 'sensor::BME680_IIR_FILTER_15X', '15X': sensor.sensor_ns.BME680_IIR_FILTER_15X,
'31X': 'sensor::BME680_IIR_FILTER_31X', '31X': sensor.sensor_ns.BME680_IIR_FILTER_31X,
'63X': 'sensor::BME680_IIR_FILTER_63X', '63X': sensor.sensor_ns.BME680_IIR_FILTER_63X,
'127X': 'sensor::BME680_IIR_FILTER_127X', '127X': sensor.sensor_ns.BME680_IIR_FILTER_127X,
} }
BME680_OVERSAMPLING_SENSOR_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ BME680_OVERSAMPLING_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({
vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, vol.Any(*OVERSAMPLING_OPTIONS)), vol.Optional(CONF_OVERSAMPLING): vol.All(vol.Upper, cv.one_of(*OVERSAMPLING_OPTIONS)),
}) })
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bme680'): cv.register_variable_id, cv.GenerateID('bme680', CONF_MAKE_ID): cv.register_variable_id,
vol.Optional(CONF_ADDRESS, default=0x76): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x76): cv.i2c_address,
vol.Required(CONF_TEMPERATURE): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): BME680_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_PRESSURE): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): BME680_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): BME680_OVERSAMPLING_SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): BME680_OVERSAMPLING_SENSOR_SCHEMA,
vol.Required(CONF_GAS_RESISTANCE): MQTT_SENSOR_SCHEMA, vol.Required(CONF_GAS_RESISTANCE): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, vol.Any(*IIR_FILTER_OPTIONS)), vol.Optional(CONF_IIR_FILTER): vol.All(vol.Upper, cv.one_of(*IIR_FILTER_OPTIONS)),
# TODO: Heater # TODO: Heater
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeBME680Sensor = Application.MakeBME680Sensor
def to_code(config): def to_code(config):
rhs = App.make_bme680_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_bme680_sensor(config[CONF_TEMPERATURE][CONF_NAME],
@@ -53,32 +55,29 @@ def to_code(config):
config[CONF_GAS_RESISTANCE][CONF_NAME], config[CONF_GAS_RESISTANCE][CONF_NAME],
config[CONF_ADDRESS], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable('Application::MakeBME680Sensor', config[CONF_ID], rhs) make = variable(MakeBME680Sensor, config[CONF_MAKE_ID], rhs)
bme680 = make.Pbme680 bme680 = make.Pbme680
if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]: if CONF_OVERSAMPLING in config[CONF_TEMPERATURE]:
constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_TEMPERATURE][CONF_OVERSAMPLING]]
add(bme680.set_temperature_oversampling(RawExpression(constant))) add(bme680.set_temperature_oversampling(constant))
if CONF_OVERSAMPLING in config[CONF_PRESSURE]: if CONF_OVERSAMPLING in config[CONF_PRESSURE]:
constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_PRESSURE][CONF_OVERSAMPLING]]
add(bme680.set_pressure_oversampling(RawExpression(constant))) add(bme680.set_pressure_oversampling(constant))
if CONF_OVERSAMPLING in config[CONF_HUMIDITY]: if CONF_OVERSAMPLING in config[CONF_HUMIDITY]:
constant = OVERSAMPLING_OPTIONS[config[CONF_HUMIDITY][CONF_OVERSAMPLING]] constant = OVERSAMPLING_OPTIONS[config[CONF_HUMIDITY][CONF_OVERSAMPLING]]
add(bme680.set_humidity_oversampling(RawExpression(constant))) add(bme680.set_humidity_oversampling(constant))
if CONF_IIR_FILTER in config: if CONF_IIR_FILTER in config:
constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]] constant = IIR_FILTER_OPTIONS[config[CONF_IIR_FILTER]]
add(bme680.set_iir_filter(RawExpression(constant))) add(bme680.set_iir_filter(constant))
sensor.setup_sensor(bme680.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) sensor.setup_sensor(bme680.Pget_temperature_sensor(), make.Pmqtt_temperature,
sensor.setup_mqtt_sensor_component(make.Pmqtt_temperature, config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])
sensor.setup_sensor(bme680.Pget_pressure_sensor(), make.Pmqtt_pressure,
sensor.setup_sensor(bme680.Pget_pressure_sensor(), config[CONF_PRESSURE]) config[CONF_PRESSURE])
sensor.setup_mqtt_sensor_component(make.Pmqtt_pressure, config[CONF_PRESSURE]) sensor.setup_sensor(bme680.Pget_humidity_sensor(), make.Pmqtt_humidity,
config[CONF_HUMIDITY])
sensor.setup_sensor(bme680.Pget_humidity_sensor(), config[CONF_HUMIDITY]) sensor.setup_sensor(bme680.Pget_gas_resistance_sensor(), make.Pmqtt_gas_resistance,
sensor.setup_mqtt_sensor_component(make.Pmqtt_humidity, config[CONF_HUMIDITY]) config[CONF_GAS_RESISTANCE])
sensor.setup_sensor(bme680.Pget_gas_resistance_sensor(), config[CONF_GAS_RESISTANCE])
sensor.setup_mqtt_sensor_component(make.Pmqtt_gas_resistance, config[CONF_GAS_RESISTANCE])
BUILD_FLAGS = '-DUSE_BME680' BUILD_FLAGS = '-DUSE_BME680'

View File

@@ -2,33 +2,35 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA from esphomeyaml.const import CONF_ADDRESS, CONF_MAKE_ID, CONF_NAME, CONF_PRESSURE, \
from esphomeyaml.const import CONF_ADDRESS, CONF_ID, CONF_NAME, \ CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
CONF_PRESSURE, CONF_TEMPERATURE, CONF_UPDATE_INTERVAL from esphomeyaml.helpers import App, HexIntLiteral, add, variable, Application
from esphomeyaml.helpers import App, HexIntLiteral, add, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('bmp085_sensor'): cv.register_variable_id, cv.GenerateID('bmp085_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_PRESSURE): MQTT_SENSOR_SCHEMA, vol.Required(CONF_PRESSURE): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_ADDRESS): cv.i2c_address, vol.Optional(CONF_ADDRESS): cv.i2c_address,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeBMP085Sensor = Application.MakeBMP085Sensor
def to_code(config): def to_code(config):
rhs = App.make_bmp085_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_bmp085_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_PRESSURE][CONF_NAME], config[CONF_PRESSURE][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
bmp = variable('Application::MakeBMP085Sensor', config[CONF_ID], rhs) bmp = variable(MakeBMP085Sensor, config[CONF_MAKE_ID], rhs)
if CONF_ADDRESS in config: if CONF_ADDRESS in config:
add(bmp.Pbmp.set_address(HexIntLiteral(config[CONF_ADDRESS]))) add(bmp.Pbmp.set_address(HexIntLiteral(config[CONF_ADDRESS])))
sensor.setup_sensor(bmp.Pbmp.Pget_temperature_sensor(), config[CONF_TEMPERATURE])
sensor.setup_mqtt_sensor_component(bmp.Pmqtt_temperature, config[CONF_TEMPERATURE]) sensor.setup_sensor(bmp.Pbmp.Pget_temperature_sensor(), bmp.Pmqtt_temperature,
sensor.setup_sensor(bmp.Pbmp.Pget_pressure_sensor(), config[CONF_PRESSURE]) config[CONF_TEMPERATURE])
sensor.setup_mqtt_sensor_component(bmp.Pmqtt_pressure, config[CONF_PRESSURE]) sensor.setup_sensor(bmp.Pbmp.Pget_pressure_sensor(), bmp.Pmqtt_pressure,
config[CONF_PRESSURE])
BUILD_FLAGS = '-DUSE_BMP085_SENSOR' BUILD_FLAGS = '-DUSE_BMP085_SENSOR'

View File

@@ -2,23 +2,21 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.dallas import DALLAS_COMPONENT_CLASS from esphomeyaml.components.dallas import DallasComponent
from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \ from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \
CONF_RESOLUTION, \ CONF_RESOLUTION, CONF_UPDATE_INTERVAL
CONF_UPDATE_INTERVAL, CONF_ID from esphomeyaml.helpers import HexIntLiteral, get_variable
from esphomeyaml.helpers import HexIntLiteral, get_variable, Pvariable
PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = vol.All(sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('dallas_sensor'): cv.register_variable_id,
vol.Exclusive(CONF_ADDRESS, 'dallas'): cv.hex_int, vol.Exclusive(CONF_ADDRESS, 'dallas'): cv.hex_int,
vol.Exclusive(CONF_INDEX, 'dallas'): cv.positive_int, vol.Exclusive(CONF_INDEX, 'dallas'): cv.positive_int,
vol.Optional(CONF_DALLAS_ID): cv.variable_id, vol.Optional(CONF_DALLAS_ID): cv.variable_id,
vol.Optional(CONF_RESOLUTION): vol.All(vol.Coerce(int), vol.Range(min=8, max=12)), vol.Optional(CONF_RESOLUTION): vol.All(vol.Coerce(int), vol.Range(min=8, max=12)),
}).extend(sensor.MQTT_SENSOR_ID_SCHEMA.schema), cv.has_at_least_one_key(CONF_ADDRESS, CONF_INDEX)) }).extend(sensor.SENSOR_SCHEMA.schema), cv.has_at_least_one_key(CONF_ADDRESS, CONF_INDEX))
def to_code(config): def to_code(config):
hub = get_variable(config.get(CONF_DALLAS_ID), DALLAS_COMPONENT_CLASS) hub = get_variable(config.get(CONF_DALLAS_ID), DallasComponent)
update_interval = config.get(CONF_UPDATE_INTERVAL) update_interval = config.get(CONF_UPDATE_INTERVAL)
if CONF_RESOLUTION in config and update_interval is None: if CONF_RESOLUTION in config and update_interval is None:
update_interval = 10000 update_interval = 10000
@@ -30,8 +28,7 @@ def to_code(config):
else: else:
rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX], rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX],
update_interval, config.get(CONF_RESOLUTION)) update_interval, config.get(CONF_RESOLUTION))
sensor_ = Pvariable('sensor::DallasTemperatureSensor', config[CONF_ID], rhs) sensor.register_sensor(rhs, config)
sensor.register_sensor(sensor_, config)
BUILD_FLAGS = '-DUSE_DALLAS_SENSOR' BUILD_FLAGS = '-DUSE_DALLAS_SENSOR'

View File

@@ -2,43 +2,45 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_MODEL, CONF_NAME, CONF_PIN, \
from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_MODEL, CONF_NAME, CONF_PIN, \
CONF_TEMPERATURE, CONF_UPDATE_INTERVAL CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, RawExpression, add, variable, exp_gpio_output_pin from esphomeyaml.helpers import App, Application, add, gpio_output_pin_expression, variable
from esphomeyaml.pins import GPIO_OUTPUT_PIN_SCHEMA from esphomeyaml.pins import GPIO_OUTPUT_PIN_SCHEMA
DHT_MODELS = { DHT_MODELS = {
'AUTO_DETECT': 'sensor::DHT_MODEL_AUTO_DETECT', 'AUTO_DETECT': sensor.sensor_ns.DHT_MODEL_AUTO_DETECT,
'DHT11': 'sensor::DHT_MODEL_DHT11', 'DHT11': sensor.sensor_ns.DHT_MODEL_DHT11,
'DHT22': 'sensor::DHT_MODEL_DHT22', 'DHT22': sensor.sensor_ns.DHT_MODEL_DHT22,
'AM2302': 'sensor::DHT_MODEL_AM2302', 'AM2302': sensor.sensor_ns.DHT_MODEL_AM2302,
'RHT03': 'sensor::DHT_MODEL_RHT03', 'RHT03': sensor.sensor_ns.DHT_MODEL_RHT03,
} }
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('dht_sensor'): cv.register_variable_id, cv.GenerateID('dht_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): GPIO_OUTPUT_PIN_SCHEMA,
vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_MODEL): vol.All(vol.Upper, vol.Any(*DHT_MODELS)), vol.Optional(CONF_MODEL): vol.All(vol.Upper, cv.one_of(*DHT_MODELS)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeDHTSensor = Application.MakeDHTSensor
def to_code(config): def to_code(config):
pin = exp_gpio_output_pin(config[CONF_PIN]) pin = gpio_output_pin_expression(config[CONF_PIN])
rhs = App.make_dht_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_dht_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
pin, config.get(CONF_UPDATE_INTERVAL)) pin, config.get(CONF_UPDATE_INTERVAL))
dht = variable('Application::MakeDHTSensor', config[CONF_ID], rhs) dht = variable(MakeDHTSensor, config[CONF_MAKE_ID], rhs)
if CONF_MODEL in config: if CONF_MODEL in config:
constant = DHT_MODELS[config[CONF_MODEL]] constant = DHT_MODELS[config[CONF_MODEL]]
add(dht.Pdht.set_dht_model(RawExpression(constant))) add(dht.Pdht.set_dht_model(constant))
sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), config[CONF_TEMPERATURE])
sensor.setup_mqtt_sensor_component(dht.Pmqtt_temperature, config[CONF_TEMPERATURE]) sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(),
sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), config[CONF_HUMIDITY]) dht.Pmqtt_temperature, config[CONF_TEMPERATURE])
sensor.setup_mqtt_sensor_component(dht.Pmqtt_humidity, config[CONF_HUMIDITY]) sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(),
dht.Pmqtt_humidity, config[CONF_HUMIDITY])
BUILD_FLAGS = '-DUSE_DHT_SENSOR' BUILD_FLAGS = '-DUSE_DHT_SENSOR'

View File

@@ -0,0 +1,33 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, CONF_TEMPERATURE, \
CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, variable
DEPENDENCIES = ['i2c']
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('dht_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
})
MakeDHT12Sensor = Application.MakeDHT12Sensor
def to_code(config):
rhs = App.make_dht12_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL))
dht = variable(MakeDHT12Sensor, config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), dht.Pmqtt_temperature,
config[CONF_TEMPERATURE])
sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), dht.Pmqtt_humidity,
config[CONF_HUMIDITY])
BUILD_FLAGS = '-DUSE_DHT12_SENSOR'

View File

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

View File

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

View File

@@ -0,0 +1,32 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN_CLOCK, CONF_PIN_CS, CONF_PIN_MISO, \
CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, Application, gpio_input_pin_expression, \
gpio_output_pin_expression, variable
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('max6675', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN_CS): pins.GPIO_OUTPUT_PIN_SCHEMA,
vol.Required(CONF_PIN_CLOCK): pins.GPIO_OUTPUT_PIN_SCHEMA,
vol.Optional(CONF_PIN_MISO): pins.GPIO_INPUT_PIN_SCHEMA,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema)
MakeMAX6675Sensor = Application.MakeMAX6675Sensor
def to_code(config):
pin_cs = gpio_output_pin_expression(config[CONF_PIN_CS])
pin_clock = gpio_output_pin_expression(config[CONF_PIN_CLOCK])
pin_miso = gpio_input_pin_expression(config[CONF_PIN_MISO])
rhs = App.make_max6675_sensor(config[CONF_NAME], pin_cs, pin_clock, pin_miso,
config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeMAX6675Sensor, config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Pmax6675, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_MAX6675_SENSOR'

View File

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

View File

@@ -3,32 +3,32 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_ID, CONF_INTERNAL_FILTER, \ from esphomeyaml.const import CONF_COUNT_MODE, CONF_FALLING_EDGE, CONF_INTERNAL_FILTER, \
CONF_NAME, CONF_PIN, CONF_PULL_MODE, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, \ CONF_MAKE_ID, CONF_NAME, CONF_PIN, CONF_PULL_MODE, CONF_RISING_EDGE, CONF_UPDATE_INTERVAL, \
ESP_PLATFORM_ESP32 ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, RawExpression, add, variable from esphomeyaml.helpers import App, add, global_ns, variable, Application
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
GPIO_PULL_MODES = { GPIO_PULL_MODES = {
'PULLUP': 'GPIO_PULLUP_ONLY', 'PULLUP': global_ns.GPIO_PULLUP_ONLY,
'PULLDOWN': 'GPIO_PULLDOWN_ONLY', 'PULLDOWN': global_ns.GPIO_PULLDOWN_ONLY,
'PULLUP_PULLDOWN': 'GPIO_PULLUP_PULLDOWN', 'PULLUP_PULLDOWN': global_ns.GPIO_PULLUP_PULLDOWN,
'FLOATING': 'GPIO_FLOATING', 'FLOATING': global_ns.GPIO_FLOATING,
} }
GPIO_PULL_MODE_SCHEMA = vol.All(vol.Upper, vol.Any(*list(GPIO_PULL_MODES.keys()))) GPIO_PULL_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*GPIO_PULL_MODES))
COUNT_MODES = { COUNT_MODES = {
'DISABLE': 'PCNT_COUNT_DIS', 'DISABLE': global_ns.PCNT_COUNT_DIS,
'INCREMENT': 'PCNT_COUNT_INC', 'INCREMENT': global_ns.PCNT_COUNT_INC,
'DECREMENT': 'PCNT_COUNT_DEC', 'DECREMENT': global_ns.PCNT_COUNT_DEC,
} }
COUNT_MODE_SCHEMA = vol.All(vol.Upper, vol.Any(*list(COUNT_MODES.keys()))) COUNT_MODE_SCHEMA = vol.All(vol.Upper, cv.one_of(*COUNT_MODES))
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('pulse_counter'): cv.register_variable_id, cv.GenerateID('pulse_counter', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.input_pin, vol.Required(CONF_PIN): pins.input_pin,
vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA, vol.Optional(CONF_PULL_MODE): GPIO_PULL_MODE_SCHEMA,
vol.Optional(CONF_COUNT_MODE): vol.Schema({ vol.Optional(CONF_COUNT_MODE): vol.Schema({
@@ -37,26 +37,27 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
}), }),
vol.Optional(CONF_INTERNAL_FILTER): vol.All(vol.Coerce(int), vol.Range(min=0, max=1023)), vol.Optional(CONF_INTERNAL_FILTER): vol.All(vol.Coerce(int), vol.Range(min=0, max=1023)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakePulseCounterSensor = Application.MakePulseCounterSensor
def to_code(config): def to_code(config):
rhs = App.make_pulse_counter_sensor(config[CONF_NAME], config[CONF_PIN], rhs = App.make_pulse_counter_sensor(config[CONF_NAME], config[CONF_PIN],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable('Application::MakePulseCounterSensor', config[CONF_ID], rhs) make = variable(MakePulseCounterSensor, config[CONF_MAKE_ID], rhs)
pcnt = make.Ppcnt pcnt = make.Ppcnt
if CONF_PULL_MODE in config: if CONF_PULL_MODE in config:
pull_mode = GPIO_PULL_MODES[config[CONF_PULL_MODE]] pull_mode = GPIO_PULL_MODES[config[CONF_PULL_MODE]]
add(pcnt.set_pull_mode(RawExpression(pull_mode))) add(pcnt.set_pull_mode(pull_mode))
if CONF_COUNT_MODE in config: if CONF_COUNT_MODE in config:
count_mode = config[CONF_COUNT_MODE] count_mode = config[CONF_COUNT_MODE]
rising_edge = COUNT_MODES[count_mode[CONF_RISING_EDGE]] rising_edge = COUNT_MODES[count_mode[CONF_RISING_EDGE]]
falling_edge = COUNT_MODES[count_mode[CONF_FALLING_EDGE]] falling_edge = COUNT_MODES[count_mode[CONF_FALLING_EDGE]]
add(pcnt.set_edge_mode(RawExpression(rising_edge), RawExpression(falling_edge))) add(pcnt.set_edge_mode(rising_edge, falling_edge))
if CONF_INTERNAL_FILTER in config: if CONF_INTERNAL_FILTER in config:
add(pcnt.set_filter(config[CONF_INTERNAL_FILTER])) add(pcnt.set_filter(config[CONF_INTERNAL_FILTER]))
sensor.setup_sensor(pcnt, config) sensor.setup_sensor(make.Ppcnt, make.Pmqtt, config)
sensor.setup_mqtt_sensor_component(make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_PULSE_COUNTER_SENSOR' BUILD_FLAGS = '-DUSE_PULSE_COUNTER_SENSOR'

View File

@@ -0,0 +1,45 @@
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_RESOLUTION
from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, variable
RESOLUTIONS = {
'1': sensor.sensor_ns.ROTARY_ENCODER_1_PULSE_PER_CYCLE,
'2': sensor.sensor_ns.ROTARY_ENCODER_2_PULSES_PER_CYCLE,
'4': sensor.sensor_ns.ROTARY_ENCODER_4_PULSES_PER_CYCLE,
}
CONF_PIN_A = 'pin_a'
CONF_PIN_B = 'pin_b'
CONF_PIN_RESET = 'pin_reset'
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('rotary_encoder', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN_A): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Required(CONF_PIN_B): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Optional(CONF_PIN_RESET): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Optional(CONF_RESOLUTION): vol.All(cv.string, cv.one_of(*RESOLUTIONS)),
}).extend(sensor.SENSOR_SCHEMA.schema)
MakeRotaryEncoderSensor = Application.MakeRotaryEncoderSensor
def to_code(config):
pin_a = gpio_input_pin_expression(config[CONF_PIN_A])
pin_b = gpio_input_pin_expression(config[CONF_PIN_B])
rhs = App.make_rotary_encoder_sensor(config[CONF_NAME], pin_a, pin_b)
make = variable(MakeRotaryEncoderSensor, config[CONF_MAKE_ID], rhs)
encoder = make.Protary_encoder
if CONF_PIN_RESET in config:
pin_i = gpio_input_pin_expression(config[CONF_PIN_RESET])
add(encoder.set_reset_pin(pin_i))
if CONF_RESOLUTION in config:
resolution = RESOLUTIONS[config[CONF_RESOLUTION]]
add(encoder.set_resolution(resolution))
sensor.setup_sensor(encoder, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_ROTARY_ENCODER_SENSOR'

View File

@@ -2,44 +2,43 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.components.sensor import MQTT_SENSOR_SCHEMA from esphomeyaml.const import CONF_ACCURACY, CONF_ADDRESS, CONF_HUMIDITY, CONF_MAKE_ID, CONF_NAME, \
from esphomeyaml.const import CONF_HUMIDITY, CONF_ID, CONF_NAME, CONF_TEMPERATURE, \ CONF_TEMPERATURE, CONF_UPDATE_INTERVAL
CONF_UPDATE_INTERVAL, CONF_ADDRESS, CONF_ACCURACY from esphomeyaml.helpers import App, Application, add, variable
from esphomeyaml.helpers import App, variable, RawExpression, add
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
SHT_ACCURACIES = { SHT_ACCURACIES = {
'LOW': 'sensor::SHT3XD_ACCURACY_LOW', 'LOW': sensor.sensor_ns.SHT3XD_ACCURACY_LOW,
'MEDIUM': 'sensor::SHT3XD_ACCURACY_MEDIUM', 'MEDIUM': sensor.sensor_ns.SHT3XD_ACCURACY_MEDIUM,
'HIGH': 'sensor::SHT3XD_ACCURACY_HIGH', 'HIGH': sensor.sensor_ns.SHT3XD_ACCURACY_HIGH,
} }
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('sht3xd'): cv.register_variable_id, cv.GenerateID('sht3xd', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_TEMPERATURE): MQTT_SENSOR_SCHEMA, vol.Required(CONF_TEMPERATURE): sensor.SENSOR_SCHEMA,
vol.Required(CONF_HUMIDITY): MQTT_SENSOR_SCHEMA, vol.Required(CONF_HUMIDITY): sensor.SENSOR_SCHEMA,
vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x44): cv.i2c_address,
vol.Optional(CONF_ACCURACY): vol.All(vol.Upper, vol.Any(*SHT_ACCURACIES)), vol.Optional(CONF_ACCURACY): vol.All(vol.Upper, cv.one_of(*SHT_ACCURACIES)),
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}) })
MakeSHT3XDSensor = Application.MakeSHT3XDSensor
def to_code(config): def to_code(config):
rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_sht3xd_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config[CONF_HUMIDITY][CONF_NAME],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
sht3xd = variable('Application::MakeSHT3XDSensor', config[CONF_ID], rhs) sht3xd = variable(MakeSHT3XDSensor, config[CONF_MAKE_ID], rhs)
if CONF_ACCURACY in config: if CONF_ACCURACY in config:
constant = RawExpression(SHT_ACCURACIES[config[CONF_ACCURACY]]) add(sht3xd.Psht3xd.set_accuracy(SHT_ACCURACIES[config[CONF_ACCURACY]]))
add(sht3xd.Psht3xd.set_accuracy(constant))
sensor.setup_sensor(sht3xd.Psht3xd.Pget_temperature_sensor(), config[CONF_TEMPERATURE]) sensor.setup_sensor(sht3xd.Psht3xd.Pget_temperature_sensor(), sht3xd.Pmqtt_temperature,
sensor.setup_mqtt_sensor_component(sht3xd.Pmqtt_temperature, config[CONF_TEMPERATURE]) config[CONF_TEMPERATURE])
sensor.setup_sensor(sht3xd.Psht3xd.Pget_humidity_sensor(), sht3xd.Pmqtt_humidity,
sensor.setup_sensor(sht3xd.PPsht3xd.Pget_humidity_sensor(), config[CONF_HUMIDITY]) config[CONF_HUMIDITY])
sensor.setup_mqtt_sensor_component(sht3xd.Pmqtt_humidity, config[CONF_HUMIDITY])
BUILD_FLAGS = '-DUSE_SHT3XD' BUILD_FLAGS = '-DUSE_SHT3XD'

View File

@@ -0,0 +1,25 @@
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
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.SENSOR_SCHEMA.schema)
MakeTemplateSensor = Application.MakeTemplateSensor
def to_code(config):
template_ = process_lambda(config[CONF_LAMBDA], [])
rhs = App.make_template_sensor(config[CONF_NAME], template_,
config.get(CONF_UPDATE_INTERVAL))
make = variable(MakeTemplateSensor, config[CONF_MAKE_ID], rhs)
sensor.setup_sensor(make.Ptemplate_, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_TEMPLATE_SENSOR'

View File

@@ -2,20 +2,20 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADDRESS, CONF_GAIN, CONF_ID, CONF_INTEGRATION_TIME, CONF_NAME, \ from esphomeyaml.const import CONF_ADDRESS, CONF_GAIN, CONF_INTEGRATION_TIME, CONF_MAKE_ID, \
CONF_UPDATE_INTERVAL CONF_NAME, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, RawExpression, add, variable from esphomeyaml.helpers import App, Application, add, variable
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
INTEGRATION_TIMES = { INTEGRATION_TIMES = {
14: 'sensor::TSL2561_INTEGRATION_14MS', 14: sensor.sensor_ns.TSL2561_INTEGRATION_14MS,
101: 'sensor::TSL2561_INTEGRATION_101MS', 101: sensor.sensor_ns.TSL2561_INTEGRATION_101MS,
402: 'sensor::TSL2561_INTEGRATION_402MS', 402: sensor.sensor_ns.TSL2561_INTEGRATION_402MS,
} }
GAINS = { GAINS = {
'1X': 'sensor::TSL2561_GAIN_1X', '1X': sensor.sensor_ns.TSL2561_GAIN_1X,
'16X': 'sensor::TSL2561_GAIN_16X', '16X': sensor.sensor_ns.TSL2561_GAIN_16X,
} }
CONF_IS_CS_PACKAGE = 'is_cs_package' CONF_IS_CS_PACKAGE = 'is_cs_package'
@@ -29,30 +29,29 @@ def validate_integration_time(value):
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('tsl2561_sensor'): cv.register_variable_id, cv.GenerateID('tsl2561_sensor', CONF_MAKE_ID): cv.register_variable_id,
vol.Optional(CONF_ADDRESS, default=0x39): cv.i2c_address, vol.Optional(CONF_ADDRESS, default=0x39): cv.i2c_address,
vol.Optional(CONF_INTEGRATION_TIME): validate_integration_time, vol.Optional(CONF_INTEGRATION_TIME): validate_integration_time,
vol.Optional(CONF_GAIN): vol.All(vol.Upper, vol.Any(*GAINS)), vol.Optional(CONF_GAIN): vol.All(vol.Upper, cv.one_of(*GAINS)),
vol.Optional(CONF_IS_CS_PACKAGE): cv.boolean, vol.Optional(CONF_IS_CS_PACKAGE): cv.boolean,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeTSL2561Sensor = Application.MakeTSL2561Sensor
def to_code(config): def to_code(config):
rhs = App.make_tsl2561_sensor(config[CONF_NAME], config[CONF_ADDRESS], rhs = App.make_tsl2561_sensor(config[CONF_NAME], config[CONF_ADDRESS],
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make_tsl = variable('Application::MakeTSL2561Sensor', config[CONF_ID], rhs) make_tsl = variable(MakeTSL2561Sensor, config[CONF_MAKE_ID], rhs)
tsl2561 = make_tsl.Ptsl2561 tsl2561 = make_tsl.Ptsl2561
if CONF_INTEGRATION_TIME in config: if CONF_INTEGRATION_TIME in config:
constant = INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]] add(tsl2561.set_integration_time(INTEGRATION_TIMES[config[CONF_INTEGRATION_TIME]]))
add(tsl2561.set_integration_time(RawExpression(constant)))
if CONF_GAIN in config: if CONF_GAIN in config:
constant = GAINS[config[CONF_GAIN]] add(tsl2561.set_gain(GAINS[config[CONF_GAIN]]))
add(tsl2561.set_gain(RawExpression(constant)))
if CONF_IS_CS_PACKAGE in config: if CONF_IS_CS_PACKAGE in config:
add(tsl2561.set_is_cs_package(config[CONF_IS_CS_PACKAGE])) add(tsl2561.set_is_cs_package(config[CONF_IS_CS_PACKAGE]))
sensor.setup_sensor(tsl2561, config) sensor.setup_sensor(tsl2561, make_tsl.Pmqtt, config)
sensor.setup_mqtt_sensor_component(make_tsl.Pmqtt, config)
BUILD_FLAGS = '-DUSE_TSL2561' BUILD_FLAGS = '-DUSE_TSL2561'

View File

@@ -3,34 +3,35 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ECHO_PIN, CONF_ID, CONF_NAME, \ from esphomeyaml.const import CONF_ECHO_PIN, CONF_MAKE_ID, CONF_NAME, CONF_TIMEOUT_METER, \
CONF_TIMEOUT_METER, CONF_TIMEOUT_TIME, CONF_TRIGGER_PIN, CONF_UPDATE_INTERVAL CONF_TIMEOUT_TIME, CONF_TRIGGER_PIN, CONF_UPDATE_INTERVAL
from esphomeyaml.helpers import App, add, exp_gpio_input_pin, exp_gpio_output_pin, \ from esphomeyaml.helpers import App, Application, add, gpio_input_pin_expression, \
variable gpio_output_pin_expression, variable
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID('ultrasonic'): cv.register_variable_id, cv.GenerateID('ultrasonic', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_TRIGGER_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_TRIGGER_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
vol.Required(CONF_ECHO_PIN): pins.GPIO_INPUT_PIN_SCHEMA, vol.Required(CONF_ECHO_PIN): pins.GPIO_INTERNAL_INPUT_PIN_SCHEMA,
vol.Exclusive(CONF_TIMEOUT_METER, 'timeout'): cv.positive_float, vol.Exclusive(CONF_TIMEOUT_METER, 'timeout'): cv.positive_float,
vol.Exclusive(CONF_TIMEOUT_TIME, 'timeout'): cv.positive_time_period_microseconds, vol.Exclusive(CONF_TIMEOUT_TIME, 'timeout'): cv.positive_time_period_microseconds,
vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds, vol.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(sensor.MQTT_SENSOR_SCHEMA.schema) }).extend(sensor.SENSOR_SCHEMA.schema)
MakeUltrasonicSensor = Application.MakeUltrasonicSensor
def to_code(config): def to_code(config):
trigger = exp_gpio_output_pin(config[CONF_TRIGGER_PIN]) trigger = gpio_output_pin_expression(config[CONF_TRIGGER_PIN])
echo = exp_gpio_input_pin(config[CONF_ECHO_PIN]) echo = gpio_input_pin_expression(config[CONF_ECHO_PIN])
rhs = App.make_ultrasonic_sensor(config[CONF_NAME], trigger, echo, rhs = App.make_ultrasonic_sensor(config[CONF_NAME], trigger, echo,
config.get(CONF_UPDATE_INTERVAL)) config.get(CONF_UPDATE_INTERVAL))
make = variable('Application::MakeUltrasonicSensor', config[CONF_ID], rhs) make = variable(MakeUltrasonicSensor, config[CONF_MAKE_ID], rhs)
ultrasonic = make.Pultrasonic ultrasonic = make.Pultrasonic
if CONF_TIMEOUT_TIME in config: if CONF_TIMEOUT_TIME in config:
add(ultrasonic.set_timeout_us(config[CONF_TIMEOUT_TIME])) add(ultrasonic.set_timeout_us(config[CONF_TIMEOUT_TIME]))
elif CONF_TIMEOUT_METER in config: elif CONF_TIMEOUT_METER in config:
add(ultrasonic.set_timeout_m(config[CONF_TIMEOUT_METER])) add(ultrasonic.set_timeout_m(config[CONF_TIMEOUT_METER]))
sensor.setup_sensor(ultrasonic, config) sensor.setup_sensor(ultrasonic, make.Pmqtt, config)
sensor.setup_mqtt_sensor_component(make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_ULTRASONIC_SENSOR' BUILD_FLAGS = '-DUSE_ULTRASONIC_SENSOR'

View File

@@ -1,36 +1,50 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_NAME, CONF_MQTT_ID from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_INVERTED, CONF_MQTT_ID
from esphomeyaml.helpers import App, Pvariable, add, setup_mqtt_component from esphomeyaml.helpers import App, Pvariable, add, esphomelib_ns, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
MQTT_SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
vol.Optional(CONF_ICON): cv.icon, cv.GenerateID('switch_'): cv.register_variable_id,
})
MQTT_SWITCH_ID_SCHEMA = MQTT_SWITCH_SCHEMA.extend({
cv.GenerateID('mqtt_switch', CONF_MQTT_ID): cv.register_variable_id, cv.GenerateID('mqtt_switch', CONF_MQTT_ID): cv.register_variable_id,
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INVERTED): cv.boolean,
}) })
switch_ns = esphomelib_ns.namespace('switch_')
def setup_mqtt_switch(obj, config): Switch = switch_ns.Switch
setup_mqtt_component(obj, config) MQTTSwitchComponent = switch_ns.MQTTSwitchComponent
ToggleAction = switch_ns.ToggleAction
TurnOffAction = switch_ns.TurnOffAction
TurnOnAction = switch_ns.TurnOnAction
def setup_switch(obj, config): def setup_switch_core_(switch_var, mqtt_var, config):
if CONF_ICON in config: if CONF_ICON in config:
add(obj.set_icon(config[CONF_ICON])) add(switch_var.set_icon(config[CONF_ICON]))
if CONF_INVERTED in config:
add(switch_var.set_inverted(config[CONF_INVERTED]))
setup_mqtt_component(mqtt_var, config)
def setup_switch(switch_obj, mqtt_obj, config):
switch_var = Pvariable(Switch, config[CONF_ID], switch_obj, has_side_effects=False)
mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], mqtt_obj,
has_side_effects=False)
setup_switch_core_(switch_var, mqtt_var, config)
def register_switch(var, config): def register_switch(var, config):
setup_switch(var, config) switch_var = Pvariable(Switch, config[CONF_ID], var, has_side_effects=True)
rhs = App.register_switch(var) rhs = App.register_switch(switch_var)
mqtt_switch = Pvariable('switch_::MQTTSwitchComponent', config[CONF_MQTT_ID], rhs) mqtt_var = Pvariable(MQTTSwitchComponent, config[CONF_MQTT_ID], rhs,
setup_mqtt_switch(mqtt_switch, config) has_side_effects=True)
setup_switch_core_(switch_var, mqtt_var, config)
BUILD_FLAGS = '-DUSE_SWITCH' BUILD_FLAGS = '-DUSE_SWITCH'

View File

@@ -3,20 +3,21 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import pins from esphomeyaml import pins
from esphomeyaml.components import switch from esphomeyaml.components import switch
from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_PIN from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_PIN
from esphomeyaml.helpers import App, exp_gpio_output_pin, variable from esphomeyaml.helpers import App, Application, gpio_output_pin_expression, variable
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('gpio_switch'): cv.register_variable_id, cv.GenerateID('gpio_switch', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA,
}).extend(switch.MQTT_SWITCH_SCHEMA.schema) }).extend(switch.SWITCH_SCHEMA.schema)
MakeGPIOSwitch = Application.MakeGPIOSwitch
def to_code(config): def to_code(config):
rhs = App.make_gpio_switch(config[CONF_NAME], exp_gpio_output_pin(config[CONF_PIN])) rhs = App.make_gpio_switch(config[CONF_NAME], gpio_output_pin_expression(config[CONF_PIN]))
gpio = variable('Application::MakeGPIOSwitch', config[CONF_ID], rhs) gpio = variable(MakeGPIOSwitch, config[CONF_MAKE_ID], rhs)
switch.setup_switch(gpio.Pswitch_, config) switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config)
switch.setup_mqtt_switch(gpio.Pmqtt, config)
BUILD_FLAGS = '-DUSE_GPIO_SWITCH' BUILD_FLAGS = '-DUSE_GPIO_SWITCH'

View File

@@ -2,12 +2,12 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import switch from esphomeyaml.components import switch
from esphomeyaml.components.ir_transmitter import IR_TRANSMITTER_COMPONENT_CLASS from esphomeyaml.components.ir_transmitter import IRTransmitterComponent
from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_COMMAND, CONF_DATA, \ from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_COMMAND, CONF_DATA, \
CONF_ID, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, CONF_PANASONIC, \ CONF_INVERTED, CONF_IR_TRANSMITTER_ID, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \
CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME CONF_PANASONIC, CONF_RAW, CONF_REPEAT, CONF_SONY, CONF_TIMES, CONF_WAIT_TIME
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import ArrayInitializer, HexIntLiteral, MockObj, Pvariable, get_variable from esphomeyaml.helpers import App, ArrayInitializer, HexIntLiteral, get_variable
DEPENDENCIES = ['ir_transmitter'] DEPENDENCIES = ['ir_transmitter']
@@ -45,10 +45,13 @@ PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
vol.Optional('wait_time_us'): cv.invalid(WAIT_TIME_MESSAGE), vol.Optional('wait_time_us'): cv.invalid(WAIT_TIME_MESSAGE),
})), })),
vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id, vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id,
}).extend(switch.MQTT_SWITCH_ID_SCHEMA.schema), cv.has_at_least_one_key(*IR_KEYS)) 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 # pylint: disable=invalid-name
SendData = MockObj('switch_::ir::SendData', '::') ir_ns = switch.switch_ns.namespace('ir')
SendData = ir_ns.namespace('SendData')
DataTransmitter = IRTransmitterComponent.DataTransmitter
def safe_hex(value): def safe_hex(value):
@@ -86,18 +89,15 @@ def exp_send_data(config):
else: else:
times = config[CONF_REPEAT][CONF_TIMES] times = config[CONF_REPEAT][CONF_TIMES]
wait_us = config[CONF_REPEAT][CONF_WAIT_TIME] wait_us = config[CONF_REPEAT][CONF_WAIT_TIME]
base = MockObj(unicode(base), u'.')
base = base.repeat(times, wait_us) base = base.repeat(times, wait_us)
return base return base
def to_code(config): def to_code(config):
ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IR_TRANSMITTER_COMPONENT_CLASS) ir = get_variable(config.get(CONF_IR_TRANSMITTER_ID), IRTransmitterComponent)
send_data = exp_send_data(config) send_data = exp_send_data(config)
rhs = ir.create_transmitter(config[CONF_NAME], send_data) rhs = App.register_component(ir.create_transmitter(config[CONF_NAME], send_data))
switch_ = Pvariable(IR_TRANSMITTER_COMPONENT_CLASS + '::DataTransmitter', config[CONF_ID], switch.register_switch(rhs, config)
rhs)
switch.register_switch(switch_, config)
BUILD_FLAGS = '-DUSE_IR_TRANSMITTER' BUILD_FLAGS = '-DUSE_IR_TRANSMITTER'

View File

@@ -2,21 +2,22 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import switch from esphomeyaml.components import switch
from esphomeyaml.const import CONF_ID, CONF_NAME, CONF_OUTPUT from esphomeyaml.const import CONF_MAKE_ID, CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, get_variable, variable from esphomeyaml.helpers import App, Application, get_variable, variable
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('output_switch'): cv.register_variable_id, cv.GenerateID('output_switch', CONF_MAKE_ID): cv.register_variable_id,
vol.Required(CONF_OUTPUT): cv.variable_id, vol.Required(CONF_OUTPUT): cv.variable_id,
}).extend(switch.MQTT_SWITCH_SCHEMA.schema) }).extend(switch.SWITCH_SCHEMA.schema)
MakeSimpleSwitch = Application.MakeSimpleSwitch
def to_code(config): def to_code(config):
output = get_variable(config[CONF_OUTPUT]) output = get_variable(config[CONF_OUTPUT])
rhs = App.make_simple_switch(config[CONF_NAME], output) rhs = App.make_simple_switch(config[CONF_NAME], output)
gpio = variable('Application::MakeSimpleSwitch', config[CONF_ID], rhs) gpio = variable(MakeSimpleSwitch, config[CONF_MAKE_ID], rhs)
switch.setup_switch(gpio.Pswitch_, config) switch.setup_switch(gpio.Pswitch_, gpio.Pmqtt, config)
switch.setup_mqtt_switch(gpio.Pmqtt, config)
BUILD_FLAGS = '-DUSE_SIMPLE_SWITCH' BUILD_FLAGS = '-DUSE_SIMPLE_SWITCH'

View File

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

View File

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

View File

@@ -0,0 +1,40 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
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
PLATFORM_SCHEMA = vol.All(switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('template_switch', CONF_MAKE_ID): cv.register_variable_id,
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_TURN_OFF_ACTION): automation.ACTIONS_SCHEMA,
vol.Optional(CONF_TURN_ON_ACTION): automation.ACTIONS_SCHEMA,
}).extend(switch.SWITCH_SCHEMA.schema), cv.has_at_exactly_one_key(CONF_LAMBDA, CONF_OPTIMISTIC))
MakeTemplateSwitch = Application.MakeTemplateSwitch
def to_code(config):
rhs = App.make_template_switch(config[CONF_NAME])
make = variable(MakeTemplateSwitch, config[CONF_MAKE_ID], rhs)
if CONF_LAMBDA in config:
template_ = process_lambda(config[CONF_LAMBDA], [])
add(make.Ptemplate.set_state_lambda(template_))
if CONF_TURN_OFF_ACTION in config:
actions = automation.build_actions(config[CONF_TURN_OFF_ACTION], NoArg)
add(make.Ptemplate_.add_turn_off_actions(actions))
if CONF_TURN_ON_ACTION in config:
actions = automation.build_actions(config[CONF_TURN_ON_ACTION], NoArg)
add(make.Ptemplate_.add_turn_on_actions(actions))
if CONF_OPTIMISTIC in config:
add(make.Ptemplate_.set_optimistic(config[CONF_OPTIMISTIC]))
switch.setup_switch(make.Ptemplate_, make.Pmqtt, config)
BUILD_FLAGS = '-DUSE_TEMPLATE_SWITCH'

View File

@@ -5,7 +5,7 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core from esphomeyaml import core
from esphomeyaml.const import CONF_PORT, CONF_JS_URL, CONF_CSS_URL, CONF_ID, ESP_PLATFORM_ESP32 from esphomeyaml.const import CONF_PORT, CONF_JS_URL, CONF_CSS_URL, CONF_ID, ESP_PLATFORM_ESP32
from esphomeyaml.helpers import App, add, Pvariable from esphomeyaml.helpers import App, add, Pvariable, esphomelib_ns
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -16,10 +16,12 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_JS_URL): vol.Url, vol.Optional(CONF_JS_URL): vol.Url,
}) })
WebServer = esphomelib_ns.WebServer
def to_code(config): def to_code(config):
rhs = App.init_web_server(config.get(CONF_PORT)) rhs = App.init_web_server(config.get(CONF_PORT))
web_server = Pvariable('WebServer', config[CONF_ID], rhs) web_server = Pvariable(WebServer, config[CONF_ID], rhs)
if CONF_CSS_URL in config: if CONF_CSS_URL in config:
add(web_server.set_css_url(config[CONF_CSS_URL])) add(web_server.set_css_url(config[CONF_CSS_URL]))
if CONF_JS_URL in config: if CONF_JS_URL in config:

View File

@@ -2,10 +2,10 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core from esphomeyaml import core
from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_GATEWAY, \ from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, \
CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, \ CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_SSID, \
ESP_PLATFORM_ESP8266 CONF_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266
from esphomeyaml.helpers import App, MockObj, Pvariable, StructInitializer, add from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, esphomelib_ns, global_ns
def validate_password(value): def validate_password(value):
@@ -42,10 +42,13 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA, vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
}), }),
vol.Optional(CONF_HOSTNAME): cv.hostname, vol.Optional(CONF_HOSTNAME): cv.hostname,
vol.Required(CONF_DOMAIN, default='.local'): cv.domainname,
}) })
# pylint: disable=invalid-name # pylint: disable=invalid-name
IPAddress = MockObj('IPAddress') IPAddress = global_ns.IPAddress
ManualIP = esphomelib_ns.ManualIP
WiFiComponent = esphomelib_ns.WiFiComponent
def safe_ip(ip): def safe_ip(ip):
@@ -56,7 +59,7 @@ def safe_ip(ip):
def manual_ip(config): def manual_ip(config):
return StructInitializer( return StructInitializer(
'ManualIP', ManualIP,
('static_ip', safe_ip(config[CONF_STATIC_IP])), ('static_ip', safe_ip(config[CONF_STATIC_IP])),
('gateway', safe_ip(config[CONF_GATEWAY])), ('gateway', safe_ip(config[CONF_GATEWAY])),
('subnet', safe_ip(config[CONF_SUBNET])), ('subnet', safe_ip(config[CONF_SUBNET])),
@@ -72,7 +75,7 @@ def to_code(config):
rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD)) rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD))
else: else:
rhs = App.init_wifi() rhs = App.init_wifi()
wifi = Pvariable('WiFiComponent', config[CONF_ID], rhs) wifi = Pvariable(WiFiComponent, config[CONF_ID], rhs)
if sta and CONF_MANUAL_IP in config: if sta and CONF_MANUAL_IP in config:
add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP]))) add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP])))

23
esphomeyaml/config.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "esphomeyaml",
"version": "1.6.0",
"slug": "esphomeyaml",
"description": "esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices.",
"url": "https://esphomelib.com/esphomeyaml/index.html",
"startup": "application",
"webui": "http://[HOST]:[PORT:6052]",
"boot": "auto",
"ports": {
"6052/tcp": 6052,
"6053/tcp": 6053
},
"auto_uart": true,
"map": [
"config:rw"
],
"options": {},
"environment": {
"ESPHOMEYAML_OTA_HOST_PORT": "6053"
},
"schema": {}
}

View File

@@ -9,15 +9,18 @@ from voluptuous.humanize import humanize_error
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core, yaml_util from esphomeyaml import core, yaml_util
from esphomeyaml.const import CONF_BOARD, CONF_ESPHOMEYAML, CONF_LIBRARY_URI, CONF_NAME, \ from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, ESP_PLATFORMS, \ CONF_LIBRARY_URI, \
CONF_NAME, CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, ESP_PLATFORMS, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, add, color from esphomeyaml.helpers import App, add, color
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.4.0' DEFAULT_LIBRARY_URI = u'https://github.com/OttoWinter/esphomelib.git#v1.6.0'
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
CORE_SCHEMA = vol.Schema({ CORE_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.valid_name, vol.Required(CONF_NAME): cv.valid_name,
@@ -26,6 +29,7 @@ CORE_SCHEMA = vol.Schema({
vol.Optional(CONF_LIBRARY_URI, default=DEFAULT_LIBRARY_URI): cv.string, vol.Optional(CONF_LIBRARY_URI, default=DEFAULT_LIBRARY_URI): cv.string,
vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean, vol.Optional(CONF_SIMPLIFY, default=True): cv.boolean,
vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean, vol.Optional(CONF_USE_BUILD_FLAGS, default=True): cv.boolean,
vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)),
}) })
REQUIRED_COMPONENTS = [ REQUIRED_COMPONENTS = [
@@ -167,6 +171,12 @@ def validate_config(config):
if not success: if not success:
continue continue
esp_platforms = getattr(platform, 'ESP_PLATFORMS', ESP_PLATFORMS)
if core.ESP_PLATFORM not in esp_platforms:
result.add_error(
u"Platform {}.{} doesn't support {}.".format(domain, p_name, core.ESP_PLATFORM))
continue
if hasattr(platform, u'PLATFORM_SCHEMA'): if hasattr(platform, u'PLATFORM_SCHEMA'):
try: try:
p_validated = platform.PLATFORM_SCHEMA(p_config) p_validated = platform.PLATFORM_SCHEMA(p_config)
@@ -211,14 +221,18 @@ def load_config(path):
if CONF_ESPHOMEYAML not in config: if CONF_ESPHOMEYAML not in config:
raise ESPHomeYAMLError(u"No esphomeyaml section in config") raise ESPHomeYAMLError(u"No esphomeyaml section in config")
core_conf = config[CONF_ESPHOMEYAML] core_conf = config[CONF_ESPHOMEYAML]
esp_platform = unicode(core_conf.get(CONF_PLATFORM, u"")) if CONF_PLATFORM not in core_conf:
raise ESPHomeYAMLError("esphomeyaml.platform not specified.")
esp_platform = unicode(core_conf[CONF_PLATFORM])
esp_platform = esp_platform.upper() esp_platform = esp_platform.upper()
if '8266' in esp_platform: if '8266' in esp_platform:
esp_platform = ESP_PLATFORM_ESP8266 esp_platform = ESP_PLATFORM_ESP8266
if '32' in esp_platform: if '32' in esp_platform:
esp_platform = ESP_PLATFORM_ESP32 esp_platform = ESP_PLATFORM_ESP32
core.ESP_PLATFORM = esp_platform core.ESP_PLATFORM = esp_platform
core.BOARD = unicode(core_conf.get(CONF_BOARD, u"")) if CONF_BOARD not in core_conf:
raise ESPHomeYAMLError("esphomeyaml.board not specified.")
core.BOARD = unicode(core_conf[CONF_BOARD])
core.SIMPLIFY = cv.boolean(core_conf.get(CONF_SIMPLIFY, True)) core.SIMPLIFY = cv.boolean(core_conf.get(CONF_SIMPLIFY, True))
try: try:

View File

@@ -12,8 +12,8 @@ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOV
CONF_NAME, CONF_PAYLOAD_AVAILABLE, \ CONF_NAME, CONF_PAYLOAD_AVAILABLE, \
CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \ CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \
ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
from esphomeyaml.core import HexInt, IPAddress, TimePeriod, TimePeriodMilliseconds, \ from esphomeyaml.core import HexInt, IPAddress, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMicroseconds, TimePeriodSeconds TimePeriodMilliseconds, TimePeriodSeconds, Lambda
from esphomeyaml.helpers import ensure_unique_string from esphomeyaml.helpers import ensure_unique_string
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -26,7 +26,7 @@ zero_to_one_float = vol.All(vol.Coerce(float), vol.Range(min=0, max=1))
positive_int = vol.All(vol.Coerce(int), vol.Range(min=0)) positive_int = vol.All(vol.Coerce(int), vol.Range(min=0))
positive_not_null_int = vol.All(vol.Coerce(int), vol.Range(min=0, min_included=False)) positive_not_null_int = vol.All(vol.Coerce(int), vol.Range(min=0, min_included=False))
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
RESERVED_IDS = [ RESERVED_IDS = [
# C++ keywords http://en.cppreference.com/w/cpp/keyword # C++ keywords http://en.cppreference.com/w/cpp/keyword
@@ -134,16 +134,33 @@ def int_(value):
hex_int = vol.Coerce(hex_int_) hex_int = vol.Coerce(hex_int_)
match_cpp_var_ = vol.Match(r'^[a-zA-Z_][a-zA-Z0-9_]+$', msg=u"Must be a valid C++ variable name")
def variable_id(value): def variable_id(value):
value = match_cpp_var_(value) value = string(value)
if not value:
raise vol.Invalid("ID must not be empty")
if value[0].isdigit():
raise vol.Invalid("First character in ID cannot be a digit.")
if '-' in value:
raise vol.Invalid("Dashes are not supported in IDs, please use underscores instead.")
for char in value:
if char != '_' and not char.isalnum():
raise vol.Invalid(u"IDs must only consist of upper/lowercase characters and numbers."
u"The character '{}' cannot be used".format(char))
if value in RESERVED_IDS: if value in RESERVED_IDS:
raise vol.Invalid(u"ID {} is reserved internally and cannot be used".format(value)) raise vol.Invalid(u"ID {} is reserved internally and cannot be used".format(value))
return value return value
def templatable(other_validators):
def validator(value):
if isinstance(value, Lambda):
return value
return other_validators(value)
return validator
def only_on(platforms): def only_on(platforms):
if not isinstance(platforms, list): if not isinstance(platforms, list):
platforms = [platforms] platforms = [platforms]
@@ -170,10 +187,24 @@ def has_at_least_one_key(*keys):
if not isinstance(obj, dict): if not isinstance(obj, dict):
raise vol.Invalid('expected dictionary') raise vol.Invalid('expected dictionary')
for k in obj.keys(): if not any(k in keys for k in obj):
if k in keys: raise vol.Invalid('Must contain at least one of {}.'.format(', '.join(keys)))
return obj return obj
raise vol.Invalid('must contain one of {}.'.format(', '.join(keys)))
return validate
def has_at_exactly_one_key(*keys):
def validate(obj):
if not isinstance(obj, dict):
raise vol.Invalid('expected dictionary')
number = sum(k in keys for k in obj)
if number > 1:
raise vol.Invalid("Cannot specify more than one of {}.".format(', '.join(keys)))
if number < 1:
raise vol.Invalid('Must contain exactly one of {}.'.format(', '.join(keys)))
return obj
return validate return validate
@@ -209,13 +240,6 @@ def time_period_str_colon(value):
elif not isinstance(value, str): elif not isinstance(value, str):
raise vol.Invalid(TIME_PERIOD_ERROR.format(value)) raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
negative_offset = False
if value.startswith('-'):
negative_offset = True
value = value[1:]
elif value.startswith('+'):
value = value[1:]
try: try:
parsed = [int(x) for x in value.split(':')] parsed = [int(x) for x in value.split(':')]
except ValueError: except ValueError:
@@ -229,12 +253,7 @@ def time_period_str_colon(value):
else: else:
raise vol.Invalid(TIME_PERIOD_ERROR.format(value)) raise vol.Invalid(TIME_PERIOD_ERROR.format(value))
offset = TimePeriod(hours=hour, minutes=minute, seconds=second) return TimePeriod(hours=hour, minutes=minute, seconds=second)
if negative_offset:
offset *= -1
return offset
def time_period_str_unit(value): def time_period_str_unit(value):
@@ -277,17 +296,17 @@ def time_period_str_unit(value):
return TimePeriod(**{kwarg: float(match.group(1))}) return TimePeriod(**{kwarg: float(match.group(1))})
def time_period_in_milliseconds(value): def time_period_in_milliseconds_(value):
if value.microseconds is not None and value.microseconds != 0: if value.microseconds is not None and value.microseconds != 0:
raise vol.Invalid("Maximum precision is milliseconds") raise vol.Invalid("Maximum precision is milliseconds")
return TimePeriodMilliseconds(**value.as_dict()) return TimePeriodMilliseconds(**value.as_dict())
def time_period_in_microseconds(value): def time_period_in_microseconds_(value):
return TimePeriodMicroseconds(**value.as_dict()) return TimePeriodMicroseconds(**value.as_dict())
def time_period_in_seconds(value): def time_period_in_seconds_(value):
if value.microseconds is not None and value.microseconds != 0: if value.microseconds is not None and value.microseconds != 0:
raise vol.Invalid("Maximum precision is seconds") raise vol.Invalid("Maximum precision is seconds")
if value.milliseconds is not None and value.milliseconds != 0: if value.milliseconds is not None and value.milliseconds != 0:
@@ -297,9 +316,9 @@ def time_period_in_seconds(value):
time_period = vol.Any(time_period_str_unit, time_period_str_colon, time_period_dict) time_period = vol.Any(time_period_str_unit, time_period_str_colon, time_period_dict)
positive_time_period = vol.All(time_period, vol.Range(min=TimePeriod())) positive_time_period = vol.All(time_period, vol.Range(min=TimePeriod()))
positive_time_period_milliseconds = vol.All(positive_time_period, time_period_in_milliseconds) positive_time_period_milliseconds = vol.All(positive_time_period, time_period_in_milliseconds_)
positive_time_period_seconds = vol.All(positive_time_period, time_period_in_seconds) positive_time_period_seconds = vol.All(positive_time_period, time_period_in_seconds_)
positive_time_period_microseconds = vol.All(positive_time_period, time_period_in_microseconds) positive_time_period_microseconds = vol.All(positive_time_period, time_period_in_microseconds_)
positive_not_null_time_period = vol.All(time_period, positive_not_null_time_period = vol.All(time_period,
vol.Range(min=TimePeriod(), min_included=False)) vol.Range(min=TimePeriod(), min_included=False))
@@ -337,6 +356,18 @@ def hostname(value):
return value return value
def domainname(value):
value = string(value)
if not value.startswith('.'):
raise vol.Invalid("Domainname must start with .")
if value.startswith('..'):
raise vol.Invalid("Domainname must start with single .")
for c in value:
if not (c.isalnum() or c in '._-'):
raise vol.Invalid("Domainname can only have alphanumeric characters and _ or -")
return value
def ssid(value): def ssid(value):
if value is None: if value is None:
raise vol.Invalid("SSID can not be None") raise vol.Invalid("SSID can not be None")
@@ -422,6 +453,14 @@ def mqtt_payload(value):
return string(value) return string(value)
def mqtt_qos(value):
try:
value = int(value)
except (TypeError, ValueError):
raise vol.Invalid(u"MQTT Quality of Service must be integer, got {}".format(value))
return one_of(0, 1, 2)(value)
uint8_t = vol.All(int_, vol.Range(min=0, max=255)) uint8_t = vol.All(int_, vol.Range(min=0, max=255))
uint16_t = vol.All(int_, vol.Range(min=0, max=65535)) uint16_t = vol.All(int_, vol.Range(min=0, max=65535))
uint32_t = vol.All(int_, vol.Range(min=0, max=4294967295)) uint32_t = vol.All(int_, vol.Range(min=0, max=4294967295))
@@ -431,6 +470,12 @@ hex_uint32_t = vol.All(hex_int, vol.Range(min=0, max=4294967295))
i2c_address = hex_uint8_t i2c_address = hex_uint8_t
def percentage(value):
if isinstance(value, (str, unicode)) and value.endswith('%'):
value = float(value[:-1].rstrip()) / 100.0
return zero_to_one_float(value)
def invalid(message): def invalid(message):
def validator(value): def validator(value):
raise vol.Invalid(message) raise vol.Invalid(message)
@@ -441,6 +486,22 @@ def valid(value):
return value return value
def one_of(*values):
options = u', '.join(u"'{}'".format(x) for x in values)
def validator(value):
if value not in values:
raise vol.Invalid(u"Unknown value '{}', must be one of {}".format(value, options))
return value
return validator
def lambda_(value):
if isinstance(value, Lambda):
return value
return Lambda(string_strict(value))
REGISTERED_IDS = set() REGISTERED_IDS = set()

View File

@@ -1,7 +1,7 @@
"""Constants used by esphomeyaml.""" """Constants used by esphomeyaml."""
MAJOR_VERSION = 1 MAJOR_VERSION = 1
MINOR_VERSION = 4 MINOR_VERSION = 6
PATCH_VERSION = '0' PATCH_VERSION = '0'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
@@ -34,6 +34,13 @@ CONF_USERNAME = 'username'
CONF_POWER_SUPPLY = 'power_supply' CONF_POWER_SUPPLY = 'power_supply'
CONF_ID = 'id' CONF_ID = 'id'
CONF_MQTT_ID = 'mqtt_id' CONF_MQTT_ID = 'mqtt_id'
CONF_SENSOR_ID = 'sensor_id'
CONF_TRIGGER_ID = 'trigger_id'
CONF_ACTION_ID = 'action_id'
CONF_CONDITION_ID = 'condition_id'
CONF_MAKE_ID = 'make_id'
CONF_AUTOMATION_ID = 'automation_id'
CONF_DELAY = 'delay'
CONF_PIN = 'pin' CONF_PIN = 'pin'
CONF_NUMBER = 'number' CONF_NUMBER = 'number'
CONF_INVERTED = 'inverted' CONF_INVERTED = 'inverted'
@@ -70,6 +77,15 @@ CONF_TOPIC = 'topic'
CONF_PAYLOAD_AVAILABLE = 'payload_available' CONF_PAYLOAD_AVAILABLE = 'payload_available'
CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available' CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available'
CONF_DEFAULT_TRANSITION_LENGTH = 'default_transition_length' CONF_DEFAULT_TRANSITION_LENGTH = 'default_transition_length'
CONF_TRANSITION_LENGTH = 'transition_length'
CONF_FLASH_LENGTH = 'flash_length'
CONF_BRIGHTNESS = 'brightness'
CONF_EFFECT = 'effect'
CONF_ABOVE = 'above'
CONF_BELOW = 'below'
CONF_ON = 'on'
CONF_IF = 'if'
CONF_THEN = 'then'
CONF_BINARY = 'binary' CONF_BINARY = 'binary'
CONF_WHITE = 'white' CONF_WHITE = 'white'
CONF_RGBW = 'rgbw' CONF_RGBW = 'rgbw'
@@ -109,6 +125,14 @@ CONF_WINDOW_SIZE = 'window_size'
CONF_SEND_EVERY = 'send_every' CONF_SEND_EVERY = 'send_every'
CONF_ALPHA = 'alpha' CONF_ALPHA = 'alpha'
CONF_LAMBDA = 'lambda' CONF_LAMBDA = 'lambda'
CONF_THROTTLE = 'throttle'
CONF_DELTA = 'delta'
CONF_OR = 'or'
CONF_AND = 'and'
CONF_RANGE = 'range'
CONF_UNIQUE = 'unique'
CONF_HEARTBEAT = 'heartbeat'
CONF_DEBOUNCE = 'debounce'
CONF_UPDATE_INTERVAL = 'update_interval' CONF_UPDATE_INTERVAL = 'update_interval'
CONF_PULL_MODE = 'pull_mode' CONF_PULL_MODE = 'pull_mode'
CONF_COUNT_MODE = 'count_mode' CONF_COUNT_MODE = 'count_mode'
@@ -140,6 +164,7 @@ CONF_OSCILLATION_OUTPUT = 'oscillation_output'
CONF_SPEED = 'speed' CONF_SPEED = 'speed'
CONF_OSCILLATION_STATE_TOPIC = 'oscillation_state_topic' CONF_OSCILLATION_STATE_TOPIC = 'oscillation_state_topic'
CONF_OSCILLATION_COMMAND_TOPIC = 'oscillation_command_topic' CONF_OSCILLATION_COMMAND_TOPIC = 'oscillation_command_topic'
CONF_OSCILLATING = 'oscillating'
CONF_SPEED_STATE_TOPIC = 'speed_state_topic' CONF_SPEED_STATE_TOPIC = 'speed_state_topic'
CONF_SPEED_COMMAND_TOPIC = 'speed_command_topic' CONF_SPEED_COMMAND_TOPIC = 'speed_command_topic'
CONF_LOW = 'low' CONF_LOW = 'low'
@@ -185,6 +210,27 @@ CONF_DATA_PIN = 'data_pin'
CONF_CLOCK_PIN = 'clock_pin' CONF_CLOCK_PIN = 'clock_pin'
CONF_RGB_ORDER = 'rgb_order' CONF_RGB_ORDER = 'rgb_order'
CONF_ACCURACY = 'accuracy' CONF_ACCURACY = 'accuracy'
CONF_BOARD_FLASH_MODE = 'board_flash_mode'
CONF_ON_PRESS = 'on_press'
CONF_ON_RELEASE = 'on_release'
CONF_ON_CLICK = 'on_click'
CONF_ON_DOUBLE_CLICK = 'on_double_click'
CONF_MIN_LENGTH = 'min_length'
CONF_MAX_LENGTH = 'max_length'
CONF_ON_VALUE = 'on_value'
CONF_ON_RAW_VALUE = 'on_raw_value'
CONF_ON_VALUE_RANGE = 'on_value_range'
CONF_ON_MESSAGE = 'on_message'
CONF_PIN_CS = 'pin_cs'
CONF_PIN_CLOCK = 'pin_clock'
CONF_PIN_MISO = 'pin_miso'
CONF_TURN_ON_ACTION = 'turn_on_action'
CONF_TURN_OFF_ACTION = 'turn_off_action'
CONF_OPEN_ACTION = 'open_action'
CONF_CLOSE_ACTION = 'close_action'
CONF_STOP_ACTION = 'stop_action'
CONF_DOMAIN = 'domain'
CONF_OPTIMISTIC = 'optimistic'
ESP32_BOARDS = [ ESP32_BOARDS = [
'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1', 'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1',

View File

@@ -171,6 +171,14 @@ class TimePeriodSeconds(TimePeriod):
pass pass
class Lambda(object):
def __init__(self, value):
self.value = value
def __str__(self):
return u'Lambda<{}>'.format(self.value)
CONFIG_PATH = None CONFIG_PATH = None
SIMPLIFY = True SIMPLIFY = True
ESP_PLATFORM = '' ESP_PLATFORM = ''

View File

View File

@@ -0,0 +1,177 @@
from __future__ import print_function
import codecs
import json
import logging
import os
import random
import subprocess
try:
import tornado
import tornado.gen
import tornado.ioloop
import tornado.iostream
import tornado.process
import tornado.web
import tornado.websocket
import tornado.concurrent
except ImportError as err:
pass
from esphomeyaml import const, core, __main__
from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name
from esphomeyaml.helpers import quote
_LOGGER = logging.getLogger(__name__)
CONFIG_DIR = ''
# pylint: disable=abstract-method, arguments-differ
class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler):
def __init__(self, application, request, **kwargs):
super(EsphomeyamlCommandWebSocket, self).__init__(application, request, **kwargs)
self.proc = None
self.closed = False
def on_message(self, message):
if self.proc is not None:
return
command = self.build_command(message)
_LOGGER.debug(u"WebSocket opened for command %s", [quote(x) for x in command])
self.proc = tornado.process.Subprocess(command,
stdout=tornado.process.Subprocess.STREAM,
stderr=subprocess.STDOUT)
self.proc.set_exit_callback(self.proc_on_exit)
tornado.ioloop.IOLoop.current().spawn_callback(self.redirect_stream)
@tornado.gen.coroutine
def redirect_stream(self):
while True:
try:
data = yield self.proc.stdout.read_until_regex('[\n\r]')
except tornado.iostream.StreamClosedError:
break
if data.endswith('\r') and random.randrange(100) < 90:
continue
data = data.replace('\033', '\\033')
self.write_message({'event': 'line', 'data': data})
def proc_on_exit(self, returncode):
if not self.closed:
_LOGGER.debug("Process exited with return code %s", returncode)
self.write_message({'event': 'exit', 'code': returncode})
def on_close(self):
self.closed = True
if self.proc is not None and self.proc.returncode is None:
_LOGGER.debug("Terminating process")
self.proc.proc.terminate()
def build_command(self, message):
raise NotImplementedError
class EsphomeyamlLogsHandler(EsphomeyamlCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = CONFIG_DIR + '/' + js['configuration']
return ["esphomeyaml", config_file, "logs", '--serial-port', js["port"], '--escape']
class EsphomeyamlRunHandler(EsphomeyamlCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphomeyaml", config_file, "run", '--upload-port', js["port"],
'--escape', '--use-esptoolpy']
class EsphomeyamlCompileHandler(EsphomeyamlCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphomeyaml", config_file, "compile"]
class SerialPortRequestHandler(tornado.web.RequestHandler):
def get(self):
ports = get_serial_ports()
data = []
for port, desc in ports:
if port == '/dev/ttyAMA0':
# ignore RPi built-in serial port
continue
data.append({'port': port, 'desc': desc})
data.append({'port': 'OTA', 'desc': 'Over-The-Air Upload/Logs'})
self.write(json.dumps(data))
class WizardRequestHandler(tornado.web.RequestHandler):
def post(self):
from esphomeyaml import wizard
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')
with codecs.open(destination, 'w') as f_handle:
f_handle.write(config)
self.redirect('/')
class DownloadBinaryRequestHandler(tornado.web.RequestHandler):
def get(self):
configuration = self.get_argument('configuration')
config_file = os.path.join(CONFIG_DIR, configuration)
core.CONFIG_PATH = config_file
config = __main__.read_config(core.CONFIG_PATH)
name = get_name(config)
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
self.set_header('Content-Type', 'application/octet-stream')
self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(name))
with open(path, 'rb') as f:
while 1:
data = f.read(16384) # or some other nice-sized chunk
if not data:
break
self.write(data)
self.finish()
class MainRequestHandler(tornado.web.RequestHandler):
def get(self):
files = sorted([f for f in os.listdir(CONFIG_DIR) if f.endswith('.yaml') and
not f.startswith('.')])
full_path_files = [os.path.join(CONFIG_DIR, f) for f in files]
self.render("templates/index.html", files=files, full_path_files=full_path_files,
version=const.__version__)
def make_app():
static_path = os.path.join(os.path.dirname(__file__), 'static')
return tornado.web.Application([
(r"/", MainRequestHandler),
(r"/logs", EsphomeyamlLogsHandler),
(r"/run", EsphomeyamlRunHandler),
(r"/compile", EsphomeyamlCompileHandler),
(r"/download.bin", DownloadBinaryRequestHandler),
(r"/serial-ports", SerialPortRequestHandler),
(r"/wizard.html", WizardRequestHandler),
(r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}),
], debug=False)
def start_web_server(args):
global CONFIG_DIR
CONFIG_DIR = args.configuration
if not os.path.exists(CONFIG_DIR):
os.makedirs(CONFIG_DIR)
_LOGGER.info("Starting dashboard web server on port %s and configuration dir %s...",
args.port, CONFIG_DIR)
app = make_app()
app.listen(args.port)
try:
tornado.ioloop.IOLoop.current().start()
except KeyboardInterrupt:
_LOGGER.info("Shutting down...")

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,738 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>esphomeyaml Dashboard</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<link rel="stylesheet" href="/static/materialize-stepper.min.css">
<!-- jQuery :( -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.5/jquery-ui.min.js" integrity="sha256-fOse6WapxTrUSJOJICXXYwHRJOPa6C1OUQXi7C9Ddy8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js"></script>
<script src="/static/materialize-stepper.min.js"></script>
<style>
nav .brand-logo {
margin-left: 48px;
font-size: 20px;
}
main .container {
margin-top: -12vh;
flex-shrink: 0;
}
.ribbon {
width: 100%;
height: 17vh;
background-color: #3F51B5;
flex-shrink: 0;
}
.ribbon-fab:not(.tap-target-origin) {
position: absolute;
right: 24px;
top: calc(17vh + 34px);
}
i.very-large {
font-size: 8rem;
padding-top: 2px;
color: #424242;
}
.card .card-content {
padding-left: 18px;
padding-bottom: 10px;
}
.chip {
height: 26px;
font-size: 12px;
line-height: 26px;
}
.log {
background-color: #1c1c1c;
margin-top: 0;
margin-bottom: 0;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
padding: 16px;
overflow: auto;
line-height: 1.45;
border-radius: 3px;
white-space: pre-wrap;
overflow-wrap: break-word;
color: #DDD;
}
.inlinecode {
box-sizing: border-box;
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27,31,35,0.05);
border-radius: 3px;
font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;
}
.log.bold {
font-weight: bold;
}
.log .v {
color: #888888;
}
.log .d {
color: #00DDDD;
}
.log .c {
color: magenta;
}
.log .i {
color: limegreen;
}
.log .w {
color: yellow;
}
.log .e {
color: red;
font-weight: bold;
}
.log .e {
color: red;
}
.log .ww {
color: white;
}
.modal {
width: 90%;
max-height: 85%;
height: 80% !important;
}
.page-footer {
padding-top: 0;
}
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
ul.browser-default {
padding-left: 30px;
margin-top: 10px;
margin-bottom: 15px;
}
ul.browser-default li {
list-style-type: initial;
}
ul.stepper:not(.horizontal) .step.active::before, ul.stepper:not(.horizontal) .step.done::before, ul.stepper.horizontal .step.active .step-title::before, ul.stepper.horizontal .step.done .step-title::before {
background-color: #3f51b5 !important;
}
.select-port-container {
margin-top: 19px;
}
</style>
</head>
<body>
<header>
<nav>
<div class="nav-wrapper indigo">
<a href="#" class="brand-logo left">esphomeyaml Dashboard</a>
</div>
</nav>
<div class="ribbon"></div>
</header>
<main>
<div class="container">
{% for file, full_path in zip(files, full_path_files) %}
<div class="row">
<div class="col s8 offset-s2 m10 offset-m1 l12">
<div class="card horizontal">
<div class="card-image center-align">
<i class="material-icons very-large icon-grey">memory</i>
</div>
<div class="card-stacked">
<div class="card-content">
<span class="card-title">{{ escape(file) }}</span>
<p>
Full path: <code class="inlinecode">{{ escape(full_path) }}</code>
</p>
</div>
<div class="card-action">
<a href="#" class="action-upload" data-node="{{ file }}">Upload</a>
<a href="#" class="action-compile" data-node="{{ file }}">Compile</a>
<a href="#" class="action-show-logs" data-node="{{ file }}">Show Logs</a>
</div>
</div>
</div>
</div>
</div>
{% end %}
</div>
<div id="modal-logs" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Show Logs</h4>
<div class="upload-port row">
<div class="col s12">
<h5>Found multiple serial ports, please choose one:</h5>
</div>
<div class="input-field col s8">
<select></select>
</div>
<div class="col s4 select-port-container">
<button class="btn waves-effect waves-light upload-port-submit" type="submit" name="action">Select
<i class="material-icons right">send</i>
</button>
</div>
</div>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat">Close</a>
</div>
</div>
<div id="modal-upload" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Compile And Upload</h4>
<div class="upload-port row">
<div class="col s12">
<h5>Found multiple upload options, please choose one:</h5>
</div>
<div class="input-field col s8">
<select></select>
</div>
<div class="col s4 select-port-container">
<button class="btn waves-effect waves-light upload-port-submit" type="submit" name="action">Select
<i class="material-icons right">send</i>
</button>
</div>
</div>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat">Stop</a>
</div>
</div>
<div id="modal-compile" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Compile</h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat disabled download-binary">Download Binary</a>
<a class="modal-close waves-effect waves-green btn-flat">Stop</a>
</div>
</div>
<div id="modal-wizard" class="modal">
<div class="modal-content">
<form action="/wizard.html" method="POST">
<ul class="stepper linear">
<li class="step active">
<div class="step-title waves-effect">Introduction And Name</div>
<div class="step-content">
<div class="row">
<p>
Hi there! I'm the esphomeyaml setup wizard and will guide you through setting up
your first ESP8266 or ESP32-powered device using esphomeyaml.
</p>
<a href="https://www.espressif.com/en/products/hardware/esp8266ex/overview" target="_blank">ESP8266s</a> and
their successors (the <a href="https://www.espressif.com/en/products/hardware/esp32/overview" target="_blank">ESP32s</a>)
are great low-cost microcontrollers that can communicate with the outside world using WiFi.
They're found in many devices such as the popular Sonoff/iTead, but also exist as development boards
such as the <a href="http://nodemcu.com/index_en.html" target="_blank">NodeMCU</a>.
<p>
</p>
<a href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml</a>,
the tool you're using here, creates custom firmwares for these devices using YAML configuration
files (similar to the ones you might be used to with Home Assistant).
<p>
</p>
This wizard will create a basic YAML configuration file for your "node" (the microcontroller).
Later, you will be able to customize this file and add some of
<a href="https://github.com/OttoWinter/esphomelib" target="_blank">esphomelib's</a>
many integrations.
<p>
<p>
First, I need to know what this node should be called. Choose this name wisely, changing this
later makes Over-The-Air Update attempts difficult.
It may only contain the characters <code class="inlinecode">a-z</code>,
<code class="inlinecode">0-9</code> and <code class="inlinecode">_</code>
</p>
<div class="input-field col s12">
<input id="node_name" class="validate" type="text" name="name" required>
<label for="node_name">Name of node</label>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step"">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">Device Type</div>
<div class="step-content">
<div class="row">
<p>
Great! Now I need to know what type of microcontroller you're using so that I can compile firmware for them.
Please choose either ESP32 or ESP8266 (use ESP8266 for Sonoff devices). Note that the ESP32 is currently
unsupported if HassIO is running on a Raspberry Pi.
</p>
<div class="input-field col s12">
<select id="esp_type" name="platform" required>
<option value="ESP8266">ESP8266</option>
<option value="ESP32">ESP32</option>
</select>
<label>Microcontroller Type</label>
</div>
<p>
I'm also going to need to know which type of board you're using. Please go to
<a href="http://docs.platformio.org/en/latest/platforms/espressif32.html#boards" target="_blank">ESP32 boards</a> or
<a href="http://docs.platformio.org/en/latest/platforms/espressif8266.html#boards" target="_blank">ESP8266 boards</a>,
find your board and enter it here. For example, enter <code class="inlinecode">nodemcuv2</code>
for ESP8266 NodeMCU boards. Note: Use <code class="inlinecode">esp01_1m</code> for Sonoff devices.
</p>
<div class="input-field col s12">
<input id="board_type" class="validate" type="text" name="board" required>
<label for="board_type">Board Type</label>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">WiFi And Over-The-Air Updates</div>
<div class="step-content">
<div class="row">
<p>
Thanks! Now I need to know what WiFi Access Point I should instruct the node to connect to.
Please enter an SSID (name of the WiFi network) and password (leave empty for no password).
</p>
<div class="input-field col s12">
<input id="wifi_ssid" class="validate" type="text" name="ssid" required>
<label for="wifi_ssid">WiFi SSID</label>
</div>
<div class="input-field col s12">
<input id="wifi_password" name="psk" type="password">
<label for="wifi_password">WiFi Password</label>
</div>
<p>
Esphomelib automatically sets up an Over-The-Air update server on the node
so that you only need to flash a firmware once. Optionally, you can set a password for this
upload process here.
</p>
<div class="input-field col s12">
<input id="ota_password" class="validate" name="ota_password" type="password">
<label for="ota_password">OTA Password</label>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">MQTT</div>
<div class="step-content">
<div class="row">
<p>
esphomelib connects to your Home Assistant instance via
<a href="https://www.home-assistant.io/docs/mqtt/">MQTT</a>. If you haven't already, please set up
MQTT on your Home Assistant server, for example with the awesome
<a href="https://www.home-assistant.io/addons/mosquitto/">Mosquitto Hass.io Add-on</a>.
</p>
<p>
When you're done with that, please enter your MQTT broker here. For example
<code class="inlinecode">192.168.1.100</code> (Note
<code class="inlinecode">hassio.local</code> often doesn't work, please use a static IP).
Please also specify the MQTT username and password you wish esphomelib to use
(leave them empty if you're not using any authentication).
</p>
<div class="input-field col s12">
<input id="mqtt_broker" class="validate" type="text" name="broker" required>
<label for="mqtt_broker">MQTT Broker</label>
</div>
<div class="input-field col s6">
<input id="mqtt_username" class="validate" type="text" name="mqtt_username">
<label for="mqtt_username">MQTT Username</label>
</div>
<div class="input-field col s6">
<input id="mqtt_password" class="validate" name="mqtt_password" type="password">
<label for="mqtt_password">MQTT Password</label>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">Done!</div>
<div class="step-content">
<p>
Hooray! 🎉🎉🎉 You've successfully created your first esphomeyaml configuration file.
When you click Submit, I will save this configuration file under
<code class="inlinecode">&lt;HASS_CONFIG_FOLDER&gt;/esphomeyaml/&lt;NAME_OF_NODE&gt;.yaml</code> and
you will be able to edit this file with the
<a href="https://www.home-assistant.io/addons/configurator/" target="_blank">HASS Configuratior add-on</a>.
</p>
<h5>Next steps</h5>
<ul class="browser-default">
<li>
Flash the firmware. This can be done using the “UPLOAD” option in the dashboard. See
<a href="https://esphomelib.com/esphomeyaml/index.html#using-with" target="_blank">this</a>
for guides on how to flash different types of devices. Note that you need to restart this add-on
for newly plugged in serial devices to be detected.
</li>
<li>
See the <a href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml index</a>
for a list of supported sensors/devices.
</li>
<li>
Join the <a href="https://discord.gg/KhAMKrd" target="_blank">Discord server</a> and say hi. When I
have time, I would be happy to help with issues and discuss new features.
</li>
<li>
Star <a href="https://github.com/OttoWinter/esphomelib" target="_blank">esphomelib</a> and
<a href="https://github.com/OttoWinter/esphomeyaml" target="_blank">esphomeyaml</a> on GitHub and
report issues using the bug trackers there.
</li>
</ul>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo" type="submit">SUBMIT</button>
</div>
</div>
</li>
</ul>
</form>
</div>
<div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-green btn-flat">Abort</a>
</div>
</div>
<a class="btn-floating btn-large ribbon-fab waves-effect waves-light pink accent-2" id="setup-wizard-start">
<i class="material-icons">add</i>
</a>
<div class="tap-target pink lighten-1" data-target="setup-wizard-start">
<div class="tap-target-content">
<h5>Set up your first Node</h5>
<p>
Huh... It seems like you you don't have any esphomeyaml configuration files yet...
Fortunately, there's a setup wizard that will step you through setting up your first node 🎉
</p>
</div>
</div>
</main>
<footer class="page-footer indigo darken-1">
<div class="container">
</div>
<div class="footer-copyright">
<div class="container">
© 2018 Copyright Otto Winter, Made with <a class="grey-text text-lighten-4" href="https://materializecss.com/" target="_blank">Materialize</a>
<a class="grey-text text-lighten-4 right" href="https://esphomelib.com/esphomeyaml/index.html" target="_blank">esphomeyaml {{ version }} Documentation</a>
</div>
</div>
</footer>
<script>
document.addEventListener('DOMContentLoaded', () => {
M.AutoInit(document.body);
});
const colorReplace = (input) => {
input = input.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
input = input.replace(/\\033\[(?:0;)?31m/g, '<span class="e">');
input = input.replace(/\\033\[(?:1;)?31m/g, '<span class="e bold">');
input = input.replace(/\\033\[(?:0;)?32m/g, '<span class="i">');
input = input.replace(/\\033\[(?:1;)?32m/g, '<span class="i bold">');
input = input.replace(/\\033\[(?:0;)?33m/g, '<span class="w">');
input = input.replace(/\\033\[(?:1;)?33m/g, '<span class="w bold">');
input = input.replace(/\\033\[(?:0;)?35m/g, '<span class="c">');
input = input.replace(/\\033\[(?:1;)?35m/g, '<span class="c bold">');
input = input.replace(/\\033\[(?:0;)?36m/g, '<span class="d">');
input = input.replace(/\\033\[(?:1;)?36m/g, '<span class="d bold">');
input = input.replace(/\\033\[(?:0;)?37m/g, '<span class="v">');
input = input.replace(/\\033\[(?:1;)?37m/g, '<span class="v bold">');
input = input.replace(/\\033\[(?:0;)?38m/g, '<span class="vv">');
input = input.replace(/\\033\[(?:1;)?38m/g, '<span class="vv bold">');
input = input.replace(/\\033\[0m/g, '</span>');
return input;
};
let configuration = "";
const ws_url = 'ws://' + window.location.hostname + ':' + window.location.port;
const logsModalElem = document.getElementById("modal-logs");
const logsPortSelect = logsModalElem.querySelector('select');
const logsPortDiv = logsModalElem.querySelector(".upload-port");
const logsPortSubmit = logsModalElem.querySelector('.upload-port-submit');
let logsStart = undefined;
logsPortSubmit.addEventListener('click', () => {
const inst = M.FormSelect.getInstance(logsPortSelect);
logsStart(inst.getSelectedValues()[0]);
inst.destroy();
});
document.querySelectorAll(".action-show-logs").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(logsModalElem);
const log = logsModalElem.querySelector(".log");
log.innerHTML = "";
if (M.FormSelect.getInstance(logsPortSelect) !== undefined) {
M.FormSelect.getInstance(logsPortSelect).destroy();
}
modalInstance.open();
if (logsPortDiv.classList.contains('hide')) {
logsPortDiv.classList.remove('hide');
}
logsStart = (port) => {
logsPortDiv.classList.add('hide');
const logSocket = new WebSocket(ws_url + "/logs");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully!"});
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: port});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
M.toast({html: 'Terminated process.'});
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
};
fetch('/serial-ports').then(res => res.json())
.then(response => {
if (response.length > 1) {
logsPortSelect.innerHTML = "";
for (let i = 0; i < response.length; i++) {
const val = response[i];
logsPortSelect.innerHTML += `<option value="${val.port}">${val.port} (${val.desc})</option>`;
}
M.FormSelect.init(logsPortSelect, {});
} else {
logsStart("OTA");
}
});
});
});
const uploadModalElem = document.getElementById("modal-upload");
const uploadPortSelect = uploadModalElem.querySelector('select');
const uploadPortDiv = uploadModalElem.querySelector(".upload-port");
const uploadPortSubmit = uploadModalElem.querySelector('.upload-port-submit');
let uploadStart = undefined;
uploadPortSubmit.addEventListener('click', () => {
const inst = M.FormSelect.getInstance(uploadPortSelect);
uploadStart(inst.getSelectedValues()[0]);
inst.destroy();
});
document.querySelectorAll(".action-upload").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(uploadModalElem);
const log = uploadModalElem.querySelector(".log");
log.innerHTML = "";
if (M.FormSelect.getInstance(uploadPortSelect) !== undefined) {
M.FormSelect.getInstance(uploadPortSelect).destroy();
}
modalInstance.open();
if (uploadPortDiv.classList.contains('hide')) {
uploadPortDiv.classList.remove('hide');
}
uploadStart = (port) => {
uploadPortDiv.classList.add('hide');
const logSocket = new WebSocket(ws_url + "/run");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully!"});
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: port});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
M.toast({html: 'Terminated process.'});
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
};
fetch('/serial-ports').then(res => res.json())
.then(response => {
if (response.length > 1) {
uploadPortSelect.innerHTML = "";
for (let i = 0; i < response.length; i++) {
const val = response[i];
uploadPortSelect.innerHTML += `<option value="${val.port}">${val.port} (${val.desc})</option>`;
}
M.FormSelect.init(uploadPortSelect, {});
} else {
uploadStart("OTA");
}
});
});
});
const compileModalElem = document.getElementById("modal-compile");
const downloadButton = compileModalElem.querySelector('.download-binary');
document.querySelectorAll(".action-compile").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(compileModalElem);
const log = compileModalElem.querySelector(".log");
log.innerHTML = "";
downloadButton.classList.add('disabled');
modalInstance.open();
const logSocket = new WebSocket(ws_url + "/compile");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully!"});
downloadButton.classList.remove('disabled');
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
M.toast({html: 'Terminated process.'});
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
downloadButton.addEventListener('click', () => {
const link = document.createElement("a");
link.download = name;
link.href = '/download.bin?configuration=' + encodeURIComponent(configuration);
link.click();
});
const modalSetupElem = document.getElementById("modal-wizard");
const setupWizardStart = document.getElementById('setup-wizard-start');
const startWizard = () => {
const modalInstance = M.Modal.getInstance(modalSetupElem);
modalInstance.open();
modalInstance.options.onCloseStart = () => {
};
$('.stepper').activateStepper({
linearStepsNavigation: false,
autoFocusInput: true,
autoFormCreation: true,
showFeedbackLoader: true,
parallel: false
});
};
setupWizardStart.addEventListener('click', startWizard);
</script>
{% if len(files) == 0 %}
<script>
document.addEventListener('DOMContentLoaded', () => {
const tapTargetElem = document.querySelector('.tap-target');
const tapTargetInstance = M.TapTarget.getInstance(tapTargetElem);
tapTargetInstance.options.onOpen = () => {
$('.tap-target-origin').on('click', () => {
startWizard();
});
};
tapTargetInstance.open();
});
</script>
{% end %}
</body>
</html>

View File

@@ -7,10 +7,10 @@ from collections import OrderedDict, deque
from esphomeyaml import core from esphomeyaml import core
from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, \ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, \
CONF_INVERTED, \ CONF_INVERTED, \
CONF_MODE, CONF_NUMBER, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_RETAIN, \ CONF_MODE, CONF_NUMBER, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_PCF8574, \
CONF_STATE_TOPIC, CONF_TOPIC, CONF_PCF8574 CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC
from esphomeyaml.core import ESPHomeYAMLError, HexInt, TimePeriodMicroseconds, \ from esphomeyaml.core import ESPHomeYAMLError, HexInt, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds TimePeriodMilliseconds, TimePeriodSeconds, Lambda
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -58,6 +58,9 @@ class Expression(object):
continue continue
require.require() require.require()
def has_side_effects(self):
return self.required
class RawExpression(Expression): class RawExpression(Expression):
def __init__(self, text): def __init__(self, text):
@@ -65,7 +68,7 @@ class RawExpression(Expression):
self.text = text self.text = text
def __str__(self): def __str__(self):
return self.text return str(self.text)
# pylint: disable=redefined-builtin # pylint: disable=redefined-builtin
@@ -85,6 +88,9 @@ class AssignmentExpression(Expression):
type_ = u'auto' type_ = u'auto'
return u"{} {}{} = {}".format(type_, self.modifier, self.name, self.rhs) return u"{} {}{} = {}".format(type_, self.modifier, self.name, self.rhs)
def has_side_effects(self):
return self.rhs.has_side_effects()
class ExpressionList(Expression): class ExpressionList(Expression):
def __init__(self, *args): def __init__(self, *args):
@@ -100,7 +106,7 @@ class ExpressionList(Expression):
self.args.append(exp) self.args.append(exp)
def __str__(self): def __str__(self):
text = u", ".join(unicode(x) for x in self.args) text = u", ".join(str(x) for x in self.args)
return indent_all_but_first_and_last(text) return indent_all_but_first_and_last(text)
@@ -137,6 +143,8 @@ class StructInitializer(Expression):
def __init__(self, base, *args): def __init__(self, base, *args):
super(StructInitializer, self).__init__() super(StructInitializer, self).__init__()
self.base = base self.base = base
if isinstance(base, Expression):
self.requires.append(base)
if not isinstance(args, OrderedDict): if not isinstance(args, OrderedDict):
args = OrderedDict(args) args = OrderedDict(args)
self.args = OrderedDict() self.args = OrderedDict()
@@ -180,18 +188,82 @@ class ArrayInitializer(Expression):
return cpp return cpp
# pylint: disable=invalid-name
class ParameterExpression(Expression):
def __init__(self, type, id):
super(ParameterExpression, self).__init__()
self.type = type
self.id = id
def __str__(self):
return u"{} {}".format(self.type, self.id)
class ParameterListExpression(Expression):
def __init__(self, *parameters):
super(ParameterListExpression, self).__init__()
self.parameters = []
for parameter in parameters:
if not isinstance(parameter, ParameterExpression):
parameter = ParameterExpression(*parameter)
self.parameters.append(parameter)
self.requires.append(parameter)
def __str__(self):
return u", ".join(unicode(x) for x in self.parameters)
class LambdaExpression(Expression):
def __init__(self, parts, parameters, capture='=', return_type=None):
super(LambdaExpression, self).__init__()
self.parts = parts
if not isinstance(parameters, ParameterListExpression):
parameters = ParameterListExpression(*parameters)
self.parameters = parameters
self.requires.append(self.parameters)
self.capture = capture
self.return_type = return_type
if return_type is not None:
self.requires.append(return_type)
for i in range(1, len(parts), 2):
self.requires.append(parts[i])
def __str__(self):
cpp = u'[{}]({})'.format(self.capture, self.parameters)
if self.return_type is not None:
cpp += u' -> {}'.format(self.return_type)
cpp += u' {\n'
for part in self.parts:
cpp += unicode(part)
cpp += u'\n}'
return indent_all_but_first_and_last(cpp)
class Literal(Expression): class Literal(Expression):
def __str__(self): def __str__(self):
raise NotImplementedError raise NotImplementedError
# From https://stackoverflow.com/a/14945195/8924614
def cpp_string_escape(string, encoding='utf-8'):
if isinstance(string, unicode):
string = string.encode(encoding)
result = ''
for character in string:
if not (32 <= ord(character) < 127) or character in ('\\', '"'):
result += '\\%03o' % ord(character)
else:
result += character
return '"' + result + '"'
class StringLiteral(Literal): class StringLiteral(Literal):
def __init__(self, string): def __init__(self, string):
super(StringLiteral, self).__init__() super(StringLiteral, self).__init__()
self.string = string self.string = string
def __str__(self): def __str__(self):
return u'"{}"'.format(self.string) return u'{}'.format(cpp_string_escape(self.string))
class IntLiteral(Literal): class IntLiteral(Literal):
@@ -222,9 +294,9 @@ class HexIntLiteral(Literal):
class FloatLiteral(Literal): class FloatLiteral(Literal):
def __init__(self, float_): def __init__(self, value):
super(FloatLiteral, self).__init__() super(FloatLiteral, self).__init__()
self.float_ = float_ self.float_ = value
def __str__(self): def __str__(self):
return u"{:f}f".format(self.float_) return u"{:f}f".format(self.float_)
@@ -284,23 +356,30 @@ def statement(expression):
return ExpressionStatement(expression) return ExpressionStatement(expression)
def register_variable(type, id, obj):
_VARIABLES[id] = obj, type
# pylint: disable=redefined-builtin, invalid-name # pylint: disable=redefined-builtin, invalid-name
def variable(type, id, rhs): def variable(type, id, rhs):
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
obj = MockObj(id, u'.') obj = MockObj(id, u'.')
assignment = AssignmentExpression(type, '', id, rhs, obj) assignment = AssignmentExpression(type, '', id, rhs, obj)
add(assignment) add(assignment)
_VARIABLES[id] = obj, type register_variable(type, id, obj)
obj.requires.append(assignment) obj.requires.append(assignment)
return obj return obj
def Pvariable(type, id, rhs): def Pvariable(type, id, rhs, has_side_effects=True):
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
obj = MockObj(id, u'->') if not has_side_effects and hasattr(rhs, '_has_side_effects'):
# pylint: disable=attribute-defined-outside-init, protected-access
rhs._has_side_effects = False
obj = MockObj(id, u'->', has_side_effects=has_side_effects)
assignment = AssignmentExpression(type, '*', id, rhs, obj) assignment = AssignmentExpression(type, '*', id, rhs, obj)
add(assignment) add(assignment)
_VARIABLES[id] = obj, type register_variable(type, id, obj)
obj.requires.append(assignment) obj.requires.append(assignment)
return obj return obj
@@ -311,32 +390,45 @@ _EXPRESSIONS = []
def get_variable(id, type=None): def get_variable(id, type=None):
result = None def get_result():
while _QUEUE:
if id is not None: if id is not None:
if id in _VARIABLES: if id in _VARIABLES:
result = _VARIABLES[id][0] return _VARIABLES[id][0]
break
elif type is not None: elif type is not None:
result = next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None) return next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None)
if result is not None: return None
break
while _QUEUE:
result = get_result()
if result is not None:
return result
func, config = _QUEUE.popleft() func, config = _QUEUE.popleft()
func(config) func(config)
if id is None and type is None: if id is None and type is None:
return None return None
result = get_result()
if result is None: if result is None:
if id is not None: if type is None:
if id in _VARIABLES: raise ESPHomeYAMLError(u"Couldn't find ID '{}'".format(id))
result = _VARIABLES[id][0] raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type '{}'".format(id, type))
elif type is not None:
result = next((x[0] for x in _VARIABLES.itervalues() if x[1] == type), None)
if result is None:
raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type {}".format(id, type))
return result return result
def process_lambda(value, parameters, capture='=', return_type=None):
if value is None:
return None
parts = re.split(r'id\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)\.', value.value)
for i in range(1, len(parts), 2):
parts[i] = get_variable(parts[i])._
return LambdaExpression(parts, parameters, capture, return_type)
def templatable(value, input_type, output_type):
if isinstance(value, Lambda):
return process_lambda(value, [(input_type, 'x')], return_type=output_type)
return value
def add_task(func, config): def add_task(func, config):
_QUEUE.append((func, config)) _QUEUE.append((func, config))
@@ -349,18 +441,28 @@ def add(expression, require=True):
class MockObj(Expression): class MockObj(Expression):
def __init__(self, base, op=u'.'): def __init__(self, base, op=u'.', has_side_effects=True):
self.base = base self.base = base
self.op = op self.op = op
self._has_side_effects = has_side_effects
super(MockObj, self).__init__() super(MockObj, self).__init__()
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == u'_':
obj = MockObj(u'{}{}'.format(self.base, self.op))
obj.requires.append(self)
return obj
if attr == u'new':
obj = MockObj(u'new {}'.format(self.base), u'->')
obj.requires.append(self)
return obj
next_op = u'.' next_op = u'.'
if attr.startswith(u'P'): if attr.startswith(u'P') and self.op != '::':
attr = attr[1:] attr = attr[1:]
next_op = u'->' next_op = u'->'
op = self.op if attr.startswith(u'_'):
obj = MockObj(u'{}{}{}'.format(self.base, op, attr), next_op) attr = attr[1:]
obj = MockObj(u'{}{}{}'.format(self.base, self.op, attr), next_op)
obj.requires.append(self) obj.requires.append(self)
return obj return obj
@@ -381,12 +483,41 @@ class MockObj(Expression):
continue continue
require.require() require.require()
def template(self, args):
if not isinstance(args, TemplateArguments):
args = TemplateArguments(args)
obj = MockObj(u'{}{}'.format(self.base, args))
obj.requires.append(self)
obj.requires.append(args)
return obj
App = MockObj(u'App') def namespace(self, name):
obj = MockObj(u'{}{}{}'.format(self.base, self.op, name), u'::')
obj.requires.append(self)
return obj
GPIOPin = MockObj(u'GPIOPin') def has_side_effects(self):
GPIOOutputPin = MockObj(u'GPIOOutputPin') return self._has_side_effects
GPIOInputPin = MockObj(u'GPIOInputPin')
global_ns = MockObj('', '')
float_ = global_ns.namespace('float')
bool_ = global_ns.namespace('bool')
std_ns = global_ns.namespace('std')
std_string = std_ns.string
uint8 = global_ns.namespace('uint8_t')
uint16 = global_ns.namespace('uint16_t')
uint32 = global_ns.namespace('uint32_t')
NAN = global_ns.namespace('NAN')
esphomelib_ns = global_ns # using namespace esphomelib;
NoArg = esphomelib_ns.NoArg
App = esphomelib_ns.App
Application = esphomelib_ns.namespace('Application')
optional = esphomelib_ns.optional
GPIOPin = esphomelib_ns.GPIOPin
GPIOOutputPin = esphomelib_ns.GPIOOutputPin
GPIOInputPin = esphomelib_ns.GPIOInputPin
def get_gpio_pin_number(conf): def get_gpio_pin_number(conf):
@@ -395,37 +526,34 @@ def get_gpio_pin_number(conf):
return conf[CONF_NUMBER] return conf[CONF_NUMBER]
def exp_gpio_pin_(obj, conf, default_mode): def generic_gpio_pin_expression_(conf, mock_obj, default_mode):
if isinstance(conf, int): if conf is None:
return conf return None
number = conf[CONF_NUMBER]
inverted = conf.get(CONF_INVERTED)
if CONF_PCF8574 in conf: if CONF_PCF8574 in conf:
hub = get_variable(conf[CONF_PCF8574], 'io::PCF8574Component') hub = get_variable(conf[CONF_PCF8574], 'io::PCF8574Component')
if default_mode == u'INPUT': if default_mode == u'INPUT':
return hub.make_input_pin(conf[CONF_NUMBER], mode = conf.get(CONF_MODE, u'INPUT')
RawExpression('PCF8574_' + conf[CONF_MODE]), return hub.make_input_pin(number,
conf[CONF_INVERTED]) RawExpression('PCF8574_' + mode),
inverted)
elif default_mode == u'OUTPUT': elif default_mode == u'OUTPUT':
return hub.make_output_pin(conf[CONF_NUMBER], conf[CONF_INVERTED]) return hub.make_output_pin(number, inverted)
else: else:
raise ESPHomeYAMLError(u"Unknown default mode {}".format(default_mode)) raise ESPHomeYAMLError(u"Unknown default mode {}".format(default_mode))
if len(conf) == 1:
if conf.get(CONF_INVERTED) is None: return IntLiteral(number)
return obj(conf[CONF_NUMBER], conf.get(CONF_MODE)) mode = RawExpression(conf.get(CONF_MODE, default_mode))
return obj(conf[CONF_NUMBER], RawExpression(conf.get(CONF_MODE, default_mode)), return mock_obj(number, mode, inverted)
conf[CONF_INVERTED])
def exp_gpio_pin(conf): def gpio_output_pin_expression(conf):
return GPIOPin(conf[CONF_NUMBER], conf[CONF_MODE], conf.get(CONF_INVERTED)) return generic_gpio_pin_expression_(conf, GPIOOutputPin, 'OUTPUT')
def exp_gpio_output_pin(conf): def gpio_input_pin_expression(conf):
return exp_gpio_pin_(GPIOOutputPin, conf, u'OUTPUT') return generic_gpio_pin_expression_(conf, GPIOInputPin, 'INPUT')
def exp_gpio_input_pin(conf):
return exp_gpio_pin_(GPIOInputPin, conf, u'INPUT')
def setup_mqtt_component(obj, config): def setup_mqtt_component(obj, config):
@@ -443,16 +571,6 @@ def setup_mqtt_component(obj, config):
availability[CONF_PAYLOAD_NOT_AVAILABLE])) availability[CONF_PAYLOAD_NOT_AVAILABLE]))
def exp_empty_optional(type):
return RawExpression(u'Optional<{}>()'.format(type))
def exp_optional(type, value):
if value is None:
return exp_empty_optional(type)
return value
# shlex's quote for Python 2.7 # shlex's quote for Python 2.7
_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search _find_unsafe = re.compile(r'[^\w@%+=:,./-]').search

View File

@@ -39,7 +39,7 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
return 0 return 0
def show_logs(config, topic=None, username=None, password=None, client_id=None): def show_logs(config, topic=None, username=None, password=None, client_id=None, escape=False):
if topic is not None: if topic is not None:
pass # already have topic pass # already have topic
elif CONF_MQTT in config: elif CONF_MQTT in config:
@@ -57,7 +57,10 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None):
def on_message(client, userdata, msg): def on_message(client, userdata, msg):
time = datetime.now().time().strftime(u'[%H:%M:%S]') time = datetime.now().time().strftime(u'[%H:%M:%S]')
print(time + msg.payload) message = msg.payload.decode('utf-8')
if escape:
message = message.replace('\033', '\\033')
print(time + message)
return initialize(config, [topic], on_message, username, password, client_id) return initialize(config, [topic], on_message, username, password, client_id)

View File

@@ -64,7 +64,8 @@ ESP32_BOARD_TO_PINS = {
def _translate_pin(value): def _translate_pin(value):
if isinstance(value, dict) or value is None: if isinstance(value, dict) or value is None:
raise vol.Invalid(u"This option doesn't allow more complicated options like inverted.") raise vol.Invalid(u"This variable only supports pin numbers, not full pin schemas "
u"(with inverted and mode).")
if isinstance(value, int): if isinstance(value, int):
return value return value
try: try:
@@ -171,41 +172,50 @@ PIN_MODES_ESP32 = [
def pin_mode(value): def pin_mode(value):
value = vol.All(vol.Coerce(str), vol.Upper)(value) value = vol.All(vol.Coerce(str), vol.Upper)(value)
if core.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
return vol.Any(*PIN_MODES_ESP32)(value) return cv.one_of(*PIN_MODES_ESP32)(value)
elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
return vol.Any(*PIN_MODES_ESP8266)(value) return cv.one_of(*PIN_MODES_ESP8266)(value)
raise vol.Invalid(u"Invalid ESP platform.") raise vol.Invalid(u"Invalid ESP platform.")
GPIO_FULL_OUTPUT_PIN_SCHEMA = vol.Schema({
vol.Required(CONF_NUMBER): output_pin,
vol.Optional(CONF_MODE): pin_mode,
vol.Optional(CONF_INVERTED): cv.boolean,
})
GPIO_FULL_INPUT_PIN_SCHEMA = vol.Schema({
vol.Required(CONF_NUMBER): output_pin,
vol.Optional(CONF_MODE): pin_mode,
vol.Optional(CONF_INVERTED): cv.boolean,
})
def shorthand_output_pin(value):
value = output_pin(value)
return {CONF_NUMBER: value}
def shorthand_input_pin(value):
value = input_pin(value)
return {CONF_NUMBER: value}
PCF8574_OUTPUT_PIN_SCHEMA = vol.Schema({ PCF8574_OUTPUT_PIN_SCHEMA = vol.Schema({
vol.Required(CONF_PCF8574): cv.variable_id, vol.Required(CONF_PCF8574): cv.variable_id,
vol.Required(CONF_NUMBER): vol.Coerce(int), vol.Required(CONF_NUMBER): vol.Coerce(int),
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_MODE): vol.All(vol.Upper, "OUTPUT"),
vol.Optional(CONF_INVERTED, default=False): cv.boolean,
}) })
PCF8574_INPUT_PIN_SCHEMA = PCF8574_OUTPUT_PIN_SCHEMA.extend({ PCF8574_INPUT_PIN_SCHEMA = PCF8574_OUTPUT_PIN_SCHEMA.extend({
vol.Optional(CONF_MODE, default='INPUT'): vol.All(vol.Upper, vol.Any("INPUT", "INPUT_PULLUP")), vol.Optional(CONF_MODE): vol.All(vol.Upper, vol.Any("INPUT", "INPUT_PULLUP")),
}) })
GPIO_OUTPUT_PIN_SCHEMA = vol.Any(output_pin, PCF8574_OUTPUT_PIN_SCHEMA, vol.Schema({ GPIO_INTERNAL_OUTPUT_PIN_SCHEMA = vol.Any(shorthand_output_pin, GPIO_FULL_OUTPUT_PIN_SCHEMA)
vol.Required(CONF_NUMBER): output_pin,
vol.Optional(CONF_MODE): pin_mode,
vol.Optional(CONF_INVERTED): cv.boolean,
}))
GPIO_INPUT_PIN_SCHEMA = vol.Any(input_pin, PCF8574_INPUT_PIN_SCHEMA, vol.Schema({ GPIO_OUTPUT_PIN_SCHEMA = vol.Any(PCF8574_OUTPUT_PIN_SCHEMA, GPIO_INTERNAL_OUTPUT_PIN_SCHEMA)
vol.Required(CONF_NUMBER): input_pin,
vol.Optional(CONF_MODE): pin_mode,
vol.Optional(CONF_INVERTED): cv.boolean,
}))
GPIO_INTERNAL_INPUT_PIN_SCHEMA = vol.Any(shorthand_input_pin, GPIO_FULL_INPUT_PIN_SCHEMA)
def schema_validate_number(validator): GPIO_INPUT_PIN_SCHEMA = vol.Any(PCF8574_INPUT_PIN_SCHEMA, GPIO_INTERNAL_INPUT_PIN_SCHEMA)
def valid(value):
if isinstance(value, dict):
value[CONF_NUMBER] = validator(value[CONF_NUMBER])
else:
value = validator(value)
return value
return valid

View File

@@ -8,7 +8,8 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.components import mqtt from esphomeyaml.components import mqtt
from esphomeyaml.const import ESP_BOARDS_FOR_PLATFORM, ESP_PLATFORMS, ESP_PLATFORM_ESP32 from esphomeyaml.const import ESP_BOARDS_FOR_PLATFORM, ESP_PLATFORMS, ESP_PLATFORM_ESP32, \
ESP_PLATFORM_ESP8266
from esphomeyaml.helpers import color from esphomeyaml.helpers import color
@@ -69,6 +70,18 @@ logger:
""" """
def wizard_file(**kwargs):
config = BASE_CONFIG.format(**kwargs)
if kwargs['ota_password']:
config += "ota:\n password: '{}'\n".format(kwargs['ota_password'])
else:
config += "ota:\n"
return config
if os.getenv('ESPHOMEYAML_QUICKWIZARD', False): if os.getenv('ESPHOMEYAML_QUICKWIZARD', False):
def sleep(time): def sleep(time):
pass pass
@@ -141,10 +154,10 @@ def wizard(path):
print("Great! Your node is now called \"{}\".".format(color('cyan', name))) print("Great! Your node is now called \"{}\".".format(color('cyan', name)))
sleep(1) sleep(1)
print_step(2, ESP_BIG) print_step(2, ESP_BIG)
print("Now I'd like to know which *board* you're using so that I can compile " print("Now I'd like to know what microcontroller you're using so that I can compile "
"firmwares for it.") "firmwares for it.")
print("Are you using an " + color('green', 'ESP32') + " or " + print("Are you using an " + color('green', 'ESP32') + " or " +
color('green', 'ESP8266') + " based board?") color('green', 'ESP8266') + " platform? (Choose ESP8266 for Sonoff devices)")
while True: while True:
sleep(0.5) sleep(0.5)
print() print()
@@ -168,6 +181,8 @@ def wizard(path):
print("Next, I need to know what " + color('green', 'board') + " you're using.") print("Next, I need to know what " + color('green', 'board') + " you're using.")
sleep(0.5) sleep(0.5)
print("Please go to {} and choose a board.".format(color('green', board_link))) print("Please go to {} and choose a board.".format(color('green', board_link)))
if platform == ESP_PLATFORM_ESP8266:
print("(Type " + color('green', 'esp01_1m') + " for Sonoff devices)")
print() print()
# Don't sleep because user needs to copy link # Don't sleep because user needs to copy link
if platform == ESP_PLATFORM_ESP32: if platform == ESP_PLATFORM_ESP32:
@@ -217,7 +232,7 @@ def wizard(path):
sleep(0.75) sleep(0.75)
print("Now please state the " + color('green', 'password') + print("Now please state the " + color('green', 'password') +
" of the WiFi network so that I can connect to it.") " of the WiFi network so that I can connect to it (Leave empty for no password)")
print() print()
print("For example \"{}\"".format(color('bold_white', 'PASSWORD42'))) print("For example \"{}\"".format(color('bold_white', 'PASSWORD42')))
sleep(0.5) sleep(0.5)
@@ -269,14 +284,10 @@ def wizard(path):
print("Press ENTER for no password") print("Press ENTER for no password")
ota_password = raw_input(color('bold_white', '(password): ')) ota_password = raw_input(color('bold_white', '(password): '))
config = BASE_CONFIG.format(name=name, platform=platform, board=board, config = wizard_file(name=name, platform=platform, board=board,
ssid=ssid, psk=psk, broker=broker, ssid=ssid, psk=psk, broker=broker,
mqtt_username=mqtt_username, mqtt_password=mqtt_password) mqtt_username=mqtt_username, mqtt_password=mqtt_password,
ota_password=ota_password)
if ota_password:
config += "ota:\n password: '{}'\n".format(ota_password)
else:
config += "ota:\n"
with codecs.open(path, 'w') as f_handle: with codecs.open(path, 'w') as f_handle:
f_handle.write(config) f_handle.write(config)

View File

@@ -6,8 +6,9 @@ import os
from esphomeyaml import core from esphomeyaml import core
from esphomeyaml.config import iter_components from esphomeyaml.config import iter_components
from esphomeyaml.const import CONF_BOARD, CONF_ESPHOMEYAML, CONF_LIBRARY_URI, CONF_NAME, \ from esphomeyaml.const import CONF_BOARD, CONF_BOARD_FLASH_MODE, CONF_ESPHOMEYAML, \
CONF_PLATFORM, CONF_USE_BUILD_FLAGS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 CONF_LIBRARY_URI, \
CONF_NAME, CONF_PLATFORM, CONF_USE_BUILD_FLAGS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
CPP_AUTO_GENERATE_BEGIN = u'// ========== AUTO GENERATED CODE BEGIN ===========' CPP_AUTO_GENERATE_BEGIN = u'// ========== AUTO GENERATED CODE BEGIN ==========='
@@ -29,7 +30,7 @@ void setup() {
void loop() { void loop() {
App.loop(); App.loop();
delay(1); delay(16);
} }
""") """)
@@ -116,7 +117,11 @@ def get_ini_content(config):
if lib_deps: if lib_deps:
options[u'lib_deps'] = u'\n '.join(lib_deps) options[u'lib_deps'] = u'\n '.join(lib_deps)
return INI_CONTENT_FORMAT.format(**options) content = INI_CONTENT_FORMAT.format(**options)
if CONF_BOARD_FLASH_MODE in config[CONF_ESPHOMEYAML]:
flash_mode = config[CONF_ESPHOMEYAML][CONF_BOARD_FLASH_MODE]
content += "board_flash_mode = {}\n".format(flash_mode)
return content
def mkdir_p(path): def mkdir_p(path):
@@ -162,7 +167,7 @@ def write_platformio_ini(content, path):
mkdir_p(os.path.dirname(path)) mkdir_p(os.path.dirname(path))
content_format = INI_BASE_FORMAT content_format = INI_BASE_FORMAT
full_file = content_format[0] + INI_AUTO_GENERATE_BEGIN + '\n' + \ full_file = content_format[0] + INI_AUTO_GENERATE_BEGIN + '\n' + \
content + INI_AUTO_GENERATE_END + content_format[1] content + INI_AUTO_GENERATE_END + content_format[1]
if prev_file == full_file: if prev_file == full_file:
return return
with codecs.open(path, mode='w+', encoding='utf-8') as f_handle: with codecs.open(path, mode='w+', encoding='utf-8') as f_handle:
@@ -184,7 +189,7 @@ def write_cpp(code_s, path):
code_format = CPP_BASE_FORMAT code_format = CPP_BASE_FORMAT
full_file = code_format[0] + CPP_AUTO_GENERATE_BEGIN + '\n' + \ full_file = code_format[0] + CPP_AUTO_GENERATE_BEGIN + '\n' + \
code_s + CPP_AUTO_GENERATE_END + code_format[1] code_s + CPP_AUTO_GENERATE_END + code_format[1]
if prev_file == full_file: if prev_file == full_file:
return return
with codecs.open(path, 'w+', encoding='utf-8') as f_handle: with codecs.open(path, 'w+', encoding='utf-8') as f_handle:

View File

@@ -8,8 +8,7 @@ from collections import OrderedDict
import yaml import yaml
from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, MACAddress, TimePeriod, \ from esphomeyaml.core import ESPHomeYAMLError, HexInt, IPAddress, Lambda, MACAddress, TimePeriod
TimePeriodMicroseconds, TimePeriodMilliseconds, TimePeriodSeconds
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -195,6 +194,10 @@ def _secret_yaml(loader, node):
return secrets[node.value] return secrets[node.value]
def _lambda(loader, node):
return Lambda(unicode(node.value))
yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _ordered_dict) yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _ordered_dict)
yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_SEQUENCE_TAG, _construct_seq) yaml.SafeLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_SEQUENCE_TAG, _construct_seq)
yaml.SafeLoader.add_constructor('!env_var', _env_var_yaml) yaml.SafeLoader.add_constructor('!env_var', _env_var_yaml)
@@ -206,6 +209,7 @@ yaml.SafeLoader.add_constructor('!include_dir_merge_list',
yaml.SafeLoader.add_constructor('!include_dir_named', _include_dir_named_yaml) yaml.SafeLoader.add_constructor('!include_dir_named', _include_dir_named_yaml)
yaml.SafeLoader.add_constructor('!include_dir_merge_named', yaml.SafeLoader.add_constructor('!include_dir_merge_named',
_include_dir_merge_named_yaml) _include_dir_merge_named_yaml)
yaml.SafeLoader.add_constructor('!lambda', _lambda)
# From: https://gist.github.com/miracle2k/3184458 # From: https://gist.github.com/miracle2k/3184458
@@ -270,6 +274,11 @@ def represent_time_period(dumper, data):
return represent_odict(dumper, 'tag:yaml.org,2002:map', dictionary) return represent_odict(dumper, 'tag:yaml.org,2002:map', dictionary)
def represent_lambda(_, data):
node = yaml.ScalarNode(tag='!lambda', value=data.value, style='>')
return node
yaml.SafeDumper.add_representer( yaml.SafeDumper.add_representer(
OrderedDict, OrderedDict,
lambda dumper, value: lambda dumper, value:
@@ -286,7 +295,5 @@ yaml.SafeDumper.add_representer(unicode, unicode_representer)
yaml.SafeDumper.add_representer(HexInt, hex_int_representer) yaml.SafeDumper.add_representer(HexInt, hex_int_representer)
yaml.SafeDumper.add_representer(IPAddress, stringify_representer) yaml.SafeDumper.add_representer(IPAddress, stringify_representer)
yaml.SafeDumper.add_representer(MACAddress, stringify_representer) yaml.SafeDumper.add_representer(MACAddress, stringify_representer)
yaml.SafeDumper.add_representer(TimePeriod, represent_time_period) yaml.SafeDumper.add_multi_representer(TimePeriod, represent_time_period)
yaml.SafeDumper.add_representer(TimePeriodMicroseconds, represent_time_period) yaml.SafeDumper.add_multi_representer(Lambda, represent_lambda)
yaml.SafeDumper.add_representer(TimePeriodMilliseconds, represent_time_period)
yaml.SafeDumper.add_representer(TimePeriodSeconds, represent_time_period)

View File

@@ -14,6 +14,8 @@ disable=
too-many-arguments, too-many-arguments,
too-many-return-statements, too-many-return-statements,
duplicate-code, duplicate-code,
invalid-name,
cyclic-import,
additional-builtins= additional-builtins=

5
repository.json Normal file
View File

@@ -0,0 +1,5 @@
{
"name": "esphomeyaml HassIO Add-On Repository",
"url": "https://github.com/OttoWinter/esphomeyaml",
"maintainer": "Otto Winter <contact@otto-winter.com>"
}