Reverse Engineer BLE Smart Lights
Learn how to reverse engineer BLE Smart Devices (like colour changing lights), so you can write your one script to control them all, even lights from multiple manufacturers.
Forwarded this email? Subscribe here for more β¨
Welcome to the 13th edition of the 100 GenAI MVPs newsletter, a journey all about shipping 100 happy and helpful GenAI solutions, and how to build them! ππ©βπ»β¨ Together, we built a Robot Panda you can chat with (π award winner), a video clip extractor (Men In Black edition), and many more!
Hellooo AI Alchemists! π€π§ͺβ¨
Learning how to reverse engineer bluetooth (or WiFi) powered smart lights is a really useful project, especially if youβre interested in smart home automation.
At the moment, when you buy smart lights from different manufactures, you have to download an app for each of them to be able to control them. No one wants to open three apps just to turn the lights on. Ick.

In this post, youβll learn how to Reverse engineer Low Energy Bluetooth (BLE) devices so you can create your own βremote controlβ for their actions (in this case, colour changing lightsπ‘).
This isnβt an AI deep dive, but itβll be used as a foundation for near future AI & BLE device projects. For example:
In the next post, Iβll show you how to build your own AI-powered Alexa/Siri to control your smart lights!
Are you ready!??
Letβs get building! π€Ώ
β Becca π
If youβd like to see more frequent updates, connect with me on LinkedIn π₯°
How to reverse engineer a bluetooth smart light?
Reverse engineering a bluetooth smart light involves interacting with the light using the app that comes with it, capturing the data that is sent between them over bluetooth, unpacking that data, then sending the commands to your light and observing what happens when you do. Then you can write a script to automate it.
It isnβt always possible to do this if security has been taken seriously. Luckily for us (and pretty sketchily), most cheaper BLE devices donβt obfuscate their packet data.
For example, I was able to send colour values to Philips Hue Lights successfully, but could not reverse engineer the values that changed them (on and off and brightness was fine tho).
What you need
Youβll need the following apps and tools (or their equivalent) to do this:
A Bluetooth Low-Energy (BLE) Smart Light.
Android phone (or bluetooth sniffer dongle) - Capture BLE data.
A cable to connect phone to computer.
rNF Connect App (Android) - Send commands to your device.
Wireshark App (Computer) - Unpack data sent between phone and light.
Core Concepts
Bluetooth Low Energy (BLE): Most bluetooth-powered smart devices youβll find in your home like lights, appliances, toys, gadgets and fitness trackers etc use the BLE communication protocol. Itβs designed for sending small amounts of data without consuming too much power.
Generic Attribute Profile (GATT) Framework: Used in BLE communication. It defines how data is sent and accessed between devices (e.g. a light and an app).
Services: Services group together related device characteristics, pretty much like a folder. Often services correspond to a primary feature or capability of a device. Each service has itβs own Universally Unique Identifier (UUID). Standard UUIDs exist for common device services, but you can also create your own.
Characteristics: Characteristics are individual items of state data. They have a type, a value (e.g. colour value for a light that changes colour) and a set of properties which indicate how the data may be used (read, write, write and respond, notify, indicate).
Descriptors: Extra info about the characteristic, like its format, unit of measurement or range of possible values etc. A characteristic can have 0 or many descriptors.
If you reeeaallllly want to deep dive, hereβs the full Bluetooth Low Energy Primer white paper from Bluetooth.
Step 1: Sniff out the Bluetooth packets
We need to capture the raw data that is sent between our light and our phone over bluetooth. We can do this with a bluetooth sniffer.
What are Bluetooth sniffers?
A Bluetooth Sniffer captures Bluetooth communication between devices. It acts as a βman-in-the-middleβ observer, letting you see the raw data packets as they are exchanged between your devices in realtime.
Unfortunately, there isnβt an easy way to do this on IOS devices, because Apple apps are sandboxed and we canβt easily eavesdrop on data sent over Bluetooth (for security reasons). There are options, like PacketLogger, or hardware dongles like the NRF52840 dongle that you can plug into your laptop.
Itβs much easier to do on Android.
Sniff Bluetooth packets on Android
Android has a diagnostic feature called Bluetooth HCI snoop logging, which lets you capture and save the raw data packets sent over bluetooth. Itβs stored in a file called βbtsnoop_hci.logβ).
1. Enable Bluetooth HCI Snoop logging on Android
These are the steps for enabling bluetooth snoop logging:
Go to your Android phoneβs Settings.
Click on βAbout phoneβ and find the βBuild numberβ.
Tap the Build number 7 times to enable Developer Options.
Then go back to settings and click on βDeveloper Optionsβ.
Scroll down and enable Bluetooth HCI snoop log.
Scroll down and enable βUSB debuggingβ too.
Turn Bluetooth off and on again.
You need to turn Bluetooth HCI Snoop logging off when youβre not using it to test actions. Itβll start a brand new log each time you turn it on.
2. Perform bluetooth actions
Open the app that comes with your colour changing smart light, and start performing actions in it. Itβll be easier to reverse engineer the commands later by grouping same actions together:
Turn your light on and off 10-20 times.
Increment your brightness all the way down and all the way back up again.
Change the colour a gazillion times. It also helps to group your colour changes by hue too β like changing it to a few different reds, then oranges, then yellows and so on around the colour wheel.
Turn your light on and off 10-20 times again (for the symmetry).
3. Retrieve the HCI snoop log file
To get the file on from an Android phone, first connect your phone to your computer. Then:
Install the Android Platform tools onto your computer. I used Homebrew on Mac:
brew install android-platform-tools
Check that adb is installed. ADB is the Android Debug Bridge command line tool. Youβll use it to grab the bluetooth log from your phone.
adb --version
Use abd to list connected devices to check it has been connected correctly.
adb devices
After running this command, you should see a unique identifier followed by βdeviceβ. If you see a unique identifier followed by βunauthorizedβ, it means you need to unlock your phone and authorise your computer. Hereβs what both cases look like:
Generate a bug report via your command line so you can access your bluetooth log (replace bugreport.zip with the filename you want):
adb bugreport bugreport.zip
Extract the zip file, then navigate to the FS/data/log/bt directory. You should see the btsnoop_hci.log file there:
cd bugreport/FS/data/log/bt && ls
The contents of the btsnoop_hci.log file is in binary format, so weβll need another tool to unpack and read the contents.
Step 2: Unpack the Packets with Wireshark
Wireshark is a network protocol analyser. You can used it to read the data exchanged between devices over various protocols, including BLE.
1. Install WireShark
Download it from the Wireshark website. I used Homebrew on Mac to install it:
brew install --cask wireshark
2. Open the file in Wireshark
Open the btsnoop_hci.log file in Wireshark. File > Open > search for the log file > open
.
When you first open it, youβll see a list of all of the packets sent over bluetooth while your Bluetooth HCI snoop logging was enabled, in order of oldest to newest:
3. Filter the packets to write commands sent from phone to device
Next, we want to narrow down the packets to just those where we are sending a write command from our phone light control app to our smart light. We can do this by pasting the following filter into the βapply a filterβ bar at the top of the Wireshark screen:
btatt.opcode == 0x12
btatt - Bluetooth Attribute Protocol (ATT).
.opcode - Specifies the type of operation being performed. For example, reading data, writing data, or sending notifications.
0x12 - Is the hexadecimal value for the Write Request operation. A Write Request is a command sent by the client (your phone) to the server (the smart light) to write a value to a specific GATT characteristic.
4. Add custom columns and export packet data as CSV
The key information we need to extract are the service and characteristic UUIDs, along with the values that were written to them. When you click on a packet, these are displayed under the bottom left panel, under Bluetooth Attribute protocol.
To add them to your main table, click on βWiresharkβ in the toolbar > βpreferencesβ > βColumnsβ.
Then click the β+β
button, and choose the βCustomβ
Type for the field. The values you need are shown in the Fields column, e.g. βbtatt.characteristic_uuid128β for the characteristic ID.
Note: If you donβt see the Characteristics and Services UUIDs after pressing βOKβ, youβll need to open your bluetooth settings on your phone, forget device, then re-run the bluetooth packet snooping steps because theyβll have been cached.
Then export this data as a CSV by clicking βFileβ > βExport Packet Dissectionsβ > βAs CSVβ. This will make it easier to explore the data.
Step 3: Find out what the values do
The values will all be in hexadecimal format, where each digit can be a number from 0-9, or a letter from a-f (11-15). If youβve ever seen a colour hex code, this will feel more familiar to you.
1. Spot patterns
The first thing to do with packet values, is try and spot the difference. Look at what stays the same, and what changes. For example, the parts that change have been highlighted in pink below.
As you can see, the patterns are much easier to spot when you group all of the device actions you perform when capturing bluetooth packets β e.g. on/off, then brightness, then colour changes.
While we might be confident that this is what the values are doing, we wonβt know for sure until we write them to our device and see what happens. Letβs do that next.
2. Write the values to your device and see what happens
Finally, itβs time to start writing commands to our light and see what it does. You could write a script to do this (Iβll show you how later). But for the discovery phase itβs easiest to use the rNF Connect App.
The rNF Connect app lets you interact with BLE devices via their services and characteristics, like reading and writing data or monitoring notifications.
Write data to your light via rNF Connect App
Open the app and navigate to the βScannerβ tab.
Connect to your BLE smart light.
Navigate to the services tab (list icon).
Find the characteristic for an action you want to test, using the Service then Characteristic UUIDs that you exported to a CSV file earlier.
Click on the Up arrow next to that Characteristic.
Enter the value you want to test. It will be the full hexadecimal value from your spreadsheet. Click βSendβ.
Observe what happens.
See if there are any changes in the physical light.
You can use the app that comes with the light to confirm specific values like a brightness percentage or colour codes.
Write what happens in your spreadsheet next to the relevant characteristic for your future self.
By plugging in the value β7e0705034bff0010efβ to the right characteristic, I learned that it changed the colour of my light to blue.
Step 4: Write a script to interact with your light
Now weβve worked out what some or all the values all do when sent to our device, we can start writing a script to automate those actions.
Here is a breakdown of a python script for connecting to one device and writing values for different behaviours:
Imports:
import asyncio
from bleak import BleakScanner, BleakClient
import subprocess
Turn bluetooth on:
def turn_bluetooth_on():
result = subprocess.run(["blueutil", "--power"], capture_output=True, text=True)
if result.returncode == 0 and result.stdout.strip() == "0":
subprocess.run(["blueutil", "--power", "1"], capture_output=True, text=True)
Scan for bluetooth devices:
async def scan_ble_devices():
return await BleakScanner.discover()
Connect to your device:
async def connect_to_light(devices):
hexilights_address = "D8A41495-36BF-55D6-2117-6EAF0DD27995"
matched_device = next((d for d in devices if d.address == hexilights_address), None)
if matched_device:
async with BleakClient(matched_device.address) as client:
if client.is_connected:
print(f"Connected to {matched_device.name}")
# Add your light control behaviour here:
# Switch on and off
await switch(client, "OFF")
await switch(client, "ON")
await change_colour(client, "052df7") # blue
await set_brightness(client, 50) # 50% brightness
else:
return "Failed to connect to the light."
else:
return "Light not found. Make sure the device is powered on and in range."
Turn lights on and off:
async def switch(client, toggle="ON"):
characteristic_uuid = "0000FFF3-0000-1000-8000-00805F9B34FB"
value = "7e0404f00001ff00ef" if toggle == "ON" else "7e0404000000ff00ef"
await client.write_gatt_char(characteristic_uuid, bytes.fromhex(value))
await asyncio.sleep(0.5)
print(f"Turned light {toggle}")
Change colour:
async def change_colour(client, hex_code="0f2efa"):
await client.write_gatt_char(
"0000FFF3-0000-1000-8000-00805F9B34FB",
bytes.fromhex(f"7e070503{hex_code}10EF")
)
await asyncio.sleep(0.5)
print(f"Changed colour to {hex_code}")
Change brightness:
async def set_brightness(client, percentage):
if percentage < 0 or percentage > 100:
raise ValueError("Brightness percentage must be between 0 and 100.")
brightness_value = f"{round(percentage * 255 / 100):02x}"
await client.write_gatt_char(
"0000FFF3-0000-1000-8000-00805F9B34FB",
bytes.fromhex(f"7e0401{brightness_value}0000ef")
)
await asyncio.sleep(0.5)
print(f"Set brightness to {percentage}%")
Usage:
if __name__ == "__main__":
turn_bluetooth_on()
devices = asyncio.run(scan_ble_devices())
asyncio.run(connect_to_light(devices))
I used ChatGPT to help me write the first draft for this (e.g. how to connect to ble device with python, how to write to a ble device characteristic). Then I cleaned it up a bit.
To use this for your own lights, you need to change the device address, the characteristic UUID and the value codes written to your lights.
Step 5: Repeat for your other lights
Repeat this whole process for all of your other lights. Then update your script to:
Make each light interchangeable, so they can all respond to the same commands even if they implement them differently. In Python, you can use an abstract class to define the blueprint for the light behaviours. Then create a class for each light that uses it, but implements the commands in their own way (this is polymorphism in action).
Enable calling the same commands on multiple lights at the same time (parallel processing). You can do this by grouping commands (on/off, colour etc) for each light into a coroutine in python, then use asyncio.gather to run them all at the same time.
Final Code!
Here is my version, which runs my light interaction code on two lights from different brands at the same time.
GitHub Gist: Script for controlling multiple BLE smart lights
Hereβs a light being controlled from a single custom remote control script (totally boring video but I love it):
The possibilities of IOT & AI are so magical to me. Weβll be exploring this in future deep dives! In the meantime, if you reverse engineer your own devices, Iβd LOVE to see!!! (Share them with me via LinkedIn DM).
Until next time,
Stay sparkly π
If youβd like to see more frequent updates, connect with me on LinkedIn π₯°
Moar GenAI Projects! π€π§ͺβ¨
π Here are some more projects to check out if you loved this one!
Extract clips from videos based on a prompt, using OpenAI's GPT-4o model.
Build a prompt-based video clip extracter using OpenAI's GPT-4o model. In this project, we extract all clips where Will Smith wears sunglasses in the 1997 Men In Black movie trailer.
#8. ChatGPT-Powered Robot Panda
Helloooo AI Alchemists! β¨π€π§ͺ Late last year, my friend Stan and I won the Peopleβs Choice Award at Fishburnerβs Young Entrepreneur Pitch night, where I demoβd chatting with the panda on stage in front of 200+ founders and entrepreneurs πΌπ€ The CEO of Fishburners said:
#2. Analyse a journal entry for unhelpful thinking patterns with ChatGPT's function calling π€―
Helloooo AI Alchemists! β¨π€π§ͺ Last weekend, I built a program that Iβve personally wished existed for years. Itβs solved a real pain point for me, and Iβm so grateful it was even possible. Not only was it possible, but it was easy. Crazy easy. This is it:
β¨ Fairylights | 100 GenAI Projects is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.