From 20dd74468033e97f015d6627c7f652bf23030b32 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 2 Nov 2020 06:24:26 +1300 Subject: [PATCH] Add on_clockwise and on_anticlockwise triggers to rotary encoder (#1330) --- .../rotary_encoder/rotary_encoder.cpp | 2 ++ .../rotary_encoder/rotary_encoder.h | 25 +++++++++++++++++++ esphome/components/rotary_encoder/sensor.py | 22 +++++++++++++++- tests/test1.yaml | 4 +++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/esphome/components/rotary_encoder/rotary_encoder.cpp b/esphome/components/rotary_encoder/rotary_encoder.cpp index 769d3e1103..873aaf1971 100644 --- a/esphome/components/rotary_encoder/rotary_encoder.cpp +++ b/esphome/components/rotary_encoder/rotary_encoder.cpp @@ -94,10 +94,12 @@ void ICACHE_RAM_ATTR HOT RotaryEncoderSensorStore::gpio_intr(RotaryEncoderSensor if ((new_state & arg->resolution & STATE_HAS_INCREMENTED) != 0) { if (arg->counter < arg->max_value) arg->counter++; + arg->on_clockwise_callback_.call(); } if ((new_state & arg->resolution & STATE_HAS_DECREMENTED) != 0) { if (arg->counter > arg->min_value) arg->counter--; + arg->on_anticlockwise_callback_.call(); } arg->state = new_state; diff --git a/esphome/components/rotary_encoder/rotary_encoder.h b/esphome/components/rotary_encoder/rotary_encoder.h index f0e47dfe0a..e066188f22 100644 --- a/esphome/components/rotary_encoder/rotary_encoder.h +++ b/esphome/components/rotary_encoder/rotary_encoder.h @@ -27,6 +27,9 @@ struct RotaryEncoderSensorStore { int32_t last_read{0}; uint8_t state{0}; + CallbackManager on_clockwise_callback_; + CallbackManager on_anticlockwise_callback_; + static void gpio_intr(RotaryEncoderSensorStore *arg); }; @@ -62,6 +65,14 @@ class RotaryEncoderSensor : public sensor::Sensor, public Component { float get_setup_priority() const override; + void add_on_clockwise_callback(std::function callback) { + this->store_.on_clockwise_callback_.add(std::move(callback)); + } + + void add_on_anticlockwise_callback(std::function callback) { + this->store_.on_anticlockwise_callback_.add(std::move(callback)); + } + protected: GPIOPin *pin_a_; GPIOPin *pin_b_; @@ -81,5 +92,19 @@ template class RotaryEncoderSetValueAction : public Action { + public: + explicit RotaryEncoderClockwiseTrigger(RotaryEncoderSensor *parent) { + parent->add_on_clockwise_callback([this]() { this->trigger(); }); + } +}; + +class RotaryEncoderAnticlockwiseTrigger : public Trigger<> { + public: + explicit RotaryEncoderAnticlockwiseTrigger(RotaryEncoderSensor *parent) { + parent->add_on_anticlockwise_callback([this]() { this->trigger(); }); + } +}; + } // namespace rotary_encoder } // namespace esphome diff --git a/esphome/components/rotary_encoder/sensor.py b/esphome/components/rotary_encoder/sensor.py index 214ccbd056..c518982bc6 100644 --- a/esphome/components/rotary_encoder/sensor.py +++ b/esphome/components/rotary_encoder/sensor.py @@ -3,7 +3,7 @@ import esphome.config_validation as cv from esphome import pins, automation from esphome.components import sensor from esphome.const import CONF_ID, CONF_RESOLUTION, CONF_MIN_VALUE, CONF_MAX_VALUE, UNIT_STEPS, \ - ICON_ROTATE_RIGHT, CONF_VALUE, CONF_PIN_A, CONF_PIN_B + ICON_ROTATE_RIGHT, CONF_VALUE, CONF_PIN_A, CONF_PIN_B, CONF_TRIGGER_ID rotary_encoder_ns = cg.esphome_ns.namespace('rotary_encoder') RotaryEncoderResolution = rotary_encoder_ns.enum('RotaryEncoderResolution') @@ -14,11 +14,18 @@ RESOLUTIONS = { } CONF_PIN_RESET = 'pin_reset' +CONF_ON_CLOCKWISE = 'on_clockwise' +CONF_ON_ANTICLOCKWISE = 'on_anticlockwise' RotaryEncoderSensor = rotary_encoder_ns.class_('RotaryEncoderSensor', sensor.Sensor, cg.Component) RotaryEncoderSetValueAction = rotary_encoder_ns.class_('RotaryEncoderSetValueAction', automation.Action) +RotaryEncoderClockwiseTrigger = rotary_encoder_ns.class_('RotaryEncoderClockwiseTrigger', + automation.Trigger) +RotaryEncoderAnticlockwiseTrigger = rotary_encoder_ns.class_('RotaryEncoderAnticlockwiseTrigger', + automation.Trigger) + def validate_min_max_value(config): if CONF_MIN_VALUE in config and CONF_MAX_VALUE in config: @@ -40,6 +47,12 @@ CONFIG_SCHEMA = cv.All(sensor.sensor_schema(UNIT_STEPS, ICON_ROTATE_RIGHT, 0).ex cv.Optional(CONF_RESOLUTION, default=1): cv.enum(RESOLUTIONS, int=True), cv.Optional(CONF_MIN_VALUE): cv.int_, cv.Optional(CONF_MAX_VALUE): cv.int_, + cv.Optional(CONF_ON_CLOCKWISE): automation.validate_automation({ + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(RotaryEncoderClockwiseTrigger), + }), + cv.Optional(CONF_ON_ANTICLOCKWISE): automation.validate_automation({ + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(RotaryEncoderAnticlockwiseTrigger), + }), }).extend(cv.COMPONENT_SCHEMA), validate_min_max_value) @@ -61,6 +74,13 @@ def to_code(config): if CONF_MAX_VALUE in config: cg.add(var.set_max_value(config[CONF_MAX_VALUE])) + for conf in config.get(CONF_ON_CLOCKWISE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + yield automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_ANTICLOCKWISE, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + yield automation.build_automation(trigger, [], conf) + @automation.register_action('sensor.rotary_encoder.set_value', RotaryEncoderSetValueAction, cv.Schema({ diff --git a/tests/test1.yaml b/tests/test1.yaml index f5371eeab6..10e35594fe 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -586,6 +586,10 @@ sensor: - sensor.rotary_encoder.set_value: id: rotary_encoder1 value: !lambda 'return -1;' + on_clockwise: + - logger.log: "Clockwise" + on_anticlockwise: + - logger.log: "Anticlockwise" - platform: pulse_width name: Pulse Width pin: GPIO12