mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +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) | MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) | ||||||
| FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) | FilterOutValueFilter = sensor_ns.class_("FilterOutValueFilter", Filter) | ||||||
| ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) | ThrottleFilter = sensor_ns.class_("ThrottleFilter", Filter) | ||||||
|  | ThrottleWithPriorityFilter = sensor_ns.class_("ThrottleWithPriorityFilter", Filter) | ||||||
| TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) | TimeoutFilter = sensor_ns.class_("TimeoutFilter", Filter, cg.Component) | ||||||
| DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) | DebounceFilter = sensor_ns.class_("DebounceFilter", Filter, cg.Component) | ||||||
| HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", 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) |     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( | @FILTER_REGISTRY.register( | ||||||
|     "heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds |     "heartbeat", HeartbeatFilter, cv.positive_time_period_milliseconds | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #include "filter.h" | #include "filter.h" | ||||||
| #include <cmath> | #include <cmath> | ||||||
|  | #include "esphome/core/application.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "sensor.h" | #include "sensor.h" | ||||||
| @@ -332,6 +333,40 @@ optional<float> ThrottleFilter::new_value(float value) { | |||||||
|   return {}; |   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::DeltaFilter(float delta, bool percentage_mode) | DeltaFilter::DeltaFilter(float delta, bool percentage_mode) | ||||||
|     : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} |     : 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_; |   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 { | class TimeoutFilter : public Filter, public Component { | ||||||
|  public: |  public: | ||||||
|   explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value); |   explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user