mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			42 Commits
		
	
	
		
			remove-uni
			...
			2023.7.0b3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					362a19c2e1 | ||
| 
						 | 
					f4a4956dd4 | ||
| 
						 | 
					746488cabf | ||
| 
						 | 
					4449248c6f | ||
| 
						 | 
					036e14ab7f | ||
| 
						 | 
					f840eee1b7 | ||
| 
						 | 
					553132443f | ||
| 
						 | 
					d20242f589 | ||
| 
						 | 
					68affce274 | ||
| 
						 | 
					c4b9065749 | ||
| 
						 | 
					d57a5d1793 | ||
| 
						 | 
					74e062fdb3 | ||
| 
						 | 
					6bdc0c92fe | ||
| 
						 | 
					d7945de001 | ||
| 
						 | 
					3ba2a29e54 | ||
| 
						 | 
					76b438f79c | ||
| 
						 | 
					bc14f06a07 | ||
| 
						 | 
					feee075122 | ||
| 
						 | 
					a77cf1beec | ||
| 
						 | 
					d7bfdd0efc | ||
| 
						 | 
					62aee36f82 | ||
| 
						 | 
					0709367587 | ||
| 
						 | 
					98277f6ceb | ||
| 
						 | 
					8dd509ba53 | ||
| 
						 | 
					8df455f55b | ||
| 
						 | 
					36782f13bf | ||
| 
						 | 
					e823067a6b | ||
| 
						 | 
					c3ef12d580 | ||
| 
						 | 
					321155eb40 | ||
| 
						 | 
					d34c074b92 | ||
| 
						 | 
					abc8e903c1 | ||
| 
						 | 
					832ba38f1b | ||
| 
						 | 
					70de2f5278 | ||
| 
						 | 
					604d4eec79 | ||
| 
						 | 
					b806eb6a61 | ||
| 
						 | 
					39948db59a | ||
| 
						 | 
					fbfb4e2a73 | ||
| 
						 | 
					595ac84779 | ||
| 
						 | 
					746f72a279 | ||
| 
						 | 
					dec6f04499 | ||
| 
						 | 
					a90d266017 | ||
| 
						 | 
					df9fcf9850 | 
@@ -32,7 +32,7 @@ from esphome.const import (
 | 
			
		||||
    SECRETS_FILES,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, EsphomeError, coroutine
 | 
			
		||||
from esphome.helpers import indent
 | 
			
		||||
from esphome.helpers import indent, is_ip_address
 | 
			
		||||
from esphome.util import (
 | 
			
		||||
    run_external_command,
 | 
			
		||||
    run_external_process,
 | 
			
		||||
@@ -308,8 +308,10 @@ def upload_program(config, args, host):
 | 
			
		||||
    password = ota_conf.get(CONF_PASSWORD, "")
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
        get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED]
 | 
			
		||||
    ) and CONF_MQTT in config:
 | 
			
		||||
        not is_ip_address(CORE.address)
 | 
			
		||||
        and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
 | 
			
		||||
        and CONF_MQTT in config
 | 
			
		||||
    ):
 | 
			
		||||
        from esphome import mqtt
 | 
			
		||||
 | 
			
		||||
        host = mqtt.get_esphome_device_ip(
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ ATTENUATION_MODES = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
# 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):
 | 
			
		||||
    if str(value).upper() == "VCC":
 | 
			
		||||
@@ -89,11 +133,18 @@ def validate_adc_pin(value):
 | 
			
		||||
    if CORE.is_esp32:
 | 
			
		||||
        value = pins.internal_gpio_input_pin_number(value)
 | 
			
		||||
        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")
 | 
			
		||||
 | 
			
		||||
        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")
 | 
			
		||||
 | 
			
		||||
        return pins.internal_gpio_input_pin_schema(value)
 | 
			
		||||
 | 
			
		||||
    if CORE.is_esp8266:
 | 
			
		||||
@@ -104,7 +155,7 @@ def validate_adc_pin(value):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        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(
 | 
			
		||||
            {CONF_ANALOG: True, CONF_INPUT: True}, internal=True
 | 
			
		||||
        )(value)
 | 
			
		||||
@@ -112,7 +163,7 @@ def validate_adc_pin(value):
 | 
			
		||||
    if CORE.is_rp2040:
 | 
			
		||||
        value = pins.internal_gpio_input_pin_number(value)
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
    raise NotImplementedError
 | 
			
		||||
 
 | 
			
		||||
@@ -20,20 +20,20 @@ namespace 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
 | 
			
		||||
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
 | 
			
		||||
#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
 | 
			
		||||
static const int SOC_ADC_RTC_MAX_BITWIDTH = 12;
 | 
			
		||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static const int 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_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;    // 4095 (12 bit) or 8191 (13 bit)
 | 
			
		||||
static const int32_t ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;  // 2048 (12 bit) or 4096 (13 bit)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_RP2040
 | 
			
		||||
@@ -47,14 +47,21 @@ extern "C"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
  if (channel1_ != ADC1_CHANNEL_MAX) {
 | 
			
		||||
    adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
 | 
			
		||||
    if (!autorange_) {
 | 
			
		||||
    adc1_config_channel_atten(channel_, attenuation_);
 | 
			
		||||
      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
 | 
			
		||||
  for (int i = 0; i < (int) ADC_ATTEN_MAX; i++) {
 | 
			
		||||
    auto cal_value = esp_adc_cal_characterize(ADC_UNIT_1, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
 | 
			
		||||
  for (int32_t i = 0; i < (int32_t) ADC_ATTEN_MAX; i++) {
 | 
			
		||||
    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
 | 
			
		||||
                                              &cal_characteristics_[i]);
 | 
			
		||||
    switch (cal_value) {
 | 
			
		||||
@@ -136,9 +143,9 @@ void ADCSensor::update() {
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
#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
 | 
			
		||||
  int raw = analogRead(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
  int32_t raw = analogRead(this->pin_->get_pin());  // NOLINT
 | 
			
		||||
#endif
 | 
			
		||||
  if (output_raw_) {
 | 
			
		||||
    return raw;
 | 
			
		||||
@@ -150,29 +157,53 @@ float ADCSensor::sample() {
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
float ADCSensor::sample() {
 | 
			
		||||
  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) {
 | 
			
		||||
      return NAN;
 | 
			
		||||
    }
 | 
			
		||||
    if (output_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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int raw11, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
 | 
			
		||||
  adc1_config_channel_atten(channel_, ADC_ATTEN_DB_11);
 | 
			
		||||
  raw11 = adc1_get_raw(channel_);
 | 
			
		||||
  int32_t raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
 | 
			
		||||
 | 
			
		||||
  if (channel1_ != ADC1_CHANNEL_MAX) {
 | 
			
		||||
    adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11);
 | 
			
		||||
    raw11 = adc1_get_raw(channel1_);
 | 
			
		||||
    if (raw11 < ADC_MAX) {
 | 
			
		||||
    adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6);
 | 
			
		||||
    raw6 = adc1_get_raw(channel_);
 | 
			
		||||
      adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6);
 | 
			
		||||
      raw6 = adc1_get_raw(channel1_);
 | 
			
		||||
      if (raw6 < ADC_MAX) {
 | 
			
		||||
      adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5);
 | 
			
		||||
      raw2 = adc1_get_raw(channel_);
 | 
			
		||||
        adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5);
 | 
			
		||||
        raw2 = adc1_get_raw(channel1_);
 | 
			
		||||
        if (raw2 < ADC_MAX) {
 | 
			
		||||
        adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0);
 | 
			
		||||
        raw0 = adc1_get_raw(channel_);
 | 
			
		||||
          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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int) ADC_ATTEN_DB_11]);
 | 
			
		||||
  uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int) ADC_ATTEN_DB_6]);
 | 
			
		||||
  uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int) ADC_ATTEN_DB_2_5]);
 | 
			
		||||
  uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int) ADC_ATTEN_DB_0]);
 | 
			
		||||
  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_[(int32_t) ADC_ATTEN_DB_6]);
 | 
			
		||||
  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_[(int32_t) ADC_ATTEN_DB_0]);
 | 
			
		||||
 | 
			
		||||
  // 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);
 | 
			
		||||
@@ -212,7 +243,7 @@ float ADCSensor::sample() {
 | 
			
		||||
    adc_select_input(pin - 26);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int raw = adc_read();
 | 
			
		||||
  int32_t raw = adc_read();
 | 
			
		||||
  if (this->is_temperature_) {
 | 
			
		||||
    adc_set_temp_sensor_enabled(false);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,16 +19,23 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
  /// Set the attenuation for this pin. Only available on the ESP32.
 | 
			
		||||
  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; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /// Update adc values.
 | 
			
		||||
  /// Update ADC values
 | 
			
		||||
  void update() override;
 | 
			
		||||
  /// Setup ADc
 | 
			
		||||
  /// Setup ADC
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  /// `HARDWARE_LATE` setup priority.
 | 
			
		||||
  /// `HARDWARE_LATE` setup priority
 | 
			
		||||
  float get_setup_priority() const override;
 | 
			
		||||
  void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
 | 
			
		||||
  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
 | 
			
		||||
  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};
 | 
			
		||||
  esp_adc_cal_characteristics_t cal_characteristics_[(int) ADC_ATTEN_MAX] = {};
 | 
			
		||||
  esp_adc_cal_characteristics_t cal_characteristics_[(int32_t) ADC_ATTEN_MAX] = {};
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
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.esp32 import get_esp32_variant
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
@@ -8,15 +10,15 @@ from esphome.const import (
 | 
			
		||||
    CONF_NUMBER,
 | 
			
		||||
    CONF_PIN,
 | 
			
		||||
    CONF_RAW,
 | 
			
		||||
    CONF_WIFI,
 | 
			
		||||
    DEVICE_CLASS_VOLTAGE,
 | 
			
		||||
    STATE_CLASS_MEASUREMENT,
 | 
			
		||||
    UNIT_VOLT,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
 | 
			
		||||
from . import (
 | 
			
		||||
    ATTENUATION_MODES,
 | 
			
		||||
    ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
 | 
			
		||||
    ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
 | 
			
		||||
    validate_adc_pin,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -25,7 +27,23 @@ AUTO_LOAD = ["voltage_sampler"]
 | 
			
		||||
 | 
			
		||||
def validate_config(config):
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -55,6 +73,8 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    validate_config,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
FINAL_VALIDATE_SCHEMA = final_validate_config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
@@ -81,5 +101,15 @@ async def to_code(config):
 | 
			
		||||
    if CORE.is_esp32:
 | 
			
		||||
        variant = get_esp32_variant()
 | 
			
		||||
        pin_num = config[CONF_PIN][CONF_NUMBER]
 | 
			
		||||
        if (
 | 
			
		||||
            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_channel(chan))
 | 
			
		||||
            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))
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; }
 | 
			
		||||
bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return voc <= 16383; }
 | 
			
		||||
 | 
			
		||||
void AirthingsWaveBase::update() {
 | 
			
		||||
  if (this->node_state != espbt::ClientState::ESTABLISHED) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,9 +51,9 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) {
 | 
			
		||||
  this->response_received_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; }
 | 
			
		||||
bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return radon <= 16383; }
 | 
			
		||||
 | 
			
		||||
bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; }
 | 
			
		||||
bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return co2 <= 16383; }
 | 
			
		||||
 | 
			
		||||
void AirthingsWavePlus::dump_config() {
 | 
			
		||||
  // these really don't belong here, but there doesn't seem to be a
 | 
			
		||||
 
 | 
			
		||||
@@ -1420,6 +1420,7 @@ message VoiceAssistantRequest {
 | 
			
		||||
 | 
			
		||||
  bool start = 1;
 | 
			
		||||
  string conversation_id = 2;
 | 
			
		||||
  bool use_vad = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message VoiceAssistantResponse {
 | 
			
		||||
 
 | 
			
		||||
@@ -907,12 +907,13 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_VOICE_ASSISTANT
 | 
			
		||||
bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id) {
 | 
			
		||||
bool APIConnection::request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad) {
 | 
			
		||||
  if (!this->voice_assistant_subscription_)
 | 
			
		||||
    return false;
 | 
			
		||||
  VoiceAssistantRequest msg;
 | 
			
		||||
  msg.start = start;
 | 
			
		||||
  msg.conversation_id = conversation_id;
 | 
			
		||||
  msg.use_vad = use_vad;
 | 
			
		||||
  return this->send_voice_assistant_request(msg);
 | 
			
		||||
}
 | 
			
		||||
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,7 @@ class APIConnection : public APIServerConnection {
 | 
			
		||||
  void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override {
 | 
			
		||||
    this->voice_assistant_subscription_ = msg.subscribe;
 | 
			
		||||
  }
 | 
			
		||||
  bool request_voice_assistant(bool start, const std::string &conversation_id);
 | 
			
		||||
  bool request_voice_assistant(bool start, const std::string &conversation_id, bool use_vad);
 | 
			
		||||
  void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
 | 
			
		||||
  void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -6348,6 +6348,10 @@ bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
 | 
			
		||||
      this->start = value.as_bool();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 3: {
 | 
			
		||||
      this->use_vad = value.as_bool();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -6365,6 +6369,7 @@ bool VoiceAssistantRequest::decode_length(uint32_t field_id, ProtoLengthDelimite
 | 
			
		||||
void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
  buffer.encode_bool(1, this->start);
 | 
			
		||||
  buffer.encode_string(2, this->conversation_id);
 | 
			
		||||
  buffer.encode_bool(3, this->use_vad);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
void VoiceAssistantRequest::dump_to(std::string &out) const {
 | 
			
		||||
@@ -6377,6 +6382,10 @@ void VoiceAssistantRequest::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("  conversation_id: ");
 | 
			
		||||
  out.append("'").append(this->conversation_id).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  use_vad: ");
 | 
			
		||||
  out.append(YESNO(this->use_vad));
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
  out.append("}");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1655,6 +1655,7 @@ class VoiceAssistantRequest : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  bool start{false};
 | 
			
		||||
  std::string conversation_id{};
 | 
			
		||||
  bool use_vad{false};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
 
 | 
			
		||||
@@ -323,16 +323,16 @@ void APIServer::on_shutdown() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef USE_VOICE_ASSISTANT
 | 
			
		||||
bool APIServer::start_voice_assistant(const std::string &conversation_id) {
 | 
			
		||||
bool APIServer::start_voice_assistant(const std::string &conversation_id, bool use_vad) {
 | 
			
		||||
  for (auto &c : this->clients_) {
 | 
			
		||||
    if (c->request_voice_assistant(true, conversation_id))
 | 
			
		||||
    if (c->request_voice_assistant(true, conversation_id, use_vad))
 | 
			
		||||
      return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
void APIServer::stop_voice_assistant() {
 | 
			
		||||
  for (auto &c : this->clients_) {
 | 
			
		||||
    if (c->request_voice_assistant(false, ""))
 | 
			
		||||
    if (c->request_voice_assistant(false, "", false))
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ class APIServer : public Component, public Controller {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_VOICE_ASSISTANT
 | 
			
		||||
  bool start_voice_assistant(const std::string &conversation_id);
 | 
			
		||||
  bool start_voice_assistant(const std::string &conversation_id, bool use_vad);
 | 
			
		||||
  void stop_voice_assistant();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ async def to_code(config):
 | 
			
		||||
    cg.add_build_flag("-DDSMR_WATER_MBUS_ID=" + str(config[CONF_WATER_MBUS_ID]))
 | 
			
		||||
 | 
			
		||||
    # DSMR Parser
 | 
			
		||||
    cg.add_library("glmnet/Dsmr", "0.7")
 | 
			
		||||
    cg.add_library("glmnet/Dsmr", "0.8")
 | 
			
		||||
 | 
			
		||||
    # Crypto
 | 
			
		||||
    cg.add_library("rweather/Crypto", "0.4.0")
 | 
			
		||||
 
 | 
			
		||||
@@ -243,6 +243,30 @@ CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
            device_class=DEVICE_CLASS_WATER,
 | 
			
		||||
            state_class=STATE_CLASS_TOTAL_INCREASING,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            "active_energy_import_current_average_demand"
 | 
			
		||||
        ): sensor.sensor_schema(
 | 
			
		||||
            unit_of_measurement=UNIT_KILOWATT,
 | 
			
		||||
            accuracy_decimals=3,
 | 
			
		||||
            device_class=DEVICE_CLASS_POWER,
 | 
			
		||||
            state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            "active_energy_import_maximum_demand_running_month"
 | 
			
		||||
        ): sensor.sensor_schema(
 | 
			
		||||
            unit_of_measurement=UNIT_KILOWATT,
 | 
			
		||||
            accuracy_decimals=3,
 | 
			
		||||
            device_class=DEVICE_CLASS_POWER,
 | 
			
		||||
            state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            "active_energy_import_maximum_demand_last_13_months"
 | 
			
		||||
        ): sensor.sensor_schema(
 | 
			
		||||
            unit_of_measurement=UNIT_KILOWATT,
 | 
			
		||||
            accuracy_decimals=3,
 | 
			
		||||
            device_class=DEVICE_CLASS_POWER,
 | 
			
		||||
            state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
).extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -112,7 +112,6 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
 | 
			
		||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
 | 
			
		||||
    "ld2410",
 | 
			
		||||
    baud_rate=256000,
 | 
			
		||||
    require_tx=True,
 | 
			
		||||
    require_rx=True,
 | 
			
		||||
    parity="NONE",
 | 
			
		||||
 
 | 
			
		||||
@@ -217,6 +217,7 @@ OffsetFilter = sensor_ns.class_("OffsetFilter", Filter)
 | 
			
		||||
MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter)
 | 
			
		||||
FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter)
 | 
			
		||||
ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter)
 | 
			
		||||
TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component)
 | 
			
		||||
DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component)
 | 
			
		||||
HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component)
 | 
			
		||||
DeltaFilter = sensor_ns.class_("DeltaFilter", Filter)
 | 
			
		||||
@@ -536,6 +537,15 @@ async def heartbeat_filter_to_code(config, filter_id):
 | 
			
		||||
    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(
 | 
			
		||||
    "debounce", DebounceFilter, cv.positive_time_period_milliseconds
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -373,6 +373,17 @@ void OrFilter::initialize(Sensor *parent, Filter *next) {
 | 
			
		||||
  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
 | 
			
		||||
optional<float> DebounceFilter::new_value(float 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_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit DebounceFilter(uint32_t time_period);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								esphome/components/sigma_delta_output/sigma_delta_output.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								esphome/components/sigma_delta_output/sigma_delta_output.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
#include "sigma_delta_output.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace sigma_delta_output {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "output.sigma_delta";
 | 
			
		||||
 | 
			
		||||
void SigmaDeltaOutput::setup() {
 | 
			
		||||
  if (this->pin_)
 | 
			
		||||
    this->pin_->setup();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SigmaDeltaOutput::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Sigma Delta Output:");
 | 
			
		||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
  if (this->state_change_trigger_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  State change automation configured");
 | 
			
		||||
  }
 | 
			
		||||
  if (this->turn_on_trigger_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Turn on automation configured");
 | 
			
		||||
  }
 | 
			
		||||
  if (this->turn_off_trigger_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Turn off automation configured");
 | 
			
		||||
  }
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
  LOG_FLOAT_OUTPUT(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SigmaDeltaOutput::update() {
 | 
			
		||||
  this->accum_ += this->state_;
 | 
			
		||||
  const bool next_value = this->accum_ > 0;
 | 
			
		||||
 | 
			
		||||
  if (next_value) {
 | 
			
		||||
    this->accum_ -= 1.;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (next_value != this->value_) {
 | 
			
		||||
    this->value_ = next_value;
 | 
			
		||||
    if (this->pin_) {
 | 
			
		||||
      this->pin_->digital_write(next_value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this->state_change_trigger_) {
 | 
			
		||||
      this->state_change_trigger_->trigger(next_value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (next_value && this->turn_on_trigger_) {
 | 
			
		||||
      this->turn_on_trigger_->trigger();
 | 
			
		||||
    } else if (!next_value && this->turn_off_trigger_) {
 | 
			
		||||
      this->turn_off_trigger_->trigger();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace sigma_delta_output
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "esphome/core/automation.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/components/output/float_output.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace sigma_delta_output {
 | 
			
		||||
 | 
			
		||||
class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput {
 | 
			
		||||
 public:
 | 
			
		||||
  Trigger<> *get_turn_on_trigger() {
 | 
			
		||||
@@ -25,31 +28,9 @@ class SigmaDeltaOutput : public PollingComponent, public output::FloatOutput {
 | 
			
		||||
 | 
			
		||||
  void set_pin(GPIOPin *pin) { this->pin_ = pin; };
 | 
			
		||||
  void write_state(float state) override { this->state_ = state; }
 | 
			
		||||
  void update() override {
 | 
			
		||||
    this->accum_ += this->state_;
 | 
			
		||||
    const bool next_value = this->accum_ > 0;
 | 
			
		||||
 | 
			
		||||
    if (next_value) {
 | 
			
		||||
      this->accum_ -= 1.;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (next_value != this->value_) {
 | 
			
		||||
      this->value_ = next_value;
 | 
			
		||||
      if (this->pin_) {
 | 
			
		||||
        this->pin_->digital_write(next_value);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this->state_change_trigger_) {
 | 
			
		||||
        this->state_change_trigger_->trigger(next_value);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (next_value && this->turn_on_trigger_) {
 | 
			
		||||
        this->turn_on_trigger_->trigger();
 | 
			
		||||
      } else if (!next_value && this->turn_off_trigger_) {
 | 
			
		||||
        this->turn_off_trigger_->trigger();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  void update() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  GPIOPin *pin_{nullptr};
 | 
			
		||||
 
 | 
			
		||||
@@ -954,10 +954,18 @@ void Sprinkler::pause() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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())) {
 | 
			
		||||
    // Resume only if valve has not been completed yet
 | 
			
		||||
    if (!this->valve_cycle_complete_(this->paused_valve_.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();
 | 
			
		||||
  } else {
 | 
			
		||||
    ESP_LOGD(TAG, "No valve to resume!");
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,9 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
            cv.Optional(CONF_TURN_ON_ACTION): automation.validate_automation(
 | 
			
		||||
                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),
 | 
			
		||||
@@ -70,7 +72,6 @@ async def to_code(config):
 | 
			
		||||
        )
 | 
			
		||||
    cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
 | 
			
		||||
    cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
 | 
			
		||||
    cg.add(var.set_restore_state(config[CONF_RESTORE_STATE]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@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_off_trigger() const { return this->turn_off_trigger_; }
 | 
			
		||||
void TemplateSwitch::setup() {
 | 
			
		||||
  if (!this->restore_state_)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  optional<bool> initial_state = this->get_initial_state_with_restore_mode();
 | 
			
		||||
 | 
			
		||||
  if (initial_state.has_value()) {
 | 
			
		||||
@@ -57,10 +54,8 @@ void TemplateSwitch::setup() {
 | 
			
		||||
}
 | 
			
		||||
void TemplateSwitch::dump_config() {
 | 
			
		||||
  LOG_SWITCH("", "Template Switch", this);
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Restore State: %s", YESNO(this->restore_state_));
 | 
			
		||||
  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; }
 | 
			
		||||
 | 
			
		||||
}  // namespace template_
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@ class TemplateSwitch : public switch_::Switch, public Component {
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
 | 
			
		||||
  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_off_trigger() const;
 | 
			
		||||
  void set_optimistic(bool optimistic);
 | 
			
		||||
@@ -35,7 +34,6 @@ class TemplateSwitch : public switch_::Switch, public Component {
 | 
			
		||||
  Trigger<> *turn_on_trigger_;
 | 
			
		||||
  Trigger<> *turn_off_trigger_;
 | 
			
		||||
  Trigger<> *prev_trigger_{nullptr};
 | 
			
		||||
  bool restore_state_{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace template_
 | 
			
		||||
 
 | 
			
		||||
@@ -130,7 +130,7 @@ void VoiceAssistant::start(struct sockaddr_storage *addr, uint16_t port) {
 | 
			
		||||
 | 
			
		||||
void VoiceAssistant::request_start(bool continuous) {
 | 
			
		||||
  ESP_LOGD(TAG, "Requesting start...");
 | 
			
		||||
  if (!api::global_api_server->start_voice_assistant(this->conversation_id_)) {
 | 
			
		||||
  if (!api::global_api_server->start_voice_assistant(this->conversation_id_, this->silence_detection_)) {
 | 
			
		||||
    ESP_LOGW(TAG, "Could not request start.");
 | 
			
		||||
    this->error_trigger_->trigger("not-connected", "Could not request start.");
 | 
			
		||||
    this->continuous_ = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,10 +25,9 @@ namespace voice_assistant {
 | 
			
		||||
 | 
			
		||||
// Version 1: Initial version
 | 
			
		||||
// Version 2: Adds raw speaker support
 | 
			
		||||
// Version 3: Adds continuous support
 | 
			
		||||
// Version 3: Unused/skip
 | 
			
		||||
static const uint32_t INITIAL_VERSION = 1;
 | 
			
		||||
static const uint32_t SPEAKER_SUPPORT = 2;
 | 
			
		||||
static const uint32_t SILENCE_DETECTION_SUPPORT = 3;
 | 
			
		||||
 | 
			
		||||
class VoiceAssistant : public Component {
 | 
			
		||||
 public:
 | 
			
		||||
@@ -48,9 +47,6 @@ class VoiceAssistant : public Component {
 | 
			
		||||
  uint32_t get_version() const {
 | 
			
		||||
#ifdef USE_SPEAKER
 | 
			
		||||
    if (this->speaker_ != nullptr) {
 | 
			
		||||
      if (this->silence_detection_) {
 | 
			
		||||
        return SILENCE_DETECTION_SUPPORT;
 | 
			
		||||
      }
 | 
			
		||||
      return SPEAKER_SUPPORT;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2023.7.0-dev"
 | 
			
		||||
__version__ = "2023.7.0b3"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
VALID_SUBSTITUTIONS_CHARACTERS = (
 | 
			
		||||
 
 | 
			
		||||
@@ -2475,7 +2475,6 @@ switch:
 | 
			
		||||
          level: !lambda "return 0.5;"
 | 
			
		||||
    turn_off_action:
 | 
			
		||||
      - switch.turn_on: living_room_lights_off
 | 
			
		||||
    restore_state: false
 | 
			
		||||
    on_turn_on:
 | 
			
		||||
      - switch.template.publish:
 | 
			
		||||
          id: livingroom_lights
 | 
			
		||||
@@ -2511,7 +2510,6 @@ switch:
 | 
			
		||||
      }
 | 
			
		||||
    optimistic: true
 | 
			
		||||
    assumed_state: false
 | 
			
		||||
    restore_state: true
 | 
			
		||||
    on_turn_off:
 | 
			
		||||
      - switch.template.publish:
 | 
			
		||||
          id: my_switch
 | 
			
		||||
 
 | 
			
		||||
@@ -86,6 +86,7 @@ sensor:
 | 
			
		||||
      - delta: 100
 | 
			
		||||
      - throttle: 100ms
 | 
			
		||||
      - debounce: 500s
 | 
			
		||||
      - timeout: 10min
 | 
			
		||||
      - calibrate_linear:
 | 
			
		||||
          - 0 -> 0
 | 
			
		||||
          - 100 -> 100
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user