1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-15 07:08:20 +00:00

Merge branch 'dev' into tcl-climate

This commit is contained in:
Otto Winter 2019-05-27 20:05:08 +02:00
commit de4b4091ec
No known key found for this signature in database
GPG Key ID: DB66C0BE6013F97E
61 changed files with 434 additions and 119 deletions

View File

@ -41,11 +41,11 @@ stages:
- | - |
if [[ "${IS_HASSIO}" == "YES" ]]; then if [[ "${IS_HASSIO}" == "YES" ]]; then
BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.6.0 BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.5.1
BUILD_TO=esphome/esphome-hassio-${BUILD_ARCH} BUILD_TO=esphome/esphome-hassio-${BUILD_ARCH}
DOCKERFILE=docker/Dockerfile.hassio DOCKERFILE=docker/Dockerfile.hassio
else else
BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.6.0 BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.5.1
if [[ "${BUILD_ARCH}" == "amd64" ]]; then if [[ "${BUILD_ARCH}" == "amd64" ]]; then
BUILD_TO=esphome/esphome BUILD_TO=esphome/esphome
else else

View File

@ -1,4 +1,4 @@
ARG BUILD_FROM=esphome/esphome-base-amd64:1.6.0 ARG BUILD_FROM=esphome/esphome-base-amd64:1.5.1
FROM ${BUILD_FROM} FROM ${BUILD_FROM}
COPY . . COPY . .

View File

@ -1,4 +1,4 @@
#include "esphome/components/adc/adc_sensor.h" #include "adc_sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#ifdef USE_ADC_SENSOR_VCC #ifdef USE_ADC_SENSOR_VCC

View File

@ -1,10 +1,9 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import sensor, voltage_sampler from esphome.components import sensor, voltage_sampler
from esphome.components.ads1115 import ADS1115Component
from esphome.const import CONF_GAIN, CONF_MULTIPLEXER, ICON_FLASH, UNIT_VOLT, CONF_ID from esphome.const import CONF_GAIN, CONF_MULTIPLEXER, ICON_FLASH, UNIT_VOLT, CONF_ID
from esphome.py_compat import string_types from esphome.py_compat import string_types
from . import ads1115_ns from . import ads1115_ns, ADS1115Component
DEPENDENCIES = ['ads1115'] DEPENDENCIES = ['ads1115']

View File

@ -7,7 +7,7 @@ from esphome.const import CONF_AWAY_CONFIG, CONF_COOL_ACTION, \
CONF_ID, CONF_IDLE_ACTION, CONF_SENSOR CONF_ID, CONF_IDLE_ACTION, CONF_SENSOR
bang_bang_ns = cg.esphome_ns.namespace('bang_bang') bang_bang_ns = cg.esphome_ns.namespace('bang_bang')
BangBangClimate = bang_bang_ns.class_('BangBangClimate', climate.Climate) BangBangClimate = bang_bang_ns.class_('BangBangClimate', climate.Climate, cg.Component)
BangBangClimateTargetTempConfig = bang_bang_ns.struct('BangBangClimateTargetTempConfig') BangBangClimateTargetTempConfig = bang_bang_ns.struct('BangBangClimateTargetTempConfig')
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({ CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({

View File

@ -254,6 +254,7 @@ def setup_binary_sensor_core_(var, config):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings)
if CONF_INVALID_COOLDOWN in conf: if CONF_INVALID_COOLDOWN in conf:
cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN])) cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN]))
yield cg.register_component(trigger, conf)
yield automation.build_automation(trigger, [], conf) yield automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_STATE, []): for conf in config.get(CONF_ON_STATE, []):

View File

@ -1,4 +1,4 @@
#include "esphome/components/binary_sensor/binary_sensor.h" #include "binary_sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {

View File

@ -1,5 +1,5 @@
#include "esphome/components/binary_sensor/filter.h" #include "filter.h"
#include "esphome/components/binary_sensor/binary_sensor.h" #include "binary_sensor.h"
namespace esphome { namespace esphome {

View File

@ -6,13 +6,13 @@ namespace climate {
const char *climate_mode_to_string(ClimateMode mode) { const char *climate_mode_to_string(ClimateMode mode) {
switch (mode) { switch (mode) {
case CLIMATE_MODE_OFF: case CLIMATE_MODE_OFF:
return "off"; return "OFF";
case CLIMATE_MODE_AUTO: case CLIMATE_MODE_AUTO:
return "auto"; return "AUTO";
case CLIMATE_MODE_COOL: case CLIMATE_MODE_COOL:
return "cool"; return "COOL";
case CLIMATE_MODE_HEAT: case CLIMATE_MODE_HEAT:
return "heat"; return "HEAT";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }

View File

@ -19,7 +19,8 @@ void DeepSleepComponent::setup() {
void DeepSleepComponent::dump_config() { void DeepSleepComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep..."); ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
if (this->sleep_duration_.has_value()) { if (this->sleep_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Sleep Duration: %llu ms", *this->sleep_duration_ / 1000); uint32_t duration = *this->sleep_duration_ / 1000;
ESP_LOGCONFIG(TAG, " Sleep Duration: %u ms", duration);
} }
if (this->run_duration_.has_value()) { if (this->run_duration_.has_value()) {
ESP_LOGCONFIG(TAG, " Run Duration: %u ms", *this->run_duration_); ESP_LOGCONFIG(TAG, " Run Duration: %u ms", *this->run_duration_);

View File

@ -1,4 +1,4 @@
#include "esphome/components/dht/dht.h" #include "dht.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"

View File

@ -1,10 +1,9 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import binary_sensor from esphome.components import binary_sensor
from esphome.components.esp32_touch import ESP32TouchComponent
from esphome.const import CONF_NAME, CONF_PIN, CONF_THRESHOLD, ESP_PLATFORM_ESP32, CONF_ID from esphome.const import CONF_NAME, CONF_PIN, CONF_THRESHOLD, ESP_PLATFORM_ESP32, CONF_ID
from esphome.pins import validate_gpio_pin from esphome.pins import validate_gpio_pin
from . import esp32_touch_ns from . import esp32_touch_ns, ESP32TouchComponent
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['esp32_touch'] DEPENDENCIES = ['esp32_touch']

View File

@ -67,7 +67,7 @@ CONFIG_SCHEMA = cv.All(cv.Schema({
cv.Optional(CONF_USE_ADDRESS): cv.string_strict, cv.Optional(CONF_USE_ADDRESS): cv.string_strict,
cv.Optional('hostname'): cv.invalid("The hostname option has been removed in 1.11.0"), cv.Optional('hostname'): cv.invalid("The hostname option has been removed in 1.11.0"),
}), validate) }).extend(cv.COMPONENT_SCHEMA), validate)
def manual_ip(config): def manual_ip(config):
@ -84,6 +84,7 @@ def manual_ip(config):
@coroutine_with_priority(60.0) @coroutine_with_priority(60.0)
def to_code(config): def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
cg.add(var.set_phy_addr(config[CONF_PHY_ADDR])) cg.add(var.set_phy_addr(config[CONF_PHY_ADDR]))
cg.add(var.set_mdc_pin(config[CONF_MDC_PIN])) cg.add(var.set_mdc_pin(config[CONF_MDC_PIN]))

View File

@ -63,6 +63,7 @@ def register_fan(var, config):
if not CORE.has_id(config[CONF_ID]): if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var) var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_fan(var)) cg.add(cg.App.register_fan(var))
yield cg.register_component(var, config)
yield setup_fan_core_(var, config) yield setup_fan_core_(var, config)

View File

@ -1,4 +1,4 @@
#include "esphome/components/gpio/binary_sensor/gpio_binary_sensor.h" #include "gpio_binary_sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {

View File

@ -1,4 +1,4 @@
#include "esphome/components/gpio/switch/gpio_switch.h" #include "gpio_switch.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {

View File

@ -6,7 +6,8 @@ from .. import homeassistant_ns
DEPENDENCIES = ['api'] DEPENDENCIES = ['api']
HomeassistantBinarySensor = homeassistant_ns.class_('HomeassistantBinarySensor', HomeassistantBinarySensor = homeassistant_ns.class_('HomeassistantBinarySensor',
binary_sensor.BinarySensor) binary_sensor.BinarySensor,
cg.Component)
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(HomeassistantBinarySensor), cv.GenerateID(): cv.declare_id(HomeassistantBinarySensor),

View File

@ -6,7 +6,8 @@ from .. import homeassistant_ns
DEPENDENCIES = ['api'] DEPENDENCIES = ['api']
HomeassistantSensor = homeassistant_ns.class_('HomeassistantSensor', sensor.Sensor) HomeassistantSensor = homeassistant_ns.class_('HomeassistantSensor', sensor.Sensor,
cg.Component)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({ CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({
cv.GenerateID(): cv.declare_id(HomeassistantSensor), cv.GenerateID(): cv.declare_id(HomeassistantSensor),

View File

@ -71,3 +71,5 @@ def to_code(config):
yield output.register_output(var, config) yield output.register_output(var, config)
if CONF_CHANNEL in config: if CONF_CHANNEL in config:
cg.add(var.set_channel(config[CONF_CHANNEL])) cg.add(var.set_channel(config[CONF_CHANNEL]))
cg.add(var.set_frequency(config[CONF_FREQUENCY]))
cg.add(var.set_bit_depth(config[CONF_BIT_DEPTH]))

View File

@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome.components import mqtt, power_supply from esphome.components import mqtt, power_supply
from esphome.const import CONF_COLOR_CORRECT, \ from esphome.const import CONF_COLOR_CORRECT, \
CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_ID, \ CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_ID, \
CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID, CONF_POWER_SUPPLY CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID, CONF_POWER_SUPPLY, CONF_RESTORE_MODE
from esphome.core import coroutine, coroutine_with_priority from esphome.core import coroutine, coroutine_with_priority
from .automation import light_control_to_code # noqa from .automation import light_control_to_code # noqa
from .effects import validate_effects, BINARY_EFFECTS, \ from .effects import validate_effects, BINARY_EFFECTS, \
@ -12,9 +12,20 @@ from .types import ( # noqa
LightState, AddressableLightState, light_ns, LightOutput, AddressableLight) LightState, AddressableLightState, light_ns, LightOutput, AddressableLight)
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
LightRestoreMode = light_ns.enum('LightRestoreMode')
RESTORE_MODES = {
'RESTORE_DEFAULT_OFF': LightRestoreMode.LIGHT_RESTORE_DEFAULT_OFF,
'RESTORE_DEFAULT_ON': LightRestoreMode.LIGHT_RESTORE_DEFAULT_ON,
'ALWAYS_OFF': LightRestoreMode.LIGHT_ALWAYS_OFF,
'ALWAYS_ON': LightRestoreMode.LIGHT_ALWAYS_ON,
}
LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({ LIGHT_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(LightState), cv.GenerateID(): cv.declare_id(LightState),
cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTJSONLightComponent), cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTJSONLightComponent),
cv.Optional(CONF_RESTORE_MODE, default='restore_default_off'):
cv.enum(RESTORE_MODES, upper=True, space='_'),
}) })
BINARY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend({ BINARY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend({
@ -41,6 +52,7 @@ ADDRESSABLE_LIGHT_SCHEMA = RGB_LIGHT_SCHEMA.extend({
@coroutine @coroutine
def setup_light_core_(light_var, output_var, config): def setup_light_core_(light_var, output_var, config):
cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))
if CONF_INTERNAL in config: if CONF_INTERNAL in config:
cg.add(light_var.set_internal(config[CONF_INTERNAL])) cg.add(light_var.set_internal(config[CONF_INTERNAL]))
if CONF_DEFAULT_TRANSITION_LENGTH in config: if CONF_DEFAULT_TRANSITION_LENGTH in config:

View File

@ -4,7 +4,7 @@ from esphome import automation
from esphome.const import CONF_NAME, CONF_LAMBDA, CONF_UPDATE_INTERVAL, CONF_TRANSITION_LENGTH, \ from esphome.const import CONF_NAME, CONF_LAMBDA, CONF_UPDATE_INTERVAL, CONF_TRANSITION_LENGTH, \
CONF_COLORS, CONF_STATE, CONF_DURATION, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, \ CONF_COLORS, CONF_STATE, CONF_DURATION, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, \
CONF_WHITE, CONF_ALPHA, CONF_INTENSITY, CONF_SPEED, CONF_WIDTH, CONF_NUM_LEDS, CONF_RANDOM, \ CONF_WHITE, CONF_ALPHA, CONF_INTENSITY, CONF_SPEED, CONF_WIDTH, CONF_NUM_LEDS, CONF_RANDOM, \
CONF_THEN CONF_SEQUENCE
from esphome.util import Registry from esphome.util import Registry
from .types import LambdaLightEffect, RandomLightEffect, StrobeLightEffect, \ from .types import LambdaLightEffect, RandomLightEffect, StrobeLightEffect, \
StrobeLightEffectColor, LightColorValues, AddressableLightRef, AddressableLambdaLightEffect, \ StrobeLightEffectColor, LightColorValues, AddressableLightRef, AddressableLambdaLightEffect, \
@ -63,11 +63,11 @@ def lambda_effect_to_code(config, effect_id):
@register_effect('automation', AutomationLightEffect, "Automation", { @register_effect('automation', AutomationLightEffect, "Automation", {
cv.Required(CONF_THEN): automation.validate_automation(single=True), cv.Required(CONF_SEQUENCE): automation.validate_automation(single=True),
}) })
def automation_effect_to_code(config, effect_id): def automation_effect_to_code(config, effect_id):
var = yield cg.new_Pvariable(effect_id, config[CONF_NAME]) var = yield cg.new_Pvariable(effect_id, config[CONF_NAME])
yield automation.build_automation(var.get_trig(), [], config[CONF_THEN]) yield automation.build_automation(var.get_trig(), [], config[CONF_SEQUENCE])
yield var yield var

View File

@ -98,12 +98,25 @@ void LightState::setup() {
effect->init_internal(this); effect->init_internal(this);
} }
this->rtc_ = global_preferences.make_preference<LightStateRTCState>(this->get_object_id_hash());
LightStateRTCState recovered{};
// Attempt to load from preferences, else fall back to default values from struct
this->rtc_.load(&recovered);
auto call = this->make_call(); auto call = this->make_call();
LightStateRTCState recovered{};
switch (this->restore_mode_) {
case LIGHT_RESTORE_DEFAULT_OFF:
case LIGHT_RESTORE_DEFAULT_ON:
this->rtc_ = global_preferences.make_preference<LightStateRTCState>(this->get_object_id_hash());
// Attempt to load from preferences, else fall back to default values from struct
if (!this->rtc_.load(&recovered)) {
recovered.state = this->restore_mode_ == LIGHT_RESTORE_DEFAULT_ON;
}
break;
case LIGHT_ALWAYS_OFF:
recovered.state = false;
break;
case LIGHT_ALWAYS_ON:
recovered.state = true;
break;
}
call.set_state(recovered.state); call.set_state(recovered.state);
call.set_brightness_if_supported(recovered.brightness); call.set_brightness_if_supported(recovered.brightness);
call.set_red_if_supported(recovered.red); call.set_red_if_supported(recovered.red);

View File

@ -160,6 +160,13 @@ class LightCall {
bool save_{true}; bool save_{true};
}; };
enum LightRestoreMode {
LIGHT_RESTORE_DEFAULT_OFF,
LIGHT_RESTORE_DEFAULT_ON,
LIGHT_ALWAYS_OFF,
LIGHT_ALWAYS_ON,
};
/** This class represents the communication layer between the front-end MQTT layer and the /** This class represents the communication layer between the front-end MQTT layer and the
* hardware output layer. * hardware output layer.
*/ */
@ -249,6 +256,7 @@ class LightState : public Nameable, public Component {
/// Set the gamma correction factor /// Set the gamma correction factor
void set_gamma_correct(float gamma_correct); void set_gamma_correct(float gamma_correct);
float get_gamma_correct() const { return this->gamma_correct_; } float get_gamma_correct() const { return this->gamma_correct_; }
void set_restore_mode(LightRestoreMode restore_mode) { restore_mode_ = restore_mode; }
const std::vector<LightEffect *> &get_effects() const; const std::vector<LightEffect *> &get_effects() const;
@ -292,6 +300,8 @@ class LightState : public Nameable, public Component {
/// Object used to store the persisted values of the light. /// Object used to store the persisted values of the light.
ESPPreferenceObject rtc_; ESPPreferenceObject rtc_;
/// Restore mode of the light.
LightRestoreMode restore_mode_;
/// Default transition length for all transitions in ms. /// Default transition length for all transitions in ms.
uint32_t default_transition_length_{}; uint32_t default_transition_length_{};
/// Value for storing the index of the currently active effect. 0 if no effect is active /// Value for storing the index of the currently active effect. 0 if no effect is active

View File

@ -1,4 +1,4 @@
#include "esphome/components/logger/logger.h" #include "logger.h"
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include <esp_log.h> #include <esp_log.h>

View File

@ -24,12 +24,12 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC
JsonArray &modes = root.createNestedArray("modes"); JsonArray &modes = root.createNestedArray("modes");
// sort array for nice UI in HA // sort array for nice UI in HA
if (traits.supports_mode(CLIMATE_MODE_AUTO)) if (traits.supports_mode(CLIMATE_MODE_AUTO))
modes.add(climate_mode_to_string(CLIMATE_MODE_AUTO)); modes.add("auto");
modes.add(climate_mode_to_string(CLIMATE_MODE_OFF)); modes.add("off");
if (traits.supports_mode(CLIMATE_MODE_COOL)) if (traits.supports_mode(CLIMATE_MODE_COOL))
modes.add(climate_mode_to_string(CLIMATE_MODE_COOL)); modes.add("cool");
if (traits.supports_mode(CLIMATE_MODE_HEAT)) if (traits.supports_mode(CLIMATE_MODE_HEAT))
modes.add(climate_mode_to_string(CLIMATE_MODE_HEAT)); modes.add("heat");
if (traits.get_supports_two_point_target_temperature()) { if (traits.get_supports_two_point_target_temperature()) {
// temperature_low_command_topic // temperature_low_command_topic

View File

@ -72,11 +72,13 @@ bool MQTTComponent::send_discovery_() {
root["command_topic"] = this->get_command_topic_(); root["command_topic"] = this->get_command_topic_();
if (this->availability_ == nullptr) { if (this->availability_ == nullptr) {
root["availability_topic"] = global_mqtt_client->get_availability().topic; if (!global_mqtt_client->get_availability().topic.empty()) {
if (global_mqtt_client->get_availability().payload_available != "online") root["availability_topic"] = global_mqtt_client->get_availability().topic;
root["payload_available"] = global_mqtt_client->get_availability().payload_available; if (global_mqtt_client->get_availability().payload_available != "online")
if (global_mqtt_client->get_availability().payload_not_available != "offline") root["payload_available"] = global_mqtt_client->get_availability().payload_available;
root["payload_not_available"] = global_mqtt_client->get_availability().payload_not_available; if (global_mqtt_client->get_availability().payload_not_available != "offline")
root["payload_not_available"] = global_mqtt_client->get_availability().payload_not_available;
}
} else if (!this->availability_->topic.empty()) { } else if (!this->availability_->topic.empty()) {
root["availability_topic"] = this->availability_->topic; root["availability_topic"] = this->availability_->topic;
if (this->availability_->payload_available != "online") if (this->availability_->payload_available != "online")

View File

@ -1,8 +1,8 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import output from esphome.components import output
from esphome.components.my9231 import MY9231OutputComponent
from esphome.const import CONF_CHANNEL, CONF_ID from esphome.const import CONF_CHANNEL, CONF_ID
from . import MY9231OutputComponent
DEPENDENCIES = ['my9231'] DEPENDENCIES = ['my9231']

View File

@ -23,6 +23,13 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* Set the text of a component to a static string. * Set the text of a component to a static string.
* @param component The component name. * @param component The component name.
* @param text The static text to set. * @param text The static text to set.
*
* Example:
* ```cpp
* it.set_component_text("textview", "Hello World!");
* ```
*
* This will set the `txt` property of the component `textview` to `Hello World`.
*/ */
void set_component_text(const char *component, const char *text); void set_component_text(const char *component, const char *text);
/** /**
@ -30,18 +37,41 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param component The component name. * @param component The component name.
* @param format The printf-style format string. * @param format The printf-style format string.
* @param ... The arguments to the format. * @param ... The arguments to the format.
*
* Example:
* ```cpp
* it.set_component_text_printf("textview", "The uptime is: %.0f", id(uptime_sensor).state);
* ```
*
* This will change the text on the component named `textview` to `The uptime is:` Then the value of `uptime_sensor`.
* with zero decimals of accuracy (whole number).
* For example when `uptime_sensor` = 506, then, `The uptime is: 506` will be displayed.
*/ */
void set_component_text_printf(const char *component, const char *format, ...) __attribute__((format(printf, 3, 4))); void set_component_text_printf(const char *component, const char *format, ...) __attribute__((format(printf, 3, 4)));
/** /**
* Set the integer value of a component * Set the integer value of a component
* @param component The component name. * @param component The component name.
* @param value The value to set. * @param value The value to set.
*
* Example:
* ```cpp
* it.set_component_value("gauge", 50);
* ```
*
* This will change the property `value` of the component `gauge` to 50.
*/ */
void set_component_value(const char *component, int value); void set_component_value(const char *component, int value);
/** /**
* Set the picture of an image component. * Set the picture of an image component.
* @param component The component name. * @param component The component name.
* @param value The picture name. * @param value The picture name.
*
* Example:
* ```cpp
* it.set_component_picture("pic", "4");
* ```
*
* This will change the image of the component `pic` to the image with ID `4`.
*/ */
void set_component_picture(const char *component, const char *picture) { void set_component_picture(const char *component, const char *picture) {
this->send_command_printf("%s.val=%s", component, picture); this->send_command_printf("%s.val=%s", component, picture);
@ -50,24 +80,61 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* Set the background color of a component. * Set the background color of a component.
* @param component The component name. * @param component The component name.
* @param color The color (as a string). * @param color The color (as a string).
*
* Example:
* ```cpp
* it.set_component_background_color("button", "17013");
* ```
*
* This will change the background color of the component `button` to blue.
* Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to
* Nextion HMI colors.
*/ */
void set_component_background_color(const char *component, const char *color); void set_component_background_color(const char *component, const char *color);
/** /**
* Set the pressed background color of a component. * Set the pressed background color of a component.
* @param component The component name. * @param component The component name.
* @param color The color (as a string). * @param color The color (as a string).
*
* Example:
* ```cpp
* it.set_component_pressed_background_color("button", "17013");
* ```
*
* This will change the pressed background color of the component `button` to blue. This is the background color that
* is shown when the component is pressed. Use this [color
* picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to Nextion HMI
* colors.
*/ */
void set_component_pressed_background_color(const char *component, const char *color); void set_component_pressed_background_color(const char *component, const char *color);
/** /**
* Set the font color of a component. * Set the font color of a component.
* @param component The component name. * @param component The component name.
* @param color The color (as a string). * @param color The color (as a string).
*
* Example:
* ```cpp
* it.set_component_font_color("textview", "17013");
* ```
*
* This will change the font color of the component `textview` to a blue color.
* Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to
* Nextion HMI colors.
*/ */
void set_component_font_color(const char *component, const char *color); void set_component_font_color(const char *component, const char *color);
/** /**
* Set the pressed font color of a component. * Set the pressed font color of a component.
* @param component The component name. * @param component The component name.
* @param color The color (as a string). * @param color The color (as a string).
*
* Example:
* ```cpp
* it.set_component_pressed_font_color("button", "17013");
* ```
*
* This will change the pressed font color of the component `button` to a blue color.
* Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to
* Nextion HMI colors.
*/ */
void set_component_pressed_font_color(const char *component, const char *color); void set_component_pressed_font_color(const char *component, const char *color);
/** /**
@ -75,12 +142,26 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param component The component name. * @param component The component name.
* @param x The x coordinate. * @param x The x coordinate.
* @param y The y coordinate. * @param y The y coordinate.
*
* Example:
* ```cpp
* it.set_component_coordinates("pic", 55, 100);
* ```
*
* This will move the position of the component `pic` to the x coordinate `55` and y coordinate `100`.
*/ */
void set_component_coordinates(const char *component, int x, int y); void set_component_coordinates(const char *component, int x, int y);
/** /**
* Set the font id for a component. * Set the font id for a component.
* @param component The component name. * @param component The component name.
* @param font_id The ID of the font (number). * @param font_id The ID of the font (number).
*
* Example:
* ```cpp
* it.set_component_font("textview", "3");
* ```
*
* Changes the font of the component named `textveiw`. Font IDs are set in the Nextion Editor.
*/ */
void set_component_font(const char *component, uint8_t font_id); void set_component_font(const char *component, uint8_t font_id);
#ifdef USE_TIME #ifdef USE_TIME
@ -94,26 +175,61 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
/** /**
* Show the page with a given name. * Show the page with a given name.
* @param page The name of the page. * @param page The name of the page.
*
* Example:
* ```cpp
* it.goto_page("main");
* ```
*
* Switches to the page named `main`. Pages are named in the Nextion Editor.
*/ */
void goto_page(const char *page); void goto_page(const char *page);
/** /**
* Hide a component. * Hide a component.
* @param component The component name. * @param component The component name.
*
* Example:
* ```cpp
* hide_component("button");
* ```
*
* Hides the component named `button`.
*/ */
void hide_component(const char *component); void hide_component(const char *component);
/** /**
* Show a component. * Show a component.
* @param component The component name. * @param component The component name.
*
* Example:
* ```cpp
* show_component("button");
* ```
*
* Shows the component named `button`.
*/ */
void show_component(const char *component); void show_component(const char *component);
/** /**
* Enable touch for a component. * Enable touch for a component.
* @param component The component name. * @param component The component name.
*
* Example:
* ```cpp
* enable_component_touch("button");
* ```
*
* Enables touch for component named `button`.
*/ */
void enable_component_touch(const char *component); void enable_component_touch(const char *component);
/** /**
* Disable touch for a component. * Disable touch for a component.
* @param component The component name. * @param component The component name.
*
* Example:
* ```cpp
* disable_component_touch("button");
* ```
*
* Disables touch for component named `button`.
*/ */
void disable_component_touch(const char *component); void disable_component_touch(const char *component);
/** /**
@ -128,6 +244,13 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param picture_id The picture id. * @param picture_id The picture id.
* @param x1 The x coordinate. * @param x1 The x coordinate.
* @param y1 The y coordniate. * @param y1 The y coordniate.
*
* Example:
* ```cpp
* display_picture(2, 15, 25);
* ```
*
* Displays the picture who has the id `2` at the x coordinates `15` and y coordinates `25`.
*/ */
void display_picture(int picture_id, int x_start, int y_start); void display_picture(int picture_id, int x_start, int y_start);
/** /**
@ -137,6 +260,15 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param width The width to draw. * @param width The width to draw.
* @param height The height to draw. * @param height The height to draw.
* @param color The color to draw with (as a string). * @param color The color to draw with (as a string).
*
* Example:
* ```cpp
* fill_area(50, 50, 100, 100, "17013");
* ```
*
* Fills an area that starts at x coordiante `50` and y coordinate `50` with a height of `100` and width of `100` with
* the color of blue. Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to
* convert color codes to Nextion HMI colors
*/ */
void fill_area(int x1, int y1, int width, int height, const char *color); void fill_area(int x1, int y1, int width, int height, const char *color);
/** /**
@ -146,6 +278,16 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param x2 The ending x coordinate. * @param x2 The ending x coordinate.
* @param y2 The ending y coordinate. * @param y2 The ending y coordinate.
* @param color The color to draw with (as a string). * @param color The color to draw with (as a string).
*
* Example:
* ```cpp
* it.line(50, 50, 75, 75, "17013");
* ```
*
* Makes a line that starts at x coordinate `50` and y coordinate `50` and ends at x coordinate `75` and y coordinate
* `75` with the color of blue. Use this [color
* picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to Nextion HMI
* colors.
*/ */
void line(int x1, int y1, int x2, int y2, const char *color); void line(int x1, int y1, int x2, int y2, const char *color);
/** /**
@ -155,6 +297,16 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param width The width of the rectangle. * @param width The width of the rectangle.
* @param height The height of the rectangle. * @param height The height of the rectangle.
* @param color The color to draw with (as a string). * @param color The color to draw with (as a string).
*
* Example:
* ```cpp
* it.rectangle(25, 35, 40, 50, "17013");
* ```
*
* Makes a outline of a rectangle that starts at x coordinate `25` and y coordinate `35` and has a width of `40` and a
* length of `50` with color of blue. Use this [color
* picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to Nextion HMI
* colors.
*/ */
void rectangle(int x1, int y1, int width, int height, const char *color); void rectangle(int x1, int y1, int width, int height, const char *color);
/** /**
@ -171,17 +323,41 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
* @param center_y The center y coordinate. * @param center_y The center y coordinate.
* @param radius The circle radius. * @param radius The circle radius.
* @param color The color to draw with (as a string). * @param color The color to draw with (as a string).
*
* Example:
* ```cpp
* it.filled_cricle(25, 25, 10, "17013");
* ```
*
* Makes a filled circle at the x cordinates `25` and y coordinate `25` with a radius of `10` with a color of blue.
* Use this [color picker](https://nodtem66.github.io/nextion-hmi-color-convert/index.html) to convert color codes to
* Nextion HMI colors.
*/ */
void filled_circle(int center_x, int center_y, int radius, const char *color); void filled_circle(int center_x, int center_y, int radius, const char *color);
/** Set the brightness of the backlight. /** Set the brightness of the backlight.
* *
* @param brightness The brightness, from 0 to 100. * @param brightness The brightness, from 0 to 100.
*
* Example:
* ```cpp
* it.set_backlight_brightness(30);
* ```
*
* Changes the brightness of the display to 30%.
*/ */
void set_backlight_brightness(uint8_t brightness); void set_backlight_brightness(uint8_t brightness);
/** /**
* Set the touch sleep timeout of the display. * Set the touch sleep timeout of the display.
* @param timeout Timeout in seconds. * @param timeout Timeout in seconds.
*
* Example:
* ```cpp
* it.set_touch_sleep_timeout(30);
* ```
*
* After 30 seconds the display will go to sleep. Note: the display will only wakeup by a restart or by setting up
* `thup`.
*/ */
void set_touch_sleep_timeout(uint16_t timeout); void set_touch_sleep_timeout(uint16_t timeout);

View File

@ -1,10 +1,9 @@
#include "esphome/components/ota/ota_component.h" #include "ota_component.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/util.h" #include "esphome/core/util.h"
//#include "esphome/components/status_led.h"
#include <cstdio> #include <cstdio>
#include <MD5Builder.h> #include <MD5Builder.h>

View File

@ -10,7 +10,7 @@ PulseWidthSensor = pulse_width_ns.class_('PulseWidthSensor', sensor.Sensor, cg.P
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 3).extend({ CONFIG_SCHEMA = sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 3).extend({
cv.GenerateID(): cv.declare_id(PulseWidthSensor), cv.GenerateID(): cv.declare_id(PulseWidthSensor),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pullup_pin_schema, cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt), pins.validate_has_interrupt),
}).extend(cv.polling_component_schema('60s')) }).extend(cv.polling_component_schema('60s'))

View File

@ -1,5 +1,5 @@
#include "esphome/components/sensor/filter.h" #include "filter.h"
#include "esphome/components/sensor/sensor.h" #include "sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {

View File

@ -1,4 +1,4 @@
#include "esphome/components/sensor/sensor.h" #include "sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {

View File

@ -1,6 +1,7 @@
#include "status_binary_sensor.h" #include "status_binary_sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/util.h" #include "esphome/core/util.h"
#include "esphome/core/defines.h"
#ifdef USE_MQTT #ifdef USE_MQTT
#include "esphome/components/mqtt/mqtt_client.h" #include "esphome/components/mqtt/mqtt_client.h"
@ -18,19 +19,16 @@ void StatusBinarySensor::loop() {
bool status = network_is_connected(); bool status = network_is_connected();
#ifdef USE_MQTT #ifdef USE_MQTT
if (mqtt::global_mqtt_client != nullptr) { if (mqtt::global_mqtt_client != nullptr) {
status = mqtt::global_mqtt_client->is_connected(); status = status && mqtt::global_mqtt_client->is_connected();
} }
#endif #endif
#ifdef USE_API #ifdef USE_API
if (api::global_api_server != nullptr) { if (api::global_api_server != nullptr) {
status = api::global_api_server->is_connected(); status = status && api::global_api_server->is_connected();
} }
#endif #endif
if (this->last_status_ != status) { this->publish_state(status);
this->publish_state(status);
this->last_status_ = status;
}
} }
void StatusBinarySensor::setup() { this->publish_state(false); } void StatusBinarySensor::setup() { this->publish_state(false); }
void StatusBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Status Binary Sensor", this); } void StatusBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Status Binary Sensor", this); }

View File

@ -16,9 +16,6 @@ class StatusBinarySensor : public binary_sensor::BinarySensor, public Component
float get_setup_priority() const override { return setup_priority::DATA; } float get_setup_priority() const override { return setup_priority::DATA; }
bool is_status_binary_sensor() const override { return true; } bool is_status_binary_sensor() const override { return true; }
protected:
bool last_status_{false};
}; };
} // namespace status } // namespace status

View File

@ -83,13 +83,13 @@ def switch_toggle_to_code(config, action_id, template_arg, args):
@automation.register_condition('switch.is_on', SwitchCondition, SWITCH_ACTION_SCHEMA) @automation.register_condition('switch.is_on', SwitchCondition, SWITCH_ACTION_SCHEMA)
def switch_is_on_to_code(config, condition_id, template_arg, args): def switch_is_on_to_code(config, condition_id, template_arg, args):
paren = yield cg.get_variable(config[CONF_ID]) paren = yield cg.get_variable(config[CONF_ID])
yield cg.new_Pvariable(condition_id, template_arg, paren) yield cg.new_Pvariable(condition_id, template_arg, paren, True)
@automation.register_condition('switch.is_off', SwitchCondition, SWITCH_ACTION_SCHEMA) @automation.register_condition('switch.is_off', SwitchCondition, SWITCH_ACTION_SCHEMA)
def switch_is_off_to_code(config, condition_id, template_arg, args): def switch_is_off_to_code(config, condition_id, template_arg, args):
paren = yield cg.get_variable(config[CONF_ID]) paren = yield cg.get_variable(config[CONF_ID])
yield cg.new_Pvariable(condition_id, template_arg, paren) yield cg.new_Pvariable(condition_id, template_arg, paren, False)
@coroutine_with_priority(100.0) @coroutine_with_priority(100.0)

View File

@ -1,4 +1,4 @@
#include "esphome/components/switch/switch.h" #include "switch.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome {

View File

@ -7,7 +7,7 @@ from esphome.const import CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_CURRENT_OP
CONF_STATE, CONF_STOP_ACTION CONF_STATE, CONF_STOP_ACTION
from .. import template_ns from .. import template_ns
TemplateCover = template_ns.class_('TemplateCover', cover.Cover) TemplateCover = template_ns.class_('TemplateCover', cover.Cover, cg.Component)
TemplateCoverRestoreMode = template_ns.enum('TemplateCoverRestoreMode') TemplateCoverRestoreMode = template_ns.enum('TemplateCoverRestoreMode')
RESTORE_MODES = { RESTORE_MODES = {

View File

@ -285,6 +285,7 @@ def setup_time_core_(time_var, config):
days_of_week = conf.get(CONF_DAYS_OF_WEEK, [x for x in range(1, 8)]) days_of_week = conf.get(CONF_DAYS_OF_WEEK, [x for x in range(1, 8)])
cg.add(trigger.add_days_of_week(days_of_week)) cg.add(trigger.add_days_of_week(days_of_week))
yield cg.register_component(trigger, conf)
yield automation.build_automation(trigger, [], conf) yield automation.build_automation(trigger, [], conf)

View File

@ -8,7 +8,7 @@ from .. import uart_ns
DEPENDENCIES = ['uart'] DEPENDENCIES = ['uart']
UARTSwitch = uart_ns.class_('UARTSwitch', switch.Switch, uart.UARTDevice) UARTSwitch = uart_ns.class_('UARTSwitch', switch.Switch, uart.UARTDevice, cg.Component)
def validate_data(value): def validate_data(value):

View File

@ -1,4 +1,4 @@
#include "esphome/components/uptime/uptime_sensor.h" #include "uptime_sensor.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"

View File

@ -1,4 +1,4 @@
#include "esphome/components/wifi/wifi_component.h" #include "wifi_component.h"
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include <esp_wifi.h> #include <esp_wifi.h>

View File

@ -1,4 +1,4 @@
#include "esphome/components/wifi/wifi_component.h" #include "wifi_component.h"
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32

View File

@ -1,4 +1,4 @@
#include "esphome/components/wifi/wifi_component.h" #include "wifi_component.h"
#ifdef ARDUINO_ARCH_ESP8266 #ifdef ARDUINO_ARCH_ESP8266

View File

@ -322,6 +322,7 @@ def iter_ids(config, path=None):
def do_id_pass(result): # type: (Config) -> None def do_id_pass(result): # type: (Config) -> None
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
from esphome.cpp_types import Component
declare_ids = [] # type: List[Tuple[core.ID, ConfigPath]] declare_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
searching_ids = [] # type: List[Tuple[core.ID, ConfigPath]] searching_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
@ -340,6 +341,8 @@ def do_id_pass(result): # type: (Config) -> None
# Resolve default ids after manual IDs # Resolve default ids after manual IDs
for id, _ in declare_ids: for id, _ in declare_ids:
id.resolve([v[0].id for v in declare_ids]) id.resolve([v[0].id for v in declare_ids])
if isinstance(id.type, MockObjClass) and id.type.inherits_from(Component):
CORE.component_ids.add(id.id)
# Check searched IDs # Check searched IDs
for id, path in searching_ids: for id, path in searching_ids:
@ -447,7 +450,9 @@ def validate_config(config):
result.remove_output_path([domain], domain) result.remove_output_path([domain], domain)
# Ensure conf is a list # Ensure conf is a list
if not isinstance(conf, list) and conf: if not conf:
result[domain] = conf = []
elif not isinstance(conf, list):
result[domain] = conf = [conf] result[domain] = conf = [conf]
for i, p_config in enumerate(conf): for i, p_config in enumerate(conf):

View File

@ -1092,6 +1092,7 @@ def typed_schema(schemas, **kwargs):
key_v = key_validator(value.pop(key)) key_v = key_validator(value.pop(key))
value = schemas[key_v](value) value = schemas[key_v](value)
value[key] = key_v value[key] = key_v
return value
return validator return validator

View File

@ -19,6 +19,7 @@ ARDUINO_VERSION_ESP8266_DEV = 'https://github.com/platformio/platform-espressif8
'/stage' '/stage'
ARDUINO_VERSION_ESP8266_2_5_0 = 'espressif8266@2.0.0' ARDUINO_VERSION_ESP8266_2_5_0 = 'espressif8266@2.0.0'
ARDUINO_VERSION_ESP8266_2_5_1 = 'espressif8266@2.1.0' ARDUINO_VERSION_ESP8266_2_5_1 = 'espressif8266@2.1.0'
ARDUINO_VERSION_ESP8266_2_5_2 = 'espressif8266@2.2.0'
ARDUINO_VERSION_ESP8266_2_3_0 = 'espressif8266@1.5.0' ARDUINO_VERSION_ESP8266_2_3_0 = 'espressif8266@1.5.0'
SOURCE_FILE_EXTENSIONS = {'.cpp', '.hpp', '.h', '.c', '.tcc', '.ino'} SOURCE_FILE_EXTENSIONS = {'.cpp', '.hpp', '.h', '.c', '.tcc', '.ino'}
HEADER_FILE_EXTENSIONS = {'.h', '.hpp', '.tcc'} HEADER_FILE_EXTENSIONS = {'.h', '.hpp', '.tcc'}
@ -365,6 +366,7 @@ CONF_SERVICE = 'service'
CONF_SERVICES = 'services' CONF_SERVICES = 'services'
CONF_SETUP_MODE = 'setup_mode' CONF_SETUP_MODE = 'setup_mode'
CONF_SETUP_PRIORITY = 'setup_priority' CONF_SETUP_PRIORITY = 'setup_priority'
CONF_SEQUENCE = 'sequence'
CONF_SHUNT_RESISTANCE = 'shunt_resistance' CONF_SHUNT_RESISTANCE = 'shunt_resistance'
CONF_SHUNT_VOLTAGE = 'shunt_voltage' CONF_SHUNT_VOLTAGE = 'shunt_voltage'
CONF_SHUTDOWN_MESSAGE = 'shutdown_message' CONF_SHUTDOWN_MESSAGE = 'shutdown_message'

View File

@ -505,6 +505,8 @@ class EsphomeCore(object):
self.active_coroutines = {} # type: Dict[int, Any] self.active_coroutines = {} # type: Dict[int, Any]
# A set of strings of names of loaded integrations, used to find namespace ID conflicts # A set of strings of names of loaded integrations, used to find namespace ID conflicts
self.loaded_integrations = set() self.loaded_integrations = set()
# A set of component IDs to track what Component subclasses are declared
self.component_ids = set()
def reset(self): def reset(self):
self.dashboard = False self.dashboard = False
@ -525,6 +527,7 @@ class EsphomeCore(object):
self.defines = set() self.defines = set()
self.active_coroutines = {} self.active_coroutines = {}
self.loaded_integrations = set() self.loaded_integrations = set()
self.component_ids = set()
@property @property
def address(self): # type: () -> str def address(self): # type: () -> str
@ -626,6 +629,12 @@ class EsphomeCore(object):
_LOGGER.warning(u"Please file a bug report with your configuration.") _LOGGER.warning(u"Please file a bug report with your configuration.")
if self.active_coroutines: if self.active_coroutines:
raise EsphomeError() raise EsphomeError()
if self.component_ids:
comps = u', '.join(u"'{}'".format(x) for x in self.component_ids)
_LOGGER.warning(u"Components %s were never registered. Please create a bug report",
comps)
_LOGGER.warning(u"with your configuration.")
raise EsphomeError()
self.active_coroutines.clear() self.active_coroutines.clear()
def add(self, expression): def add(self, expression):

View File

@ -257,7 +257,7 @@ std::string to_string(long double val) {
optional<float> parse_float(const std::string &str) { optional<float> parse_float(const std::string &str) {
char *end; char *end;
float value = ::strtof(str.c_str(), &end); float value = ::strtof(str.c_str(), &end);
if (end == nullptr) if (end == nullptr || end != str.end().base())
return {}; return {};
return value; return value;
} }

View File

@ -11,16 +11,18 @@ from esphome.const import ARDUINO_VERSION_ESP32_DEV, ARDUINO_VERSION_ESP8266_DEV
CONF_NAME, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, CONF_PLATFORM, \ CONF_NAME, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, CONF_PLATFORM, \
CONF_PLATFORMIO_OPTIONS, CONF_PRIORITY, CONF_TRIGGER_ID, \ CONF_PLATFORMIO_OPTIONS, CONF_PRIORITY, CONF_TRIGGER_ID, \
CONF_ESP8266_RESTORE_FROM_FLASH, __version__, ARDUINO_VERSION_ESP8266_2_3_0, \ CONF_ESP8266_RESTORE_FROM_FLASH, __version__, ARDUINO_VERSION_ESP8266_2_3_0, \
ARDUINO_VERSION_ESP8266_2_5_0, ARDUINO_VERSION_ESP8266_2_5_1 ARDUINO_VERSION_ESP8266_2_5_0, ARDUINO_VERSION_ESP8266_2_5_1, ARDUINO_VERSION_ESP8266_2_5_2
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
from esphome.pins import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS from esphome.pins import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout'] BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
StartupTrigger = cg.esphome_ns.StartupTrigger StartupTrigger = cg.esphome_ns.class_('StartupTrigger', cg.Component, automation.Trigger.template())
ShutdownTrigger = cg.esphome_ns.ShutdownTrigger ShutdownTrigger = cg.esphome_ns.class_('ShutdownTrigger', cg.Component,
LoopTrigger = cg.esphome_ns.LoopTrigger automation.Trigger.template())
LoopTrigger = cg.esphome_ns.class_('LoopTrigger', cg.Component,
automation.Trigger.template())
VERSION_REGEX = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+(?:[ab]\d+)?$') VERSION_REGEX = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+(?:[ab]\d+)?$')
@ -42,13 +44,14 @@ def validate_board(value):
validate_platform = cv.one_of('ESP32', 'ESP8266', upper=True) validate_platform = cv.one_of('ESP32', 'ESP8266', upper=True)
PLATFORMIO_ESP8266_LUT = { PLATFORMIO_ESP8266_LUT = {
'2.5.2': 'espressif8266@2.2.0',
'2.5.1': 'espressif8266@2.1.0', '2.5.1': 'espressif8266@2.1.0',
'2.5.0': 'espressif8266@2.0.1', '2.5.0': 'espressif8266@2.0.1',
'2.4.2': 'espressif8266@1.8.0', '2.4.2': 'espressif8266@1.8.0',
'2.4.1': 'espressif8266@1.7.3', '2.4.1': 'espressif8266@1.7.3',
'2.4.0': 'espressif8266@1.6.0', '2.4.0': 'espressif8266@1.6.0',
'2.3.0': 'espressif8266@1.5.0', '2.3.0': 'espressif8266@1.5.0',
'RECOMMENDED': 'espressif8266@2.1.0', 'RECOMMENDED': 'espressif8266@1.8.0',
'LATEST': 'espressif8266', 'LATEST': 'espressif8266',
'DEV': ARDUINO_VERSION_ESP8266_DEV, 'DEV': ARDUINO_VERSION_ESP8266_DEV,
} }
@ -191,7 +194,7 @@ def to_code(config):
'espressif8266@1.6.0'): 'espressif8266@1.6.0'):
ld_script = ld_scripts[0] ld_script = ld_scripts[0]
elif CORE.arduino_version in (ARDUINO_VERSION_ESP8266_DEV, ARDUINO_VERSION_ESP8266_2_5_0, elif CORE.arduino_version in (ARDUINO_VERSION_ESP8266_DEV, ARDUINO_VERSION_ESP8266_2_5_0,
ARDUINO_VERSION_ESP8266_2_5_1): ARDUINO_VERSION_ESP8266_2_5_1, ARDUINO_VERSION_ESP8266_2_5_2):
ld_script = ld_scripts[1] ld_script = ld_scripts[1]
if ld_script is not None: if ld_script is not None:

View File

@ -1,8 +1,9 @@
from esphome.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_SETUP_PRIORITY, \ from esphome.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_SETUP_PRIORITY, \
CONF_UPDATE_INTERVAL, CONF_TYPE_ID CONF_UPDATE_INTERVAL, CONF_TYPE_ID
from esphome.core import coroutine, ID from esphome.core import coroutine, ID, CORE
from esphome.cpp_generator import RawExpression, add, get_variable from esphome.cpp_generator import RawExpression, add, get_variable
from esphome.cpp_types import App, GPIOPin from esphome.cpp_types import App, GPIOPin
from esphome.py_compat import text_type
@coroutine @coroutine
@ -34,6 +35,12 @@ def register_component(var, config):
:param var: The variable representing the component. :param var: The variable representing the component.
:param config: The configuration for the component. :param config: The configuration for the component.
""" """
id_ = text_type(var.base)
if id_ not in CORE.component_ids:
raise ValueError(u"Component ID {} was not declared to inherit from Component, "
u"or was registered twice. Please create a bug report with your "
u"configuration.".format(id_))
CORE.component_ids.remove(id_)
if CONF_SETUP_PRIORITY in config: if CONF_SETUP_PRIORITY in config:
add(var.set_setup_priority(config[CONF_SETUP_PRIORITY])) add(var.set_setup_priority(config[CONF_SETUP_PRIORITY]))
if CONF_UPDATE_INTERVAL in config: if CONF_UPDATE_INTERVAL in config:

View File

@ -86,9 +86,12 @@ def lint_content_find_check(find, **kwargs):
decor = lint_content_check(**kwargs) decor = lint_content_check(**kwargs)
def decorator(func): def decorator(func):
def new_func(content): def new_func(fname, content):
for line, col in find_all(content, find): find_ = find
err = func() if callable(find):
find_ = find(fname, content)
for line, col in find_all(content, find_):
err = func(fname)
return "{err} See line {line}:{col}.".format(err=err, line=line+1, col=col+1) return "{err} See line {line}:{col}.".format(err=err, line=line+1, col=col+1)
return decor(new_func) return decor(new_func)
return decorator return decorator
@ -123,31 +126,63 @@ def lint_executable_bit(fname):
'esphome/dashboard/static/ace.js', 'esphome/dashboard/static/ext-searchbox.js', 'esphome/dashboard/static/ace.js', 'esphome/dashboard/static/ext-searchbox.js',
'script/.neopixelbus.patch', 'script/.neopixelbus.patch',
]) ])
def lint_tabs(): def lint_tabs(fname):
return "File contains tab character. Please convert tabs to spaces." return "File contains tab character. Please convert tabs to spaces."
@lint_content_find_check('\r') @lint_content_find_check('\r')
def lint_newline(): def lint_newline(fname):
return "File contains windows newline. Please set your editor to unix newline mode." return "File contains windows newline. Please set your editor to unix newline mode."
@lint_content_check() @lint_content_check()
def lint_end_newline(content): def lint_end_newline(fname, content):
if content and not content.endswith('\n'): if content and not content.endswith('\n'):
return "File does not end with a newline, please add an empty line at the end of the file." return "File does not end with a newline, please add an empty line at the end of the file."
return None return None
def relative_cpp_search_text(fname, content):
parts = fname.split('/')
integration = parts[2]
return '#include "esphome/components/{}'.format(integration)
@lint_content_find_check(relative_cpp_search_text, include=['esphome/components/*.cpp'])
def lint_relative_cpp_import(fname):
return ("Component contains absolute import - Components must always use "
"relative imports.\n"
"Change:\n"
' #include "esphome/components/abc/abc.h"\n'
'to:\n'
' #include "abc.h"\n\n')
def relative_py_search_text(fname, content):
parts = fname.split('/')
integration = parts[2]
return 'esphome.components.{}'.format(integration)
@lint_content_find_check(relative_py_search_text, include=['esphome/components/*.py'])
def lint_relative_py_import(fname):
return ("Component contains absolute import - Components must always use "
"relative imports within the integration.\n"
"Change:\n"
' from esphome.components.abc import abc_ns"\n'
'to:\n'
' from . import abc_ns\n\n')
@lint_content_find_check('"esphome.h"', include=cpp_include, exclude=['tests/custom.h']) @lint_content_find_check('"esphome.h"', include=cpp_include, exclude=['tests/custom.h'])
def lint_esphome_h(): def lint_esphome_h(fname):
return ("File contains reference to 'esphome.h' - This file is " return ("File contains reference to 'esphome.h' - This file is "
"auto-generated and should only be used for *custom* " "auto-generated and should only be used for *custom* "
"components. Please replace with references to the direct files.") "components. Please replace with references to the direct files.")
@lint_content_check(include=['*.h']) @lint_content_check(include=['*.h'])
def lint_pragma_once(content): def lint_pragma_once(fname, content):
if '#pragma once' not in content: if '#pragma once' not in content:
return ("Header file contains no 'pragma once' header guard. Please add a " return ("Header file contains no 'pragma once' header guard. Please add a "
"'#pragma once' line at the top of the file.") "'#pragma once' line at the top of the file.")
@ -171,7 +206,7 @@ def lint_pragma_once(content):
'esphome/core/log.h', 'esphome/core/log.h',
'tests/custom.h', 'tests/custom.h',
]) ])
def lint_log_in_header(): def lint_log_in_header(fname):
return ('Found reference to ESP_LOG in header file. Using ESP_LOG* in header files ' return ('Found reference to ESP_LOG in header file. Using ESP_LOG* in header files '
'is currently not possible - please move the definition to a source file (.cpp)') 'is currently not possible - please move the definition to a source file (.cpp)')
@ -202,7 +237,7 @@ for fname in files:
except UnicodeDecodeError: except UnicodeDecodeError:
add_errors(fname, "File is not readable as UTF-8. Please set your editor to UTF-8 mode.") add_errors(fname, "File is not readable as UTF-8. Please set your editor to UTF-8 mode.")
continue continue
run_checks(LINT_CONTENT_CHECKS, fname, content) run_checks(LINT_CONTENT_CHECKS, fname, fname, content)
for f, errs in sorted(errors.items()): for f, errs in sorted(errors.items()):
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(f)) print("\033[0;32m************* File \033[1;32m{}\033[0m".format(f))

View File

@ -13,7 +13,7 @@ import threading
import click import click
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from helpers import basepath, get_output, walk_files, filter_changed from helpers import basepath, get_output, git_ls_files, filter_changed
is_py2 = sys.version[0] == '2' is_py2 = sys.version[0] == '2'
@ -83,7 +83,7 @@ def main():
return 1 return 1
files = [] files = []
for path in walk_files(basepath): for path in git_ls_files():
filetypes = ('.cpp', '.h', '.tcc') filetypes = ('.cpp', '.h', '.tcc')
ext = os.path.splitext(path)[1] ext = os.path.splitext(path)[1]
if ext in filetypes: if ext in filetypes:

View File

@ -18,7 +18,7 @@ import threading
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from helpers import basepath, shlex_quote, get_output, build_compile_commands, \ from helpers import basepath, shlex_quote, get_output, build_compile_commands, \
build_all_include, temp_header_file, walk_files, filter_changed build_all_include, temp_header_file, git_ls_files, filter_changed
is_py2 = sys.version[0] == '2' is_py2 = sys.version[0] == '2'
@ -100,7 +100,7 @@ def main():
build_compile_commands() build_compile_commands()
files = [] files = []
for path in walk_files(basepath): for path in git_ls_files():
filetypes = ('.cpp',) filetypes = ('.cpp',)
ext = os.path.splitext(path)[1] ext = os.path.splitext(path)[1]
if ext in filetypes: if ext in filetypes:

View File

@ -126,3 +126,13 @@ def filter_changed(files):
for c in files: for c in files:
print(" {}".format(c)) print(" {}".format(c))
return files return files
def git_ls_files():
command = ['git', 'ls-files', '-s']
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
output, err = proc.communicate()
lines = [x.split() for x in output.decode('utf-8').splitlines()]
return {
s[3].strip(): int(s[0]) for s in lines
}

View File

@ -9,7 +9,7 @@ import re
import sys import sys
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from helpers import basepath, get_output, walk_files, filter_changed from helpers import get_output, git_ls_files, filter_changed
def main(): def main():
@ -21,10 +21,10 @@ def main():
args = parser.parse_args() args = parser.parse_args()
files = [] files = []
for path in walk_files(basepath): for path in git_ls_files():
filetypes = ('.py',) filetypes = ('.py',)
ext = os.path.splitext(path)[1] ext = os.path.splitext(path)[1]
if ext in filetypes: if ext in filetypes and path.startswith('esphome'):
path = os.path.relpath(path, os.getcwd()) path = os.path.relpath(path, os.getcwd())
files.append(path) files.append(path)
# Match against re # Match against re
@ -35,6 +35,8 @@ def main():
files = filter_changed(files) files = filter_changed(files)
files.sort() files.sort()
if not files:
sys.exit(0)
errors = collections.defaultdict(list) errors = collections.defaultdict(list)
cmd = ['flake8'] + files cmd = ['flake8'] + files

View File

@ -3,38 +3,36 @@
class CustomSensor : public Component, public Sensor { class CustomSensor : public Component, public Sensor {
public: public:
void loop() override { void loop() override { publish_state(42.0); }
publish_state(42.0);
}
}; };
class CustomTextSensor : public Component, public TextSensor { class CustomTextSensor : public Component, public TextSensor {
public: public:
void loop() override { void loop() override { publish_state("Hello World"); }
publish_state("Hello World");
}
}; };
class CustomBinarySensor : public Component, public BinarySensor { class CustomBinarySensor : public Component, public BinarySensor {
public: public:
void loop() override { void loop() override { publish_state(false); }
publish_state(false);
}
}; };
class CustomSwitch : public Switch { class CustomSwitch : public Switch {
protected: protected:
void write_state(bool state) override { void write_state(bool state) override { ESP_LOGD("custom_switch", "Setting %s", ONOFF(state)); }
ESP_LOGD("custom_switch", "Setting %s", ONOFF(state));
}
}; };
class CustomComponent : public PollingComponent { class CustomComponent : public PollingComponent {
public: public:
void setup() override { void setup() override { ESP_LOGD("custom_component", "Setup"); }
ESP_LOGD("custom_component", "Setup"); void update() override { ESP_LOGD("custom_component", "Update"); }
} };
void update() override {
ESP_LOGD("custom_component", "Update"); class CustomBinaryOutput : public BinaryOutput, public Component {
} protected:
void write_state(bool state) override { ESP_LOGD("custom_output", "Setting %s", ONOFF(state)); }
};
class CustomFloatOutput : public FloatOutput, public Component {
protected:
void write_state(float state) override { ESP_LOGD("custom_output", "Setting %f", state); }
}; };

View File

@ -11,7 +11,7 @@ void setup() {
App.init_ota()->start_safe_mode(); App.init_ota()->start_safe_mode();
// LEDC is only available on ESP32! for the ESP8266, take a look at App.make_esp8266_pwm_output(). // LEDC is only available on ESP32! for the ESP8266, take a look at App.make_esp8266_pwm_output().
auto *red = App.make_ledc_output(32); // on pin 32 auto *red = App.make_ledc_output(32); // on pin 32
auto *green = App.make_ledc_output(33); auto *green = App.make_ledc_output(33);
auto *blue = App.make_ledc_output(34); auto *blue = App.make_ledc_output(34);
App.make_rgb_light("Livingroom Light", red, green, blue); App.make_rgb_light("Livingroom Light", red, green, blue);
@ -23,6 +23,4 @@ void setup() {
App.setup(); App.setup();
} }
void loop() { void loop() { App.loop(); }
App.loop();
}

View File

@ -29,6 +29,4 @@ void setup() {
App.setup(); App.setup();
} }
void loop() { void loop() { App.loop(); }
App.loop();
}

View File

@ -17,7 +17,7 @@ esphome:
ESP_LOGV("main", "ON LOOP!"); ESP_LOGV("main", "ON LOOP!");
- light.addressable_set: - light.addressable_set:
id: addr1 id: addr1
range_from: 1 range_from: 0
range_to: 100 range_to: 100
red: 100% red: 100%
green: !lambda 'return 255;' green: !lambda 'return 255;'
@ -839,6 +839,20 @@ light:
name: Flicker Effect With Custom Values name: Flicker Effect With Custom Values
update_interval: 16ms update_interval: 16ms
intensity: 5% intensity: 5%
- automation:
name: Custom Effect
sequence:
- light.addressable_set:
id: addr1
red: 100%
green: 100%
blue: 0%
- delay: 100ms
- light.addressable_set:
id: addr1
red: 0%
green: 100%
blue: 0%
- platform: fastled_spi - platform: fastled_spi
id: addr2 id: addr2
chipset: WS2801 chipset: WS2801

View File

@ -238,3 +238,6 @@ interval:
interval: 5s interval: 5s
then: then:
- logger.log: "Interval Run" - logger.log: "Interval Run"
display:

View File

@ -377,6 +377,22 @@ output:
id: out id: out
pin: D3 pin: D3
frequency: 50Hz frequency: 50Hz
- platform: custom
type: binary
lambda: |-
auto s = new CustomBinaryOutput();
App.register_component(s);
return {s};
outputs:
- id: custom_binary
- platform: custom
type: float
lambda: |-
auto s = new CustomFloatOutput();
App.register_component(s);
return {s};
outputs:
- id: custom_float
mcp23017: mcp23017:
id: mcp id: mcp