mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +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); | ||||
|   } | ||||
|  | ||||
|   /// 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: | ||||
|   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: | ||||
|   std::function<void(bool initial_run)> f_; | ||||
|   uint32_t update_interval_; | ||||
| @@ -143,6 +147,10 @@ class AutomationLightEffect : public LightEffect { | ||||
|   } | ||||
|   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: | ||||
|   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(); | ||||
|   } | ||||
|  | ||||
|   /// 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: | ||||
|   LightState *state_{nullptr}; | ||||
|   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 | ||||
|   | ||||
| @@ -36,8 +36,11 @@ static constexpr const char *get_color_mode_json_str(ColorMode mode) { | ||||
|  | ||||
| void LightJSONSchema::dump_json(LightState &state, JsonObject root) { | ||||
|   // 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_index"] = state.get_current_effect_index(); | ||||
|     root["effect_count"] = state.get_effect_count(); | ||||
|   } | ||||
|  | ||||
|   auto values = state.remote_values; | ||||
|   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"]; | ||||
|     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 | ||||
|   | ||||
| @@ -163,6 +163,44 @@ class LightState : public EntityBase, public Component { | ||||
|   /// Add effects for this light state. | ||||
|   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. | ||||
|   void current_values_as_binary(bool *binary); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user