diff --git a/.travis.yml b/.travis.yml index b5642478f5..fd2e759fc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,6 @@ matrix: - clang-format-7 -version - clang-apply-replacements-7 -version script: - - script/clang-tidy.py --all-headers -j 2 --fix - - script/clang-format.py -i -j 2 + - script/clang-tidy --all-headers -j 2 --fix + - script/clang-format -i -j 2 - script/ci-suggest-changes diff --git a/esphome/__main__.py b/esphome/__main__.py index c06b570cb5..199b68a6f1 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -1,16 +1,18 @@ from __future__ import print_function import argparse +import functools import logging import os import sys from datetime import datetime from esphome import const, writer, yaml_util +import esphome.codegen as cg from esphome.config import iter_components, read_config, strip_default_ids from esphome.const import CONF_BAUD_RATE, CONF_BROKER, CONF_LOGGER, CONF_OTA, \ CONF_PASSWORD, CONF_PORT -from esphome.core import CORE, EsphomeError +from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority from esphome.helpers import color, indent from esphome.py_compat import IS_PY2, safe_input from esphome.util import run_external_command, run_external_process, safe_print @@ -117,12 +119,27 @@ def run_miniterm(config, port): config, line, backtrace_state=backtrace_state) +def wrap_to_code(name, comp): + coro = coroutine(comp.to_code) + + @functools.wraps(comp.to_code) + @coroutine_with_priority(coro.priority) + def wrapped(conf): + cg.add(cg.LineComment(u"{}:".format(name))) + if comp.config_schema is not None: + cg.add(cg.LineComment(indent(yaml_util.dump(conf).decode('utf-8')))) + yield coro(conf) + + return wrapped + + def write_cpp(config): _LOGGER.info("Generating C++ source...") - for _, component, conf in iter_components(CORE.config): + for name, component, conf in iter_components(CORE.config): if component.to_code is not None: - CORE.add_job(component.to_code, conf) + coro = wrap_to_code(name, component) + CORE.add_job(coro, conf) CORE.flush_tasks() diff --git a/esphome/codegen.py b/esphome/codegen.py index c2dea04995..46d652a3cd 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -10,7 +10,7 @@ # pylint: disable=unused-import from esphome.cpp_generator import ( # noqa Expression, RawExpression, RawStatement, TemplateArguments, - StructInitializer, ArrayInitializer, safe_exp, Statement, + StructInitializer, ArrayInitializer, safe_exp, Statement, LineComment, progmem_array, statement, variable, Pvariable, new_Pvariable, add, add_global, add_library, add_build_flag, add_define, get_variable, get_variable_with_full_id, process_lambda, is_template, templatable, MockObj, diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp index 439847f72a..39b88f867c 100644 --- a/esphome/components/binary_sensor/filter.cpp +++ b/esphome/components/binary_sensor/filter.cpp @@ -5,7 +5,7 @@ namespace esphome { namespace binary_sensor { -static const char *TAG = "something.Filter"; +static const char *TAG = "sensor.filter"; void Filter::output(bool value, bool is_initial) { if (!this->dedup_.next(value)) diff --git a/esphome/components/ble_presence/ble_presence_device.cpp b/esphome/components/ble_presence/ble_presence_device.cpp index 5a69d48a86..ad6b5ece88 100644 --- a/esphome/components/ble_presence/ble_presence_device.cpp +++ b/esphome/components/ble_presence/ble_presence_device.cpp @@ -6,7 +6,7 @@ namespace esphome { namespace ble_presence { -static const char *TAG = "something.something"; +static const char *TAG = "ble_presence"; void BLEPresenceDevice::dump_config() { LOG_BINARY_SENSOR("", "BLE Presence", this); } diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.cpp b/esphome/components/esp8266_pwm/esp8266_pwm.cpp index 363f4d24bc..96290871e0 100644 --- a/esphome/components/esp8266_pwm/esp8266_pwm.cpp +++ b/esphome/components/esp8266_pwm/esp8266_pwm.cpp @@ -11,7 +11,7 @@ namespace esphome { namespace esp8266_pwm { -static const char *TAG = "something.something"; +static const char *TAG = "esp8266_pwm"; void ESP8266PWM::setup() { ESP_LOGCONFIG(TAG, "Setting up ESP8266 PWM Output..."); diff --git a/esphome/components/fastled_base/__init__.py b/esphome/components/fastled_base/__init__.py index 5ad7280ee8..aad30198af 100644 --- a/esphome/components/fastled_base/__init__.py +++ b/esphome/components/fastled_base/__init__.py @@ -1,8 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import light, power_supply -from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_RGB_ORDER, CONF_MAX_REFRESH_RATE, \ - CONF_POWER_SUPPLY +from esphome.components import light +from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_RGB_ORDER, CONF_MAX_REFRESH_RATE from esphome.core import coroutine fastled_base_ns = cg.esphome_ns.namespace('fastled_base') @@ -24,8 +23,6 @@ BASE_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend({ cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, cv.Optional(CONF_RGB_ORDER): cv.one_of(*RGB_ORDERS, upper=True), cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds, - - cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), }).extend(cv.COMPONENT_SCHEMA) @@ -37,10 +34,6 @@ def new_fastled_light(config): if CONF_MAX_REFRESH_RATE in config: cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE])) - if CONF_POWER_SUPPLY in config: - var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY]) - cg.add(var.set_power_supply(var_)) - yield light.register_light(var, config) cg.add_library('FastLED', '3.2.0') yield var diff --git a/esphome/components/fastled_base/fastled_light.cpp b/esphome/components/fastled_base/fastled_light.cpp index d5cc85d266..8420748dd5 100644 --- a/esphome/components/fastled_base/fastled_light.cpp +++ b/esphome/components/fastled_base/fastled_light.cpp @@ -33,27 +33,6 @@ void FastLEDLightOutput::loop() { this->mark_shown_(); ESP_LOGVV(TAG, "Writing RGB values to bus..."); - -#ifdef USE_POWER_SUPPLY - if (this->power_supply_ != nullptr) { - bool is_on = false; - for (int i = 0; i < this->num_leds_; i++) { - if (bool(this->leds_[i])) { - is_on = true; - break; - } - } - - if (is_on && !this->has_requested_high_power_) { - this->power_supply_->request_high_power(); - this->has_requested_high_power_ = true; - } - if (!is_on && this->has_requested_high_power_) { - this->power_supply_->unrequest_high_power(); - this->has_requested_high_power_ = false; - } - } -#endif this->controller_->showLeds(); } diff --git a/esphome/components/fastled_base/fastled_light.h b/esphome/components/fastled_base/fastled_light.h index 55a48fcb3e..f9ae2f58d5 100644 --- a/esphome/components/fastled_base/fastled_light.h +++ b/esphome/components/fastled_base/fastled_light.h @@ -4,10 +4,6 @@ #include "esphome/core/helpers.h" #include "esphome/components/light/addressable_light.h" -#ifdef USE_POWER_SUPPLY -#include "esphome/components/power_supply/power_supply.h" -#endif - #define FASTLED_ESP8266_RAW_PIN_ORDER #define FASTLED_ESP32_RAW_PIN_ORDER #define FASTLED_RMT_BUILTIN_DRIVER true @@ -30,10 +26,6 @@ class FastLEDLightOutput : public Component, public light::AddressableLight { /// Set a maximum refresh rate in µs as some lights do not like being updated too often. void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; } -#ifdef USE_POWER_SUPPLY - void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_supply_ = power_supply; } -#endif - /// Add some LEDS, can only be called once. CLEDController &add_leds(CLEDController *controller, int num_leds) { this->controller_ = controller; @@ -242,10 +234,6 @@ class FastLEDLightOutput : public Component, public light::AddressableLight { int num_leds_{0}; uint32_t last_refresh_{0}; optional max_refresh_rate_{}; -#ifdef USE_POWER_SUPPLY - power_supply::PowerSupply *power_supply_{nullptr}; - bool has_requested_high_power_{false}; -#endif }; } // namespace fastled_base diff --git a/esphome/components/integration/sensor.py b/esphome/components/integration/sensor.py index 13c69f81f2..9e4dc0847f 100644 --- a/esphome/components/integration/sensor.py +++ b/esphome/components/integration/sensor.py @@ -33,7 +33,7 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend({ cv.Required(CONF_TIME_UNIT): cv.enum(INTEGRATION_TIMES, lower=True), cv.Optional(CONF_INTEGRATION_METHOD, default='trapezoid'): cv.enum(INTEGRATION_METHODS, lower=True), - cv.Optional(CONF_RESTORE, default=True): cv.boolean, + cv.Optional(CONF_RESTORE, default=False): cv.boolean, }).extend(cv.COMPONENT_SCHEMA) diff --git a/esphome/components/ledc/output.py b/esphome/components/ledc/output.py index e9e41c398a..e5cb073ca9 100644 --- a/esphome/components/ledc/output.py +++ b/esphome/components/ledc/output.py @@ -1,20 +1,54 @@ +import math from esphome import pins from esphome.components import output import esphome.config_validation as cv import esphome.codegen as cg -from esphome.const import APB_CLOCK_FREQ, CONF_BIT_DEPTH, CONF_CHANNEL, CONF_FREQUENCY, \ +from esphome.const import CONF_BIT_DEPTH, CONF_CHANNEL, CONF_FREQUENCY, \ CONF_ID, CONF_PIN, ESP_PLATFORM_ESP32 ESP_PLATFORMS = [ESP_PLATFORM_ESP32] +def calc_max_frequency(bit_depth): + return 80e6 / (2**bit_depth) + + +def calc_min_frequency(bit_depth): + # LEDC_DIV_NUM_HSTIMER is 15-bit unsigned integer + # lower 8 bits represent fractional part + max_div_num = ((1 << 16) - 1) / 256.0 + return 80e6 / (max_div_num * (2**bit_depth)) + + def validate_frequency_bit_depth(obj): frequency = obj[CONF_FREQUENCY] + if CONF_BIT_DEPTH not in obj: + obj = obj.copy() + for bit_depth in range(15, 0, -1): + if calc_min_frequency(bit_depth) <= frequency <= calc_max_frequency(bit_depth): + obj[CONF_BIT_DEPTH] = bit_depth + break + else: + min_freq = min(calc_min_frequency(x) for x in range(1, 16)) + max_freq = max(calc_max_frequency(x) for x in range(1, 16)) + if frequency < min_freq: + raise cv.Invalid("This frequency setting is not possible, please choose a higher " + "frequency (at least {}Hz)".format(int(min_freq))) + if frequency > max_freq: + raise cv.Invalid("This frequency setting is not possible, please choose a lower " + "frequency (at most {}Hz)".format(int(max_freq))) + raise cv.Invalid("Invalid frequency!") + bit_depth = obj[CONF_BIT_DEPTH] - max_freq = APB_CLOCK_FREQ / (2**bit_depth) + min_freq = calc_min_frequency(bit_depth) + max_freq = calc_max_frequency(bit_depth) if frequency > max_freq: - raise cv.Invalid('Maximum frequency for bit depth {} is {}Hz'.format(bit_depth, max_freq)) + raise cv.Invalid('Maximum frequency for bit depth {} is {}Hz. Please decrease the ' + 'bit_depth.'.format(bit_depth, int(math.floor(max_freq)))) + if frequency < calc_min_frequency(bit_depth): + raise cv.Invalid('Minimum frequency for bit depth {} is {}Hz. Please increase the ' + 'bit_depth.'.format(bit_depth, int(math.ceil(min_freq)))) return obj @@ -25,7 +59,7 @@ CONFIG_SCHEMA = cv.All(output.FLOAT_OUTPUT_SCHEMA.extend({ cv.Required(CONF_ID): cv.declare_id(LEDCOutput), cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, cv.Optional(CONF_FREQUENCY, default='1kHz'): cv.frequency, - cv.Optional(CONF_BIT_DEPTH, default=12): cv.int_range(min=1, max=15), + cv.Optional(CONF_BIT_DEPTH): cv.int_range(min=1, max=15), cv.Optional(CONF_CHANNEL): cv.int_range(min=0, max=15), }).extend(cv.COMPONENT_SCHEMA), validate_frequency_bit_depth) diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 858475f8cf..e0ea8f246d 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -1,9 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import mqtt +from esphome.components import mqtt, power_supply from esphome.const import CONF_COLOR_CORRECT, \ CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_ID, \ - CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID + CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID, CONF_POWER_SUPPLY from esphome.core import coroutine, coroutine_with_priority from .automation import light_control_to_code # noqa from .effects import validate_effects, BINARY_EFFECTS, \ @@ -35,6 +35,7 @@ ADDRESSABLE_LIGHT_SCHEMA = RGB_LIGHT_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(AddressableLightState), cv.Optional(CONF_EFFECTS): validate_effects(ADDRESSABLE_EFFECTS), cv.Optional(CONF_COLOR_CORRECT): cv.All([cv.percentage], cv.Length(min=3, max=4)), + cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), }) @@ -52,6 +53,10 @@ def setup_light_core_(light_var, output_var, config): if CONF_COLOR_CORRECT in config: cg.add(output_var.set_correction(*config[CONF_COLOR_CORRECT])) + if CONF_POWER_SUPPLY in config: + var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY]) + cg.add(output_var.set_power_supply(var_)) + if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], light_var) yield mqtt.register_mqtt_component(mqtt_, config) diff --git a/esphome/components/light/addressable_light.h b/esphome/components/light/addressable_light.h index 993b430d3c..b4249097db 100644 --- a/esphome/components/light/addressable_light.h +++ b/esphome/components/light/addressable_light.h @@ -1,9 +1,14 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "light_output.h" #include "light_state.h" +#ifdef USE_POWER_SUPPLY +#include "esphome/components/power_supply/power_supply.h" +#endif + namespace esphome { namespace light { @@ -30,6 +35,7 @@ struct ESPColor { }; }; uint8_t raw[4]; + uint32_t raw_32; }; inline ESPColor() ALWAYS_INLINE : r(0), g(0), b(0), w(0) {} // NOLINT inline ESPColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) ALWAYS_INLINE : r(red), @@ -47,7 +53,7 @@ struct ESPColor { this->b = rhs.b; this->w = rhs.w; } - inline bool is_on() ALWAYS_INLINE { return this->r != 0 || this->g != 0 || this->b != 0 || this->w != 0; } + inline bool is_on() ALWAYS_INLINE { return this->raw_32 != 0; } inline ESPColor &operator=(const ESPColor &rhs) ALWAYS_INLINE { this->r = rhs.r; this->g = rhs.g; @@ -527,14 +533,32 @@ class AddressableLight : public LightOutput { void setup_state(LightState *state) override { this->correction_.calculate_gamma_table(state->get_gamma_correct()); } void schedule_show() { this->next_show_ = true; } +#ifdef USE_POWER_SUPPLY + void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); } +#endif + protected: bool should_show_() const { return this->effect_active_ || this->next_show_; } - void mark_shown_() { this->next_show_ = false; } + void mark_shown_() { + this->next_show_ = false; +#ifdef USE_POWER_SUPPLY + for (auto c : *this) { + if (c.get().is_on()) { + this->power_.request(); + return; + } + } + this->power_.unrequest(); +#endif + } virtual ESPColorView get_view_internal(int32_t index) const = 0; bool effect_active_{false}; bool next_show_{true}; ESPColorCorrection correction_{}; +#ifdef USE_POWER_SUPPLY + power_supply::PowerSupplyRequester power_; +#endif }; } // namespace light diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py index 060aeb0648..f07bdc80d7 100644 --- a/esphome/components/neopixelbus/light.py +++ b/esphome/components/neopixelbus/light.py @@ -1,9 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.components import light, power_supply +from esphome.components import light from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_METHOD, CONF_NUM_LEDS, CONF_PIN, \ - CONF_POWER_SUPPLY, CONF_TYPE, CONF_VARIANT, CONF_OUTPUT_ID + CONF_TYPE, CONF_VARIANT, CONF_OUTPUT_ID from esphome.core import CORE neopixelbus_ns = cg.esphome_ns.namespace('neopixelbus') @@ -138,8 +138,6 @@ CONFIG_SCHEMA = cv.All(light.ADDRESSABLE_LIGHT_SCHEMA.extend({ cv.Optional(CONF_DATA_PIN): pins.output_pin, cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int, - - cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), }).extend(cv.COMPONENT_SCHEMA), validate, validate_method_pin) @@ -162,8 +160,4 @@ def to_code(config): cg.add(var.set_pixel_order(getattr(ESPNeoPixelOrder, config[CONF_TYPE]))) - if CONF_POWER_SUPPLY in config: - var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY]) - cg.add(var.set_power_supply(var_)) - cg.add_library('NeoPixelBus', '2.4.1') diff --git a/esphome/components/neopixelbus/neopixelbus_light.h b/esphome/components/neopixelbus/neopixelbus_light.h index 68d99fb374..25e10d9bbd 100644 --- a/esphome/components/neopixelbus/neopixelbus_light.h +++ b/esphome/components/neopixelbus/neopixelbus_light.h @@ -9,10 +9,6 @@ #error The NeoPixelBus library requires at least arduino_core_version 2.4.x #endif -#ifdef USE_POWER_SUPPLY -#include "esphome/components/power_supply/power_supply.h" -#endif - #include "NeoPixelBus.h" namespace esphome { @@ -54,10 +50,6 @@ enum class ESPNeoPixelOrder { template class NeoPixelBusLightOutputBase : public Component, public light::AddressableLight { public: -#ifdef USE_POWER_SUPPLY - void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_supply_ = power_supply; } -#endif - NeoPixelBus *get_controller() const { return this->controller_; } void clear_effect_data() override { @@ -95,27 +87,6 @@ class NeoPixelBusLightOutputBase : public Component, public light::AddressableLi this->mark_shown_(); this->controller_->Dirty(); -#ifdef USE_POWER_SUPPLY - if (this->power_supply_ != nullptr) { - bool is_light_on = false; - for (int i = 0; i < this->size(); i++) { - if ((*this)[i].get().is_on()) { - is_light_on = true; - break; - } - } - - if (is_light_on && !this->has_requested_high_power_) { - this->power_supply_->request_high_power(); - this->has_requested_high_power_ = true; - } - if (!is_light_on && this->has_requested_high_power_) { - this->power_supply_->unrequest_high_power(); - this->has_requested_high_power_ = false; - } - } -#endif - this->controller_->Show(); } @@ -135,10 +106,6 @@ class NeoPixelBusLightOutputBase : public Component, public light::AddressableLi NeoPixelBus *controller_{nullptr}; uint8_t *effect_data_{nullptr}; uint8_t rgb_offsets_[4]{0, 1, 2, 3}; -#ifdef USE_POWER_SUPPLY - power_supply::PowerSupply *power_supply_{nullptr}; - bool has_requested_high_power_{false}; -#endif }; template diff --git a/esphome/components/output/binary_output.h b/esphome/components/output/binary_output.h index 96f6b3fb48..2697b23616 100644 --- a/esphome/components/output/binary_output.h +++ b/esphome/components/output/binary_output.h @@ -27,16 +27,13 @@ class BinaryOutput { * * @param power_supply The PowerSupplyComponent, set this to nullptr to disable the power supply. */ - void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_supply_ = power_supply; } + void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); } #endif /// Enable this binary output. virtual void turn_on() { #ifdef USE_POWER_SUPPLY - if (this->power_supply_ != nullptr && !this->has_requested_high_power_) { - this->power_supply_->request_high_power(); - this->has_requested_high_power_ = true; - } + this->power_.request(); #endif this->write_state(!this->inverted_); } @@ -44,10 +41,7 @@ class BinaryOutput { /// Disable this binary output. virtual void turn_off() { #ifdef USE_POWER_SUPPLY - if (this->power_supply_ != nullptr && this->has_requested_high_power_) { - this->power_supply_->unrequest_high_power(); - this->has_requested_high_power_ = false; - } + this->power_.unrequest(); #endif this->write_state(this->inverted_); } @@ -62,8 +56,7 @@ class BinaryOutput { bool inverted_{false}; #ifdef USE_POWER_SUPPLY - power_supply::PowerSupply *power_supply_{nullptr}; - bool has_requested_high_power_{false}; + power_supply::PowerSupplyRequester power_{}; #endif }; diff --git a/esphome/components/output/float_output.cpp b/esphome/components/output/float_output.cpp index 30984aecc8..0d536d0946 100644 --- a/esphome/components/output/float_output.cpp +++ b/esphome/components/output/float_output.cpp @@ -24,15 +24,9 @@ void FloatOutput::set_level(float state) { #ifdef USE_POWER_SUPPLY if (state > 0.0f) { // ON - if (this->power_supply_ != nullptr && !this->has_requested_high_power_) { - this->power_supply_->request_high_power(); - this->has_requested_high_power_ = true; - } + this->power_.request(); } else { // OFF - if (this->power_supply_ != nullptr && this->has_requested_high_power_) { - this->power_supply_->unrequest_high_power(); - this->has_requested_high_power_ = false; - } + this->power_.unrequest(); } #endif diff --git a/esphome/components/pmsx003/pmsx003.cpp b/esphome/components/pmsx003/pmsx003.cpp index bbf76ce697..548099a495 100644 --- a/esphome/components/pmsx003/pmsx003.cpp +++ b/esphome/components/pmsx003/pmsx003.cpp @@ -132,14 +132,20 @@ void PMSX003Component::parse_data_() { break; } case PMSX003_TYPE_5003ST: { + uint16_t pm_1_0_concentration = this->get_16_bit_uint_(10); uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12); + uint16_t pm_10_0_concentration = this->get_16_bit_uint_(14); uint16_t formaldehyde = this->get_16_bit_uint_(28); float temperature = this->get_16_bit_uint_(30) / 10.0f; float humidity = this->get_16_bit_uint_(32) / 10.0f; ESP_LOGD(TAG, "Got PM2.5 Concentration: %u µg/m^3, Temperature: %.1f°C, Humidity: %.1f%% Formaldehyde: %u µg/m^3", pm_2_5_concentration, temperature, humidity, formaldehyde); + if (this->pm_1_0_sensor_ != nullptr) + this->pm_1_0_sensor_->publish_state(pm_1_0_concentration); if (this->pm_2_5_sensor_ != nullptr) this->pm_2_5_sensor_->publish_state(pm_2_5_concentration); + if (this->pm_10_0_sensor_ != nullptr) + this->pm_10_0_sensor_->publish_state(pm_10_0_concentration); if (this->temperature_sensor_ != nullptr) this->temperature_sensor_->publish_state(temperature); if (this->humidity_sensor_ != nullptr) diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py index a949fbb1ca..fa9a92d430 100644 --- a/esphome/components/pmsx003/sensor.py +++ b/esphome/components/pmsx003/sensor.py @@ -24,9 +24,9 @@ PMSX003_TYPES = { } SENSORS_TO_TYPE = { - CONF_PM_1_0: [CONF_PMSX003], + CONF_PM_1_0: [CONF_PMSX003, CONF_PMS5003ST], CONF_PM_2_5: [CONF_PMSX003, CONF_PMS5003T, CONF_PMS5003ST], - CONF_PM_10_0: [CONF_PMSX003], + CONF_PM_10_0: [CONF_PMSX003, CONF_PMS5003ST], CONF_TEMPERATURE: [CONF_PMS5003T, CONF_PMS5003ST], CONF_HUMIDITY: [CONF_PMS5003T, CONF_PMS5003ST], CONF_FORMALDEHYDE: [CONF_PMS5003ST], diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp index 5ce2e38eed..1f8471ac9f 100644 --- a/esphome/components/power_supply/power_supply.cpp +++ b/esphome/components/power_supply/power_supply.cpp @@ -42,7 +42,7 @@ void PowerSupply::request_high_power() { void PowerSupply::unrequest_high_power() { this->active_requests_--; if (this->active_requests_ < 0) { - // if asserts are disabled we're just going to use 0 as our now counter. + // we're just going to use 0 as our now counter. this->active_requests_ = 0; } diff --git a/esphome/components/power_supply/power_supply.h b/esphome/components/power_supply/power_supply.h index b49da3b32a..12d2a9984f 100644 --- a/esphome/components/power_supply/power_supply.h +++ b/esphome/components/power_supply/power_supply.h @@ -39,5 +39,26 @@ class PowerSupply : public Component { int16_t active_requests_{0}; // use signed integer to make catching negative requests easier. }; +class PowerSupplyRequester { + public: + void set_parent(PowerSupply *parent) { parent_ = parent; } + void request() { + if (!this->requested_ && this->parent_ != nullptr) { + this->parent_->request_high_power(); + this->requested_ = true; + } + } + void unrequest() { + if (this->requested_ && this->parent_ != nullptr) { + this->parent_->unrequest_high_power(); + this->requested_ = false; + } + } + + protected: + PowerSupply *parent_{nullptr}; + bool requested_{false}; +}; + } // namespace power_supply } // namespace esphome diff --git a/esphome/components/sun/sun.h b/esphome/components/sun/sun.h index 8e477e9196..2592c75c62 100644 --- a/esphome/components/sun/sun.h +++ b/esphome/components/sun/sun.h @@ -92,36 +92,27 @@ class SunTrigger : public Trigger<>, public PollingComponent, public Parentedparent_->get_time()->utcnow(); - if (!now.is_valid()) + double current = this->parent_->elevation(); + if (isnan(current)) return; - if (!this->last_result_.has_value() || this->last_result_->day_of_year != now.day_of_year) { - this->recalc_(); - return; + bool crossed; + if (this->sunrise_) { + crossed = this->last_elevation_ <= this->elevation_ && this->elevation_ < current; + } else { + crossed = this->last_elevation_ >= this->elevation_ && this->elevation_ > current; } - if (this->prev_check_ != -1) { - auto res = *this->last_result_; - // now >= sunrise > prev_check - if (now.timestamp >= res.timestamp && res.timestamp > this->prev_check_) { - this->trigger(); - } + if (crossed) { + this->trigger(); } - this->prev_check_ = now.timestamp; + this->last_elevation_ = current; } protected: - void recalc_() { - if (this->sunrise_) - this->last_result_ = this->parent_->sunrise(this->elevation_); - else - this->last_result_ = this->parent_->sunset(this->elevation_); - } bool sunrise_; + double last_elevation_; double elevation_; - time_t prev_check_{-1}; - optional last_result_{}; }; template class SunCondition : public Condition, public Parented { diff --git a/esphome/components/time/automation.cpp b/esphome/components/time/automation.cpp index b6032ca2a2..1232e6f834 100644 --- a/esphome/components/time/automation.cpp +++ b/esphome/components/time/automation.cpp @@ -4,7 +4,7 @@ namespace esphome { namespace time { -static const char *TAG = "something.something"; +static const char *TAG = "automation"; void CronTrigger::add_second(uint8_t second) { this->seconds_[second] = true; } void CronTrigger::add_minute(uint8_t minute) { this->minutes_[minute] = true; } diff --git a/esphome/config.py b/esphome/config.py index c969641422..d6f5735066 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -69,10 +69,6 @@ class ComponentManifest(object): def auto_load(self): return getattr(self.module, 'AUTO_LOAD', []) - @property - def to_code_priority(self): - return getattr(self.module, 'TO_CODE_PRIORITY', []) - def _get_flags_set(self, name, config): if not hasattr(self.module, name): return set() diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 7676f2816a..a424d800dc 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -8,6 +8,7 @@ import re from contextlib import contextmanager import uuid as uuid_ from datetime import datetime +from string import ascii_letters, digits import voluptuous as vol @@ -279,8 +280,9 @@ def validate_id_name(value): raise Invalid("First character in ID cannot be a digit.") if '-' in value: raise Invalid("Dashes are not supported in IDs, please use underscores instead.") + valid_chars = ascii_letters + digits + '_' for char in value: - if char != '_' and not char.isalnum(): + if char not in valid_chars: raise Invalid(u"IDs must only consist of upper/lowercase characters, the underscore" u"character and numbers. The character '{}' cannot be used" u"".format(char)) @@ -611,7 +613,7 @@ if IS_PY2: path = u' @ data[%s]' % u']['.join(map(repr, self.path)) \ if self.path else '' # pylint: disable=no-member - output = Exception.__unicode__(self) + output = self.message if self.error_type: output += u' for ' + self.error_type return output + path diff --git a/esphome/const.py b/esphome/const.py index 4e98dee394..b820c0d4c1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -11,8 +11,6 @@ ESP_PLATFORM_ESP32 = 'ESP32' ESP_PLATFORM_ESP8266 = 'ESP8266' ESP_PLATFORMS = [ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266] -APB_CLOCK_FREQ = 80000000 - ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_' ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage' ARDUINO_VERSION_ESP32_1_0_0 = 'espressif32@1.5.0' diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 99d5f7fe29..98eca4ce87 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -60,7 +60,7 @@ void Application::setup() { this->dump_config(); } void Application::dump_config() { - ESP_LOGI(TAG, "esphome-core version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str()); + ESP_LOGI(TAG, "esphome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str()); for (auto component : this->components_) { component->dump_config(); diff --git a/esphome/core_config.py b/esphome/core_config.py index 8d2f83c4f1..3ed07a8343 100644 --- a/esphome/core_config.py +++ b/esphome/core_config.py @@ -89,8 +89,7 @@ def default_build_path(): CONFIG_SCHEMA = cv.Schema({ cv.Required(CONF_NAME): cv.valid_name, - cv.Required(CONF_PLATFORM): cv.one_of('ESP8266', 'ESP32', 'ESPRESSIF32', - upper=True), + cv.Required(CONF_PLATFORM): cv.one_of('ESP8266', 'ESP32', upper=True), cv.Required(CONF_BOARD): validate_board, cv.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version, cv.Optional(CONF_BUILD_PATH, default=default_build_path): cv.string, @@ -114,6 +113,10 @@ CONFIG_SCHEMA = cv.Schema({ }), cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(cv.file_), cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict), + + cv.Optional('esphome_core_version'): cv.invalid("The esphome_core_version option has been " + "removed in 1.13 - the esphome core source " + "files are now bundled with ESPHome.") }) PRELOAD_CONFIG_SCHEMA = cv.Schema({ diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 38217ea9bb..c1e4a87179 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -328,6 +328,17 @@ class ExpressionStatement(Statement): return u"{};".format(self.expression) +class LineComment(Statement): + def __init__(self, value): # type: (unicode) -> None + super(LineComment, self).__init__() + self._value = value + + def __str__(self): + parts = self._value.split(u'\n') + parts = [u'// {}'.format(x) for x in parts] + return u'\n'.join(parts) + + class ProgmemAssignmentExpression(AssignmentExpression): def __init__(self, type, name, rhs, obj): super(ProgmemAssignmentExpression, self).__init__( diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 91370a8194..0d6a26c6ee 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -729,7 +729,7 @@ def start_web_server(args): webbrowser.open('localhost:{}'.format(args.port)) - if not settings.status_use_ping: + if settings.status_use_ping: status_thread = PingStatusThread() else: status_thread = MDNSStatusThread() diff --git a/esphome/dashboard/static/esphome.js b/esphome/dashboard/static/esphome.js index 5a4a89ef5f..568537a3c9 100644 --- a/esphome/dashboard/static/esphome.js +++ b/esphome/dashboard/static/esphome.js @@ -708,3 +708,11 @@ const startWizard = () => { }; setupWizardStart.addEventListener('click', startWizard); + +jQuery.validator.addMethod("nospaces", (value, element) => { + return value.indexOf(' ') < 0; +}, "Name must not contain spaces."); + +jQuery.validator.addMethod("lowercase", (value, element) => { + return value === value.toLowerCase(); +}, "Name must be lowercase."); diff --git a/esphome/dashboard/templates/index.html b/esphome/dashboard/templates/index.html index e7259b719d..b7df4509cc 100644 --- a/esphome/dashboard/templates/index.html +++ b/esphome/dashboard/templates/index.html @@ -189,7 +189,7 @@ 0-9 and _)

- +
@@ -207,8 +207,7 @@ Please choose the board you're using below.

- If you're not sure you can also use similar ones or even the - "Generic" option. In most cases that will work too. + If unsure you can also select a similar board or choose the "Generic" option.