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


 

214
Online

8.6k
Users

9.4k
Topics

99.0k
Posts