mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-03 16:41:50 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			fan_no_dou
			...
			select_fix
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					3291488a8b | ||
| 
						 | 
					75550b39f4 | ||
| 
						 | 
					02e1ed2130 | ||
| 
						 | 
					2948264917 | ||
| 
						 | 
					660411ac42 | ||
| 
						 | 
					88e3f02c9c | ||
| 
						 | 
					f3f419077b | 
@@ -1143,7 +1143,7 @@ message ListEntitiesSelectResponse {
 | 
			
		||||
  reserved 4; // Deprecated: was string unique_id
 | 
			
		||||
 | 
			
		||||
  string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"];
 | 
			
		||||
  repeated string options = 6 [(container_pointer) = "std::vector"];
 | 
			
		||||
  repeated string options = 6 [(container_pointer) = "FixedVector"];
 | 
			
		||||
  bool disabled_by_default = 7;
 | 
			
		||||
  EntityCategory entity_category = 8;
 | 
			
		||||
  uint32 device_id = 9 [(field_ifdef) = "USE_DEVICES"];
 | 
			
		||||
 
 | 
			
		||||
@@ -1534,7 +1534,7 @@ class ListEntitiesSelectResponse final : public InfoResponseProtoMessage {
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  const char *message_name() const override { return "list_entities_select_response"; }
 | 
			
		||||
#endif
 | 
			
		||||
  const std::vector<std::string> *options{};
 | 
			
		||||
  const FixedVector<std::string> *options{};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
  void calculate_size(ProtoSize &size) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,8 @@ static const char *const TAG = "copy.select";
 | 
			
		||||
void CopySelect::setup() {
 | 
			
		||||
  source_->add_on_state_callback([this](const std::string &value, size_t index) { this->publish_state(value); });
 | 
			
		||||
 | 
			
		||||
  traits.set_options(source_->traits.get_options());
 | 
			
		||||
  // Copy options from source select
 | 
			
		||||
  this->traits.copy_options(source_->traits.get_options());
 | 
			
		||||
 | 
			
		||||
  if (source_->has_state())
 | 
			
		||||
    this->publish_state(source_->state);
 | 
			
		||||
 
 | 
			
		||||
@@ -300,11 +300,11 @@ void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t a
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LvSelectable::set_options(std::vector<std::string> options) {
 | 
			
		||||
void LvSelectable::set_options(std::initializer_list<std::string> options) {
 | 
			
		||||
  auto index = this->get_selected_index();
 | 
			
		||||
  if (index >= options.size())
 | 
			
		||||
    index = options.size() - 1;
 | 
			
		||||
  this->options_ = std::move(options);
 | 
			
		||||
  this->options_ = options;
 | 
			
		||||
  this->set_option_string(join_string(this->options_).c_str());
 | 
			
		||||
  lv_event_send(this->obj, LV_EVENT_REFRESH, nullptr);
 | 
			
		||||
  this->set_selected_index(index, LV_ANIM_OFF);
 | 
			
		||||
 
 | 
			
		||||
@@ -358,12 +358,12 @@ class LvSelectable : public LvCompound {
 | 
			
		||||
  virtual void set_selected_index(size_t index, lv_anim_enable_t anim) = 0;
 | 
			
		||||
  void set_selected_text(const std::string &text, lv_anim_enable_t anim);
 | 
			
		||||
  std::string get_selected_text();
 | 
			
		||||
  std::vector<std::string> get_options() { return this->options_; }
 | 
			
		||||
  void set_options(std::vector<std::string> options);
 | 
			
		||||
  const FixedVector<std::string> &get_options() { return this->options_; }
 | 
			
		||||
  void set_options(std::initializer_list<std::string> options);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  virtual void set_option_string(const char *options) = 0;
 | 
			
		||||
  std::vector<std::string> options_{};
 | 
			
		||||
  FixedVector<std::string> options_{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef USE_LVGL_DROPDOWN
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,10 @@ class LVGLSelect : public select::Select, public Component {
 | 
			
		||||
    this->widget_->set_selected_text(value, this->anim_);
 | 
			
		||||
    this->publish();
 | 
			
		||||
  }
 | 
			
		||||
  void set_options_() { this->traits.set_options(this->widget_->get_options()); }
 | 
			
		||||
  void set_options_() {
 | 
			
		||||
    // Copy options from lvgl widget to select traits
 | 
			
		||||
    this->traits.copy_options(this->widget_->get_options());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  LvSelectable *widget_;
 | 
			
		||||
  lv_anim_enable_t anim_;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace select {
 | 
			
		||||
 | 
			
		||||
void SelectTraits::set_options(std::vector<std::string> options) { this->options_ = std::move(options); }
 | 
			
		||||
void SelectTraits::set_options(std::initializer_list<std::string> options) { this->options_ = options; }
 | 
			
		||||
 | 
			
		||||
const std::vector<std::string> &SelectTraits::get_options() const { return this->options_; }
 | 
			
		||||
const FixedVector<std::string> &SelectTraits::get_options() const { return this->options_; }
 | 
			
		||||
 | 
			
		||||
}  // namespace select
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,21 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace select {
 | 
			
		||||
 | 
			
		||||
class SelectTraits {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_options(std::vector<std::string> options);
 | 
			
		||||
  const std::vector<std::string> &get_options() const;
 | 
			
		||||
  void set_options(std::initializer_list<std::string> options);
 | 
			
		||||
  const FixedVector<std::string> &get_options() const;
 | 
			
		||||
  /// Copy options from another SelectTraits (for copy_select, lvgl)
 | 
			
		||||
  void copy_options(const FixedVector<std::string> &other) { this->options_.copy_from(other); }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::vector<std::string> options_;
 | 
			
		||||
  FixedVector<std::string> options_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace select
 | 
			
		||||
 
 | 
			
		||||
@@ -378,14 +378,18 @@ async def to_code(config):
 | 
			
		||||
    # Track if any network uses Enterprise authentication
 | 
			
		||||
    has_eap = False
 | 
			
		||||
 | 
			
		||||
    def add_sta(ap, network):
 | 
			
		||||
        ip_config = network.get(CONF_MANUAL_IP, config.get(CONF_MANUAL_IP))
 | 
			
		||||
        cg.add(var.add_sta(wifi_network(network, ap, ip_config)))
 | 
			
		||||
    # Build all WiFiAP objects
 | 
			
		||||
    networks = config.get(CONF_NETWORKS, [])
 | 
			
		||||
    if networks:
 | 
			
		||||
        wifi_aps = []
 | 
			
		||||
        for network in networks:
 | 
			
		||||
            if CONF_EAP in network:
 | 
			
		||||
                has_eap = True
 | 
			
		||||
            ip_config = network.get(CONF_MANUAL_IP, config.get(CONF_MANUAL_IP))
 | 
			
		||||
            wifi_aps.append(wifi_network(network, WiFiAP(), ip_config))
 | 
			
		||||
 | 
			
		||||
    for network in config.get(CONF_NETWORKS, []):
 | 
			
		||||
        if CONF_EAP in network:
 | 
			
		||||
            has_eap = True
 | 
			
		||||
        cg.with_local_variable(network[CONF_ID], WiFiAP(), add_sta, network)
 | 
			
		||||
        # Set all WiFi networks at once
 | 
			
		||||
        cg.add(var.set_stas(wifi_aps))
 | 
			
		||||
 | 
			
		||||
    if CONF_AP in config:
 | 
			
		||||
        conf = config[CONF_AP]
 | 
			
		||||
 
 | 
			
		||||
@@ -330,11 +330,8 @@ float WiFiComponent::get_loop_priority() const {
 | 
			
		||||
  return 10.0f;  // before other loop components
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiComponent::add_sta(const WiFiAP &ap) { this->sta_.push_back(ap); }
 | 
			
		||||
void WiFiComponent::set_sta(const WiFiAP &ap) {
 | 
			
		||||
  this->clear_sta();
 | 
			
		||||
  this->add_sta(ap);
 | 
			
		||||
}
 | 
			
		||||
void WiFiComponent::set_stas(const std::initializer_list<WiFiAP> &aps) { this->sta_ = aps; }
 | 
			
		||||
void WiFiComponent::set_sta(const WiFiAP &ap) { this->set_stas({ap}); }
 | 
			
		||||
void WiFiComponent::clear_sta() { this->sta_.clear(); }
 | 
			
		||||
void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &password) {
 | 
			
		||||
  SavedWifiSettings save{};  // zero-initialized - all bytes set to \0, guaranteeing null termination
 | 
			
		||||
 
 | 
			
		||||
@@ -219,7 +219,7 @@ class WiFiComponent : public Component {
 | 
			
		||||
 | 
			
		||||
  void set_sta(const WiFiAP &ap);
 | 
			
		||||
  WiFiAP get_sta() { return this->selected_ap_; }
 | 
			
		||||
  void add_sta(const WiFiAP &ap);
 | 
			
		||||
  void set_stas(const std::initializer_list<WiFiAP> &aps);
 | 
			
		||||
  void clear_sta();
 | 
			
		||||
 | 
			
		||||
#ifdef USE_WIFI_AP
 | 
			
		||||
@@ -393,7 +393,7 @@ class WiFiComponent : public Component {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  std::string use_address_;
 | 
			
		||||
  std::vector<WiFiAP> sta_;
 | 
			
		||||
  FixedVector<WiFiAP> sta_;
 | 
			
		||||
  std::vector<WiFiSTAPriority> sta_priorities_;
 | 
			
		||||
  wifi_scan_vector_t<WiFiScanResult> scan_result_;
 | 
			
		||||
  WiFiAP selected_ap_;
 | 
			
		||||
 
 | 
			
		||||
@@ -194,12 +194,8 @@ template<typename T> class FixedVector {
 | 
			
		||||
    size_ = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  FixedVector() = default;
 | 
			
		||||
 | 
			
		||||
  /// Constructor from initializer list - allocates exact size needed
 | 
			
		||||
  /// This enables brace initialization: FixedVector<int> v = {1, 2, 3};
 | 
			
		||||
  FixedVector(std::initializer_list<T> init_list) {
 | 
			
		||||
  // Helper to assign from initializer list (shared by constructor and assignment operator)
 | 
			
		||||
  void assign_from_initializer_list_(std::initializer_list<T> init_list) {
 | 
			
		||||
    init(init_list.size());
 | 
			
		||||
    size_t idx = 0;
 | 
			
		||||
    for (const auto &item : init_list) {
 | 
			
		||||
@@ -209,9 +205,17 @@ template<typename T> class FixedVector {
 | 
			
		||||
    size_ = init_list.size();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  FixedVector() = default;
 | 
			
		||||
 | 
			
		||||
  /// Constructor from initializer list - allocates exact size needed
 | 
			
		||||
  /// This enables brace initialization: FixedVector<int> v = {1, 2, 3};
 | 
			
		||||
  FixedVector(std::initializer_list<T> init_list) { assign_from_initializer_list_(init_list); }
 | 
			
		||||
 | 
			
		||||
  ~FixedVector() { cleanup_(); }
 | 
			
		||||
 | 
			
		||||
  // Disable copy operations (avoid accidental expensive copies)
 | 
			
		||||
  // Use copy_from() for explicit copying when needed (e.g., copy_select)
 | 
			
		||||
  FixedVector(const FixedVector &) = delete;
 | 
			
		||||
  FixedVector &operator=(const FixedVector &) = delete;
 | 
			
		||||
 | 
			
		||||
@@ -234,6 +238,28 @@ template<typename T> class FixedVector {
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Assignment from initializer list - avoids temporary and move overhead
 | 
			
		||||
  /// This enables: FixedVector<int> v; v = {1, 2, 3};
 | 
			
		||||
  FixedVector &operator=(std::initializer_list<T> init_list) {
 | 
			
		||||
    cleanup_();
 | 
			
		||||
    reset_();
 | 
			
		||||
    assign_from_initializer_list_(init_list);
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Explicitly copy another FixedVector
 | 
			
		||||
  /// This method exists instead of operator= to make copying intentional and visible.
 | 
			
		||||
  /// Copying is expensive on embedded systems, so we require explicit opt-in.
 | 
			
		||||
  /// Use cases: copy_select (copying source options), lvgl (copying widget options)
 | 
			
		||||
  void copy_from(const FixedVector &other) {
 | 
			
		||||
    cleanup_();
 | 
			
		||||
    reset_();
 | 
			
		||||
    init(other.size());
 | 
			
		||||
    for (const auto &item : other) {
 | 
			
		||||
      push_back(item);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Allocate capacity - can be called multiple times to reinit
 | 
			
		||||
  void init(size_t n) {
 | 
			
		||||
    cleanup_();
 | 
			
		||||
@@ -292,6 +318,11 @@ template<typename T> class FixedVector {
 | 
			
		||||
    return data_[size_ - 1];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Access first element (no bounds checking - matches std::vector behavior)
 | 
			
		||||
  /// Caller must ensure vector is not empty (size() > 0)
 | 
			
		||||
  T &front() { return data_[0]; }
 | 
			
		||||
  const T &front() const { return data_[0]; }
 | 
			
		||||
 | 
			
		||||
  /// Access last element (no bounds checking - matches std::vector behavior)
 | 
			
		||||
  /// Caller must ensure vector is not empty (size() > 0)
 | 
			
		||||
  T &back() { return data_[size_ - 1]; }
 | 
			
		||||
@@ -305,6 +336,12 @@ template<typename T> class FixedVector {
 | 
			
		||||
  T &operator[](size_t i) { return data_[i]; }
 | 
			
		||||
  const T &operator[](size_t i) const { return data_[i]; }
 | 
			
		||||
 | 
			
		||||
  /// Access element with bounds checking (matches std::vector behavior)
 | 
			
		||||
  /// Returns reference to element at index i
 | 
			
		||||
  /// Behavior for out of bounds access matches std::vector::at() (undefined on embedded)
 | 
			
		||||
  T &at(size_t i) { return data_[i]; }
 | 
			
		||||
  const T &at(size_t i) const { return data_[i]; }
 | 
			
		||||
 | 
			
		||||
  // Iterator support for range-based for loops
 | 
			
		||||
  T *begin() { return data_; }
 | 
			
		||||
  T *end() { return data_ + size_; }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,5 +12,8 @@ esphome:
 | 
			
		||||
            - logger.log: "Failed to connect to WiFi!"
 | 
			
		||||
 | 
			
		||||
wifi:
 | 
			
		||||
  ssid: MySSID
 | 
			
		||||
  password: password1
 | 
			
		||||
  networks:
 | 
			
		||||
    - ssid: MySSID
 | 
			
		||||
      password: password1
 | 
			
		||||
    - ssid: MySSID2
 | 
			
		||||
      password: password2
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user