Jhn S
Published

Wifi Death Lamp

IKEA PS 2014 Pendant Lamp Modification

BeginnerShowcase (no instructions)40,897
Wifi Death Lamp

Things used in this project

Hardware components

Photon
Particle Photon
×1
IKEA PS 2014
×1
Arduino UNO
Arduino UNO
×1
Arduino Motor Shield Rev3
×1
Stepper Motor with 28cm Lead Screw: Bipolar, 200 Steps/Rev, 42×38mm, 2.8V, 1.7 A/Phase
×1
NeoPixel Ring - 24 x WS2812 5050 RGB LED with Integrated Drivers
×1
NeoPixel 1/4 60 Ring - WS2812 5050 RGB LED w/ Integrated Drivers
×4
Ultrasonic Sensor HC-SR04
×1

Story

Read more

Schematics

Wiring diagram

Wiring diagram, see how to connect the parts

Schematic draft

Hand drawn project sketch

Code

Particle photon test code (works with Particle Core aswell)

C/C++
Test code for controlling the NeoPixels + Stepper with your hand (gestures).
// This #include statement was automatically added by the Spark IDE.
#include "neopixel/neopixel.h"

// This #include statement was automatically added by the Spark IDE.
#include "application.h"
// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN D2
#define PIXEL_COUNT 114
#define PIXEL_TYPE WS2812B

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

int led0 = D7; // This one is the built-in tiny one to the right of the USB jack
int motortrigg = D6; // Stepper-trigger to ARDUINO -> PIN2 INPUT trigg Arduino/MotorShield
int trigger = D3; // TRIGG
int echo = D4; //ECHO
int ping = 0; //loop couter
int showType = 0; //led show start

unsigned long triggerTarget;

uint8_t value = 1;

void setup() {
    pinMode(motortrigg, OUTPUT);
    pinMode(trigger, OUTPUT);
    pinMode(echo, INPUT);
    pinMode(led0, OUTPUT);
    digitalWrite(trigger, LOW);
    digitalWrite(motortrigg, LOW);
    strip.begin();
    strip.show(); // Initialize all pixels to 'off'
  
    showType = value;
    startShow(showType); // Set last shownumber from EEPROM
}

void loop() {
    
    digitalWrite(led0, LOW);    // Turn OFF the LED pin

    // Pull the trigger pin high for roughly 10uS then pull it low and wait another 10uS.
    triggerTarget = micros();
    while (micros() < triggerTarget + 10) {
        digitalWrite(trigger, HIGH);
    }
    while (micros() < triggerTarget + 20) {
        digitalWrite(trigger, LOW);
    }

    // Read the return echo then convert it to in and cm.
    unsigned long sonar = pulseIn(echo, HIGH);
    //float in = sonar / 148;
    int cm = sonar / 58;

    if (cm >= 8 && cm <= 10){  digitalWrite(led0, HIGH); // // Internal led
                    digitalWrite(motortrigg, HIGH);   // Trigger stepper on PARTICLE CORE PIN D6 -> PIN D2 ARDUINO + MOTOR SHIELD
                    delay(50);
                    digitalWrite(motortrigg, LOW);
                    digitalWrite(led0, LOW);
         
    }
    //if (cm < 35){ digitalWrite(led2, HIGH);   // LED on object closer than x cm
    if (cm >= 15 && cm <=30 ){ digitalWrite(led0, HIGH);   // Internal led on
                // NEOPIXELS light em up!
                //colorAll(strip.Color(255, 20, 0), 5); // Orangeish!!
                showType++;
                if (showType > 9) //Number of SHOWS
                    showType=0;
                    startShow(showType);
    }
       
    // Bump the ping counter.
    ping++;

}

//--- functions
unsigned long pulseIn(uint8_t pin, uint8_t state) {
    
    GPIO_TypeDef* portMask = (PIN_MAP[pin].gpio_peripheral); // Cache the target's peripheral mask to speed up the loops.
    uint16_t pinMask = (PIN_MAP[pin].gpio_pin); // Cache the target's GPIO pin mask to speed up the loops.
    unsigned long pulseCount = 0; // Initialize the pulseCount variable now to save time.
    unsigned long loopCount = 0; // Initialize the loopCount variable now to save time.
    unsigned long loopMax = 20000000; // Roughly just under 10 seconds timeout to maintain the Spark Cloud connection.
      // Wait for the pin to enter target state while keeping track of the timeout.
    while (GPIO_ReadInputDataBit(portMask, pinMask) != state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
    }
    
    // Iterate the pulseCount variable each time through the loop to measure the pulse length; we also still keep track of the timeout.
    while (GPIO_ReadInputDataBit(portMask, pinMask) == state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
        pulseCount++;
    }
    
    // Return the pulse time in microseconds by multiplying the pulseCount variable with the time it takes to run once through the loop.
    return pulseCount * 0.405; // Calculated the pulseCount++ loop to be about 0.405uS in length.
}

//---- NEOPIXEL functions
void colorAll(uint32_t c, uint8_t wait) {
  uint16_t i;
  
  for(i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
  }
  strip.show();
  delay(wait);
}


void startShow(int i) {
  switch(i){
    case 0: value = 0; 
            colorWipe(strip.Color(0, 0, 0), 2);    // Black/off
            break;
    case 1: value = 1;
           
            colorWipe(strip.Color(255, 45, 0), 2);  // Orange
            break;
    case 2: value = 2;
            colorWipe(strip.Color(0, 255, 0), 2);  // Green
            break;
    case 3: value = 3;
            colorWipe(strip.Color(255, 255, 255), 2);  // White
            break;
    case 4: value = 4;
            theaterChase(strip.Color(0, 255, 0), 5); // Green
            break;
    case 5: value = 5;
            theaterChase(strip.Color(255,   0,   0), 5); // Red
            break;
    case 6: value = 6;
            theaterChase(strip.Color(  0,   0, 255), 5); // Blue
            break;
    case 7: value = 7;
            lightTop(0,255,255,5);
            break;
    case 8: value = 8;
            lightBottom(0,255,255,5);
            break;
    case 9: value = 9;
          
            wave(255,0,128);
            break;
  }
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

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

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();
     
      delay(wait);
     
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
    
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
        for (int i=0; i < strip.numPixels(); i=i+3) {
          strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
        }
        strip.show();
       
        delay(wait);
       
        for (int i=0; i < strip.numPixels(); i=i+3) {
          strip.setPixelColor(i+q, 0);        //turn every third pixel off
        }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else if(WheelPos < 170) {
    WheelPos -= 85;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
}

//------------------- cut in functions

void wave(int r,int g,int b){
  for(uint8_t i=0; i<99; i++) { 
    setThreePixels(i, r, g, b);
    strip.show();
    delay(10);
  }
  for(uint8_t i=0; i<45; i++){
    setThreePixels(strip.numPixels()-i, r, g, b);
    strip.show();
    delay(10);
  }
}

void lightTop(int r,int g,int b, uint8_t wait){   
  for(uint8_t i=0; i<45; i++) { 
    strip.setPixelColor(i/1.875, r, g, b);
    strip.setPixelColor(24+i, r, g, b);  
    strip.setPixelColor(114-i, 0, 0, 0); 
    strip.show();
    delay(wait);  
  }
}

void lightBottom(int r,int g,int b, uint8_t wait){    
  for(uint8_t i=0; i<45; i++) {
    strip.setPixelColor(i/1.875, 0, 0, 0);
    strip.setPixelColor(24+i, 0, 0, 0);  
    strip.setPixelColor(114-i, r, g, b); 
    strip.show();  
    delay(wait);  
  }
}

void setThreePixels(int LED,int r,int g,int b) {
   strip.setPixelColor(LED, r, g, b);
   if (LED>0) strip.setPixelColor(LED-1, r, g, b);
   if (LED<strip.numPixels()-1)strip.setPixelColor(LED+1, r, g, b);
}

Arduino stepper motor code

C/C++
Stepper motor code for Arduino + Motor shield. Stepper has three states/positions (fully open/semi-open/fully closed). The current position is also stored in the EEPROM (to know postiion when power off/on).
#include <EEPROM.h> // position 0-220 stored in position 0 
#include <Stepper.h>
const int stepsPerRevolution = 200;  
Stepper myStepper(stepsPerRevolution, 12,13);     
 
// give the motor control pins names:
const uint8_t pwmA = 3;
const uint8_t pwmB = 11;
const uint8_t brakeA = 9;
const uint8_t brakeB = 8;
const uint8_t dirA = 12;
const uint8_t dirB = 13;

uint16_t currentPosition = 0;   // 0 - 2200; set by position from smartthings; 0 is closed/furthest from motor 

//button toggle switch
int button = 2; //button pin, connect to +3.3V as button, otherwise ground through resistor
int press = 0;
int toggle = 0; // 0-3; Switch case loop


void setup() {
   //Serial.begin(9600); //debug
  // read values out of memory
  //EEPROM.write(1, toggle);
  currentPosition = EEPROM.read(0)*10;// Read current position
  //toggle = EEPROM.read(1);// 0-3; Switch case loop stored in EEPROM (when power off)
  //Serial.print("EEPROM Position: ");
  //Serial.print(EEPROM.read(0)*10);
  //Serial.print(" Toggle: ");
  //Serial.print(toggle);
  
  // set the PWM and brake pins so that the direction pins  // can be used to control the motor:
  pinMode(pwmA, OUTPUT);
  pinMode(pwmB, OUTPUT);
  pinMode(brakeA, OUTPUT);
  pinMode(brakeB, OUTPUT);
   
  // turn on POWER (turn to low to release the motor and avoid heating)
  digitalWrite(pwmA, HIGH);
  digitalWrite(pwmB, HIGH);
   
  // turn off BRAKES
  digitalWrite(brakeA, LOW);
  digitalWrite(brakeB, LOW);
     
  // 150 is max speed unloaded
  // at 150, there is not enough torque to open the lamp, lowering speed overcomes this.
  myStepper.setSpeed(110); 
  
  // turn off POWER (to release the motor and avoid heating)
  digitalWrite(pwmA, LOW);
  digitalWrite(pwmB, LOW);
 
 //button toggle switch stuff
 // pinMode(10, OUTPUT); //LED on pin 10 "Debug led"
  pinMode(button, INPUT); //arduino monitor pin state
  digitalWrite(2, LOW); //enable pullups to make pin 5 high --- PULL DOWN!!! earth natural state
}

void loop() {
  
  press = digitalRead(button);
  if (press == HIGH)
  {
    switch(toggle){
      case 0: //digitalWrite(10, LOW);   // set the LED on
              //Stepper
              digitalWrite(pwmA, HIGH);
              digitalWrite(pwmB, HIGH);
              digitalWrite(brakeA, LOW);
              digitalWrite(brakeB, LOW);
              digitalWrite(dirA, HIGH);
              digitalWrite(dirB, HIGH);
              setPosition("0"); //MAX step 0-106 
              digitalWrite(pwmA, LOW);
              digitalWrite(pwmB, LOW);
              digitalWrite(brakeA, HIGH);
              digitalWrite(brakeB, HIGH);
              digitalWrite(dirA, LOW);
              digitalWrite(dirB, LOW);
              //stepper slut
              toggle++;
             //EEPROM.write(1, toggle);// Store current switch-case in EEPROM
              break;
        case 1: //digitalWrite(10, HIGH);   // set the LED on
              //Stepper
              digitalWrite(pwmA, HIGH);
              digitalWrite(pwmB, HIGH);
              digitalWrite(brakeA, LOW);
              digitalWrite(brakeB, LOW);
              digitalWrite(dirA, HIGH);
              digitalWrite(dirB, HIGH);
              setPosition("50"); //MAX step 0-106 
              digitalWrite(pwmA, LOW);
              digitalWrite(pwmB, LOW);
              digitalWrite(brakeA, HIGH);
              digitalWrite(brakeB, HIGH);
              digitalWrite(dirA, LOW);
              digitalWrite(dirB, LOW);
              //stepper slut
              toggle++;
              //EEPROM.write(1, toggle);// Store current switch-case in EEPROM
              break;
       case 2: //digitalWrite(10, HIGH);   // set the LED on
              //Stepper
              digitalWrite(pwmA, HIGH);
              digitalWrite(pwmB, HIGH);
              digitalWrite(brakeA, LOW);
              digitalWrite(brakeB, LOW);
              digitalWrite(dirA, HIGH);
              digitalWrite(dirB, HIGH);
              setPosition("102"); //MAX step 0-106 | Currently 102
              digitalWrite(pwmA, LOW);
              digitalWrite(pwmB, LOW);
              digitalWrite(brakeA, HIGH);
              digitalWrite(brakeB, HIGH);
              digitalWrite(dirA, LOW);
              digitalWrite(dirB, LOW);
              //stepper slut
              toggle++;
              //EEPROM.write(1, toggle);// Store current switch-case in EEPROM
              break;
        case 3: //digitalWrite(10, HIGH);   // set the LED on
              //Stepper
              digitalWrite(pwmA, HIGH);
              digitalWrite(pwmB, HIGH);
              digitalWrite(brakeA, LOW);
              digitalWrite(brakeB, LOW);
              digitalWrite(dirA, HIGH);
              digitalWrite(dirB, HIGH);
              setPosition("50"); //MAX step 0-106 
              digitalWrite(pwmA, LOW);
              digitalWrite(pwmB, LOW);
              digitalWrite(brakeA, HIGH);
              digitalWrite(brakeB, HIGH);
              digitalWrite(dirA, LOW);
              digitalWrite(dirB, LOW);
              //stepper slut
              toggle = 0;
              //EEPROM.write(1, toggle);// Store current switch-case in EEPROM
              break;
          } 
      delay(50);  //delay for debounce
} //End of if statement
} //End of main loop

void setPosition (String targetPosition) {
  uint16_t targetMapped = map(targetPosition.toInt(), 0, 99, 0, 220);
  targetMapped = targetMapped*10; // since we save value 0-220 we want an increment of 10
  uint16_t deltaPosition = targetMapped - currentPosition;
    
  // TODO: add a saftey to be sure current position will be 0-2200;
  currentPosition += deltaPosition;
 
  EEPROM.write(0, currentPosition/10);
  //Serial.print(" New position:");
  //Serial.print(EEPROM.read(0)); //DEBUG - print latest position
  
  digitalWrite(pwmA, HIGH);
  digitalWrite(pwmB, HIGH);
  delay(250);
  myStepper.step(deltaPosition);  
  digitalWrite(pwmA, LOW);
  digitalWrite(pwmB, LOW);
}

davidbliss/spherelamp/spherelamp.ino

Code for stepper motor (Arduino)

technobly/SparkCore-NeoPixel

For litting WS2812B/Neopixels with Particle (Spark) Core

Ultrasonic Sensor Spark Core Code

Function used for the Ultrasonic Sensor HC-SR04 (function pulseIn) - connected to the Particle (Spark) Core

Credits

Jhn S

Jhn S

1 project • 17 followers
I like buttons
Thanks to David Bliss and Chase Hinshaw.

Comments