How To: Control a non-supported BLE light with ESPHOME

I had a problem adding a BLE strip I have (see GitHub issue here). That bug/problem is until now not fix.

Since I really wanted to control that strip, I ended up creating a virtual light. Maybe this helps to another person on with the same problem.

This is the code I used:

esp32-board.ymal

substitutions:
  bluetooth_virtual_light_mac: THE:LBE:MAC:HERE

packages:
  bluetooth_virtual_light: !include common/bluetooth-virtual-light.yaml

common/bluetooth-virtual-light.yaml

esphome:
  includes: 
    - common/bluetooth-virtual-light.h

binary_sensor: 
  - platform: template
    name: "Led BLE Connected"
    id: led_ble_connected_sensor

ble_client:
  - mac_address: ${bluetooth_virtual_light_mac}
    id: led_strip_ble_client
    on_connect:
      then:
        - lambda: |-
            ESP_LOGD("virtual_ble_light", "Connected to BLE device");
        - binary_sensor.template.publish:
            id: led_ble_connected_sensor
            state: ON
        - switch.turn_off: led_ble_on_off_switch

    on_disconnect:
      then:
        - lambda: |-
            ESP_LOGD("virtual_ble_light", "Disconnected to BLE device");
        - binary_sensor.template.publish:
            id: led_ble_connected_sensor
            state: OFF

light:
  - platform: rgb
    id: rbg_led
    name: BLE LED
    red: red_channel_output
    green: green_channel_output
    blue: blue_channel_output
    default_transition_length: 0.25s
    on_state: 
      - lambda: |-
          ESP_LOGD("virtual_ble_light", "State Send");
    on_turn_on:
      - lambda: |-
          id(led_ble_on_off_switch).turn_on();
    on_turn_off:
      - lambda: |-
          id(led_ble_on_off_switch).turn_off();

output: 
  - platform: template
    id: red_channel_output
    type: float
    min_power: 0.003
    zero_means_zero: true
    write_action:
      - lambda: |-
            SSDBluetoothVirtualLight::updateRed(state);
            // char buf[30];
            // sprintf(buf, "red_channel_output=%.6f", state);
            // ESP_LOGI("virtual_ble_light", buf);
  - platform: template
    id: green_channel_output
    type: float
    min_power: 0.003
    zero_means_zero: true
    write_action:
      - lambda: |-
            SSDBluetoothVirtualLight::updateGreen(state);
            // char buf[30];
            // sprintf(buf, "green_channel_output=%.6f", state);
            // ESP_LOGI("virtual_ble_light", buf);
  - platform: template
    id: blue_channel_output
    type: float
    min_power: 0.003
    zero_means_zero: true
    write_action:
      - lambda: |-
            SSDBluetoothVirtualLight::updateBlue(state);
            // char buf[30];
            // sprintf(buf, "blue_channel_output=%.6f", state);
            // ESP_LOGI("virtual_ble_light", buf);
      - ble_client.ble_write:
          id: led_strip_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return SSDBluetoothVirtualLight::getCreateColorUpdateArray();


switch:
  - platform: ble_client
    ble_client_id: led_strip_ble_client
    name: "Enable Bluetooth"
    internal: true

  - platform: template
    id: led_ble_on_off_switch
    name: "Turn On Led"
    internal: true
    restore_mode: ALWAYS_OFF
    turn_on_action:
      - ble_client.ble_write:
          id: led_strip_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return SSDBluetoothVirtualLight::turnOnArray;

    turn_off_action:
      - ble_client.ble_write:
          id: led_strip_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return SSDBluetoothVirtualLight::turnOffArray;
      - lambda: |-
            ESP_LOGD(SSDBluetoothVirtualLight::logTag, "SEND MESSAGE TO TURN OFF");

bluetooth-virtual-light.h

// #include <esphome.h>
#include <vector>
namespace SSDBluetoothVirtualLight {
  const char* logTag = "ssd_virtual_bluetooth_light";
  const std::vector<uint8_t> turnOffArray = {126, 255, 4, 0, 255, 255, 255, 255, 239};
  const std::vector<uint8_t> turnOnArray =  {126, 255, 4, 1, 255, 255, 255, 255, 239};
  const std::vector<uint8_t> noColorArray =  {126, 255, 5, 3, 0, 0, 0, 255, 239};

  float red = 0;
  float green = 0;
  float blue = 0;

    std::vector<uint8_t> getCreateColorUpdateArray()
    {
      
      uint8_t convertedRed = static_cast<uint8_t>(red * 255);
      uint8_t convertedGreen = static_cast<uint8_t>(green * 255);
      uint8_t convertedBlue = static_cast<uint8_t>(blue * 255);
      
      return {126, 255, 5, 3, convertedRed, convertedGreen, convertedBlue, 255, 239};
  }    
  
  

  void updateRed(float value){
    red = value;
  }
  
  void updateGreen(float value){
    green = value;
  }

  void updateBlue(float value){
    blue = value;
  }


}

Enjoy!

4 Likes

Hello @Distante ! I’ll be rather interested but cannot understand very well where those stuf have to be written.

I have installed bluetooh-proxy on an esp32 via esphome by using this yaml :

 esphome:
  name: btproxy

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
   level: DEBUG

# Enable Home Assistant API
api:
  password: ""

ota:
  - platform: esphome
    password: ""

wifi:
  ssid: "MYSSID"
  password: "MYPASS"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Btproxy Fallback Hotspot"
    password: "VerySecurePassword"

captive_portal:

esp32_ble_tracker:
  scan_parameters:
    active: true

bluetooth_proxy:   
  active: true

and the device is visible in Homeassistant as esphome.
When downloading the debug logs I can see the mac for my bt devices:

        "discovered_devices_and_advertisement_data": [
          {
            "name": "KS03~b12100",
            "address": "13:06:AB:00:21:B1",
            "rssi": -43,
            "advertisement_data": [
              "KS03~b12100",
              {
                "496": {
                  "__type": "<class 'bytes'>",
                  "repr": "b'\\x02\\x03\\x04\\x05\\x06\\x00'"
                }
              },
              {},
              [
                "00001812-0000-1000-8000-00805f9b34fb"
              ],
              -127,
              -43,
              []
            ],
            "details": {
              "source": "5C:02:3A:68:1E:04",
              "address_type": 0
            }
          },

but when I add ledble integration it says “No device Found”.

Can you ( or someone ) point me to a working direction ?
Thanks

This is not for the ledble integration, it is for ledstrips that are not supported (and they are compatible with what I wrote)

You can try coping the code I wrote above and see if you can connect.

Important! If you are connected to the led strip with your phone, you need to turn off Bluetooth on your phone so the led is also disconnected.

Thanks for the reply.
Yes, I’ve understood they are not the same but I will give a try.
My question is: where should I put this configs ?
In the config dir for home assistant ( I’ve always added stuffs to configuration.yaml so I’m not used to ) ?

In your ESPHome device config.yml

hi @distante would you please walk through how you figured out the BLE message payload? was it captured by getting some bluetooth message dump from the app->device mesasge?

I posted it on the github issue as far as I remember.