This shows you the differences between two versions of the page.
iothings:proiecte:2023sric:smartled [2024/05/30 00:54] dragos.petre [How it works] |
iothings:proiecte:2023sric:smartled [2024/05/30 01:56] (current) dragos.petre [Software] |
||
---|---|---|---|
Line 3: | Line 3: | ||
* Email: <dragso.petre@stud.acs.pub.ro> | * Email: <dragso.petre@stud.acs.pub.ro> | ||
* Master: SCPD | * Master: SCPD | ||
+ | * Video link: [[https://youtu.be/PxzQ7asWBro]] | ||
+ | * Source Code: {{:iothings:proiecte:2023sric:petredragos_sourcecode.zip|}} | ||
===== Overview ===== | ===== Overview ===== | ||
Line 15: | Line 17: | ||
==== Hardware Components Used ==== | ==== Hardware Components Used ==== | ||
* **ESP32-WROOM-32**: 1 x ESP32 Sparrow development board (purchased from [[https://www.emag.ro/placa-dezvoltare-esp-wroom-32-esp-32s-cl398/pd/D3NF9VBBM/|here]]) | * **ESP32-WROOM-32**: 1 x ESP32 Sparrow development board (purchased from [[https://www.emag.ro/placa-dezvoltare-esp-wroom-32-esp-32s-cl398/pd/D3NF9VBBM/|here]]) | ||
- | * **NeoPixel LED Strip**: 1 x 5m NeoPixel LED Strip (became 4m after an accident =)) (300 NeoPixel LEDs for 5m or 270 NeoPixel LEDs for 4m) | + | * **NeoPixel LED Strip**: 1 x 5m NeoPixel LED Strip (became 4.5m after an accident =)) (300 NeoPixel LEDs for 5m or 270 NeoPixel LEDs for 4.5m) |
* **Breadboard**: 1 x 830 holes Breadboard | * **Breadboard**: 1 x 830 holes Breadboard | ||
* **OLED Display**: 1 x 0.91inch OLED Display | * **OLED Display**: 1 x 0.91inch OLED Display | ||
Line 23: | Line 25: | ||
* **Arduino IDE** for code development and Serial Monitor | * **Arduino IDE** for code development and Serial Monitor | ||
* **BLE Scanner Android App** for connecting my phone to the ESP32 board via BLE | * **BLE Scanner Android App** for connecting my phone to the ESP32 board via BLE | ||
+ | |||
+ | === Libraries needed === | ||
+ | * Adafruit_BusIO | ||
+ | * Adafruit_GFX_Library | ||
+ | * Adafruit_NeoPixel | ||
+ | * Adafruit_SSD1306 | ||
+ | * ArduinoBLE | ||
===== Architecture ===== | ===== Architecture ===== | ||
Line 121: | Line 130: | ||
mode = command; | mode = command; | ||
} | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Choose the lighting mode === | ||
+ | <code cpp> | ||
+ | void loop() { | ||
+ | // Check if the lights are turned on or off | ||
+ | if (lightsOn) { | ||
+ | unsigned long currentMillis = millis(); | ||
+ | if (currentMillis - previousMillis >= interval) { | ||
+ | previousMillis = currentMillis; | ||
+ | updateLEDs(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Function that handles the commands got from the Phone via BLE | ||
+ | void handleCommand(const std::string& command) { | ||
+ | if (command == "off") { | ||
+ | lightsOn = false; | ||
+ | strip.clear(); | ||
+ | strip.show(); | ||
+ | } else { | ||
+ | lightsOn = true; | ||
+ | mode = command; | ||
+ | if (mode == "red") { | ||
+ | setAllPixels(strip.Color(255, 0, 0)); | ||
+ | } else if (mode == "blue") { | ||
+ | setAllPixels(strip.Color(0, 0, 255)); | ||
+ | } else if (mode == "yellow") { | ||
+ | setAllPixels(strip.Color(255, 255, 0)); | ||
+ | } else if (mode == "green") { | ||
+ | setAllPixels(strip.Color(0, 255, 0)); | ||
+ | } else if (mode == "purple") { | ||
+ | setAllPixels(strip.Color(128, 0, 128)); | ||
+ | } else if (mode == "orange") { | ||
+ | setAllPixels(strip.Color(255, 100, 0)); // Adjusted towards red | ||
+ | } else if (mode == "cyan") { | ||
+ | setAllPixels(strip.Color(0, 255, 255)); | ||
+ | } else if (command.find("-") != std::string::npos) { | ||
+ | mode = "split"; | ||
+ | std::string color1 = command.substr(0, command.find('-')); | ||
+ | std::string color2 = command.substr(command.find('-') + 1); | ||
+ | setSplitPixels(getColor(color1), getColor(color2)); | ||
+ | } | ||
+ | strip.show(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Set all the pixels to one color | ||
+ | void setAllPixels(uint32_t color) { | ||
+ | for (int i = 0; i < NUM_LEDS; i++) { | ||
+ | strip.setPixelColor(i, color); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Set half the pixels to one color and the otehr half to the other | ||
+ | void setSplitPixels(uint32_t color1, uint32_t color2) { | ||
+ | for (int i = 0; i < NUM_LEDS / 2; i++) { | ||
+ | strip.setPixelColor(i, color1); | ||
+ | } | ||
+ | for (int i = NUM_LEDS / 2; i < NUM_LEDS; i++) { | ||
+ | strip.setPixelColor(i, color2); | ||
+ | } | ||
+ | strip.show(); | ||
+ | } | ||
+ | |||
+ | uint32_t getColor(const std::string& color) { | ||
+ | if (color == "red") return strip.Color(255, 0, 0); | ||
+ | if (color == "blue") return strip.Color(0, 0, 255); | ||
+ | if (color == "yellow") return strip.Color(255, 255, 0); | ||
+ | if (color == "green") return strip.Color(0, 255, 0); | ||
+ | if (color == "purple") return strip.Color(128, 0, 128); | ||
+ | if (color == "orange") return strip.Color(242, 133, 0); | ||
+ | if (color == "cyan") return strip.Color(0, 255, 255); | ||
+ | return strip.Color(0, 0, 0); // Default to black if color not recognized | ||
+ | } | ||
+ | |||
+ | // Run the selected mode | ||
+ | void updateLEDs() { | ||
+ | if (mode == "cycle") { | ||
+ | cycleColors(); | ||
+ | } else if (mode == "rainbow") { | ||
+ | rainbowCycle(); | ||
+ | } else if (mode == "snake") { | ||
+ | snakeMode(); | ||
+ | } else if (mode == "random_blink") { | ||
+ | randomBlink(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Function to cycle through colors | ||
+ | void cycleColors() { | ||
+ | static int currentColor = 0; | ||
+ | uint32_t colors[] = { | ||
+ | strip.Color(255, 0, 0), // Red | ||
+ | strip.Color(0, 0, 255), // Blue | ||
+ | strip.Color(255, 255, 0), // Yellow | ||
+ | strip.Color(0, 255, 0), // Green | ||
+ | strip.Color(128, 0, 128), // Purple | ||
+ | strip.Color(242, 132, 0), // Orange | ||
+ | strip.Color(0, 255, 255) // Cyan | ||
+ | }; | ||
+ | setAllPixels(colors[currentColor]); | ||
+ | currentColor = (currentColor + 1) % 7; | ||
+ | strip.show(); | ||
+ | } | ||
+ | |||
+ | // Function that lights the LED strip in an evolving rainbow | ||
+ | void rainbowCycle() { | ||
+ | static uint16_t j = 0; | ||
+ | for (int i = 0; i < strip.numPixels(); i++) { | ||
+ | strip.setPixelColor(i, Wheel((i + j) & 255)); | ||
+ | } | ||
+ | strip.show(); | ||
+ | j++; | ||
+ | if (j >= 256) j = 0; | ||
+ | } | ||
+ | |||
+ | // Auxilary function that helps the rainbow function | ||
+ | uint32_t Wheel(byte WheelPos) { | ||
+ | WheelPos = 255 - WheelPos; | ||
+ | if (WheelPos < 85) { | ||
+ | return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | ||
+ | } | ||
+ | if (WheelPos < 170) { | ||
+ | WheelPos -= 85; | ||
+ | return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | ||
+ | } | ||
+ | WheelPos -= 170; | ||
+ | return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | ||
+ | } | ||
+ | |||
+ | // Build a snake that slitters through the light strip | ||
+ | void snakeMode() { | ||
+ | static int head = 0; | ||
+ | strip.clear(); | ||
+ | for (int i = 0; i < 10; i++) { | ||
+ | int pos = (head - i + NUM_LEDS) % NUM_LEDS; | ||
+ | strip.setPixelColor(pos, strip.Color(0, 255 - i * 25, 0)); // Body is darker green | ||
+ | } | ||
+ | strip.show(); | ||
+ | head = (head + 1) % NUM_LEDS; | ||
+ | } | ||
+ | |||
+ | // Function that makes the light strip to blink random LEDs with random colors | ||
+ | void randomBlink() { | ||
+ | strip.clear(); | ||
+ | for (int i = 0; i < NUM_LEDS; i++) { | ||
+ | if (random(10) < 2) { | ||
+ | strip.setPixelColor(i, strip.Color(random(256), random(256), random(256))); | ||
+ | } | ||
+ | } | ||
+ | strip.show(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Display setup and printing === | ||
+ | <code cpp> | ||
+ | // OLED display settings | ||
+ | #define SCREEN_WIDTH 128 | ||
+ | #define SCREEN_HEIGHT 32 | ||
+ | #define OLED_RESET -1 | ||
+ | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); | ||
+ | |||
+ | void setup() { | ||
+ | // Initialize the OLED display | ||
+ | // Address 0x3C for 128x32 OLED display | ||
+ | if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { | ||
+ | Serial.println(F("SSD1306 allocation failed")); | ||
+ | for(;;); | ||
+ | } | ||
+ | display.display(); | ||
+ | delay(2000); // Pause for 2 seconds | ||
+ | display.clearDisplay(); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | // Update the display with the current status | ||
+ | updateDisplay(); | ||
+ | } | ||
+ | |||
+ | // Update the OLED display with the current status | ||
+ | void updateDisplay() { | ||
+ | display.clearDisplay(); | ||
+ | display.setTextSize(1); | ||
+ | display.setTextColor(SSD1306_WHITE); | ||
+ | |||
+ | // Show if any device is connected | ||
+ | display.setCursor(0, 0); | ||
+ | display.print("Device: "); | ||
+ | display.print(deviceConnected ? "Connected" : "Disconnected"); | ||
+ | |||
+ | // Show if the lights are on or off | ||
+ | display.setCursor(0, 10); | ||
+ | display.print("Lights: "); | ||
+ | display.print(lightsOn ? "On" : "Off"); | ||
+ | |||
+ | // Show the current lighting mode | ||
+ | display.setCursor(0, 20); | ||
+ | display.print("Mode: "); | ||
+ | display.print(mode.c_str()); | ||
+ | |||
+ | display.display(); | ||
} | } | ||
</code> | </code> | ||
Line 149: | Line 362: | ||
First of all, buy a better development board, one that has at leas a LTR308 module on it. | First of all, buy a better development board, one that has at leas a LTR308 module on it. | ||
After that, I will implement the automatic light detection function and have the lights start automatically when it becomes dark in the room. | After that, I will implement the automatic light detection function and have the lights start automatically when it becomes dark in the room. | ||
+ | I also have to actually fix the connection that I screwed up and had to glue together. | ||
+ | Lastly, I have to find a way to mount this thing. | ||
===== Resources ===== | ===== Resources ===== | ||
+ | * IoT Laboratories | ||
+ | * Lots of sites, especially StackOverflow (for debugging ;-)) |