Controlling a Bluetooth LED strip with HA

Hi there,

I have purchased a Bluetooth controlled LED strip that uses this generic Android/IOS app called Happy lighting to control it.
Is it possible to control this light strip through HA working in a RPi4?
Does anyone knows how to do it?

1 Like

HI,

I did it using the BT embedded on an RPi 3+. But it should work in the same way with an RPi 4.

It takes a bit of time, because you have to find out the codes to be sent to the BT controller of the LED, but at the end it is working.

For the moment I have created a simple card with some buttons to drive the main commands on the LED…

I am going to make it nicer with the custom button card.

The buttons are connected to scripts and the scripts contain shell commands to the BT controller like this…

balcony_led_on: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n cc2333

You will have to find the mac_addr of the BT device, the UID (-a) of the function and the command to send for the specific operation (-n). These are specific for each device.

Good luck. :slight_smile:

3 Likes

Hi @vic !

Thanks for your reply. I found it very helpful.
Could you share how you could find the BT codes? Maybe if you share yours I could try them to see if it is the same colour/effect, a lot of Chinese manufacturers use the same app, though they may use the same codes.

Thanks again!

I’m also interested in a way to snif the BT traffic for a later replay.

Hi,

if you do not know anything about sniffing BT commands you can have a look here https://learn.adafruit.com/reverse-engineering-a-bluetooth-low-energy-light-bulb?view=all

It also explains how to use the gattool and the hciconfig on the RPi BT directly (which is what I have done).

My final shell commands look like this:

shell_command:
  balcony_led_on: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n cc2333
  balcony_led_off: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n cc2433
  balcony_led_red: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 56ff000000f0aa
  balcony_led_green: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 5600ff0000f0aa
  balcony_led_blue: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 560000ff00f0aa
  balcony_led_cyan: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 5600ffff00f0aa
  balcony_led_magenta: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 56ff00ff00f0aa
  balcony_led_yellow: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 56ffff0000f0aa
  balcony_led_white: gatttool -i hci0 -b {{ mac_addr }} --char-write-req -a 0x0009 -n 56ffffff00f0aa

Then I added scripts like the one below (old script version) to the config file for using them in the buttons:

balcony_led_up_on:
  alias: Balcony LED up on
  sequence:
    service: shell_command.balcony_led_on
    data_template:
      mac_addr: !secret mac_balcony_led_up
3 Likes

@vic - This is great information - Thank you!

I’ve used this to get a Melpo RGB Floodlight working with an RPI3 running Octopi on my 3D printer.

I did run into an issue with how you’ve written the code, though… it wasn’t clear until I read the man page for gatttool that the double braces you’ve used around the “mac_addr” to indicate that this is a variable. It would be way more clear if you just drop the braces and just write it like the bash variable it is:

mac_addr="mac address of BT device to control"
gatttool -i hci0 -b $mac_addr --char-write-req -a 0x0009 -n cc2333

I wrote up a script for my own use case with the unique parts defined as variables so you can easily replace it with your own values:

#!/bin/bash

sendBluetoothCommand() {
  mac="$1"
  characteristic="$2"
  commandcode="$3"
  gatttool -i hci0 -b $mac --char-write-req -a $characteristic -n $commandcode
}

mac="$1"
command="$2"
characteristic=0x0007

case $command in
  on)
    commandcode="cc2333"
    ;;
  off)
    commandcode="cc2433"
    ;;
  red)
    commandcode="56ff000000f0aa"
    ;;
  green)
    commandcode="5600ff0000f0aa"
    ;;
  blue)
    commandcode="560000ff00f0aa"
    ;;
  cyan)
    commandcode="5600ffff00f0aa"
    ;;
  magenta)
    commandcode="56ff00ff00f0aa"
    ;;
  yellow)
    commandcode="56ffff0000f0aa"
    ;;
  white)
    commandcode="56ffffff00f0aa"
    ;;
  warmwhite)
    commandcode="56ffff3300f0aa"
    ;;
  *)
    echo "Unsupported command!"
    exit 22
    ;;
esac

sendBluetoothCommand $mac $characteristic $commandcode

Call it like this:
./bt_command_script.sh F0:0F:15:13:4Z:W7 on

2 Likes

Thank you @mainmachine for the feedback.
Indeed when I have put here the command I copied the line from the config file. :slight_smile:

In the meantime I have swapped the BT controllers of the LED and replaced them with WiFi ones, from Shelly. It is much better and they are way more flexible. :stuck_out_tongue_winking_eye:

1 Like

By the way, if you are interested, I have created much better ad hoc buttons to manage the LEDs, starting from the light widget.
They look like this…
LED buttons

When you press one of them, then a popup is opening to select in a fast way one of the main colors…

And if you keep it pressed, you get a popup window with the controller info…

4 Likes

I made a custom integration for HappyLighting based protocol here. Feel free to try it out.

2 Likes

Hi, I can’t find in HACS. :-\ Name od app in HACS?

You need to manually add the repo to HACS

Gonna give it a go. Thanks

I try a similar approach for my BLE light, but I get the following response after calling gatttool:

connect error: Device or resource busy (16)

Are you familiar with this error?

Hi,

I had not get that type of error in my tests.
It looks like the BT device is used by another program.
Have you checked if the BT device is up and running? Is the device address correct?

If not done yet, you could try in interactive mode to see where it gets stuck (below an example):

sudo gattool -I
connect XX:XX:XX:XX:XX:XX
primary
char-desc 0xNNNN 0xNNNN

Unfortunately I cannot re-run the tests at the moment because I have changed my setup.

hi sysofwan,

I successfully integrated my device thanks to your integration, but I can see it as a simple “light”, without any setting for RGB or brightness.
How can I manage colors and brightness?

EDIT 22/03/22
Solved…thanks!!

Hi guys,

Wanted to say thanks for the information in this thread. Inspired me to get an oddball bulb working that I had picked up when it was on sale.

Sengled Smart LED with Bluetooth Speaker Bulb – Sengled Canada - that guy

The tricky bit I had to work around was the bulb expecting brightness between 1-100, but in hex which I solved in my bash script. Then Home Assistant wants to use 1-255… :roll_eyes:

Here’s what I came up with.

#!/bin/bash

sendBluetoothCommand() {
  mac="$mac"
  characteristic="$characteristic"
  commandcode="$1"
  gatttool -i hci0 -b $mac --char-write-req -a $characteristic -n $commandcode
}

mac="01:23:45:67:89:AB"
command="$1"
characteristic=0x0017

case $command in
  volume_up)
    commandcode="7efeffffff0000000000000d000101"
    ;;
  volume_down)
    commandcode="7efeffffff0000000000000d000001"
    ;;
  on)
    commandcode="7efeffffff0000000001000000000000"
    ;;
  off)
    commandcode="7efeffffff0000000001000000000001"
    ;;
  [0-9]|[1-9][0-9]|100)
    hex=$(printf '%02x\n' $1)
    commandcode="7efeffffff00000000010001000000ff$hex"
    ;;
  *)
    echo "Unsupported command!"
    exit 22
    ;;
esac

sendBluetoothCommand $commandcode

Then for the light in home assistant - template to the rescue. Here I convert 1-255 to 1-100 which is what the script is expecting.

  - platform: template
    lights:
      workbench_lamp:
        friendly_name: "Workbench Lamp"
        icon_template: mdi:desk-lamp
        turn_on:
          service: shell_command.sengled_control_on
        turn_off:
          service: shell_command.sengled_control_off
        set_level:
          service: shell_command.sengled_brightness_control
          data:
            brightness: "{{ (brightness | float / 255 * 100) | round(0) }}"

Oh right I also made simple shell command that just calls the script with args specified.

# Sengled Pulse Solo control
sengled_control_on: bash /config/scripts/sengled_control.sh on
sengled_control_off: bash /config/scripts/sengled_control.sh off
sengled_control_volume_up: bash /config/scripts/sengled_control.sh volume_up
sengled_control_volume_down: bash /config/scripts/sengled_control.sh volume_down
sengled_brightness_control: bash /config/scripts/sengled_control.sh {{brightness}}

Magically this all works and made an otherwise useless bulb very useful.

Thanks again everybody! :beers:

2 Likes

Hi, does this work with bluetooth proxy feature that’s recently added to homeassistant?

I’m not sure what proxy you refer to. If your home assistant has bluetooth like Bluetooth - Home Assistant - that. Then most likely yes.

My script is very much customized for my bulb though. Don’t try just copy pasting it.

Ah I just found out about this - ESPHome Bluetooth Proxy - very cool and yes I think this would work but I don’t suffer from an overabundance of space.

can you share the details on setting up the Melpo RBG Floods…

Looking at doing a few of these - https://www.amazon.com/Outdoor-Equivalent-Landscape-Lighting-Control/dp/B09QKLN8CX?ref_=ast_sto_dp

Everything I’ve done is in the post you replied to.

That said, the first Melpo I got works with the above quite nicely, but as we’ve seen with the majority of these “generic” tier smart products, they can vary wildly from one batch to the next. Since the first one was working I bought 3 more, but these three won’t do any color but a weird bluish white! :roll_eyes:

I am toying with the idea of gutting one of the half-dozen dead RGB bulbs I have sitting around and frakensteining the ESP boards into the Melpo’s as I would rather have WiFi control than BT. That plan hinges on being able to salvage part or all of the smart bulbs boards… I’ve autopsied a couple - having worked with electronics repair professionally for 20 years, my first suspicion is failed capacitor(s) in the power circuit, and while I haven’t gotten further than visual assessment, they sure look like the kind of caps that like to keel over dead in gear like this. I would just repair the bulbs but reassembly with the A16 screw base is really sketchy as of course these are not designed for serviceability, sadly.