KaufHA/kauf-rgbww-bulbs

Color temperature incorrect with low main brightness and warm_rgb on

Opened this issue · 9 comments

Summary

When setting the brightness of the main bulb to low values (<20%) with warm_rgb turned on, the actual color is incorrect, and sometimes even flickers (17% is especially bad). This wouldn't really be an issue except when using these bulbs with the flicker effect to simulate a candle, the drastic change in color temperature whenever the brightness drops too low is not good. And there's not a great way to get the correct color without using the warm_rbg.

More details:

  • color temperature on main bulb set to 350mireds
  • warm_rbg bulb turned on and set to reddish orange (white: 40%, red: 100%, green: 73%, blue: 0%)
  • Version 1.845 of kauf_bulb.yaml (with a few custom additions). Full yaml copied below
  • Added the effect->apply() code to light_state.cpp so effects will work.
  • I'm pretty sure this color issue also happens without any of this custom code, but I haven't had a chance to try lately.
  • I started digging into the color math that happens, but that was looking like a deeper dive than I had the time for.

Full yaml:

# esphome upload desk.yaml --device <orignal ip address>

# https://esphome.io/guides/configuration-types.html#substitutions
substitutions:

  # substitutions can be changed here if you are using this file directly in the ESPHome dashboard.  The better approach is
  # to incorporate this file as a package using the following lines, and then overwrite these substitutions in your local
  # yaml file by redefining them.
  #
  # packages:
  #   kauf.rgbww: github://KaufHA/kauf-rgbww-bulbs/kauf-bulb.yaml
  #

  name: kauf-bulb              # **** CHANGE DEVICE NAME TO SOMETHING UNIQUE PER DEVICE.  RENAME YAML FILE TO SAME NAME.    ****
                               # **** USE DASHES (-) INSTEAD OF SPACES OR UNDERSCORE (_).  USE ONLY LOWER CASE LETTERS.     ****

  friendly_name: Kauf Bulb     # **** CHANGE FRIENDLY NAME TO SOMETHING UNIQUE PER DEVICE ****

  disable_entities: "true"     # set to "false" to have all entities show up in Home Assistant automatically

  # https://esphome.io/components/light/index.html#base-light-configuration
  light_restore_mode: RESTORE_DEFAULT_OFF   # change power-on action for main light entity - NAT CHANGED
  default_power_on_state: "Restore Power Off State"

  wifi_ap_timeout: 2min    # default to 2 minute timeout for yaml file as package.

  # https://esphome.io/components/esphome.html#esphome-creators-project
  project_name: Kauf.RGBWW
  project_ver_num: "1.845"
  project_ver_let: y

  sub_on_turn_on:  script_do_nothing
  sub_on_turn_off: script_do_nothing


# https://esphome.io/components/esp8266.html
esp8266:
  board: esp01_1m
  restore_from_flash: true
  start_free: 76
  global_addr: global_forced_addr


# https://esphome.io/components/external_components.html
external_components:
  - source:
      type: git
      url: https://github.com/KaufHA/common
    refresh: 0s
  - source:
      type: git
      url: https://github.com/KaufHA/kauf-rgbww-bulbs
    refresh: 0s
  - source:
      type: local
      path: copied_components


# https://esphome.io/guides/automations.html#global-variables
globals:
  - id: global_forced_addr
    type: int
    restore_value: no
    initial_value: '12345'


# https://esphome.io/components/esphome.html
esphome:

  name: $name
  name_add_mac_suffix: true

  project:
    name: $project_name
    version: $project_ver_num($project_ver_let)

  on_boot:
    priority: 799.5 # after numbers/selects/switches being setup (800) and before lights being setup (799).
    then: # restore settings
      - script.execute: script_set_boot_mode
      - script.execute: script_set_wled


# https://esphome.io/components/button/index.html
# https://esphome.io/components/button/restart.html
button:
  - platform: restart
    id: restart_button
    name: $friendly_name Restart Firmware
    entity_category: diagnostic
    disabled_by_default: $disable_entities


# https://esphome.io/components/wifi.html
wifi:

  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Uncomment below to set a static IP
  manual_ip:
    static_ip: !secret ip_address
    gateway: !secret gateway
    subnet: !secret subnet

  # default is 20, 17 is recommended.
  output_power: 17

  # using fast_connect as default since it is required for hidden networks.
  fast_connect: true

  forced_addr: 0
  global_addr: global_forced_addr

  ap:
    ap_timeout: $wifi_ap_timeout


# https://esphome.io/components/captive_portal.html
captive_portal:


# https://esphome.io/components/logger.html
logger:


# https://esphome.io/components/api.html
api:
  id: kauf_api


# https://esphome.io/components/ota.html
ota:
  on_error:
    then:
      - button.press: restart_button


# https://esphome.io/components/web_server.html
web_server:
  local: true


# PWM outputs for each LED channel
# https://esphome.io/components/output/esp8266_pwm.html
output:
  - platform: esp8266_pwm
    pin: GPIO4
    frequency: 1000 Hz
    id: pwm_red
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO12
    frequency: 1000 Hz
    id: pwm_green
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO14
    frequency: 1000 Hz
    id: pwm_blue
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO5
    frequency: 1000 Hz
    id: pwm_cw
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO13
    frequency: 1000 Hz
    id: pwm_ww
    max_power: .85


# https://esphome.io/components/light/index.html
light:

  # Additive RGB light for Warm White
  - platform: kauf_rgbww
    id: warm_rgb
    entity_category: config
    default_transition_length: 0ms
    icon: mdi:store-cog
    aux: true
    name: $friendly_name Warm RGB
    forced_hash: 4077116474
    forced_addr: 28
    global_addr: global_forced_addr
    disabled_by_default: $disable_entities

# Additive RGB light for Cold White
  - platform: kauf_rgbww
    id: cold_rgb
    entity_category: config
    default_transition_length: 0ms
    icon: mdi:store-cog-outline
    aux: true
    name: $friendly_name Cold RGB
    forced_hash: 301094535
    forced_addr: 40
    global_addr: global_forced_addr
    disabled_by_default: $disable_entities

  # Main RGBWW light
  - platform: kauf_rgbww
    id: kauf_light
    default_transition_length: 250ms
    name: $friendly_name
    red: pwm_red
    green: pwm_green
    blue: pwm_blue
    warm_white: pwm_ww
    cold_white: pwm_cw
    warm_rgb: warm_rgb
    cold_rgb: cold_rgb
    forced_hash: 2723974766
    forced_addr: 52
    global_addr: global_forced_addr
    restore_mode: $light_restore_mode
    on_turn_on:
      - script.execute: $sub_on_turn_on
    on_turn_off:
      - script.execute: $sub_on_turn_off
      - switch.turn_off: kauf_light_candle
    effects:
      - flicker:
          name: Candle
          alpha: 95%
          intensity: 3%


# https://esphome.io/components/select/index.html
# https://esphome.io/components/select/template.html
select:

  - platform: template
    name: $friendly_name Effect
    id: effect
    optimistic: true
    options:
      - "None"
      - "WLED / DDP"
    initial_option: "None"
    restore_value: true
    icon: mdi:string-lights
    set_action:
      - delay: 1ms
      - script.execute: script_set_wled
      - script.execute: script_save_changes

    entity_category: config
    forced_hash: 5841966
    forced_addr: 66
    global_addr: global_forced_addr

  - platform: template
    name: $friendly_name DDP Debug
    id: select_ddp_debug
    optimistic: true
    options:
      - "Print no packets"
      - "Print imperfect packets"
      - "Print all packets"
    initial_option: "Print no packets"
    restore_value: false
    icon: mdi:play-network
    entity_category: diagnostic
    disabled_by_default: $disable_entities
    set_action:
      - lambda: |-
          if      ( x == "Print no packets" )        { id(kauf_light)->set_ddp_debug(0); }
          else if ( x == "Print imperfect packets" ) { id(kauf_light)->set_ddp_debug(1); }
          else if ( x == "Print all packets" )       { id(kauf_light)->set_ddp_debug(2); }

  # default light state on boot
  - platform: template
    name: $friendly_name Power On State
    id: select_boot_state
    optimistic: true
    options:
      - "Restore Power Off State"
      - "Always On - Last Value"
      - "Always On - Bright White"
      - "Always Off"
      - "YAML Configured ($light_restore_mode)"
    # defaulting to always on is nice so you know new bulbs are working
    initial_option: $default_power_on_state
    restore_value: true
    icon: mdi:restart-alert
    set_action:
      - delay: 1ms
      - script.execute: script_save_changes
      - script.execute: script_set_boot_mode
      - lambda: kauf_light->save_remote_values_();
    entity_category: config
    forced_hash: 3524332562
    forced_addr: 64
    global_addr: global_forced_addr


# https://esphome.io/components/number/index.html
# https://esphome.io/components/number/template.html
number:      # set max power output for PWMs
  - platform: template
    name: ${friendly_name} Max Power
    min_value: 1
    max_value: 100
    step: 1
    initial_value: 85
    id: number_max_power
    entity_category: config
    disabled_by_default: $disable_entities
    icon: mdi:brightness-percent
    optimistic: true
    restore_value: true
    unit_of_measurement: "%"
    mode: box
    forced_hash: 4189052763
    forced_addr: 74
    global_addr: global_forced_addr
    on_value:
      - lambda: |-
          float new_power = ((float)x)/100.0f;
          id(pwm_red).set_max_power(new_power);
          id(pwm_green).set_max_power(new_power);
          id(pwm_blue).set_max_power(new_power);
          id(pwm_ww).set_max_power(new_power);
          id(pwm_cw).set_max_power(new_power);
          id(kauf_light)->set_next_write();
      - script.execute: script_save_changes

  - platform: template
    name: ${friendly_name} Default Fade
    min_value: 0
    max_value: 5000
    step: 50
    initial_value: 250
    id: number_default_fade
    entity_category: config
    icon: mdi:timer-outline
    optimistic: true
    restore_value: true
    unit_of_measurement: "ms"
    mode: box
    forced_hash: 3133748577
    forced_addr: 72
    global_addr: global_forced_addr
    on_value:
      - lambda: 'id(kauf_light)->set_default_transition_length(x);'
      - script.execute: script_save_changes


# https://esphome.io/components/switch/index.html
# https://esphome.io/components/switch/template.html
switch:
  - platform: template
    icon: mdi:candle
    id: kauf_light_candle
    name: $friendly_name Candle
    optimistic: true
    restore_state: true
    disabled_by_default: $disable_entities
    global_addr: global_forced_addr
    on_turn_on:
      # We shouldn't be using this one so just leave it out for now
      # - light.turn_off:
      #     id: kauf_light
      - homeassistant.service:
          service: switch.turn_off
          data:
            entity_id: switch.circadian_lighting_dining_table_light
      - delay: 1ms
      # originally it was [255, 188, 0]
      # but that felt just a smidge too green so trying adjusting
      # [232, 170, 0]
      - light.turn_on:
          id: warm_rgb
          white: 40%
          red: 100%
          green: 73%
          blue: 0%
          transition_length: 0ms
      - delay: 1ms
      # Something about turning the light on first and then setting the effect
      # seems to be more reliable. It's also a nicer fade in
      - light.turn_on:
          id: kauf_light
          brightness: 35%
          color_temperature: 350mireds
          transition_length: 250ms
      - delay: 300ms
      - light.turn_on:
          id: kauf_light
          brightness: 35%
          color_temperature: 350mireds
          effect: Candle
          # Can't do transition length and candle
          # transition_length: 200ms

    on_turn_off:
      - light.turn_off:
          id: kauf_light
          transition_length: 250ms
      - delay: 300ms
      - light.control:
          id: warm_rgb
          white: 100%
          red: 100%
          green: 74%
          blue: 0%
      - delay: 100ms
      - homeassistant.service:
          service: switch.turn_on
          data:
            entity_id: switch.circadian_lighting_dining_table_light

  - platform: template
    id: switch_no_hass
    name: $friendly_name No HASS
    optimistic: true
    restore_state: true
    entity_category: config
    disabled_by_default: $disable_entities
    icon: mdi:toggle-switch-off-outline
    forced_hash: 706743398
    forced_addr: 70
    global_addr: global_forced_addr
    on_turn_on:
      - lambda: id(kauf_api)->set_reboot_timeout(0);
      - script.execute: script_save_changes
    on_turn_off:
      - lambda: id(kauf_api)->set_reboot_timeout(900000);
      - script.execute: script_save_changes


# https://esphome.io/components/sensor/uptime.html
sensor:
  - platform: uptime
    name: $friendly_name Uptime
    update_interval: 60s
    entity_category: diagnostic
    disabled_by_default: $disable_entities


# Send IP Address to HA.
# https://esphome.io/components/text_sensor/wifi_info.html
text_sensor:
  - platform: wifi_info
    ip_address:
      name: $friendly_name IP Address
      entity_category: diagnostic
      disabled_by_default: $disable_entities


# https://esphome.io/guides/automations.html#script-component
script:
  - id: script_save_changes
    mode: restart
    then:
      - delay: 3s
      - lambda: 'global_preferences->sync();'

  - id: script_set_wled
    then:
      - lambda: |-
          if ( id(effect).state == "WLED / DDP" ) { id(kauf_light)->set_use_wled(true); }
          else                                    { id(kauf_light)->set_use_wled(false); }

  - id: script_set_boot_mode
    then:
      lambda: |-
        if ( id(select_boot_state).state == "Restore Power Off State")
          kauf_light->set_restore_mode(LIGHT_RESTORE_DEFAULT_OFF);
        else if ( id(select_boot_state).state == "Always On - Last Value")
          kauf_light->set_restore_mode(LIGHT_RESTORE_AND_ON);
        else if ( id(select_boot_state).state == "Always On - Bright White")
          kauf_light->set_restore_mode(LIGHT_ALWAYS_ON);
        else if ( id(select_boot_state).state == "Always Off")
          kauf_light->set_restore_mode(LIGHT_RESTORE_AND_OFF);
        else
          kauf_light->set_restore_mode(LIGHT_$light_restore_mode);

  - id: script_do_nothing
    then:
      lambda: return;


# Current reserved flash memory:
# 00-25: Wi-Fi Credentials

# 28-39: Warm RGB
# 40-51: Cold RGB
# 52-63: Main Light
# 64-65: Power On State select
# 66-67: Effect select

# 70-71: No HASS switch
# 72-73: Default Fade Length
# 74-75: Max Power

Thanks adding so many details. I'll check it out this weekend.

Did the flicker effect work for you with the main light set to 350 mireds?

In addition to adding the effect->apply() code back in I had to add in a line to base_light_effect.h to copy the color temperature from remote to out (Line 222: out.set_color_temperature(remote.get_color_temperature());). Otherwise it would always flicker with the cold white LEDs and never warm white. Meaning, turning the Candle effect on would change the light's display from warm white to cold white even though it still showed warm white in Home Assistant.

BTW I'll add the effect->apply() code back in so you don't need your own custom components. Still looking at the flickering issue, I have a couple of ideas.

Try turning down the frequency on the PWM outputs. I think I'm doing too much on the ESP8266 to be able to also have 5 channels of software PWM running at 1000Hz, so it causes inaccuracies in timing. I used the following and it seemed to improve. I used 400Hz for the white channels and 200Hz for the colors. I'll probably play around with it more and find new values for the release firmware.

Lowering the PWM rate also increases resolution at low brightness so should help with accuracy that way as well.

# PWM outputs for each LED channel
# https://esphome.io/components/output/esp8266_pwm.html
output:
  - platform: esp8266_pwm
    pin: GPIO4
    frequency: 200 Hz
    id: pwm_red
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO12
    frequency: 200 Hz
    id: pwm_green
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO14
    frequency: 200 Hz
    id: pwm_blue
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO5
    frequency: 400 Hz
    id: pwm_cw
    max_power: .85
  - platform: esp8266_pwm
    pin: GPIO13
    frequency: 400 Hz
    id: pwm_ww
    max_power: .85

Finally got a chance to come back to this. I copied over the latest version (1.863) from kauf_bulb.yaml and this seems to have fixed it! Thanks for adding back the effects piece too!

Ah spoke too soon. It's definitely better, but still flickers around 10% brightness and below.

Hmmm. Can you reply with complete exact settings of main light and cold/warm rgb lights? color and brightness. If you go to the states tab under developer tools it will show you the exact rgb values etc.

I'm having a similar issue with color temperatures: at their warmest settings, the bulbs are still relatively cool. Looking at the States tab, I see the bulbs have min_color_temp_kelvin: 2857, where for other of my bulbs, that's 2000 (allowing for much warmer light like I'm looking for).

Can I change that value to enable warmer light? If so, how?

EDIT: Reviewing the docs again, it sounds like what I actually want is to use the Kauf Bulb Warm RGB entity. I'll have to take a look tomorrow to figure out how to do that.

I'm having a similar issue with color temperatures: at their warmest settings, the bulbs are still relatively cool. Looking at the States tab, I see the bulbs have min_color_temp_kelvin: 2857, where for other of my bulbs, that's 2000 (allowing for much warmer light like I'm looking for).

Not necessarily related to the main issue, but the color temperature of the bulbs definitely shifts towards cool as the bulbs warm up from being on. Apparently this is common with LEDs, but I wonder if the color temperature of these bulbs is the steady state, or the initial on temp...

natp13 commented

Hmmm. Can you reply with complete exact settings of main light and cold/warm rgb lights? color and brightness. If you go to the states tab under developer tools it will show you the exact rgb values etc.

main_light:
min_mireds: 150
max_mireds: 350
effect_list: None, Candle
supported_color_modes: color_temp, rgb
friendly_name: Kauf Bulb
supported_features: 44
color_mode: color_temp
brightness: 26
color_temp: 350
hs_color: 28.077, 60.925
rgb_color: 255, 172, 99
xy_color: 0.51, 0.386
effect: None

cold rgb off

warm rgb
supported_color_modes: rgbw
icon: mdi:store-cog
friendly_name: Kauf Bulb Warm RGB
supported_features: 40
color_mode: rgbw
brightness: 255
hs_color: 44.409, 49.804
rgb_color: 255, 222, 128
rgbw_color: 255, 189, 0, 255
xy_color: 0.437, 0.421