Pinkman
Published © MIT

Death Stranding Desk Lamp

A smart table lamp based on the Death Stranding Odradek device, the lamp consists of a combination of five individual light-emitting blades,

IntermediateFull instructions provided3 hours6,141

Things used in this project

Hardware components

Seeed XIAO BLE nRF52840 Sense
Seeed Studio Seeed XIAO BLE nRF52840 Sense
×1
10mm boat type toggle switch *1
×1
DC connectors (female)
×1
Wires * 3.5m
×1
TTp223
×1
5v single color LED light
×1
5v 2.5A power adapter * 1
×1
Soldering tools
×1
Hot melt glue gun
×1
10* M3x4 screws 15* M3x12 screws 5* M3x20 screws 21* M3 nut 5* M4x20 screw 5* M4 Female
×1

Software apps and online services

Bluefruit Connect

Story

Read more

Custom parts and enclosures

All parts

Contains all files

Schematics

Hardware connection diagram

Code

code.ino

C/C++
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <bluefruit.h>
int SensorPin = A5;
int  val = 0;
int oldval = 0;
  int flog =0;
#define NEOPIXEL_VERSION_STRING "Neopixel v2.0"

/* Pin used to drive the NeoPixels */
#if defined ARDUINO_NRF52840_CIRCUITPLAY || defined ARDUINO_NRF52840_FEATHER
  #define PIN     PIN_NEOPIXEL
#elif defined ARDUINO_NRF52832_FEATHER
  #define PIN     15
#else
  #define PIN0     0
  #define PIN1     1
  #define PIN2     2
  #define PIN3     3
  #define PIN4     4
#endif

#define MAXCOMPONENTS  4
uint8_t *pixelBuffer = NULL;
uint8_t width = 0;
uint8_t height = 0;
uint8_t stride;
uint8_t componentsValue;
bool is400Hz;
uint8_t components = 3;     // only 3 and 4 are valid values
//
Adafruit_NeoPixel neopixel0 = Adafruit_NeoPixel();
Adafruit_NeoPixel neopixel1 = Adafruit_NeoPixel();
Adafruit_NeoPixel neopixel2 = Adafruit_NeoPixel();
Adafruit_NeoPixel neopixel3 = Adafruit_NeoPixel();
Adafruit_NeoPixel neopixel4 = Adafruit_NeoPixel();

//
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(19, PIN0, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(19, PIN1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip3 = Adafruit_NeoPixel(19, PIN2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip4 = Adafruit_NeoPixel(19, PIN3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip5 = Adafruit_NeoPixel(19, PIN4, NEO_GRB + NEO_KHZ800);
// BLE Service
BLEDfu  bledfu;
BLEDis  bledis;
BLEUart bleuart;

void setup()
{
  Serial.begin(115200);
//  while ( !Serial ) delay(10);   // for nrf52840 with native usb

  Serial.println("Adafruit Bluefruit Neopixel Test");
  Serial.println("--------------------------------");

  Serial.println();
  Serial.println("Please connect using the Bluefruit Connect LE application");
  pinMode(SensorPin,INPUT);
  // Config Neopixels
  neopixel0.begin();
  neopixel1.begin();
  neopixel2.begin();
  neopixel3.begin();
  neopixel4.begin();
  neopixel0.show();
  neopixel1.show();
  neopixel2.show();
  neopixel3.show();
  neopixel4.show();

  strip1.begin();
  strip2.begin();
  strip3.begin();
  strip4.begin();
  strip5.begin();
  strip1.show(); 
  strip2.show();
  strip3.show();
  strip4.show();
  strip5.show();
 rainbow(5);//
strip1.clear();
strip2.clear();
strip3.clear();
strip4.clear();
strip5.clear();
strip1.show(); 
strip2.show();
strip3.show();
strip4.show();
strip5.show();
  delay(100);
  colorWipe(strip1.Color(227, 207, 87), 87); //
  colorWipe(strip2.Color(227, 207, 87), 87); 
  colorWipe(strip3.Color(227, 207, 87), 87); 
  colorWipe(strip4.Color(227, 207, 87), 87); 
  colorWipe(strip5.Color(227, 207, 87), 87); 
  strip1.show();
  strip2.show();
  strip3.show();
  strip4.show();
  strip5.show();
  delay(100);
  // Init Bluefruit
  Bluefruit.begin();
  Bluefruit.setTxPower(4);    // Check bluefruit.h for supported values

  Bluefruit.Periph.setConnectCallback(connect_callback);

  // To be consistent OTA DFU should be added first if it exists
  bledfu.begin();

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather52");
  bledis.begin();  

  // Configure and start BLE UART service
  bleuart.begin();

  // Set up and start advertising
  startAdv();
}

void startAdv(void)
{  
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  
  // Include bleuart 128-bit uuid
  Bluefruit.Advertising.addService(bleuart);

  // Secondary Scan Response packet (optional)
  // Since there is no room for 'Name' in Advertising packet
  Bluefruit.ScanResponse.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds  
}

void connect_callback(uint16_t conn_handle)
{
  // Get the reference to current connection
  BLEConnection* connection = Bluefruit.Connection(conn_handle);

  char central_name[32] = { 0 };
  connection->getPeerName(central_name, sizeof(central_name));

  Serial.print("Connected to ");
  Serial.println(central_name);

  Serial.println("Please select the 'Neopixels' tab, click 'Connect' and have fun");
}

void loop()
{
  val = analogRead(SensorPin);
   Serial.println(val);
if((val >400) && (oldval == 0)){
  delay(500);
  if((val >400) && (oldval == 0)){
  flog = 1-flog;
  delay(40);
  }
}
oldval = val;

if(flog == 1){
  rainbow(5);
   Serial.println("yes");
}
//if(flog == 0){
//strip1.clear();
//strip2.clear();
//strip3.clear();
//strip4.clear();
//strip5.clear();
//strip1.show(); 
//strip2.show();
//strip3.show();
//strip4.show();
//strip5.show();
// Serial.println("no"); 

   if ( Bluefruit.connected() && bleuart.notifyEnabled() )
  {
    int command = bleuart.read();

    switch (command) {
      case 'V': {   // Get Version
          commandVersion();
          break;
        }
  
      case 'S': {   // Setup dimensions, components, stride...
          commandSetup();
          break;
       }

      case 'C': {   // Clear with color
          commandClearColor();
          break;
      }

      case 'B': {   // Set Brightness
          commandSetBrightness();
          break;
      }
            
      case 'P': {   // Set Pixel
          commandSetPixel();
          break;
      }
  
      case 'I': {   // Receive new image
          commandImage();
          break;
       }

    }
//  }
}
    delay(200);   
  


}

void swapBuffers()
{
  uint8_t *base_addr = pixelBuffer;
  int pixelIndex = 0;
  for (int j = 0; j < height; j++)
  {
    for (int i = 0; i < width; i++) {
      if (components == 3) {
        neopixel0.setPixelColor(pixelIndex, neopixel0.Color(*base_addr, *(base_addr+1), *(base_addr+2)));
        neopixel1.setPixelColor(pixelIndex, neopixel1.Color(*base_addr, *(base_addr+1), *(base_addr+2)));
        neopixel2.setPixelColor(pixelIndex, neopixel2.Color(*base_addr, *(base_addr+1), *(base_addr+2)));
        neopixel3.setPixelColor(pixelIndex, neopixel3.Color(*base_addr, *(base_addr+1), *(base_addr+2)));
        neopixel4.setPixelColor(pixelIndex, neopixel4.Color(*base_addr, *(base_addr+1), *(base_addr+2)));
      }
      else {
        neopixel0.setPixelColor(pixelIndex, neopixel0.Color(*base_addr, *(base_addr+1), *(base_addr+2), *(base_addr+3) ));
         neopixel1.setPixelColor(pixelIndex, neopixel1.Color(*base_addr, *(base_addr+1), *(base_addr+2), *(base_addr+3) ));
          neopixel2.setPixelColor(pixelIndex, neopixel2.Color(*base_addr, *(base_addr+1), *(base_addr+2), *(base_addr+3) ));
           neopixel3.setPixelColor(pixelIndex, neopixel3.Color(*base_addr, *(base_addr+1), *(base_addr+2), *(base_addr+3) ));
            neopixel4.setPixelColor(pixelIndex, neopixel4.Color(*base_addr, *(base_addr+1), *(base_addr+2), *(base_addr+3) ));
      }
      base_addr+=components;
      pixelIndex++;
    }
    pixelIndex += stride - width;   // Move pixelIndex to the next row (take into account the stride)
  }
  neopixel0.show();
  neopixel1.show();
  neopixel2.show();
  neopixel3.show();
  neopixel4.show();

}

void commandVersion() {
  Serial.println(F("Command: Version check"));
  sendResponse(NEOPIXEL_VERSION_STRING);
}

void commandSetup() {
  Serial.println(F("Command: Setup"));

  width = bleuart.read();
  height = bleuart.read();
  stride = bleuart.read();
  componentsValue = bleuart.read();
  is400Hz = bleuart.read();

  neoPixelType pixelType;
  pixelType = componentsValue + (is400Hz ? NEO_KHZ400 : NEO_KHZ800);

  components = (componentsValue == NEO_RGB || componentsValue == NEO_RBG || componentsValue == NEO_GRB || componentsValue == NEO_GBR || componentsValue == NEO_BRG || componentsValue == NEO_BGR) ? 3:4;
  
  Serial.printf("\tsize: %dx%d\n", width, height);
  Serial.printf("\tstride: %d\n", stride);
  Serial.printf("\tpixelType %d\n", pixelType);
  Serial.printf("\tcomponents: %d\n", components);

  if (pixelBuffer != NULL) {
      delete[] pixelBuffer;
  }

  uint32_t size = width*height;
  pixelBuffer = new uint8_t[size*components];
  neopixel0.updateLength(size);
  neopixel1.updateLength(size);
  neopixel2.updateLength(size);
  neopixel3.updateLength(size);
  neopixel4.updateLength(size);
  neopixel0.updateType(pixelType);
  neopixel1.updateType(pixelType);
  neopixel2.updateType(pixelType);
  neopixel3.updateType(pixelType);
  neopixel4.updateType(pixelType);
  neopixel0.setPin(PIN0);
  neopixel1.setPin(PIN1);
  neopixel2.setPin(PIN2);
  neopixel3.setPin(PIN3);
  neopixel4.setPin(PIN4);

  // Done
  sendResponse("OK");
}

void commandSetBrightness() {
  Serial.println(F("Command: SetBrightness"));

   // Read value
  uint8_t brightness = bleuart.read();

  // Set brightness
  neopixel0.setBrightness(brightness);
  neopixel1.setBrightness(brightness);
  neopixel2.setBrightness(brightness);
  neopixel3.setBrightness(brightness);
  neopixel4.setBrightness(brightness);

  // Refresh pixels
  swapBuffers();

  // Done
  sendResponse("OK");
}

void commandClearColor() {
  Serial.println(F("Command: ClearColor"));

  // Read color
  uint8_t color[MAXCOMPONENTS];
  for (int j = 0; j < components;) {
    if (bleuart.available()) {
      color[j] = bleuart.read();
      j++;
    }
  }

  // Set all leds to color
  int size = width * height;
  uint8_t *base_addr = pixelBuffer;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < components; j++) {
      *base_addr = color[j];
      base_addr++;
    }
  }

  // Swap buffers
  Serial.println(F("ClearColor completed"));
  swapBuffers();


  if (components == 3) {
    Serial.printf("\tclear (%d, %d, %d)\n", color[0], color[1], color[2] );
  }
  else {
    Serial.printf("\tclear (%d, %d, %d, %d)\n", color[0], color[1], color[2], color[3] );
  }
  
  // Done
  sendResponse("OK");
}

void commandSetPixel() {
  Serial.println(F("Command: SetPixel"));

  // Read position
  uint8_t x = bleuart.read();
  uint8_t y = bleuart.read();

  // Read colors
  uint32_t pixelOffset = y*width+x;
  uint32_t pixelDataOffset = pixelOffset*components;
  uint8_t *base_addr = pixelBuffer+pixelDataOffset;
  for (int j = 0; j < components;) {
    if (bleuart.available()) {
      *base_addr = bleuart.read();
      base_addr++;
      j++;
    }
  }

  // Set colors
  uint32_t neopixelIndex = y*stride+x;
  uint8_t *pixelBufferPointer = pixelBuffer + pixelDataOffset;
  uint32_t color;
  if (components == 3) {
    color = neopixel0.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
    color = neopixel1.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
    color = neopixel2.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
    color = neopixel3.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
    color = neopixel4.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
    Serial.printf("\tcolor (%d, %d, %d)\n",*pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2) );
  }
  else {
    color = neopixel0.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
     color = neopixel1.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
      color = neopixel2.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
       color = neopixel3.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
        color = neopixel4.Color( *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );
    Serial.printf("\tcolor (%d, %d, %d, %d)\n", *pixelBufferPointer, *(pixelBufferPointer+1), *(pixelBufferPointer+2), *(pixelBufferPointer+3) );    
  }
  neopixel0.setPixelColor(neopixelIndex, color);
    neopixel1.setPixelColor(neopixelIndex, color);
      neopixel2.setPixelColor(neopixelIndex, color);
        neopixel3.setPixelColor(neopixelIndex, color);
          neopixel4.setPixelColor(neopixelIndex, color);
  neopixel0.show();
  neopixel1.show();
  neopixel2.show();
  neopixel3.show();
  neopixel4.show();

  // Done
  sendResponse("OK");
}

void commandImage() {
  Serial.printf("Command: Image %dx%d, %d, %d\n", width, height, components, stride);
  
  // Receive new pixel buffer
  int size = width * height;
  uint8_t *base_addr = pixelBuffer;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < components;) {
      if (bleuart.available()) {
        *base_addr = bleuart.read();
        base_addr++;
        j++;
      }
    }

/*
    if (components == 3) {
      uint32_t index = i*components;
      Serial.printf("\tp%d (%d, %d, %d)\n", i, pixelBuffer[index], pixelBuffer[index+1], pixelBuffer[index+2] );
    }
    */
  }

  // Swap buffers
  Serial.println(F("Image received"));
  swapBuffers();

  // Done
  sendResponse("OK");
}

void sendResponse(char const *response) {
    Serial.printf("Send Response: %s\n", response);
    bleuart.write(response, strlen(response)*sizeof(char));
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip1.numPixels(); i++) {
      strip1.setPixelColor(i, Wheel((i+j) & 255));
      strip2.setPixelColor(i, Wheel((i+j) & 255));
      strip3.setPixelColor(i, Wheel((i+j) & 255));
      strip4.setPixelColor(i, Wheel((i+j) & 255));
      strip5.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip1.show();
    strip2.show();
    strip3.show();
    strip4.show();
    strip5.show();
    delay(wait);
  }
}


uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip1.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip1.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip1.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip1.numPixels(); i++) {
    strip1.setPixelColor(i, c);
    strip2.setPixelColor(i, c);
    strip3.setPixelColor(i, c);
    strip4.setPixelColor(i, c);
    strip5.setPixelColor(i, c);
    strip1.show();
    strip2.show();
    strip3.show();
    strip4.show();
    strip5.show();
  }
}

Credits

Pinkman

Pinkman

1 project • 5 followers
Seeed

Comments