This is an old revision of the document!
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.
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.
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.
// 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...");
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.
// 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; }