This shows you the differences between two versions of the page.
|
iothings:proiecte:2025sric:ledstrip [2025/04/24 08:11] andrei.besliu |
iothings:proiecte:2025sric:ledstrip [2025/05/29 00:48] (current) andrei.besliu [ESP32 Web-based LED strip] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== ESP32 Web-based LED strip ====== | + | ====== ESP32 BLE-based LED strip ====== |
| * Author: Besliu Andrei-Cornel | * Author: Besliu Andrei-Cornel | ||
| * Email: andrei.besliu@stud.acs.pub.ro | * Email: andrei.besliu@stud.acs.pub.ro | ||
| * Master: SCPD | * Master: SCPD | ||
| + | * Video Link: https://youtu.be/Q6bHqYo0OGY | ||
| + | * Source Code: {{:iothings:proiecte:2025sric:besliu_andrei_iot.zip}} | ||
| ====== Introduction ====== | ====== Introduction ====== | ||
| - | Provide smart lighting to a home using an RGB LED strip and an ESP32. The ESP32 will act as a web server, accessible from devices such as a smartphone or desktop PC. | + | Provide smart lighting to a home using an RGB LED strip and an ESP32. The ESP32 will expose a BLE server that can receive commands from any BLE client. To prove functionality I implemented some simple features such as selecting from a number of preset colors and adjusting brightness. |
| - | ====== Context ====== | ||
| ====== Hardware ====== | ====== Hardware ====== | ||
| + | * **ESP32-WROOM-32:** 1 x ESP32 Sparrow development board | ||
| + | * **NeoPixel LED Strip:** 1 x 5m NeoPixel LED strip, 300 LED's. | ||
| + | * **Breadboard:** 1x Breadboard for securing connections. | ||
| + | * **Connecting Cables** | ||
| + | * **USB-A to micro USB cable** | ||
| + | ====== Diagram ====== | ||
| + | {{ :iothings:proiecte:2025sric:diagram_ledstrip.png }} | ||
| + | |||
| + | ====== Actual Hardware ====== | ||
| + | |||
| + | {{ :iothings:proiecte:2025sric:actualHw_ledStrip.jpeg?500 |}} | ||
| + | |||
| + | The NeoPixel LED strip need +5V and GND to power the LED's and the addresing is done using a single data pin, which I have connected to GPIO 17. | ||
| ====== Software ====== | ====== Software ====== | ||
| - | === Code Snippets === | + | * Arduino IDE for development |
| + | * Adafruit_NeoPixel library for easy LED strip manipulation | ||
| + | * ArduinoBLE library for Bluetooth service. | ||
| - | ==== Firebase ==== | + | ====== Code Snippets ====== |
| + | Setting up BLE service with 2 Characteristics, one for setting the color and one for setting the brightness. The color receives a string | ||
| + | with the desired color ("red", "blue", "yellow", "green", "purple", "orange", "cyan") and the brightness is a single 8-bit value where 0 is off and 255 is the highest possible brightness. | ||
| + | <code C++> | ||
| + | // BLE server callback | ||
| + | class MyServerCallbacks: public BLEServerCallbacks { | ||
| + | void onConnect(BLEServer* pServer) { | ||
| + | deviceConnected = true; | ||
| + | }; | ||
| + | |||
| + | void onDisconnect(BLEServer* pServer) { | ||
| + | deviceConnected = false; | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | /* BLE Characteristics */ | ||
| + | BLECharacteristic *colorCharacteristic; | ||
| + | class ColorCallback: public BLECharacteristicCallbacks { | ||
| + | void onWrite(BLECharacteristic *colorCharacteristic) { | ||
| + | receivedColor = colorCharacteristic->getValue(); | ||
| + | if (receivedColor.length() > 0) { | ||
| + | Serial.print("Received Color: "); | ||
| + | Serial.println(receivedColor.c_str()); | ||
| + | } | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | BLECharacteristic *brightCharacteristic; | ||
| + | class BrightnessCallback: public BLECharacteristicCallbacks { | ||
| + | void onWrite(BLECharacteristic *brightCharacteristic) { | ||
| + | receivedBrightness = brightCharacteristic->getValue().c_str()[0]; | ||
| + | Serial.print("Received Brightness: "); | ||
| + | Serial.println(receivedBrightness, DEC); | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | [ ... ] | ||
| + | |||
| + | // Initialize BLE | ||
| + | BLEDevice::init("ESP32_LED_Strip"); | ||
| + | BLEServer *pServer = BLEDevice::createServer(); | ||
| + | pServer->setCallbacks(new MyServerCallbacks()); | ||
| + | |||
| + | BLEService *bmeService = pServer->createService(SERVICE_UUID); | ||
| + | |||
| + | // Create colorCharacteristic | ||
| + | colorCharacteristic = bmeService->createCharacteristic( | ||
| + | COLOR_UUID, | ||
| + | BLECharacteristic::PROPERTY_READ | | ||
| + | BLECharacteristic::PROPERTY_WRITE | ||
| + | ); | ||
| + | colorCharacteristic->setCallbacks(new ColorCallback()); | ||
| + | colorCharacteristic->setValue("Hello, World!"); | ||
| + | |||
| + | // Create colorCharacteristic | ||
| + | brightCharacteristic = bmeService->createCharacteristic( | ||
| + | BRIGHTNESS_UUID, | ||
| + | BLECharacteristic::PROPERTY_READ | | ||
| + | BLECharacteristic::PROPERTY_WRITE | ||
| + | ); | ||
| + | brightCharacteristic->setCallbacks(new BrightnessCallback()); | ||
| + | int defaultBrightness = 255; | ||
| + | brightCharacteristic->setValue(defaultBrightness); | ||
| + | |||
| + | // Start bme service. | ||
| + | bmeService->start(); | ||
| + | |||
| + | // Start Advertising | ||
| + | pServer->getAdvertising()->start(); | ||
| + | Serial.println("Waiting a client connection to notify..."); | ||
| + | |||
| + | </code> | ||
| + | |||
| + | Setting up the LedStrip and control logic is straight-forward. We have global variables holding the current state of the strip that get update on BLECallback triggers. We also have a chgStrip boolean that prevents unneccesary updating of the LedStrip if no changes are currently performed. | ||
| + | <code c++> | ||
| + | // Initialize the NeoPixel library | ||
| + | strip.begin(); | ||
| + | // Set all pixels to 'off' | ||
| + | strip.show(); | ||
| + | |||
| + | // Set some default strip values; | ||
| + | actualBrightness = 128; | ||
| + | actualColor = strip.Color(0, 75, 0); // moderately bright green | ||
| + | chgStrip = true; | ||
| + | |||
| + | [ ... ] | ||
| + | |||
| + | // Check if a device was connected | ||
| + | if (deviceConnected) { | ||
| + | if (!receivedColor.isEmpty()) { | ||
| + | actualColor = getColor(receivedColor); | ||
| + | receivedColor = ""; | ||
| + | chgStrip = true; | ||
| + | } | ||
| + | |||
| + | if (receivedBrightness != 0) { | ||
| + | actualBrightness = receivedBrightness; | ||
| + | receivedBrightness = 0; | ||
| + | chgStrip = true; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Update Strip. | ||
| + | if (chgStrip) { | ||
| + | strip.clear(); | ||
| + | |||
| + | for(int i=0; i<NUM_PIXELS; i++) { // For each pixel... | ||
| + | strip.setPixelColor(i, actualColor); | ||
| + | } | ||
| + | |||
| + | strip.setBrightness(actualBrightness); | ||
| + | strip.show(); | ||
| + | |||
| + | // Do not change strip next cycle | ||
| + | chgStrip = false; | ||
| + | } | ||
| + | |||
| + | </code> | ||
| ====== Challenges ====== | ====== Challenges ====== | ||
| - | ====== References ====== | + | Not having proper soldering tools leads to bad electrical contacts and makes it a nightmare to debug any issues. Thankfully, jamming a wire through the ESP32 DevBoard pins worked brilliantly, just don't ask me to move it anywhere. |
| + | Initially I wanted to use both BLE and a webpage hosted on the ESP32 itself to allow control of the LED strip from multiple sources but due to memory constraints on the ESP32 I had to choose only one (91% memory usage with the BLE implementation alone). | ||
| + | I find it very annoying how BLE handles characteristics, only having a predefined set of BLEUUID's available to pick and choose from. For example, the was no readily available UUID for brightness or color, just a generic "LED Array" or "Led Strip". | ||
| + | |||
| + | I choose BLE due to the easy implementaion as baking-in a HTML page in the Arduino IDE seems janky to me. The right way to approach would be by installing a lightweight RTOS such as NuttX or freeRTOS and ditching the BLE for a more customizable webpage, as in our case battery and power constraints are irrelevant. | ||
| + | |||
| + | ====== References ====== | ||
| + | * Adafruit_NeoPixel: https://github.com/adafruit/Adafruit_NeoPixel | ||
| + | * ArduinoBle: https://docs.arduino.cc/libraries/arduinoble/ | ||
| + | * Our OCW labs. | ||
| + | * Some helpful StackOverflow threads. | ||