mirror of
https://github.com/esphome/esphome.git
synced 2025-09-23 05:32:22 +01:00
Add native ESPHome API (#265)
* Esphomeapi * Updates * Remove MQTT from wizard * Add protobuf to requirements * Fix * API Client updates * Dump config on API connect * Old WiFi config migration * Home Assistant state import * Lint
This commit is contained in:
85
esphomeyaml/components/api.py
Normal file
85
esphomeyaml/components/api.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import voluptuous as vol
|
||||
|
||||
from esphomeyaml.automation import ACTION_REGISTRY
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_DATA, CONF_DATA_TEMPLATE, CONF_ID, CONF_PASSWORD, CONF_PORT, \
|
||||
CONF_SERVICE, CONF_VARIABLES
|
||||
from esphomeyaml.core import CORE
|
||||
from esphomeyaml.cpp_generator import ArrayInitializer, Pvariable, add, get_variable, process_lambda
|
||||
from esphomeyaml.cpp_helpers import setup_component
|
||||
from esphomeyaml.cpp_types import Action, App, Component, StoringController, esphomelib_ns
|
||||
|
||||
api_ns = esphomelib_ns.namespace('api')
|
||||
APIServer = api_ns.class_('APIServer', Component, StoringController)
|
||||
HomeAssistantServiceCallAction = api_ns.class_('HomeAssistantServiceCallAction', Action)
|
||||
KeyValuePair = api_ns.class_('KeyValuePair')
|
||||
TemplatableKeyValuePair = api_ns.class_('TemplatableKeyValuePair')
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(APIServer),
|
||||
vol.Optional(CONF_PORT, default=6053): cv.port,
|
||||
vol.Optional(CONF_PASSWORD, default=''): cv.string_strict,
|
||||
}).extend(cv.COMPONENT_SCHEMA.schema)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.init_api_server()
|
||||
api = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if config[CONF_PORT] != 6053:
|
||||
add(api.set_port(config[CONF_PORT]))
|
||||
if config.get(CONF_PASSWORD):
|
||||
add(api.set_password(config[CONF_PASSWORD]))
|
||||
|
||||
setup_component(api, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_API'
|
||||
|
||||
|
||||
def lib_deps(config):
|
||||
if CORE.is_esp32:
|
||||
return 'AsyncTCP@1.0.1'
|
||||
elif CORE.is_esp8266:
|
||||
return 'ESPAsyncTCP@1.1.3'
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
CONF_HOMEASSISTANT_SERVICE = 'homeassistant.service'
|
||||
LOGGER_LOG_ACTION_SCHEMA = vol.Schema({
|
||||
cv.GenerateID(): cv.use_variable_id(APIServer),
|
||||
vol.Required(CONF_SERVICE): cv.string,
|
||||
vol.Optional(CONF_DATA): vol.Schema({
|
||||
cv.string: cv.string,
|
||||
}),
|
||||
vol.Optional(CONF_DATA_TEMPLATE): vol.Schema({
|
||||
cv.string: cv.string,
|
||||
}),
|
||||
vol.Optional(CONF_VARIABLES): vol.Schema({
|
||||
cv.string: cv.lambda_,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@ACTION_REGISTRY.register(CONF_HOMEASSISTANT_SERVICE, LOGGER_LOG_ACTION_SCHEMA)
|
||||
def homeassistant_service_to_code(config, action_id, arg_type, template_arg):
|
||||
for var in get_variable(config[CONF_ID]):
|
||||
yield None
|
||||
rhs = var.make_home_assistant_service_call_action(template_arg)
|
||||
type = HomeAssistantServiceCallAction.template(arg_type)
|
||||
act = Pvariable(action_id, rhs, type=type)
|
||||
add(act.set_service(config[CONF_SERVICE]))
|
||||
if CONF_DATA in config:
|
||||
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA].items()]
|
||||
add(act.set_data(ArrayInitializer(*datas)))
|
||||
if CONF_DATA_TEMPLATE in config:
|
||||
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA_TEMPLATE].items()]
|
||||
add(act.set_data_template(ArrayInitializer(*datas)))
|
||||
if CONF_VARIABLES in config:
|
||||
datas = []
|
||||
for key, value in config[CONF_VARIABLES].items():
|
||||
for value_ in process_lambda(value, []):
|
||||
yield None
|
||||
datas.append(TemplatableKeyValuePair(key, value_))
|
||||
add(act.set_variables(ArrayInitializer(*datas)))
|
||||
yield act
|
@@ -9,7 +9,7 @@ from esphomeyaml.const import CONF_DELAYED_OFF, CONF_DELAYED_ON, CONF_DEVICE_CLA
|
||||
CONF_HEARTBEAT, CONF_ID, CONF_INTERNAL, CONF_INVALID_COOLDOWN, CONF_INVERT, CONF_INVERTED, \
|
||||
CONF_LAMBDA, CONF_MAX_LENGTH, CONF_MIN_LENGTH, CONF_MQTT_ID, CONF_ON_CLICK, \
|
||||
CONF_ON_DOUBLE_CLICK, CONF_ON_MULTI_CLICK, CONF_ON_PRESS, CONF_ON_RELEASE, CONF_STATE, \
|
||||
CONF_TIMING, CONF_TRIGGER_ID
|
||||
CONF_TIMING, CONF_TRIGGER_ID, CONF_ON_STATE
|
||||
from esphomeyaml.core import CORE
|
||||
from esphomeyaml.cpp_generator import process_lambda, ArrayInitializer, add, Pvariable, \
|
||||
StructInitializer, get_variable
|
||||
@@ -38,6 +38,7 @@ ClickTrigger = binary_sensor_ns.class_('ClickTrigger', Trigger.template(NoArg))
|
||||
DoubleClickTrigger = binary_sensor_ns.class_('DoubleClickTrigger', Trigger.template(NoArg))
|
||||
MultiClickTrigger = binary_sensor_ns.class_('MultiClickTrigger', Trigger.template(NoArg), Component)
|
||||
MultiClickTriggerEvent = binary_sensor_ns.struct('MultiClickTriggerEvent')
|
||||
StateTrigger = binary_sensor_ns.class_('StateTrigger', Trigger.template(bool_))
|
||||
|
||||
# Condition
|
||||
BinarySensorCondition = binary_sensor_ns.class_('BinarySensorCondition', Condition)
|
||||
@@ -53,13 +54,13 @@ LambdaFilter = binary_sensor_ns.class_('LambdaFilter', Filter)
|
||||
|
||||
FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA, CONF_HEARTBEAT]
|
||||
|
||||
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
FILTERS_SCHEMA = cv.ensure_list({
|
||||
vol.Optional(CONF_INVERT): None,
|
||||
vol.Optional(CONF_DELAYED_ON): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_DELAYED_OFF): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
}, cv.has_exactly_one_key(*FILTER_KEYS))])
|
||||
}, cv.has_exactly_one_key(*FILTER_KEYS))
|
||||
|
||||
MULTI_CLICK_TIMING_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_STATE): cv.boolean,
|
||||
@@ -181,6 +182,9 @@ BINARY_SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend({
|
||||
validate_multi_click_timing),
|
||||
vol.Optional(CONF_INVALID_COOLDOWN): cv.positive_time_period_milliseconds,
|
||||
}),
|
||||
vol.Optional(CONF_ON_STATE): automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(StateTrigger),
|
||||
}),
|
||||
|
||||
vol.Optional(CONF_INVERTED): cv.invalid(
|
||||
"The inverted binary_sensor property has been replaced by the "
|
||||
@@ -268,6 +272,11 @@ def setup_binary_sensor_core_(binary_sensor_var, mqtt_var, config):
|
||||
add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN]))
|
||||
automation.build_automation(trigger, NoArg, conf)
|
||||
|
||||
for conf in config.get(CONF_ON_STATE, []):
|
||||
rhs = binary_sensor_var.make_state_trigger()
|
||||
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
|
||||
automation.build_automation(trigger, bool_, conf)
|
||||
|
||||
setup_mqtt_component(mqtt_var, config)
|
||||
|
||||
|
||||
|
@@ -13,9 +13,9 @@ PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomBinarySensorConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Required(CONF_BINARY_SENSORS):
|
||||
vol.All(cv.ensure_list, [binary_sensor.BINARY_SENSOR_SCHEMA.extend({
|
||||
cv.ensure_list(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(binary_sensor.BinarySensor),
|
||||
})]),
|
||||
})),
|
||||
})
|
||||
|
||||
|
||||
|
@@ -5,7 +5,6 @@ from esphomeyaml.cpp_generator import variable
|
||||
from esphomeyaml.cpp_helpers import setup_component
|
||||
from esphomeyaml.cpp_types import Application, Component, App
|
||||
|
||||
DEPENDENCIES = ['mqtt']
|
||||
|
||||
MakeStatusBinarySensor = Application.struct('MakeStatusBinarySensor')
|
||||
StatusBinarySensor = binary_sensor.binary_sensor_ns.class_('StatusBinarySensor',
|
||||
|
@@ -12,9 +12,9 @@ MULTI_CONF = True
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomComponentConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Optional(CONF_COMPONENTS): vol.All(cv.ensure_list, [vol.Schema({
|
||||
vol.Optional(CONF_COMPONENTS): cv.ensure_list(vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(Component)
|
||||
}).extend(cv.COMPONENT_SCHEMA.schema)]),
|
||||
}).extend(cv.COMPONENT_SCHEMA.schema)),
|
||||
})
|
||||
|
||||
|
||||
|
@@ -46,8 +46,7 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_WAKEUP_PIN_MODE): vol.All(cv.only_on_esp32,
|
||||
cv.one_of(*WAKEUP_PIN_MODES), upper=True),
|
||||
vol.Optional(CONF_ESP32_EXT1_WAKEUP): vol.All(cv.only_on_esp32, vol.Schema({
|
||||
vol.Required(CONF_PINS): vol.All(cv.ensure_list, [pins.shorthand_input_pin],
|
||||
[validate_pin_number]),
|
||||
vol.Required(CONF_PINS): cv.ensure_list(pins.shorthand_input_pin, validate_pin_number),
|
||||
vol.Required(CONF_MODE): cv.one_of(*EXT1_WAKEUP_MODES, upper=True),
|
||||
})),
|
||||
vol.Optional(CONF_RUN_CYCLES): cv.positive_int,
|
||||
|
23
esphomeyaml/components/interval.py
Normal file
23
esphomeyaml/components/interval.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import voluptuous as vol
|
||||
|
||||
from esphomeyaml import automation
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_ID
|
||||
from esphomeyaml.cpp_generator import Pvariable
|
||||
from esphomeyaml.cpp_helpers import setup_component
|
||||
from esphomeyaml.cpp_types import App, NoArg, PollingComponent, Trigger, esphomelib_ns
|
||||
|
||||
IntervalTrigger = esphomelib_ns.class_('IntervalTrigger', Trigger.template(NoArg), PollingComponent)
|
||||
|
||||
CONFIG_SCHEMA = automation.validate_automation(vol.Schema({
|
||||
vol.Required(CONF_ID): cv.declare_variable_id(IntervalTrigger),
|
||||
}).extend(cv.COMPONENT_SCHEMA.schema))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
for conf in config:
|
||||
rhs = App.register_component(IntervalTrigger.new())
|
||||
trigger = Pvariable(conf[CONF_ID], rhs)
|
||||
setup_component(trigger, conf)
|
||||
|
||||
automation.build_automation(trigger, NoArg, conf)
|
@@ -100,7 +100,7 @@ EFFECTS_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_STROBE): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(StrobeLightEffect),
|
||||
vol.Optional(CONF_NAME, default="Strobe"): cv.string,
|
||||
vol.Optional(CONF_COLORS): vol.All(cv.ensure_list, [vol.All(vol.Schema({
|
||||
vol.Optional(CONF_COLORS): vol.All(cv.ensure_list(vol.Schema({
|
||||
vol.Optional(CONF_STATE, default=True): cv.boolean,
|
||||
vol.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_RED, default=1.0): cv.percentage,
|
||||
@@ -109,7 +109,7 @@ EFFECTS_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_WHITE, default=1.0): cv.percentage,
|
||||
vol.Required(CONF_DURATION): cv.positive_time_period_milliseconds,
|
||||
}), cv.has_at_least_one_key(CONF_STATE, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE,
|
||||
CONF_WHITE))], vol.Length(min=2)),
|
||||
CONF_WHITE)), vol.Length(min=2)),
|
||||
}),
|
||||
vol.Optional(CONF_FLICKER): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FlickerLightEffect),
|
||||
@@ -131,13 +131,13 @@ EFFECTS_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_FASTLED_COLOR_WIPE): vol.Schema({
|
||||
cv.GenerateID(CONF_EFFECT_ID): cv.declare_variable_id(FastLEDColorWipeEffect),
|
||||
vol.Optional(CONF_NAME, default="Color Wipe"): cv.string,
|
||||
vol.Optional(CONF_COLORS): vol.All(cv.ensure_list, [vol.Schema({
|
||||
vol.Optional(CONF_COLORS): cv.ensure_list({
|
||||
vol.Optional(CONF_RED, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_GREEN, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_BLUE, default=1.0): cv.percentage,
|
||||
vol.Optional(CONF_RANDOM, default=False): cv.boolean,
|
||||
vol.Required(CONF_NUM_LEDS): vol.All(cv.uint32_t, vol.Range(min=1)),
|
||||
})]),
|
||||
}),
|
||||
vol.Optional(CONF_ADD_LED_INTERVAL): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_REVERSE): cv.boolean,
|
||||
}),
|
||||
@@ -178,7 +178,8 @@ EFFECTS_SCHEMA = vol.Schema({
|
||||
def validate_effects(allowed_effects):
|
||||
def validator(value):
|
||||
is_list = isinstance(value, list)
|
||||
value = cv.ensure_list(value)
|
||||
if not is_list:
|
||||
value = [value]
|
||||
names = set()
|
||||
ret = []
|
||||
for i, effect in enumerate(value):
|
||||
@@ -471,10 +472,10 @@ def light_turn_on_to_code(config, action_id, arg_type, template_arg):
|
||||
|
||||
def core_to_hass_config(data, config, brightness=True, rgb=True, color_temp=True,
|
||||
white_value=True):
|
||||
ret = mqtt.build_hass_config(data, 'light', config, include_state=True, include_command=True,
|
||||
platform='mqtt_json')
|
||||
ret = mqtt.build_hass_config(data, 'light', config, include_state=True, include_command=True)
|
||||
if ret is None:
|
||||
return None
|
||||
ret['schema'] = 'json'
|
||||
if brightness:
|
||||
ret['brightness'] = True
|
||||
if rgb:
|
||||
|
@@ -108,7 +108,7 @@ def validate_printf(value):
|
||||
CONF_LOGGER_LOG = 'logger.log'
|
||||
LOGGER_LOG_ACTION_SCHEMA = vol.All(maybe_simple_message({
|
||||
vol.Required(CONF_FORMAT): cv.string,
|
||||
vol.Optional(CONF_ARGS, default=list): vol.All(cv.ensure_list, [cv.lambda_]),
|
||||
vol.Optional(CONF_ARGS, default=list): cv.ensure_list(cv.lambda_),
|
||||
vol.Optional(CONF_LEVEL, default="DEBUG"): cv.one_of(*LOG_LEVEL_TO_ESP_LOG, upper=True),
|
||||
vol.Optional(CONF_TAG, default="main"): cv.string,
|
||||
}), validate_printf)
|
||||
|
@@ -85,7 +85,7 @@ CONFIG_SCHEMA = vol.All(vol.Schema({
|
||||
vol.Optional(CONF_LEVEL): logger.is_log_level,
|
||||
}), validate_message_just_topic),
|
||||
vol.Optional(CONF_SSL_FINGERPRINTS): vol.All(cv.only_on_esp8266,
|
||||
cv.ensure_list, [validate_fingerprint]),
|
||||
cv.ensure_list(validate_fingerprint)),
|
||||
vol.Optional(CONF_KEEPALIVE): cv.positive_time_period_seconds,
|
||||
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_ON_MESSAGE): automation.validate_automation({
|
||||
@@ -260,12 +260,11 @@ def get_default_topic_for(data, component_type, name, suffix):
|
||||
sanitized_name, suffix)
|
||||
|
||||
|
||||
def build_hass_config(data, component_type, config, include_state=True, include_command=True,
|
||||
platform='mqtt'):
|
||||
def build_hass_config(data, component_type, config, include_state=True, include_command=True):
|
||||
if config.get(CONF_INTERNAL, False):
|
||||
return None
|
||||
ret = OrderedDict()
|
||||
ret['platform'] = platform
|
||||
ret['platform'] = 'mqtt'
|
||||
ret['name'] = config[CONF_NAME]
|
||||
if include_state:
|
||||
default = get_default_topic_for(data, component_type, config[CONF_NAME], 'state')
|
||||
|
@@ -13,18 +13,18 @@ BINARY_SCHEMA = output.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomBinaryOutputConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Required(CONF_OUTPUTS):
|
||||
vol.All(cv.ensure_list, [output.BINARY_OUTPUT_SCHEMA.extend({
|
||||
cv.ensure_list(output.BINARY_OUTPUT_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(output.BinaryOutput),
|
||||
})]),
|
||||
})),
|
||||
})
|
||||
|
||||
FLOAT_SCHEMA = output.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomFloatOutputConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Required(CONF_OUTPUTS):
|
||||
vol.All(cv.ensure_list, [output.FLOAT_OUTPUT_PLATFORM_SCHEMA.extend({
|
||||
cv.ensure_list(output.FLOAT_OUTPUT_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(output.FloatOutput),
|
||||
})]),
|
||||
})),
|
||||
})
|
||||
|
||||
|
||||
|
@@ -41,8 +41,7 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(RemoteReceiverComponent),
|
||||
vol.Required(CONF_PIN): pins.gpio_input_pin_schema,
|
||||
vol.Optional(CONF_DUMP, default=[]):
|
||||
vol.Any(validate_dumpers_all,
|
||||
vol.All(cv.ensure_list, [cv.one_of(*DUMPERS, lower=True)])),
|
||||
vol.Any(validate_dumpers_all, cv.ensure_list(cv.one_of(*DUMPERS, lower=True))),
|
||||
vol.Optional(CONF_TOLERANCE): vol.All(cv.percentage_int, vol.Range(min=0)),
|
||||
vol.Optional(CONF_BUFFER_SIZE): cv.validate_bytes,
|
||||
vol.Optional(CONF_FILTER): cv.positive_time_period_microseconds,
|
||||
|
@@ -40,7 +40,7 @@ FILTER_KEYS = [CONF_OFFSET, CONF_MULTIPLY, CONF_FILTER_OUT, CONF_FILTER_NAN,
|
||||
CONF_SLIDING_WINDOW_MOVING_AVERAGE, CONF_EXPONENTIAL_MOVING_AVERAGE, CONF_LAMBDA,
|
||||
CONF_THROTTLE, CONF_DELTA, CONF_UNIQUE, CONF_HEARTBEAT, CONF_DEBOUNCE, CONF_OR]
|
||||
|
||||
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
FILTERS_SCHEMA = cv.ensure_list({
|
||||
vol.Optional(CONF_OFFSET): cv.float_,
|
||||
vol.Optional(CONF_MULTIPLY): cv.float_,
|
||||
vol.Optional(CONF_FILTER_OUT): cv.float_,
|
||||
@@ -61,7 +61,7 @@ FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
|
||||
vol.Optional(CONF_HEARTBEAT): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_DEBOUNCE): cv.positive_time_period_milliseconds,
|
||||
vol.Optional(CONF_OR): validate_recursive_filter,
|
||||
}, cv.has_exactly_one_key(*FILTER_KEYS))])
|
||||
}, cv.has_exactly_one_key(*FILTER_KEYS))
|
||||
|
||||
# Base
|
||||
sensor_ns = esphomelib_ns.namespace('sensor')
|
||||
|
@@ -11,9 +11,9 @@ CustomSensorConstructor = sensor.sensor_ns.class_('CustomSensorConstructor')
|
||||
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomSensorConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Required(CONF_SENSORS): vol.All(cv.ensure_list, [sensor.SENSOR_SCHEMA.extend({
|
||||
vol.Required(CONF_SENSORS): cv.ensure_list(sensor.SENSOR_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(sensor.Sensor),
|
||||
})]),
|
||||
})),
|
||||
})
|
||||
|
||||
|
||||
|
32
esphomeyaml/components/sensor/homeassistant.py
Normal file
32
esphomeyaml/components/sensor/homeassistant.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import voluptuous as vol
|
||||
|
||||
from esphomeyaml.components import sensor
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_ENTITY_ID, CONF_MAKE_ID, CONF_NAME
|
||||
from esphomeyaml.cpp_generator import variable
|
||||
from esphomeyaml.cpp_types import App, Application
|
||||
|
||||
DEPENDENCIES = ['api']
|
||||
|
||||
MakeHomeassistantSensor = Application.struct('MakeHomeassistantSensor')
|
||||
HomeassistantSensor = sensor.sensor_ns.class_('HomeassistantSensor', sensor.Sensor)
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(HomeassistantSensor),
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHomeassistantSensor),
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_homeassistant_sensor(config[CONF_NAME], config[CONF_ENTITY_ID])
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
subs = make.Psensor
|
||||
sensor.setup_sensor(subs, make.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_SENSOR'
|
||||
|
||||
|
||||
def to_hass_config(data, config):
|
||||
return sensor.core_to_hass_config(data, config)
|
@@ -12,9 +12,9 @@ PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomSwitchConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Required(CONF_SWITCHES):
|
||||
vol.All(cv.ensure_list, [switch.SWITCH_SCHEMA.extend({
|
||||
cv.ensure_list(switch.SWITCH_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(switch.Switch),
|
||||
})]),
|
||||
})),
|
||||
})
|
||||
|
||||
|
||||
|
@@ -12,9 +12,9 @@ PLATFORM_SCHEMA = text_sensor.PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(CustomTextSensorConstructor),
|
||||
vol.Required(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Required(CONF_TEXT_SENSORS):
|
||||
vol.All(cv.ensure_list, [text_sensor.TEXT_SENSOR_SCHEMA.extend({
|
||||
cv.ensure_list(text_sensor.TEXT_SENSOR_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(text_sensor.TextSensor),
|
||||
})]),
|
||||
})),
|
||||
})
|
||||
|
||||
|
||||
|
33
esphomeyaml/components/text_sensor/homeassistant.py
Normal file
33
esphomeyaml/components/text_sensor/homeassistant.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import voluptuous as vol
|
||||
|
||||
from esphomeyaml.components import text_sensor
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_ENTITY_ID, CONF_MAKE_ID, CONF_NAME
|
||||
from esphomeyaml.cpp_generator import variable
|
||||
from esphomeyaml.cpp_types import App, Application, Component
|
||||
|
||||
DEPENDENCIES = ['api']
|
||||
|
||||
MakeHomeassistantTextSensor = Application.struct('MakeHomeassistantTextSensor')
|
||||
HomeassistantTextSensor = text_sensor.text_sensor_ns.class_('HomeassistantTextSensor',
|
||||
text_sensor.TextSensor, Component)
|
||||
|
||||
PLATFORM_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(HomeassistantTextSensor),
|
||||
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeHomeassistantTextSensor),
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
}))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_homeassistant_text_sensor(config[CONF_NAME], config[CONF_ENTITY_ID])
|
||||
make = variable(config[CONF_MAKE_ID], rhs)
|
||||
sensor_ = make.Psensor
|
||||
text_sensor.setup_text_sensor(sensor_, make.Pmqtt, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_TEXT_SENSOR'
|
||||
|
||||
|
||||
def to_hass_config(data, config):
|
||||
return text_sensor.core_to_hass_config(data, config)
|
25
esphomeyaml/components/time/homeassistant.py
Normal file
25
esphomeyaml/components/time/homeassistant.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from esphomeyaml.components import time as time_
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_ID
|
||||
from esphomeyaml.cpp_generator import Pvariable
|
||||
from esphomeyaml.cpp_helpers import setup_component
|
||||
from esphomeyaml.cpp_types import App
|
||||
|
||||
|
||||
DEPENDENCIES = ['api']
|
||||
|
||||
HomeAssistantTime = time_.time_ns.class_('HomeAssistantTime', time_.RealTimeClockComponent)
|
||||
|
||||
PLATFORM_SCHEMA = time_.TIME_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(HomeAssistantTime),
|
||||
}).extend(cv.COMPONENT_SCHEMA.schema)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.make_homeassistant_time_component()
|
||||
ha_time = Pvariable(config[CONF_ID], rhs)
|
||||
time_.setup_time(ha_time, config)
|
||||
setup_component(ha_time, config)
|
||||
|
||||
|
||||
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_TIME'
|
@@ -1,8 +1,8 @@
|
||||
import voluptuous as vol
|
||||
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.components import time as time_
|
||||
from esphomeyaml.const import CONF_ID, CONF_LAMBDA, CONF_SERVERS
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_ID, CONF_SERVERS
|
||||
from esphomeyaml.cpp_generator import Pvariable, add
|
||||
from esphomeyaml.cpp_helpers import setup_component
|
||||
from esphomeyaml.cpp_types import App
|
||||
@@ -11,8 +11,7 @@ SNTPComponent = time_.time_ns.class_('SNTPComponent', time_.RealTimeClockCompone
|
||||
|
||||
PLATFORM_SCHEMA = time_.TIME_PLATFORM_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(SNTPComponent),
|
||||
vol.Optional(CONF_SERVERS): vol.All(cv.ensure_list, [cv.domain], vol.Length(min=1, max=3)),
|
||||
vol.Optional(CONF_LAMBDA): cv.lambda_,
|
||||
vol.Optional(CONF_SERVERS): vol.All(cv.ensure_list(cv.domain), vol.Length(min=1, max=3)),
|
||||
}).extend(cv.COMPONENT_SCHEMA.schema)
|
||||
|
||||
|
||||
|
@@ -3,12 +3,25 @@ import voluptuous as vol
|
||||
import esphomeyaml.config_validation as cv
|
||||
from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, \
|
||||
CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_POWER_SAVE_MODE, \
|
||||
CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET
|
||||
from esphomeyaml.core import CORE
|
||||
from esphomeyaml.cpp_generator import Pvariable, StructInitializer, add
|
||||
CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, CONF_NETWORKS, CONF_BSSID
|
||||
from esphomeyaml.core import CORE, HexInt
|
||||
from esphomeyaml.cpp_generator import Pvariable, StructInitializer, add, variable, ArrayInitializer
|
||||
from esphomeyaml.cpp_types import App, Component, esphomelib_ns, global_ns
|
||||
|
||||
|
||||
IPAddress = global_ns.class_('IPAddress')
|
||||
ManualIP = esphomelib_ns.struct('ManualIP')
|
||||
WiFiComponent = esphomelib_ns.class_('WiFiComponent', Component)
|
||||
WiFiAP = esphomelib_ns.struct('WiFiAP')
|
||||
|
||||
WiFiPowerSaveMode = esphomelib_ns.enum('WiFiPowerSaveMode')
|
||||
WIFI_POWER_SAVE_MODES = {
|
||||
'NONE': WiFiPowerSaveMode.WIFI_POWER_SAVE_NONE,
|
||||
'LIGHT': WiFiPowerSaveMode.WIFI_POWER_SAVE_LIGHT,
|
||||
'HIGH': WiFiPowerSaveMode.WIFI_POWER_SAVE_HIGH,
|
||||
}
|
||||
|
||||
|
||||
def validate_password(value):
|
||||
value = cv.string(value)
|
||||
if not value:
|
||||
@@ -41,10 +54,11 @@ STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
|
||||
})
|
||||
|
||||
WIFI_NETWORK_BASE = vol.Schema({
|
||||
vol.Required(CONF_SSID): cv.ssid,
|
||||
cv.GenerateID(): cv.declare_variable_id(WiFiAP),
|
||||
vol.Optional(CONF_SSID): cv.ssid,
|
||||
vol.Optional(CONF_PASSWORD): validate_password,
|
||||
vol.Optional(CONF_CHANNEL): validate_channel,
|
||||
vol.Optional(CONF_MANUAL_IP): AP_MANUAL_IP_SCHEMA,
|
||||
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
|
||||
})
|
||||
|
||||
WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend({
|
||||
@@ -53,35 +67,39 @@ WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend({
|
||||
|
||||
WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend({
|
||||
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
|
||||
vol.Optional(CONF_BSSID): cv.mac_address,
|
||||
})
|
||||
|
||||
|
||||
def validate(config):
|
||||
if CONF_PASSWORD in config and CONF_SSID not in config:
|
||||
raise vol.Invalid("Cannot have WiFi password without SSID!")
|
||||
if (CONF_SSID not in config) and (CONF_AP not in config):
|
||||
|
||||
if CONF_SSID in config:
|
||||
network = {CONF_SSID: config.pop(CONF_SSID)}
|
||||
if CONF_PASSWORD in config:
|
||||
network[CONF_PASSWORD] = config.pop(CONF_PASSWORD)
|
||||
if CONF_MANUAL_IP in config:
|
||||
network[CONF_MANUAL_IP] = config.pop(CONF_MANUAL_IP)
|
||||
if CONF_NETWORKS in config:
|
||||
raise vol.Invalid("You cannot use the 'ssid:' option together with 'networks:'. Please "
|
||||
"copy your network into the 'networks:' key")
|
||||
config[CONF_NETWORKS] = cv.ensure_list(WIFI_NETWORK_STA)(network)
|
||||
|
||||
if (CONF_NETWORKS not in config) and (CONF_AP not in config):
|
||||
raise vol.Invalid("Please specify at least an SSID or an Access Point "
|
||||
"to create.")
|
||||
return config
|
||||
|
||||
|
||||
IPAddress = global_ns.class_('IPAddress')
|
||||
ManualIP = esphomelib_ns.struct('ManualIP')
|
||||
WiFiComponent = esphomelib_ns.class_('WiFiComponent', Component)
|
||||
WiFiAp = esphomelib_ns.struct('WiFiAp')
|
||||
|
||||
WiFiPowerSaveMode = esphomelib_ns.enum('WiFiPowerSaveMode')
|
||||
WIFI_POWER_SAVE_MODES = {
|
||||
'NONE': WiFiPowerSaveMode.WIFI_POWER_SAVE_NONE,
|
||||
'LIGHT': WiFiPowerSaveMode.WIFI_POWER_SAVE_LIGHT,
|
||||
'HIGH': WiFiPowerSaveMode.WIFI_POWER_SAVE_HIGH,
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = vol.All(vol.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(WiFiComponent),
|
||||
vol.Optional(CONF_NETWORKS): cv.ensure_list(WIFI_NETWORK_STA),
|
||||
|
||||
vol.Optional(CONF_SSID): cv.ssid,
|
||||
vol.Optional(CONF_PASSWORD): validate_password,
|
||||
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
|
||||
|
||||
vol.Optional(CONF_AP): WIFI_NETWORK_AP,
|
||||
vol.Optional(CONF_HOSTNAME): cv.hostname,
|
||||
vol.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
|
||||
@@ -110,21 +128,28 @@ def manual_ip(config):
|
||||
|
||||
|
||||
def wifi_network(config):
|
||||
return StructInitializer(
|
||||
WiFiAp,
|
||||
('ssid', config.get(CONF_SSID, "")),
|
||||
('password', config.get(CONF_PASSWORD, "")),
|
||||
('channel', config.get(CONF_CHANNEL, -1)),
|
||||
('manual_ip', manual_ip(config.get(CONF_MANUAL_IP))),
|
||||
)
|
||||
ap = variable(config[CONF_ID], WiFiAP())
|
||||
if CONF_SSID in config:
|
||||
add(ap.set_ssid(config[CONF_SSID]))
|
||||
if CONF_PASSWORD in config:
|
||||
add(ap.set_password(config[CONF_PASSWORD]))
|
||||
if CONF_BSSID in config:
|
||||
bssid = [HexInt(i) for i in config[CONF_BSSID].parts]
|
||||
add(ap.set_bssid(ArrayInitializer(*bssid, multiline=False)))
|
||||
if CONF_CHANNEL in config:
|
||||
add(ap.set_channel(config[CONF_CHANNEL]))
|
||||
if CONF_MANUAL_IP in config:
|
||||
add(ap.set_manual_ip(manual_ip(config[CONF_MANUAL_IP])))
|
||||
|
||||
return ap
|
||||
|
||||
|
||||
def to_code(config):
|
||||
rhs = App.init_wifi()
|
||||
wifi = Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
if CONF_SSID in config:
|
||||
add(wifi.set_sta(wifi_network(config)))
|
||||
for network in config.get(CONF_NETWORKS, []):
|
||||
add(wifi.add_sta(wifi_network(network)))
|
||||
|
||||
if CONF_AP in config:
|
||||
add(wifi.set_ap(wifi_network(config[CONF_AP])))
|
||||
|
Reference in New Issue
Block a user