Fade Neopixel Colors


#1

I have one of the early Particle Neopixel rings with 24 pixels and the photon plugs into it.

I am using the 24 LEDs to display the battery SOC of another device. This is working well.

Right now I choose one LED to light up depending on the incoming SOC and the number of pixels (24)

socled = (PIXEL_COUNT * soc_int / 100);

I choose the color of the pixel in an if statement:

if(soc_int >= 0 && soc_int <= 30 ){                     //if SOC is between 0% and 30% led is red
        ring.clear();
        ring.setPixelColor(socled, RED);
    }
    else if(soc_int > 30 && soc_int <= 70 ){                //if SOC is between 30% and 70% led is amber
        ring.clear();
        ring.setPixelColor(socled, AMBER);
    }
    else if(soc_int > 70 && soc_int <= 100 ){               //if SOC is between 70% and 100% led is green
        ring.clear();
        ring.setPixelColor(socled, GREEN);
    }
    else{
        ring.clear();                                       //if SOC is not a value between 0 and 100, LED is off
    }

What I would like is to show a gradient, for example if the SOC falls between two LED’s values, so if the result doesn’t exactly land on an LED position, Two leds would be partially lit, their relative values represent the weighting. ie… if the SOC chosen is 10.25, the led 10 would be fully lit, and led 11 would be 1/4 lit.

Can anyone give some clues how to accomplish that?

My full code below:

STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));                  //select u.FL antenna

#include <neopixel.h>                                       // define neopixel ring

#define PIXEL_COUNT 24
#define PIXEL_PIN D6
#define PIXEL_TYPE WS2812B

Adafruit_NeoPixel ring(PIXEL_COUNT,PIXEL_PIN,PIXEL_TYPE);   

#define RED ring.Color(255,0,0)                             //setup the main colors for the fuel gauge
#define GREEN ring.Color(0,255,0)
#define AMBER ring.Color(255,140,0)

double socled;                                              //initialize variable for the position of the lit led

void setup() {
    

    ring.begin();                                           //initialize led ring
    ring.show();                                            //turn pixels off
    ring.setBrightness(80);                                 //set the ring brightness
    
    Particle.subscribe("ps-soc", myHandler, MY_DEVICES);    //subscribe to the state of charge published by our friend device
    Particle.variable("soc-led", socled);                   //publish a variable to indicate which led position was chosen
}

void myHandler(const char *event, const char *data)         //this handles the string from the particle.subscribe function
{
    String SOC = String(data);                              //create a new string that will hold the SOC data
    int soc_int = SOC.toInt();                              //create an int and convert the string into an int
    socled = (PIXEL_COUNT * soc_int / 100);                 //turn the SOC data from a percentage to an LED position based on how many leds in the ring
    if(soc_int >= 0 && soc_int <= 30 ){                     //if SOC is between 0% and 30% led is red
        ring.clear();
        ring.setPixelColor(socled, RED);
    }
    else if(soc_int > 30 && soc_int <= 70 ){                //if SOC is between 30% and 70% led is amber
        ring.clear();
        ring.setPixelColor(socled, AMBER);
    }
    else if(soc_int > 70 && soc_int <= 100 ){               //if SOC is between 70% and 100% led is green
        ring.clear();
        ring.setPixelColor(socled, GREEN);
    }
    else{
        ring.clear();                                       //if SOC is not a value between 0 and 100, LED is off
    }
}

void loop() {
    ring.show();
    delay(1000);

}

#2

Just a side note about your first snippet:
Each and every branch in your statement performs a ring.clear() action, hence it would be better in style and shorter in code to put that call befor the condition.

About your original request, the modulo operator (%) would give you the remainder of your division

  socled         = (PIXEL_COUNT * soc_int / 100);  // number of fully lit LEDs
  int rest       = (PIXEL_COUNT * soc_int) % 100;  // part of SoC that goes beyond the last lit LED's value
  int brightness = rest * 255 / 100;               // normalise brighness value 

#3

Thanks very much for your insight, that will help me out big time!

I’m having issues with keeping this photon online. The light keeps breathing cyan, but the web console shows offline (gray dot), and if I flash it through the web-ide, it says “flash successful” but nothing happens to the photon. If I reboot it, it comes back online properly.

The only “weird” thing about this photon compared to the others I have is that the chip antenna broke off of it years ago, hence, I’m using external antenna with STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));

It stays online for hours while I’m interacting with it. But if I walk away for ~30 mins, it becomes unreachable, and the “Last Handshake” reflects the loss of connectivity.

the wifi network is near, 2.4ghz, and 20mhz bw (and I have other photons connected to it).

Is there anything in this code that would be contributing to this issue?

Is there anything I should put in my code that could alleviate it?


#4

Have you tried?

SYSTEM_MODE(SEMI_AUTOMATIC);
SYSTEM_THREAD(ENABLED);