Hacking PLAYBULB candles

PLAYBULB candles are smart LED candles that can be controlled by mobile Android/iOS devices. The official apps are good enough but I’d like to be able to control these candles using say a STACK Box or a NINJA SPHERE (when I’ll get them). The candles are Bluetooth Smart (aka Bluetooth Low Energy or BLE) devices so that shouldn’t be too complicated.

I just started playing with the candles and I’ll show you in this post how to control them using a computer with a BLE adapter. You’ll only need a Linux PC (should also work on a Mac) with integrated Bluetooth 4.0 or a USB BLE adapter (tested with this one but this one should also work). I used Santoku Linux on VirtualBox for my tests because it comes with BlueZ, the tool we are going to use to interact with the candle.

Turn the candle on then open a terminal and type in the following command to scan for BLE devices:

$ sudo hcitool lescan

The candle should appear in the list of devices:

LE Scan ...
AC:E6:4B:06:6F:CD (unknown)
AC:E6:4B:06:6F:CD PLAYBULB CANDLE

We can then use the mac address of the candle to enter interactive mode using gatttool:

$ gatttool -b AC:E6:4B:06:6F:CD -I

And connect to the candle:

[  ][AC:E6:4B:06:6F:CD][LE]> connect

Now that we are connected, we just need to write the right value to the right characteristic to do something useful with the candle. Using an Android device with the official app, I captured the communication to find out what data is sent when the app is used. For example, here’s the command to turn the candle on and set the color to red:

> char-write-cmd 0x0016 00FF0000

0X0016 is the handle to indicate what characteristic we want to write to and 00FF0000 is the value. FF0000 is the hex code for the color red so to set the candle to green (#00FF00) we just need to send the following command:

> char-write-cmd 0x0016 0000FF00

After capturing a few more packets, I figured out how to set an effect. We have to use another handle and the value format is slightly different. Here’s how we can set the candle effect on with the color blue:

> char-write-cmd 0x0014 000000FF04000100

The first eight bytes (000000FF) indicate that we want to set blue (#0000FF) as a static color. The next byte (04) indicates that we want the candle effect on. I don’t know yet what the next byte is used for but we can also choose the effect speed using the next one (01).

Here are a few other examples on how to use gatttool to control the candle.

Flashing effect, green color, lower speed:

> char-write-cmd 0x0014 0000FF0000001F00

Pulse effect, blue color, lower speed:

> char-write-cmd 0x0014 000000FF01001F00

Rainbow effect, highest speed:

> char-write-cmd 0x0014 0100000002000100

Rainbow effect fade, lower speed:

> char-write-cmd 0x0014 0100000003002600

To turn the candle off, it seems we just need to use this command:

> char-write-cmd 0x0016 00000000

This data could be used to control the candles through any BLE central device but also to develop alternate apps for Android/iOS.

18 thoughts on “Hacking PLAYBULB candles

  1. Thanks for the explanation how to intercept the commands and your analysis!

    I just received my Kickstarter Playbulb Rainbow, and the commands are slightly different:

    Format for the effects is: 0x0019 WWRRGGBBMM??SS?? where the questionmarks are still unknown to me, but MM is the effect mode (00 = Flash solid color, 01 = Pulse solid color, 02 = Rainbow, 03 = Rainbow with fading effect). SS is the speed, from 00 to ff.

    For solid colors the command is: 0x001b WWRRGGBB

    Liked by 1 person

    1. Hey Patrick,

      did find out any more commands? Sadly I don’t have a BLE sniffer and can’t find it out by myself. I’m working on a python script to control my candle and bulb via my raspberry.

      Thanks for your help

      Like

    2. Did you have any issues with Host is down or Connection refused errors? I have a Playbulb Rainbow and have tried both Bluez v4.99 and v5.35. v4.99 gives me the Host is down error, v5.35 gives Connection refused. I can see lescan and see the device with both version.

      Any ideas? There aren’t many sites talking about hacking these bulbs and I’ve read everything I can.

      Thanks.

      Like

  2. Nevermind. I got this working with a fresh install of Raspbian Jessie and Bluez 5.23. Works like a charm. I have a Playbulb Rainbow, so I’m using the commands Patrick lists above.

    Like

  3. Hi,

    Your commands do not work under macOS Sierra. You said you can write your own apps for the Playbulbs. How exactly does it work?

    Best regards
    Philipp Vogel

    Like

    1. Hi,

      You need Bluez for this to work and as far as I know Bluez is for Linux only. If you want to develop your own app, you’ll have to learn how to develop Android or iOS apps and use the information on this blog.

      You can use pretty much any BLE device (phone, pc, mac etc.) to control these bulbs. Here’s a nice tutorial on how you can control them with a Puck.js (http://www.puck-js.com/) : https://www.espruino.com/Puck.js+and+Bluetooth+Lightbulbs

      Cheers,
      Pierre

      Like

  4. Thanks for this article, really cool! However, I have the Playbulb Sphere and these commands wouldn’t work…did a little digging around and you need to change the handle to 0x001b to adjust colours on this particular model – then just use the hex colours as described in the article.

    More info here:

    https://github.com/Phhere/Playbulb/issues/1

    Like

  5. Mipow Playbulb BTL201

    After several days of debugging and playing around with gatttool I have almost find out the meaning and functionality of handles of the MIPOW Playbulb BTL201 (Version 2 BTL201_v2).

    I have written an expect-scripts that gives me more features, e.g. smooth wake-program with blue colors or doze-programm with red colors or dia-effects (little pause between switching colors). These things are of course not build in the playbulb. They are controlled by an INTEL NUC or Raspberry pi.

    I want to share my results. Find here everything that I have found out about the Playbulb by MIPOW.

    Device Information
    Handle 0x28 – The product id of the bulb
    Encoded in ASCII, you must transform hex to ascii
    Default value: „BTL201“
    Get: char-read-hnd 28
    Characteristic value/descriptor: 42 54 4c 32 30 31
    Set: n/a

    Handle 0x2C – The product id of the bulb incl. Version
    Encoded in ASCII, you must transform hex to ascii
    Default value: „BTL201_v2“
    Get: char-read-hnd 2c
    Characteristic value/descriptor: 42 54 4c 32 30 31 5f 76 32
    Set: n/a

    Handle 0x30 – The vendor of the bulb
    Encoded in ASCII, you must transform hex to ascii
    Default value: „Mipow Limited“
    Get: char-read-hnd 2e
    Characteristic value/descriptor: 4d 69 70 6f 77 20 4c 69 6d 69 74 65 64
    Set: n/a

    Handle 0x2E – The software version of the bulb
    Encoded in ASCII, you must transform hex to ascii
    Default value: „Application version 2.4.3.26“
    Get: char-read-hnd 2e
    Characteristic value/descriptor: 41 70 70 6c 69 63 61 74 69 6f 6e 20 76 65 72 73 69 6f 6e 20 32 2e 34 2e 33 2e 32 36
    Set: n/a

    Handle 0x2A – Microprocessor of bulb
    Encoded in ASCII, you must transform hex to ascii
    Default value: „CSR101x A05“
    Get: char-read-hnd 2a
    Characteristic value/descriptor: 43 53 52 31 30 31 78 20 41 30 35
    Set: n/a

    Handle 0x03 / 0x21 – The given name of the bulb
    Default value: “MIPOW SMART BULB”
    Get: char-read-hnd 3
    Characteristic value/descriptor: 4d 49 50 4f 57 20 53 4d 41 52 54 20 42 55 4c 42
    Set: char-write-req 3 4142434445464748494a4b4c4d4e4f
    Set: char-write-req 12 4142434445464748494a4b4c4d4e4f
    Note: This seems to be the only value that will be kept after you have disconnected the bulb from power.

    Color
    Handle 0x1B – Color of bulb
    The color of the bulb. Can also be used in order to read current color, in case that effect or runs or timer is on.
    Get: char-read-hnd 1b
    Characteristic value/descriptor: ff 00 00 00
    Set: char-write-cmd 1b ff000000
    Setting the color deactivates a running effect. Set all colors to zero in order to turn bulb off.

    Byte 1: White in hex (0 – ff)
    Byte 2: Red in hex (0 – ff)
    Byte 3: Green in hex (0 – ff)
    Byte 4: Blue in hex (0 – ff)

    Effects
    The bulb has four effects, i.e. blink, pulse, smooth rainbow, hard rainbow.
    Note: Although according the app there is an additional effect called „candle“ It does not work with my bulb.

    Handle 0x19 – effect of bulb
    The effect of the bulb.
    Get: char-read-hnd 19
    Characteristic value/descriptor: 00 00 00 00 ff 00 00 00
    Set: char-write-cmd 19 00000000ff00ff00
    Byte: 1 to 4: Color of effect, current color, values are persisted even if effect stops (can be written in order to remember previous color after bulb has been soft-turned off in order to be able to toggle to colors before – must be programmed by yourself of course)
    Byte 5: Effect (blink=00, pulse=01, hard rainbow=02, smooth rainbow=03, halt=ff)
    Byte 6: no special meaning, always „ff“, use „00“ if you set handle
    Byte 7: Delay of the effect
    Byte 8: no special meaning, always „ff“, use „00“ if you set handle

    More about delay of effect
    1. Delay for smooth rainbow effect
    The value is the delay in ms for every single step.

    Example: Delay is 255 (ff)
    – It takes exactly 6:30 min (390 sec.) for one sequence with fading and changing all 6 colors (red → yellow → green → magenta → blue → cyan)
    – The fading from 0 to 255 takes 65 seconds
    – It takes 0,255 secs for one step with delay of 255

    2. Delay for hard rainbow effect
    The value is the hold value in seconds for each color (red → yellow → green → magenta → blue → cyan)

    Example: Delay is 255 (ff)
    – It takes exactly 15,3 sec. for one sequence and all 6 colors (red → yellow → green → magenta → blue → cyan)
    – one color will be displayed for 2,55 secs with hold of 255
    – numeric value for effect is hold in 1/10s

    3. Delay for pulse effect
    The value is the delay in ms for every single step.

    Example: Pulse with hold 255 (ff)
    – The fading from 0 to 255 takes 65 seconds
    – Therefore the fading from 0 to 255 and back takes 130secs.
    – It takes 0,255 secs for one step with hold of 255

    4. Delay for blink effect
    The value is the period in seconds for each state (on, off).

    Example: Blink with hold 255
    – 10 on/off-turns take 51 seconds
    – 1 turn takes 5,1 seconds
    – Hold of 255 means 2,55 seconds on and another 2,55 seconds off

    Read current timers
    The MIPOW Playbulb has 4 timers and an internal clock (maybe a good chance to feed a Raspberry Pi since it does not have its own realtime clock).
    Note that information about timers are read from 2 different handles.

    Handle 0x1f – Status and starting times of timers
    Get: char-write-req 1f
    Characteristic value/descriptor: 04 ff ff 04 ff ff 04 ff ff 04 ff ff 00 00
    Set: (see chapter „write new timer)
    Timer 1:
    Byte 1: Timer type (00 – wake-up timer, 02 – doze timer, 04 – deactivated timer)
    Byte 2 and 3: Time of the timer in hex (hh mm), „ff“ if timer is deactivated
    Timer 2:
    ident. timer 1 but in bytes 4 to 6
    Timer 3:
    ident. timer 1 but in bytes 7 to 9
    Timer 3:
    ident. timer 1 but in bytes 10 to 12

    Clock:
    Byte 13 and 14: Current time (hh mm) in hex, does not run if neither random mode nor at least one timer is active!

    Handle 0x13 – Color and running time of timers
    Get: char-write-req 13
    Characteristic value/descriptor: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Set: (see chapter „write new timer)
    Timer 1:
    Byte 1 to 4: Color of this timer (values for white, red, green blue)
    Byte 5: Delay of timer effect (in app called „minutes“ but this seems to be wrong)
    Timer 2:
    ident. timer 1 but in bytes 6 to 10
    Timer 3:
    ident. timer 1 but in bytes 11 to 15
    Timer 4:
    ident. timer 1 but in bytes 16 to 20

    Write new timer
    The MIPOW Playbulb has 4 timers and an internal clock. In order to set a new timer only one handle must be written in request-mode (instead of command mode)
    Write to Handle 0x1f
    Set: char-write-req 1f 00010013120002030000000000
    Byte 1: Number of timer that you want to set (value 01 to 04) – stored in handle 0x1f
    Byte 2: Timer type (00 – wake-up timer, 02 – doze timer, 04 – deactivated timer) – stored in handle 0x1f
    Byte 3: (meaning is unclear, value will be written to handle 0x15 byte 1), use prob. random values, e.g. „1b“, „31“
    Byte 4: set current time minutes of internal clock in hex – afterwards available in handle 0x1f byte 14 and handle 0x15 byte 2, clock runs automatically
    Byte 5: set current time hours of internal clock in hex – afterwards available in handle 0x1f byte 13 and handle 0x15 byte 3, clock runs automatically
    Byte 6: Minutes of starting time in hex – stored in handle 0x1f
    Byte 7: Hours of starting time in hex – stored in handle 0x1f
    Bytes 8 – 11: Color of this timer (values for white, red, green blue) – stored in handle 0x13
    Byte 12: Delay of timer effect (in app called „minutes“ but this seems to be wrong) – stored in handle 13

    Random mode (called „security“ in app)
    The bulb has a build-in functionality to turn on and off in a certain period. It is called „Security“ in app.
    Note that handle must be written in request-mode (instead of command mode)
    Get: char-read-hnd 15
    Characteristic value/descriptor: 17 12 12 01 02 03 04 05 06 ff 00 00 00
    Set: char-write-req 15 000312ffffffffffff00000000
    Byte 1: Meaning is unclear, if random mode or timer is active value is different from „00“
    Bytes 2 – 3: Current time in hex (mm hh)
    Bytes 4 – 5: Starting time of random mode (hh mm) in hex
    Bytes 6 to 7: Ending time of random mode (hh mm) in hex
    Byte 8: Min. interval (in minutes) in hex
    Byte 9: Max. interval (in minutes) in hex
    Byte 10 – 13: Color security mode (white red green blue)
    Example:
    char-write-req 15 000312ffffffffffff00000000
    sets time to 18:48 and turns security function off

    Internal clock
    The MIPOW Playbulb has an internal clock. This is probably a good chance to feed a Raspberry Pi since it does not have its own realtime clock.
    However, in order to

    Password (n/a)
    Although according the app it should be possible to set a password for the bulb it does not work with my bulb.

    Factory Reset
    The official app has a button for factory reset. I am not sure if the apps sets all values manually or calls something of the bulb.
    BTW: The bulb forgets everything after you have disconnected it from power. Therefore this is simular to a factory reset. It seems that the „given name“ of the bulb is the only thing that is still available after loss of power.

    —-

    Best regards,
    Heckie

    PS: Maybe I will also post my expect script in future. But I haven’t finally programmed timers and security functionally yet.

    Like

Leave a comment