Dimmable led actuator sketch enhancement


  • Hero Member

    Hello,

    I've been working on a simple mod of the dimmable led actuator available in the examples folder.

    I needed a few things that were not included, like the ability to set a more precise fade level, make longer fades and also being able to change those fade times dynamically.

    Also, as a result of longer dafe times, I had to modify the sketch so the node is still able to send/receive messages during fade time.

    You could send messages from VERA this way:

    luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {radioId="6;100", variableId="DIMMER", value="100,25"}, 130)
    

    This message is sent to node id 6, with parent node id 130, and tells the node to fade to 100% in 25 seconds.
    You could choose any number (0-100) to fade to, instead of the 10% increment Vera offers. Also the old functionality remains working as before.

    Here's the sketch in case someone is interested:

    /***
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     * 
     * DESCRIPTION
     * This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad 
     * <henrik.ekblad@gmail.com> Vera Arduino Sensor project.  
     * Developed by Bruce Lacey, inspired by Hek's MySensor's example sketches.
     * 
     * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip.  
     * The MOSFET Gate pin is connected to Arduino pin 3 (LED_PIN), the MOSFET Drain pin is connected
     * to the LED negative terminal and the MOSFET Source pin is connected to ground.  
     *
     * This sketch is extensible to support more than one MOSFET/PWM dimmer per circuit.
     *
     * REVISION HISTORY
     * Version 1.0 - February 15, 2014 - Bruce Lacey
     * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek) 
     * Version 1.2 - April 13, 2015 - Added long dynamic and precise fade, also made fade non exclusive (ferpando)
     ***/
     
     #include <Time.h> 
     
    #define SN "DimmableLED"
    #define SV "1.2"
    
    #include <MySensor.h> 
    #include <SPI.h>
    
    #define LED_PIN 5      // Arduino pin attached to MOSFET Gate pin
    
    MySensor gw(9,10);
    
    static int currentLevel = 0;  // Current dim level...
    static int requestedLevel = 0;
    
    MyMessage dimmerMsg(0, V_DIMMER);
    MyMessage lightMsg(0, V_LIGHT);
    
    int FADE_DELAY;   // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
    
    /***
     * Dimmable LED initialization method
     */
    void setup()  
    { 
      Serial.println( SN ); 
      gw.begin( incomingMessage );
      
      // Register the LED Dimmable Light with the gateway
      gw.present( 0, S_DIMMER );
      
      gw.sendSketchInfo(SN, SV);
      // Pull the gateway's current dim level - restore light level upon sendor node power-up
      gw.request( 0, V_DIMMER );
    
    }
    
    /***
     *  Dimmable LED main processing loop 
     */
    void loop() 
    {
      gw.process();
      fadeToLevel();
      // if delay is too long, it might stop the node from receiving/sending more messages for a long time.
      //doing it this way, the node can keep functioning regardless fade completition.
    }
    
    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT || message.type == V_DIMMER) {
        
        if(message.sensor == 100 ){ //fade special, addressed to node 100
          // Message payload: value to fade to, seconds to fade     example: "20,10"
          
          int commaIndex = msg.indexOf(',');
    
          String firstValue = msg.substring(0, commaIndex);
          String secondValue = msg.substring(commaIndex+1);
    
          requestedLevel=firstValue.toInt();
          int steps=abs(currentLevel-requestedLevel);
    
          if(commaIndex == -1){
             FADE_DELAY=10;
          }else { 
             FADE_DELAY = 1000* secondValue.toInt() / steps;
          }
        }else { //fade normal
        
              FADE_DELAY=10;
              //  Retrieve the power or dim level from the incoming request message
              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;
              
              }
           
          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(currentLevel) );
        
        }
    }
    
    /***
     *  This method provides a graceful fade up/down effect
     */
    void fadeToLevel() {
    
      if ( currentLevel != requestedLevel ) {
        int delta = ( requestedLevel - currentLevel ) < 0 ? -1 : 1;
      
        currentLevel += delta;
        Serial.print( "analog write: " );
        Serial.println( currentLevel / 100. * 255 );
        analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) );
        delay( FADE_DELAY );
      }
      
    }
    

  • Hero Member

    A few bug fixes and also this sends back to gateway the value of 'requestedValue' instead of 'currentValue' as I think it should be.
    Delays and precise setpoint are now correct.

    /***
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     * 
     * DESCRIPTION
     * This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad 
     * <henrik.ekblad@gmail.com> Vera Arduino Sensor project.  
     * Developed by Bruce Lacey, inspired by Hek's MySensor's example sketches.
     * 
     * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip.  
     * The MOSFET Gate pin is connected to Arduino pin 3 (LED_PIN), the MOSFET Drain pin is connected
     * to the LED negative terminal and the MOSFET Source pin is connected to ground.  
     *
     * This sketch is extensible to support more than one MOSFET/PWM dimmer per circuit.
     *
     * REVISION HISTORY
     * Version 1.0 - February 15, 2014 - Bruce Lacey
     * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek) 
     * Version 1.2 - April 13, 2015 - Added long dynamic and precise fade, also made fade non exclusive (ferpando)
     ***/
     
     #include <Time.h> 
     
    #define SN "DimmableLED"
    #define SV "1.2"
    
    #include <MySensor.h> 
    #include <SPI.h>
    
    #define LED_PIN 5      // Arduino pin attached to MOSFET Gate pin
    
    MySensor gw(9,10);
    
    static int currentLevel = 0;  // Current dim level...
    static int requestedLevel = 0;
    boolean preciseFade = false;
    
    MyMessage dimmerMsg(0, V_DIMMER);
    MyMessage lightMsg(0, V_LIGHT);
    
    int FADE_DELAY;   // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
    
    /***
     * Dimmable LED initialization method
     */
    void setup()  
    { 
      Serial.println( SN ); 
      gw.begin( incomingMessage );
      
      // Register the LED Dimmable Light with the gateway
      gw.present( 0, S_DIMMER );
      
      gw.sendSketchInfo(SN, SV);
      // Pull the gateway's current dim level - restore light level upon sendor node power-up
      gw.request( 0, V_DIMMER );
    
    }
    
    /***
     *  Dimmable LED main processing loop 
     */
    void loop() 
    {
      gw.process();
      fadeToLevel();
      // if delay is too long, it might stop the node from receiving/sending more messages for a long time.
      //doing it this way, the node can keep functioning regardless fade completition.
    }
    
    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT || message.type == V_DIMMER) {
        int steps;
        int multiplier;
        if(message.sensor == 100 ){ //fade special, addressed to node 100
          // Message payload: value to fade to, seconds to fade     example: "20,10"
          preciseFade = true;
          String msg=message.getString();
          
          int commaIndex = msg.indexOf(',');
    
          String firstValue = msg.substring(0, commaIndex);
          String secondValue = msg.substring(commaIndex+1);
    
          requestedLevel=firstValue.toInt();
          steps = currentLevel-requestedLevel;
          multiplier = abs(1000 / steps);
          if(commaIndex == -1){
             FADE_DELAY=multiplier * 10;
          }else { 
             FADE_DELAY = multiplier * secondValue.toInt();
          }
        }else { //fade normal
              preciseFade = false;
              steps = currentLevel-requestedLevel;
              multiplier = abs(1000 / steps);
              FADE_DELAY=multiplier * 10;
              //  Retrieve the power or dim level from the incoming request message
              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;
              
              }
              
        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(requestedLevel > 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() {
      
      if ( currentLevel != requestedLevel ) {
        int pwmLevel;
        int delta = ( requestedLevel - currentLevel ) < 0 ? -1 : 1;
        currentLevel += delta;
        Serial.print( "analog write: " );
        if(preciseFade){ //set to specific number
            pwmLevel = (int)currentLevel;
            }else  { //set to 10% increment level
               pwmLevel=(int)(currentLevel / 100. * 255);
               }
      Serial.println( pwmLevel );
      analogWrite( LED_PIN, pwmLevel );
      delay( FADE_DELAY );
      }
    }
    


  • Can this be expanded to include 2-3 more outputs?


  • Hero Member

    @ferpando I maybe misinterpreting things but for me it looks like the "fadeToLevel" is still blocking with respect to the receipt of messages for a time as long as FADE_DELAY. would suggest making it non-blocking by means of a time counter.

    like

    // timer value for "once in a while" events
        unsigned long now = millis();
        gw.process() ;								// process MySensors messages (needed for repeater)
        // Read/update every "delay" (60) seconds
        if (now-lastUpdate > 60000) {
    		read_sensors();
    		lastUpdate = now;
        }
    

  • Hero Member

    @AWI
    You are right but now the blocking is just a few milliseconds instead of the whole fade time.
    I think messages are still received because the are interrupt driven, so in the next cycle message will arrive.
    You will be just delaying a few millis sending new messages.

    Your solutions is indeed an improvement to be considered.
    In my case I don't need that much control.


  • Hero Member

    @Drcashman
    by outputs you mean to control 2-3 light fades?
    I guess it wouldn't be too difficult. Just add counters for current and requested values for each fade to keep them independent


Log in to reply
 

Suggested Topics

25
Online

11.2k
Users

11.1k
Topics

112.5k
Posts