mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 16:38:16 +01:00
Updates
This commit is contained in:
parent
c3d4ef284d
commit
521c080989
41 changed files with 396 additions and 148 deletions
|
@ -48,6 +48,11 @@ void ADCSensor::dump_config() {
|
||||||
}
|
}
|
||||||
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
|
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
void ADCSensor::update() {
|
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
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
float value_v = analogRead(this->pin_) / 4095.0f;
|
float value_v = analogRead(this->pin_) / 4095.0f;
|
||||||
switch (this->attenuation_) {
|
switch (this->attenuation_) {
|
||||||
|
@ -64,19 +69,16 @@ void ADCSensor::update() {
|
||||||
value_v *= 3.9;
|
value_v *= 3.9;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return value_v;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
#ifdef USE_ADC_SENSOR_VCC
|
#ifdef USE_ADC_SENSOR_VCC
|
||||||
float value_v = ESP.getVcc() / 1024.0f;
|
return ESP.getVcc() / 1024.0f;
|
||||||
#else
|
#else
|
||||||
float value_v = analogRead(this->pin_) / 1024.0f;
|
return analogRead(this->pin_) / 1024.0f;
|
||||||
#endif
|
#endif
|
||||||
#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
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
||||||
|
|
|
@ -3,19 +3,23 @@
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/esphal.h"
|
#include "esphome/core/esphal.h"
|
||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace adc {
|
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:
|
public:
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
/// Set the attenuation for this pin. Only available on the ESP32.
|
/// Set the attenuation for this pin. Only available on the ESP32.
|
||||||
void set_attenuation(adc_attenuation_t attenuation);
|
void set_attenuation(adc_attenuation_t attenuation);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ========== INTERNAL METHODS ==========
|
|
||||||
// (In most use cases you won't need these)
|
|
||||||
/// Update adc values.
|
/// Update adc values.
|
||||||
void update() override;
|
void update() override;
|
||||||
/// Setup ADc
|
/// Setup ADc
|
||||||
|
@ -24,6 +28,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent {
|
||||||
/// `HARDWARE_LATE` setup priority.
|
/// `HARDWARE_LATE` setup priority.
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||||
|
float sample() override;
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
std::string unique_id() override;
|
std::string unique_id() override;
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome import pins
|
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
|
from esphome.const import CONF_ATTENUATION, CONF_ID, CONF_PIN, ICON_FLASH, UNIT_VOLT
|
||||||
|
|
||||||
|
|
||||||
|
AUTO_LOAD = ['voltage_sampler']
|
||||||
|
|
||||||
ATTENUATION_MODES = {
|
ATTENUATION_MODES = {
|
||||||
'0db': cg.global_ns.ADC_0db,
|
'0db': cg.global_ns.ADC_0db,
|
||||||
'2.5db': cg.global_ns.ADC_2_5db,
|
'2.5db': cg.global_ns.ADC_2_5db,
|
||||||
|
@ -20,7 +23,8 @@ def validate_adc_pin(value):
|
||||||
|
|
||||||
|
|
||||||
adc_ns = cg.esphome_ns.namespace('adc')
|
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({
|
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 2).extend({
|
||||||
cv.GenerateID(): cv.declare_id(ADCSensor),
|
cv.GenerateID(): cv.declare_id(ADCSensor),
|
||||||
|
@ -37,7 +41,6 @@ def to_code(config):
|
||||||
|
|
||||||
if config[CONF_PIN] == 'VCC':
|
if config[CONF_PIN] == 'VCC':
|
||||||
cg.add_define('USE_ADC_SENSOR_VCC')
|
cg.add_define('USE_ADC_SENSOR_VCC')
|
||||||
cg.add_global(cg.global_ns.ADC_MODE(cg.global_ns.ADC_VCC))
|
|
||||||
else:
|
else:
|
||||||
cg.add(var.set_pin(config[CONF_PIN]))
|
cg.add(var.set_pin(config[CONF_PIN]))
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from esphome.components import i2c
|
||||||
from esphome.const import CONF_ID
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
DEPENDENCIES = ['i2c']
|
DEPENDENCIES = ['i2c']
|
||||||
AUTO_LOAD = ['sensor']
|
AUTO_LOAD = ['sensor', 'voltage_sampler']
|
||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
|
|
||||||
ads1115_ns = cg.esphome_ns.namespace('ads1115')
|
ads1115_ns = cg.esphome_ns.namespace('ads1115')
|
||||||
|
|
|
@ -59,7 +59,9 @@ void ADS1115Component::setup() {
|
||||||
}
|
}
|
||||||
for (auto *sensor : this->sensors_) {
|
for (auto *sensor : this->sensors_) {
|
||||||
this->set_interval(sensor->get_name(), sensor->update_interval(),
|
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() {
|
void ADS1115Component::dump_config() {
|
||||||
|
@ -76,11 +78,11 @@ void ADS1115Component::dump_config() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float ADS1115Component::get_setup_priority() const { return setup_priority::DATA; }
|
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;
|
uint16_t config;
|
||||||
if (!this->read_byte_16(ADS1115_REGISTER_CONFIG, &config)) {
|
if (!this->read_byte_16(ADS1115_REGISTER_CONFIG, &config)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return;
|
return NAN;
|
||||||
}
|
}
|
||||||
// Multiplexer
|
// Multiplexer
|
||||||
// 0bxBBBxxxxxxxxxxxx
|
// 0bxBBBxxxxxxxxxxxx
|
||||||
|
@ -96,7 +98,7 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) {
|
||||||
|
|
||||||
if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) {
|
if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return;
|
return NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// about 1.6 ms with 860 samples per second
|
// about 1.6 ms with 860 samples per second
|
||||||
|
@ -107,7 +109,7 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) {
|
||||||
if (millis() - start > 100) {
|
if (millis() - start > 100) {
|
||||||
ESP_LOGW(TAG, "Reading ADS1115 timed out");
|
ESP_LOGW(TAG, "Reading ADS1115 timed out");
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return;
|
return NAN;
|
||||||
}
|
}
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
@ -115,7 +117,7 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) {
|
||||||
uint16_t raw_conversion;
|
uint16_t raw_conversion;
|
||||||
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) {
|
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return;
|
return NAN;
|
||||||
}
|
}
|
||||||
auto signed_conversion = static_cast<int16_t>(raw_conversion);
|
auto signed_conversion = static_cast<int16_t>(raw_conversion);
|
||||||
|
|
||||||
|
@ -143,16 +145,24 @@ void ADS1115Component::request_measurement_(ADS1115Sensor *sensor) {
|
||||||
millivolts = NAN;
|
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();
|
this->status_clear_warning();
|
||||||
|
return millivolts / 1e4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ADS1115Sensor::get_multiplexer() const { return this->multiplexer_; }
|
uint8_t ADS1115Sensor::get_multiplexer() const { return this->multiplexer_; }
|
||||||
void ADS1115Sensor::set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
|
void ADS1115Sensor::set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
|
||||||
uint8_t ADS1115Sensor::get_gain() const { return this->gain_; }
|
uint8_t ADS1115Sensor::get_gain() const { return this->gain_; }
|
||||||
void ADS1115Sensor::set_gain(ADS1115Gain gain) { this->gain_ = 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 ads1115
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
#include "esphome/components/i2c/i2c.h"
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ads1115 {
|
namespace ads1115 {
|
||||||
|
@ -38,28 +39,30 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
|
||||||
/// HARDWARE_LATE setup priority
|
/// HARDWARE_LATE setup priority
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
protected:
|
|
||||||
/// Helper method to request a measurement from a sensor.
|
/// Helper method to request a measurement from a sensor.
|
||||||
void request_measurement_(ADS1115Sensor *sensor);
|
float request_measurement_(ADS1115Sensor *sensor);
|
||||||
|
|
||||||
|
protected:
|
||||||
std::vector<ADS1115Sensor *> sensors_;
|
std::vector<ADS1115Sensor *> sensors_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Internal holder class that is in instance of Sensor so that the hub can create individual 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:
|
public:
|
||||||
|
ADS1115Sensor(ADS1115Component *parent) : parent_(parent) {}
|
||||||
|
void update() override;
|
||||||
void set_multiplexer(ADS1115Multiplexer multiplexer);
|
void set_multiplexer(ADS1115Multiplexer multiplexer);
|
||||||
void set_gain(ADS1115Gain gain);
|
void set_gain(ADS1115Gain gain);
|
||||||
|
|
||||||
// ========== INTERNAL METHODS ==========
|
float sample() override;
|
||||||
// (In most use cases you won't need these)
|
|
||||||
uint8_t get_multiplexer() const;
|
uint8_t get_multiplexer() const;
|
||||||
uint8_t get_gain() const;
|
uint8_t get_gain() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ADS1115Component *parent_;
|
||||||
ADS1115Multiplexer multiplexer_;
|
ADS1115Multiplexer multiplexer_;
|
||||||
ADS1115Gain gain_;
|
ADS1115Gain gain_;
|
||||||
uint32_t update_interval_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ads1115
|
} // namespace ads1115
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
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
|
from esphome.components import sensor, voltage_sampler
|
||||||
from esphome.components.ads1115 import ADS1115Component
|
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
|
||||||
|
@ -40,7 +40,8 @@ def validate_gain(value):
|
||||||
return cv.enum(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'
|
CONF_ADS1115_ID = 'ads1115_id'
|
||||||
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 3).extend({
|
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):
|
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 sensor.register_sensor(var, config)
|
||||||
|
yield cg.register_component(var, config)
|
||||||
|
|
||||||
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
||||||
cg.add(var.set_gain(config[CONF_GAIN]))
|
cg.add(var.set_gain(config[CONF_GAIN]))
|
||||||
|
|
||||||
hub = yield cg.get_variable(config[CONF_ADS1115_ID])
|
cg.add(paren.register_sensor(var))
|
||||||
cg.add(hub.register_sensor(var))
|
|
||||||
|
|
|
@ -260,7 +260,6 @@ APIConnection::APIConnection(AsyncClient *client, APIServer *parent)
|
||||||
}
|
}
|
||||||
APIConnection::~APIConnection() { delete this->client_; }
|
APIConnection::~APIConnection() { delete this->client_; }
|
||||||
void APIConnection::on_error_(int8_t error) {
|
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
|
// disconnect will also be called, nothing to do here
|
||||||
this->remove_ = true;
|
this->remove_ = true;
|
||||||
}
|
}
|
||||||
|
|
18
esphome/components/ble_ibeacon/__init__.py
Normal file
18
esphome/components/ble_ibeacon/__init__.py
Normal file
|
@ -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)
|
|
@ -1,24 +1,24 @@
|
||||||
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, esp32_ble_tracker
|
||||||
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESP_BLE_DEVICE_SCHEMA, \
|
from esphome.const import CONF_MAC_ADDRESS, CONF_ID
|
||||||
ESPBTDeviceListener
|
|
||||||
from esphome.const import CONF_MAC_ADDRESS, CONF_NAME, CONF_ID
|
|
||||||
|
|
||||||
DEPENDENCIES = ['esp32_ble_tracker']
|
DEPENDENCIES = ['esp32_ble_tracker']
|
||||||
|
|
||||||
ble_presence_ns = cg.esphome_ns.namespace('ble_presence')
|
ble_presence_ns = cg.esphome_ns.namespace('ble_presence')
|
||||||
BLEPresenceDevice = ble_presence_ns.class_('BLEPresenceDevice', binary_sensor.BinarySensor,
|
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({
|
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
|
||||||
cv.GenerateID(): cv.declare_id(BLEPresenceDevice),
|
cv.GenerateID(): cv.declare_id(BLEPresenceDevice),
|
||||||
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
|
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):
|
def to_code(config):
|
||||||
hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], hub, config[CONF_MAC_ADDRESS].as_hex)
|
|
||||||
yield cg.register_component(var, config)
|
yield cg.register_component(var, config)
|
||||||
|
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||||
yield binary_sensor.register_binary_sensor(var, config)
|
yield binary_sensor.register_binary_sensor(var, config)
|
||||||
|
|
||||||
|
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||||
|
|
|
@ -13,9 +13,9 @@ class BLEPresenceDevice : public binary_sensor::BinarySensor,
|
||||||
public esp32_ble_tracker::ESPBTDeviceListener,
|
public esp32_ble_tracker::ESPBTDeviceListener,
|
||||||
public Component {
|
public Component {
|
||||||
public:
|
public:
|
||||||
BLEPresenceDevice(const std::string &name, esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address)
|
void set_address(uint64_t address) {
|
||||||
: binary_sensor::BinarySensor(name), esp32_ble_tracker::ESPBTDeviceListener(parent), address_(address) {}
|
address_ = address;
|
||||||
|
}
|
||||||
void on_scan_end() override {
|
void on_scan_end() override {
|
||||||
if (!this->found_)
|
if (!this->found_)
|
||||||
this->publish_state(false);
|
this->publish_state(false);
|
||||||
|
@ -29,7 +29,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensor,
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void setup() override { this->setup_ble(); }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ namespace ble_rssi {
|
||||||
|
|
||||||
class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDeviceListener, public Component {
|
class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDeviceListener, public Component {
|
||||||
public:
|
public:
|
||||||
BLERSSISensor(const std::string &name, esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address)
|
void set_address(uint64_t address) {
|
||||||
: sensor::Sensor(name), esp32_ble_tracker::ESPBTDeviceListener(parent), address_(address) {}
|
address_ = address;
|
||||||
|
}
|
||||||
void on_scan_end() override {
|
void on_scan_end() override {
|
||||||
if (!this->found_)
|
if (!this->found_)
|
||||||
this->publish_state(NAN);
|
this->publish_state(NAN);
|
||||||
|
@ -27,7 +27,6 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void setup() override { this->setup_ble(); }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
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
|
from esphome.components import sensor, esp32_ble_tracker
|
||||||
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
|
from esphome.const import CONF_MAC_ADDRESS, CONF_ID, UNIT_DECIBEL, ICON_SIGNAL
|
||||||
ESP_BLE_DEVICE_SCHEMA
|
|
||||||
from esphome.const import CONF_MAC_ADDRESS, CONF_NAME, CONF_ID, UNIT_DECIBEL, ICON_SIGNAL
|
|
||||||
|
|
||||||
DEPENDENCIES = ['esp32_ble_tracker']
|
DEPENDENCIES = ['esp32_ble_tracker']
|
||||||
|
|
||||||
ble_rssi_ns = cg.esphome_ns.namespace('ble_rssi')
|
ble_rssi_ns = cg.esphome_ns.namespace('ble_rssi')
|
||||||
BLERSSISensor = ble_rssi_ns.class_('BLERSSISensor', sensor.Sensor, cg.Component,
|
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({
|
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_DECIBEL, ICON_SIGNAL, 0).extend({
|
||||||
cv.GenerateID(): cv.declare_id(BLERSSISensor),
|
cv.GenerateID(): cv.declare_id(BLERSSISensor),
|
||||||
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
|
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):
|
def to_code(config):
|
||||||
hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], hub, config[CONF_MAC_ADDRESS].as_hex)
|
|
||||||
yield cg.register_component(var, config)
|
yield cg.register_component(var, config)
|
||||||
|
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||||
yield sensor.register_sensor(var, config)
|
yield sensor.register_sensor(var, config)
|
||||||
|
|
||||||
|
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32
|
from esphome.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32
|
||||||
|
from esphome.core import coroutine
|
||||||
|
|
||||||
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
|
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
|
||||||
AUTO_LOAD = ['xiaomi_ble']
|
AUTO_LOAD = ['xiaomi_ble', 'ble_ibeacon']
|
||||||
|
|
||||||
CONF_ESP32_BLE_ID = 'esp32_ble_id'
|
CONF_ESP32_BLE_ID = 'esp32_ble_id'
|
||||||
esp32_ble_tracker_ns = cg.esphome_ns.namespace('esp32_ble_tracker')
|
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])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
yield cg.register_component(var, config)
|
yield cg.register_component(var, config)
|
||||||
cg.add(var.set_scan_interval(config[CONF_SCAN_INTERVAL]))
|
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
|
||||||
|
|
|
@ -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<uint8_t>(raw_data[i]));
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "0x%02X ", static_cast<uint8_t>(raw_data[i]));
|
||||||
|
}
|
||||||
|
res += buf;
|
||||||
|
}
|
||||||
|
sprintf(buf, "(%zu)", raw_data.size());
|
||||||
|
res += buf;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
ESPBTUUID::ESPBTUUID() : uuid_() {}
|
ESPBTUUID::ESPBTUUID() : uuid_() {}
|
||||||
ESPBTUUID ESPBTUUID::from_uint16(uint16_t uuid) {
|
ESPBTUUID ESPBTUUID::from_uint16(uint16_t uuid) {
|
||||||
ESPBTUUID ret;
|
ESPBTUUID ret;
|
||||||
|
@ -259,12 +275,22 @@ std::string ESPBTUUID::to_string() {
|
||||||
return sbuf;
|
return sbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESPBLEiBeacon::ESPBLEiBeacon(const uint8_t *data) { memcpy(&this->beacon_data_, data, sizeof(beacon_data_)); }
|
||||||
|
optional<ESPBLEiBeacon> 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<const uint8_t *>(data.data()));
|
||||||
|
}
|
||||||
|
|
||||||
void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) {
|
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++)
|
for (uint8_t i = 0; i < ESP_BD_ADDR_LEN; i++)
|
||||||
this->address_[i] = param.bda[i];
|
this->address_[i] = param.bda[i];
|
||||||
this->address_type_ = param.ble_addr_type;
|
this->address_type_ = param.ble_addr_type;
|
||||||
this->rssi_ = param.rssi;
|
this->rssi_ = param.rssi;
|
||||||
this->parse_adv(param);
|
this->parse_adv_(param);
|
||||||
|
|
||||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||||
ESP_LOGVV(TAG, "Parse Result:");
|
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);
|
this->address_[2], this->address_[3], this->address_[4], this->address_[5], address_type);
|
||||||
|
|
||||||
ESP_LOGVV(TAG, " RSSI: %d", this->rssi_);
|
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()) {
|
if (this->tx_power_.has_value()) {
|
||||||
ESP_LOGVV(TAG, " TX Power: %d", *this->tx_power_);
|
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_) {
|
for (auto uuid : this->service_uuids_) {
|
||||||
ESP_LOGVV(TAG, " Service UUID: %s", uuid.to_string().c_str());
|
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, " Manufacturer data: %s", hexencode(this->manufacturer_data_).c_str());
|
||||||
ESP_LOGVV(TAG, " Service data: '%s'", this->service_data_.c_str());
|
ESP_LOGVV(TAG, " Service data: %s", hexencode(this->service_data_).c_str());
|
||||||
|
|
||||||
if (this->service_data_uuid_.has_value()) {
|
if (this->service_data_uuid_.has_value()) {
|
||||||
ESP_LOGVV(TAG, " Service Data UUID: %s", this->service_data_uuid_->to_string().c_str());
|
ESP_LOGVV(TAG, " Service Data UUID: %s", this->service_data_uuid_->to_string().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[200];
|
ESP_LOGVV(TAG, "Adv data: %s",
|
||||||
size_t off = 0;
|
hexencode(std::string(reinterpret_cast<const char *>(param.ble_adv), param.adv_data_len)).c_str());
|
||||||
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);
|
|
||||||
#endif
|
#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;
|
size_t offset = 0;
|
||||||
const uint8_t *payload = param.ble_adv;
|
const uint8_t *payload = param.ble_adv;
|
||||||
uint8_t len = param.adv_data_len;
|
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 esp32_ble_tracker
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,31 @@ class ESPBTUUID {
|
||||||
esp_bt_uuid_t uuid_;
|
esp_bt_uuid_t uuid_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ESPBLEiBeacon {
|
||||||
|
public:
|
||||||
|
ESPBLEiBeacon(const uint8_t *data);
|
||||||
|
static optional<ESPBLEiBeacon> 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 {
|
class ESPBTDevice {
|
||||||
public:
|
public:
|
||||||
void parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m);
|
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;
|
std::string address_str() const;
|
||||||
|
|
||||||
uint64_t address_uint64() const;
|
uint64_t address_uint64() const;
|
||||||
|
@ -51,8 +70,13 @@ class ESPBTDevice {
|
||||||
const std::string &get_manufacturer_data() const;
|
const std::string &get_manufacturer_data() const;
|
||||||
const std::string &get_service_data() const;
|
const std::string &get_service_data() const;
|
||||||
const optional<ESPBTUUID> &get_service_data_uuid() const;
|
const optional<ESPBTUUID> &get_service_data_uuid() const;
|
||||||
|
const optional<ESPBLEiBeacon> get_ibeacon() const {
|
||||||
|
return ESPBLEiBeacon::from_manufacturer_data(this->manufacturer_data_);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m);
|
||||||
|
|
||||||
esp_bd_addr_t address_{
|
esp_bd_addr_t address_{
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
@ -72,28 +96,30 @@ class ESP32BLETracker;
|
||||||
|
|
||||||
class ESPBTDeviceListener {
|
class ESPBTDeviceListener {
|
||||||
public:
|
public:
|
||||||
ESPBTDeviceListener(ESP32BLETracker *parent) : parent_(parent) {}
|
|
||||||
void setup_ble();
|
|
||||||
virtual void on_scan_end() {}
|
virtual void on_scan_end() {}
|
||||||
virtual bool parse_device(const ESPBTDevice &device) = 0;
|
virtual bool parse_device(const ESPBTDevice &device) = 0;
|
||||||
|
void set_parent(ESP32BLETracker *parent) {
|
||||||
|
parent_ = parent;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ESP32BLETracker *parent_;
|
ESP32BLETracker *parent_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ESP32BLETracker : public Component {
|
class ESP32BLETracker : public Component {
|
||||||
public:
|
public:
|
||||||
void set_scan_interval(uint32_t scan_interval);
|
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.
|
/// Setup the FreeRTOS task and the Bluetooth stack.
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
void loop() 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);
|
void print_bt_device_info(const ESPBTDevice &device);
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ template<typename... Ts> class AddressableSet : public Action<Ts...> {
|
||||||
void play(Ts... x) override {
|
void play(Ts... x) override {
|
||||||
auto *out = (AddressableLight *) this->parent_->get_output();
|
auto *out = (AddressableLight *) this->parent_->get_output();
|
||||||
int32_t range_from = this->range_from_.value_or(x..., 0);
|
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);
|
auto range = out->range(range_from, range_to);
|
||||||
if (this->red_.has_value())
|
if (this->red_.has_value())
|
||||||
range.set_red(this->red_.value(x...));
|
range.set_red(this->red_.value(x...));
|
||||||
|
|
|
@ -3,8 +3,9 @@ import esphome.config_validation as cv
|
||||||
from esphome import automation
|
from esphome import automation
|
||||||
from esphome.const import CONF_ID, CONF_TRANSITION_LENGTH, CONF_STATE, CONF_FLASH_LENGTH, \
|
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_EFFECT, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, \
|
||||||
CONF_COLOR_TEMPERATURE
|
CONF_COLOR_TEMPERATURE, CONF_RANGE_FROM, CONF_RANGE_TO
|
||||||
from .types import DimRelativeAction, ToggleAction, LightState, LightControlAction
|
from .types import DimRelativeAction, ToggleAction, LightState, LightControlAction, \
|
||||||
|
AddressableLightState, AddressableSet
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action('light.toggle', ToggleAction, automation.maybe_simple_id({
|
@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'
|
CONF_RELATIVE_BRIGHTNESS = 'relative_brightness'
|
||||||
LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema({
|
LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema({
|
||||||
cv.Required(CONF_ID): cv.use_id(LightState),
|
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),
|
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)
|
templ = yield cg.templatable(config[CONF_TRANSITION_LENGTH], args, cg.uint32)
|
||||||
cg.add(var.set_transition_length(templ))
|
cg.add(var.set_transition_length(templ))
|
||||||
yield var
|
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
|
||||||
|
|
|
@ -15,6 +15,7 @@ LightColorValues = light_ns.class_('LightColorValues')
|
||||||
ToggleAction = light_ns.class_('ToggleAction', automation.Action)
|
ToggleAction = light_ns.class_('ToggleAction', automation.Action)
|
||||||
LightControlAction = light_ns.class_('LightControlAction', automation.Action)
|
LightControlAction = light_ns.class_('LightControlAction', automation.Action)
|
||||||
DimRelativeAction = light_ns.class_('DimRelativeAction', automation.Action)
|
DimRelativeAction = light_ns.class_('DimRelativeAction', automation.Action)
|
||||||
|
AddressableSet = light_ns.class_('AddressableSet', automation.Action)
|
||||||
|
|
||||||
# Effects
|
# Effects
|
||||||
LightEffect = light_ns.class_('LightEffect')
|
LightEffect = light_ns.class_('LightEffect')
|
||||||
|
|
|
@ -71,6 +71,7 @@ def validate_local_no_higher_than_global(value):
|
||||||
|
|
||||||
Logger = logger_ns.class_('Logger', cg.Component)
|
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({
|
CONFIG_SCHEMA = cv.All(cv.Schema({
|
||||||
cv.GenerateID(): cv.declare_id(Logger),
|
cv.GenerateID(): cv.declare_id(Logger),
|
||||||
cv.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int,
|
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_LEVEL, default='DEBUG'): is_log_level,
|
||||||
cv.Optional(CONF_LOGS, default={}): cv.Schema({
|
cv.Optional(CONF_LOGS, default={}): cv.Schema({
|
||||||
cv.string: is_log_level,
|
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)
|
}).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')
|
cg.add_build_flag('-DCORE_DEBUG_LEVEL=5')
|
||||||
if CORE.is_esp32 and is_at_least_very_verbose:
|
if CORE.is_esp32 and is_at_least_very_verbose:
|
||||||
cg.add_build_flag('-DENABLE_I2C_DEBUG_BUFFER')
|
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')
|
cg.add_build_flag('-DUSE_STORE_LOG_STR_IN_FLASH')
|
||||||
|
|
||||||
# Register at end for safe mode
|
# Register at end for safe mode
|
||||||
|
|
|
@ -99,17 +99,18 @@ void MPU6050Component::dump_config() {
|
||||||
|
|
||||||
void MPU6050Component::update() {
|
void MPU6050Component::update() {
|
||||||
ESP_LOGV(TAG, " Updating MPU6050...");
|
ESP_LOGV(TAG, " Updating MPU6050...");
|
||||||
uint16_t data[7];
|
uint16_t raw_data[7];
|
||||||
if (!this->read_bytes_16(MPU6050_REGISTER_ACCEL_XOUT_H, data, 7)) {
|
if (!this->read_bytes_16(MPU6050_REGISTER_ACCEL_XOUT_H, raw_data, 7)) {
|
||||||
this->status_set_warning();
|
this->status_set_warning();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto *data = reinterpret_cast<int16_t *>(raw_data);
|
||||||
|
|
||||||
float accel_x = data[0] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH;
|
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_y = data[1] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH;
|
||||||
float accel_z = data[2] * 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_x = data[4] * MPU6050_SCALE_DPS_PER_DIGIT_2000;
|
||||||
float gyro_y = data[5] * MPU6050_SCALE_DPS_PER_DIGIT_2000;
|
float gyro_y = data[5] * MPU6050_SCALE_DPS_PER_DIGIT_2000;
|
||||||
|
|
|
@ -51,8 +51,6 @@ sensor_ns = cg.esphome_ns.namespace('sensor')
|
||||||
Sensor = sensor_ns.class_('Sensor', cg.Nameable)
|
Sensor = sensor_ns.class_('Sensor', cg.Nameable)
|
||||||
SensorPtr = Sensor.operator('ptr')
|
SensorPtr = Sensor.operator('ptr')
|
||||||
|
|
||||||
PollingSensorComponent = sensor_ns.class_('PollingSensorComponent', cg.PollingComponent, Sensor)
|
|
||||||
|
|
||||||
# Triggers
|
# Triggers
|
||||||
SensorStateTrigger = sensor_ns.class_('SensorStateTrigger', automation.Trigger.template(cg.float_))
|
SensorStateTrigger = sensor_ns.class_('SensorStateTrigger', automation.Trigger.template(cg.float_))
|
||||||
SensorRawStateTrigger = sensor_ns.class_('SensorRawStateTrigger',
|
SensorRawStateTrigger = sensor_ns.class_('SensorRawStateTrigger',
|
||||||
|
|
|
@ -11,16 +11,6 @@ namespace time {
|
||||||
static const char *TAG = "time";
|
static const char *TAG = "time";
|
||||||
|
|
||||||
RealTimeClock::RealTimeClock() = default;
|
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() {
|
void RealTimeClock::call_setup() {
|
||||||
this->setup_internal_();
|
this->setup_internal_();
|
||||||
setenv("TZ", this->timezone_.c_str(), 1);
|
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();
|
struct tm c_tm = this->to_c_tm();
|
||||||
return ::strftime(buffer, buffer_len, format, &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),
|
return ESPTime{.second = uint8_t(c_tm->tm_sec),
|
||||||
.minute = uint8_t(c_tm->tm_min),
|
.minute = uint8_t(c_tm->tm_min),
|
||||||
.hour = uint8_t(c_tm->tm_hour),
|
.hour = uint8_t(c_tm->tm_hour),
|
||||||
|
|
|
@ -52,7 +52,26 @@ struct ESPTime {
|
||||||
|
|
||||||
bool in_range() const;
|
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();
|
struct tm to_c_tm();
|
||||||
|
|
||||||
|
@ -81,10 +100,19 @@ class RealTimeClock : public Component {
|
||||||
std::string get_timezone() { return this->timezone_; }
|
std::string get_timezone() { return this->timezone_; }
|
||||||
|
|
||||||
/// Get the time in the currently defined 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.
|
/// 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;
|
void call_setup() override;
|
||||||
|
|
||||||
|
|
4
esphome/components/voltage_sampler/__init__.py
Normal file
4
esphome/components/voltage_sampler/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
voltage_sampler_ns = cg.esphome_ns.namespace('voltage_sampler')
|
||||||
|
VoltageSampler = voltage_sampler_ns.class_('VoltageSampler')
|
16
esphome/components/voltage_sampler/voltage_sampler.h
Normal file
16
esphome/components/voltage_sampler/voltage_sampler.h
Normal file
|
@ -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
|
|
@ -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]);
|
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
return buf;
|
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) {
|
bool sta_field_equal(const uint8_t *field_a, const uint8_t *field_b, int len) {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
|
|
@ -164,8 +164,6 @@ class WiFiComponent : public Component {
|
||||||
/// Reconnect WiFi if required.
|
/// Reconnect WiFi if required.
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
void on_safe_shutdown() override;
|
|
||||||
|
|
||||||
bool has_sta() const;
|
bool has_sta() const;
|
||||||
bool has_ap() const;
|
bool has_ap() const;
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,8 @@ bool WiFiComponent::wifi_sta_connect_(WiFiAP ap) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->wifi_apply_hostname_();
|
||||||
|
|
||||||
err = esp_wifi_connect();
|
err = esp_wifi_connect();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGW(TAG, "esp_wifi_connect failed! %d", err);
|
ESP_LOGW(TAG, "esp_wifi_connect failed! %d", err);
|
||||||
|
|
|
@ -196,6 +196,8 @@ bool WiFiComponent::wifi_sta_connect_(WiFiAP ap) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->wifi_apply_hostname_();
|
||||||
|
|
||||||
ETS_UART_INTR_DISABLE();
|
ETS_UART_INTR_DISABLE();
|
||||||
ret = wifi_station_connect();
|
ret = wifi_station_connect();
|
||||||
ETS_UART_INTR_ENABLE();
|
ETS_UART_INTR_ENABLE();
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
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.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
|
from esphome.components import esp32_ble_tracker
|
||||||
ESP_BLE_DEVICE_SCHEMA
|
|
||||||
from esphome.const import CONF_ID
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
DEPENDENCIES = ['esp32_ble_tracker']
|
DEPENDENCIES = ['esp32_ble_tracker']
|
||||||
|
|
||||||
xiaomi_ble_ns = cg.esphome_ns.namespace('xiaomi_ble')
|
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({
|
CONFIG_SCHEMA = cv.Schema({
|
||||||
cv.GenerateID(): cv.declare_id(XiaomiListener),
|
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):
|
def to_code(config):
|
||||||
hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(config[CONF_ID], hub)
|
yield esp32_ble_tracker.register_ble_device(var, config)
|
||||||
yield cg.register_component(var, config)
|
|
||||||
|
|
|
@ -138,8 +138,6 @@ bool XiaomiListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void XiaomiListener::setup() { this->setup_ble(); }
|
|
||||||
XiaomiListener::XiaomiListener(esp32_ble_tracker::ESP32BLETracker *parent) : ESPBTDeviceListener(parent) {}
|
|
||||||
|
|
||||||
} // namespace xiaomi_ble
|
} // namespace xiaomi_ble
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -22,11 +22,9 @@ bool parse_xiaomi_data_byte(uint8_t data_type, const uint8_t *data, uint8_t data
|
||||||
|
|
||||||
optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &device);
|
optional<XiaomiParseResult> 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:
|
public:
|
||||||
XiaomiListener(esp32_ble_tracker::ESP32BLETracker *parent);
|
|
||||||
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
||||||
void setup() override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xiaomi_ble
|
} // namespace xiaomi_ble
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
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
|
from esphome.components import sensor, esp32_ble_tracker
|
||||||
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
|
|
||||||
ESP_BLE_DEVICE_SCHEMA
|
|
||||||
from esphome.const import CONF_BATTERY_LEVEL, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
|
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, \
|
UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, ICON_BATTERY, CONF_ID, \
|
||||||
CONF_MOISTURE, CONF_ILLUMINANCE, ICON_BRIGHTNESS_5, UNIT_LUX, CONF_CONDUCTIVITY, \
|
CONF_MOISTURE, CONF_ILLUMINANCE, ICON_BRIGHTNESS_5, UNIT_LUX, CONF_CONDUCTIVITY, \
|
||||||
|
@ -12,7 +10,8 @@ DEPENDENCIES = ['esp32_ble_tracker']
|
||||||
AUTO_LOAD = ['xiaomi_ble']
|
AUTO_LOAD = ['xiaomi_ble']
|
||||||
|
|
||||||
xiaomi_miflora_ns = cg.esphome_ns.namespace('xiaomi_miflora')
|
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({
|
CONFIG_SCHEMA = cv.Schema({
|
||||||
cv.GenerateID(): cv.declare_id(XiaomiMiflora),
|
cv.GenerateID(): cv.declare_id(XiaomiMiflora),
|
||||||
|
@ -23,13 +22,15 @@ CONFIG_SCHEMA = cv.Schema({
|
||||||
cv.Optional(CONF_CONDUCTIVITY):
|
cv.Optional(CONF_CONDUCTIVITY):
|
||||||
sensor.sensor_schema(UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0),
|
sensor.sensor_schema(UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0),
|
||||||
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 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):
|
def to_code(config):
|
||||||
hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(config[CONF_ID], hub, config[CONF_MAC_ADDRESS].as_hex)
|
|
||||||
yield cg.register_component(var, config)
|
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:
|
if CONF_TEMPERATURE in config:
|
||||||
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||||
|
|
|
@ -12,8 +12,9 @@ namespace xiaomi_miflora {
|
||||||
|
|
||||||
class XiaomiMiflora : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
|
class XiaomiMiflora : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
|
||||||
public:
|
public:
|
||||||
XiaomiMiflora(esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address)
|
void set_address(uint64_t address) {
|
||||||
: ESPBTDeviceListener(parent), address_(address) {}
|
address_ = address;
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
|
||||||
if (device.address_uint64() != this->address_)
|
if (device.address_uint64() != this->address_)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
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
|
from esphome.components import sensor, esp32_ble_tracker
|
||||||
from esphome.components.esp32_ble_tracker import CONF_ESP32_BLE_ID, ESPBTDeviceListener, \
|
|
||||||
ESP_BLE_DEVICE_SCHEMA
|
|
||||||
from esphome.const import CONF_BATTERY_LEVEL, CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
|
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
|
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']
|
AUTO_LOAD = ['xiaomi_ble']
|
||||||
|
|
||||||
xiaomi_mijia_ns = cg.esphome_ns.namespace('xiaomi_mijia')
|
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({
|
CONFIG_SCHEMA = cv.Schema({
|
||||||
cv.GenerateID(): cv.declare_id(XiaomiMijia),
|
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_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_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1),
|
||||||
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 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):
|
def to_code(config):
|
||||||
hub = yield cg.get_variable(config[CONF_ESP32_BLE_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(config[CONF_ID], hub, config[CONF_MAC_ADDRESS].as_hex)
|
|
||||||
yield cg.register_component(var, config)
|
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:
|
if CONF_TEMPERATURE in config:
|
||||||
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
|
||||||
|
|
|
@ -12,8 +12,9 @@ namespace xiaomi_mijia {
|
||||||
|
|
||||||
class XiaomiMijia : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
|
class XiaomiMijia : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
|
||||||
public:
|
public:
|
||||||
XiaomiMijia(esp32_ble_tracker::ESP32BLETracker *parent, uint64_t address)
|
void set_address(uint64_t address) {
|
||||||
: ESPBTDeviceListener(parent), address_(address) {}
|
address_ = address;
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
|
||||||
if (device.address_uint64() != this->address_)
|
if (device.address_uint64() != this->address_)
|
||||||
|
|
|
@ -317,6 +317,8 @@ CONF_PULSE_LENGTH = 'pulse_length'
|
||||||
CONF_QOS = 'qos'
|
CONF_QOS = 'qos'
|
||||||
CONF_RANDOM = 'random'
|
CONF_RANDOM = 'random'
|
||||||
CONF_RANGE = 'range'
|
CONF_RANGE = 'range'
|
||||||
|
CONF_RANGE_FROM = 'range_from'
|
||||||
|
CONF_RANGE_TO = 'range_to'
|
||||||
CONF_RATE = 'rate'
|
CONF_RATE = 'rate'
|
||||||
CONF_RAW = 'raw'
|
CONF_RAW = 'raw'
|
||||||
CONF_REBOOT_TIMEOUT = 'reboot_timeout'
|
CONF_REBOOT_TIMEOUT = 'reboot_timeout'
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#define HOT __attribute__((hot))
|
#define HOT __attribute__((hot))
|
||||||
#define ESPDEPRECATED(msg) __attribute__((deprecated(msg)))
|
#define ESPDEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||||
#define ALWAYS_INLINE __attribute__((always_inline))
|
#define ALWAYS_INLINE __attribute__((always_inline))
|
||||||
|
#define PACKED __attribute__((packed))
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
|
|
79
script/build_compile_commands.py
Executable file
79
script/build_compile_commands.py
Executable file
|
@ -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()
|
|
@ -45,6 +45,8 @@ def run_tidy(args, tmpdir, queue, lock, failed_files):
|
||||||
invocation.append('-p=.')
|
invocation.append('-p=.')
|
||||||
if args.quiet:
|
if args.quiet:
|
||||||
invocation.append('-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.append(os.path.abspath(path))
|
||||||
invocation_s = ' '.join(shlex_quote(x) for x in invocation)
|
invocation_s = ' '.join(shlex_quote(x) for x in invocation)
|
||||||
|
|
||||||
|
@ -135,9 +137,6 @@ def build_compile_commands():
|
||||||
command.append('-Wall')
|
command.append('-Wall')
|
||||||
command.append('-Wno-delete-non-virtual-dtor')
|
command.append('-Wno-delete-non-virtual-dtor')
|
||||||
command.append('-Wno-unused-variable')
|
command.append('-Wno-unused-variable')
|
||||||
command.append('-Wfor-loop-analysis')
|
|
||||||
command.append('-Wshadow-field')
|
|
||||||
command.append('-Wshadow-field-in-constructor')
|
|
||||||
command.append('-Wunreachable-code')
|
command.append('-Wunreachable-code')
|
||||||
|
|
||||||
source_files = []
|
source_files = []
|
||||||
|
|
Loading…
Reference in a new issue