I had this, not working, ceiling lamp that collected dust. And I was wondering what to do with it and I found a way how to turn it into artwork.
And it’s relatively easy to do if you have access to some technologies like laser cutting and printing. The picture is printed under plexiglass.
I use one of my drawings. You can find the rest on Instagram or here.
The radar sensor detects movements and the microcontroller (MCU) changes the RGB LEDs colours to react to human movement. And if the is no motion at certain time lights will turn off.
Three main components are:
- Microcontroller, with 5V logic. Like Arduino Nano.
- NeoPixel type RGB LED stripe.
- RCWL-0516 microwave radar sensor.









/*
Lõvi lamp
Tauno Erik
18.02.2023
*/
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
const uint8_t RADAR_PIN = 4;
const uint8_t RGB_PIN = 3;
const uint8_t NUMPIXELS = 49;
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
bool is_movement = false;
bool change_color = false;
uint32_t time_px_prev = 0; // Millis
uint16_t px_interval = 50; // Millis
const uint16_t OFF_TIME = 20000;
uint32_t no_movment_time = 0;
Adafruit_NeoPixel pixels(NUMPIXELS, RGB_PIN, NEO_GRB + NEO_KHZ800);
// Fill pixels pixels one after another with a color. pixels is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// pixels.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<pixels.numPixels(); i++) { // For each pixel in pixels...
pixels.setPixelColor(i, color); // Set pixel's color (in RAM)
pixels.show(); // Update pixels to match
delay(wait); // Pause for a moment
}
}
// Rainbow cycle along whole pixels. Pass delay time (in ms) between frames.
void rainbow(int wait) {
// Hue of first pixel runs 5 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
// means we'll make 5*65536/256 = 1280 passes through this loop:
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
// pixels.rainbow() can take a single argument (first pixel hue) or
// optionally a few extras: number of rainbow repetitions (default 1),
// saturation and value (brightness) (both 0-255, similar to the
// ColorHSV() function, default 255), and a true/false flag for whether
// to apply gamma correction to provide 'truer' colors (default true).
pixels.rainbow(firstPixelHue);
// Above line is equivalent to:
// pixels.rainbow(firstPixelHue, 1, 255, 255, true);
pixels.show(); // Update pixels with new contents
delay(wait); // Pause for a moment
}
}
void setup() {
pinMode(RADAR_PIN, INPUT);
pixels.begin();
pixels.show(); // Turn OFF all pixels ASAP
pixels.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
randomSeed(analogRead(0));
rainbow(3);
colorWipe(pixels.Color(0, 0, 0), 0);
}
void loop() {
uint32_t time_now = millis();
is_movement = digitalRead(RADAR_PIN);
if (is_movement) {
change_color = true;
no_movment_time = time_now;
} else {
change_color = false;
}
// All LEDs off
if (time_now - no_movment_time >= OFF_TIME) {
colorWipe(pixels.Color(0, 0, 0), 0);
}
// Colour change routine
if (time_now - time_px_prev >= px_interval) {
time_px_prev = time_now;
if (change_color) {
r = random(0, 255);
g = random(0, 255);
b = random(0, 255);
colorWipe(pixels.Color(r, g, b), 50); // Blue
change_color = false;
}
}
}