Dimmable led actuator sketch enhancement
-
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 ); } } -
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 ); } } -
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 ); } }@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; } -
@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; }@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. -
@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
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login