Light not exposing dimming function to Home Assistant

I tried tidying up the names of the devices in Home Assistant last week, and lost the ability to control the brightness of the device, and it now only registers as a On/Off light.

I’ve been scratching my head for the last few days, and not sure where I’m going wrong, would anyone be so kind as to point me in the right direction. For anyone interested this code is to control a Light fixture with 6 bulbs (and dimming by changing the number of On/Off bulbs)

# Basic Config
---
substitutions:
#   # https://esphome.io/guides/configuration-types.html#substitutions
  device_name: dining-room-light   # hostname & entity_id
  friendly_name: Table Light    # Displayed in HA frontend
  ip_address: 10.10.1.62   # use /config/esphome/secrets.yaml
  
globals:
 - id: lastSwitchTime
   type: unsigned long
   restore_value: no
   initial_value: millis()
 - id: dimmer_lvl
   # https://esphome.io/guides/automations.html#bonus-2-global-variables
   type: float
   restore_value: no
   initial_value: '1.0'

esphome:
  # https://esphome.io/components/esphome
  name: ${device_name}
  platform: ESP8266
  board: esp12e
  esp8266_restore_from_flash: true
  includes:
    - relay_dimmer.h
  on_shutdown:
    then:
      - light.turn_off: dimmer

wifi:
  # https://esphome.io/components/wifi
  ssid: !secret wifissid
  password: !secret wifipass
  manual_ip:
    static_ip: ${ip_address}
    gateway: !secret wifigateway
    subnet: !secret wifisubnet
    dns1: !secret wifidns
  ap:
    ssid: ${friendly_name}_AP
    password: !secret wifipass
    channel: 1
    manual_ip:
      static_ip: 192.168.1.1
      gateway: 192.168.1.1
      subnet: 255.255.255.0


web_server:
  port: 80
  # https://esphome.io/components/web_server.html


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


api:
  password: !secret esphome_api_password
  reboot_timeout: 24h
  # https://esphome.io/components/api


ota:
  password: !secret esphome_ota_password
  # https://esphome.io/components/ota

#sensor:
  #- platform: wifi_signal
    #name: $friendly_name Wifi Signal
    #update_interval: 60s
  #- platform: uptime
    #name: $friendly_name uptime
  
light:
  - platform: monochromatic
    output: relay_dimmer
    name: $friendly_name
    gamma_correct: 1
    default_transition_length: 0s
    id: dimmer
  

output:
  - platform: custom
    type: float
    lambda: |-
      auto relay_dimmer_output = new MyCustomFloatOutput();
      App.register_component(relay_dimmer_output);
      return {relay_dimmer_output};
    outputs:
      id: relay_dimmer

binary_sensor:
  - platform: gpio
    pin: 
      number: 5
      mode: INPUT_PULLUP
    id: spst_switch
    internal: true
    #filters:
      #- delayed_off: 100ms
      #- delayed_on_off: 100ms
    on_press:
      then:
        - logger.log: "1"
    on_release:
      then:
        - logger.log: "0"
    on_multi_click:
    - timing:
        - ON for at most 600ms
      then:
        - script.execute: toggle_script
    - timing:
        - OFF for at most 600ms
      then:
        - script.execute: toggle_script
    - timing:
        - OFF for at least 600ms
      then:
        - script.execute: switch_script
    - timing:
        - ON for at least 600ms
      then:
        - script.execute: switch_script
        

script:
  - id: toggle_script
    then:
      - lambda: 'id(lastSwitchTime) = millis();'
      - if:
          condition:
            lambda: 'return id(dimmer)->remote_values.get_brightness() > 0.84;'
          then:
            - light.turn_on:
                id: dimmer
                brightness: 0.16
          else:
            - light.dim_relative:
                id: dimmer
                relative_brightness: 0.16
      - logger.log: "Toggle"
  - id: switch_script
    then:
      - if:
          condition:
            lambda: 'return (millis() - id(lastSwitchTime)) > 700;'
          then:
            - logger.log: "Switch"
            - light.toggle: dimmer

What version of esphome?

Sounds awfully like the bug I experienced last week :thinking:

1 Like

that’s what I thought.

1 Like

@Alextrical just fyi, we are talking about the esphome software version flashed in the device :wink:,
image
not ha core….

Hi @aceindy & @nickrout thank you. I’ve just checked the logs and can confirm that both my lights with this issue are running 2021.8.1.

I assumed that I was on the latest version like you, as there was no update notification. I will get them re flashed in the morning, but from what you have said I’m pretty sure the update will be the solution.
Sorry I didn’t catch your post, it seems my Google Fu is a bit off these last few years :wink:

Mods feel free to mark this as a duplicate.

It seems that I was indeed running 2021.8.1, and I hadn’t noticed that there was an update in the Supervisor. Thank you all for helping :relaxed:

Exactly the same happened to me…also took me a few days to figure it out :yum:

Hey guys, how are you? I’ve been reading posts all day and trying several things (recompiling, flashing new devices, updating versions, etc…) but still having this same issue. :disappointed:

Versions I’m using

  • Home Assistant 2021.9.0.dev20210813
  • ESPHome version 2021.12.1

Please find here a really simple setup I just did for 2 monochromatic lights using NodeMCU device.

esphome:
  name: test-device

esp8266:
  board: nodemcuv2

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: "72571b9d0736658d370b13518165285a"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Test-Device Fallback Hotspot"
    password: "OAd3vFmuHn6B"

captive_portal:

web_server:
  port: 80

# Example configuration entry
output:
  - platform: esp8266_pwm
    pin: D2
    id: pwm_output2
    
  - platform: esp8266_pwm
    pin: D1
    id: pwm_output1

# Example usage in a light
light:
  - platform: monochromatic
    output: pwm_output1
    name: "Test Mono Light 1"
    
  - platform: monochromatic
    output: pwm_output2
    name: "Test Mono Light 2"

But integrations config doesn’t show brightness support.

What am I doing wrong?

Thanks for your help

Hmm… I don’t think it is that easy,
You need some variable to store the actual dimming value, which is controlling the pwm_output.
You need the pwm frequency (and transition lenght ?)

The essence is below in the variable dummy_pwm1, which is the actual state and links the pwm_output to the light , but you got that part :wink:

output:
  - platform: esp8266_pwm
    pin: D1
    frequency: 800 Hz
    id: dummy_pwm1

light:
  - platform: monochromatic
    default_transition_length: 20ms
    name: "Light 1"
    output: dummy_pwm1
    id: light_main_1

And then you need some sensors that will report the actual dimming state of light_main_1 back to HA.

  - platform: template
    name: "${switch_id} Brightness Sensor CH1"
    id: sensor_g_bright_1
    internal: true
    update_interval: 20ms
    # Ensure on_value only triggered when brightness (0-255) changes
    filters:
      delta: 0.8
    # Read brightness (0 - 1) from light , convert to (0-255) for MCU
    lambda: |-
      if (id(light_main_1).remote_values.is_on()) {
        return (int(id(light_main_1).remote_values.get_brightness() * 255));
      }
      else {
        return 0;
      }
    # On Change send to MCU via UART
    on_value:
      then:
        - uart.write: !lambda |-
            return {0xFF, 0x55, 0x01, (char) id(sensor_g_bright_1).state, 0x00, 0x00, 0x00, 0x0A};
        - logger.log:
            level: INFO
            format: "CH1 Sensor Value Change sent to UART %3.1f"
            args: ["id(sensor_g_bright_1).state"]

I can give you my config for a 2ch dimmer (re-flashed tuya moeshouse), but that one also has 2 push buttons, allowing manual dimming:

esphome:
  name: qs-wifi-ds02-ip62
  platform: ESP8266
  board: esp01_1m

wifi:
  ssid: !secret wifi_ssid1
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "qs-wifi-ds02-ip62 Fallback"
    password: <redacted>

captive_portal:

# Enable Home Assistant API
api:
  password: !secret api_password

ota:

# Example configuration entry
web_server:
  port: 80

# Make sure logging is not using the serial port
logger:
  baud_rate: 0
  logs:
    sensor: ERROR
    duty_cycle: ERROR
    binary_sensor: ERROR
    light: ERROR

# level: VERBOSE
time:
  - platform: homeassistant

substitutions:
  switch_id: "dim_2ch_01"

# globals:
# Dummy light brightness tracker Global

globals:
  # Dim direction for Switch 1: 0=Up (brighten) 1=down (dim)
  - id: g_direction_1
    type: int
    restore_value: no
    initial_value: "1"
  # Counter for time pressed for switch 1
  - id: g_counter_1
    type: int
    restore_value: no
    initial_value: "0"
  # initial brightness
  # Dim direction for Switch 2: 0=Up (brighten) 1=down (dim)
  - id: g_direction_2
    type: int
    restore_value: no
    initial_value: "1"
  # Counter for time pressed for switch 2
  - id: g_counter_2
    type: int
    restore_value: no
    initial_value: "0"
  # initial brightness
  
# Uart definition to talk to MCU dimmer
uart:
  tx_pin: GPIO1
  rx_pin: GPIO3
  stop_bits: 1
  baud_rate: 9600

sensor:
  - platform: wifi_signal
    name: "${switch_id} WiFi Signal Sensor"
    update_interval: 60s
  - platform: uptime
    name: "Uptime"
  # Primary template sensor to track Brightness of light object for "on_value" sending to MCU dimmer
  # CH1
  - platform: template
    name: "${switch_id} Brightness Sensor CH1"
    id: sensor_g_bright_1
    internal: true
    update_interval: 20ms
    # Ensure on_value only triggered when brightness (0-255) changes
    filters:
      delta: 0.8
    # Read brightness (0 - 1) from light , convert to (0-255) for MCU
    lambda: |-
      if (id(light_main_1).remote_values.is_on()) {
        return (int(id(light_main_1).remote_values.get_brightness() * 255));
      }
      else {
        return 0;
      }
    # On Change send to MCU via UART
    on_value:
      then:
        - uart.write: !lambda |-
            return {0xFF, 0x55, 0x01, (char) id(sensor_g_bright_1).state, 0x00, 0x00, 0x00, 0x0A};
        - logger.log:
            level: INFO
            format: "CH1 Sensor Value Change sent to UART %3.1f"
            args: ["id(sensor_g_bright_1).state"]
  # Sensor to detect button push (via duty_cycle of 50hz mains signal)
  - platform: template
    name: "${switch_id} Brightness Sensor CH2"
    id: sensor_g_bright_2
    internal: true
    update_interval: 20ms
    # Ensure on_value only triggered when brightness (0-255) changes
    filters:
      delta: 0.8
    # Read brightness (0 - 1) from light , convert to (0-255) for MCU
    lambda: |-
      if (id(light_main_2).remote_values.is_on()) {
        return (int(id(light_main_2).remote_values.get_brightness() * 255));
      }
      else {
        return 0;
      }
    # On Change send to MCU via UART
    on_value:
      then:
        - uart.write: !lambda |-
            return {0xFF, 0x55, 0x02, 0x00, (char) id(sensor_g_bright_2).state, 0x00, 0x00, 0x0A};
        - logger.log:
            level: INFO
            format: "CH2 Sensor Value Change sent to UART %3.1f"
            args: ["id(sensor_g_bright_2).state"]
  # Sensor to detect button push (via duty_cycle of 50hz mains signal)
  - platform: duty_cycle
    pin: GPIO13
    internal: true
    id: sensor_push_switch_1
    name: "${switch_id} Sensor Push Switch 1"
    update_interval: 20ms
  - platform: duty_cycle
    pin: GPIO5
    internal: true
    id: sensor_push_switch_2
    name: "${switch_id} Sensor Push Switch 2"
    update_interval: 20ms

binary_sensor:
  #Binary sensor (on/off) which reads duty_cyle sensor readings. CH1
  - platform: template
    id: switch1
    internal: true
    name: "${switch_id} Switch Binary Sensor 1"
    # read duty_cycle, convert to on/off
    lambda: |-
      if (id(sensor_push_switch_1).state < 95.0) {
        return true;
      } else {
        return false;
      }
    # Short Click - toggle light only
    on_click:
      max_length: 300ms
      then:
        light.toggle: light_main_1
    # Generic On_Press - log press, toggle DIM Direction and reset press interval counter
    on_press:
      then:
        - logger.log: "Switch 1 Press"
        - lambda: |-
            if (id(g_direction_1) == 0) {
              id(g_direction_1) = 1;
            } else {
              id(g_direction_1) = 0;
            }
            id(g_counter_1) = 0;
  #Binary sensor (on/off) which reads duty_cyle sensor readings. CH2
  - platform: template
    id: switch2
    internal: true
    name: "${switch_id} Switch Binary Sensor 2"
    # read duty_cycle, convert to on/off
    lambda: |-
      if (id(sensor_push_switch_2).state < 95.0) {
        return true;
      } else {
        return false;
      }
    # Short Click - toggle light only
    on_click:
      max_length: 300ms
      then:
        light.toggle: light_main_2
    # Generic On_Press - log press, toggle DIM Direction and reset press interval counter
    on_press:
      then:
        - logger.log: "Switch 2 Press"
        - lambda: |-
            if (id(g_direction_2) == 0) {
              id(g_direction_2) = 1;
            } else {
              id(g_direction_2) = 0;
            }
            id(g_counter_2) = 0;

# Dummy light output to allow creation of light object
output:
  - platform: esp8266_pwm
    pin: GPIO14
    frequency: 800 Hz
    id: dummy_pwm1
  - platform: esp8266_pwm
    pin: GPIO16
    frequency: 800 Hz
    id: dummy_pwm2

# Primary Light object exposed to HA
light:
  - platform: monochromatic
    default_transition_length: 20ms
    restore_mode: RESTORE_DEFAULT_OFF
    name: "${switch_id} Light 1"
    output: dummy_pwm1
    id: light_main_1
  - platform: monochromatic
    default_transition_length: 20ms
    restore_mode: RESTORE_DEFAULT_OFF
    name: "${switch_id} Light 2"
    output: dummy_pwm2
    id: light_main_2

switch:
  - platform: restart
    name: "${switch_id} Restart"

# Polling object for long press handling of switch for dim/brighten cycle
interval:
  - interval: 20ms
    then:
      - if:
          condition:
            binary_sensor.is_on: switch1
          then:
            # Ramp rate for dim is product of interval (20ms) * number of intervals
            # Every 20ms Dimmer is increased/decreased by 2/255
            # Lower limit = 10%
            # Upper limit = 100%
            # 100% - 10% = 90% = 230/255. Therefore 230/2 * 20ms = 2.3 seconds for full range
            # At full/min brightness - further 16x20ms = 0.32 Seconds "dwell" by resetting counter to 0
            # Initial pause for 16x20ms = 0.32s to allow "on_click" to be discounted 1st
            # g_direction_1 = 0 (Increasing brightness)
            # g_direction_1 = 1 (decreasing brightness)
            # g_counter_1 = Interval pulse counter

            lambda: |-
              float curr_bright = id(light_main_1).remote_values.get_brightness();
              id(g_counter_1) += 1; 

              // If max bright, change direction
              if (curr_bright >= 0.999 && id(g_direction_1) == 0) {
                id(g_direction_1) = 1;
                id(g_counter_1) = 0;
              }

              // If below min_bright, change direction
              if (curr_bright < 0.1 && id(g_direction_1) == 1) {
                id(g_direction_1) = 0;
                id(g_counter_1) = 0;
              }

              if (id(g_direction_1) == 0 && id(g_counter_1) > 15) {
                // Increase Bright
                auto call = id(light_main_1).turn_on();
                call.set_brightness(curr_bright + (2.0/255.0));
                call.perform();
              }

              else if(id(g_direction_1) == 1 && id(g_counter_1) > 15) {
                // Decrease Bright
                auto call = id(light_main_1).turn_on();
                call.set_brightness(curr_bright - (2.0/255.0));
                call.perform();
              }
      - if:
          condition:
            binary_sensor.is_on: switch2
          then:
            # Ramp rate for dim is product of interval (20ms) * number of intervals
            # Every 20ms Dimmer is increased/decreased by 2/255
            # Lower limit = 10%
            # Upper limit = 100%
            # 100% - 10% = 90% = 230/255. Therefore 230/2 * 20ms = 2.3 seconds for full range
            # At full/min brightness - further 16x20ms = 0.32 Seconds "dwell" by resetting counter to 0
            # Initial pause for 16x20ms = 0.32s to allow "on_click" to be discounted 1st
            # g_direction_1 = 0 (Increasing brightness)
            # g_direction_1 = 1 (decreasing brightness)
            # g_counter_1 = Interval pulse counter

            lambda: |-
              float curr_bright = id(light_main_2).remote_values.get_brightness();
              id(g_counter_2) += 1; 

              // If max bright, change direction
              if (curr_bright >= 0.999 && id(g_direction_2) == 0) {
                id(g_direction_2) = 1;
                id(g_counter_2) = 0;
              }

              // If below min_bright, change direction
              if (curr_bright < 0.1 && id(g_direction_2) == 1) {
                id(g_direction_2) = 0;
                id(g_counter_2) = 0;
              }

              if (id(g_direction_2) == 0 && id(g_counter_2) > 15) {
                // Increase Bright
                auto call = id(light_main_2).turn_on();
                call.set_brightness(curr_bright + (2.0/255.0));
                call.perform();
              }

              else if(id(g_direction_2) == 1 && id(g_counter_2) > 15) {
                // Decrease Bright
                auto call = id(light_main_2).turn_on();
                call.set_brightness(curr_bright - (2.0/255.0));
                call.perform();
              }        

Thanks for your answer, you give me an idea for a different project. However, the issue I’m facing is that the Monochromatic light Component should be handling by itself the Brightness feature as explained in documentation.
I’ve been using the same configuration quite a bit for 3 different devices and all worked fine until version 2021.8.1. The initial post solution was to update to 2021.8.2 but is not working for me.

As you can see in your Home Assistant instance, living_ceiling Attributes contains the following

  • supported_color_modes: brightness
  • color_mode: brightness
  • brightness: xxx
  • supported_features: 40

Those attributes should be exposed by the device API and created in HomeAssistant as soon as the device is integrated into it. In my case, I have an empty array in supported_color_modes and supported_features set to 8 instead of 40.

I just tested the device using ESPHome API and Brightness is working fine
GET - http://<device-name>.local/light/<id>
POST - http://<device-name>.local/light/<id>/turn_on?brightness=128&transition=3

Not sure why it stopped working in Home Assistant.

Nonsense. Read the docs.

Ah…yes…I see…it was me who was over complicating @setchevest’s issue…sorry abt that.
I figured he used something similar as my dual dimmer, but he wasn’t :stuck_out_tongue:

1 Like