Tim Robertson
Created June 25, 2016

Extending C-Sleep by GE to the bedside

The C-Sleep individually controlled light sources are an excellent start, in the Healthcare setting, local control is required.

80
Extending C-Sleep by GE to the bedside

Things used in this project

Hardware components

Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
Used in prototype, placeholder for buttons compatible with final enclosure
×8
RedBear Duo – Wi-Fi + BLE IoT Board
Wifi is included to allow for mass management
×1
GE C-Sleep LED Bulb
At least two to demonstrate scenes
×2
Adafruit 12mm Diffused Thin Digital RGB LED Pixels
Used in the prototype as a stand in for the C-Sleep LED Bulbs. The direction of the bus is important, review https://learn.adafruit.com/12mm-led-pixels/code for getting started.
×1

Software apps and online services

c by ge App
Connection and claiming of the C-Sleep LED bulbs

Story

Read more

Schematics

Breadboard Prototype of Controller

This includes the initial Prototype connection to a String of Adafruit 12mm LED Pixels as the GE Light Stand-ins

Schematic for the Prototype Controller

This includes the initial Prototype connection to a String of Adafruit 12mm LED Pixels as the GE Light Stand-ins

Code

ControllerProtoV1

Arduino
Particle IDE based implementation on Redbear Duo, Libraries for Matrix Keypad decoding (Keypad Library) and Adafruit 12mm "Pixels" (WS2801 Library) need to be attached
// This #include statement was automatically added by the Particle IDE.
#include "Keypad/Keypad.h"

// This #include statement was automatically added by the Particle IDE.
#include "WS2801/WS2801.h"

/* Portions derived from Adafuit_WS2801 Library "Spark Code" Port Sample

    Prototype v1.0 of Light Controler (substituting Adafruit "Pixels" for GE C-Sleep bulbs)

    Modifications
        17JUL2016   Tim Robertson
            Initial brute force procedural solution, mostly focused on the Light Control API without buttons
            to start with.
*/

const int numPixel = 8;
const long fixed_transition_mills = 1000 * 30; // 30 Seconds for visible demonstration of the transitions

// Track what the Pixels should show
unsigned char current_state[numPixel] = {
    0, 0, 0, 0,
    0, 0, 0, 0
};

// Track what we want to transition to
unsigned char desired_state[numPixel] = {
    0, 0, 0, 0,
    0, 0, 0, 0
};

// Current static patterns (represents Half the room)
const unsigned char allOn[numPixel/2] = {
    10, 10, 10, 10
};
const unsigned char midOn[numPixel/2] = {
    6, 8, 8, 5
};
const unsigned char midOff[numPixel/2] = {
    3, 4, 4, 2
};
const unsigned char allOff[numPixel/2] = {
    0, 0, 0, 1
};
const int maxLevel = 10;
#define RED_INDEX 0
#define GREEN_INDEX 1
#define BLUE_INDEX 2

// The various Levels supported
unsigned char level_values[maxLevel + 1][3] = {
    { 0,  0,  0},   // 0
    { 1,  0,  0},   // 1
    { 2,  1,  0},   // 2
    { 4,  2,  0},   // 3
    { 8,  4,  1},   // 4
    {16,  8,  4},   // 5
    {32, 16, 16},   // 6
    {64, 32, 32},   // 7
    {64, 64, 64},   // 8
    {128, 128, 128},// 9
    {255, 255, 255} //10
};

// Comments from the Example:
/*****************************************************************************
Example sketch for driving Adafruit WS2801 pixels on the Spark Core!
  Designed specifically to work with the Adafruit RGB Pixels!
  12mm Bullet shape ----> https://www.adafruit.com/products/322
  12mm Flat shape   ----> https://www.adafruit.com/products/738
  36mm Square shape ----> https://www.adafruit.com/products/683
  These pixels use SPI to transmit the color data, and have built in
  high speed PWM drivers for 24 bit color per pixel
  2 pins are required to interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!
  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
*****************************************************************************/

// The colors of the wires may be totally different so
// BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!

// SPARK CORE SPI PINOUTS
// http://docs.spark.io/#/firmware/communication-spi
// A5 (MOSI) Yellow wire on Adafruit Pixels
// A3 (SCK) Green wire on Adafruit Pixels

// Don't forget to connect the ground wire to Arduino ground,
// and the +5V wire to a +5V supply$

// const int numPixel = 8;

// Set the argument to the NUMBER of pixels.
Adafruit_WS2801 strip = Adafruit_WS2801(numPixel);

// For 36mm LED pixels: these pixels internally represent color in a
// different format.  Either of the above constructors can accept an
// optional extra parameter: WS2801_RGB is 'conventional' RGB order
// WS2801_GRB is the GRB order required by the 36mm pixels.  Other
// than this parameter, your code does not need to do anything different;
// the library will handle the format change.  Example:
//Adafruit_WS2801 strip = Adafruit_WS2801(25, WS2801_GRB);


// Simple use of single Button Push (from Keypad: HelloKeypad example)
const int ROWS = 4; //four rows
const int COLS = 2; //three columns
char keys[ROWS][COLS] = {
  {'1','A'},{'2','B'},
  {'3','C'},{'4','D'}
};
byte row_pins[ROWS] = {D7, D6, D5, D4}; // Button Rows
byte column_pins[COLS] = {D3, D2}; // Button Columns

Keypad keypad = Keypad( makeKeymap(keys), row_pins, column_pins, ROWS, COLS );

char lastKey;
bool colorChanges;


void setup() {
    strip.begin();
    delay(20);
    showColors(); // Initially clear lights to starting state
    lastKey=0x0; // Set up simple detection of two key presses
}



void loop(){

  // Process any key changes
  char key = keypad.getKey();
  const unsigned char *pattern = NULL;
  bool twice;
  bool firstHalf;
  
  if (key){
    twice = (key == lastKey);
    lastKey = key;
    switch(key) {
        // RED
        case '1':
          firstHalf=true;
          pattern = allOn;
          break;
        case 'A':
          firstHalf=false;
          pattern = allOn;
          break;
        
        // YELLOW
        case '2':
          firstHalf=true;
          pattern = midOn;
          break;
        case 'B':
          firstHalf=false;
          pattern = midOn;
          break;
          
        // GREEN
        case '3':
          firstHalf=true;
          pattern = midOff;
          break;
        case 'C':
          firstHalf=false;
          pattern = midOff;
          break;
          
        // BLUE
        case '4':
          firstHalf=true;
          pattern = allOff;
          break;
        case 'D':
          firstHalf=false;
          pattern = allOff;
          break;
          
        default:
          break;
    }
    
    if(pattern != NULL) {
        int changeCount = numPixel / 2;
        int startLamp = firstHalf ? 0 : changeCount;
        for (int i=0; i < changeCount; i++) {
            if (twice) {
              // Immediate change (at least twice)
              current_state[startLamp + i] = pattern[i];
            } else {
              // Gradual change
              desired_state[startLamp + i] = pattern[i];
            }
        }
        colorChanges = true; // Force the strip to be sync'd with current state.
    }
  } /* Key had been pressed */
  
  if(colorChanges) {
    showColors();
  }
  
  computeNextColors(fixed_transition_mills);
}

void showColors() {
    for (int i=0; i < numPixel; i++) {
        int theState = current_state[i];
        //theState = (theState < 0)?0:theState;
        //theState = (theState > maxLevel)?maxLevel:theState;
        int red   = level_values[theState][RED_INDEX];
        int green = level_values[theState][GREEN_INDEX];
        int blue  = level_values[theState][BLUE_INDEX];
        strip.setPixelColor(i, red, green, blue);
    }
    strip.show();
    colorChanges = false;
}

long previousTransition = 0;

void computeNextColors(int transitionDelay) {
    unsigned long currentTime = millis();
    if(transitionDelay < (currentTime - previousTransition)) {
        previousTransition = currentTime; // Reset for next interval
        for (int i=0; i < numPixel; i++) {
            // Move to the desired state one click an interval
            if(current_state[i] < desired_state[i]) {
                current_state[i]++;
            } else if (current_state[i] > desired_state[i]) {
                current_state[i]--;
            }
        }
    }
}

Credits

Tim Robertson

Tim Robertson

1 project β€’ 0 followers
Experienced in Digital Hardware since 1975; Software since 1971.

Comments