mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 08:55:22 +01:00
parent
2650441013
commit
1b4156646e
4 changed files with 79 additions and 36 deletions
|
@ -16,8 +16,17 @@ enum HLW8012SensorModels {
|
|||
HLW8012_SENSOR_MODEL_BL0937
|
||||
};
|
||||
|
||||
#ifdef HAS_PCNT
|
||||
#define USE_PCNT true
|
||||
#else
|
||||
#define USE_PCNT false
|
||||
#endif
|
||||
|
||||
class HLW8012Component : public PollingComponent {
|
||||
public:
|
||||
HLW8012Component()
|
||||
: cf_store_(*pulse_counter::get_storage(USE_PCNT)), cf1_store_(*pulse_counter::get_storage(USE_PCNT)) {}
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
@ -49,9 +58,9 @@ class HLW8012Component : public PollingComponent {
|
|||
uint64_t cf_total_pulses_{0};
|
||||
GPIOPin *sel_pin_;
|
||||
InternalGPIOPin *cf_pin_;
|
||||
pulse_counter::PulseCounterStorage cf_store_;
|
||||
pulse_counter::PulseCounterStorageBase &cf_store_;
|
||||
InternalGPIOPin *cf1_pin_;
|
||||
pulse_counter::PulseCounterStorage cf1_store_;
|
||||
pulse_counter::PulseCounterStorageBase &cf1_store_;
|
||||
sensor::Sensor *voltage_sensor_{nullptr};
|
||||
sensor::Sensor *current_sensor_{nullptr};
|
||||
sensor::Sensor *power_sensor_{nullptr};
|
||||
|
|
|
@ -8,8 +8,16 @@ static const char *const TAG = "pulse_counter";
|
|||
|
||||
const char *const EDGE_MODE_TO_STRING[] = {"DISABLE", "INCREMENT", "DECREMENT"};
|
||||
|
||||
#ifndef HAS_PCNT
|
||||
void IRAM_ATTR PulseCounterStorage::gpio_intr(PulseCounterStorage *arg) {
|
||||
#ifdef HAS_PCNT
|
||||
PulseCounterStorageBase *get_storage(bool hw_pcnt) {
|
||||
return (hw_pcnt ? (PulseCounterStorageBase *) (new HwPulseCounterStorage)
|
||||
: (PulseCounterStorageBase *) (new BasicPulseCounterStorage));
|
||||
}
|
||||
#else
|
||||
PulseCounterStorageBase *get_storage(bool) { return new BasicPulseCounterStorage; }
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR BasicPulseCounterStorage::gpio_intr(BasicPulseCounterStorage *arg) {
|
||||
const uint32_t now = micros();
|
||||
const bool discard = now - arg->last_pulse < arg->filter_us;
|
||||
arg->last_pulse = now;
|
||||
|
@ -28,23 +36,22 @@ void IRAM_ATTR PulseCounterStorage::gpio_intr(PulseCounterStorage *arg) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
bool PulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
||||
bool BasicPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
||||
this->pin = pin;
|
||||
this->pin->setup();
|
||||
this->isr_pin = this->pin->to_isr();
|
||||
this->pin->attach_interrupt(PulseCounterStorage::gpio_intr, this, gpio::INTERRUPT_ANY_EDGE);
|
||||
this->pin->attach_interrupt(BasicPulseCounterStorage::gpio_intr, this, gpio::INTERRUPT_ANY_EDGE);
|
||||
return true;
|
||||
}
|
||||
pulse_counter_t PulseCounterStorage::read_raw_value() {
|
||||
pulse_counter_t BasicPulseCounterStorage::read_raw_value() {
|
||||
pulse_counter_t counter = this->counter;
|
||||
pulse_counter_t ret = counter - this->last_value;
|
||||
this->last_value = counter;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PCNT
|
||||
bool PulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
||||
bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
||||
static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0;
|
||||
this->pin = pin;
|
||||
this->pin->setup();
|
||||
|
@ -127,7 +134,7 @@ bool PulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
pulse_counter_t PulseCounterStorage::read_raw_value() {
|
||||
pulse_counter_t HwPulseCounterStorage::read_raw_value() {
|
||||
pulse_counter_t counter;
|
||||
pcnt_get_counter_value(this->pcnt_unit, &counter);
|
||||
pulse_counter_t ret = counter - this->last_value;
|
||||
|
|
|
@ -24,31 +24,44 @@ using pulse_counter_t = int16_t;
|
|||
using pulse_counter_t = int32_t;
|
||||
#endif
|
||||
|
||||
struct PulseCounterStorage {
|
||||
bool pulse_counter_setup(InternalGPIOPin *pin);
|
||||
pulse_counter_t read_raw_value();
|
||||
|
||||
static void gpio_intr(PulseCounterStorage *arg);
|
||||
|
||||
#ifndef HAS_PCNT
|
||||
volatile pulse_counter_t counter{0};
|
||||
volatile uint32_t last_pulse{0};
|
||||
#endif
|
||||
struct PulseCounterStorageBase {
|
||||
virtual bool pulse_counter_setup(InternalGPIOPin *pin) = 0;
|
||||
virtual pulse_counter_t read_raw_value() = 0;
|
||||
|
||||
InternalGPIOPin *pin;
|
||||
#ifdef HAS_PCNT
|
||||
pcnt_unit_t pcnt_unit;
|
||||
#else
|
||||
ISRInternalGPIOPin isr_pin;
|
||||
#endif
|
||||
PulseCounterCountMode rising_edge_mode{PULSE_COUNTER_INCREMENT};
|
||||
PulseCounterCountMode falling_edge_mode{PULSE_COUNTER_DISABLE};
|
||||
uint32_t filter_us{0};
|
||||
pulse_counter_t last_value{0};
|
||||
};
|
||||
|
||||
struct BasicPulseCounterStorage : public PulseCounterStorageBase {
|
||||
static void gpio_intr(BasicPulseCounterStorage *arg);
|
||||
|
||||
bool pulse_counter_setup(InternalGPIOPin *pin) override;
|
||||
pulse_counter_t read_raw_value() override;
|
||||
|
||||
volatile pulse_counter_t counter{0};
|
||||
volatile uint32_t last_pulse{0};
|
||||
|
||||
ISRInternalGPIOPin isr_pin;
|
||||
};
|
||||
|
||||
#ifdef HAS_PCNT
|
||||
struct HwPulseCounterStorage : public PulseCounterStorageBase {
|
||||
bool pulse_counter_setup(InternalGPIOPin *pin) override;
|
||||
pulse_counter_t read_raw_value() override;
|
||||
|
||||
pcnt_unit_t pcnt_unit;
|
||||
};
|
||||
#endif
|
||||
|
||||
PulseCounterStorageBase *get_storage(bool hw_pcnt = false);
|
||||
|
||||
class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
|
||||
public:
|
||||
explicit PulseCounterSensor(bool hw_pcnt = false) : storage_(*get_storage(hw_pcnt)) {}
|
||||
|
||||
void set_pin(InternalGPIOPin *pin) { pin_ = pin; }
|
||||
void set_rising_edge_mode(PulseCounterCountMode mode) { storage_.rising_edge_mode = mode; }
|
||||
void set_falling_edge_mode(PulseCounterCountMode mode) { storage_.falling_edge_mode = mode; }
|
||||
|
@ -65,7 +78,7 @@ class PulseCounterSensor : public sensor::Sensor, public PollingComponent {
|
|||
|
||||
protected:
|
||||
InternalGPIOPin *pin_;
|
||||
PulseCounterStorage storage_;
|
||||
PulseCounterStorageBase &storage_;
|
||||
uint32_t last_time_{0};
|
||||
uint32_t current_total_{0};
|
||||
sensor::Sensor *total_sensor_;
|
||||
|
|
|
@ -20,6 +20,8 @@ from esphome.const import (
|
|||
)
|
||||
from esphome.core import CORE
|
||||
|
||||
CONF_USE_PCNT = "use_pcnt"
|
||||
|
||||
pulse_counter_ns = cg.esphome_ns.namespace("pulse_counter")
|
||||
PulseCounterCountMode = pulse_counter_ns.enum("PulseCounterCountMode")
|
||||
COUNT_MODES = {
|
||||
|
@ -40,11 +42,19 @@ SetTotalPulsesAction = pulse_counter_ns.class_(
|
|||
|
||||
|
||||
def validate_internal_filter(value):
|
||||
value = cv.positive_time_period_microseconds(value)
|
||||
if CORE.is_esp32:
|
||||
if value.total_microseconds > 13:
|
||||
raise cv.Invalid("Maximum internal filter value for ESP32 is 13us")
|
||||
return value
|
||||
use_pcnt = value.get(CONF_USE_PCNT)
|
||||
if CORE.is_esp8266 and use_pcnt:
|
||||
raise cv.Invalid(
|
||||
"Using hardware PCNT is only available on ESP32",
|
||||
[CONF_USE_PCNT],
|
||||
)
|
||||
|
||||
if CORE.is_esp32 and use_pcnt:
|
||||
if value.get(CONF_INTERNAL_FILTER).total_microseconds > 13:
|
||||
raise cv.Invalid(
|
||||
"Maximum internal filter value when using ESP32 hardware PCNT is 13us",
|
||||
[CONF_INTERNAL_FILTER],
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
|
@ -69,7 +79,7 @@ def validate_count_mode(value):
|
|||
return value
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.sensor_schema(
|
||||
PulseCounterSensor,
|
||||
unit_of_measurement=UNIT_PULSES_PER_MINUTE,
|
||||
|
@ -95,21 +105,25 @@ CONFIG_SCHEMA = (
|
|||
),
|
||||
validate_count_mode,
|
||||
),
|
||||
cv.Optional(CONF_INTERNAL_FILTER, default="13us"): validate_internal_filter,
|
||||
cv.SplitDefault(CONF_USE_PCNT, esp32=True): cv.boolean,
|
||||
cv.Optional(
|
||||
CONF_INTERNAL_FILTER, default="13us"
|
||||
): cv.positive_time_period_microseconds,
|
||||
cv.Optional(CONF_TOTAL): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_PULSES,
|
||||
icon=ICON_PULSE,
|
||||
accuracy_decimals=0,
|
||||
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||
),
|
||||
}
|
||||
},
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(cv.polling_component_schema("60s")),
|
||||
validate_internal_filter,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = await sensor.new_sensor(config)
|
||||
var = await sensor.new_sensor(config, config.get(CONF_USE_PCNT))
|
||||
await cg.register_component(var, config)
|
||||
|
||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||
|
|
Loading…
Reference in a new issue