ESPHome  2025.2.0
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 // HAS_PCNT
18 #endif // HAS_PCNT
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  auto x = arg->counter + 1;
33  arg->counter = x;
34  } break;
36  auto x = arg->counter - 1;
37  arg->counter = x;
38  } break;
39  }
40 }
41 
43  this->pin = pin;
44  this->pin->setup();
45  this->isr_pin = this->pin->to_isr();
47  return true;
48 }
49 
52  pulse_counter_t ret = counter - this->last_value;
53  this->last_value = counter;
54  return ret;
55 }
56 
57 #ifdef HAS_PCNT
59  static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0;
60  static pcnt_channel_t next_pcnt_channel = PCNT_CHANNEL_0;
61  this->pin = pin;
62  this->pin->setup();
63  this->pcnt_unit = next_pcnt_unit;
64  this->pcnt_channel = next_pcnt_channel;
65  next_pcnt_unit = pcnt_unit_t(int(next_pcnt_unit) + 1);
66  if (int(next_pcnt_unit) >= PCNT_UNIT_0 + PCNT_UNIT_MAX) {
67  next_pcnt_unit = PCNT_UNIT_0;
68  next_pcnt_channel = pcnt_channel_t(int(next_pcnt_channel) + 1);
69  }
70 
71  ESP_LOGCONFIG(TAG, " PCNT Unit Number: %u", this->pcnt_unit);
72  ESP_LOGCONFIG(TAG, " PCNT Channel Number: %u", this->pcnt_channel);
73 
74  pcnt_count_mode_t rising = PCNT_COUNT_DIS, falling = PCNT_COUNT_DIS;
75  switch (this->rising_edge_mode) {
77  rising = PCNT_COUNT_DIS;
78  break;
80  rising = PCNT_COUNT_INC;
81  break;
83  rising = PCNT_COUNT_DEC;
84  break;
85  }
86  switch (this->falling_edge_mode) {
88  falling = PCNT_COUNT_DIS;
89  break;
91  falling = PCNT_COUNT_INC;
92  break;
94  falling = PCNT_COUNT_DEC;
95  break;
96  }
97 
98  pcnt_config_t pcnt_config = {
99  .pulse_gpio_num = this->pin->get_pin(),
100  .ctrl_gpio_num = PCNT_PIN_NOT_USED,
101  .lctrl_mode = PCNT_MODE_KEEP,
102  .hctrl_mode = PCNT_MODE_KEEP,
103  .pos_mode = rising,
104  .neg_mode = falling,
105  .counter_h_lim = 0,
106  .counter_l_lim = 0,
107  .unit = this->pcnt_unit,
108  .channel = this->pcnt_channel,
109  };
110  esp_err_t error = pcnt_unit_config(&pcnt_config);
111  if (error != ESP_OK) {
112  ESP_LOGE(TAG, "Configuring Pulse Counter failed: %s", esp_err_to_name(error));
113  return false;
114  }
115 
116  if (this->filter_us != 0) {
117  uint16_t filter_val = std::min(static_cast<unsigned int>(this->filter_us * 80u), 1023u);
118  ESP_LOGCONFIG(TAG, " Filter Value: %" PRIu32 "us (val=%u)", this->filter_us, filter_val);
119  error = pcnt_set_filter_value(this->pcnt_unit, filter_val);
120  if (error != ESP_OK) {
121  ESP_LOGE(TAG, "Setting filter value failed: %s", esp_err_to_name(error));
122  return false;
123  }
124  error = pcnt_filter_enable(this->pcnt_unit);
125  if (error != ESP_OK) {
126  ESP_LOGE(TAG, "Enabling filter failed: %s", esp_err_to_name(error));
127  return false;
128  }
129  }
130 
131  error = pcnt_counter_pause(this->pcnt_unit);
132  if (error != ESP_OK) {
133  ESP_LOGE(TAG, "Pausing pulse counter failed: %s", esp_err_to_name(error));
134  return false;
135  }
136  error = pcnt_counter_clear(this->pcnt_unit);
137  if (error != ESP_OK) {
138  ESP_LOGE(TAG, "Clearing pulse counter failed: %s", esp_err_to_name(error));
139  return false;
140  }
141  error = pcnt_counter_resume(this->pcnt_unit);
142  if (error != ESP_OK) {
143  ESP_LOGE(TAG, "Resuming pulse counter failed: %s", esp_err_to_name(error));
144  return false;
145  }
146  return true;
147 }
148 
151  pcnt_get_counter_value(this->pcnt_unit, &counter);
152  pulse_counter_t ret = counter - this->last_value;
153  this->last_value = counter;
154  return ret;
155 }
156 #endif // HAS_PCNT
157 
159  ESP_LOGCONFIG(TAG, "Setting up pulse counter '%s'...", this->name_.c_str());
160  if (!this->storage_.pulse_counter_setup(this->pin_)) {
161  this->mark_failed();
162  return;
163  }
164 }
165 
167  this->current_total_ = pulses;
168  this->total_sensor_->publish_state(pulses);
169 }
170 
172  LOG_SENSOR("", "Pulse Counter", this);
173  LOG_PIN(" Pin: ", this->pin_);
174  ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode]);
175  ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode]);
176  ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %" PRIu32 " µs", this->storage_.filter_us);
177  LOG_UPDATE_INTERVAL(this);
178 }
179 
181  pulse_counter_t raw = this->storage_.read_raw_value();
182  uint32_t now = millis();
183  if (this->last_time_ != 0) {
184  uint32_t interval = now - this->last_time_;
185  float value = (60000.0f * raw) / float(interval); // per minute
186  ESP_LOGD(TAG, "'%s': Retrieved counter: %0.2f pulses/min", this->get_name().c_str(), value);
187  this->publish_state(value);
188  }
189 
190  if (this->total_sensor_ != nullptr) {
191  current_total_ += raw;
192  ESP_LOGD(TAG, "'%s': Total : %" PRIu32 " pulses", this->get_name().c_str(), current_total_);
193  this->total_sensor_->publish_state(current_total_);
194  }
195  this->last_time_ = now;
196 }
197 
198 } // namespace pulse_counter
199 } // 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)
uint16_t x
Definition: tt21100.cpp:17
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:183
bool pulse_counter_setup(InternalGPIOPin *pin) override
virtual ISRInternalGPIOPin to_isr() const =0
Implementation of SPI Controller mode.
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:88