mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	[sensor] Add new filter: `throttle_with_priority` (#9937)
				
					
				
			This commit is contained in:
		| @@ -256,6 +256,7 @@ OffsetFilter = sensor_ns.class_("OffsetFilter", Filter) | ||||
| MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) | ||||
| FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) | ||||
| ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) | ||||
| ThrottleWithPriorityFilter = sensor_ns.class_("ThrottleWithPriorityFilter", Filter) | ||||
| TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) | ||||
| DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) | ||||
| HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component) | ||||
| @@ -595,6 +596,25 @@ async def throttle_filter_to_code(config, filter_id): | ||||
|     return cg.new_Pvariable(filter_id, config) | ||||
|  | ||||
|  | ||||
| TIMEOUT_WITH_PRIORITY_SCHEMA = cv.maybe_simple_value( | ||||
|     { | ||||
|         cv.Required(CONF_TIMEOUT): cv.positive_time_period_milliseconds, | ||||
|         cv.Optional(CONF_VALUE, default="nan"): cv.ensure_list(cv.float_), | ||||
|     }, | ||||
|     key=CONF_TIMEOUT, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @FILTER_REGISTRY.register( | ||||
|     "throttle_with_priority", | ||||
|     ThrottleWithPriorityFilter, | ||||
|     TIMEOUT_WITH_PRIORITY_SCHEMA, | ||||
| ) | ||||
| async def throttle_with_priority_filter_to_code(config, filter_id): | ||||
|     template_ = [await cg.templatable(x, [], float) for x in config[CONF_VALUE]] | ||||
|     return cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], template_) | ||||
|  | ||||
|  | ||||
| @FILTER_REGISTRY.register( | ||||
|     "heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds | ||||
| ) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #include "filter.h" | ||||
| #include <cmath> | ||||
| #include "esphome/core/application.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "sensor.h" | ||||
| @@ -332,6 +333,40 @@ optional<float> ThrottleFilter::new_value(float value) { | ||||
|   return {}; | ||||
| } | ||||
|  | ||||
| // ThrottleWithPriorityFilter | ||||
| ThrottleWithPriorityFilter::ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, | ||||
|                                                        std::vector<TemplatableValue<float>> prioritized_values) | ||||
|     : min_time_between_inputs_(min_time_between_inputs), prioritized_values_(std::move(prioritized_values)) {} | ||||
|  | ||||
| optional<float> ThrottleWithPriorityFilter::new_value(float value) { | ||||
|   bool is_prioritized_value = false; | ||||
|   int8_t accuracy = this->parent_->get_accuracy_decimals(); | ||||
|   float accuracy_mult = powf(10.0f, accuracy); | ||||
|   const uint32_t now = App.get_loop_component_start_time(); | ||||
|   // First, determine if the new value is one of the prioritized values | ||||
|   for (auto prioritized_value : this->prioritized_values_) { | ||||
|     if (std::isnan(prioritized_value.value())) { | ||||
|       if (std::isnan(value)) { | ||||
|         is_prioritized_value = true; | ||||
|         break; | ||||
|       } | ||||
|       continue; | ||||
|     } | ||||
|     float rounded_prioritized_value = roundf(accuracy_mult * prioritized_value.value()); | ||||
|     float rounded_value = roundf(accuracy_mult * value); | ||||
|     if (rounded_prioritized_value == rounded_value) { | ||||
|       is_prioritized_value = true; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   // Finally, determine if the new value should be throttled and pass it through if not | ||||
|   if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_ || is_prioritized_value) { | ||||
|     this->last_input_ = now; | ||||
|     return value; | ||||
|   } | ||||
|   return {}; | ||||
| } | ||||
|  | ||||
| // DeltaFilter | ||||
| DeltaFilter::DeltaFilter(float delta, bool percentage_mode) | ||||
|     : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} | ||||
|   | ||||
| @@ -314,6 +314,20 @@ class ThrottleFilter : public Filter { | ||||
|   uint32_t min_time_between_inputs_; | ||||
| }; | ||||
|  | ||||
| /// Same as 'throttle' but will immediately publish values contained in `value_to_prioritize`. | ||||
| class ThrottleWithPriorityFilter : public Filter { | ||||
|  public: | ||||
|   explicit ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, | ||||
|                                       std::vector<TemplatableValue<float>> prioritized_values); | ||||
|  | ||||
|   optional<float> new_value(float value) override; | ||||
|  | ||||
|  protected: | ||||
|   uint32_t last_input_{0}; | ||||
|   uint32_t min_time_between_inputs_; | ||||
|   std::vector<TemplatableValue<float>> prioritized_values_; | ||||
| }; | ||||
|  | ||||
| class TimeoutFilter : public Filter, public Component { | ||||
|  public: | ||||
|   explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user