From 5646dd5d0cf1788fc90f8f163a6ef347578dbf53 Mon Sep 17 00:00:00 2001 From: brisk Date: Sat, 27 Jul 2024 23:12:06 +0930 Subject: [PATCH] pulse_counter_ulp: Make sleep duration configurable, keep estimate of ulp runtime --- .../pulse_counter_ulp/pulse_counter_ulp_sensor.cpp | 14 +++++++------- .../pulse_counter_ulp/pulse_counter_ulp_sensor.h | 12 +++++++++++- esphome/components/pulse_counter_ulp/sensor.py | 7 +++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp index f259b6022f..fb9dd3ef9f 100644 --- a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp +++ b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.cpp @@ -28,8 +28,7 @@ const char *to_string(CountMode count_mode) { extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); -namespace { -bool setup_ulp(gpio_num_t gpio_num) { +bool UlpProgram::setup_ulp() { esp_err_t error = ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); if (error != ESP_OK) { ESP_LOGE(TAG, "Loading ULP binary failed: %s", esp_err_to_name(error)); @@ -37,6 +36,7 @@ bool setup_ulp(gpio_num_t gpio_num) { } /* GPIO used for pulse counting. */ + auto gpio_num = static_cast(this->pin->get_pin()); int rtcio_num = rtc_io_number_get(gpio_num); if (!rtc_gpio_is_valid_gpio(gpio_num)) { ESP_LOGE(TAG, "GPIO used for pulse counting must be an RTC IO"); @@ -63,10 +63,10 @@ bool setup_ulp(gpio_num_t gpio_num) { rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_INPUT_ONLY); rtc_gpio_hold_en(gpio_num); - /* Set ULP wake up period to T = 20ms. - * Minimum pulse width has to be T * (ulp_debounce_counter + 1) = 80ms. + /* Set ULP wake up period T + * Minimum pulse width has to be T * (ulp_debounce_counter + 1). */ - ulp_set_wakeup_period(0, 20000); + ulp_set_wakeup_period(0, this->sleep_duration_ / std::chrono::microseconds{1}); /* Start the program */ error = ulp_run(&ulp_entry - RTC_SLOW_MEM); @@ -77,7 +77,6 @@ bool setup_ulp(gpio_num_t gpio_num) { return true; } -} // namespace bool UlpProgram::setup(InternalGPIOPin *pin) { this->pin = pin; @@ -88,7 +87,7 @@ bool UlpProgram::setup(InternalGPIOPin *pin) { if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_UNDEFINED) { ESP_LOGD(TAG, "Did not wake up from sleep, assuming restart or first boot and setting up ULP program"); - return setup_ulp(static_cast(pin->get_pin())); + return setup_ulp(); } else { ESP_LOGD(TAG, "Woke up from sleep, skipping set-up of ULP program"); return true; @@ -138,6 +137,7 @@ void PulseCounterUlpSensor::update() { clock::time_point now = clock::now(); clock::duration interval = now - this->last_time_; if (interval != clock::duration::zero()) { + ulp_mean_exec_time_ = interval / static_cast(raw.run_count); float value = std::chrono::minutes{1} * static_cast(raw.edge_count) / interval; // pulses per minute ESP_LOGD(TAG, "'%s': Retrieved counter: %0.2f pulses/min", this->get_name().c_str(), value); this->publish_state(value); diff --git a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h index e3c24154b4..0d8fd1a75d 100644 --- a/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h +++ b/esphome/components/pulse_counter_ulp/pulse_counter_ulp_sensor.h @@ -15,7 +15,8 @@ enum class CountMode { disable = 0, increment = 1, decrement = -1 }; // millis() jumps when a time component synchronises, so we use steady_clock instead using clock = std::chrono::steady_clock; -struct UlpProgram { +class UlpProgram { + public: struct state { uint16_t edge_count; uint16_t run_count; @@ -27,6 +28,10 @@ struct UlpProgram { InternalGPIOPin *pin; CountMode rising_edge_mode{CountMode::increment}; CountMode falling_edge_mode{CountMode::disable}; + std::chrono::duration sleep_duration_{20000}; + + private: + bool setup_ulp(); }; class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { @@ -36,6 +41,10 @@ class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { void set_pin(InternalGPIOPin *pin) { pin_ = pin; } void set_rising_edge_mode(CountMode mode) { storage_.rising_edge_mode = mode; } void set_falling_edge_mode(CountMode mode) { storage_.falling_edge_mode = mode; } + void set_sleep_duration(uint32_t duration_us) { + storage_.sleep_duration_ = std::chrono::microseconds{1} * duration_us; + this->ulp_mean_exec_time_ = duration_us * std::chrono::microseconds{1}; + } void set_total_sensor(sensor::Sensor *total_sensor) { total_sensor_ = total_sensor; } void set_total_pulses(uint32_t pulses); @@ -50,6 +59,7 @@ class PulseCounterUlpSensor : public sensor::Sensor, public PollingComponent { InternalGPIOPin *pin_; UlpProgram storage_; clock::time_point last_time_{}; + std::chrono::duration ulp_mean_exec_time_{}; uint32_t current_total_{0}; sensor::Sensor *total_sensor_{nullptr}; }; diff --git a/esphome/components/pulse_counter_ulp/sensor.py b/esphome/components/pulse_counter_ulp/sensor.py index a7662ad7c6..442eedd5ad 100644 --- a/esphome/components/pulse_counter_ulp/sensor.py +++ b/esphome/components/pulse_counter_ulp/sensor.py @@ -11,6 +11,8 @@ from esphome.const import ( CONF_PIN, CONF_RISING_EDGE, CONF_NUMBER, + CONF_SLEEP_DURATION, + CONF_DEBOUNCE, CONF_TOTAL, CONF_VALUE, ICON_PULSE, @@ -86,6 +88,10 @@ CONFIG_SCHEMA = cv.All( ), validate_count_mode, ), + cv.Optional( + CONF_SLEEP_DURATION, default="20000us" + ): cv.positive_time_period_microseconds, + cv.Optional(CONF_DEBOUNCE, default=3): cv.positive_int, cv.Optional(CONF_TOTAL): sensor.sensor_schema( unit_of_measurement=UNIT_PULSES, icon=ICON_PULSE, @@ -119,6 +125,7 @@ async def to_code(config): count = config[CONF_COUNT_MODE] cg.add(var.set_rising_edge_mode(count[CONF_RISING_EDGE])) cg.add(var.set_falling_edge_mode(count[CONF_FALLING_EDGE])) + cg.add(var.set_sleep_duration(config[CONF_SLEEP_DURATION])) if CONF_TOTAL in config: sens = await sensor.new_sensor(config[CONF_TOTAL])