Add Stepper Motor Support (#206)

* Add stepper support

* Fix output set_level

* Lint
This commit is contained in:
Otto Winter 2018-10-26 22:57:03 +02:00 committed by GitHub
parent 21c22fe04a
commit af4e2bf61d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 202 additions and 3 deletions

View file

@ -5,7 +5,7 @@ import esphomeyaml.config_validation as cv
from esphomeyaml.components.power_supply import PowerSupplyComponent
from esphomeyaml.const import CONF_INVERTED, CONF_MAX_POWER, CONF_POWER_SUPPLY, CONF_ID, CONF_LEVEL
from esphomeyaml.helpers import add, esphomelib_ns, get_variable, TemplateArguments, Pvariable, \
templatable, bool_
templatable, float_
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
@ -85,7 +85,7 @@ def output_turn_off_to_code(config, action_id, arg_type):
CONF_OUTPUT_SET_LEVEL = 'output.set_level'
OUTPUT_SET_LEVEL_ACTION = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Required(CONF_LEVEL): cv.percentage,
vol.Required(CONF_LEVEL): cv.templatable(cv.percentage),
})
@ -97,7 +97,7 @@ def output_set_level_to_code(config, action_id, arg_type):
rhs = var.make_set_level_action(template_arg)
type = SetLevelAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_LEVEL], arg_type, bool_):
for template_ in templatable(config[CONF_LEVEL], arg_type, float_):
yield None
add(action.set_level(template_))
yield action

View file

@ -0,0 +1,126 @@
import voluptuous as vol
from esphomeyaml.automation import ACTION_REGISTRY
import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_ACCELERATION, CONF_DECELERATION, CONF_ID, CONF_MAX_SPEED, \
CONF_POSITION, CONF_TARGET
from esphomeyaml.helpers import Pvariable, TemplateArguments, add, add_job, esphomelib_ns, \
get_variable, int32, templatable
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
})
# pylint: disable=invalid-name
stepper_ns = esphomelib_ns.namespace('stepper')
Stepper = stepper_ns.Stepper
SetTargetAction = stepper_ns.SetTargetAction
ReportPositionAction = stepper_ns.ReportPositionAction
def validate_acceleration(value):
value = cv.string(value)
for suffix in ('steps/s^2', 'steps/s*s', 'steps/s/s', 'steps/ss', 'steps/(s*s)'):
if value.endswith(suffix):
value = value[:-len(suffix)]
if value == 'inf':
return 1e6
try:
value = float(value)
except ValueError:
raise vol.Invalid("Expected acceleration as floating point number, got {}".format(value))
if value <= 0:
raise vol.Invalid("Acceleration must be larger than 0 steps/s^2!")
return value
def validate_speed(value):
value = cv.string(value)
for suffix in ('steps/s', 'steps/s'):
if value.endswith(suffix):
value = value[:-len(suffix)]
if value == 'inf':
return 1e6
try:
value = float(value)
except ValueError:
raise vol.Invalid("Expected speed as floating point number, got {}".format(value))
if value <= 0:
raise vol.Invalid("Speed must be larger than 0 steps/s!")
return value
STEPPER_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(Stepper),
vol.Required(CONF_MAX_SPEED): validate_speed,
vol.Optional(CONF_ACCELERATION): validate_acceleration,
vol.Optional(CONF_DECELERATION): validate_acceleration,
})
STEPPER_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(STEPPER_SCHEMA.schema)
def setup_stepper_core_(stepper_var, config):
if CONF_ACCELERATION in config:
add(stepper_var.set_acceleration(config[CONF_ACCELERATION]))
if CONF_DECELERATION in config:
add(stepper_var.set_deceleration(config[CONF_DECELERATION]))
if CONF_MAX_SPEED in config:
add(stepper_var.set_max_speed(config[CONF_MAX_SPEED]))
def setup_stepper(stepper_var, config):
add_job(setup_stepper_core_, stepper_var, config)
BUILD_FLAGS = '-DUSE_STEPPER'
CONF_STEPPER_SET_TARGET = 'stepper.set_target'
STEPPER_SET_TARGET_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Required(CONF_TARGET): cv.templatable(cv.int_),
})
@ACTION_REGISTRY.register(CONF_STEPPER_SET_TARGET, STEPPER_SET_TARGET_ACTION_SCHEMA)
def stepper_set_target_to_code(config, action_id, arg_type):
template_arg = TemplateArguments(arg_type)
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_set_target_action(template_arg)
type = SetTargetAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_TARGET], arg_type, int32):
yield None
add(action.set_target(template_))
yield action
CONF_STEPPER_REPORT_POSITION = 'stepper.report_position'
STEPPER_REPORT_POSITION_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(None),
vol.Required(CONF_POSITION): cv.templatable(cv.int_),
})
@ACTION_REGISTRY.register(CONF_STEPPER_REPORT_POSITION, STEPPER_REPORT_POSITION_ACTION_SCHEMA)
def stepper_report_position_to_code(config, action_id, arg_type):
template_arg = TemplateArguments(arg_type)
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_report_position_action(template_arg)
type = ReportPositionAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_POSITION], arg_type, int32):
yield None
add(action.set_target(template_))
yield action

View file

@ -0,0 +1,35 @@
import voluptuous as vol
from esphomeyaml import pins
from esphomeyaml.components import stepper
import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_DIR_PIN, CONF_ID, CONF_SLEEP_PIN, CONF_STEP_PIN
from esphomeyaml.helpers import App, Pvariable, add, gpio_output_pin_expression
A4988 = stepper.stepper_ns.A4988
PLATFORM_SCHEMA = stepper.STEPPER_PLATFORM_SCHEMA.extend({
vol.Required(CONF_ID): cv.declare_variable_id(A4988),
vol.Required(CONF_STEP_PIN): pins.gpio_output_pin_schema,
vol.Required(CONF_DIR_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_SLEEP_PIN): pins.gpio_output_pin_schema,
})
def to_code(config):
for step_pin in gpio_output_pin_expression(config[CONF_STEP_PIN]):
yield
for dir_pin in gpio_output_pin_expression(config[CONF_DIR_PIN]):
yield
rhs = App.make_a4988(step_pin, dir_pin)
a4988 = Pvariable(config[CONF_ID], rhs)
if CONF_SLEEP_PIN in config:
for sleep_pin in gpio_output_pin_expression(config[CONF_SLEEP_PIN]):
yield
add(a4988.set_sleep_pin(sleep_pin))
stepper.setup_stepper(a4988, config)
BUILD_FLAGS = '-DUSE_A4988'

View file

@ -350,6 +350,14 @@ CONF_ARGS = 'args'
CONF_FORMAT = 'format'
CONF_COLOR_CORRECT = 'color_correct'
CONF_ON_JSON_MESSAGE = 'on_json_message'
CONF_ACCELERATION = 'acceleration'
CONF_DECELERATION = 'deceleration'
CONF_MAX_SPEED = 'max_speed'
CONF_TARGET = 'target'
CONF_POSITION = 'position'
CONF_STEP_PIN = 'step_pin'
CONF_DIR_PIN = 'dir_pin'
CONF_SLEEP_PIN = 'sleep_pin'
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'

View file

@ -565,6 +565,7 @@ std_string = std_ns.string
uint8 = global_ns.namespace('uint8_t')
uint16 = global_ns.namespace('uint16_t')
uint32 = global_ns.namespace('uint32_t')
int32 = global_ns.namespace('int32_t')
const_char_p = global_ns.namespace('const char *')
NAN = global_ns.namespace('NAN')
esphomelib_ns = global_ns # using namespace esphomelib;

View file

@ -797,6 +797,12 @@ switch:
optimistic: True
turn_on_action:
- switch.turn_on: living_room_lights_on
- output.set_level:
id: gpio_19
level: 50%
- output.set_level:
id: gpio_19
level: !lambda 'return 0.5;'
turn_off_action:
- switch.turn_on: living_room_lights_off
- platform: restart
@ -831,6 +837,19 @@ switch:
- platform: uart
name: "UART Bytes Output"
data: [0xDE, 0xAD, 0xBE, 0xEF]
- platform: template
optimistic: true
name: Stepper Switch
turn_on_action:
- stepper.set_target:
id: my_stepper
target: !lambda |-
static int32_t i = 0;
i += 1000;
if (i > 5000) {
i = -5000;
}
return i;
fan:
- platform: binary
@ -941,3 +960,13 @@ pcf8574:
- id: 'pcf8574_hub'
address: 0x21
pcf8575: False
stepper:
- platform: a4988
id: my_stepper
step_pin: GPIO23
dir_pin: GPIO24
sleep_pin: GPIO25
max_speed: 250 steps/s
acceleration: 100 steps/s^2
deceleration: 200 steps/s^2