mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 09:18:00 +01:00
commit
d20242f589
15 changed files with 220 additions and 64 deletions
|
@ -32,7 +32,7 @@ from esphome.const import (
|
||||||
SECRETS_FILES,
|
SECRETS_FILES,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, EsphomeError, coroutine
|
from esphome.core import CORE, EsphomeError, coroutine
|
||||||
from esphome.helpers import indent
|
from esphome.helpers import indent, is_ip_address
|
||||||
from esphome.util import (
|
from esphome.util import (
|
||||||
run_external_command,
|
run_external_command,
|
||||||
run_external_process,
|
run_external_process,
|
||||||
|
@ -308,8 +308,10 @@ def upload_program(config, args, host):
|
||||||
password = ota_conf.get(CONF_PASSWORD, "")
|
password = ota_conf.get(CONF_PASSWORD, "")
|
||||||
|
|
||||||
if (
|
if (
|
||||||
get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]
|
not is_ip_address(CORE.address)
|
||||||
) and CONF_MQTT in config:
|
and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
|
||||||
|
and CONF_MQTT in config
|
||||||
|
):
|
||||||
from esphome import mqtt
|
from esphome import mqtt
|
||||||
|
|
||||||
host = mqtt.get_esphome_device_ip(
|
host = mqtt.get_esphome_device_ip(
|
||||||
|
|
|
@ -24,6 +24,7 @@ ATTENUATION_MODES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
|
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
|
||||||
|
adc2_channel_t = cg.global_ns.enum("adc2_channel_t")
|
||||||
|
|
||||||
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
|
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
|
||||||
# pin to adc1 channel mapping
|
# pin to adc1 channel mapping
|
||||||
|
@ -78,6 +79,49 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
||||||
|
# TODO: add other variants
|
||||||
|
VARIANT_ESP32: {
|
||||||
|
4: adc2_channel_t.ADC2_CHANNEL_0,
|
||||||
|
0: adc2_channel_t.ADC2_CHANNEL_1,
|
||||||
|
2: adc2_channel_t.ADC2_CHANNEL_2,
|
||||||
|
15: adc2_channel_t.ADC2_CHANNEL_3,
|
||||||
|
13: adc2_channel_t.ADC2_CHANNEL_4,
|
||||||
|
12: adc2_channel_t.ADC2_CHANNEL_5,
|
||||||
|
14: adc2_channel_t.ADC2_CHANNEL_6,
|
||||||
|
27: adc2_channel_t.ADC2_CHANNEL_7,
|
||||||
|
25: adc2_channel_t.ADC2_CHANNEL_8,
|
||||||
|
26: adc2_channel_t.ADC2_CHANNEL_9,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32S2: {
|
||||||
|
11: adc2_channel_t.ADC2_CHANNEL_0,
|
||||||
|
12: adc2_channel_t.ADC2_CHANNEL_1,
|
||||||
|
13: adc2_channel_t.ADC2_CHANNEL_2,
|
||||||
|
14: adc2_channel_t.ADC2_CHANNEL_3,
|
||||||
|
15: adc2_channel_t.ADC2_CHANNEL_4,
|
||||||
|
16: adc2_channel_t.ADC2_CHANNEL_5,
|
||||||
|
17: adc2_channel_t.ADC2_CHANNEL_6,
|
||||||
|
18: adc2_channel_t.ADC2_CHANNEL_7,
|
||||||
|
19: adc2_channel_t.ADC2_CHANNEL_8,
|
||||||
|
20: adc2_channel_t.ADC2_CHANNEL_9,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32S3: {
|
||||||
|
11: adc2_channel_t.ADC2_CHANNEL_0,
|
||||||
|
12: adc2_channel_t.ADC2_CHANNEL_1,
|
||||||
|
13: adc2_channel_t.ADC2_CHANNEL_2,
|
||||||
|
14: adc2_channel_t.ADC2_CHANNEL_3,
|
||||||
|
15: adc2_channel_t.ADC2_CHANNEL_4,
|
||||||
|
16: adc2_channel_t.ADC2_CHANNEL_5,
|
||||||
|
17: adc2_channel_t.ADC2_CHANNEL_6,
|
||||||
|
18: adc2_channel_t.ADC2_CHANNEL_7,
|
||||||
|
19: adc2_channel_t.ADC2_CHANNEL_8,
|
||||||
|
20: adc2_channel_t.ADC2_CHANNEL_9,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32C3: {
|
||||||
|
5: adc2_channel_t.ADC2_CHANNEL_0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def validate_adc_pin(value):
|
def validate_adc_pin(value):
|
||||||
if str(value).upper() == "VCC":
|
if str(value).upper() == "VCC":
|
||||||
|
@ -89,11 +133,18 @@ def validate_adc_pin(value):
|
||||||
if CORE.is_esp32:
|
if CORE.is_esp32:
|
||||||
value = pins.internal_gpio_input_pin_number(value)
|
value = pins.internal_gpio_input_pin_number(value)
|
||||||
variant = get_esp32_variant()
|
variant = get_esp32_variant()
|
||||||
if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL:
|
if (
|
||||||
|
variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL
|
||||||
|
and variant not in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL
|
||||||
|
):
|
||||||
raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported")
|
raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported")
|
||||||
|
|
||||||
if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]:
|
if (
|
||||||
|
value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]
|
||||||
|
and value not in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant]
|
||||||
|
):
|
||||||
raise cv.Invalid(f"{variant} doesn't support ADC on this pin")
|
raise cv.Invalid(f"{variant} doesn't support ADC on this pin")
|
||||||
|
|
||||||
return pins.internal_gpio_input_pin_schema(value)
|
return pins.internal_gpio_input_pin_schema(value)
|
||||||
|
|
||||||
if CORE.is_esp8266:
|
if CORE.is_esp8266:
|
||||||
|
@ -104,7 +155,7 @@ def validate_adc_pin(value):
|
||||||
)
|
)
|
||||||
|
|
||||||
if value != 17: # A0
|
if value != 17: # A0
|
||||||
raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.")
|
raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC")
|
||||||
return pins.gpio_pin_schema(
|
return pins.gpio_pin_schema(
|
||||||
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
||||||
)(value)
|
)(value)
|
||||||
|
@ -112,7 +163,7 @@ def validate_adc_pin(value):
|
||||||
if CORE.is_rp2040:
|
if CORE.is_rp2040:
|
||||||
value = pins.internal_gpio_input_pin_number(value)
|
value = pins.internal_gpio_input_pin_number(value)
|
||||||
if value not in (26, 27, 28, 29):
|
if value not in (26, 27, 28, 29):
|
||||||
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
|
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC")
|
||||||
return pins.internal_gpio_input_pin_schema(value)
|
return pins.internal_gpio_input_pin_schema(value)
|
||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
|
@ -20,20 +20,20 @@ namespace adc {
|
||||||
|
|
||||||
static const char *const TAG = "adc";
|
static const char *const TAG = "adc";
|
||||||
|
|
||||||
// 13bit for S2, and 12bit for all other esp32 variants
|
// 13-bit for S2, 12-bit for all other ESP32 variants
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
|
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
|
||||||
|
|
||||||
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
|
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
|
||||||
#if USE_ESP32_VARIANT_ESP32S2
|
#if USE_ESP32_VARIANT_ESP32S2
|
||||||
static const int SOC_ADC_RTC_MAX_BITWIDTH = 13;
|
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13;
|
||||||
#else
|
#else
|
||||||
static const int SOC_ADC_RTC_MAX_BITWIDTH = 12;
|
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit)
|
static const int32_t ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit)
|
||||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
static const int32_t ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_RP2040
|
#ifdef USE_RP2040
|
||||||
|
@ -47,14 +47,21 @@ extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
|
if (channel1_ != ADC1_CHANNEL_MAX) {
|
||||||
if (!autorange_) {
|
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
|
||||||
adc1_config_channel_atten(channel_, attenuation_);
|
if (!autorange_) {
|
||||||
|
adc1_config_channel_atten(channel1_, attenuation_);
|
||||||
|
}
|
||||||
|
} else if (channel2_ != ADC2_CHANNEL_MAX) {
|
||||||
|
if (!autorange_) {
|
||||||
|
adc2_config_channel_atten(channel2_, attenuation_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load characteristics for each attenuation
|
// load characteristics for each attenuation
|
||||||
for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) {
|
for (int32_t i = 0; i < (int32_t) ADC_ATTEN_MAX; i++) {
|
||||||
auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
|
auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
|
||||||
|
auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
|
||||||
1100, // default vref
|
1100, // default vref
|
||||||
&cal_characteristics_[i]);
|
&cal_characteristics_[i]);
|
||||||
switch (cal_value) {
|
switch (cal_value) {
|
||||||
|
@ -136,9 +143,9 @@ void ADCSensor::update() {
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
float ADCSensor::sample() {
|
float ADCSensor::sample() {
|
||||||
#ifdef USE_ADC_SENSOR_VCC
|
#ifdef USE_ADC_SENSOR_VCC
|
||||||
int raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance)
|
int32_t raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#else
|
#else
|
||||||
int raw = analogRead(this->pin_->get_pin()); // NOLINT
|
int32_t raw = analogRead(this->pin_->get_pin()); // NOLINT
|
||||||
#endif
|
#endif
|
||||||
if (output_raw_) {
|
if (output_raw_) {
|
||||||
return raw;
|
return raw;
|
||||||
|
@ -150,29 +157,53 @@ float ADCSensor::sample() {
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
float ADCSensor::sample() {
|
float ADCSensor::sample() {
|
||||||
if (!autorange_) {
|
if (!autorange_) {
|
||||||
int raw = adc1_get_raw(channel_);
|
int32_t raw = -1;
|
||||||
|
if (channel1_ != ADC1_CHANNEL_MAX) {
|
||||||
|
raw = adc1_get_raw(channel1_);
|
||||||
|
} else if (channel2_ != ADC2_CHANNEL_MAX) {
|
||||||
|
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
|
||||||
|
}
|
||||||
|
|
||||||
if (raw == -1) {
|
if (raw == -1) {
|
||||||
return NAN;
|
return NAN;
|
||||||
}
|
}
|
||||||
if (output_raw_) {
|
if (output_raw_) {
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int) attenuation_]);
|
uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]);
|
||||||
return mv / 1000.0f;
|
return mv / 1000.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int raw11, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
|
int32_t raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_11);
|
|
||||||
raw11 = adc1_get_raw(channel_);
|
if (channel1_ != ADC1_CHANNEL_MAX) {
|
||||||
if (raw11 < ADC_MAX) {
|
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11);
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6);
|
raw11 = adc1_get_raw(channel1_);
|
||||||
raw6 = adc1_get_raw(channel_);
|
if (raw11 < ADC_MAX) {
|
||||||
if (raw6 < ADC_MAX) {
|
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6);
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5);
|
raw6 = adc1_get_raw(channel1_);
|
||||||
raw2 = adc1_get_raw(channel_);
|
if (raw6 < ADC_MAX) {
|
||||||
if (raw2 < ADC_MAX) {
|
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5);
|
||||||
adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0);
|
raw2 = adc1_get_raw(channel1_);
|
||||||
raw0 = adc1_get_raw(channel_);
|
if (raw2 < ADC_MAX) {
|
||||||
|
adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0);
|
||||||
|
raw0 = adc1_get_raw(channel1_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (channel2_ != ADC2_CHANNEL_MAX) {
|
||||||
|
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11);
|
||||||
|
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11);
|
||||||
|
if (raw11 < ADC_MAX) {
|
||||||
|
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6);
|
||||||
|
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
|
||||||
|
if (raw6 < ADC_MAX) {
|
||||||
|
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5);
|
||||||
|
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
|
||||||
|
if (raw2 < ADC_MAX) {
|
||||||
|
adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0);
|
||||||
|
adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,10 +212,10 @@ float ADCSensor::sample() {
|
||||||
return NAN;
|
return NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int) ADC_ATTEN_DB_11]);
|
uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]);
|
||||||
uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int) ADC_ATTEN_DB_6]);
|
uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
|
||||||
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int) ADC_ATTEN_DB_2_5]);
|
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
|
||||||
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int) ADC_ATTEN_DB_0]);
|
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
|
||||||
|
|
||||||
// Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
|
// Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
|
||||||
uint32_t c11 = std::min(raw11, ADC_HALF);
|
uint32_t c11 = std::min(raw11, ADC_HALF);
|
||||||
|
@ -212,7 +243,7 @@ float ADCSensor::sample() {
|
||||||
adc_select_input(pin - 26);
|
adc_select_input(pin - 26);
|
||||||
}
|
}
|
||||||
|
|
||||||
int raw = adc_read();
|
int32_t raw = adc_read();
|
||||||
if (this->is_temperature_) {
|
if (this->is_temperature_) {
|
||||||
adc_set_temp_sensor_enabled(false);
|
adc_set_temp_sensor_enabled(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,23 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_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_atten_t attenuation) { attenuation_ = attenuation; }
|
void set_attenuation(adc_atten_t attenuation) { attenuation_ = attenuation; }
|
||||||
void set_channel(adc1_channel_t channel) { channel_ = channel; }
|
void set_channel1(adc1_channel_t channel) {
|
||||||
|
channel1_ = channel;
|
||||||
|
channel2_ = ADC2_CHANNEL_MAX;
|
||||||
|
}
|
||||||
|
void set_channel2(adc2_channel_t channel) {
|
||||||
|
channel2_ = channel;
|
||||||
|
channel1_ = ADC1_CHANNEL_MAX;
|
||||||
|
}
|
||||||
void set_autorange(bool autorange) { autorange_ = autorange; }
|
void set_autorange(bool autorange) { autorange_ = autorange; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Update adc values.
|
/// Update ADC values
|
||||||
void update() override;
|
void update() override;
|
||||||
/// Setup ADc
|
/// Setup ADC
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
/// `HARDWARE_LATE` setup priority.
|
/// `HARDWARE_LATE` setup priority
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
|
void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
|
||||||
void set_output_raw(bool output_raw) { output_raw_ = output_raw; }
|
void set_output_raw(bool output_raw) { output_raw_ = output_raw; }
|
||||||
|
@ -52,9 +59,10 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
||||||
adc1_channel_t channel_{};
|
adc1_channel_t channel1_{ADC1_CHANNEL_MAX};
|
||||||
|
adc2_channel_t channel2_{ADC2_CHANNEL_MAX};
|
||||||
bool autorange_{false};
|
bool autorange_{false};
|
||||||
esp_adc_cal_characteristics_t cal_characteristics_[(int) ADC_ATTEN_MAX] = {};
|
esp_adc_cal_characteristics_t cal_characteristics_[(int32_t) ADC_ATTEN_MAX] = {};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
import esphome.final_validate as fv
|
||||||
|
from esphome.core import CORE
|
||||||
from esphome.components import sensor, voltage_sampler
|
from esphome.components import sensor, voltage_sampler
|
||||||
from esphome.components.esp32 import get_esp32_variant
|
from esphome.components.esp32 import get_esp32_variant
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
@ -8,15 +10,15 @@ from esphome.const import (
|
||||||
CONF_NUMBER,
|
CONF_NUMBER,
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
CONF_RAW,
|
CONF_RAW,
|
||||||
|
CONF_WIFI,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_VOLT,
|
UNIT_VOLT,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE
|
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
ATTENUATION_MODES,
|
ATTENUATION_MODES,
|
||||||
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
|
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
|
||||||
|
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
|
||||||
validate_adc_pin,
|
validate_adc_pin,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +27,23 @@ AUTO_LOAD = ["voltage_sampler"]
|
||||||
|
|
||||||
def validate_config(config):
|
def validate_config(config):
|
||||||
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
|
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
|
||||||
raise cv.Invalid("Automatic attenuation cannot be used when raw output is set.")
|
raise cv.Invalid("Automatic attenuation cannot be used when raw output is set")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def final_validate_config(config):
|
||||||
|
if CORE.is_esp32:
|
||||||
|
variant = get_esp32_variant()
|
||||||
|
if (
|
||||||
|
CONF_WIFI in fv.full_config.get()
|
||||||
|
and config[CONF_PIN][CONF_NUMBER]
|
||||||
|
in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant]
|
||||||
|
):
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"{variant} doesn't support ADC on this pin when Wi-Fi is configured"
|
||||||
|
)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +73,8 @@ CONFIG_SCHEMA = cv.All(
|
||||||
validate_config,
|
validate_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = final_validate_config
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
@ -81,5 +101,15 @@ async def to_code(config):
|
||||||
if CORE.is_esp32:
|
if CORE.is_esp32:
|
||||||
variant = get_esp32_variant()
|
variant = get_esp32_variant()
|
||||||
pin_num = config[CONF_PIN][CONF_NUMBER]
|
pin_num = config[CONF_PIN][CONF_NUMBER]
|
||||||
chan = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num]
|
if (
|
||||||
cg.add(var.set_channel(chan))
|
variant in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL
|
||||||
|
and pin_num in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]
|
||||||
|
):
|
||||||
|
chan = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num]
|
||||||
|
cg.add(var.set_channel1(chan))
|
||||||
|
elif (
|
||||||
|
variant in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL
|
||||||
|
and pin_num in ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant]
|
||||||
|
):
|
||||||
|
chan = ESP32_VARIANT_ADC2_PIN_TO_CHANNEL[variant][pin_num]
|
||||||
|
cg.add(var.set_channel2(chan))
|
||||||
|
|
|
@ -217,6 +217,7 @@ OffsetFilter = sensor_ns.class_("OffsetFilter", Filter)
|
||||||
MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter)
|
MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter)
|
||||||
FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter)
|
FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter)
|
||||||
ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter)
|
ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter)
|
||||||
|
TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component)
|
||||||
DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component)
|
DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component)
|
||||||
HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component)
|
HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component)
|
||||||
DeltaFilter = sensor_ns.class_("DeltaFilter", Filter)
|
DeltaFilter = sensor_ns.class_("DeltaFilter", Filter)
|
||||||
|
@ -536,6 +537,15 @@ async def heartbeat_filter_to_code(config, filter_id):
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@FILTER_REGISTRY.register(
|
||||||
|
"timeout", TimeoutFilter, cv.positive_time_period_milliseconds
|
||||||
|
)
|
||||||
|
async def timeout_filter_to_code(config, filter_id):
|
||||||
|
var = cg.new_Pvariable(filter_id, config)
|
||||||
|
await cg.register_component(var, {})
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
@FILTER_REGISTRY.register(
|
@FILTER_REGISTRY.register(
|
||||||
"debounce", DebounceFilter, cv.positive_time_period_milliseconds
|
"debounce", DebounceFilter, cv.positive_time_period_milliseconds
|
||||||
)
|
)
|
||||||
|
|
|
@ -373,6 +373,17 @@ void OrFilter::initialize(Sensor *parent, Filter *next) {
|
||||||
this->phi_.initialize(parent, nullptr);
|
this->phi_.initialize(parent, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimeoutFilter
|
||||||
|
optional<float> TimeoutFilter::new_value(float value) {
|
||||||
|
this->set_timeout("timeout", this->time_period_, [this]() { this->output(NAN); });
|
||||||
|
this->output(value);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeoutFilter::TimeoutFilter(uint32_t time_period) : time_period_(time_period) {}
|
||||||
|
float TimeoutFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
// DebounceFilter
|
// DebounceFilter
|
||||||
optional<float> DebounceFilter::new_value(float value) {
|
optional<float> DebounceFilter::new_value(float value) {
|
||||||
this->set_timeout("debounce", this->time_period_, [this, value]() { this->output(value); });
|
this->set_timeout("debounce", this->time_period_, [this, value]() { this->output(value); });
|
||||||
|
|
|
@ -313,6 +313,18 @@ class ThrottleFilter : public Filter {
|
||||||
uint32_t min_time_between_inputs_;
|
uint32_t min_time_between_inputs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TimeoutFilter : public Filter, public Component {
|
||||||
|
public:
|
||||||
|
explicit TimeoutFilter(uint32_t time_period);
|
||||||
|
|
||||||
|
optional<float> new_value(float value) override;
|
||||||
|
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t time_period_;
|
||||||
|
};
|
||||||
|
|
||||||
class DebounceFilter : public Filter, public Component {
|
class DebounceFilter : public Filter, public Component {
|
||||||
public:
|
public:
|
||||||
explicit DebounceFilter(uint32_t time_period);
|
explicit DebounceFilter(uint32_t time_period);
|
||||||
|
|
|
@ -954,10 +954,18 @@ void Sprinkler::pause() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprinkler::resume() {
|
void Sprinkler::resume() {
|
||||||
|
if (this->standby()) {
|
||||||
|
ESP_LOGD(TAG, "resume called but standby is enabled; no action taken");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->paused_valve_.has_value() && (this->resume_duration_.has_value())) {
|
if (this->paused_valve_.has_value() && (this->resume_duration_.has_value())) {
|
||||||
ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0),
|
// Resume only if valve has not been completed yet
|
||||||
this->resume_duration_.value_or(0));
|
if (!this->valve_cycle_complete_(this->paused_valve_.value())) {
|
||||||
this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value());
|
ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0),
|
||||||
|
this->resume_duration_.value_or(0));
|
||||||
|
this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value());
|
||||||
|
}
|
||||||
this->reset_resume();
|
this->reset_resume();
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "No valve to resume!");
|
ESP_LOGD(TAG, "No valve to resume!");
|
||||||
|
|
|
@ -43,7 +43,9 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Optional(CONF_TURN_ON_ACTION): automation.validate_automation(
|
cv.Optional(CONF_TURN_ON_ACTION): automation.validate_automation(
|
||||||
single=True
|
single=True
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_RESTORE_STATE, default=False): cv.boolean,
|
cv.Optional(CONF_RESTORE_STATE): cv.invalid(
|
||||||
|
"The restore_state option has been removed in 2023.7.0. Use the restore_mode option instead"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.COMPONENT_SCHEMA),
|
.extend(cv.COMPONENT_SCHEMA),
|
||||||
|
@ -70,7 +72,6 @@ async def to_code(config):
|
||||||
)
|
)
|
||||||
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||||
cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
|
cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
|
||||||
cg.add(var.set_restore_state(config[CONF_RESTORE_STATE]))
|
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
|
|
|
@ -40,9 +40,6 @@ float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWA
|
||||||
Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; }
|
Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; }
|
||||||
Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; }
|
Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; }
|
||||||
void TemplateSwitch::setup() {
|
void TemplateSwitch::setup() {
|
||||||
if (!this->restore_state_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
optional<bool> initial_state = this->get_initial_state_with_restore_mode();
|
optional<bool> initial_state = this->get_initial_state_with_restore_mode();
|
||||||
|
|
||||||
if (initial_state.has_value()) {
|
if (initial_state.has_value()) {
|
||||||
|
@ -57,10 +54,8 @@ void TemplateSwitch::setup() {
|
||||||
}
|
}
|
||||||
void TemplateSwitch::dump_config() {
|
void TemplateSwitch::dump_config() {
|
||||||
LOG_SWITCH("", "Template Switch", this);
|
LOG_SWITCH("", "Template Switch", this);
|
||||||
ESP_LOGCONFIG(TAG, " Restore State: %s", YESNO(this->restore_state_));
|
|
||||||
ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_));
|
ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_));
|
||||||
}
|
}
|
||||||
void TemplateSwitch::set_restore_state(bool restore_state) { this->restore_state_ = restore_state; }
|
|
||||||
void TemplateSwitch::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
|
void TemplateSwitch::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
|
||||||
|
|
||||||
} // namespace template_
|
} // namespace template_
|
||||||
|
|
|
@ -15,7 +15,6 @@ class TemplateSwitch : public switch_::Switch, public Component {
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
void set_state_lambda(std::function<optional<bool>()> &&f);
|
void set_state_lambda(std::function<optional<bool>()> &&f);
|
||||||
void set_restore_state(bool restore_state);
|
|
||||||
Trigger<> *get_turn_on_trigger() const;
|
Trigger<> *get_turn_on_trigger() const;
|
||||||
Trigger<> *get_turn_off_trigger() const;
|
Trigger<> *get_turn_off_trigger() const;
|
||||||
void set_optimistic(bool optimistic);
|
void set_optimistic(bool optimistic);
|
||||||
|
@ -35,7 +34,6 @@ class TemplateSwitch : public switch_::Switch, public Component {
|
||||||
Trigger<> *turn_on_trigger_;
|
Trigger<> *turn_on_trigger_;
|
||||||
Trigger<> *turn_off_trigger_;
|
Trigger<> *turn_off_trigger_;
|
||||||
Trigger<> *prev_trigger_{nullptr};
|
Trigger<> *prev_trigger_{nullptr};
|
||||||
bool restore_state_{false};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace template_
|
} // namespace template_
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Constants used by esphome."""
|
"""Constants used by esphome."""
|
||||||
|
|
||||||
__version__ = "2023.7.0b1"
|
__version__ = "2023.7.0b2"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
|
|
@ -2475,7 +2475,6 @@ switch:
|
||||||
level: !lambda "return 0.5;"
|
level: !lambda "return 0.5;"
|
||||||
turn_off_action:
|
turn_off_action:
|
||||||
- switch.turn_on: living_room_lights_off
|
- switch.turn_on: living_room_lights_off
|
||||||
restore_state: false
|
|
||||||
on_turn_on:
|
on_turn_on:
|
||||||
- switch.template.publish:
|
- switch.template.publish:
|
||||||
id: livingroom_lights
|
id: livingroom_lights
|
||||||
|
@ -2511,7 +2510,6 @@ switch:
|
||||||
}
|
}
|
||||||
optimistic: true
|
optimistic: true
|
||||||
assumed_state: false
|
assumed_state: false
|
||||||
restore_state: true
|
|
||||||
on_turn_off:
|
on_turn_off:
|
||||||
- switch.template.publish:
|
- switch.template.publish:
|
||||||
id: my_switch
|
id: my_switch
|
||||||
|
|
|
@ -86,6 +86,7 @@ sensor:
|
||||||
- delta: 100
|
- delta: 100
|
||||||
- throttle: 100ms
|
- throttle: 100ms
|
||||||
- debounce: 500s
|
- debounce: 500s
|
||||||
|
- timeout: 10min
|
||||||
- calibrate_linear:
|
- calibrate_linear:
|
||||||
- 0 -> 0
|
- 0 -> 0
|
||||||
- 100 -> 100
|
- 100 -> 100
|
||||||
|
|
Loading…
Reference in a new issue