Is it possible to group RGB light outputs?

I am mapping a Light RGB platform into an LED BLE device (no supported by the existing integration)

The problem I have is that I get each R,G,B update in different “outputs” so each color update gets 3 times bigger and they just do not come through.

Is there a way to group the RBG light updates into one array of those values?

this is my existing config:

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

###############################
########## BLUETOOTH #########
#############################
# bluetooth_proxy:
#   active: true

      
# esp32_ble_tracker:
#   scan_parameters:
#     # We currently use the defaults to ensure Bluetooth
#     # can co-exist with WiFi In the future we may be able to
#     # enable the built-in coexistence logic in ESP-IDF
#     active: false

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


ble_client:
  - mac_address: ${bluetooth_virtual_light_mac}
    id: my_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

    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
    name: BLE LED
    red: red_channel_output
    green: green_channel_output
    blue: blue_channel_output
    default_transition_length: 0s
    on_turn_on:
      - lambda: |-
          id(led_ble_on_off_switch).turn_on();
    on_turn_off:
      - lambda: |-
          id(led_ble_on_off_switch).turn_off();

globals:
  - id: red_value
    type: float
    initial_value: "0.00"
    # restore_value: true
  - id: green_value
    type: float
    initial_value: "0.00"
    # restore_value: true
  - id: blue_value
    type: float
    initial_value: "0.00"
    # restore_value: true

output: 
  - platform: template
    id: red_channel_output
    type: float
    write_action:
      - lambda: |-
            char buf[30];
            id(red_value) = state;
            sprintf(buf, "red_channel_output=%.2f", id(red_value));
            ESP_LOGI("virtual_ble_light", buf);
      - ble_client.ble_write:
          id: my_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return bvl_createColorUpdateArray(id(red_value), id(green_value),  id(blue_value));
  - platform: template
    id: green_channel_output
    type: float
    write_action:
      - lambda: |-
            char buf[30];
            id(green_value) = state;
            sprintf(buf, "green_channel_output=%.2f", id(green_value));
            ESP_LOGI("virtual_ble_light", buf);
      - ble_client.ble_write:
          id: my_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return bvl_createColorUpdateArray(id(red_value), id(green_value),  id(blue_value));
  - platform: template
    id: blue_channel_output
    type: float
    write_action:
      - lambda: |-
            char buf[30];
            id(blue_value) = state;
            sprintf(buf, "blue_channel_output=%.2f", id(blue_value));
            ESP_LOGI("virtual_ble_light", buf);
      - ble_client.ble_write:
          id: my_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return bvl_createColorUpdateArray(id(red_value), id(green_value),  id(blue_value));

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

  - platform: template
    id: led_ble_on_off_switch
    name: "Turn On Led"
    turn_on_action:
      - ble_client.ble_write:
          id: my_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: [ 126, 255, 4, 1, 255, 255, 255, 255, 239 ]
      - lambda: |-
            ESP_LOGI("virtual_ble_light", "SEND MESSAGE TO TURN ON");
    turn_off_action:
      - ble_client.ble_write:
          id: my_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: [ 126, 255, 4, 0, 255, 255, 255, 255, 239 ]
      - lambda: |-
            ESP_LOGI("virtual_ble_light", "SEND MESSAGE TO TURN OFF");

have a look at

Although it sounds promising, seems that it just groups my light there but does not offer any way to get an “rgb” value in one single update.

Unless I am doing something wrong, which is a big possibility.

My bad, I thought it was 3 seperate lights (because of group) , previous post can be ignored

Do you realy need 3 seperate outputs or actually one? as in “R”,“G”,“B” or “RGB” if the latter is the case a other platform might be usefull, although below should work if it make(s) any sense … my lambda skills are low.

if it is 3 then do a “on_state” (change), send update directly in 1 “string” via lambda meaning:
what you do now in the output component → (don’t need the write lambda)
move that to the light component. → on_state (here thew “write” lamda) just collect the values of the respective channels and send as a string.

it will at least reduce the amount of messages sent

hope this helps in some way

I also had the feeling I need another platform but I have not found any that sends me an RGB update.

The problem with the on_state is that it will skip transitions steps (from Light Component — ESPHome)

This trigger is activated each time the set light state is changed. It is not triggered based on current state, but rather, it triggers on the set state which can differ from the current state due to transitions. For example, the light.on_state trigger can be used for immediate action when the light is set to off; while light.on_turn_off does not trigger until the light actually achieves the off state.

I see that on the logs also, The state is send first, then R,G,B step changes are send until they reach the state.

What I am trying now is to manually group the emits into my own file.h but I can not figure out how to call ble_client.ble_write there.

In the end, It was easier than I thought.

I realized that each RGB update is triggered in the same order R → G → B.

Also, if some channel already achieved their final value (let’s say 1.0) it will be repeated until all the channels have their final value.

So I just stored each channel update into global variables and then send an Bluetooth write command after each B channel update. It works as expected

output: 
  - platform: template
    id: red_channel_output
    type: float
    write_action:
      - lambda: |-
            char buf[30];
            id(red_value) = state;
            sprintf(buf, "red_channel_output=%.2f", id(red_value));
            ESP_LOGI("virtual_ble_light", buf);
  - platform: template
    id: green_channel_output
    type: float
    write_action:
      - lambda: |-
            char buf[30];
            id(green_value) = state;
            sprintf(buf, "green_channel_output=%.2f", id(green_value));
            ESP_LOGI("virtual_ble_light", buf);
  - platform: template
    id: blue_channel_output
    type: float
    write_action:
      - lambda: |-
            char buf[30];
            id(blue_value) = state;
            sprintf(buf, "blue_channel_output=%.2f", id(blue_value));
            ESP_LOGI("virtual_ble_light", buf);
      - ble_client.ble_write:
          id: my_ble_client
          service_uuid: FFE0
          characteristic_uuid: FFE1
          value: !lambda |- 
            return SSDBluetoothVirtualLight::createColorUpdateArray(id(red_value), id(green_value),  id(blue_value));