Controlling PlayBulb candles with Python

I recently found these candles which have a little RGBW LED inside and can be controlled via Bluetooth 4. They have a nice little feature where a small microphone built into the candle will detect if you blow into them, turning them off and – somewhat counter-intuitively – turning them back on again.


When they arrived, I started searching for a way to script them so I could add them to my home automation. The app left a little to be desired, it was a little slow and was cumbersome.

Two very important resources were this list of codes and this write-up. I ended up having to use my Android phone to sniff the packets from the app using `Developer` -> `Enable Bluetooth HCI snoop log` to help with setting the names (it needed --char-write-req for the name to save).

After a night of caffeine-filled coding, I had a Raspberry Pi 3 with a cheap CSR 4.0 BTLE dongle and a python library.

The retry logic is not the most robust but should work most of the time. Call the same command again to make sure it gets to the bulb.

Code can he found here.

The full installation instructions are up on GitHub, but you can grab the package with pip install playbulbcandle


For most commands, the ‘parsed’ element of the dict is the most useful.

First create a PlayBulbCandle object with the device address


Optionally you can disable automatic name retrieval with

[python]bulb.PlayBulbCandle(‘AC:E6:4B:07:EE:6B’, False)[/python]

This will make each command run a little faster because the lookup doesn’t have to be done first.


dict getName()

Returns a dict containing name information

{'msg': '43 61 6e 64 6c 65 20 31', 'result': 'success', 'address': '0x001C', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 'Candle 1'}

dict getEffect()

Returns a dict containing information about the currently set effect

{'msg': '00 00 00 00 ff 00 0a 0a', 'result': 'success', 'address': '0x0014', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': {'blue': 0, 'green': 0, 'mode': 'off', 'white': 0, 'speed': 10, 'red': 0}}

dict getColor()

Returns a dict containing color information

{'msg': '00 00 00 00', 'result': 'success', 'address': '0x0016', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': {'blue': 0, 'white': 0, 'green': 0, 'red': 0}}

dict getType()

Returns dict of device type

{'msg': '42 54 4c 33 30 30', 'result': 'success', 'address': '0x0023', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 'BTL300'}

dict getFamily()

Returns dict of the family of device

{'msg': '43 53 52 31 30 31 78 20 41 30 35', 'result': 'success', 'address': '0x0025', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 'CSR101x A05'}

dict getFirmwareVersion()

Returns a dict of the firmware version

{'msg': '42 54 4c 33 30 30 5f 76 35', 'result': 'success', 'address': '0x0027', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 'BTL300_v5'}

dict getAppVersion()

Returns a dict of the software version

{'msg': '41 70 70 6c 69 63 61 74 69 6f 6e 20 76 65 72 73 69 6f 6e 20 32 2e 33 2e 30 2e 33 31', 'result': 'success', 'address': '0x0029', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 'Application version'}

dict getManufacturer()

Returns dict of who made the bulb

{'msg': '4d 69 70 6f 77 20 4c 69 6d 69 74 65 64', 'result': 'success', 'address': '0x002b', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 'Mipow Limited'}

dict getBatteryLevel()

Returns dict of current battery level

{'msg': '64', 'result': 'success', 'address': '0x001f', 'device': {'name': 'Candle 1', 'address': 'AC:E6:4B:07:EE:6B'}, 'type': 'read', 'parsed': 100}

dict setName(string name)

Set the name of the device

[python]bulb.setName(‘Candle 5’)[/python]

dict setColor(int white, int red, int green, int blue)

Set the color of the bulb. Each int is between 0 (off) and 255 (full)

[python]bulb.setColor(255, 0, 0, 0)[/python]

dict setEffect(int white, int red, int green, int blue, string mode, int speed)

Set the effect of the bulb. Each int is between 0 (off) and 255 (full). Mode can be `off`, `fade`, `jumpRgb`, `fadeRgb`, `candle`.

[python]bulb.setEffect(255, 0, 0, 0, ‘candle’, 0)[/python]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.