Differences

This shows you the differences between two versions of the page.

Link to this comparison view

iothings:proiecte:2023sric:smartled [2024/05/29 18:13]
dragos.petre
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 =====
 ==== Physical Architecture ==== ==== Physical Architecture ====
 +=== Diagram ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_iot_architecture.png?​500 |}}
  
 +=== Real Hardware ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_real_hardware.jpg?​700 |}}
 ==== Software Architecture ==== ==== Software Architecture ====
  
-==== How it works ====+=== Setup de BLE Service ​=== 
 +<code c++> 
 +// BLE settings 
 +#define SERVICE_UUID ​       "​LED12345-1234-1234-1234-123456789LED"​ 
 +#define CHARACTERISTIC_UUID "​87654321-4321-4321-4321-LED987654321"​
  
 +BLECharacteristic *pCharacteristic;​
 +bool deviceConnected = false;
 +std::string receivedValue;​
 +
 +// BLE server callback
 +class MyServerCallbacks:​ public BLEServerCallbacks {
 +  void onConnect(BLEServer* pServer) {
 +    deviceConnected = true;
 +  };
 +
 +  void onDisconnect(BLEServer* pServer) {
 +    deviceConnected = false;
 +  }
 +};
 +
 +// BLE characteristic callback
 +class MyCallbacks:​ public BLECharacteristicCallbacks {
 +  void onWrite(BLECharacteristic *pCharacteristic) {
 +    receivedValue = pCharacteristic->​getValue();​
 +    if (receivedValue.length() > 0) {
 +      Serial.print("​Received Value: ");
 +      Serial.println(receivedValue.c_str());​
 +    }
 +  }
 +};
 +
 +void setup() {
 +  Serial.begin(115200);​
 +
 +  // Initialize the NeoPixel library
 +  strip.begin();​
 +  // Set all pixels to '​off'​
 +  strip.show();​
 +
 +  // Initialize BLE
 +  BLEDevice::​init("​ESP32_LED_Control"​);​
 +  BLEServer *pServer = BLEDevice::​createServer();​
 +  pServer->​setCallbacks(new MyServerCallbacks());​
 +
 +  BLEService *pService = pServer->​createService(SERVICE_UUID);​
 +  pCharacteristic = pService->​createCharacteristic(
 +                      CHARACTERISTIC_UUID,​
 +                      BLECharacteristic::​PROPERTY_READ |
 +                      BLECharacteristic::​PROPERTY_WRITE
 +                    );
 +  pCharacteristic->​setCallbacks(new MyCallbacks());​
 +  pCharacteristic->​setValue("​Hello,​ World!"​);​
 +  pService->​start();​
 +
 +  BLEAdvertising *pAdvertising = pServer->​getAdvertising();​
 +  pAdvertising->​addServiceUUID(SERVICE_UUID);​
 +  pAdvertising->​setScanResponse(true);​
 +  pAdvertising->​setMinPreferred(0x06);​
 +  pAdvertising->​setMinPreferred(0x12);​
 +  BLEDevice::​startAdvertising();​
 +
 +  Serial.println("​Waiting for a client connection to notify..."​);​
 +}
 +</​code>​
 +
 +=== Get the commands from the phone via the created service ===
 +<code cpp>
 +void loop() {
 +  // Check if a device was connected
 +  if (deviceConnected) {
 +    if (!receivedValue.empty()) {
 +      handleCommand(receivedValue);​
 +      receivedValue = "";​
 +    }
 +  }
 +}
 +
 +// 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;
 +  }
 +}
 +</​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>​
 +==== How it works ====
 +=== Main service page ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_ble_service.jpg?​300 |}}
 +=== Command for a static color ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_static.jpg?​300 |}}
 +=== Command for splitting the strip in 2 colors ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_split.jpg?​300 |}}
 +=== Command for cycling through colors ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_cycle.jpg?​300 |}}
 +=== Command for having a rainbow show ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_rainbow.jpg?​300 |}}
 +=== Command for having a snake-like moving ===
 +{{ :​iothings:​proiecte:​2023sric:​peterdragos_snake.jpg?​300 |}}
 +=== Command for lighting-up random LEDs with random colors ===
 +{{ :​iothings:​proiecte:​2023sric:​petredragos_random.jpg?​300 |}}
 ===== Challenges ===== ===== Challenges =====
 Initially, I wanted to use both WiFi and BLE to control the LED Strip, but I had to limit myself to just one of them, so I chose BLE. The issue was that the WiFi library was just too big in size, taking over 59% of the text memory on my development board, so I dropped it. Initially, I wanted to use both WiFi and BLE to control the LED Strip, but I had to limit myself to just one of them, so I chose BLE. The issue was that the WiFi library was just too big in size, taking over 59% of the text memory on my development board, so I dropped it.
Line 42: 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 ;-))
iothings/proiecte/2023sric/smartled.1716995624.txt.gz · Last modified: 2024/05/29 18:13 by dragos.petre
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0