RGB LED strip



  • I built a RGB LED strip controllable via mysensor, based on a 12V RGB LED strip and three IRF540 MOSFETs. The arduino is a 5V pro mini clone that I feed with 12V on the RAW pin.

    I followed the guide on https://learn.adafruit.com/rgb-led-strips/usage for wiring the MOSFETS and the LED strip. I used the Newbie PCB by @sundberg84 for holding the arduino and the radio, but put the MOSFETs on a separate prototyping board (maybe next time I'll try to solder them to the prototyping area of the Newbie PCB).

    I implemented a fading feature in the sketch, so it can fade slowly between colors or on/off. The speed is controlled by sending a V_VAR1 message with the speed (typical value could be around 200-300 for a nice effect). Speed = 0 means fading is off.

    Here is the code:

    /**
     * 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.
     *
     * LED STRIP sketch for Mysensors
     *******************************
     *
     * REVISION HISTORY
     * 1.0 
     *   Based on the example sketch in mysensors
     * 1.1
     *   fadespeed parameter (send as V_VAR1 message)
     *   HomeAssistant compatible (send status to ack)
     */
    
    #define MY_OTA_FIRMWARE_FEATURE
    #define MY_NODE_ID AUTO
    
    #define MY_RADIO_NRF24
    
    #include <MySensors.h>
    
    #define CHILD_ID_LIGHT 1
    
    #define SN "LED Strip"
    #define SV "1.1"
    
    MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
    MyMessage rgbMsg(CHILD_ID_LIGHT, V_RGB);
    MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
    
    byte red = 255;
    byte green = 255;
    byte blue = 255;
    byte r0 = 255;
    byte g0 = 255;
    byte b0 = 255;
    char rgbstring[] = "ffffff";
    
    int on_off_status = 0;
    int dimmerlevel = 100;
    int fadespeed = 0;
    
    #define REDPIN 6
    #define GREENPIN 5
    #define BLUEPIN 3
    
    void setup()
    {
      // Fix the PWM timer. Without this the LEDs will flicker.
      TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
    
      // Output pins
      pinMode(REDPIN, OUTPUT);
      pinMode(GREENPIN, OUTPUT);
      pinMode(BLUEPIN, OUTPUT);
      
    }
    
    void presentation()
    {
    	// Send the Sketch Version Information to the Gateway
    	sendSketchInfo(SN, SV);
    	present(CHILD_ID_LIGHT, S_RGB_LIGHT);
    }
    
    void loop()
    {
      static bool first_message_sent = false;
      if ( first_message_sent == false ) {
        Serial.println( "Sending initial state..." );
        set_hw_status();
        send_status();
        first_message_sent = true;
      }
    }
    
    void receive(const MyMessage &message)
    {
      int val;
      
    	if (message.type == V_RGB) {
    		Serial.println( "V_RGB command: " );
        Serial.println(message.data);
        long number = (long) strtol( message.data, NULL, 16);
    
        // Save old value
        strcpy(rgbstring, message.data);
        
        // Split it up into r, g, b values
        red = number >> 16;
        green = number >> 8 & 0xFF;
        blue = number & 0xFF;
    
        send_status();
        set_hw_status();
    
    	} else if (message.type == V_LIGHT || message.type == V_STATUS) {
        Serial.println( "V_LIGHT command: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val == 0 or val == 1) {
          on_off_status = val;
          send_status();
          set_hw_status();
        }
        
      } else if (message.type == V_DIMMER || message.type == V_PERCENTAGE) {
        Serial.print( "V_DIMMER command: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val >= 0 and val <=100) {
          dimmerlevel = val;
          send_status();
          set_hw_status();
        }
        
      } else if (message.type == V_VAR1 ) {
        Serial.print( "V_VAR1 command: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val >= 0 and val <= 2000) {
          fadespeed = val;
        }
        
    	} else {
    		Serial.println( "Invalid command received..." );
    		return;
    	}
    
    }
    
    void set_rgb(int r, int g, int b) {
      analogWrite(REDPIN, r);
      analogWrite(GREENPIN, g);
      analogWrite(BLUEPIN, b);
    }
    
    void set_hw_status() {
      int r = on_off_status * (int)(red * dimmerlevel/100.0);
      int g = on_off_status * (int)(green * dimmerlevel/100.0);
      int b = on_off_status * (int)(blue * dimmerlevel/100.0);
    
      if (fadespeed >0) {
        
        float dr = (r - r0) / float(fadespeed);
        float db = (b - b0) / float(fadespeed);
        float dg = (g - g0) / float(fadespeed);
        
        for (int x = 0;  x < fadespeed; x++) {
          set_rgb(r0 + dr*x, g0 + dg*x, b0 + db*x);
          delay(100);
        }
      }
    
      set_rgb(r, g, b);
     
      r0 = r;
      b0 = b;
      g0 = g;
      
    }
    
    
    void send_status() {
      send(rgbMsg.set(rgbstring));
      send(lightMsg.set(on_off_status));
      send(dimmerMsg.set(dimmerlevel));
    }
    

    I have a MQTT gateway and I can turn the strip on, set the color to pink and fade speed to 500 by the following commands:

    mosquitto_pub -t mysensors-in/240/1/1/0/40 -m ff6060
    mosquitto_pub -t mysensors-in/240/1/1/0/24 -m 500
    mosquitto_pub -t mysensors-in/240/1/1/0/2 -m 1
    

    A couple of pics:

    0_1493844732314_File_000 (4).jpeg
    0_1493844743322_File_001.jpeg


  • Hardware Contributor

    Nice project! The code looks really clean, I might just copy some of that for the next version of firmware for my rgb(w) node. Have you looked into how to fix the non linear fading when using pwm?
    I had started to but never finished that.


  • Hardware Contributor

    @maghac said in RGB LED strip:
    Nice work!! I have some led strips laying around... maybe I have to start using them.

    The arduino is a 5V pro mini clone that I feed with 12V on the RAW pin.

    Just a hint, this makes me nervous because Ive seen many clones with 12specs but the voltage reg is so cheap/bad it will not make it for long. Be careful using 12v on raw on the clones.



  • @LastSamurai Thanks!

    I started looking into it but realized it's a bit complex since you probably need to consider the characteristics of the MOSFETs as well. Also, when playing with it I've realized that fading between colours actually looks linear (e.g moving from ff8080 to 00ff80 is actually quite smooth), which means you need to consider the overall intensity too.

    Another interesting situation is when the user sets colour 808080 and intensity 100% compared to colour ffffff and intensity 50%. In my sketch this ends up as the same value.



  • @sundberg84 Thanks.

    Yes, I've noticed that some of them are a bit unreliable when fed with 12V. Maybe I will put a separate regulator to drive the board with 5V instead.



  • I noticed that the indents in the sketch are a bit off, I guess there's a mix of spaces and tabs in the file 🙂 I blame the crappy editor in the Arduino IDE.

    As a side note, has anyone managed to set up a Arduino development environment based on Notepad++ or some other editor? I know about platformio.org but I never managed to make friends with Atom so I haven't looked into it.


  • Hero Member

    @maghac You can setup Notepad++ to run the arduino IDE

    0_1493896237105_upload-8e11d470-d379-485c-ac24-e40cd9b1920a

    There is a good instruction (in German ;-), use google translate if you need to ) here


  • Hero Member

    @maghac The FastLed library has some functions for linear fading. The characteristics of the Mosfet's can be ignored. When using PWM these are used as switches (i.e. on/off).
    For inspiration: this sketch was for a RGBW strip and uses the FastLED nscale8() for smooth fading. Also there is a non-blocking version of the fading routine and a state machine to have button control.
    (the 'W' in the RGBW can easily be removed. It is calculated here as a kind of greatest common divisor of RGB)

    /*
     PROJECT: MySensors / RGB light NEOPIXEL
     PROGRAMMER: AWI
     DATE: october 10, 2015/ last update: september 20, 2016
     FILE: AWI_Wall_LIght_x.ino
     LICENSE: Public domain
    
     Hardware: RGBW Pro Mini and MySensors 2.0,
    		
     Special:
    	uses Fastled library  (great & fast RBG/HSV universal library) 			https://github.com/FastLED/FastLED
    	
     SUMMARY:
    	
    	Different patterns and brightness settings
    	
    	Button switches on/off and color with long press
    	
     Remarks:
    	Fixed node-id
    	
     Change log:
     20160915 - Updated to MySensors 2.0
     20160920 - Changed state change to dimmer i.s.o. switch()
     20161120 - Various small adjustments
     20170120 - Change to RGBW non addressable strip
    
    */
    //****  MySensors *****
    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    #define MY_RADIO_NRF24										// Enable and select radio type attached
    
    #define MY_NODE_ID 63										// 62
    #define NODE_TXT "W 63"										// Text to add to sensor name
    
    // change the pins to free up the pwm pin for led control
    #define MY_RF24_CE_PIN   4 									//<-- NOTE!!! changed, the default is 9
    #define MY_RF24_CS_PIN   10  								// default is 10
    //#define RF24_PA_LEVEL RF24_PA_MAX
    
    // helpers
    #define LOCAL_DEBUG											// enable if print wanted 
    
    #ifdef LOCAL_DEBUG
    #define Sprint(...) (Serial.print( __VA_ARGS__))			// macro as substitute for print, enable if no print wanted
    #define Sprintln(...) (Serial.println( __VA_ARGS__))		// macro as substitute for println
    #else
    #define Sprint(a)										
    #define Sprintln(a)
    #endif
    
    
    #include <SPI.h>											// My Sensors
    #include <MySensors.h>
    
    #include <FastLED.h>										// https://github.com/FastLED/FastLED
    #include "Button.h"											// https://github.com/JChristensen/Button
    
    // Arduino pin attached to drivers
    const int RED_PIN  = 5 ; 
    const int WHITE_PIN = 9 ;
    const int GREEN_PIN = 3 ;
    const int BLUE_PIN = 6 ;
    
    const int buttonPin = 7 ;									// push button
    
    const int RGB_LightChild = 0 ;								// Child Id's, standard light child on/off/ dim
    const int RGB_RGBChild = 1 ;								// RGB light child (on/off/dim/color, if controller supports V_RBG))
    
    CRGB strip ;												// RGB(W) strip (Fastled)
    uint8_t stripW = 0 ;										// White component
    uint8_t actualBrightness = 0xFF ;							// actual strip brightness
    
    // Kelving colors: Light & daylight (in Fastled reference only)
    /// 1900 Kelvin Candle=0xFF9329 /* 1900 K, 255, 147, 41 */,
    /// 2600 Kelvin Tungsten40W=0xFFC58F /* 2600 K, 255, 197, 143 */,
    /// 2850 Kelvin Tungsten100W=0xFFD6AA /* 2850 K, 255, 214, 170 */,
    /// 3200 Kelvin	Halogen=0xFFF1E0 /* 3200 K, 255, 241, 224 */,
    /// 5200 Kelvin CarbonArc=0xFFFAF4 /* 5200 K, 255, 250, 244 */,
    /// 5400 Kelvin HighNoonSun=0xFFFFFB /* 5400 K, 255, 255, 251 */,
    /// 6000 Kelvin DirectSunlight=0xFFFFFF /* 6000 K, 255, 255, 255 */,
    /// 7000 Kelvin OvercastSky=0xC9E2FF /* 7000 K, 201, 226, 255 */,
    /// 20000 Kelvin ClearBlueSky=0x409CFF /* 20000 K, 64, 156, 255 */
    
    char setRGBvalue[] = "FEBC5400";
    CRGB curRGB = 0xFEBC54 ;	 								// Controller sent RGB(W) value, default tungsten40W "FFC58F"
    uint16_t curBrightness = 0xFF, setBrightness = 0xFF ;		// Brightness globals (actualBrightness)
    unsigned long updateBrightnessDelay, lastBrightnessUpdate ; // Brightness timers
    int RGBonoff ;												// OnOff flag
    
    unsigned long idleTimer = millis() ;						// return to idle timer
    const unsigned long idleTime = 10000UL;						// return to idle after 10 secs
    
    const unsigned long dimTime = 1000UL;						// dim period
    
    const unsigned long heartbeatInterval = 1 * 60UL * 1000UL ;	// heartbeatinterval, just to let the controller know I am alive
    unsigned long heartbeatCounter = 0 ;
    
    MyMessage lightRGBMsg(RGB_LightChild, V_RGB);				// standard messages, light
    MyMessage lightdimmerMsG(RGB_LightChild ,V_DIMMER);	
    MyMessage lightOnOffMessage(RGB_LightChild, V_STATUS);
    
    Button myBtn(buttonPin, true, true, 20);					//Declare the button (pin, pull_up, invert, debounce_ms)
    
    // Simple state machine for button state
    enum {sIdle, sBrightness, sPattern} ;						// simple state machine for button press
    int State ;
    
    void setup() {
    	pinMode(RED_PIN,   OUTPUT);
    	pinMode(GREEN_PIN, OUTPUT);
    	pinMode(BLUE_PIN,  OUTPUT);
    	pinMode(WHITE_PIN, OUTPUT); 
    	request(RGB_LightChild, V_RGBW) ;
    
    	/*for(int i = 0 ; i < 6 ; i++) {			// get color value from EEPROM (8 char for RGBW)
    		setRGBvalue[i] = loadState(i) ;
    		}
    	
    	curRGB = strtol( setRGBvalue, NULL, 16);				// copy the RGB value to the led Strip (convert to long)
    	showAnalogRGB() ;
    	*/
    }
    
    void presentation(){
    // MySensors
    	sendSketchInfo("AWI RGBW strip " NODE_TXT, "2.0"); wait(50) ;
    	present(RGB_RGBChild, S_RGB_LIGHT, "RGB RGBW strip " NODE_TXT); wait(50) ;
    }
    
    // read button and act accordingly
    // short press: on/off
    // longer press: set patterns with following short press
    // long press: set brightness increase 
    void loop() {
    	myBtn.read();               							//Read the button (only read)
    	unsigned long now = millis(); 							// loop timer reference
    	switch (State) {
    		case sIdle:											// default state, browse through patterns
    			if (myBtn.wasReleased()){						// light on/ off in idle
    				RGBonoff = !RGBonoff ;						// invert light state
    				setLightBrightness((RGBonoff == 1)?setBrightness:0, dimTime);
    				send(lightOnOffMessage.set(RGBonoff));		// and update controller	
    			} else if (myBtn.pressedFor(800)){				// move to Pattern update state with long press
    				idleTimer = now ;							// return to idle after ...
    				State = sPattern ;
    			}
    			break ;
    		case sPattern:										// entered after long press/ change colors (tbd)
    			if (myBtn.pressedFor(4000)){					// when press even longer move to Brightness update
    				State = sBrightness ;
    			} else if (myBtn.wasPressed()){
    				//setPattern = (setPattern + 1) % lastPatternIdx ;  // increase pattern and wrap
    				//setLightPattern((setPattern), 500 );
    				idleTimer = now ;
    			} else if ( now > idleTime + idleTimer  ){		// return to idle after ...
    				State = sIdle ;
    			}
    			break ;
    		case sBrightness:									// entered after looong press
    			if (myBtn.wasPressed()){						// if pressed again increase brightness
    				setLightBrightness((curBrightness+0x1F) % 0xFF, 0) ; // increase brightness and wrap (0..0xFF)
    				idleTimer = now ;
    			} else if ( now > idleTime + idleTimer  ){		// return to idle after ...
    				State = sIdle ;
    			}
    			break ;
    		default :
    			State = sIdle ;
    			break ;
    	}
    	updateLightBrightness();								// update Brightness if time
    	if ( now > heartbeatCounter  + heartbeatInterval){		// heartbeat every hour
    	    sendHeartbeat();
    		heartbeatCounter = now ; 
    	}
    }
    
    // Sets the light brightness, takes value and time (ms) as input
    void setLightBrightness(int newBrightness, unsigned long updateTime){
    	// global: curBrightness, actualBrightness, updateBrightnessDelay
    	updateBrightnessDelay = updateTime / 0xFF ;				// delay = time / max steps
    	curBrightness = newBrightness ;							// set curBrightness to new value, rest is done in update
    }	
     
    // Update the light brightness if time
    void updateLightBrightness(){
    	// global: curBrightness, actualBrightness, updateBrightnessDelay, lastBrightnessUpdate ;
    	//static byte actualBrightness ;							// store real brightness state for slow dim
    	unsigned long now = millis() ;
    	if (now > lastBrightnessUpdate + updateBrightnessDelay){// check if time for update
    		if ( actualBrightness > curBrightness) {
    			--actualBrightness ;
    			showAnalogRGB() ;
    		} else if ( actualBrightness < curBrightness){
    			++actualBrightness ;
    			showAnalogRGB() ;
    			}
    		lastBrightnessUpdate = now ;
    	}
    }
    
    // Incoming messages from MySensors
    void receive(const MyMessage &message){
    	int ID = message.sensor;
    	Serial.print("Sensor: ");
    	Serial.println(ID);
    	switch (ID){
    		case RGB_LightChild:									// same behaviour as RGB child/ fall through
    		case RGB_RGBChild:										// if controller can handle V_RGB
    			if (message.type == V_RGB) {						// check for RGB type
    				strcpy(setRGBvalue, message.getString());		// get the payload
    				curRGB = strtoul( setRGBvalue, NULL, 16) ;	// copy the RGB value to the led Strip (convert to long)
    			} else if (message.type == V_RGBW) {						// check for RGB type
    				strcpy(setRGBvalue, message.getString());		// get the payload
    				curRGB = strtoul( setRGBvalue, NULL, 16) >> 8;	// copy the RGB value to the led Strip (convert to long)
    			} else if (message.type == V_DIMMER) {				// if DIMMER type, adjust brightness
    				setBrightness = map(message.getInt(), 0, 100, 0, 255);
    				setLightBrightness(setBrightness, dimTime) ;
    			} else if (message.type == V_STATUS) {				// if on/off type, toggle brightness
    				RGBonoff = message.getInt();
    				setLightBrightness((RGBonoff == 1)?setBrightness:0, dimTime);
    			}
    			break ;
    	}
        showAnalogRGB();
    	dispRGBstat();
    }
    
    
    // showAnalogRGB: this is like FastLED.show(), but outputs on 
    // analog PWM output pins instead of sending data to an intelligent,
    // pixel-addressable LED strip.
    void showAnalogRGB(){
    	strip = curRGB ;
    	strip.nscale8(actualBrightness)  ;
    	int commonRGB = min(min(strip.r, strip.g), strip.b) ;		// smallest value is White component
    	strip.r -= commonRGB ;
    	strip.g -= commonRGB ;
    	strip.b -= commonRGB ;
    	stripW = commonRGB ;
    	Sprint("Color RGBW ") ;
    	Sprint(strip.r, HEX); 
    	Sprint(" ") ;
    	Sprint(strip.g, HEX); 
    	Sprint(" ") ;
    	Sprint(strip.b, HEX); 
    	Sprint(" ") ;
    	Sprintln(stripW, HEX) ;
    	analogWrite(RED_PIN,   strip.r );
    	analogWrite(GREEN_PIN, strip.g );
    	analogWrite(BLUE_PIN,  strip.b );
    	analogWrite(WHITE_PIN, stripW ) ;
    }
    
    
    
    // debug	
    // display the status of all RGB: controller, requested, real
    void dispRGBstat(void){
        Serial.print(" Color: "); Serial.print(setRGBvalue); 
        Serial.print(" Brightness: "); Serial.println(setBrightness);
    }
    
    
    	```


  • @AWI Looks good, I'll see if I can incorporate this in my solution. Thanks!



  • I'd thought I'd share a pic now that the led strip has been mounted. Unfortunately the iphone camera doesn't have enough dynamic range to capture the light correctly - it looks a lot better in reality!

    Through some HomeAssistant/tellstick magic I can also turn it on and off using a normal 433Mhz remote instead of having to send MQTT messages from the command line. This increased the WAF considerably 🙂

    0_1494318228883_File_000.jpeg



  • @maghac , great work!!!

    I want to build a battery powered Mood Light based on your sketch and RGB Common Cathode Leds (4 or 5 of them).

    Before getting those RGB leds yet (already ordered but it takes 2 months to receive) I tested your sketch with three ordinary 3 mm colored leds - Green, Red and Yellow (should be blue but I don´t have it) and got it running on Home Assistant. On batteries as well. Color selection and Dimmer working as well...

    But I don´t get fading effects (called by transition time on Home Assistant). No matter how long I ask the transition it changes the same time I ask.

    Serial monitor never shows that V_VAR1 message type. Was it supposed to show it?
    What did I miss?

    Thanks.



  • @OliverDog, thanks!

    The V_VAR1 message is used to set the speed of the fading (e.g the time between stepping the RGB values towards the value received with the V_RGB message). Not sure why it doesn't work for you, but maybe it's related to the fact that you don't have the real RGB leds?

    You may be interested to know that I have implemented a new version of this sketch. The problem with the old one is that it did the fading in a loop which meant that no new commands were processed during the fade. The new version implements it differently so that messages can be received while the light is fading in a sort of multitasking fashion. This opened up the possibility to implement "programs" that control the LED strip in the background while the device is still receiving messages (e.g during a slow fade to green I can tell it to turn off or to fade to blue instead, without having to wait for the current fade to stop). I have implemented two such programs - one is a sort of an alarm mode (blink white on/off) and the other is a relax program (very slow fade between various pastel colours). To enable the programs, you send a V_VAR2 message with a number: 0: normal (e.g fixed to one colour), 1: alarm and 2: relax.

    Since V_VAR2 is message type 25, this is the corresponding MQTT message to enable the relax program:

    mosquitto_pub -t mysensors-in/2/1/1/0/25 -m 2
    

    Code is below. I intend to update it further (i.e the "party" program is missing! 🙂 ) and then I'll post the new versions here.

    Have fun!

    /**
     * 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.
     *
     * LED STRIP sketch for Mysensors
     *******************************
     *
     * REVISION HISTORY
     * 1.0 
     *   Based on the example sketch in mysensors
     * 1.1
     *   fadespeed parameter (send as V_VAR1 message)
     *   HomeAssistant compatible (send status to ack)
     * 1.2
     *   OTA support
     * 1.3
     *   Power-on self test
     * 1.4
     *   Bug fix
     * 1.5
     *   Other default values
     * 1.6
     *   Repeater feature
     * 1.7
     *   Multitasking. Alarm, Relax and normal modes.
     */
    
    #define MY_OTA_FIRMWARE_FEATURE
    #define MY_REPEATER_FEATURE
    #define MY_NODE_ID AUTO
    
    #define MY_RADIO_NRF24
    
    #define MY_DEBUG
    
    #include <MySensors.h>
    
    #define CHILD_ID_LIGHT 1
    
    #define SN "LED Strip"
    #define SV "1.7"
    
    MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
    MyMessage rgbMsg(CHILD_ID_LIGHT, V_RGB);
    MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
    
    int current_r = 255;
    int current_g = 255;
    int current_b = 255;
    int target_r = 255;
    int target_g = 255;
    int target_b = 255;
    int save_r;
    int save_g;
    int save_b;
    
    
    float delta_r = 0.0;
    float delta_g = 0.0;
    float delta_b = 0.0;
    
    char rgbstring[] = "ffffff";
    
    int on_off_status = 0;
    int dimmerlevel = 100;
    int fadespeed = 20;
    unsigned long last_update = 0;
    int tick_length = 10;
    int fade_step = 0;
    
    int program_timer;
    int program_cycle;
    
    #define REDPIN 6
    #define GREENPIN 5
    #define BLUEPIN 3
    
    #define LIGHT_NORMAL 0
    #define LIGHT_FADING 1
    
    #define PROGRAM_NORMAL 0
    #define PROGRAM_ALARM 1
    #define PROGRAM_RELAX 2
    
    int light_mode = LIGHT_NORMAL;
    int program_mode = PROGRAM_NORMAL;
    
    #define RELAX_SPEED 50
    #define MAX_CYCLES_RELAX 7
    const int program_param_RELAX[MAX_CYCLES_RELAX][3] = {
      {255, 32, 0},
      {255, 32, 16},
      {255, 16, 32},
      {255, 128, 0},
      {255, 32, 00},
      {255, 32, 32},
      {255, 0, 32}
    };
    
    void setup()
    {
      // Fix the PWM timer. Without this the LEDs will flicker.
      TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
    
      // Output pins
      pinMode(REDPIN, OUTPUT);
      pinMode(GREENPIN, OUTPUT);
      pinMode(BLUEPIN, OUTPUT);
      
    }
    
    void presentation()
    {
    	// Send the Sketch Version Information to the Gateway
    	sendSketchInfo(SN, SV);
    	present(CHILD_ID_LIGHT, S_RGB_LIGHT);
    }
    
    void selftest() {
      on_off_status = 1;
      current_r = 255;
      current_g = 0;
      current_b = 0;
      set_hw_status();
      wait(100);
      current_r = 0;
      current_g = 255;
      set_hw_status();
      wait(100);
      current_g = 0;
      current_b = 255;
      set_hw_status();
      wait(100);
      current_r = 255;
      current_g = 255;
      set_hw_status();
      wait(100);
      on_off_status = 0;
    }
    
    
    void loop()
    {
      static bool first_message_sent = false;
      if ( first_message_sent == false ) {
        selftest();
        set_hw_status();
        send_status(1, 1, 1);
        first_message_sent = true;
      }
    
      unsigned long now = millis();
      
      if (now - last_update > tick_length) {
        last_update = now;
    
        if (light_mode == LIGHT_FADING) {
          calc_fade();
        }
    
        if (program_mode > PROGRAM_NORMAL) {
          handle_program();
        }
        
      }
      set_hw_status();
      
    }
    
    void receive(const MyMessage &message)
    {
      int val;
      
    	if (message.type == V_RGB) {
    		Serial.print( "V_RGB: " );
        Serial.println(message.data);
        long number = (long) strtol( message.data, NULL, 16);
    
        // Save old value
        strcpy(rgbstring, message.data);
        
        // Split it up into r, g, b values
        int r = number >> 16;
        int g = number >> 8 & 0xFF;
        int b = number & 0xFF;
    
        init_fade(fadespeed, r, g, b); 
        send_status(0, 0, 1);
    
    	} else if (message.type == V_LIGHT || message.type == V_STATUS) {
        Serial.print( "V_LIGHT: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val == 0 or val == 1) {
          on_off_status = val;
          send_status(1, 0, 0);
        }
        
      } else if (message.type == V_DIMMER || message.type == V_PERCENTAGE) {
        Serial.print( "V_DIMMER: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val >= 0 and val <=100) {
          dimmerlevel = val;
          send_status(0, 1, 0);
        }
        
      } else if (message.type == V_VAR1 ) {
        Serial.print( "V_VAR1: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val >= 0 and val <= 2000) {
          fadespeed = val;
        }
    
      } else if (message.type == V_VAR2 ) {
        Serial.print( "V_VAR2: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val == PROGRAM_NORMAL) {
          stop_program();
        } else if (val == PROGRAM_ALARM || val == PROGRAM_RELAX) {
          init_program(val);
        }
    
    	} else {
    		Serial.println( "Invalid command received..." );
    		return;
    	}
    
    }
    
    void set_rgb(int r, int g, int b) {
      analogWrite(REDPIN, r);
      analogWrite(GREENPIN, g);
      analogWrite(BLUEPIN, b);
    }
    
    void init_program(int program) {
      program_mode = program;
      program_cycle = 0;
      save_rgb();
      
      if (program == PROGRAM_ALARM) {
        light_mode = LIGHT_NORMAL;
        current_r = 255;
        current_g = 255;
        current_b = 255;
        program_timer = 50;
      } else if (program == PROGRAM_RELAX) {
        program_timer = 300;
        init_fade(fadespeed,
                  program_param_RELAX[program_cycle][0],
                  program_param_RELAX[program_cycle][1],
                  program_param_RELAX[program_cycle][2]);
      }
    }
    
    void handle_program() {
      program_timer--;
      if (program_mode == PROGRAM_ALARM) {
        if (program_timer == 0) {
          program_timer = 50;
          if (program_cycle == 0) {
            program_cycle = 1;
            current_r = 0;
            current_g = 0;
            current_b = 0;
          } else {
            program_cycle = 0;
            current_r = 255;
            current_g = 255;
            current_b = 255;
          }
        }
      } else if (program_mode == PROGRAM_RELAX) {
        if (light_mode == LIGHT_NORMAL) {
          program_cycle = (program_cycle+1) % MAX_CYCLES_RELAX;
          Serial.print("Next cycle step ");
          Serial.println(program_cycle);
          init_fade(fadespeed * RELAX_SPEED,
                    program_param_RELAX[program_cycle][0],
                    program_param_RELAX[program_cycle][1],
                    program_param_RELAX[program_cycle][2]);
        
        }
        
      }
    }
    
    void stop_program() {
      restore_rgb();
      light_mode = LIGHT_NORMAL;
      program_mode = PROGRAM_NORMAL;
    }
    
    void save_rgb() {
      save_r = current_r;
      save_g = current_g;
      save_b = current_b;
    }
    
    void restore_rgb() {
      current_r = save_r;
      current_g = save_g;
      current_b = save_b;
    }
    void init_fade(int t, int r, int g, int b) {
      Serial.print( "Init fade" );
      light_mode = LIGHT_FADING;
      target_r = r;
      target_g = g;
      target_b = b;
      fade_step = t;
      delta_r = (target_r - current_r) / float(fade_step);
      delta_g = (target_g - current_g) / float(fade_step);
      delta_b = (target_b - current_b) / float(fade_step);
    }
    
    void calc_fade() {
      if (fade_step > 0) {
        fade_step--;
        current_r = target_r - delta_r * fade_step;
        current_g = target_g - delta_g * fade_step;
        current_b = target_b - delta_b * fade_step;
      } else {
        Serial.println( "Normal mode" );
        light_mode = LIGHT_NORMAL;
      } 
    }
    
    void set_hw_status() {
      int r = on_off_status * (int)(current_r * dimmerlevel/100.0);
      int g = on_off_status * (int)(current_g * dimmerlevel/100.0);
      int b = on_off_status * (int)(current_b * dimmerlevel/100.0);
    
      set_rgb(r, g, b);
      
    }
    
    
    void send_status(int send_on_off_status, int send_dimmerlevel, int send_rgbstring) {
      if (send_rgbstring) send(rgbMsg.set(rgbstring));
      if (send_on_off_status) send(lightMsg.set(on_off_status));
      if (send_dimmerlevel) send(dimmerMsg.set(dimmerlevel));
    }
    


  • the new sketch is even better... it responds faster than the other...

    but I still don't have fading effects... just the one that you have configured on the sketch (20) which is awesome by the way...

    It seems that Home Assistant does not send neither V_VAR1 nor V_VAR2 messages...

    the command:
    {"entity_id":"light.rgb_leds_12_1", "color_name":"green", "brightness_pct": 15, "transition":20}

    shows the same effect that the command:
    {"entity_id":"light.rgb_leds_12_1", "color_name":"green", "brightness_pct": 15, "transition":1}

    I will try HASS forum!
    Thank you very much.



  • Have tried to integrate your code and it's awesome except for one thing.
    Fixing the PWM breaks the timer. So if i use it straight away my DHT22 and MQ-2 will not send any data.
    Well not like that - DHT22 sends humidity but no temp

    As soon as i comment out the below line everything starts to work out

    TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);

    The only exception that i use PWM pins 5,6,9 and pin3 is user for IR transmitter. Any ideas for an easy fix?



  • @OliverDog HA will not send VAR1 or VAR2 unless you implement some specific functionality to do this. I set up switches in HA to send the correct MQTT message to the mysensors gateway in order to activate the alarm and relax modes. Here's my switch.yaml file:

    - platform: tellstick
    
    
    - platform: mqtt
      name: "Alarm"
      command_topic: "mysensors-in/3/1/1/0/25"
      payload_on: "1"
      payload_off: "0"
      optimistic: false
      qos: 0
      retain: false
    
    - platform: mqtt
      name: "Relax"
      command_topic: "mysensors-in/3/1/1/0/25"
      payload_on: "2"
      payload_off: "0"
      optimistic: false
      qos: 0
      retain: false
    


  • @moskovskiy82 Thanks!

    To be absolutely honest I'm not exactly sure what the TCCR0A statement does 🙂 I had problems with flickering LEDs so I googled it and someone on the arduino.cc forums had the same problem and fixed it by putting that line in the code.

    Using other pins for the LEDs should be fine, as long as they are PWM pins of course. Just change the #define statements accordingly.



  • @maghac @moskovskiy82 I came across this some time ago, with an RGB LED project. Whilst I can't recall the details, it's to do with setting the Arduino's PWM timers - apparently, the frequencies of the R(ed) & B(lue) channels can be close enough to causing 'beating', which gives rise to flickering. This statement changes the frequency of one of the channels slightly, thereby eliminating the flickering.



  • Yes, after googling it I could see it was related to setting the timers. There is maybe another way to fix it and still keep the correct timer functions for other functionalities to be intact (e.g so that @moskovskiy82 can still use the DHT22), but I haven't investigated further. In any case, I believe it's easier to split separate functions to separate physical units instead of trying to put as much functionality into one single unit as possible.

    In my case, the unit is mounted in a not-so-well-ventilated enclosure in the ceiling, so I doubt that I would get a correct temperature reading anyway 🙂



  • @maghac I have posted the issue (not working VAR1 and VAR2 on Home Assistant) on the HA forum, and got steps for asking the implement...
    I will ask for such implement and it may work later...
    Thanks for the help...

    By the way, I did not test the switches but seems doing the job...



  • After some investigating it wasn't a timer issue but a range issue with a node (it was hard to figure out). So went ahead and built another node with your code. But being lazy - just bought an rgb strip drive from aliexpress (too much soldering of mosfets for me).

    It uses some RGBdriver.h library https://github.com/letsgoING/Libraries/tree/master/LEDStripDriver
    fe
    All i had to change was

    void set_rgb(int r, int g, int b) {
      Driver.begin();
      Driver.SetColor(r, g, b);
      Driver.end();
    }
    

    And it worked. Except that fading/RELAX don't work out for me. Instead just get a flashing of white light. So i thought you might know some other parts must be adjusted as my arduino knowledge is not there yer



  • @maghac What board is that?





  • @maghac Wow! I guess I haven't been around here for a while.

    Thanks



  • @maghac Oh yes by the way the code above works great just added some code for Motion sensor and Now I have a much better light.

    /**
     * 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.
     *
     * LED STRIP sketch for Mysensors
     *******************************
     *
     * REVISION HISTORY
     * 1.0 
     *   Based on the example sketch in mysensors
     * 1.1
     *   fadespeed parameter (send as V_VAR1 message)
     *   HomeAssistant compatible (send status to ack)
     * 1.2
     *   OTA support
     * 1.3
     *   Power-on self test
     * 1.4
     *   Bug fix
     * 1.5
     *   Other default values
     * 1.6
     *   Repeater feature
     * 1.7
     *   Multitasking. Alarm, Relax and normal modes.
     */
    
    #define MY_OTA_FIRMWARE_FEATURE
    #define MY_REPEATER_FEATURE
    #define MY_NODE_ID 31
    
    // added all the motion stuff DrJeff September 10, 2017
    #define MOTION_1 3   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
    #define MOTION_ID 90   // Id of the sensor child
    uint8_t lastMotion_1 = 0;
    unsigned long previousMillis1 = 0;
    unsigned long motionDelay1 = 10000; // interval at which to keep motion sensor trippped (milliseconds).  Used to prevent too frequent updates to Vera.
    ///
    
    #define MY_RADIO_NRF24
    
    #define MY_DEBUG
    
    #include <MySensors.h>
    
    #define CHILD_ID_LIGHT 1
    
    #define SN "LED Strip"
    #define SV "1.7"
    
    MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
    MyMessage rgbMsg(CHILD_ID_LIGHT, V_RGB);
    MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
    
    // added all the motion stuff DrJeff September 10, 2017
    MyMessage motion(MOTION_ID, V_TRIPPED);
    //
    
    int current_r = 255;
    int current_g = 255;
    int current_b = 255;
    int target_r = 255;
    int target_g = 255;
    int target_b = 255;
    int save_r;
    int save_g;
    int save_b;
    
    
    float delta_r = 0.0;
    float delta_g = 0.0;
    float delta_b = 0.0;
    
    char rgbstring[] = "ffffff";
    
    int on_off_status = 0;
    int dimmerlevel = 100;
    int fadespeed = 20;
    unsigned long last_update = 0;
    int tick_length = 10;
    int fade_step = 0;
    
    int program_timer;
    int program_cycle;
    
    #define REDPIN 6
    #define GREENPIN 4
    #define BLUEPIN 5
    
    #define LIGHT_NORMAL 0
    #define LIGHT_FADING 1
    
    #define PROGRAM_NORMAL 0
    #define PROGRAM_ALARM 1
    #define PROGRAM_RELAX 2
    
    int light_mode = LIGHT_NORMAL;
    int program_mode = PROGRAM_NORMAL;
    
    #define RELAX_SPEED 50
    #define MAX_CYCLES_RELAX 7
    const int program_param_RELAX[MAX_CYCLES_RELAX][3] = {
      {255, 32, 0},
      {255, 32, 16},
      {255, 16, 32},
      {255, 128, 0},
      {255, 32, 00},
      {255, 32, 32},
      {255, 0, 32}
    };
    
    void setup()
    {
      // Fix the PWM timer. Without this the LEDs will flicker.
      TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
    
      // Output pins
      pinMode(REDPIN, OUTPUT);
      pinMode(GREENPIN, OUTPUT);
      pinMode(BLUEPIN, OUTPUT);
      // added all the motion stuff DrJeff September 10, 2017
      pinMode(MOTION_1, INPUT);  
    //
      
    }
    
    void presentation()
    {
      // Send the Sketch Version Information to the Gateway
      sendSketchInfo(SN, SV);
      present(CHILD_ID_LIGHT, S_RGB_LIGHT);
      // added all the motion stuff DrJeff September 10, 2017
      present(MOTION_ID, S_MOTION);
    //
    
    }
    
    void selftest() {
      on_off_status = 1;
      current_r = 255;
      current_g = 0;
      current_b = 0;
      set_hw_status();
      wait(100);
      current_r = 0;
      current_g = 255;
      set_hw_status();
      wait(100);
      current_g = 0;
      current_b = 255;
      set_hw_status();
      wait(100);
      current_r = 255;
      current_g = 255;
      set_hw_status();
      wait(100);
      on_off_status = 0;
    }
    
    
    void loop()
    {
      static bool first_message_sent = false;
      if ( first_message_sent == false ) {
        selftest();
        set_hw_status();
        send_status(1, 1, 1);
        first_message_sent = true;
      }
        // added all the motion stuff DrJeff September 10, 2017//loop for motion
       unsigned long currentMillis = millis();
    
     if(currentMillis - previousMillis1 > motionDelay1)
      {
    
        uint8_t motionDetect1 = digitalRead(MOTION_1);
    
        if(motionDetect1 != lastMotion_1)
        {
          Serial.print("Motion 1 = ");
          Serial.println(motionDetect1);
          //  gw.send(motionStatus_1.set(motionDetect1 ? "1" : "0")); // Send tripped value to gw
          send(motion.set(motionDetect1));
          if(motionDetect1 == 1)
          {
            previousMillis1 = currentMillis;  //"Tripped" delay
          }
          else
          {
            previousMillis1 = currentMillis - motionDelay1 + 1000; //"Not tripped" delay for 1 second to stop rapid "not tripped" and "tripped" updates to Vera
          }
    
          lastMotion_1 = motionDetect1;
        }
      }
    
    //end of motion loop
    
      unsigned long now = millis();
      
      if (now - last_update > tick_length) {
        last_update = now;
    
        if (light_mode == LIGHT_FADING) {
          calc_fade();
        }
    
        if (program_mode > PROGRAM_NORMAL) {
          handle_program();
        }
        
      }
      set_hw_status();
      
    }
    
    void receive(const MyMessage &message)
    {
      int val;
      
      if (message.type == V_RGB) {
        Serial.print( "V_RGB: " );
        Serial.println(message.data);
        long number = (long) strtol( message.data, NULL, 16);
    
        // Save old value
        strcpy(rgbstring, message.data);
        
        // Split it up into r, g, b values
        int r = number >> 16;
        int g = number >> 8 & 0xFF;
        int b = number & 0xFF;
    
        init_fade(fadespeed, r, g, b); 
        send_status(0, 0, 1);
    
      } else if (message.type == V_LIGHT || message.type == V_STATUS) {
        Serial.print( "V_LIGHT: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val == 0 or val == 1) {
          on_off_status = val;
          send_status(1, 0, 0);
        }
        
      } else if (message.type == V_DIMMER || message.type == V_PERCENTAGE) {
        Serial.print( "V_DIMMER: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val >= 0 and val <=100) {
          dimmerlevel = val;
          send_status(0, 1, 0);
        }
        
      } else if (message.type == V_VAR1 ) {
        Serial.print( "V_VAR1: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val >= 0 and val <= 2000) {
          fadespeed = val;
        }
    
      } else if (message.type == V_VAR2 ) {
        Serial.print( "V_VAR2: " );
        Serial.println(message.data);
        val = atoi(message.data);
        if (val == PROGRAM_NORMAL) {
          stop_program();
        } else if (val == PROGRAM_ALARM || val == PROGRAM_RELAX) {
          init_program(val);
        }
    
      } else {
        Serial.println( "Invalid command received..." );
        return;
      }
    
    }
    
    void set_rgb(int r, int g, int b) {
      analogWrite(REDPIN, r);
      analogWrite(GREENPIN, g);
      analogWrite(BLUEPIN, b);
    }
    
    void init_program(int program) {
      program_mode = program;
      program_cycle = 0;
      save_rgb();
      
      if (program == PROGRAM_ALARM) {
        light_mode = LIGHT_NORMAL;
        current_r = 255;
        current_g = 255;
        current_b = 255;
        program_timer = 50;
      } else if (program == PROGRAM_RELAX) {
        program_timer = 300;
        init_fade(fadespeed,
                  program_param_RELAX[program_cycle][0],
                  program_param_RELAX[program_cycle][1],
                  program_param_RELAX[program_cycle][2]);
      }
    }
    
    void handle_program() {
      program_timer--;
      if (program_mode == PROGRAM_ALARM) {
        if (program_timer == 0) {
          program_timer = 50;
          if (program_cycle == 0) {
            program_cycle = 1;
            current_r = 0;
            current_g = 0;
            current_b = 0;
          } else {
            program_cycle = 0;
            current_r = 255;
            current_g = 255;
            current_b = 255;
          }
        }
      } else if (program_mode == PROGRAM_RELAX) {
        if (light_mode == LIGHT_NORMAL) {
          program_cycle = (program_cycle+1) % MAX_CYCLES_RELAX;
          Serial.print("Next cycle step ");
          Serial.println(program_cycle);
          init_fade(fadespeed * RELAX_SPEED,
                    program_param_RELAX[program_cycle][0],
                    program_param_RELAX[program_cycle][1],
                    program_param_RELAX[program_cycle][2]);
        
        }
        
      }
    }
    
    void stop_program() {
      restore_rgb();
      light_mode = LIGHT_NORMAL;
      program_mode = PROGRAM_NORMAL;
    }
    
    void save_rgb() {
      save_r = current_r;
      save_g = current_g;
      save_b = current_b;
    }
    
    void restore_rgb() {
      current_r = save_r;
      current_g = save_g;
      current_b = save_b;
    }
    void init_fade(int t, int r, int g, int b) {
      Serial.print( "Init fade" );
      light_mode = LIGHT_FADING;
      target_r = r;
      target_g = g;
      target_b = b;
      fade_step = t;
      delta_r = (target_r - current_r) / float(fade_step);
      delta_g = (target_g - current_g) / float(fade_step);
      delta_b = (target_b - current_b) / float(fade_step);
    }
    
    void calc_fade() {
      if (fade_step > 0) {
        fade_step--;
        current_r = target_r - delta_r * fade_step;
        current_g = target_g - delta_g * fade_step;
        current_b = target_b - delta_b * fade_step;
      } else {
        Serial.println( "Normal mode" );
        light_mode = LIGHT_NORMAL;
      } 
    }
    
    void set_hw_status() {
      int r = on_off_status * (int)(current_r * dimmerlevel/100.0);
      int g = on_off_status * (int)(current_g * dimmerlevel/100.0);
      int b = on_off_status * (int)(current_b * dimmerlevel/100.0);
    
      set_rgb(r, g, b);
      
    }
    
    
    void send_status(int send_on_off_status, int send_dimmerlevel, int send_rgbstring) {
      if (send_rgbstring) send(rgbMsg.set(rgbstring));
      if (send_on_off_status) send(lightMsg.set(on_off_status));
      if (send_dimmerlevel) send(dimmerMsg.set(dimmerlevel));
    }


  • Hey @maghac - just wondering how you got the 12V to your fitting? have you got a transformer in the ceiling above ? Regards, mick



  • @mick No, I have a separate 12V cable and a transformer from a regular wall outlet.



  • @maghac Thanks for the reply, mate. The light looks great mounted up - very impressed!



  • @mick said in RGB LED strip:

    @maghac Thanks for the reply, mate. The light looks great mounted up - very impressed!

    Thanks! The "relax" program is actually quite nice since it changes colours so slowly so it takes a while before you notice it. A great way to impress your dinner guests 🙂



  • I dont know what went wrong, but RED is just always on. Yesterday in the breadboard it was ok. Today in the breadboard red was on. So i thought lets just solder it... Now I soldered it to a pcb, RED on all the time. This must be a ground issue, but where do i look?

    It is even red when just all the connections are off, 12v to raw and strip, then connect ground to arduino, BOOM red comes on...



  • @xypzo Double check your connections, perhaps you're connecting to the wrong pin on the arduino? If you swap red and green, what happens then?



  • @maghac said in RGB LED strip:

    your connections, perhaps you're connecting to the wrong pin on the arduino

    Then green keeps on, so it should be a pin 6 problem, but i can't find it. Maybe I try a 10kohm resistor between gate and ground... Or IRFZ instead of IRLZ transistors.

    BTW, bought a LD362A ufo which works great with my controller, but i still want to win this battle!



  • @xypzo said in RGB LED strip:

    @maghac said in RGB LED strip:

    your connections, perhaps you're connecting to the wrong pin on the arduino

    Then green keeps on, so it should be a pin 6 problem, but i can't find it. Maybe I try a 10kohm resistor between gate and ground... Or IRFZ instead of IRLZ transistors.

    BTW, bought a LD362A ufo which works great with my controller, but i still want to win this battle!

    You could try to use a different pin. Can't remember off the top of my head which pins are PWM capable though.

    I've had a couple of cheap arduino clones where some of the pins were not correctly soldered.



  • @maghac The stupid thing, is that the day before, same setup, no red lights stayed on. It happened overnight!!! Maybe the mice did it! :')



  • @xypzo Gremlins! 🙂



  • what DID happen the day before, was that when i added more WHITE, at around 60% white the whole unit stopped responding to any inputs, it would just freeze in that color, until i removed the 12v power supply. Also strange! 🙂



  • Hi!
    I'm doing some further development based on the sketch by @maghac and @DrJeff above and I have found two potential bugs that could create some unexpected behaviour.
    The first is that if you have #DEFINE RELAX_SPEED 50 in the sketch and then set fadespeed (V_VAR1) to anything greater than 650 or so, you will get an overflow when you call the function init_fade (t, r, g, b ) since t is defined as int in init_fade.
    fadespeed can be set between 0 and 2000 in the sketch. So then the resulting fadespeed could be anything, even negative.

    init_fade(fadespeed * RELAX_SPEED,
                    program_param_RELAX[program_cycle][0],
                    program_param_RELAX[program_cycle][1],
                    program_param_RELAX[program_cycle][2]);
    

    Also in this function there is a potential risk of a "divide by zero" crash since the input variable t is used as fade_step to divide in order to get the size of each step in the fade cycle.

    void init_fade(int t, int r, int g, int b) {
      Serial.print( "Init fade" );
      light_mode = LIGHT_FADING;
      target_r = r;
      target_g = g;
      target_b = b;
      fade_step = t;
      delta_r = (target_r - current_r) / float(fade_step);
      delta_g = (target_g - current_g) / float(fade_step);
      delta_b = (target_b - current_b) / float(fade_step);
    }
    

    It might be that this function is never called with fadestep = t = 0 but since this is a value allowed in the input check of V_VAR1 nasty things may happen.
    Part from this I am impressed by the sketch. Once I have debugged my own additions I will post the project here.



  • @bgunnarb Thanks. As program space is limited, I chose not to put too much effort in input data validation, instead relying on the controller to not submit incorrect values. Maybe a quick range check would not waste so many bytes though.

    Right now I am however experiencing some strange behavior - I can turn the the lamp on and off and I can dim it, but I cannot change the color of the strip. Also, the RELAX program does not work but the ALARM program works fine. So there are some other bugs that need to be ironed out 🙂



  • @moskovskiy82 said in RGB LED strip:

    And it worked. Except that fading/RELAX don't work out for me. Instead just get a flashing of white light. So i thought you might know some other parts must be adjusted as my arduino knowledge is not there yer

    That's the alarm program you are seeing. Perhaps it doesn't decode the incoming messages properly - I'll have to take a second look at the code.



  • Thanks. Will await eagerly for v1.8 as it seems this is the only great RGB code left for mysensors



  • @maghac Great project.

    I've made something similar, Arduino Pro Mini 5v, 5m LED strip (non-addressable), nrf24L01+ and MOSTFETs

    I know it took me awhile to find code examples, so I figured I would share my code incase it helps anyone else.

    I use Domoticz as a controller. This code talks to:

    • Switch - to control turning my color cycle fade effect on
    • Dimmer - to control the speed of the color cycle fade effect
    • RGB switch - to control having only a single color turned on and the brightness of the string.

    Much of my code is standard stuff, using FastLED analogue, but I'm particularly proud of the brightness part, since I bashed my head against the keyboard several times trying to figure it out

    //## INCLUDES ##
    #define MY_DEBUG
    #define MY_RADIO_NRF24
    #define MY_NODE_ID 20
    
    #include <MySensors.h>
    #include <SPI.h>
    #include <FastLED.h>
    
    #define cID_RGB_SELECTOR 0
    #define cID_CYCLE_EFFECT 1
    #define cID_CYCLE_EFFECT_SPEED 2
    
    #define PIN_RED   5
    #define PIN_GREEN 6
    #define PIN_BLUE  3
    
    //## VARIABLES ##
    // MySensors
    #define MySensors_SketchName      "RGB LED Strip"
    #define MySensors_SketchVersion   "v0.3"
    MyMessage MySensors_MSG_Last_Color(cID_RGB_SELECTOR,V_VAR1);
    MyMessage MySensors_MSG_RGB_Selector(cID_RGB_SELECTOR, V_LIGHT);
    MyMessage MySeonsors_MSG_CYCLE_EFFECT(cID_CYCLE_EFFECT, V_LIGHT);
    MyMessage MySensors_MSG_CYCLE_EFFECT_SPEED(cID_CYCLE_EFFECT_SPEED, V_DIMMER);
    bool MySensors_RequestACK = false;
    // Single color
    int Solid_RGB_Active=0;
    char Solid_RGB_Color[] = "000000";
    uint16_t Solid_RGB_Brightness = 0xFF;
    // Cycle effect
    int Cycle_Effect_Active=0;
    unsigned long Cycle_Effect_pMillis = 0;
    long Cycle_Effect_Speed = 20;
    static uint8_t Cycle_Effect_Current_Hue;
    // Supporting
    bool Status_Change = false;
    bool Print_Debug = false;
    
    // ## Primary flow control
    void setup() {
      Serial.begin(115200);
      while (!Serial) ;
      Serial.print("compiled: ");Serial.print(__DATE__);Serial.println(__TIME__);
    
      pinMode(PIN_RED,   OUTPUT);
      pinMode(PIN_GREEN, OUTPUT);
      pinMode(PIN_BLUE,  OUTPUT);
    
      Event_ColorTestBars();
    
      request(cID_RGB_SELECTOR, V_VAR1);
      request(cID_RGB_SELECTOR, V_LIGHT);
      request(cID_CYCLE_EFFECT, V_LIGHT);
      request(cID_CYCLE_EFFECT_SPEED, V_DIMMER);
    }
    void loop() {
      if (Cycle_Effect_Active == 1){
        unsigned long currentMillis = millis();
        Event_RunCycleEffect(currentMillis);
      } else if (Status_Change){
        Status_Change = false;
          #ifdef MY_DEBUG
            if (Print_Debug) {Serial.println("STATUS CHANGE");}
          #endif
        if (Solid_RGB_Active == 0){
          Event_SetLEDColors( CRGB::Black );
        }else if (Solid_RGB_Active == 1){
          CHSV colorHSV = rgb2hsv_approximate(str2CRGB(Solid_RGB_Color));
          Event_SetLEDColors(CHSV(colorHSV.h, colorHSV.s, Solid_RGB_Brightness));
        }
      }
    }
    // ## MySensors Methods
    void presentation()  {
      sendSketchInfo(MySensors_SketchName, MySensors_SketchVersion);
    
      present(cID_RGB_SELECTOR, S_RGB_LIGHT, "RGB Color Selector", MySensors_RequestACK);
      present(cID_CYCLE_EFFECT, S_LIGHT, "RGB Cycle Effect", MySensors_RequestACK);
      present(cID_CYCLE_EFFECT_SPEED, S_DIMMER, "RGB Cycle Effect Speed", MySensors_RequestACK);
    }
    void receive(const MyMessage &message){
      #ifdef MY_DEBUG
        if (message.isAck()){
          Serial.println("Got ack from gateway");
        }
      #endif
      if (message.type == V_LIGHT){
        #ifdef MY_DEBUG
          if (Print_Debug) {Serial.println("message v_light");}
        #endif
        int current_Light_State = message.getString()[0] == '1';// Incoming on/off command sent from controller ("1" or "0")
        if (message.sensor==cID_CYCLE_EFFECT){// is Cycle Message
          if (current_Light_State==1){//turn cycle on
            Event_LightCycle(true, true, false);
            Event_SolidColor(false, false, true);
          } else {//turn cycle off
            Event_LightCycle(false, true, false);
            Event_SolidColor(false, false, true);
          }
        } else if (message.sensor==cID_RGB_SELECTOR){// is RGB Message
          if (current_Light_State==1){//turn RGB on
            Event_SolidColor(true, true, false);
            Event_LightCycle(false, false, true);
          } else {//turn RGB off
            Event_SolidColor(false, true, false);
            Event_LightCycle(false, false, true);
          }
        } else {
          #ifdef MY_DEBUG
            Serial.print("UNKNOWN Light - Message:");
            Serial.print(message.getString());
            Serial.print(" - Sensor:");
            Serial.println(message.sensor);
          #endif
        }
      } else if (message.type == V_RGB){
        #ifdef MY_DEBUG
          if (Print_Debug) {Serial.println("message v_rgb");}
        #endif
        String szMessage=message.getString();
        strcpy(Solid_RGB_Color, getValue(szMessage,'&',0).c_str());
        Solid_RGB_Active = 1;
      }else if (message.type == V_DIMMER) {// if DIMMER type, adjust brightness
        #ifdef MY_DEBUG
          if (Print_Debug) {Serial.println("message v_dimmer");}
        #endif
        if (message.sensor==cID_RGB_SELECTOR){// is single Message
          if (Solid_RGB_Active==1){//turn RGB on
            Event_SolidColor(true, true, false);
            Event_LightCycle(false, false, true);
          } else {//turn RGB off
            Event_SolidColor(false, true, false);
            Event_LightCycle(false, false, true);
          }
          Solid_RGB_Brightness = map(message.getLong(), 0, 100, 0, 255);
          CRGB colorRGB = str2CRGB(Solid_RGB_Color);
          CHSV colorHSV = rgb2hsv_approximate(colorRGB);
          colorHSV = CHSV(colorHSV.h, colorHSV.s, Solid_RGB_Brightness);
          Event_SetLEDColors(colorHSV);
          #ifdef MY_DEBUG
            if (Print_Debug) {
              Serial.print("colorHSV.h:");
              Serial.println(colorHSV.h);
              Serial.print("colorHSV.s:");
              Serial.println(colorHSV.s);
              Serial.print("colorHSV.v:");
              Serial.println(colorHSV.v);
            }
          #endif
          Event_SendLastColor();
        } else if (message.sensor==cID_CYCLE_EFFECT_SPEED){// is Speed dimmer Message
          Cycle_Effect_Speed = map(message.getLong(), 0, 100, 1, 202);
          #ifdef MY_DEBUG
            if (Print_Debug) {
              Serial.print("Cycle_Effect_Speed: ");
              Serial.println(Cycle_Effect_Speed);
            }
          #endif
        }
      }else if (message.type == V_STATUS) {           // if on/off type, toggle brightness
        #ifdef MY_DEBUG
          if (Print_Debug) {Serial.println("message v_status");}
        #endif
        Solid_RGB_Active = message.getInt();
        Cycle_Effect_Active = 0;
        if (Solid_RGB_Active == 0){
          if (Print_Debug) {Serial.println("Strip OFF");}
          Event_SetLEDColors( CRGB::Black );
        }else{
          if (Print_Debug) {Serial.println("Strip ON");}
          Event_SetLEDColors(strtol(Solid_RGB_Color, NULL, 16));
        }
        //Event_SendLastColor();
      }else if (message.type==V_VAR1) {            // color status
        String szMessage=message.getString();
        #ifdef MY_DEBUG
          if (Print_Debug) {
            Serial.println("message v_var1");
            Serial.println(szMessage);
          }
        #endif
        strcpy(Solid_RGB_Color, getValue(szMessage,'&',0).c_str());
        Solid_RGB_Active = 1;
        Cycle_Effect_Active = 0;
      }
      Status_Change = true;
    }
    // ## Events
    void Event_LightCycle(bool t, bool s, bool u) {
      Cycle_Effect_Active = (t) ? 1 : 0;
      if (u){
        send(MySeonsors_MSG_CYCLE_EFFECT.set(Cycle_Effect_Active),MySensors_RequestACK);
      }
    }
    void Event_SolidColor(bool t, bool s, bool u) {
      Solid_RGB_Active = (t) ? 1 : 0;
      if (u){
        send(MySensors_MSG_RGB_Selector.set(Solid_RGB_Active),MySensors_RequestACK);
      }
    }
    void Event_SetLEDColors( const CRGB& rgb){
      analogWrite(PIN_RED,   rgb.r );
      analogWrite(PIN_GREEN, rgb.g );
      analogWrite(PIN_BLUE,  rgb.b );
    }
    void Event_SendLastColor(){
      String current_status=Solid_RGB_Color+String("&")+String(Solid_RGB_Brightness)+String("&")+String(Solid_RGB_Active);
      send(MySensors_MSG_Last_Color.set(current_status.c_str()),MySensors_RequestACK);
    }
    void Event_RunCycleEffect(unsigned long theMills){
      if (theMills - Cycle_Effect_pMillis >= Cycle_Effect_Speed){
        Cycle_Effect_pMillis = theMills;
        Cycle_Effect_Current_Hue = Cycle_Effect_Current_Hue + 1;
        Event_SetLEDColors( CHSV( Cycle_Effect_Current_Hue, 255, 255) );
      }
    }
    void Event_ColorTestBars(){// Event_ColorTestBars: flashes Red, then Green, then Blue, then Black. Helpful for diagnosing if you've mis-wired which is which.
      Event_SetLEDColors( CRGB::Red );   delay(500);
      Event_SetLEDColors( CRGB::Green ); delay(500);
      Event_SetLEDColors( CRGB::Blue );  delay(500);
      Event_SetLEDColors( CRGB::Black ); delay(500);
    }
    // ## Helper Functions
    String getValue(String data, char separator, int index){
     int found = 0;
      int strIndex[] = {0, -1};
      int maxIndex = data.length()-1;
      for(int i=0; i<=maxIndex && found<=index; i++){
        if(data.charAt(i)==separator || i==maxIndex){
          found++;
          strIndex[0] = strIndex[1]+1;
          strIndex[1] = (i == maxIndex) ? i+1 : i;
        }
      }
      return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
    }
    int x2i(char *s) {
      int x = 0;
      for(;;) {
        char c = *s;
        if (c >= '0' && c <= '9') {
          x *= 16;
          x += c - '0';
        }else if (c >= 'A' && c <= 'F') {
          x *= 16;
          x += (c - 'A') + 10;
        }else {
          break;
        }
        s++;
      }
      return x;
    }
    char* str2char(String command){
        if(command.length()!=0){
            char *p = const_cast<char*>(command.c_str());
            return p;
        }
    }
    CRGB str2CRGB(String s){
      String r = str2char(s.substring(0,2));
      String g = str2char(s.substring(2,4));
      String b = str2char(s.substring(4,6));
      uint8_t red = x2i(r.c_str());
      uint8_t green = x2i(g.c_str());
      uint8_t blue = x2i(b.c_str());
      #ifdef MY_DEBUG
        if (Print_Debug) {
          Serial.print("r:");
          Serial.println(r);
          Serial.print("g:");
          Serial.println(g);
          Serial.print("b:");
          Serial.println(b);
          Serial.print("red:");
          Serial.println(red);
          Serial.print("green:");
          Serial.println(green);
          Serial.print("blue:");
          Serial.println(blue);
        }
      #endif
      CRGB colorRGB = CRGB(red, green, blue);
      return colorRGB;
    }
    

    Hopefully this proves useful to someone 🙂



  • Here is a photo of my actual device with the cover off

    0_1508763006582_IMG_20170317_175657100.jpg



  • @moskovskiy82 I'll see if I'll have time to work on it this week, I'll post an update when I have something.



  • @maghac

    Hello
    I need some help !

    I've ordered few IRLZ44N Mosfets to play with Dimmable LED Actuator project.
    Adafruit RGB LED stripe uses IRLB8721
    Could You please tell me if I could use mentioned IRLZ instead of IRLB in case of described RGB project ?

    Thank You in advance.



  • @Plantex
    In my opinion that should work just fine. The specs are fairly similar. I am using the IRLZ44N myself to drive a five meter long RGBW LED-strip and they do not get warm, even without a heat sink. Total current consumption at 24V is just above 2A when all LEDs are lit.
    Schematics below:
    0_1511539204888_LEDstrip_sch.pdf



  • Geat Work



  • Great project! I could use some help getting this to work. I am using the newbie PCB, just a regular RGB LED for testing and Homeassistant as my controller. Hass adopts the node but I get this error message everytime I restart the node and the switch does not appear on my frontend.

    "Not a valid message: Not valid message sub-type: 40 for dictionary value @ data['sub_type']"

    I am running '2.0' in my hass config file. I have tried '2.1.' and '2.1.1' with no success. Homeassistant version .60.

    I have several temperature sensor nodes talking to hass just fine. Any ideas? I assume I am just missing something simple as I am relatively new to homeassistant and mysensors.

    Thank you in advance for your help!



  • Well, it took some time, but here is v1.8 at last!

    I have modified the code to handle RGBW strips, since I realized that the white light from RGB strips is very uncomfortable and not really suitable for general illumination. It should be fairly easy to convert it back to RGB though. Adding the W channel means that I now need 4 PWM pins, and therefore it was necessary to redefine one of the pins that the radio is connected to - the sketch now expects CE to be connected to pin 8 instead of 9 which is the default (a pro mini only has 3 free PWM pins if you use the default setup).

    I've also completely changed now programs/modes are implemented so it should be easier to add new programs. Feel free to experiment with this and let me know what you think.

    /**
     * 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.
     *
     * LED STRIP sketch for Mysensors
     *******************************
     *
     * REVISION HISTORY
     * 1.0 
     *   Based on the example sketch in mysensors
     * 1.1
     *   prgspeed parameter (send as V_VAR1 message)
     *   HomeAssistant compatible (send status to ack)
     * 1.2
     *   OTA support
     * 1.3
     *   Power-on self test
     * 1.4
     *   Bug fix
     * 1.5
     *   Other default values
     * 1.6
     *   Repeater feature
     * 1.7
     *   Multitasking. Alarm and RELAX modes.
     * 1.8
     *   Reengineered programs/modes logic.
     *   RGBW variant. Requires 4 PWM pins, so we need to move use a different pin for one of radio connections.
     */
    
    #define MY_OTA_FIRMWARE_FEATURE
    // #define MY_REPEATER_FEATURE
    #define MY_NODE_ID AUTO
    
    #define MY_RADIO_NRF24
    
    //#define MY_DEBUG
    
    // Normally the radio uses pin 9 for CE
    #define MY_RF24_CE_PIN  8
    
    #include <MySensors.h>
    
    #define CHILD_ID_LIGHT 1
    
    #define SN "LED Strip"
    #define SV "1.8"
    
    MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
    MyMessage rgbwMsg(CHILD_ID_LIGHT, V_RGBW);
    MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
    MyMessage prgspeedMsg(CHILD_ID_LIGHT, V_VAR1);
    MyMessage programMsg(CHILD_ID_LIGHT, V_VAR2);
    
    #define RR 0
    #define GG 1
    #define BB 2
    #define WW 3
    
    byte current[] = {255, 255, 255, 255};
    byte target[] = {255, 255, 255, 255};
    byte save[] = {0, 0, 0, 0};
    byte temp[] = {0, 0, 0, 0};
    
    float delta[] = {0.0, 0.0, 0.0, 0.0};
    
    char rgbwstring[] = "000000ff";
    
    int on_off_status = 0;
    int dimmerlevel = 100;
    int prgspeed = 20;
    unsigned long last_update = 0;
    unsigned long tick_length = 5;
    int fade_step = 0;
    
    int program_timer;
    int program_cycle;
    int program_step;
    
    // Make sure these are PWM pins
    #define REDPIN 6
    #define GREENPIN 5
    #define BLUEPIN 3
    #define WHITEPIN 9
    
    #define LIGHT_NORMAL 0
    #define LIGHT_FADING 1
    
    #define PROGRAM_NOP 0
    
    int light_mode = LIGHT_NORMAL;
    int program_mode = PROGRAM_NOP;
    
    #define SET 0    
    #define SET_AND_WAIT 1    
    #define SET_RANDOM 2
    #define SET_RANDOM_AND_WAIT 3
    #define FADE 4
    #define FADE_RANDOM 5
    #define WAIT 6
    
    typedef struct rgb_cmd {
      byte cmd;
      int p;
      byte rgbw[4];
    } rgb_cmd;
    
    rgb_cmd program_ALARM[] = {
      {SET_AND_WAIT, 25, {255, 255, 255, 0}},
      {SET_AND_WAIT, 25, {0, 0, 0, 0}},
      {SET_AND_WAIT, 25, {0, 0, 0, 255}},
      {SET_AND_WAIT, 25, {0, 0, 0, 0}}
    };
    
    rgb_cmd program_RELAX[] = {
      {FADE, 1000, {255, 32, 0, 0}},
      {FADE, 1000, {255, 32, 16, 0}},
      {FADE, 1000, {255, 16, 32, 0}},
      {FADE, 1000, {255, 128, 0, 0}},
      {FADE, 1000, {255, 32, 0, 0}},
      {FADE, 1000, {255, 32, 32, 0}},
      {FADE, 1000, {255, 0, 32, 0}}
    };
    
    rgb_cmd program_PARTY[] = {
      {SET_AND_WAIT, 10, {255, 0, 0, 0}},
      {SET_AND_WAIT, 10, {0, 0, 0, 255}},
      {SET_AND_WAIT, 10, {255, 0, 0, 0}},
      {SET_AND_WAIT, 10, {0, 0, 0, 255}},
      {SET_AND_WAIT, 10, {255, 0, 0,0}},
      {SET_AND_WAIT, 10, {0, 0, 0, 255}},
      {SET_AND_WAIT, 10, {255, 0, 0,0}},
      {SET_AND_WAIT, 10, {0, 0, 0, 255}},
      {SET_AND_WAIT, 10, {255, 0, 0, 0}},
      {SET_AND_WAIT, 10, {0, 0, 0, 255}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {SET_AND_WAIT, 50, {0, 0, 255, 0}},
      {SET_AND_WAIT, 50, {0, 255, 255 ,0}},
      {SET_AND_WAIT, 50, {255, 255, 0, 0}},
      {SET_AND_WAIT, 50, {0, 255, 0, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}},
      {FADE_RANDOM, 50, {255, 255, 255, 0}}
    };
    
    
    rgb_cmd* programs[] = {
      &program_ALARM[0], &program_RELAX[0], &program_PARTY[0]
    };
    
    const int program_steps[] = {
      sizeof(program_ALARM)/sizeof(rgb_cmd),
      7,
      22
    };
    
    void setup()
    {
      // Fix the PWM timer. Without this the LEDs will flicker.
      TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
    
      // Output pins
      pinMode(REDPIN, OUTPUT);
      pinMode(GREENPIN, OUTPUT);
      pinMode(BLUEPIN, OUTPUT);
      pinMode(WHITEPIN, OUTPUT);
      
    }
    
    void presentation()
    {
    	// Send the Sketch Version Information to the Gateway
    	sendSketchInfo(SN, SV);
    	present(CHILD_ID_LIGHT, S_RGBW_LIGHT);
    }
    
    void selftest() {
      on_off_status = 1;
      current[RR] = 255;
      current[GG] = 0;
      current[BB] = 0;
      current[WW] = 0;
      set_hw_status();
      wait(200);
      current[RR] = 0;
      current[GG] = 255;
      set_hw_status();
      wait(200);
      current[GG] = 0;
      current[BB] = 255;
      set_hw_status();
      wait(200);
      current[BB] = 0;
      current[WW] = 255;
      set_hw_status();
      wait(200);
      current[RR] = 0;
      current[GG] = 0;
      current[BB] = 0;
      set_hw_status();
      wait(200);
      on_off_status = 0;
    }
    
    void loop()
    {
      static bool first_message_sent = false;
      if ( first_message_sent == false ) {
        selftest();
        set_hw_status();
        send(rgbwMsg.set(rgbwstring));
        send(lightMsg.set(on_off_status));
        send(dimmerMsg.set(dimmerlevel));
        send(prgspeedMsg.set(prgspeed));
        send(programMsg.set(program_mode));
        first_message_sent = true;
      }
    
      unsigned long now = millis();
      // Maybe we wrapped around? Then reset last_update to 0.
      if (now < last_update) {
        last_update = 0;
      }
      
      if (now - last_update > tick_length) {
        last_update = now;
    
        // If we're fading, finish that before we do anything else
        if (light_mode == LIGHT_FADING) {
          calc_fade();
        } else {
          if (program_mode > PROGRAM_NOP) {
            handle_program();
          }
        }
      }
      
      set_hw_status();
      
    }
    
    void receive(const MyMessage &message)
    {
      int val;
      
    	if (message.type == V_RGBW) {
        for (int i=0; i<=3; i++) {
          temp[i] = hextoint(message.data[i*2]) * 16 + hextoint(message.data[i*2+1]);
        }
        // Save old value
        strcpy(rgbwstring, message.data);
    
        init_fade(prgspeed, temp); 
        send(rgbwMsg.set(rgbwstring));
    
    	} else if (message.type == V_LIGHT || message.type == V_STATUS) {
        val = atoi(message.data);
        if (val == 0 or val == 1) {
          on_off_status = val;
          send(lightMsg.set(on_off_status));
        }
        
      } else if (message.type == V_PERCENTAGE) {
        val = atoi(message.data);
        if (val >= 0 and val <=100) {
          dimmerlevel = val;
          send(dimmerMsg.set(dimmerlevel));
        }
        
      } else if (message.type == V_VAR1 ) {
        val = atoi(message.data);
        if (val >= 0 and val <= 2000) {
          prgspeed = val;
          send(prgspeedMsg.set(val));
        }
    
      } else if (message.type == V_VAR2 ) {
        val = atoi(message.data);
        if (val == PROGRAM_NOP) {
          stop_program();
          send(programMsg.set(val));
        } else {
          init_program(val);
          send(programMsg.set(val));
        }
    
    	} else {
    		return;
    	}
    
    }
    
    void execute_step(rgb_cmd cmd) {
    
      if (cmd.cmd == SET) {
        set_rgb(cmd.rgbw);
      } else if (cmd.cmd == SET_AND_WAIT) {
        set_rgb(cmd.rgbw);
        program_timer = cmd.p;
      } else if (cmd.cmd == SET_RANDOM) {
        set_rgb_random(cmd.rgbw);
      } else if (cmd.cmd == SET_RANDOM_AND_WAIT) {
        set_rgb_random(cmd.rgbw);
        program_timer = cmd.p;
      } else if (cmd.cmd == FADE) {
        init_fade(cmd.p, cmd.rgbw);
      } else if (cmd.cmd == FADE_RANDOM) {
        init_fade_random(cmd.p, cmd.rgbw);
      } else if (cmd.cmd == WAIT) {
        program_timer = cmd.p;
      }
    }
    
    void init_program(int program) {
      program_mode = program;
      program_step = 0;
      program_timer = 0;
      save_state();
      execute_step(programs[program_mode-1][0]);
    }
    
    void handle_program() {
      if (program_timer > 0) {
        program_timer--;
      }
      
      if (program_timer == 0) {
        program_step++;
        if (program_step == program_steps[program_mode-1]) {
          program_step = 0;
        }
        execute_step(programs[program_mode-1][program_step]);
      }
    }
    
    void stop_program() {
      restore_state();
      light_mode = LIGHT_NORMAL;
      program_mode = PROGRAM_NOP;
    }
    
    void save_state() {
      memcpy(save, current, 4 );
    }
    
    void restore_state() {
      memcpy(current, save, 4 );
    }
    
    void set_rgb (byte rgbw[]) {
      light_mode = LIGHT_NORMAL;
      memcpy(current, rgbw, 4);
    }
    
    void set_rgb_random (byte rgbw[]) { 
      light_mode = LIGHT_NORMAL;
      for (int i=0; i <= 3; i++){
        current[i] = random(rgbw[i]);
      }
    }
    
    void init_fade(int t, byte rgbw[]) {
      light_mode = LIGHT_FADING;
      fade_step = t;
      memcpy(target, rgbw, 4);
      for (int i=0; i<=3; i++) {
        delta[i] = (target[i] - current[i]) / float(fade_step);
      }
    }
    
    void init_fade_random(int t, byte rgbw[]) {
      light_mode = LIGHT_FADING;
      fade_step = t;
      for (int i=0; i<=3; i++) {
        target[i] = random(rgbw[i]);
        delta[i] = (target[i] - current[i]) / float(fade_step);
      }
    }
    
    void calc_fade() {
      if (fade_step > 0) {
        fade_step--;
        for (int i=0; i<=3; i++) {
         current[i] = target[i] - delta[i] * fade_step;
        }
      } else {
        light_mode = LIGHT_NORMAL;
      } 
    }
    
    void set_hw_status() {
      analogWrite(REDPIN, on_off_status * (int)(current[RR] * dimmerlevel/100.0));
      analogWrite(GREENPIN, on_off_status * (int)(current[GG] * dimmerlevel/100.0));
      analogWrite(BLUEPIN, on_off_status * (int)(current[BB] * dimmerlevel/100.0));
      analogWrite(WHITEPIN, on_off_status * (int)(current[WW] * dimmerlevel/100.0));
    }
    
    byte hextoint (byte c) {
       if ((c >= '0') && (c <= '9')) return c - '0';
       if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
       if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
       return 0;
    }
    

  • Mod

    @maghac I have used the rgbww (warm white) version. Have not compared it with the normal version, but ww is supposed to give a more pleasant tone. By mixing in a lot of red, some green and very little blue I was able to match our existing halogen bulbs very close to 100%.

    https://www.openhardware.io/view/122/Dimmable-LED-kitchen-light-Arduino-APDS-9960-RGBWW-led



  • @maghac I have implemented your 1.8 and I am impressed with the good structure and the performance of your code! Kudos!



  • Just finished a similar project using WS2812B.

    • MySensors/Domoticz support.
    • Infrared Remote support (common 44 key color picker)
    • Color change & fade animations ++.

    https://github.com/dmonty2/ir_remote_leds/tree/mysensors



  • @bgunnarb said in RGB LED strip:

    @maghac I have implemented your 1.8 and I am impressed with the good structure and the performance of your code! Kudos!

    Thanks! Let me know if you have any problems with it - I am still facing some issues actually. After some time (a couple of days or so), the LED strip does not respond to on/off commands any longer. I've implemented a debug feature to try to diagnose the cause of it (I send the node a V_TEXT message and it responds with a series of V_TEXT messages containing the values of variables).



  • @dmonty said in RGB LED strip:

    Just finished a similar project using WS2812B.

    • MySensors/Domoticz support.
    • Infrared Remote support (common 44 key color picker)
    • Color change & fade animations ++.

    https://github.com/dmonty2/ir_remote_leds/tree/mysensors

    Cool. I've played with WS2812B and FastLed in another project. But I'm not sure if they are good enough for general illumination though?



  • @maghac
    No, I have not experienced loss of response like that. At least not since I upgraded my GW to 2.2.0.

    One thing happened though: I was testing the relax, alarm and party modes several times. After that, when fading from one colour to the next in normal mode, it looked like the program first wanted to fade through a number of colours before reaching the final value. This happened a few times and after that it became unresponsive. Cycling power made it go back to normal. I have not been able to repeat the behaviour.



  • @maghac

    Cool. I've played with WS2812B and FastLed in another project. But I'm not sure if they are good enough for general illumination though?

    Yes, the WS2812B are most definitely accent-style lighting with beautiful animations.

    The code also drives a relay switch to turn on my larger light. It shows up in Domoticz as two lights.



  • Thanks a lot for sharing this! I already did the Arduino and MySensors stuff, and started thinking of writing program for it. I'm glad I found this, it fit exactly what I was doing. Here's your code a bit modified, and added some different kind of lamps for the next one looking for references: https://github.com/ikke-t/Arduino-RGB-leds-and-lightbulbs/blob/master/README.md

    The additional piece here is how to command this from OpenHAB, as that's my controller. One needs to modify the RGB info via rules, it's there for reference:

    https://github.com/ikke-t/Arduino-RGB-leds-and-lightbulbs/raw/master/src/rgb.rules

    There are links within that file to references for how to create similar rules for RGB mangling.



  • @maghac A friend just showed me your 1.8 version sketch, and for me so far this is the best working sketch even though I have one issue under Domoticz. (setup: raspberry with mysensors 2 serial gateway, node is arduino pro mini, and 4 mosfet, right now only on breadborad. )

    So I can't control the white and the RGB leds independently. If I adjust the brightness for the W-led, like raise up, the RGB leds will lower their brightness in the same ammount. Same for the RGB, if I raise up the RGB brightness, the W led lowers itself.
    Also the turn on/off seems to be strange if I want to turn on/off the RGB and W independently.

    Are these features, or bugs width Domoticz? 🙂

    I assumed that I will be able to control independently the W and the RGB channel, in domoticz I have two device, one RGB light device, and one White lamp device.

    Can you please help, if all ok with this behaviour, or something needs to be adjusted for Domoticz in the sketch?

    Thanks,
    Yoshi



  • Hi,
    yes, W is just another channel and it works the same way as the RGB channels. There is one single on/off and dimmer amount for all 4 channels. In Home Assistant this works as expected - there is one single unit which has a color selector for RGB values and a slider for the W value.

    Not sure why Domoticz shows it as two separate units - perhaps you can check if there is an option to modify this behaviour?



  • Hello everybody! The connected LED strip lights up, but for some reason the Atmega chip heats up very quickly and strongly. Has anyone come across this?
    My connection scheme:
    alt text


  • Hardware Contributor

    @vladimir - why inputing 5v to RAW? This pin can handle 6-12v only. Try inputing the 5v output from LM2940CT-5 to VCC instead.



  • @sundberg84 I have version 3.3B. I always thought that this is the correct power connection if the source voltage is more than 3.3 V. And with this power connection I wanted to avoid using a separate voltage regulator for the radio module. If I feed 5V to the VCC input, will there be a logic signal on the terminals 3.3V or 5V? And will not this be detrimental to the controller?


  • Hardware Contributor

    @vladimir - ah sorry, my misstake. Didnt see the 3.3v there.
    Strange your chip is getting hot... is there some solder-bridge that shorts something? A bad capacitor? Can you measure resistance between VCC and GND?



  • @sundberg84 said in RGB LED strip:

    Can you measure resistance between VCC and GND?

    I completely rebuilt the whole scheme, I used the new components. This time I used Arduino Nano. Connect power to terminal 5V. The situation is repeated again, the microcontroller becomes very hot. But only when the light is on.

    Honestly, I never measured the resistance. I hope everything was done right.
    alt text


  • Hardware Contributor

    @vladimir not sure about this. Make sure you connected the digital pins to the gate (left pin on irlz44). I don't know why the IC should get hot unless you draw alot of current.



  • @sundberg84 Sorry... I incorrectly connected IRLZ44.🤦‍♂️ 😄 But last time they were connected correctly. Now everything works well. Only LM2940 slightly heats up, according to my subjective sensations, up to 60-70 degrees. This is normal?
    I am very grateful for your help!🙌


  • Hardware Contributor

    @vladimir LM2940 has recommended limit of 125dgr c. 60dgr should be just fine... but still a bit strange since this is rated for 1A and only powers the atmega328p. The current should come directly from the 12v source.



  • @sundberg84 At this time, everything is collected on a plastic prototyping board, in the evening I will move all the components to a breadboard from a textolite, perhaps there will be better results.🤔



  • Colleagues, please share your fresh sketches for RGB-strips.✌



  • @maghac said in RGB LED strip:

    Well, it took some time, but here is v1.8 at last!

    Maybe you have a sketch option for RGB stripes? Same wonderful, but without white LEDs?



  • 0_1542707232553_led controller V3.jpg

    Wanted to leave this here I currently created this PCB to work with @maghac his code. The prototype on the breadboard worked so now it is being produced. As soon as I have a working model I will post the gerber files so anybody interested can also order it for manufacturing. The weird shape by the way is because of a enclosure I am using this one (the 100 X 68 X 50).



  • I have been researching controlling LEDs and this seems one of the better threads on MySensors with links to all the relevant related projects (this @maghac OP one for analog RGB, @LastSamurai RGBW alternative, @dmonty for digital, @ikkeT and others' improvements, and finally @Jim-de-Groot latest board; sorry if I left anyone out). Thanks to everyone for sharing your work!

    So I will ask here a variation of what I I asked @LastSamurai in his thread: Are all of you still using these MySensors based nodes?

    Because I initially started thinking to use a MySensors based solution because I thought Wi-Fi based ones (although arguably easier, cheaper) like MagicHome controllers would be "too slow" but @LastSamurai seemed to state that he changed from MySensors because it was "too slow" in responding.

    Or maybe the reasons are not speed / response time related? Maybe you guys didn't like that interface? Or maybe they were not as readily and cheaply available back when this post began (may 2017)? Or maybe people just like to tinker (I get it, some times I do too)?

    But right now I am thinking about ordering some of those MagicHome devices just to play around with, they are only few dollars each on AliExpress instead of dorking around ordering boards, figuring out correct mosfets to use, implementing software, etc...

    What am I missing here?

    I am not trying to be contrary! I honestly want to know! 😄


Log in to reply
 

Suggested Topics

  • 8
  • 90
  • 2
  • 2
  • 2
  • 3

0
Online

11.2k
Users

11.1k
Topics

112.5k
Posts