RGB Light, cancel loop?



  • Hello, I have modified the RGB-3D example to run my Neopixel as a moodlight. I am trying to do so that When I press light switch ON, it will run a loop that slowly changes colour. When I press light switch OFF it will exit the loop and turn leds off.

    Turning it on works, but It seem that it gets stuck in the loop so that it cant turn off.. How can I fix this?

    #define SN   "Moodlight"
    #define SV   "v1.0"
    
    
    #include <Adafruit_NeoPixel.h>
    #ifdef __AVR__
      #include <avr/power.h>
    #endif
    #include <SPI.h>
    #include <MySensor.h>
    
    
    #define NEO_PIN      4 // NeoPixels input pin
    #define NUMPIXELS    16 // Number of nexpixels in ring/strip
    
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, NEO_PIN, NEO_GRB + NEO_KHZ800);
    
    MySensor gw;
    
    MyMessage rgbShowState(0, V_LIGHT);
    
    int isShow;
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
    
      gw.sendSketchInfo(SN, SV);
    
      gw.present(0, S_LIGHT, "Moodlight", false);
    
       // Correct RGB show state for first start and load it (set to 'On' at first start)
      gw.saveState(0, constrain((int8_t)gw.loadState(0), 0, 1));
      isShow=gw.loadState(0);
           
      // Send RGB show state to controler (request ack back: true/false)
      gw.send( rgbShowState.set(isShow), false);
      
      if (isShow==1){Serial.println("RGB show running..."); }
      Serial.println("Ready to receive messages...");  
    
      strip.begin();
      strip.show();
      
    }
    
    void loop()
    {
      // Process incoming messages (like config and light state from controller)
      gw.process();    
          
      // Run RGB show if is set
      while (isShow==1)
      {
          rainbow(6000);
      }
      
    }
    
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck())
      {
         Serial.println("Got ack from gateway");
      }
      if (message.type == V_LIGHT)
      {
        // Incoming on/off command sent from controller ("1" or "0")
        int lightState = message.getString()[0] == '1';
      
        // if receive RGB Show On commands, start the show
        if (message.sensor==0 && lightState==1){ rgbShowOn(); }
        
            // if receive RGB Show Off commands, stop the show
        else if (message.sensor==0 && lightState==0){ rgbShowOff(); }
           
        
      }
    }
         
    void rgbShowOn()
    {
      // define show On
      isShow=1;
      // Write some debug info
      Serial.println("Show must go on");
    }
       
    void rgbShowOff()
    {
      // define show Off
      isShow=0;
      Serial.println("Stop the show");      
    }
    
    void rainbow(uint8_t wait) {
      uint16_t i, j;
    
      for(j=0; j<256; j++) {
        for(i=0; i<strip.numPixels(); i++) {
          strip.setPixelColor(i, Wheel((i+j) & 255));
        }
        strip.show();
        delay(wait);
       }
     }
    
    
    // Input a value 0 to 255 to get a color value.
    // The colours are a transition r - g - b - back to r.
    uint32_t Wheel(byte WheelPos) {
      WheelPos = 255 - WheelPos;
      if(WheelPos < 85) {
        return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
      }
      if(WheelPos < 170) {
        WheelPos -= 85;
        return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
      }
      WheelPos -= 170;
      return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
    }```

  • Hero Member

    Put the gw.process inside your while (isShow==1) loop should help. You are not receiving anything when inside that loop...



  • @AWI Hi, thanks for reply.

    I tried putting gw.process on a few different places now but it still seems like it gets stuck in the loop rainbow();

    If I remove rainbow(); from the main loop, everything seems to work according to the debug messages. Except for that there is no lights but.. Either I need to listen to messages from gw in the rainbow(); or this to be reworked in some way.


  • Hardware Contributor

    I think the issue is that you shouldn't be calling delay() basically anywhere. The main loop() needs to run at a reasonable rate (i.e. be called at least every millisecond). One option: make rainbow() just show one time (remove the outer loop and delay calls) and pass in the current j variable as an argument. Then in loop(), use a timer to test if enough time has passed to re-call rainbow(). Any arduino ellapsed time/timer libraries will work fine. Here is an example: http://playground.arduino.cc/Code/ElapsedMillis. In that example, change the ledState/digitalWrite lines to call the new rainbow() function.



  • @TD22057 Okey, thank you. I will try with millis when I have time this weekend :+1:


  • Hero Member

    @msebbe another option is to replace the delay( time ) with gw.wait( time ). This will allow for reception of messages and still use a simple "delay".



  • This is my attempt at millis... I can still not get it to stop. :sadface:

    #define SN   "Moodlight"
    #define SV   "v1.0"
    
    
    #include <Adafruit_NeoPixel.h>
    #ifdef __AVR__
    #include <avr/power.h>
    #endif
    #include <SPI.h>
    #include <MySensor.h>
    
    
    #define NEO_PIN 4 // NeoPixels input pin
    #define NUMPIXELS 16 // Number of nexpixels in ring/strip
    #define interval 50
    
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, NEO_PIN, NEO_GRB + NEO_KHZ800);
    
    long previousMillis = 0;
    int l = 0;
    int isShow;
    
    MySensor gw;
    MyMessage rgbShowState(0, V_LIGHT);
    
    void setup()
    {
      gw.begin(incomingMessage, AUTO, true);
    
      gw.sendSketchInfo(SN, SV);
    
      gw.present(0, S_LIGHT, "Moodlight", false);
    
       // Correct RGB show state for first start and load it (set to 'On' at first start)
      gw.saveState(0, constrain((int8_t)gw.loadState(0), 0, 1));
      isShow=gw.loadState(0);
           
      // Send RGB show state to controler (request ack back: true/false)
      gw.send( rgbShowState.set(isShow), false);
      
      if (isShow==1){Serial.println("RGB show running..."); }
      Serial.println("Ready to receive messages...");  
    
      strip.begin();
      strip.show();
      
    }
    
    void loop()
    {
      // Process incoming messages (like config and light state from controller)
      gw.process();    
          
      // LEDs off if state 0
      if (isShow == 0)
      {
        strip.Color(0,0,0);
      }
      // Run RGB show if state 1
      if (isShow == 1)
      {
        
        newRainbow();
      }
      
      
    }
    
    void incomingMessage(const MyMessage &message)
    {
      
      if (message.type == V_LIGHT)
      {
        // Incoming on/off command sent from controller ("1" or "0")
        int lightState = message.getString()[0] == '1';
      
        // if receive RGB Show On commands, start the show
        if (message.sensor==0 && lightState==1){ rgbShowOn(); }
        
            // if receive RGB Show Off commands, stop the show
        else if (message.sensor==0 && lightState==0){ rgbShowOff(); }
           
        
      }
    }
         
    void rgbShowOn()
    {
      // define show On
      isShow = 1;
      // Write some debug info
      Serial.println("Show must go on");
    }
       
    void rgbShowOff()
    {
      // define show Off
      isShow = 0;
      Serial.println("Stop the show");      
    }
    
    void newRainbow()
    {
      if (millis() - previousMillis > interval * 2)
      {
        for (int h = 0; h < strip.numPixels(); h++)
        {
          strip.setPixelColor(h, Wheel((h + l) & 255));
        }
        l++;
        if (l >= 256)
          l = 0;
        strip.show();
        previousMillis = millis();
      }
    }
    
    
    // Input a value 0 to 255 to get a color value.
    // The colours are a transition r - g - b - back to r.
    uint32_t Wheel(byte WheelPos) {
      WheelPos = 255 - WheelPos;
      if(WheelPos < 85) {
        
        return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
      }
      if(WheelPos < 170) {
        
        WheelPos -= 85;
        return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
      }
      WheelPos -= 170;
      return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
    }
    


  • hi,

    what difference between what I had named rgbShow and your moodlight ?



  • @vil1driver

    I guess it is that neopixel cant run with your RGB-3D since it only has 3 pins - VCC, GND, DATA.

    Edit : I figured it out! I will add some more functions to it and then share it.

    Thx for help!


  • Contest Winner

    @msebbe

    an easy way would be a non-blocking function that breathes the LED... I did this for a recent project:

    void breatheUpdate(const uint8_t * segment, const uint8_t numLeds, const uint32_t increment, const uint8_t step)
    {
      static uint32_t lastTimeChange = 0;
      static uint8_t direction = 1;
      const static uint8_t lowLimit = 50;
      static uint8_t value = lowLimit;
      if(millis() - lastTimeChange > increment)
      {
        value +=(direction * step);
        value = constrain(value, lowLimit, 255);
        if (value <= lowLimit || value >= 255)
        {
          direction = direction * -1;
        }
        for(uint8_t i = 0; i < numLeds; i++)
        {
          myPixels.setPixelColor(segment[i], myPixels.Color(0, 0, value));
        }
        myPixels.show();
        lastTimeChange += increment;
      }
    }
    

    segment here is an array of leds, but you can convert the function to a single neopixel easily.

    loop() would look like this:

    void loop()
    {
      gw.process();
      if (isShow)
      {
        breatheUpdate(mySegment, sizeof(mySegment), breatheRate, 1);
      }
    }
    


  • I made a ws2812 (neopixel) sketch not to long ago, maybe you can use some or all of the code.
    my loop only contains gw.process() for incomming messages (color, brightness, off).
    I made no loops for color shows because i'm not interested in that but is should not be to difficult to adapt the code, there is however a short colorwhipe (chaser) when changing the strip color

    #include <MySensor.h>
    #include <SPI.h>
    
    #include "Adafruit_NeoPixel.h"
    
    #define NUMPIXELS 4   // Number of connected pixels on a single datapin
    #define PIN 4         // Digital output pin
    
    #define NODE_ID AUTO  //254 for testing purpose
    #define CHILD_ID 0  
    
    
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
    long RGB_values[3] = {0,0,0};
    
    MySensor gw;
    
    void setup()
    {
        gw.begin(incomingMessage, NODE_ID, false);
        gw.sendSketchInfo("RGB Node", "1.0");
        gw.present(CHILD_ID, S_RGB_LIGHT);
        strip.begin();
        strip.show(); // Update the strip, to start they are all 'off'
    }
    
    
    void loop()
    {
        gw.process();
    }
    
    void incomingMessage(const MyMessage &message) {
        if (message.type==V_RGB) {
      // starting to process the hex code
            String hexstring = message.getString(); //here goes the hex color code coming from through MySensors (like FF9A00)
            long number = (long) strtol( &hexstring[0], NULL, 16);
            RGB_values[0] = number >> 16;
            RGB_values[1] = number >> 8 & 0xFF;
            RGB_values[2] = number & 0xFF;
    
            colorWipe(Color(RGB_values[0],RGB_values[1],RGB_values[2]), 60);
         }
         
        if (message.type==V_DIMMER) {
          strip.setBrightness(round((2.55*message.getInt())));
          strip.show();
          }
          
        if (message.type==V_LIGHT) {
           if (message.getInt() == 0) {
            strip.clear();
            strip.show();
           }
        }
      
    }
     
    void colorWipe(uint32_t c, uint8_t wait) {
      int i;
     
      for (i=0; i < strip.numPixels(); i++) {
          strip.setPixelColor(i, c);
          strip.show();
          delay(wait);
      }
    }
    
        /* Helper functions */
    
    // Create a 15 bit color value from R,G,B
    uint32_t Color(byte r, byte g, byte b)
    {
      uint32_t c;
      c = r;
      c <<= 8;
      c |= g;
      c <<= 8;
      c |= b;
      return c;
    }
       
    

    It's not the cleanest code but it works for me...

    have fun.


Log in to reply
 

Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.