From 4e99433ae4355a50e3d0cc6fb16c12189c72f818 Mon Sep 17 00:00:00 2001 From: Christ van Willegen Date: Fri, 24 May 2024 08:15:49 +0200 Subject: [PATCH] Add rotation config parameter for stepper component. --- esphome/components/stepper/__init__.py | 38 ++++++++++++++++++++++++++ esphome/components/stepper/stepper.cpp | 2 +- esphome/components/stepper/stepper.h | 20 +++++++++++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/esphome/components/stepper/__init__.py b/esphome/components/stepper/__init__.py index f2367fd62a..f4f5a937cb 100644 --- a/esphome/components/stepper/__init__.py +++ b/esphome/components/stepper/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_POSITION, CONF_TARGET, CONF_SPEED, + CONF_ROTATION, ) from esphome.core import CORE, coroutine_with_priority @@ -22,6 +23,7 @@ ReportPositionAction = stepper_ns.class_("ReportPositionAction", automation.Acti SetSpeedAction = stepper_ns.class_("SetSpeedAction", automation.Action) SetAccelerationAction = stepper_ns.class_("SetAccelerationAction", automation.Action) SetDecelerationAction = stepper_ns.class_("SetDecelerationAction", automation.Action) +SetRotationAction = stepper_ns.class_("SetRotationAction", automation.Action) def validate_acceleration(value): @@ -66,11 +68,27 @@ def validate_speed(value): return value +def validate_rotation(value): + value = cv.string(value) + + if value == "both": + return 0 + + if value == "cw" or value == "clockwise": + return 1 + + if value == "ccw" or value == "counterclockwise" or value == "counter-clockwise": + return -1 + + raise cv.Invalid(f"Expected rotation as 'both', 'cw', 'ccw', 'clockwise', 'counterclockwise', 'counter-clockwise', got {value}") + + STEPPER_SCHEMA = cv.Schema( { cv.Required(CONF_MAX_SPEED): validate_speed, cv.Optional(CONF_ACCELERATION, default="inf"): validate_acceleration, cv.Optional(CONF_DECELERATION, default="inf"): validate_acceleration, + cv.Optional(CONF_ROTATION, default="both"): validate_rotation, } ) @@ -82,6 +100,8 @@ async def setup_stepper_core_(stepper_var, config): cg.add(stepper_var.set_deceleration(config[CONF_DECELERATION])) if CONF_MAX_SPEED in config: cg.add(stepper_var.set_max_speed(config[CONF_MAX_SPEED])) + if CONF_ROTATION in config: + cg.add(stepper_var.set_rotation(config[CONF_ROTATION])) async def register_stepper(var, config): @@ -180,6 +200,24 @@ async def stepper_set_deceleration_to_code(config, action_id, template_arg, args return var +@automation.register_action( + "stepper.set_rotation", + SetRotationAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(Stepper), + cv.Required(CONF_ROTATION): cv.templatable(validate_rotation), + } + ), +) +async def stepper_set_rotation_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + template_ = await cg.templatable(config[CONF_ROTATION], args, cg.string_) + cg.add(var.set_rotation(template_)) + return var + + @coroutine_with_priority(100.0) async def to_code(config): cg.add_global(stepper_ns.using) diff --git a/esphome/components/stepper/stepper.cpp b/esphome/components/stepper/stepper.cpp index 7926024204..2a1e7b5740 100644 --- a/esphome/components/stepper/stepper.cpp +++ b/esphome/components/stepper/stepper.cpp @@ -38,7 +38,7 @@ int32_t Stepper::should_step_() { // assumes this method is called in a constant interval uint32_t dt = now - this->last_step_; if (dt >= (1 / this->current_speed_) * 1e6f) { - int32_t mag = this->target_position > this->current_position ? 1 : -1; + int32_t mag = (rotation_ == 0 ? (this->target_position > this->current_position ? 1 : -1) : rotation_); this->last_step_ = now; this->current_position += mag; return mag; diff --git a/esphome/components/stepper/stepper.h b/esphome/components/stepper/stepper.h index 560362e4d0..3009286947 100644 --- a/esphome/components/stepper/stepper.h +++ b/esphome/components/stepper/stepper.h @@ -10,7 +10,8 @@ namespace stepper { #define LOG_STEPPER(this) \ ESP_LOGCONFIG(TAG, " Acceleration: %.0f steps/s^2", this->acceleration_); \ ESP_LOGCONFIG(TAG, " Deceleration: %.0f steps/s^2", this->deceleration_); \ - ESP_LOGCONFIG(TAG, " Max Speed: %.0f steps/s", this->max_speed_); + ESP_LOGCONFIG(TAG, " Max Speed: %.0f steps/s", this->max_speed_); \ + ESP_LOGCONFIG(TAG, " Rotation: %s", this->rotation_); class Stepper { public: @@ -19,6 +20,7 @@ class Stepper { void set_acceleration(float acceleration) { this->acceleration_ = acceleration; } void set_deceleration(float deceleration) { this->deceleration_ = deceleration; } void set_max_speed(float max_speed) { this->max_speed_ = max_speed; } + void set_rotation(int rotation) { this->rotation_ = rotation; } virtual void on_update_speed() {} bool has_reached_target() { return this->current_position == this->target_position; } @@ -33,6 +35,7 @@ class Stepper { float deceleration_{1e6f}; float current_speed_{0.0f}; float max_speed_{1e6f}; + int rotation_{0}; uint32_t last_calculation_{0}; uint32_t last_step_{0}; }; @@ -107,5 +110,20 @@ template class SetDecelerationAction : public Action { Stepper *parent_; }; +template class SetRotationAction : public Action { + public: + explicit SetRotationAction(Stepper *parent) : parent_(parent) {} + + TEMPLATABLE_VALUE(int, rotation); + + void play(Ts... x) override { + int rotation = this->rotation_.value(x...); + this->parent_->set_rotation(rotation); + } + + protected: + Stepper *parent_; +}; + } // namespace stepper } // namespace esphome