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 ); } }
-
Can this be expanded to include 2-3 more outputs?
-
@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