Web server (#7)

* Web Server

* Preparations for 1.3

* Fixes

* Fix Lint
This commit is contained in:
Otto Winter 2018-04-18 18:43:13 +02:00 committed by GitHub
parent ac5ab33975
commit 3540b3fbb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 754 additions and 313 deletions

View file

@ -6,19 +6,16 @@ import os
import random import random
import sys import sys
from esphomeyaml import helpers, mqtt, writer, yaml_util, wizard from esphomeyaml import core, mqtt, wizard, writer, yaml_util, const
from esphomeyaml.config import add_component_task, read_config from esphomeyaml.config import core_to_code, get_component, iter_components, read_config
from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_HOSTNAME, CONF_MANUAL_IP, CONF_NAME, \ from esphomeyaml.const import CONF_BAUD_RATE, CONF_ESPHOMEYAML, CONF_HOSTNAME, CONF_LOGGER, \
CONF_STATIC_IP, \ CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_WIFI
CONF_WIFI, CONF_LOGGER, CONF_BAUD_RATE from esphomeyaml.helpers import AssignmentExpression, RawStatement, _EXPRESSIONS, add, add_task, \
from esphomeyaml.helpers import AssignmentExpression, RawStatement, _EXPRESSIONS, add, \ color, get_variable, indent, quote, statement, Expression
get_variable, indent, quote, statement, color
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'i2c'] PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'web_server', 'i2c']
CONFIG_PATH = None
def get_name(config): def get_name(config):
@ -26,7 +23,7 @@ def get_name(config):
def get_base_path(config): def get_base_path(config):
return os.path.join(os.path.dirname(CONFIG_PATH), get_name(config)) return os.path.join(os.path.dirname(core.CONFIG_PATH), get_name(config))
def discover_serial_ports(): def discover_serial_ports():
@ -47,8 +44,6 @@ def discover_serial_ports():
if not result: if not result:
return None return None
if len(result) == 1:
return result[0]
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(zip(result, descs)):
print(u" [{}] {} ({})".format(i, res, desc)) print(u" [{}] {} ({})".format(i, res, desc))
@ -107,18 +102,24 @@ def run_miniterm(config, port):
def write_cpp(config): def write_cpp(config):
_LOGGER.info("Generating C++ source...") _LOGGER.info("Generating C++ source...")
add_task(core_to_code, config[CONF_ESPHOMEYAML])
for domain in PRE_INITIALIZE: for domain in PRE_INITIALIZE:
if domain == CONF_ESPHOMEYAML:
continue
if domain in config: if domain in config:
add_component_task(domain, config[domain]) add_task(get_component(domain).to_code, config[domain])
# Clear queue # Clear queue
get_variable(None) get_variable(None)
add(RawStatement('')) add(RawStatement(''))
for domain, conf in config.iteritems(): for domain, component, conf in iter_components(config):
if domain in PRE_INITIALIZE: if domain in PRE_INITIALIZE:
continue continue
add_component_task(domain, conf) if not hasattr(component, 'to_code'):
continue
add_task(component.to_code, conf)
# Clear queue # Clear queue
get_variable(None) get_variable(None)
@ -127,7 +128,10 @@ def write_cpp(config):
all_code = [] all_code = []
for exp in _EXPRESSIONS: for exp in _EXPRESSIONS:
if helpers.SIMPLIFY and isinstance(exp, AssignmentExpression) and exp.obj.usages == 0: if core.SIMPLIFY:
if isinstance(exp, Expression) and not exp.required:
continue
if isinstance(exp, AssignmentExpression) and not exp.obj.required:
exp = exp.rhs exp = exp.rhs
all_code.append(unicode(statement(exp))) all_code.append(unicode(statement(exp)))
@ -211,8 +215,6 @@ def setup_log():
def main(): def main():
global CONFIG_PATH
setup_log() setup_log()
parser = argparse.ArgumentParser(prog='esphomeyaml') parser = argparse.ArgumentParser(prog='esphomeyaml')
@ -260,13 +262,17 @@ def main():
subparsers.add_parser('wizard', help="A helpful setup wizard that will guide " subparsers.add_parser('wizard', help="A helpful setup wizard that will guide "
"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('version', help="Print the esphomeyaml version and exit.")
args = parser.parse_args() args = parser.parse_args()
if args.command == 'wizard': if args.command == 'wizard':
return wizard.wizard(args.configuration) return wizard.wizard(args.configuration)
CONFIG_PATH = args.configuration core.CONFIG_PATH = args.configuration
config = read_config(CONFIG_PATH)
config = read_config(core.CONFIG_PATH)
if config is None: if config is None:
return 1 return 1
@ -294,6 +300,8 @@ def main():
return show_logs(config, args, port) return show_logs(config, args, port)
elif args.command == 'clean-mqtt': elif args.command == 'clean-mqtt':
return clean_mqtt(config, args) return clean_mqtt(config, args)
elif args.command == 'mqtt-fingerprint':
return mqtt.get_fingerprint(config)
elif args.command == 'run': elif args.command == 'run':
exit_code = write_cpp(config) exit_code = write_cpp(config)
if exit_code != 0: if exit_code != 0:
@ -302,14 +310,17 @@ def main():
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info(u"Successfully compiled program.") _LOGGER.info(u"Successfully compiled program.")
if args.no_logs:
return 0
port = args.upload_port or discover_serial_ports() port = args.upload_port or discover_serial_ports()
exit_code = upload_program(config, args, port) exit_code = upload_program(config, args, port)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info(u"Successfully uploaded program.") _LOGGER.info(u"Successfully uploaded program.")
if args.no_logs:
return 0
return show_logs(config, args, port) 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

View file

@ -35,3 +35,7 @@ def to_code(config):
ads1115 = Pvariable(ADS1115_COMPONENT_CLASS, conf[CONF_ID], rhs) ads1115 = Pvariable(ADS1115_COMPONENT_CLASS, conf[CONF_ID], rhs)
if CONF_RATE in conf: if CONF_RATE in conf:
add(ads1115.set_rate(RawExpression(RATES[conf[CONF_RATE]]))) add(ads1115.set_rate(RawExpression(RATES[conf[CONF_RATE]])))
def build_flags(config):
return '-DUSE_ADS1115_SENSOR'

View file

@ -4,10 +4,6 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_INVERTED from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_INVERTED
from esphomeyaml.helpers import add, setup_mqtt_component from esphomeyaml.helpers import add, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_INVERTED): cv.boolean,
})
DEVICE_CLASSES = [ DEVICE_CLASSES = [
'', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas', '', 'battery', 'cold', 'connectivity', 'door', 'garage_door', 'gas',
'heat', 'light', 'lock', 'moisture', 'motion', 'moving', 'occupancy', 'heat', 'light', 'lock', 'moisture', 'motion', 'moving', 'occupancy',
@ -17,13 +13,27 @@ DEVICE_CLASSES = [
DEVICE_CLASSES_MSG = "Unknown device class. Must be one of {}".format(', '.join(DEVICE_CLASSES)) DEVICE_CLASSES_MSG = "Unknown device class. Must be one of {}".format(', '.join(DEVICE_CLASSES))
MQTT_BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_INVERTED): cv.boolean,
vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower, vol.Optional(CONF_DEVICE_CLASS): vol.All(vol.Lower,
vol.Any(*DEVICE_CLASSES, msg=DEVICE_CLASSES_MSG)), vol.Any(*DEVICE_CLASSES, msg=DEVICE_CLASSES_MSG)),
}) })
MQTT_BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
def setup_mqtt_binary_sensor(obj, config, skip_device_class=False): })
if not skip_device_class and CONF_DEVICE_CLASS in config:
def setup_binary_sensor(obj, config):
if CONF_DEVICE_CLASS in config:
add(obj.set_device_class(config[CONF_DEVICE_CLASS])) add(obj.set_device_class(config[CONF_DEVICE_CLASS]))
if CONF_INVERTED in config:
add(obj.set_inverted(config[CONF_INVERTED]))
def setup_mqtt_binary_sensor(obj, config):
setup_mqtt_component(obj, config) setup_mqtt_component(obj, config)
def build_flags(config):
return '-DUSE_BINARY_SENSOR'

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.components import binary_sensor from esphomeyaml.components import binary_sensor
from esphomeyaml.const import CONF_DEVICE_CLASS, CONF_ID, CONF_INVERTED, CONF_NAME, CONF_PIN from esphomeyaml.const import CONF_ID, CONF_INVERTED, CONF_NAME, CONF_PIN
from esphomeyaml.helpers import App, add, exp_gpio_input_pin, variable from esphomeyaml.helpers import App, add, exp_gpio_input_pin, variable
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
@ -13,9 +13,13 @@ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
rhs = App.make_gpio_binary_sensor(exp_gpio_input_pin(config[CONF_PIN]), rhs = App.make_gpio_binary_sensor(config[CONF_NAME], exp_gpio_input_pin(config[CONF_PIN]))
config[CONF_NAME], config.get(CONF_DEVICE_CLASS)) gpio = variable('Application::MakeGPIOBinarySensor', config[CONF_ID], rhs)
gpio = variable('Application::SimpleBinarySensor', config[CONF_ID], rhs)
if CONF_INVERTED in config: if CONF_INVERTED in config:
add(gpio.Pgpio.set_inverted(config[CONF_INVERTED])) add(gpio.Pgpio.set_inverted(config[CONF_INVERTED]))
binary_sensor.setup_mqtt_binary_sensor(gpio.Pmqtt, config, skip_device_class=True) binary_sensor.setup_binary_sensor(gpio.Pgpio, config)
binary_sensor.setup_mqtt_binary_sensor(gpio.Pmqtt, config)
def build_flags(config):
return '-DUSE_GPIO_BINARY_SENSOR'

View file

@ -1,7 +1,9 @@
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_ID, CONF_NAME
from esphomeyaml.helpers import App, Pvariable from esphomeyaml.helpers import App, variable
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'): cv.register_variable_id,
@ -10,5 +12,10 @@ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
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])
gpio = Pvariable('binary_sensor::MQTTBinarySensorComponent', config[CONF_ID], rhs) status = variable('Application::MakeStatusBinarySensor', config[CONF_ID], rhs)
binary_sensor.setup_mqtt_binary_sensor(gpio.Pmqtt, config) binary_sensor.setup_binary_sensor(status.Pstatus, config)
binary_sensor.setup_mqtt_binary_sensor(status.Pmqtt, config)
def build_flags(config):
return '-DUSE_STATUS_BINARY_SENSOR'

View file

@ -18,3 +18,7 @@ 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(DALLAS_COMPONENT_CLASS, conf[CONF_ID], rhs)
def build_flags(config):
return '-DUSE_DALLAS_SENSOR'

View file

@ -0,0 +1,15 @@
import voluptuous as vol
from esphomeyaml.helpers import App, add
DEPENDENCIES = ['logger']
CONFIG_SCHEMA = vol.Schema({})
def to_code(config):
add(App.make_debug_component())
def build_flags(config):
return '-DUSE_DEBUG_COMPONENT'

View file

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

View file

@ -21,3 +21,7 @@ def setup_mqtt_fan(obj, config):
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(obj.set_custom_speed_command_topic(config[CONF_SPEED_COMMAND_TOPIC]))
setup_mqtt_component(obj, config) setup_mqtt_component(obj, config)
def build_flags(config):
return '-DUSE_FAN'

View file

@ -15,7 +15,7 @@ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
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::FanStruct', config[CONF_ID], rhs) fan_struct = variable('Application::MakeFan', config[CONF_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])

View file

@ -24,7 +24,7 @@ PLATFORM_SCHEMA = fan.PLATFORM_SCHEMA.extend({
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::FanStruct', config[CONF_ID], rhs) fan_struct = variable('Application::MakeFan', config[CONF_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,

View file

@ -14,3 +14,7 @@ CONFIG_SCHEMA = vol.Schema({
def to_code(config): def to_code(config):
add(App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_FREQUENCY))) add(App.init_i2c(config[CONF_SDA], config[CONF_SCL], config.get(CONF_FREQUENCY)))
def build_flags(config):
return '-DUSE_I2C'

View file

@ -21,3 +21,7 @@ def to_code(config):
pin = exp_gpio_output_pin(conf[CONF_PIN]) pin = exp_gpio_output_pin(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(IR_TRANSMITTER_COMPONENT_CLASS, conf[CONF_ID], rhs)
def build_flags(config):
return '-DUSE_IR_TRANSMITTER'

View file

@ -1,13 +1,16 @@
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH from esphomeyaml.const import CONF_DEFAULT_TRANSITION_LENGTH
from esphomeyaml.helpers import add, setup_mqtt_component from esphomeyaml.helpers import add
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}).extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA.schema) }).extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA.schema)
def setup_mqtt_light_component(obj, config): def setup_light_component(obj, 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(obj.set_default_transition_length(config[CONF_DEFAULT_TRANSITION_LENGTH]))
setup_mqtt_component(obj, config)
def build_flags(config):
return '-DUSE_LIGHT'

View file

@ -4,7 +4,7 @@ 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_ID, CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, get_variable, variable from esphomeyaml.helpers import App, get_variable, variable, setup_mqtt_component
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('binary_light'): cv.register_variable_id, cv.GenerateID('binary_light'): cv.register_variable_id,
@ -15,5 +15,6 @@ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
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::LightStruct', config[CONF_ID], rhs) light_struct = variable('Application::MakeLight', config[CONF_ID], rhs)
light.setup_mqtt_light_component(light_struct.Pmqtt, config) setup_mqtt_component(light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View file

@ -4,7 +4,7 @@ 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_ID, \
CONF_NAME, CONF_OUTPUT CONF_NAME, CONF_OUTPUT
from esphomeyaml.helpers import App, add, get_variable, variable from esphomeyaml.helpers import App, add, get_variable, variable, setup_mqtt_component
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('monochromatic_light'): cv.register_variable_id, cv.GenerateID('monochromatic_light'): cv.register_variable_id,
@ -17,7 +17,8 @@ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
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::LightStruct', config[CONF_ID], rhs) light_struct = variable('Application::MakeLight', config[CONF_ID], rhs)
if CONF_GAMMA_CORRECT in config: if CONF_GAMMA_CORRECT in config:
add(light_struct.Poutput.set_gamma_correct(config[CONF_GAMMA_CORRECT])) add(light_struct.Poutput.set_gamma_correct(config[CONF_GAMMA_CORRECT]))
light.setup_mqtt_light_component(light_struct.Pmqtt, config) setup_mqtt_component(light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View file

@ -4,7 +4,7 @@ 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_ID, CONF_NAME, CONF_RED
from esphomeyaml.helpers import App, add, get_variable, variable from esphomeyaml.helpers import App, add, get_variable, variable, setup_mqtt_component
PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = light.PLATFORM_SCHEMA.extend({
cv.GenerateID('rgb_light'): cv.register_variable_id, cv.GenerateID('rgb_light'): cv.register_variable_id,
@ -21,7 +21,8 @@ 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::LightStruct', config[CONF_ID], rhs) light_struct = variable('Application::MakeLight', config[CONF_ID], rhs)
if CONF_GAMMA_CORRECT in config: if CONF_GAMMA_CORRECT in config:
add(light_struct.Poutput.set_gamma_correct(config[CONF_GAMMA_CORRECT])) add(light_struct.Poutput.set_gamma_correct(config[CONF_GAMMA_CORRECT]))
light.setup_mqtt_light_component(light_struct.Pmqtt, config) setup_mqtt_component(light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View file

@ -4,7 +4,7 @@ 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_ID, CONF_NAME, CONF_RED, CONF_WHITE
from esphomeyaml.helpers import App, get_variable, variable, add from esphomeyaml.helpers import App, add, get_variable, setup_mqtt_component, 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'): cv.register_variable_id,
@ -23,7 +23,8 @@ 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::LightStruct', config[CONF_ID], rhs) light_struct = variable('Application::MakeLight', config[CONF_ID], rhs)
if CONF_GAMMA_CORRECT in config: if CONF_GAMMA_CORRECT in config:
add(light_struct.Poutput.set_gamma_correct(config[CONF_GAMMA_CORRECT])) add(light_struct.Poutput.set_gamma_correct(config[CONF_GAMMA_CORRECT]))
light.setup_mqtt_light_component(light_struct.Pmqtt, config) setup_mqtt_component(light_struct.Pmqtt, config)
light.setup_light_component(light_struct.Pstate, config)

View file

@ -2,20 +2,18 @@ import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, \ from esphomeyaml.const import CONF_BAUD_RATE, CONF_ID, CONF_LEVEL, CONF_LOGGER, CONF_LOGS, \
CONF_LOG_TOPIC, 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, exp_empty_optional from esphomeyaml.helpers import App, Pvariable, RawExpression, add
LOG_LEVELS = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE'] LOG_LEVELS = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', '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, vol.Any(*LOG_LEVELS))
CONFIG_SCHEMA = cv.ID_SCHEMA.extend({ CONFIG_SCHEMA = 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_LOG_TOPIC): vol.Any(None, '', cv.publish_topic),
vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int, vol.Optional(CONF_TX_BUFFER_SIZE): cv.positive_int,
vol.Optional(CONF_LEVEL): is_log_level, vol.Optional(CONF_LEVEL): is_log_level,
vol.Optional(CONF_LOGS): vol.Schema({ vol.Optional(CONF_LOGS): vol.Schema({
@ -33,16 +31,7 @@ def exp_log_level(level):
def to_code(config): def to_code(config):
baud_rate = config.get(CONF_BAUD_RATE) rhs = App.init_log(config.get(CONF_BAUD_RATE))
if baud_rate is None and CONF_LOG_TOPIC in config:
baud_rate = 115200
log_topic = None
if CONF_LOG_TOPIC in config:
if not config[CONF_LOG_TOPIC]:
log_topic = exp_empty_optional(u'std::string')
else:
log_topic = config[CONF_LOG_TOPIC]
rhs = App.init_log(baud_rate, log_topic)
log = Pvariable(u'LogComponent', config[CONF_ID], rhs) log = Pvariable(u'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]))
@ -56,7 +45,7 @@ def to_code(config):
add(log.set_log_level(tag, exp_log_level(level))) add(log.set_log_level(tag, exp_log_level(level)))
def get_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(esphomelib_log_level(config[CONF_LEVEL]))
return u'' return None

View file

@ -1,11 +1,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.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_DISCOVERY, \ from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, CONF_DISCOVERY, \
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_MQTT, CONF_PASSWORD, \ CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_SSL_FINGERPRINTS, CONF_ID, CONF_LOG_TOPIC, \
CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_USERNAME, \ CONF_MQTT, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, CONF_RETAIN, CONF_TOPIC, \
CONF_WILL_MESSAGE, CONF_CLIENT_ID CONF_TOPIC_PREFIX, CONF_USERNAME, CONF_WILL_MESSAGE
from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, exp_empty_optional from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, StructInitializer, add, \
exp_empty_optional, RawExpression
MQTT_WILL_BIRTH_SCHEMA = vol.Any(None, vol.Schema({ MQTT_WILL_BIRTH_SCHEMA = vol.Any(None, vol.Schema({
vol.Required(CONF_TOPIC): cv.publish_topic, vol.Required(CONF_TOPIC): cv.publish_topic,
@ -19,7 +22,7 @@ def validate_broker(value):
value = cv.string_strict(value) value = cv.string_strict(value)
if value.endswith(u'.local'): if value.endswith(u'.local'):
raise vol.Invalid(u"MQTT server addresses ending with '.local' are currently unsupported." raise vol.Invalid(u"MQTT server addresses ending with '.local' are currently unsupported."
u" Please specify the static IP instead.") 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:
@ -27,7 +30,14 @@ def validate_broker(value):
return value return value
CONFIG_SCHEMA = cv.ID_SCHEMA.extend({ def validate_fingerprint(value):
value = cv.string(value)
if re.match(r'^[0-9a-f]{40}$', value) is None:
raise vol.Invalid(u"fingerprint must be valid SHA1 hash")
return value
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(CONF_MQTT): cv.register_variable_id, cv.GenerateID(CONF_MQTT): cv.register_variable_id,
vol.Required(CONF_BROKER): validate_broker, vol.Required(CONF_BROKER): validate_broker,
vol.Optional(CONF_PORT, default=1883): cv.port, vol.Optional(CONF_PORT, default=1883): cv.port,
@ -40,6 +50,9 @@ CONFIG_SCHEMA = cv.ID_SCHEMA.extend({
vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA, vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA, vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_TOPIC_PREFIX): cv.publish_topic, vol.Optional(CONF_TOPIC_PREFIX): cv.publish_topic,
vol.Optional(CONF_LOG_TOPIC): cv.publish_topic,
vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266,
cv.ensure_list, [validate_fingerprint]),
}) })
@ -74,3 +87,15 @@ def to_code(config):
add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX])) add(mqtt.set_topic_prefix(config[CONF_TOPIC_PREFIX]))
if CONF_CLIENT_ID in config: if CONF_CLIENT_ID in config:
add(mqtt.set_client_id(config[CONF_CLIENT_ID])) add(mqtt.set_client_id(config[CONF_CLIENT_ID]))
if CONF_LOG_TOPIC in config:
add(mqtt.set_log_topic(config[CONF_LOG_TOPIC]))
if CONF_SSL_FINGERPRINTS in config:
for fingerprint in config[CONF_SSL_FINGERPRINTS]:
arr = [RawExpression("0x{}".format(fingerprint[i:i + 2])) for i in range(0, 40, 2)]
add(mqtt.add_ssl_fingerprint(ArrayInitializer(*arr, multiline=False)))
def required_build_flags(config):
if CONF_SSL_FINGERPRINTS in config:
return '-DASYNC_TCP_SSL_ENABLED=1'
return None

View file

@ -4,14 +4,15 @@ import logging
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
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_ESP8266, ESP_PLATFORM_ESP32 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
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = cv.ID_SCHEMA.extend({ CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(CONF_OTA): cv.register_variable_id, cv.GenerateID(CONF_OTA): cv.register_variable_id,
vol.Optional(CONF_SAFE_MODE, default=True): cv.boolean, vol.Optional(CONF_SAFE_MODE, default=True): cv.boolean,
# TODO Num attempts + wait time # TODO Num attempts + wait time
@ -33,12 +34,16 @@ def to_code(config):
def get_port(config): def get_port(config):
if CONF_PORT in config[CONF_OTA]: if CONF_PORT in config[CONF_OTA]:
return config[CONF_OTA][CONF_PORT] return config[CONF_OTA][CONF_PORT]
if cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
return 3232 return 3232
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
return 8266 return 8266
raise ESPHomeYAMLError(u"Invalid ESP Platform for ESP OTA port.") raise ESPHomeYAMLError(u"Invalid ESP Platform for ESP OTA port.")
def get_auth(config): def get_auth(config):
return config[CONF_OTA].get(CONF_PASSWORD, '') return config[CONF_OTA].get(CONF_PASSWORD, '')
def build_flags(config):
return '-DUSE_OTA'

View file

@ -23,3 +23,7 @@ def setup_output_platform(obj, config, skip_power_supply=False):
add(obj.set_power_supply(power_supply)) add(obj.set_power_supply(power_supply))
if CONF_MAX_POWER in config: if CONF_MAX_POWER in config:
add(obj.set_max_power(config[CONF_MAX_POWER])) add(obj.set_max_power(config[CONF_MAX_POWER]))
def build_flags(config):
return '-DUSE_OUTPUT'

View file

@ -2,23 +2,31 @@ 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, ESP_PLATFORM_ESP8266
ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, Pvariable, exp_gpio_output_pin, get_gpio_pin_number from esphomeyaml.helpers import App, Pvariable, exp_gpio_output_pin
ESP_PLATFORMS = [ESP_PLATFORM_ESP8266] ESP_PLATFORMS = [ESP_PLATFORM_ESP8266]
def valid_pwm_pin(value):
if value >= 16:
raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.")
return value
PLATFORM_SCHEMA = output.FLOAT_PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = output.FLOAT_PLATFORM_SCHEMA.extend({
vol.Required(CONF_PIN): pins.GPIO_OUTPUT_PIN_SCHEMA, vol.Required(CONF_PIN): vol.All(pins.GPIO_OUTPUT_PIN_SCHEMA,
pins.schema_validate_number(valid_pwm_pin)),
}) })
def to_code(config): def to_code(config):
if get_gpio_pin_number(config[CONF_PIN]) >= 16:
# Too difficult to do in config validation
raise ESPHomeYAMLError(u"ESP8266: Only pins 0-16 support PWM.")
pin = exp_gpio_output_pin(config[CONF_PIN]) pin = exp_gpio_output_pin(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('output::ESP8266PWMOutput', config[CONF_ID], rhs)
output.setup_output_platform(gpio, config) output.setup_output_platform(gpio, config)
def build_flags(config):
return '-DUSE_ESP8266_PWM_OUTPUT'

View file

@ -15,3 +15,7 @@ def to_code(config):
rhs = App.make_gpio_output(pin) rhs = App.make_gpio_output(pin)
gpio = Pvariable('output::GPIOBinaryOutputComponent', config[CONF_ID], rhs) gpio = Pvariable('output::GPIOBinaryOutputComponent', config[CONF_ID], rhs)
output.setup_output_platform(gpio, config) output.setup_output_platform(gpio, config)
def build_flags(config):
return '-DUSE_GPIO_OUTPUT'

View file

@ -36,3 +36,7 @@ def to_code(config):
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)
def build_flags(config):
return '-DUSE_LEDC_OUTPUT'

View file

@ -23,3 +23,7 @@ def to_code(config):
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('output::PCA9685OutputComponent::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)
def build_flags(config):
return '-DUSE_PCA9685_OUTPUT'

View file

@ -31,3 +31,7 @@ def to_code(config):
phase_balancer = RawExpression(u'PCA9685_PhaseBalancer_{}'.format( phase_balancer = RawExpression(u'PCA9685_PhaseBalancer_{}'.format(
conf[CONF_PHASE_BALANCER])) conf[CONF_PHASE_BALANCER]))
add(pca9685.set_phase_balancer(phase_balancer)) add(pca9685.set_phase_balancer(phase_balancer))
def build_flags(config):
return '-DUSE_PCA9685_OUTPUT'

View file

@ -23,3 +23,7 @@ def to_code(config):
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:
add(psu.set_keep_on_time(conf[CONF_KEEP_ON_TIME])) add(psu.set_keep_on_time(conf[CONF_KEEP_ON_TIME]))
def build_flags(config):
return '-DUSE_OUTPUT'

View file

@ -3,8 +3,8 @@ 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.const import CONF_ACCURACY_DECIMALS, CONF_ALPHA, CONF_EXPIRE_AFTER, \
CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, CONF_FILTER_NAN, CONF_FILTER_OUT, CONF_ICON, \ CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_FILTERS, CONF_FILTER_NAN, CONF_FILTER_OUT, CONF_ICON, \
CONF_ID, CONF_LAMBDA, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_SEND_EVERY, \ CONF_LAMBDA, CONF_MQTT_ID, CONF_MULTIPLY, CONF_NAME, CONF_OFFSET, CONF_SEND_EVERY, \
CONF_SLIDING_WINDOW_MOVING_AVERAGE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE CONF_SLIDING_WINDOW_MOVING_AVERAGE, CONF_UNIT_OF_MEASUREMENT, CONF_WINDOW_SIZE, CONF_ID
from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \ from esphomeyaml.helpers import App, ArrayInitializer, MockObj, Pvariable, RawExpression, add, \
setup_mqtt_component setup_mqtt_component
@ -13,7 +13,6 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
}) })
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.Any( FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.Any(
# TODO Fix weird voluptuous error messages
vol.Schema({vol.Required(CONF_OFFSET): vol.Coerce(float)}), vol.Schema({vol.Required(CONF_OFFSET): vol.Coerce(float)}),
vol.Schema({vol.Required(CONF_MULTIPLY): 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_OUT): vol.Coerce(float)}),
@ -43,7 +42,7 @@ MQTT_SENSOR_SCHEMA = vol.Schema({
}) })
MQTT_SENSOR_ID_SCHEMA = MQTT_SENSOR_SCHEMA.extend({ MQTT_SENSOR_ID_SCHEMA = MQTT_SENSOR_SCHEMA.extend({
cv.GenerateID('mqtt_sensor'): cv.register_variable_id, cv.GenerateID('mqtt_sensor', CONF_MQTT_ID): cv.register_variable_id,
}) })
# pylint: disable=invalid-name # pylint: disable=invalid-name
@ -72,30 +71,38 @@ def setup_filter(config):
conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE] conf = config[CONF_EXPONENTIAL_MOVING_AVERAGE]
return ExponentialMovingAverageFilter(conf[CONF_ALPHA], conf[CONF_SEND_EVERY]) return ExponentialMovingAverageFilter(conf[CONF_ALPHA], conf[CONF_SEND_EVERY])
if CONF_LAMBDA in config: if CONF_LAMBDA in config:
s = '[](float x) -> Optional<float> {{ return {}; }}'.format(config[CONF_LAMBDA]) s = u'[](float x) -> Optional<float> {{ return {}; }}'.format(config[CONF_LAMBDA])
return LambdaFilter(RawExpression(s)) return LambdaFilter(RawExpression(s))
raise ValueError("Filter unsupported: {}".format(config)) raise ValueError(u"Filter unsupported: {}".format(config))
def setup_mqtt_sensor_component(obj, config): def setup_mqtt_sensor_component(obj, config):
if CONF_EXPIRE_AFTER in config:
if config[CONF_EXPIRE_AFTER] is None:
add(obj.disable_expire_after())
else:
add(obj.set_expire_after(config[CONF_EXPIRE_AFTER]))
setup_mqtt_component(obj, config)
def setup_sensor(obj, config):
if CONF_UNIT_OF_MEASUREMENT in config: if CONF_UNIT_OF_MEASUREMENT in config:
add(obj.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT])) add(obj.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
if CONF_ICON in config: if CONF_ICON in config:
add(obj.set_icon(config[CONF_ICON])) add(obj.set_icon(config[CONF_ICON]))
if CONF_ACCURACY_DECIMALS in config: if CONF_ACCURACY_DECIMALS in config:
add(obj.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS])) add(obj.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
if CONF_EXPIRE_AFTER in config:
if config[CONF_EXPIRE_AFTER] is None:
add(obj.disable_expire_after())
else:
add(obj.set_expire_after(config[CONF_EXPIRE_AFTER]))
if CONF_FILTERS in config: if CONF_FILTERS in config:
filters = [setup_filter(x) for x in config[CONF_FILTERS]] filters = [setup_filter(x) for x in config[CONF_FILTERS]]
add(obj.set_filters(ArrayInitializer(*filters))) add(obj.set_filters(ArrayInitializer(*filters)))
setup_mqtt_component(obj, config)
def make_mqtt_sensor_for(exp, config): def register_sensor(var, config):
rhs = App.make_mqtt_sensor_for(exp, config[CONF_NAME]) setup_sensor(var, config)
mqtt_sensor = Pvariable('sensor::MQTTSensorComponent', config[CONF_ID], rhs) rhs = App.register_sensor(var)
mqtt_sensor = Pvariable('sensor::MQTTSensorComponent', config[CONF_MQTT_ID], rhs)
setup_mqtt_sensor_component(mqtt_sensor, config) setup_mqtt_sensor_component(mqtt_sensor, config)
def build_flags(config):
return '-DUSE_SENSOR'

View file

@ -25,11 +25,16 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
rhs = App.make_adc_sensor(config[CONF_PIN], config[CONF_NAME], 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('Application::MakeADCSensor', config[CONF_ID], rhs)
adc = make.Padc adc = make.Padc
if CONF_ATTENUATION in config: if CONF_ATTENUATION in config:
attenuation = ATTENUATION_MODES[config[CONF_ATTENUATION]] attenuation = ATTENUATION_MODES[config[CONF_ATTENUATION]]
add(adc.set_attenuation(RawExpression(attenuation))) add(adc.set_attenuation(RawExpression(attenuation)))
sensor.setup_sensor(adc, config)
sensor.setup_mqtt_sensor_component(make.Pmqtt, config) sensor.setup_mqtt_sensor_component(make.Pmqtt, config)
def build_flags(config):
return '-DUSE_ADC_SENSOR'

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 sensor from esphomeyaml.components import sensor
from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_UPDATE_INTERVAL from esphomeyaml.const import CONF_ADS1115_ID, CONF_GAIN, CONF_MULTIPLEXER, CONF_UPDATE_INTERVAL, \
from esphomeyaml.helpers import get_variable, RawExpression CONF_NAME, CONF_ID
from esphomeyaml.helpers import RawExpression, get_variable, Pvariable
DEPENDENCIES = ['ads1115'] DEPENDENCIES = ['ads1115']
@ -40,6 +41,7 @@ def validate_gain(value):
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
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): vol.All(vol.Upper, vol.Any(*list(MUX.keys()))),
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,
@ -52,5 +54,10 @@ def to_code(config):
mux = RawExpression(MUX[config[CONF_MULTIPLEXER]]) mux = RawExpression(MUX[config[CONF_MULTIPLEXER]])
gain = RawExpression(GAIN[config[CONF_GAIN]]) gain = RawExpression(GAIN[config[CONF_GAIN]])
sensor_ = hub.get_sensor(mux, gain, config.get(CONF_UPDATE_INTERVAL)) rhs = hub.get_sensor(config[CONF_NAME], mux, gain, config.get(CONF_UPDATE_INTERVAL))
sensor.make_mqtt_sensor_for(sensor_, config) sensor_ = Pvariable('sensor::ADS1115Sensor', config[CONF_ID], rhs)
sensor.register_sensor(sensor_, config)
def build_flags(config):
return '-DUSE_ADS1115_SENSOR'

View file

@ -22,8 +22,14 @@ 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::MakeBMP085Component', config[CONF_ID], rhs) bmp = variable('Application::MakeBMP085Sensor', config[CONF_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_mqtt_sensor_component(bmp.Pmqtt_temperature, config[CONF_TEMPERATURE])
sensor.setup_sensor(bmp.Pbmp.Pget_pressure_sensor(), config[CONF_PRESSURE])
sensor.setup_mqtt_sensor_component(bmp.Pmqtt_pressure, config[CONF_PRESSURE]) sensor.setup_mqtt_sensor_component(bmp.Pmqtt_pressure, config[CONF_PRESSURE])
def build_flags(config):
return '-DUSE_BMP085_SENSOR'

View file

@ -3,11 +3,13 @@ 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 DALLAS_COMPONENT_CLASS
from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_RESOLUTION, \ from esphomeyaml.const import CONF_ADDRESS, CONF_DALLAS_ID, CONF_INDEX, CONF_NAME, \
CONF_UPDATE_INTERVAL CONF_RESOLUTION, \
from esphomeyaml.helpers import HexIntLiteral, get_variable CONF_UPDATE_INTERVAL, CONF_ID
from esphomeyaml.helpers import HexIntLiteral, get_variable, Pvariable
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = 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,
@ -23,9 +25,14 @@ def to_code(config):
if CONF_ADDRESS in config: if CONF_ADDRESS in config:
address = HexIntLiteral(config[CONF_ADDRESS]) address = HexIntLiteral(config[CONF_ADDRESS])
sensor_ = hub.Pget_sensor_by_address(address, update_interval, rhs = hub.Pget_sensor_by_address(config[CONF_NAME], address, update_interval,
config.get(CONF_RESOLUTION)) config.get(CONF_RESOLUTION))
else: else:
sensor_ = hub.Pget_sensor_by_index(config[CONF_INDEX], update_interval, rhs = hub.Pget_sensor_by_index(config[CONF_NAME], config[CONF_INDEX],
config.get(CONF_RESOLUTION)) update_interval, config.get(CONF_RESOLUTION))
sensor.make_mqtt_sensor_for(sensor_, config) sensor_ = Pvariable('sensor::DallasTemperatureSensor', config[CONF_ID], rhs)
sensor.register_sensor(sensor_, config)
def build_flags(config):
return '-DUSE_DALLAS_SENSOR'

View file

@ -21,11 +21,18 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
rhs = App.make_dht_sensor(config[CONF_PIN], config[CONF_TEMPERATURE][CONF_NAME], rhs = App.make_dht_sensor(config[CONF_TEMPERATURE][CONF_NAME],
config[CONF_HUMIDITY][CONF_NAME], config.get(CONF_UPDATE_INTERVAL)) config[CONF_HUMIDITY][CONF_NAME],
dht = variable('Application::MakeDHTComponent', config[CONF_ID], rhs) config[CONF_PIN], config.get(CONF_UPDATE_INTERVAL))
dht = variable('Application::MakeDHTSensor', config[CONF_ID], rhs)
if CONF_MODEL in config: if CONF_MODEL in config:
model = RawExpression('DHT::{}'.format(config[CONF_MODEL])) model = RawExpression('DHT::{}'.format(config[CONF_MODEL]))
add(dht.Pdht.set_dht_model(model)) add(dht.Pdht.set_dht_model(model))
sensor.setup_sensor(dht.Pdht.Pget_temperature_sensor(), config[CONF_TEMPERATURE])
sensor.setup_mqtt_sensor_component(dht.Pmqtt_temperature, config[CONF_TEMPERATURE]) sensor.setup_mqtt_sensor_component(dht.Pmqtt_temperature, config[CONF_TEMPERATURE])
sensor.setup_sensor(dht.Pdht.Pget_humidity_sensor(), config[CONF_HUMIDITY])
sensor.setup_mqtt_sensor_component(dht.Pmqtt_humidity, config[CONF_HUMIDITY]) sensor.setup_mqtt_sensor_component(dht.Pmqtt_humidity, config[CONF_HUMIDITY])
def build_flags(config):
return '-DUSE_DHT_SENSOR'

View file

@ -21,6 +21,12 @@ 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::MakeHDC1080Component', config[CONF_ID], rhs) hdc1080 = variable('Application::MakeHDC1080Sensor', config[CONF_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_mqtt_sensor_component(hdc1080.Pmqtt_temperature, config[CONF_TEMPERATURE])
sensor.setup_sensor(hdc1080.Phdc1080.Pget_humidity_sensor(), config[CONF_HUMIDITY])
sensor.setup_mqtt_sensor_component(hdc1080.Pmqtt_humidity, config[CONF_HUMIDITY]) sensor.setup_mqtt_sensor_component(hdc1080.Pmqtt_humidity, config[CONF_HUMIDITY])
def build_flags(config):
return '-DUSE_HDC1080_SENSOR'

View file

@ -21,6 +21,12 @@ 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::MakeHTU21DComponent', config[CONF_ID], rhs) htu21d = variable('Application::MakeHTU21DSensor', config[CONF_ID], rhs)
sensor.setup_sensor(htu21d.Phtu21d.Pget_temperature_sensor(), config[CONF_TEMPERATURE])
sensor.setup_mqtt_sensor_component(htu21d.Pmqtt_temperature, config[CONF_TEMPERATURE]) sensor.setup_mqtt_sensor_component(htu21d.Pmqtt_temperature, config[CONF_TEMPERATURE])
sensor.setup_sensor(htu21d.Phtu21d.Pget_humidity_sensor(), config[CONF_HUMIDITY])
sensor.setup_mqtt_sensor_component(htu21d.Pmqtt_humidity, config[CONF_HUMIDITY]) sensor.setup_mqtt_sensor_component(htu21d.Pmqtt_humidity, config[CONF_HUMIDITY])
def build_flags(config):
return '-DUSE_HTU21D_SENSOR'

View file

@ -41,9 +41,9 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
rhs = App.make_pulse_counter_sensor(config[CONF_PIN], config[CONF_NAME], 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::MakePulseCounter', config[CONF_ID], rhs) make = variable('Application::MakePulseCounterSensor', config[CONF_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]]
@ -55,4 +55,9 @@ def to_code(config):
add(pcnt.set_edge_mode(RawExpression(rising_edge), RawExpression(falling_edge))) add(pcnt.set_edge_mode(RawExpression(rising_edge), RawExpression(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_mqtt_sensor_component(make.Pmqtt, config) sensor.setup_mqtt_sensor_component(make.Pmqtt, config)
def build_flags(config):
return '-DUSE_PULSE_COUNTER_SENSOR'

View file

@ -21,7 +21,7 @@ PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
trigger = exp_gpio_output_pin(config[CONF_TRIGGER_PIN]) trigger = exp_gpio_output_pin(config[CONF_TRIGGER_PIN])
echo = exp_gpio_input_pin(config[CONF_ECHO_PIN]) echo = exp_gpio_input_pin(config[CONF_ECHO_PIN])
rhs = App.make_ultrasonic_sensor(trigger, echo, config[CONF_NAME], 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('Application::MakeUltrasonicSensor', config[CONF_ID], rhs)
ultrasonic = make.Pultrasonic ultrasonic = make.Pultrasonic
@ -29,4 +29,9 @@ def to_code(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_mqtt_sensor_component(make.Pmqtt, config) sensor.setup_mqtt_sensor_component(make.Pmqtt, config)
def build_flags(config):
return '-DUSE_ULTRASONIC_SENSOR'

View file

@ -1,7 +1,7 @@
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_NAME from esphomeyaml.const import CONF_ICON, CONF_ID, CONF_NAME, CONF_MQTT_ID
from esphomeyaml.helpers import App, Pvariable, add, setup_mqtt_component from esphomeyaml.helpers import App, Pvariable, add, setup_mqtt_component
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
@ -12,14 +12,26 @@ MQTT_SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
}) })
MQTT_SWITCH_ID_SCHEMA = MQTT_SWITCH_SCHEMA.extend({
cv.GenerateID('mqtt_switch', CONF_MQTT_ID): cv.register_variable_id,
})
def setup_mqtt_switch(obj, config): def setup_mqtt_switch(obj, config):
if CONF_ICON in config:
add(obj.set_icon(config[CONF_ICON]))
setup_mqtt_component(obj, config) setup_mqtt_component(obj, config)
def make_mqtt_switch_for(exp, config): def setup_switch(obj, config):
rhs = App.make_mqtt_switch_for(exp, config[CONF_NAME]) if CONF_ICON in config:
mqtt_switch = Pvariable('switch_::MQTTSwitchComponent', config[CONF_ID], rhs) add(obj.set_icon(config[CONF_ICON]))
def register_switch(var, config):
setup_switch(var, config)
rhs = App.register_switch(var)
mqtt_switch = Pvariable('switch_::MQTTSwitchComponent', config[CONF_MQTT_ID], rhs)
setup_mqtt_switch(mqtt_switch, config) setup_mqtt_switch(mqtt_switch, config)
def build_flags(config):
return '-DUSE_SWITCH'

View file

@ -13,6 +13,11 @@ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
rhs = App.make_gpio_switch(exp_gpio_output_pin(config[CONF_PIN]), config[CONF_NAME]) rhs = App.make_gpio_switch(config[CONF_NAME], exp_gpio_output_pin(config[CONF_PIN]))
gpio = variable('Application::GPIOSwitchStruct', config[CONF_ID], rhs) gpio = variable('Application::MakeGPIOSwitch', config[CONF_ID], rhs)
switch.setup_switch(gpio.Pswitch_, config)
switch.setup_mqtt_switch(gpio.Pmqtt, config) switch.setup_mqtt_switch(gpio.Pmqtt, config)
def build_flags(config):
return '-DUSE_GPIO_SWITCH'

View file

@ -5,12 +5,12 @@ from esphomeyaml.components import switch
from esphomeyaml.components.ir_transmitter import IR_TRANSMITTER_COMPONENT_CLASS from esphomeyaml.components.ir_transmitter import IR_TRANSMITTER_COMPONENT_CLASS
from esphomeyaml.const import CONF_ADDRESS, CONF_COMMAND, CONF_DATA, CONF_IR_TRANSMITTER_ID, \ from esphomeyaml.const import CONF_ADDRESS, CONF_COMMAND, CONF_DATA, CONF_IR_TRANSMITTER_ID, \
CONF_LG, CONF_NBITS, CONF_NEC, CONF_PANASONIC, CONF_REPEAT, CONF_SONY, CONF_TIMES, \ CONF_LG, CONF_NBITS, CONF_NEC, CONF_PANASONIC, CONF_REPEAT, CONF_SONY, CONF_TIMES, \
CONF_WAIT_TIME_US, CONF_RAW, CONF_CARRIER_FREQUENCY CONF_WAIT_TIME_US, CONF_RAW, CONF_CARRIER_FREQUENCY, CONF_NAME, CONF_ID
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import HexIntLiteral, MockObj, get_variable, ArrayInitializer from esphomeyaml.helpers import HexIntLiteral, MockObj, get_variable, ArrayInitializer, Pvariable
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID('ir_transmitter'): cv.register_variable_id, cv.GenerateID('ir_transmitter_switch'): cv.register_variable_id,
vol.Exclusive(CONF_NEC, 'code'): vol.Schema({ vol.Exclusive(CONF_NEC, 'code'): vol.Schema({
vol.Required(CONF_ADDRESS): cv.hex_uint16_t, vol.Required(CONF_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint16_t, vol.Required(CONF_COMMAND): cv.hex_uint16_t,
@ -36,7 +36,7 @@ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
vol.Required(CONF_WAIT_TIME_US): cv.uint32_t, vol.Required(CONF_WAIT_TIME_US): cv.uint32_t,
})), })),
vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id, vol.Optional(CONF_IR_TRANSMITTER_ID): cv.variable_id,
}).extend(switch.MQTT_SWITCH_SCHEMA.schema) }).extend(switch.MQTT_SWITCH_ID_SCHEMA.schema)
# pylint: disable=invalid-name # pylint: disable=invalid-name
@ -86,4 +86,11 @@ def exp_send_data(config):
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), IR_TRANSMITTER_COMPONENT_CLASS)
send_data = exp_send_data(config) send_data = exp_send_data(config)
switch.make_mqtt_switch_for(ir.create_transmitter(send_data), config) rhs = ir.create_transmitter(config[CONF_NAME], send_data)
switch_ = Pvariable(IR_TRANSMITTER_COMPONENT_CLASS + '::DataTransmitter', config[CONF_ID],
rhs)
switch.register_switch(switch_, config)
def build_flags(config):
return '-DUSE_IR_TRANSMITTER'

View file

@ -1,7 +1,7 @@
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_ID, CONF_NAME
from esphomeyaml.helpers import App, Pvariable from esphomeyaml.helpers import App, 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'): cv.register_variable_id,
@ -10,5 +10,10 @@ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
def to_code(config): def to_code(config):
rhs = App.make_restart_switch(config[CONF_NAME]) rhs = App.make_restart_switch(config[CONF_NAME])
mqtt = Pvariable('switch_::MQTTSwitchComponent', config[CONF_ID], rhs) restart = variable('Application::MakeRestartSwitch', config[CONF_ID], rhs)
switch.setup_mqtt_switch(mqtt, config) switch.setup_switch(restart.Prestart, config)
switch.setup_mqtt_switch(restart.Pmqtt, config)
def build_flags(config):
return '-DUSE_RESTART_SWITCH'

View file

@ -0,0 +1,29 @@
import logging
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_PORT, CONF_JS_URL, CONF_CSS_URL, CONF_ID
from esphomeyaml.helpers import App, add, Pvariable
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('web_server'): cv.register_variable_id,
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_CSS_URL): vol.Url,
vol.Optional(CONF_JS_URL): vol.Url,
})
def to_code(config):
rhs = App.init_web_server(config.get(CONF_PORT))
web_server = Pvariable('WebServer', config[CONF_ID], rhs)
if CONF_CSS_URL in config:
add(web_server.set_css_url(config[CONF_CSS_URL]))
if CONF_JS_URL in config:
add(web_server.set_js_url(config[CONF_JS_URL]))
def build_flags(config):
return '-DUSE_WEB_SERVER'

View file

@ -1,25 +1,47 @@
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_DNS1, CONF_DNS2, CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, \ from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_GATEWAY, \
CONF_MANUAL_IP, CONF_PASSWORD, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, CONF_WIFI CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET
from esphomeyaml.helpers import App, MockObj, Pvariable, StructInitializer, add from esphomeyaml.helpers import App, MockObj, Pvariable, StructInitializer, add
CONFIG_SCHEMA = cv.ID_SCHEMA.extend({
cv.GenerateID(CONF_WIFI): cv.register_variable_id, def validate_password(value):
vol.Required(CONF_SSID): cv.ssid, value = cv.string(value)
vol.Optional(CONF_PASSWORD): cv.string, if not value:
vol.Optional(CONF_MANUAL_IP): vol.Schema({ return value
if len(value) < 8:
raise vol.Invalid(u"WPA password must be at least 8 characters long")
if len(value) > 63:
raise vol.Invalid(u"WPA password must be at most 63 characters long")
return value
AP_MANUAL_IP_SCHEMA = vol.Schema({
vol.Required(CONF_STATIC_IP): cv.ipv4, vol.Required(CONF_STATIC_IP): cv.ipv4,
vol.Required(CONF_GATEWAY): cv.ipv4, vol.Required(CONF_GATEWAY): cv.ipv4,
vol.Required(CONF_SUBNET): cv.ipv4, vol.Required(CONF_SUBNET): cv.ipv4,
})
STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
vol.Inclusive(CONF_DNS1, 'dns'): cv.ipv4, vol.Inclusive(CONF_DNS1, 'dns'): cv.ipv4,
vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4, vol.Inclusive(CONF_DNS2, 'dns'): cv.ipv4,
})
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID('wifi'): cv.register_variable_id,
vol.Optional(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
vol.Optional(CONF_AP): vol.Schema({
vol.Required(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_CHANNEL): vol.All(cv.positive_int, vol.Range(min=1, max=14)),
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
}), }),
vol.Optional(CONF_HOSTNAME): cv.hostname, vol.Optional(CONF_HOSTNAME): cv.hostname,
}) })
# pylint: disable=invalid-name # pylint: disable=invalid-name
IPAddress = MockObj('IPAddress') IPAddress = MockObj('IPAddress')
@ -30,19 +52,38 @@ def safe_ip(ip):
return IPAddress(*ip.args) return IPAddress(*ip.args)
def to_code(config): def manual_ip(config):
rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD)) return StructInitializer(
wifi = Pvariable('WiFiComponent', config[CONF_ID], rhs)
if CONF_MANUAL_IP in config:
manual_ip = config[CONF_MANUAL_IP]
exp = StructInitializer(
'ManualIP', 'ManualIP',
('static_ip', safe_ip(manual_ip[CONF_STATIC_IP])), ('static_ip', safe_ip(config[CONF_STATIC_IP])),
('gateway', safe_ip(manual_ip[CONF_GATEWAY])), ('gateway', safe_ip(config[CONF_GATEWAY])),
('subnet', safe_ip(manual_ip[CONF_SUBNET])), ('subnet', safe_ip(config[CONF_SUBNET])),
('dns1', safe_ip(manual_ip.get(CONF_DNS1))), ('dns1', safe_ip(config.get(CONF_DNS1))),
('dns2', safe_ip(manual_ip.get(CONF_DNS2))), ('dns2', safe_ip(config.get(CONF_DNS2))),
) )
add(wifi.set_manual_ip(exp))
def to_code(config):
sta = CONF_SSID in config
ap = CONF_AP in config
if sta:
rhs = App.init_wifi(config[CONF_SSID], config.get(CONF_PASSWORD))
else:
rhs = App.init_wifi()
wifi = Pvariable('WiFiComponent', config[CONF_ID], rhs)
if sta and CONF_MANUAL_IP in config:
add(wifi.set_sta_manual_ip(manual_ip(config[CONF_MANUAL_IP])))
if ap:
conf = config[CONF_AP]
password = config.get(CONF_PASSWORD)
if password is None and CONF_CHANNEL in conf:
password = u""
add(wifi.set_ap(conf[CONF_SSID], password, conf.get(CONF_CHANNEL)))
if CONF_MANUAL_IP in conf:
add(wifi.set_ap_manual_ip(manual_ip(conf[CONF_MANUAL_IP])))
if CONF_HOSTNAME in config: if CONF_HOSTNAME in config:
add(wifi.set_hostname(config[CONF_HOSTNAME])) add(wifi.set_hostname(config[CONF_HOSTNAME]))

View file

@ -8,13 +8,12 @@ import voluptuous as vol
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import helpers, yaml_util from esphomeyaml import core, yaml_util
from esphomeyaml.const import CONF_BOARD, CONF_ESPHOMEYAML, CONF_LIBRARY_URI, CONF_MQTT, \ from esphomeyaml.const import CONF_BOARD, CONF_ESPHOMEYAML, CONF_LIBRARY_URI, CONF_NAME, \
CONF_NAME, \ CONF_PLATFORM, CONF_SIMPLIFY, CONF_USE_BUILD_FLAGS, CONF_WIFI, ESP_PLATFORMS, \
CONF_PLATFORM, CONF_SIMPLIFY, CONF_WIFI, ESP_PLATFORMS, ESP_PLATFORM_ESP32, \ ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, add, add_task, color from esphomeyaml.helpers import App, add, color
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -22,15 +21,15 @@ DEFAULT_LIBRARY_URI = u'esphomelib@1.2.1'
CORE_SCHEMA = vol.Schema({ CORE_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.valid_name, vol.Required(CONF_NAME): cv.valid_name,
vol.Required(CONF_PLATFORM): vol.All( vol.Required(CONF_PLATFORM): cv.string,
vol.Upper, vol.Any(ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266)),
vol.Required(CONF_BOARD): cv.string, vol.Required(CONF_BOARD): cv.string,
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=False): cv.boolean,
}) })
REQUIRED_COMPONENTS = [ REQUIRED_COMPONENTS = [
CONF_ESPHOMEYAML, CONF_WIFI, CONF_MQTT CONF_ESPHOMEYAML, CONF_WIFI
] ]
_COMPONENT_CACHE = {} _COMPONENT_CACHE = {}
@ -66,8 +65,17 @@ def is_platform_component(component):
return hasattr(component, 'PLATFORM_SCHEMA') return hasattr(component, 'PLATFORM_SCHEMA')
def validate_schema(config, schema): def iter_components(config):
return schema(config) for domain, conf in config.iteritems():
if domain == CONF_ESPHOMEYAML:
continue
component = get_component(domain)
yield domain, component, conf
if is_platform_component(component):
for p_config in conf:
p_name = u"{}.{}".format(domain, p_config[CONF_PLATFORM])
platform = get_component(p_name)
yield p_name, platform, p_config
class Config(OrderedDict): class Config(OrderedDict):
@ -96,7 +104,7 @@ def validate_config(config):
result.add_error(_format_config_error(ex, domain, config), domain, config) result.add_error(_format_config_error(ex, domain, config), domain, config)
try: try:
result[CONF_ESPHOMEYAML] = validate_schema(config[CONF_ESPHOMEYAML], CORE_SCHEMA) result[CONF_ESPHOMEYAML] = CORE_SCHEMA(config[CONF_ESPHOMEYAML])
except vol.Invalid as ex: except vol.Invalid as ex:
_comp_error(ex, CONF_ESPHOMEYAML, config) _comp_error(ex, CONF_ESPHOMEYAML, config)
@ -111,8 +119,8 @@ def validate_config(config):
continue continue
esp_platforms = getattr(component, 'ESP_PLATFORMS', ESP_PLATFORMS) esp_platforms = getattr(component, 'ESP_PLATFORMS', ESP_PLATFORMS)
if cv.ESP_PLATFORM not in esp_platforms: if core.ESP_PLATFORM not in esp_platforms:
result.add_error(u"Component {} doesn't support {}.".format(domain, cv.ESP_PLATFORM)) result.add_error(u"Component {} doesn't support {}.".format(domain, core.ESP_PLATFORM))
continue continue
success = True success = True
@ -129,7 +137,7 @@ def validate_config(config):
validated = component.CONFIG_SCHEMA(conf) validated = component.CONFIG_SCHEMA(conf)
result[domain] = validated result[domain] = validated
except vol.Invalid as ex: except vol.Invalid as ex:
_comp_error(ex, domain, config) _comp_error(ex, domain, conf)
continue continue
if not hasattr(component, 'PLATFORM_SCHEMA'): if not hasattr(component, 'PLATFORM_SCHEMA'):
@ -138,7 +146,7 @@ def validate_config(config):
platforms = [] platforms = []
for p_config in conf: for p_config in conf:
if not isinstance(p_config, dict): if not isinstance(p_config, dict):
result.add_error(u"Platform schemas mus have 'platform:' key") result.add_error(u"Platform schemas must have 'platform:' key")
continue continue
p_name = p_config.get(u'platform') p_name = p_config.get(u'platform')
if p_name is None: if p_name is None:
@ -149,6 +157,16 @@ def validate_config(config):
result.add_error(u"Platform not found: {}.{}") result.add_error(u"Platform not found: {}.{}")
continue continue
success = True
dependencies = getattr(platform, 'DEPENDENCIES', [])
for dependency in dependencies:
if dependency not in _ALL_COMPONENTS:
result.add_error(u"Platform {}.{} requires {}".format(domain, p_name,
dependency))
success = False
if not success:
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)
@ -160,7 +178,7 @@ def validate_config(config):
return result return result
REQUIRED = ['esphomeyaml', 'wifi', 'mqtt'] REQUIRED = ['esphomeyaml', 'wifi']
def _format_config_error(ex, domain, config): def _format_config_error(ex, domain, config):
@ -186,13 +204,18 @@ def load_config(path):
except OSError: except OSError:
raise ESPHomeYAMLError(u"Could not read configuration file at {}".format(path)) raise ESPHomeYAMLError(u"Could not read configuration file at {}".format(path))
esp_platform = unicode(config.get(CONF_ESPHOMEYAML, {}).get(CONF_PLATFORM, u"")) if CONF_ESPHOMEYAML not in config:
raise ESPHomeYAMLError(u"No esphomeyaml section in config")
core_conf = config[CONF_ESPHOMEYAML]
esp_platform = unicode(core_conf.get(CONF_PLATFORM, u""))
esp_platform = esp_platform.upper() esp_platform = esp_platform.upper()
if esp_platform not in (ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266): if '8266' in esp_platform:
raise ESPHomeYAMLError(u"Invalid ESP Platform {}".format(esp_platform)) esp_platform = ESP_PLATFORM_ESP8266
cv.ESP_PLATFORM = esp_platform if '32' in esp_platform:
cv.BOARD = unicode(config.get(CONF_ESPHOMEYAML, {}).get(CONF_BOARD, u"")) esp_platform = ESP_PLATFORM_ESP32
helpers.SIMPLIFY = cv.boolean(config.get(CONF_SIMPLIFY, True)) core.ESP_PLATFORM = esp_platform
core.BOARD = unicode(core_conf.get(CONF_BOARD, u""))
core.SIMPLIFY = cv.boolean(core_conf.get(CONF_SIMPLIFY, True))
try: try:
result = validate_config(config) result = validate_config(config)
@ -203,28 +226,6 @@ def load_config(path):
return result return result
def add_platform_task(domain, config):
platform_ = config[CONF_PLATFORM]
platform = get_platform(domain, platform_)
if not hasattr(platform, 'to_code'):
raise ESPHomeYAMLError(u"Platform '{}.{}' doesn't have to_code.".format(domain, platform_))
add_task(platform.to_code, config)
def add_component_task(domain, config):
if domain == CONF_ESPHOMEYAML:
add_task(core_to_code, config)
return
component = get_component(domain)
if is_platform_component(component):
for conf in config:
add_platform_task(domain, conf)
else:
if not hasattr(component, 'to_code'):
raise ESPHomeYAMLError(u"Component '{}' doesn't have to_code.".format(domain))
add_task(component.to_code, config)
def line_info(obj, **kwargs): def line_info(obj, **kwargs):
"""Display line config source.""" """Display line config source."""
if hasattr(obj, '__config_file__'): if hasattr(obj, '__config_file__'):

View file

@ -7,6 +7,7 @@ from datetime import timedelta
import voluptuous as vol import voluptuous as vol
from esphomeyaml import core
from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \ from esphomeyaml.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
CONF_NAME, CONF_PAYLOAD_AVAILABLE, \ CONF_NAME, CONF_PAYLOAD_AVAILABLE, \
CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \ CONF_PAYLOAD_NOT_AVAILABLE, CONF_PLATFORM, CONF_RETAIN, CONF_STATE_TOPIC, CONF_TOPIC, \
@ -24,9 +25,6 @@ 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))
ESP_PLATFORM = ''
BOARD = ''
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
RESERVED_IDS = [ RESERVED_IDS = [
@ -150,7 +148,7 @@ def only_on(platforms):
platforms = [platforms] platforms = [platforms]
def validator_(obj): def validator_(obj):
if ESP_PLATFORM not in platforms: if core.ESP_PLATFORM not in platforms:
raise vol.Invalid(u"This feature is only available on {}".format(platforms)) raise vol.Invalid(u"This feature is only available on {}".format(platforms))
return obj return obj
@ -274,8 +272,8 @@ def ssid(value):
raise vol.Invalid("SSID must be a string. Did you wrap it in quotes?") raise vol.Invalid("SSID must be a string. Did you wrap it in quotes?")
if not value: if not value:
raise vol.Invalid("SSID can't be empty.") raise vol.Invalid("SSID can't be empty.")
if len(value) > 32: if len(value) > 31:
raise vol.Invalid("SSID can't be longer than 32 characters") raise vol.Invalid("SSID can't be longer than 31 characters")
return value return value
@ -300,6 +298,8 @@ def publish_topic(value):
value = string_strict(value) value = string_strict(value)
if value.endswith('/'): if value.endswith('/'):
raise vol.Invalid("Publish topic can't end with '/'") raise vol.Invalid("Publish topic can't end with '/'")
if '+' in value or '#' in value:
raise vol.Invalid("Publish topic can't contain '+' or '#'")
return value return value
@ -334,23 +334,19 @@ def register_variable_id(value):
class GenerateID(vol.Optional): class GenerateID(vol.Optional):
def __init__(self, basename): def __init__(self, basename, key=CONF_ID):
self._basename = basename self._basename = basename
super(GenerateID, self).__init__(CONF_ID, default=self.default_variable_id) super(GenerateID, self).__init__(key, default=self.default_variable_id)
def default_variable_id(self): def default_variable_id(self):
return ensure_unique_string(self._basename, REGISTERED_IDS) return ensure_unique_string(self._basename, REGISTERED_IDS)
ID_SCHEMA = vol.Schema({
vol.Required(CONF_ID): invalid,
})
REQUIRED_ID_SCHEMA = vol.Schema({ REQUIRED_ID_SCHEMA = vol.Schema({
vol.Required(CONF_ID): register_variable_id, vol.Required(CONF_ID): register_variable_id,
}) })
PLATFORM_SCHEMA = ID_SCHEMA.extend({ PLATFORM_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): valid, vol.Required(CONF_PLATFORM): valid,
}) })

View file

@ -2,7 +2,7 @@
MAJOR_VERSION = 1 MAJOR_VERSION = 1
MINOR_VERSION = 2 MINOR_VERSION = 2
PATCH_VERSION = '2' PATCH_VERSION = '2-dev'
__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)
@ -17,6 +17,7 @@ CONF_NAME = 'name'
CONF_PLATFORM = 'platform' CONF_PLATFORM = 'platform'
CONF_BOARD = 'board' CONF_BOARD = 'board'
CONF_SIMPLIFY = 'simplify' CONF_SIMPLIFY = 'simplify'
CONF_USE_BUILD_FLAGS = 'use_build_flags'
CONF_LIBRARY_URI = 'library_uri' CONF_LIBRARY_URI = 'library_uri'
CONF_LOGGER = 'logger' CONF_LOGGER = 'logger'
CONF_WIFI = 'wifi' CONF_WIFI = 'wifi'
@ -32,6 +33,7 @@ CONF_BROKER = 'broker'
CONF_USERNAME = 'username' 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_PIN = 'pin' CONF_PIN = 'pin'
CONF_NUMBER = 'number' CONF_NUMBER = 'number'
CONF_INVERTED = 'inverted' CONF_INVERTED = 'inverted'
@ -151,6 +153,14 @@ CONF_RATE = 'rate'
CONF_ADS1115_ID = 'ads1115_id' CONF_ADS1115_ID = 'ads1115_id'
CONF_MULTIPLEXER = 'multiplexer' CONF_MULTIPLEXER = 'multiplexer'
CONF_GAIN = 'gain' CONF_GAIN = 'gain'
CONF_SLEEP_DURATION = 'sleep_duration'
CONF_WAKEUP_PIN = 'wakeup_pin'
CONF_RUN_CYCLES = 'run_cycles'
CONF_RUN_DURATION = 'run_duration'
CONF_AP = 'ap'
CONF_CSS_URL = 'css_url'
CONF_JS_URL = 'js_url'
CONF_FINGERPRINTS = 'fingerprints'
ESP32_BOARDS = [ ESP32_BOARDS = [
'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1', 'featheresp32', 'node32s', 'espea32', 'firebeetle32', 'esp32doit-devkit-v1',

View file

@ -16,3 +16,9 @@ class IPAddress(object):
def __str__(self): def __str__(self):
return '.'.join(str(x) for x in self.args) return '.'.join(str(x) for x in self.args)
CONFIG_PATH = None
SIMPLIFY = True
ESP_PLATFORM = ''
BOARD = ''

View file

@ -4,6 +4,7 @@ import logging
import re import re
from collections import OrderedDict, deque from collections import OrderedDict, deque
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_RETAIN, \
@ -12,8 +13,6 @@ from esphomeyaml.core import ESPHomeYAMLError, HexInt
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SIMPLIFY = False
def ensure_unique_string(preferred_string, current_strings): def ensure_unique_string(preferred_string, current_strings):
test_string = preferred_string test_string = preferred_string
@ -45,11 +44,19 @@ def indent(text, padding=u' '):
class Expression(object): class Expression(object):
def __init__(self): def __init__(self):
pass self.requires = []
self.required = False
def __str__(self): def __str__(self):
raise NotImplementedError raise NotImplementedError
def require(self):
self.required = True
for require in self.requires:
if require.required:
continue
require.require()
class RawExpression(Expression): class RawExpression(Expression):
def __init__(self, text): def __init__(self, text):
@ -60,15 +67,22 @@ class RawExpression(Expression):
return self.text return self.text
# pylint: disable=redefined-builtin
class AssignmentExpression(Expression): class AssignmentExpression(Expression):
def __init__(self, lhs, rhs, obj): def __init__(self, type, modifier, name, rhs, obj):
super(AssignmentExpression, self).__init__() super(AssignmentExpression, self).__init__()
self.obj = obj self.type = type
self.lhs = safe_exp(lhs) self.modifier = modifier
self.name = name
self.rhs = safe_exp(rhs) self.rhs = safe_exp(rhs)
self.requires.append(self.rhs)
self.obj = obj
def __str__(self): def __str__(self):
return u"{} = {}".format(self.lhs, self.rhs) type_ = self.type
if core.SIMPLIFY:
type_ = u'auto'
return u"{} {}{} = {}".format(type_, self.modifier, self.name, self.rhs)
class ExpressionList(Expression): class ExpressionList(Expression):
@ -78,7 +92,11 @@ class ExpressionList(Expression):
args = list(args) args = list(args)
while args and args[-1] is None: while args and args[-1] is None:
args.pop() args.pop()
self.args = [safe_exp(x) for x in args] self.args = []
for arg in args:
exp = safe_exp(arg)
self.requires.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(unicode(x) for x in self.args)
@ -90,6 +108,7 @@ class CallExpression(Expression):
super(CallExpression, self).__init__() super(CallExpression, self).__init__()
self.base = base self.base = base
self.args = ExpressionList(*args) self.args = ExpressionList(*args)
self.requires.append(self.args)
def __str__(self): def __str__(self):
return u'{}({})'.format(self.base, self.args) return u'{}({})'.format(self.base, self.args)
@ -103,8 +122,11 @@ class StructInitializer(Expression):
args = OrderedDict(args) args = OrderedDict(args)
self.args = OrderedDict() self.args = OrderedDict()
for key, value in args.iteritems(): for key, value in args.iteritems():
if value is not None: if value is None:
self.args[key] = safe_exp(value) continue
exp = safe_exp(value)
self.args[key] = exp
self.requires.append(exp)
def __str__(self): def __str__(self):
cpp = u'{}{{\n'.format(self.base) cpp = u'{}{{\n'.format(self.base)
@ -115,17 +137,27 @@ class StructInitializer(Expression):
class ArrayInitializer(Expression): class ArrayInitializer(Expression):
def __init__(self, *args): def __init__(self, *args, **kwargs):
super(ArrayInitializer, self).__init__() super(ArrayInitializer, self).__init__()
self.args = [safe_exp(x) for x in args if x is not None] self.multiline = kwargs.get('multiline', True)
self.args = []
for arg in args:
if arg is None:
continue
exp = safe_exp(arg)
self.args.append(exp)
self.requires.append(exp)
def __str__(self): def __str__(self):
if not self.args: if not self.args:
return u'{}' return u'{}'
if self.multiline:
cpp = u'{\n' cpp = u'{\n'
for arg in self.args: for arg in self.args:
cpp += u' {},\n'.format(arg) cpp += u' {},\n'.format(arg)
cpp += u'}' cpp += u'}'
else:
cpp = u'{' + u', '.join(str(arg) for arg in self.args) + u'}'
return cpp return cpp
@ -227,20 +259,22 @@ def statement(expression):
# pylint: disable=redefined-builtin, invalid-name # pylint: disable=redefined-builtin, invalid-name
def variable(type, id, rhs): def variable(type, id, rhs):
lhs = RawExpression(u'{} {}'.format(type if not SIMPLIFY else u'auto', id))
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
obj = MockObj(id, u'.') obj = MockObj(id, u'.')
add(AssignmentExpression(lhs, rhs, obj)) assignment = AssignmentExpression(type, '', id, rhs, obj)
add(assignment)
_VARIABLES[id] = obj, type _VARIABLES[id] = obj, type
obj.requires.append(assignment)
return obj return obj
def Pvariable(type, id, rhs): def Pvariable(type, id, rhs):
lhs = RawExpression(u'{} *{}'.format(type if not SIMPLIFY else u'auto', id))
rhs = safe_exp(rhs) rhs = safe_exp(rhs)
obj = MockObj(id, u'->') obj = MockObj(id, u'->')
add(AssignmentExpression(lhs, rhs, obj)) assignment = AssignmentExpression(type, '*', id, rhs, obj)
add(assignment)
_VARIABLES[id] = obj, type _VARIABLES[id] = obj, type
obj.requires.append(assignment)
return obj return obj
@ -272,7 +306,6 @@ def get_variable(id, type=None):
if result is None: if result is None:
raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type {}".format(id, type)) raise ESPHomeYAMLError(u"Couldn't find ID '{}' with type {}".format(id, type))
result.usages += 1
return result return result
@ -280,17 +313,17 @@ def add_task(func, config):
_QUEUE.append((func, config)) _QUEUE.append((func, config))
def add(expression): def add(expression, require=True):
if require and isinstance(expression, Expression):
expression.require()
_EXPRESSIONS.append(expression) _EXPRESSIONS.append(expression)
return expression return expression
class MockObj(Expression): class MockObj(Expression):
def __init__(self, base, op=u'.', parent=None): def __init__(self, base, op=u'.'):
self.base = base self.base = base
self.op = op self.op = op
self.usages = 0
self.parent = parent
super(MockObj, self).__init__() super(MockObj, self).__init__()
def __getattr__(self, attr): def __getattr__(self, attr):
@ -299,18 +332,26 @@ class MockObj(Expression):
attr = attr[1:] attr = attr[1:]
next_op = u'->' next_op = u'->'
op = self.op op = self.op
return MockObj(u'{}{}{}'.format(self.base, op, attr), next_op, self) obj = MockObj(u'{}{}{}'.format(self.base, op, attr), next_op)
obj.requires.append(self)
return obj
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
self.usages += 1 call = CallExpression(self.base, *args)
it = self.parent obj = MockObj(call, self.op)
while it is not None: obj.requires.append(self)
it.usages += 1 obj.requires.append(call)
it = it.parent return obj
return CallExpression(self.base, *args)
def __str__(self): def __str__(self):
return self.base return unicode(self.base)
def require(self):
self.required = True
for require in self.requires:
if require.required:
continue
require.require()
App = MockObj(u'App') App = MockObj(u'App')
@ -358,13 +399,8 @@ def setup_mqtt_component(obj, config):
add(obj.set_custom_command_topic(config[CONF_COMMAND_TOPIC])) add(obj.set_custom_command_topic(config[CONF_COMMAND_TOPIC]))
if CONF_AVAILABILITY in config: if CONF_AVAILABILITY in config:
availability = config[CONF_AVAILABILITY] availability = config[CONF_AVAILABILITY]
exp = StructInitializer( add(obj.set_availability(availability[CONF_TOPIC], availability[CONF_PAYLOAD_AVAILABLE],
u'mqtt::Availability', availability[CONF_PAYLOAD_NOT_AVAILABLE]))
(u'topic', availability[CONF_TOPIC]),
(u'payload_available', availability[CONF_PAYLOAD_AVAILABLE]),
(u'payload_not_available', availability[CONF_PAYLOAD_NOT_AVAILABLE]),
)
add(obj.set_availability(exp))
def exp_empty_optional(type): def exp_empty_optional(type):

View file

@ -1,13 +1,17 @@
from __future__ import print_function from __future__ import print_function
import hashlib
import logging import logging
from datetime import datetime from datetime import datetime
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
from esphomeyaml.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOMEYAML, CONF_LOGGER, \ from esphomeyaml import core
CONF_LOG_TOPIC, CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \ from esphomeyaml.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOMEYAML, \
CONF_LOG_TOPIC, \
CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \
CONF_USERNAME CONF_USERNAME
from esphomeyaml.helpers import color
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -38,16 +42,21 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
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):
if topic is not None: if topic is not None:
pass # already have topic pass # already have topic
elif CONF_LOG_TOPIC in config.get(CONF_LOGGER, {}): elif CONF_MQTT in config:
topic = config[CONF_LOGGER][CONF_LOG_TOPIC] conf = config[CONF_MQTT]
if CONF_LOG_TOPIC in conf:
topic = config[CONF_MQTT][CONF_LOG_TOPIC]
elif CONF_TOPIC_PREFIX in config[CONF_MQTT]: elif CONF_TOPIC_PREFIX in config[CONF_MQTT]:
topic = config[CONF_MQTT][CONF_TOPIC_PREFIX] + u'/debug' topic = config[CONF_MQTT][CONF_TOPIC_PREFIX] + u'/debug'
else: else:
topic = config[CONF_ESPHOMEYAML][CONF_NAME] + u'/debug' topic = config[CONF_ESPHOMEYAML][CONF_NAME] + u'/debug'
else:
_LOGGER.error(u"MQTT isn't setup, can't start MQTT logs")
return 1
_LOGGER.info(u"Starting log output from %s", topic) _LOGGER.info(u"Starting log output from %s", topic)
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) print(time + msg.payload)
return initialize(config, [topic], on_message, username, password, client_id) return initialize(config, [topic], on_message, username, password, client_id)
@ -67,3 +76,23 @@ def clear_topic(config, topic, username=None, password=None, client_id=None):
client.publish(msg.topic, None, retain=True) client.publish(msg.topic, None, retain=True)
return initialize(config, [topic], on_message, username, password, client_id) return initialize(config, [topic], on_message, username, password, client_id)
# From marvinroger/async-mqtt-client -> scripts/get-fingerprint/get-fingerprint.py
def get_fingerprint(config):
import ssl
addr = config[CONF_MQTT][CONF_BROKER], config[CONF_MQTT][CONF_PORT]
_LOGGER.info("Getting fingerprint from %s:%s", addr[0], addr[1])
try:
cert_pem = ssl.get_server_certificate(addr)
except IOError as err:
_LOGGER.error("Unable to connect to server: %s", err)
return 1
cert_der = ssl.PEM_cert_to_DER_cert(cert_pem)
sha1 = hashlib.sha1(cert_der).hexdigest()
print(u"SHA1 Fingerprint: " + color('cyan', sha1))
print(u"Copy above string into mqtt.ssl_fingerprints section of {}".format(core.CONFIG_PATH))
return 0

View file

@ -3,6 +3,7 @@ import logging
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml import core
from esphomeyaml.const import ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, CONF_NUMBER, CONF_MODE, \ from esphomeyaml.const import ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266, CONF_NUMBER, CONF_MODE, \
CONF_INVERTED CONF_INVERTED
@ -72,32 +73,32 @@ def _translate_pin(value):
pass pass
if value.startswith('GPIO'): if value.startswith('GPIO'):
return vol.Coerce(int)(value[len('GPIO'):]) return vol.Coerce(int)(value[len('GPIO'):])
if cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
if value in ESP32_PINS: if value in ESP32_PINS:
return ESP32_PINS[value] return ESP32_PINS[value]
if cv.BOARD not in ESP32_BOARD_TO_PINS: if core.BOARD not in ESP32_BOARD_TO_PINS:
raise vol.Invalid(u"ESP32: Unknown board {} with unknown " raise vol.Invalid(u"ESP32: Unknown board {} with unknown "
u"pin {}.".format(cv.BOARD, value)) u"pin {}.".format(core.BOARD, value))
if value not in ESP32_BOARD_TO_PINS[cv.BOARD]: if value not in ESP32_BOARD_TO_PINS[core.BOARD]:
raise vol.Invalid(u"ESP32: Board {} doesn't have" raise vol.Invalid(u"ESP32: Board {} doesn't have"
u"pin {}".format(cv.BOARD, value)) u"pin {}".format(core.BOARD, value))
return ESP32_BOARD_TO_PINS[cv.BOARD][value] return ESP32_BOARD_TO_PINS[core.BOARD][value]
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
if value in ESP8266_PINS: if value in ESP8266_PINS:
return ESP8266_PINS[value] return ESP8266_PINS[value]
if cv.BOARD not in ESP8266_BOARD_TO_PINS: if core.BOARD not in ESP8266_BOARD_TO_PINS:
raise vol.Invalid(u"ESP8266: Unknown board {} with unknown " raise vol.Invalid(u"ESP8266: Unknown board {} with unknown "
u"pin {}.".format(cv.BOARD, value)) u"pin {}.".format(core.BOARD, value))
if value not in ESP8266_BOARD_TO_PINS[cv.BOARD]: if value not in ESP8266_BOARD_TO_PINS[core.BOARD]:
raise vol.Invalid(u"ESP8266: Board {} doesn't have" raise vol.Invalid(u"ESP8266: Board {} doesn't have"
u"pin {}".format(cv.BOARD, value)) u"pin {}".format(core.BOARD, value))
return ESP8266_BOARD_TO_PINS[cv.BOARD][value] return ESP8266_BOARD_TO_PINS[core.BOARD][value]
raise vol.Invalid(u"Invalid ESP platform.") raise vol.Invalid(u"Invalid ESP platform.")
def _validate_gpio_pin(value): def _validate_gpio_pin(value):
value = _translate_pin(value) value = _translate_pin(value)
if cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
if value < 0 or value > 39: if value < 0 or value > 39:
raise vol.Invalid(u"ESP32: Invalid pin number: {}".format(value)) raise vol.Invalid(u"ESP32: Invalid pin number: {}".format(value))
if 6 <= value <= 11: if 6 <= value <= 11:
@ -107,7 +108,7 @@ def _validate_gpio_pin(value):
_LOGGER.warning(u"ESP32: Pin %s (20, 24, 28-31) can usually not be used. " _LOGGER.warning(u"ESP32: Pin %s (20, 24, 28-31) can usually not be used. "
u"Be warned.", value) u"Be warned.", value)
return value return value
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
if 6 <= value <= 11: if 6 <= value <= 11:
_LOGGER.warning(u"ESP8266: Pin %s (6-11) might already be used by the " _LOGGER.warning(u"ESP8266: Pin %s (6-11) might already be used by the "
u"flash interface. Be warned.", value) u"flash interface. Be warned.", value)
@ -119,21 +120,21 @@ def _validate_gpio_pin(value):
def input_pin(value): def input_pin(value):
value = _validate_gpio_pin(value) value = _validate_gpio_pin(value)
if cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
return value return value
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
return value return value
raise vol.Invalid(u"Invalid ESP platform.") raise vol.Invalid(u"Invalid ESP platform.")
def output_pin(value): def output_pin(value):
value = _validate_gpio_pin(value) value = _validate_gpio_pin(value)
if cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
if 34 <= value <= 39: if 34 <= value <= 39:
raise vol.Invalid(u"ESP32: Pin {} (34-39) can only be used as " raise vol.Invalid(u"ESP32: Pin {} (34-39) can only be used as "
u"input pins.".format(value)) u"input pins.".format(value))
return value return value
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
if value == 16: if value == 16:
raise vol.Invalid(u"Pin {} doesn't support output mode".format(value)) raise vol.Invalid(u"Pin {} doesn't support output mode".format(value))
return value return value
@ -142,11 +143,11 @@ def output_pin(value):
def analog_pin(value): def analog_pin(value):
value = _validate_gpio_pin(value) value = _validate_gpio_pin(value)
if cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
if 32 <= value <= 39: # ADC1 if 32 <= value <= 39: # ADC1
return value return value
raise vol.Invalid(u"ESP32: Only pins 32 though 39 support ADC.") raise vol.Invalid(u"ESP32: Only pins 32 though 39 support ADC.")
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
if value == 17: # A0 if value == 17: # A0
return value return value
raise vol.Invalid(u"ESP8266: Only pin A0 (17) supports ADC.") raise vol.Invalid(u"ESP8266: Only pin A0 (17) supports ADC.")
@ -171,9 +172,9 @@ 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 cv.ESP_PLATFORM == ESP_PLATFORM_ESP32: if core.ESP_PLATFORM == ESP_PLATFORM_ESP32:
return vol.Any(*PIN_MODES_ESP32)(value) return vol.Any(*PIN_MODES_ESP32)(value)
elif cv.ESP_PLATFORM == ESP_PLATFORM_ESP8266: elif core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:
return vol.Any(*PIN_MODES_ESP8266)(value) return vol.Any(*PIN_MODES_ESP8266)(value)
raise vol.Invalid(u"Invalid ESP platform.") raise vol.Invalid(u"Invalid ESP platform.")
@ -195,3 +196,14 @@ GPIO_INPUT_PIN_SCHEMA = vol.Any(input_pin, vol.Schema({
vol.Optional(CONF_MODE): pin_mode, vol.Optional(CONF_MODE): pin_mode,
vol.Optional(CONF_INVERTED): cv.boolean, vol.Optional(CONF_INVERTED): cv.boolean,
})) }))
def schema_validate_number(validator):
def valid(value):
if isinstance(value, dict):
value[CONF_NUMBER] = validator(value[CONF_NUMBER])
else:
value = validator(value)
return value
return valid

View file

@ -4,9 +4,9 @@ import codecs
import errno import errno
import os import os
from esphomeyaml.config import get_component from esphomeyaml.config import iter_components
from esphomeyaml.const import CONF_BOARD, CONF_ESPHOMEYAML, CONF_LIBRARY_URI, CONF_LOGGER, \ from esphomeyaml.const import CONF_BOARD, CONF_ESPHOMEYAML, CONF_LIBRARY_URI, CONF_NAME, \
CONF_NAME, CONF_PLATFORM, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 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 ==========='
@ -52,7 +52,8 @@ framework = arduino
lib_deps = lib_deps =
{esphomeyaml_uri} {esphomeyaml_uri}
${{common.lib_deps}} ${{common.lib_deps}}
build_flags ={build_flags} build_flags =
{build_flags}
${{common.build_flags}} ${{common.build_flags}}
""" """
@ -62,18 +63,41 @@ PLATFORM_TO_PLATFORMIO = {
} }
def get_build_flags(config, key):
build_flags = set()
for _, component, conf in iter_components(config):
if not hasattr(component, key):
continue
flags = getattr(component, key)(conf)
if flags is None:
continue
if isinstance(flags, (str, unicode)):
flags = [flags]
build_flags |= set(flags)
return build_flags
def get_ini_content(config): def get_ini_content(config):
platform = config[CONF_ESPHOMEYAML][CONF_PLATFORM]
if platform in PLATFORM_TO_PLATFORMIO:
platform = PLATFORM_TO_PLATFORMIO[platform]
options = { options = {
u'env': config[CONF_ESPHOMEYAML][CONF_NAME], u'env': config[CONF_ESPHOMEYAML][CONF_NAME],
u'platform': PLATFORM_TO_PLATFORMIO[config[CONF_ESPHOMEYAML][CONF_PLATFORM]], u'platform': platform,
u'board': config[CONF_ESPHOMEYAML][CONF_BOARD], u'board': config[CONF_ESPHOMEYAML][CONF_BOARD],
u'esphomeyaml_uri': config[CONF_ESPHOMEYAML][CONF_LIBRARY_URI], u'esphomeyaml_uri': config[CONF_ESPHOMEYAML][CONF_LIBRARY_URI],
u'build_flags': u'', u'build_flags': u'',
} }
if CONF_LOGGER in config: build_flags = set()
build_flags = get_component(CONF_LOGGER).get_build_flags(config[CONF_LOGGER]) if config[CONF_ESPHOMEYAML][CONF_USE_BUILD_FLAGS]:
build_flags |= get_build_flags(config, 'build_flags')
build_flags.add(u"-DESPHOMEYAML_USE")
build_flags |= get_build_flags(config, 'required_build_flags')
# avoid changing build flags order
build_flags = sorted(list(build_flags))
if build_flags: if build_flags:
options[u'build_flags'] = u'\n ' + build_flags options[u'build_flags'] = u'\n '.join(build_flags)
return INI_CONTENT_FORMAT.format(**options) return INI_CONTENT_FORMAT.format(**options)

View file

@ -1,9 +1,10 @@
from __future__ import print_function from __future__ import print_function
import codecs import codecs
import fnmatch import fnmatch
import logging import logging
from collections import OrderedDict
import os import os
from collections import OrderedDict
import yaml import yaml
@ -79,9 +80,8 @@ def _ordered_dict(loader, node):
if key in seen: if key in seen:
fname = getattr(loader.stream, 'name', '') fname = getattr(loader.stream, 'name', '')
_LOGGER.error( raise ESPHomeYAMLError(u'YAML file {} contains duplicate key "{}". '
u'YAML file %s contains duplicate key "%s". ' u'Check lines {} and {}.'.format(fname, key, seen[key], line))
u'Check lines %d and %d.', fname, key, seen[key], line)
seen[key] = line seen[key] = line
return _add_reference(OrderedDict(nodes), loader, node) return _add_reference(OrderedDict(nodes), loader, node)