Need help with programming :-( on seemingly simple esphome device (4 state light)

Hello everyone,

Could someone give me some assistance with the below code?

The “simulated button” I have created when clicked in home assistant cycles through the 4 states properly. The reset button works properly and the button press counter seems to be working properly when both using the simulated button and when setting the light state directly from a service call.

However, my issue is that the service calls never get the light to actually come on in any state. When looking at the logs and esphome, the esp is changing the counters so it is receiving information to make the state change. However, the light is never changing to the proper mode when using the service calls. (i.e., mode 1 Device OFF, mode 2 Device On, etc.)

Could I get someone to help me fix this based on the above info. Essentially I want to be able to used the “simulated button” to cycle through the states one at a time (which is working currently) but I would also like to be able to use direct state change method through the service call. (I am using the “perform action” are in developer tools for testing)

I think I need to somehow press the simulated button the proper number of times based on the change of the number from 1 to 4. (as I have assigned 1,2,3,4 to the various states.-- I thought that was what is programmed in the code provided but its not working for some reason.

Thank you all for helping me with this. I think it’s simple, I just don’t know what I’m doing.

Full transparency: ChatGPT got me to here or I wouldn’t have even been able to get this far. :frowning:

esphome:
  name: "supermariolight"
  friendly_name: supermariolight
  min_version: 2024.11.0
  name_add_mac_suffix: false

esp32:
  board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
    - service: set_light_state
      variables:
        state: string
      then:
        - lambda: |-
            // Map the desired state string to a target number
            int target_state;
            if (state == "Device OFF") {
              target_state = 1;
            } else if (state == "Device ON") {
              target_state = 2;
            } else if (state == "Device PULSING") {
              target_state = 3;
            } else if (state == "Device REACTS TO SOUND") {
              target_state = 4;
            } else {
              ESP_LOGE("main", "Invalid state received: %s", state.c_str());
              return;
            }

            // Calculate how many presses are needed to reach the target state
            int current_state = id(button_counter);
            int presses_needed = target_state - current_state;
            if (presses_needed < 0) {
              presses_needed += 4; // Wrap around to handle state cycling
            }

            // Simulate the required number of presses
            for (int i = 0; i < presses_needed; i++) {
              id(simulated_button).turn_on();
              delay(1000);  // Simulate the physical button press duration
              id(simulated_button).turn_off();
              delay(1000);  // Wait before the next press
            }

            // Update the counter to match the target state
            id(button_counter) = target_state;

            // Publish the new counter value to Home Assistant
            id(button_counter_sensor).publish_state(id(button_counter));

            ESP_LOGD("main", "Set light state to %s, counter updated to %d", state.c_str(), id(button_counter));

# Allow Over-The-Air updates
ota:
- platform: esphome

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

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

captive_portal:

# Global variable to track the state
globals:
  - id: button_counter
    type: int
    restore_value: yes
    initial_value: '1'

# Define the GPIO output to simulate button presses
output:
  - platform: gpio
    pin: GPIO5  # Use GPIO5 to simulate the button press
    id: simulated_button
    inverted: True  # Inverts the signal, making it low by default

# Template switch to simulate button presses
switch:
  - platform: template
    name: "Simulated Button"
    turn_on_action:
      - lambda: |-
          // Increment the counter
          id(button_counter) += 1;

          // Reset the counter after state 4
          if (id(button_counter) > 4) {
            id(button_counter) = 1;
          }

          // Log the current state
          ESP_LOGD("main", "Simulated button pressed, current state: %d", id(button_counter));

          // Simulate the button press
          id(simulated_button).turn_on();
          delay(1000);  // Simulate the physical button press duration
          id(simulated_button).turn_off();

          // Update the sensor value
          id(button_counter_sensor).publish_state(id(button_counter));

  # Virtual reset button
  - platform: template
    name: "Reset Button"
    turn_on_action:
      - lambda: |-
          // Reset the counter to 1
          id(button_counter) = 1;
          ESP_LOGD("main", "Counter reset to 1");

          // Publish the updated state
          id(button_counter_sensor).publish_state(id(button_counter));

# Expose the button counter as a sensor to Home Assistant
sensor:
  - platform: template
    name: "Button Press Counter"
    id: button_counter_sensor
    lambda: |-
      return id(button_counter);
    on_value:
      then:
        - homeassistant.service:
            service: input_select.select_option
            data:
              entity_id: input_select.super_mario_light_state
              option: !lambda |-
                if (x == 1) {
                  return "Device OFF";
                } else if (x == 2) {
                  return "Device ON";
                } else if (x == 3) {
                  return "Device PULSING";
                } else if (x == 4) {
                  return "Device REACTS TO SOUND";
                } else {
                  return "Device OFF";
                }

From what I have seen and heard, this is your problem.

You should probably start with a much clearer description of what you are trying to achieve and what your physical hardware looks like.

The thing about ChatGPT is that (unlike Alexa) it will tell you with certainty that it has given you exactly what you want, when it has no clue and it is just stringing words together that might look plausible.

I don’t see anything in your YAML that looks like a light and it is unclear why you want it pressing a button (unless you are trying to help the people on Lost with one of their tasks :wink:).

Haha. I follow you on the Lost response and I agree ChatGPT is always “I’m so sure of this”.

Essentially I am shorting a button in a paladone branded super Mario light. The light has 4 states. I have gpio 5 sending the signal.

I have a virtual button/ switch called “simulated button” that dumbly cycles through the 4 states. I also have a service call that is supposed to be able to help me go directly to a state even though the physical device only has one button. So to use the service call, I then have to use the simulated button to virtually press the physical button through shorting a calculated number of times- not just once.

Sorry, I thought the existing code would be enough to deduce that but I definitely see how it would just be easier for me to come out and say what I’m doing.

I have an updated code post that I will post later today with a more detailed response as to what the exact issue is currently.

The current issue is that the device is put into the proper state but the sensor “button press counter” doesn’t seem to be put into the proper tracking number based on the actual state of physical device.

So if I use the service call “Device REACTS TO SOUND”, the actual device does go to that state, but the sensor button press counter isn’t showing the right number.

The issue with this is, the physical device state is out of sync with number I am using as a tracker (the “button press counter” sensor)

Generally, you should see your logs to find where your problem is.
Anyway try to add optimistic: true to your template switch configuration.

Ahh, sorry about that. I will add those shortly with a narrative of what I am sending from home assistant service calls.

I will give that a try when I get back to working on this.

If you don’t mind me asking, what is the purpose of that line?

To update the state of itself.

ps. you should ask ChatGPT… :wink:

:slight_smile:

haha. Thank you. Still blows my mind what that thing is capable of.

I’m still a virgin. How do you use it?

By the way, I think you could do the whole crap just with a button and number:

button:
  - platform: template
    name: Virtual Button
    on_press:
      then:
        - number.increment:
            id: counter
            cycle: true
        - lambda: |-
            id(simulated_button).turn_on();
            delay(1000);  // Simulate the physical button press duration
            id(simulated_button).turn_off();


number:
  - platform: template
    name: "Button Press Counter"
    id: counter
    min_value: 1
    max_value: 4
    step: 1
    optimistic: true
    set_action:
      then:
        - homeassistant.service:
            service: input_select.select_option
            data:
              entity_id: input_select.super_mario_light_state
              option: !lambda |-
                if (x == 1) {
                  return "Device OFF";
                } else if (x == 2) {
                  return "Device ON";
                } else if (x == 3) {
                  return "Device PULSING";
                } else if (x == 4) {
                  return "Device REACTS TO SOUND";
                } else {
                  return "Device OFF";
                }

not tested…