ESPHome with display. Linking a button to home Assistant light

Hi

I’ve got myself a couple of Guition 4848S040 displays and fairly quickly got OpenHasp working on one with screen buttons able to control lights and cover in HA.

I then tried to do the same with Tasmota and although I got stuff on the display, got nowhere trying to link to HA!

I’m now trying with ESPHome. I’ve loaded the example code given for the Guition display found here.

I don’t know a lot about ESPHome and am having trouble finding an example of linking a simple on/off light (light.light_switch_lounge_main) already in HA to the button in the sample code (lv_button_1).

I tried, as a starter, the following entry:

binary_sensor:
  - platform: homeassistant
    name: "Lounge_Main_Light"
    entity_id: light.light_switch_lounge_main
    on_state:
      then:
        if:
          condition:
            lambda: 'return Lounge_Main_Light.state = "on";'
          then:
            - lvgl.widget.update:
                id: lv_button_1_icon
                text_color: 0xFFFF00
            - lvgl.widget.update:
                id: lv_button_1
                state:
                  checked: true
          else:
            - lvgl.widget.update:
                id: lv_button_1_icon
                text_color: 0xB6B6B6
            - lvgl.widget.update:
                id: lv_button_1
                state:
                  checked: false

but whilst it validates ok, it fails to compile with the error:

/config/esphome/display-4848s040.yaml: In lambda function:
/config/esphome/display-4848s040.yaml:141:14: error: 'Lounge_Main_Light' was not declared in this scope
  141 |             lambda: 'return Lounge_Main_Light.state = "on";'
      |              ^~~~~~~~~~~~~~~~~

Maybe I’m trying to use it before it’s fully defined!

Any help appreciated.

I persevered and got it working (almost perfectly!)

This snippet creates the binary sensor in ESPHome from the actual light in HA and updates the button and its lightbulb icon colours.

binary_sensor:
  - platform: homeassistant
    name: "Lounge Main Light"
    id: lounge_main_light
    entity_id: light.light_switch_lounge_main
    on_state:
      then:
        if:
          condition:
            binary_sensor.is_on: lounge_main_light
          then:
            - lvgl.widget.update:
                id: lv_button_1_icon
                text_color: 0xFFFF00
            - lvgl.widget.update:
                id: lv_button_1
                state:
                  checked: true
          else:
            - lvgl.widget.update:
                id: lv_button_1_icon
                text_color: 0xB6B6B6
            - lvgl.widget.update:
                id: lv_button_1
                state:
                  checked: false

This snippet creates the button and triggers a toggle for the internal_light.

lvgl:
  ...
  pages:
    ...
      widgets:
        - button:
            height: 223
            checkable: true
            id: lv_button_1
            widgets:
              - label:
                  text_font: light40
                  align: top_left
                  text: $lightbulb
                  id: lv_button_1_icon
              - label:
                  align: bottom_left
                  text: "Center Light"
                  long_mode: dot
            on_click:
              light.toggle: internal_light

And lastly, this snippet creates the internal_light and sets up the actions when the screen button is pressed. Apparently, I should be using action terminology as services have been renamed as such in HA, but I just copied a real life example I found in the forum rather than those cryptic examples given in the docs!

light:
  - platform: binary
    output: internal_relay_1
    name: Internal Light
    id: internal_light
    on_turn_on:
      then:
        homeassistant.service:
          service: light.turn_on
          data:
            entity_id: light.light_switch_lounge_main

    on_turn_off:
      then:
        homeassistant.service:
          service: light.turn_off
          data:
            entity_id: light.light_switch_lounge_main

I say it ‘almost works’ because it reacts properly when the light is turned on/ff in HA and when turned on/off with the button in ESPHome. Except when turned on in HA and the off from ESPHome. In that case the button shows it as having gone off but the light stays on. A second press briefly brings the button light back on but the actual light does go off followed by the button light. Does that make sense?

Any clues anyone?

For some reason, the example of doing this state change from the ESPHome LVGL cookbook uses a text sensor:

text_sensor:
  - platform: homeassistant
    id: ts_remote_light
    entity_id: light.remote_light
    on_value:
      then:
        - lvgl.widget.update:
            id: btn_lightbulb
            state:
              checked: !lambda return (0 == x.compare(std::string{"on"}));
              disabled: !lambda return ((0 == x.compare(std::string{"unavailable"})) or (0 == x.compare(std::string{"unknown"})));
        - lvgl.label.update:
            id: lbl_lightbulb
            text: !lambda |-
              static char buf[10];
              std::string icon;
              if (0 == x.compare(std::string{"on"})) {
                  icon = "\U000F0335";
              } else {
                  icon = "\U000F0336";
              }
              snprintf(buf, sizeof(buf), "%s", icon.c_str());
              return buf;

This is what I copied for my display and it works fine. The use of lambda for state checking is not something I would normally do either, but it works.

Thanks, I’ll give it a go to see if it works 100%.

  on_value:
    - lvgl.widget.update:
        id: btn_lightbulb
        state:
          checked: !lambda return x == "on";
          disabled: !lambda return x == "unavailable" || x == "unknown";

    - lvgl.label.update:
        id: lbl_lightbulb
        text:
          format: "%s"
          args: ['x == "on" ? "\U000F0335" : "\U000F0336"']

Hello, I can’t get this example to work. I’m not a programmer. I would be grateful for any help. The output component is reporting an error.

INFO ESPHome 2025.12.0-dev
INFO Reading configuration /config/esphome/zentraleinheit01.yaml...
INFO Detected timezone 'Europe/Vienna'
Failed config

light.binary: [source /config/esphome/zentraleinheit01.yaml:458]
  
  'output' is a required option for [light.binary].
  platform: binary
  name: remote_light01
  id: remote_light01
  on_turn_on: 
    then: 
      homeassistant.action: 
        service: light.turn_on
        data: 
          entity_id: light.tischzentrale01
  on_turn_off: 
    then: 
      homeassistant.action: 

Here is my current configuration.

binary_sensor:
#########
#text_sensor:?
######### für licht remote button
  - platform: homeassistant
    id: tischzentrale01
#    widget: light_btn01
    entity_id: light.tischzentrale01
#    trigger_on_initial_state: true
#    publish_initial_state: true # wird entfernt
###########
  - platform: homeassistant
    name: "tischzentrale01"
    id: tischzentrale01_button01
    entity_id: light.tischzentrale01
    on_state:
      then:
        if:
          condition:
            binary_sensor.is_on: tischzentrale01_button01
          then:
            - lvgl.widget.update:
                id: lvgl_button01_icon
                text_color: 0xFFFF00
            - lvgl.widget.update:
                id: lvgl_button01
                state:
                  checked: true
          else:
            - lvgl.widget.update:
                id: lvgl_button01_icon
                text_color: 0xB6B6B6
            - lvgl.widget.update:
                id: lvgl_button01
                state:
                  checked: false

output:
  - platform: ledc
    pin: GPIO22
    id: backlight_pwm
    frequency: 1000Hz
########## für licht ??????
#  - platform: template
#    id: remote_relay01
#    type: float
#    write_action:
#      if:
#        condition:
#          light.is_on: remote_light01
#        then:
#          - light.turn_on: tischzentrale01_button01
#        else:
#          - light.turn_off: tischzentrale01_button01
light:
########## für licht neu
  - platform: binary
    output: remote_relay01
    name: "remote_light01"
    id: remote_light01
    on_turn_on:
      then:
        homeassistant.action:
          service: light.turn_on
          data:
            entity_id: light.tischzentrale01
    on_turn_off:
      then:
        homeassistant.action:
          service: light.turn_off
          data:
            entity_id: light.tischzentrale01

lvgl: #...sniped

        - button:
            height: 223
            checkable: true
            id: lvgl_button01
            widgets:
              - label:
                  #text_font: light40
                  align: top_left
                  text: $lightbulb
                  id: lvgl_button01_icon
              - label:
                  align: bottom_left
                  text: "Center Light"
                  long_mode: dot
            on_click:
              light.toggle: remote_light01