But it ended up being to weak, so I got a nema 17 stepper but it is capped at 350mAH…
I would like to mount the nema directly to the window ceiling and put on a cap on the nema to be inserted directly into the tube. (I have cut the blind according to the link above…)
I see a lot of people are doing the gear box version, is that the only way to get this to work?
I am using DRV8825 drivers with NEMA 17HS4401 in ESPHome (although not officially supported.) The DRV8825 is almost plug and play with the A4988 - there is just a minor difference in connections:
EN(able) pin is an active low input - the DRV8825 is enabled by default. To disable, you can pull it high. I leave mine detached.
SL(ee)P pin is also an active low input - the DRV8825 is in sleep mode by default. I’m wiring this to ESPHome’s sleep_pin for the A4988
R(e)S(e)T is again an active low input - the DRV8825 will ignore signalling on the ST(e)P pin unless you pull it high. Now here’s the part I’m not sure about: this pin is also used to reset the driver to HOME, but seeing as there is no VDD on the DRV8825 as there is on the A4988, I’m attaching this to 3.3V from the ESP8266, so keeping it high. Anything from 2.5V to 5V should be okay.
So far, so good. When SLP is low, there doesn’t appear to be any power going to the motor. It appears to be fine to leave RST on 3.3V.
I haven’t played with the F(au)LT pin at all, which is in the place of the VDD on the A4988. Everything else is pretty much the same.
I wound up with a few NEMA 17HS4401’s and the DRV8825 gets pretty hot even after just 15-20 revolutions - heat sinks are a must! This may be because my power supply is not rated for the 1.7A 17HS4401’s though. I’m just starting out with steppers, so still learning.
The 1.7A NEMA 17HS4401 is pretty strong when it pulls, but freewheels without power. Probably good for a stiff blind that is sprung to remain in position once moved.
Anyone else experimented with ESPHome and the DRV8825? Basic config is:
@dhartsmith Thanks for your explanation
Got my NEMA 17 and A4988 also wokring with ESPHome. Will try it with the DRV8825 when it is arrived from China.
Also need to print some new gear/wheels with a better balance between torque and grip.
Great great topic. I am planing to do a DIY project based on the NEMA 17 + A4988, i.e. a 1-axis solar tracker based on magnetic compass measurements and the sun azithmut course among the day.
I just compiled some first example found here in this topic with a cover… but my motor don’t move at all.
Since this project is an outdoor one, I am powering the electronic with a 3S LiPo battery (up to 12.4V). A 5V stepdown regulator is used to power the ESP8266+ QMC5883 compass.
Anyone can confirm the exact pinout I have to follow ? From my current ESPHome model, the SLP pin is D2. No need to use the RST pin too ? or the ENABLE ?
Thanks in advance…
EDIT: I think my A4988 is smoked
To be more precise … Since nothing worked with the pin D2 connected to SLP. I tried then connect RST & SLP togather as depicted in many blogs. It worked from HA with the cover object. then;… I decided to connected also D2 to SLP with still SLP & RST connected… then no more mouvements :(… I tried everything. Recheck 100x time connexion :(. I am afraid the A4988 is gone. There is a way to test it wiithout oscilloscope ?
Hi all, I’ve been reading this thread for a while and I though I’d give the blinds a go. I originally used the Motor on a roller blind and have 4 blinds running on it, however, I do prefer ESPhome.
THIS IS NOT A DIRECT REPLACEMENT FOR THE SAME WIRING AS THE ‘Motor on a roller blind’, the next post is.
The following sketch is complete, other than the passwords. It has one button and can be set up in situ. Hold the button down to enter setup mode, press again to start moving to the bottom, press at the bottom and it starts moving up, press again at the top and the blind is calibrated.
Location and action are stored in memory and it will remember where it should be, even after power loss.
I’ve have done a little testing and so far, so good. It could probably do with an LED to display setup mode, but it’ll be fine.
I wrote this and didn’t think of the 4 blinds I already have that have NO button, but I’ll sort it out
This setup uses a Robotdyne ESP8266 Wifi D1 Mini and a 28BYJ-48 stepper motor + ULN2003 driver board.
# Press button for > 1 second to enter setup mode
# Press button again to start the blind closing
# Press button again when closed and blind starts to open (actually resets the stepper position to 0)
# Press button again when blind is fully open
# Job Done
# Button is also used to open/close the blind (must be fully open/closed first)
# NOTE: If you find that your shades are going the wrong way, you can change the pin
# settings below or reverse the + and – wires for each of the A and B motor
# pairs on your driver and the motor will spin in the opposite direction.
substitutions:
devicename: bathroomleft
upper_devicename: Bathroom Left Blind
mystepper: my_stepper
pina: D5
pinb: D1
pinc: D2
pind: D3
# Wrong direction? Comment the previous 4 lines and uncomment the following 4
# pina: D1
# pinb: D5
# pinc: D3
# pind: D2
esphome:
name: $devicename
platform: ESP8266
board: d1_mini
esp8266_restore_from_flash: True
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);
wifi:
networks:
- ssid: !secret wifi
password: !secret wifi_password
- ssid: !secret wifi2
password: !secret wifi_password2
ap:
ssid: $upper_devicename
password: !secret wifi_password
web_server:
port: 80
logger:
api:
password: !secret api_password
ota:
password: !secret ota_password
captive_portal:
stepper:
- platform: uln2003
id: $mystepper
pin_a: $pina
pin_b: $pinb
pin_c: $pinc
pin_d: $pind
max_speed: 300 steps/s # Speed of the motor
sleep_when_done: True
acceleration: inf
deceleration: inf
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 OPEN (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: settingup # Boolean for Setup Active
type: bool
restore_value: no
initial_value: '0'
binary_sensor:
- platform: gpio
pin:
number: D7
mode: INPUT_PULLUP
inverted: True
name: Button
internal: True
on_click:
- min_length: 50ms
max_length: 500ms
then: # Short press to OPEN/CLOSE blinds and also for setting up
- script.execute: moveit
- min_length: 1000ms
max_length: 3000ms
then: # Long press to Enter Setting Mode
- script.execute: setting
cover:
- platform: template
name: $upper_devicename
lambda: |-
if (id(openclosed)) {
return COVER_OPEN;
} else {
return COVER_CLOSED;
}
open_action:
- script.execute: openscript
close_action:
- script.execute: closescript
device_class: blind
script:
- id: moveit
then:
- if: # If settings variable is on
condition:
- lambda: 'return id(settingup);'
then: # Enter Setting Mode
- script.execute: setupbutton
else:
- if: # If blind is closed
condition:
- lambda: 'return id(openclosed) == 0;'
then: # Open blind
- script.execute: openscript
else: # Close blind
- script.execute: closescript
- id: openscript
then:
- logger.log: "Opening"
- stepper.set_target: # Send stepper to endstop
id: $mystepper
target: !lambda return id(endstop);
- 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'
- id: closescript
then:
- logger.log: "Closing"
- stepper.set_target: # Send stepper to 0
id: $mystepper
target: '0'
- wait_until: # Wait until 0 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'
- id: setting
then:
- logger.log: "Entered Settings Mode"
- globals.set:
id: settingup
value: '1'
- globals.set:
id: settingmode
value: '1'
- id: setupbutton
then:
- if:
condition:
- lambda: 'return (id(settingmode) == 3);'
then:
- logger.log: "Pressed Setup Button: Mode 3"
- 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: # Reset Setting Mode
id: settingup
value: '0'
- globals.set: # Set toggle to Open
id: openclosed
value: '1'
- logger.log: "Exiting Setting Mode"
- if:
condition:
- lambda: 'return (id(settingmode) == 2);'
then:
- logger.log: "Pressed Setup Button: Mode 2"
- 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 72000
id: $mystepper
target: '72000'
- 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"
- stepper.report_position: # Set Stepper position to 72000, makes it move to 0 (Closed)
id: $mystepper
position: '72000'
- globals.set: # Advance setup to next mode
id: settingmode
value: '2'
This IS a working replacement for the ‘Motor on a roller blind’ sketch. I have it set up on my kitchen blind that has been running the original ‘moarb’ sketch for a year or so.
I couldn’t find a way of sending it OTA, maybe someone else knows a way.
To upload via WIFI, go to this page and follow the instructions, took less than one minute to upload and configure!
# This sketch will add 2 switches named <upper_devicename> Setup Switch and Setup Button
# Use your mobile or tablet and connect to http://<devicename>.local to set up the blind
# Turn on the Setup Switch to enter Setup Mode and use the Setup Button as shown below to setup blinds.
# 1) Turn on the Setup Switch to enter setup mode
# 2) Press Setup button to start the blind closing
# 3) Press Setup button again when closed and blind starts to open (actually resets the stepper position to 0)
# 4) Press Setup button again when blind is fully open
# 5) Job Done
# This sketch also includes a momentary button on D7 which can be used in the following way
# 1) Press button for > 1 second to enter setup mode
# 2) Press button again to start the blind closing
# 3) Press button again when closed and blind starts to open (actually resets the stepper position to 0)
# 4) Press button again when blind is fully open
# 5) Job Done
# Button is also used to open/close the blind (must be fully open/closed first)
# NOTE: If you find that your shades are going the wrong way, you can change the pin
# settings below or reverse the + and – wires for each of the A and B motor
# pairs on your driver and the motor will spin in the opposite direction.
# The following pins are for the original 'Motor on a Roller Blind'
substitutions:
devicename: kitchen_blind
upper_devicename: Kitchen Blind
mystepper: my_stepper
pina: D1
pinb: D3
pinc: D2
pind: D4
# Wrong direction? Comment the previous 4 lines and uncomment the following 4
# pina: D3
# pinb: D1
# pinc: D4
# pind: D2
esphome:
name: $devicename
platform: ESP8266
board: d1_mini
esp8266_restore_from_flash: True
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);
wifi:
networks:
- ssid: !secret wifi
password: !secret wifi_password
ap:
ssid: $upper_devicename
password: !secret wifi_password
web_server:
port: 80
logger:
api:
password: !secret api_password
ota:
password: !secret ota_password
captive_portal:
stepper:
- platform: uln2003
id: $mystepper
pin_a: $pina
pin_b: $pinb
pin_c: $pinc
pin_d: $pind
max_speed: 600 steps/s # Speed of the motor
sleep_when_done: True
acceleration: inf
deceleration: inf
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: settingup # Boolean for Setup Active
type: bool
restore_value: no
initial_value: '0'
binary_sensor:
- platform: gpio
pin:
number: D7 # Connect Button to D7 and GND
mode: INPUT_PULLUP
inverted: True
name: Button
internal: True
on_click:
- min_length: 50ms
max_length: 500ms
then: # Short press to OPEN/CLOSE blinds and also for setting up
- script.execute: moveit
- min_length: 1000ms
max_length: 3000ms
then: # Long press to Enter Setting Mode
- script.execute: setting
switch:
- platform: template
name: ${upper_devicename} Setup Switch # Switch to enter Setup Mode
id: setupswitch
lambda: |-
if (id(settingup)) {
return true;
} else {
return false;
}
turn_on_action:
- script.execute: setting
turn_off_action:
- logger.log: "Exiting Settings Mode"
- globals.set:
id: settingup
value: '0'
- globals.set:
id: settingmode
value: '0'
- platform: template
name: ${upper_devicename} Setup Button # Switch to replicate the Physical Button
id: hasetup
turn_on_action:
- if: # If settings variable is on
condition:
- lambda: 'return id(settingup);'
then: # Enter Setting Mode
- script.execute: setupbutton
- switch.turn_off: hasetup
cover:
- platform: template
name: $upper_devicename
id: blinded
lambda: |-
if (id(openclosed)) {
return COVER_OPEN;
} else {
return COVER_CLOSED;
}
open_action:
- script.execute: openscript
close_action:
- script.execute: closescript
position_action:
# - script.execute: positional
then:
- stepper.set_target:
id: $mystepper
target: !lambda return id(endstop) * pos;
- wait_until: # Wait until 0 reached
lambda: 'return id($mystepper).current_position == (id(endstop) * pos);'
- globals.set: # Set global to current position
id: ${mystepper}_global
value: !lambda return id($mystepper).current_position;
has_position: true
device_class: blind
script:
- id: moveit
then:
- if: # If settings variable is on
condition:
- lambda: 'return id(settingup);'
then: # Enter Setting Mode
- script.execute: setupbutton
else:
- if: # If blind is closed
condition:
- lambda: 'return id(openclosed) == 0;'
then: # Open blind
- script.execute: openscript
else: # Close blind
- script.execute: closescript
- id: openscript
then:
- logger.log: "Opening"
- stepper.set_target: # Send stepper to endstop
id: $mystepper
target: !lambda return id(endstop);
- 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'
- logger.log:
format: "The position is being reported as %d, endstop is %d"
args: [ 'id($mystepper).current_position','id(endstop)' ]
- id: closescript
then:
- logger.log: "Closing"
- stepper.set_target: # Send stepper to 0
id: $mystepper
target: '0'
- wait_until: # Wait until 0 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'
- id: setting
then:
- logger.log: "Entered Settings Mode"
- globals.set:
id: settingup
value: '1'
- globals.set:
id: settingmode
value: '1'
- id: setupbutton
then:
- if:
condition:
- lambda: 'return (id(settingmode) == 3);'
then:
- logger.log: "Pressed Setup Button: Mode 3"
- 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: # Reset Setting Mode
id: settingup
value: '0'
- globals.set: # Set toggle to Open
id: openclosed
value: '1'
- logger.log: "Exiting Setting Mode"
- if:
condition:
- lambda: 'return (id(settingmode) == 2);'
then:
- logger.log: "Pressed Setup Button: Mode 2"
- 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 72000
id: $mystepper
target: '72000'
- 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"
- stepper.report_position: # Set Stepper position to 72000, makes it move to 0 (Closed)
id: $mystepper
position: '72000'
- globals.set: # Advance setup to next mode
id: settingmode
value: '2'
Hey @RoadkillUK
Awesome work! Thank you so much for sharing!
I tested this out and wanted to report a few things and ask a few questions
ESPHome is concerned about the ‘position_action’ of the cover and says is not supported. I had to comment the whole section out to get it validated.
During the setup stepper starts moving the blind up instead of down in the first place in both pin configurations (readme says the opposite). The only problem with this is that 0 is always set for a fully open position from what I understand and so HA reverts open and close buttons.
Is there no stop action? Unless ‘position_action’ is meant to achieve the same thing.
Is there a way to configure open and closed positions steps manually?
Previously it would only compile on the ESPHome 1.15 Dev version, however there has just been an updated version of ESPHome Beta which is what I usually use.
Oh, I’m surprised, I’ve tested it and changing the pins should work, can anyone else confirm this please? (silly question, but have you wired the motor the same way as in the original MOARB?)
Regarding the positioning, it’s not 100%. When you press the stop button, the slider doesn’t change to the correct position. When not fully open or closed, it will only allow either up or down, this is to do with the single button function as it needs to know which way to go.
If anyone wants to take a look and improve it then please do
I think I’ll have to rewrite some of this as it’s mainly ‘functional’
I’m using ESPhome 1.14, please disregard the rotation direction, I think it was late night and I messed up the connection after all experimenting. Thank you for everything else but I guess I’ll be moving on Need to configure 4 blinds (2 x 1 ESP). Will try to figure out your code for the parts I’m struggling with if you don’t mind
Hi all,
I come in this topic because I see a lot of specialist of Esphome related with stepper motor. My goal is to buiild a 1-axis solar tracker via i) a magnetic compass, here a BMM150 and ii) a stepper motor with the a4988. In my idea, the control of the stepper motor (direction & step) must be done on the difference between the heading given by the compass and the solar heading given the sun object with my local GPS coordinates. So in theory it’s simple if the difference is +D then set the target of the stepper with int(D/delta_angle), if the difference is -D then set with -int(D/delta_angle).
Here my current code
In practice it’s not working … oscillating between the 0 value or even worser can converge the a non-zero value I think the problem comes from the fact that during the rotation of the motor, the template sensor associated with difference of heading is also changing and then a new set_target is set.
When I would like to write and I don’t know yet how is to
i) compute the difference of heading and be sure its value is stablized then if the motor is in IDLE
ii) send the command to rotate correspondly to this difference AND do not update the difference sensor and/or wait the rotation reaches the target_position in order to send a new rotation command.
I’m trying to build my own roller but I find the 28BYJ-48 stepper motor (in 12v) has not enough torque to move my blind (36’’ or 91 cm wide). What kind of motor do you use?
I initially used 12v 0.25A power supply and it worked. So you have plenty of power out there. I use uln2003 so it’s fine. If your motor works without the blind as expected then I guess blind is too heavy.