From 521c080989d43ff83e102184df6c9662b7e8ab4b Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Wed, 8 May 2019 09:58:03 +0200 Subject: [PATCH] Updates --- esphome/components/adc/adc_sensor.cpp | 14 ++-- esphome/components/adc/adc_sensor.h | 11 ++- esphome/components/adc/sensor.py | 9 ++- esphome/components/ads1115/__init__.py | 2 +- esphome/components/ads1115/ads1115.cpp | 28 ++++--- esphome/components/ads1115/ads1115.h | 15 ++-- esphome/components/ads1115/sensor.py | 12 +-- esphome/components/api/api_server.cpp | 1 - esphome/components/ble_ibeacon/__init__.py | 18 +++++ .../components/ble_presence/binary_sensor.py | 16 ++-- .../ble_presence/ble_presence_device.h | 7 +- esphome/components/ble_rssi/ble_rssi_sensor.h | 7 +- esphome/components/ble_rssi/sensor.py | 16 ++-- .../components/esp32_ble_tracker/__init__.py | 10 ++- .../esp32_ble_tracker/esp32_ble_tracker.cpp | 50 ++++++++---- .../esp32_ble_tracker/esp32_ble_tracker.h | 42 ++++++++-- esphome/components/light/automation.h | 2 +- esphome/components/light/automation.py | 45 ++++++++++- esphome/components/light/types.py | 1 + esphome/components/logger/__init__.py | 8 +- esphome/components/mpu6050/mpu6050.cpp | 7 +- esphome/components/sensor/__init__.py | 2 - esphome/components/time/real_time_clock.cpp | 12 +-- esphome/components/time/real_time_clock.h | 34 +++++++- .../components/voltage_sampler/__init__.py | 4 + .../voltage_sampler/voltage_sampler.h | 16 ++++ esphome/components/wifi/wifi_component.cpp | 4 - esphome/components/wifi/wifi_component.h | 2 - .../components/wifi/wifi_component_esp32.cpp | 2 + .../wifi/wifi_component_esp8266.cpp | 2 + esphome/components/xiaomi_ble/__init__.py | 12 ++- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 2 - esphome/components/xiaomi_ble/xiaomi_ble.h | 4 +- esphome/components/xiaomi_miflora/sensor.py | 15 ++-- .../xiaomi_miflora/xiaomi_miflora.h | 5 +- esphome/components/xiaomi_mijia/sensor.py | 15 ++-- .../components/xiaomi_mijia/xiaomi_mijia.h | 5 +- esphome/const.py | 2 + esphome/core/helpers.h | 1 + script/build_compile_commands.py | 79 +++++++++++++++++++ script/clang-tidy.py | 5 +- 41 files changed, 396 insertions(+), 148 deletions(-) create mode 100644 esphome/components/ble_ibeacon/__init__.py create mode 100644 esphome/components/voltage_sampler/__init__.py create mode 100644 esphome/components/voltage_sampler/voltage_sampler.h create mode 100755 script/build_compile_commands.py diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp index 849a1f31e5..aef952f27b 100644 --- a/esphome/components/adc/adc_sensor.cpp +++ b/esphome/components/adc/adc_sensor.cpp @@ -48,6 +48,11 @@ void ADCSensor::dump_config() { } float ADCSensor::get_setup_priority() const { return setup_priority::DATA; } void ADCSensor::update() { + float value_v = this->sample(); + ESP_LOGD(TAG, "'%s': Got voltage=%.2fV", this->get_name().c_str(), value_v); + this->publish_state(value_v); +} +float ADCSensor::sample() { #ifdef ARDUINO_ARCH_ESP32 float value_v = analogRead(this->pin_) / 4095.0f; switch (this->attenuation_) { @@ -64,19 +69,16 @@ void ADCSensor::update() { value_v *= 3.9; break; } + return value_v; #endif #ifdef ARDUINO_ARCH_ESP8266 #ifdef USE_ADC_SENSOR_VCC - float value_v = ESP.getVcc() / 1024.0f; + return ESP.getVcc() / 1024.0f; #else - float value_v = analogRead(this->pin_) / 1024.0f; + return analogRead(this->pin_) / 1024.0f; #endif #endif - - ESP_LOGD(TAG, "'%s': Got voltage=%.2fV", this->get_name().c_str(), value_v); - - this->publish_state(value_v); } #ifdef ARDUINO_ARCH_ESP8266 std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; } diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h index 72afe5c1e9..e44d3ee8d7 100644 --- a/esphome/components/adc/adc_sensor.h +++ b/esphome/components/adc/adc_sensor.h @@ -3,19 +3,23 @@ #include "esphome/core/component.h" #include "esphome/core/esphal.h" #include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" namespace esphome { namespace adc { -class ADCSensor : public sensor::Sensor, public PollingComponent { +#ifdef USE_ADC_SENSOR_VCC +ADC_MODE(ADC_VCC) +#endif + +class ADCSensor : public sensor::Sensor, public PollingComponent, + public voltage_sampler::VoltageSampler { public: #ifdef ARDUINO_ARCH_ESP32 /// Set the attenuation for this pin. Only available on the ESP32. void set_attenuation(adc_attenuation_t attenuation); #endif - // ========== INTERNAL METHODS ========== - // (In most use cases you won't need these) /// Update adc values. void update() override; /// Setup ADc @@ -24,6 +28,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent { /// `HARDWARE_LATE` setup priority. float get_setup_priority() const override; void set_pin(uint8_t pin) { this->pin_ = pin; } + float sample() override; #ifdef ARDUINO_ARCH_ESP8266 std::string unique_id() override; diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py index c369ea5be5..6a274f04af 100644 --- a/esphome/components/adc/sensor.py +++ b/esphome/components/adc/sensor.py @@ -1,9 +1,12 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins -from esphome.components import sensor +from esphome.components import sensor, voltage_sampler from esphome.const import CONF_ATTENUATION, CONF_ID, CONF_PIN, ICON_FLASH, UNIT_VOLT + +AUTO_LOAD = ['voltage_sampler'] + ATTENUATION_MODES = { '0db': cg.global_ns.ADC_0db, '2.5db': cg.global_ns.ADC_2_5db, @@ -20,7 +23,8 @@ def validate_adc_pin(value): adc_ns = cg.esphome_ns.namespace('adc') -ADCSensor = adc_ns.class_('ADCSensor', sensor.PollingSensorComponent) +ADCSensor = adc_ns.class_('ADCSensor', sensor.Sensor, cg.PollingComponent, + voltage_sampler.VoltageSampler) CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2).extend({ cv.GenerateID(): cv.declare_id(ADCSensor), @@ -37,7 +41,6 @@ def to_code(config): if config[CONF_PIN] == 'VCC': cg.add_define('USE_ADC_SENSOR_VCC') - cg.add_global(cg.global_ns.ADC_MODE(cg.global_ns.ADC_VCC)) else: cg.add(var.set_pin(config[CONF_PIN])) diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py index e34bab8582..28cfac49ec 100644 --- a/esphome/components/ads1115/__init__.py +++ b/esphome/components/ads1115/__init__.py @@ -4,7 +4,7 @@ from esphome.components import i2c from esphome.const import CONF_ID DEPENDENCIES = ['i2c'] -AUTO_LOAD = ['sensor'] +AUTO_LOAD = ['sensor', 'voltage_sampler'] MULTI_CONF = True ads1115_ns = cg.esphome_ns.namespace('ads1115') diff --git a/esphome/components/ads1115/ads1115.cpp b/esphome/components/ads1115/ads1115.cpp index 398aad3d02..a6fd2d76cd 100644 --- a/esphome/components/ads1115/ads1115.cpp +++ b/esphome/components/ads1115/ads1115.cpp @@ -59,7 +59,9 @@ void ADS1115Component::setup() { } for (auto *sensor : this->sensors_) { this->set_interval(sensor->get_name(), sensor->update_interval(), - [this, sensor] { this->request_measurement_(sensor); }); + [this, sensor] { + this->request_measurement_(sensor); + }); } } void ADS1115Component::dump_config() { @@ -76,11 +78,11 @@ void ADS1115Component::dump_config() { } } float ADS1115Component::get_setup_priority() const { return setup_priority::DATA; } -void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) { +float ADS1115Component::request_measurement_(ADS1115Sensor *sensor) { uint16_t config; if (!this->read_byte_16(ADS1115_REGISTER_CONFIG, &config)) { this->status_set_warning(); - return; + return NAN; } // Multiplexer // 0bxBBBxxxxxxxxxxxx @@ -96,7 +98,7 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) { if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { this->status_set_warning(); - return; + return NAN; } // about 1.6 ms with 860 samples per second @@ -107,7 +109,7 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) { if (millis() - start > 100) { ESP_LOGW(TAG, "Reading ADS1115 timed out"); this->status_set_warning(); - return; + return NAN; } yield(); } @@ -115,7 +117,7 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) { uint16_t raw_conversion; if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) { this->status_set_warning(); - return; + return NAN; } auto signed_conversion = static_cast(raw_conversion); @@ -143,16 +145,24 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) { millivolts = NAN; } - float v = millivolts / 1000.0f; - ESP_LOGD(TAG, "'%s': Got Voltage=%fV", sensor->get_name().c_str(), v); - sensor->publish_state(v); this->status_clear_warning(); + return millivolts / 1e4f; } uint8_t ADS1115Sensor::get_multiplexer() const { return this->multiplexer_; } void ADS1115Sensor::set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; } uint8_t ADS1115Sensor::get_gain() const { return this->gain_; } void ADS1115Sensor::set_gain(ADS1115Gain gain) { this->gain_ = gain; } +float ADS1115Sensor::sample() { + return this->parent_->request_measurement_(this); +} +void ADS1115Sensor::update() { + float v = this->parent_->request_measurement_(this); + if (!isnan(v)) { + ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v); + this->publish_state(v); + } +} } // namespace ads1115 } // namespace esphome diff --git a/esphome/components/ads1115/ads1115.h b/esphome/components/ads1115/ads1115.h index 863bb247aa..28efc1f5ba 100644 --- a/esphome/components/ads1115/ads1115.h +++ b/esphome/components/ads1115/ads1115.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" namespace esphome { namespace ads1115 { @@ -38,28 +39,30 @@ class ADS1115Component : public Component, public i2c::I2CDevice { /// HARDWARE_LATE setup priority float get_setup_priority() const override; - protected: /// Helper method to request a measurement from a sensor. - void request_measurement_(ADS1115Sensor *sensor); + float request_measurement_(ADS1115Sensor *sensor); + protected: std::vector sensors_; }; /// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. -class ADS1115Sensor : public sensor::Sensor { +class ADS1115Sensor : public sensor::Sensor, public PollingComponent, + public voltage_sampler::VoltageSampler { public: + ADS1115Sensor(ADS1115Component *parent) : parent_(parent) {} + void update() override; void set_multiplexer(ADS1115Multiplexer multiplexer); void set_gain(ADS1115Gain gain); - // ========== INTERNAL METHODS ========== - // (In most use cases you won't need these) + float sample() override; uint8_t get_multiplexer() const; uint8_t get_gain() const; protected: + ADS1115Component *parent_; ADS1115Multiplexer multiplexer_; ADS1115Gain gain_; - uint32_t update_interval_; }; } // namespace ads1115 diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor.py index 4a1d109c23..2fe9b6fa86 100644 --- a/esphome/components/ads1115/sensor.py +++ b/esphome/components/ads1115/sensor.py @@ -1,6 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor +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.py_compat import string_types @@ -40,7 +40,8 @@ def validate_gain(value): return cv.enum(GAIN)(value) -ADS1115Sensor = ads1115_ns.class_('ADS1115Sensor', sensor.Sensor) +ADS1115Sensor = ads1115_ns.class_('ADS1115Sensor', sensor.Sensor, cg.PollingComponent, + voltage_sampler.VoltageSampler) CONF_ADS1115_ID = 'ads1115_id' CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 3).extend({ @@ -52,11 +53,12 @@ CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 3).extend({ def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) + paren = yield cg.get_variable(config[CONF_ADS1115_ID]) + var = cg.new_Pvariable(config[CONF_ID], paren) yield sensor.register_sensor(var, config) + yield cg.register_component(var, config) cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER])) cg.add(var.set_gain(config[CONF_GAIN])) - hub = yield cg.get_variable(config[CONF_ADS1115_ID]) - cg.add(hub.register_sensor(var)) + cg.add(paren.register_sensor(var)) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 2e9b9f6841..a15fe59a6a 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -260,7 +260,6 @@ APIConnection::APIConnection(AsyncClient *client, APIServer *parent) } APIConnection::~APIConnection() { delete this->client_; } void APIConnection::on_error_(int8_t error) { - ESP_LOGD(TAG, "Error from client '%s': %d", this->client_info_.c_str(), error); // disconnect will also be called, nothing to do here this->remove_ = true; } diff --git a/esphome/components/ble_ibeacon/__init__.py b/esphome/components/ble_ibeacon/__init__.py new file mode 100644 index 0000000000..dac5b7c46f --- /dev/null +++ b/esphome/components/ble_ibeacon/__init__.py @@ -0,0 +1,18 @@ +import esphome.config_validation as cv +import esphome.codegen as cg +from esphome.components import esp32_ble_tracker +from esphome.const import CONF_ID + +DEPENDENCIES = ['esp32_ble_tracker'] +ble_ibeacon_ns = cg.esphome_ns.namespace('ble_ibeacon') +IBeaconListener = ble_ibeacon_ns.class_('IBeaconListener', esp32_ble_tracker.ESPBTDeviceListener) + + +CONFIG_SCHEMA = cv.Schema({ + cv.GenerateID(): cv.declare_id(IBeaconListener), +}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield esp32_ble_tracker.register_ble_device(var, config) diff --git a/esphome/components/ble_presence/binary_sensor.py b/esphome/components/ble_presence/binary_sensor.py index beab5448be..43ec9455d4 100644 --- a/esphome/components/ble_presence/binary_sensor.py +++ b/esphome/components/ble_presence/binary_sensor.py @@ -1,24 +1,24 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import binary_sensor -from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESP_BLE_DEVICE_SCHEMA, \ - ESPBTDeviceListener -from esphome.const import CONF_MAC_ADDRESS, CONF_NAME, CONF_ID +from esphome.components import binary_sensor, esp32_ble_tracker +from esphome.const import CONF_MAC_ADDRESS, CONF_ID DEPENDENCIES = ['esp32_ble_tracker'] ble_presence_ns = cg.esphome_ns.namespace('ble_presence') BLEPresenceDevice = ble_presence_ns.class_('BLEPresenceDevice', binary_sensor.BinarySensor, - cg.Component, ESPBTDeviceListener) + cg.Component, esp32_ble_tracker.ESPBTDeviceListener) CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(BLEPresenceDevice), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, -}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) +}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) def to_code(config): - hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) - var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], hub, config[CONF_MAC_ADDRESS].as_hex) + var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) + yield esp32_ble_tracker.register_ble_device(var, config) yield binary_sensor.register_binary_sensor(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) diff --git a/esphome/components/ble_presence/ble_presence_device.h b/esphome/components/ble_presence/ble_presence_device.h index a5aba35bea..04152d7695 100644 --- a/esphome/components/ble_presence/ble_presence_device.h +++ b/esphome/components/ble_presence/ble_presence_device.h @@ -13,9 +13,9 @@ class BLEPresenceDevice : public binary_sensor::BinarySensor, public esp32_ble_tracker::ESPBTDeviceListener, public Component { public: - BLEPresenceDevice(const std::string &name, esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address) - : binary_sensor::BinarySensor(name), esp32_ble_tracker::ESPBTDeviceListener(parent), address_(address) {} - + void set_address(uint64_t address) { + address_ = address; + } void on_scan_end() override { if (!this->found_) this->publish_state(false); @@ -29,7 +29,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensor, } return false; } - void setup() override { this->setup_ble(); } void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } diff --git a/esphome/components/ble_rssi/ble_rssi_sensor.h b/esphome/components/ble_rssi/ble_rssi_sensor.h index 686e70f82f..633bf1e52f 100644 --- a/esphome/components/ble_rssi/ble_rssi_sensor.h +++ b/esphome/components/ble_rssi/ble_rssi_sensor.h @@ -11,9 +11,9 @@ namespace ble_rssi { class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDeviceListener, public Component { public: - BLERSSISensor(const std::string &name, esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address) - : sensor::Sensor(name), esp32_ble_tracker::ESPBTDeviceListener(parent), address_(address) {} - + void set_address(uint64_t address) { + address_ = address; + } void on_scan_end() override { if (!this->found_) this->publish_state(NAN); @@ -27,7 +27,6 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi } return false; } - void setup() override { this->setup_ble(); } void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py index 22e1c82f64..ee8f71632f 100644 --- a/esphome/components/ble_rssi/sensor.py +++ b/esphome/components/ble_rssi/sensor.py @@ -1,24 +1,24 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor -from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \ - ESP_BLE_DEVICE_SCHEMA -from esphome.const import CONF_MAC_ADDRESS, CONF_NAME, CONF_ID, UNIT_DECIBEL, ICON_SIGNAL +from esphome.components import sensor, esp32_ble_tracker +from esphome.const import CONF_MAC_ADDRESS, CONF_ID, UNIT_DECIBEL, ICON_SIGNAL DEPENDENCIES = ['esp32_ble_tracker'] ble_rssi_ns = cg.esphome_ns.namespace('ble_rssi') BLERSSISensor = ble_rssi_ns.class_('BLERSSISensor', sensor.Sensor, cg.Component, - ESPBTDeviceListener) + esp32_ble_tracker.ESPBTDeviceListener) CONFIG_SCHEMA = sensor.sensor_schema(UNIT_DECIBEL, ICON_SIGNAL, 0).extend({ cv.GenerateID(): cv.declare_id(BLERSSISensor), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, -}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) +}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) def to_code(config): - hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) - var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], hub, config[CONF_MAC_ADDRESS].as_hex) + var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) + yield esp32_ble_tracker.register_ble_device(var, config) yield sensor.register_sensor(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index c77e5cd440..05ca748a99 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -1,9 +1,10 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32 +from esphome.core import coroutine ESP_PLATFORMS = [ESP_PLATFORM_ESP32] -AUTO_LOAD = ['xiaomi_ble'] +AUTO_LOAD = ['xiaomi_ble', 'ble_ibeacon'] CONF_ESP32_BLE_ID = 'esp32_ble_id' esp32_ble_tracker_ns = cg.esphome_ns.namespace('esp32_ble_tracker') @@ -24,3 +25,10 @@ def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) cg.add(var.set_scan_interval(config[CONF_SCAN_INTERVAL])) + + +@coroutine +def register_ble_device(var, config): + paren = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) + cg.add(paren.register_listener(var)) + yield var diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index ff88ea79b2..5ef814c2ba 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -201,6 +201,22 @@ void ESP32BLETracker::gap_scan_result(const esp_ble_gap_cb_param_t::ble_scan_res } } +std::string hexencode(const std::string &raw_data) { + char buf[20]; + std::string res; + for (size_t i = 0; i < raw_data.size(); i++) { + if (i + 1 != raw_data.size()) { + sprintf(buf, "0x%02X.", static_cast(raw_data[i])); + } else { + sprintf(buf, "0x%02X ", static_cast(raw_data[i])); + } + res += buf; + } + sprintf(buf, "(%zu)", raw_data.size()); + res += buf; + return res; +} + ESPBTUUID::ESPBTUUID() : uuid_() {} ESPBTUUID ESPBTUUID::from_uint16(uint16_t uuid) { ESPBTUUID ret; @@ -259,12 +275,22 @@ std::string ESPBTUUID::to_string() { return sbuf; } +ESPBLEiBeacon::ESPBLEiBeacon(const uint8_t *data) { memcpy(&this->beacon_data_, data, sizeof(beacon_data_)); } +optional ESPBLEiBeacon::from_manufacturer_data(const std::string &data) { + if (data.size() != 25) + return {}; + if (data[0] != 0x4C || data[1] != 0x00) + return {}; + + return ESPBLEiBeacon(reinterpret_cast(data.data())); +} + void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) { for (uint8_t i = 0; i < ESP_BD_ADDR_LEN; i++) this->address_[i] = param.bda[i]; this->address_type_ = param.ble_addr_type; this->rssi_ = param.rssi; - this->parse_adv(param); + this->parse_adv_(param); #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE ESP_LOGVV(TAG, "Parse Result:"); @@ -287,7 +313,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e this->address_[2], this->address_[3], this->address_[4], this->address_[5], address_type); ESP_LOGVV(TAG, " RSSI: %d", this->rssi_); - ESP_LOGVV(TAG, " Name: %s", this->name_.c_str()); + ESP_LOGVV(TAG, " Name: '%s'", this->name_.c_str()); if (this->tx_power_.has_value()) { ESP_LOGVV(TAG, " TX Power: %d", *this->tx_power_); } @@ -300,26 +326,18 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e for (auto uuid : this->service_uuids_) { ESP_LOGVV(TAG, " Service UUID: %s", uuid.to_string().c_str()); } - ESP_LOGVV(TAG, " Manufacturer data: '%s'", this->manufacturer_data_.c_str()); - ESP_LOGVV(TAG, " Service data: '%s'", this->service_data_.c_str()); + ESP_LOGVV(TAG, " Manufacturer data: %s", hexencode(this->manufacturer_data_).c_str()); + ESP_LOGVV(TAG, " Service data: %s", hexencode(this->service_data_).c_str()); if (this->service_data_uuid_.has_value()) { ESP_LOGVV(TAG, " Service Data UUID: %s", this->service_data_uuid_->to_string().c_str()); } - char buffer[200]; - size_t off = 0; - for (uint8_t i = 0; i < param.adv_data_len; i++) { - int ret = snprintf(buffer + off, sizeof(buffer) - off, "%02X.", param.ble_adv[i]); - if (ret < 0) { - break; - } - off += ret; - } - ESP_LOGVV(TAG, "Adv data: %s (%u bytes)", buffer, param.adv_data_len); + ESP_LOGVV(TAG, "Adv data: %s", + hexencode(std::string(reinterpret_cast(param.ble_adv), param.adv_data_len)).c_str()); #endif } -void ESPBTDevice::parse_adv(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) { +void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) { size_t offset = 0; const uint8_t *payload = param.ble_adv; uint8_t len = param.adv_data_len; @@ -472,8 +490,6 @@ void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) { } } -void ESPBTDeviceListener::setup_ble() { this->parent_->add_listener(this); } - } // namespace esp32_ble_tracker } // namespace esphome diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 29927ea53c..a2c68063e7 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -31,12 +31,31 @@ class ESPBTUUID { esp_bt_uuid_t uuid_; }; +class ESPBLEiBeacon { + public: + ESPBLEiBeacon(const uint8_t *data); + static optional from_manufacturer_data(const std::string &data); + + uint16_t get_major() { return reverse_bits_16(this->beacon_data_.major); } + uint16_t get_minor() { return reverse_bits_16(this->beacon_data_.minor); } + int8_t get_signal_power() { return this->beacon_data_.signal_power; } + ESPBTUUID get_uuid() { return ESPBTUUID::from_raw(this->beacon_data_.proximity_uuid); } + + protected: + struct { + uint16_t manufacturer_id; + uint8_t sub_type; + uint8_t proximity_uuid[16]; + uint16_t major; + uint16_t minor; + int8_t signal_power; + } PACKED beacon_data_; +}; + class ESPBTDevice { public: void parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m); - void parse_adv(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m); - std::string address_str() const; uint64_t address_uint64() const; @@ -51,8 +70,13 @@ class ESPBTDevice { const std::string &get_manufacturer_data() const; const std::string &get_service_data() const; const optional &get_service_data_uuid() const; + const optional get_ibeacon() const { + return ESPBLEiBeacon::from_manufacturer_data(this->manufacturer_data_); + } protected: + void parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m); + esp_bd_addr_t address_{ 0, }; @@ -72,28 +96,30 @@ class ESP32BLETracker; class ESPBTDeviceListener { public: - ESPBTDeviceListener(ESP32BLETracker *parent) : parent_(parent) {} - void setup_ble(); virtual void on_scan_end() {} virtual bool parse_device(const ESPBTDevice &device) = 0; + void set_parent(ESP32BLETracker *parent) { + parent_ = parent; + } protected: - ESP32BLETracker *parent_; + ESP32BLETracker *parent_{nullptr}; }; class ESP32BLETracker : public Component { public: void set_scan_interval(uint32_t scan_interval); - // ========== INTERNAL METHODS ========== - // (In most use cases you won't need these) /// Setup the FreeRTOS task and the Bluetooth stack. void setup() override; void dump_config() override; void loop() override; - void add_listener(ESPBTDeviceListener *listener) { this->listeners_.push_back(listener); } + void register_listener(ESPBTDeviceListener *listener) { + listener->set_parent(this); + this->listeners_.push_back(listener); + } void print_bt_device_info(const ESPBTDevice &device); diff --git a/esphome/components/light/automation.h b/esphome/components/light/automation.h index f907c70963..af295df369 100644 --- a/esphome/components/light/automation.h +++ b/esphome/components/light/automation.h @@ -112,7 +112,7 @@ template class AddressableSet : public Action { void play(Ts... x) override { auto *out = (AddressableLight *) this->parent_->get_output(); int32_t range_from = this->range_from_.value_or(x..., 0); - int32_t range_to = this->range_to_.value_or(x..., out->size()); + int32_t range_to = this->range_to_.value_or(x..., out->size() - 1) + 1; auto range = out->range(range_from, range_to); if (this->red_.has_value()) range.set_red(this->red_.value(x...)); diff --git a/esphome/components/light/automation.py b/esphome/components/light/automation.py index 4718a22052..42a8319728 100644 --- a/esphome/components/light/automation.py +++ b/esphome/components/light/automation.py @@ -3,8 +3,9 @@ import esphome.config_validation as cv from esphome import automation from esphome.const import CONF_ID, CONF_TRANSITION_LENGTH, CONF_STATE, CONF_FLASH_LENGTH, \ CONF_EFFECT, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, \ - CONF_COLOR_TEMPERATURE -from .types import DimRelativeAction, ToggleAction, LightState, LightControlAction + CONF_COLOR_TEMPERATURE, CONF_RANGE_FROM, CONF_RANGE_TO +from .types import DimRelativeAction, ToggleAction, LightState, LightControlAction, \ + AddressableLightState, AddressableSet @automation.register_action('light.toggle', ToggleAction, automation.maybe_simple_id({ @@ -87,7 +88,7 @@ def light_control_to_code(config, action_id, template_arg, args): CONF_RELATIVE_BRIGHTNESS = 'relative_brightness' LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema({ cv.Required(CONF_ID): cv.use_id(LightState), - cv.Required(CONF_RELATIVE_BRIGHTNESS): cv.templatable(cv.percentage), + cv.Required(CONF_RELATIVE_BRIGHTNESS): cv.templatable(cv.possibly_negative_percentage), cv.Optional(CONF_TRANSITION_LENGTH): cv.templatable(cv.positive_time_period_milliseconds), }) @@ -103,3 +104,41 @@ def light_dim_relative_to_code(config, action_id, template_arg, args): templ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32) cg.add(var.set_transition_length(templ)) yield var + + +LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA = cv.Schema({ + cv.Required(CONF_ID): cv.use_id(AddressableLightState), + cv.Optional(CONF_RANGE_FROM): cv.templatable(cv.positive_int), + cv.Optional(CONF_RANGE_TO): cv.templatable(cv.positive_int), + cv.Optional(CONF_RED): cv.templatable(cv.percentage), + cv.Optional(CONF_GREEN): cv.templatable(cv.percentage), + cv.Optional(CONF_BLUE): cv.templatable(cv.percentage), + cv.Optional(CONF_WHITE): cv.templatable(cv.percentage), +}) + + +@automation.register_action('light.addressable_set', AddressableSet, + LIGHT_ADDRESSABLE_SET_ACTION_SCHEMA) +def light_addressable_set_to_code(config, action_id, template_arg, args): + paren = yield cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + if CONF_RANGE_FROM in config: + templ = yield cg.templatable(config[CONF_RANGE_FROM], args, cg.int32) + cg.add(var.set_range_from(templ)) + if CONF_RANGE_TO in config: + templ = yield cg.templatable(config[CONF_RANGE_TO], args, cg.int32) + cg.add(var.set_range_to(templ)) + rgbw_to_exp = lambda x: int(round(x * 255)) + if CONF_RED in config: + templ = yield cg.templatable(config[CONF_RED], args, cg.uint8, to_exp=rgbw_to_exp) + cg.add(var.set_red(templ)) + if CONF_GREEN in config: + templ = yield cg.templatable(config[CONF_GREEN], args, cg.uint8, to_exp=rgbw_to_exp) + cg.add(var.set_green(templ)) + if CONF_BLUE in config: + templ = yield cg.templatable(config[CONF_BLUE], args, cg.uint8, to_exp=rgbw_to_exp) + cg.add(var.set_blue(templ)) + if CONF_WHITE in config: + templ = yield cg.templatable(config[CONF_WHITE], args, cg.uint8, to_exp=rgbw_to_exp) + cg.add(var.set_white(templ)) + yield var diff --git a/esphome/components/light/types.py b/esphome/components/light/types.py index c9f638a4a4..33ba759df0 100644 --- a/esphome/components/light/types.py +++ b/esphome/components/light/types.py @@ -15,6 +15,7 @@ LightColorValues = light_ns.class_('LightColorValues') ToggleAction = light_ns.class_('ToggleAction', automation.Action) LightControlAction = light_ns.class_('LightControlAction', automation.Action) DimRelativeAction = light_ns.class_('DimRelativeAction', automation.Action) +AddressableSet = light_ns.class_('AddressableSet', automation.Action) # Effects LightEffect = light_ns.class_('LightEffect') diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 9e351d0b01..27141f93c2 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -71,6 +71,7 @@ def validate_local_no_higher_than_global(value): Logger = logger_ns.class_('Logger', cg.Component) +CONF_ESP8266_STORE_LOG_STRINGS_IN_FLASH = 'esp8266_store_log_strings_in_flash' CONFIG_SCHEMA = cv.All(cv.Schema({ cv.GenerateID(): cv.declare_id(Logger), cv.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int, @@ -79,7 +80,10 @@ CONFIG_SCHEMA = cv.All(cv.Schema({ cv.Optional(CONF_LEVEL, default='DEBUG'): is_log_level, cv.Optional(CONF_LOGS, default={}): cv.Schema({ cv.string: is_log_level, - }) + }), + + cv.SplitDefault(CONF_ESP8266_STORE_LOG_STRINGS_IN_FLASH, esp8266=True): + cv.All(cv.only_on_esp8266, cv.boolean), }).extend(cv.COMPONENT_SCHEMA), validate_local_no_higher_than_global) @@ -126,7 +130,7 @@ def to_code(config): cg.add_build_flag('-DCORE_DEBUG_LEVEL=5') if CORE.is_esp32 and is_at_least_very_verbose: cg.add_build_flag('-DENABLE_I2C_DEBUG_BUFFER') - if CORE.is_esp8266: + if config.get(CONF_ESP8266_STORE_LOG_STRINGS_IN_FLASH): cg.add_build_flag('-DUSE_STORE_LOG_STR_IN_FLASH') # Register at end for safe mode diff --git a/esphome/components/mpu6050/mpu6050.cpp b/esphome/components/mpu6050/mpu6050.cpp index 68ec35f6c0..deba316a7f 100644 --- a/esphome/components/mpu6050/mpu6050.cpp +++ b/esphome/components/mpu6050/mpu6050.cpp @@ -99,17 +99,18 @@ void MPU6050Component::dump_config() { void MPU6050Component::update() { ESP_LOGV(TAG, " Updating MPU6050..."); - uint16_t data[7]; - if (!this->read_bytes_16(MPU6050_REGISTER_ACCEL_XOUT_H, data, 7)) { + uint16_t raw_data[7]; + if (!this->read_bytes_16(MPU6050_REGISTER_ACCEL_XOUT_H, raw_data, 7)) { this->status_set_warning(); return; } + auto *data = reinterpret_cast(raw_data); float accel_x = data[0] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH; float accel_y = data[1] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH; float accel_z = data[2] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH; - float temperature = data[3] / 340.0f + 36.53f; + float temperature = raw_data[3] / 340.0f + 36.53f; float gyro_x = data[4] * MPU6050_SCALE_DPS_PER_DIGIT_2000; float gyro_y = data[5] * MPU6050_SCALE_DPS_PER_DIGIT_2000; diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index a233468762..0fe0fc6bca 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -51,8 +51,6 @@ sensor_ns = cg.esphome_ns.namespace('sensor') Sensor = sensor_ns.class_('Sensor', cg.Nameable) SensorPtr = Sensor.operator('ptr') -PollingSensorComponent = sensor_ns.class_('PollingSensorComponent', cg.PollingComponent, Sensor) - # Triggers SensorStateTrigger = sensor_ns.class_('SensorStateTrigger', automation.Trigger.template(cg.float_)) SensorRawStateTrigger = sensor_ns.class_('SensorRawStateTrigger', diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index b2966cd8e0..f20a9fcaa2 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -11,16 +11,6 @@ namespace time { static const char *TAG = "time"; RealTimeClock::RealTimeClock() = default; -ESPTime RealTimeClock::now() { - time_t t = ::time(nullptr); - struct tm *c_tm = ::localtime(&t); - return ESPTime::from_tm(c_tm, t); -} -ESPTime RealTimeClock::utcnow() { - time_t t = ::time(nullptr); - struct tm *c_tm = ::gmtime(&t); - return ESPTime::from_tm(c_tm, t); -} void RealTimeClock::call_setup() { this->setup_internal_(); setenv("TZ", this->timezone_.c_str(), 1); @@ -44,7 +34,7 @@ size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) { struct tm c_tm = this->to_c_tm(); return ::strftime(buffer, buffer_len, format, &c_tm); } -ESPTime ESPTime::from_tm(struct tm *c_tm, time_t c_time) { +ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) { return ESPTime{.second = uint8_t(c_tm->tm_sec), .minute = uint8_t(c_tm->tm_min), .hour = uint8_t(c_tm->tm_hour), diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h index 21d63900b6..f416938717 100644 --- a/esphome/components/time/real_time_clock.h +++ b/esphome/components/time/real_time_clock.h @@ -52,7 +52,26 @@ struct ESPTime { bool in_range() const; - static ESPTime from_tm(struct tm *c_tm, time_t c_time); + static ESPTime from_c_tm(struct tm *c_tm, time_t c_time); + + /** Convert an epoch timestamp to an ESPTime instance of local time. + * + * @param epoch Seconds since 1st January 1970. In UTC. + * @return The generated ESPTime + */ + static ESPTime from_epoch_local(time_t epoch) { + struct tm *c_tm = ::localtime(&epoch); + return ESPTime::from_c_tm(c_tm, epoch); + } + /** Convert an epoch timestamp to an ESPTime instance of UTC time. + * + * @param epoch Seconds since 1st January 1970. In UTC. + * @return The generated ESPTime + */ + static ESPTime from_epoch_utc(time_t epoch) { + struct tm *c_tm = ::gmtime(&epoch); + return ESPTime::from_c_tm(c_tm, epoch); + } struct tm to_c_tm(); @@ -81,10 +100,19 @@ class RealTimeClock : public Component { std::string get_timezone() { return this->timezone_; } /// Get the time in the currently defined timezone. - ESPTime now(); + ESPTime now() { + return ESPTime::from_epoch_utc(this->timestamp_now()); + } /// Get the time without any time zone or DST corrections. - ESPTime utcnow(); + ESPTime utcnow() { + return ESPTime::from_epoch_local(this->timestamp_now()); + } + + /// Get the current time as the UTC epoch since January 1st 1970. + time_t timestamp_now() { + return ::time(nullptr); + } void call_setup() override; diff --git a/esphome/components/voltage_sampler/__init__.py b/esphome/components/voltage_sampler/__init__.py new file mode 100644 index 0000000000..64161205d8 --- /dev/null +++ b/esphome/components/voltage_sampler/__init__.py @@ -0,0 +1,4 @@ +import esphome.codegen as cg + +voltage_sampler_ns = cg.esphome_ns.namespace('voltage_sampler') +VoltageSampler = voltage_sampler_ns.class_('VoltageSampler') diff --git a/esphome/components/voltage_sampler/voltage_sampler.h b/esphome/components/voltage_sampler/voltage_sampler.h new file mode 100644 index 0000000000..d2e74d33bc --- /dev/null +++ b/esphome/components/voltage_sampler/voltage_sampler.h @@ -0,0 +1,16 @@ +#pragma once + +#include "esphome/core/component.h" + +namespace esphome { +namespace voltage_sampler { + +/// Abstract interface for components to request voltage (usually ADC readings) +class VoltageSampler { + public: + /// Get a voltage reading, in V. + virtual float sample() = 0; +}; + +} // namespace voltage_sampler +} // namespace esphome diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 28d911606b..35735e5f08 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -468,10 +468,6 @@ std::string WiFiComponent::format_mac_addr(const uint8_t *mac) { sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return buf; } -void WiFiComponent::on_safe_shutdown() { - // Disable WiFi interface on shutdown - this->wifi_mode_(false, false); -} bool sta_field_equal(const uint8_t *field_a, const uint8_t *field_b, int len) { for (int i = 0; i < len; i++) { diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index a9e67f23c6..8e6418791c 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -164,8 +164,6 @@ class WiFiComponent : public Component { /// Reconnect WiFi if required. void loop() override; - void on_safe_shutdown() override; - bool has_sta() const; bool has_ap() const; diff --git a/esphome/components/wifi/wifi_component_esp32.cpp b/esphome/components/wifi/wifi_component_esp32.cpp index 1edfe11ce2..f50acee614 100644 --- a/esphome/components/wifi/wifi_component_esp32.cpp +++ b/esphome/components/wifi/wifi_component_esp32.cpp @@ -173,6 +173,8 @@ bool WiFiComponent::wifi_sta_connect_(WiFiAP ap) { return false; } + this->wifi_apply_hostname_(); + err = esp_wifi_connect(); if (err != ESP_OK) { ESP_LOGW(TAG, "esp_wifi_connect failed! %d", err); diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 5030e87e25..a2c9ac2551 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -196,6 +196,8 @@ bool WiFiComponent::wifi_sta_connect_(WiFiAP ap) { return false; } + this->wifi_apply_hostname_(); + ETS_UART_INTR_DISABLE(); ret = wifi_station_connect(); ETS_UART_INTR_ENABLE(); diff --git a/esphome/components/xiaomi_ble/__init__.py b/esphome/components/xiaomi_ble/__init__.py index ef5df12cd9..2b36090293 100644 --- a/esphome/components/xiaomi_ble/__init__.py +++ b/esphome/components/xiaomi_ble/__init__.py @@ -1,20 +1,18 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \ - ESP_BLE_DEVICE_SCHEMA +from esphome.components import esp32_ble_tracker from esphome.const import CONF_ID DEPENDENCIES = ['esp32_ble_tracker'] xiaomi_ble_ns = cg.esphome_ns.namespace('xiaomi_ble') -XiaomiListener = xiaomi_ble_ns.class_('XiaomiListener', cg.Component, ESPBTDeviceListener) +XiaomiListener = xiaomi_ble_ns.class_('XiaomiListener', esp32_ble_tracker.ESPBTDeviceListener) CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(XiaomiListener), -}).extend(ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) +}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) def to_code(config): - hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) - var = cg.new_Pvariable(config[CONF_ID], hub) - yield cg.register_component(var, config) + var = cg.new_Pvariable(config[CONF_ID]) + yield esp32_ble_tracker.register_ble_device(var, config) diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 8addbe6401..7431b84491 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -138,8 +138,6 @@ bool XiaomiListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) return true; } -void XiaomiListener::setup() { this->setup_ble(); } -XiaomiListener::XiaomiListener(esp32_ble_tracker::ESP32BLETracker *parent) : ESPBTDeviceListener(parent) {} } // namespace xiaomi_ble } // namespace esphome diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.h b/esphome/components/xiaomi_ble/xiaomi_ble.h index df70fd2fc5..058a89927b 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.h +++ b/esphome/components/xiaomi_ble/xiaomi_ble.h @@ -22,11 +22,9 @@ bool parse_xiaomi_data_byte(uint8_t data_type, const uint8_t *data, uint8_t data optional parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &device); -class XiaomiListener : public Component, public esp32_ble_tracker::ESPBTDeviceListener { +class XiaomiListener : public esp32_ble_tracker::ESPBTDeviceListener { public: - XiaomiListener(esp32_ble_tracker::ESP32BLETracker *parent); bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; - void setup() override; }; } // namespace xiaomi_ble diff --git a/esphome/components/xiaomi_miflora/sensor.py b/esphome/components/xiaomi_miflora/sensor.py index f6b44f9239..8be06a93f3 100644 --- a/esphome/components/xiaomi_miflora/sensor.py +++ b/esphome/components/xiaomi_miflora/sensor.py @@ -1,8 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor -from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \ - ESP_BLE_DEVICE_SCHEMA +from esphome.components import sensor, esp32_ble_tracker from esphome.const import CONF_BATTERY_LEVEL, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \ UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, ICON_BATTERY, CONF_ID, \ CONF_MOISTURE, CONF_ILLUMINANCE, ICON_BRIGHTNESS_5, UNIT_LUX, CONF_CONDUCTIVITY, \ @@ -12,7 +10,8 @@ DEPENDENCIES = ['esp32_ble_tracker'] AUTO_LOAD = ['xiaomi_ble'] xiaomi_miflora_ns = cg.esphome_ns.namespace('xiaomi_miflora') -XiaomiMiflora = xiaomi_miflora_ns.class_('XiaomiMiflora', ESPBTDeviceListener, cg.Component) +XiaomiMiflora = xiaomi_miflora_ns.class_('XiaomiMiflora', esp32_ble_tracker.ESPBTDeviceListener, + cg.Component) CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(XiaomiMiflora), @@ -23,13 +22,15 @@ CONFIG_SCHEMA = cv.Schema({ cv.Optional(CONF_CONDUCTIVITY): sensor.sensor_schema(UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 0), -}).extend(ESP_BLE_DEVICE_SCHEMA) +}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) def to_code(config): - hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) - var = cg.new_Pvariable(config[CONF_ID], hub, config[CONF_MAC_ADDRESS].as_hex) + var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) + yield esp32_ble_tracker.register_ble_device(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) diff --git a/esphome/components/xiaomi_miflora/xiaomi_miflora.h b/esphome/components/xiaomi_miflora/xiaomi_miflora.h index 987e0cc409..7a1459b3b9 100644 --- a/esphome/components/xiaomi_miflora/xiaomi_miflora.h +++ b/esphome/components/xiaomi_miflora/xiaomi_miflora.h @@ -12,8 +12,9 @@ namespace xiaomi_miflora { class XiaomiMiflora : public Component, public esp32_ble_tracker::ESPBTDeviceListener { public: - XiaomiMiflora(esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address) - : ESPBTDeviceListener(parent), address_(address) {} + void set_address(uint64_t address) { + address_ = address; + } bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override { if (device.address_uint64() != this->address_) diff --git a/esphome/components/xiaomi_mijia/sensor.py b/esphome/components/xiaomi_mijia/sensor.py index ef68443304..995a6cbf25 100644 --- a/esphome/components/xiaomi_mijia/sensor.py +++ b/esphome/components/xiaomi_mijia/sensor.py @@ -1,8 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import sensor -from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \ - ESP_BLE_DEVICE_SCHEMA +from esphome.components import sensor, esp32_ble_tracker from esphome.const import CONF_BATTERY_LEVEL, CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \ UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, ICON_BATTERY, CONF_ID @@ -10,7 +8,8 @@ DEPENDENCIES = ['esp32_ble_tracker'] AUTO_LOAD = ['xiaomi_ble'] xiaomi_mijia_ns = cg.esphome_ns.namespace('xiaomi_mijia') -XiaomiMijia = xiaomi_mijia_ns.class_('XiaomiMijia', ESPBTDeviceListener, cg.Component) +XiaomiMijia = xiaomi_mijia_ns.class_('XiaomiMijia', esp32_ble_tracker.ESPBTDeviceListener, + cg.Component) CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(XiaomiMijia), @@ -18,13 +17,15 @@ CONFIG_SCHEMA = cv.Schema({ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1), cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1), cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 0), -}).extend(ESP_BLE_DEVICE_SCHEMA) +}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) def to_code(config): - hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID]) - var = cg.new_Pvariable(config[CONF_ID], hub, config[CONF_MAC_ADDRESS].as_hex) + var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) + yield esp32_ble_tracker.register_ble_device(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) if CONF_TEMPERATURE in config: sens = yield sensor.new_sensor(config[CONF_TEMPERATURE]) diff --git a/esphome/components/xiaomi_mijia/xiaomi_mijia.h b/esphome/components/xiaomi_mijia/xiaomi_mijia.h index e5b947e6b2..6ed066f3be 100644 --- a/esphome/components/xiaomi_mijia/xiaomi_mijia.h +++ b/esphome/components/xiaomi_mijia/xiaomi_mijia.h @@ -12,8 +12,9 @@ namespace xiaomi_mijia { class XiaomiMijia : public Component, public esp32_ble_tracker::ESPBTDeviceListener { public: - XiaomiMijia(esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address) - : ESPBTDeviceListener(parent), address_(address) {} + void set_address(uint64_t address) { + address_ = address; + } bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override { if (device.address_uint64() != this->address_) diff --git a/esphome/const.py b/esphome/const.py index 10e2781b44..fa9bae4304 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -317,6 +317,8 @@ CONF_PULSE_LENGTH = 'pulse_length' CONF_QOS = 'qos' CONF_RANDOM = 'random' CONF_RANGE = 'range' +CONF_RANGE_FROM = 'range_from' +CONF_RANGE_TO = 'range_to' CONF_RATE = 'rate' CONF_RAW = 'raw' CONF_REBOOT_TIMEOUT = 'reboot_timeout' diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index c9ee402a39..cc046a6962 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -18,6 +18,7 @@ #define HOT __attribute__((hot)) #define ESPDEPRECATED(msg) __attribute__((deprecated(msg))) #define ALWAYS_INLINE __attribute__((always_inline)) +#define PACKED __attribute__((packed)) namespace esphome { diff --git a/script/build_compile_commands.py b/script/build_compile_commands.py new file mode 100755 index 0000000000..91eb75bd00 --- /dev/null +++ b/script/build_compile_commands.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +import codecs +import json +import os +import re +import sys + +root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..'))) +basepath = os.path.join(root_path, 'esphome') + + +def walk_files(path): + for root, _, files in os.walk(path): + for name in files: + yield os.path.join(root, name) + + +def shlex_quote(s): + if not s: + return u"''" + if re.search(r'[^\w@%+=:,./-]', s) is None: + return s + + return u"'" + s.replace(u"'", u"'\"'\"'") + u"'" + + +def build_compile_commands(): + gcc_flags_json = os.path.join(root_path, '.gcc-flags.json') + if not os.path.isfile(gcc_flags_json): + print("Could not find {} file which is required for clang-tidy.") + print('Please run "pio init --ide atom" in the root esphome folder to generate that file.') + sys.exit(1) + with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f: + gcc_flags = json.load(f) + exec_path = gcc_flags['execPath'] + include_paths = gcc_flags['gccIncludePaths'].split(',') + includes = ['-I{}'.format(p) for p in include_paths] + cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ') + defines = [flag for flag in cpp_flags if flag.startswith('-D')] + command = [exec_path] + command.extend(includes) + command.extend(defines) + command.append('-std=gnu++11') + command.append('-Wall') + command.append('-Wno-delete-non-virtual-dtor') + command.append('-Wno-unused-variable') + command.append('-Wunreachable-code') + + source_files = [] + for path in walk_files(basepath): + filetypes = ('.cpp',) + ext = os.path.splitext(path)[1] + if ext in filetypes: + source_files.append(os.path.abspath(path)) + source_files.sort() + compile_commands = [{ + 'directory': root_path, + 'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])), + 'file': p + } for p in source_files] + compile_commands_json = os.path.join(root_path, 'compile_commands.json') + if os.path.isfile(compile_commands_json): + with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f: + try: + if json.load(f) == compile_commands: + return + except: + pass + with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f: + json.dump(compile_commands, f, indent=2) + + +def main(): + build_compile_commands() + print("Done.") + + +if __name__ == '__main__': + main() diff --git a/script/clang-tidy.py b/script/clang-tidy.py index ae850d427f..5b6129b35a 100755 --- a/script/clang-tidy.py +++ b/script/clang-tidy.py @@ -45,6 +45,8 @@ def run_tidy(args, tmpdir, queue, lock, failed_files): invocation.append('-p=.') if args.quiet: invocation.append('-quiet') + for arg in ['-Wfor-loop-analysis', '-Wshadow-field', '-Wshadow-field-in-constructor']: + invocation.append('-extra-arg={}'.format(arg)) invocation.append(os.path.abspath(path)) invocation_s = ' '.join(shlex_quote(x) for x in invocation) @@ -135,9 +137,6 @@ def build_compile_commands(): command.append('-Wall') command.append('-Wno-delete-non-virtual-dtor') command.append('-Wno-unused-variable') - command.append('-Wfor-loop-analysis') - command.append('-Wshadow-field') - command.append('-Wshadow-field-in-constructor') command.append('-Wunreachable-code') source_files = []