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. Plantation Shutters - Auto\Lux\ Motorized 1.4b1

Plantation Shutters - Auto\Lux\ Motorized 1.4b1

Scheduled Pinned Locked Moved My Project
diyservowooddifficultsensor
11 Posts 6 Posters 15.5k Views 1 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.
  • hekH Offline
    hekH Offline
    hek
    Admin
    wrote on last edited by
    #2

    Nice, thanks for sharing @blong!

    Looking forward to see pictures of your multi sensor/actuator.

    1 Reply Last reply
    1
    • YveauxY Offline
      YveauxY Offline
      Yveaux
      Mod
      wrote on last edited by
      #3

      Nice work! Especially the part where messages from the gateway are interpreted will be helpful to some people as we get a lot of questions on this :+1:

      http://yveaux.blogspot.nl

      1 Reply Last reply
      0
      • blongB blong

        I typically lurk on these sites, but I conducted so much research on this project that I felt that I should share and contribute back to this excellent platform by @hek. * Please take it easy on me, as I am a former website designer and a current hobby programmer. * This was not an easy project for me and it took plenty of time, research and new tools! This project is certainly not for the faint of heart, but the WAF is outstanding once completed! I will update this post with video/pictures at a later date. Special thanks to @naveen for his excellent examples that got me started (and finished). I would truly appreciate any updates or modifications that you can provide to make this code more efficient!

        See code below:

        /*
        Description: Sensor to control 2 or more servos and light sensor.  Manual and lux sensor feedback changes shutter position.
        Sensor type: Adafruit TSL2561 luminosity sensor 
        Servo type:  Hitec HS-5645MG High Torque, Metal Gear Digital Sport Servo
        Controllers: Arduino Nano v3.1 / Veralite UI5
        
        Websites:    https://learn.adafruit.com/tsl2561
        			 http://homeawesomation.wordpress.com/2013/02/26/automated-window-blinds-with-arduino/
        			 https://github.com/ssshake/arduino/blob/master/autoblinds-0.5.ino
        			 http://hitecrcd.com/products/servos/sport-servos/digital-sport-servos/hs-5645mg-high-torque-metal-gear-servo/product
        		  
        Libraries: Adafruit sensor libraries are required for this sketch at the above URL.
        
        Acknowledgements: 
        
        Sketch is adapted from multiple resources and is shared in order to minimize your learning curve.
        Thanks to everyone who has contibuted directly and indirectly!  Please feel free to use and distribute this sketch at your own risk! 
        BPL 7/31/2014
        */
        
        #include <SPI.h>
        #include <Wire.h>
        #include <Servo.h>
        #include <MySensor.h>
        #include <Adafruit_Sensor.h>
        #include <Adafruit_TSL2561_U.h>
        
        #define servos 2
        #define servo_min 900 // Fine tune your servos min. 900-2100
        #define servo_max 2100  // Fine tune your servos max. 900-2100
        #define detach_delay 1500 // Tune this to let your movement finish before detaching the servo
        #define child_id_light servos
        #define servo_west 0
        #define servo_west_pin 6
        #define servo_east 1
        #define servo_east_pin 5
        
        MySensor gw;
        MyMessage servo_msg;
        MyMessage lux_msg(child_id_light, V_LIGHT_LEVEL);
        
        Adafruit_TSL2561_Unified lightsensor = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);
        Servo myservo[servos] = Servo();
        
        // Configuration Settings
        int servoPin[servos] = {servo_east_pin, servo_west_pin};  // Input pin for servo
        int lastPos = 0;  // variable to store the servo position
        int detension_val = 12;
        int spd[10] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50};     // how fast should the servo move? 50 is quiet
        bool attachedServo = false;
        bool auto_lux_shutters = true;
        
        uint16_t lux;
        uint16_t lastlux;
        int state = 0; //Keep track of state so we don't send signal to the servo without reason
        int prevstate = 0; //Keeps history of prior state
        int servo_time_base = 0;
        int lux_read_delay = 25000;
        int lux_time_base = 0;
        
        /**************************************************************************/
        /*   Configures all sensors                                               */
        /**************************************************************************/
        void setup()
        {
          gw.begin(incomingMessage);                  // Attach method for incoming messages
          gw.sendSketchInfo("Shutters", "2.0");       // Send Sketch information
          gw.present(child_id_light, S_LIGHT_LEVEL);  // Create child device (Lux sensor)
        
          /* Initialise the sensor */
          if (lightsensor.begin()) {
        	/*
        	Best resolution time is also slowest (402ms = 16-bit data)
        	lightsensor.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);   /* fast but low resolution
        	lightsensor.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);  /* 16-bit data but slowest conversions
        	*/
        	lightsensor.enableAutoRange(true);                              // Auto-gain; switches automatically between 1x and 16x
        	lightsensor.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS);  // medium resolution and speed
          }
          else {
        	Serial.println("Sensor not working!?");
          }
        
          for (int servo = 0; servo <= servos - 1; servo++) {
        	MyMessage servo_msg(servo, V_DIMMER);
        	gw.present(servo, S_COVER);     // Create child devices
        	gw.request(servo, V_DIMMER);    // Request previous state
        	delay(500);
          }
        }
        
        void loop()
        {
          gw.process();
        
          sensors_event_t event;           // Get a new sensor event
          lightsensor.getEvent(&event);
          uint16_t lux = event.light;      // Get Lux value;
        
          if (lux != lastlux) {
        	int rotate_value;
        	Serial.print("[Lux auto-sense routine] ");
        
        	/*
        	Illumination Examples
        	from https://learn.adafruit.com/photocells/measuring-light
        
        	0.002 lux    Moonless clear night sky
        	0.2 lux	 Design minimum for emergency lighting (AS2293).
        	0.27 - 1 lux Full moon on a clear night
        	3.4 lux	 Dark limit of civil twilight under a clear sky
        	*/
        	if (lux >= 0 && lux < 50) {
        	  //      Serial.print("Night or very low light");
        	  rotate_value = 2100;
        	  state = 1;
        	}
        
        	/*
        	50 lux	 Family living room
        	80 lux	 Hallway/toilet
        	*/
        	else if ( lux >= 50 && lux < 100) {
        	  Serial.print("Dusk or Family living room");
        	  rotate_value = 1785;
        	  state = 2;
        	}
        
        	/*
        	100 lux        Very dark overcast day
        	300 - 500 lux  Sunrise or sunset on a clear day. Well-lit office area.
        	*/
        	else if (lux >= 100 && lux < 500) {
        	  Serial.print("Very dark overcast day");
        	  rotate_value = 1500;
        	  state = 3;
        	}
        
        	/*
        	1,000 lux      Overcast day; typical TV studio lighting
        	*/
        	else if (lux >= 500 && lux < 10000) {
        	  Serial.print("Overcast Day or Indoor Studio");
        	  rotate_value = 1155;
        	  state = 4;
        	}
        
        	/*
        	10,000 - 25,000 lux    Full daylight (not direct sun)
        	*/
        	else if (lux >= 10000 && lux < 25000) {
        	  Serial.print("Indirect Sunlight");
        	  rotate_value = 1365;
        	  state = 5;
        	}
        
        	/*
        	32,000 - 130,000 lux    Direct sunlight
        	*/
        	else if (lux >= 25000 && lux < 40000) {
        	  Serial.print("Full Direct Sunlight");
        	  rotate_value = 1575;
        	  state = 6;
        	}
        
        	Serial.println("");
        
        	// Execute servo controls when state changes
        	if (state != prevstate && auto_lux_shutters) {
        	  luxAutoUpdate(rotate_value);
        	  gw.send(lux_msg.set(lux));
        	  lux_time_base = millis();
        	}
          }
        
          //  Serial.print("Update lux value: "); Serial.println(lux);
        
          prevstate = state; //Save state so we can compare it again
          lastlux = lux;
        
          if (attachedServo && millis() - servo_time_base > detach_delay) {
        	for (int servo = 0; servo <= servos - 1; servo++) {
        	  myservo[servo].detach();
        
        	  if (millis() - lux_time_base > lux_read_delay) {
        		auto_lux_shutters = true;
        	  }
        	  else {
        		auto_lux_shutters = false;
        	  }
        
        	  attachedServo = false;
        	  Serial.println("Servos detached");
        	}
          }
        }
        
        long detension(int delay_time, int det_val, bool isClockwiseRotation) {
          // Reduce Stress on servo
          int destination;
        
          if (isClockwiseRotation) {
        	// Serial.println("    CW rotation >>>");
        	destination = lastPos - det_val;
          } else if (!isClockwiseRotation) {
        	// Serial.println("    CCW rotation <<<");
        	destination = lastPos + det_val;
          }
        
          if (destination != lastPos) {
        	delay(delay_time);
        	myservo[servo_west].writeMicroseconds(destination);
        	myservo[servo_east].writeMicroseconds(destination);
          }
          else {
        	Serial.println("New destination is same as last position.");
          }
        
          // Report completed time
          return millis();
        }
        
        void incomingMessage(const MyMessage & message) {
          // Disable lux sensor
          Serial.println("[incomingMessage]");
          auto_lux_shutters = false;
        
          int servoVal = map(message.getInt(), 0, 100, servo_min, servo_max);
          int pluginVal = servoVal;
          bool isClockwiseRotation;
        
          for (int servo = 0; servo <= servos - 1; servo++) {
        	if (!myservo[servo].attached()) {
        	  myservo[servo].attach(servoPin[servo], servo_min, servo_max);
        	  lastPos = myservo[servo].readMicroseconds();
        	}
        	attachedServo = true;
          }
        
          if (message.type == V_DIMMER) {
        	if (servoVal <= lastPos) {
        	  for (int pos = lastPos; pos >= servoVal && pos >= servo_min; pos -= 1)
        	  {
        		myservo[servo_west].writeMicroseconds(pos);
        		myservo[servo_east].writeMicroseconds(pos);
        		delay(spd[4]); lastPos = pos;
        	  }
        	  pluginVal = map(servoVal, servo_min, servo_max, 0, 100);
        	  isClockwiseRotation = false;
        	}
        	else if (servoVal > lastPos) {
        	  for (int pos = lastPos; pos <= servoVal && pos <= servo_max; pos += 1)
        	  {
        		myservo[servo_west].writeMicroseconds(pos);
        		myservo[servo_east].writeMicroseconds(pos);
        		delay(spd[3]); lastPos = pos;
        	  }
        	  pluginVal = map(servoVal, servo_min, servo_max, 0, 100);
        	  isClockwiseRotation = true;
        	}
        
        	// Reduce Stress on servo
        	servo_time_base = detension(500, detension_val, isClockwiseRotation);
          }
        
          else if (message.type == V_DOWN) {
        	Serial.println("Servo down command");
        	for (int pos = lastPos; pos <= servoVal && pos <= servo_max; pos += 1)
        	{
        	  myservo[servo_west].writeMicroseconds(servo_max);
        	  myservo[servo_east].writeMicroseconds(servo_max);
        	  delay(spd[2]); lastPos = pos;
        	}
        	isClockwiseRotation == true;
        	pluginVal = map(servo_max, servo_min, servo_max, 0, 100);
        
        	// Reduce Stress on servo
        	servo_time_base = detension(200, 5, isClockwiseRotation);
        
          } else if (message.type == V_UP) {
        	Serial.println("Servo up command");
        	for (int pos = lastPos; pos >= servoVal && pos >= servo_min; pos -= 1)
        	{
        	  myservo[servo_west].writeMicroseconds(servo_max);
        	  myservo[servo_east].writeMicroseconds(servo_max);
        	  delay(spd[1]); lastPos = pos;
        	}
        	isClockwiseRotation == false;
        	pluginVal = map(servo_min, servo_min, servo_max, 0, 100);
        
        	// Reduce Stress on servo
        	servo_time_base = detension(250, 5, isClockwiseRotation);
          } else if (message.type == V_STOP) {
        	Serial.println("Servo stop command");
        	for (int servo = 0; servo <= servos - 1; servo++) {
        	  myservo[servo].detach();
        	  attachedServo = false;
        	}
          }
        
          for (int servo = 0; servo <= servos - 1; servo++) {
        	MyMessage servo_msg(servo, V_DIMMER);
        	gw.send(servo_msg.set(pluginVal));
          }
        }
        
        void luxAutoUpdate(int servoVal) {
          Serial.println("[luxAutoUpdate]");
          int pluginVal = map(servoVal, servo_min, servo_max, 0, 100);
          bool isClockwiseRotation;
        
          if (auto_lux_shutters) {
        	for (int servo = 0; servo <= servos - 1; servo++) {
        	  if (!myservo[servo].attached()) {
        		myservo[servo].attach(servoPin[servo], servo_min, servo_max);
        		attachedServo = true;
        	  }
        	  lastPos = myservo[servo].readMicroseconds();
        	}
        
        	if (servoVal <= lastPos) {
        	  for (int pos = lastPos; pos >= servoVal && pos >= servo_min; pos -= 1)
        	  {
        		myservo[servo_west].writeMicroseconds(pos);
        		myservo[servo_east].writeMicroseconds(pos);
        		delay(spd[3]); lastPos = pos;
        	  }
        	  isClockwiseRotation = true;
        	}
        	else if (servoVal > lastPos) {
        	  for (int pos = lastPos; pos <= servoVal && pos <= servo_max; pos += 1)
        	  {
        		myservo[servo_west].writeMicroseconds(pos);
        		myservo[servo_east].writeMicroseconds(pos);
        		delay(spd[3]); lastPos = pos;
        	  }
        	  isClockwiseRotation = false;
        	}
        
        	for (int servo = 0; servo <= servos - 1; servo++) {
        	  MyMessage servo_msg(servo, V_DIMMER);
        	  gw.send(servo_msg.set(pluginVal));
        	}
        
        	// Reduce Stress on servo
        	servo_time_base = detension(350, detension_val, isClockwiseRotation);
          }
          else {
        	Serial.print("Auto-shutter sensor is disabled at this time.");
          }
        }
        

        Pictures of project setup and Vera screenshot:

        servo disguised.jpg
        Nano Controller.jpg
        Lux sensor contolling automated angles.jpg
        inside view.jpg
        vera screenshot.jpg

        Short videos below:

        link text

        link text

        N Offline
        N Offline
        naveen
        wrote on last edited by
        #4

        @blong

        Hey! Cool to see you translated your project over to integrate with Vera - you were using a self contained sensor/actuator before right?

        blongB 1 Reply Last reply
        0
        • N naveen

          @blong

          Hey! Cool to see you translated your project over to integrate with Vera - you were using a self contained sensor/actuator before right?

          blongB Offline
          blongB Offline
          blong
          wrote on last edited by
          #5

          @naveen No, this was a build from the ground up. From routering the servos into the shutters to compiling the code. The project has been completed for a full day now and works great. Thanks for your encouragement and code guidance...

          N 1 Reply Last reply
          1
          • blongB blong

            @naveen No, this was a build from the ground up. From routering the servos into the shutters to compiling the code. The project has been completed for a full day now and works great. Thanks for your encouragement and code guidance...

            N Offline
            N Offline
            naveen
            wrote on last edited by
            #6

            @blong

            Nice! Please do post videos of its operation when you get a chance!

            blongB 1 Reply Last reply
            0
            • N naveen

              @blong

              Nice! Please do post videos of its operation when you get a chance!

              blongB Offline
              blongB Offline
              blong
              wrote on last edited by blong
              #7

              @naveen @hek pics posted, but video wouldn't upload in .mov format... Also, I plan on building a 3D case for the controller. I think I am just going to enjoy my work for now though :)

              hekH 1 Reply Last reply
              0
              • blongB blong

                @naveen @hek pics posted, but video wouldn't upload in .mov format... Also, I plan on building a 3D case for the controller. I think I am just going to enjoy my work for now though :)

                hekH Offline
                hekH Offline
                hek
                Admin
                wrote on last edited by
                #8

                @blong said:

                @hek pics posted, but video wouldn't upload in .mov format.

                Post movie to youtube and put the link to your movie here (it will be embedded).

                1 Reply Last reply
                0
                • blongB Offline
                  blongB Offline
                  blong
                  wrote on last edited by blong
                  #9

                  Videos are now posted! Forgive the shaky hand! @hek @naveen

                  1 Reply Last reply
                  1
                  • JohnJ Offline
                    JohnJ Offline
                    John
                    Plugin Developer
                    wrote on last edited by
                    #10

                    This one is very cool, especially the slow shutters movement...

                    My Domotica project: http://www.pidome.org

                    1 Reply Last reply
                    0
                    • RJ_MakeR Offline
                      RJ_MakeR Offline
                      RJ_Make
                      Hero Member
                      wrote on last edited by
                      #11

                      Very Cool -- Thanks

                      RJ_Make

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


                      20

                      Online

                      11.7k

                      Users

                      11.2k

                      Topics

                      113.1k

                      Posts


                      Copyright 2025 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