Added Averager
This commit is contained in:
parent
d6c8d35385
commit
a96531dda9
@ -45,7 +45,13 @@ sensor:
|
|||||||
pin: A0
|
pin: A0
|
||||||
zero_point: 640
|
zero_point: 640
|
||||||
inverted: true
|
inverted: true
|
||||||
update_interval: 2s
|
update_interval: 1s
|
||||||
|
average:
|
||||||
|
mesurements: 5
|
||||||
|
send_state_every: 10
|
||||||
|
on_completely_new_value:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("WHAT", "Just a test %.1f", value);
|
||||||
# GPIO A0 to acd
|
# GPIO A0 to acd
|
||||||
|
|
||||||
# Here is space for any display implementation that could possibliy be. Have fun OK
|
# Here is space for any display implementation that could possibliy be. Have fun OK
|
@ -5,25 +5,65 @@ namespace analog_orp {
|
|||||||
|
|
||||||
static const char *const TAG = "sensor.analog_orp";
|
static const char *const TAG = "sensor.analog_orp";
|
||||||
|
|
||||||
|
FloatAverager::FloatAverager(size_t size): size_(size), vector_(size_){
|
||||||
|
this->index_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatAverager::add_value(float value){
|
||||||
|
vector_.at(index_++) = value;
|
||||||
|
if(index_ == size_){
|
||||||
|
index_ = 0;
|
||||||
|
has_filled_once_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float FloatAverager::create_average(){
|
||||||
|
float sum = 0;
|
||||||
|
for(auto point : vector_){
|
||||||
|
sum += point;
|
||||||
|
}
|
||||||
|
return sum / (float) size_;
|
||||||
|
}
|
||||||
|
bool FloatAverager::isFull(){
|
||||||
|
return index_ == 0;
|
||||||
|
}
|
||||||
|
bool FloatAverager::has_filled_once(){
|
||||||
|
return has_filled_once_;
|
||||||
|
}
|
||||||
|
|
||||||
void ChlorineSensor::set_pin(InternalGPIOPin *pin){
|
void ChlorineSensor::set_pin(InternalGPIOPin *pin){
|
||||||
this->pin = pin;
|
this->pin_ = pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChlorineSensor::set_zero_point(int zero_point){
|
void ChlorineSensor::set_zero_point(int zero_point){
|
||||||
this->zero_point_int = zero_point;
|
this->zero_point_int_ = zero_point;
|
||||||
this->zero_point = ((float) zero_point / 1024.0f) * 3.3f; // Base Value for Clorine in Volt
|
this->zero_point_ = ((float) zero_point / 1024.0f) * 3.3f; // Base Value for Clorine in Volt
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChlorineSensor::set_print_raw(bool print_raw){
|
void ChlorineSensor::set_print_raw(bool print_raw){
|
||||||
this->print_raw = print_raw;
|
this->print_raw_ = print_raw;
|
||||||
}
|
}
|
||||||
void ChlorineSensor::set_inverted(bool inverted){
|
void ChlorineSensor::set_inverted(bool inverted){
|
||||||
this->inverted = inverted;
|
this->inverted_ = inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChlorineSensor::init_averager(int mesurements, int send_average_every){
|
||||||
|
this->averager_ = new FloatAverager(mesurements);
|
||||||
|
this->send_averager_every_ = send_average_every;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChlorineSensor::add_read_callback(std::function<void(float)> &&callback){
|
||||||
|
this->on_value_read_.add(std::move(callback));
|
||||||
|
}
|
||||||
|
void ChlorineSensor::add_average_change_callback(std::function<void(float)> &&callback){
|
||||||
|
this->on_average_changed_.add(std::move(callback));
|
||||||
|
}
|
||||||
|
void ChlorineSensor::add_new_value_callback(std::function<void(float)> &&callback){
|
||||||
|
this->new_value_callback_.add(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChlorineSensor::setup(){
|
void ChlorineSensor::setup(){
|
||||||
ESP_LOGCONFIG(TAG, "Setting up AnalogOrp '%s'...", this->get_name().c_str());
|
ESP_LOGCONFIG(TAG, "Setting up AnalogOrp '%s'...", this->get_name().c_str());
|
||||||
pin->setup();
|
pin_->setup();
|
||||||
ESP_LOGCONFIG(TAG, "AnalogOrp '%s' setup finished!", this->get_name().c_str());
|
ESP_LOGCONFIG(TAG, "AnalogOrp '%s' setup finished!", this->get_name().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +71,31 @@ void ChlorineSensor::setup(){
|
|||||||
void ChlorineSensor::update() {
|
void ChlorineSensor::update() {
|
||||||
float value_v = this->sample();
|
float value_v = this->sample();
|
||||||
ESP_LOGV(TAG, "'%s': Got orp value=%.4fmV", this->get_name().c_str(), value_v);
|
ESP_LOGV(TAG, "'%s': Got orp value=%.4fmV", this->get_name().c_str(), value_v);
|
||||||
|
if(averager_ != nullptr){
|
||||||
|
averager_->add_value(value_v);
|
||||||
|
on_value_read_.call(value_v);
|
||||||
|
|
||||||
|
if(++averager_send_counter_ >= send_averager_every_) averager_send_counter_ = 0;
|
||||||
|
|
||||||
|
if(!averager_->has_filled_once()) return;
|
||||||
|
float average = averager_->create_average();
|
||||||
|
on_average_changed_.call(average);
|
||||||
|
|
||||||
|
if(send_averager_every_ == -1){
|
||||||
|
if(averager_->isFull()){
|
||||||
|
this->publish_state(average);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(averager_->isFull()){
|
||||||
|
this->new_value_callback_.call(average);
|
||||||
|
}
|
||||||
|
if(averager_send_counter_ == 0){
|
||||||
|
this->publish_state(average);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
this->publish_state(value_v);
|
this->publish_state(value_v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,10 +104,10 @@ float ChlorineSensor::get_setup_priority() const { return setup_priority::DATA;
|
|||||||
void ChlorineSensor::dump_config(){
|
void ChlorineSensor::dump_config(){
|
||||||
LOG_SENSOR("", "AnalogOrp Sensor", this);
|
LOG_SENSOR("", "AnalogOrp Sensor", this);
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
LOG_PIN(" Pin: ", pin);
|
LOG_PIN(" Pin: ", pin_);
|
||||||
ESP_LOGCONFIG(TAG, " Zero Point: %d", zero_point_int);
|
ESP_LOGCONFIG(TAG, " Zero Point: %d", zero_point_int_);
|
||||||
ESP_LOGCONFIG(TAG, " Inverted: %s", inverted ? "true" : "false");
|
ESP_LOGCONFIG(TAG, " Inverted: %s", inverted_ ? "true" : "false");
|
||||||
ESP_LOGCONFIG(TAG, " Print Raw: %s", print_raw ? "true" : "false");
|
ESP_LOGCONFIG(TAG, " Print Raw: %s", print_raw_ ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -50,15 +115,15 @@ Nullwert : 680
|
|||||||
*/
|
*/
|
||||||
float ChlorineSensor::sample(){
|
float ChlorineSensor::sample(){
|
||||||
|
|
||||||
float raw_read = (float) analogRead(pin->get_pin());
|
float raw_read = (float) analogRead(pin_->get_pin());
|
||||||
if(print_raw){
|
if(print_raw_){
|
||||||
ESP_LOGD(TAG, "analogRead read a raw value of: %.0f", raw_read);
|
ESP_LOGD(TAG, "analogRead read a raw value of: %.0f", raw_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
float raw_voltage = (raw_read / 1024.0f) * 3.3f;
|
float raw_voltage = (raw_read / 1024.0f) * 3.3f;
|
||||||
float messured_voltage = raw_voltage - zero_point;
|
float messured_voltage = raw_voltage - zero_point_;
|
||||||
|
|
||||||
if(inverted){
|
if(inverted_){
|
||||||
messured_voltage = messured_voltage * -1.0f;
|
messured_voltage = messured_voltage * -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,28 +4,72 @@
|
|||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/gpio.h"
|
#include "esphome/core/gpio.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace analog_orp {
|
namespace analog_orp {
|
||||||
|
|
||||||
|
class FloatAverager{
|
||||||
|
public:
|
||||||
|
FloatAverager(size_t size);
|
||||||
|
void add_value(float value);
|
||||||
|
bool isFull();
|
||||||
|
float create_average();
|
||||||
|
bool has_filled_once();
|
||||||
|
protected:
|
||||||
|
size_t size_;
|
||||||
|
std::vector<float> vector_;
|
||||||
|
size_t index_;
|
||||||
|
bool has_filled_once_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
class ChlorineSensor: public PollingComponent, public sensor::Sensor {
|
class ChlorineSensor: public PollingComponent, public sensor::Sensor {
|
||||||
public:
|
public:
|
||||||
void set_pin(InternalGPIOPin *pin);
|
void set_pin(InternalGPIOPin *pin);
|
||||||
void set_zero_point(int zero_point);
|
void set_zero_point(int zero_point);
|
||||||
void set_print_raw(bool print_raw);
|
void set_print_raw(bool print_raw);
|
||||||
void set_inverted(bool inverted);
|
void set_inverted(bool inverted);
|
||||||
|
void add_read_callback(std::function<void(float)> &&callback);
|
||||||
|
void add_average_change_callback(std::function<void(float)> &&callback);
|
||||||
|
void add_new_value_callback(std::function<void(float)> &&callback);
|
||||||
|
void init_averager(int mesurements, int send_average_every);
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
float sample();
|
float sample();
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
float get_setup_priority() const;
|
float get_setup_priority() const;
|
||||||
protected:
|
protected:
|
||||||
InternalGPIOPin *pin;
|
InternalGPIOPin *pin_;
|
||||||
bool inverted;
|
CallbackManager<void(float)> on_value_read_;
|
||||||
bool print_raw;
|
CallbackManager<void(float)> on_average_changed_;
|
||||||
float zero_point;
|
CallbackManager<void(float)> new_value_callback_;
|
||||||
int zero_point_int;
|
bool inverted_;
|
||||||
|
bool print_raw_;
|
||||||
|
float zero_point_;
|
||||||
|
int zero_point_int_;
|
||||||
|
FloatAverager *averager_;
|
||||||
|
bool use_averager_ = false;
|
||||||
|
int send_averager_every_ = -1;
|
||||||
|
int averager_send_counter_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChlorineValueReadTrigger : public Trigger<float> {
|
||||||
|
public:
|
||||||
|
explicit ChlorineValueReadTrigger(ChlorineSensor *parent) {
|
||||||
|
parent->add_read_callback([this](int value) { this->trigger(value); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class ChlorineAverageChangeTrigger : public Trigger<float> {
|
||||||
|
public:
|
||||||
|
explicit ChlorineAverageChangeTrigger(ChlorineSensor *parent) {
|
||||||
|
parent->add_average_change_callback([this](int value) { this->trigger(value); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class ChlorineNewValueTrigger : public Trigger<float> {
|
||||||
|
public:
|
||||||
|
explicit ChlorineNewValueTrigger(ChlorineSensor *parent) {
|
||||||
|
parent->add_new_value_callback([this](int value) { this->trigger(value); });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
from esphome import automation
|
||||||
from esphome.components import sensor
|
from esphome.components import sensor
|
||||||
from esphome.components.adc import sensor as adc
|
from esphome.components.adc import sensor as adc
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
CONF_TRIGGER_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
chlorine_sensor_ns = cg.esphome_ns.namespace('analog_orp')
|
chlorine_sensor_ns = cg.esphome_ns.namespace('analog_orp')
|
||||||
@ -15,11 +17,27 @@ CONF_SENSOR_PIN = "pin"
|
|||||||
CONF_INVERTED = "inverted"
|
CONF_INVERTED = "inverted"
|
||||||
CONF_PRINT_RAW = "print_raw"
|
CONF_PRINT_RAW = "print_raw"
|
||||||
CONF_ZERO_POINT = "zero_point"
|
CONF_ZERO_POINT = "zero_point"
|
||||||
|
CONF_AVERAGE = "average"
|
||||||
|
CONF_AVERAGE_MESUREMENTS="mesurements"
|
||||||
|
CONF_SEND_STATE_EVERY="send_state_every"
|
||||||
|
CONF_ON_READ_VALUE = "on_value_read"
|
||||||
|
CONF_AVERAGE_ON_VALUE = "on_value"
|
||||||
|
CONF_AVERAGE_NEW = "on_completely_new_value"
|
||||||
|
|
||||||
UNIT_MILLI_VOLT = "mV"
|
UNIT_MILLI_VOLT = "mV"
|
||||||
|
|
||||||
ICON_LIGHTNING_BOLT="mdi:lightning-bolt"
|
ICON_LIGHTNING_BOLT="mdi:lightning-bolt"
|
||||||
|
|
||||||
|
ChlorineValueRead = chlorine_sensor_ns.class_(
|
||||||
|
"ChlorineValueReadTrigger", automation.Trigger.template(cg.float_)
|
||||||
|
)
|
||||||
|
ChlorineAverageChange = chlorine_sensor_ns.class_(
|
||||||
|
"ChlorineAverageChangeTrigger", automation.Trigger.template(cg.float_)
|
||||||
|
)
|
||||||
|
ChlorineNewValue = chlorine_sensor_ns.class_(
|
||||||
|
"ChlorineNewValueTrigger", automation.Trigger.template(cg.float_)
|
||||||
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
sensor.sensor_schema(
|
sensor.sensor_schema(
|
||||||
ChlorineSensor,
|
ChlorineSensor,
|
||||||
@ -32,19 +50,50 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Required(CONF_SENSOR_PIN): adc.validate_adc_pin,
|
cv.Required(CONF_SENSOR_PIN): adc.validate_adc_pin,
|
||||||
cv.Required(CONF_ZERO_POINT): cv.Range(min=0, max=1023),
|
cv.Required(CONF_ZERO_POINT): cv.Range(min=0, max=1023),
|
||||||
cv.Optional(CONF_INVERTED, False): cv.boolean,
|
cv.Optional(CONF_INVERTED, False): cv.boolean,
|
||||||
cv.Optional(CONF_PRINT_RAW, False): cv.boolean
|
cv.Optional(CONF_PRINT_RAW, False): cv.boolean,
|
||||||
|
cv.Optional(CONF_AVERAGE): cv.Schema({
|
||||||
|
cv.Required(CONF_AVERAGE_MESUREMENTS): cv.int_range(min=1),
|
||||||
|
cv.Optional(CONF_SEND_STATE_EVERY): cv.int_range(min=1),
|
||||||
|
cv.Optional(CONF_ON_READ_VALUE): automation.validate_automation({
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChlorineValueRead),
|
||||||
|
}),
|
||||||
|
cv.Optional(CONF_AVERAGE_ON_VALUE): automation.validate_automation({
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChlorineAverageChange),
|
||||||
|
}),
|
||||||
|
cv.Optional(CONF_AVERAGE_NEW): automation.validate_automation({
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChlorineNewValue),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
).extend(cv.polling_component_schema("60s"))
|
).extend(cv.polling_component_schema("60s"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
yield cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
yield sensor.register_sensor(var, config)
|
await sensor.register_sensor(var, config)
|
||||||
|
|
||||||
sensor_pin = yield cg.gpio_pin_expression(config[CONF_SENSOR_PIN])
|
sensor_pin = await cg.gpio_pin_expression(config[CONF_SENSOR_PIN])
|
||||||
cg.add(var.set_pin(sensor_pin))
|
cg.add(var.set_pin(sensor_pin))
|
||||||
|
|
||||||
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
cg.add(var.set_inverted(config[CONF_INVERTED]))
|
||||||
cg.add(var.set_print_raw(config[CONF_PRINT_RAW]))
|
cg.add(var.set_print_raw(config[CONF_PRINT_RAW]))
|
||||||
cg.add(var.set_zero_point(config[CONF_ZERO_POINT]))
|
cg.add(var.set_zero_point(config[CONF_ZERO_POINT]))
|
||||||
|
|
||||||
|
if averager_config := config.get(CONF_AVERAGE):
|
||||||
|
update_each = -1
|
||||||
|
if CONF_SEND_STATE_EVERY in averager_config:
|
||||||
|
update_each = averager_config[CONF_SEND_STATE_EVERY]
|
||||||
|
cg.add(var.init_averager(averager_config[CONF_AVERAGE_MESUREMENTS], update_each))
|
||||||
|
|
||||||
|
for conf in averager_config.get(CONF_ON_READ_VALUE, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(trigger, [(float, "value")], conf)
|
||||||
|
|
||||||
|
for conf in averager_config.get(CONF_AVERAGE_ON_VALUE, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(trigger, [(float, "value")], conf)
|
||||||
|
|
||||||
|
for conf in averager_config.get(CONF_AVERAGE_NEW, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(trigger, [(float, "value")], conf)
|
Loading…
Reference in New Issue
Block a user