Jon Phillips
Published © MIT

Blue Tooth NeoPixel controller

A tower of Neo Pixels controlled by a combination of a Blue Tooth Controller and an Encoder Dial.

IntermediateWork in progress100
Blue Tooth NeoPixel controller

Things used in this project

Hardware components

Photon 2
Particle Photon 2
×1
Adafruit NeoPixel Digital RGB LED Strip 144 LED, 1m White
Adafruit NeoPixel Digital RGB LED Strip 144 LED, 1m White
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1

Software apps and online services

Visual Studio 2017
Microsoft Visual Studio 2017
Adafruit Bluefruit mobile app

Story

Read more

Code

Neo Pixel controller with BlueTooth and encoder input

C/C++
 * Project NeoPixel controller with Blue Tooth and Encoder Input
 * Author: Jon Phillips
 * Last Updated: 19 November 2023
 * 
 */

#include "Particle.h"
#include <colors.h>
#include <Encoder.h>
#include <neopixel.h>
#include <math.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
SYSTEM_MODE(SEMI_AUTOMATIC);
int OLED_RESET(-1);
Adafruit_SSD1306 display(OLED_RESET);



const BleUuid serviceUuid("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
const BleUuid rxUuid("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
const BleUuid txUuid("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
const int UART_TX_BUF_SIZE = 50;
uint8_t txBuf[UART_TX_BUF_SIZE];
uint8_t i;

void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context);
BleCharacteristic txCharacteristic("tx", BleCharacteristicProperty::NOTIFY, txUuid, serviceUuid);
BleCharacteristic rxCharacteristic("rx", BleCharacteristicProperty::WRITE_WO_RSP, rxUuid, serviceUuid, onDataReceived, NULL);
BleAdvertisingData data;

Encoder enCoder(D8,D9);
const int PIXELCOUNT = 30;
Adafruit_NeoPixel pixel(PIXELCOUNT,SPI1,WS2812B);
int encRead;
int encPos;
int newEnc;
int prevEnc;
int j;
int k;
int rBow;
int rRed;
int rBlue;
int rGreen;
void pixelFill(int startPixel, int endPixel,int hex);
void ChooseShow();
void DisplayShow();
int setColor;
int pBright=60;
int pHeight=30;
int rainB;
int randColor; 
int hexColor;
int x;
int y;
int z;
float t;
float t2;
int sinWave;
int sinPix;
int ShowChoice;


void setup() {
  Serial.begin(9600);


  BLE.on();
  BLE.addCharacteristic(txCharacteristic);
  BLE.addCharacteristic(rxCharacteristic);
  data.appendServiceUUID(serviceUuid);
  BLE.advertise(&data);

  pixel.begin();
  pixel.show();
  pixel.setBrightness(60);

  display.begin(SSD1306_SWITCHCAPVCC,0x3C);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.display();


  Serial.printf("Photon2 BLE Address %s\n",BLE.address().toString().c_str());
}

void loop() {
  ChooseShow(); //uses encoder to choose which show will be presented when button 3 is pushed
}

void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context){
  uint8_t i;
  int rRx, bRx, gRx;
 
 

  
  
  

  Serial.printf("Received data from: %02X:%02X:%02X:%02X:%02X:%02X\n",peer.address()[0],peer.address()[1],peer.address()[2],peer.address()[3],peer.address()[4],peer.address()[5]);
  Serial.printf("Bytes: ");
  for (i=0;i<len;i++){
    Serial.printf("%02X ",data[i]);
  }
  Serial.printf("\n");
  Serial.printf("Message: %s\n",(char *)data);



                        //COLOR PICKER
  
  
  // Photon2 Recieves RGB data from color picker, converts to Hex, and displays color on pixels

  if(data[1]==0x43){ 
    rRx = data[2];
    gRx = data[3];
    bRx = data[4];
    hexColor = (rRx<<16)|(gRx<<8)|(bRx);
    pixelFill(0,pHeight,hexColor);
    Serial.printf("Hex color -- %i",hexColor);
    setColor = hexColor;  // allows color to remain when switcing to Control Pad
  }


                    // CONTROL PAD
    
 
// button 1 puts pixels in room light mode
if((data[1]==0x42)&&(data[2]==0x31)&&(data[3]==0x31)){
  pixel.setBrightness(150);
  pixelFill(0,30,white);
 
}
 //up arrow increases brightness 
if((data[1]==0x42)&&(data[2]==0x35)&&(data[3]==0x31)){
  pBright = pBright+20;
  pixel.setBrightness(pBright);
  pixelFill(0,pHeight,setColor);
             
}
  //down arrow decreases brightness
if((data[1]==0x42)&&(data[2]==0x36)&&(data[3]==0x31)){
  pBright=pBright-20;
  pixel.setBrightness(pBright);
  pixelFill(0,pHeight,setColor);
}

  // left arrow decreases pixel height
if((data[1]==0x42)&&(data[2]==0x37)&&(data[3]==0x31)){
  pHeight=pHeight-1;
  pixelFill(0,pHeight,setColor);
} 

// right arrow increases pixel height
if((data[1]==0x42)&&(data[2]==0x38)&&(data[3]==0x31)){
  pHeight=pHeight+1;
  pixelFill(0,pHeight,setColor);
}

  // button 2 cylcles through the colors of the rainbow
if((data[1]==0x42)&&(data[2]==0x32)&&(data[3]==0x31)){ rainB=rainbow[y];
  pixelFill(0,pHeight,rainB);
  setColor=rainB;   //sets color at a constant for the rest of the code
  y++;
  if(y>=7){
    y=0;
  }

  
}

   // button 3 displays show on OLED screen
if((data[1]==0x42)&&(data[2]==0x33)&&(data[3]==0x31)){ 
    pixel.clear();  
    DisplayShow();
}



   // button 4 turns off pixels
if((data[1]==0x42)&&(data[2]==0x34)&&(data[3]==0x31)){
    pixel.clear();
    pixel.show();
  
  
}

}

void pixelFill(int startPixel, int endPixel, int hex){
int i;
int j;

pixel.clear();
for(i=startPixel;i<endPixel;i++){
    pixel.setPixelColor(i,hex);   
}

pixel.show();

for(j=29;j>endPixel;j--){
    pixel.clear();
}
}

void ChooseShow(){
  encPos = enCoder.read();
  
  if((encPos>=0)&&(encPos<=5)){
    display.clearDisplay();
    display.setCursor(0,0);
    display.printf("Sparkle");
    display.display();
    ShowChoice=1;
  }
  if((encPos>=10)&&(encPos<=15)){
    display.clearDisplay();
    display.setCursor(0,0);
    display.printf("Blob");
    display.display();
    ShowChoice=2;
  }

  if((encPos>=20)&&(encPos<=25)){
    display.clearDisplay();
    display.setCursor(0,0);
    display.printf("Rainbow");
    display.display();
    ShowChoice=3;
  }
  if((encPos>=30)&&(encPos<=35)){
    display.clearDisplay();
    display.setCursor(0,0);
    display.printf("Fill The\nGlass");
    display.display();
    ShowChoice=4;
  }
  
  if(encPos<0){
    enCoder.write(35);
    encPos=35;
  }
  if(encPos>35){
    enCoder.write(0);
    encPos=0;
  }


}
void DisplayShow(){
  int rbTimer;
  int blobTimer;
  static int y;
  static int lasty;

//sparkle
if(ShowChoice==1){
  for(x=0;x<75;x++){
      randColor = random(0x000000,0xFFFFFF);
      pixel.setBrightness(random(0,255));
      pixel.setPixelColor(random(0,30),randColor);
      pixel.show();
      pixel.clear();
      delay(random(50,100));   
  }
  pixel.setBrightness(pBright);   
  pixelFill(0,pHeight,setColor);

}

//Blob
if(ShowChoice==2){
  blobTimer=millis();
  while((millis()-blobTimer)<15000){
      t=millis()/4000.0;
      t2=millis()/20000.0;
      sinWave = 125*sin(2*M_PI*(2)*t)+127;
      sinPix = 14*sin(2*M_PI*(2)*t2)+15;
      pixel.setBrightness(sinWave);
      pixelFill(sinPix-1,sinPix+2,setColor);
     
  }
  pixel.setBrightness(pBright);   
  pixelFill(0,pHeight,setColor);
}

//Rainbow
if(ShowChoice==3){
  rbTimer=millis();
  while ((millis()-rbTimer)<10000){
    for(x=0;x<7;x++){
      pixelFill(0,30,rainbow[x]);
      delay(250);
    }
  }
  pixel.setBrightness(pBright);   
  pixelFill(0,pHeight,setColor);
}


// fill the glass
if(ShowChoice==4){
y=0;

  while(y<31){    
    for(x=31;x>y;x--){
      pixel.setPixelColor(x,setColor);
      pixel.show();
      delay(20);
      pixel.setPixelColor(x,black);
      pixel.show();       
    }
    y=y+1;
    for(z=0;z<y;z++){
      pixel.setPixelColor(z,setColor);
    }
    
    
  }   
}
}

Credits

Jon Phillips
4 projects • 6 followers
Recently graduated a full time Deep Dive IoT bootcamp and interested in starting a career in robotics. Also pursing a degree in Comp Prog.

Comments