Motion controlled dimmable LED porch light



  • Hi all,

    Just wanted to show you all my motion-activated LED Porch Light. Lots of 12v LED lights on here, not so many mains AC-powered bulb projects, so I thought I'd show you mine. Sketch is a standard motion sensor interrupt sketch alongside a dimming sketch, I'm sure I got it from the forums. Initially I wanted it to perform local control of the lamp via the PIR but then decided I wanted the light to come on low (33%) from dusk till dawn, and then raise to 100% when it detects motion. Because of that I've left the control logic to Vera. Below about 30% the bulb shows an obvious unstable flicker so I don't go there! Dimming and ramp up/down is beautifully smooth.

    It consists of:

    Arduino Nano
    NRF24L01 radio
    HLK-PM01 240v AC>5v DC
    HC-SR501 (PIR)
    240v AC Phase control dimming circuit: http://www.ebay.com/itm/111764492631
    4w dimmable filament LED bulb
    Wall box with blanking plate

    0_1474834106449_IMG_20160925_202213_20160925210546985.jpg
    0_1474834122929_IMG_20160925_202525_20160925210615873.jpg

    https://youtu.be/g7UY0zDP7zU


  • MySensors Evangelist

    @pjblink thanks for sharing. This is exactly something I can use at my parents house. At the moment I use the security camera for motion detection 😉



  • No problem, happy I could have been of some help!

    What's nice is that mysensors triggers so fast that it grabs a security cam image from before the camera has caught up!! Excuse the driveway...

    0_1475011102917_1172682752.jpg



  • @pjblink what a great project perfect for my needs.

    Can you post the sketch please
    Thanks Doug



  • @5546dug Hi Doug,

    Here you go. Annoyingly my PIR seems to have died after a week or so. Hoping it's a faulty unit rather than anything to do with the circuit. I've ordered another, and will see how it holds up. It seems i can trigger it by touching the unit in places, but the PIR sensor itself is dead and not detecting anything.

    /*
    AC Light Control
    Uses up and down buttons to set levels
    makes use of a timer interrupt to set the level of dimming
    */
    #include <SPI.h>
    #include <MySensor.h>  
    #include <TimerOne.h>
    
    #define SN "AC LED Porch Dimmer Control"
    #define SV "1.3"
    #define NODE_ID 30  //change to a number to assign a specific ID
    #define FADE_DELAY 20  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
    #define MOTION_CHILD 1  //ID of the motion sensor child
    #define MOTION_PIN  2  // Arduino pin tied to trigger pin on the motion sensor.
    
    volatile int i=0;               // Variable to use as a counter of dimming steps. It is volatile since it is passed between interrupts
    volatile boolean zero_cross=0;  // Flag to indicate we have crossed zero
    int AC_pin = 7;                 // Output to Opto Triac
    int freqStep = 75;              // This is the delay-per-brightness step in microseconds. It allows for 128 steps
                                    // If using 60 Hz grid frequency set this to 65
    MySensor gw;
    
    //dimming
    static int currentLevel = 128;  // Current dim level...
    uint8_t fadeLevel = 128; //used to store the fade level when using the buttons
    
    //motion sensor
    uint8_t lastMotion = 0;
    unsigned long previousMillis = 0; // last time update //see http://stackoverflow.com/questions/10773425/performing-a-function-after-x-time for more details on this
    unsigned long motionDelay = 10000; // interval at which to keep motion sensor trippped (milliseconds).  Used to prevent too frequent updates to Vera. 
    
    boolean metric = true; 
    
    MyMessage dimmerMsg(AC_pin, V_DIMMER);
    MyMessage lightMsg(AC_pin, V_LIGHT);
    MyMessage motionMsg(MOTION_CHILD, V_TRIPPED);
    
    void setup() {  // Begin setup
      Serial.begin(115200);
      Serial.println( SN ); 
      gw.begin( incomingMessage,  NODE_ID, true);
      // Register the LED Dimmable Light with the gateway
      gw.present( 6, S_DIMMER );
      gw.sendSketchInfo(SN, SV);
      // Pull the gateway's current dim level - restore light level upon sendor node power-up
      gw.request( 6, V_DIMMER );
      gw.present(MOTION_CHILD, S_MOTION);
      
      //Setup AC PIN
      pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
      attachInterrupt(1, zero_cross_detect, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
      Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
      Timer1.attachInterrupt(dim_check, freqStep);      // Go to dim_check procedure every 75 uS (50Hz)  or 65 uS (60Hz)
      // Use the TimerOne Library to attach an interrupt
    }
    
    void zero_cross_detect() {    
      zero_cross = true;               // set flag for dim_check function that a zero cross has occured
      i=0;                             // stepcounter to 0.... as we start a new cycle
      digitalWrite(AC_pin, LOW);
    }                                 
    
    // Turn on the TRIAC at the appropriate time
    // We arrive here every 75 (65) uS
    // First check if a flag has been set
    // Then check if the counter 'i' has reached the dimming level
    // if so.... switch on the TRIAC and reset the counter
    
    void dim_check() {                   
      if(zero_cross == true) {              
        if(i>=fadeLevel) {                     
          digitalWrite(AC_pin, HIGH);  // turn on light       
          i=0;  // reset time step counter                         
          zero_cross=false;    // reset zero cross detection flag
                          } 
        else {
          i++;  // increment time step counter                     
        }                                
      }    
    }
    
    void loop() {  
        gw.process();
    
      //motion sensor code
      unsigned long currentMillis = millis();
      
         if(currentMillis - previousMillis > motionDelay){
          uint8_t motionDetect = digitalRead(MOTION_PIN);
            if(motionDetect != lastMotion){
    //        Serial.print("motionDetect Value: ");
    //        Serial.println(motionDetect);
              gw.send(motionMsg.set(motionDetect));  // Send tripped value to gw
              if(motionDetect == 1){
              previousMillis = currentMillis;  //"Tripped" delay 
              }
              else{
              previousMillis = currentMillis - motionDelay + 1000; //"Not tripped" delay for 1 second to stop rapid "not tripped" and "tripped" updates to Vera
              }
          lastMotion = motionDetect; 
        }    
      }
    }
    
    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT || message.type == V_DIMMER) {
        
        //  Retrieve the power or dim level from the incoming request message
        int requestedLevel = atoi( message.data );
        
        // Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on]
        requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
        
        // Clip incoming level to valid range of 0 to 100
        requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
        requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
        
        float percent_level;
        percent_level = 128 - (requestedLevel * 1.28);
        fadeToLevel( percent_level );
        Serial.print( "Changing level to " );
        Serial.print( requestedLevel );
        Serial.print( ", from " ); 
        Serial.println( currentLevel );
        // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
        //gw.send(lightMsg.set(currentLevel > 0 ? 1 : 0));
      
        // hek comment: Is this really nessesary?
        // gw.send( dimmerMsg.set(requestedLevel) );
      }
    }
    
    /***
     *  This method provides a graceful fade up/down effect
     */
    
    void fadeToLevel( int toLevel ) {
     Serial.print("currentLevel Value: ");
     Serial.println(currentLevel);
     Serial.print("toLevel Value: ");
     Serial.println(toLevel);
    
      int delta = ( currentLevel - toLevel ) < 0 ? 1 : -1;
      Serial.print("delta Value: ");
     Serial.println(delta);
      while ( currentLevel != toLevel ) {
        currentLevel += delta;
    
     fadeLevel= ((int)currentLevel);
        delay( FADE_DELAY );
        //fadeLevel = toLevel;
      }
    }```


  • thanks @pjblink , I get lots of errors just wondering before I do anything, was this sketch wrote for 1.5or 2.0?
    this is probably my issue as I still run 1.4.1
    but thought I would run it past you first.

    thx doug



  • @pjblink :
    Did you use any fuses between the 240v and the 220 > 5v module?
    Could you post a picture of the backside of your perfboard? I'm interested in how you wired everything up 🙂


Log in to reply
 

Suggested Topics

  • 8
  • 1
  • 5
  • 1
  • 7
  • 90

17
Online

11.4k
Users

11.1k
Topics

112.7k
Posts