mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	| @@ -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 | ||||||
|  |   if (channel1_ != ADC1_CHANNEL_MAX) { | ||||||
|     adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); |     adc1_config_width(ADC_WIDTH_MAX_SOC_BITS); | ||||||
|     if (!autorange_) { |     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 |   // 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) { | ||||||
|  |     adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11); | ||||||
|  |     raw11 = adc1_get_raw(channel1_); | ||||||
|     if (raw11 < ADC_MAX) { |     if (raw11 < ADC_MAX) { | ||||||
|     adc1_config_channel_atten(channel_, ADC_ATTEN_DB_6); |       adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6); | ||||||
|     raw6 = adc1_get_raw(channel_); |       raw6 = adc1_get_raw(channel1_); | ||||||
|       if (raw6 < ADC_MAX) { |       if (raw6 < ADC_MAX) { | ||||||
|       adc1_config_channel_atten(channel_, ADC_ATTEN_DB_2_5); |         adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5); | ||||||
|       raw2 = adc1_get_raw(channel_); |         raw2 = adc1_get_raw(channel1_); | ||||||
|         if (raw2 < ADC_MAX) { |         if (raw2 < ADC_MAX) { | ||||||
|         adc1_config_channel_atten(channel_, ADC_ATTEN_DB_0); |           adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0); | ||||||
|         raw0 = adc1_get_raw(channel_); |           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] | ||||||
|  |         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] |             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)) | ||||||
|   | |||||||
| @@ -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())) { | ||||||
|  |     // 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), |       ESP_LOGD(TAG, "Resuming valve %u with %u seconds remaining", this->paused_valve_.value_or(0), | ||||||
|                this->resume_duration_.value_or(0)); |                this->resume_duration_.value_or(0)); | ||||||
|       this->fsm_request_(this->paused_valve_.value(), this->resume_duration_.value()); |       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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user