LAB03_AmbientOrb
Made by Phoebe
Made by Phoebe
Create an ambient IOT LED notification
Created: December 11th, 2022
//----------------------------------------------------------------------
//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
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
//----------------------------------------------------------------------
//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
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.
// 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