ESPHome  2024.3.1
pulse_counter_sensor.cpp
Go to the documentation of this file.
1 #include "pulse_counter_sensor.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace pulse_counter {
6 
7 static const char *const TAG = "pulse_counter";
8 
9 const char *const EDGE_MODE_TO_STRING[] = {"DISABLE", "INCREMENT", "DECREMENT"};
10 
11 #ifdef HAS_PCNT
13  return (hw_pcnt ? (PulseCounterStorageBase *) (new HwPulseCounterStorage)
15 }
16 #else
18 #endif
19 
21  const uint32_t now = micros();
22  const bool discard = now - arg->last_pulse < arg->filter_us;
23  arg->last_pulse = now;
24  if (discard)
25  return;
26 
28  switch (mode) {
30  break;
32  arg->counter++;
33  break;
35  arg->counter--;
36  break;
37  }
38 }
40  this->pin = pin;
41  this->pin->setup();
42  this->isr_pin = this->pin->to_isr();
44  return true;
45 }
48  pulse_counter_t ret = counter - this->last_value;
49  this->last_value = counter;
50  return ret;
51 }
52 
53 #ifdef HAS_PCNT
55  static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0;
56  this->pin = pin;
57  this->pin->setup();
58  this->pcnt_unit = next_pcnt_unit;
59  next_pcnt_unit = pcnt_unit_t(int(next_pcnt_unit) + 1);
60 
61  ESP_LOGCONFIG(TAG, " PCNT Unit Number: %u", this->pcnt_unit);
62 
63  pcnt_count_mode_t rising = PCNT_COUNT_DIS, falling = PCNT_COUNT_DIS;
64  switch (this->rising_edge_mode) {
66  rising = PCNT_COUNT_DIS;
67  break;
69  rising = PCNT_COUNT_INC;
70  break;
72  rising = PCNT_COUNT_DEC;
73  break;
74  }
75  switch (this->falling_edge_mode) {
77  falling = PCNT_COUNT_DIS;
78  break;
80  falling = PCNT_COUNT_INC;
81  break;
83  falling = PCNT_COUNT_DEC;
84  break;
85  }
86 
87  pcnt_config_t pcnt_config = {
88  .pulse_gpio_num = this->pin->get_pin(),
89  .ctrl_gpio_num = PCNT_PIN_NOT_USED,
90  .lctrl_mode = PCNT_MODE_KEEP,
91  .hctrl_mode = PCNT_MODE_KEEP,
92  .pos_mode = rising,
93  .neg_mode = falling,
94  .counter_h_lim = 0,
95  .counter_l_lim = 0,
96  .unit = this->pcnt_unit,
97  .channel = PCNT_CHANNEL_0,
98  };
99  esp_err_t error = pcnt_unit_config(&pcnt_config);
100  if (error != ESP_OK) {
101  ESP_LOGE(TAG, "Configuring Pulse Counter failed: %s", esp_err_to_name(error));
102  return false;
103  }
104 
105  if (this->filter_us != 0) {
106  uint16_t filter_val = std::min(static_cast<unsigned int>(this->filter_us * 80u), 1023u);
107  ESP_LOGCONFIG(TAG, " Filter Value: %" PRIu32 "us (val=%u)", this->filter_us, filter_val);
108  error = pcnt_set_filter_value(this->pcnt_unit, filter_val);
109  if (error != ESP_OK) {
110  ESP_LOGE(TAG, "Setting filter value failed: %s", esp_err_to_name(error));
111  return false;
112  }
113  error = pcnt_filter_enable(this->pcnt_unit);
114  if (error != ESP_OK) {
115  ESP_LOGE(TAG, "Enabling filter failed: %s", esp_err_to_name(error));
116  return false;
117  }
118  }
119 
120  error = pcnt_counter_pause(this->pcnt_unit);
121  if (error != ESP_OK) {
122  ESP_LOGE(TAG, "Pausing pulse counter failed: %s", esp_err_to_name(error));
123  return false;
124  }
125  error = pcnt_counter_clear(this->pcnt_unit);
126  if (error != ESP_OK) {
127  ESP_LOGE(TAG, "Clearing pulse counter failed: %s", esp_err_to_name(error));
128  return false;
129  }
130  error = pcnt_counter_resume(this->pcnt_unit);
131  if (error != ESP_OK) {
132  ESP_LOGE(TAG, "Resuming pulse counter failed: %s", esp_err_to_name(error));
133  return false;
134  }
135  return true;
136 }
139  pcnt_get_counter_value(this->pcnt_unit, &counter);
140  pulse_counter_t ret = counter - this->last_value;
141  this->last_value = counter;
142  return ret;
143 }
144 #endif
145 
147  ESP_LOGCONFIG(TAG, "Setting up pulse counter '%s'...", this->name_.c_str());
148  if (!this->storage_.pulse_counter_setup(this->pin_)) {
149  this->mark_failed();
150  return;
151  }
152 }
153 
155  this->current_total_ = pulses;
156  this->total_sensor_->publish_state(pulses);
157 }
158 
160  LOG_SENSOR("", "Pulse Counter", this);
161  LOG_PIN(" Pin: ", this->pin_);
162  ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode]);
163  ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode]);
164  ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %" PRIu32 " µs", this->storage_.filter_us);
165  LOG_UPDATE_INTERVAL(this);
166 }
167 
169  pulse_counter_t raw = this->storage_.read_raw_value();
170  uint32_t now = millis();
171  if (this->last_time_ != 0) {
172  uint32_t interval = now - this->last_time_;
173  float value = (60000.0f * raw) / float(interval); // per minute
174  ESP_LOGD(TAG, "'%s': Retrieved counter: %0.2f pulses/min", this->get_name().c_str(), value);
175  this->publish_state(value);
176  }
177 
178  if (this->total_sensor_ != nullptr) {
179  current_total_ += raw;
180  ESP_LOGD(TAG, "'%s': Total : %" PRIu32 " pulses", this->get_name().c_str(), current_total_);
181  this->total_sensor_->publish_state(current_total_);
182  }
183  this->last_time_ = now;
184 }
185 
186 } // namespace pulse_counter
187 } // namespace esphome
void setup() override
Unit of measurement is "pulses/min".
uint8_t raw[35]
Definition: bl0939.h:19
const char *const EDGE_MODE_TO_STRING[]
PulseCounterStorageBase * get_storage(bool hw_pcnt)
virtual void setup()=0
uint32_t IRAM_ATTR HOT micros()
Definition: core.cpp:27
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
bool pulse_counter_setup(InternalGPIOPin *pin) override
virtual uint8_t get_pin() const =0
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:151
bool pulse_counter_setup(InternalGPIOPin *pin) override
virtual ISRInternalGPIOPin to_isr() const =0
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
static void gpio_intr(BasicPulseCounterStorage *arg)
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
Definition: gpio.h:81