mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			14 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e725e15f7a | ||
| 
						 | 
					4d1113e265 | ||
| 
						 | 
					52352ac27a | ||
| 
						 | 
					f60b2b754d | ||
| 
						 | 
					b89c04b928 | ||
| 
						 | 
					12090657bb | ||
| 
						 | 
					4e21cf0bdd | ||
| 
						 | 
					ba4ef72d56 | ||
| 
						 | 
					f3e6a4314f | ||
| 
						 | 
					e14ce3d950 | ||
| 
						 | 
					0f1e186189 | ||
| 
						 | 
					96d208e0d8 | ||
| 
						 | 
					38ed38864e | ||
| 
						 | 
					a12ba7bd38 | 
@@ -429,15 +429,16 @@ void APIServer::on_shutdown() {
 | 
			
		||||
 | 
			
		||||
#ifdef USE_VOICE_ASSISTANT
 | 
			
		||||
bool APIServer::start_voice_assistant() {
 | 
			
		||||
  bool result = false;
 | 
			
		||||
  for (auto &c : this->clients_) {
 | 
			
		||||
    result |= c->request_voice_assistant(true);
 | 
			
		||||
    if (c->request_voice_assistant(true))
 | 
			
		||||
      return true;
 | 
			
		||||
  }
 | 
			
		||||
  return result;
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
void APIServer::stop_voice_assistant() {
 | 
			
		||||
  for (auto &c : this->clients_) {
 | 
			
		||||
    c->request_voice_assistant(false);
 | 
			
		||||
    if (c->request_voice_assistant(false))
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -17,26 +17,29 @@ debug_ns = cg.esphome_ns.namespace("debug")
 | 
			
		||||
DebugComponent = debug_ns.class_("DebugComponent", cg.PollingComponent)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(DebugComponent),
 | 
			
		||||
        cv.Optional(CONF_DEVICE): cv.invalid(
 | 
			
		||||
            "The 'device' option has been moved to the 'debug' text_sensor component"
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_FREE): cv.invalid(
 | 
			
		||||
            "The 'free' option has been moved to the 'debug' sensor component"
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_BLOCK): cv.invalid(
 | 
			
		||||
            "The 'block' option has been moved to the 'debug' sensor component"
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_FRAGMENTATION): cv.invalid(
 | 
			
		||||
            "The 'fragmentation' option has been moved to the 'debug' sensor component"
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_LOOP_TIME): cv.invalid(
 | 
			
		||||
            "The 'loop_time' option has been moved to the 'debug' sensor component"
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
).extend(cv.polling_component_schema("60s"))
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(): cv.declare_id(DebugComponent),
 | 
			
		||||
            cv.Optional(CONF_DEVICE): cv.invalid(
 | 
			
		||||
                "The 'device' option has been moved to the 'debug' text_sensor component"
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_FREE): cv.invalid(
 | 
			
		||||
                "The 'free' option has been moved to the 'debug' sensor component"
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_BLOCK): cv.invalid(
 | 
			
		||||
                "The 'block' option has been moved to the 'debug' sensor component"
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_FRAGMENTATION): cv.invalid(
 | 
			
		||||
                "The 'fragmentation' option has been moved to the 'debug' sensor component"
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_LOOP_TIME): cv.invalid(
 | 
			
		||||
                "The 'loop_time' option has been moved to the 'debug' sensor component"
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    ).extend(cv.polling_component_schema("60s")),
 | 
			
		||||
    cv.only_on(["esp32", "esp8266"]),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
 
 | 
			
		||||
@@ -77,10 +77,12 @@ void FingerprintGrowComponent::finish_enrollment(uint8_t result) {
 | 
			
		||||
    this->enrollment_done_callback_.call(this->enrollment_slot_);
 | 
			
		||||
    this->get_fingerprint_count_();
 | 
			
		||||
  } else {
 | 
			
		||||
    this->enrollment_failed_callback_.call(this->enrollment_slot_);
 | 
			
		||||
    if (this->enrollment_slot_ != ENROLLMENT_SLOT_UNUSED) {
 | 
			
		||||
      this->enrollment_failed_callback_.call(this->enrollment_slot_);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  this->enrollment_image_ = 0;
 | 
			
		||||
  this->enrollment_slot_ = 0;
 | 
			
		||||
  this->enrollment_slot_ = ENROLLMENT_SLOT_UNUSED;
 | 
			
		||||
  if (this->enrolling_binary_sensor_ != nullptr) {
 | 
			
		||||
    this->enrolling_binary_sensor_->publish_state(false);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,8 @@ namespace fingerprint_grow {
 | 
			
		||||
 | 
			
		||||
static const uint16_t START_CODE = 0xEF01;
 | 
			
		||||
 | 
			
		||||
static const uint16_t ENROLLMENT_SLOT_UNUSED = 0xFFFF;
 | 
			
		||||
 | 
			
		||||
enum GrowPacketType {
 | 
			
		||||
  COMMAND = 0x01,
 | 
			
		||||
  DATA = 0x02,
 | 
			
		||||
@@ -158,7 +160,7 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic
 | 
			
		||||
  uint32_t new_password_ = -1;
 | 
			
		||||
  GPIOPin *sensing_pin_{nullptr};
 | 
			
		||||
  uint8_t enrollment_image_ = 0;
 | 
			
		||||
  uint16_t enrollment_slot_ = 0;
 | 
			
		||||
  uint16_t enrollment_slot_ = ENROLLMENT_SLOT_UNUSED;
 | 
			
		||||
  uint8_t enrollment_buffers_ = 5;
 | 
			
		||||
  bool waiting_removal_ = false;
 | 
			
		||||
  uint32_t last_aura_led_control_ = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
#include "i2c_bus_arduino.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
@@ -227,10 +228,14 @@ void ArduinoI2CBus::recover_() {
 | 
			
		||||
    // When SCL is kept LOW at this point, we might be looking at a device
 | 
			
		||||
    // that applies clock stretching. Wait for the release of the SCL line,
 | 
			
		||||
    // but not forever. There is no specification for the maximum allowed
 | 
			
		||||
    // time. We'll stick to 500ms here.
 | 
			
		||||
    auto wait = 20;
 | 
			
		||||
    // time. We yield and reset the WDT, so as to avoid triggering reset.
 | 
			
		||||
    // No point in trying to recover the bus by forcing a uC reset. Bus
 | 
			
		||||
    // should recover in a few ms or less else not likely to recovery at
 | 
			
		||||
    // all.
 | 
			
		||||
    auto wait = 250;
 | 
			
		||||
    while (wait-- && digitalRead(scl_pin_) == LOW) {  // NOLINT
 | 
			
		||||
      delay(25);
 | 
			
		||||
      App.feed_wdt();
 | 
			
		||||
      delayMicroseconds(half_period_usec * 2);
 | 
			
		||||
    }
 | 
			
		||||
    if (digitalRead(scl_pin_) == LOW) {  // NOLINT
 | 
			
		||||
      ESP_LOGE(TAG, "Recovery failed: SCL is held LOW during clock pulse cycle");
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cinttypes>
 | 
			
		||||
 | 
			
		||||
@@ -273,10 +274,14 @@ void IDFI2CBus::recover_() {
 | 
			
		||||
    // When SCL is kept LOW at this point, we might be looking at a device
 | 
			
		||||
    // that applies clock stretching. Wait for the release of the SCL line,
 | 
			
		||||
    // but not forever. There is no specification for the maximum allowed
 | 
			
		||||
    // time. We'll stick to 500ms here.
 | 
			
		||||
    auto wait = 20;
 | 
			
		||||
    // time. We yield and reset the WDT, so as to avoid triggering reset.
 | 
			
		||||
    // No point in trying to recover the bus by forcing a uC reset. Bus
 | 
			
		||||
    // should recover in a few ms or less else not likely to recovery at
 | 
			
		||||
    // all.
 | 
			
		||||
    auto wait = 250;
 | 
			
		||||
    while (wait-- && gpio_get_level(scl_pin) == 0) {
 | 
			
		||||
      delay(25);
 | 
			
		||||
      App.feed_wdt();
 | 
			
		||||
      delayMicroseconds(half_period_usec * 2);
 | 
			
		||||
    }
 | 
			
		||||
    if (gpio_get_level(scl_pin) == 0) {
 | 
			
		||||
      ESP_LOGE(TAG, "Recovery failed: SCL is held LOW during clock pulse cycle");
 | 
			
		||||
 
 | 
			
		||||
@@ -141,7 +141,7 @@ void I2SAudioMediaPlayer::start_() {
 | 
			
		||||
    this->audio_ = make_unique<Audio>(true, this->internal_dac_mode_, this->parent_->get_port());
 | 
			
		||||
  } else {
 | 
			
		||||
#endif
 | 
			
		||||
    this->audio_ = make_unique<Audio>(false, I2S_DAC_CHANNEL_BOTH_EN, this->parent_->get_port());
 | 
			
		||||
    this->audio_ = make_unique<Audio>(false, 3, this->parent_->get_port());
 | 
			
		||||
 | 
			
		||||
    i2s_pin_config_t pin_config = this->parent_->get_pin_config();
 | 
			
		||||
    pin_config.data_out_num = this->dout_pin_;
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@ async def to_code(config):
 | 
			
		||||
    cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
 | 
			
		||||
    cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
 | 
			
		||||
    cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
 | 
			
		||||
    cg.add(var.set_flip_x([CONF_FLIP_X]))
 | 
			
		||||
    cg.add(var.set_flip_x(config[CONF_FLIP_X]))
 | 
			
		||||
 | 
			
		||||
    if CONF_LAMBDA in config:
 | 
			
		||||
        lambda_ = await cg.process_lambda(
 | 
			
		||||
 
 | 
			
		||||
@@ -25,10 +25,12 @@ from esphome.const import (
 | 
			
		||||
    CONF_STATE_CLASS,
 | 
			
		||||
    CONF_TO,
 | 
			
		||||
    CONF_TRIGGER_ID,
 | 
			
		||||
    CONF_TYPE,
 | 
			
		||||
    CONF_UNIT_OF_MEASUREMENT,
 | 
			
		||||
    CONF_WINDOW_SIZE,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_FORCE_UPDATE,
 | 
			
		||||
    CONF_VALUE,
 | 
			
		||||
    DEVICE_CLASS_APPARENT_POWER,
 | 
			
		||||
    DEVICE_CLASS_AQI,
 | 
			
		||||
    DEVICE_CLASS_ATMOSPHERIC_PRESSURE,
 | 
			
		||||
@@ -476,21 +478,38 @@ async def lambda_filter_to_code(config, filter_id):
 | 
			
		||||
    return cg.new_Pvariable(filter_id, lambda_)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DELTA_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.Required(CONF_VALUE): cv.positive_float,
 | 
			
		||||
        cv.Optional(CONF_TYPE, default="absolute"): cv.one_of(
 | 
			
		||||
            "absolute", "percentage", lower=True
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_delta(config):
 | 
			
		||||
    try:
 | 
			
		||||
        return (cv.positive_float(config), False)
 | 
			
		||||
        value = cv.positive_float(config)
 | 
			
		||||
        return DELTA_SCHEMA({CONF_VALUE: value, CONF_TYPE: "absolute"})
 | 
			
		||||
    except cv.Invalid:
 | 
			
		||||
        pass
 | 
			
		||||
    try:
 | 
			
		||||
        return (cv.percentage(config), True)
 | 
			
		||||
        value = cv.percentage(config)
 | 
			
		||||
        return DELTA_SCHEMA({CONF_VALUE: value, CONF_TYPE: "percentage"})
 | 
			
		||||
    except cv.Invalid:
 | 
			
		||||
        pass
 | 
			
		||||
    raise cv.Invalid("Delta filter requires a positive number or percentage value.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta)
 | 
			
		||||
@FILTER_REGISTRY.register("delta", DeltaFilter, cv.Any(DELTA_SCHEMA, validate_delta))
 | 
			
		||||
async def delta_filter_to_code(config, filter_id):
 | 
			
		||||
    return cg.new_Pvariable(filter_id, *config)
 | 
			
		||||
    percentage = config[CONF_TYPE] == "percentage"
 | 
			
		||||
    return cg.new_Pvariable(
 | 
			
		||||
        filter_id,
 | 
			
		||||
        config[CONF_VALUE],
 | 
			
		||||
        percentage,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("or", OrFilter, validate_filters)
 | 
			
		||||
 
 | 
			
		||||
@@ -286,7 +286,9 @@ SPRINKLER_VALVE_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.Optional(CONF_ENABLE_SWITCH): cv.maybe_simple_value(
 | 
			
		||||
            switch.switch_schema(
 | 
			
		||||
                SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
 | 
			
		||||
                SprinklerControllerSwitch,
 | 
			
		||||
                entity_category=ENTITY_CATEGORY_CONFIG,
 | 
			
		||||
                default_restore_mode="RESTORE_DEFAULT_OFF",
 | 
			
		||||
            ),
 | 
			
		||||
            key=CONF_NAME,
 | 
			
		||||
        ),
 | 
			
		||||
@@ -333,7 +335,9 @@ SPRINKLER_CONTROLLER_SCHEMA = cv.Schema(
 | 
			
		||||
        cv.Optional(CONF_NAME): cv.string,
 | 
			
		||||
        cv.Optional(CONF_AUTO_ADVANCE_SWITCH): cv.maybe_simple_value(
 | 
			
		||||
            switch.switch_schema(
 | 
			
		||||
                SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
 | 
			
		||||
                SprinklerControllerSwitch,
 | 
			
		||||
                entity_category=ENTITY_CATEGORY_CONFIG,
 | 
			
		||||
                default_restore_mode="RESTORE_DEFAULT_OFF",
 | 
			
		||||
            ),
 | 
			
		||||
            key=CONF_NAME,
 | 
			
		||||
        ),
 | 
			
		||||
@@ -343,19 +347,25 @@ SPRINKLER_CONTROLLER_SCHEMA = cv.Schema(
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_QUEUE_ENABLE_SWITCH): cv.maybe_simple_value(
 | 
			
		||||
            switch.switch_schema(
 | 
			
		||||
                SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
 | 
			
		||||
                SprinklerControllerSwitch,
 | 
			
		||||
                entity_category=ENTITY_CATEGORY_CONFIG,
 | 
			
		||||
                default_restore_mode="RESTORE_DEFAULT_OFF",
 | 
			
		||||
            ),
 | 
			
		||||
            key=CONF_NAME,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_REVERSE_SWITCH): cv.maybe_simple_value(
 | 
			
		||||
            switch.switch_schema(
 | 
			
		||||
                SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
 | 
			
		||||
                SprinklerControllerSwitch,
 | 
			
		||||
                entity_category=ENTITY_CATEGORY_CONFIG,
 | 
			
		||||
                default_restore_mode="RESTORE_DEFAULT_OFF",
 | 
			
		||||
            ),
 | 
			
		||||
            key=CONF_NAME,
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_STANDBY_SWITCH): cv.maybe_simple_value(
 | 
			
		||||
            switch.switch_schema(
 | 
			
		||||
                SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG
 | 
			
		||||
                SprinklerControllerSwitch,
 | 
			
		||||
                entity_category=ENTITY_CATEGORY_CONFIG,
 | 
			
		||||
                default_restore_mode="RESTORE_DEFAULT_OFF",
 | 
			
		||||
            ),
 | 
			
		||||
            key=CONF_NAME,
 | 
			
		||||
        ),
 | 
			
		||||
 
 | 
			
		||||
@@ -1176,6 +1176,21 @@ optional<uint32_t> Sprinkler::time_remaining_current_operation() {
 | 
			
		||||
  return nullopt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Sprinkler::any_controller_is_active() {
 | 
			
		||||
  if (this->state_ != IDLE) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (auto &controller : this->other_controllers_) {
 | 
			
		||||
    if (controller != this) {  // dummy check
 | 
			
		||||
      if (controller->controller_state() != IDLE) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SprinklerControllerSwitch *Sprinkler::control_switch(size_t valve_number) {
 | 
			
		||||
  if (this->is_a_valid_valve(valve_number)) {
 | 
			
		||||
    return this->valve_[valve_number].controller_switch;
 | 
			
		||||
 
 | 
			
		||||
@@ -406,6 +406,12 @@ class Sprinkler : public Component {
 | 
			
		||||
  /// returns the amount of time remaining in seconds for all valves remaining, including the active valve, if any
 | 
			
		||||
  optional<uint32_t> time_remaining_current_operation();
 | 
			
		||||
 | 
			
		||||
  /// returns true if this or any sprinkler controller this controller knows about is active
 | 
			
		||||
  bool any_controller_is_active();
 | 
			
		||||
 | 
			
		||||
  /// returns the current state of the sprinkler controller
 | 
			
		||||
  SprinklerState controller_state() { return this->state_; };
 | 
			
		||||
 | 
			
		||||
  /// returns a pointer to a valve's control switch object
 | 
			
		||||
  SprinklerControllerSwitch *control_switch(size_t valve_number);
 | 
			
		||||
 | 
			
		||||
@@ -503,7 +509,6 @@ class Sprinkler : public Component {
 | 
			
		||||
  /// callback functions for timers
 | 
			
		||||
  void valve_selection_callback_();
 | 
			
		||||
  void sm_timer_callback_();
 | 
			
		||||
  void pump_stop_delay_callback_();
 | 
			
		||||
 | 
			
		||||
  /// Maximum allowed queue size
 | 
			
		||||
  const uint8_t max_queue_size_{100};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2023.4.0"
 | 
			
		||||
__version__ = "2023.4.3"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user