Merge pull request #2 from esphome/dev

Update dev branch
This commit is contained in:
Michiel van Turnhout 2019-05-08 20:30:24 +02:00 committed by GitHub
commit 5f66aac1b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 576 additions and 220 deletions

27
.editorconfig Normal file
View file

@ -0,0 +1,27 @@
root = true
# general
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
# python
[*.{py}]
indent_style = space
indent_size = 4
# C++
[*.{cpp,h,tcc}]
indent_style = space
indent_size = 2
# Web
[*.{js,html,css}]
indent_style = space
indent_size = 2
# YAML
[*.{yaml,yml}]
indent_style = space
indent_size = 2

6
.gitpod.yml Normal file
View file

@ -0,0 +1,6 @@
ports:
- port: 6052
onOpen: open-preview
tasks:
- before: script/setup
command: python -m esphome config dashboard

View file

@ -9,7 +9,7 @@
# pylint: disable=unused-import
from esphome.cpp_generator import ( # noqa
Expression, RawExpression, TemplateArguments,
Expression, RawExpression, RawStatement, TemplateArguments,
StructInitializer, ArrayInitializer, safe_exp, Statement,
progmem_array, statement, variable, Pvariable, new_Pvariable,
add, add_global, add_library, add_build_flag, add_define,

View file

@ -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"; }

View file

@ -3,19 +3,22 @@
#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 +27,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;

View file

@ -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]))

View file

@ -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')

View file

@ -59,7 +59,7 @@ 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 +76,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 +96,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 +107,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 +115,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<int16_t>(raw_conversion);
@ -143,16 +143,22 @@ 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

View file

@ -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,29 @@ 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<ADS1115Sensor *> 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

View file

@ -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))

View file

@ -67,6 +67,7 @@ def to_code(config):
templ = cg.TemplateArguments(*template_args)
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], templ,
conf[CONF_SERVICE], service_type_args)
cg.add(var.register_user_service(trigger))
yield automation.build_automation(trigger, func_args, conf)
cg.add_define('USE_API')

View file

@ -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;
}

View file

@ -13,7 +13,7 @@ BH1750_RESOLUTIONS = {
0.5: BH1750Resolution.BH1750_RESOLUTION_0P5_LX,
}
BH1750Sensor = bh1750_ns.class_('BH1750Sensor', sensor.PollingSensorComponent, i2c.I2CDevice)
BH1750Sensor = bh1750_ns.class_('BH1750Sensor', sensor.Sensor, cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1).extend({
cv.GenerateID(): cv.declare_id(BH1750Sensor),

View file

@ -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))

View file

@ -13,9 +13,7 @@ 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 +27,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; }

View file

@ -11,9 +11,7 @@ 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 +25,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; }

View file

@ -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))

View file

@ -1,6 +1,6 @@
from esphome.components import output
import esphome.config_validation as cv
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_OUTPUTS, CONF_TYPE
from .. import custom_ns

View file

@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_SENSORS
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_SENSORS
from .. import custom_ns
CustomSensorConstructor = custom_ns.class_('CustomSensorConstructor')
@ -20,6 +20,5 @@ def to_code(config):
rhs = CustomSensorConstructor(template_)
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_SENSORS]):
sens = cg.new_Pvariable(conf[CONF_ID], var.get_switch(i))
cg.add(sens.set_name(conf[CONF_NAME]))
sens = cg.Pvariable(conf[CONF_ID], var.get_sensor(i))
yield sensor.register_sensor(sens, conf)

View file

@ -1,10 +1,9 @@
from esphome.components import switch
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_SWITCHES
import esphome.config_validation as cv
from esphome.components import switch
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_SWITCHES
from .. import custom_ns
CustomSwitchConstructor = custom_ns.class_('CustomSwitchConstructor')
CONFIG_SCHEMA = cv.Schema({
@ -24,6 +23,5 @@ def to_code(config):
rhs = CustomSwitchConstructor(template_)
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_SWITCHES]):
switch_ = cg.new_Pvariable(conf[CONF_ID], var.get_switch(i))
cg.add(switch_.set_name(conf[CONF_NAME]))
switch_ = cg.Pvariable(conf[CONF_ID], var.get_switch(i))
yield switch.register_switch(switch_, conf)

View file

@ -1,7 +1,7 @@
from esphome.components import text_sensor
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_TEXT_SENSORS
import esphome.config_validation as cv
from esphome.components import text_sensor
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_TEXT_SENSORS
from .. import custom_ns
CustomTextSensorConstructor = custom_ns.class_('CustomTextSensorConstructor')
@ -24,6 +24,5 @@ def to_code(config):
var = cg.variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_TEXT_SENSORS]):
text = cg.new_Pvariable(conf[CONF_ID], var.get_text_sensor(i))
cg.add(text.set_name(conf[CONF_NAME]))
text = cg.Pvariable(conf[CONF_ID], var.get_text_sensor(i))
yield text_sensor.register_text_sensor(text, conf)

View file

@ -5,7 +5,7 @@ from esphome.components import sensor
from esphome.const import CONF_ID, CONF_PIN, UNIT_PERCENT, ICON_PERCENT
duty_cycle_ns = cg.esphome_ns.namespace('duty_cycle')
DutyCycleSensor = duty_cycle_ns.class_('DutyCycleSensor', sensor.PollingSensorComponent)
DutyCycleSensor = duty_cycle_ns.class_('DutyCycleSensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_PERCENT, ICON_PERCENT, 1).extend({
cv.GenerateID(): cv.declare_id(DutyCycleSensor),

View file

@ -1,6 +1,7 @@
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']
@ -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

View file

@ -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::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> 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 &param) {
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<const char *>(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 &param) {
void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param) {
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

View file

@ -31,12 +31,32 @@ class ESPBTUUID {
esp_bt_uuid_t uuid_;
};
class ESPBLEiBeacon {
public:
ESPBLEiBeacon() { memset(&this->beacon_data_, 0, sizeof(this->beacon_data_)); }
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 {
public:
void parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param);
void parse_adv(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &param);
std::string address_str() const;
uint64_t address_uint64() const;
@ -51,8 +71,13 @@ class ESPBTDevice {
const std::string &get_manufacturer_data() const;
const std::string &get_service_data() const;
const optional<ESPBTUUID> &get_service_data_uuid() const;
const optional<ESPBLEiBeacon> 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 &param);
esp_bd_addr_t address_{
0,
};
@ -72,28 +97,28 @@ 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);

View file

@ -8,11 +8,8 @@
namespace esphome {
namespace esp32_hall {
class ESP32HallSensor : public sensor::PollingSensorComponent {
class ESP32HallSensor : public sensor::Sensor, public PollingComponent {
public:
explicit ESP32HallSensor(const std::string &name, uint32_t update_interval)
: sensor::PollingSensorComponent(name, update_interval) {}
void dump_config() override;
void update() override;

View file

@ -1,21 +1,19 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import CONF_ID, CONF_NAME, CONF_UPDATE_INTERVAL, ESP_PLATFORM_ESP32, \
UNIT_MICROTESLA, ICON_MAGNET
from esphome.const import CONF_ID, ESP_PLATFORM_ESP32, UNIT_MICROTESLA, ICON_MAGNET
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
esp32_hall_ns = cg.esphome_ns.namespace('esp32_hall')
ESP32HallSensor = esp32_hall_ns.class_('ESP32HallSensor', sensor.PollingSensorComponent)
ESP32HallSensor = esp32_hall_ns.class_('ESP32HallSensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_MICROTESLA, ICON_MAGNET, 1).extend({
cv.GenerateID(): cv.declare_id(ESP32HallSensor),
cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
}).extend(cv.COMPONENT_SCHEMA)
}).extend(cv.polling_component_schema('60s'))
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], config[CONF_UPDATE_INTERVAL])
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)

View file

@ -4,6 +4,8 @@ from esphome import pins
from esphome.components import fastled_base
from esphome.const import CONF_CHIPSET, CONF_NUM_LEDS, CONF_PIN, CONF_RGB_ORDER
AUTO_LOAD = ['fastled_base']
CHIPSETS = [
'NEOPIXEL',
'TM1829',

View file

@ -5,7 +5,7 @@ from esphome.components import sensor
from esphome.const import CONF_CLK_PIN, CONF_GAIN, CONF_ID, ICON_SCALE
hx711_ns = cg.esphome_ns.namespace('hx711')
HX711Sensor = hx711_ns.class_('HX711Sensor', sensor.PollingSensorComponent)
HX711Sensor = hx711_ns.class_('HX711Sensor', sensor.Sensor, cg.PollingComponent)
CONF_DOUT_PIN = 'dout_pin'

View file

@ -10,8 +10,8 @@ ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
def validate_frequency_bit_depth(obj):
frequency = obj.get(CONF_FREQUENCY, 1000)
bit_depth = obj.get(CONF_BIT_DEPTH, 12)
frequency = obj[CONF_FREQUENCY]
bit_depth = obj[CONF_BIT_DEPTH]
max_freq = APB_CLOCK_FREQ / (2**bit_depth)
if frequency > max_freq:
raise cv.Invalid('Maximum frequency for bit depth {} is {}Hz'.format(bit_depth, max_freq))

View file

@ -112,7 +112,7 @@ template<typename... Ts> class AddressableSet : public Action<Ts...> {
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...));

View file

@ -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,44 @@ 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))
def rgbw_to_exp(x):
return 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

View file

@ -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')

View file

@ -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

View file

@ -4,7 +4,8 @@ from esphome.components import sensor, spi
from esphome.const import CONF_ID, ICON_THERMOMETER, UNIT_CELSIUS
max31855_ns = cg.esphome_ns.namespace('max31855')
MAX31855Sensor = max31855_ns.class_('MAX31855Sensor', sensor.PollingSensorComponent, spi.SPIDevice)
MAX31855Sensor = max31855_ns.class_('MAX31855Sensor', sensor.Sensor, cg.PollingComponent,
spi.SPIDevice)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({
cv.GenerateID(): cv.declare_id(MAX31855Sensor),

View file

@ -14,7 +14,7 @@ void MAX6675Sensor::update() {
// Conversion time typ: 170ms, max: 220ms
auto f = std::bind(&MAX6675Sensor::read_data_, this);
this->set_timeout("value", 220, f);
this->set_timeout("value", 250, f);
}
void MAX6675Sensor::setup() {

View file

@ -4,7 +4,7 @@ from esphome.components import sensor, spi
from esphome.const import CONF_ID, ICON_THERMOMETER, UNIT_CELSIUS
max6675_ns = cg.esphome_ns.namespace('max6675')
MAX6675Sensor = max6675_ns.class_('MAX6675Sensor', sensor.PollingSensorComponent,
MAX6675Sensor = max6675_ns.class_('MAX6675Sensor', sensor.Sensor, cg.PollingComponent,
spi.SPIDevice)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).extend({

View file

@ -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<int16_t *>(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;

View file

@ -150,12 +150,13 @@ def exp_mqtt_message(config):
@coroutine_with_priority(40.0)
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
cg.add_library('AsyncMqttClient', '0.8.2')
cg.add_define('USE_MQTT')
cg.add_global(mqtt_ns.using)
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_broker_address(config[CONF_BROKER]))
cg.add(var.set_broker_port(config[CONF_PORT]))
cg.add(var.set_username(config[CONF_USERNAME]))

View file

@ -152,7 +152,7 @@ class NeoPixelRGBLightOutput : public NeoPixelBusLightOutputBase<T_METHOD, T_COL
}
protected:
light::ESPColorView get_view_internal(int32_t index) const override {
light::ESPColorView get_view_internal(int32_t index) const override { // NOLINT
uint8_t *base = this->controller_->Pixels() + 3ULL * index;
return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
nullptr, this->effect_data_ + index, &this->correction_);
@ -171,7 +171,7 @@ class NeoPixelRGBWLightOutput : public NeoPixelBusLightOutputBase<T_METHOD, T_CO
}
protected:
light::ESPColorView get_view_internal(int32_t index) const override {
light::ESPColorView get_view_internal(int32_t index) const override { // NOLINT
uint8_t *base = this->controller_->Pixels() + 4ULL * index;
return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
base + this->rgb_offsets_[3], this->effect_data_ + index, &this->correction_);

View file

@ -37,7 +37,23 @@ class PartitionLightOutput : public light::AddressableLight, public Component {
auto &last_seg = this->segments_[this->segments_.size() - 1];
return last_seg.get_dst_offset() + last_seg.get_size();
}
light::ESPColorView operator[](int32_t index) const override {
void clear_effect_data() override {
for (auto &seg : this->segments_) {
seg.get_src()->clear_effect_data();
}
}
light::LightTraits get_traits() override { return this->segments_[0].get_src()->get_traits(); }
void loop() override {
if (this->should_show_()) {
for (auto seg : this->segments_) {
seg.get_src()->schedule_show();
}
this->mark_shown_();
}
}
protected:
light::ESPColorView get_view_internal(int32_t index) const override {
uint32_t lo = 0;
uint32_t hi = this->segments_.size() - 1;
while (lo < hi) {
@ -61,22 +77,7 @@ class PartitionLightOutput : public light::AddressableLight, public Component {
view.raw_set_color_correction(&this->correction_);
return view;
}
void clear_effect_data() override {
for (auto &seg : this->segments_) {
seg.get_src()->clear_effect_data();
}
}
light::LightTraits get_traits() override { return this->segments_[0].get_src()->get_traits(); }
void loop() override {
if (this->should_show_()) {
for (auto seg : this->segments_) {
seg.get_src()->schedule_show();
}
this->mark_shown_();
}
}
protected:
std::vector<AddressableSegment> segments_;
};

View file

@ -18,7 +18,7 @@ COUNT_MODES = {
COUNT_MODE_SCHEMA = cv.enum(COUNT_MODES, upper=True)
PulseCounterSensor = pulse_counter_ns.class_('PulseCounterSensor',
sensor.PollingSensorComponent)
sensor.Sensor, cg.PollingComponent)
def validate_internal_filter(value):

View file

@ -6,7 +6,7 @@ from esphome.const import CONF_ID, CONF_PIN, UNIT_SECOND, ICON_TIMER
pulse_width_ns = cg.esphome_ns.namespace('pulse_width')
PulseWidthSensor = pulse_width_ns.class_('PulseWidthSensor', sensor.PollingSensorComponent)
PulseWidthSensor = pulse_width_ns.class_('PulseWidthSensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 3).extend({
cv.GenerateID(): cv.declare_id(PulseWidthSensor),

View file

@ -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',

View file

@ -5,7 +5,7 @@ from esphome.components import sensor
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_STATE, UNIT_EMPTY, ICON_EMPTY
from .. import template_ns
TemplateSensor = template_ns.class_('TemplateSensor', sensor.PollingSensorComponent)
TemplateSensor = template_ns.class_('TemplateSensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({
cv.GenerateID(): cv.declare_id(TemplateSensor),

View file

@ -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),

View file

@ -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,13 @@ 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;

View file

@ -27,7 +27,8 @@ def validate_integration_time(value):
return cv.enum(INTEGRATION_TIMES, int=True)(value)
TSL2561Sensor = tsl2561_ns.class_('TSL2561Sensor', sensor.PollingSensorComponent, i2c.I2CDevice)
TSL2561Sensor = tsl2561_ns.class_('TSL2561Sensor', sensor.Sensor, cg.PollingComponent,
i2c.I2CDevice)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1).extend({
cv.GenerateID(): cv.declare_id(TSL2561Sensor),

View file

@ -9,7 +9,7 @@ CONF_PULSE_TIME = 'pulse_time'
ultrasonic_ns = cg.esphome_ns.namespace('ultrasonic')
UltrasonicSensorComponent = ultrasonic_ns.class_('UltrasonicSensorComponent',
sensor.PollingSensorComponent)
sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({
cv.GenerateID(): cv.declare_id(UltrasonicSensorComponent),

View file

@ -4,7 +4,7 @@ from esphome.components import sensor
from esphome.const import CONF_ID, UNIT_SECOND, ICON_TIMER
uptime_ns = cg.esphome_ns.namespace('uptime')
UptimeSensor = uptime_ns.class_('UptimeSensor', sensor.PollingSensorComponent)
UptimeSensor = uptime_ns.class_('UptimeSensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_SECOND, ICON_TIMER, 0).extend({
cv.GenerateID(): cv.declare_id(UptimeSensor),

View 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')

View 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

View file

@ -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++) {

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -5,7 +5,7 @@ from esphome.const import CONF_ID, ICON_WIFI, UNIT_DECIBEL
DEPENDENCIES = ['wifi']
wifi_signal_ns = cg.esphome_ns.namespace('wifi_signal')
WiFiSignalSensor = wifi_signal_ns.class_('WiFiSignalSensor', sensor.PollingSensorComponent)
WiFiSignalSensor = wifi_signal_ns.class_('WiFiSignalSensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_DECIBEL, ICON_WIFI, 0).extend({
cv.GenerateID(): cv.declare_id(WiFiSignalSensor),

View file

@ -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)

View file

@ -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

View file

@ -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);
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

View file

@ -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])

View file

@ -12,8 +12,7 @@ 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_)

View file

@ -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])

View file

@ -12,8 +12,7 @@ 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_)

View file

@ -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'

View file

@ -55,7 +55,7 @@ template<typename... Ts> class Trigger {
bool is_running() {
if (this->automation_parent_ == nullptr)
return false;
return this->automation_parent_.is_running();
return this->automation_parent_->is_running();
}
protected:

View file

@ -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 {

View file

@ -152,7 +152,7 @@ def add_includes(includes):
for include in includes:
path = CORE.relative_config_path(include)
res = os.path.relpath(path, CORE.relative_build_path('src')).replace(os.path.sep, '/')
cg.add_global(cg.RawExpression(u'#include "{}"'.format(res)))
cg.add_global(cg.RawStatement(u'#include "{}"'.format(res)))
@coroutine_with_priority(100.0)

View file

@ -430,6 +430,9 @@ const validateModal = new LogModalElem({
name: 'validate',
onPrepare: (modalElem, config) => {
modalElem.querySelector(".stop-logs").innerHTML = "Stop";
modalElem.querySelector(".action-edit").setAttribute('data-node', validateModal.activeConfig);
modalElem.querySelector(".action-upload").setAttribute('data-node', validateModal.activeConfig);
modalElem.querySelector(".action-upload").classList.add('disabled');
},
onProcessExit: (modalElem, code) => {
if (code === 0) {
@ -437,6 +440,7 @@ const validateModal = new LogModalElem({
html: `<code class="inlinecode">${validateModal.activeConfig}</code> is valid 👍`,
displayLength: 5000,
});
modalElem.querySelector(".action-upload").classList.remove('disabled');
} else {
M.toast({
html: `<code class="inlinecode">${validateModal.activeConfig}</code> is invalid 😕`,
@ -552,6 +556,7 @@ editor.session.setOption('useSoftTabs', true);
editor.session.setOption('tabSize', 2);
const saveButton = editModalElem.querySelector(".save-button");
const saveValidateButton = editModalElem.querySelector(".save-validate-button");
const saveEditor = () => {
fetch(`./edit?configuration=${activeEditorConfig}`, {
credentials: "same-origin",
@ -572,12 +577,14 @@ editor.commands.addCommand({
});
saveButton.addEventListener('click', saveEditor);
saveValidateButton.addEventListener('click', saveEditor);
document.querySelectorAll(".action-edit").forEach((btn) => {
btn.addEventListener('click', (e) => {
activeEditorConfig = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(editModalElem);
const filenameField = editModalElem.querySelector('.filename');
editModalElem.querySelector(".save-validate-button").setAttribute('data-node', activeEditorConfig);
filenameField.innerHTML = activeEditorConfig;
fetch(`./edit?configuration=${activeEditorConfig}`, {credentials: "same-origin"})

View file

@ -147,6 +147,8 @@
<pre class="log"></pre>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat action-edit">Edit</a>
<a class="modal-close waves-effect waves-green btn-flat action-upload">Upload</a>
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
@ -430,6 +432,7 @@
</div>
<div class="modal-footer">
<a class="waves-effect waves-green btn-flat save-button">Save</a>
<a class="modal-close waves-effect waves-green btn-flat action-validate save-validate-button">Save &amp; Validate</a>
<a class="modal-close waves-effect waves-green btn-flat">Close</a>
</div>
</div>

100
script/build_compile_commands.py Executable file
View file

@ -0,0 +1,100 @@
#!/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')
temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
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_all_include():
# Build a cpp file that includes all header files in this repo.
# Otherwise header-only integrations would not be tested by clang-tidy
headers = []
for path in walk_files(basepath):
filetypes = ('.h',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
path = os.path.relpath(path, root_path)
include_p = path.replace(os.path.sep, '/')
headers.append('#include "{}"'.format(include_p))
headers.sort()
headers.append('')
content = '\n'.join(headers)
with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
f.write(content)
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.append(temp_header_file)
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_all_include()
build_compile_commands()
print("Done.")
if __name__ == '__main__':
main()

View file

@ -22,8 +22,18 @@ files = []
for root, _, fs in os.walk('esphome'):
for f in fs:
_, ext = os.path.splitext(f)
if ext in ('.h', '.c', '.cpp', '.tcc', '.py'):
if ext in ('.h', '.c', '.cpp', '.tcc', '.yaml', '.yml', '.ini', '.txt',
'.py', '.html', '.js', '.md'):
files.append(os.path.join(root, f))
ignore = [
'esphome/dashboard/static/materialize.min.js',
'esphome/dashboard/static/ace.js',
'esphome/dashboard/static/mode-yaml.js',
'esphome/dashboard/static/theme-dreamweaver.js',
'esphome/dashboard/static/jquery.validate.min.js',
'esphome/dashboard/static/ext-searchbox.js',
]
files = [f for f in files if f not in ignore]
files.sort()
errors = collections.defaultdict(list)

View file

@ -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 = []
@ -265,8 +264,6 @@ def main():
print('Ctrl-C detected, goodbye.')
if tmpdir:
shutil.rmtree(tmpdir)
if os.path.exists(temp_header_file):
os.remove(temp_header_file)
os.kill(0, 9)
if args.fix and failed_files:
@ -275,12 +272,8 @@ def main():
subprocess.call(['clang-apply-replacements-7', tmpdir])
except:
print('Error applying fixes.\n', file=sys.stderr)
if os.path.exists(temp_header_file):
os.remove(temp_header_file)
raise
if os.path.exists(temp_header_file):
os.remove(temp_header_file)
sys.exit(return_code)

View file

@ -12,5 +12,5 @@ fi
set -x
script/clang-tidy.py -c --fix
script/clang-tidy.py -c --fix --all-headers
script/clang-format.py -c -i

38
tests/custom.h Normal file
View file

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

View file

@ -7,6 +7,8 @@ esphome:
- wait_until:
- api.connected
- wifi.connected
includes:
- custom.h
substitutions:
devicename: test3
@ -65,6 +67,7 @@ ota:
logger:
hardware_uart: UART1
level: DEBUG
esp8266_store_log_strings_in_flash: false
web_server:
@ -122,6 +125,14 @@ sensor:
name: Color Temperature
integration_time: 700ms
gain: 60x
- platform: custom
lambda: |-
auto s = new CustomSensor();
App.register_component(s);
return {s};
sensors:
- id: custom_sensor
name: Custom Sensor
time:
- platform: homeassistant
@ -178,6 +189,14 @@ binary_sensor:
- platform: ttp229_lsf
channel: 1
name: TTP229 LSF Test
- platform: custom
lambda: |-
auto s = new CustomBinarySensor();
App.register_component(s);
return {s};
binary_sensors:
- id: custom_binary_sensor
name: Custom Binary Sensor
remote_receiver:
pin: GPIO12
@ -211,6 +230,14 @@ text_sensor:
- platform: homeassistant
entity_id: sensor.hello_world2
id: ha_hello_world2
- platform: custom
lambda: |-
auto s = new CustomTextSensor();
App.register_component(s);
return {s};
text_sensors:
- id: custom_text_sensor
name: Custom Text Sensor
script:
- id: my_script
@ -233,6 +260,19 @@ switch:
id: gpio_switch2
pin: GPIO1
interlock: *interlock
- platform: custom
lambda: |-
auto s = new CustomSwitch();
return {s};
switches:
- id: custom_switch
name: Custom Switch
custom_component:
lambda: |-
auto s = new CustomComponent();
s->set_update_interval(15000);
return {s};
stepper:
- platform: uln2003