mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[light] Add support for querying effects by index (#10195)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
		| @@ -44,6 +44,13 @@ class AddressableLightEffect : public LightEffect { | |||||||
|     this->apply(*this->get_addressable_(), current_color); |     this->apply(*this->get_addressable_(), current_color); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /// Get effect index specifically for addressable effects. | ||||||
|  |   /// Can be used by effects to modify behavior based on their position in the list. | ||||||
|  |   uint32_t get_effect_index() const { return this->get_index(); } | ||||||
|  |  | ||||||
|  |   /// Check if this is the currently running addressable effect. | ||||||
|  |   bool is_current_effect() const { return this->is_active() && this->get_addressable_()->is_effect_active(); } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   AddressableLight *get_addressable_() const { return (AddressableLight *) this->state_->get_output(); } |   AddressableLight *get_addressable_() const { return (AddressableLight *) this->state_->get_output(); } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -125,6 +125,10 @@ class LambdaLightEffect : public LightEffect { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /// Get the current effect index for use in lambda functions. | ||||||
|  |   /// This can be useful for lambda effects that need to know their own index. | ||||||
|  |   uint32_t get_current_index() const { return this->get_index(); } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   std::function<void(bool initial_run)> f_; |   std::function<void(bool initial_run)> f_; | ||||||
|   uint32_t update_interval_; |   uint32_t update_interval_; | ||||||
| @@ -143,6 +147,10 @@ class AutomationLightEffect : public LightEffect { | |||||||
|   } |   } | ||||||
|   Trigger<> *get_trig() const { return trig_; } |   Trigger<> *get_trig() const { return trig_; } | ||||||
|  |  | ||||||
|  |   /// Get the current effect index for use in automations. | ||||||
|  |   /// Useful for automations that need to know which effect is running. | ||||||
|  |   uint32_t get_current_index() const { return this->get_index(); } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   Trigger<> *trig_{new Trigger<>}; |   Trigger<> *trig_{new Trigger<>}; | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								esphome/components/light/light_effect.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								esphome/components/light/light_effect.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | #include "light_effect.h" | ||||||
|  | #include "light_state.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace light { | ||||||
|  |  | ||||||
|  | uint32_t LightEffect::get_index() const { | ||||||
|  |   if (this->state_ == nullptr) { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   return this->get_index_in_parent_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool LightEffect::is_active() const { | ||||||
|  |   if (this->state_ == nullptr) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   return this->get_index() != 0 && this->state_->get_current_effect_index() == this->get_index(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t LightEffect::get_index_in_parent_() const { | ||||||
|  |   if (this->state_ == nullptr) { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const auto &effects = this->state_->get_effects(); | ||||||
|  |   for (size_t i = 0; i < effects.size(); i++) { | ||||||
|  |     if (effects[i] == this) { | ||||||
|  |       return i + 1;  // Effects are 1-indexed in the API | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return 0;  // Not found | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace light | ||||||
|  | }  // namespace esphome | ||||||
| @@ -34,9 +34,23 @@ class LightEffect { | |||||||
|     this->init(); |     this->init(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /// Get the index of this effect in the parent light's effect list. | ||||||
|  |   /// Returns 0 if not found or not initialized. | ||||||
|  |   uint32_t get_index() const; | ||||||
|  |  | ||||||
|  |   /// Check if this effect is currently active. | ||||||
|  |   bool is_active() const; | ||||||
|  |  | ||||||
|  |   /// Get a reference to the parent light state. | ||||||
|  |   /// Returns nullptr if not initialized. | ||||||
|  |   LightState *get_light_state() const { return this->state_; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   LightState *state_{nullptr}; |   LightState *state_{nullptr}; | ||||||
|   std::string name_; |   std::string name_; | ||||||
|  |  | ||||||
|  |   /// Internal method to find this effect's index in the parent light's effect list. | ||||||
|  |   uint32_t get_index_in_parent_() const; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace light | }  // namespace light | ||||||
|   | |||||||
| @@ -36,8 +36,11 @@ static constexpr const char *get_color_mode_json_str(ColorMode mode) { | |||||||
|  |  | ||||||
| void LightJSONSchema::dump_json(LightState &state, JsonObject root) { | void LightJSONSchema::dump_json(LightState &state, JsonObject root) { | ||||||
|   // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson |   // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson | ||||||
|   if (state.supports_effects()) |   if (state.supports_effects()) { | ||||||
|     root["effect"] = state.get_effect_name(); |     root["effect"] = state.get_effect_name(); | ||||||
|  |     root["effect_index"] = state.get_current_effect_index(); | ||||||
|  |     root["effect_count"] = state.get_effect_count(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   auto values = state.remote_values; |   auto values = state.remote_values; | ||||||
|   auto traits = state.get_output()->get_traits(); |   auto traits = state.get_output()->get_traits(); | ||||||
| @@ -160,6 +163,11 @@ void LightJSONSchema::parse_json(LightState &state, LightCall &call, JsonObject | |||||||
|     const char *effect = root["effect"]; |     const char *effect = root["effect"]; | ||||||
|     call.set_effect(effect); |     call.set_effect(effect); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if (root["effect_index"].is<uint32_t>()) { | ||||||
|  |     uint32_t effect_index = root["effect_index"]; | ||||||
|  |     call.set_effect(effect_index); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace light | }  // namespace light | ||||||
|   | |||||||
| @@ -163,6 +163,44 @@ class LightState : public EntityBase, public Component { | |||||||
|   /// Add effects for this light state. |   /// Add effects for this light state. | ||||||
|   void add_effects(const std::vector<LightEffect *> &effects); |   void add_effects(const std::vector<LightEffect *> &effects); | ||||||
|  |  | ||||||
|  |   /// Get the total number of effects available for this light. | ||||||
|  |   size_t get_effect_count() const { return this->effects_.size(); } | ||||||
|  |  | ||||||
|  |   /// Get the currently active effect index (0 = no effect, 1+ = effect index). | ||||||
|  |   uint32_t get_current_effect_index() const { return this->active_effect_index_; } | ||||||
|  |  | ||||||
|  |   /// Get effect index by name. Returns 0 if effect not found. | ||||||
|  |   uint32_t get_effect_index(const std::string &effect_name) const { | ||||||
|  |     if (strcasecmp(effect_name.c_str(), "none") == 0) { | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     for (size_t i = 0; i < this->effects_.size(); i++) { | ||||||
|  |       if (strcasecmp(effect_name.c_str(), this->effects_[i]->get_name().c_str()) == 0) { | ||||||
|  |         return i + 1;  // Effects are 1-indexed in active_effect_index_ | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return 0;  // Effect not found | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /// Get effect by index. Returns nullptr if index is invalid. | ||||||
|  |   LightEffect *get_effect_by_index(uint32_t index) const { | ||||||
|  |     if (index == 0 || index > this->effects_.size()) { | ||||||
|  |       return nullptr; | ||||||
|  |     } | ||||||
|  |     return this->effects_[index - 1];  // Effects are 1-indexed in active_effect_index_ | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /// Get effect name by index. Returns "None" for index 0, empty string for invalid index. | ||||||
|  |   std::string get_effect_name_by_index(uint32_t index) const { | ||||||
|  |     if (index == 0) { | ||||||
|  |       return "None"; | ||||||
|  |     } | ||||||
|  |     if (index > this->effects_.size()) { | ||||||
|  |       return "";  // Invalid index | ||||||
|  |     } | ||||||
|  |     return this->effects_[index - 1]->get_name(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /// The result of all the current_values_as_* methods have gamma correction applied. |   /// The result of all the current_values_as_* methods have gamma correction applied. | ||||||
|   void current_values_as_binary(bool *binary); |   void current_values_as_binary(bool *binary); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user