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