Motor on a roller blind - ESPHome version?

what config are you using?

A mashup from things that have been posted here with my own tweaks :slight_smile:

esphome:
  name: blinds
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_pw
  fast_connect: true
  manual_ip:
    static_ip: !secret blinds_ip
    subnet: !secret net1_subnet
    dns1: !secret net1_dns1
    dns2: !secret net1_dns2
    gateway: !secret net1_gw

# Enable logging
logger:
  
# Enable Home Assistant API
api:
  password: !secret HA_API
  services:
    - service: control_stepper
      variables:
        target: float
      then:
        - stepper.set_target:
            id: my_stepper
            target: !lambda "return target;"
        - cover.template.publish:
            id: blinds
            position: !lambda "return 1 - ((target) / id(stepper_steps));"

ota:
  password: !secret OTA_pw

globals:
  - id: stepper_steps
    type: int
    initial_value: '11600'
  - id: stepper_position
    type: float
    initial_value: '0'
  - id: stepper_state
    type: int
    initial_value: '0'

binary_sensor:
  - platform: gpio
    pin: D8
    name: "Button"
    filters:
    on_press:
      then:
        - lambda: |
            if (id(stepper_state) == 0) {
              //shade is stopped
              if (((id(stepper_position) < (id(stepper_steps) / 2)) || (id(stepper_position) == id(stepper_steps))) && (id(stepper_position) > 0)) {
                id(blinds).open();
              } else {
                id(blinds).close();
              }
            } else {
              //shade is moving
              id(blinds).stop();
            }

cover:
  - platform: template
    name: "Blinds"
    id: blinds
    open_action:
      - globals.set:
          id: stepper_state
          value: '1'
      - stepper.set_target:
          id: my_stepper
          target: 0
      - delay: !lambda "return (id(my_stepper).current_position / id(stepper_steps)) * 30000;"
      - globals.set:
          id: stepper_position
          value: !lambda "return id(my_stepper).target_position;"
      - globals.set:
          id: stepper_state
          value: '0'
    close_action:
      - globals.set:
          id: stepper_state
          value: '1'
      - stepper.set_target:
          id: my_stepper
          target: !lambda "return id(stepper_steps);"
      - delay: !lambda "return (1 - (id(my_stepper).current_position / id(stepper_steps))) * 30000;"
      - globals.set:
          id: stepper_position
          value: !lambda "return id(my_stepper).target_position;"
      - globals.set:
          id: stepper_state
          value: '0'
    stop_action:
      - stepper.set_target:
          id: my_stepper
          target: !lambda "return id(my_stepper).current_position;" 
      - globals.set:
          id: stepper_position
          value: !lambda "return id(my_stepper).current_position;"
      - globals.set:
          id: stepper_state
          value: '0'
      - cover.template.publish:
          id: blinds
          position: !lambda "return 1 - (id(stepper_position) / id(stepper_steps));"
    position_action:
      - stepper.set_target:
          id: my_stepper
          target: !lambda "return id(stepper_steps) * (1 - pos);"
    optimistic: true
    assumed_state: true
    has_position: true
    
stepper:
  - platform: a4988
    id: my_stepper
    dir_pin: D1
    step_pin: D2
    max_speed: 500 steps/s

    # Optional:
    sleep_pin: D3
    acceleration: inf
    deceleration: inf
3 Likes

cheers. im using this setup https://www.youtube.com/watch?v=ocOO-8X_-Rk&list=WL&index=9&t=0s. but wonder if it could be converted over to the one you are using. im using different drivers to what esphome supports. i tried pluggin it onto my setup but just got whines from the motors. maybe its the dip switches or power issue.

@FF-Fox
Great work! I am also using 12V 48BYJ-28 steppers with ULN2003 driver board using this project https://www.thingiverse.com/thing:2392856

Also having a bigger blind (2-2.5m) which is to heavy for the 12V 48BYJ-28.
Ordered the same NEMA 17HS4401 you are using and the DRV8825 driver board (https://nl.aliexpress.com/item/33010878323.html) but that driver isn’t supported by ESPHome.

Two questions:

  1. You are using A4988 with success? Not the DRV8825 because they are not supported by ESPHome, or did you (also) have other reasons using another?
  2. Based on your description I find it quite hard to understand how you mount the stepper and other stuff. Are you able to post some pictues and share your gearbox? Thanks!

Yeah, I used the a4988 driver board, as you can see in my ESPHome code:
platform: a4988

I tried it with the 12V 48BYJ-28 stepper in unipolar mode with ULN2003 driver board, too slow/underpowered even with a gearbox.
Then I modded the stepper tot bipolar and used the a4988 driver, still too slow/underpowered even with a gearbox.
The NEMA17 with a4988 driver did the job, but doesn’t have any holding torque when in sleep mode, so I added the spring-holding mechanism from another blind. But by doing so, the stepper was underpowered ^^
So final version is NEMA17 with the a4988 driver, a planetary gearbox and the spring-mechanism :slight_smile:

The mounting/gearbox looks like this:


So for mounting:
Screw the bracket with the oval holes to the ceiling.
Insert stepper motor.
Slide casing over it (just for looks, to hide the stepper).
Put on the gearbox, screw into stepper at the 4 corners of the stepper.

Hi all, this is my version with 230V motors: ESPHome 6 shutters controller

@FF-Fox Thanks!

Did you also think about the possibility to remember the current steps position when powercycling/restarting the ESP? Maybe by saving the step position in HA and send it to the ESP when it comes online again?

Yup, thought about it and implemented it at first! but after some use, decided I didn’t really need it :wink:

Since I’m using a global var for stepper position, you can just add restore_value: yes instead of initial_value: '0'. But, keep in mind that this is written in flash memory every time and has a limited number of writes. That’s why I left it out. I still have my manual pull cord if a power failure would happen to position it (and it’s been in use for about 6months now in all its itterations and haven’t had a power failure or had to powercycle the esp).

Hi fox. Seems you find the best compromise for all problems (torque/heavy when stopped).

Could you share the stl for the printed part please?

Sure, If I got time this weekend, I’ll generate the STL’s.

I would really recommend to design this yourself, there are too many variables. The chances are pretty slim this will be what you want if you just download and print it. This is designed for:

  • The tolerances of my printer
  • The location I wanted it (ceiling mounted, also an impact on the screw holes of the mounting bracket)
  • Material used (I reused the M4 screws, and since I wanted to use a cable tray it was moved a couple of millimeters so it would fit, …)
  • My roller blinds, there is a small difference on inner diameter of the tube where the blinds are mounted on. This won’t fit on the Ikea blinds I had lying around
  • Gear reduction I needed for the best speed-torque ratio
1 Like

Uploaded the STL’s here.
Disclaimer from previous post still applies, I would recommend designing this yourself for a good fit.

2 Likes

Amazing job! Thank you!
I’m using this thing at the moment, because my blinds are huge (120cm wide, 180cm drop), and I couldn’t find a ready to use planetary gear stuff. But now, here it is :slight_smile:

I just want so write that if you need more torque its really easy to use 2 uln boards and 2 motors on one blind just connect all cabels but switch order for one uln. I have also had success of two 48byj28 on one A4988 stepper driver.

Anyone managed to get acceleration to work with the ULN board? no matter what I write, it desn’t seem to do acceleration/deacceleration.

Finally got around to test this a bit more.

Acceleration and deceleration is non functioning :frowning:
Saving position is non-existant (stopping the cover at sat 50% and then opening it again will make it go further than 0) :frowning:

That’s 2 essential functions for me, which is missing.

Anyone have an idea on how to get these 2 thing working with ULN?

Position not saving would be caused by your code (or simply not implemented). So no way to answer that if you don’t post it…

Currently this is what I have:

substitutions:
  devicename: cover_livingroom_window
  upper_devicename: Stue Vindue
  fallback: LC
  platform: ESP8266
  board: nodemcuv2
  ip: 10.254.254.50
  gateway: 10.254.254.1
  subnet: 255.255.255.0

<<: !include .common.yaml

# in Home Assistant 
api:
  services:
    - service: control_stepper
      variables:
        target: int
      then:
        - stepper.set_target:
            id: my_stepper
            target: !lambda 'return target;'

web_server:
  port: 80
  
# physical connection
stepper:
  - platform: uln2003
    id: my_stepper
    pin_a: D1
    pin_b: D2
    pin_c: D3
    pin_d: D7
    max_speed: 650 steps/s
    acceleration: 100
    deceleration: 100
    sleep_when_done: true
    
# items for Home Assistant 
cover:
  - platform: template
    name: "$upper_devicename"
    id: $devicename

    open_action:
      - stepper.report_position:
          id: my_stepper
          position: !lambda return id(my_stepper).current_position;
      - stepper.set_target:
          id: my_stepper
          target: !lambda return 11000 - id(my_stepper).current_position;

    close_action:
      - stepper.report_position:
          id: my_stepper
          position: !lambda return id(my_stepper).current_position;
      - stepper.set_target:
          id: my_stepper
          target: !lambda return -11000 + id(my_stepper).current_position;

    stop_action:
      - stepper.set_target:
          id: my_stepper
          target: !lambda return id(my_stepper).current_position;      

    optimistic: true
    has_position: true

# for manual adjustment of the initial setting position
switch:
  - platform: template
    name: "Step minus"
    turn_on_action:
      - stepper.report_position:
          id: my_stepper
          position: 0
      - stepper.set_target:
          id: my_stepper
          target: 200
  - platform: template
    name: "Step plus"
    turn_on_action:
      - stepper.report_position:
          id: my_stepper
          position: 0
      - stepper.set_target:
          id: my_stepper
          target: -200

That’s a weird open and close action :stuck_out_tongue:
What’s your min and max value? So what stepper position would be completely open and what position would be completely closed?

Let’s say your current position is 0. If you open it, it would go to 11000; if you close it, it would go to -11000.
If your current position is 5000 and you open it, it would go to 6000; if you close it, it would go to -6000.

Wouldn’t it be better to work with fixed values in your open and close action (the min and max I asked about)? And report the position as 0 after moving it up or down a bit in the adjustment block. Cause now you’re reporting it as 0 and then moving it, but your stepper would stay at 200 or -200…

Well min (open) is 0
Closed is yet to be determined, as I have not had it running succesfull yet (missing the current position, so stopping at 5000 would make it go to -6000 or 16000, depending on the next action would be open or close, rather than 0 or 11000)

Then start walking before you try to run.

Figure out your max position. Start at 0 and find the close position (easiest way I found is just to put the blind in the open position, turn on the esp & use the control_stepper service from HA). Strip unneeded code for now and add it 1 block/functionality at a time and get that block working like you want before adding anything new.

Then and only then can you look at the code and say if it’s working or not… Cause with this code it’s 100% normal it’ll go “further than 0” as you said.