I am using one button to both start and stop a motor. If pressed when the motor is stopped, then I need it to start. But if pressed when the motor is started, then I need it to stop.
This motor controls a cover, so I’m using the Template Cover component as well.
To figure out if the motor is stopped or not, I’m using this lambda in an if statement in a binary_sensor:
lambda: 'return (id(ropener_cover).current_operation != COVER_OPERATION_IDLE);'
This should allow me to know if the motor is not idle. And if not idle, then stop. However, it does not work, it never evaluates to true and skips this step and I have no idea what I’m doing wrong. The reference I"m going off of for this is here and here.
The full YAML is below. The line above is in the binary_sensor section, about half way down. Thank you!!!
external_components:
- source: github://slimcdk/esphome-custom-components
components: [tmc2209_hub, tmc2209, stepper]
substitutions:
steps_per_revolution: "1600"
max_distance_revs: "float(231.9207)"
max_distance_steps: "${max_distance_revs}*${steps_per_revolution}"
api:
ota:
- platform: esphome
logger:
level: VERBOSE
esp32:
board: esp32-c6-devkitc-1
framework:
type: esp-idf
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
esphome:
name: glasscalibur
on_boot:
then:
- tmc2209.configure:
direction: cw
microsteps: 8
interpolation: true
- tmc2209.stallguard:
threshold: 50
- tmc2209.currents:
standstill_mode: freewheeling
irun: 26
ihold: 0
tpowerdown: 0
iholddelay: 0
- if:
condition:
binary_sensor.is_off: limit_switch_1 # Check if switch is pressed
then:
- stepper.report_position:
id: driver
position: !lambda return ${max_distance_steps};
- if:
condition:
binary_sensor.is_off: limit_switch_2 # Check if switch is pressed
then:
- stepper.report_position:
id: driver
position: 0
uart:
tx_pin: 1
rx_pin: 0
baud_rate: 500000
stepper:
- platform: tmc2209
id: driver
max_speed: 1500 steps/s
acceleration: 1000 steps/s^2
deceleration: 100000 steps/s^2
config_dump_include_registers: true
rsense: 220 mOhm
vsense: False
enn_pin: 8
index_pin: 6
diag_pin: 14
on_stall:
- stepper.stop: driver
# id(ropener_cover)->current_operation
# COVER_OPERATION_IDLE, COVER_OPERATION_OPENING, COVER_OPERATION_CLOSING
binary_sensor:
- platform: gpio
name: Button 1
id: btn1
pin:
number: 23
mode: INPUT
inverted: true
filters:
- delayed_on: 10ms
on_multi_click:
# --- Single Click ---
- timing:
- ON for at most 1.0s
- OFF for at least 0.5s
then:
- if:
condition: ## If moving, then stop
lambda: 'return (id(ropener_cover).current_operation != COVER_OPERATION_IDLE);' # Should evaluate to TRUE if moving
then:
- cover.stop: ropener_cover
else: ## If not moving, then close
- cover.close: ropener_cover
# --- Double Click ---
- timing:
- ON for at most 1.0s
- OFF for at most 0.3s
- ON for at most 1.0s
- OFF for at least 0.5s
then:
- cover.open: ropener_cover
- platform: gpio
name: Open Limit Switch
id: limit_switch_1
pin:
number: 15
mode: INPUT
inverted: true
on_press:
then:
- stepper.report_position:
id: driver
position: 0
- cover.stop: ropener_cover
- platform: gpio
name: Close Limit Switch
id: limit_switch_2
pin:
number: 3
mode: INPUT
inverted: true
on_press:
then:
- stepper.report_position:
id: driver
position: !lambda return ${max_distance_steps};
- cover.stop: ropener_cover
cover:
- platform: template
id: ropener_cover
name: Ropener
has_position: true
assumed_state: false
lambda: "return 1.0 - (id(driver)->current_position / ${max_distance_steps});"
stop_action:
- stepper.stop: driver
open_action:
- stepper.set_target:
id: driver
target: 0
close_action:
- stepper.set_target:
id: driver
target: !lambda return ${max_distance_steps};
position_action:
- stepper.set_target:
id: driver
target: !lambda return (1.0 - pos) * ${max_distance_steps};```
Doesn’t look like the template cover ever sets the operation mode. You would need to do that yourself in the actions.
The problem is related to the cover position. When I was dividing two integers I would get a 0, and not a float like is required. So I just cast the position as a float and that’s fixed the tracking issue.
It’s still not working, even though I thought I had it. I’m even trying to set the operation manually in the cover and still no luck. It stays stuck in IDLE
Here are the logs while it’s moving:
14:05:26.494][D][main:246]: COVER open_action
[14:05:26.494][D][cover:147]: 'Glasscalibur' >>
[14:05:26.503][D][cover:150]: Position: 0%
[14:05:26.503][D][cover:163]: Current Operation: IDLE
[14:05:26.518][D][cover:147]: 'Glasscalibur' >>
[14:05:26.527][D][cover:150]: Position: 0%
[14:05:26.528][D][cover:163]: Current Operation: IDLE
Here’s the updated config:
external_components:
- source: github://slimcdk/esphome-custom-components
components: [tmc2209_hub, tmc2209, stepper]
substitutions:
steps_per_revolution: "1600"
max_distance_revs: "float(231.9207)"
max_distance_steps: 371073 # converts cm to steps. Use this in remaining code
api:
encryption:
key: !secret api_key
ota:
- platform: esphome
logger:
level: VERBOSE
hardware_uart: UART0
esp32:
variant: esp32c6
framework:
type: esp-idf
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
on_connect:
then:
- logger.log: "Connected to WiFi! Running post-connect actions."
- if: # NEED TO CHECK IF EITHER LIMIT SWITCH IS PRESSED AND SET POSITION BASED ON THAT
condition:
binary_sensor.is_on: limit_switch_1 # Check if switch is pressed
then:
- logger.log: "SETTING LIMIT 1"
- stepper.report_position:
id: driver
position: ${max_distance_steps}
- stepper.set_target:
id: driver
target: ${max_distance_steps}
- if:
condition:
binary_sensor.is_on: limit_switch_2 # Check if switch is pressed
then:
- logger.log: "SETTING LIMIT 2"
- stepper.report_position:
id: driver
position: 0
- stepper.set_target:
id: driver
target: 0
esphome:
name: "glasscalibur-kids-bedroom"
on_boot:
# - priority: -100
# then:
- logger.log: "CHECKING LIMIT SWITCHES"
- if: # NEED TO CHECK IF EITHER LIMIT SWITCH IS PRESSED AND SET POSITION BASED ON THAT
condition:
binary_sensor.is_on: limit_switch_1 # Check if switch is pressed
then:
- logger.log: "SETTING LIMIT 1"
- stepper.report_position:
id: driver
position: ${max_distance_steps}
- stepper.set_target:
id: driver
target: ${max_distance_steps}
- if:
condition:
binary_sensor.is_on: limit_switch_2 # Check if switch is pressed
then:
- logger.log: "SETTING LIMIT 2"
- stepper.report_position:
id: driver
position: 0
- stepper.set_target:
id: driver
target: 0
- tmc2209.configure:
direction: ccw
microsteps: 8
interpolation: true
- tmc2209.stallguard:
threshold: 50
- tmc2209.currents:
standstill_mode: freewheeling
irun: 25 # 26 = 0.6A current. DO NOT EXCEED. MOTOR GETS STUPID HOT.
ihold: 0
tpowerdown: 0
iholddelay: 0
output:
- platform: ledc
pin: GPIO5
id: buzzer
uart:
tx_pin: 1
rx_pin: 0
baud_rate: 500000
stepper:
- platform: tmc2209
id: driver
#max_speed: 1500 steps/s # Faster speed is louder #2000 good. #1500 great
max_speed: 1501 steps/s # Faster speed is louder #2000 good. #1500 great
acceleration: 1000 steps/s^2
deceleration: 100000 steps/s^2 # Stop very fast in case limit swith reached
config_dump_include_registers: true
rsense: 220 mOhm
vsense: False
enn_pin: 8
index_pin: 6
diag_pin: 14
#on_stall:
#- stepper.stop: driver
binary_sensor:
- platform: gpio
name: Button 1
id: btn1
pin:
number: 23
mode: INPUT
inverted: true
filters:
- delayed_on: 10ms
on_multi_click:
# --- Single Click ---
- timing:
- ON for at most 1.0s
- OFF for at least 0.5s
then:
- cover.close: glasscalibur_cover
- if:
condition: ## If moving, then stop
lambda: return (id(glasscalibur_cover).current_operation != COVER_OPERATION_IDLE); # Should evaluate to TRUE if moving
then:
- cover.stop: glasscalibur_cover
else: ## If not moving, then close
- cover.close: glasscalibur_cover
# --- Double Click ---
- timing:
- ON for at most 1.0s
- OFF for at most 0.3s
- ON for at most 1.0s
- OFF for at least 0.5s
then:
- cover.open: glasscalibur_cover
- platform: gpio
name: Open Limit Switch
id: limit_switch_1
pin:
number: 15
mode: INPUT
inverted: true
interrupt_type: FALLING
filters:
- delayed_on: 10ms
on_press:
then:
- logger.log: "LIMIT 1 PRESSED"
- cover.stop: glasscalibur_cover
- stepper.report_position:
id: driver
position: ${max_distance_steps}
- stepper.set_target:
id: driver
target: ${max_distance_steps}
- cover.template.publish:
id: glasscalibur_cover
position: 1.0
- platform: gpio
name: Close Limit Switch
id: limit_switch_2
pin:
number: 3
mode: INPUT
inverted: true
interrupt_type: FALLING
# Optional: filters to prevent noise from triggering the sensor
filters:
- delayed_on: 10ms
on_press:
then:
- cover.stop: glasscalibur_cover
- logger.log: "LIMIT 2 PRESSED"
- stepper.report_position:
id: driver
position: 0
- stepper.set_target:
id: driver
target: 0
- cover.template.publish:
id: glasscalibur_cover
position: 0
cover:
- platform: template
id: glasscalibur_cover
name: Glasscalibur
has_position: true
lambda: "return (float(id(driver)->current_position) / float(${max_distance_steps}));"
stop_action:
- logger.log: "COVER stop_action"
- stepper.stop: driver
open_action:
- logger.log: "COVER open_action"
- cover.template.publish:
id: glasscalibur_cover
current_operation : OPENING
- stepper.set_target:
id: driver
target: ${max_distance_steps}
close_action:
- logger.log: "COVER close_action"
- stepper.set_target:
id: driver
target: 0
position_action:
- logger.log: "COVER position_action"
- stepper.set_target:
id: driver
target: !lambda return pos * ${max_distance_steps};
on_opening:
- logger.log: "COVER Opening"
- cover.template.publish:
id: glasscalibur_cover
current_operation : OPENING
on_opened:
- logger.log: "COVER Open"
- cover.template.publish:
id: glasscalibur_cover
current_operation : IDLE
on_closing:
- logger.log: "COVER Closing"
- cover.template.publish:
id: glasscalibur_cover
current_operation : CLOSING
on_closed:
- logger.log: "COVER Closed"
- cover.template.publish:
id: glasscalibur_cover
current_operation : IDLE