Hello, in the smart curtain system I have been using for a long time, I can only raise and lower the curtain. But when the power is cut off, I want the motor to remember where it left off and continue. Plus I want to be able to raise and lower the curtain to the desired %. Can you help me with this?
My tools in the curtain system.
Nema 17 stepper motor
A4988 motor driver board
Esp32-wroom-32 programming board
LM2596 Regulator
3 buttons
DC 12v adapter
Self-prepared coding
substitutions:
devicename: yatakodasiperde
mystepper: my_stepper
speed: 1200 steps/s
esphome:
name: $devicename
platform: ESP32
board: nodemcu-32s
libraries:
- EEPROM
# Enable logging
logger:
level: DEBUG
logs:
esphome.core: DEBUG
esphome.components: DEBUG
# Enable Home Assistant API
api:
services:
- service: control_stepper
variables:
target: int
then:
- stepper.set_target:
id: my_stepper
target: !lambda 'return target;'
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
manual_ip:
static_ip: 192.168.1.69
gateway: 192.168.1.1
subnet: 255.255.255.0
dns1: 192.168.1.1
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Akilli Perde"
password: "password"
captive_portal:
web_server:
port: 80
stepper:
- platform: a4988
id: $mystepper
step_pin: GPIO19
dir_pin:
number: GPIO18
inverted: true
max_speed: ${speed}
acceleration: inf
deceleration: inf
sensor:
- platform: wifi_signal
name: "WiFi Sinyali yatakodasiperde"
update_interval: 60s
text_sensor:
- platform: wifi_info
ip_address:
icon: "mdi:ip"
name: "IP yatakodasiperde"
ssid:
name: "SSID yatakodasiperde"
icon: "mdi:access-point-network"
bssid:
name: "BSSID yatakodasiperde"
icon: "mdi:access-point-network"
output:
- platform: gpio
pin: GPIO21
inverted: true
id: enable_pin
binary_sensor:
- platform: gpio
id: perde_kaldirma_button
name: Perdeyi kaldir
pin:
number: GPIO12
mode: INPUT_PULLUP
inverted: true
on_press:
then:
- output.turn_on: enable_pin
- if:
condition:
lambda: 'return id($mystepper).current_position != 35000;'
then:
- stepper.set_target:
id: $mystepper
target: 35000
- delay: 1ms
- while:
condition:
lambda: 'return id($mystepper).current_position != 35000;'
then:
- delay: 1ms
- delay: 1ms
- output.turn_off: enable_pin
- platform: gpio
id: perde_indirme_button
name: Perdeyi indir
pin:
number: GPIO13
mode: INPUT_PULLUP
inverted: true
on_press:
then:
- output.turn_on: enable_pin
- if:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- stepper.set_target:
id: $mystepper
target: 0
- delay: 1ms
- while:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- delay: 1ms
- delay: 1ms
- output.turn_off: enable_pin
- cover.template.publish:
id: blinded
position: !lambda 'return id($mystepper).current_position;'
- platform: gpio
id: perde_durdurma_button
name: Perdeyi durdur
pin:
number: GPIO14
mode: INPUT_PULLUP
inverted: true
on_press:
then:
- output.turn_off: enable_pin
- stepper.set_target:
id: $mystepper
target: !lambda 'return id($mystepper).current_position;'
cover:
- platform: template
name: Yatakodasi-Perde
id: blinded
open_action:
- output.turn_on: enable_pin
- if:
condition:
lambda: 'return id($mystepper).current_position != 35000;'
then:
- stepper.set_target:
id: $mystepper
target: 35000
- delay: 1ms
- while:
condition:
lambda: 'return id($mystepper).current_position != 35000;'
then:
- delay: 1ms
- delay: 1ms
- output.turn_off: enable_pin
close_action:
- output.turn_on: enable_pin
- if:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- stepper.set_target:
id: $mystepper
target: 0
- delay: 1ms
- while:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- delay: 1ms
- delay: 1ms
- output.turn_off: enable_pin
stop_action:
- output.turn_off: enable_pin
- stepper.set_target:
id: $mystepper
target: !lambda 'return id($mystepper).current_position;'
- cover.template.publish:
id: blinded
position: !lambda 'return id($mystepper).current_position;'
The curtain card coding I’m trying to use.
[GitHub - tungmeister/hass-blind-card: Blind card for Home Assistant Lovelace UI]
type: 'custom:blind-card'
title: My blinds
entities:
- entity: cover.yatakodasiperde
name: Left blind
buttons_position: left
title_position: bottom
blind_color: '#FFD580'
Take a look at my repo
This setup uses a Robotdyne ESP8266 Wifi D1 Mini and a 28BYJ-48 stepper motor + ULN2003 driver board.
It looks like you’ll be able to change the stepper motor and board, I’m a bit tired atm, otherwise I’ll check in tomorrow.
It should work with that card too.
1 Like
Thank you @RoadkillUK , the purpose of using nema17 motor is because my curtain is big and heavy. As a driver, I chose these components because I cannot find many types in my country.
Thank you very much for your interest. I am waiting for your return after you rest.
I meant for you to change the code, it’s pretty easy, just copy it from your code.
Hello @RoadkillUK , I have adapted your coding and the system is loading successfully. But I’m trying to raise or lower the curtain, it doesn’t work. I think I’m missing something.
Yeah, you could post your code give us a clue.
I’ll take a look. put ``` before and after the code so it formats correctly.
The way I adapted the code.
substitutions:
devicename: yatakodasiperde
mystepper: my_stepper
speed: 1200 steps/s
reportin: "0"
esphome:
name: $devicename
platform: ESP32
board: nodemcu-32s
on_boot:
- priority: -200.0
then:
- stepper.report_position: # Set stepper to global variable
id: $mystepper
position: !lambda return id(${mystepper}_global);
- stepper.set_target: # Set stepper to global variable
id: $mystepper
target: !lambda return id(${mystepper}_global);
- if: # If blind is Closed
condition:
- lambda: 'return id(${mystepper}_global) == 0;'
then: # Publish state etc.
- cover.template.publish:
id: blinded
state: CLOSED
current_operation: IDLE
- if: # If blind is Open
condition:
- lambda: 'return id(${mystepper}_global) == id(endstop);'
then: # Publish state etc.
- cover.template.publish:
id: blinded
state: OPEN
current_operation: IDLE
- if: # If blind is Neither
condition:
- lambda: 'return (id(${mystepper}_global) != 0) && (id(${mystepper}_global) != id(endstop));'
then: # # Publish state etc.
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: IDLE
wifi:
ssid: !secret wifi_ssid_2mi
password: !secret wifi_password
fast_connect: true
manual_ip:
static_ip: 192.168.1.69
gateway: 192.168.1.1
subnet: 255.255.255.0
dns1: 192.168.1.1
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Akilli Perde"
password: !secret wifi_password
web_server:
port: 80
# Enable logging
logger:
# level: DEBUG
# logs:
# esphome.core: DEBUG
# esphome.components: DEBUG# Enable Home Assistant API
api:
ota:
captive_portal:
stepper:
- platform: a4988
id: $mystepper
step_pin: GPIO19
dir_pin:
number: GPIO18
inverted: true
max_speed: ${speed}
acceleration: inf
deceleration: inf
output:
- platform: gpio
pin: GPIO21
inverted: true
id: enable_pin
globals:
- id: ${mystepper}_global # Integer for storing the stepper position in case of reboot
type: int
restore_value: True
initial_value: '0'
- id: openclosed # Boolean to store OPEN/CLOSED state
type: bool
restore_value: True
initial_value: '0'
- id: endstop # Variable for storing ENDSTOP (how far to move stepper)
type: int
restore_value: True
initial_value: '1000'
- id: settingmode # Integer for Setup Mode
type: int
restore_value: no
initial_value: '0'
- id: reportin # Boolean for reporting the position of blind when moving (See testblind.yaml)
type: bool
restore_value: no
initial_value: '${reportin}'
text_sensor:
- platform: version
name: ${devicename} ESPHome Version
hide_timestamp: true
- platform: wifi_info
ip_address:
name: "IP ${devicename}"
icon: "mdi:ip"
ssid:
name: "SSID ${devicename}"
icon: "mdi:access-point-network"
bssid:
name: "BSSID ${devicename}"
icon: "mdi:access-point-network"
mac_address:
name: "MAC ${devicename}"
icon: "mdi:identifier"
- platform: template
name: ${devicename} Friendly Name
icon: 'mdi:information-outline'
lambda: |-
return {"$devicename"};
binary_sensor:
- platform: gpio
id: perde_kaldirma_button
name: Perdeyi kaldir
pin:
number: GPIO12
mode: INPUT_PULLUP
inverted: true
on_press:
then:
- output.turn_on: enable_pin
- if:
condition:
lambda: 'return id($mystepper).current_position != 35000;'
then:
- stepper.set_target:
id: $mystepper
target: 35000
- delay: 1ms
- while:
condition:
lambda: 'return id($mystepper).current_position != 35000;'
then:
- delay: 1ms
- delay: 1ms
- output.turn_off: enable_pin
- platform: gpio
id: perde_indirme_button
name: Perdeyi indir
pin:
number: GPIO13
mode: INPUT_PULLUP
inverted: true
on_press:
then:
- output.turn_on: enable_pin
- if:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- stepper.set_target:
id: $mystepper
target: 0
- delay: 1ms
- while:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- delay: 1ms
- delay: 1ms
- output.turn_off: enable_pin
- cover.template.publish:
id: blinded
position: !lambda 'return id($mystepper).current_position;'
- platform: gpio
id: perde_durdurma_button
name: Perdeyi durdur
pin:
number: GPIO14
mode: INPUT_PULLUP
inverted: true
on_press:
then:
- output.turn_off: enable_pin
- stepper.set_target:
id: $mystepper
target: !lambda 'return id($mystepper).current_position;'
sensor:
- platform: wifi_signal
name: "WiFi Sinyali ${devicename}"
update_interval: 60s
switch:
- platform: template
name: ${devicename} Setup Switch # Switch to enter Setup Mode
id: setupswitch
lambda: |-
if (id(settingmode) != 0) {
return true;
} else {
return false;
}
turn_on_action:
then:
- logger.log: "Entered Settings Mode"
- globals.set:
id: settingmode
value: '1'
turn_off_action:
then:
- logger.log: "Exiting Settings Mode"
- globals.set:
id: settingmode
value: '0'
button:
- platform: template
name: ${devicename} Setup Button # Software Button to replicate the Physical Button
id: hasetup
on_press:
- if: # If settings variable is on
condition:
- lambda: 'return id(settingmode) != 0;'
then: # Enter Setting Mode
- script.execute: setupbutton
cover:
- platform: template
name: $devicename
id: blinded
open_action:
then:
- logger.log: "Opening"
- logger.log:
format: "Endstop is: %d"
args: [ 'id(endstop)' ]
- stepper.set_target: # Send stepper to endstop
id: $mystepper
target: !lambda return id(endstop);
- if:
condition:
lambda: 'return id(reportin) == 1;' # If Reporting is Selected
then:
- while:
condition:
lambda: 'return id($mystepper).current_position != id(endstop);'
then:
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: OPENING
- delay: 1000 ms
else:
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: OPENING
- wait_until: # Wait until endstop reached
lambda: 'return (id($mystepper).current_position == id(endstop));'
- globals.set: # Set global to current position
id: ${mystepper}_global
value: !lambda return id($mystepper).current_position;
- globals.set: # Set toggle to OPEN (No need for 'optimistic mode')
id: openclosed
value: '1'
- cover.template.publish:
id: blinded
state: OPEN
current_operation: IDLE
close_action:
then:
- logger.log: "Closing"
- stepper.set_target: # Send stepper to 0
id: $mystepper
target: '0'
- if:
condition:
lambda: 'return id(reportin) == 1;'
then:
- while:
condition:
lambda: 'return id($mystepper).current_position != 0;'
then:
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: CLOSING
- delay: 1000 ms
else:
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: CLOSING
- wait_until: # Wait until endstop reached
lambda: 'return id($mystepper).current_position == 0;'
- globals.set: # Set global to current position
id: ${mystepper}_global
value: !lambda return id($mystepper).current_position;
- globals.set: # Set toggle to CLOSED (No need for 'optimistic mode')
id: openclosed
value: '0'
- cover.template.publish:
id: blinded
state: CLOSED
current_operation: IDLE
position_action:
then:
- stepper.set_target:
id: $mystepper
target: !lambda return int(id(endstop) * pos);
- if:
condition:
lambda: 'return id(reportin) == 1;'
then:
- while:
condition:
lambda: 'return id($mystepper).current_position != int(id(endstop) * pos);'
then:
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
- delay: 1000 ms
else:
- wait_until: # Wait until endstop reached
lambda: 'return id($mystepper).current_position == (int(id(endstop) * pos));'
- globals.set: # Set global to current position
id: ${mystepper}_global
value: !lambda return id($mystepper).current_position;
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: IDLE
stop_action:
then:
- stepper.set_target:
id: $mystepper
target: !lambda return id($mystepper).current_position;
- globals.set: # Set global to current position
id: ${mystepper}_global
value: !lambda return id($mystepper).current_position;
- cover.template.publish:
id: blinded
position: !lambda 'return (float(float(id($mystepper).current_position) / float(id(endstop))));'
current_operation: IDLE
has_position: true
device_class: blind
script:
- id: setupbutton
then:
- if:
condition:
- lambda: 'return (id(settingmode) == 3);'
then:
- logger.log: "Pressed Setup Button: Mode 3"
- logger.log: "Blind is now set up"
- logger.log:
format: "Endstop is: %d"
args: [ 'id(endstop)' ]
- stepper.set_target: # Set Stepper position
id: $mystepper
target: !lambda return id($mystepper).current_position;
- globals.set: # Set Endstop Variable
id: endstop
value: !lambda return id($mystepper).current_position;
- globals.set: # Set Global stepper position
id: ${mystepper}_global
value: !lambda return id($mystepper).current_position;
- globals.set: # Reset Setting Mode
id: settingmode
value: '0'
- globals.set: # Set toggle to Open
id: openclosed
value: '1'
- cover.template.publish:
id: blinded
state: OPEN
current_operation: IDLE
- logger.log: "Exiting Setting Mode"
- if:
condition:
- lambda: 'return (id(settingmode) == 2);'
then:
- logger.log: "Pressed Setup Button: Mode 2"
- logger.log: "Blind is Opening, Press button when fully open"
- stepper.report_position: # Reset Stepper position to 0
id: $mystepper
position: '0'
- stepper.set_target: # Reset Stepper position to 0
id: $mystepper
target: '0'
- globals.set: # Move stepper to 0 (doesn't move it's already there!)
id: ${mystepper}_global
value: '0'
- stepper.set_target: # Reset Stepper position to 35000
id: $mystepper
target: '35000'
- globals.set: # Advance setup to next mode
id: settingmode
value: '3'
- if:
condition:
- lambda: 'return (id(settingmode) == 1);'
then:
- logger.log: "Pressed Setup Button: Mode 1"
- logger.log: "Blind is Closing, Press button when fully closed"
- stepper.report_position: # Set Stepper position to 35000, makes it move to 0 (Closed)
id: $mystepper
position: '35000'
- globals.set: # Advance setup to next mode
id: settingmode
value: '2'
It would seem you have added your own version of a sleep/enable pin. Looking at this, there is a enable pin option already.
If you change your stepper config to this below and ensure you need the pins inverted. Then delete all your additional enable/disable stuff. It might work
There may be more issues, I don’t think so, but one step at a time.
Good Luck.
stepper:
- platform: a4988
id: $mystepper
step_pin: GPIO19
dir_pin:
number: GPIO18
inverted: true
max_speed: ${speed}
acceleration: inf
deceleration: inf
sleep_pin: GPIO21
Thank you for your help. But I pasted the stepper code you gave. I could not understand the additional enable/disable items in the coding. So I deleted the following codes. The system did not work again. Are these the codes to be deleted?
- output.turn_on: enable_pin
- output.turn_off: enable_pin