From 8cb9be7560ff370da8d70c098e5e90170f75ee62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Panella?= Date: Thu, 17 Feb 2022 14:14:10 -0600 Subject: [PATCH] Analog threshold (#3190) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + .../components/analog_threshold/__init__.py | 1 + .../analog_threshold_binary_sensor.cpp | 40 +++++++++++++++++ .../analog_threshold_binary_sensor.h | 29 ++++++++++++ .../analog_threshold/binary_sensor.py | 44 +++++++++++++++++++ tests/test1.yaml | 15 +++++++ 6 files changed, 130 insertions(+) create mode 100644 esphome/components/analog_threshold/__init__.py create mode 100644 esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp create mode 100644 esphome/components/analog_threshold/analog_threshold_binary_sensor.h create mode 100644 esphome/components/analog_threshold/binary_sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 165ce52485..f533ff5c47 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -19,6 +19,7 @@ esphome/components/airthings_wave_mini/* @ncareau esphome/components/airthings_wave_plus/* @jeromelaban esphome/components/am43/* @buxtronix esphome/components/am43/cover/* @buxtronix +esphome/components/analog_threshold/* @ianchi esphome/components/animation/* @syndlex esphome/components/anova/* @buxtronix esphome/components/api/* @OttoWinter diff --git a/esphome/components/analog_threshold/__init__.py b/esphome/components/analog_threshold/__init__.py new file mode 100644 index 0000000000..9ae2df986d --- /dev/null +++ b/esphome/components/analog_threshold/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@ianchi"] diff --git a/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp b/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp new file mode 100644 index 0000000000..f679b9994f --- /dev/null +++ b/esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp @@ -0,0 +1,40 @@ +#include "analog_threshold_binary_sensor.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace analog_threshold { + +static const char *const TAG = "analog_threshold.binary_sensor"; + +void AnalogThresholdBinarySensor::setup() { + float sensor_value = this->sensor_->get_state(); + + // TRUE state is defined to be when sensor is >= threshold + // so when undefined sensor value initialize to FALSE + if (std::isnan(sensor_value)) { + this->publish_initial_state(false); + } else { + this->publish_initial_state(sensor_value >= (this->lower_threshold_ + this->upper_threshold_) / 2.0f); + } +} + +void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) { + this->sensor_ = analog_sensor; + + this->sensor_->add_on_state_callback([this](float sensor_value) { + // if there is an invalid sensor reading, ignore the change and keep the current state + if (!std::isnan(sensor_value)) { + this->publish_state(sensor_value >= (this->state ? this->lower_threshold_ : this->upper_threshold_)); + } + }); +} + +void AnalogThresholdBinarySensor::dump_config() { + LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this); + LOG_SENSOR(" ", "Sensor", this->sensor_); + ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_); + ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_); +} + +} // namespace analog_threshold +} // namespace esphome diff --git a/esphome/components/analog_threshold/analog_threshold_binary_sensor.h b/esphome/components/analog_threshold/analog_threshold_binary_sensor.h new file mode 100644 index 0000000000..619aef1075 --- /dev/null +++ b/esphome/components/analog_threshold/analog_threshold_binary_sensor.h @@ -0,0 +1,29 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace analog_threshold { + +class AnalogThresholdBinarySensor : public Component, public binary_sensor::BinarySensor { + public: + void dump_config() override; + void setup() override; + + float get_setup_priority() const override { return setup_priority::DATA; } + + void set_sensor(sensor::Sensor *analog_sensor); + void set_upper_threshold(float threshold) { this->upper_threshold_ = threshold; } + void set_lower_threshold(float threshold) { this->lower_threshold_ = threshold; } + + protected: + sensor::Sensor *sensor_{nullptr}; + + float upper_threshold_; + float lower_threshold_; +}; + +} // namespace analog_threshold +} // namespace esphome diff --git a/esphome/components/analog_threshold/binary_sensor.py b/esphome/components/analog_threshold/binary_sensor.py new file mode 100644 index 0000000000..ef4a6044bf --- /dev/null +++ b/esphome/components/analog_threshold/binary_sensor.py @@ -0,0 +1,44 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor, sensor +from esphome.const import ( + CONF_SENSOR_ID, + CONF_THRESHOLD, +) + +analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold") + +AnalogThresholdBinarySensor = analog_threshold_ns.class_( + "AnalogThresholdBinarySensor", binary_sensor.BinarySensor, cg.Component +) + +CONF_UPPER = "upper" +CONF_LOWER = "lower" + +CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(AnalogThresholdBinarySensor), + cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor), + cv.Required(CONF_THRESHOLD): cv.Any( + cv.float_, + cv.Schema( + {cv.Required(CONF_UPPER): cv.float_, cv.Required(CONF_LOWER): cv.float_} + ), + ), + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = await binary_sensor.new_binary_sensor(config) + await cg.register_component(var, config) + + sens = await cg.get_variable(config[CONF_SENSOR_ID]) + cg.add(var.set_sensor(sens)) + + if isinstance(config[CONF_THRESHOLD], float): + cg.add(var.set_upper_threshold(config[CONF_THRESHOLD])) + cg.add(var.set_lower_threshold(config[CONF_THRESHOLD])) + else: + cg.add(var.set_upper_threshold(config[CONF_THRESHOLD][CONF_UPPER])) + cg.add(var.set_lower_threshold(config[CONF_THRESHOLD][CONF_LOWER])) diff --git a/tests/test1.yaml b/tests/test1.yaml index 54343f59c7..e2d5fdc0c5 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1307,6 +1307,21 @@ binary_sensor: ] - platform: as3935 name: "Storm Alert" + - platform: analog_threshold + name: Analog Trheshold 1 + sensor_id: template_sensor + threshold: + upper: 110 + lower: 90 + filters: + - delayed_on: 0s + - delayed_off: 10s + - platform: analog_threshold + name: Analog Trheshold 2 + sensor_id: template_sensor + threshold: 100 + filters: + - invert: pca9685: frequency: 500