Isabel - Ambient Orb
Made by Isabel Fleck
Made by Isabel Fleck
Learning how to use the Neopixel stick and program it to create unique light patterns in response to the period of time in which pressure is applied.
Created: December 5th, 2024
While the main intention of this project was to create an ambient light effect as a response to a google calendar alert. I struggled to get the IFTTT to work, and resorted to creating a different alert system that is based on the period of time in which someone is holding the pressure sensor. Much like how a calendar has different alerts and settings, this creates a different signal light based upon the period of time you hold the pressure sensor.
As I worked through the assignment. I began by creating a basic circuit that connected purely the neopixel to the board, and tested the rainbow code on my board to see if the wiring was correct. However, while I was trying to implement this test code to my original code, I found myself being consistently faced with the error of the neopixel library not being found. After many attempts, I finally was able to get some help and learned how to add this library to my board, and was happy to see this work. From here, I wanted to explore a new way to interact with the light, and added a pressure module to my board, so that when pressed at different pressures there would be a different light setting that is triggered. Organizing the code in different events, I could then create specific light patterns within each and call them based on the amount of pressure that was applied.
#include "Particle.h"
#include "neopixel.h"
SYSTEM_MODE(AUTOMATIC);
// Define pin and NeoPixel configuration for Photon 2
#if (PLATFORM_ID == 32)
#define NEOPIXEL_PIN SPI // Use MOSI for Photon 2
#else
#define NEOPIXEL_PIN D3 // Use D3 for other Particle devices
#endif
#define NUM_PIXELS 8 // Number of LEDs in the NeoPixel strip
#define PIXEL_TYPE WS2812B // Specify the NeoPixel type
// Pressure sensor pin
#define PRESSURE_PIN A0
// Create a NeoPixel object
Adafruit_NeoPixel strip(NUM_PIXELS, NEOPIXEL_PIN, PIXEL_TYPE);
void setup() {
strip.begin(); // Initialize NeoPixel strip
strip.show(); // Turn off all LEDs initially
Serial.begin(9600); // Debugging
// Subscribe to events from the Particle Cloud
Particle.subscribe("weatherEvent", weatherEventHandler);
}
// Function prototypes for weather effects
void thunderEffect();
void rainEffect();
void cloudyEffect();
void sunnyEffect();
// Function to publish weather events
void publishWeatherEvent(const char* eventName) {
String event = String("weatherEvent/") + eventName;
Particle.publish(event); // Publish the event with the prefix
weatherEventHandler(event.c_str(), ""); // Call event handler immediately
}
// Particle event handler
void weatherEventHandler(const char* event, const char* data) {
String eventString = String(event);
if (eventString == "weatherEvent/sunny") {
sunnyEffect(); // Call sunny effect function
}
else if (eventString == "weatherEvent/cloudy") {
cloudyEffect(); // Call cloudy effect function
}
else if (eventString == "weatherEvent/rainy") {
rainEffect(); // Call rainy effect function
}
else if (eventString == "weatherEvent/thunder") {
thunderEffect(); // Call thunder effect function
}
}
void loop() {
// Read the pressure sensor value
int pressure = analogRead(PRESSURE_PIN);
Serial.println(pressure); // Debugging the sensor value
// Check how long the pressure is held
static unsigned long pressStartTime = 0;
static bool isPressed = false;
if (pressure > 1000) { // Threshold for detecting a press
if (!isPressed) {
pressStartTime = millis(); // Start timing
isPressed = true;
}
} else {
isPressed = false;
}
if (isPressed) {
unsigned long pressDuration = millis() - pressStartTime;
if (pressDuration > 5000) {
publishWeatherEvent("thunder");
} else if (pressDuration > 3000) {
publishWeatherEvent("rainy");
} else if (pressDuration > 2000) {
publishWeatherEvent("cloudy");
} else if (pressDuration > 1000) {
publishWeatherEvent("sunny");
}
} else {
strip.clear(); // Turn off LEDs when not pressed
strip.show();
}
}
// Thunder: Blue and yellow flash
void thunderEffect() {
for (int i = 0; i < NUM_PIXELS; i++) {
strip.clear();
if (i % 2 == 0) {
strip.setPixelColor(i, strip.Color(0, 0, 128)); // Dim blue
} else {
strip.setPixelColor(i, strip.Color(128, 128, 0)); // Dim yellow
}
strip.show();
delay(50);
}
strip.clear();
strip.show();
}
// Rain: Light dim blue light
void rainEffect() {
for (int i = 0; i < NUM_PIXELS; i++) {
strip.clear();
strip.setPixelColor(i, strip.Color(0, 0, 128)); // Dim blue
strip.show();
delay(100);
}
}
// Cloudy: Dim violet/lavender light
void cloudyEffect() {
static int brightness = 0;
static int direction = 5;
brightness += direction;
if (brightness >= 100 || brightness <= 0) {
direction = -direction;
}
uint32_t color = strip.Color(75 + brightness, 50 + brightness, 150 + brightness); // Dim lavender/violet
for (int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, color);
}
strip.show();
delay(50);
}
// Sunny: Warm orange light
void sunnyEffect() {
static int brightness = 0;
static int direction = 5;
brightness += direction;
if (brightness >= 255 || brightness <= 50) {
direction = -direction;
}
uint32_t color = strip.Color(255, 140, 0); // Warm orange
for (int i = 0; i < NUM_PIXELS; i++) {
strip.setPixelColor(i, color);
}
strip.show();
delay(50);
}
Click to Expand
In the future I would like to look at how I can apply this setup in different settings, as well as figuring out how this might fit in to a more everyday device, and work as an ambient device. Possibly hooking it up to another servo to create a flower blooming effect when in response to different lights, and applying different narratives these each of these contexts.
Learning how to use the Neopixel stick and program it to create unique light patterns in response to the period of time in which pressure is applied.