LAB03_AmbientOrb

Made by Phoebe

Create an ambient IOT LED notification

Created: December 11th, 2022

0

Ambient Frosted Donut

My final iteration of the ambient orb - an ambient mini donut. The donut shape was made with a 3D pen to diffuse the light from the neopixel ring. This works with IFTTT to change color as a reminder for upcoming google calendar events.


0
Final Code
//----------------------------------------------------------------------
//Phoebe DeGroot
//AMBIENT ORB
//----------------------------------------------------------------------

#include <neopixel.h>
#define LEDPIN D3
#define PROBE A1
#define LED02 D2

#define PIXEL_COUNT 12
#define PIXEL_TYPE WS2812

Adafruit_NeoPixel ring = Adafruit_NeoPixel(PIXEL_COUNT, LEDPIN, PIXEL_TYPE);

typedef struct{
    uint8_t r; 
    uint8_t g; 
    uint8_t b; 
}c; 
typedef struct {
    uint8_t mode = 0;
    c color[PIXEL_COUNT]; 
    bool loop = false; 
    // timer t; 
}LED;

uint8_t count = HIGH; //LED blink for checking timer state
unsigned long timer = 0; 
uint32_t tdelay = 0; 
int dir = -1; 
LED myLEDs; 
bool test = false; 
c ledColor; 

int runFade(String command){
    int input = command.toInt();
    tdelay = round(input*60*1000/255);
    if (test){
        tdelay = tdelay/10;
    }
    dir = -1;
    myLEDs.loop = true; 
    timer = millis();
    
    return input; 
}

void setLEDs(int S,int F,c color){
    uint32_t c = ring.Color(color.r,color.g,color.b);
    constrain(F, S, PIXEL_COUNT);
    for (int i = S; i<F; i++){
        ring.setPixelColor(i,c);
    }
    ring.show();
    delay(1);
}

void setup() {
    ring.begin();
    ring.show();
    Particle.function("fade over minutes", runFade);
    pinMode(LED02,OUTPUT);

    ledColor = {255,255,255};
    setLEDs(0,PIXEL_COUNT,ledColor);
}

void loop() {
    if (myLEDs.loop == true){

        if (millis()-timer>=tdelay){
            count = !count;
            digitalWrite(LED02,count );
            fadeREDWHITE(dir);
            timer = millis();
        }
    }
}


void fadeREDWHITE(int d){
    if (d == 1){
        //to white
        ledColor.g= ledColor.g+1;
        ledColor.b= ledColor.b+1;
        
        constrain(ledColor.g,0,255);
        constrain(ledColor.b,0,255);
        setLEDs(0,PIXEL_COUNT,ledColor);
        
        if (ledColor.g>=255){
            myLEDs.loop = false; //stop loop
        }
    }
    else{
        //to red
        ledColor.g= ledColor.g-1;
        ledColor.b= ledColor.b-1;
        constrain(ledColor.g,0,255);
        constrain(ledColor.b,0,255);
        setLEDs(0,PIXEL_COUNT,ledColor);
        if (ledColor.g<=0) dir = 1;//swap loop direction
        
    }
}
Click to Expand
0

Process

When first working with the neopixels I wrote up a script for a particle function that accepts string based commands and parse them into different LED functions such as "ALL" (sets all pixels to given color), NUM: 1,5 (sets pixels 1-5 to given color) or STORE:1 (store given color at index 1 in pattern). A second particle function parses a a user string of RGB values formated as RRR,GGG,BBB to use with the given LED function.

This seemed to work well and I wanted to use it as a basis for the orb exercise as it would be a good demonstration of more complex user-programmable functionality from robust flexible functions. I could store a couple colors in a pattern and then fade between them when the notification triggers the pattern.  (Code below

However when attempting to get this running I had a lot of excess functionality making it difficult to test, I tried to streamline a bit and made a function explicitly for the red-white fade. Eventually I gave up and started a new file stripping away the generalized functions.

With the code stripped back I was able to trigger the white->red-white fade pretty reliably. I wanted to expand the code so it could flexibly handle other colors and attempted to use the constrain function and a variety of methods to calculate the time interval and increment for each color value. I also tried both struct and array based methods for color definition. I liked the variable naming of the struct but it made

0
Original wip code with multiple led modes - this may have been working but it was hard to debug
//----------------------------------------------------------------------
//Phoebe DeGroot
//AMBIENT ORB
//----------------------------------------------------------------------
#include <neopixel.h>

#define LEDPIN D3
#define PROBE A1

#define PIXEL_COUNT 12
#define PIXEL_TYPE WS2812

Adafruit_NeoPixel ring = Adafruit_NeoPixel(PIXEL_COUNT, LEDPIN, PIXEL_TYPE);

typedef struct {
    unsigned long c_t = 0; 
    uint32_t delay = 0; 
    uint32_t end;
    bool active = true; 
}timer;

typedef struct{
    uint8_t r; 
    uint8_t g; 
    uint8_t b; 
}c; 

typedef struct {
    uint8_t mode = 0;
    c color[PIXEL_COUNT]; 
    bool loop = false; 
    timer t; 
}LED;

uint32_t delay_1 = 1000; 
unsigned long timer_1 = 0; 

String cmdNames[] = {"OFF","ALL","NUM","CHASE","BLINK","FADE","STORE"};
String loopmodeNames[] = {"FADE","BLINK","CHASE","RED2WHITE"};

c setColor; //temp for setting from command only!
c ledColor; //stored single color
c stored[8]; //stored color pattern
char msgString[8];
char tempmsg[12];
int msgInt[2]= {0,0};
LED myLEDs; 
int dir = 1; 

void setLEDs(int S,int F,c color){
    uint32_t c = ring.Color(color.r,color.g,color.b);
    constrain(F, S, PIXEL_COUNT);
    for (int i = S; i<F; i++){
        ring.setPixelColor(i,c);
    }
    ring.show();
    delay(10);
}

void fadeLEDs(int n1, int n2){
    
}

int setLEDMode(String command){
    msgInt[0],msgInt[1] = 0,0;
    char *msgNdx; // pointer index for parsing input message into tokens
    strcpy(tempmsg,command); //store first part of message as char array 
    msgNdx = strtok(tempmsg, ":,"); //split on : , 
    strcpy(msgString, msgNdx); //store first part of message as char array 
    msgString[0] &= 0xDF; 
    msgString[1] &= 0xDF; //make chars uppercase
    msgNdx = strtok(NULL, ":,"); //continue tokenizing message
    msgInt[0] = atoi(msgNdx); //store next part of message as int
     msgNdx = strtok(NULL, ":,"); //continue tokenizing message
    msgInt[1] = atoi(msgNdx); //store next part of message as int
    getCommand(); //run command with message
    timer_1 = millis();
    return myLEDs.mode; 
}


void store(int n, c color){
    constrain(n, 1, 8);
    stored[n] ={color.r,color.g,color.b};
}

int setLEDColor(String command){
    char *msgNdx; // pointer index for parsing input message into tokens
    strcpy(tempmsg,command); //store first part of message as char array 
    msgNdx = strtok(tempmsg, ":,"); //split on : , 
    setColor.r = atoi(msgNdx);
    msgNdx = strtok(NULL, ":,");
    setColor.g = atoi(msgNdx);
    msgNdx = strtok(NULL, ":,");
    setColor.b = atoi(msgNdx);
    return colortoint(setColor);
}


void getCommand(){
    char cmd = msgString[0];
    int minutes; 
    switch(cmd){
        case 'A':
        myLEDs.loop = false; 
        myLEDs.mode = 4; 
        setLEDs(0,PIXEL_COUNT,setColor);
        break;
        case 'N':
        myLEDs.loop = false; 
        myLEDs.mode = 4; 
        setLEDs(msgInt[0],msgInt[1],setColor);
        break;
        case 'F':
        fadeLEDs(msgInt[0],msgInt[1]);
        myLEDs.mode = 0; 
        break;
        case 'C':
        myLEDs.mode = 2; 
        //chase mode
        break;
        case 'B':
        myLEDs.mode = 1; 
        //blink mode
        break;
        case 'S':
        //store the color at index
        break;
        store(msgInt[0]+1,setColor);
        case 'R':
        //fade to red
        myLEDs.loop = true; 
        myLEDs.mode = 3; 
        minutes = msgInt[0];
        delay_1= 10000;
        myLEDs.t.delay = round(minutes*1000*60/255);
        dir = -1;
        break;
        case 'W':
        //fade to white
        myLEDs.loop = true; 
        myLEDs.mode = 3; 
        minutes = msgInt[0];
        myLEDs.t.delay = round(minutes*1000/255);
        delay_1 = 10000;
        dir = 1; 
        break;
    }
    
}


void setup() {
    ring.begin();
    ring.show();

    Particle.function("LED mode", setLEDMode);
    Particle.function("LED Color", setLEDColor);

    ledColor = {255,255,255};
    setLEDs(0,PIXEL_COUNT,ledColor);
}
int colortoint(c color){
    return color.r*1000000+color.g*1000+color.b; 
    
}

void fadeREDWHITE(){
    if (dir == 1){
        //to white
        ledColor.g= ledColor.g+1;
        ledColor.b= ledColor.b+1;
        
        constrain(ledColor.g,0,255);
        constrain(ledColor.b,0,255);
        setLEDs(0,PIXEL_COUNT,ledColor);
        
        if (ledColor.g>=255) myLEDs.loop = false; //stop loop
    }
    else{
        //to red
        ledColor.g= ledColor.g-1;
        ledColor.b= ledColor.b-1;
        constrain(ledColor.g,0,255);
        constrain(ledColor.b,0,255);
        setLEDs(0,PIXEL_COUNT,ledColor);
        if (ledColor.g<=0) dir = 1;//swap loop direction
        
    }
}
void loop() {
    if (myLEDs.loop == true){
        if (millis()-timer_1>=delay_1){
            switch(myLEDs.mode){
                case 0:
                //fade
                case 1:
                //blink
                case 2:
                //chase
                default:
                    fadeREDWHITE;
            }
            timer_1 = millis();
        }
    }
}
Click to Expand
0

Reflection


This is not the first time even in this class where I overcomplicate things by trying to write more advanced code

Again I feel I need to be more realistic about the goal of the process- avoid optimizing functions I'm only using for simple tasks and make sure to iteratively build and test code I'm working on.

As with my experiences with other labs I do find the online particle IDE to be frustrating -causing the loss of work and making it hard to debug. I had tried the VScode environment earlier on in the course but I had forgotten how to work with it. This reminds me that it's worth taking the time to better utilize that environment.

0
code modification trying to allow fade to any color - this wont fade back to white and just loops
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
#define LEDPIN D3
#define PROBE A1
#define LED01 D4
#define LED02 D2


#define PIXEL_COUNT 12
#define PIXEL_TYPE WS2812

Adafruit_NeoPixel ring = Adafruit_NeoPixel(PIXEL_COUNT, LEDPIN, PIXEL_TYPE);

typedef struct{
    uint8_t r; 
    uint8_t g; 
    uint8_t b; 
}c; 

typedef struct {
    uint8_t mode = 0;
    c color[PIXEL_COUNT]; 
    bool loop = false; 
    int dir = -1; 
    // timer t; 
}LED;
LED myLEDs; 

uint8_t count = HIGH; //LED blink for checking timer state
unsigned long timer = 0; 
uint32_t tdelay = 0; 


bool test = false; 
int ledColor[3];
int setColor[3];
float factor[3]= {1,1,1};
float colorVals[3]; 
int colorFactor=255;
int mode; 



void getFactor(){
    int f[3];
    for (int i=0; i<3; i++){
        f[i] = ledColor[i]-setColor[i];
    }
    int maxnum = max(abs(f[0]),abs(f[1]));
    maxnum=max(maxnum,abs(f[2]));
    colorFactor = maxnum;
    for (int i=0; i<3; i++){
        factor[i]=f[i]/maxnum;
        colorVals[i]=ledColor[i];
    }
}

int runFade(String command){
    int input = command.toInt();
    tdelay = round(input*60*1000/255);
    if (test){
        tdelay = tdelay/10;
    }
    myLEDs.dir = -1;
    myLEDs.loop = true;
    digitalWrite(LED01,HIGH);
    timer = millis();
    
    return input; 
}

int setLEDColor(String command){
    char tempmsg[12];
    char *msgNdx; // pointer index for parsing input message into tokens
    strcpy(tempmsg,command); //store first part of message as char array 
    msgNdx = strtok(tempmsg, ":,"); //split on : , 
    setColor[0] = atoi(msgNdx);
    msgNdx = strtok(NULL, ":,");
    setColor[1]= atoi(msgNdx);
    msgNdx = strtok(NULL, ":,");
    setColor[2] = atoi(msgNdx);
    getFactor();
    return 1;
}

void setLEDs(int S,int F,int* color){
    uint32_t c = ring.Color(color[0],color[1],color[2]);
    constrain(F, S, PIXEL_COUNT);
    for (int i = S; i<F; i++){
        ring.setPixelColor(i,c);
    }
    ring.show();
    delay(1);
}

void setup() {
    ring.begin();
    ring.show();
    Particle.function("fade over minutes", runFade);
    Particle.function("LED Color", setLEDColor);
    pinMode(LED02,OUTPUT);
    pinMode(LED01,OUTPUT);

    for (int i=0; i<3; i++){
        ledColor[i]=255;
    }
    setLEDs(0,PIXEL_COUNT,ledColor);
}

void loop() {
    if (myLEDs.loop == true){
        if (millis()-timer>=tdelay){
            count = !count;
            digitalWrite(LED02,count );
            digitalWrite(LED01,count );
            fade(myLEDs.dir);
            timer = millis();
        }
    }

}

bool check(int* A,int* B){
    for (int i=0; i<3; i++){
        if (A[i]!=B[i]){
            return false; 
        }
    }
    return true;
}
    
    
void fade(int d){
    int white[3]={255,255,255};
    if (check(ledColor,white)){
        //if ledColor is white
        myLEDs.loop = false; //stop loop
        mode=0;//waiting
    }
    
    else if (check(ledColor,setColor)){
        //if ledColor and setColor are the same
        myLEDs.dir = 1; 
        mode=2;//return to white
    }
    
    
    if (d == 1){
        digitalWrite(LED02,HIGH);
        //to white
        for (int i=0; i<3; i++){
            ledColor[i]++;
            constrain(ledColor[i],0,255);
        }
        setLEDs(0,PIXEL_COUNT,ledColor);
    }
    else if (d == -1){
        digitalWrite(LED01,HIGH);
        //to other color
        for (int i=0; i<3; i++){
            colorVals[i] = colorVals[i]-factor[i];
            ledColor[i] = round(colorVals[i]);
            constrain(ledColor[i],setColor[i],255);
        }
        setLEDs(0,PIXEL_COUNT,ledColor);
    }
}
Click to Expand
x