Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. My Project
  3. Curtain Control Node.

Curtain Control Node.

Scheduled Pinned Locked Moved My Project
domoticzcurtain controlmysensors node
51 Posts 15 Posters 19.9k Views 22 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • AWIA AWI

    @TheoL Ikea :smile:

    TheoLT Offline
    TheoLT Offline
    TheoL
    Contest Winner
    wrote on last edited by
    #29

    @AWI Really interested in the mechanics ;-)

    1 Reply Last reply
    0
    • franzelareF Offline
      franzelareF Offline
      franzelare
      wrote on last edited by
      #30

      I'm currently working on a similar project, only I got started with 24V DC motors that I got from my work (left overs from a test project) These motors are very strong (way way over rated) and have a big gearbox what unfortunately makes the movement a bit slow.
      I started off with 1 motor to move 2 curtains at the same time, but will change this to 2 motors for either side since the better half of me likes to control the curtains separately in case she only wants to close 1.
      Next to the automation there will also be a manual control switch be hidden behind the curtains in case the node is down and I'm not at home to fix the issue...
      all running on an ESP8266 (ESP-12e) unit to have it over WiFi and have enough io

      Currently the test setup is working fine and I'm ordering parts to start implementing this a bit bigger in the first room. the test setup I made with some old wood 1 meter of rail and a few old rugs as curtains...
      alt text

      I use a GT2 timing belt that is commently used for 3D printers and pully's are widely available as well as the belts in different lengths (I order them on rolls of 10 meters) and attached the timing belt to a carriage that is normally to pull the curtains with a rod.
      alt text

      the motor is mounted on a bracket with currently 2 end stop switches for open and close (but will be 1 switch for open and 1 for close in the final solution)
      alt text

      resulting in driving the curtain from 1 side
      alt text

      alt text

      electronics are working fine now and need to be ported to a test print and later to a real PCB design

      alt text

      alt text

      1 Reply Last reply
      3
      • R Offline
        R Offline
        romeok01
        wrote on last edited by romeok01
        #31

        Hello.

        To my project i use stepper motor JK42HS34-0404 and driver L298N.

        This is a wiring diagram.
        alt text

        This is a program code that I use

        #include <MySensor.h>  
        #include <SPI.h>
        #include <AccelStepper.h>
        #define HALFSTEP 4  // Stepper uses "Halfstep" mode
        #define CURTAIN_CLOSED 1000 // value when closed
        #define CURTAIN_OPEN 0 // value when open
        #define CHILD_ID 1   // Id of the sensor child
        // MySensors definitions
        MySensor gw;
        // Initialize message
        MyMessage msg(CHILD_ID, V_TRIPPED);
        
        
        // Motor pin definitions
        #define motorPin1  3     // IN1 on the ULN2003 driver 1
        #define motorPin2  4     // IN2 on the ULN2003 driver 1
        #define motorPin3  5     // IN3 on the ULN2003 driver 1
        #define motorPin4  6     // IN4 on the ULN2003 driver 1
        
        // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
        AccelStepper stepper1(HALFSTEP, motorPin1, motorPin2, motorPin3, motorPin4);
        
        unsigned long current_position ; // remembers current position, need to be saved in EEPROM?
        
        void setup() {
          // MySensors
          gw.begin(); // fixed node 13
          gw.sendSketchInfo("Curtain control 13", "1.0"); // Send the sketch version information to the gateway and Controller
        
          //pinMode(DIGITAL_INPUT_SENSOR, INPUT);      // sets the motion sensor digital pin as input
          // Register all sensors to gw (they will be created as child devices)
          gw.present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
          
          stepper1.setMaxSpeed(500.0);
          stepper1.setAcceleration(700.0);
          stepper1.moveTo(CURTAIN_OPEN);
          
          current_position = CURTAIN_OPEN ;
          stepper1.moveTo(CURTAIN_OPEN);
        }//--(end setup )---
        
        void loop() {
          // if message = V_UP start moving until closed
          // if message = V_DOWN start moving back until open
          // if message = V_STOP stop moving
          // Test: Change direction when the stepper reaches the target position
          gw.process(); // check if message from controller
          if (stepper1.distanceToGo() == 0){
            if (stepper1.currentPosition() == CURTAIN_OPEN){
              stepper1.moveTo(CURTAIN_CLOSED);
              Serial.println("Curtain Open, now closing");
              gw.request(CHILD_ID, V_UP, 0); // request new values from controller  
            }
            else{
              stepper1.moveTo(CURTAIN_OPEN);
              Serial.println("Curtain Closed, now opening");
              gw.request(CHILD_ID, V_DOWN, 0); // request new values from controller   
            }
          }
          
          stepper1.run();
        }
        
        // This is called when a message is received 
        void incomingMessage(const MyMessage &message) {
          // We only expect few types of messages from controller, check which
          stepper1.moveTo(message.getInt() * CURTAIN_CLOSED/100);
          Serial.print("Message - valid: ");
          Serial.print(message.sensor);
          Serial.print(" , value: % ");
          Serial.println(message.getInt());
          switch (message.getInt()) {
          case 100:
            // Curtain should be opened
             Serial.print("Message - valid: ");
             Serial.print(message.sensor);
             Serial.print(", Message UP ");
             stepper1.moveTo(CURTAIN_OPEN);
             break;
          case 0:
            // Curtain should be closed
             Serial.print("Message - valid: ");
             Serial.print(message.sensor);
             Serial.print(", Message DOWN ");
             stepper1.moveTo(CURTAIN_CLOSED);
            break;
          case 50:
            // Curtain action should be stopped
             Serial.print("Message - valid: ");
             Serial.print(message.sensor);
             Serial.print(", Message STOP ");
            break;
          default: 
            // not recognizable message
             Serial.print("Message - valid: ");
             Serial.print(message.sensor);
             Serial.print(", Unrecognized ");
        
          }
         
        }
        

        When the program I have uploaded to my mysensors, the engine still turns, one left and one to the right and did not work the button blinds in Domoticz.

        I cant turn off my stepper motor in Domoticz.

        https://www.youtube.com/embed/1Wc1p_9YDQQ

        Please help me.

        1 Reply Last reply
        1
        • R Offline
          R Offline
          romeok01
          wrote on last edited by
          #32

          I write a program on library Stepper not AccelStepper.
          Now is working.

          Program code:

          // Enable debug prints to serial monitor
          #define MY_DEBUG 
          
          // Enable and select radio type attached
          #define MY_RADIO_NRF24
          //#define MY_RADIO_RFM69
          
          // Enable repeater functionality for this node
          #define MY_REPEATER_FEATURE
          
          #include <SPI.h>
          #include <MySensors.h>
          #include <Stepper.h>
          
          #define CURTAIN_CLOSED 1000  // wartosc gdy kurtyna zamknieta
          #define CURTAIN_OPEN -1000         // wartosc gdy kurtyna otwarta 
          #define CHILD_ID 1
          
          // definicje MySensors 
          
          MyMessage message(CHILD_ID, S_COVER);
          
          int in1Pin = 3;
          int in2Pin = 4;
          int in3Pin = 5;
          int in4Pin = 6;
          int lastState;
           
          // liczba kroków na jeden obrót
          #define stepsPerRevolution 200
          
          //ustawienie szybkości silnika 
          int motorSpeed = 40;
          
          Stepper myStepper(stepsPerRevolution, in1Pin, in2Pin, in3Pin, in4Pin);
          
          void setup() {
            
          // ustawienie pinów jako wyjście
            pinMode(in1Pin, OUTPUT);
            pinMode(in2Pin, OUTPUT);
            pinMode(in3Pin, OUTPUT);
            pinMode(in4Pin, OUTPUT);
          // ustawienie szybkosci silnika
            myStepper.setSpeed(motorSpeed);
          }
          
          void presentation()  
          { 
            // Wyslanie informacji o wersji programu
            sendSketchInfo("Program kurtyna", "1.0");
            // Register all sensors to gw (they will be created as child devices)
            present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
          }
          
          void receive(const MyMessage &message) {
            // if message = V_UP start moving until closed
            if (message.type==V_UP) {
               myStepper.step(CURTAIN_OPEN);
               // Store state in eeprom
               saveState(message.sensor, message.getBool());
               request(CHILD_ID, V_UP, 0); // request new values from controller
                  }
               
           if (message.type==V_DOWN) {
               myStepper.step(CURTAIN_CLOSED);
               // Store state in eeprom
               saveState(message.sensor, message.getBool());
               request(CHILD_ID, V_DOWN, 0); // request new values from controller
                  } 
          }
          
          

          I use MySensors Library 2.0

          Youtube film

          https://www.youtube.com/embed/gm0r2kDXrt4

          1 Reply Last reply
          2
          • franzelareF Offline
            franzelareF Offline
            franzelare
            wrote on last edited by
            #33

            your wiring diagram is not accessable:
            Error (403)
            It seems you don't belong here! You should probably sign in. Check out our Help Center and forums for help, or head back to home.

            i use a DC motor so can't help with stepper motors, but can you share an image of how you setup your rails?

            1 Reply Last reply
            0
            • R Offline
              R Offline
              romeok01
              wrote on last edited by
              #34

              Now the wiring diagram should be visible.

              1 Reply Last reply
              1
              • R Offline
                R Offline
                romeok01
                wrote on last edited by
                #35

                I write program with AccelStepper library

                / Enable debug prints to serial monitor
                #define MY_DEBUG
                
                // Enable and select radio type attached
                #define MY_RADIO_NRF24
                //#define MY_RADIO_RFM69
                
                // Enable repeater functionality for this node
                #define MY_REPEATER_FEATURE
                
                #include <SPI.h>
                #include <MySensors.h>
                #include <AccelStepper.h>      //import biblioteki AccelStepper 
                
                #define HALFSTEP 8
                #define CURTAIN_CLOSED 2000  // wartosc gdy kurtyna zamknieta
                #define CURTAIN_OPEN 0       // wartosc gdy kurtyna otwarta
                #define CHILD_ID 1
                
                // definicje MySensors
                
                MyMessage message(CHILD_ID, S_COVER);
                
                // Definicja pinow silnika
                #define IN1  3     // IN1 - zielony
                #define IN2  4     // IN2 - czarny
                #define IN3  5     // IN3 - niebieski
                #define IN4  6     // IN4 - czerwony
                 
                AccelStepper stepper1(HALFSTEP, IN1, IN2, IN3, IN4);
                
                void setup()
                {
                  stepper1.setMaxSpeed(200.0);
                  stepper1.setAcceleration(1000.0);
                  stepper1.setSpeed(200);
                  stepper1.moveTo(CURTAIN_OPEN);
                }
                
                void presentation() 
                {
                  // Wyslanie informacji o wersji programu
                  sendSketchInfo("Program kurtyna", "1.0");
                  // Register all sensors to gw (they will be created as child devices)
                  present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                }
                
                void loop()
                {
                  stepper1.run();  //Start
                }
                
                void receive(const MyMessage &message)
                {
                  // if message = V_UP start moving until closed
                  if (message.type==V_UP) {
                     if (stepper1.distanceToGo() == 0){
                         if (stepper1.currentPosition() == CURTAIN_OPEN){
                             stepper1.moveTo(CURTAIN_CLOSED);
                     // Store state in eeprom
                     saveState(message.sensor, message.getBool());
                     request(CHILD_ID, V_UP, 0); // request new values from controller
                         }
                      }
                   }
                   if (message.type==V_DOWN) {
                       stepper1.moveTo(CURTAIN_OPEN);
                       // Store state in eeprom
                       saveState(message.sensor, message.getBool());
                       request(CHILD_ID, V_DOWN, 0); // request new values from controller   
                    }
                    if (message.type==V_STOP) {
                        stepper1.setCurrentPosition(0);
                        // Store state in eeprom
                        saveState(message.sensor, message.getBool());
                        request(CHILD_ID, V_STOP, 0); // request new values from controller
                    }
                }
                
                

                I use MySensors library 2.0

                Now i working.

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  jacikaas
                  wrote on last edited by
                  #36

                  Hello,

                  I trying to adopt the code for 28BYJ-48 stepper motor with ULN2003 driver board for roller blinds control. Code is working, but when the stepper motor is always on - it gets hot. Because of it also its consumes more energy. So thats why I want to turn on ULN2003 board only when new action is started, and after that it should be shuted down again. I could do it, because ULN2003 has On/Off jumper:
                  alt text

                  Question #1: I trying to use relay for that On/Off. Could I do it without relay and control On/Off jumper directly from arduino? Does relay is the best solution?

                  Question #2: I suck at programming, but I trying to add theese lines to my code to control the relay SIL05-1A72-71D, which controls the ULN2003 driver board:
                  int powerPin = 7; //before SETUP
                  pinMode(powerPin, OUTPUT); // In SETUP
                  digitalWrite(powerPin, LOW); // In SETUP
                  digitalWrite(powerPin, HIGH); // In void receive function
                  delay(CURTAIN_CLOSED); // In void receive function
                  digitalWrite(powerPin, LOW); // In void receive function

                  digitalWrite(powerPin, HIGH); - I think is in right position, but I don't know how to turn off relay when action is done. Please advise for coding, because I not good in it. Thank You! Below is the code:

                  // Enable debug prints to serial monitor
                  #define MY_DEBUG
                  
                  // Enable and select radio type attached
                  #define MY_NODE_ID 10
                  #define MY_RADIO_NRF24
                  //#define MY_RADIO_RFM69
                  
                  // Enable repeater functionality for this node
                  //#define MY_REPEATER_FEATURE
                  
                  #include <SPI.h>
                  #include <MySensors.h>
                  #include <AccelStepper.h>      //import biblioteki AccelStepper 
                  
                  #define HALFSTEP 8
                  #define CURTAIN_CLOSED 10000  // wartosc gdy kurtyna zamknieta
                  #define CURTAIN_OPEN 0       // wartosc gdy kurtyna otwarta
                  #define CHILD_ID 1
                  
                  int powerPin = 7;
                  
                  // definicje MySensors
                  
                  MyMessage message(CHILD_ID, S_COVER);
                  
                  // Definicja pinow silnika
                  #define IN1  3     // IN1 - zielony
                  #define IN2  4     // IN2 - czarny
                  #define IN3  5     // IN3 - niebieski
                  #define IN4  6     // IN4 - czerwony
                   
                  AccelStepper stepper1(HALFSTEP, IN1, IN3, IN2, IN4);
                  
                  void setup()
                  {
                    stepper1.setMaxSpeed(1000.0);
                    stepper1.setAcceleration(100.0);
                    stepper1.setSpeed(200);
                    stepper1.moveTo(CURTAIN_OPEN);
                    
                    pinMode(powerPin, OUTPUT);
                    digitalWrite(powerPin, LOW);
                  }
                  
                  void presentation() 
                  {
                    // Wyslanie informacji o wersji programu
                    sendSketchInfo("Roller blinds", "1.0");
                    // Register all sensors to gw (they will be created as child devices)
                    present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                  }
                  
                  void loop()
                  {
                    stepper1.run();  //Start
                  }
                  
                  void receive(const MyMessage &message)
                  {
                    // if message = V_UP start moving until closed
                    if (message.type==V_UP) {
                       digitalWrite(powerPin, HIGH);
                       if (stepper1.distanceToGo() == 0){
                           if (stepper1.currentPosition() == CURTAIN_OPEN){
                               stepper1.moveTo(CURTAIN_CLOSED);
                       // Store state in eeprom
                       saveState(message.sensor, message.getBool());
                       request(CHILD_ID, V_UP, 0); // request new values from controller
                           }
                        }
                     }
                     if (message.type==V_DOWN) {
                         digitalWrite(powerPin, HIGH);
                         stepper1.moveTo(CURTAIN_OPEN);
                         // Store state in eeprom
                         saveState(message.sensor, message.getBool());
                         request(CHILD_ID, V_DOWN, 0); // request new values from controller   
                      }
                      if (message.type==V_STOP) {
                          digitalWrite(powerPin, HIGH);
                          stepper1.setCurrentPosition(0);
                          // Store state in eeprom
                          saveState(message.sensor, message.getBool());
                          request(CHILD_ID, V_STOP, 0); // request new values from controller
                      }
                   //   delay(CURTAIN_CLOSED);
                   //   digitalWrite(powerPin, LOW);
                  }
                  
                  
                  Suresh MaliS 1 Reply Last reply
                  0
                  • J jacikaas

                    Hello,

                    I trying to adopt the code for 28BYJ-48 stepper motor with ULN2003 driver board for roller blinds control. Code is working, but when the stepper motor is always on - it gets hot. Because of it also its consumes more energy. So thats why I want to turn on ULN2003 board only when new action is started, and after that it should be shuted down again. I could do it, because ULN2003 has On/Off jumper:
                    alt text

                    Question #1: I trying to use relay for that On/Off. Could I do it without relay and control On/Off jumper directly from arduino? Does relay is the best solution?

                    Question #2: I suck at programming, but I trying to add theese lines to my code to control the relay SIL05-1A72-71D, which controls the ULN2003 driver board:
                    int powerPin = 7; //before SETUP
                    pinMode(powerPin, OUTPUT); // In SETUP
                    digitalWrite(powerPin, LOW); // In SETUP
                    digitalWrite(powerPin, HIGH); // In void receive function
                    delay(CURTAIN_CLOSED); // In void receive function
                    digitalWrite(powerPin, LOW); // In void receive function

                    digitalWrite(powerPin, HIGH); - I think is in right position, but I don't know how to turn off relay when action is done. Please advise for coding, because I not good in it. Thank You! Below is the code:

                    // Enable debug prints to serial monitor
                    #define MY_DEBUG
                    
                    // Enable and select radio type attached
                    #define MY_NODE_ID 10
                    #define MY_RADIO_NRF24
                    //#define MY_RADIO_RFM69
                    
                    // Enable repeater functionality for this node
                    //#define MY_REPEATER_FEATURE
                    
                    #include <SPI.h>
                    #include <MySensors.h>
                    #include <AccelStepper.h>      //import biblioteki AccelStepper 
                    
                    #define HALFSTEP 8
                    #define CURTAIN_CLOSED 10000  // wartosc gdy kurtyna zamknieta
                    #define CURTAIN_OPEN 0       // wartosc gdy kurtyna otwarta
                    #define CHILD_ID 1
                    
                    int powerPin = 7;
                    
                    // definicje MySensors
                    
                    MyMessage message(CHILD_ID, S_COVER);
                    
                    // Definicja pinow silnika
                    #define IN1  3     // IN1 - zielony
                    #define IN2  4     // IN2 - czarny
                    #define IN3  5     // IN3 - niebieski
                    #define IN4  6     // IN4 - czerwony
                     
                    AccelStepper stepper1(HALFSTEP, IN1, IN3, IN2, IN4);
                    
                    void setup()
                    {
                      stepper1.setMaxSpeed(1000.0);
                      stepper1.setAcceleration(100.0);
                      stepper1.setSpeed(200);
                      stepper1.moveTo(CURTAIN_OPEN);
                      
                      pinMode(powerPin, OUTPUT);
                      digitalWrite(powerPin, LOW);
                    }
                    
                    void presentation() 
                    {
                      // Wyslanie informacji o wersji programu
                      sendSketchInfo("Roller blinds", "1.0");
                      // Register all sensors to gw (they will be created as child devices)
                      present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                    }
                    
                    void loop()
                    {
                      stepper1.run();  //Start
                    }
                    
                    void receive(const MyMessage &message)
                    {
                      // if message = V_UP start moving until closed
                      if (message.type==V_UP) {
                         digitalWrite(powerPin, HIGH);
                         if (stepper1.distanceToGo() == 0){
                             if (stepper1.currentPosition() == CURTAIN_OPEN){
                                 stepper1.moveTo(CURTAIN_CLOSED);
                         // Store state in eeprom
                         saveState(message.sensor, message.getBool());
                         request(CHILD_ID, V_UP, 0); // request new values from controller
                             }
                          }
                       }
                       if (message.type==V_DOWN) {
                           digitalWrite(powerPin, HIGH);
                           stepper1.moveTo(CURTAIN_OPEN);
                           // Store state in eeprom
                           saveState(message.sensor, message.getBool());
                           request(CHILD_ID, V_DOWN, 0); // request new values from controller   
                        }
                        if (message.type==V_STOP) {
                            digitalWrite(powerPin, HIGH);
                            stepper1.setCurrentPosition(0);
                            // Store state in eeprom
                            saveState(message.sensor, message.getBool());
                            request(CHILD_ID, V_STOP, 0); // request new values from controller
                        }
                     //   delay(CURTAIN_CLOSED);
                     //   digitalWrite(powerPin, LOW);
                    }
                    
                    
                    Suresh MaliS Offline
                    Suresh MaliS Offline
                    Suresh Mali
                    wrote on last edited by
                    #37

                    @jacikaas said in Curtain Control Node.:

                    void receive(const MyMessage &message)
                    {
                    // if message = V_UP start moving until closed
                    if (message.type==V_UP) {
                    digitalWrite(powerPin, HIGH);
                    if (stepper1.distanceToGo() == 0){
                    if (stepper1.currentPosition() == CURTAIN_OPEN){
                    stepper1.moveTo(CURTAIN_CLOSED);
                    // Store state in eeprom
                    saveState(message.sensor, message.getBool());
                    request(CHILD_ID, V_UP, 0); // request new values from controller
                    }
                    }
                    }
                    if (message.type==V_DOWN) {
                    digitalWrite(powerPin, HIGH);
                    stepper1.moveTo(CURTAIN_OPEN);
                    // Store state in eeprom
                    saveState(message.sensor, message.getBool());
                    request(CHILD_ID, V_DOWN, 0); // request new values from controller
                    }
                    if (message.type==V_STOP) {
                    digitalWrite(powerPin, HIGH);
                    stepper1.setCurrentPosition(0);
                    // Store state in eeprom
                    saveState(message.sensor, message.getBool());
                    request(CHILD_ID, V_STOP, 0); // request new values from controller
                    }
                    // delay(CURTAIN_CLOSED);
                    // digitalWrite(powerPin, LOW);
                    }

                    You can enable and disable outputs and try. In the following function:

                    void receive(const MyMessage &message)
                    
                    //add the following at the begining of the function
                    stepper1.enableOutputs ()
                    //and add the following at the end in the same function.
                    stepper1.disableOutputs ()
                    

                    I hope this helps haven't tried it myself.

                    J 1 Reply Last reply
                    0
                    • Suresh MaliS Suresh Mali

                      @jacikaas said in Curtain Control Node.:

                      void receive(const MyMessage &message)
                      {
                      // if message = V_UP start moving until closed
                      if (message.type==V_UP) {
                      digitalWrite(powerPin, HIGH);
                      if (stepper1.distanceToGo() == 0){
                      if (stepper1.currentPosition() == CURTAIN_OPEN){
                      stepper1.moveTo(CURTAIN_CLOSED);
                      // Store state in eeprom
                      saveState(message.sensor, message.getBool());
                      request(CHILD_ID, V_UP, 0); // request new values from controller
                      }
                      }
                      }
                      if (message.type==V_DOWN) {
                      digitalWrite(powerPin, HIGH);
                      stepper1.moveTo(CURTAIN_OPEN);
                      // Store state in eeprom
                      saveState(message.sensor, message.getBool());
                      request(CHILD_ID, V_DOWN, 0); // request new values from controller
                      }
                      if (message.type==V_STOP) {
                      digitalWrite(powerPin, HIGH);
                      stepper1.setCurrentPosition(0);
                      // Store state in eeprom
                      saveState(message.sensor, message.getBool());
                      request(CHILD_ID, V_STOP, 0); // request new values from controller
                      }
                      // delay(CURTAIN_CLOSED);
                      // digitalWrite(powerPin, LOW);
                      }

                      You can enable and disable outputs and try. In the following function:

                      void receive(const MyMessage &message)
                      
                      //add the following at the begining of the function
                      stepper1.enableOutputs ()
                      //and add the following at the end in the same function.
                      stepper1.disableOutputs ()
                      

                      I hope this helps haven't tried it myself.

                      J Offline
                      J Offline
                      jacikaas
                      wrote on last edited by
                      #38

                      @suresh-mali Thank You Suresh for Your answer!
                      I disconnect relay and delete it lines from the code.

                      I add lines to code like You said:

                      void receive(const MyMessage &message)
                      {
                      stepper1.enableOutputs ();
                       // rest of code
                      stepper1.disableOutputs ();
                      }
                      

                      It looks like it have to work because it is simple solution, but it doesn't... On driver board ULN2003, when motor is not rotating, A Led is always on. I think if command with disableOutputs would be activated, then the LED should not be on?

                      Suresh MaliS 1 Reply Last reply
                      0
                      • J jacikaas

                        @suresh-mali Thank You Suresh for Your answer!
                        I disconnect relay and delete it lines from the code.

                        I add lines to code like You said:

                        void receive(const MyMessage &message)
                        {
                        stepper1.enableOutputs ();
                         // rest of code
                        stepper1.disableOutputs ();
                        }
                        

                        It looks like it have to work because it is simple solution, but it doesn't... On driver board ULN2003, when motor is not rotating, A Led is always on. I think if command with disableOutputs would be activated, then the LED should not be on?

                        Suresh MaliS Offline
                        Suresh MaliS Offline
                        Suresh Mali
                        wrote on last edited by Suresh Mali
                        #39

                        @jacikaas Ok.

                        //Remove this line from loop function
                        stepper1.run(); 
                        
                        //Change this line
                        stepper1.moveTo(CURTAIN_CLOSED);
                        //to
                        stepper1.runToPosition(CURTAIN_CLOSED);
                        

                        I hope this works. Also make similar changes in block which closes curtains.
                        Refernce article: https://www.pjrc.com/teensy/td_libs_AccelStepper.html

                        1 Reply Last reply
                        0
                        • J Offline
                          J Offline
                          jacikaas
                          wrote on last edited by
                          #40

                          @suresh-mali
                          I now reading about that funktions in http://www.airspayce.com/mikem/arduino/AccelStepper/classAccelStepper.html#a344f58fef8cc34ac5aa75ba4b665d21c

                          Did what You said, but getting error: no matching function for call to 'AccelStepper::runToPosition(int)'
                          I paste here all code, but I think I did everything without mistakes:

                          // Enable debug prints to serial monitor
                          #define MY_DEBUG
                          
                          // Enable and select radio type attached
                          #define MY_NODE_ID 10
                          #define MY_RADIO_NRF24
                          //#define MY_RADIO_RFM69
                          
                          // Enable repeater functionality for this node
                          //#define MY_REPEATER_FEATURE
                          
                          #include <SPI.h>
                          #include <MySensors.h>
                          #include <AccelStepper.h>
                          
                          #define HALFSTEP 8
                          #define CURTAIN_CLOSED 10000
                          #define CURTAIN_OPEN 0
                          #define CHILD_ID 1
                          
                          // int powerPin = 7;
                          
                          // definicje MySensors
                          
                          MyMessage message(CHILD_ID, S_COVER);
                          
                          // Definicja pinow silnika
                          #define IN1  3     // IN1
                          #define IN2  4     // IN2
                          #define IN3  5     // IN3
                          #define IN4  6     // IN4
                           
                          AccelStepper stepper1(HALFSTEP, IN1, IN3, IN2, IN4);
                          
                          void setup()
                          {
                            stepper1.setMaxSpeed(1000.0);
                            stepper1.setAcceleration(100.0);
                            stepper1.setSpeed(200);
                            stepper1.runToPosition(CURTAIN_CLOSED);
                          }
                          
                          void presentation() 
                          {
                            sendSketchInfo("Roller blinds", "1.0");
                            present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                          }
                          
                          void loop()
                          {
                            //stepper1.run();  //Start
                          }
                          
                          void receive(const MyMessage &message)
                          {
                          stepper1.enableOutputs ();
                            // if message = V_UP start moving until closed
                            if (message.type==V_UP) {
                               if (stepper1.distanceToGo() == 0){
                                   if (stepper1.currentPosition() == CURTAIN_OPEN){
                                       stepper1.runToPosition(CURTAIN_CLOSED);
                               // Store state in eeprom
                               saveState(message.sensor, message.getBool());
                               request(CHILD_ID, V_UP, 0); // request new values from controller
                                   }
                                }
                             }
                             if (message.type==V_DOWN) {
                                 stepper1.moveTo(CURTAIN_OPEN);
                                 // Store state in eeprom
                                 saveState(message.sensor, message.getBool());
                                 request(CHILD_ID, V_DOWN, 0); // request new values from controller   
                              }
                              if (message.type==V_STOP) {
                                  stepper1.setCurrentPosition(0);
                                  // Store state in eeprom
                                  saveState(message.sensor, message.getBool());
                                  request(CHILD_ID, V_STOP, 0); // request new values from controller
                              }
                          stepper1.disableOutputs ();
                          }
                          
                          
                          skywatchS 1 Reply Last reply
                          0
                          • J jacikaas

                            @suresh-mali
                            I now reading about that funktions in http://www.airspayce.com/mikem/arduino/AccelStepper/classAccelStepper.html#a344f58fef8cc34ac5aa75ba4b665d21c

                            Did what You said, but getting error: no matching function for call to 'AccelStepper::runToPosition(int)'
                            I paste here all code, but I think I did everything without mistakes:

                            // Enable debug prints to serial monitor
                            #define MY_DEBUG
                            
                            // Enable and select radio type attached
                            #define MY_NODE_ID 10
                            #define MY_RADIO_NRF24
                            //#define MY_RADIO_RFM69
                            
                            // Enable repeater functionality for this node
                            //#define MY_REPEATER_FEATURE
                            
                            #include <SPI.h>
                            #include <MySensors.h>
                            #include <AccelStepper.h>
                            
                            #define HALFSTEP 8
                            #define CURTAIN_CLOSED 10000
                            #define CURTAIN_OPEN 0
                            #define CHILD_ID 1
                            
                            // int powerPin = 7;
                            
                            // definicje MySensors
                            
                            MyMessage message(CHILD_ID, S_COVER);
                            
                            // Definicja pinow silnika
                            #define IN1  3     // IN1
                            #define IN2  4     // IN2
                            #define IN3  5     // IN3
                            #define IN4  6     // IN4
                             
                            AccelStepper stepper1(HALFSTEP, IN1, IN3, IN2, IN4);
                            
                            void setup()
                            {
                              stepper1.setMaxSpeed(1000.0);
                              stepper1.setAcceleration(100.0);
                              stepper1.setSpeed(200);
                              stepper1.runToPosition(CURTAIN_CLOSED);
                            }
                            
                            void presentation() 
                            {
                              sendSketchInfo("Roller blinds", "1.0");
                              present(CHILD_ID, S_COVER); // Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                            }
                            
                            void loop()
                            {
                              //stepper1.run();  //Start
                            }
                            
                            void receive(const MyMessage &message)
                            {
                            stepper1.enableOutputs ();
                              // if message = V_UP start moving until closed
                              if (message.type==V_UP) {
                                 if (stepper1.distanceToGo() == 0){
                                     if (stepper1.currentPosition() == CURTAIN_OPEN){
                                         stepper1.runToPosition(CURTAIN_CLOSED);
                                 // Store state in eeprom
                                 saveState(message.sensor, message.getBool());
                                 request(CHILD_ID, V_UP, 0); // request new values from controller
                                     }
                                  }
                               }
                               if (message.type==V_DOWN) {
                                   stepper1.moveTo(CURTAIN_OPEN);
                                   // Store state in eeprom
                                   saveState(message.sensor, message.getBool());
                                   request(CHILD_ID, V_DOWN, 0); // request new values from controller   
                                }
                                if (message.type==V_STOP) {
                                    stepper1.setCurrentPosition(0);
                                    // Store state in eeprom
                                    saveState(message.sensor, message.getBool());
                                    request(CHILD_ID, V_STOP, 0); // request new values from controller
                                }
                            stepper1.disableOutputs ();
                            }
                            
                            
                            skywatchS Offline
                            skywatchS Offline
                            skywatch
                            wrote on last edited by
                            #41

                            @jacikaas Sorry to revive an old thread, but did you get this resolved and if so how?

                            I just 3D printed my first motorised roller blind mounts and have tested with arduino stepper only.

                            Next is to go mysensors with it, but which way is best? Standard arduino stepper or accelstepper?

                            1 Reply Last reply
                            0
                            • xydixX Offline
                              xydixX Offline
                              xydix
                              wrote on last edited by
                              #42

                              Okey. This is an old thread but I hope it's ok I keep it alive.
                              I just printed som parts for my blinds.
                              I use a stepper motor (28BYJ-48 with ULN2003 Driver board) and this sketch found in this thread.
                              The sketch is awesome.
                              To my quiestion.
                              I want to run 2 blinds at the same time from ONE node. Synchronized or maybe individual.
                              Is this possible?
                              There isn't any digital pins over for this when using button(s).
                              I think i saw someone using analog pin connected to the ULN2003 someware.
                              Is it possible to run 2 motors on one board?
                              Really hope somone can answer som of my question.
                              What modifications is needed in the sketch if this is possible.
                              This is the sketch I use.

                              /*
                               PROJECT: MY Sensors curtain controller
                               PROGRAMMER: AWI
                               DATE: march 11, 2016
                               FILE: AWI stepper1.ino
                               LICENSE: Public domain
                              
                               Hardware: ATMega328p board w/ NRF24l01
                              	and MySensors 2.0 (Development)
                              		
                              Special:
                              	uses AccelStepper library
                              	
                              Summary:
                              	Curtain control with stepper motor. 
                              	Manual operation with 1 push button 
                              	Calibration with manual button
                              
                              Remarks:
                              	Fixed node-id
                              	
                              Change log:
                              20160312 - Cleanup
                              */
                              
                              // Enable debug prints to serial monitor
                              #define MY_DEBUG 
                              
                              #define MY_NODE_ID 13											// fixed node number
                              // Enable and select radio type attached
                              #define MY_RADIO_RF24
                              //#define MY_RADIO_RFM69
                              
                              #include <SPI.h>
                              #include <MySensors.h> 
                              
                              // stepper library
                              #include <AccelStepper.h>										// http://www.airspayce.com/mikem/arduino/AccelStepper/
                              #define HALFSTEP 8  											// Stepper uses "Halfstep" mode
                              
                              // button library
                              // used for:
                              // - manual open close - single click: close/ stop/ open/ stop
                              // - calibration  - after long press: open calibarion- until single press - closed calibration - until single press (stop)
                              #include <Button.h>												// https://github.com/JChristensen/Button
                              
                              #define CHILD_ID 1   											// Id of the sensor child
                              
                              #define SN "Curtain control 13"
                              #define SV "1.0"
                              
                              #define buttonPin1 7  											// Arduino pin connected to buttonPin1
                              #define buttonPin2 A0  											// Arduino pin connected to buttonPin2 (fixed to ground)
                              
                              // Motor pin definitions
                              #define motorPin1  3     										// IN1 on the ULN2003 driver 1
                              #define motorPin2  4     										// IN2 on the ULN2003 driver 1
                              #define motorPin3  5     										// IN3 on the ULN2003 driver 1
                              #define motorPin4  6     										// IN4 on the ULN2003 driver 1
                              
                              const unsigned long heartbeatInterval = 1 * 3600UL * 1000UL ;	// heartbeatinterval
                              unsigned long heartbeatCounter = 0 ;
                              
                              //
                              // helper routines to store and retrieve long in mysensors EEPROM
                              union {															// used to convert long to bytes for EEPROM storage
                              	long longInt;
                              	uint8_t LongByte[4];
                              	} convLongInt ;
                              
                              void saveStateL(int EEposition, long StateL){
                              	convLongInt.longInt = StateL ;
                              	for (int y = 0; y < 4 ; y++){								// convert to bytes
                              		saveState(EEposition + y , convLongInt.LongByte[y]) ;
                              		}
                              	Serial.print("State saved: "); Serial.println(StateL);
                              	}
                              		
                              long loadStateL(int EEposition){
                              	for (int y = 0; y < 4 ; y++){								// convert from bytes
                              		convLongInt.LongByte[y] = loadState(EEposition + y) ;
                              		}
                              	Serial.print("State read: "); Serial.println(convLongInt.longInt);
                              	return convLongInt.longInt ;
                              	}
                              	
                              
                              // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
                              AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
                              // Initialize button active low, debounce and internal pull-up
                              Button myBtn(buttonPin1, true, true, 40);						// Initiate the button (pin, pull_up, invert, debounce_ms)
                              
                              MyMessage percentageMsg(CHILD_ID, V_PERCENTAGE);				// used to send updates to controller
                              
                              const long maxRun = 4000000L ;									// maximum runway
                              long setPosition = 0 ; 											// remembers set position, need to be saved in EEPROM
                              const int setPositionEE = 4 ;									// eeprom location
                              long openPosition = 0 ; 										// Position at open, need to be saved in EEPROM?
                              const int openPositionEE = setPositionEE + 4 ;					// eeprom location
                              long closedPosition = 120000UL ; 								// Position at full close, need to be saved in EEPROM
                              const int closedPositionEE = openPositionEE + 4 ;				// eeprom location
                              
                              unsigned long idleTimer = millis() ;							// return to idle timer
                              unsigned long idleTime = 100000UL ;								// return to idle after 100 secs
                              
                              unsigned long printTimer = millis() ;							// print timer
                              unsigned long printTime = 1000UL ;								// print after 1 secs
                              
                              enum position_t {Open, Close, Idle, Running} ;
                              position_t lastDirection = Open ; 								// lastDirection only for buttonpress
                              position_t runStatus = Idle ;									// indicates current status for running motor. used for status reporting to controller
                              
                              enum State_t {sIdle, sCalibrateOpen, sCalibrateClose} ;
                              State_t State = sIdle ;
                              
                              
                              void setup() {
                              	// setup buttons
                              	pinMode(buttonPin1, OUTPUT);
                              	stepper1.setMaxSpeed(2000.0);
                              	stepper1.setAcceleration(1000.0);
                              	//saveStateL(closedPositionEE, closedPosition) ; 			// INIT: save closed position in EEPROM
                              	closedPosition = loadStateL(closedPositionEE) ;				// need to get last values from EEPROM and assume the current position is correct
                              	setPosition = loadStateL(setPositionEE) ;
                              	stepper1.setCurrentPosition(setPosition );
                              }//--(end setup )---
                              
                              void presentation() {
                                present(CHILD_ID, S_COVER, "Curtain");						// Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                              
                                // Register the LED Dimmable Light with the gateway
                                sendSketchInfo(SN, SV);
                              }
                              
                              
                              void loop() {
                              unsigned int now = millis() ;								// current time for loop
                              // simple state machine for button press
                              	myBtn.read();  
                              	switch (State) {
                                      // Idle state, waiting for some action
                              		// - button press
                              		// - idleTimer
                                      case sIdle:                
                                          if (myBtn.wasReleased()){						// idle
                              				Serial.println("Button release") ;
                              				// if running stop
                              				if (stepper1.isRunning()){
                              					setPosition = stepper1.currentPosition();
                              					stepper1.moveTo(setPosition) ;			// move to current position (was already there..)
                              				} else if (lastDirection == Open) {
                              					stepper1.moveTo(closedPosition) ;
                              					lastDirection = Close ;
                              				} else {									// lastDirection == Close
                              					stepper1.moveTo(openPosition) ;
                              					lastDirection = Open ;
                              				}	
                              			} else if (myBtn.pressedFor(3000)){				// move to calibratete state with long press
                              				Serial.println("Button press long") ;
                              				idleTimer = now ;							// return to idle after ...
                              				State = sCalibrateOpen ;
                              				stepper1.move(-maxRun) ;					// let the stepper open with maximum
                              				}
                              			break ;
                              		// if not running and last action was open close ;  else open
                              		// if longpress Calibrate open
                                      case sCalibrateOpen:           						// calibration going on     
                              			if (myBtn.wasPressed()){
                              				stepper1.setCurrentPosition(0 );		// set new 0 position ??
                              				openPosition = setPosition = 0 ;
                              				State = sCalibrateClose ;					// next is close calibarion
                              				stepper1.move(maxRun) ;						// let the stepper close with maximum
                              			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                              				State = sIdle ;
                              			}
                              			break ;
                                      case sCalibrateClose:								// calibrate closed position, end with keypress
                              			if (myBtn.wasPressed())	{
                              				closedPosition = setPosition = stepper1.currentPosition() ;
                              				saveStateL(closedPositionEE, closedPosition) ; // save closed position in EEPROM
                              				State = sIdle ;
                              				stepper1.moveTo(openPosition) ;				// return to open after calibration
                              			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                              				State = sIdle ;
                              			}
                              			break ;
                              		default :
                              			break ;
                              		}
                              	// power off stepper if not running (no need to reenable))
                              	if (!stepper1.isRunning()){
                              		if (runStatus != Idle){								// there was a change in runningstatus, so report to controller
                              			setPosition = stepper1.currentPosition() ;		// store in EEPROM and report ready to controller
                              			saveStateL(setPositionEE, setPosition) ;
                              			send( percentageMsg.set((100 * setPosition)/(closedPosition - openPosition))) ;
                              			runStatus = Idle ;
                              		}
                              		stepper1.disableOutputs();
                              	} else {
                              		runStatus = Running ;
                              	}
                              	stepper1.run();
                              	/*
                              	if (printTimer++ > now + printTime){
                              		printTimer = now ;
                              		Serial.println(stepper1.currentPosition());
                              		}
                              	*/
                              }
                              
                              // This is called when a message is received 
                              void receive(const MyMessage &message) {
                              // We only expect few types of messages from controller, check which
                                switch (message.type) {
                              	case V_PERCENTAGE:
                              	// Curtain should be opened
                              	stepper1.moveTo(message.getInt() * (closedPosition - openPosition)/100);
                              	Serial.print("Message: "); Serial.print(message.sensor); Serial.print(" , value: % "); Serial.println( message.getInt());
                              	Serial.print("Moving to: "); Serial.println(message.getInt() * (closedPosition - openPosition)/100);
                              	break ;
                              	case V_STATUS:
                              	// Curtain should be opened or closed full
                              	stepper1.moveTo((message.getInt() == HIGH)?openPosition:closedPosition);
                              	Serial.print("Message - valid: ");
                              	Serial.print(message.sensor);
                              	Serial.print(" , value: % ");
                              	break ;
                              	default : 
                              	// not recognizable message
                              	Serial.print("Message - valid: ");
                              	Serial.print(message.sensor);
                              	Serial.print(", Unrecognized ");
                              	break ;
                              	}
                                }
                              
                              TON RIJNAARDT xydixX 2 Replies Last reply
                              0
                              • TheoLT Offline
                                TheoLT Offline
                                TheoL
                                Contest Winner
                                wrote on last edited by
                                #43

                                You can use an I/O expander like an MCP23017 which is a 16 port expander or a 8 port expander. They're cheap. Keep in mind they consume 1 mAmp. I'm currently working on a product to overcome that power issue for a battery powered Node. Will try to post about it in a while

                                1 Reply Last reply
                                0
                                • xydixX xydix

                                  Okey. This is an old thread but I hope it's ok I keep it alive.
                                  I just printed som parts for my blinds.
                                  I use a stepper motor (28BYJ-48 with ULN2003 Driver board) and this sketch found in this thread.
                                  The sketch is awesome.
                                  To my quiestion.
                                  I want to run 2 blinds at the same time from ONE node. Synchronized or maybe individual.
                                  Is this possible?
                                  There isn't any digital pins over for this when using button(s).
                                  I think i saw someone using analog pin connected to the ULN2003 someware.
                                  Is it possible to run 2 motors on one board?
                                  Really hope somone can answer som of my question.
                                  What modifications is needed in the sketch if this is possible.
                                  This is the sketch I use.

                                  /*
                                   PROJECT: MY Sensors curtain controller
                                   PROGRAMMER: AWI
                                   DATE: march 11, 2016
                                   FILE: AWI stepper1.ino
                                   LICENSE: Public domain
                                  
                                   Hardware: ATMega328p board w/ NRF24l01
                                  	and MySensors 2.0 (Development)
                                  		
                                  Special:
                                  	uses AccelStepper library
                                  	
                                  Summary:
                                  	Curtain control with stepper motor. 
                                  	Manual operation with 1 push button 
                                  	Calibration with manual button
                                  
                                  Remarks:
                                  	Fixed node-id
                                  	
                                  Change log:
                                  20160312 - Cleanup
                                  */
                                  
                                  // Enable debug prints to serial monitor
                                  #define MY_DEBUG 
                                  
                                  #define MY_NODE_ID 13											// fixed node number
                                  // Enable and select radio type attached
                                  #define MY_RADIO_RF24
                                  //#define MY_RADIO_RFM69
                                  
                                  #include <SPI.h>
                                  #include <MySensors.h> 
                                  
                                  // stepper library
                                  #include <AccelStepper.h>										// http://www.airspayce.com/mikem/arduino/AccelStepper/
                                  #define HALFSTEP 8  											// Stepper uses "Halfstep" mode
                                  
                                  // button library
                                  // used for:
                                  // - manual open close - single click: close/ stop/ open/ stop
                                  // - calibration  - after long press: open calibarion- until single press - closed calibration - until single press (stop)
                                  #include <Button.h>												// https://github.com/JChristensen/Button
                                  
                                  #define CHILD_ID 1   											// Id of the sensor child
                                  
                                  #define SN "Curtain control 13"
                                  #define SV "1.0"
                                  
                                  #define buttonPin1 7  											// Arduino pin connected to buttonPin1
                                  #define buttonPin2 A0  											// Arduino pin connected to buttonPin2 (fixed to ground)
                                  
                                  // Motor pin definitions
                                  #define motorPin1  3     										// IN1 on the ULN2003 driver 1
                                  #define motorPin2  4     										// IN2 on the ULN2003 driver 1
                                  #define motorPin3  5     										// IN3 on the ULN2003 driver 1
                                  #define motorPin4  6     										// IN4 on the ULN2003 driver 1
                                  
                                  const unsigned long heartbeatInterval = 1 * 3600UL * 1000UL ;	// heartbeatinterval
                                  unsigned long heartbeatCounter = 0 ;
                                  
                                  //
                                  // helper routines to store and retrieve long in mysensors EEPROM
                                  union {															// used to convert long to bytes for EEPROM storage
                                  	long longInt;
                                  	uint8_t LongByte[4];
                                  	} convLongInt ;
                                  
                                  void saveStateL(int EEposition, long StateL){
                                  	convLongInt.longInt = StateL ;
                                  	for (int y = 0; y < 4 ; y++){								// convert to bytes
                                  		saveState(EEposition + y , convLongInt.LongByte[y]) ;
                                  		}
                                  	Serial.print("State saved: "); Serial.println(StateL);
                                  	}
                                  		
                                  long loadStateL(int EEposition){
                                  	for (int y = 0; y < 4 ; y++){								// convert from bytes
                                  		convLongInt.LongByte[y] = loadState(EEposition + y) ;
                                  		}
                                  	Serial.print("State read: "); Serial.println(convLongInt.longInt);
                                  	return convLongInt.longInt ;
                                  	}
                                  	
                                  
                                  // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
                                  AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
                                  // Initialize button active low, debounce and internal pull-up
                                  Button myBtn(buttonPin1, true, true, 40);						// Initiate the button (pin, pull_up, invert, debounce_ms)
                                  
                                  MyMessage percentageMsg(CHILD_ID, V_PERCENTAGE);				// used to send updates to controller
                                  
                                  const long maxRun = 4000000L ;									// maximum runway
                                  long setPosition = 0 ; 											// remembers set position, need to be saved in EEPROM
                                  const int setPositionEE = 4 ;									// eeprom location
                                  long openPosition = 0 ; 										// Position at open, need to be saved in EEPROM?
                                  const int openPositionEE = setPositionEE + 4 ;					// eeprom location
                                  long closedPosition = 120000UL ; 								// Position at full close, need to be saved in EEPROM
                                  const int closedPositionEE = openPositionEE + 4 ;				// eeprom location
                                  
                                  unsigned long idleTimer = millis() ;							// return to idle timer
                                  unsigned long idleTime = 100000UL ;								// return to idle after 100 secs
                                  
                                  unsigned long printTimer = millis() ;							// print timer
                                  unsigned long printTime = 1000UL ;								// print after 1 secs
                                  
                                  enum position_t {Open, Close, Idle, Running} ;
                                  position_t lastDirection = Open ; 								// lastDirection only for buttonpress
                                  position_t runStatus = Idle ;									// indicates current status for running motor. used for status reporting to controller
                                  
                                  enum State_t {sIdle, sCalibrateOpen, sCalibrateClose} ;
                                  State_t State = sIdle ;
                                  
                                  
                                  void setup() {
                                  	// setup buttons
                                  	pinMode(buttonPin1, OUTPUT);
                                  	stepper1.setMaxSpeed(2000.0);
                                  	stepper1.setAcceleration(1000.0);
                                  	//saveStateL(closedPositionEE, closedPosition) ; 			// INIT: save closed position in EEPROM
                                  	closedPosition = loadStateL(closedPositionEE) ;				// need to get last values from EEPROM and assume the current position is correct
                                  	setPosition = loadStateL(setPositionEE) ;
                                  	stepper1.setCurrentPosition(setPosition );
                                  }//--(end setup )---
                                  
                                  void presentation() {
                                    present(CHILD_ID, S_COVER, "Curtain");						// Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                                  
                                    // Register the LED Dimmable Light with the gateway
                                    sendSketchInfo(SN, SV);
                                  }
                                  
                                  
                                  void loop() {
                                  unsigned int now = millis() ;								// current time for loop
                                  // simple state machine for button press
                                  	myBtn.read();  
                                  	switch (State) {
                                          // Idle state, waiting for some action
                                  		// - button press
                                  		// - idleTimer
                                          case sIdle:                
                                              if (myBtn.wasReleased()){						// idle
                                  				Serial.println("Button release") ;
                                  				// if running stop
                                  				if (stepper1.isRunning()){
                                  					setPosition = stepper1.currentPosition();
                                  					stepper1.moveTo(setPosition) ;			// move to current position (was already there..)
                                  				} else if (lastDirection == Open) {
                                  					stepper1.moveTo(closedPosition) ;
                                  					lastDirection = Close ;
                                  				} else {									// lastDirection == Close
                                  					stepper1.moveTo(openPosition) ;
                                  					lastDirection = Open ;
                                  				}	
                                  			} else if (myBtn.pressedFor(3000)){				// move to calibratete state with long press
                                  				Serial.println("Button press long") ;
                                  				idleTimer = now ;							// return to idle after ...
                                  				State = sCalibrateOpen ;
                                  				stepper1.move(-maxRun) ;					// let the stepper open with maximum
                                  				}
                                  			break ;
                                  		// if not running and last action was open close ;  else open
                                  		// if longpress Calibrate open
                                          case sCalibrateOpen:           						// calibration going on     
                                  			if (myBtn.wasPressed()){
                                  				stepper1.setCurrentPosition(0 );		// set new 0 position ??
                                  				openPosition = setPosition = 0 ;
                                  				State = sCalibrateClose ;					// next is close calibarion
                                  				stepper1.move(maxRun) ;						// let the stepper close with maximum
                                  			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                                  				State = sIdle ;
                                  			}
                                  			break ;
                                          case sCalibrateClose:								// calibrate closed position, end with keypress
                                  			if (myBtn.wasPressed())	{
                                  				closedPosition = setPosition = stepper1.currentPosition() ;
                                  				saveStateL(closedPositionEE, closedPosition) ; // save closed position in EEPROM
                                  				State = sIdle ;
                                  				stepper1.moveTo(openPosition) ;				// return to open after calibration
                                  			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                                  				State = sIdle ;
                                  			}
                                  			break ;
                                  		default :
                                  			break ;
                                  		}
                                  	// power off stepper if not running (no need to reenable))
                                  	if (!stepper1.isRunning()){
                                  		if (runStatus != Idle){								// there was a change in runningstatus, so report to controller
                                  			setPosition = stepper1.currentPosition() ;		// store in EEPROM and report ready to controller
                                  			saveStateL(setPositionEE, setPosition) ;
                                  			send( percentageMsg.set((100 * setPosition)/(closedPosition - openPosition))) ;
                                  			runStatus = Idle ;
                                  		}
                                  		stepper1.disableOutputs();
                                  	} else {
                                  		runStatus = Running ;
                                  	}
                                  	stepper1.run();
                                  	/*
                                  	if (printTimer++ > now + printTime){
                                  		printTimer = now ;
                                  		Serial.println(stepper1.currentPosition());
                                  		}
                                  	*/
                                  }
                                  
                                  // This is called when a message is received 
                                  void receive(const MyMessage &message) {
                                  // We only expect few types of messages from controller, check which
                                    switch (message.type) {
                                  	case V_PERCENTAGE:
                                  	// Curtain should be opened
                                  	stepper1.moveTo(message.getInt() * (closedPosition - openPosition)/100);
                                  	Serial.print("Message: "); Serial.print(message.sensor); Serial.print(" , value: % "); Serial.println( message.getInt());
                                  	Serial.print("Moving to: "); Serial.println(message.getInt() * (closedPosition - openPosition)/100);
                                  	break ;
                                  	case V_STATUS:
                                  	// Curtain should be opened or closed full
                                  	stepper1.moveTo((message.getInt() == HIGH)?openPosition:closedPosition);
                                  	Serial.print("Message - valid: ");
                                  	Serial.print(message.sensor);
                                  	Serial.print(" , value: % ");
                                  	break ;
                                  	default : 
                                  	// not recognizable message
                                  	Serial.print("Message - valid: ");
                                  	Serial.print(message.sensor);
                                  	Serial.print(", Unrecognized ");
                                  	break ;
                                  	}
                                    }
                                  
                                  TON RIJNAARDT Offline
                                  TON RIJNAARDT Offline
                                  TON RIJNAARD
                                  wrote on last edited by
                                  #44

                                  @xydix
                                  Hello @xydix do you have the curtain working with the sketch above?
                                  I don't get the button working on pin 7.
                                  Witch button library do you use?
                                  I have the library witch is in the sketch, i only must change Bbutton.h in LC_Button.h.
                                  Is that maby my problem.
                                  I hope u can help me.
                                  Greatz Ton

                                  xydixX 1 Reply Last reply
                                  0
                                  • barduinoB barduino

                                    @Suresh-Mali

                                    DC Motor, very interesting!

                                    Do you have end stops? The sketch doesn't open for some reason...

                                    Cheers

                                    S Offline
                                    S Offline
                                    SENIORA
                                    wrote on last edited by
                                    #45

                                    @barduino said in Curtain Control Node.:

                                    @Suresh-Mali

                                    DC Motor, very interesting!

                                    Do you have end stops? The sketch doesn't open for some reason...

                                    Cheers

                                    I have been working on a similar project last week. The mechanics and ´looks´ are the most difficult part for me.

                                    1 Reply Last reply
                                    0
                                    • TON RIJNAARDT TON RIJNAARD

                                      @xydix
                                      Hello @xydix do you have the curtain working with the sketch above?
                                      I don't get the button working on pin 7.
                                      Witch button library do you use?
                                      I have the library witch is in the sketch, i only must change Bbutton.h in LC_Button.h.
                                      Is that maby my problem.
                                      I hope u can help me.
                                      Greatz Ton

                                      xydixX Offline
                                      xydixX Offline
                                      xydix
                                      wrote on last edited by
                                      #46

                                      @ton-rijnaard
                                      Hi. This was a problem for me to. The reason is the library changed name and updates was made.
                                      I use the library version 0.9.
                                      I have like zero skills in arduino. If you use the old library the button will work with the sketch i posted a moth ago.
                                      Looke here: https://github.com/JChristensen/JC_Button/releases
                                      Maybe some of the other older releases will work. Don't remember why o choose V0.9
                                      Look at 2.0.0, "This is a major release that is not backwards-compatible with previous releases."

                                      1 Reply Last reply
                                      0
                                      • xydixX xydix

                                        Okey. This is an old thread but I hope it's ok I keep it alive.
                                        I just printed som parts for my blinds.
                                        I use a stepper motor (28BYJ-48 with ULN2003 Driver board) and this sketch found in this thread.
                                        The sketch is awesome.
                                        To my quiestion.
                                        I want to run 2 blinds at the same time from ONE node. Synchronized or maybe individual.
                                        Is this possible?
                                        There isn't any digital pins over for this when using button(s).
                                        I think i saw someone using analog pin connected to the ULN2003 someware.
                                        Is it possible to run 2 motors on one board?
                                        Really hope somone can answer som of my question.
                                        What modifications is needed in the sketch if this is possible.
                                        This is the sketch I use.

                                        /*
                                         PROJECT: MY Sensors curtain controller
                                         PROGRAMMER: AWI
                                         DATE: march 11, 2016
                                         FILE: AWI stepper1.ino
                                         LICENSE: Public domain
                                        
                                         Hardware: ATMega328p board w/ NRF24l01
                                        	and MySensors 2.0 (Development)
                                        		
                                        Special:
                                        	uses AccelStepper library
                                        	
                                        Summary:
                                        	Curtain control with stepper motor. 
                                        	Manual operation with 1 push button 
                                        	Calibration with manual button
                                        
                                        Remarks:
                                        	Fixed node-id
                                        	
                                        Change log:
                                        20160312 - Cleanup
                                        */
                                        
                                        // Enable debug prints to serial monitor
                                        #define MY_DEBUG 
                                        
                                        #define MY_NODE_ID 13											// fixed node number
                                        // Enable and select radio type attached
                                        #define MY_RADIO_RF24
                                        //#define MY_RADIO_RFM69
                                        
                                        #include <SPI.h>
                                        #include <MySensors.h> 
                                        
                                        // stepper library
                                        #include <AccelStepper.h>										// http://www.airspayce.com/mikem/arduino/AccelStepper/
                                        #define HALFSTEP 8  											// Stepper uses "Halfstep" mode
                                        
                                        // button library
                                        // used for:
                                        // - manual open close - single click: close/ stop/ open/ stop
                                        // - calibration  - after long press: open calibarion- until single press - closed calibration - until single press (stop)
                                        #include <Button.h>												// https://github.com/JChristensen/Button
                                        
                                        #define CHILD_ID 1   											// Id of the sensor child
                                        
                                        #define SN "Curtain control 13"
                                        #define SV "1.0"
                                        
                                        #define buttonPin1 7  											// Arduino pin connected to buttonPin1
                                        #define buttonPin2 A0  											// Arduino pin connected to buttonPin2 (fixed to ground)
                                        
                                        // Motor pin definitions
                                        #define motorPin1  3     										// IN1 on the ULN2003 driver 1
                                        #define motorPin2  4     										// IN2 on the ULN2003 driver 1
                                        #define motorPin3  5     										// IN3 on the ULN2003 driver 1
                                        #define motorPin4  6     										// IN4 on the ULN2003 driver 1
                                        
                                        const unsigned long heartbeatInterval = 1 * 3600UL * 1000UL ;	// heartbeatinterval
                                        unsigned long heartbeatCounter = 0 ;
                                        
                                        //
                                        // helper routines to store and retrieve long in mysensors EEPROM
                                        union {															// used to convert long to bytes for EEPROM storage
                                        	long longInt;
                                        	uint8_t LongByte[4];
                                        	} convLongInt ;
                                        
                                        void saveStateL(int EEposition, long StateL){
                                        	convLongInt.longInt = StateL ;
                                        	for (int y = 0; y < 4 ; y++){								// convert to bytes
                                        		saveState(EEposition + y , convLongInt.LongByte[y]) ;
                                        		}
                                        	Serial.print("State saved: "); Serial.println(StateL);
                                        	}
                                        		
                                        long loadStateL(int EEposition){
                                        	for (int y = 0; y < 4 ; y++){								// convert from bytes
                                        		convLongInt.LongByte[y] = loadState(EEposition + y) ;
                                        		}
                                        	Serial.print("State read: "); Serial.println(convLongInt.longInt);
                                        	return convLongInt.longInt ;
                                        	}
                                        	
                                        
                                        // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
                                        AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
                                        // Initialize button active low, debounce and internal pull-up
                                        Button myBtn(buttonPin1, true, true, 40);						// Initiate the button (pin, pull_up, invert, debounce_ms)
                                        
                                        MyMessage percentageMsg(CHILD_ID, V_PERCENTAGE);				// used to send updates to controller
                                        
                                        const long maxRun = 4000000L ;									// maximum runway
                                        long setPosition = 0 ; 											// remembers set position, need to be saved in EEPROM
                                        const int setPositionEE = 4 ;									// eeprom location
                                        long openPosition = 0 ; 										// Position at open, need to be saved in EEPROM?
                                        const int openPositionEE = setPositionEE + 4 ;					// eeprom location
                                        long closedPosition = 120000UL ; 								// Position at full close, need to be saved in EEPROM
                                        const int closedPositionEE = openPositionEE + 4 ;				// eeprom location
                                        
                                        unsigned long idleTimer = millis() ;							// return to idle timer
                                        unsigned long idleTime = 100000UL ;								// return to idle after 100 secs
                                        
                                        unsigned long printTimer = millis() ;							// print timer
                                        unsigned long printTime = 1000UL ;								// print after 1 secs
                                        
                                        enum position_t {Open, Close, Idle, Running} ;
                                        position_t lastDirection = Open ; 								// lastDirection only for buttonpress
                                        position_t runStatus = Idle ;									// indicates current status for running motor. used for status reporting to controller
                                        
                                        enum State_t {sIdle, sCalibrateOpen, sCalibrateClose} ;
                                        State_t State = sIdle ;
                                        
                                        
                                        void setup() {
                                        	// setup buttons
                                        	pinMode(buttonPin1, OUTPUT);
                                        	stepper1.setMaxSpeed(2000.0);
                                        	stepper1.setAcceleration(1000.0);
                                        	//saveStateL(closedPositionEE, closedPosition) ; 			// INIT: save closed position in EEPROM
                                        	closedPosition = loadStateL(closedPositionEE) ;				// need to get last values from EEPROM and assume the current position is correct
                                        	setPosition = loadStateL(setPositionEE) ;
                                        	stepper1.setCurrentPosition(setPosition );
                                        }//--(end setup )---
                                        
                                        void presentation() {
                                          present(CHILD_ID, S_COVER, "Curtain");						// Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                                        
                                          // Register the LED Dimmable Light with the gateway
                                          sendSketchInfo(SN, SV);
                                        }
                                        
                                        
                                        void loop() {
                                        unsigned int now = millis() ;								// current time for loop
                                        // simple state machine for button press
                                        	myBtn.read();  
                                        	switch (State) {
                                                // Idle state, waiting for some action
                                        		// - button press
                                        		// - idleTimer
                                                case sIdle:                
                                                    if (myBtn.wasReleased()){						// idle
                                        				Serial.println("Button release") ;
                                        				// if running stop
                                        				if (stepper1.isRunning()){
                                        					setPosition = stepper1.currentPosition();
                                        					stepper1.moveTo(setPosition) ;			// move to current position (was already there..)
                                        				} else if (lastDirection == Open) {
                                        					stepper1.moveTo(closedPosition) ;
                                        					lastDirection = Close ;
                                        				} else {									// lastDirection == Close
                                        					stepper1.moveTo(openPosition) ;
                                        					lastDirection = Open ;
                                        				}	
                                        			} else if (myBtn.pressedFor(3000)){				// move to calibratete state with long press
                                        				Serial.println("Button press long") ;
                                        				idleTimer = now ;							// return to idle after ...
                                        				State = sCalibrateOpen ;
                                        				stepper1.move(-maxRun) ;					// let the stepper open with maximum
                                        				}
                                        			break ;
                                        		// if not running and last action was open close ;  else open
                                        		// if longpress Calibrate open
                                                case sCalibrateOpen:           						// calibration going on     
                                        			if (myBtn.wasPressed()){
                                        				stepper1.setCurrentPosition(0 );		// set new 0 position ??
                                        				openPosition = setPosition = 0 ;
                                        				State = sCalibrateClose ;					// next is close calibarion
                                        				stepper1.move(maxRun) ;						// let the stepper close with maximum
                                        			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                                        				State = sIdle ;
                                        			}
                                        			break ;
                                                case sCalibrateClose:								// calibrate closed position, end with keypress
                                        			if (myBtn.wasPressed())	{
                                        				closedPosition = setPosition = stepper1.currentPosition() ;
                                        				saveStateL(closedPositionEE, closedPosition) ; // save closed position in EEPROM
                                        				State = sIdle ;
                                        				stepper1.moveTo(openPosition) ;				// return to open after calibration
                                        			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                                        				State = sIdle ;
                                        			}
                                        			break ;
                                        		default :
                                        			break ;
                                        		}
                                        	// power off stepper if not running (no need to reenable))
                                        	if (!stepper1.isRunning()){
                                        		if (runStatus != Idle){								// there was a change in runningstatus, so report to controller
                                        			setPosition = stepper1.currentPosition() ;		// store in EEPROM and report ready to controller
                                        			saveStateL(setPositionEE, setPosition) ;
                                        			send( percentageMsg.set((100 * setPosition)/(closedPosition - openPosition))) ;
                                        			runStatus = Idle ;
                                        		}
                                        		stepper1.disableOutputs();
                                        	} else {
                                        		runStatus = Running ;
                                        	}
                                        	stepper1.run();
                                        	/*
                                        	if (printTimer++ > now + printTime){
                                        		printTimer = now ;
                                        		Serial.println(stepper1.currentPosition());
                                        		}
                                        	*/
                                        }
                                        
                                        // This is called when a message is received 
                                        void receive(const MyMessage &message) {
                                        // We only expect few types of messages from controller, check which
                                          switch (message.type) {
                                        	case V_PERCENTAGE:
                                        	// Curtain should be opened
                                        	stepper1.moveTo(message.getInt() * (closedPosition - openPosition)/100);
                                        	Serial.print("Message: "); Serial.print(message.sensor); Serial.print(" , value: % "); Serial.println( message.getInt());
                                        	Serial.print("Moving to: "); Serial.println(message.getInt() * (closedPosition - openPosition)/100);
                                        	break ;
                                        	case V_STATUS:
                                        	// Curtain should be opened or closed full
                                        	stepper1.moveTo((message.getInt() == HIGH)?openPosition:closedPosition);
                                        	Serial.print("Message - valid: ");
                                        	Serial.print(message.sensor);
                                        	Serial.print(" , value: % ");
                                        	break ;
                                        	default : 
                                        	// not recognizable message
                                        	Serial.print("Message - valid: ");
                                        	Serial.print(message.sensor);
                                        	Serial.print(", Unrecognized ");
                                        	break ;
                                        	}
                                          }
                                        
                                        xydixX Offline
                                        xydixX Offline
                                        xydix
                                        wrote on last edited by xydix
                                        #47

                                        @xydix
                                        To answer my own question the stepper runs fine from the analog pins.
                                        Next step is to find some intersted in the same thing and see if we could get the sketch adjusted to run two steppers.
                                        I will try when i get some time but I guess I will have problem to clone the calibration and store-to-eerprom-part.

                                        1 Reply Last reply
                                        0
                                        • AWIA AWI

                                          @patchmaster This is my current curtain control sketch. I work with the development branch, so the syntax can be a little different.

                                          The Accelstepper library gives you all the abilities to slow start/stop with numerous kinds of steppers.
                                          My sketch includes a calibration function (stored in EEPROM) so the you don't need end stop detection (a stepper knows where it is)

                                          /*
                                           PROJECT: MY Sensors curtain controller
                                           PROGRAMMER: AWI
                                           DATE: march 11, 2016
                                           FILE: AWI stepper1.ino
                                           LICENSE: Public domain
                                          
                                           Hardware: ATMega328p board w/ NRF24l01
                                          	and MySensors 2.0 (Development)
                                          		
                                          Special:
                                          	uses AccelStepper library
                                          	
                                          Summary:
                                          	Curtain control with stepper motor. 
                                          	Manual operation with 1 push button 
                                          	Calibration with manual button
                                          
                                          Remarks:
                                          	Fixed node-id
                                          	
                                          Change log:
                                          20160312 - Cleanup
                                          */
                                          
                                          // Enable debug prints to serial monitor
                                          #define MY_DEBUG 
                                          
                                          #define MY_NODE_ID 13											// fixed node number
                                          // Enable and select radio type attached
                                          #define MY_RADIO_NRF24
                                          //#define MY_RADIO_RFM69
                                          
                                          #include <SPI.h>
                                          #include <MySensor.h> 
                                          
                                          // stepper library
                                          #include <AccelStepper.h>										// http://www.airspayce.com/mikem/arduino/AccelStepper/
                                          #define HALFSTEP 8  											// Stepper uses "Halfstep" mode
                                          
                                          // button library
                                          // used for:
                                          // - manual open close - single click: close/ stop/ open/ stop
                                          // - calibration  - after long press: open calibarion- until single press - closed calibration - until single press (stop)
                                          #include <Button.h>												// https://github.com/JChristensen/Button
                                          
                                          #define CHILD_ID 1   											// Id of the sensor child
                                          
                                          #define SN "Curtain control 13"
                                          #define SV "1.0"
                                          
                                          #define buttonPin1 7  											// Arduino pin connected to buttonPin1
                                          #define buttonPin2 A0  											// Arduino pin connected to buttonPin2 (fixed to ground)
                                          
                                          // Motor pin definitions
                                          #define motorPin1  3     										// IN1 on the ULN2003 driver 1
                                          #define motorPin2  4     										// IN2 on the ULN2003 driver 1
                                          #define motorPin3  5     										// IN3 on the ULN2003 driver 1
                                          #define motorPin4  6     										// IN4 on the ULN2003 driver 1
                                          
                                          const unsigned long heartbeatInterval = 1 * 3600UL * 1000UL ;	// heartbeatinterval
                                          unsigned long heartbeatCounter = 0 ;
                                          
                                          //
                                          // helper routines to store and retrieve long in mysensors EEPROM
                                          union {															// used to convert long to bytes for EEPROM storage
                                          	long longInt;
                                          	uint8_t LongByte[4];
                                          	} convLongInt ;
                                          
                                          void saveStateL(int EEposition, long StateL){
                                          	convLongInt.longInt = StateL ;
                                          	for (int y = 0; y < 4 ; y++){								// convert to bytes
                                          		saveState(EEposition + y , convLongInt.LongByte[y]) ;
                                          		}
                                          	Serial.print("State saved: "); Serial.println(StateL);
                                          	}
                                          		
                                          long loadStateL(int EEposition){
                                          	for (int y = 0; y < 4 ; y++){								// convert from bytes
                                          		convLongInt.LongByte[y] = loadState(EEposition + y) ;
                                          		}
                                          	Serial.print("State read: "); Serial.println(convLongInt.longInt);
                                          	return convLongInt.longInt ;
                                          	}
                                          	
                                          
                                          // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
                                          AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
                                          // Initialize button active low, debounce and internal pull-up
                                          Button myBtn(buttonPin1, true, true, 40);						// Initiate the button (pin, pull_up, invert, debounce_ms)
                                          
                                          MyMessage percentageMsg(CHILD_ID, V_PERCENTAGE);				// used to send updates to controller
                                          
                                          const long maxRun = 4000000L ;									// maximum runway
                                          long setPosition = 0 ; 											// remembers set position, need to be saved in EEPROM
                                          const int setPositionEE = 4 ;									// eeprom location
                                          long openPosition = 0 ; 										// Position at open, need to be saved in EEPROM?
                                          const int openPositionEE = setPositionEE + 4 ;					// eeprom location
                                          long closedPosition = 120000UL ; 								// Position at full close, need to be saved in EEPROM
                                          const int closedPositionEE = openPositionEE + 4 ;				// eeprom location
                                          
                                          unsigned long idleTimer = millis() ;							// return to idle timer
                                          unsigned long idleTime = 100000UL ;								// return to idle after 100 secs
                                          
                                          unsigned long printTimer = millis() ;							// print timer
                                          unsigned long printTime = 1000UL ;								// print after 1 secs
                                          
                                          enum position_t {Open, Close, Idle, Running} ;
                                          position_t lastDirection = Open ; 								// lastDirection only for buttonpress
                                          position_t runStatus = Idle ;									// indicates current status for running motor. used for status reporting to controller
                                          
                                          enum State_t {sIdle, sCalibrateOpen, sCalibrateClose} ;
                                          State_t State = sIdle ;
                                          
                                          
                                          void setup() {
                                          	// setup buttons
                                          	pinMode(buttonPin1, OUTPUT);
                                          	stepper1.setMaxSpeed(2000.0);
                                          	stepper1.setAcceleration(1000.0);
                                          	//saveStateL(closedPositionEE, closedPosition) ; 			// INIT: save closed position in EEPROM
                                          	closedPosition = loadStateL(closedPositionEE) ;				// need to get last values from EEPROM and assume the current position is correct
                                          	setPosition = loadStateL(setPositionEE) ;
                                          	stepper1.setCurrentPosition(setPosition );
                                          }//--(end setup )---
                                          
                                          void presentation() {
                                            present(CHILD_ID, S_COVER, "Curtain");						// Window Cover sub-type, commands: V_UP, V_DOWN, V_STOP
                                          
                                            // Register the LED Dimmable Light with the gateway
                                            sendSketchInfo(SN, SV);
                                          }
                                          
                                          
                                          void loop() {
                                          unsigned int now = millis() ;								// current time for loop
                                          // simple state machine for button press
                                          	myBtn.read();  
                                          	switch (State) {
                                                  // Idle state, waiting for some action
                                          		// - button press
                                          		// - idleTimer
                                                  case sIdle:                
                                                      if (myBtn.wasReleased()){						// idle
                                          				Serial.println("Button release") ;
                                          				// if running stop
                                          				if (stepper1.isRunning()){
                                          					setPosition = stepper1.currentPosition();
                                          					stepper1.moveTo(setPosition) ;			// move to current position (was already there..)
                                          				} else if (lastDirection == Open) {
                                          					stepper1.moveTo(closedPosition) ;
                                          					lastDirection = Close ;
                                          				} else {									// lastDirection == Close
                                          					stepper1.moveTo(openPosition) ;
                                          					lastDirection = Open ;
                                          				}	
                                          			} else if (myBtn.pressedFor(3000)){				// move to calibratete state with long press
                                          				Serial.println("Button press long") ;
                                          				idleTimer = now ;							// return to idle after ...
                                          				State = sCalibrateOpen ;
                                          				stepper1.move(-maxRun) ;					// let the stepper open with maximum
                                          				}
                                          			break ;
                                          		// if not running and last action was open close ;  else open
                                          		// if longpress Calibrate open
                                                  case sCalibrateOpen:           						// calibration going on     
                                          			if (myBtn.wasPressed()){
                                          				stepper1.setCurrentPosition(0 );		// set new 0 position ??
                                          				openPosition = setPosition = 0 ;
                                          				State = sCalibrateClose ;					// next is close calibarion
                                          				stepper1.move(maxRun) ;						// let the stepper close with maximum
                                          			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                                          				State = sIdle ;
                                          			}
                                          			break ;
                                                  case sCalibrateClose:								// calibrate closed position, end with keypress
                                          			if (myBtn.wasPressed())	{
                                          				closedPosition = setPosition = stepper1.currentPosition() ;
                                          				saveStateL(closedPositionEE, closedPosition) ; // save closed position in EEPROM
                                          				State = sIdle ;
                                          				stepper1.moveTo(openPosition) ;				// return to open after calibration
                                          			} else if (now > idleTimer + idleTime) {		// timer expired -> abort calibration
                                          				State = sIdle ;
                                          			}
                                          			break ;
                                          		default :
                                          			break ;
                                          		}
                                          	// power off stepper if not running (no need to reenable))
                                          	if (!stepper1.isRunning()){
                                          		if (runStatus != Idle){								// there was a change in runningstatus, so report to controller
                                          			setPosition = stepper1.currentPosition() ;		// store in EEPROM and report ready to controller
                                          			saveStateL(setPositionEE, setPosition) ;
                                          			send( percentageMsg.set((100 * setPosition)/(closedPosition - openPosition))) ;
                                          			runStatus = Idle ;
                                          		}
                                          		stepper1.disableOutputs();
                                          	} else {
                                          		runStatus = Running ;
                                          	}
                                          	stepper1.run();
                                          	/*
                                          	if (printTimer++ > now + printTime){
                                          		printTimer = now ;
                                          		Serial.println(stepper1.currentPosition());
                                          		}
                                          	*/
                                          }
                                          
                                          // This is called when a message is received 
                                          void receive(const MyMessage &message) {
                                          // We only expect few types of messages from controller, check which
                                            switch (message.type) {
                                          	case V_PERCENTAGE:
                                          	// Curtain should be opened
                                          	stepper1.moveTo(message.getInt() * (closedPosition - openPosition)/100);
                                          	Serial.print("Message: "); Serial.print(message.sensor); Serial.print(" , value: % "); Serial.println( message.getInt());
                                          	Serial.print("Moving to: "); Serial.println(message.getInt() * (closedPosition - openPosition)/100);
                                          	break ;
                                          	case V_STATUS:
                                          	// Curtain should be opened or closed full
                                          	stepper1.moveTo((message.getInt() == HIGH)?openPosition:closedPosition);
                                          	Serial.print("Message - valid: ");
                                          	Serial.print(message.sensor);
                                          	Serial.print(" , value: % ");
                                          	break ;
                                          	default : 
                                          	// not recognizable message
                                          	Serial.print("Message - valid: ");
                                          	Serial.print(message.sensor);
                                          	Serial.print(", Unrecognized ");
                                          	break ;
                                          	}
                                            }
                                            
                                          
                                          
                                          
                                          
                                          A Offline
                                          A Offline
                                          adds666
                                          wrote on last edited by
                                          #48

                                          @AWI Sorry for butting in to an old thread, but automating my blinds is top priority!

                                          I've copied your sketch and have everything setup - however, I have eratic behaviour and a few questions:

                                          void setup() {
                                            // setup buttons
                                            pinMode(buttonPin1, OUTPUT);
                                            stepper1.setMaxSpeed(2000.0);
                                            stepper1.setAcceleration(1000.0);
                                            //saveStateL(closedPositionEE, closedPosition) ;      // INIT: save closed position in EEPROM
                                            closedPosition = loadStateL(closedPositionEE) ;       // need to get last values from EEPROM and assume the current position is correct
                                            setPosition = loadStateL(setPositionEE) ;
                                            stepper1.setCurrentPosition(setPosition );
                                          }//--(end setup )---
                                          
                                          • Should the pinMode on buttonPin1 actually be an INPUT?

                                          • Can you please describe how to go about calibrating the system?

                                          • Does the //saveStateL(closedPositionEE, closedPosition);
                                            need uncommenting for one boot of the arduino and the blind closed - then the sketch re-uploading with it commented again?

                                          Your help is greatly appreciated as I have a twitching motor and feel I'm almost there!

                                          xydixX 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          12

                                          Online

                                          11.7k

                                          Users

                                          11.2k

                                          Topics

                                          113.0k

                                          Posts


                                          Copyright 2019 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • MySensors
                                          • OpenHardware.io
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular